diff --git a/dust-lang/src/analyzer.rs b/dust-lang/src/analyzer.rs index f7f3cf1..bc46a36 100644 --- a/dust-lang/src/analyzer.rs +++ b/dust-lang/src/analyzer.rs @@ -86,8 +86,6 @@ impl<'a> Analyzer<'a> { Statement::Let(let_statement) => match &let_statement.inner { LetStatement::Let { identifier, value } | LetStatement::LetMut { identifier, value } => { - self.analyze_expression(value)?; - let r#type = value.return_type(self.context); if let Some(r#type) = r#type { @@ -98,52 +96,54 @@ impl<'a> Analyzer<'a> { ); } else { return Err(AnalysisError::ExpectedValueFromExpression { - actual: value.clone(), + expression: value.clone(), + found_type: r#type, }); } + + self.analyze_expression(value)?; } LetStatement::LetType { .. } => todo!(), LetStatement::LetMutType { .. } => todo!(), }, - Statement::StructDefinition(struct_definition) => { - let (name, struct_type) = match &struct_definition.inner { - StructDefinition::Unit { name } => ( - name, - Type::Struct(StructType::Unit { + Statement::StructDefinition(struct_definition) => match &struct_definition.inner { + StructDefinition::Unit { name } => self.context.set_constructor_type( + name.inner.clone(), + StructType::Unit { + name: name.inner.clone(), + }, + name.position, + ), + StructDefinition::Tuple { name, items } => { + let fields = items.iter().map(|item| item.inner.clone()).collect(); + + self.context.set_constructor_type( + name.inner.clone(), + StructType::Tuple { name: name.inner.clone(), - }), - ), - StructDefinition::Tuple { name, items } => { - let fields = items.iter().map(|item| item.inner.clone()).collect(); + fields, + }, + name.position, + ); + } + StructDefinition::Fields { name, fields } => { + let fields = fields + .iter() + .map(|(identifier, r#type)| { + (identifier.inner.clone(), r#type.inner.clone()) + }) + .collect(); - ( - name, - Type::Struct(StructType::Tuple { - name: name.inner.clone(), - fields, - }), - ) - } - StructDefinition::Fields { name, fields } => { - let fields = fields - .iter() - .map(|(identifier, r#type)| { - (identifier.inner.clone(), r#type.inner.clone()) - }) - .collect(); - - ( - name, - Type::Struct(StructType::Fields { - name: name.inner.clone(), - fields, - }), - ) - } - }; - - todo!("Set constructor") - } + self.context.set_constructor_type( + name.inner.clone(), + StructType::Fields { + name: name.inner.clone(), + fields, + }, + name.position, + ); + } + }, } Ok(()) @@ -240,18 +240,20 @@ impl<'a> Analyzer<'a> { if expected_type.is_none() { return Err(AnalysisError::ExpectedValueFromExpression { - actual: assignee.clone(), + expression: assignee.clone(), + found_type: expected_type, }); } if actual_type.is_none() { return Err(AnalysisError::ExpectedValueFromExpression { - actual: modifier.clone(), + expression: modifier.clone(), + found_type: actual_type, }); } if let (Some(expected_type), Some(actual_type)) = (expected_type, actual_type) { - expected_type.check(&actual_type).map_err(|type_conflct| { + expected_type.check(&actual_type).map_err(|_| { AnalysisError::TypeConflict { actual_expression: modifier.clone(), actual_type, @@ -288,14 +290,16 @@ impl<'a> Analyzer<'a> { }, Expression::Struct(struct_expression) => match struct_expression.inner.as_ref() { StructExpression::Unit { name } => { - todo!("Update constructor position"); + self.context + .update_last_position(&name.inner, name.position); } StructExpression::Fields { name, fields } => { - todo!("Update constructor position"); + self.context + .update_last_position(&name.inner, name.position); - // for (_, expression) in fields { - // self.analyze_expression(expression)?; - // } + for (_, expression) in fields { + self.analyze_expression(expression)?; + } } }, Expression::TupleAccess(tuple_access) => { @@ -381,7 +385,8 @@ pub enum AnalysisError { actual: Statement, }, ExpectedValueFromExpression { - actual: Expression, + expression: Expression, + found_type: Option, }, ExpectedValueArgumentCount { expected: usize, @@ -426,7 +431,7 @@ impl AnalysisError { AnalysisError::ExpectedIntegerOrRange { actual } => actual.position(), AnalysisError::ExpectedList { actual } => actual.position(), AnalysisError::ExpectedMap { actual } => actual.position(), - AnalysisError::ExpectedValueFromExpression { actual } => actual.position(), + AnalysisError::ExpectedValueFromExpression { expression, .. } => expression.position(), AnalysisError::ExpectedValueFromStatement { actual } => actual.position(), AnalysisError::ExpectedValueArgumentCount { position, .. } => *position, AnalysisError::IndexOutOfBounds { index, .. } => index.position(), @@ -461,11 +466,14 @@ impl Display for AnalysisError { } AnalysisError::ExpectedList { actual } => write!(f, "Expected list, found {}", actual), AnalysisError::ExpectedMap { actual } => write!(f, "Expected map, found {}", actual), - AnalysisError::ExpectedValueFromExpression { actual, .. } => { + AnalysisError::ExpectedValueFromExpression { + expression, + found_type, + } => { write!( f, - "Expected expression to produce a value, found {}", - actual + "Expected {} to produce a value, found {:?}", + expression, found_type ) } AnalysisError::ExpectedValueFromStatement { actual, .. } => { diff --git a/dust-lang/src/ast/expression.rs b/dust-lang/src/ast/expression.rs index 1c3cf7a..f73a0a1 100644 --- a/dust-lang/src/ast/expression.rs +++ b/dust-lang/src/ast/expression.rs @@ -297,7 +297,7 @@ impl Expression { } } Expression::Grouped(expression) => expression.inner.return_type(context), - Expression::Identifier(identifier) => context.get_variable_type(&identifier.inner), + Expression::Identifier(identifier) => context.get_type(&identifier.inner), Expression::If(if_expression) => { return match if_expression.inner.as_ref() { IfExpression::If { .. } => None, diff --git a/dust-lang/src/constructor.rs b/dust-lang/src/constructor.rs new file mode 100644 index 0000000..f2320a7 --- /dev/null +++ b/dust-lang/src/constructor.rs @@ -0,0 +1,51 @@ +use std::collections::HashMap; + +use serde::{Deserialize, Serialize}; + +use crate::{Identifier, Struct, Value}; + +#[derive(Clone, Debug, Eq, PartialEq, Serialize, Deserialize)] +pub enum Constructor { + Unit(UnitConstructor), + Tuple(TupleConstructor), + Fields(FieldsConstructor), +} + +#[derive(Clone, Debug, Eq, PartialEq, Serialize, Deserialize)] +pub struct UnitConstructor { + pub name: Identifier, +} + +impl UnitConstructor { + pub fn construct(self) -> Value { + Value::Struct(Struct::Unit { name: self.name }) + } +} + +#[derive(Clone, Debug, Eq, PartialEq, Serialize, Deserialize)] +pub struct TupleConstructor { + pub name: Identifier, +} + +impl TupleConstructor { + pub fn construct(self, fields: Vec) -> Value { + Value::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::Struct(Struct::Fields { + name: self.name, + fields, + }) + } +} diff --git a/dust-lang/src/context.rs b/dust-lang/src/context.rs index d7d4478..eefbdee 100644 --- a/dust-lang/src/context.rs +++ b/dust-lang/src/context.rs @@ -4,9 +4,9 @@ use std::{ sync::{Arc, PoisonError as StdPoisonError, RwLock, RwLockWriteGuard}, }; -use crate::{ast::Span, Identifier, Type, Value}; +use crate::{ast::Span, Constructor, Identifier, StructType, Type, Value}; -pub type Variables = HashMap; +pub type Variables = HashMap; /// Garbage-collecting context for variables. #[derive(Debug, Clone)] @@ -39,21 +39,24 @@ impl Context { } /// Returns the full VariableData and Span if the context contains the given identifier. - pub fn get(&self, identifier: &Identifier) -> Option<(VariableData, Span)> { + pub fn get(&self, identifier: &Identifier) -> Option<(ContextData, Span)> { self.variables.read().unwrap().get(identifier).cloned() } /// Returns the type of the variable with the given identifier. - pub fn get_variable_type(&self, identifier: &Identifier) -> Option { + pub fn get_type(&self, identifier: &Identifier) -> Option { match self.variables.read().unwrap().get(identifier) { - Some((VariableData::Type(r#type), _)) => Some(r#type.clone()), - Some((VariableData::Value(value), _)) => Some(value.r#type()), + Some((ContextData::VariableType(r#type), _)) => Some(r#type.clone()), + Some((ContextData::VariableValue(value), _)) => Some(value.r#type()), + Some((ContextData::ConstructorType(struct_type), _)) => { + Some(Type::Struct(struct_type.clone())) + } _ => None, } } /// Returns the VariableData of the variable with the given identifier. - pub fn get_variable_data(&self, identifier: &Identifier) -> Option { + pub fn get_data(&self, identifier: &Identifier) -> Option { match self.variables.read().unwrap().get(identifier) { Some((variable_data, _)) => Some(variable_data.clone()), _ => None, @@ -63,7 +66,15 @@ impl Context { /// Returns the value of the variable with the given identifier. pub fn get_variable_value(&self, identifier: &Identifier) -> Option { match self.variables.read().unwrap().get(identifier) { - Some((VariableData::Value(value), _)) => Some(value.clone()), + Some((ContextData::VariableValue(value), _)) => Some(value.clone()), + _ => None, + } + } + + /// Returns the constructor associated with the given identifier. + pub fn get_constructor(&self, identifier: &Identifier) -> Option { + match self.variables.read().unwrap().get(identifier) { + Some((ContextData::Constructor(constructor), _)) => Some(constructor.clone()), _ => None, } } @@ -75,7 +86,7 @@ impl Context { self.variables .write() .unwrap() - .insert(identifier, (VariableData::Type(r#type), position)); + .insert(identifier, (ContextData::VariableType(r#type), position)); } /// Sets a variable to a value. @@ -89,7 +100,44 @@ impl Context { .map(|(_, last_position)| *last_position) .unwrap_or_default(); - variables.insert(identifier, (VariableData::Value(value), last_position)); + variables.insert( + identifier, + (ContextData::VariableValue(value), last_position), + ); + } + + /// Associates a constructor with an identifier. + pub fn set_constructor(&self, identifier: Identifier, constructor: Constructor) { + log::trace!("Setting {identifier} to constructor {constructor:?}"); + + let mut variables = self.variables.write().unwrap(); + + let last_position = variables + .get(&identifier) + .map(|(_, last_position)| *last_position) + .unwrap_or_default(); + + variables.insert( + identifier, + (ContextData::Constructor(constructor), last_position), + ); + } + + /// Associates a constructor type with an identifier. + pub fn set_constructor_type( + &self, + identifier: Identifier, + struct_type: StructType, + position: Span, + ) { + log::trace!("Setting {identifier} to constructor of type {struct_type:?}"); + + let mut variables = self.variables.write().unwrap(); + + variables.insert( + identifier, + (ContextData::ConstructorType(struct_type), position), + ); } /// Collects garbage up to the given position, removing all variables with lesser positions. @@ -149,9 +197,11 @@ impl Default for Context { } #[derive(Debug, Clone)] -pub enum VariableData { - Value(Value), - Type(Type), +pub enum ContextData { + Constructor(Constructor), + ConstructorType(StructType), + VariableValue(Value), + VariableType(Type), } pub type ContextPoisonError<'err> = StdPoisonError>; diff --git a/dust-lang/src/lib.rs b/dust-lang/src/lib.rs index 1147691..837d1bd 100644 --- a/dust-lang/src/lib.rs +++ b/dust-lang/src/lib.rs @@ -18,6 +18,7 @@ pub mod analyzer; pub mod ast; pub mod built_in_function; +pub mod constructor; pub mod context; pub mod dust_error; pub mod identifier; @@ -31,7 +32,8 @@ pub mod vm; pub use analyzer::{analyze, AnalysisError, Analyzer}; pub use ast::{AbstractSyntaxTree, Expression, Statement}; pub use built_in_function::{BuiltInFunction, BuiltInFunctionError}; -pub use context::{Context, VariableData}; +pub use constructor::Constructor; +pub use context::{Context, ContextData}; pub use dust_error::DustError; pub use identifier::Identifier; pub use lexer::{lex, LexError, Lexer}; diff --git a/dust-lang/src/type.rs b/dust-lang/src/type.rs index 27f0236..7822d45 100644 --- a/dust-lang/src/type.rs +++ b/dust-lang/src/type.rs @@ -13,11 +13,15 @@ use std::{ cmp::Ordering, collections::HashMap, fmt::{self, Display, Formatter}, + rc::Weak, }; use serde::{Deserialize, Serialize}; -use crate::{Enum, Identifier, Struct, Value}; +use crate::{ + constructor::{FieldsConstructor, TupleConstructor, UnitConstructor}, + Constructor, Enum, Identifier, Struct, Value, +}; /// Description of a kind of value. /// @@ -59,12 +63,14 @@ pub enum Type { impl Type { /// Returns a concrete type, either the type itself or the concrete type of a generic type. pub fn concrete_type(&self) -> &Type { - match self { - Type::Generic { - concrete_type: Some(concrete_type), - .. - } => concrete_type.concrete_type(), - _ => self, + if let Type::Generic { + concrete_type: Some(concrete_type), + .. + } = self + { + concrete_type.concrete_type() + } else { + self } } @@ -435,20 +441,16 @@ impl StructType { } } - pub fn constructor(&self) -> Option { - let constructor = match self { - StructType::Unit { name } => Constructor::Unit { name: name.clone() }, - StructType::Tuple { name, fields } => Constructor::Tuple(TupleConstructor { - name: name.clone(), - tuple_arguments: Vec::with_capacity(fields.len()), - }), - StructType::Fields { name, fields } => Constructor::Fields { - name: name.clone(), - field_arguments: HashMap::with_capacity(fields.len()), - }, - }; - - Some(constructor) + 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() }) + } + } } } @@ -547,116 +549,12 @@ impl Ord for StructType { } } -#[derive(Clone, Debug, Eq, PartialEq, Serialize, Deserialize)] -pub enum Constructor { - Unit { - name: Identifier, - }, - Tuple(TupleConstructor), - Fields { - name: Identifier, - field_arguments: HashMap, - }, - Enum { - name: Identifier, - r#type: EnumType, - variant_constructor: Box, - }, -} - -impl Constructor { - pub fn construct(self) -> Value { - match self { - Constructor::Unit { name } => Value::Struct(Struct::Unit { name }), - Constructor::Tuple(tuple_constructor) => tuple_constructor.construct(), - Constructor::Fields { - name, - field_arguments, - } => Value::Struct(Struct::Fields { - name, - fields: field_arguments, - }), - Constructor::Enum { - name, - r#type, - variant_constructor, - } => Value::Enum(Enum { - name, - r#type, - variant_data: Self::make_struct(*variant_constructor), - }), - } - } - - fn make_struct(this: Self) -> Struct { - match this { - Constructor::Unit { name } => Struct::Unit { name }, - Constructor::Tuple(TupleConstructor { - name, - tuple_arguments, - }) => Struct::Tuple { - name, - fields: tuple_arguments, - }, - Constructor::Fields { - name, - field_arguments, - } => Struct::Fields { - name, - fields: field_arguments, - }, - Constructor::Enum { - variant_constructor, - .. - } => Self::make_struct(*variant_constructor), - } - } -} - -#[derive(Clone, Debug, Eq, PartialEq, Serialize, Deserialize)] -pub struct TupleConstructor { - pub name: Identifier, - pub tuple_arguments: Vec, -} - -impl TupleConstructor { - pub fn push_argument(&mut self, value: Value) { - self.tuple_arguments.push(value); - } - - pub fn construct(self) -> Value { - Value::Struct(Struct::Tuple { - name: self.name, - fields: self.tuple_arguments, - }) - } -} - #[derive(Clone, Debug, Eq, PartialEq, PartialOrd, Ord, Serialize, Deserialize)] pub struct EnumType { pub name: Identifier, pub variants: Vec, } -impl EnumType { - pub fn constructor(&self) -> Option { - let get_variant_constructor = self - .variants - .iter() - .find_map(|struct_type| struct_type.constructor()); - - if let Some(variant_constructor) = get_variant_constructor { - Some(Constructor::Enum { - name: self.name.clone(), - r#type: self.clone(), - variant_constructor: Box::new(variant_constructor), - }) - } else { - None - } - } -} - impl Display for EnumType { fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result { let EnumType { name, variants } = self; diff --git a/dust-lang/src/vm.rs b/dust-lang/src/vm.rs index 04a8468..46837f7 100644 --- a/dust-lang/src/vm.rs +++ b/dust-lang/src/vm.rs @@ -21,9 +21,8 @@ use crate::{ OperatorExpression, PrimitiveValueExpression, RangeExpression, RawStringExpression, Span, Statement, StructDefinition, StructExpression, }, - parse, Analyzer, BuiltInFunctionError, Constructor, Context, DustError, Enum, EnumType, - Expression, Identifier, ParseError, Struct, StructType, TupleConstructor, Type, Value, - ValueError, + parse, Analyzer, BuiltInFunctionError, Constructor, Context, ContextData, DustError, Enum, + EnumType, Expression, Identifier, ParseError, Struct, StructType, Type, Value, ValueError, }; /// Run the source code and return the result. @@ -156,8 +155,9 @@ impl Vm { ) } }; + let constructor = struct_type.constructor(); - todo!("Set constructor"); + self.context.set_constructor(name, constructor); Ok(None) } @@ -222,16 +222,20 @@ impl Vm { self.run_expression(*expression.inner, collect_garbage) } Expression::Identifier(identifier) => { - let get_value = self.context.get_variable_value(&identifier.inner); + let get_data = self.context.get_data(&identifier.inner); - if let Some(value) = get_value { - Ok(Evaluation::Return(Some(value))) - } else { - Err(RuntimeError::UndefinedValue { - identifier: identifier.inner, - position: identifier.position, - }) + if let Some(ContextData::VariableValue(value)) = get_data { + return Ok(Evaluation::Return(Some(value.clone()))); } + + if let Some(ContextData::Constructor(constructor)) = get_data { + return Ok(Evaluation::Constructor(constructor)); + } + + Err(RuntimeError::UndefinedValue { + identifier: identifier.inner, + position, + }) } Expression::If(if_expression) => self.run_if(*if_expression.inner, collect_garbage), Expression::List(list_expression) => { @@ -269,7 +273,7 @@ impl Vm { match struct_expression { StructExpression::Unit { name } => { let position = name.position; - let r#type = self.context.get_variable_type(&name.inner).ok_or_else(|| { + let r#type = self.context.get_type(&name.inner).ok_or_else(|| { RuntimeError::UndefinedType { identifier: name.inner.clone(), position, @@ -293,7 +297,7 @@ impl Vm { fields: expressions, } => { let position = name.position; - let r#type = self.context.get_variable_type(&name.inner).ok_or_else(|| { + let r#type = self.context.get_type(&name.inner).ok_or_else(|| { RuntimeError::UndefinedType { identifier: name.inner.clone(), position, @@ -679,78 +683,61 @@ impl Vm { let invoker_position = invoker.position(); let run_invoker = self.run_expression(invoker, collect_garbage)?; - if let Evaluation::Constructor(Type::Struct(StructType::Tuple { name, fields })) = - &run_invoker - { - let struct_type = fields - .iter() - .find(|r#type| { - if let Type::Struct(struct_type) = r#type { - struct_type.name() == name - } else { - false - } - }) - .ok_or(RuntimeError::EnumVariantNotFound { - identifier: name.clone(), - position: invoker_position, - })?; + match run_invoker { + Evaluation::Constructor(constructor) => { + if let Constructor::Tuple(tuple_constructor) = constructor { + let mut fields = Vec::new(); - if let Type::Struct(StructType::Tuple { name, fields }) = struct_type { - let mut values = Vec::with_capacity(arguments.len()); + 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 }); + } + } + + let tuple = tuple_constructor.construct(fields); + + return Ok(Evaluation::Return(Some(tuple))); + } + } + Evaluation::Return(Some(value)) => { + let function = if let Value::Function(function) = value { + function + } else { + return Err(RuntimeError::ExpectedFunction { + actual: value.to_owned(), + position: invoker_position, + }); + }; + + let mut value_arguments = Vec::new(); for argument in arguments { let position = argument.position(); - let value = self - .run_expression(argument, collect_garbage)? - .expect_value(position)?; - values.push(value); + if let Some(value) = self.run_expression(argument, collect_garbage)?.value() { + value_arguments.push(value); + } else { + return Err(RuntimeError::ExpectedValue { position }); + } } - let r#struct = Struct::Tuple { - name: name.clone(), - fields: values, - }; + let context = Context::new(); - return Ok(Evaluation::Return(Some(Value::Struct(r#struct)))); + return function + .call(None, Some(value_arguments), &context) + .map(Evaluation::Return); } + _ => (), } - let invoker_value = if let Some(value) = run_invoker.value() { - value - } else { - return Err(RuntimeError::ExpectedValue { - position: invoker_position, - }); - }; - - let function = if let Value::Function(function) = invoker_value { - function - } else { - return Err(RuntimeError::ExpectedFunction { - actual: invoker_value, - position: invoker_position, - }); - }; - - let mut value_arguments = Vec::new(); - - for argument in arguments { - let position = argument.position(); - - if let Some(value) = self.run_expression(argument, collect_garbage)?.value() { - value_arguments.push(value); - } else { - return Err(RuntimeError::ExpectedValue { position }); - } - } - - let context = Context::new(); - - function - .call(None, Some(value_arguments), &context) - .map(Evaluation::Return) + Err(RuntimeError::ExpectedValue { + position: invoker_position, + }) } fn run_field_access( @@ -923,7 +910,7 @@ impl Vm { enum Evaluation { Break, - Constructor(Type), + Constructor(Constructor), Return(Option), }