diff --git a/dust-lang/src/abstract_tree/as.rs b/dust-lang/src/abstract_tree/as.rs index 6858112..0d499da 100644 --- a/dust-lang/src/abstract_tree/as.rs +++ b/dust-lang/src/abstract_tree/as.rs @@ -27,7 +27,7 @@ impl As { } impl AbstractNode for As { - fn define_types(&self, context: &Context) -> Result<(), ValidationError> { + fn define_types(&self, _: &Context) -> Result<(), ValidationError> { Ok(()) } diff --git a/dust-lang/src/abstract_tree/assignment.rs b/dust-lang/src/abstract_tree/assignment.rs index f3182b7..5b4bed4 100644 --- a/dust-lang/src/abstract_tree/assignment.rs +++ b/dust-lang/src/abstract_tree/assignment.rs @@ -8,8 +8,8 @@ use crate::{ }; use super::{ - type_constructor::{RawTypeConstructor, TypeInvokationConstructor}, - AbstractNode, Evaluation, Expression, Statement, Type, TypeConstructor, WithPosition, + type_constructor::TypeInvokationConstructor, AbstractNode, Evaluation, Expression, Statement, + Type, TypeConstructor, WithPosition, }; #[derive(Clone, Debug, Eq, PartialEq, PartialOrd, Ord, Serialize, Deserialize)] @@ -74,14 +74,6 @@ impl AbstractNode for Assignment { } fn validate(&self, context: &Context, manage_memory: bool) -> Result<(), ValidationError> { - if let Some(TypeConstructor::Raw(WithPosition { - node: RawTypeConstructor::None, - position, - })) = &self.constructor - { - return Err(ValidationError::CannotAssignToNone(position.clone())); - } - let relevant_statement = self.statement.last_evaluated_statement(); let statement_type = if let Some(r#type) = relevant_statement.expected_type(context)? { r#type @@ -144,7 +136,7 @@ impl AbstractNode for Assignment { .. }) = function_type { - if let Type::Generic { identifier, .. } = *return_type { + if let Some(Type::Generic { identifier, .. }) = return_type.map(|r#box| *r#box) { let returned_parameter = type_parameters .into_iter() .find(|parameter| parameter == &identifier); diff --git a/dust-lang/src/abstract_tree/function_call.rs b/dust-lang/src/abstract_tree/function_call.rs index d7811f8..638dd0c 100644 --- a/dust-lang/src/abstract_tree/function_call.rs +++ b/dust-lang/src/abstract_tree/function_call.rs @@ -163,10 +163,12 @@ impl AbstractNode for FunctionCall { .. } = function_type { - if let Type::Generic { + let return_type = return_type.map(|r#box| *r#box); + + if let Some(Type::Generic { identifier: return_identifier, .. - } = *return_type.clone() + }) = &return_type { if let (Some(type_arguments), Some(type_parameters)) = (&self.type_arguments, &type_parameters) @@ -174,7 +176,7 @@ impl AbstractNode for FunctionCall { for (constructor, identifier) in type_arguments.into_iter().zip(type_parameters.into_iter()) { - if identifier == &return_identifier { + if identifier == return_identifier { let concrete_type = constructor.clone().construct(&context)?; return Ok(Some(Type::Generic { @@ -190,7 +192,7 @@ impl AbstractNode for FunctionCall { .into_iter() .zip(type_parameters.into_iter()) { - if identifier == return_identifier { + if &identifier == return_identifier { let concrete_type = if let Some(r#type) = expression.expected_type(context)? { r#type @@ -209,7 +211,7 @@ impl AbstractNode for FunctionCall { } } - Ok(Some(*return_type)) + Ok(return_type) } else { Err(ValidationError::ExpectedFunction { actual: function_type, diff --git a/dust-lang/src/abstract_tree/list_index.rs b/dust-lang/src/abstract_tree/list_index.rs index 084f7f5..407bb55 100644 --- a/dust-lang/src/abstract_tree/list_index.rs +++ b/dust-lang/src/abstract_tree/list_index.rs @@ -32,19 +32,25 @@ impl AbstractNode for ListIndex { self.collection.validate(context, _manage_memory)?; self.index.validate(context, _manage_memory)?; - 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())); - } + let collection_type = if let Some(r#type) = self.index.expected_type(context)? { + r#type + } else { + return Err(ValidationError::ExpectedExpression( + self.collection.position(), + )); + }; + let index_type = if let Some(r#type) = self.index.expected_type(context)? { + r#type + } else { + return Err(ValidationError::ExpectedExpression(self.index.position())); + }; match collection_type { Type::List { length: _, item_type: _, } => { - if index_type == Some(Type::Integer) { + if index_type == Type::Integer { Ok(()) } else { Err(ValidationError::CannotIndexWith { @@ -69,8 +75,8 @@ impl AbstractNode for ListIndex { _clear_variables: bool, ) -> 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 { + let left_evaluation = self.collection.evaluate(context, _clear_variables)?; + let left_value = if let Some(Evaluation::Return(value)) = left_evaluation { value } else { return Err(RuntimeError::ValidationFailure( @@ -78,8 +84,8 @@ impl AbstractNode for ListIndex { )); }; let right_position = self.index.position(); - let right_action = self.index.evaluate(context, _clear_variables)?; - let right_value = if let Evaluation::Return(value) = right_action { + let right_evaluation = self.index.evaluate(context, _clear_variables)?; + let right_value = if let Some(Evaluation::Return(value)) = right_evaluation { value } else { return Err(RuntimeError::ValidationFailure( @@ -93,7 +99,7 @@ impl AbstractNode for ListIndex { if let Some(item) = found_item { Ok(Some(Evaluation::Return(item.clone()))) } else { - Ok(Evaluation::Void) + Ok(None) } } else { Err(RuntimeError::ValidationFailure( @@ -108,7 +114,13 @@ impl AbstractNode for ListIndex { } fn expected_type(&self, _context: &Context) -> Result, ValidationError> { - let left_type = self.collection.expected_type(_context)?; + let left_type = if let Some(r#type) = self.collection.expected_type(_context)? { + r#type + } else { + return Err(ValidationError::ExpectedExpression( + self.collection.position(), + )); + }; if let ( Expression::Value(WithPosition { @@ -124,7 +136,7 @@ impl AbstractNode for ListIndex { let expression = if let Some(expression) = expression_list.get(*index as usize) { expression } else { - return Ok(Type::Void); + return Ok(None); }; expression.expected_type(_context) diff --git a/dust-lang/src/abstract_tree/logic.rs b/dust-lang/src/abstract_tree/logic.rs index 04d4a83..325484d 100644 --- a/dust-lang/src/abstract_tree/logic.rs +++ b/dust-lang/src/abstract_tree/logic.rs @@ -72,8 +72,16 @@ impl AbstractNode for Logic { left.validate(context, _manage_memory)?; right.validate(context, _manage_memory)?; - let left_type = left.expected_type(context)?; - let right_type = right.expected_type(context)?; + let left_type = if let Some(r#type) = left.expected_type(context)? { + r#type + } else { + return Err(ValidationError::ExpectedExpression(left.position())); + }; + let right_type = if let Some(r#type) = right.expected_type(context)? { + r#type + } else { + return Err(ValidationError::ExpectedExpression(right.position())); + }; left_type .check(&right_type) @@ -89,8 +97,16 @@ impl AbstractNode for Logic { left.validate(context, _manage_memory)?; right.validate(context, _manage_memory)?; - let left_type = left.expected_type(context)?; - let right_type = right.expected_type(context)?; + let left_type = if let Some(r#type) = left.expected_type(context)? { + r#type + } else { + return Err(ValidationError::ExpectedExpression(left.position())); + }; + let right_type = if let Some(r#type) = right.expected_type(context)? { + r#type + } else { + return Err(ValidationError::ExpectedExpression(right.position())); + }; if let Type::Boolean = left_type { } else { @@ -113,7 +129,11 @@ impl AbstractNode for Logic { Logic::Not(expression) => { expression.validate(context, _manage_memory)?; - let expression_type = expression.expected_type(context)?; + let expression_type = if let Some(r#type) = expression.expected_type(context)? { + r#type + } else { + return Err(ValidationError::ExpectedExpression(expression.position())); + }; if let Type::Boolean = expression_type { Ok(()) @@ -134,8 +154,8 @@ impl AbstractNode for Logic { ) -> Result, RuntimeError> { let run_and_expect_value = |expression: Expression| -> Result { let expression_position = expression.position(); - let action = expression.evaluate(&mut context.clone(), _manage_memory)?; - let value = if let Evaluation::Return(value) = action { + let evaluation = expression.evaluate(&mut context.clone(), _manage_memory)?; + let value = if let Some(Evaluation::Return(value)) = evaluation { value } else { return Err(RuntimeError::ValidationFailure( @@ -148,8 +168,8 @@ impl AbstractNode for Logic { let run_and_expect_boolean = |expression: Expression| -> Result { let expression_position = expression.position(); - let action = expression.evaluate(&mut context.clone(), _manage_memory)?; - let value = if let Evaluation::Return(value) = action { + let evaluation = expression.evaluate(&mut context.clone(), _manage_memory)?; + let value = if let Some(Evaluation::Return(value)) = evaluation { value } else { return Err(RuntimeError::ValidationFailure( @@ -251,7 +271,7 @@ mod tests { Expression::Value(ValueNode::Integer(42).with_position((0, 0))) ) .evaluate(&mut Context::new(None), true), - Ok(Evaluation::Return(Value::boolean(true))) + Ok(Some(Evaluation::Return(Value::boolean(true)))) ) } @@ -263,7 +283,7 @@ mod tests { Expression::Value(ValueNode::Integer(43).with_position((0, 0))) ) .evaluate(&mut Context::new(None), true), - Ok(Evaluation::Return(Value::boolean(true))) + Ok(Some(Evaluation::Return(Value::boolean(true)))) ) } @@ -275,7 +295,7 @@ mod tests { Expression::Value(ValueNode::Integer(42).with_position((0, 0))) ) .evaluate(&mut Context::new(None), true), - Ok(Evaluation::Return(Value::boolean(true))) + Ok(Some(Evaluation::Return(Value::boolean(true)))) ) } @@ -287,7 +307,7 @@ mod tests { Expression::Value(ValueNode::Integer(43).with_position((0, 0))) ) .evaluate(&mut Context::new(None), true), - Ok(Evaluation::Return(Value::boolean(true))) + Ok(Some(Evaluation::Return(Value::boolean(true)))) ) } @@ -299,7 +319,7 @@ mod tests { Expression::Value(ValueNode::Integer(41).with_position((0, 0))) ) .evaluate(&mut Context::new(None), true), - Ok(Evaluation::Return(Value::boolean(true))) + Ok(Some(Evaluation::Return(Value::boolean(true)))) ); assert_eq!( @@ -308,7 +328,7 @@ mod tests { Expression::Value(ValueNode::Integer(42).with_position((0, 0))), ) .evaluate(&mut Context::new(None), true), - Ok(Evaluation::Return(Value::boolean(true))) + Ok(Some(Evaluation::Return(Value::boolean(true)))) ); } @@ -320,7 +340,7 @@ mod tests { Expression::Value(ValueNode::Integer(42).with_position((0, 0))), ) .evaluate(&mut Context::new(None), true), - Ok(Evaluation::Return(Value::boolean(true))) + Ok(Some(Evaluation::Return(Value::boolean(true)))) ); assert_eq!( @@ -329,7 +349,7 @@ mod tests { Expression::Value(ValueNode::Integer(42).with_position((0, 0))), ) .evaluate(&mut Context::new(None), true), - Ok(Evaluation::Return(Value::boolean(true))) + Ok(Some(Evaluation::Return(Value::boolean(true)))) ); } @@ -341,7 +361,7 @@ mod tests { Expression::Value(ValueNode::Boolean(true).with_position((0, 0))), ) .evaluate(&mut Context::new(None), true), - Ok(Evaluation::Return(Value::boolean(true))) + Ok(Some(Evaluation::Return(Value::boolean(true)))) ) } @@ -353,7 +373,7 @@ mod tests { Expression::Value(ValueNode::Boolean(false).with_position((0, 0))), ) .evaluate(&mut Context::new(None), true), - Ok(Evaluation::Return(Value::boolean(true))) + Ok(Some(Evaluation::Return(Value::boolean(true)))) ) } @@ -364,7 +384,7 @@ mod tests { ValueNode::Boolean(false).with_position((0, 0)) )) .evaluate(&mut Context::new(None), true), - Ok(Evaluation::Return(Value::boolean(true))) + Ok(Some(Evaluation::Return(Value::boolean(true)))) ) } } diff --git a/dust-lang/src/abstract_tree/loop.rs b/dust-lang/src/abstract_tree/loop.rs index 9d33909..fc00b5d 100644 --- a/dust-lang/src/abstract_tree/loop.rs +++ b/dust-lang/src/abstract_tree/loop.rs @@ -45,7 +45,7 @@ impl AbstractNode for Loop { ) -> Result, RuntimeError> { loop { for statement in &self.statements { - let run = statement.clone().run(_context, false)?; + let run = statement.clone().evaluate(_context, false)?; if let Some(Evaluation::Break) = run { return Ok(run); diff --git a/dust-lang/src/abstract_tree/map_index.rs b/dust-lang/src/abstract_tree/map_index.rs index eb67db6..a04b050 100644 --- a/dust-lang/src/abstract_tree/map_index.rs +++ b/dust-lang/src/abstract_tree/map_index.rs @@ -39,8 +39,8 @@ impl AbstractNode for MapIndex { _manage_memory: bool, ) -> Result, RuntimeError> { let collection_position = self.collection.position(); - let action = self.collection.evaluate(context, _manage_memory)?; - let collection = if let Evaluation::Return(value) = action { + let evaluation = self.collection.evaluate(context, _manage_memory)?; + let collection = if let Some(Evaluation::Return(value)) = evaluation { value } else { return Err(RuntimeError::ValidationFailure( @@ -51,11 +51,12 @@ impl AbstractNode for MapIndex { if let (ValueInner::Map(map), Expression::Identifier(index)) = (collection.inner().as_ref(), self.index) { - let evaluation = map + let eval_option = map .get(&index.node) - .map(|value| Some(Evaluation::Return(value.clone()))); + .cloned() + .map(|value| Evaluation::Return(value)); - Ok(evaluation) + Ok(eval_option) } else { Err(RuntimeError::ValidationFailure( ValidationError::CannotIndex { @@ -111,7 +112,7 @@ impl AbstractNode for MapIndex { } } - return Ok(Type::Void); + return Ok(None); } if let ( @@ -131,12 +132,20 @@ impl AbstractNode for MapIndex { }) { type_result } else { - Ok(Type::Void) + Ok(None) }; } + let collection_type = if let Some(r#type) = self.collection.expected_type(context)? { + r#type + } else { + return Err(ValidationError::ExpectedExpression( + self.collection.position(), + )); + }; + Err(ValidationError::CannotIndex { - r#type: self.collection.expected_type(context)?, + r#type: collection_type, position: self.collection.position(), }) } diff --git a/dust-lang/src/abstract_tree/math.rs b/dust-lang/src/abstract_tree/math.rs index 9b828a0..8e6baeb 100644 --- a/dust-lang/src/abstract_tree/math.rs +++ b/dust-lang/src/abstract_tree/math.rs @@ -47,25 +47,30 @@ impl AbstractNode for Math { fn validate(&self, context: &Context, _manage_memory: bool) -> Result<(), ValidationError> { match self { Math::Add(left, right) => { - let left_position = left.position(); - let left_type = left.expected_type(context)?; + let left_type = if let Some(r#type) = left.expected_type(context)? { + r#type + } else { + return Err(ValidationError::ExpectedExpression(left.position())); + }; + let right_type = if let Some(r#type) = right.expected_type(context)? { + r#type + } else { + return Err(ValidationError::ExpectedExpression(right.position())); + }; if let Type::Integer | Type::Float | Type::String = left_type { - let right_position = right.position(); - let right_type = right.expected_type(context)?; - if let Type::Integer | Type::Float | Type::String = right_type { Ok(()) } else { Err(ValidationError::ExpectedIntegerFloatOrString { actual: right_type, - position: right_position, + position: right.position(), }) } } else { Err(ValidationError::ExpectedIntegerFloatOrString { actual: left_type, - position: left_position, + position: left.position(), }) } } @@ -73,20 +78,25 @@ impl AbstractNode for Math { | Math::Multiply(left, right) | Math::Divide(left, right) | Math::Modulo(left, right) => { - let left_position = left.position(); - let left_type = left.expected_type(context)?; + let left_type = if let Some(r#type) = left.expected_type(context)? { + r#type + } else { + return Err(ValidationError::ExpectedExpression(left.position())); + }; + let right_type = if let Some(r#type) = right.expected_type(context)? { + r#type + } else { + return Err(ValidationError::ExpectedExpression(right.position())); + }; if let Type::Integer | Type::Float = left_type { - let right_position = right.position(); - let right_type = right.expected_type(context)?; - if let Type::Integer | Type::Float = right_type { Ok(()) } else { - Err(ValidationError::ExpectedIntegerOrFloat(right_position)) + Err(ValidationError::ExpectedIntegerOrFloat(right.position())) } } else { - Err(ValidationError::ExpectedIntegerOrFloat(left_position)) + Err(ValidationError::ExpectedIntegerOrFloat(left.position())) } } } @@ -99,8 +109,8 @@ impl AbstractNode for Math { ) -> Result, RuntimeError> { let run_and_expect_value = |position: SourcePosition, expression: Expression| -> Result { - let action = expression.evaluate(&mut _context.clone(), _clear_variables)?; - let value = if let Evaluation::Return(value) = action { + let evaluation = expression.evaluate(&mut _context.clone(), _clear_variables)?; + let value = if let Some(Evaluation::Return(value)) = evaluation { value } else { return Err(RuntimeError::ValidationFailure( @@ -326,8 +336,16 @@ impl AbstractNode for Math { | Math::Multiply(left, right) | Math::Divide(left, right) | Math::Modulo(left, right) => { - let left_type = left.expected_type(_context)?; - let right_type = right.expected_type(_context)?; + let left_type = if let Some(r#type) = left.expected_type(_context)? { + r#type + } else { + return Err(ValidationError::ExpectedExpression(left.position())); + }; + let right_type = if let Some(r#type) = right.expected_type(_context)? { + r#type + } else { + return Err(ValidationError::ExpectedExpression(right.position())); + }; if let Type::Float = left_type { return Ok(Some(Type::Float)); @@ -337,7 +355,7 @@ impl AbstractNode for Math { return Ok(Some(Type::Float)); } - Ok(left_type) + Ok(Some(left_type)) } } } diff --git a/dust-lang/src/abstract_tree/mod.rs b/dust-lang/src/abstract_tree/mod.rs index 4cf1454..852a535 100644 --- a/dust-lang/src/abstract_tree/mod.rs +++ b/dust-lang/src/abstract_tree/mod.rs @@ -147,12 +147,12 @@ impl AbstractTree { for statement in self.0 { let position = statement.position(); - let run = statement.run(context, manage_memory); + let run = statement.evaluate(context, manage_memory); match run { Ok(evaluation) => match evaluation { Some(Evaluation::Return(value)) => previous_value = Some(value), - Some(Evaluation::Void) | None => previous_value = None, + None => previous_value = None, _ => {} }, Err(runtime_error) => { diff --git a/dust-lang/src/abstract_tree/statement.rs b/dust-lang/src/abstract_tree/statement.rs index 2e1daae..f76372b 100644 --- a/dust-lang/src/abstract_tree/statement.rs +++ b/dust-lang/src/abstract_tree/statement.rs @@ -59,7 +59,7 @@ impl AbstractNode for Statement { 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::Break(_) => Ok(()), Statement::Loop(r#loop) => r#loop.node.define_types(_context), Statement::StructureDefinition(struct_definition) => { struct_definition.node.define_types(_context) diff --git a/dust-lang/src/abstract_tree/structure_definition.rs b/dust-lang/src/abstract_tree/structure_definition.rs index 81606c2..809fa8e 100644 --- a/dust-lang/src/abstract_tree/structure_definition.rs +++ b/dust-lang/src/abstract_tree/structure_definition.rs @@ -24,10 +24,10 @@ impl AbstractNode for StructureDefinition { fn define_types(&self, context: &Context) -> Result<(), ValidationError> { let mut fields = Vec::with_capacity(self.fields.len()); - for (identifier, constructor) in self.fields { + for (identifier, constructor) in &self.fields { let r#type = constructor.construct(&context)?; - fields.push((identifier, r#type)); + fields.push((identifier.clone(), r#type)); } let struct_type = Type::Structure { @@ -35,12 +35,12 @@ impl AbstractNode for StructureDefinition { fields, }; - context.set_type(self.name, struct_type)?; + context.set_type(self.name.clone(), struct_type)?; - Ok(None) + Ok(()) } - fn validate(&self, context: &Context, manage_memory: bool) -> Result<(), ValidationError> { + fn validate(&self, _: &Context, _: bool) -> Result<(), ValidationError> { Ok(()) } @@ -67,7 +67,7 @@ impl AbstractNode for StructureDefinition { Ok(None) } - fn expected_type(&self, context: &Context) -> Result, ValidationError> { + fn expected_type(&self, _: &Context) -> Result, ValidationError> { Ok(None) } } diff --git a/dust-lang/src/abstract_tree/type.rs b/dust-lang/src/abstract_tree/type.rs index 2eb874a..efa9283 100644 --- a/dust-lang/src/abstract_tree/type.rs +++ b/dust-lang/src/abstract_tree/type.rs @@ -18,7 +18,7 @@ pub enum Type { Function { type_parameters: Option>, value_parameters: Vec, - return_type: Box, + return_type: Option>, }, Generic { identifier: Identifier, @@ -48,7 +48,6 @@ impl Type { | (Type::Float, Type::Float) | (Type::Integer, Type::Integer) | (Type::Map, Type::Map) - | (Type::Void, Type::Void) | (Type::Range, Type::Range) | (Type::String, Type::String) => return Ok(()), ( @@ -239,7 +238,6 @@ impl Display for Type { Type::List { length, item_type } => write!(f, "[{length}; {}]", item_type), Type::ListOf(item_type) => write!(f, "list({})", item_type), Type::Map => write!(f, "map"), - Type::Void => write!(f, "none"), Type::Range => write!(f, "range"), Type::String => write!(f, "str"), Type::Function { @@ -261,7 +259,13 @@ impl Display for Type { write!(f, "{type}")?; } - write!(f, ") : {}", return_type) + write!(f, ")")?; + + if let Some(r#type) = return_type { + write!(f, " -> {}", r#type) + } else { + Ok(()) + } } Type::Structure { name, .. } => write!(f, "{name}"), } @@ -295,7 +299,6 @@ mod tests { ); assert_eq!(Type::Map.check(&Type::Map), Ok(())); - assert_eq!(Type::Void.check(&Type::Void), Ok(())); assert_eq!(Type::Range.check(&Type::Range), Ok(())); assert_eq!(Type::String.check(&Type::String), Ok(())); } @@ -321,7 +324,6 @@ mod tests { ); let types = [ - Type::Any, Type::Boolean, Type::Float, Type::Integer, @@ -331,23 +333,24 @@ mod tests { }, Type::ListOf(Box::new(Type::Boolean)), Type::Map, - Type::Void, Type::Range, Type::String, ]; - for (left, right) in types.iter().zip(types.iter()) { - if left == right { - continue; - } + for left in types.clone() { + for right in types.clone() { + if left == right { + continue; + } - assert_eq!( - left.check(right), - Err(TypeConflict { - actual: right.clone(), - expected: left.clone() - }) - ); + assert_eq!( + left.check(&right), + Err(TypeConflict { + actual: right.clone(), + expected: left.clone() + }) + ); + } } } diff --git a/dust-lang/src/abstract_tree/type_alias.rs b/dust-lang/src/abstract_tree/type_alias.rs index 40dbe8d..5823442 100644 --- a/dust-lang/src/abstract_tree/type_alias.rs +++ b/dust-lang/src/abstract_tree/type_alias.rs @@ -27,24 +27,20 @@ impl AbstractNode 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)?; + context.set_type(self.identifier.node.clone(), r#type)?; Ok(()) } - fn validate(&self, context: &Context, manage_memory: bool) -> Result<(), ValidationError> { + fn validate(&self, _: &Context, _: bool) -> Result<(), ValidationError> { Ok(()) } - fn evaluate( - self, - context: &Context, - manage_memory: bool, - ) -> Result, RuntimeError> { + fn evaluate(self, _: &Context, _: bool) -> Result, RuntimeError> { Ok(None) } - fn expected_type(&self, context: &Context) -> Result, ValidationError> { + fn expected_type(&self, _: &Context) -> Result, ValidationError> { Ok(None) } } diff --git a/dust-lang/src/abstract_tree/type_constructor.rs b/dust-lang/src/abstract_tree/type_constructor.rs index 400b70f..5d656c0 100644 --- a/dust-lang/src/abstract_tree/type_constructor.rs +++ b/dust-lang/src/abstract_tree/type_constructor.rs @@ -23,7 +23,6 @@ pub enum RawTypeConstructor { Float, Integer, Map, - None, Range, String, } @@ -144,7 +143,11 @@ impl TypeConstructor { value_parameters.push(r#type); } - let return_type = Box::new(return_type.construct(&context)?); + let return_type = if let Some(constructor) = return_type { + Some(Box::new(constructor.construct(context)?)) + } else { + None + }; Type::Function { type_parameters, @@ -172,7 +175,6 @@ impl TypeConstructor { RawTypeConstructor::Float => Type::Float, RawTypeConstructor::Integer => Type::Integer, RawTypeConstructor::Map => Type::Map, - RawTypeConstructor::None => Type::Void, RawTypeConstructor::Range => Type::Range, RawTypeConstructor::String => Type::String, }, @@ -199,7 +201,7 @@ pub struct EnumTypeConstructor { pub struct FunctionTypeConstructor { pub type_parameters: Option>>, pub value_parameters: Vec, - pub return_type: Box, + pub return_type: Option>, } #[derive(Clone, Debug, Eq, PartialEq, PartialOrd, Ord, Serialize, Deserialize)] diff --git a/dust-lang/src/abstract_tree/value_node.rs b/dust-lang/src/abstract_tree/value_node.rs index acd3f81..6b8be9e 100644 --- a/dust-lang/src/abstract_tree/value_node.rs +++ b/dust-lang/src/abstract_tree/value_node.rs @@ -34,7 +34,7 @@ pub enum ValueNode { Function { type_parameters: Option>, value_parameters: Vec<(Identifier, TypeConstructor)>, - return_type: TypeConstructor, + return_type: Option, body: WithPosition, }, } @@ -64,12 +64,7 @@ impl AbstractNode for ValueNode { expression.define_types(_context)?; } } - ValueNode::Function { - type_parameters, - value_parameters, - return_type, - body, - } => { + ValueNode::Function { body, .. } => { body.node.define_types(_context)?; } _ => {} @@ -156,20 +151,23 @@ impl AbstractNode for ValueNode { body.node.validate(&mut function_context, _manage_memory)?; + let (expected_return_type, expected_position) = if let Some(constructor) = return_type { + (constructor.construct(context)?, constructor.position()) + } else { + return Err(ValidationError::ExpectedExpression(body.position)); + }; let actual_return_type = if let Some(r#type) = body.node.expected_type(context)? { r#type } else { return Err(ValidationError::ExpectedExpression(body.position)); }; - return_type - .clone() - .construct(&function_context)? + expected_return_type .check(&actual_return_type) .map_err(|conflict| ValidationError::TypeCheck { conflict, actual_position: body.position, - expected_position: Some(return_type.position()), + expected_position: Some(expected_position), })?; return Ok(()); @@ -316,7 +314,11 @@ impl AbstractNode for ValueNode { } } - let return_type = return_type.construct(&function_context)?; + let return_type = if let Some(constructor) = return_type { + Some(constructor.construct(&function_context)?) + } else { + None + }; Value::function(type_parameters, value_parameters, return_type, body.node) } @@ -398,12 +400,16 @@ impl AbstractNode for ValueNode { .map(|identifier| identifier.clone()) .collect() }); - let return_type = return_type.clone().construct(&context)?; + let return_type = if let Some(constructor) = return_type { + Some(Box::new(constructor.construct(context)?)) + } else { + None + }; Type::Function { type_parameters, value_parameters: value_parameter_types, - return_type: Box::new(return_type), + return_type, } } ValueNode::Structure { diff --git a/dust-lang/src/abstract_tree/while.rs b/dust-lang/src/abstract_tree/while.rs index cc50120..6867f61 100644 --- a/dust-lang/src/abstract_tree/while.rs +++ b/dust-lang/src/abstract_tree/while.rs @@ -52,12 +52,12 @@ impl AbstractNode for While { ) -> Result, RuntimeError> { let get_boolean = || -> Result { let expression_position = self.expression.position(); - let action = self + let evaluation = self .expression .clone() .evaluate(&mut _context.clone(), false)?; - if let Evaluation::Return(value) = action { + if let Some(Evaluation::Return(value)) = evaluation { Ok(value) } else { Err(RuntimeError::ValidationFailure( @@ -68,7 +68,7 @@ impl AbstractNode for While { while let ValueInner::Boolean(true) = get_boolean()?.inner().as_ref() { for statement in &self.statements { - let evaluation = statement.clone().run(&mut _context.clone(), false)?; + let evaluation = statement.clone().evaluate(&mut _context.clone(), false)?; if let Some(Evaluation::Break) = evaluation { return Ok(evaluation); diff --git a/dust-lang/src/lib.rs b/dust-lang/src/lib.rs index 2bfd02a..fbd6cf4 100644 --- a/dust-lang/src/lib.rs +++ b/dust-lang/src/lib.rs @@ -455,7 +455,6 @@ impl InterpreterError { } } ValidationError::EnumVariantNotFound { .. } => todo!(), - ValidationError::CannotIndexWithVoid(_) => todo!(), } } diff --git a/dust-lang/src/parser/mod.rs b/dust-lang/src/parser/mod.rs index 2068bab..8da9197 100644 --- a/dust-lang/src/parser/mod.rs +++ b/dust-lang/src/parser/mod.rs @@ -84,7 +84,6 @@ pub fn parser<'src>( just(Token::Keyword(Keyword::Float)).to(RawTypeConstructor::Float), just(Token::Keyword(Keyword::Int)).to(RawTypeConstructor::Integer), just(Token::Keyword(Keyword::Map)).to(RawTypeConstructor::Map), - just(Token::Keyword(Keyword::None)).to(RawTypeConstructor::None), just(Token::Keyword(Keyword::Range)).to(RawTypeConstructor::Range), just(Token::Keyword(Keyword::Str)).to(RawTypeConstructor::String), )) @@ -115,15 +114,18 @@ pub fn parser<'src>( just(Token::Symbol(Symbol::ParenClose)), ), ) - .then_ignore(just(Token::Symbol(Symbol::SkinnyArrow))) - .then(type_constructor.clone()) + .then( + just(Token::Symbol(Symbol::SkinnyArrow)) + .ignore_then(type_constructor.clone()) + .or_not(), + ) .map_with( |((type_parameters, value_parameters), return_type), state| { TypeConstructor::Function( FunctionTypeConstructor { type_parameters, value_parameters, - return_type: Box::new(return_type), + return_type: return_type.map(|r#type| Box::new(r#type)), } .with_position(state.span()), ) @@ -282,8 +284,11 @@ pub fn parser<'src>( just(Token::Symbol(Symbol::ParenClose)), ), ) - .then_ignore(just(Token::Symbol(Symbol::SkinnyArrow))) - .then(type_constructor.clone()) + .then( + just(Token::Symbol(Symbol::SkinnyArrow)) + .ignore_then(type_constructor.clone()) + .or_not(), + ) .then(block.clone()) .map_with( |(((type_parameters, value_parameters), return_type), body), state| { diff --git a/dust-lang/src/parser/tests.rs b/dust-lang/src/parser/tests.rs index da40637..383b4c8 100644 --- a/dust-lang/src/parser/tests.rs +++ b/dust-lang/src/parser/tests.rs @@ -438,12 +438,12 @@ fn function_type() { value_parameters: vec![TypeConstructor::Raw( RawTypeConstructor::Integer.with_position((19, 22)) )], - return_type: Box::new(TypeConstructor::Invokation( + return_type: Some(Box::new(TypeConstructor::Invokation( TypeInvokationConstructor { identifier: Identifier::new("T").with_position((27, 28)), type_arguments: None } - )) + ))) } .with_position((11, 28)) ) @@ -505,9 +505,9 @@ fn function() { ValueNode::Function { type_parameters: None, value_parameters: vec![], - return_type: TypeConstructor::Raw( + return_type: Some(TypeConstructor::Raw( RawTypeConstructor::Integer.with_position((9, 12)) - ), + )), body: Block::new(vec![Statement::Expression(Expression::Value( ValueNode::Integer(0).with_position((15, 16)) ))]) @@ -526,9 +526,9 @@ fn function() { Identifier::new("x"), TypeConstructor::Raw(RawTypeConstructor::Integer.with_position((7, 10))) )], - return_type: TypeConstructor::Raw( + return_type: Some(TypeConstructor::Raw( RawTypeConstructor::Integer.with_position((15, 18)) - ), + )), body: Block::new(vec![Statement::Expression(Expression::Identifier( Identifier::new("x").with_position((21, 22)) ))]) @@ -562,10 +562,10 @@ fn function_with_type_arguments() { }) ) ], - return_type: TypeConstructor::Invokation(TypeInvokationConstructor { + return_type: Some(TypeConstructor::Invokation(TypeInvokationConstructor { identifier: Identifier::new("T").with_position((26, 27)), type_arguments: None, - }), + })), body: Block::new(vec![Statement::Expression(Expression::Identifier( Identifier::new("x").with_position((30, 31)) ))]) diff --git a/dust-lang/src/value.rs b/dust-lang/src/value.rs index 4c22596..78e78bc 100644 --- a/dust-lang/src/value.rs +++ b/dust-lang/src/value.rs @@ -71,7 +71,7 @@ impl Value { pub fn function( type_parameters: Option>, value_parameters: Vec<(Identifier, Type)>, - return_type: Type, + return_type: Option, body: Block, ) -> Self { Value(Arc::new(ValueInner::Function(Function { @@ -188,7 +188,13 @@ impl Display for Value { write!(f, "{identifier}: {}", r#type)?; } - write!(f, "): {} {:?}", return_type, body) + write!(f, ")")?; + + if let Some(return_type) = return_type { + write!(f, "-> {return_type}")? + } + + write!(f, " {{ {body:?} }}") } ValueInner::Structure { name, fields } => { write!(f, "{}\n{{", name.node)?; @@ -590,11 +596,12 @@ impl ValueInner { .map(|(_, r#type)| r#type) .cloned() .collect(); + let return_type = function.return_type.clone().map(|r#type| Box::new(r#type)); Type::Function { type_parameters: function.type_parameters().clone(), value_parameters, - return_type: Box::new(function.return_type.clone()), + return_type, } } ValueInner::Structure { name, .. } => { @@ -704,7 +711,7 @@ impl Ord for ValueInner { pub struct Function { type_parameters: Option>, value_parameters: Vec<(Identifier, Type)>, - return_type: Type, + return_type: Option, body: Block, } diff --git a/dust-lang/tests/variables.rs b/dust-lang/tests/variables.rs index 9a6fa3c..f252b70 100644 --- a/dust-lang/tests/variables.rs +++ b/dust-lang/tests/variables.rs @@ -48,7 +48,7 @@ fn function_variable() { Ok(Some(Value::function( None, vec![(Identifier::new("x"), Type::Integer)], - Type::Integer, + Some(Type::Integer), Block::new(vec![Statement::Expression(Expression::Identifier( Identifier::new("x").with_position((30, 31)) ))]) diff --git a/std/io.ds b/std/io.ds index 02a5df2..4ee1913 100644 --- a/std/io.ds +++ b/std/io.ds @@ -3,7 +3,7 @@ io = { READ_LINE } - write_line = fn (output: any) -> none { + write_line = fn (output: any) { WRITE_LINE output } }