diff --git a/dust-lang/src/analyzer.rs b/dust-lang/src/analyzer.rs index 45b0933..e19d641 100644 --- a/dust-lang/src/analyzer.rs +++ b/dust-lang/src/analyzer.rs @@ -82,9 +82,11 @@ impl<'a> Analyzer<'a> { fn analyze_statement(&mut self, statement: &Statement) { match statement { - Statement::Expression(expression) => self.analyze_expression(expression), + Statement::Expression(expression) => { + self.analyze_expression(expression, statement.position()) + } Statement::ExpressionNullified(expression_node) => { - self.analyze_expression(&expression_node.inner); + self.analyze_expression(&expression_node.inner, statement.position()); } Statement::Let(let_statement) => match &let_statement.inner { LetStatement::Let { identifier, value } @@ -118,7 +120,7 @@ impl<'a> Analyzer<'a> { }); } - self.analyze_expression(value); + self.analyze_expression(value, statement.position()); } LetStatement::LetType { .. } => todo!(), LetStatement::LetMutType { .. } => todo!(), @@ -130,7 +132,7 @@ impl<'a> Analyzer<'a> { StructType::Unit { name: name.inner.clone(), }, - name.position, + statement.position(), ), StructDefinition::Tuple { name, items } => { let fields = items.iter().map(|item| item.inner.clone()).collect(); @@ -141,7 +143,7 @@ impl<'a> Analyzer<'a> { name: name.inner.clone(), fields, }, - name.position, + statement.position(), ) } StructDefinition::Fields { name, fields } => { @@ -158,7 +160,7 @@ impl<'a> Analyzer<'a> { name: name.inner.clone(), fields, }, - name.position, + statement.position(), ) } }; @@ -173,69 +175,96 @@ impl<'a> Analyzer<'a> { } } - fn analyze_expression(&mut self, expression: &Expression) { + fn analyze_expression(&mut self, expression: &Expression, statement_position: Span) { match expression { Expression::Block(block_expression) => self.analyze_block(&block_expression.inner), Expression::Break(break_node) => { if let Some(expression) = &break_node.inner { - self.analyze_expression(expression); + self.analyze_expression(expression, statement_position); } } Expression::Call(call_expression) => { let CallExpression { invoker, arguments } = call_expression.inner.as_ref(); - self.analyze_expression(invoker); + self.analyze_expression(invoker, statement_position); for argument in arguments { - self.analyze_expression(argument); + self.analyze_expression(argument, statement_position); } } Expression::FieldAccess(field_access_expression) => { - let FieldAccessExpression { container, .. } = + let FieldAccessExpression { container, field } = field_access_expression.inner.as_ref(); - self.analyze_expression(container); + let container_type = match container.return_type(&self.context) { + Ok(Some(r#type)) => r#type, + Ok(None) => { + self.errors + .push(AnalysisError::ExpectedValueFromExpression { + expression: container.clone(), + }); + + return; + } + Err(ast_error) => { + self.errors.push(AnalysisError::AstError(ast_error)); + + return; + } + }; + + if !container_type.has_field(&field.inner) { + self.errors.push(AnalysisError::UndefinedFieldIdentifier { + identifier: field.clone(), + container: container.clone(), + }); + } + + self.analyze_expression(container, statement_position); } Expression::Grouped(expression) => { - self.analyze_expression(expression.inner.as_ref()); + self.analyze_expression(expression.inner.as_ref(), statement_position); } Expression::Identifier(identifier) => { - let found = self + let find_identifier = self .context - .update_last_position(&identifier.inner, identifier.position) - .map_err(|error| { - self.errors.push(AnalysisError::ContextError { - error, - position: identifier.position, - }) - }); + .update_last_position(&identifier.inner, statement_position); - if let Ok(false) = found { + if let Ok(false) = find_identifier { self.errors.push(AnalysisError::UndefinedVariable { identifier: identifier.clone(), }); } + + if let Err(context_error) = find_identifier { + self.errors.push(AnalysisError::ContextError { + error: context_error, + position: identifier.position, + }); + } + } + Expression::If(if_expression) => { + self.analyze_if(&if_expression.inner, statement_position) } - Expression::If(if_expression) => self.analyze_if(&if_expression.inner), Expression::List(list_expression) => match list_expression.inner.as_ref() { ListExpression::AutoFill { repeat_operand, length_operand, } => { - self.analyze_expression(repeat_operand); - self.analyze_expression(length_operand); + self.analyze_expression(repeat_operand, statement_position); + self.analyze_expression(length_operand, statement_position); } ListExpression::Ordered(expressions) => { for expression in expressions { - self.analyze_expression(expression); + self.analyze_expression(expression, statement_position); } } }, Expression::ListIndex(list_index_expression) => { let ListIndexExpression { list, index } = list_index_expression.inner.as_ref(); - self.analyze_expression(list); - self.analyze_expression(index); + self.analyze_expression(list, statement_position); + self.analyze_expression(index, statement_position); let list_type = match list.return_type(&self.context) { Ok(Some(r#type)) => r#type, @@ -253,7 +282,7 @@ impl<'a> Analyzer<'a> { return; } }; - let index_type = match list.return_type(&self.context) { + let index_type = match index.return_type(&self.context) { Ok(Some(r#type)) => r#type, Ok(None) => { self.errors @@ -301,6 +330,22 @@ impl<'a> Analyzer<'a> { index_value: integer, }); } + } else if let Type::Integer + | Type::Range { + r#type: RangeableType::Integer, + } = index_type + { + } else { + self.errors.push(AnalysisError::ExpectedTypeMultiple { + expected: vec![ + Type::Integer, + Type::Range { + r#type: RangeableType::Integer, + }, + ], + actual: index_type.clone(), + actual_expression: index.clone(), + }); } } @@ -329,13 +374,13 @@ impl<'a> Analyzer<'a> { Expression::Loop(loop_expression) => match loop_expression.inner.as_ref() { LoopExpression::Infinite { block } => self.analyze_block(&block.inner), LoopExpression::While { condition, block } => { - self.analyze_expression(condition); + self.analyze_expression(condition, statement_position); self.analyze_block(&block.inner); } LoopExpression::For { iterator, block, .. } => { - self.analyze_expression(iterator); + self.analyze_expression(iterator, statement_position); self.analyze_block(&block.inner); } }, @@ -343,23 +388,23 @@ impl<'a> Analyzer<'a> { let MapExpression { pairs } = map_expression.inner.as_ref(); for (_, expression) in pairs { - self.analyze_expression(expression); + self.analyze_expression(expression, statement_position); } } Expression::Operator(operator_expression) => match operator_expression.inner.as_ref() { OperatorExpression::Assignment { assignee, value } => { - self.analyze_expression(assignee); - self.analyze_expression(value); + self.analyze_expression(assignee, statement_position); + self.analyze_expression(value, statement_position); } OperatorExpression::Comparison { left, right, .. } => { - self.analyze_expression(left); - self.analyze_expression(right); + self.analyze_expression(left, statement_position); + self.analyze_expression(right, statement_position); } OperatorExpression::CompoundAssignment { assignee, modifier, .. } => { - self.analyze_expression(assignee); - self.analyze_expression(modifier); + self.analyze_expression(assignee, statement_position); + self.analyze_expression(modifier, statement_position); let (expected_type, actual_type) = match ( assignee.return_type(&self.context), @@ -413,14 +458,14 @@ impl<'a> Analyzer<'a> { } OperatorExpression::ErrorPropagation(_) => todo!(), OperatorExpression::Negation(expression) => { - self.analyze_expression(expression); + self.analyze_expression(expression, statement_position); } OperatorExpression::Not(expression) => { - self.analyze_expression(expression); + self.analyze_expression(expression, statement_position); } OperatorExpression::Math { left, right, .. } => { - self.analyze_expression(left); - self.analyze_expression(right); + self.analyze_expression(left, statement_position); + self.analyze_expression(right, statement_position); let (left_type, right_type) = match ( left.return_type(&self.context), @@ -506,8 +551,8 @@ impl<'a> Analyzer<'a> { } } OperatorExpression::Logic { left, right, .. } => { - self.analyze_expression(left); - self.analyze_expression(right); + self.analyze_expression(left, statement_position); + self.analyze_expression(right, statement_position); let (left_type, right_type) = match ( left.return_type(&self.context), @@ -560,19 +605,19 @@ impl<'a> Analyzer<'a> { }, Expression::Range(range_expression) => match range_expression.inner.as_ref() { RangeExpression::Exclusive { start, end } => { - self.analyze_expression(start); - self.analyze_expression(end); + self.analyze_expression(start, statement_position); + self.analyze_expression(end, statement_position); } RangeExpression::Inclusive { start, end } => { - self.analyze_expression(start); - self.analyze_expression(end); + self.analyze_expression(start, statement_position); + self.analyze_expression(end, statement_position); } }, Expression::Struct(struct_expression) => match struct_expression.inner.as_ref() { StructExpression::Fields { name, fields } => { let update_position = self .context - .update_last_position(&name.inner, name.position); + .update_last_position(&name.inner, statement_position); if let Err(error) = update_position { self.errors.push(AnalysisError::ContextError { @@ -584,14 +629,14 @@ impl<'a> Analyzer<'a> { } for (_, expression) in fields { - self.analyze_expression(expression); + self.analyze_expression(expression, statement_position); } } }, Expression::TupleAccess(tuple_access) => { let TupleAccessExpression { tuple, .. } = tuple_access.inner.as_ref(); - self.analyze_expression(tuple); + self.analyze_expression(tuple, statement_position); } } } @@ -611,13 +656,13 @@ impl<'a> Analyzer<'a> { } } - fn analyze_if(&mut self, if_expression: &IfExpression) { + fn analyze_if(&mut self, if_expression: &IfExpression, statement_position: Span) { match if_expression { IfExpression::If { condition, if_block, } => { - self.analyze_expression(condition); + self.analyze_expression(condition, statement_position); self.analyze_block(&if_block.inner); } IfExpression::IfElse { @@ -625,7 +670,7 @@ impl<'a> Analyzer<'a> { if_block, r#else, } => { - self.analyze_expression(condition); + self.analyze_expression(condition, statement_position); self.analyze_block(&if_block.inner); match r#else { @@ -633,7 +678,7 @@ impl<'a> Analyzer<'a> { self.analyze_block(&block_expression.inner); } ElseExpression::If(if_expression) => { - self.analyze_if(&if_expression.inner); + self.analyze_if(&if_expression.inner, statement_position); } } } @@ -691,9 +736,9 @@ pub enum AnalysisError { actual_type: Type, expected: Type, }, - UndefinedField { - identifier: Expression, - expression: Expression, + UndefinedFieldIdentifier { + identifier: Node, + container: Expression, }, UndefinedType { identifier: Node, @@ -736,7 +781,7 @@ impl AnalysisError { AnalysisError::TypeConflict { actual_expression, .. } => actual_expression.position(), - AnalysisError::UndefinedField { identifier, .. } => identifier.position(), + AnalysisError::UndefinedFieldIdentifier { identifier, .. } => identifier.position, AnalysisError::UndefinedType { identifier } => identifier.position, AnalysisError::UndefinedVariable { identifier } => identifier.position, AnalysisError::UnexpectedIdentifier { identifier } => identifier.position, @@ -826,11 +871,15 @@ impl Display for AnalysisError { expected, actual_statement, actual_type ) } - AnalysisError::UndefinedField { + AnalysisError::UndefinedFieldIdentifier { identifier, - expression: map, + container, } => { - write!(f, "Undefined field {} in map {}", identifier, map) + write!( + f, + "Undefined field {} in container {}", + identifier, container + ) } AnalysisError::UndefinedType { identifier } => { write!(f, "Undefined type {}", identifier) @@ -850,6 +899,7 @@ impl Display for AnalysisError { #[cfg(test)] mod tests { + use crate::RangeableType; use super::*; @@ -963,43 +1013,21 @@ mod tests { } #[test] - fn nonexistant_field_identifier() { - let source = "{ x = 1 }.y"; + fn nonexistant_map_field_identifier() { + let source = "map { x = 1 }.y"; assert_eq!( analyze(source), Err(DustError::Analysis { - analysis_errors: vec![AnalysisError::UndefinedField { - identifier: Expression::identifier(Identifier::new("y"), (11, 12)), - expression: Expression::map( + analysis_errors: vec![AnalysisError::UndefinedFieldIdentifier { + container: Expression::map( [( - Node::new(Identifier::new("x"), (2, 3)), - Expression::literal(1, (6, 7)) + Node::new(Identifier::new("x"), (6, 7)), + Expression::literal(1, (10, 11)) )], - (0, 11) - ), - }], - source, - }) - ); - } - - #[test] - fn nonexistant_field_string() { - let source = "{ x = 1 }.'y'"; - - assert_eq!( - analyze(source), - Err(DustError::Analysis { - analysis_errors: vec![AnalysisError::UndefinedField { - identifier: Expression::literal("y", (11, 14)), - expression: Expression::map( - [( - Node::new(Identifier::new("x"), (2, 3)), - Expression::literal(1, (6, 7)) - )], - (0, 11) + (0, 13) ), + identifier: Node::new(Identifier::new("y"), (14, 15)), }], source, }) @@ -1030,7 +1058,7 @@ mod tests { #[test] fn malformed_field_access() { - let source = "{ x = 1 }.0"; + let source = "struct Foo { x: int } Foo { x: 1 }.0"; assert_eq!( analyze(source), @@ -1079,14 +1107,14 @@ mod tests { #[test] fn nonexistant_field() { - let source = "'hello'.foo"; + let source = "\"hello\".foo"; assert_eq!( analyze(source), Err(DustError::Analysis { - analysis_errors: vec![AnalysisError::UndefinedField { - expression: Expression::literal("hello", (0, 7)), - identifier: Expression::identifier(Identifier::new("foo"), (8, 11)), + analysis_errors: vec![AnalysisError::UndefinedFieldIdentifier { + container: Expression::literal("hello", (0, 7)), + identifier: Node::new(Identifier::new("foo"), (8, 11)), }], source, }) diff --git a/dust-lang/src/constructor.rs b/dust-lang/src/constructor.rs index 3d8d7c5..ee847b5 100644 --- a/dust-lang/src/constructor.rs +++ b/dust-lang/src/constructor.rs @@ -5,60 +5,103 @@ use std::{ use serde::{Deserialize, Serialize}; -use crate::{Identifier, Struct, Value}; +use crate::{Identifier, Struct, StructType, TypeConflict, Value}; #[derive(Clone, Debug, Eq, PartialEq, Serialize, Deserialize)] -pub enum Constructor { - Unit(UnitConstructor), - Tuple(TupleConstructor), - Fields(FieldsConstructor), +pub struct Constructor { + pub struct_type: StructType, } -impl Display for Constructor { - fn fmt(&self, f: &mut Formatter) -> fmt::Result { - match self { - Constructor::Unit(unit) => write!(f, "{}", unit.name), - Constructor::Tuple(tuple) => write!(f, "{}", tuple.name), - Constructor::Fields(fields) => write!(f, "{}", fields.name), +impl Constructor { + pub fn construct_unit(&self) -> Result { + if let StructType::Unit { name } = &self.struct_type { + Ok(Value::r#struct(Struct::Unit { name: name.clone() })) + } else { + Err(ConstructError::ExpectedUnit) + } + } + + pub fn construct_tuple(&self, fields: Vec) -> Result { + if let StructType::Tuple { + name: expected_name, + fields: expected_fields, + } = &self.struct_type + { + if fields.len() != expected_fields.len() { + return Err(ConstructError::FieldCountMismatch); + } + + for (i, value) in fields.iter().enumerate() { + let expected_type = expected_fields.get(i).unwrap(); + let actual_type = value.r#type(); + + expected_type.check(&actual_type)?; + } + + Ok(Value::r#struct(Struct::Tuple { + name: expected_name.clone(), + fields, + })) + } else { + Err(ConstructError::ExpectedTuple) + } + } + + pub fn construct_fields( + &self, + fields: HashMap, + ) -> Result { + if let StructType::Fields { + name: expected_name, + fields: expected_fields, + } = &self.struct_type + { + if fields.len() != expected_fields.len() { + return Err(ConstructError::FieldCountMismatch); + } + + for (field_name, field_value) in fields.iter() { + let expected_type = expected_fields.get(field_name).unwrap(); + let actual_type = field_value.r#type(); + + expected_type.check(&actual_type)?; + } + + Ok(Value::r#struct(Struct::Fields { + name: expected_name.clone(), + fields, + })) + } else { + Err(ConstructError::ExpectedFields) } } } #[derive(Clone, Debug, Eq, PartialEq, Serialize, Deserialize)] -pub struct UnitConstructor { - pub name: Identifier, +pub enum ConstructError { + FieldCountMismatch, + ExpectedUnit, + ExpectedTuple, + ExpectedFields, + TypeConflict(TypeConflict), } -impl UnitConstructor { - pub fn construct(self) -> Value { - Value::r#struct(Struct::Unit { name: self.name }) +impl From for ConstructError { + fn from(conflict: TypeConflict) -> Self { + Self::TypeConflict(conflict) } } -#[derive(Clone, Debug, Eq, PartialEq, Serialize, Deserialize)] -pub struct TupleConstructor { - pub name: Identifier, -} - -impl TupleConstructor { - pub fn construct(self, fields: Vec) -> Value { - Value::r#struct(Struct::Tuple { - name: self.name, - fields, - }) - } -} - -#[derive(Clone, Debug, Eq, PartialEq, Serialize, Deserialize)] -pub struct FieldsConstructor { - pub name: Identifier, -} - -impl FieldsConstructor { - pub fn construct(self, fields: HashMap) -> Value { - Value::r#struct(Struct::Fields { - name: self.name, - fields, - }) +impl Display for ConstructError { + fn fmt(&self, f: &mut Formatter) -> fmt::Result { + match self { + ConstructError::FieldCountMismatch => write!(f, "Field count mismatch"), + ConstructError::ExpectedUnit => write!(f, "Expected unit struct"), + ConstructError::ExpectedTuple => write!(f, "Expected tuple struct"), + ConstructError::ExpectedFields => write!(f, "Expected fields struct"), + ConstructError::TypeConflict(TypeConflict { expected, actual }) => { + write!(f, "Type conflict: expected {}, got {}", expected, actual) + } + } } } diff --git a/dust-lang/src/context.rs b/dust-lang/src/context.rs index 6d71a07..f549758 100644 --- a/dust-lang/src/context.rs +++ b/dust-lang/src/context.rs @@ -172,7 +172,7 @@ impl Context { identifier: Identifier, constructor: Constructor, ) -> Result<(), ContextError> { - log::trace!("Setting {identifier} to constructor {constructor}"); + log::trace!("Setting {identifier} to constructor {constructor:?}"); let mut associations = self.associations.write()?; diff --git a/dust-lang/src/parser.rs b/dust-lang/src/parser.rs index b8a11aa..8f1a054 100644 --- a/dust-lang/src/parser.rs +++ b/dust-lang/src/parser.rs @@ -204,14 +204,10 @@ impl<'src> Parser<'src> { self.next_token()?; if let Token::Semicolon = self.current_token { - break; - } else { - return Err(ParseError::ExpectedToken { - expected: TokenKind::Semicolon, - actual: self.current_token.to_owned(), - position: self.current_position, - }); + self.next_token()?; } + + break; } let type_node = self.parse_type()?; @@ -227,8 +223,6 @@ impl<'src> Parser<'src> { let position = (start_position.0, self.current_position.1); - self.next_token()?; - return if types.is_empty() { Ok(Statement::struct_definition( StructDefinition::Unit { name }, @@ -249,6 +243,8 @@ impl<'src> Parser<'src> { loop { if let Token::RightCurlyBrace = self.current_token { + self.next_token()?; + if let Token::Semicolon = self.current_token { self.next_token()?; } @@ -281,8 +277,6 @@ impl<'src> Parser<'src> { let position = (start_position.0, self.current_position.1); - self.next_token()?; - return if fields.is_empty() { Ok(Statement::struct_definition( StructDefinition::Unit { name }, diff --git a/dust-lang/src/type.rs b/dust-lang/src/type.rs index d914696..13726c3 100644 --- a/dust-lang/src/type.rs +++ b/dust-lang/src/type.rs @@ -17,10 +17,7 @@ use std::{ use serde::{Deserialize, Serialize}; -use crate::{ - constructor::{FieldsConstructor, TupleConstructor, UnitConstructor}, - Constructor, Identifier, -}; +use crate::{constructor::Constructor, Identifier}; /// Description of a kind of value. /// @@ -234,6 +231,28 @@ impl Type { expected: self.clone(), }) } + + pub fn has_field(&self, field: &Identifier) -> bool { + match field.as_str() { + "to_string" => true, + "length" => { + matches!( + self, + Type::List { .. } + | Type::ListOf { .. } + | Type::ListEmpty + | Type::Map { .. } + | Type::String { .. } + ) + } + "is_even" | "is_odd" => matches!(self, Type::Integer | Type::Float), + _ => match self { + Type::Struct(StructType::Fields { fields, .. }) => fields.contains_key(field), + Type::Map { pairs } => pairs.contains_key(field), + _ => false, + }, + } + } } impl Display for Type { @@ -445,14 +464,8 @@ impl StructType { } pub fn constructor(&self) -> Constructor { - match self { - StructType::Unit { name } => Constructor::Unit(UnitConstructor { name: name.clone() }), - StructType::Tuple { name, .. } => { - Constructor::Tuple(TupleConstructor { name: name.clone() }) - } - StructType::Fields { name, .. } => { - Constructor::Fields(FieldsConstructor { name: name.clone() }) - } + Constructor { + struct_type: self.clone(), } } } diff --git a/dust-lang/src/vm.rs b/dust-lang/src/vm.rs index a8562af..4b0a5b3 100644 --- a/dust-lang/src/vm.rs +++ b/dust-lang/src/vm.rs @@ -20,6 +20,7 @@ use crate::{ OperatorExpression, PrimitiveValueExpression, RangeExpression, Span, Statement, StructDefinition, StructExpression, }, + constructor::ConstructError, core_library, parse, Analyzer, BuiltInFunctionError, Constructor, Context, ContextData, ContextError, DustError, Expression, Function, FunctionCallError, Identifier, ParseError, StructType, Type, Value, ValueData, ValueError, @@ -313,17 +314,22 @@ impl Vm { } if let Some(ContextData::Constructor(constructor)) = get_data { - if let Constructor::Unit(unit_constructor) = constructor { - return Ok(Evaluation::Return(Some(unit_constructor.construct()))); + let construct_result = constructor.construct_unit(); + + match construct_result { + Ok(value) => Ok(Evaluation::Return(Some(value))), + Err(ConstructError::ExpectedUnit) => Ok(Evaluation::Constructor(constructor)), + Err(error) => Err(RuntimeError::ConstructError { + error, + position: identifier.position, + }), } - - return Ok(Evaluation::Constructor(constructor)); + } else { + Err(RuntimeError::UnassociatedIdentifier { + identifier: identifier.inner, + position: identifier.position, + }) } - - Err(RuntimeError::UnassociatedIdentifier { - identifier: identifier.inner, - position: identifier.position, - }) } fn run_struct( @@ -340,24 +346,22 @@ impl Vm { .map_err(|error| RuntimeError::ContextError { error, position })?; if let Some(constructor) = constructor { - if let Constructor::Fields(fields_constructor) = constructor { - let mut arguments = HashMap::with_capacity(fields.len()); + let mut arguments = HashMap::with_capacity(fields.len()); - for (identifier, expression) in fields { - let position = expression.position(); - let value = self - .run_expression(expression, collect_garbage)? - .expect_value(position)?; + for (identifier, expression) in fields { + let position = expression.position(); + let value = self + .run_expression(expression, collect_garbage)? + .expect_value(position)?; - arguments.insert(identifier.inner, value); - } - - Ok(Evaluation::Return(Some( - fields_constructor.construct(arguments), - ))) - } else { - Err(RuntimeError::ExpectedFieldsConstructor { position }) + arguments.insert(identifier.inner, value); } + + let value = constructor + .construct_fields(arguments.clone()) + .map_err(|error| RuntimeError::ConstructError { error, position })?; + + Ok(Evaluation::Return(Some(value))) } else { Err(RuntimeError::ExpectedConstructor { position }) } @@ -803,32 +807,28 @@ impl Vm { let run_invoker = self.run_expression(invoker, collect_garbage)?; match run_invoker { - Evaluation::Constructor(constructor) => match constructor { - Constructor::Unit(unit_constructor) => { - Ok(Evaluation::Return(Some(unit_constructor.construct()))) - } - Constructor::Tuple(tuple_constructor) => { - let mut fields = Vec::new(); + Evaluation::Constructor(constructor) => { + let mut fields = Vec::new(); - for argument in arguments { - let position = argument.position(); + for argument in arguments { + let position = argument.position(); - if let Some(value) = self.run_expression(argument, collect_garbage)?.value() - { - fields.push(value); - } else { - return Err(RuntimeError::ExpectedValue { position }); - } + if let Some(value) = self.run_expression(argument, collect_garbage)?.value() { + fields.push(value); + } else { + return Err(RuntimeError::ExpectedValue { position }); } - - let tuple = tuple_constructor.construct(fields); - - Ok(Evaluation::Return(Some(tuple))) } - Constructor::Fields(_) => { - todo!("Return an error") - } - }, + + let value = constructor.construct_tuple(fields).map_err(|error| { + RuntimeError::ConstructError { + error, + position: invoker_position, + } + })?; + + Ok(Evaluation::Return(Some(value))) + } Evaluation::Return(Some(value)) => { let function = match value { Value::Raw(ValueData::Function(function)) => function, @@ -1091,6 +1091,10 @@ impl Evaluation { #[derive(Clone, Debug, PartialEq)] pub enum RuntimeError { + ConstructError { + error: ConstructError, + position: Span, + }, ContextError { error: ContextError, position: Span, @@ -1113,9 +1117,6 @@ pub enum RuntimeError { left_position: Span, right_position: Span, }, - - // Anaylsis Failures - // These should be prevented by running the analyzer before the VM BuiltInFunctionError { error: BuiltInFunctionError, position: Span, @@ -1192,6 +1193,7 @@ pub enum RuntimeError { impl RuntimeError { pub fn position(&self) -> Span { match self { + Self::ConstructError { position, .. } => *position, Self::ContextError { position, .. } => *position, Self::BuiltInFunctionError { position, .. } => *position, Self::FunctionCall { position, .. } => *position, @@ -1242,6 +1244,9 @@ impl From for RuntimeError { impl Display for RuntimeError { fn fmt(&self, f: &mut Formatter) -> fmt::Result { match self { + Self::ConstructError { error, position } => { + write!(f, "Constructor error at {:?}: {}", position, error) + } Self::ContextError { error, position } => { write!(f, "Context error at {:?}: {}", position, error) }