From 23017188ee906ecc0292d2fab8fb8d24ea9f913f Mon Sep 17 00:00:00 2001 From: Chris Date: Fri, 29 Nov 2024 22:51:00 -0600 Subject: [PATCH 1/3] adding enum and others --- ast/src/lib.rs | 28 ++++++++++++++++++++++++++++ bootstrap/token/lib.ty | 8 +++++++- ebnf.txt | 24 +++++++++++++----------- parser/src/lib.rs | 29 +++++++++++++++++++++++++++-- token/src/lib.rs | 6 ++++++ 5 files changed, 81 insertions(+), 14 deletions(-) diff --git a/ast/src/lib.rs b/ast/src/lib.rs index 0056f7c..2a091a5 100644 --- a/ast/src/lib.rs +++ b/ast/src/lib.rs @@ -283,6 +283,33 @@ impl TagDecl { } } +#[derive(Debug, Clone, PartialEq)] +pub struct EnumDecl { + pub visibility: Option, + pub mutability: Lexeme, + pub identifier: Box, + pub declarators: Vec>, + pub variant: Option>, +} + +impl EnumDecl { + pub fn new( + visibility: Option, + mutability: Lexeme, + identifier: Box, + declarators: Vec>, + variant: Option>, + ) -> Self { + EnumDecl { + visibility, + mutability, + identifier, + declarators, + variant, + } + } +} + #[derive(Debug, Clone, PartialEq)] pub struct ErrorDecl { pub visibility: Option, @@ -640,6 +667,7 @@ pub enum Expr { StructDecl(StructDecl), ErrorDecl(ErrorDecl), TagDecl(TagDecl), + EnumDecl(EnumDecl), InnerDecl(InnerDecl), TopDecl(TopDecl), Reassignment(Reassignment), diff --git a/bootstrap/token/lib.ty b/bootstrap/token/lib.ty index a51e3bd..b78d2b7 100644 --- a/bootstrap/token/lib.ty +++ b/bootstrap/token/lib.ty @@ -2,7 +2,7 @@ pub type TokenError = error | InvalidToken | UnexpectedEnd -pub type Token = tag +pub type Token = enum(u16) { | Error | Defer | ErrDefer @@ -77,6 +77,9 @@ pub type Token = tag | TypeOf | InstanceOf | RangeOf + | Enum + | Try + | Catch // end keywords | Split | Yield @@ -215,6 +218,9 @@ const keywords: [[char]] = [ "typeof", "instanceof", "rangeof", + "enum", + "try", + "catch", ] pub const get_next = fn(buf: &[char], len: *u32) TokenError!Token { diff --git a/ebnf.txt b/ebnf.txt index 493ccc3..86287d5 100644 --- a/ebnf.txt +++ b/ebnf.txt @@ -1,21 +1,22 @@ // use this to test, and this must pass at all times // https://bnfplayground.pauliankline.com/ - ::= ()* - ::= "pub "? ("const " | "let " | "type " | "impl ") (":" )? "= " ( | | | | | | | ) + ::= ()* + ::= "pub "? ("const " | "let " | "type " | "impl ") (":" )? " = " ( | | | | | | | | ) ::= "import " - ::= "trait" - ::= | ("const" | "let")? ("&" | "*")? ("[" "]" | ("." )* | ) + ::= "trait " "{ " ( ::= | ("&" | "*")? ("[" "]" | ("." )* | ) ::= "fn" "(" ")" ("void" | ) ::= ( ("," )*)? ::= ("self " (":" )?) | ::= "fn " "(" ? ") " ::= "struct " "{ " ? "}" - ::= "error " "{" "}" - ::= "if " "(" ")" ( | ) ("else " )? + ::= "error " ("| " )+ + ::= "if " "(" ")" ( | ) ("else if "(" ")" )* ("else " )? ::= "for " "(" ")" ( | ) ::= "match " "(" ")" "{ " + "}" ::= "=> " ( | ) - ::= "tag " ("| " (":" )? ("=" )?)+ + ::= "tag " ("| " (":" )??)+ + ::= "enum" "(" ")" ("| " ("=" )?)+ ::= ()* ::= "pub "? (":" )? ::= ( ("," )*)? @@ -31,10 +32,11 @@ ::= (("!= " | "== ") )* ::= ((">" | ">=" | "<" | "<=") )* ::= (("+" | "-") )* - ::= (("*" | "/" | ".." | "%") )* - ::= (("!" | "-" | "&" | "*") ) | + ::= (("*" | "/" | ".." | "%" | "as") )* + ::= (("defer" | "try" | "errdefer" | "!" | "-" | "&" | "*") ) | ::= "[" ( ("," )*)? "]" - ::= ("?" | "!" | | | | )* + ::= ("?" | "!" | | | | | )* + ::= "catch" "(" ? ")" ::= "[" "]" ::= "." ::= "(" ( ("," )*)? ")" @@ -46,4 +48,4 @@ ::= "\"" [a-z]* "\"" ::= "i32" | "u32" | "i64" | "u64" | "i16" | "u16" | "u8" | "i8" | "bit" | "f64" | "d64" | "f32" | "d32" | "d128" | "f128" | "isize" | "usize" | "char" | "bool" | "any" | "scalar" | "utf8" | "utf16" | "utf32" | "utf64" | "sized" // illegal ebnf but actual implementation - ::= #[regex(r#""([^"\\]|\\t|\\u|\\n|\\")*""#)n + ::= #[regex(r#""([^"\\]|\\t|\\u|\\n|\\")*""#)] diff --git a/parser/src/lib.rs b/parser/src/lib.rs index afa694b..8318cbd 100644 --- a/parser/src/lib.rs +++ b/parser/src/lib.rs @@ -49,7 +49,7 @@ impl<'s> Parser<'s> { .xresult_or(|expr| result_expr!(Import, mutability, identifier, expr)) } - pub fn tag( + pub fn _tag( &mut self, visibility: Option, mutability: Lexeme, @@ -82,6 +82,29 @@ impl<'s> Parser<'s> { result_expr!(ErrorDecl, visibility, mutability, identifier, sig) } + pub fn _enum( + &mut self, + visibility: Option, + mutability: Lexeme, + identifier: Box, + sig: Option>, + ) -> ResultExpr { + let mut variants: Vec> = vec![]; + let oparen = self.lexer.collect_if(Token::OParen); + if oparen.is_some() { + let enum_type = self.val_type(); + let _ = self + .lexer + .collect_if(Token::CParen) + .xexpect_token(&self, "expected ')'".to_string())?; + } + while let Some(_) = self.lexer.collect_if(Token::Bar) { + let x = self.ident().xconvert_to_sym_decl()?; + variants.push(x); + } + result_expr!(TagDecl, visibility, mutability, identifier, variants, sig) + } + pub fn _struct( &mut self, visibility: Option, @@ -123,14 +146,16 @@ impl<'s> Parser<'s> { Token::Import, Token::Tag, Token::Error, + Token::Enum, ]) { match val.token { Token::Struct => return self._struct(has_pub, mutability, identifier, sig), Token::Func => return self._fn(has_pub, mutability, identifier, sig), Token::Import => return self._import(mutability, identifier), - Token::Tag => return self.tag(has_pub, mutability, identifier, sig), + Token::Tag => return self._tag(has_pub, mutability, identifier, sig), Token::Trait => return self._trait(has_pub, mutability, identifier, sig), Token::Error => return self._error(has_pub, mutability, identifier, sig), + Token::Enum => return self._enum(has_pub, mutability, identifier, sig), _ => panic!("type-lang error unreachable code hit"), } } diff --git a/token/src/lib.rs b/token/src/lib.rs index c915aae..d0dfd66 100644 --- a/token/src/lib.rs +++ b/token/src/lib.rs @@ -150,6 +150,12 @@ pub enum Token { InstanceOf, #[token("rangeof")] RangeOf, + #[token("enum")] + Enum, + #[token("try")] + Try, + #[token("catch")] + Catch, #[token("|>")] Split, From f570486ec4bf171c9cb4e9b4fc800b2579d95552 Mon Sep 17 00:00:00 2001 From: Chris Date: Sat, 30 Nov 2024 15:32:10 -0600 Subject: [PATCH 2/3] todo is up-to-date --- ast/src/lib.rs | 21 +++++++++++++++++++++ ebnf.txt | 9 +++++---- parser/src/lib.rs | 37 ++++++++++++++++++++++++++++++++----- todos.txt | 6 ++++++ 4 files changed, 64 insertions(+), 9 deletions(-) diff --git a/ast/src/lib.rs b/ast/src/lib.rs index 2a091a5..930c814 100644 --- a/ast/src/lib.rs +++ b/ast/src/lib.rs @@ -289,6 +289,7 @@ pub struct EnumDecl { pub mutability: Lexeme, pub identifier: Box, pub declarators: Vec>, + pub sig: Option>, pub variant: Option>, } @@ -298,6 +299,7 @@ impl EnumDecl { mutability: Lexeme, identifier: Box, declarators: Vec>, + sig: Option>, variant: Option>, ) -> Self { EnumDecl { @@ -305,6 +307,7 @@ impl EnumDecl { mutability, identifier, declarators, + sig, variant, } } @@ -391,6 +394,23 @@ impl TraitDecl { } } +#[derive(Debug, Clone, PartialEq)] +pub struct CatchDecl { + pub args: Option>>, + pub ret_typ: Box, + pub block: Box, +} + +impl CatchDecl { + pub fn new(args: Option>>, ret_typ: Box, block: Box) -> Self { + CatchDecl { + args, + ret_typ, + block, + } + } +} + #[derive(Debug, Clone, PartialEq)] pub struct AnonFuncDecl { pub args: Option>>, @@ -661,6 +681,7 @@ pub enum Expr { Symbol(Symbol), SymbolDecl(Symbol), AnonFuncDecl(AnonFuncDecl), + CatchDecl(CatchDecl), FuncDecl(FuncDecl), SelfDecl(SelfKeyword), TraitDecl(TraitDecl), diff --git a/ebnf.txt b/ebnf.txt index 86287d5..3d78ea0 100644 --- a/ebnf.txt +++ b/ebnf.txt @@ -11,11 +11,12 @@ ::= "fn " "(" ? ") " ::= "struct " "{ " ? "}" ::= "error " ("| " )+ - ::= "if " "(" ")" ( | ) ("else if "(" ")" )* ("else " )? + ::= "if " "(" ")" ( | ) ("else if "(" ")" ( | ))* ("else " ( | ))? ::= "for " "(" ")" ( | ) + ::= "while " "(" ")" ( | ) ::= "match " "(" ")" "{ " + "}" ::= "=> " ( | ) - ::= "tag " ("| " (":" )??)+ + ::= "tag " ("| " (":" )?)+ ::= "enum" "(" ")" ("| " ("=" )?)+ ::= ()* ::= "pub "? (":" )? @@ -23,7 +24,7 @@ ::= ("self " (": " )?) | (":" )? ::= ( "const " | "let ") (":" )? "= " ::= ("= " )? - ::= "{ " ( | | | )* ( | )? "}" + ::= "{ " ( | | | | )* ( | )? "}" ::= "return " ? ::= "break " ? ::= | | @@ -33,7 +34,7 @@ ::= ((">" | ">=" | "<" | "<=") )* ::= (("+" | "-") )* ::= (("*" | "/" | ".." | "%" | "as") )* - ::= (("defer" | "try" | "errdefer" | "!" | "-" | "&" | "*") ) | + ::= (("try" | "copy" | "clone" | "!" | "-" | "&" | "*") ) | ::= "[" ( ("," )*)? "]" ::= ("?" | "!" | | | | | )* ::= "catch" "(" ? ")" diff --git a/parser/src/lib.rs b/parser/src/lib.rs index 8318cbd..c92ff87 100644 --- a/parser/src/lib.rs +++ b/parser/src/lib.rs @@ -91,8 +91,8 @@ impl<'s> Parser<'s> { ) -> ResultExpr { let mut variants: Vec> = vec![]; let oparen = self.lexer.collect_if(Token::OParen); + let enum_type = self.val_type(); if oparen.is_some() { - let enum_type = self.val_type(); let _ = self .lexer .collect_if(Token::CParen) @@ -102,7 +102,7 @@ impl<'s> Parser<'s> { let x = self.ident().xconvert_to_sym_decl()?; variants.push(x); } - result_expr!(TagDecl, visibility, mutability, identifier, variants, sig) + result_expr!(EnumDecl, visibility, mutability, identifier, variants, sig, enum_type) } pub fn _struct( @@ -666,9 +666,10 @@ impl<'s> Parser<'s> { let lexeme = self.lexer.collect_of_if(&[ Token::Ampersand, Token::Asterisk, - Token::Exclam, Token::Dash, Token::Copy, + Token::Clone, + Token::Try, ]); if let Some(x) = lexeme { let expr = self.unary(); @@ -683,14 +684,15 @@ impl<'s> Parser<'s> { if let Some(x) = self.lexer.collect_of_if(&[ Token::Question, Token::Period, - Token::Tilde, + Token::Try, Token::OBracket, Token::OParen, Token::OBrace, + Token::Catch, ]) { match x.token { Token::Question => self.resolve_access(expr!(UndefBubble, prev)), - Token::Tilde => self.resolve_access(expr!(ErrBubble, prev)), + Token::Try => self.resolve_access(expr!(ErrBubble, prev)), Token::Period => { let ident = self .ident() @@ -698,6 +700,11 @@ impl<'s> Parser<'s> { self.resolve_access(expr!(PropAccess, prev, ident)) } + Token::Catch => { + let catch = self.catch(); + + self.resolve_access(expr!(PropAccess, prev, ident)) + } Token::OBracket => { let expr = self.array_access()?; self.resolve_access(expr!(ArrayAccess, expr, prev)) @@ -757,6 +764,26 @@ impl<'s> Parser<'s> { Ok(Some(prev)) } } + pub fn catch(&mut self) -> ResultExpr { + let _ = self + .lexer + .collect_if(Token::OParen) + .xexpect_token(&self, "expected one of '('".to_string())?; + let args = self.arg()?; + let ret_type = self + .sig_union() + .xexpect_expr(&self, "expected catch return type".to_string())?; + let _ = self + .lexer + .collect_if(Token::CParen) + .xexpect_token(&self, "expected one of ')'".to_string())?; + + let bl = self.block()?; + if args.is_some() { + return result_expr!(CatchDecl, Some(vec![args.unwrap()]), ret_type, bl); + } + return result_expr!(CatchDecl, None, ret_type, bl); + } pub fn access(&mut self) -> ResultOptExpr { let term = self.terminal()?; if let Some(t) = term { diff --git a/todos.txt b/todos.txt index 7afddec..30d5181 100644 --- a/todos.txt +++ b/todos.txt @@ -1,2 +1,8 @@ - data layout - scopes +- add while loop +- add for loop +- Bar '|' ebnf doesn't match parser, update parser for every '|' syntax +- check parser for implementing lambdas 'anon functions', on those that accept captures. + - arm, for, if, while +- "all function declarations must have types in arguments." this can be changed to support deducing types at some point From 44ead46891e9b56373b1e071db588840b6e43c85 Mon Sep 17 00:00:00 2001 From: Chris Date: Sat, 30 Nov 2024 22:19:49 -0600 Subject: [PATCH 3/3] updated syntax --- ast/src/lib.rs | 13 +++++++++++++ bootstrap/token/lib.ty | 2 +- ebnf.txt | 2 +- parser/src/lib.rs | 29 +++++++++++++++++++++++++---- todos.txt | 8 ++++---- 5 files changed, 44 insertions(+), 10 deletions(-) diff --git a/ast/src/lib.rs b/ast/src/lib.rs index 930c814..c8020f7 100644 --- a/ast/src/lib.rs +++ b/ast/src/lib.rs @@ -1,5 +1,17 @@ use lexer::Lexeme; +#[derive(Debug, Clone, PartialEq)] +pub struct While { + pub expr: Box, + pub var_loop: Box, +} + +impl While { + pub fn new(expr: Box, var_loop: Box) -> Self { + While { expr, var_loop } + } +} + #[derive(Debug, Clone, PartialEq)] pub struct For { pub expr: Box, @@ -664,6 +676,7 @@ pub enum Expr { ArrayDecl(ArrayDecl), Rest(Rest), For(For), + While(While), Match(Match), Arm(Arm), FileAll(FileAll), diff --git a/bootstrap/token/lib.ty b/bootstrap/token/lib.ty index b78d2b7..c4060da 100644 --- a/bootstrap/token/lib.ty +++ b/bootstrap/token/lib.ty @@ -2,7 +2,7 @@ pub type TokenError = error | InvalidToken | UnexpectedEnd -pub type Token = enum(u16) { +pub type Token = enum(u8) { | Error | Defer | ErrDefer diff --git a/ebnf.txt b/ebnf.txt index 3d78ea0..63bb5a3 100644 --- a/ebnf.txt +++ b/ebnf.txt @@ -36,7 +36,7 @@ ::= (("*" | "/" | ".." | "%" | "as") )* ::= (("try" | "copy" | "clone" | "!" | "-" | "&" | "*") ) | ::= "[" ( ("," )*)? "]" - ::= ("?" | "!" | | | | | )* + ::= ("?" | | | | )* ? ::= "catch" "(" ? ")" ::= "[" "]" ::= "." diff --git a/parser/src/lib.rs b/parser/src/lib.rs index c92ff87..5363770 100644 --- a/parser/src/lib.rs +++ b/parser/src/lib.rs @@ -452,6 +452,26 @@ impl<'s> Parser<'s> { let blk = self.block()?; return bubble_expr!(For, x, blk); } + pub fn _while(&mut self) -> ResultOptExpr { + let f = self.lexer.collect_if(Token::While); + if f.is_none() { + return Ok(None); + } + let _ = self + .lexer + .collect_if(Token::OParen) + .xexpect_token(&self, "expected '('".to_string())?; + let x = self.or()?; + let _ = self + .lexer + .collect_if(Token::CParen) + .xexpect_token(&self, "expected ')'".to_string())?; + if let Some(_fn) = self.anon_fn()? { + return bubble_expr!(While, x, _fn); + } + let blk = self.block()?; + return bubble_expr!(While, x, blk); + } pub fn _for(&mut self) -> ResultOptExpr { let f = self.lexer.collect_if(Token::For); if f.is_none() { @@ -486,7 +506,10 @@ impl<'s> Parser<'s> { Some(x) => exprs.push(x), None => match self._if()? { Some(x) => exprs.push(x), - None => break, + None => match self._while()? { + Some(x) => exprs.push(x), + None => break, + }, }, }, }, @@ -701,9 +724,7 @@ impl<'s> Parser<'s> { self.resolve_access(expr!(PropAccess, prev, ident)) } Token::Catch => { - let catch = self.catch(); - - self.resolve_access(expr!(PropAccess, prev, ident)) + return self.catch().xconvert_to_result_opt(); } Token::OBracket => { let expr = self.array_access()?; diff --git a/todos.txt b/todos.txt index 30d5181..e7d14fe 100644 --- a/todos.txt +++ b/todos.txt @@ -1,8 +1,8 @@ - data layout - scopes -- add while loop -- add for loop - Bar '|' ebnf doesn't match parser, update parser for every '|' syntax -- check parser for implementing lambdas 'anon functions', on those that accept captures. - - arm, for, if, while - "all function declarations must have types in arguments." this can be changed to support deducing types at some point +- impl +- destructuring +- rework import +- make types typey instead of values "function declarations" tags, enums, etc.