From af20dab0d29b2dee1b8f7ef3f0adeb895e2e172f Mon Sep 17 00:00:00 2001 From: Jeff Date: Sun, 23 Jun 2024 22:39:33 -0400 Subject: [PATCH] Refactor function types --- dust-lang/src/abstract_tree/function_call.rs | 171 ++++++++---------- dust-lang/src/abstract_tree/type.rs | 10 +- .../src/abstract_tree/type_constructor.rs | 19 +- dust-lang/src/abstract_tree/value_node.rs | 47 +++-- dust-lang/src/parser/mod.rs | 47 ++++- dust-lang/src/parser/tests.rs | 52 +++--- dust-lang/src/value.rs | 32 ++-- dust-lang/tests/variables.rs | 2 +- 8 files changed, 209 insertions(+), 171 deletions(-) diff --git a/dust-lang/src/abstract_tree/function_call.rs b/dust-lang/src/abstract_tree/function_call.rs index 3d61b3c..c4c18aa 100644 --- a/dust-lang/src/abstract_tree/function_call.rs +++ b/dust-lang/src/abstract_tree/function_call.rs @@ -1,7 +1,4 @@ -use std::{ - cmp::Ordering, - sync::{Arc, Mutex}, -}; +use std::cmp::Ordering; use serde::{Deserialize, Serialize}; @@ -17,23 +14,23 @@ use super::{AbstractNode, Evaluation, Expression, Type, TypeConstructor}; pub struct FunctionCall { function_expression: Box, type_arguments: Option>, - value_arguments: Vec, + value_arguments: Option>, #[serde(skip)] - context: Arc>>, + context: Context, } impl FunctionCall { pub fn new( function_expression: Expression, type_arguments: Option>, - value_arguments: Vec, + value_arguments: Option>, ) -> Self { FunctionCall { function_expression: Box::new(function_expression), type_arguments, value_arguments, - context: Arc::new(Mutex::new(None)), + context: Context::new(None), } } @@ -44,24 +41,49 @@ impl FunctionCall { impl AbstractNode for FunctionCall { fn define_types(&self, context: &Context) -> Result<(), ValidationError> { - *self.context.lock()? = Some(context.create_child()); - self.function_expression.define_types(context)?; - let mut previous = (); + let (type_parameters, value_parameters) = + if let Some(r#type) = self.function_expression.expected_type(context)? { + if let Type::Function { + type_parameters, + value_parameters, + .. + } = r#type + { + (type_parameters, value_parameters) + } else { + return Err(ValidationError::ExpectedFunction { + actual: r#type, + position: self.function_expression.position(), + }); + } + } else { + todo!("Create an error for this occurence"); + }; - for expression in &self.value_arguments { - previous = expression.define_types(context)?; + if let (Some(type_parameters), Some(type_arguments)) = + (type_parameters, &self.type_arguments) + { + for (identifier, constructor) in + type_parameters.into_iter().zip(type_arguments.into_iter()) + { + let r#type = constructor.construct(context)?; + + self.context.set_type(identifier, r#type)?; + } } - Ok(previous) + Ok(()) } fn validate(&self, context: &Context, manage_memory: bool) -> Result<(), ValidationError> { self.function_expression.validate(context, manage_memory)?; - for expression in &self.value_arguments { - expression.validate(context, manage_memory)?; + if let Some(value_arguments) = &self.value_arguments { + for expression in value_arguments { + expression.validate(context, manage_memory)?; + } } let function_node_type = @@ -126,11 +148,6 @@ impl AbstractNode for FunctionCall { }, )); }; - let function_context = if let Some(context) = self.context.lock()?.clone() { - context - } else { - todo!("New error for out-of-order execution.") - }; match (function.type_parameters(), self.type_arguments) { (Some(type_parameters), Some(type_arguments)) => { @@ -139,103 +156,59 @@ impl AbstractNode for FunctionCall { { let r#type = constructor.construct(context)?; - function_context.set_type(parameter.clone(), r#type)?; + self.context.set_type(parameter.clone(), r#type)?; } } _ => {} } - for ((identifier, _), expression) in function - .value_parameters() - .into_iter() - .zip(self.value_arguments.iter()) + if let (Some(value_parameters), Some(value_arguments)) = + (function.value_parameters(), self.value_arguments) { - let expression_position = expression.position(); - let evaluation = expression.clone().evaluate(context, clear_variables)?; - let value = if let Some(Evaluation::Return(value)) = evaluation { - value - } else { - return Err(RuntimeError::ValidationFailure( - ValidationError::ExpectedExpression(expression_position), - )); - }; + for ((identifier, _), expression) in + value_parameters.into_iter().zip(value_arguments.iter()) + { + let expression_position = expression.position(); + let evaluation = expression.clone().evaluate(context, clear_variables)?; + let value = if let Some(Evaluation::Return(value)) = evaluation { + value + } else { + return Err(RuntimeError::ValidationFailure( + ValidationError::ExpectedExpression(expression_position), + )); + }; - function_context.set_value(identifier.clone(), value)?; + self.context.set_value(identifier.clone(), value)?; + } } - function.clone().call(&function_context, clear_variables) + function.clone().call(&self.context, clear_variables) } fn expected_type(&self, context: &Context) -> Result, ValidationError> { - let function_type = if let Some(r#type) = self.function_expression.expected_type(context)? { - r#type + let return_type = if let Some(r#type) = self.function_expression.expected_type(context)? { + if let Type::Function { + type_parameters, + value_parameters, + return_type, + } = r#type + { + return_type + } else { + return Err(ValidationError::ExpectedFunction { + actual: r#type, + position: self.function_expression.position(), + }); + } } else { return Err(ValidationError::ExpectedExpression( self.function_expression.position(), )); }; - if let Type::Function { - return_type, - type_parameters, - .. - } = function_type - { - let return_type = return_type.map(|r#box| *r#box); + let return_type = return_type.map(|r#box| *r#box); - if let Some(Type::Generic { - identifier: return_identifier, - .. - }) = &return_type - { - if let (Some(type_arguments), Some(type_parameters)) = - (&self.type_arguments, &type_parameters) - { - for (constructor, identifier) in - type_arguments.into_iter().zip(type_parameters.into_iter()) - { - if identifier == return_identifier { - let concrete_type = constructor.clone().construct(&context)?; - - return Ok(Some(Type::Generic { - identifier: identifier.clone(), - concrete_type: Some(Box::new(concrete_type)), - })); - } - } - } - - if let (None, Some(type_parameters)) = (&self.type_arguments, type_parameters) { - for (expression, identifier) in (&self.value_arguments) - .into_iter() - .zip(type_parameters.into_iter()) - { - if &identifier == return_identifier { - let concrete_type = - if let Some(r#type) = expression.expected_type(context)? { - r#type - } else { - return Err(ValidationError::ExpectedExpression( - expression.position(), - )); - }; - - return Ok(Some(Type::Generic { - identifier, - concrete_type: Some(Box::new(concrete_type)), - })); - } - } - } - } - - Ok(return_type) - } else { - Err(ValidationError::ExpectedFunction { - actual: function_type, - position: self.function_expression.position(), - }) - } + Ok(return_type) } } diff --git a/dust-lang/src/abstract_tree/type.rs b/dust-lang/src/abstract_tree/type.rs index efa9283..e45b648 100644 --- a/dust-lang/src/abstract_tree/type.rs +++ b/dust-lang/src/abstract_tree/type.rs @@ -17,7 +17,7 @@ pub enum Type { Float, Function { type_parameters: Option>, - value_parameters: Vec, + value_parameters: Option>, return_type: Option>, }, Generic { @@ -255,14 +255,16 @@ impl Display for Type { write!(f, ")(")?; } - for r#type in value_parameters { - write!(f, "{type}")?; + if let Some(value_parameters) = value_parameters { + for (identifier, r#type) in value_parameters { + write!(f, "{identifier}: {type}")?; + } } write!(f, ")")?; if let Some(r#type) = return_type { - write!(f, " -> {}", r#type) + write!(f, " -> {type}") } else { Ok(()) } diff --git a/dust-lang/src/abstract_tree/type_constructor.rs b/dust-lang/src/abstract_tree/type_constructor.rs index 1eca1a6..2c80f82 100644 --- a/dust-lang/src/abstract_tree/type_constructor.rs +++ b/dust-lang/src/abstract_tree/type_constructor.rs @@ -135,13 +135,20 @@ impl TypeConstructor { .map(|identifier| identifier.node.clone()) .collect() }); - let mut value_parameters = Vec::with_capacity(declared_value_parameters.len()); + let value_parameters = + if let Some(declared_value_parameters) = declared_value_parameters { + let mut parameters = Vec::with_capacity(declared_value_parameters.len()); - for parameter in declared_value_parameters { - let r#type = parameter.construct(&context)?; + for (identifier, constructor) in declared_value_parameters { + let r#type = constructor.construct(&context)?; - value_parameters.push(r#type); - } + parameters.push((identifier.node.clone(), r#type)); + } + + Some(parameters) + } else { + None + }; let return_type = if let Some(constructor) = return_type { Some(Box::new(constructor.construct(context)?)) @@ -200,7 +207,7 @@ pub struct EnumTypeConstructor { #[derive(Clone, Debug, Eq, PartialEq, PartialOrd, Ord, Serialize, Deserialize)] pub struct FunctionTypeConstructor { pub type_parameters: Option>>, - pub value_parameters: Vec, + pub value_parameters: Option, TypeConstructor)>>, pub return_type: Option>, } diff --git a/dust-lang/src/abstract_tree/value_node.rs b/dust-lang/src/abstract_tree/value_node.rs index 6103dea..2a9c53d 100644 --- a/dust-lang/src/abstract_tree/value_node.rs +++ b/dust-lang/src/abstract_tree/value_node.rs @@ -37,7 +37,7 @@ pub enum ValueNode { impl ValueNode { pub fn function( type_parameters: Option>, - value_parameters: Vec<(Identifier, TypeConstructor)>, + value_parameters: Option>, return_type: Option, body: WithPosition, ) -> Self { @@ -95,10 +95,12 @@ impl AbstractNode for ValueNode { } } - for (identifier, type_constructor) in value_parameters { - let r#type = type_constructor.clone().construct(outer_context)?; + if let Some(value_parameters) = value_parameters { + for (identifier, type_constructor) in value_parameters { + let r#type = type_constructor.clone().construct(outer_context)?; - context_template.set_type(identifier.clone(), r#type)?; + context_template.set_type(identifier.clone(), r#type)?; + } } body.node.define_types(context_template)?; @@ -310,20 +312,25 @@ impl AbstractNode for ValueNode { ValueNode::String(string) => Value::string(string), ValueNode::Function(FunctionNode { type_parameters, - value_parameters: constructors, + value_parameters, return_type, body, context_template, }) => { let outer_context = context; - let mut value_parameters = Vec::with_capacity(constructors.len()); + let value_parameters = if let Some(value_parameters) = value_parameters { + let mut parameters = Vec::with_capacity(value_parameters.len()); - for (identifier, constructor) in constructors { - let r#type = constructor.construct(&outer_context)?; + for (identifier, constructor) in value_parameters { + let r#type = constructor.construct(&outer_context)?; - value_parameters.push((identifier, r#type)); - } + parameters.push((identifier, r#type)); + } + Some(parameters) + } else { + None + }; let return_type = if let Some(constructor) = return_type { Some(constructor.construct(&outer_context)?) } else { @@ -402,13 +409,19 @@ impl AbstractNode for ValueNode { return_type, .. }) => { - let mut value_parameter_types = Vec::with_capacity(value_parameters.len()); + let value_parameters = if let Some(value_parameters) = value_parameters { + let mut parameters = Vec::with_capacity(value_parameters.len()); - for (_, type_constructor) in value_parameters { - let r#type = type_constructor.clone().construct(&context)?; + for (identifier, type_constructor) in value_parameters { + let r#type = type_constructor.clone().construct(&context)?; - value_parameter_types.push(r#type); - } + parameters.push((identifier.clone(), r#type)); + } + + Some(parameters) + } else { + None + }; let type_parameters = type_parameters.clone().map(|parameters| { parameters @@ -424,7 +437,7 @@ impl AbstractNode for ValueNode { Type::Function { type_parameters, - value_parameters: value_parameter_types, + value_parameters, return_type, } } @@ -586,7 +599,7 @@ impl Ord for ValueNode { #[derive(Clone, Debug, Serialize, Deserialize)] pub struct FunctionNode { type_parameters: Option>, - value_parameters: Vec<(Identifier, TypeConstructor)>, + value_parameters: Option>, return_type: Option, body: WithPosition, #[serde(skip)] diff --git a/dust-lang/src/parser/mod.rs b/dust-lang/src/parser/mod.rs index aaa77fd..f11d75f 100644 --- a/dust-lang/src/parser/mod.rs +++ b/dust-lang/src/parser/mod.rs @@ -104,8 +104,10 @@ pub fn parser<'src>( .or_not(), ) .then( - type_constructor + positioned_identifier .clone() + .then_ignore(just(Token::Symbol(Symbol::Colon))) + .then(type_constructor.clone()) .separated_by(just(Token::Symbol(Symbol::Comma))) .collect() .delimited_by( @@ -119,7 +121,20 @@ pub fn parser<'src>( .or_not(), ) .map_with( - |((type_parameters, value_parameters), return_type), state| { + |((type_parameters, value_parameters), return_type): ( + ( + Option>>, + Vec<(WithPosition, TypeConstructor)>, + ), + Option, + ), + state| { + let value_parameters = if value_parameters.is_empty() { + None + } else { + Some(value_parameters) + }; + TypeConstructor::Function( FunctionTypeConstructor { type_parameters, @@ -290,7 +305,20 @@ pub fn parser<'src>( ) .then(block.clone()) .map_with( - |(((type_parameters, value_parameters), return_type), body), state| { + |(((type_parameters, value_parameters), return_type), body): ( + ( + (Option>, Vec<(Identifier, TypeConstructor)>), + Option, + ), + WithPosition, + ), + state| { + let value_parameters = if value_parameters.is_empty() { + None + } else { + Some(value_parameters) + }; + Expression::Value( ValueNode::function( type_parameters, @@ -561,7 +589,18 @@ pub fn parser<'src>( just(Token::Symbol(Symbol::ParenClose)), ), ), - |function_expression, (type_parameters, value_parameters), span| { + |function_expression, + (type_parameters, value_parameters): ( + Option>, + Vec, + ), + span| { + let value_parameters = if value_parameters.is_empty() { + None + } else { + Some(value_parameters) + }; + Expression::FunctionCall( FunctionCall::new( function_expression, diff --git a/dust-lang/src/parser/tests.rs b/dust-lang/src/parser/tests.rs index 8fd8215..fadcedf 100644 --- a/dust-lang/src/parser/tests.rs +++ b/dust-lang/src/parser/tests.rs @@ -344,9 +344,9 @@ fn r#while() { FunctionCall::new( Expression::Identifier(Identifier::new("output").with_position((13, 19))), None, - vec![Expression::Value( + Some(vec![Expression::Value( ValueNode::String("hi".to_string()).with_position((20, 24)) - )] + )]) ) .with_position((13, 25)) ))] @@ -431,22 +431,25 @@ fn list_of_type() { #[test] fn function_type() { assert_eq!( - parse(&lex("type Foo = fn |T| (int)").unwrap()).unwrap()[0], + parse(&lex("type Foo = fn |T| (x: int)").unwrap()).unwrap()[0], Statement::TypeAlias( TypeAlias::new( Identifier::new("Foo").with_position((5, 8)), TypeConstructor::Function( FunctionTypeConstructor { type_parameters: Some(vec![Identifier::new("T").with_position((15, 16))]), - value_parameters: vec![TypeConstructor::Raw( - RawTypeConstructor::Integer.with_position((19, 22)) - )], + value_parameters: Some(vec![( + Identifier::new("x").with_position((19, 20)), + TypeConstructor::Raw( + RawTypeConstructor::Integer.with_position((22, 25)) + ) + )]), return_type: None } - .with_position((11, 23)) + .with_position((11, 26)) ) ) - .with_position((0, 23)) + .with_position((0, 26)) ) ); } @@ -454,27 +457,30 @@ fn function_type() { #[test] fn function_type_with_return() { assert_eq!( - parse(&lex("type Foo = fn |T| (int) -> T").unwrap()).unwrap()[0], + parse(&lex("type Foo = fn |T| (x: int) -> T").unwrap()).unwrap()[0], Statement::TypeAlias( TypeAlias::new( Identifier::new("Foo").with_position((5, 8)), TypeConstructor::Function( FunctionTypeConstructor { type_parameters: Some(vec![Identifier::new("T").with_position((15, 16))]), - value_parameters: vec![TypeConstructor::Raw( - RawTypeConstructor::Integer.with_position((19, 22)) - )], + value_parameters: Some(vec![( + Identifier::new("x").with_position((19, 20)), + TypeConstructor::Raw( + RawTypeConstructor::Integer.with_position((22, 25)) + ) + )]), return_type: Some(Box::new(TypeConstructor::Invokation( TypeInvokationConstructor { - identifier: Identifier::new("T").with_position((27, 28)), + identifier: Identifier::new("T").with_position((30, 31)), type_arguments: None } ))) } - .with_position((11, 28)) + .with_position((11, 31)) ) ) - .with_position((0, 28)) + .with_position((0, 31)) ) ); } @@ -487,7 +493,7 @@ fn function_call() { FunctionCall::new( Expression::Identifier(Identifier::new("foobar").with_position((0, 6))), None, - Vec::with_capacity(0), + None, ) .with_position((0, 8)) )) @@ -504,9 +510,9 @@ fn function_call_with_type_arguments() { Some(vec![TypeConstructor::Raw( RawTypeConstructor::String.with_position((9, 12)) )]), - vec![Expression::Value( + Some(vec![Expression::Value( ValueNode::String("hi".to_string()).with_position((16, 20)) - )], + )]), ) .with_position((0, 21)) )) @@ -530,7 +536,7 @@ fn function() { Statement::Expression(Expression::Value( ValueNode::function( None, - vec![], + None, Some(TypeConstructor::Raw( RawTypeConstructor::Integer.with_position((9, 12)) )), @@ -548,10 +554,10 @@ fn function() { Statement::Expression(Expression::Value( ValueNode::function( None, - vec![( + Some(vec![( Identifier::new("x"), TypeConstructor::Raw(RawTypeConstructor::Integer.with_position((7, 10))) - )], + )]), Some(TypeConstructor::Raw( RawTypeConstructor::Integer.with_position((15, 18)) )), @@ -572,7 +578,7 @@ fn function_with_type_arguments() { Statement::Expression(Expression::Value( ValueNode::function( Some(vec![Identifier::new("T"), Identifier::new("U"),]), - vec![ + Some(vec![ ( Identifier::new("x"), TypeConstructor::Invokation(TypeInvokationConstructor { @@ -587,7 +593,7 @@ fn function_with_type_arguments() { type_arguments: None, }) ) - ], + ]), Some(TypeConstructor::Invokation(TypeInvokationConstructor { identifier: Identifier::new("T").with_position((26, 27)), type_arguments: None, diff --git a/dust-lang/src/value.rs b/dust-lang/src/value.rs index 7f00c28..b276245 100644 --- a/dust-lang/src/value.rs +++ b/dust-lang/src/value.rs @@ -70,7 +70,7 @@ impl Value { pub fn function( type_parameters: Option>, - value_parameters: Vec<(Identifier, Type)>, + value_parameters: Option>, return_type: Option, body: Block, context_template: Context, @@ -166,7 +166,7 @@ impl Display for Value { ValueInner::String(string) => write!(f, "{string}"), ValueInner::Function(Function { type_parameters, - value_parameters: parameters, + value_parameters, return_type, body, .. @@ -187,8 +187,10 @@ impl Display for Value { write!(f, "(")?; - for (identifier, r#type) in parameters { - write!(f, "{identifier}: {}", r#type)?; + if let Some(value_parameters) = value_parameters { + for (identifier, r#type) in value_parameters { + write!(f, "{identifier}: {}", r#type)?; + } } write!(f, ")")?; @@ -594,17 +596,11 @@ impl ValueInner { ValueInner::Range(_) => Type::Range, ValueInner::String(_) => Type::String, ValueInner::Function(function) => { - let value_parameters = function - .value_parameters() - .into_iter() - .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, + value_parameters: function.value_parameters().clone(), return_type, } } @@ -714,7 +710,7 @@ impl Ord for ValueInner { #[derive(Clone, Debug)] pub struct Function { type_parameters: Option>, - value_parameters: Vec<(Identifier, Type)>, + value_parameters: Option>, return_type: Option, body: Block, context_template: Context, @@ -723,7 +719,7 @@ pub struct Function { impl Function { pub fn new( type_parameters: Option>, - value_parameters: Vec<(Identifier, Type)>, + value_parameters: Option>, return_type: Option, body: Block, context_template: Context, @@ -745,7 +741,7 @@ impl Function { &self.type_parameters } - pub fn value_parameters(&self) -> &Vec<(Identifier, Type)> { + pub fn value_parameters(&self) -> &Option> { &self.value_parameters } @@ -774,9 +770,11 @@ impl Function { } } - for (identifier, r#type) in &self.value_parameters { - self.context_template - .set_type(identifier.clone(), r#type.clone())?; + if let Some(value_parameters) = &self.value_parameters { + for (identifier, r#type) in value_parameters { + self.context_template + .set_type(identifier.clone(), r#type.clone())?; + } } Ok(()) diff --git a/dust-lang/tests/variables.rs b/dust-lang/tests/variables.rs index 5ce1cae..cdf8707 100644 --- a/dust-lang/tests/variables.rs +++ b/dust-lang/tests/variables.rs @@ -48,7 +48,7 @@ fn function_variable() { interpret("test", "foobar = fn (x: int) -> int { x }; foobar"), Ok(Some(Value::function( None, - vec![(Identifier::new("x"), Type::Integer)], + Some(vec![(Identifier::new("x"), Type::Integer)]), Some(Type::Integer), Block::new(vec![Statement::Expression(Expression::Identifier( Identifier::new("x").with_position((30, 31))