From 56fbbdee0b2ca84d847b6259784af03b2c5fa21c Mon Sep 17 00:00:00 2001 From: Jeff Date: Fri, 8 Mar 2024 16:14:47 -0500 Subject: [PATCH] Begin implementing functions --- src/abstract_tree/assignment.rs | 10 ++--- src/abstract_tree/block.rs | 12 +++--- src/abstract_tree/expression.rs | 12 +++--- src/abstract_tree/if_else.rs | 24 +++++------ src/abstract_tree/index.rs | 12 +++--- src/abstract_tree/logic.rs | 22 +++++----- src/abstract_tree/loop.rs | 10 ++--- src/abstract_tree/math.rs | 14 +++---- src/abstract_tree/statement.rs | 16 ++++---- src/abstract_tree/value_node.rs | 56 +++++++++++++++++++++---- src/parser.rs | 73 ++++++++++++++++++++++++--------- src/value.rs | 56 ++++++++++++++++++++----- 12 files changed, 212 insertions(+), 105 deletions(-) diff --git a/src/abstract_tree/assignment.rs b/src/abstract_tree/assignment.rs index 6c8d66d..442b1ec 100644 --- a/src/abstract_tree/assignment.rs +++ b/src/abstract_tree/assignment.rs @@ -6,11 +6,11 @@ use crate::{ use super::{AbstractTree, Action, Identifier, Statement, Type}; #[derive(Clone, Debug, Eq, PartialEq, PartialOrd, Ord)] -pub struct Assignment<'src> { +pub struct Assignment { identifier: Identifier, r#type: Option, operator: AssignmentOperator, - statement: Box>, + statement: Box, } #[derive(Clone, Debug, Eq, PartialEq, PartialOrd, Ord)] @@ -20,12 +20,12 @@ pub enum AssignmentOperator { SubAssign, } -impl<'src> Assignment<'src> { +impl Assignment { pub fn new( identifier: Identifier, r#type: Option, operator: AssignmentOperator, - statement: Statement<'src>, + statement: Statement, ) -> Self { Self { identifier, @@ -36,7 +36,7 @@ impl<'src> Assignment<'src> { } } -impl<'src> AbstractTree for Assignment<'src> { +impl AbstractTree for Assignment { fn expected_type(&self, _context: &Context) -> Result { todo!() } diff --git a/src/abstract_tree/block.rs b/src/abstract_tree/block.rs index 2ce6340..54f6810 100644 --- a/src/abstract_tree/block.rs +++ b/src/abstract_tree/block.rs @@ -7,17 +7,17 @@ use crate::{ use super::{AbstractTree, Action, Statement, Type}; #[derive(Clone, Debug, Eq, PartialEq, PartialOrd, Ord)] -pub struct Block<'src> { - statements: Vec>, +pub struct Block { + statements: Vec, } -impl<'src> Block<'src> { - pub fn new(statements: Vec>) -> Self { +impl Block { + pub fn new(statements: Vec) -> Self { Self { statements } } } -impl<'src> AbstractTree for Block<'src> { +impl AbstractTree for Block { fn expected_type(&self, _context: &Context) -> Result { let final_statement = self.statements.last().unwrap(); @@ -70,7 +70,7 @@ mod tests { #[test] fn expected_type_returns_type_of_final_statement() { let block = Block::new(vec![ - Statement::Expression(Expression::Value(ValueNode::String("42"))), + Statement::Expression(Expression::Value(ValueNode::String("42".to_string()))), Statement::Expression(Expression::Value(ValueNode::Integer(42))), ]); diff --git a/src/abstract_tree/expression.rs b/src/abstract_tree/expression.rs index b1cd6d4..42dd988 100644 --- a/src/abstract_tree/expression.rs +++ b/src/abstract_tree/expression.rs @@ -6,15 +6,15 @@ use crate::{ use super::{AbstractTree, Action, Identifier, Index, Logic, Math, Type, ValueNode}; #[derive(Clone, Debug, Eq, PartialEq, PartialOrd, Ord)] -pub enum Expression<'src> { +pub enum Expression { Identifier(Identifier), - Index(Box>), - Logic(Box>), - Math(Box>), - Value(ValueNode<'src>), + Index(Box), + Logic(Box), + Math(Box), + Value(ValueNode), } -impl<'src> AbstractTree for Expression<'src> { +impl AbstractTree for Expression { fn expected_type(&self, _context: &Context) -> Result { match self { Expression::Identifier(identifier) => identifier.expected_type(_context), diff --git a/src/abstract_tree/if_else.rs b/src/abstract_tree/if_else.rs index e42f03c..6343b5d 100644 --- a/src/abstract_tree/if_else.rs +++ b/src/abstract_tree/if_else.rs @@ -6,17 +6,17 @@ use crate::{ use super::{AbstractTree, Action, Expression, Statement, Type}; #[derive(Clone, Debug, Eq, PartialEq, PartialOrd, Ord)] -pub struct IfElse<'src> { - if_expression: Expression<'src>, - if_statement: Box>, - else_statement: Option>>, +pub struct IfElse { + if_expression: Expression, + if_statement: Box, + else_statement: Option>, } -impl<'src> IfElse<'src> { +impl IfElse { pub fn new( - if_expression: Expression<'src>, - if_statement: Statement<'src>, - else_statement: Option>, + if_expression: Expression, + if_statement: Statement, + else_statement: Option, ) -> Self { Self { if_expression, @@ -26,7 +26,7 @@ impl<'src> IfElse<'src> { } } -impl<'src> AbstractTree for IfElse<'src> { +impl AbstractTree for IfElse { fn expected_type(&self, _context: &Context) -> Result { Ok(Type::None) } @@ -71,7 +71,7 @@ mod tests { assert_eq!( IfElse::new( Expression::Value(ValueNode::Boolean(true)), - Statement::Expression(Expression::Value(ValueNode::String("foo"))), + Statement::Expression(Expression::Value(ValueNode::String("foo".to_string()))), None ) .run(&Context::new()), @@ -84,9 +84,9 @@ mod tests { assert_eq!( IfElse::new( Expression::Value(ValueNode::Boolean(false)), - Statement::Expression(Expression::Value(ValueNode::String("foo"))), + Statement::Expression(Expression::Value(ValueNode::String("foo".to_string()))), Some(Statement::Expression(Expression::Value(ValueNode::String( - "bar" + "bar".to_string() )))) ) .run(&Context::new()), diff --git a/src/abstract_tree/index.rs b/src/abstract_tree/index.rs index 26a4236..2b8114f 100644 --- a/src/abstract_tree/index.rs +++ b/src/abstract_tree/index.rs @@ -7,18 +7,18 @@ use crate::{ use super::{AbstractTree, Action, Expression, Type, ValueNode}; #[derive(Clone, Debug, Eq, PartialEq, PartialOrd, Ord)] -pub struct Index<'src> { - left: Expression<'src>, - right: Expression<'src>, +pub struct Index { + left: Expression, + right: Expression, } -impl<'src> Index<'src> { - pub fn new(left: Expression<'src>, right: Expression<'src>) -> Self { +impl Index { + pub fn new(left: Expression, right: Expression) -> Self { Self { left, right } } } -impl<'src> AbstractTree for Index<'src> { +impl AbstractTree for Index { fn expected_type(&self, _context: &Context) -> Result { let left_type = self.left.expected_type(_context)?; diff --git a/src/abstract_tree/logic.rs b/src/abstract_tree/logic.rs index 886935f..c928fc8 100644 --- a/src/abstract_tree/logic.rs +++ b/src/abstract_tree/logic.rs @@ -7,19 +7,19 @@ use crate::{ use super::{AbstractTree, Action, Expression, Type}; #[derive(Clone, Debug, Eq, PartialEq, PartialOrd, Ord)] -pub enum Logic<'src> { - Equal(Expression<'src>, Expression<'src>), - NotEqual(Expression<'src>, Expression<'src>), - Greater(Expression<'src>, Expression<'src>), - Less(Expression<'src>, Expression<'src>), - GreaterOrEqual(Expression<'src>, Expression<'src>), - LessOrEqual(Expression<'src>, Expression<'src>), - And(Expression<'src>, Expression<'src>), - Or(Expression<'src>, Expression<'src>), - Not(Expression<'src>), +pub enum Logic { + Equal(Expression, Expression), + NotEqual(Expression, Expression), + Greater(Expression, Expression), + Less(Expression, Expression), + GreaterOrEqual(Expression, Expression), + LessOrEqual(Expression, Expression), + And(Expression, Expression), + Or(Expression, Expression), + Not(Expression), } -impl<'src> AbstractTree for Logic<'src> { +impl AbstractTree for Logic { fn expected_type(&self, _context: &Context) -> Result { Ok(Type::Boolean) } diff --git a/src/abstract_tree/loop.rs b/src/abstract_tree/loop.rs index 3be2eca..ac199bb 100644 --- a/src/abstract_tree/loop.rs +++ b/src/abstract_tree/loop.rs @@ -6,17 +6,17 @@ use crate::{ use super::{AbstractTree, Action, Statement, Type}; #[derive(Clone, Debug, Eq, PartialEq, PartialOrd, Ord)] -pub struct Loop<'src> { - statements: Vec>, +pub struct Loop { + statements: Vec, } -impl<'src> Loop<'src> { - pub fn new(statements: Vec>) -> Self { +impl Loop { + pub fn new(statements: Vec) -> Self { Self { statements } } } -impl<'src> AbstractTree for Loop<'src> { +impl AbstractTree for Loop { fn expected_type(&self, _context: &Context) -> Result { Ok(Type::None) } diff --git a/src/abstract_tree/math.rs b/src/abstract_tree/math.rs index 565a8db..c3ad396 100644 --- a/src/abstract_tree/math.rs +++ b/src/abstract_tree/math.rs @@ -8,15 +8,15 @@ use crate::{ use super::{AbstractTree, Action, Expression, Type}; #[derive(Clone, Debug, Eq, PartialEq, PartialOrd, Ord)] -pub enum Math<'src> { - Add(Expression<'src>, Expression<'src>), - Subtract(Expression<'src>, Expression<'src>), - Multiply(Expression<'src>, Expression<'src>), - Divide(Expression<'src>, Expression<'src>), - Modulo(Expression<'src>, Expression<'src>), +pub enum Math { + Add(Expression, Expression), + Subtract(Expression, Expression), + Multiply(Expression, Expression), + Divide(Expression, Expression), + Modulo(Expression, Expression), } -impl<'src> AbstractTree for Math<'src> { +impl AbstractTree for Math { fn expected_type(&self, _context: &Context) -> Result { match self { Math::Add(left, _) diff --git a/src/abstract_tree/statement.rs b/src/abstract_tree/statement.rs index e7d3c86..984ca09 100644 --- a/src/abstract_tree/statement.rs +++ b/src/abstract_tree/statement.rs @@ -6,16 +6,16 @@ use crate::{ use super::{AbstractTree, Action, Assignment, Block, Expression, IfElse, Loop, Type}; #[derive(Clone, Debug, Eq, PartialEq, PartialOrd, Ord)] -pub enum Statement<'src> { - Assignment(Assignment<'src>), - Block(Block<'src>), - Break(Expression<'src>), - Expression(Expression<'src>), - IfElse(IfElse<'src>), - Loop(Loop<'src>), +pub enum Statement { + Assignment(Assignment), + Block(Block), + Break(Expression), + Expression(Expression), + IfElse(IfElse), + Loop(Loop), } -impl<'src> AbstractTree for Statement<'src> { +impl AbstractTree for Statement { fn expected_type(&self, _context: &Context) -> Result { match self { Statement::Assignment(assignment) => assignment.expected_type(_context), diff --git a/src/abstract_tree/value_node.rs b/src/abstract_tree/value_node.rs index c5030a0..c6b773a 100644 --- a/src/abstract_tree/value_node.rs +++ b/src/abstract_tree/value_node.rs @@ -6,21 +6,26 @@ use crate::{ Value, }; -use super::{AbstractTree, Action, Expression, Identifier, Type}; +use super::{AbstractTree, Action, Expression, Identifier, Statement, Type}; #[derive(Clone, Debug, PartialEq)] -pub enum ValueNode<'src> { +pub enum ValueNode { Boolean(bool), Float(f64), Integer(i64), - List(Vec>), - Map(Vec<(Identifier, Option, Expression<'src>)>), + List(Vec), + Map(Vec<(Identifier, Option, Expression)>), Range(Range), - String(&'src str), + String(String), Enum(Identifier, Identifier), + Function { + parameters: Vec<(Identifier, Type)>, + return_type: Type, + body: Box, + }, } -impl<'src> AbstractTree for ValueNode<'src> { +impl AbstractTree for ValueNode { fn expected_type(&self, _context: &Context) -> Result { let r#type = match self { ValueNode::Boolean(_) => Type::Boolean, @@ -39,6 +44,7 @@ impl<'src> AbstractTree for ValueNode<'src> { ValueNode::Range(_) => Type::Range, ValueNode::String(_) => Type::String, ValueNode::Enum(name, _) => Type::Custom(name.clone()), + ValueNode::Function { .. } => todo!(), }; Ok(r#type) @@ -84,21 +90,26 @@ impl<'src> AbstractTree for ValueNode<'src> { Value::r#enum(name, variant) } } + ValueNode::Function { + parameters, + return_type, + body, + } => Value::function(parameters, return_type, *body), }; Ok(Action::Return(value)) } } -impl<'src> Eq for ValueNode<'src> {} +impl Eq for ValueNode {} -impl<'src> PartialOrd for ValueNode<'src> { +impl PartialOrd for ValueNode { fn partial_cmp(&self, other: &Self) -> Option { Some(self.cmp(other)) } } -impl<'src> Ord for ValueNode<'src> { +impl Ord for ValueNode { fn cmp(&self, other: &Self) -> Ordering { use ValueNode::*; @@ -135,6 +146,33 @@ impl<'src> Ord for ValueNode<'src> { } } (Enum(_, _), _) => Ordering::Greater, + ( + Function { + parameters: left_parameters, + return_type: left_return, + body: left_body, + }, + Function { + parameters: right_parameters, + return_type: right_return, + body: right_body, + }, + ) => { + let parameter_cmp = left_parameters.cmp(right_parameters); + + if parameter_cmp.is_eq() { + let return_cmp = left_return.cmp(right_return); + + if return_cmp.is_eq() { + left_body.cmp(right_body) + } else { + return_cmp + } + } else { + parameter_cmp + } + } + (Function { .. }, _) => Ordering::Greater, } } } diff --git a/src/parser.rs b/src/parser.rs index b7b2738..246e4b1 100644 --- a/src/parser.rs +++ b/src/parser.rs @@ -12,7 +12,7 @@ pub type DustParser<'src> = Boxed< 'src, 'src, ParserInput<'src>, - Vec<(Statement<'src>, SimpleSpan)>, + Vec<(Statement, SimpleSpan)>, extra::Err, SimpleSpan>>, >; @@ -21,7 +21,7 @@ pub type ParserInput<'src> = pub fn parse<'src>( tokens: &'src [(Token<'src>, SimpleSpan)], -) -> Result, SimpleSpan)>, Vec> { +) -> Result, Vec> { parser() .parse(tokens.spanned((tokens.len()..tokens.len()).into())) .into_result() @@ -85,7 +85,7 @@ pub fn parser<'src>() -> DustParser<'src> { Token::Boolean(boolean) => ValueNode::Boolean(boolean), Token::Integer(integer) => ValueNode::Integer(integer), Token::Float(float) => ValueNode::Float(float), - Token::String(string) => ValueNode::String(string), + Token::String(string) => ValueNode::String(string.to_string()), } .map(|value| Expression::Value(value)) .boxed(); @@ -221,6 +221,7 @@ pub fn parser<'src>() -> DustParser<'src> { .map(|expression| Statement::Break(expression)); let assignment = identifier + .clone() .then(type_specification.clone().or_not()) .then(choice(( just(Token::Operator(Operator::Assign)).to(AssignmentOperator::Assign), @@ -269,6 +270,25 @@ pub fn parser<'src>() -> DustParser<'src> { }) .boxed(); + let function = identifier + .clone() + .then(type_specification.clone()) + .separated_by(just(Token::Control(Control::Comma))) + .collect::>() + .delimited_by( + just(Token::Control(Control::ParenOpen)), + just(Token::Control(Control::ParenClose)), + ) + .then(type_specification) + .then(statement.clone()) + .map(|((parameters, return_type), body)| { + Statement::Expression(Expression::Value(ValueNode::Function { + parameters, + return_type, + body: Box::new(body), + })) + }); + choice(( assignment, expression_statement, @@ -276,6 +296,7 @@ pub fn parser<'src>() -> DustParser<'src> { block, r#loop, if_else, + function, )) .then_ignore(just(Token::Control(Control::Semicolon)).or_not()) }); @@ -293,13 +314,27 @@ mod tests { use super::*; + #[test] + fn function() { + assert_eq!( + parse(&lex("(x: int): int x ").unwrap()).unwrap()[0].0, + Statement::Expression(Expression::Value(ValueNode::Function { + parameters: vec![(Identifier::new("x"), Type::Integer)], + return_type: Type::Integer, + body: Box::new(Statement::Expression(Expression::Identifier( + Identifier::new("x") + ))) + })) + ) + } + #[test] fn r#if() { assert_eq!( parse(&lex("if true 'foo'").unwrap()).unwrap()[0].0, Statement::IfElse(IfElse::new( Expression::Value(ValueNode::Boolean(true)), - Statement::Expression(Expression::Value(ValueNode::String("foo"))), + Statement::Expression(Expression::Value(ValueNode::String("foo".to_string()))), None )) ) @@ -311,9 +346,9 @@ mod tests { parse(&lex("if true 'foo' else 'bar'").unwrap()).unwrap()[0].0, Statement::IfElse(IfElse::new( Expression::Value(ValueNode::Boolean(true)), - Statement::Expression(Expression::Value(ValueNode::String("foo"))), + Statement::Expression(Expression::Value(ValueNode::String("foo".to_string()))), Some(Statement::Expression(Expression::Value(ValueNode::String( - "bar" + "bar".to_string() )))) )) ) @@ -326,7 +361,7 @@ mod tests { Statement::Expression(Expression::Value(ValueNode::Map(vec![( Identifier::new("foo"), None, - Expression::Value(ValueNode::String("bar")) + Expression::Value(ValueNode::String("bar".to_string())) )]))) ); assert_eq!( @@ -521,7 +556,7 @@ mod tests { AssignmentOperator::Assign, Statement::Expression(Expression::Value(ValueNode::List(vec![ Expression::Value(ValueNode::Integer(42)), - Expression::Value(ValueNode::String("foo")) + Expression::Value(ValueNode::String("foo".to_string())) ]))) )), ); @@ -596,8 +631,8 @@ mod tests { parse(&lex("[42, 'foo', 'bar', [1, 2, 3,]]").unwrap()).unwrap()[0].0, Statement::Expression(Expression::Value(ValueNode::List(vec![ Expression::Value(ValueNode::Integer(42)), - Expression::Value(ValueNode::String("foo")), - Expression::Value(ValueNode::String("bar")), + Expression::Value(ValueNode::String("foo".to_string())), + Expression::Value(ValueNode::String("bar".to_string())), Expression::Value(ValueNode::List(vec![ Expression::Value(ValueNode::Integer(1)), Expression::Value(ValueNode::Integer(2)), @@ -751,15 +786,15 @@ mod tests { fn double_quoted_string() { assert_eq!( parse(&lex("\"\"").unwrap()).unwrap()[0].0, - Statement::Expression(Expression::Value(ValueNode::String(""))) + Statement::Expression(Expression::Value(ValueNode::String("".to_string()))) ); assert_eq!( parse(&lex("\"42\"").unwrap()).unwrap()[0].0, - Statement::Expression(Expression::Value(ValueNode::String("42"))) + Statement::Expression(Expression::Value(ValueNode::String("42".to_string()))) ); assert_eq!( parse(&lex("\"foobar\"").unwrap()).unwrap()[0].0, - Statement::Expression(Expression::Value(ValueNode::String("foobar"))) + Statement::Expression(Expression::Value(ValueNode::String("foobar".to_string()))) ); } @@ -767,15 +802,15 @@ mod tests { fn single_quoted_string() { assert_eq!( parse(&lex("''").unwrap()).unwrap()[0].0, - Statement::Expression(Expression::Value(ValueNode::String(""))) + Statement::Expression(Expression::Value(ValueNode::String("".to_string()))) ); assert_eq!( parse(&lex("'42'").unwrap()).unwrap()[0].0, - Statement::Expression(Expression::Value(ValueNode::String("42"))) + Statement::Expression(Expression::Value(ValueNode::String("42".to_string()))) ); assert_eq!( parse(&lex("'foobar'").unwrap()).unwrap()[0].0, - Statement::Expression(Expression::Value(ValueNode::String("foobar"))) + Statement::Expression(Expression::Value(ValueNode::String("foobar".to_string()))) ); } @@ -783,15 +818,15 @@ mod tests { fn grave_quoted_string() { assert_eq!( parse(&lex("``").unwrap()).unwrap()[0].0, - Statement::Expression(Expression::Value(ValueNode::String(""))) + Statement::Expression(Expression::Value(ValueNode::String("".to_string()))) ); assert_eq!( parse(&lex("`42`").unwrap()).unwrap()[0].0, - Statement::Expression(Expression::Value(ValueNode::String("42"))) + Statement::Expression(Expression::Value(ValueNode::String("42".to_string()))) ); assert_eq!( parse(&lex("`foobar`").unwrap()).unwrap()[0].0, - Statement::Expression(Expression::Value(ValueNode::String("foobar"))) + Statement::Expression(Expression::Value(ValueNode::String("foobar".to_string()))) ); } } diff --git a/src/value.rs b/src/value.rs index c0385e3..a28ad5b 100644 --- a/src/value.rs +++ b/src/value.rs @@ -13,7 +13,7 @@ use stanza::{ }; use crate::{ - abstract_tree::{Identifier, Type}, + abstract_tree::{Identifier, Statement, Type}, error::ValidationError, }; @@ -72,6 +72,18 @@ impl Value { Value(Arc::new(ValueInner::Enum(name, variant))) } + pub fn function( + parameters: Vec<(Identifier, Type)>, + return_type: Type, + body: Statement, + ) -> Self { + Value(Arc::new(ValueInner::Function(Function { + parameters, + return_type, + body, + }))) + } + pub fn r#type(&self) -> Type { match self.0.as_ref() { ValueInner::Boolean(_) => Type::Boolean, @@ -90,6 +102,7 @@ impl Value { ValueInner::Range(_) => Type::Range, ValueInner::String(_) => Type::String, ValueInner::Enum(name, _) => Type::Custom(name.clone()), + ValueInner::Function(_) => todo!(), } } @@ -152,17 +165,15 @@ impl Value { impl Display for Value { fn fmt(&self, f: &mut Formatter) -> fmt::Result { - use ValueInner::*; - fn create_table() -> Table { Table::with_styles(Styles::default().with(HAlign::Centred).with(MinWidth(3))) } match self.inner().as_ref() { - Boolean(boolean) => write!(f, "{boolean}"), - Float(float) => write!(f, "{float}"), - Integer(integer) => write!(f, "{integer}"), - List(list) => { + ValueInner::Boolean(boolean) => write!(f, "{boolean}"), + ValueInner::Float(float) => write!(f, "{float}"), + ValueInner::Integer(integer) => write!(f, "{integer}"), + ValueInner::List(list) => { let mut table = create_table(); for value in list { @@ -171,7 +182,7 @@ impl Display for Value { write!(f, "{}", Console::default().render(&table)) } - Map(map) => { + ValueInner::Map(map) => { let mut table = create_table(); for (identifier, value) in map { @@ -180,10 +191,23 @@ impl Display for Value { write!(f, "{}", Console::default().render(&table)) } - Range(_) => todo!(), - String(string) => write!(f, "{string}"), + ValueInner::Range(_) => todo!(), + ValueInner::String(string) => write!(f, "{string}"), - Enum(_, _) => todo!(), + ValueInner::Enum(_, _) => todo!(), + ValueInner::Function(Function { + parameters, + return_type, + body, + }) => { + write!(f, "(")?; + + for (identifier, r#type) in parameters { + write!(f, "{identifier}: {}", r#type)?; + } + + write!(f, "): {return_type} {body:?}") + } } } } @@ -206,6 +230,7 @@ impl Ord for Value { pub enum ValueInner { Boolean(bool), Float(f64), + Function(Function), Integer(i64), List(Vec), Map(BTreeMap), @@ -259,6 +284,15 @@ impl Ord for ValueInner { } } (Enum(..), _) => Ordering::Greater, + (Function(left), Function(right)) => left.cmp(right), + (Function(_), _) => Ordering::Greater, } } } + +#[derive(Clone, Debug, Eq, PartialEq, PartialOrd, Ord)] +pub struct Function { + parameters: Vec<(Identifier, Type)>, + return_type: Type, + body: Statement, +}