From 99ba7b78ab916ee97b95f6aa5d7c55ac22b1c5ad Mon Sep 17 00:00:00 2001 From: Jeff Date: Thu, 4 Jan 2024 22:30:06 -0500 Subject: [PATCH] Add lots of type checking --- src/abstract_tree/built_in_value.rs | 4 +++ src/abstract_tree/for.rs | 32 ++++++++++++------ src/abstract_tree/function_call.rs | 36 +++++++-------------- src/abstract_tree/function_expression.rs | 10 ++++++ src/abstract_tree/identifier.rs | 8 +++-- src/abstract_tree/if_else.rs | 19 +++++++++++ src/abstract_tree/index.rs | 14 ++++++++ src/abstract_tree/index_assignment.rs | 5 +++ src/abstract_tree/index_expression.rs | 9 ++++++ src/abstract_tree/logic.rs | 5 +++ src/abstract_tree/match.rs | 15 +++++++++ src/abstract_tree/math.rs | 5 +++ src/abstract_tree/mod.rs | 4 +-- src/abstract_tree/structure_instantiator.rs | 19 +++++++++++ src/abstract_tree/type_definition.rs | 8 +++++ src/abstract_tree/while.rs | 5 +++ src/abstract_tree/yield.rs | 4 +++ 17 files changed, 162 insertions(+), 40 deletions(-) diff --git a/src/abstract_tree/built_in_value.rs b/src/abstract_tree/built_in_value.rs index ff367ce..b1816a0 100644 --- a/src/abstract_tree/built_in_value.rs +++ b/src/abstract_tree/built_in_value.rs @@ -172,6 +172,10 @@ impl AbstractTree for BuiltInValue { Ok(self.get().clone()) } + fn check_type(&self, _context: &Structure) -> Result<()> { + Ok(()) + } + fn expected_type(&self, _context: &Structure) -> Result { Ok(self.r#type()) } diff --git a/src/abstract_tree/for.rs b/src/abstract_tree/for.rs index 2c1f89a..c3799bc 100644 --- a/src/abstract_tree/for.rs +++ b/src/abstract_tree/for.rs @@ -11,6 +11,7 @@ pub struct For { item_id: Identifier, collection: Expression, block: Block, + context: Structure, } impl AbstractTree for For { @@ -45,29 +46,42 @@ impl AbstractTree for For { item_id: identifier, collection: expression, block: item, + context: Structure::clone_from(context)?, }) } + fn check_type(&self, context: &Structure) -> Result<()> { + self.collection.check_type(context)?; + + let key = self.item_id.inner(); + let collection_type = self.collection.expected_type(context)?; + + Type::list(Type::Any).check(&collection_type)?; + + if let Type::List(item_type) = self.collection.expected_type(context)? { + self.context + .set(key.to_string(), Value::none(), Some(*item_type))?; + } + + self.block.check_type(&self.context) + } + fn run(&self, source: &str, context: &Structure) -> Result { let expression_run = self.collection.run(source, context)?; - let values = expression_run.as_list()?.items(); let key = self.item_id.inner(); + let values = expression_run.as_list()?.items(); if self.is_async { values.par_iter().try_for_each(|value| { - let iter_context = Structure::clone_from(context)?; + self.context.set(key.clone(), value.clone(), None)?; - iter_context.set(key.clone(), value.clone(), None)?; - - self.block.run(source, &iter_context).map(|_value| ()) + self.block.run(source, &self.context).map(|_value| ()) })?; } else { - let loop_context = Structure::clone_from(context)?; - for value in values.iter() { - loop_context.set(key.clone(), value.clone(), None)?; + self.context.set(key.clone(), value.clone(), None)?; - self.block.run(source, &loop_context)?; + self.block.run(source, &self.context)?; } } diff --git a/src/abstract_tree/function_call.rs b/src/abstract_tree/function_call.rs index e07355a..b12ccea 100644 --- a/src/abstract_tree/function_call.rs +++ b/src/abstract_tree/function_call.rs @@ -45,6 +45,8 @@ impl AbstractTree for FunctionCall { } fn check_type(&self, context: &Structure) -> Result<()> { + self.function_expression.check_type(context)?; + let variables = context.variables()?; let function_type = match &self.function_expression { FunctionExpression::Identifier(identifier) => { @@ -72,6 +74,8 @@ impl AbstractTree for FunctionCall { }; for (index, expression) in self.arguments.iter().enumerate() { + expression.check_type(context)?; + if let Some(r#type) = parameter_types.get(index) { r#type.check(&expression.expected_type(context)?)?; } @@ -133,32 +137,14 @@ impl AbstractTree for FunctionCall { } fn expected_type(&self, context: &Structure) -> Result { - match &self.function_expression { - FunctionExpression::Identifier(identifier) => { - let identifier_type = identifier.expected_type(context)?; + let function_type = self.function_expression.expected_type(context)?; - if let Type::Function { - parameter_types: _, - return_type, - } = &identifier_type - { - Ok(*return_type.clone()) - } else { - Ok(identifier_type) - } - } - FunctionExpression::FunctionCall(function_call) => function_call.expected_type(context), - FunctionExpression::Value(value_node) => { - let value_type = value_node.expected_type(context)?; - - if let Type::Function { return_type, .. } = value_type { - Ok(*return_type) - } else { - Ok(value_type) - } - } - FunctionExpression::Index(index) => index.expected_type(context), - FunctionExpression::Yield(r#yield) => r#yield.expected_type(context), + if let Type::Function { return_type, .. } = function_type { + Ok(*return_type) + } else { + Err(Error::ExpectedFunctionExpression { + actual: self.function_expression.clone(), + }) } } } diff --git a/src/abstract_tree/function_expression.rs b/src/abstract_tree/function_expression.rs index d123c56..1c96134 100644 --- a/src/abstract_tree/function_expression.rs +++ b/src/abstract_tree/function_expression.rs @@ -54,6 +54,16 @@ impl AbstractTree for FunctionExpression { Ok(function_expression) } + fn check_type(&self, _context: &Structure) -> Result<()> { + match self { + FunctionExpression::Identifier(identifier) => identifier.check_type(_context), + FunctionExpression::FunctionCall(function_call) => function_call.check_type(_context), + FunctionExpression::Value(value_node) => value_node.check_type(_context), + FunctionExpression::Index(index) => index.check_type(_context), + FunctionExpression::Yield(r#yield) => r#yield.check_type(_context), + } + } + fn run(&self, source: &str, context: &Structure) -> Result { match self { FunctionExpression::Identifier(identifier) => identifier.run(source, context), diff --git a/src/abstract_tree/identifier.rs b/src/abstract_tree/identifier.rs index 8072c08..aa28a56 100644 --- a/src/abstract_tree/identifier.rs +++ b/src/abstract_tree/identifier.rs @@ -45,10 +45,12 @@ impl AbstractTree for Identifier { Err(Error::VariableIdentifierNotFound(self.0.clone())) } - fn expected_type(&self, context: &Structure) -> Result { - if let Some((_value, r#type)) = context.variables()?.get(&self.0) { - println!("{_value}"); + fn check_type(&self, _context: &Structure) -> Result<()> { + Ok(()) + } + fn expected_type(&self, context: &Structure) -> Result { + if let Some((_, r#type)) = context.variables()?.get(&self.0) { Ok(r#type.clone()) } else { Err(Error::VariableIdentifierNotFound(self.0.clone())) diff --git a/src/abstract_tree/if_else.rs b/src/abstract_tree/if_else.rs index b7f608a..18c3fe6 100644 --- a/src/abstract_tree/if_else.rs +++ b/src/abstract_tree/if_else.rs @@ -55,6 +55,25 @@ impl AbstractTree for IfElse { }) } + fn check_type(&self, _context: &Structure) -> Result<()> { + self.if_expression.check_type(_context)?; + self.if_block.check_type(_context)?; + + for expression in &self.else_if_expressions { + expression.check_type(_context)?; + } + + for block in &self.else_if_blocks { + block.check_type(_context)?; + } + + if let Some(block) = &self.else_block { + block.check_type(_context)?; + } + + Ok(()) + } + fn run(&self, source: &str, context: &Structure) -> Result { let if_boolean = self.if_expression.run(source, context)?.as_boolean()?; diff --git a/src/abstract_tree/index.rs b/src/abstract_tree/index.rs index dd1220e..e4713c7 100644 --- a/src/abstract_tree/index.rs +++ b/src/abstract_tree/index.rs @@ -93,6 +93,20 @@ impl AbstractTree for Index { } } + fn check_type(&self, context: &Structure) -> Result<()> { + let collection_type = self.collection.expected_type(context)?; + + match collection_type { + Type::List(_) | Type::String | Type::Structure(_) | Type::StructureDefinition(_) => { + Ok(()) + } + _ => Err(Error::TypeCheck { + expected: Type::Collection, + actual: collection_type, + }), + } + } + fn expected_type(&self, context: &Structure) -> Result { match self.collection.expected_type(context)? { Type::List(item_type) => Ok(*item_type.clone()), diff --git a/src/abstract_tree/index_assignment.rs b/src/abstract_tree/index_assignment.rs index 65ad40a..be5140f 100644 --- a/src/abstract_tree/index_assignment.rs +++ b/src/abstract_tree/index_assignment.rs @@ -51,6 +51,11 @@ impl AbstractTree for IndexAssignment { }) } + fn check_type(&self, _context: &Structure) -> Result<()> { + self.index.check_type(_context)?; + self.statement.check_type(_context) + } + fn run(&self, source: &str, context: &Structure) -> Result { let index_collection = self.index.collection.run(source, context)?; let index_context = index_collection.as_structure().unwrap_or(context); diff --git a/src/abstract_tree/index_expression.rs b/src/abstract_tree/index_expression.rs index 8dea760..845cc5b 100644 --- a/src/abstract_tree/index_expression.rs +++ b/src/abstract_tree/index_expression.rs @@ -52,6 +52,15 @@ impl AbstractTree for IndexExpression { Ok(abstract_node) } + fn check_type(&self, _context: &Structure) -> Result<()> { + match self { + IndexExpression::Value(value_node) => value_node.check_type(_context), + IndexExpression::Identifier(identifier) => identifier.check_type(_context), + IndexExpression::Index(index) => index.check_type(_context), + IndexExpression::FunctionCall(function_call) => function_call.check_type(_context), + } + } + fn run(&self, source: &str, context: &Structure) -> Result { match self { IndexExpression::Value(value_node) => value_node.run(source, context), diff --git a/src/abstract_tree/logic.rs b/src/abstract_tree/logic.rs index 4866223..a961f1e 100644 --- a/src/abstract_tree/logic.rs +++ b/src/abstract_tree/logic.rs @@ -59,6 +59,11 @@ impl AbstractTree for Logic { }) } + fn check_type(&self, _context: &Structure) -> Result<()> { + self.left.check_type(_context)?; + self.right.check_type(_context) + } + fn run(&self, source: &str, context: &Structure) -> Result { let left = self.left.run(source, context)?; let right = self.right.run(source, context)?; diff --git a/src/abstract_tree/match.rs b/src/abstract_tree/match.rs index 29f4b04..e235dbf 100644 --- a/src/abstract_tree/match.rs +++ b/src/abstract_tree/match.rs @@ -58,6 +58,21 @@ impl AbstractTree for Match { }) } + fn check_type(&self, _context: &Structure) -> Result<()> { + self.matcher.check_type(_context)?; + + for (expression, statement) in &self.options { + expression.check_type(_context)?; + statement.check_type(_context)?; + } + + if let Some(statement) = &self.fallback { + statement.check_type(_context)?; + } + + Ok(()) + } + fn run(&self, source: &str, context: &Structure) -> Result { let matcher_value = self.matcher.run(source, context)?; diff --git a/src/abstract_tree/math.rs b/src/abstract_tree/math.rs index 9ab2a4e..01e04ef 100644 --- a/src/abstract_tree/math.rs +++ b/src/abstract_tree/math.rs @@ -48,6 +48,11 @@ impl AbstractTree for Math { }) } + fn check_type(&self, _context: &Structure) -> Result<()> { + self.left.check_type(_context)?; + self.right.check_type(_context) + } + fn run(&self, source: &str, context: &Structure) -> Result { let left = self.left.run(source, context)?; let right = self.right.run(source, context)?; diff --git a/src/abstract_tree/mod.rs b/src/abstract_tree/mod.rs index 185d636..f21895f 100644 --- a/src/abstract_tree/mod.rs +++ b/src/abstract_tree/mod.rs @@ -108,9 +108,7 @@ pub trait AbstractTree: Sized { fn from_syntax_node(source: &str, node: Node, context: &Structure) -> Result; /// Verify the type integrity of the node. - fn check_type(&self, _context: &Structure) -> Result<()> { - Ok(()) - } + fn check_type(&self, _context: &Structure) -> Result<()>; /// Execute dust code by traversing the tree. fn run(&self, source: &str, context: &Structure) -> Result; diff --git a/src/abstract_tree/structure_instantiator.rs b/src/abstract_tree/structure_instantiator.rs index a19274e..fc96cd6 100644 --- a/src/abstract_tree/structure_instantiator.rs +++ b/src/abstract_tree/structure_instantiator.rs @@ -79,6 +79,25 @@ impl AbstractTree for StructureInstantiator { Ok(instantiator) } + fn check_type(&self, context: &Structure) -> Result<()> { + for (_key, (statement_option, type_definition_option)) in &self.0 { + let statement_type = if let Some(statement) = statement_option { + statement.check_type(context)?; + Some(statement.expected_type(context)?) + } else { + None + }; + + if let (Some(statement_type), Some(type_definition)) = + (statement_type, type_definition_option) + { + type_definition.inner().check(&statement_type)?; + } + } + + Ok(()) + } + fn run(&self, source: &str, context: &Structure) -> Result { let mut variables = BTreeMap::new(); diff --git a/src/abstract_tree/type_definition.rs b/src/abstract_tree/type_definition.rs index 99b7fd1..89e0950 100644 --- a/src/abstract_tree/type_definition.rs +++ b/src/abstract_tree/type_definition.rs @@ -34,6 +34,10 @@ impl AbstractTree for TypeDefinition { Ok(TypeDefinition { r#type }) } + fn check_type(&self, _context: &Structure) -> Result<()> { + Ok(()) + } + fn run(&self, source: &str, context: &Structure) -> Result { self.r#type.run(source, context) } @@ -251,6 +255,10 @@ impl AbstractTree for Type { Ok(r#type) } + fn check_type(&self, _context: &Structure) -> Result<()> { + Ok(()) + } + fn run(&self, _source: &str, _context: &Structure) -> Result { Ok(Value::none()) } diff --git a/src/abstract_tree/while.rs b/src/abstract_tree/while.rs index 2c3cb39..c4d2cc8 100644 --- a/src/abstract_tree/while.rs +++ b/src/abstract_tree/while.rs @@ -25,6 +25,11 @@ impl AbstractTree for While { Ok(While { expression, block }) } + fn check_type(&self, _context: &Structure) -> Result<()> { + self.expression.check_type(_context)?; + self.block.check_type(_context) + } + fn run(&self, source: &str, context: &Structure) -> Result { while self.expression.run(source, context)?.as_boolean()? { self.block.run(source, context)?; diff --git a/src/abstract_tree/yield.rs b/src/abstract_tree/yield.rs index b69b988..d8d53c2 100644 --- a/src/abstract_tree/yield.rs +++ b/src/abstract_tree/yield.rs @@ -44,6 +44,10 @@ impl AbstractTree for Yield { Ok(Yield { call }) } + fn check_type(&self, _context: &Structure) -> Result<()> { + self.call.check_type(_context) + } + fn run(&self, source: &str, context: &Structure) -> Result { self.call.run(source, context) }