diff --git a/dust-lang/src/abstract_tree/as.rs b/dust-lang/src/abstract_tree/as.rs index b41a115..5535b31 100644 --- a/dust-lang/src/abstract_tree/as.rs +++ b/dust-lang/src/abstract_tree/as.rs @@ -9,7 +9,7 @@ use crate::{ Value, }; -use super::{Evaluate, Evaluation, ExpectedType, Expression, Type, TypeConstructor, Validate}; +use super::{AbstractNode, Evaluation, Expression, Type, TypeConstructor}; #[derive(Clone, Debug, Eq, PartialEq, PartialOrd, Ord, Serialize, Deserialize)] pub struct As { @@ -26,35 +26,33 @@ impl As { } } -impl Validate for As { - fn validate( - &self, - _context: &mut Context, - _manage_memory: bool, - ) -> Result<(), ValidationError> { +impl AbstractNode for As { + fn define_types(&self, context: &Context) -> Result<(), ValidationError> { + Ok(()) + } + + fn validate(&self, _context: &Context, _manage_memory: bool) -> Result<(), ValidationError> { match self.constructor { TypeConstructor::Raw(_) => {} _ => todo!("Create an error for this occurence."), }; match self.expression.expected_type(_context)? { - Type::Boolean | Type::Float | Type::Integer | Type::String => {} + Some(Type::Boolean) | Some(Type::Float) | Some(Type::Integer) | Some(Type::String) => {} _ => todo!("Create an error for this occurence."), }; Ok(()) } -} -impl Evaluate for As { fn evaluate( self, - context: &mut Context, + context: &Context, _manage_memory: bool, - ) -> Result { + ) -> Result, RuntimeError> { let expression_position = self.expression.position(); - let action = self.expression.evaluate(context, _manage_memory)?; - let value = if let Evaluation::Return(value) = action { + let evaluation = self.expression.evaluate(context, _manage_memory)?; + let value = if let Some(Evaluation::Return(value)) = evaluation { value } else { return Err(RuntimeError::ValidationFailure( @@ -70,12 +68,12 @@ impl Evaluate for As { _ => todo!("Create an error for this occurence."), }; - Ok(Evaluation::Return(converted)) + Ok(Some(Evaluation::Return(converted))) } -} -impl ExpectedType for As { - fn expected_type(&self, context: &mut Context) -> Result { - self.constructor.clone().construct(&context) + fn expected_type(&self, context: &Context) -> Result, ValidationError> { + self.constructor + .construct(&context) + .map(|r#type| Some(r#type)) } } diff --git a/dust-lang/src/abstract_tree/assignment.rs b/dust-lang/src/abstract_tree/assignment.rs index 8b04ff8..205760e 100644 --- a/dust-lang/src/abstract_tree/assignment.rs +++ b/dust-lang/src/abstract_tree/assignment.rs @@ -9,8 +9,7 @@ use crate::{ use super::{ type_constructor::{RawTypeConstructor, TypeInvokationConstructor}, - Evaluation, ExpectedType, Expression, Run, Statement, Type, TypeConstructor, Validate, - WithPosition, + AbstractNode, Evaluation, Expression, Statement, Type, TypeConstructor, WithPosition, }; #[derive(Clone, Debug, Eq, PartialEq, PartialOrd, Ord, Serialize, Deserialize)] @@ -44,8 +43,37 @@ impl Assignment { } } -impl Validate for Assignment { - fn validate(&self, context: &mut Context, manage_memory: bool) -> Result<(), ValidationError> { +impl AbstractNode for Assignment { + fn define_types(&self, context: &Context) -> Result<(), ValidationError> { + let relevant_statement = self.statement.last_evaluated_statement(); + let statement_type = relevant_statement.expected_type(context)?; + + if let Type::Void = &statement_type { + return Err(ValidationError::CannotAssignToNone( + self.statement.position(), + )); + } + + if let Some(constructor) = &self.constructor { + let r#type = constructor.clone().construct(&context)?; + + r#type + .check(&statement_type) + .map_err(|conflict| ValidationError::TypeCheck { + conflict, + actual_position: self.statement.position(), + expected_position: Some(constructor.position()), + })?; + + context.set_type(self.identifier.node.clone(), r#type.clone())?; + } else { + context.set_type(self.identifier.node.clone(), statement_type.clone())?; + } + + Ok(()) + } + + fn validate(&self, context: &Context, manage_memory: bool) -> Result<(), ValidationError> { if let Some(TypeConstructor::Raw(WithPosition { node: RawTypeConstructor::None, position, @@ -54,7 +82,7 @@ impl Validate for Assignment { return Err(ValidationError::CannotAssignToNone(position.clone())); } - let relevant_statement = self.statement.last_child_statement(); + let relevant_statement = self.statement.last_evaluated_statement(); let statement_type = relevant_statement.expected_type(context)?; if let Type::Void = &statement_type { @@ -137,12 +165,10 @@ impl Validate for Assignment { Ok(()) } -} -impl Run for Assignment { - fn run( + fn evaluate( self, - context: &mut Context, + context: &Context, manage_memory: bool, ) -> Result, RuntimeError> { let evaluation = self.statement.run(context, manage_memory)?; @@ -249,4 +275,8 @@ impl Run for Assignment { Ok(Some(Evaluation::Void)) } + + fn expected_type(&self, context: &Context) -> Result, ValidationError> { + Ok(None) + } } diff --git a/dust-lang/src/abstract_tree/async_block.rs b/dust-lang/src/abstract_tree/async_block.rs index a2f3212..de66b6c 100644 --- a/dust-lang/src/abstract_tree/async_block.rs +++ b/dust-lang/src/abstract_tree/async_block.rs @@ -8,7 +8,7 @@ use crate::{ error::{RuntimeError, ValidationError}, }; -use super::{Evaluation, ExpectedType, Run, Statement, Type, Validate}; +use super::{AbstractNode, Evaluation, Statement, Type}; #[derive(Clone, Debug, Eq, PartialEq, PartialOrd, Ord, Serialize, Deserialize)] pub struct AsyncBlock { @@ -21,20 +21,26 @@ impl AsyncBlock { } } -impl Validate for AsyncBlock { - fn validate(&self, _context: &mut Context, manage_memory: bool) -> Result<(), ValidationError> { +impl AbstractNode for AsyncBlock { + fn define_types(&self, _context: &Context) -> Result<(), ValidationError> { + for statement in &self.statements { + statement.define_types(_context)?; + } + + Ok(()) + } + + fn validate(&self, _context: &Context, manage_memory: bool) -> Result<(), ValidationError> { for statement in &self.statements { statement.validate(_context, manage_memory)?; } Ok(()) } -} -impl Run for AsyncBlock { - fn run( + fn evaluate( self, - _context: &mut Context, + _context: &Context, _manage_memory: bool, ) -> Result, RuntimeError> { let statement_count = self.statements.len(); @@ -61,10 +67,8 @@ impl Run for AsyncBlock { ) .unwrap_or(final_result.into_inner()?) } -} -impl ExpectedType for AsyncBlock { - fn expected_type(&self, _context: &mut Context) -> Result { - self.statements.first().unwrap().expected_type(_context) + fn expected_type(&self, _context: &Context) -> Result, ValidationError> { + self.statements.last().unwrap().expected_type(_context) } } diff --git a/dust-lang/src/abstract_tree/block.rs b/dust-lang/src/abstract_tree/block.rs index 33d97a6..12f691c 100644 --- a/dust-lang/src/abstract_tree/block.rs +++ b/dust-lang/src/abstract_tree/block.rs @@ -5,7 +5,7 @@ use crate::{ error::{RuntimeError, ValidationError}, }; -use super::{Evaluation, ExpectedType, Run, Statement, Type, Validate}; +use super::{AbstractNode, Evaluation, Statement, Type}; #[derive(Clone, Debug, Eq, PartialEq, PartialOrd, Ord, Serialize, Deserialize)] pub struct Block { @@ -26,24 +26,26 @@ impl Block { } } -impl Validate for Block { - fn validate( - &self, - _context: &mut Context, - _manage_memory: bool, - ) -> Result<(), ValidationError> { +impl AbstractNode for Block { + fn define_types(&self, _context: &Context) -> Result<(), ValidationError> { + for statement in &self.statements { + statement.define_types(_context)?; + } + + Ok(()) + } + + fn validate(&self, _context: &Context, _manage_memory: bool) -> Result<(), ValidationError> { for statement in &self.statements { statement.validate(_context, _manage_memory)?; } Ok(()) } -} -impl Run for Block { - fn run( + fn evaluate( self, - _context: &mut Context, + _context: &Context, _manage_memory: bool, ) -> Result, RuntimeError> { let mut previous = None; @@ -54,10 +56,8 @@ impl Run for Block { Ok(previous) } -} -impl ExpectedType for Block { - fn expected_type(&self, _context: &mut Context) -> Result { + fn expected_type(&self, _context: &Context) -> Result, ValidationError> { self.last_statement().expected_type(_context) } } diff --git a/dust-lang/src/abstract_tree/built_in_function_call.rs b/dust-lang/src/abstract_tree/built_in_function_call.rs index a1c84aa..4c257b0 100644 --- a/dust-lang/src/abstract_tree/built_in_function_call.rs +++ b/dust-lang/src/abstract_tree/built_in_function_call.rs @@ -14,7 +14,7 @@ use crate::{ Value, }; -use super::{Evaluate, Evaluation, ExpectedType, Expression, Type, TypeConstructor, Validate}; +use super::{AbstractNode, Evaluation, Expression, Type, TypeConstructor}; #[derive(Clone, Debug, Eq, PartialEq, PartialOrd, Ord, Serialize, Deserialize)] pub enum BuiltInFunctionCall { @@ -25,13 +25,12 @@ pub enum BuiltInFunctionCall { Sleep(Expression), WriteLine(Expression), } +impl AbstractNode for BuiltInFunctionCall { + fn define_types(&self, context: &Context) -> Result<(), ValidationError> { + Ok(()) + } -impl Validate for BuiltInFunctionCall { - fn validate( - &self, - _context: &mut Context, - _manage_memory: bool, - ) -> Result<(), ValidationError> { + fn validate(&self, _context: &Context, _manage_memory: bool) -> Result<(), ValidationError> { match self { BuiltInFunctionCall::JsonParse(_, expression) => { expression.validate(_context, _manage_memory) @@ -49,14 +48,12 @@ impl Validate for BuiltInFunctionCall { } } } -} -impl Evaluate for BuiltInFunctionCall { fn evaluate( self, - context: &mut Context, + context: &Context, _manage_memory: bool, - ) -> Result { + ) -> Result, RuntimeError> { match self { BuiltInFunctionCall::JsonParse(_type, expression) => { let action = expression.clone().evaluate(context, _manage_memory)?; @@ -71,7 +68,7 @@ impl Evaluate for BuiltInFunctionCall { if let ValueInner::String(string) = value.inner().as_ref() { let deserialized = serde_json::from_str(string)?; - Ok(Evaluation::Return(deserialized)) + Ok(Some(Evaluation::Return(deserialized))) } else { Err(RuntimeError::ValidationFailure( ValidationError::ExpectedString { @@ -96,7 +93,7 @@ impl Evaluate for BuiltInFunctionCall { 0 }; - Ok(Evaluation::Return(Value::integer(length))) + Ok(Some(Evaluation::Return(Value::integer(length)))) } BuiltInFunctionCall::ReadFile(expression) => { let action = expression.clone().evaluate(context, _manage_memory)?; @@ -113,16 +110,16 @@ impl Evaluate for BuiltInFunctionCall { String::with_capacity(0) }; - Ok(Evaluation::Return(Value::string(file_contents))) + Ok(Some(Evaluation::Return(Value::string(file_contents)))) } BuiltInFunctionCall::ReadLine => { let mut buffer = String::new(); stdin().read_line(&mut buffer)?; - Ok(Evaluation::Return(Value::string( + Ok(Some(Evaluation::Return(Value::string( buffer.strip_suffix('\n').unwrap_or(&buffer), - ))) + )))) } BuiltInFunctionCall::Sleep(expression) => { let action = expression.clone().evaluate(context, _manage_memory)?; @@ -162,17 +159,17 @@ impl Evaluate for BuiltInFunctionCall { } } } -} -impl ExpectedType for BuiltInFunctionCall { - fn expected_type(&self, context: &mut Context) -> Result { + fn expected_type(&self, context: &Context) -> Result, ValidationError> { match self { - BuiltInFunctionCall::JsonParse(r#type, _) => Ok(r#type.clone().construct(&context)?), - BuiltInFunctionCall::Length(_) => Ok(Type::Integer), - BuiltInFunctionCall::ReadFile(_) => Ok(Type::String), - BuiltInFunctionCall::ReadLine => Ok(Type::String), - BuiltInFunctionCall::Sleep(_) => Ok(Type::Void), - BuiltInFunctionCall::WriteLine(_) => Ok(Type::Void), + BuiltInFunctionCall::JsonParse(r#type, _) => { + Ok(Some(r#type.clone().construct(&context)?)) + } + BuiltInFunctionCall::Length(_) => Ok(Some(Type::Integer)), + BuiltInFunctionCall::ReadFile(_) => Ok(Some(Type::String)), + BuiltInFunctionCall::ReadLine => Ok(Some(Type::String)), + BuiltInFunctionCall::Sleep(_) => Ok(None), + BuiltInFunctionCall::WriteLine(_) => Ok(None), } } } diff --git a/dust-lang/src/abstract_tree/enum_declaration.rs b/dust-lang/src/abstract_tree/enum_declaration.rs index a05cc62..2680e62 100644 --- a/dust-lang/src/abstract_tree/enum_declaration.rs +++ b/dust-lang/src/abstract_tree/enum_declaration.rs @@ -1,8 +1,12 @@ use serde::{Deserialize, Serialize}; -use crate::{context::Context, error::RuntimeError, identifier::Identifier}; +use crate::{ + context::Context, + error::{RuntimeError, ValidationError}, + identifier::Identifier, +}; -use super::{Evaluation, Run, Type, TypeConstructor, WithPosition}; +use super::{AbstractNode, Evaluation, Type, TypeConstructor, WithPosition}; #[derive(Clone, Debug, Eq, PartialEq, PartialOrd, Ord, Serialize, Deserialize)] pub struct EnumDeclaration { @@ -25,12 +29,8 @@ impl EnumDeclaration { } } -impl Run for EnumDeclaration { - fn run( - self, - context: &mut Context, - _manage_memory: bool, - ) -> Result, RuntimeError> { +impl AbstractNode for EnumDeclaration { + fn define_types(&self, context: &Context) -> Result<(), ValidationError> { let EnumDeclaration { name, type_parameters, @@ -74,6 +74,29 @@ impl Run for EnumDeclaration { context.set_type(name.node, r#type)?; + Ok(()) + } + + fn validate( + &self, + context: &Context, + manage_memory: bool, + ) -> Result<(), crate::error::ValidationError> { + Ok(()) + } + + fn evaluate( + self, + context: &Context, + _manage_memory: bool, + ) -> Result, RuntimeError> { + Ok(None) + } + + fn expected_type( + &self, + context: &Context, + ) -> Result, crate::error::ValidationError> { Ok(None) } } diff --git a/dust-lang/src/abstract_tree/expression.rs b/dust-lang/src/abstract_tree/expression.rs index 53acc20..2c9a3ca 100644 --- a/dust-lang/src/abstract_tree/expression.rs +++ b/dust-lang/src/abstract_tree/expression.rs @@ -7,8 +7,8 @@ use crate::{ }; use super::{ - As, BuiltInFunctionCall, Evaluate, Evaluation, ExpectedType, FunctionCall, ListIndex, Logic, - MapIndex, Math, SourcePosition, Type, Validate, ValueNode, WithPosition, + AbstractNode, As, BuiltInFunctionCall, Evaluation, FunctionCall, ListIndex, Logic, MapIndex, + Math, SourcePosition, Type, ValueNode, WithPosition, }; #[derive(Clone, Debug, Eq, PartialEq, PartialOrd, Ord, Serialize, Deserialize)] @@ -40,8 +40,22 @@ impl Expression { } } -impl Validate for Expression { - fn validate(&self, context: &mut Context, manage_memory: bool) -> Result<(), ValidationError> { +impl AbstractNode for Expression { + fn define_types(&self, _context: &Context) -> Result<(), ValidationError> { + match self { + Expression::As(inner) => inner.node.define_types(_context), + Expression::BuiltInFunctionCall(inner) => inner.node.define_types(_context), + Expression::FunctionCall(inner) => inner.node.define_types(_context), + Expression::Identifier(inner) => inner.node.define_types(_context), + Expression::MapIndex(inner) => inner.node.define_types(_context), + Expression::ListIndex(inner) => inner.node.define_types(_context), + Expression::Logic(inner) => inner.node.define_types(_context), + Expression::Math(inner) => inner.node.define_types(_context), + Expression::Value(inner) => inner.node.define_types(_context), + } + } + + fn validate(&self, context: &Context, manage_memory: bool) -> Result<(), ValidationError> { match self { Expression::As(r#as) => r#as.node.validate(context, manage_memory), Expression::BuiltInFunctionCall(built_in_function_call) => { @@ -73,14 +87,12 @@ impl Validate for Expression { Expression::Value(value_node) => value_node.node.validate(context, manage_memory), } } -} -impl Evaluate for Expression { fn evaluate( self, - context: &mut Context, + context: &Context, manage_memory: bool, - ) -> Result { + ) -> Result, RuntimeError> { match self { Expression::As(r#as) => r#as.node.evaluate(context, manage_memory), Expression::FunctionCall(function_call) => { @@ -94,7 +106,7 @@ impl Evaluate for Expression { }; if let Some(value) = value_option { - Ok(Evaluation::Return(value)) + Ok(Some(Evaluation::Return(value))) } else { Err(RuntimeError::ValidationFailure( ValidationError::VariableNotFound { @@ -114,21 +126,21 @@ impl Evaluate for Expression { } } } -} -impl ExpectedType for Expression { - fn expected_type(&self, _context: &mut Context) -> Result { + fn expected_type(&self, _context: &Context) -> Result, ValidationError> { match self { Expression::As(r#as) => r#as.node.expected_type(_context), Expression::FunctionCall(function_call) => function_call.node.expected_type(_context), Expression::Identifier(identifier) => { - if let Some(r#type) = _context.get_type(&identifier.node)? { - Ok(r#type) - } else { + let get_type = _context.get_type(identifier)?; + + if get_type.is_none() { Err(ValidationError::VariableNotFound { identifier: identifier.node.clone(), position: identifier.position, }) + } else { + Ok(get_type) } } Expression::MapIndex(map_index) => map_index.node.expected_type(_context), diff --git a/dust-lang/src/abstract_tree/function_call.rs b/dust-lang/src/abstract_tree/function_call.rs index a76b885..f4d45e0 100644 --- a/dust-lang/src/abstract_tree/function_call.rs +++ b/dust-lang/src/abstract_tree/function_call.rs @@ -6,7 +6,7 @@ use crate::{ value::ValueInner, }; -use super::{Evaluate, Evaluation, ExpectedType, Expression, Type, TypeConstructor, Validate}; +use super::{AbstractNode, Evaluation, Expression, Type, TypeConstructor}; #[derive(Debug, Clone, Eq, PartialEq, PartialOrd, Ord, Serialize, Deserialize)] pub struct FunctionCall { @@ -33,8 +33,20 @@ impl FunctionCall { } } -impl Validate for FunctionCall { - fn validate(&self, context: &mut Context, manage_memory: bool) -> Result<(), ValidationError> { +impl AbstractNode for FunctionCall { + fn define_types(&self, _context: &Context) -> Result<(), ValidationError> { + self.function.define_ypes(_context)?; + + let mut previous = (); + + for expression in &self.value_arguments { + previous = expression.define_types(_context)?; + } + + Ok(previous) + } + + fn validate(&self, context: &Context, manage_memory: bool) -> Result<(), ValidationError> { self.function.validate(context, manage_memory)?; for expression in &self.value_arguments { @@ -69,14 +81,12 @@ impl Validate for FunctionCall { }) } } -} -impl Evaluate for FunctionCall { fn evaluate( self, - context: &mut Context, + context: &Context, clear_variables: bool, - ) -> Result { + ) -> Result, RuntimeError> { let function_position = self.function.position(); let action = self.function.evaluate(context, clear_variables)?; let value = if let Evaluation::Return(value) = action { @@ -131,10 +141,8 @@ impl Evaluate for FunctionCall { .clone() .call(arguments, &mut function_context, clear_variables) } -} -impl ExpectedType for FunctionCall { - fn expected_type(&self, context: &mut Context) -> Result { + fn expected_type(&self, context: &Context) -> Result, ValidationError> { let function_node_type = self.function.expected_type(context)?; if let Type::Function { @@ -157,10 +165,10 @@ impl ExpectedType for FunctionCall { if identifier == &return_identifier { let concrete_type = constructor.clone().construct(&context)?; - return Ok(Type::Generic { + return Ok(Some(Type::Generic { identifier: identifier.clone(), concrete_type: Some(Box::new(concrete_type)), - }); + })); } } } @@ -173,16 +181,16 @@ impl ExpectedType for FunctionCall { if identifier == return_identifier { let concrete_type = expression.expected_type(context)?; - return Ok(Type::Generic { + return Ok(Some(Type::Generic { identifier, concrete_type: Some(Box::new(concrete_type)), - }); + })); } } } } - Ok(*return_type) + Ok(Some(*return_type)) } else { Err(ValidationError::ExpectedFunction { actual: function_node_type, diff --git a/dust-lang/src/abstract_tree/if_else.rs b/dust-lang/src/abstract_tree/if_else.rs index d072093..fa8511b 100644 --- a/dust-lang/src/abstract_tree/if_else.rs +++ b/dust-lang/src/abstract_tree/if_else.rs @@ -6,9 +6,7 @@ use crate::{ value::ValueInner, }; -use super::{ - Block, Evaluate, Evaluation, ExpectedType, Expression, Run, Type, Validate, WithPosition, -}; +use super::{AbstractNode, Block, Evaluation, Expression, Type, WithPosition}; #[derive(Clone, Debug, Eq, PartialEq, PartialOrd, Ord, Serialize, Deserialize)] pub struct IfElse { @@ -34,8 +32,26 @@ impl IfElse { } } -impl Validate for IfElse { - fn validate(&self, context: &mut Context, manage_memory: bool) -> Result<(), ValidationError> { +impl AbstractNode for IfElse { + fn define_types(&self, _context: &Context) -> Result<(), ValidationError> { + self.if_expression.define_types(_context)?; + self.if_block.define_type(_context)?; + + if let Some(else_ifs) = self.else_ifs { + for (expression, block) in else_ifs { + expression.define_types(_context)?; + block.node.define_types(_context)?; + } + } + + if let Some(else_block) = self.else_block { + else_block.node.define_types(_context)?; + } + + Ok(()) + } + + fn validate(&self, context: &Context, manage_memory: bool) -> Result<(), ValidationError> { self.if_expression.validate(context, manage_memory)?; self.if_block.node.validate(context, manage_memory)?; @@ -90,12 +106,10 @@ impl Validate for IfElse { Ok(()) } -} -impl Run for IfElse { - fn run( + fn evaluate( self, - context: &mut Context, + context: &Context, _manage_memory: bool, ) -> Result, RuntimeError> { let if_position = self.if_expression.position(); @@ -154,10 +168,8 @@ impl Run for IfElse { )) } } -} -impl ExpectedType for IfElse { - fn expected_type(&self, _context: &mut Context) -> Result { + fn expected_type(&self, _context: &Context) -> Result, ValidationError> { self.if_block.node.expected_type(_context) } } diff --git a/dust-lang/src/abstract_tree/list_index.rs b/dust-lang/src/abstract_tree/list_index.rs index 44949ab..0843be1 100644 --- a/dust-lang/src/abstract_tree/list_index.rs +++ b/dust-lang/src/abstract_tree/list_index.rs @@ -5,9 +5,7 @@ use crate::{ error::{RuntimeError, ValidationError}, }; -use super::{ - Evaluate, Evaluation, ExpectedType, Expression, Type, Validate, ValueNode, WithPosition, -}; +use super::{AbstractNode, Evaluation, Expression, Type, Validate, ValueNode, WithPosition}; #[derive(Clone, Debug, Eq, PartialEq, PartialOrd, Ord, Serialize, Deserialize)] pub struct ListIndex { @@ -32,12 +30,16 @@ impl Validate for ListIndex { let collection_type = self.collection.expected_type(context)?; let index_type = self.index.expected_type(context)?; + if index_type.is_none() { + return Err(ValidationError::CannotIndexWithVoid(self.index.position())); + } + match collection_type { Type::List { length: _, item_type: _, } => { - if index_type == Type::Integer { + if index_type == Some(Type::Integer) { Ok(()) } else { Err(ValidationError::CannotIndexWith { @@ -57,12 +59,12 @@ impl Validate for ListIndex { } } -impl Evaluate for ListIndex { +impl AbstractNode for ListIndex { fn evaluate( self, context: &mut Context, _clear_variables: bool, - ) -> Result { + ) -> Result, RuntimeError> { let left_position = self.collection.position(); let left_action = self.collection.evaluate(context, _clear_variables)?; let left_value = if let Evaluation::Return(value) = left_action { @@ -86,7 +88,7 @@ impl Evaluate for ListIndex { let found_item = list.get(index as usize); if let Some(item) = found_item { - Ok(Evaluation::Return(item.clone())) + Ok(Some(Evaluation::Return(item.clone()))) } else { Ok(Evaluation::Void) } @@ -101,10 +103,8 @@ impl Evaluate for ListIndex { )) } } -} -impl ExpectedType for ListIndex { - fn expected_type(&self, _context: &mut Context) -> Result { + fn expected_type(&self, _context: &mut Context) -> Result, ValidationError> { let left_type = self.collection.expected_type(_context)?; if let ( diff --git a/dust-lang/src/abstract_tree/logic.rs b/dust-lang/src/abstract_tree/logic.rs index 655f954..14c73d3 100644 --- a/dust-lang/src/abstract_tree/logic.rs +++ b/dust-lang/src/abstract_tree/logic.rs @@ -7,7 +7,7 @@ use crate::{ Value, }; -use super::{Evaluate, Evaluation, ExpectedType, Expression, Type, Validate}; +use super::{AbstractNode, Evaluation, Expression, Type, Validate}; #[derive(Clone, Debug, Eq, PartialEq, PartialOrd, Ord, Serialize, Deserialize)] pub enum Logic { @@ -90,12 +90,12 @@ impl Validate for Logic { } } -impl Evaluate for Logic { +impl AbstractNode for Logic { fn evaluate( self, context: &mut Context, _manage_memory: bool, - ) -> Result { + ) -> Result, RuntimeError> { let run_and_expect_value = |expression: Expression| -> Result { let expression_position = expression.position(); let action = expression.evaluate(&mut context.clone(), _manage_memory)?; @@ -193,13 +193,11 @@ impl Evaluate for Logic { } }; - Ok(Evaluation::Return(Value::boolean(boolean))) + Ok(Some(Evaluation::Return(Value::boolean(boolean)))) } -} -impl ExpectedType for Logic { - fn expected_type(&self, _context: &mut Context) -> Result { - Ok(Type::Boolean) + fn expected_type(&self, _context: &mut Context) -> Result, ValidationError> { + Ok(Some(Type::Boolean)) } } diff --git a/dust-lang/src/abstract_tree/loop.rs b/dust-lang/src/abstract_tree/loop.rs index e591952..9d61262 100644 --- a/dust-lang/src/abstract_tree/loop.rs +++ b/dust-lang/src/abstract_tree/loop.rs @@ -5,7 +5,7 @@ use crate::{ error::{RuntimeError, ValidationError}, }; -use super::{Evaluation, Run, Statement, Validate}; +use super::{AbstractNode, Evaluation, Statement, Validate}; #[derive(Clone, Debug, Eq, PartialEq, PartialOrd, Ord, Serialize, Deserialize)] pub struct Loop { @@ -36,8 +36,8 @@ impl Validate for Loop { } } -impl Run for Loop { - fn run( +impl AbstractNode for Loop { + fn evaluate( self, _context: &mut Context, _manage_memory: bool, @@ -52,4 +52,11 @@ impl Run for Loop { } } } + + fn expected_type( + &self, + _context: &mut Context, + ) -> Result, ValidationError> { + self.last_statement().expected_type(_context) + } } diff --git a/dust-lang/src/abstract_tree/map_index.rs b/dust-lang/src/abstract_tree/map_index.rs index a0c1543..94e65c7 100644 --- a/dust-lang/src/abstract_tree/map_index.rs +++ b/dust-lang/src/abstract_tree/map_index.rs @@ -6,9 +6,7 @@ use crate::{ value::ValueInner, }; -use super::{ - Evaluate, Evaluation, ExpectedType, Expression, Type, Validate, ValueNode, WithPosition, -}; +use super::{AbstractNode, Evaluation, Expression, Type, Validate, ValueNode, WithPosition}; #[derive(Clone, Debug, Eq, PartialEq, PartialOrd, Ord, Serialize, Deserialize)] pub struct MapIndex { @@ -35,12 +33,12 @@ impl Validate for MapIndex { } } -impl Evaluate for MapIndex { +impl AbstractNode for MapIndex { fn evaluate( self, context: &mut Context, _manage_memory: bool, - ) -> Result { + ) -> Result, RuntimeError> { let collection_position = self.collection.position(); let action = self.collection.evaluate(context, _manage_memory)?; let collection = if let Evaluation::Return(value) = action { @@ -54,12 +52,11 @@ impl Evaluate for MapIndex { if let (ValueInner::Map(map), Expression::Identifier(index)) = (collection.inner().as_ref(), self.index) { - let action = map + let evaluation = map .get(&index.node) - .map(|value| Evaluation::Return(value.clone())) - .unwrap_or(Evaluation::Void); + .map(|value| Some(Evaluation::Return(value.clone()))); - Ok(action) + Ok(evaluation) } else { Err(RuntimeError::ValidationFailure( ValidationError::CannotIndex { @@ -69,10 +66,8 @@ impl Evaluate for MapIndex { )) } } -} -impl ExpectedType for MapIndex { - fn expected_type(&self, context: &mut Context) -> Result { + fn expected_type(&self, context: &mut Context) -> Result, ValidationError> { if let (Expression::Identifier(collection), Expression::Identifier(index)) = (&self.collection, &self.index) { @@ -87,7 +82,7 @@ impl ExpectedType for MapIndex { if let ValueInner::Map(map) = collection.inner().as_ref() { return if let Some(value) = map.get(&index.node) { - Ok(value.r#type(context)?) + Ok(Some(value.r#type(context)?)) } else { Err(ValidationError::PropertyNotFound { identifier: index.node.clone(), @@ -110,9 +105,9 @@ impl ExpectedType for MapIndex { return if let Some(constructor) = constructor_option { let r#type = constructor.clone().construct(&context)?; - Ok(r#type) + Ok(Some(r#type)) } else { - Ok(expression.expected_type(context)?) + expression.expected_type(context) }; } } diff --git a/dust-lang/src/abstract_tree/math.rs b/dust-lang/src/abstract_tree/math.rs index 68c8ca2..84dac74 100644 --- a/dust-lang/src/abstract_tree/math.rs +++ b/dust-lang/src/abstract_tree/math.rs @@ -7,7 +7,7 @@ use crate::{ Value, }; -use super::{Evaluate, Evaluation, ExpectedType, Expression, SourcePosition, Type, Validate}; +use super::{AbstractNode, Evaluation, Expression, SourcePosition, Type, Validate}; #[derive(Clone, Debug, Eq, PartialEq, PartialOrd, Ord, Serialize, Deserialize)] pub enum Math { @@ -68,12 +68,12 @@ impl Validate for Math { } } -impl Evaluate for Math { +impl AbstractNode for Math { fn evaluate( self, _context: &mut Context, _clear_variables: bool, - ) -> Result { + ) -> Result, RuntimeError> { let run_and_expect_value = |position: SourcePosition, expression: Expression| -> Result { let action = expression.evaluate(&mut _context.clone(), _clear_variables)?; @@ -293,12 +293,10 @@ impl Evaluate for Math { } }; - Ok(Evaluation::Return(value)) + Ok(Some(Evaluation::Return(value))) } -} -impl ExpectedType for Math { - fn expected_type(&self, _context: &mut Context) -> Result { + fn expected_type(&self, _context: &mut Context) -> Result, ValidationError> { match self { Math::Add(left, right) | Math::Subtract(left, right) @@ -309,11 +307,11 @@ impl ExpectedType for Math { let right_type = right.expected_type(_context)?; if let Type::Float = left_type { - return Ok(Type::Float); + return Ok(Some(Type::Float)); } if let Type::Float = right_type { - return Ok(Type::Float); + return Ok(Some(Type::Float)); } Ok(left_type) diff --git a/dust-lang/src/abstract_tree/mod.rs b/dust-lang/src/abstract_tree/mod.rs index e7564e7..4cf1454 100644 --- a/dust-lang/src/abstract_tree/mod.rs +++ b/dust-lang/src/abstract_tree/mod.rs @@ -94,7 +94,6 @@ pub enum Evaluation { Break, Continue, Return(Value), - Void, } #[derive(Debug, Clone)] @@ -116,10 +115,37 @@ impl AbstractTree { context: &mut Context, manage_memory: bool, ) -> Result, Vec> { - let valid_statements = self.validate(context, manage_memory)?; + let mut errors = Vec::new(); + + for statement in &self.0 { + let define_result = statement.define_types(context); + + if let Err(error) = define_result { + errors.push(DustError::Validation { + error, + position: statement.position(), + }); + + continue; + } + + let validation_result = statement.validate(context, manage_memory); + + if let Err(error) = validation_result { + errors.push(DustError::Validation { + error, + position: statement.position(), + }); + } + } + + if !errors.is_empty() { + return Err(errors); + } + let mut previous_value = None; - for statement in valid_statements { + for statement in self.0 { let position = statement.position(); let run = statement.run(context, manage_memory); @@ -140,50 +166,6 @@ impl AbstractTree { Ok(previous_value) } - - fn validate( - self, - context: &mut Context, - manage_memory: bool, - ) -> Result, Vec> { - let mut errors = Vec::new(); - let mut valid_statements = Vec::new(); - - for statement in self.0 { - let validation = statement.validate(context, manage_memory); - - if let Err(validation_error) = validation { - errors.push(DustError::Validation { - error: validation_error, - position: statement.position(), - }) - } else if errors.is_empty() { - if let Statement::StructureDefinition(_) = statement { - let position = statement.position(); - let run = statement.run(context, true); - - if let Err(runtime_error) = run { - errors.push(DustError::Runtime { - error: runtime_error, - position, - }); - - return Err(errors); - } - } else { - valid_statements.push(statement) - } - } else { - continue; - } - } - - if errors.is_empty() { - Ok(valid_statements) - } else { - Err(errors) - } - } } impl Index for AbstractTree { @@ -194,26 +176,16 @@ impl Index for AbstractTree { } } -pub trait Validate { - fn validate(&self, context: &mut Context, manage_memory: bool) -> Result<(), ValidationError>; -} +pub trait AbstractNode { + fn define_types(&self, context: &Context) -> Result<(), ValidationError>; + + fn validate(&self, context: &Context, manage_memory: bool) -> Result<(), ValidationError>; -pub trait Evaluate: ExpectedType { fn evaluate( self, - context: &mut Context, - manage_memory: bool, - ) -> Result; -} - -pub trait Run { - fn run( - self, - context: &mut Context, + context: &Context, manage_memory: bool, ) -> Result, RuntimeError>; -} -pub trait ExpectedType { - fn expected_type(&self, context: &mut Context) -> Result; + fn expected_type(&self, context: &Context) -> Result, ValidationError>; } diff --git a/dust-lang/src/abstract_tree/statement.rs b/dust-lang/src/abstract_tree/statement.rs index c2faf36..43b4119 100644 --- a/dust-lang/src/abstract_tree/statement.rs +++ b/dust-lang/src/abstract_tree/statement.rs @@ -6,9 +6,9 @@ use crate::{ }; use super::{ - Assignment, AsyncBlock, Block, EnumDeclaration, Evaluate, Evaluation, ExpectedType, Expression, - IfElse, Loop, Run, SourcePosition, StructureDefinition, Type, TypeAlias, Validate, While, - WithPosition, + AbstractNode, Assignment, AsyncBlock, Block, DefineTypes, EnumDeclaration, Evaluation, + Expression, IfElse, Loop, SourcePosition, StructureDefinition, Type, TypeAlias, Validate, + While, WithPosition, }; #[derive(Clone, Debug, Eq, PartialEq, PartialOrd, Ord, Serialize, Deserialize)] @@ -43,7 +43,7 @@ impl Statement { } } - pub fn last_child_statement(&self) -> &Self { + pub fn last_evaluated_statement(&self) -> &Self { match self { Statement::Block(inner) => inner.node.last_statement(), Statement::Loop(inner) => inner.node.last_statement(), @@ -52,30 +52,50 @@ impl Statement { } } -impl Run for Statement { - fn run( +impl DefineTypes for Statement { + fn define_types(&self, _context: &Context) -> Result<(), ValidationError> { + match self { + Statement::Expression(expression) => expression.define_types(_context), + Statement::IfElse(if_else) => if_else.node.define_types(_context), + Statement::Block(block) => block.node.define_types(_context), + Statement::AsyncBlock(async_block) => async_block.node.define_types(_context), + Statement::Assignment(assignment) => assignment.node.define_types(_context), + Statement::Break(_) => Ok(None), + Statement::Loop(r#loop) => r#loop.node.define_types(_context), + Statement::StructureDefinition(struct_definition) => { + struct_definition.node.define_types(_context) + } + Statement::TypeAlias(type_alias) => type_alias.node.define_types(_context), + Statement::EnumDeclaration(enum_declaration) => { + enum_declaration.node.define_types(_context) + } + Statement::While(r#while) => r#while.node.define_types(_context), + } + } +} + +impl AbstractNode for Statement { + fn evaluate( self, context: &mut Context, manage_memory: bool, ) -> Result, RuntimeError> { let result = match self { - Statement::Assignment(assignment) => assignment.node.run(context, manage_memory), - Statement::AsyncBlock(async_block) => async_block.node.run(context, manage_memory), - Statement::Block(block) => block.node.run(context, manage_memory), + Statement::Assignment(assignment) => assignment.node.evaluate(context, manage_memory), + Statement::AsyncBlock(async_block) => async_block.node.evaluate(context, manage_memory), + Statement::Block(block) => block.node.evaluate(context, manage_memory), Statement::Break(_) => Ok(Some(Evaluation::Break)), - Statement::Expression(expression) => { - let evaluation = expression.evaluate(context, manage_memory)?; - - Ok(Some(evaluation)) - } - Statement::IfElse(if_else) => if_else.node.run(context, manage_memory), - Statement::Loop(r#loop) => r#loop.node.run(context, manage_memory), + Statement::Expression(expression) => expression.evaluate(context, manage_memory), + Statement::IfElse(if_else) => if_else.node.evaluate(context, manage_memory), + Statement::Loop(r#loop) => r#loop.node.evaluate(context, manage_memory), Statement::StructureDefinition(structure_definition) => { - structure_definition.node.run(context, manage_memory) + structure_definition.node.evaluate(context, manage_memory) } - Statement::TypeAlias(type_alias) => type_alias.node.run(context, manage_memory), - Statement::EnumDeclaration(type_alias) => type_alias.node.run(context, manage_memory), - Statement::While(r#while) => r#while.node.run(context, manage_memory), + Statement::TypeAlias(type_alias) => type_alias.node.evaluate(context, manage_memory), + Statement::EnumDeclaration(type_alias) => { + type_alias.node.evaluate(context, manage_memory) + } + Statement::While(r#while) => r#while.node.evaluate(context, manage_memory), }; if manage_memory { @@ -84,6 +104,26 @@ impl Run for Statement { result } + + fn expected_type(&self, _context: &mut Context) -> Result, ValidationError> { + match self { + Statement::Expression(expression) => expression.expected_type(_context), + Statement::IfElse(if_else) => if_else.node.expected_type(_context), + Statement::Block(block) => block.node.expected_type(_context), + Statement::AsyncBlock(async_block) => async_block.node.expected_type(_context), + Statement::Assignment(assignment) => assignment.node.expected_type(_context), + Statement::Break(_) => Ok(None), + Statement::Loop(r#loop) => r#loop.node.expected_type(_context), + Statement::StructureDefinition(struct_definition) => { + struct_definition.node.expected_type(_context) + } + Statement::TypeAlias(type_alias) => type_alias.node.expected_type(_context), + Statement::EnumDeclaration(enum_declaration) => { + enum_declaration.node.expected_type(_context) + } + Statement::While(r#while) => r#while.node.expected_type(_context), + } + } } impl Validate for Statement { @@ -107,15 +147,3 @@ impl Validate for Statement { } } } - -impl ExpectedType for Statement { - fn expected_type(&self, _context: &mut Context) -> Result { - match self { - Statement::Expression(expression) => expression.expected_type(_context), - Statement::IfElse(if_else) => if_else.node.expected_type(_context), - Statement::Block(block) => block.node.expected_type(_context), - Statement::AsyncBlock(async_block) => async_block.node.expected_type(_context), - _ => Ok(Type::Void), - } - } -} diff --git a/dust-lang/src/abstract_tree/structure_definition.rs b/dust-lang/src/abstract_tree/structure_definition.rs index dc0dd16..d198307 100644 --- a/dust-lang/src/abstract_tree/structure_definition.rs +++ b/dust-lang/src/abstract_tree/structure_definition.rs @@ -2,7 +2,7 @@ use serde::{Deserialize, Serialize}; use crate::{context::Context, error::RuntimeError, identifier::Identifier}; -use super::{Evaluation, Run, Type, TypeConstructor}; +use super::{AbstractNode, Evaluation, Type, TypeConstructor}; #[derive(Clone, Debug, Eq, PartialEq, PartialOrd, Ord, Serialize, Deserialize)] pub struct StructureDefinition { @@ -16,8 +16,8 @@ impl StructureDefinition { } } -impl Run for StructureDefinition { - fn run( +impl AbstractNode for StructureDefinition { + fn evaluate( self, context: &mut Context, _manage_memory: bool, @@ -39,4 +39,11 @@ impl Run for StructureDefinition { Ok(None) } + + fn expected_type( + &self, + context: &mut Context, + ) -> Result, crate::error::ValidationError> { + Ok(None) + } } diff --git a/dust-lang/src/abstract_tree/type.rs b/dust-lang/src/abstract_tree/type.rs index 84a8ceb..2eb874a 100644 --- a/dust-lang/src/abstract_tree/type.rs +++ b/dust-lang/src/abstract_tree/type.rs @@ -37,7 +37,6 @@ pub enum Type { name: Identifier, fields: Vec<(Identifier, Type)>, }, - Void, } impl Type { diff --git a/dust-lang/src/abstract_tree/type_alias.rs b/dust-lang/src/abstract_tree/type_alias.rs index 3bd3a99..9107390 100644 --- a/dust-lang/src/abstract_tree/type_alias.rs +++ b/dust-lang/src/abstract_tree/type_alias.rs @@ -1,8 +1,12 @@ use serde::{Deserialize, Serialize}; -use crate::{context::Context, error::RuntimeError, identifier::Identifier}; +use crate::{ + context::Context, + error::{RuntimeError, ValidationError}, + identifier::Identifier, +}; -use super::{Evaluation, Run, TypeConstructor, WithPosition}; +use super::{AbstractNode, DefineTypes, Evaluation, Type, TypeConstructor, WithPosition}; #[derive(Clone, Debug, Eq, PartialEq, PartialOrd, Ord, Serialize, Deserialize)] pub struct TypeAlias { @@ -19,16 +23,26 @@ impl TypeAlias { } } -impl Run for TypeAlias { - fn run( +impl AbstractNode for TypeAlias { + fn evaluate( self, context: &mut Context, - _manage_memory: bool, + manage_memory: bool, ) -> Result, RuntimeError> { + Ok(None) + } + + fn expected_type(&self, context: &mut Context) -> Result, ValidationError> { + Ok(None) + } +} + +impl DefineTypes for TypeAlias { + fn define_types(&self, context: &Context) -> Result<(), ValidationError> { let r#type = self.constructor.construct(&context)?; context.set_type(self.identifier.node, r#type)?; - Ok(None) + Ok(()) } } diff --git a/dust-lang/src/abstract_tree/type_constructor.rs b/dust-lang/src/abstract_tree/type_constructor.rs index ac7c544..400b70f 100644 --- a/dust-lang/src/abstract_tree/type_constructor.rs +++ b/dust-lang/src/abstract_tree/type_constructor.rs @@ -52,14 +52,14 @@ impl TypeConstructor { } } - pub fn construct(self, context: &Context) -> Result { + pub fn construct(&self, context: &Context) -> Result { let r#type = match self { TypeConstructor::Invokation(TypeInvokationConstructor { identifier, .. }) => { let invoked_type = if let Some(r#type) = context.get_type(&identifier.node)? { r#type } else { return Err(ValidationError::VariableNotFound { - identifier: identifier.node, + identifier: identifier.node.clone(), position: identifier.position, }); }; @@ -90,7 +90,7 @@ impl TypeConstructor { name, type_parameters, variants, - } = enum_type_constructor.node; + } = &enum_type_constructor.node; let mut type_variants = Vec::with_capacity(variants.len()); for (variant_name, constructors) in variants { @@ -103,19 +103,19 @@ impl TypeConstructor { types.push(r#type); } - type_variants.push((variant_name.node, Some(types))); + type_variants.push((variant_name.node.clone(), Some(types))); } else { - type_variants.push((variant_name.node, None)) + type_variants.push((variant_name.node.clone(), None)) } } Type::Enum { - name: name.node, - type_parameters: type_parameters.map(|identifiers| { + name: name.node.clone(), + type_parameters: type_parameters.as_ref().map(|identifiers| { identifiers .into_iter() .map(|identifier| Type::Generic { - identifier: identifier.node, + identifier: identifier.node.clone(), concrete_type: None, }) .collect() @@ -128,12 +128,12 @@ impl TypeConstructor { type_parameters: declared_type_parameters, value_parameters: declared_value_parameters, return_type, - } = function_type_constructor.node; + } = &function_type_constructor.node; - let type_parameters = declared_type_parameters.map(|identifiers| { + let type_parameters = declared_type_parameters.as_ref().map(|identifiers| { identifiers .into_iter() - .map(|identifier| identifier.node) + .map(|identifier| identifier.node.clone()) .collect() }); let mut value_parameters = Vec::with_capacity(declared_value_parameters.len()); @@ -153,11 +153,11 @@ impl TypeConstructor { } } TypeConstructor::List(constructor) => { - let ListTypeConstructor { length, item_type } = constructor.node; + let ListTypeConstructor { length, item_type } = &constructor.node; let constructed_type = item_type.construct(context)?; Type::List { - length, + length: *length, item_type: Box::new(constructed_type), } } diff --git a/dust-lang/src/abstract_tree/value_node.rs b/dust-lang/src/abstract_tree/value_node.rs index 1730b80..9efe521 100644 --- a/dust-lang/src/abstract_tree/value_node.rs +++ b/dust-lang/src/abstract_tree/value_node.rs @@ -10,8 +10,7 @@ use crate::{ }; use super::{ - Block, Evaluate, Evaluation, ExpectedType, Expression, Type, TypeConstructor, Validate, - WithPosition, + AbstractNode, Block, Evaluation, Expression, Type, TypeConstructor, Validate, WithPosition, }; #[derive(Clone, Debug, PartialEq, Serialize, Deserialize)] @@ -165,12 +164,12 @@ impl Validate for ValueNode { } } -impl Evaluate for ValueNode { +impl AbstractNode for ValueNode { fn evaluate( self, context: &mut Context, _manage_memory: bool, - ) -> Result { + ) -> Result, RuntimeError> { let value = match self { ValueNode::Boolean(boolean) => Value::boolean(boolean), ValueNode::EnumInstance { @@ -297,7 +296,92 @@ impl Evaluate for ValueNode { } }; - Ok(Evaluation::Return(value)) + Ok(Some(Evaluation::Return(value))) + } + + fn expected_type(&self, context: &mut Context) -> Result, ValidationError> { + let r#type = match self { + ValueNode::Boolean(_) => Type::Boolean, + ValueNode::EnumInstance { type_name, .. } => { + if let Some(r#type) = context.get_type(&type_name.node)? { + r#type + } else { + return Err(ValidationError::EnumDefinitionNotFound { + identifier: type_name.node.clone(), + position: Some(type_name.position), + }); + } + } + ValueNode::Float(_) => Type::Float, + ValueNode::Integer(_) => Type::Integer, + ValueNode::List(items) => { + let item_type = items.first().unwrap().expected_type(context)?; + + Type::List { + length: items.len(), + item_type: Box::new(item_type), + } + } + ValueNode::Map(_) => Type::Map, + ValueNode::Range(_) => Type::Range, + ValueNode::String(_) => Type::String, + ValueNode::Function { + type_parameters, + value_parameters, + return_type, + .. + } => { + let mut value_parameter_types = Vec::with_capacity(value_parameters.len()); + + for (_, type_constructor) in value_parameters { + let r#type = type_constructor.clone().construct(&context)?; + + value_parameter_types.push(r#type); + } + + let type_parameters = type_parameters.clone().map(|parameters| { + parameters + .iter() + .map(|identifier| identifier.clone()) + .collect() + }); + let return_type = return_type.clone().construct(&context)?; + + Type::Function { + type_parameters, + value_parameters: value_parameter_types, + return_type: Box::new(return_type), + } + } + ValueNode::Structure { + name, + fields: expressions, + } => { + let mut types = Vec::with_capacity(expressions.len()); + + for (identifier, expression) in expressions { + let r#type = expression.expected_type(context)?; + + types.push(( + identifier.clone(), + WithPosition { + node: r#type, + position: expression.position(), + }, + )); + } + + Type::Structure { + name: name.node.clone(), + fields: types + .into_iter() + .map(|(identifier, r#type)| (identifier.node, r#type.node)) + .collect(), + } + } + }; + + Ok(Some(r#type)) } } @@ -420,90 +504,3 @@ impl Ord for ValueNode { } } } - -impl ExpectedType for ValueNode { - fn expected_type(&self, context: &mut Context) -> Result { - let r#type = match self { - ValueNode::Boolean(_) => Type::Boolean, - ValueNode::EnumInstance { type_name, .. } => { - if let Some(r#type) = context.get_type(&type_name.node)? { - r#type - } else { - return Err(ValidationError::EnumDefinitionNotFound { - identifier: type_name.node.clone(), - position: Some(type_name.position), - }); - } - } - ValueNode::Float(_) => Type::Float, - ValueNode::Integer(_) => Type::Integer, - ValueNode::List(items) => { - let item_type = items.first().unwrap().expected_type(context)?; - - Type::List { - length: items.len(), - item_type: Box::new(item_type), - } - } - ValueNode::Map(_) => Type::Map, - ValueNode::Range(_) => Type::Range, - ValueNode::String(_) => Type::String, - ValueNode::Function { - type_parameters, - value_parameters, - return_type, - .. - } => { - let mut value_parameter_types = Vec::with_capacity(value_parameters.len()); - - for (_, type_constructor) in value_parameters { - let r#type = type_constructor.clone().construct(&context)?; - - value_parameter_types.push(r#type); - } - - let type_parameters = type_parameters.clone().map(|parameters| { - parameters - .iter() - .map(|identifier| identifier.clone()) - .collect() - }); - let return_type = return_type.clone().construct(&context)?; - - Type::Function { - type_parameters, - value_parameters: value_parameter_types, - return_type: Box::new(return_type), - } - } - ValueNode::Structure { - name, - fields: expressions, - } => { - let mut types = Vec::with_capacity(expressions.len()); - - for (identifier, expression) in expressions { - let r#type = expression.expected_type(context)?; - - types.push(( - identifier.clone(), - WithPosition { - node: r#type, - position: expression.position(), - }, - )); - } - - Type::Structure { - name: name.node.clone(), - fields: types - .into_iter() - .map(|(identifier, r#type)| (identifier.node, r#type.node)) - .collect(), - } - } - }; - - Ok(r#type) - } -} diff --git a/dust-lang/src/abstract_tree/while.rs b/dust-lang/src/abstract_tree/while.rs index 769176e..ddbf0b5 100644 --- a/dust-lang/src/abstract_tree/while.rs +++ b/dust-lang/src/abstract_tree/while.rs @@ -7,7 +7,7 @@ use crate::{ Value, }; -use super::{Evaluate, Evaluation, Expression, Run, Statement, Validate}; +use super::{AbstractNode, Evaluation, Expression, Statement, Type, Validate}; #[derive(Clone, Debug, Eq, PartialEq, PartialOrd, Ord, Serialize, Deserialize)] pub struct While { @@ -40,8 +40,8 @@ impl Validate for While { } } -impl Run for While { - fn run( +impl AbstractNode for While { + fn evaluate( self, _context: &mut Context, _manage_memory: bool, @@ -74,4 +74,8 @@ impl Run for While { Ok(None) } + + fn expected_type(&self, _context: &mut Context) -> Result, ValidationError> { + self.statements.last().unwrap().expected_type(_context) + } } diff --git a/dust-lang/src/error.rs b/dust-lang/src/error.rs index 0465ccf..db695ef 100644 --- a/dust-lang/src/error.rs +++ b/dust-lang/src/error.rs @@ -114,6 +114,7 @@ pub enum ValidationError { index_type: Type, index_position: SourcePosition, }, + CannotIndexWithVoid(SourcePosition), ExpectedString { actual: Type, position: SourcePosition, diff --git a/dust-lang/src/value.rs b/dust-lang/src/value.rs index 6e5a4cf..798c03e 100644 --- a/dust-lang/src/value.rs +++ b/dust-lang/src/value.rs @@ -14,7 +14,7 @@ use serde::{ }; use crate::{ - abstract_tree::{Block, Evaluation, Run, Type, WithPosition}, + abstract_tree::{Block, Evaluation, Type, WithPosition}, context::Context, error::{RuntimeError, ValidationError}, identifier::Identifier,