1
0

Add list type check; Clean up

This commit is contained in:
Jeff 2024-06-28 15:35:18 -04:00
parent fe0bb0a0b5
commit adfd3aa5d4
8 changed files with 124 additions and 154 deletions

View File

@ -30,19 +30,16 @@ impl As {
} }
impl AbstractNode for As { impl AbstractNode for As {
fn define_types(&self, _: &Context) -> Result<(), ValidationError> { fn define_types(&self, _context: &Context) -> Result<(), ValidationError> {
Ok(()) self.expression.define_types(_context)
} }
fn validate(&self, _context: &Context, _manage_memory: bool) -> Result<(), ValidationError> { fn validate(&self, _context: &Context, _manage_memory: bool) -> Result<(), ValidationError> {
self.expression.validate(_context, _manage_memory)?;
match self.constructor { match self.constructor {
TypeConstructor::Raw(_) => {} TypeConstructor::Raw(_) => {}
_ => todo!("Create an error for this occurence."), _ => todo!("Create an error for this occurence"),
};
match self.expression.expected_type(_context)? {
Some(Type::Boolean) | Some(Type::Float) | Some(Type::Integer) | Some(Type::String) => {}
_ => todo!("Create an error for this occurence."),
}; };
Ok(()) Ok(())
@ -66,9 +63,8 @@ impl AbstractNode for As {
let (from_value, to_type): (&ValueInner, Type) = (value.inner().borrow(), r#type); let (from_value, to_type): (&ValueInner, Type) = (value.inner().borrow(), r#type);
let converted = match (from_value, to_type) { let converted = match (from_value, to_type) {
(ValueInner::Boolean(boolean), Type::String) => Value::string(boolean.to_string()), (_, Type::String) => Value::string(value.to_string()),
(ValueInner::Integer(integer), Type::String) => Value::string(integer.to_string()), _ => todo!("Create an error for this occurence"),
_ => todo!("Create an error for this occurence."),
}; };
Ok(Some(Evaluation::Return(converted))) Ok(Some(Evaluation::Return(converted)))

View File

@ -36,10 +36,6 @@ impl FunctionCall {
context: Context::new(None), context: Context::new(None),
} }
} }
pub fn function_expression(&self) -> &Box<Expression> {
&self.function_expression
}
} }
impl AbstractNode for FunctionCall { impl AbstractNode for FunctionCall {
@ -57,17 +53,22 @@ impl AbstractNode for FunctionCall {
Ok(()) Ok(())
} }
fn validate(&self, context: &Context, manage_memory: bool) -> Result<(), ValidationError> { fn validate(
self.function_expression.validate(context, manage_memory)?; &self,
outer_context: &Context,
manage_memory: bool,
) -> Result<(), ValidationError> {
self.function_expression
.validate(outer_context, manage_memory)?;
if let Some(value_arguments) = &self.value_arguments { if let Some(value_arguments) = &self.value_arguments {
for expression in value_arguments { for expression in value_arguments {
expression.validate(context, manage_memory)?; expression.validate(outer_context, manage_memory)?;
} }
} }
let function_node_type = let function_node_type =
if let Some(r#type) = self.function_expression.expected_type(context)? { if let Some(r#type) = self.function_expression.expected_type(outer_context)? {
r#type r#type
} else { } else {
return Err(ValidationError::ExpectedExpression( return Err(ValidationError::ExpectedExpression(
@ -90,7 +91,7 @@ impl AbstractNode for FunctionCall {
} }
for (identifier, constructor) in parameters.into_iter().zip(arguments.into_iter()) { for (identifier, constructor) in parameters.into_iter().zip(arguments.into_iter()) {
let r#type = constructor.construct(context)?; let r#type = constructor.construct(outer_context)?;
self.context.set_type(identifier, r#type)?; self.context.set_type(identifier, r#type)?;
} }
@ -101,7 +102,9 @@ impl AbstractNode for FunctionCall {
for ((identifier, _), expression) in for ((identifier, _), expression) in
parameters.iter().zip(arguments.into_iter()) parameters.iter().zip(arguments.into_iter())
{ {
let r#type = if let Some(r#type) = expression.expected_type(context)? { let r#type = if let Some(r#type) =
expression.expected_type(outer_context)?
{
r#type r#type
} else { } else {
return Err(ValidationError::ExpectedExpression(expression.position())); return Err(ValidationError::ExpectedExpression(expression.position()));
@ -143,11 +146,13 @@ impl AbstractNode for FunctionCall {
fn evaluate( fn evaluate(
self, self,
context: &Context, outer_context: &Context,
manage_memory: bool, manage_memory: bool,
) -> Result<Option<Evaluation>, RuntimeError> { ) -> Result<Option<Evaluation>, RuntimeError> {
let function_position = self.function_expression.position(); let function_position = self.function_expression.position();
let evaluation = self.function_expression.evaluate(context, manage_memory)?; let evaluation = self
.function_expression
.evaluate(outer_context, manage_memory)?;
let value = if let Some(Evaluation::Return(value)) = evaluation { let value = if let Some(Evaluation::Return(value)) = evaluation {
value value
} else { } else {
@ -163,7 +168,7 @@ impl AbstractNode for FunctionCall {
for (identifier, constructor) in for (identifier, constructor) in
type_parameters.into_iter().zip(type_arguments.into_iter()) type_parameters.into_iter().zip(type_arguments.into_iter())
{ {
let r#type = constructor.construct(context)?; let r#type = constructor.construct(outer_context)?;
self.context.set_type(identifier.clone(), r#type)?; self.context.set_type(identifier.clone(), r#type)?;
} }
@ -176,7 +181,7 @@ impl AbstractNode for FunctionCall {
parameters.into_iter().zip(arguments.into_iter()) parameters.into_iter().zip(arguments.into_iter())
{ {
let position = expression.position(); let position = expression.position();
let evaluation = expression.evaluate(context, manage_memory)?; let evaluation = expression.evaluate(outer_context, manage_memory)?;
let value = if let Some(Evaluation::Return(value)) = evaluation { let value = if let Some(Evaluation::Return(value)) = evaluation {
value value
} else { } else {
@ -215,7 +220,7 @@ impl AbstractNode for FunctionCall {
for (identifier, constructor) in for (identifier, constructor) in
type_parameters.into_iter().zip(type_arguments.into_iter()) type_parameters.into_iter().zip(type_arguments.into_iter())
{ {
let r#type = constructor.construct(context)?; let r#type = constructor.construct(outer_context)?;
self.context.set_type(identifier.clone(), r#type)?; self.context.set_type(identifier.clone(), r#type)?;
} }
@ -226,7 +231,7 @@ impl AbstractNode for FunctionCall {
parameters.into_iter().zip(arguments.into_iter()) parameters.into_iter().zip(arguments.into_iter())
{ {
let position = expression.position(); let position = expression.position();
let evaluation = expression.evaluate(context, manage_memory)?; let evaluation = expression.evaluate(outer_context, manage_memory)?;
let value = if let Some(Evaluation::Return(value)) = evaluation { let value = if let Some(Evaluation::Return(value)) = evaluation {
value value
} else { } else {
@ -246,7 +251,7 @@ impl AbstractNode for FunctionCall {
Err(RuntimeError::ValidationFailure( Err(RuntimeError::ValidationFailure(
ValidationError::ExpectedFunction { ValidationError::ExpectedFunction {
actual: value.r#type(context)?, actual: value.r#type(outer_context)?,
position: function_position, position: function_position,
}, },
)) ))
@ -257,13 +262,13 @@ impl AbstractNode for FunctionCall {
ValidationError::ExpectedExpression(self.function_expression.position()), ValidationError::ExpectedExpression(self.function_expression.position()),
)?; )?;
let (type_parameters, value_parameters, return_type) = if let Type::Function { let (type_parameters, return_type) = if let Type::Function {
type_parameters, type_parameters,
value_parameters,
return_type, return_type,
..
} = expression_type } = expression_type
{ {
(type_parameters, value_parameters, return_type) (type_parameters, return_type)
} else { } else {
return Err(ValidationError::ExpectedFunction { return Err(ValidationError::ExpectedFunction {
actual: expression_type, actual: expression_type,
@ -300,7 +305,7 @@ impl Display for FunctionCall {
function_expression, function_expression,
type_arguments, type_arguments,
value_arguments, value_arguments,
context, ..
} = self; } = self;
write!(f, "{function_expression}")?; write!(f, "{function_expression}")?;

View File

@ -53,7 +53,7 @@ impl ValueNode {
value_parameters, value_parameters,
return_type, return_type,
body, body,
context_template: Context::new(None), validation_context: Context::new(None),
}) })
} }
} }
@ -87,14 +87,14 @@ impl AbstractNode for ValueNode {
body, body,
type_parameters, type_parameters,
value_parameters, value_parameters,
context_template, validation_context,
.. ..
}) => { }) => {
context_template.set_parent(outer_context.clone())?; validation_context.set_parent(outer_context.clone())?;
if let Some(type_parameters) = type_parameters { if let Some(type_parameters) = type_parameters {
for identifier in type_parameters { for identifier in type_parameters {
context_template.set_type( validation_context.set_type(
identifier.clone(), identifier.clone(),
Type::Generic { Type::Generic {
identifier: identifier.clone(), identifier: identifier.clone(),
@ -108,11 +108,11 @@ impl AbstractNode for ValueNode {
for (identifier, type_constructor) in value_parameters { for (identifier, type_constructor) in value_parameters {
let r#type = type_constructor.clone().construct(outer_context)?; let r#type = type_constructor.clone().construct(outer_context)?;
context_template.set_type(identifier.clone(), r#type)?; validation_context.set_type(identifier.clone(), r#type)?;
} }
} }
body.node.define_types(context_template)?; body.node.define_types(validation_context)?;
} }
_ => {} _ => {}
} }
@ -121,6 +121,32 @@ impl AbstractNode for ValueNode {
} }
fn validate(&self, context: &Context, _manage_memory: bool) -> Result<(), ValidationError> { fn validate(&self, context: &Context, _manage_memory: bool) -> Result<(), ValidationError> {
if let ValueNode::List(list) = self {
let mut items = list.into_iter();
let first_item = items.next().unwrap();
let first_item_type = if let Some(r#type) = first_item.expected_type(context)? {
r#type
} else {
return Err(ValidationError::ExpectedExpression(first_item.position()));
};
for item in items {
let item_type = if let Some(r#type) = item.expected_type(context)? {
r#type
} else {
return Err(ValidationError::ExpectedExpression(item.position()));
};
first_item_type.check(&item_type).map_err(|conflict| {
ValidationError::TypeCheck {
conflict,
actual_position: item.position(),
expected_position: Some(first_item.position()),
}
})?
}
}
if let ValueNode::EnumInstance { if let ValueNode::EnumInstance {
type_name, variant, .. type_name, variant, ..
} = self } = self
@ -154,9 +180,9 @@ impl AbstractNode for ValueNode {
} else { } else {
return Err(ValidationError::ExpectedExpression(expression.position())); return Err(ValidationError::ExpectedExpression(expression.position()));
}; };
let exprected_type = constructor.clone().construct(&context)?; let expected_type = constructor.clone().construct(&context)?;
exprected_type.check(&actual_type).map_err(|conflict| { expected_type.check(&actual_type).map_err(|conflict| {
ValidationError::TypeCheck { ValidationError::TypeCheck {
conflict, conflict,
actual_position: expression.position(), actual_position: expression.position(),
@ -172,17 +198,17 @@ impl AbstractNode for ValueNode {
if let ValueNode::Function(FunctionNode { if let ValueNode::Function(FunctionNode {
return_type, return_type,
body, body,
context_template, validation_context,
.. ..
}) = self }) = self
{ {
body.node.validate(&context_template, _manage_memory)?; body.node.validate(&validation_context, _manage_memory)?;
let ((expected_return, expected_position), actual_return) = let ((expected_return, expected_position), actual_return) =
match (return_type, body.node.expected_type(&context_template)?) { match (return_type, body.node.expected_type(&validation_context)?) {
(Some(constructor), Some(r#type)) => ( (Some(constructor), Some(r#type)) => (
( (
constructor.construct(context_template)?, constructor.construct(validation_context)?,
constructor.position(), constructor.position(),
), ),
r#type, r#type,
@ -324,7 +350,7 @@ impl AbstractNode for ValueNode {
value_parameters, value_parameters,
return_type, return_type,
body, body,
context_template, ..
}) => { }) => {
let outer_context = context; let outer_context = context;
let value_parameters = if let Some(value_parameters) = value_parameters { let value_parameters = if let Some(value_parameters) = value_parameters {
@ -346,13 +372,7 @@ impl AbstractNode for ValueNode {
None None
}; };
Value::function( Value::function(type_parameters, value_parameters, return_type, body.node)
type_parameters,
value_parameters,
return_type,
body.node,
context_template,
)
} }
ValueNode::Structure { ValueNode::Structure {
name, name,
@ -450,7 +470,6 @@ impl AbstractNode for ValueNode {
} else { } else {
None None
}; };
let type_parameters = type_parameters.clone().map(|parameters| { let type_parameters = type_parameters.clone().map(|parameters| {
parameters parameters
.iter() .iter()
@ -687,7 +706,7 @@ impl Display for ValueNode {
value_parameters, value_parameters,
return_type, return_type,
body, body,
context_template: _, validation_context: _,
}) => { }) => {
write!(f, "fn ")?; write!(f, "fn ")?;
@ -728,7 +747,7 @@ pub struct FunctionNode {
return_type: Option<TypeConstructor>, return_type: Option<TypeConstructor>,
body: WithPosition<Block>, body: WithPosition<Block>,
#[serde(skip)] #[serde(skip)]
context_template: Context, validation_context: Context,
} }
impl PartialEq for FunctionNode { impl PartialEq for FunctionNode {

View File

@ -34,6 +34,18 @@ impl Context {
} }
} }
pub fn with_variables_from(other: &Context) -> Result<Self, PoisonError> {
let variables = other.data.read()?.variables.clone();
Ok(Context {
data: Arc::new(RwLock::new(ContextData {
variables,
parent: None,
})),
is_clean: Arc::new(RwLock::new(true)),
})
}
pub fn create_child(&self) -> Context { pub fn create_child(&self) -> Context {
Context::new(Some(self.clone())) Context::new(Some(self.clone()))
} }
@ -91,7 +103,8 @@ impl Context {
match value.inner().as_ref() { match value.inner().as_ref() {
ValueInner::EnumInstance { .. } ValueInner::EnumInstance { .. }
| ValueInner::Function(_) | ValueInner::Function(_)
| ValueInner::Structure { .. } => return Ok(Some(value)), | ValueInner::Structure { .. }
| ValueInner::BuiltInFunction(_) => return Ok(Some(value)),
_ => {} _ => {}
} }
} }
@ -112,7 +125,8 @@ impl Context {
match value.inner().as_ref() { match value.inner().as_ref() {
ValueInner::EnumInstance { .. } ValueInner::EnumInstance { .. }
| ValueInner::Function(_) | ValueInner::Function(_)
| ValueInner::Structure { .. } => return Ok(Some(value)), | ValueInner::Structure { .. }
| ValueInner::BuiltInFunction(_) => return Ok(Some(value)),
_ => {} _ => {}
} }
} }
@ -140,7 +154,7 @@ impl Context {
.variables .variables
.remove(&identifier) .remove(&identifier)
.map(|(_, usage_data)| usage_data) .map(|(_, usage_data)| usage_data)
.unwrap_or(UsageData::new()); .unwrap_or_else(|| UsageData::new());
data.variables data.variables
.insert(identifier, (VariableData::Value(value), usage_data)); .insert(identifier, (VariableData::Value(value), usage_data));
@ -156,12 +170,22 @@ impl Context {
usage_data.inner().write()?.expected += 1; usage_data.inner().write()?.expected += 1;
Ok(true) return Ok(true);
} else if let Some(parent) = &data.parent { } else if let Some(parent) = &data.parent {
parent.add_expected_use(identifier) let parent_data = parent.data.read()?;
} else {
Ok(false) if let Some((variable_data, usage_data)) = parent_data.variables.get(identifier) {
if let VariableData::Value(value) = variable_data {
if let ValueInner::Function(_) = value.inner().as_ref() {
usage_data.inner().write()?.expected += 1;
return Ok(true);
}
}
}
} }
Ok(false)
} }
pub fn clean(&self) -> Result<(), PoisonError> { pub fn clean(&self) -> Result<(), PoisonError> {

View File

@ -16,7 +16,7 @@ use serde::{
use crate::{ use crate::{
abstract_tree::{AbstractNode, Block, BuiltInFunction, Evaluation, Type, WithPosition}, abstract_tree::{AbstractNode, Block, BuiltInFunction, Evaluation, Type, WithPosition},
context::Context, context::Context,
error::{PoisonError, RuntimeError, ValidationError}, error::{RuntimeError, ValidationError},
identifier::Identifier, identifier::Identifier,
}; };
@ -77,14 +77,12 @@ impl Value {
value_parameters: Option<Vec<(Identifier, Type)>>, value_parameters: Option<Vec<(Identifier, Type)>>,
return_type: Option<Type>, return_type: Option<Type>,
body: Block, body: Block,
context_template: Context,
) -> Self { ) -> Self {
Value(Arc::new(ValueInner::Function(Function { Value(Arc::new(ValueInner::Function(Function {
type_parameters, type_parameters,
value_parameters, value_parameters,
return_type, return_type,
body, body,
context_template,
}))) })))
} }
@ -741,13 +739,12 @@ impl Ord for ValueInner {
} }
} }
#[derive(Clone, Debug)] #[derive(Clone, Debug, Eq, PartialEq, PartialOrd, Ord)]
pub struct Function { pub struct Function {
type_parameters: Option<Vec<Identifier>>, type_parameters: Option<Vec<Identifier>>,
value_parameters: Option<Vec<(Identifier, Type)>>, value_parameters: Option<Vec<(Identifier, Type)>>,
return_type: Option<Type>, return_type: Option<Type>,
body: Block, body: Block,
context_template: Context,
} }
impl Function { impl Function {
@ -756,21 +753,15 @@ impl Function {
value_parameters: Option<Vec<(Identifier, Type)>>, value_parameters: Option<Vec<(Identifier, Type)>>,
return_type: Option<Type>, return_type: Option<Type>,
body: Block, body: Block,
context_template: Context,
) -> Self { ) -> Self {
Self { Self {
type_parameters, type_parameters,
value_parameters, value_parameters,
return_type, return_type,
body, body,
context_template,
} }
} }
pub fn context_template(&self) -> &Context {
&self.context_template
}
pub fn type_parameters(&self) -> &Option<Vec<Identifier>> { pub fn type_parameters(&self) -> &Option<Vec<Identifier>> {
&self.type_parameters &self.type_parameters
} }
@ -790,68 +781,4 @@ impl Function {
) -> Result<Option<Evaluation>, RuntimeError> { ) -> Result<Option<Evaluation>, RuntimeError> {
self.body.evaluate(context, manage_memory) self.body.evaluate(context, manage_memory)
} }
pub fn populate_context_template(&self) -> Result<(), PoisonError> {
if let Some(type_parameters) = &self.type_parameters {
for identifier in type_parameters {
self.context_template.set_type(
identifier.clone(),
Type::Generic {
identifier: identifier.clone(),
concrete_type: None,
},
)?;
}
}
if let Some(value_parameters) = &self.value_parameters {
for (identifier, r#type) in value_parameters {
self.context_template
.set_type(identifier.clone(), r#type.clone())?;
}
}
Ok(())
}
}
impl Eq for Function {}
impl PartialEq for Function {
fn eq(&self, other: &Self) -> bool {
self.type_parameters == other.type_parameters
&& self.value_parameters == other.value_parameters
&& self.return_type == other.return_type
&& self.body == other.body
}
}
impl PartialOrd for Function {
fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
Some(self.cmp(other))
}
}
impl Ord for Function {
fn cmp(&self, other: &Self) -> Ordering {
let type_params_cmp = self.type_parameters.cmp(&other.type_parameters);
if type_params_cmp.is_eq() {
let value_params_cmp = self.value_parameters.cmp(&other.value_parameters);
if value_params_cmp.is_eq() {
let return_cmp = self.return_type.cmp(&other.return_type);
if return_cmp.is_eq() {
self.body.cmp(&other.body)
} else {
return_cmp
}
} else {
value_params_cmp
}
} else {
type_params_cmp
}
}
} }

View File

@ -1,5 +1,6 @@
use dust_lang::{ use dust_lang::{
error::{DustError, TypeConflict, ValidationError}, error::{DustError, TypeConflict, ValidationError},
identifier::Identifier,
*, *,
}; };
@ -69,15 +70,11 @@ fn scope() {
.unwrap_err() .unwrap_err()
.errors(), .errors(),
&vec![DustError::Validation { &vec![DustError::Validation {
error: ValidationError::TypeCheck { error: ValidationError::VariableNotFound {
conflict: TypeConflict { identifier: Identifier::new("x"),
actual: Type::String, position: (69, 70).into()
expected: Type::Integer
},
actual_position: (66, 71).into(),
expected_position: Some((60, 63).into())
}, },
position: (55, 71).into() position: (32, 102).into()
}] }]
); );
} }

View File

@ -1,6 +1,5 @@
use dust_lang::{ use dust_lang::{
abstract_tree::{Block, Expression, Statement, Type, WithPos}, abstract_tree::{Block, Expression, Statement, Type, WithPos},
context::Context,
identifier::Identifier, identifier::Identifier,
*, *,
}; };
@ -32,7 +31,6 @@ fn function_variable() {
Block::new(vec![Statement::Expression(Expression::Identifier( Block::new(vec![Statement::Expression(Expression::Identifier(
Identifier::new("x").with_position((30, 31)) Identifier::new("x").with_position((30, 31))
))]), ))]),
Context::new(None)
))) )))
); );
} }

View File

@ -1,19 +1,23 @@
count_slowly = fn (multiplier: int) { count_slowly = fn (
multiplier: int,
sleep: fn (milliseconds: int),
write_line: fn (output: str),
) {
i = 0 i = 0
while i < 10 { while i < 10 {
sleep_time = i * multiplier; sleep_time = i * multiplier;
thread.sleep(sleep_time) sleep(sleep_time)
io.write_line(i as str) write_line(i as str)
i += 1 i += 1
} }
} }
async { async {
count_slowly(50) count_slowly(50, thread.sleep, io.write_line)
count_slowly(100) count_slowly(100, thread.sleep, io.write_line)
count_slowly(200) count_slowly(200, thread.sleep, io.write_line)
count_slowly(250) count_slowly(250, thread.sleep, io.write_line)
} }