From adfd3aa5d40b1a71068c8449843cf6d293115bc1 Mon Sep 17 00:00:00 2001 From: Jeff Date: Fri, 28 Jun 2024 15:35:18 -0400 Subject: [PATCH] Add list type check; Clean up --- dust-lang/src/abstract_tree/as.rs | 18 ++--- dust-lang/src/abstract_tree/function_call.rs | 47 ++++++------ dust-lang/src/abstract_tree/value_node.rs | 65 +++++++++++------ dust-lang/src/context.rs | 38 ++++++++-- dust-lang/src/value.rs | 77 +------------------- dust-lang/tests/validation.rs | 13 ++-- dust-lang/tests/variables.rs | 2 - examples/async_count.ds | 18 +++-- 8 files changed, 124 insertions(+), 154 deletions(-) diff --git a/dust-lang/src/abstract_tree/as.rs b/dust-lang/src/abstract_tree/as.rs index 0664b50..49aa278 100644 --- a/dust-lang/src/abstract_tree/as.rs +++ b/dust-lang/src/abstract_tree/as.rs @@ -30,19 +30,16 @@ impl As { } impl AbstractNode for As { - fn define_types(&self, _: &Context) -> Result<(), ValidationError> { - Ok(()) + fn define_types(&self, _context: &Context) -> Result<(), ValidationError> { + self.expression.define_types(_context) } fn validate(&self, _context: &Context, _manage_memory: bool) -> Result<(), ValidationError> { + self.expression.validate(_context, _manage_memory)?; + match self.constructor { TypeConstructor::Raw(_) => {} - _ => 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."), + _ => todo!("Create an error for this occurence"), }; Ok(()) @@ -66,9 +63,8 @@ impl AbstractNode for As { let (from_value, to_type): (&ValueInner, Type) = (value.inner().borrow(), r#type); let converted = match (from_value, to_type) { - (ValueInner::Boolean(boolean), Type::String) => Value::string(boolean.to_string()), - (ValueInner::Integer(integer), Type::String) => Value::string(integer.to_string()), - _ => todo!("Create an error for this occurence."), + (_, Type::String) => Value::string(value.to_string()), + _ => todo!("Create an error for this occurence"), }; Ok(Some(Evaluation::Return(converted))) diff --git a/dust-lang/src/abstract_tree/function_call.rs b/dust-lang/src/abstract_tree/function_call.rs index 5be7fe1..f199a78 100644 --- a/dust-lang/src/abstract_tree/function_call.rs +++ b/dust-lang/src/abstract_tree/function_call.rs @@ -36,10 +36,6 @@ impl FunctionCall { context: Context::new(None), } } - - pub fn function_expression(&self) -> &Box { - &self.function_expression - } } impl AbstractNode for FunctionCall { @@ -57,17 +53,22 @@ impl AbstractNode for FunctionCall { Ok(()) } - fn validate(&self, context: &Context, manage_memory: bool) -> Result<(), ValidationError> { - self.function_expression.validate(context, manage_memory)?; + fn validate( + &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 { for expression in value_arguments { - expression.validate(context, manage_memory)?; + expression.validate(outer_context, manage_memory)?; } } 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 } else { return Err(ValidationError::ExpectedExpression( @@ -90,7 +91,7 @@ impl AbstractNode for FunctionCall { } 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)?; } @@ -101,7 +102,9 @@ impl AbstractNode for FunctionCall { for ((identifier, _), expression) in 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 } else { return Err(ValidationError::ExpectedExpression(expression.position())); @@ -143,11 +146,13 @@ impl AbstractNode for FunctionCall { fn evaluate( self, - context: &Context, + outer_context: &Context, manage_memory: bool, ) -> Result, RuntimeError> { 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 { value } else { @@ -163,7 +168,7 @@ impl AbstractNode for FunctionCall { for (identifier, constructor) in 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)?; } @@ -176,7 +181,7 @@ impl AbstractNode for FunctionCall { parameters.into_iter().zip(arguments.into_iter()) { 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 { value } else { @@ -215,7 +220,7 @@ impl AbstractNode for FunctionCall { for (identifier, constructor) in 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)?; } @@ -226,7 +231,7 @@ impl AbstractNode for FunctionCall { parameters.into_iter().zip(arguments.into_iter()) { 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 { value } else { @@ -246,7 +251,7 @@ impl AbstractNode for FunctionCall { Err(RuntimeError::ValidationFailure( ValidationError::ExpectedFunction { - actual: value.r#type(context)?, + actual: value.r#type(outer_context)?, position: function_position, }, )) @@ -257,13 +262,13 @@ impl AbstractNode for FunctionCall { 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, - value_parameters, return_type, + .. } = expression_type { - (type_parameters, value_parameters, return_type) + (type_parameters, return_type) } else { return Err(ValidationError::ExpectedFunction { actual: expression_type, @@ -300,7 +305,7 @@ impl Display for FunctionCall { function_expression, type_arguments, value_arguments, - context, + .. } = self; write!(f, "{function_expression}")?; diff --git a/dust-lang/src/abstract_tree/value_node.rs b/dust-lang/src/abstract_tree/value_node.rs index 74223be..0b8aa78 100644 --- a/dust-lang/src/abstract_tree/value_node.rs +++ b/dust-lang/src/abstract_tree/value_node.rs @@ -53,7 +53,7 @@ impl ValueNode { value_parameters, return_type, body, - context_template: Context::new(None), + validation_context: Context::new(None), }) } } @@ -87,14 +87,14 @@ impl AbstractNode for ValueNode { body, type_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 { for identifier in type_parameters { - context_template.set_type( + validation_context.set_type( identifier.clone(), Type::Generic { identifier: identifier.clone(), @@ -108,11 +108,11 @@ impl AbstractNode for ValueNode { for (identifier, type_constructor) in value_parameters { 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> { + 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 { type_name, variant, .. } = self @@ -154,9 +180,9 @@ impl AbstractNode for ValueNode { } else { 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 { conflict, actual_position: expression.position(), @@ -172,17 +198,17 @@ impl AbstractNode for ValueNode { if let ValueNode::Function(FunctionNode { return_type, body, - context_template, + validation_context, .. }) = self { - body.node.validate(&context_template, _manage_memory)?; + body.node.validate(&validation_context, _manage_memory)?; 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)) => ( ( - constructor.construct(context_template)?, + constructor.construct(validation_context)?, constructor.position(), ), r#type, @@ -324,7 +350,7 @@ impl AbstractNode for ValueNode { value_parameters, return_type, body, - context_template, + .. }) => { let outer_context = context; let value_parameters = if let Some(value_parameters) = value_parameters { @@ -346,13 +372,7 @@ impl AbstractNode for ValueNode { None }; - Value::function( - type_parameters, - value_parameters, - return_type, - body.node, - context_template, - ) + Value::function(type_parameters, value_parameters, return_type, body.node) } ValueNode::Structure { name, @@ -450,7 +470,6 @@ impl AbstractNode for ValueNode { } else { None }; - let type_parameters = type_parameters.clone().map(|parameters| { parameters .iter() @@ -687,7 +706,7 @@ impl Display for ValueNode { value_parameters, return_type, body, - context_template: _, + validation_context: _, }) => { write!(f, "fn ")?; @@ -728,7 +747,7 @@ pub struct FunctionNode { return_type: Option, body: WithPosition, #[serde(skip)] - context_template: Context, + validation_context: Context, } impl PartialEq for FunctionNode { diff --git a/dust-lang/src/context.rs b/dust-lang/src/context.rs index 59c13d1..348f6d5 100644 --- a/dust-lang/src/context.rs +++ b/dust-lang/src/context.rs @@ -34,6 +34,18 @@ impl Context { } } + pub fn with_variables_from(other: &Context) -> Result { + 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 { Context::new(Some(self.clone())) } @@ -91,7 +103,8 @@ impl Context { match value.inner().as_ref() { ValueInner::EnumInstance { .. } | 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() { ValueInner::EnumInstance { .. } | ValueInner::Function(_) - | ValueInner::Structure { .. } => return Ok(Some(value)), + | ValueInner::Structure { .. } + | ValueInner::BuiltInFunction(_) => return Ok(Some(value)), _ => {} } } @@ -140,7 +154,7 @@ impl Context { .variables .remove(&identifier) .map(|(_, usage_data)| usage_data) - .unwrap_or(UsageData::new()); + .unwrap_or_else(|| UsageData::new()); data.variables .insert(identifier, (VariableData::Value(value), usage_data)); @@ -156,12 +170,22 @@ impl Context { usage_data.inner().write()?.expected += 1; - Ok(true) + return Ok(true); } else if let Some(parent) = &data.parent { - parent.add_expected_use(identifier) - } else { - Ok(false) + let parent_data = parent.data.read()?; + + 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> { diff --git a/dust-lang/src/value.rs b/dust-lang/src/value.rs index 750aa8d..f8d6abe 100644 --- a/dust-lang/src/value.rs +++ b/dust-lang/src/value.rs @@ -16,7 +16,7 @@ use serde::{ use crate::{ abstract_tree::{AbstractNode, Block, BuiltInFunction, Evaluation, Type, WithPosition}, context::Context, - error::{PoisonError, RuntimeError, ValidationError}, + error::{RuntimeError, ValidationError}, identifier::Identifier, }; @@ -77,14 +77,12 @@ impl Value { value_parameters: Option>, return_type: Option, body: Block, - context_template: Context, ) -> Self { Value(Arc::new(ValueInner::Function(Function { type_parameters, value_parameters, return_type, body, - context_template, }))) } @@ -741,13 +739,12 @@ impl Ord for ValueInner { } } -#[derive(Clone, Debug)] +#[derive(Clone, Debug, Eq, PartialEq, PartialOrd, Ord)] pub struct Function { type_parameters: Option>, value_parameters: Option>, return_type: Option, body: Block, - context_template: Context, } impl Function { @@ -756,21 +753,15 @@ impl Function { value_parameters: Option>, return_type: Option, body: Block, - context_template: Context, ) -> Self { Self { type_parameters, value_parameters, return_type, body, - context_template, } } - pub fn context_template(&self) -> &Context { - &self.context_template - } - pub fn type_parameters(&self) -> &Option> { &self.type_parameters } @@ -790,68 +781,4 @@ impl Function { ) -> Result, RuntimeError> { 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 { - 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 - } - } } diff --git a/dust-lang/tests/validation.rs b/dust-lang/tests/validation.rs index 6dbb426..971c20e 100644 --- a/dust-lang/tests/validation.rs +++ b/dust-lang/tests/validation.rs @@ -1,5 +1,6 @@ use dust_lang::{ error::{DustError, TypeConflict, ValidationError}, + identifier::Identifier, *, }; @@ -69,15 +70,11 @@ fn scope() { .unwrap_err() .errors(), &vec![DustError::Validation { - error: ValidationError::TypeCheck { - conflict: TypeConflict { - actual: Type::String, - expected: Type::Integer - }, - actual_position: (66, 71).into(), - expected_position: Some((60, 63).into()) + error: ValidationError::VariableNotFound { + identifier: Identifier::new("x"), + position: (69, 70).into() }, - position: (55, 71).into() + position: (32, 102).into() }] ); } diff --git a/dust-lang/tests/variables.rs b/dust-lang/tests/variables.rs index 3d43721..cd3bdc7 100644 --- a/dust-lang/tests/variables.rs +++ b/dust-lang/tests/variables.rs @@ -1,6 +1,5 @@ use dust_lang::{ abstract_tree::{Block, Expression, Statement, Type, WithPos}, - context::Context, identifier::Identifier, *, }; @@ -32,7 +31,6 @@ fn function_variable() { Block::new(vec![Statement::Expression(Expression::Identifier( Identifier::new("x").with_position((30, 31)) ))]), - Context::new(None) ))) ); } diff --git a/examples/async_count.ds b/examples/async_count.ds index b4cada0..699291c 100644 --- a/examples/async_count.ds +++ b/examples/async_count.ds @@ -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 while i < 10 { sleep_time = i * multiplier; - thread.sleep(sleep_time) - io.write_line(i as str) + sleep(sleep_time) + write_line(i as str) i += 1 } } async { - count_slowly(50) - count_slowly(100) - count_slowly(200) - count_slowly(250) + count_slowly(50, thread.sleep, io.write_line) + count_slowly(100, thread.sleep, io.write_line) + count_slowly(200, thread.sleep, io.write_line) + count_slowly(250, thread.sleep, io.write_line) }