From e478ba500710a873accf4ce8fea717839aa53da4 Mon Sep 17 00:00:00 2001 From: Chris Date: Mon, 2 Dec 2024 22:59:59 -0600 Subject: [PATCH 1/5] working on impl and traits --- ast/src/lib.rs | 12 +++++++++ ebnf.txt | 2 +- parser/src/lib.rs | 69 ++++++++++++++++++++++++++++++----------------- playground.ty | 50 +++++++++++++++++----------------- todos.txt | 2 -- 5 files changed, 82 insertions(+), 53 deletions(-) diff --git a/ast/src/lib.rs b/ast/src/lib.rs index c8020f7..c1e8622 100644 --- a/ast/src/lib.rs +++ b/ast/src/lib.rs @@ -24,6 +24,17 @@ impl For { } } +#[derive(Debug, Clone, PartialEq)] +pub struct Destructure { + pub elements: Vec>, +} + +impl Destructure { + pub fn new(elements: Vec>) -> Self { + Destructure { elements } + } +} + #[derive(Debug, Clone, PartialEq)] pub struct Match { pub expr: Box, @@ -676,6 +687,7 @@ pub enum Expr { ArrayDecl(ArrayDecl), Rest(Rest), For(For), + Destructure(Destructure), While(While), Match(Match), Arm(Arm), diff --git a/ebnf.txt b/ebnf.txt index 63bb5a3..ec7dbdb 100644 --- a/ebnf.txt +++ b/ebnf.txt @@ -41,7 +41,7 @@ ::= "[" "]" ::= "." ::= "(" ( ("," )*)? ")" - ::= "{" ( ":" )* "}" + ::= "{" ( ":" ("," ":" ))? "}" ::= "_" | "true " | "false " | "undefined " | "self " | "never " | | | | | | "(" ")" ::= "fn " "(" ? ") " ::= ([a-z] | [A-Z]) ([A-Z] | [a-z] | [0-9] | "_")* diff --git a/parser/src/lib.rs b/parser/src/lib.rs index 5363770..813e7a9 100644 --- a/parser/src/lib.rs +++ b/parser/src/lib.rs @@ -58,7 +58,7 @@ impl<'s> Parser<'s> { ) -> ResultExpr { let mut variants: Vec> = vec![]; while let Some(_) = self.lexer.collect_if(Token::Bar) { - let x = self.ident().xconvert_to_sym_decl()?; + let x = self.ident().xconvert_to_decl()?; variants.push(x); } result_expr!(TagDecl, visibility, mutability, identifier, variants, sig) @@ -99,7 +99,7 @@ impl<'s> Parser<'s> { .xexpect_token(&self, "expected ')'".to_string())?; } while let Some(_) = self.lexer.collect_if(Token::Bar) { - let x = self.ident().xconvert_to_sym_decl()?; + let x = self.ident().xconvert_to_decl()?; variants.push(x); } result_expr!(EnumDecl, visibility, mutability, identifier, variants, sig, enum_type) @@ -131,9 +131,9 @@ impl<'s> Parser<'s> { .collect_of_if(&[Token::Let, Token::Const, Token::Type, Token::Impl]) .xexpect_token(&self, "expected mutability".to_string())?; let identifier = self - .ident() - .xexpect_expr(&self, "expected identifier".to_string()) - .xconvert_to_sym_decl()?; + .destructure() + .xexpect_expr(&self, "expected identifier, or destructure".to_string()) + .xconvert_to_decl()?; let sig = self.opt_signature()?; let _ = self .lexer @@ -266,7 +266,7 @@ impl<'s> Parser<'s> { let sig = self .opt_signature() .xexpect_expr(&self, "expected signature".to_string())?; - return result_expr!(Declarator, id.xconvert_to_sym_decl().unwrap(), sig) + return result_expr!(Declarator, id.xconvert_to_decl().unwrap(), sig) .xconvert_to_result_opt(); } pub fn args(&mut self) -> Result>>> { @@ -421,8 +421,9 @@ impl<'s> Parser<'s> { let mutability = self.lexer.collect_of_if(&[Token::Let, Token::Const]); if let Some(muta) = mutability { let identifier = self - .ident() - .xexpect_expr(&self, "expected an identifier".to_string())?; + .destructure() + .xexpect_expr(&self, "expected identifier, or destructure".to_string()) + .xconvert_to_decl()?; let sig = self.opt_signature()?; let _ = self .lexer @@ -492,6 +493,26 @@ impl<'s> Parser<'s> { let blk = self.block()?; return bubble_expr!(For, x, blk); } + pub fn destructure(&mut self) -> ResultOptExpr { + let brace = self.lexer.collect_if(Token::OBrace); + if brace.is_some() { + let mut idents: Vec> = vec![]; + loop { + match self.ident() { + Some(x) => { + idents.push(x); + } + None => break, + } + } + let _ = self + .lexer + .collect_if(Token::CBrace) + .xexpect_token(&self, "expected '}' or more identifiers".to_string())?; + return bubble_expr!(Destructure, idents); + } + return Ok(self.ident()); + } pub fn block(&mut self) -> ResultExpr { self.lexer .collect_if(Token::OBrace) @@ -996,12 +1017,12 @@ trait ConvertToResult { fn xconvert_to_result(self, parser: &Parser, title: String) -> ResultExpr; } -trait ConvertToSymbolDecl { - fn xconvert_to_sym_decl(self) -> ResultExpr; +trait ConvertToDecl { + fn xconvert_to_decl(self) -> ResultExpr; } -trait ConvertToSymbolDeclResult { - fn xconvert_to_sym_decl(self) -> ResultExpr; +trait ConvertToDeclResult { + fn xconvert_to_decl(self) -> ResultExpr; } trait ConvertToResultOpt { @@ -1077,22 +1098,25 @@ impl ExpectExpr for OptExpr { } } -impl ConvertToSymbolDeclResult for ResultExpr { - fn xconvert_to_sym_decl(self) -> ResultExpr { +impl ConvertToDeclResult for ResultExpr { + fn xconvert_to_decl(self) -> ResultExpr { match self { Err(x) => Err(x), Ok(val) => match *val { Expr::Symbol(x) => { return Ok(Box::new(Expr::SymbolDecl(x))); } + Expr::Declarator(_) => { + return Ok(val); + } _ => panic!("type lang issue, expected into symbol"), }, } } } -impl ConvertToSymbolDecl for OptExpr { - fn xconvert_to_sym_decl(self) -> ResultExpr { +impl ConvertToDecl for OptExpr { + fn xconvert_to_decl(self) -> ResultExpr { match self { None => panic!("type lang issue, expected a symbol"), Some(val) => match *val { @@ -1310,14 +1334,11 @@ mod tests { token: Token::Let, span: 2..5, }, - expr!( - Symbol, - Lexeme { - slice: String::from("x"), - token: Token::Symbol, - span: 6..7 - } - ), + Box::new(Expr::SymbolDecl(Symbol::new(Lexeme { + slice: String::from("x"), + token: Token::Symbol, + span: 6..7 + }))), None, expr!( Number, diff --git a/playground.ty b/playground.ty index 2dd31db..58b159a 100644 --- a/playground.ty +++ b/playground.ty @@ -1,42 +1,40 @@ -type Motorcycle = struct { +pub type Motorcycle = struct { name: [char], wheels: u8 } -type Car = struct { +// Data has a type. can be manually declared with : +const x = 7; +const y: usize = 7; + +// Types have types +// this is usually redundant +type Car: struct {[char],u8} = struct { name: [char], wheels: u8 } -// or make a props type -type Movable: struct {wheels: u8} = trait { - // linter will fail self without signature right now - fn set_wheels(self, wheels: u8) { - self.wheels = wheels - } - fn drive(self) { - } +// you can achieve polymorphism and generics with traits +type Movable = trait { + set_wheels: fn(self, wheels: u8) void, + drive: fn(self) void } -impl Movable: Car = self -impl Movable: Motorcycle = self +// you can then implement those traits +impl Car = trait(Movable) { + pub set_wheels = fn(self, wheels: u8) { + // do a thing! + } +} -let toyoba = Car { - name = "Toyoba" +// default implementations can be achieved +const set_wheels_default = fn(self, wheels: u8) void { + self.wheels = wheels; } -toyoba.set_wheels(4) -toyoba.drive() -let bonda = Motorcycle { - name = "Bonda" +// default implementation +impl Motorcycle = trait(Movable) { + pub set_wheels = set_wheels_default } -bonda.set_wheels(2) -bonda.drive() -const assert_wheels = fn(self: Movable) !void { - if (self.wheels == 0) { - return error {} - } - return -} diff --git a/todos.txt b/todos.txt index e7d14fe..8ce4406 100644 --- a/todos.txt +++ b/todos.txt @@ -3,6 +3,4 @@ - Bar '|' ebnf doesn't match parser, update parser for every '|' syntax - "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. From 0ffb4ea4e712394c66c5f6eee92f021f21937a68 Mon Sep 17 00:00:00 2001 From: Chris Date: Thu, 5 Dec 2024 15:16:55 -0600 Subject: [PATCH 2/5] finished destructure up to parsing --- parser/src/lib.rs | 5 +++-- test/test.ty | 3 +++ 2 files changed, 6 insertions(+), 2 deletions(-) diff --git a/parser/src/lib.rs b/parser/src/lib.rs index 813e7a9..315115b 100644 --- a/parser/src/lib.rs +++ b/parser/src/lib.rs @@ -500,7 +500,8 @@ impl<'s> Parser<'s> { loop { match self.ident() { Some(x) => { - idents.push(x); + idents.push(Box::new(Expr::SymbolDecl(x.into_symbol()))); + let _ = self.lexer.collect_if(Token::Comma); } None => break, } @@ -1106,7 +1107,7 @@ impl ConvertToDeclResult for ResultExpr { Expr::Symbol(x) => { return Ok(Box::new(Expr::SymbolDecl(x))); } - Expr::Declarator(_) => { + Expr::Destructure(_) => { return Ok(val); } _ => panic!("type lang issue, expected into symbol"), diff --git a/test/test.ty b/test/test.ty index 1be17e7..fb2e196 100644 --- a/test/test.ty +++ b/test/test.ty @@ -139,3 +139,6 @@ let t = { const mul2: fn(usize) usize = fn(a) usize { return a * 2 } + +// destructuring is supported +const { a, b, c } = import "std.thing" From 076d270d93a210a37e933201803c583a886d7dde Mon Sep 17 00:00:00 2001 From: Chris Date: Mon, 9 Dec 2024 12:52:32 -0600 Subject: [PATCH 3/5] switching computers --- ast/src/lib.rs | 31 +++++++++++++++++++++++++++++ parser/src/lib.rs | 3 ++- playground.ty | 50 ++++++++++++++++++++++++++++++++++++++++++++++- 3 files changed, 82 insertions(+), 2 deletions(-) diff --git a/ast/src/lib.rs b/ast/src/lib.rs index c1e8622..f12237d 100644 --- a/ast/src/lib.rs +++ b/ast/src/lib.rs @@ -24,6 +24,36 @@ impl For { } } +#[derive(Debug, Clone, PartialEq)] +pub struct IfChain { + pub if_expr: Box, + pub if_body: Box, + pub elseif_exprs: Vec>, + pub elseif_bodys: Vec>, + pub else_expr: Option>, + pub else_body: Option>, +} + +impl IfChain { + pub fn new( + if_expr: Box, + if_body: Box, + elseif_exprs: Vec>, + elseif_bodys: Vec>, + else_expr: Option>, + else_body: Option>, + ) -> Self { + IfChain { + if_expr, + if_body, + elseif_exprs, + elseif_bodys, + else_expr, + else_body, + } + } +} + #[derive(Debug, Clone, PartialEq)] pub struct Destructure { pub elements: Vec>, @@ -688,6 +718,7 @@ pub enum Expr { Rest(Rest), For(For), Destructure(Destructure), + IfChain(IfChain), While(While), Match(Match), Arm(Arm), diff --git a/parser/src/lib.rs b/parser/src/lib.rs index 315115b..6d7a5c9 100644 --- a/parser/src/lib.rs +++ b/parser/src/lib.rs @@ -441,6 +441,7 @@ impl<'s> Parser<'s> { if i.is_none() { return Ok(None); } + let mut chain = Box::new(IfChain::new( let _ = self .lexer .collect_if(Token::OParen) @@ -451,7 +452,7 @@ impl<'s> Parser<'s> { .collect_if(Token::CParen) .xexpect_token(&self, "expected ')'".to_string())?; let blk = self.block()?; - return bubble_expr!(For, x, blk); + return bubble_expr!(IfChain, x, blk); } pub fn _while(&mut self) -> ResultOptExpr { let f = self.lexer.collect_if(Token::While); diff --git a/playground.ty b/playground.ty index 58b159a..562d774 100644 --- a/playground.ty +++ b/playground.ty @@ -28,7 +28,7 @@ impl Car = trait(Movable) { } // default implementations can be achieved -const set_wheels_default = fn(self, wheels: u8) void { +pub const set_wheels_default = fn(self: Movable, wheels: u8) void { self.wheels = wheels; } @@ -37,4 +37,52 @@ impl Motorcycle = trait(Movable) { pub set_wheels = set_wheels_default } +// macro/comptime +type Newable = trait { + new: fn(var: any[]) self {} +} + +const add_new = macro(def: ident, var: any[]) { + impl def = trait(Newable) { + pub new = fn(expander(var)) { + return def { + dec_expand(var) + } + } + } +} + +const expander = macro(name: ident, sig: signature, var: any[]) { + name: sig, expander(var) +} + +const dec_expand = macro(name: ident, var: any[]) { + name: name, dec_expand(var) +} + +add_new(Motorcycle, name, [char], wheels, u8) +// this expands to. +impl Motorcycle = trait(Newable) { + pub new = fn(name: [char], wheels: u8) { + return Motorcycle { + name: name, + wheels: wheels, + } + } +} +// these macro expressions are provided in the standard library +// to implement, simply declare your structs type + +type MyThing = struct { + cool_string: [char] +} +// then call the compile time expansion macro +add_new(MyThing, cool_string, [char]) + +// comptime factorial +const factorial_table = comptime(name: ident, calculate: usize) { + const name = for (x in 0..calculate) { + return + } +} From 31a55630051ad41aa245b895f7e7ab6b08f5f163 Mon Sep 17 00:00:00 2001 From: Chris Date: Mon, 9 Dec 2024 13:08:03 -0600 Subject: [PATCH 4/5] switching computers again --- parser/src/lib.rs | 24 +++++++++++++++++++++--- 1 file changed, 21 insertions(+), 3 deletions(-) diff --git a/parser/src/lib.rs b/parser/src/lib.rs index 6d7a5c9..5498411 100644 --- a/parser/src/lib.rs +++ b/parser/src/lib.rs @@ -441,7 +441,6 @@ impl<'s> Parser<'s> { if i.is_none() { return Ok(None); } - let mut chain = Box::new(IfChain::new( let _ = self .lexer .collect_if(Token::OParen) @@ -451,8 +450,27 @@ impl<'s> Parser<'s> { .lexer .collect_if(Token::CParen) .xexpect_token(&self, "expected ')'".to_string())?; - let blk = self.block()?; - return bubble_expr!(IfChain, x, blk); + let mut _fn = self.anon_fn()?; + if _fn.is_none() { + _fn = Some(self.block()?); + } + let mut chain = Box::new(Expr::IfChain(IfChain::new( + x, + _fn.unwrap(), + vec![], + vec![], + None, + None, + ))); + + while let Some(elseif) = self.lexer.collect_if(Token::Else) { + args.push(self.or()?); + } + let i = self.lexer.collect_if(Token::If); + if i.is_none() { + return Ok(None); + } + return Ok(Some(chain)); } pub fn _while(&mut self) -> ResultOptExpr { let f = self.lexer.collect_if(Token::While); From d3d9aa19c3c576560da18af567fc1a7e9de10850 Mon Sep 17 00:00:00 2001 From: Chris Date: Mon, 9 Dec 2024 23:18:13 -0600 Subject: [PATCH 5/5] a little more playing, and syntax feeling better --- ast/src/lib.rs | 48 ++++++++++++-------------------- ebnf.txt | 2 +- linter/src/lib.rs | 14 ++++++++++ parser/src/lib.rs | 39 +++++++------------------- playground.ty | 70 +++++++++++++++++++++++++++++++++++++++++++++++ test/test.ty | 2 +- todos.txt | 3 +- types/src/lib.rs | 11 ++++++++ 8 files changed, 127 insertions(+), 62 deletions(-) diff --git a/ast/src/lib.rs b/ast/src/lib.rs index f12237d..eab4bcb 100644 --- a/ast/src/lib.rs +++ b/ast/src/lib.rs @@ -25,31 +25,16 @@ impl For { } #[derive(Debug, Clone, PartialEq)] -pub struct IfChain { - pub if_expr: Box, - pub if_body: Box, - pub elseif_exprs: Vec>, - pub elseif_bodys: Vec>, - pub else_expr: Option>, - pub else_body: Option>, +pub struct If { + pub expr: Box, + pub body: Box, } -impl IfChain { - pub fn new( - if_expr: Box, - if_body: Box, - elseif_exprs: Vec>, - elseif_bodys: Vec>, - else_expr: Option>, - else_body: Option>, - ) -> Self { - IfChain { - if_expr, - if_body, - elseif_exprs, - elseif_bodys, - else_expr, - else_body, +impl If { + pub fn new(if_expr: Box, if_body: Box) -> Self { + If { + expr: if_expr, + body: if_body, } } } @@ -341,9 +326,9 @@ pub struct EnumDecl { pub visibility: Option, pub mutability: Lexeme, pub identifier: Box, - pub declarators: Vec>, + pub variants: Vec>, pub sig: Option>, - pub variant: Option>, + pub enum_type: Option>, } impl EnumDecl { @@ -351,17 +336,17 @@ impl EnumDecl { visibility: Option, mutability: Lexeme, identifier: Box, - declarators: Vec>, + variants: Vec>, sig: Option>, - variant: Option>, + enum_type: Option>, ) -> Self { EnumDecl { visibility, mutability, identifier, - declarators, + variants, sig, - variant, + enum_type, } } } @@ -371,6 +356,7 @@ pub struct ErrorDecl { pub visibility: Option, pub mutability: Lexeme, pub identifier: Box, + pub variants: Vec>, pub sig: Option>, } @@ -379,12 +365,14 @@ impl ErrorDecl { visibility: Option, mutability: Lexeme, identifier: Box, + variants: Vec>, sig: Option>, ) -> Self { ErrorDecl { visibility, mutability, identifier, + variants, sig, } } @@ -718,7 +706,7 @@ pub enum Expr { Rest(Rest), For(For), Destructure(Destructure), - IfChain(IfChain), + If(If), While(While), Match(Match), Arm(Arm), diff --git a/ebnf.txt b/ebnf.txt index ec7dbdb..9e841bf 100644 --- a/ebnf.txt +++ b/ebnf.txt @@ -11,7 +11,7 @@ ::= "fn " "(" ? ") " ::= "struct " "{ " ? "}" ::= "error " ("| " )+ - ::= "if " "(" ")" ( | ) ("else if "(" ")" ( | ))* ("else " ( | ))? + ::= "if " "(" ")" ( | ) ::= "for " "(" ")" ( | ) ::= "while " "(" ")" ( | ) ::= "match " "(" ")" "{ " + "}" diff --git a/linter/src/lib.rs b/linter/src/lib.rs index 369b718..6968aa8 100644 --- a/linter/src/lib.rs +++ b/linter/src/lib.rs @@ -58,6 +58,7 @@ impl<'buf, 'ttb, 'sco> LintSource<'buf, 'ttb, 'sco> { Expr::Declarator(declarator) => self.check_declarator(&declarator), Expr::Match(_match) => self.check_match(&_match), Expr::For(_for) => self.check_for(&_for), + Expr::If(_if) => self.check_if(&_if), Expr::Invoke(invoke) => self.check_invoke(&invoke), Expr::PropAccess(prop) => self.check_prop_access(&prop), Expr::Arm(arm) => self.check_arm(&arm), @@ -152,6 +153,19 @@ impl<'buf, 'ttb, 'sco> LintSource<'buf, 'ttb, 'sco> { ok_simple_tree!(UndefinedValue, typ) } + pub fn check_if(&mut self, _if: &If) -> ResultTreeType { + let res = self.lint_recurse(&_if.expr)?; + let body = self.lint_recurse(&_if.body)?; + let if_op = IfOp { + in_expr: res.0, + in_curried: res.1, + body: body.0, + body_curried: body.1, + }; + let cur = if_op.body_curried.clone(); + ok_tree!(If, if_op, cur) + } + pub fn check_for(&mut self, _for: &For) -> ResultTreeType { let res = self.lint_recurse(&_for.expr)?; let body = self.lint_recurse(&_for.var_loop)?; diff --git a/parser/src/lib.rs b/parser/src/lib.rs index 5498411..1a449a6 100644 --- a/parser/src/lib.rs +++ b/parser/src/lib.rs @@ -71,15 +71,12 @@ impl<'s> Parser<'s> { identifier: Box, sig: Option>, ) -> ResultExpr { - let _ = self - .lexer - .collect_if(Token::OBrace) - .xexpect_token(&self, "expected '{'".to_string())?; - let _ = self - .lexer - .collect_if(Token::CBrace) - .xexpect_token(&self, "expected '}'".to_string())?; - result_expr!(ErrorDecl, visibility, mutability, identifier, sig) + let mut variants: Vec> = vec![]; + while let Some(_) = self.lexer.collect_if(Token::Bar) { + let x = self.ident().xconvert_to_decl()?; + variants.push(x); + } + result_expr!(ErrorDecl, visibility, mutability, identifier, variants, sig) } pub fn _enum( @@ -450,27 +447,11 @@ impl<'s> Parser<'s> { .lexer .collect_if(Token::CParen) .xexpect_token(&self, "expected ')'".to_string())?; - let mut _fn = self.anon_fn()?; - if _fn.is_none() { - _fn = Some(self.block()?); - } - let mut chain = Box::new(Expr::IfChain(IfChain::new( - x, - _fn.unwrap(), - vec![], - vec![], - None, - None, - ))); - - while let Some(elseif) = self.lexer.collect_if(Token::Else) { - args.push(self.or()?); - } - let i = self.lexer.collect_if(Token::If); - if i.is_none() { - return Ok(None); + if let Some(_fn) = self.anon_fn()? { + return bubble_expr!(If, x, _fn); } - return Ok(Some(chain)); + let blk = self.block()?; + return bubble_expr!(If, x, blk); } pub fn _while(&mut self) -> ResultOptExpr { let f = self.lexer.collect_if(Token::While); diff --git a/playground.ty b/playground.ty index 562d774..d334793 100644 --- a/playground.ty +++ b/playground.ty @@ -86,3 +86,73 @@ const factorial_table = comptime(name: ident, calculate: usize) { return } } + +const count_things = fn(to_check: &[char]) f64 { + let count: f64 = 0 + for (to_check) fn(x) void { + if (x == ' ' || x == '7') { + count += 1 + } else { + print('hello') + } + // possible match syntax + // forces exhaustion rather than if else chains missing a case + match (x) { + ' ' || '7' => { count +=1 }, + _ => { print('hello') }, + } + match (x, y, z) { + 'x', 'y', 'z' => { count +=1 }, + _, 'y', 'z' => { print('hello') }, + } + } + return count +} + +type Kenobi = enum(u8) | Hello | There | General + +// support line/block/fn +const thing = match (Kenobi.Hello) { + Kenobi.Hello => fn(m) usize { + return m as usize + }, + Kenobi.There => { return 1 }, + _ => return 2 + +// truthy values allow capturing. +// the truthy table is quite simple. if it has a value that is not empty or undefined. it is truthy. + +const counter = fn() f64 { + let count: f64 = 0 + let to_check = [] + // to_check is an empty array. falsey + for (to_check) fn(x) void { + // unreachable! + } + if (to_check) fn(x) void { + // unreachable! + // because there is nothing in to_check, we can't capture the value. this makes truthy intuitive in type-lang + + } + let my_str = "" + if (my_str) { + // unreachable! + // even when not capturing it follows the truthy rules, this block will never ran + } + let undef_example = undefined + if (undef_example) fn(x) void { + // unreachable! + // undefined is fine as a value, but we can never capture an undefined. undefined is never readable. + } + let actual = "captureable!" + for (actual) fn(x) void { + if (x.is_ascii()) { + + } + } +} + +const x: error!?usize = 7 +const y: ?usize = try x +const z: usize = y? + diff --git a/test/test.ty b/test/test.ty index fb2e196..66a6104 100644 --- a/test/test.ty +++ b/test/test.ty @@ -33,7 +33,7 @@ const next_weekday = fn(d: Day) Day { const c = [0,1,2,3].map(fn(x: usize) usize { return x + 2 }) // errors are first class citizens where control flow is designed to work well with errors. -type InvalidWeekday = error {} +type InvalidWeekday = error const assert_weekday = fn(d: Day) InvalidWeekday!Day { return match (d) { diff --git a/todos.txt b/todos.txt index 8ce4406..7916e87 100644 --- a/todos.txt +++ b/todos.txt @@ -3,4 +3,5 @@ - Bar '|' ebnf doesn't match parser, update parser for every '|' syntax - "all function declarations must have types in arguments." this can be changed to support deducing types at some point - impl -- make types typey instead of values "function declarations" tags, enums, etc. +- trait +- modify match syntax to take place of else branches diff --git a/types/src/lib.rs b/types/src/lib.rs index 7b7bb6d..ef8810e 100644 --- a/types/src/lib.rs +++ b/types/src/lib.rs @@ -64,6 +64,14 @@ pub struct ForOp { pub body_curried: Ty, } +#[derive(Debug)] +pub struct IfOp { + pub in_expr: Rc>, + pub in_curried: Ty, + pub body: Rc>, + pub body_curried: Ty, +} + #[derive(Debug)] pub struct BinaryOp { pub left: Rc>, @@ -164,6 +172,7 @@ pub enum TypeTree { SigInfo(SigInfo), // flow For(ForOp), + If(IfOp), Invoke(Invoke), Match(MatchOp), Arm(BinaryOp), @@ -240,6 +249,7 @@ impl TypeTree { TypeTree::SigInfo(x) => x.right.clone(), TypeTree::ErrorInfo(x) => x.curried.clone(), TypeTree::For(x) => x.body_curried.clone(), + TypeTree::If(x) => x.body_curried.clone(), TypeTree::Invoke(x) => x.curried.clone(), TypeTree::Match(x) => x.curried_arms.clone(), TypeTree::Arm(x) => x.curried.clone(), @@ -339,6 +349,7 @@ impl TypeTree { TypeTree::SigInfo(_) => "type signature", TypeTree::ErrorInfo(_) => "error declaration", TypeTree::For(_) => "for loop", + TypeTree::If(_) => "if statement", TypeTree::Invoke(_) => "function invocation", TypeTree::Match(_) => "match", TypeTree::Arm(_) => "pattern match arm",