diff --git a/crates/concrete_ast/src/enums.rs b/crates/concrete_ast/src/enums.rs new file mode 100644 index 0000000..a24e433 --- /dev/null +++ b/crates/concrete_ast/src/enums.rs @@ -0,0 +1,29 @@ +use crate::{ + common::{GenericParam, Ident, Span}, + expressions::Expression, + structs::Field, +}; + +#[derive(Clone, Debug, Eq, PartialEq)] +pub struct UnionDecl { + pub name: Ident, + pub generics: Vec, + pub variants: Vec, + pub span: Span, +} + +#[derive(Clone, Debug, Eq, PartialEq)] +pub struct EnumDecl { + pub name: Ident, + pub generics: Vec, + pub variants: Vec, + pub span: Span, +} + +#[derive(Clone, Debug, Eq, PartialEq)] +pub struct EnumVariant { + pub name: Ident, + pub fields: Vec, + pub discriminant: Option, + pub span: Span, +} diff --git a/crates/concrete_ast/src/lib.rs b/crates/concrete_ast/src/lib.rs index 5b0224a..1752da9 100644 --- a/crates/concrete_ast/src/lib.rs +++ b/crates/concrete_ast/src/lib.rs @@ -4,6 +4,7 @@ use modules::Module; pub mod common; pub mod constants; +pub mod enums; pub mod expressions; pub mod functions; pub mod imports; diff --git a/crates/concrete_ast/src/modules.rs b/crates/concrete_ast/src/modules.rs index c9d1c3a..490c966 100644 --- a/crates/concrete_ast/src/modules.rs +++ b/crates/concrete_ast/src/modules.rs @@ -1,6 +1,7 @@ use crate::{ common::{DocString, Ident, Span}, constants::ConstantDef, + enums::{EnumDecl, UnionDecl}, functions::{FunctionDecl, FunctionDef}, imports::ImportStmt, structs::StructDecl, @@ -22,6 +23,8 @@ pub enum ModuleDefItem { Function(FunctionDef), FunctionDecl(FunctionDecl), Struct(StructDecl), + Union(UnionDecl), + Enum(EnumDecl), Type(TypeDecl), Module(Module), } diff --git a/crates/concrete_ir/src/lowering.rs b/crates/concrete_ir/src/lowering.rs index 9cee0ba..6cf620e 100644 --- a/crates/concrete_ir/src/lowering.rs +++ b/crates/concrete_ir/src/lowering.rs @@ -168,6 +168,8 @@ fn lower_module(mut ctx: BuildCtx, module: &Module, id: DefId) -> Result { /* already processed */ } + ModuleDefItem::Union(_) => todo!(), + ModuleDefItem::Enum(_) => todo!(), ModuleDefItem::FunctionDecl(fn_decl) => { ctx = lower_func_decl(ctx, fn_decl, id)?; } diff --git a/crates/concrete_ir/src/lowering/prepass.rs b/crates/concrete_ir/src/lowering/prepass.rs index b03e2b9..c1e60b0 100644 --- a/crates/concrete_ir/src/lowering/prepass.rs +++ b/crates/concrete_ir/src/lowering/prepass.rs @@ -95,6 +95,8 @@ pub fn prepass_module( .insert(info.name.name.clone(), next_id); current_module.modules.insert(next_id); } + ast::modules::ModuleDefItem::Union(_) => todo!(), + ast::modules::ModuleDefItem::Enum(_) => todo!(), ast::modules::ModuleDefItem::FunctionDecl(info) => { let next_id = gen.next_defid(); current_module @@ -210,6 +212,8 @@ pub fn prepass_sub_module( .insert(info.name.name.clone(), next_id); submodule.modules.insert(next_id); } + ast::modules::ModuleDefItem::Union(_) => todo!(), + ast::modules::ModuleDefItem::Enum(_) => todo!(), ast::modules::ModuleDefItem::FunctionDecl(info) => { let next_id = gen.next_defid(); submodule diff --git a/crates/concrete_parser/src/grammar.lalrpop b/crates/concrete_parser/src/grammar.lalrpop index ea0c008..3b40d96 100644 --- a/crates/concrete_parser/src/grammar.lalrpop +++ b/crates/concrete_parser/src/grammar.lalrpop @@ -18,6 +18,8 @@ extern { "fn" => Token::KeywordFn, "return" => Token::KeywordReturn, "struct" => Token::KeywordStruct, + "union" => Token::KeywordUnion, + "enum" => Token::KeywordEnum, "if" => Token::KeywordIf, "else" => Token::KeywordElse, "while" => Token::KeywordWhile, @@ -243,6 +245,12 @@ pub(crate) ModuleDefItem: ast::modules::ModuleDefItem = { => { ast::modules::ModuleDefItem::Struct(<>) }, + => { + ast::modules::ModuleDefItem::Union(<>) + }, + => { + ast::modules::ModuleDefItem::Enum(<>) + }, => { ast::modules::ModuleDefItem::Function(<>) }, @@ -328,6 +336,35 @@ pub(crate) StructDef: ast::structs::StructDecl = { } } + +pub(crate) UnionDef: ast::enums::UnionDecl = { + "union" "{" > "}" => ast::enums::UnionDecl { + name, + variants, + generics: generics.unwrap_or(vec![]), + span: Span::new(lo, hi), + } +} + +pub(crate) EnumDef: ast::enums::EnumDecl = { + "enum" "{" > "}" => ast::enums::EnumDecl { + name, + variants, + generics: generics.unwrap_or(vec![]), + span: Span::new(lo, hi), + } +} + + +pub(crate) EnumVariant: ast::enums::EnumVariant = { + > "}")?> )?> => ast::enums::EnumVariant { + name, + fields: fields.unwrap_or_default(), + discriminant, + span: Span::new(lo, hi), + } +} + pub(crate) StructInitField: (ast::common::Ident, ast::expressions::StructInitField) = { ":" => (name, ast::expressions::StructInitField { value, diff --git a/crates/concrete_parser/src/lib.rs b/crates/concrete_parser/src/lib.rs index 12796b3..3108b09 100644 --- a/crates/concrete_parser/src/lib.rs +++ b/crates/concrete_parser/src/lib.rs @@ -156,6 +156,26 @@ mod ModuleName { parser.parse(lexer).unwrap(); } + #[test] + fn parse_union_declaration() { + let source = r##"mod MyMod { + union Foo { + bar: i32, + baz: i64, + } + + fn main() -> i32 { + let mut foo: Foo = Foo { bar: 1 }; + + // unsafe! + let bar: i32 = foo.bar; + } +}"##; + let lexer = Lexer::new(source); + let parser = grammar::ProgramParser::new(); + parser.parse(lexer).unwrap(); + } + #[test] fn parse_for() { let source = r##"mod MyMod { @@ -174,6 +194,24 @@ mod ModuleName { parser.parse(lexer).unwrap(); } + #[test] + fn parse_enum() { + let source = r##"mod MyMod { + enum Foo { + Bar, + Baz { n1: i32, n2: i32 }, + Qux = 3, + } + + fn main() -> i32 { + let mut foo: Foo = Foo.Bar; + } +}"##; + let lexer = Lexer::new(source); + let parser = grammar::ProgramParser::new(); + parser.parse(lexer).unwrap(); + } + #[test] fn parse_for_while() { let source = r##"mod MyMod { diff --git a/crates/concrete_parser/src/tokens.rs b/crates/concrete_parser/src/tokens.rs index 3ee265c..4b1326c 100644 --- a/crates/concrete_parser/src/tokens.rs +++ b/crates/concrete_parser/src/tokens.rs @@ -33,6 +33,10 @@ pub enum Token { KeywordReturn, #[token("struct")] KeywordStruct, + #[token("union")] + KeywordUnion, + #[token("enum")] + KeywordEnum, #[token("if")] KeywordIf, #[token("else")] diff --git a/examples/enum.con b/examples/enum.con new file mode 100644 index 0000000..1f3e187 --- /dev/null +++ b/examples/enum.con @@ -0,0 +1,17 @@ +mod EnumExample { + enum Foo { + Bar, + Baz { n1: i32, n2: i32 }, + Qux = 3, + } + + fn main() -> i32 { + let mut foo: Foo = Foo.Bar; + + match foo { + Foo.Bar -> return 1;, + Foo.Baz -> return 2;, + Foo.Qux -> return 3;, + } + } +} diff --git a/examples/union.con b/examples/union.con new file mode 100644 index 0000000..2c7d8f5 --- /dev/null +++ b/examples/union.con @@ -0,0 +1,13 @@ +mod UnionExample { + union Foo { + bar: i32, + baz: i64, + } + + fn main() -> i32 { + let mut foo: Foo = Foo { bar: 1 }; + + // unsafe! + let bar: i32 = foo.bar; + } +}