diff --git a/dust-lang/src/abstract_tree/enum_declaration.rs b/dust-lang/src/abstract_tree/enum_declaration.rs new file mode 100644 index 0000000..b710b4a --- /dev/null +++ b/dust-lang/src/abstract_tree/enum_declaration.rs @@ -0,0 +1,83 @@ +use serde::{Deserialize, Serialize}; + +use crate::{ + context::Context, + error::{RuntimeError, ValidationError}, + identifier::Identifier, +}; + +use super::{Evaluate, Evaluation, Type, TypeConstructor, WithPosition}; + +#[derive(Clone, Debug, Eq, PartialEq, PartialOrd, Ord, Serialize, Deserialize)] +pub struct EnumDeclaration { + pub name: WithPosition, + pub type_parameters: Option>>, + pub variants: Vec, +} + +impl Evaluate for EnumDeclaration { + fn validate( + &self, + _context: &mut Context, + _manage_memory: bool, + ) -> Result<(), ValidationError> { + Ok(()) + } + + fn evaluate( + self, + context: &mut Context, + _manage_memory: bool, + ) -> Result { + let EnumDeclaration { + name, + type_parameters, + variants, + } = self; + + let type_parameters = type_parameters.as_ref().map(|parameters| { + parameters + .iter() + .map(|identifier| Type::Generic { + identifier: identifier.node.clone(), + concrete_type: None, + }) + .collect() + }); + let mut type_variants = Vec::with_capacity(variants.len()); + + for EnumVariant { name, content } in variants { + let types = if let Some(content) = content { + let mut types = Vec::with_capacity(content.len()); + + for constructor in content { + let r#type = constructor.construct(&context)?; + + types.push(r#type); + } + + Some(types) + } else { + None + }; + + type_variants.push((name.node, types)); + } + + let r#type = Type::Enum { + name: name.node.clone(), + type_parameters, + variants: type_variants, + }; + + context.set_type(name.node, r#type)?; + + Ok(Evaluation::None) + } +} + +#[derive(Clone, Debug, Eq, PartialEq, PartialOrd, Ord, Serialize, Deserialize)] +pub struct EnumVariant { + pub name: WithPosition, + pub content: Option>, +} diff --git a/dust-lang/src/abstract_tree/mod.rs b/dust-lang/src/abstract_tree/mod.rs index 084fc3c..04543a2 100644 --- a/dust-lang/src/abstract_tree/mod.rs +++ b/dust-lang/src/abstract_tree/mod.rs @@ -3,6 +3,7 @@ pub mod assignment; pub mod async_block; pub mod block; pub mod built_in_function_call; +pub mod enum_declaration; pub mod expression; pub mod function_call; pub mod if_else; @@ -14,7 +15,7 @@ pub mod math; pub mod statement; pub mod structure_definition; pub mod r#type; -pub mod type_assignment; +pub mod type_alias; pub mod type_constructor; pub mod value_node; pub mod r#while; @@ -29,6 +30,7 @@ pub use self::{ async_block::AsyncBlock, block::Block, built_in_function_call::BuiltInFunctionCall, + enum_declaration::{EnumDeclaration, EnumVariant}, expression::Expression, function_call::FunctionCall, if_else::IfElse, @@ -42,7 +44,7 @@ pub use self::{ r#while::While, statement::Statement, structure_definition::StructureDefinition, - type_assignment::TypeAssignment, + type_alias::TypeAlias, type_constructor::{ EnumTypeConstructor, FunctionTypeConstructor, ListTypeConstructor, TypeConstructor, }, diff --git a/dust-lang/src/abstract_tree/statement.rs b/dust-lang/src/abstract_tree/statement.rs index 37fb201..04b8b8b 100644 --- a/dust-lang/src/abstract_tree/statement.rs +++ b/dust-lang/src/abstract_tree/statement.rs @@ -6,8 +6,8 @@ use crate::{ }; use super::{ - Assignment, AsyncBlock, Block, Evaluate, Evaluation, ExpectedType, Expression, IfElse, Loop, - SourcePosition, StructureDefinition, Type, TypeAssignment, While, WithPosition, + Assignment, AsyncBlock, Block, EnumDeclaration, Evaluate, Evaluation, ExpectedType, Expression, + IfElse, Loop, SourcePosition, StructureDefinition, Type, TypeAlias, While, WithPosition, }; #[derive(Clone, Debug, Eq, PartialEq, PartialOrd, Ord, Serialize, Deserialize)] @@ -19,7 +19,8 @@ pub enum Statement { IfElse(WithPosition), Loop(WithPosition), StructureDefinition(WithPosition), - TypeAssignment(WithPosition), + TypeAlias(WithPosition), + EnumDeclaration(WithPosition), Expression(Expression), While(WithPosition), } @@ -35,7 +36,8 @@ impl Statement { Statement::IfElse(inner) => inner.position, Statement::Loop(inner) => inner.position, Statement::StructureDefinition(inner) => inner.position, - Statement::TypeAssignment(inner) => inner.position, + Statement::TypeAlias(inner) => inner.position, + Statement::EnumDeclaration(inner) => inner.position, Statement::While(inner) => inner.position, } } @@ -68,8 +70,9 @@ impl Evaluate for Statement { Statement::StructureDefinition(structure_definition) => { structure_definition.node.validate(_context, _manage_memory) } - Statement::TypeAssignment(type_alias) => { - type_alias.node.validate(_context, _manage_memory) + Statement::TypeAlias(type_alias) => type_alias.node.validate(_context, _manage_memory), + Statement::EnumDeclaration(type_declaration) => { + type_declaration.node.validate(_context, _manage_memory) } Statement::While(r#while) => r#while.node.validate(_context, _manage_memory), } @@ -91,7 +94,8 @@ impl Evaluate for Statement { Statement::StructureDefinition(structure_definition) => { structure_definition.node.evaluate(context, manage_memory) } - Statement::TypeAssignment(type_alias) => { + Statement::TypeAlias(type_alias) => type_alias.node.evaluate(context, manage_memory), + Statement::EnumDeclaration(type_alias) => { type_alias.node.evaluate(context, manage_memory) } Statement::While(r#while) => r#while.node.evaluate(context, manage_memory), diff --git a/dust-lang/src/abstract_tree/type.rs b/dust-lang/src/abstract_tree/type.rs index 0faeb32..273d7ea 100644 --- a/dust-lang/src/abstract_tree/type.rs +++ b/dust-lang/src/abstract_tree/type.rs @@ -16,6 +16,7 @@ pub enum Type { Any, Boolean, Enum { + name: Identifier, type_parameters: Option>, variants: Vec<(Identifier, Option>)>, }, diff --git a/dust-lang/src/abstract_tree/type_assignment.rs b/dust-lang/src/abstract_tree/type_alias.rs similarity index 92% rename from dust-lang/src/abstract_tree/type_assignment.rs rename to dust-lang/src/abstract_tree/type_alias.rs index 4ed0ddb..691c1aa 100644 --- a/dust-lang/src/abstract_tree/type_assignment.rs +++ b/dust-lang/src/abstract_tree/type_alias.rs @@ -9,12 +9,12 @@ use crate::{ use super::{Evaluate, Evaluation, TypeConstructor, WithPosition}; #[derive(Clone, Debug, Eq, PartialEq, PartialOrd, Ord, Serialize, Deserialize)] -pub struct TypeAssignment { +pub struct TypeAlias { identifier: WithPosition, constructor: TypeConstructor, } -impl TypeAssignment { +impl TypeAlias { pub fn new(identifier: WithPosition, constructor: TypeConstructor) -> Self { Self { identifier, @@ -23,7 +23,7 @@ impl TypeAssignment { } } -impl Evaluate for TypeAssignment { +impl Evaluate for TypeAlias { fn validate(&self, context: &mut Context, _manage_memory: bool) -> Result<(), ValidationError> { let r#type = self.constructor.clone().construct(&context)?; diff --git a/dust-lang/src/abstract_tree/type_constructor.rs b/dust-lang/src/abstract_tree/type_constructor.rs index e78e7b6..e108b6d 100644 --- a/dust-lang/src/abstract_tree/type_constructor.rs +++ b/dust-lang/src/abstract_tree/type_constructor.rs @@ -53,6 +53,7 @@ impl TypeConstructor { }; if let Type::Enum { + name, type_parameters, variants, } = invoked_type @@ -64,6 +65,7 @@ impl TypeConstructor { } Type::Enum { + name, type_parameters: type_parameters.clone(), variants: mapped_variants, } @@ -73,6 +75,7 @@ impl TypeConstructor { } TypeConstructor::Enum(enum_type_constructor) => { let EnumTypeConstructor { + name, type_parameters, variants, } = enum_type_constructor.node; @@ -95,6 +98,7 @@ impl TypeConstructor { } Type::Enum { + name: name.node, type_parameters: type_parameters.map(|identifiers| { identifiers .into_iter() @@ -165,6 +169,7 @@ impl Display for TypeConstructor { #[derive(Clone, Debug, Eq, PartialEq, PartialOrd, Ord, Serialize, Deserialize)] pub struct EnumTypeConstructor { + pub name: WithPosition, pub type_parameters: Option>>, pub variants: Vec<(WithPosition, Option>)>, } diff --git a/dust-lang/src/parser.rs b/dust-lang/src/parser.rs index 4c3f396..beb061a 100644 --- a/dust-lang/src/parser.rs +++ b/dust-lang/src/parser.rs @@ -9,7 +9,7 @@ use crate::{ lexer::{Control, Keyword, Operator, Token}, }; -use self::type_constructor::TypeInvokationConstructor; +use self::{enum_declaration::EnumVariant, type_constructor::TypeInvokationConstructor}; pub type ParserInput<'src> = SpannedInput, SimpleSpan, &'src [(Token<'src>, SimpleSpan)]>; @@ -149,51 +149,6 @@ pub fn parser<'src>( TypeConstructor::ListOf(Box::new(item_type).with_position(state.span())) }); - let enum_variant = positioned_identifier.clone().then( - type_constructor - .clone() - .separated_by(just(Token::Control(Control::Comma))) - .collect() - .delimited_by( - just(Token::Control(Control::ParenOpen)), - just(Token::Control(Control::ParenClose)), - ) - .or_not(), - ); - - let enum_type = just(Token::Keyword(Keyword::Enum)) - .ignore_then( - positioned_identifier - .clone() - .separated_by(just(Token::Control(Control::Comma))) - .collect() - .delimited_by( - just(Token::Control(Control::Pipe)), - just(Token::Control(Control::Pipe)), - ) - .or_not(), - ) - .then( - enum_variant - .separated_by(just(Token::Control(Control::Comma))) - .at_least(1) - .allow_trailing() - .collect() - .delimited_by( - just(Token::Control(Control::CurlyOpen)), - just(Token::Control(Control::CurlyClose)), - ), - ) - .map_with(|(type_parameters, variants), state| { - TypeConstructor::Enum( - EnumTypeConstructor { - type_parameters, - variants, - } - .with_position(state.span()), - ) - }); - let type_invokation = positioned_identifier .clone() .then( @@ -222,7 +177,6 @@ pub fn parser<'src>( list_type, list_of_type, primitive_type, - enum_type, )) }); @@ -709,13 +663,64 @@ pub fn parser<'src>( }, ); - let type_assignment = just(Token::Keyword(Keyword::Type)) + let type_alias = just(Token::Keyword(Keyword::Type)) .ignore_then(positioned_identifier.clone()) .then_ignore(just(Token::Operator(Operator::Assign))) .then(type_constructor.clone()) .map_with(|(identifier, constructor), state| { - Statement::TypeAssignment( - TypeAssignment::new(identifier, constructor).with_position(state.span()), + Statement::TypeAlias( + TypeAlias::new(identifier, constructor).with_position(state.span()), + ) + }); + + let enum_variant = positioned_identifier + .clone() + .then( + type_constructor + .clone() + .separated_by(just(Token::Control(Control::Comma))) + .collect() + .delimited_by( + just(Token::Control(Control::ParenOpen)), + just(Token::Control(Control::ParenClose)), + ) + .or_not(), + ) + .map(|(identifier, constructors)| EnumVariant { + name: identifier, + content: constructors, + }); + + let enum_declaration = just(Token::Keyword(Keyword::Enum)) + .ignore_then(positioned_identifier.clone()) + .then( + positioned_identifier + .clone() + .separated_by(just(Token::Control(Control::Comma))) + .collect() + .delimited_by( + just(Token::Operator(Operator::Less)), + just(Token::Operator(Operator::Greater)), + ) + .or_not(), + ) + .then( + enum_variant + .separated_by(just(Token::Control(Control::Comma))) + .collect() + .delimited_by( + just(Token::Control(Control::CurlyOpen)), + just(Token::Control(Control::CurlyClose)), + ), + ) + .map_with(|((name, type_parameters), variants), state| { + Statement::EnumDeclaration( + EnumDeclaration { + name, + type_parameters, + variants, + } + .with_position((0, 0)), ) }); @@ -731,7 +736,8 @@ pub fn parser<'src>( block_statement, r#loop, r#while, - type_assignment, + type_alias, + enum_declaration, ))) .then_ignore(just(Token::Control(Control::Semicolon)).or_not()) }); @@ -741,6 +747,8 @@ pub fn parser<'src>( #[cfg(test)] mod tests { + use tests::enum_declaration::{EnumDeclaration, EnumVariant}; + use crate::lexer::lex; use super::*; @@ -793,103 +801,88 @@ mod tests { } #[test] - fn enum_type_empty() { + fn enum_declaration() { assert_eq!( - parse(&lex("type MyEnum = enum { X, Y }").unwrap()).unwrap()[0], - Statement::TypeAssignment( - TypeAssignment::new( - Identifier::new("MyEnum").with_position((5, 11)), - TypeConstructor::Enum( - EnumTypeConstructor { - type_parameters: None, - variants: vec![ - (Identifier::new("X").with_position((21, 22)), None), - (Identifier::new("Y").with_position((24, 25)), None) - ], + parse(&lex("enum MyEnum { X, Y }").unwrap()).unwrap()[0], + Statement::EnumDeclaration(TypeDeclaration::Enum( + EnumDeclaration { + name: Identifier::new("MyEnum").with_position((0, 0)), + type_parameters: None, + variants: vec![ + EnumVariant { + name: Identifier::new("X").with_position((0, 0)), + content: None + }, + EnumVariant { + name: Identifier::new("Y").with_position((0, 0)), + content: None } - .with_position((14, 27)) - ) - ) - .with_position((0, 27)) - ) + ], + } + .with_position((0, 0)) + )) ); } #[test] - fn enum_type_with_contents() { + fn enum_with_contents() { assert_eq!( - parse(&lex("type MyEnum = enum { X(str, int), Y(int) }").unwrap()).unwrap()[0], - Statement::TypeAssignment( - TypeAssignment::new( - Identifier::new("MyEnum").with_position((5, 11)), - TypeConstructor::Enum( - EnumTypeConstructor { - type_parameters: None, - variants: vec![ - ( - Identifier::new("X").with_position((21, 22)), - Some(vec![ - TypeConstructor::Raw(Type::String.with_position((23, 26))), - TypeConstructor::Raw(Type::Integer.with_position((28, 31))) - ]) - ), - ( - Identifier::new("Y").with_position((34, 35)), - Some(vec![TypeConstructor::Raw( - Type::Integer.with_position((36, 39)) - )]) - ) - ], + parse(&lex("enum MyEnum { X(str, int), Y(int) }").unwrap()).unwrap()[0], + Statement::EnumDeclaration(TypeDeclaration::Enum( + EnumDeclaration { + name: Identifier::new("MyEnum").with_position((0, 0)), + type_parameters: None, + variants: vec![ + EnumVariant { + name: Identifier::new("X").with_position((0, 0)), + content: Some(vec![ + TypeConstructor::Raw(Type::String.with_position((0, 0))), + TypeConstructor::Raw(Type::Integer.with_position((0, 0))), + ]) + }, + EnumVariant { + name: Identifier::new("Y").with_position((0, 0)), + content: Some(vec![TypeConstructor::Raw( + Type::Integer.with_position((0, 0)) + ),]) } - .with_position((14, 42)) - ) - ) - .with_position((0, 42)) - ) + ] + } + .with_position((0, 0)) + )) ); } #[test] - fn enum_type_with_type_parameters() { + fn enum_with_type_parameters() { assert_eq!( - parse(&lex("type MyEnum = enum |T, U| { X(T), Y(U) }").unwrap()).unwrap()[0], - Statement::TypeAssignment( - TypeAssignment::new( - Identifier::new("MyEnum").with_position((5, 11)), - TypeConstructor::Enum( - EnumTypeConstructor { - type_parameters: Some(vec![ - Identifier::new("T").with_position((20, 21)), - Identifier::new("U").with_position((23, 24)), - ]), - variants: vec![ - ( - Identifier::new("X").with_position((28, 29)), - Some(vec![TypeConstructor::Invokation( - TypeInvokationConstructor { - identifier: Identifier::new("T") - .with_position((30, 31)), - type_arguments: None, - } - )]) - ), - ( - Identifier::new("Y").with_position((34, 35)), - Some(vec![TypeConstructor::Invokation( - TypeInvokationConstructor { - identifier: Identifier::new("U") - .with_position((36, 37)), - type_arguments: None, - } - )]) - ), - ], + parse(&lex("enum MyEnum { X(T), Y(U) }").unwrap()).unwrap()[0], + Statement::EnumDeclaration(TypeDeclaration::Enum( + EnumDeclaration { + name: Identifier::new("MyEnum").with_position((0, 0)), + type_parameters: Some(vec![ + Identifier::new("T").with_position((0, 0)), + Identifier::new("U").with_position((0, 0)) + ]), + variants: vec![ + EnumVariant { + name: Identifier::new("X").with_position((0, 0)), + content: Some(vec![TypeConstructor::Raw( + Type::Generic { + identifier: Identifier::new("T"), + concrete_type: None + } + .with_position((0, 0)) + )]) + }, + EnumVariant { + name: todo!(), + content: todo!() } - .with_position((14, 40)) - ) - ) - .with_position((0, 40)) - ) + ] + } + .with_position((0, 0)) + )) ); } @@ -960,20 +953,6 @@ mod tests { // ) // } - #[test] - fn type_alias() { - assert_eq!( - parse(&lex("type MyType = str").unwrap()).unwrap()[0], - Statement::TypeAssignment( - TypeAssignment::new( - Identifier::new("MyType").with_position((5, 11)), - TypeConstructor::Raw(Type::String.with_position((14, 17))) - ) - .with_position((0, 17)) - ) - ) - } - #[test] fn r#as() { assert_eq!( @@ -1191,28 +1170,26 @@ mod tests { fn function_type() { assert_eq!( parse(&lex("type Foo = fn |T| (int) -> T").unwrap()).unwrap()[0], - Statement::TypeAssignment( - TypeAssignment::new( - Identifier::new("Foo").with_position((5, 8)), + Statement::TypeAlias( + TypeAlias::new( + Identifier::new("Foo").with_position((0, 0)), TypeConstructor::Function( FunctionTypeConstructor { - type_parameters: Some(vec![ - Identifier::new("T").with_position((15, 16)) - ]), + type_parameters: Some(vec![Identifier::new("T").with_position((0, 0))]), value_parameters: vec![TypeConstructor::Raw( - Type::Integer.with_position((19, 22)) + Type::Integer.with_position((0, 0)) )], return_type: Box::new(TypeConstructor::Invokation( TypeInvokationConstructor { - identifier: Identifier::new("T").with_position((27, 28)), - type_arguments: None, + identifier: Identifier::new("T").with_position((0, 0)), + type_arguments: None } - )), + )) } - .with_position((11, 28)) + .with_position((0, 0)) ) ) - .with_position((0, 28)) + .with_position((0, 0)) ) ); }