From d1cf63f9ec8435d2773c2cb88c5ad6f7e8600db3 Mon Sep 17 00:00:00 2001 From: glyh Date: Mon, 16 Sep 2024 17:22:07 +0800 Subject: [PATCH] reimplemented parser with parser combinator --- src/bin/main.mbt | 2 +- src/lex/lex.mbt | 89 +-- src/lex/lexeme.mbt | 65 +++ src/parser/README.md | 4 - src/parser/aliases.mbt | 11 + src/parser/cst.mbt | 87 --- src/parser/entry.mbt | 26 - src/parser/interface.mbt | 98 ++-- src/parser/moon.pkg.json | 2 + src/parser/parsec.mbt | 363 ++++++++++++ src/parser/parser.mbt | 887 +++++++----------------------- src/parser/parser.mbti | 50 -- src/parser/parser_test_inline.mbt | 154 ++++-- src/parser/show_ast.mbt | 284 ---------- 14 files changed, 783 insertions(+), 1339 deletions(-) create mode 100644 src/lex/lexeme.mbt delete mode 100644 src/parser/README.md create mode 100644 src/parser/aliases.mbt delete mode 100644 src/parser/cst.mbt delete mode 100644 src/parser/entry.mbt create mode 100644 src/parser/parsec.mbt delete mode 100644 src/parser/parser.mbti delete mode 100644 src/parser/show_ast.mbt diff --git a/src/bin/main.mbt b/src/bin/main.mbt index c0e03b4..a29ac40 100644 --- a/src/bin/main.mbt +++ b/src/bin/main.mbt @@ -89,7 +89,7 @@ fn CompileStatus::step(self : CompileStatus) -> Bool { match self.curr_stage { Parse => { let source_code = self.source_code.unwrap() - let parsed = @util.die("TODO: parse") + let parsed = @parser.parse_program(source_code) self.ast = Some(parsed) } Typecheck => { diff --git a/src/lex/lex.mbt b/src/lex/lex.mbt index fd941ab..506cb73 100644 --- a/src/lex/lex.mbt +++ b/src/lex/lex.mbt @@ -1,72 +1,5 @@ // An O(N) lexer // TODO: check int, float out of bound parsing -pub struct Loc { - row : Int - col : Int - index : Int -} derive(Show) - -pub enum LexError_ { - ExpectLE - UnexpectedChar(Char) -} derive(Show) - -pub type! LexError LexError_ - -pub fn new_loc() -> Loc { - { row: 1, col: 1, index: 0 } -} - -fn advance(self : Loc, c : Char) -> Loc { - if c == '\n' { - self.advance_line() - } else { - { ..self, col: self.col + 1, index: self.index + 1 } - } -} - -fn advance_line(self : Loc) -> Loc { - { row: self.row + 1, col: 1, index: self.index + 1 } -} - -pub enum Token { - ID(String) - COLON - ASSIGN - SEMICOL - FN - MAIN - INIT - LPAREN - RPAREN - ARROW - COMMA - LBRACE - RBRACE - EQ - LE - ADD - SUB - MUL - DIV - IF - ELSE - LBKT - RBKT - BOOL(Bool) - DOT - ARRAY - MAKE - UNIT_T - BOOL_T - DOUBLE_T - I32(Int) - F64(Double) - NOT - INT_T - LET -} derive(Show, Eq) - let reserved_keywords : @immut/hashmap.T[String, Token] = @immut/hashmap.of( [ ("true", BOOL(true)), @@ -77,13 +10,10 @@ let reserved_keywords : @immut/hashmap.T[String, Token] = @immut/hashmap.of( ("Double", DOUBLE_T), ("Array", ARRAY), ("not", NOT), - ("make", MAKE), ("if", IF), ("else", ELSE), ("fn", FN), ("let", LET), - ("main", MAIN), - ("init", INIT), ], ) @@ -117,8 +47,8 @@ enum LexState { // DFA State AfterFloatingDot } -pub fn lex_string(input : String) -> Array[(Token, Loc, Loc)]!LexError { - let result : Array[(Token, Loc, Loc)] = Array::new() +pub fn lex_string(input : String) -> Array[Lexeme]!LexError { + let result : Array[Lexeme] = Array::new() // put a new line here manually so we always spit the last token let chars = (input + "\n").iter().collect() let index_ub = chars.length() @@ -165,7 +95,7 @@ pub fn lex_string(input : String) -> Array[(Token, Loc, Loc)]!LexError { } else { match symbols.find(char) { Some(tok) => result.push((tok, loc, loc)) - None => raise LexError(UnexpectedChar(char)) + None => raise LexError(UnexpectedChar(char, loc)) } } } @@ -237,7 +167,7 @@ pub fn lex_string(input : String) -> Array[(Token, Loc, Loc)]!LexError { mode = Default result.push((LE, last_loc, loc)) } - (AfterLess, _) => raise LexError(ExpectLE) + (AfterLess, c) => raise LexError(UnexpectedChar(c, loc)) (AfterMinus, '>') => { mode = Default result.push((ARROW, last_loc, loc)) @@ -250,15 +180,10 @@ pub fn lex_string(input : String) -> Array[(Token, Loc, Loc)]!LexError { } loc = loc.advance(char) } + result.push((EOF, loc, loc)) result } -fn fst[U, V, W](pair : (U, V, W)) -> U { - match pair { - (a, _, _) => a - } -} - test "simple lexing" { inspect!( lex_string!( @@ -275,9 +200,9 @@ test "simple lexing" { #| 1.0007 9. #| 2147483647 , - ).map(fst), + ).map(fn { _1 => _1.0 }), content= - #|[FN, ID("make_adder"), LPAREN, ID("x"), COLON, INT_T, RPAREN, ARROW, LPAREN, INT_T, RPAREN, ARROW, INT_T, LBRACE, FN, ID("adder"), LPAREN, ID("y"), COLON, INT_T, RPAREN, ARROW, INT_T, LBRACE, ID("x"), ADD, ID("y"), RBRACE, SEMICOL, ID("adder"), RBRACE, SEMICOL, FN, MAIN, LBRACE, ID("print_int"), LPAREN, LPAREN, ID("make_adder"), LPAREN, I32(3), RPAREN, RPAREN, LPAREN, I32(7), RPAREN, RPAREN, RBRACE, SEMICOL, F64(1.0007), F64(9), I32(2147483647)] + #|[FN, ID("make_adder"), LPAREN, ID("x"), COLON, INT_T, RPAREN, ARROW, LPAREN, INT_T, RPAREN, ARROW, INT_T, LBRACE, FN, ID("adder"), LPAREN, ID("y"), COLON, INT_T, RPAREN, ARROW, INT_T, LBRACE, ID("x"), ADD, ID("y"), RBRACE, SEMICOL, ID("adder"), RBRACE, SEMICOL, FN, ID("main"), LBRACE, ID("print_int"), LPAREN, LPAREN, ID("make_adder"), LPAREN, I32(3), RPAREN, RPAREN, LPAREN, I32(7), RPAREN, RPAREN, RBRACE, SEMICOL, F64(1.0007), F64(9), I32(2147483647), EOF] , ) } diff --git a/src/lex/lexeme.mbt b/src/lex/lexeme.mbt new file mode 100644 index 0000000..327d6b1 --- /dev/null +++ b/src/lex/lexeme.mbt @@ -0,0 +1,65 @@ +pub struct Loc { + row : Int + col : Int + index : Int +} derive(Show) + +pub enum LexError_ { + UnexpectedChar(Char, Loc) +} derive(Show) + +pub type! LexError LexError_ + +fn new_loc() -> Loc { + { row: 1, col: 1, index: 0 } +} + +fn advance(self : Loc, c : Char) -> Loc { + if c == '\n' { + self.advance_line() + } else { + { ..self, col: self.col + 1, index: self.index + 1 } + } +} + +fn advance_line(self : Loc) -> Loc { + { row: self.row + 1, col: 1, index: self.index + 1 } +} + +pub enum Token { + ID(String) + COLON + ASSIGN + SEMICOL + FN + LPAREN + RPAREN + ARROW + COMMA + LBRACE + RBRACE + EQ + LE + ADD + SUB + MUL + DIV + IF + ELSE + LBKT + RBKT + BOOL(Bool) + DOT + ARRAY + UNIT_T + BOOL_T + DOUBLE_T + I32(Int) + F64(Double) + NOT + INT_T + LET + EOF +} derive(Show, Eq) + +typealias Lexeme = (Token, Loc, Loc) diff --git a/src/parser/README.md b/src/parser/README.md deleted file mode 100644 index 6108294..0000000 --- a/src/parser/README.md +++ /dev/null @@ -1,4 +0,0 @@ -# Some features of this parser -- Some error recovery -- Report errors encoutered -- Unparse the program into string diff --git a/src/parser/aliases.mbt b/src/parser/aliases.mbt new file mode 100644 index 0000000..9326535 --- /dev/null +++ b/src/parser/aliases.mbt @@ -0,0 +1,11 @@ +typealias S = @types.Syntax + +typealias PS = Parser[S] + +typealias T = @types.Type + +typealias PT = Parser[T] + +typealias B = @types.Op + +typealias PB = Parser[B] diff --git a/src/parser/cst.mbt b/src/parser/cst.mbt deleted file mode 100644 index 2168115..0000000 --- a/src/parser/cst.mbt +++ /dev/null @@ -1,87 +0,0 @@ -struct Ann { - src_start : @lex.Loc - src_end : @lex.Loc? -} - -type Program Array[Top] - -type! ParseError { - Unexpected((@lex.Token, @lex.Loc, @lex.Loc)) - EarlyEOF - Missing(@lex.Token, @lex.Loc) - ExpectButEOF(@lex.Token) - Unreachable - TopLevelNotColNot1((@lex.Token, @lex.Loc, @lex.Loc)) -} derive(Show) - -enum TopNaked { - LetDecl(ID, Type, Exp) - FnDecl(ID, Result[Array[(ID, Type)], ParseError], Type, Stmt) - MainDecl(Stmt) - InitDecl(Stmt) -} - -type Top Result[(TopNaked, Ann), ParseError] - -type ID Result[(String, Ann), ParseError] - -enum StmtHeadNaked { - LetTuple(Array[ID], Type?, Exp) - Let(ID, Type?, Exp) - NontopFn(ID, Array[(ID, Type?)], Type?, Stmt) - Assign(Exp, Exp) -} - -type StmtHead Result[(StmtHeadNaked, Ann), ParseError] - -type Stmt Result[(Array[StmtHead], Exp, Ann), ParseError] - -enum Value { - I32(Int) - F64(Double) - Bool(Bool) - Unit -} - -enum Unop { - Not - Neg -} - -enum BinopTag { - Eq - Le - Add - Sub - Mul - Div -} - -type Binop Result[(BinopTag, Ann), ParseError] - -enum ExpNaked { - Atom(Value) - Tuple(Array[Exp]) - Block(Stmt) - Unary(Unop, Exp) - Binary(Binop, Exp, Exp) - Apply(Exp, Array[Exp]) // we need at least 2 expression to perform an apply - If(Exp, Stmt, Stmt?) - Index(Exp, Exp) - Var(ID) - MakeArray(Exp, Exp) // (len, ele) -} - -type Exp Result[(ExpNaked, Ann), ParseError] - -enum TypeNaked { - TUnit - TBool - TInt - TDouble - TArray(Type) - TTuple(Array[Type]) - TFunction(Array[Type], Type) -} - -type Type Result[(TypeNaked, Ann), ParseError] diff --git a/src/parser/entry.mbt b/src/parser/entry.mbt deleted file mode 100644 index f6ea83e..0000000 --- a/src/parser/entry.mbt +++ /dev/null @@ -1,26 +0,0 @@ -//fn main { -// try { -// let tokens = @lex.lex_string!( -// #| fn adder(y: Int) -> Int { -// #| x + y -// #| }; -// #| adder -// , -// ) -// inspect!( -// tokens.map(fst), -// content= -// #|[FN, ID("adder"), LPAREN, ID("y"), COLON, INT_T, RPAREN, ARROW, INT_T, LBRACE, ID("x"), ADD, ID("y"), RBRACE, SEMICOL, ID("adder")] -// , -// ) -// let program = stmt(tokens[:]) -// inspect!( -// program, -// content= -// #| -// , -// ) -// } catch { -// e => println(e) -// } -//} diff --git a/src/parser/interface.mbt b/src/parser/interface.mbt index a7c654a..33c2e44 100644 --- a/src/parser/interface.mbt +++ b/src/parser/interface.mbt @@ -1,79 +1,45 @@ -fn id_to_ast!(cst : ID) -> String { - -} - -fn ty_to_ast!(cst : Type) -> @types.Type { - -} - -fn exp_to_ast!(cst : Exp) -> @types.Syntax { - -} - -fn stmt_to_ast!(cst : Stmt) -> @types.Syntax { - -} - -fn args_to_ast!( - cst : Result[Array[(ID, Type)], ParseError] -) -> Array[(String, @types.Type)] { - +fn is_concrete(t : T) -> Bool { + match t { + Var(_) => false + _ => true + } } -fn cst_to_ast!(cst : Program) -> @types.Syntax { - let mut out : @types.Syntax = Unit - for topi in cst._.rev().iter() { - match topi._ { - Err(e) => raise e - Ok((LetDecl(id, ty, exp), _)) => { - let id = id_to_ast!(id) - let _ty = ty_to_ast!(ty) - let rhs = exp_to_ast!(exp) - out = Let((id, _ty), rhs, out) - } - Ok((FnDecl(id, args, ret_ty, body), _)) => { - let name = id_to_ast!(id) - let args = args_to_ast!(args) - let ret_ty = ty_to_ast!(ret_ty) - let body = stmt_to_ast!(body) - out = LetRec({ name: (name, ret_ty), args, body }, out) +fn ensure_top_level_type_sig(program : S) -> Unit { + loop program { + Let((_, ty), _, inner) => { + if not(is_concrete(ty)) { + @util.die("Need outer level type annotation for \{program}") } - Ok((MainDecl(body), _)) => { - let name = "main" - let args = [] - let ret_ty = @types.Type::Unit - let body = stmt_to_ast!(body) - out = LetRec({ name: (name, ret_ty), args, body }, out) + continue inner + } + LetTuple(tup, _, inner) => { + if not(tup.map(fn { (_, ty) => ty }).iter().all(is_concrete)) { + @util.die("Need outer level type annotation for \{program}") } - Ok((InitDecl(body), _)) => { - let name = "init" - let args = [] - let ret_ty = @types.Type::Unit - let body = stmt_to_ast!(body) - out = LetRec({ name: (name, ret_ty), args, body }, out) + continue inner + } + LetRec({ name, args, .. }, inner) => { + if not(args.map(fn { (_, ty) => ty }).iter().all(is_concrete)) || + not(is_concrete(name.1)) { + @util.die("Need outer level type annotation for \{program}") } + continue inner } + _ => break } - out } -pub fn parse_string(s : string) -> @types.Syntax? { - let tokens = try { - @lex.lex_string!(s) +pub fn parse_program(intput : String) -> S { + let lex_stream = try { + @lex.lex_string!(intput) } catch { - LexError(e) => { - println("!Lex: \{e}.") - return None - } + LexError(e) => @util.die("Lexer Error: \{e}") } - let program_parsed = program(tokens[:]) - for e in recoverable_errors.iter() { - println("!Parse: \{e}.") + let parsed = match parser().parse(lex_stream[:]) { + (Some(parsed), []) => parsed + _ => @util.die("parse error") } - - //try { - // - // - //} - //program() + ensure_top_level_type_sig(parsed) + parsed } diff --git a/src/parser/moon.pkg.json b/src/parser/moon.pkg.json index 83c5d63..7a7fee5 100644 --- a/src/parser/moon.pkg.json +++ b/src/parser/moon.pkg.json @@ -1,9 +1,11 @@ { "import": [ "moonbitlang/minimbt/lex", + "moonbitlang/minimbt/util", { "path": "moonbitlang/minimbt", "alias": "types" + } ] } diff --git a/src/parser/parsec.mbt b/src/parser/parsec.mbt new file mode 100644 index 0000000..c3d780b --- /dev/null +++ b/src/parser/parsec.mbt @@ -0,0 +1,363 @@ +// reference: https://moonbitlang.github.io/moonbit-textbook/parser/#syntax-parsing + +typealias Lexeme = (@lex.Token, @lex.Loc, @lex.Loc) + +type Parser[V] (ArrayView[Lexeme]) -> (V?, ArrayView[Lexeme]) + +fn parse[T]( + self : Parser[T], + input : ArrayView[Lexeme] +) -> (T?, ArrayView[Lexeme]) { + (self._)(input) +} + +fn empty[T]() -> Parser[T] { + fn { view => (None, view) } +} + +fn epsilon() -> Parser[Unit] { + fn { view => (Some(()), view) } +} + +fn ref[T](referred : Ref[Parser[T]]) -> Parser[T] { + fn { input => referred.val.parse(input) } +} + +let double : Parser[Double] = fn { + [(@lex.F64(f), _, _), .. as rest] => (Some(f), rest) + view => (None, view) +} + +let int : Parser[Int] = fn { + [(@lex.I32(i), _, _), .. as rest] => (Some(i), rest) + view => (None, view) +} + +let bool : Parser[Bool] = fn { + [(@lex.BOOL(b), _, _), .. as rest] => (Some(b), rest) + view => (None, view) +} + +let id : Parser[String] = fn { + [(@lex.ID(i), _, _), .. as rest] => (Some(i), rest) + view => (None, view) +} + +fn id_p(p : (String) -> Bool) -> Parser[String] { + fn { + [(@lex.ID(id), _, _), .. as rest] as view => + if p(id) { + (Some(id), rest) + } else { + (None, view) + } + _ as view => (None, view) + } +} + +let line_start : Parser[Unit] = fn { + [(_, start_loc, _), ..] as view => + if start_loc.col == 1 { + (Some(()), view) + } else { + (None, view) + } + view => (None, view) +} + +fn op_add[T](self : Parser[T], rhs : Parser[T]) -> Parser[T] { + self.or(rhs) +} + +fn or[T](self : Parser[T], rhs : Parser[T]) -> Parser[T] { + Parser( + fn(input) { + match self.parse(input) { + (None, _) => rhs.parse(input) + result => result + } + }, + ) +} + +fn lift2[U, V, W](f : (U, V) -> W, p1 : Parser[U], p2 : Parser[V]) -> Parser[W] { + Parser( + fn(input) { + match p1.parse(input) { + (None, _) => (None, input) + (Some(u), rest) => + match p2.parse(rest) { + (None, _) => (None, input) + (Some(v), rest2) => (Some(f(u, v)), rest2) + } + } + }, + ) +} + +fn lift2_maybe[U, V, W]( + f : (U, V) -> W?, + p1 : Parser[U], + p2 : Parser[V] +) -> Parser[W] { + Parser( + fn(input) { + match p1.parse(input) { + (None, _) => (None, input) + (Some(u), rest) => + match p2.parse(rest) { + (None, _) => (None, input) + (Some(v), rest2) => (f(u, v), rest2) + } + } + }, + ) +} + +fn lift3[U, V, W, X]( + f : (U, V, W) -> X, + p1 : Parser[U], + p2 : Parser[V], + p3 : Parser[W] +) -> Parser[X] { + Parser( + fn(input) { + match p1.parse(input) { + (None, _) => (None, input) + (Some(u), rest) => + match p2.parse(rest) { + (None, _) => (None, input) + (Some(v), rest2) => + match p3.parse(rest2) { + (None, _) => (None, input) + (Some(w), rest3) => (Some(f(u, v, w)), rest3) + } + } + } + }, + ) +} + +fn lift3_maybe[U, V, W, X]( + f : (U, V, W) -> X?, + p1 : Parser[U], + p2 : Parser[V], + p3 : Parser[W] +) -> Parser[X] { + Parser( + fn(input) { + match p1.parse(input) { + (None, _) => (None, input) + (Some(u), rest) => + match p2.parse(rest) { + (None, _) => (None, input) + (Some(v), rest2) => + match p3.parse(rest2) { + (None, _) => (None, input) + (Some(w), rest3) => (f(u, v, w), rest3) + } + } + } + }, + ) +} + +fn lift4[U, V, W, X, Y]( + f : (U, V, W, X) -> Y, + p1 : Parser[U], + p2 : Parser[V], + p3 : Parser[W], + p4 : Parser[X] +) -> Parser[Y] { + Parser( + fn(input) { + match p1.parse(input) { + (None, _) => (None, input) + (Some(u), rest) => + match p2.parse(rest) { + (None, _) => (None, input) + (Some(v), rest2) => + match p3.parse(rest2) { + (None, _) => (None, input) + (Some(w), rest3) => + match p4.parse(rest3) { + (None, _) => (None, input) + (Some(x), rest4) => (Some(f(u, v, w, x)), rest4) + } + } + } + } + }, + ) +} + +fn map[U, V](self : Parser[U], f : (U) -> V) -> Parser[V] { + Parser( + fn(input) { + match self.parse(input) { + (None, rest) => (None, rest) + (Some(u), rest) => (Some(f(u)), rest) + } + }, + ) +} + +fn op_shr[U, V](self : Parser[U], rhs : Parser[V]) -> Parser[V] { + Parser( + fn(input) { + match self.parse(input) { + (None, rest) => (None, rest) + (Some(_), rest) => rhs.parse(rest) + } + }, + ) +} + +fn op_shl[U, V](self : Parser[U], rhs : Parser[V]) -> Parser[U] { + Parser( + fn(input) { + match self.parse(input) { + (None, rest) => (None, rest) + (Some(u), rest) => + match rhs.parse(rest) { + (None, _) => (None, input) + (Some(_), rest2) => (Some(u), rest2) + } + } + }, + ) +} + +fn tok(tok : @lex.Token) -> Parser[@lex.Token] { + Parser( + fn(input) { + match input { + [(tok2, _, _), .. as rest] => + if tok == tok2 { + (Some(tok), rest) + } else { + (None, input) + } + _ => (None, input) + } + }, + ) +} + +fn maybe[U](p : Parser[U]) -> Parser[U?] { + Parser( + fn(input) { + match p.parse(input) { + (Some(u), rest) => (Some(Some(u)), rest) + (None, rest) => (Some(None), rest) + } + }, + ) +} + +fn many[U](inner : Parser[U]) -> Parser[Array[U]] { + Parser( + fn(input) { + let acc : Array[U] = [] + let mut input = input + while true { + match inner.parse(input) { + (Some(v), rest) => { + acc.push(v) + input = rest + } + (None, _) => break + } + } + (Some(acc), input) + }, + ) +} + +fn sep_list1[U, V](sep : Parser[U], inner : Parser[V]) -> Parser[Array[V]] { + Parser( + fn(input) { + match inner.parse(input) { + (Some(i), rest) => { + let acc : Array[V] = [i] + let mut rest = rest + let sep_in = sep >> inner + while true { + match sep_in.parse(rest) { + (None, _) => break + (Some(i), rest2) => { + rest = rest2 + acc.push(i) + } + } + } + (Some(acc), rest) + } + (None, _) => (None, input) + } + }, + ) +} + +fn sep_list[U, V](sep : Parser[U], inner : Parser[V]) -> Parser[Array[V]] { + Parser( + fn(input) { + match inner.parse(input) { + (Some(i), rest) => { + let acc : Array[V] = [i] + let mut rest = rest + let sep_in = sep >> inner + while true { + match sep_in.parse(rest) { + (None, _) => break + (Some(i), rest2) => { + rest = rest2 + acc.push(i) + } + } + } + (Some(acc), rest) + } + (None, _) => (Some([]), input) + } + }, + ) +} + +fn tier_left(op : Parser[B], next : Parser[S]) -> Parser[S] { + let postfix = lift2(fn(op, next) { (op, next) }, op, next) + lift2( + fn(hd, rest : Array[(B, S)]) { + rest.fold( + init=hd, + fn(acc, ele) { + let (op, rhs) = ele + S::Prim(acc, rhs, op, kind=None) + }, + ) + }, + next, + many(postfix), + ) +} + +fn fold_right[U, V]( + init : Parser[V], + ele : Parser[U], + op : Parser[(U, V) -> V] +) -> Parser[V] { + let prefix = lift2(fn(ele, op) { (ele, op) }, ele, op) + lift2( + fn(rest_r : Array[(U, (U, V) -> V)], last : V) { + rest_r.rev_fold( + init=last, + fn(acc, prefix) { + let (lhs, op) = prefix + op(lhs, acc) + }, + ) + }, + many(prefix), + init, + ) +} diff --git a/src/parser/parser.mbt b/src/parser/parser.mbt index bae582a..3164f5d 100644 --- a/src/parser/parser.mbt +++ b/src/parser/parser.mbt @@ -1,698 +1,225 @@ -// According to https://taolun.moonbitlang.com/t/topic/882/2, we don't have GADT, so I have to hand roll like below - -let recoverable_errors : Array[ParseError] = [] - -fn program(view : ArrayView[(@lex.Token, @lex.Loc, @lex.Loc)]) -> Program { - let program : Program = [] - let mut view = view - while true { - match view { - [(@lex.FN, all_start, _) as tok, ..] => { - if all_start.col != 1 { // in grammar file it's enforced all top levels start at the beginning of line - recoverable_errors.push(TopLevelNotColNot1(tok)) - } - let (top_fn, rest) = top_fn(view) - program._.push(top_fn) - view = rest - } - [(@lex.LET, all_start, _) as tok, ..] => { - if all_start.col != 1 { - recoverable_errors.push(TopLevelNotColNot1(tok)) - } - let (top_let, rest) = top_let(view) - program._.push(top_let) - view = rest - } - [tok, ..] => program._.push(Err(Unexpected(tok))) - [] => break - } - } - program +enum GetApplyPostFix { + Index(S) + Apply(Array[S]) } -fn consume( - tok_expect : @lex.Token, - view : ArrayView[(@lex.Token, @lex.Loc, @lex.Loc)] // returns the end if consume -) -> (@lex.Loc?, ArrayView[(@lex.Token, @lex.Loc, @lex.Loc)]) { - match view { - [(tok, tok_s, tok_e), .. as view] => - if tok == tok_expect { - (Some(tok_e), view) - } else { - recoverable_errors.push(Missing(tok, tok_s)) - (None, view) - } - [] => { - recoverable_errors.push(ExpectButEOF(tok_expect)) - (None, view) - } +fn merge_postfix(inner : S, outers : Array[GetApplyPostFix]) -> S { + loop (inner, outers[:]) { + (acc, []) => break acc + (acc, [Index(accessor), .. as rest]) => + continue (S::Get(acc, accessor), rest) + (acc, [Apply(params), .. as rest]) => continue (S::App(acc, params), rest) } } -fn consume_head( - tok_expect : @lex.Token, - view : ArrayView[(@lex.Token, @lex.Loc, @lex.Loc)] // returns the end if consume -) -> (@lex.Loc?, ArrayView[(@lex.Token, @lex.Loc, @lex.Loc)]) { - match view { - [(tok, tok_s, _), .. as view] => - if tok == tok_expect { - (Some(tok_s), view) - } else { - recoverable_errors.push(Missing(tok, tok_s)) - (None, view) - } - [] => { - recoverable_errors.push(ExpectButEOF(tok_expect)) - (None, view) - } +fn fix_type(ty : T?) -> T { + match ty { + Some(ty) => ty + None => T::Var({ val: None }) } } -fn top_fn( - view : ArrayView[(@lex.Token, @lex.Loc, @lex.Loc)] -) -> (Top, ArrayView[(@lex.Token, @lex.Loc, @lex.Loc)]) { - guard let (Some(all_start), view) = consume_head(@lex.FN, view) else { - _ => return (Err(Unreachable), view) - } - let (name, view) = match view { - [(@lex.ID(id), id_s, id_e), .. as view] => - ((id, { src_start: id_s, src_end: Some(id_e) }), view) - [(@lex.MAIN, id_s, id_e), .. as view] => - (("main", { src_start: id_s, src_end: Some(id_e) }), view) - [(@lex.INIT, id_s, id_e), .. as view] => - (("init", { src_start: id_s, src_end: Some(id_e) }), view) - [tok, .. as view] => return (Err(Unexpected(tok)), view) - [] => return (Err(EarlyEOF), view) - } - if name.0 == "main" { - let (_, view) = consume(@lex.LBRACE, view) - let (fn_body, view) = stmt(view) // { body } - let (_, view) = consume(@lex.RBRACE, view) - let (all_end, view) = consume(@lex.SEMICOL, view) - (Ok((MainDecl(fn_body), { src_start: all_start, src_end: all_end })), view) - } else if name.0 == "init" { - let (_, view) = consume(@lex.LBRACE, view) - let (fn_body, view) = stmt(view) // { body } - let (_, view) = consume(@lex.RBRACE, view) - let (all_end, view) = consume(@lex.SEMICOL, view) - (Ok((InitDecl(fn_body), { src_start: all_start, src_end: all_end })), view) - } else { - let (params, view) = params_typed(view) // (x1, x2, x3) - let (_, view) = consume(@lex.ARROW, view) - let (return_type, view) = _type(view) // Type - let (_, view) = consume(@lex.LBRACE, view) - let (fn_body, view) = stmt(view) - let (_, view) = consume(@lex.RBRACE, view) - let (all_end, view) = consume(@lex.SEMICOL, view) +fn parser() -> PS { + let expr_ref : Ref[PS] = { val: empty() } + let stmt_ref : Ref[PS] = { val: empty() } + let block_expr = tok(@lex.LBRACE) >> ref(stmt_ref) << tok(@lex.RBRACE) + + // Type + let type_ref : Ref[PT] = { val: empty() } + type_ref.val = tok(@lex.UNIT_T).map(fn { _ => T::Unit }) + + tok(@lex.INT_T).map(fn { _ => T::Int }) + + tok(@lex.DOUBLE_T).map(fn { _ => T::Double }) + + ( + tok(@lex.ARRAY) >> + tok(@lex.LBKT) >> + ref(type_ref).map(T::Array) << + tok(@lex.RBKT) + ) + + lift2( + fn(args, ret) { T::Fun(args, ret) }, + tok(@lex.LPAREN) >> sep_list1(tok(@lex.COMMA), ref(type_ref)), + tok(@lex.RPAREN) >> tok(@lex.ARROW) >> ref(type_ref), + ) + ( - Ok( - ( - FnDecl(Ok(name), params, return_type, fn_body), - { src_start: all_start, src_end: all_end }, - ), - ), - view, + tok(@lex.LPAREN) >> + sep_list1(tok(@lex.COMMA), ref(type_ref)).map( + fn { + [ty] => ty + tys => T::Tuple(tys) + }, + ) << + tok(@lex.RPAREN) ) - } -} - -fn id( - view : ArrayView[(@lex.Token, @lex.Loc, @lex.Loc)] -) -> (ID, ArrayView[(@lex.Token, @lex.Loc, @lex.Loc)]) { - match view { - [(@lex.ID(id), id_s, id_e), .. as view] => - (Ok((id, { src_start: id_s, src_end: Some(id_e) })), view) - [tok, ..] => (Err(Unexpected(tok)), view) - [] => (Err(EarlyEOF), view) - } -} - -fn top_let( - view : ArrayView[(@lex.Token, @lex.Loc, @lex.Loc)] -) -> (Top, ArrayView[(@lex.Token, @lex.Loc, @lex.Loc)]) { - guard let (Some(all_start), view) = consume_head(@lex.LET, view) else { - _ => return (Err(Unreachable), view) - } - let (name, view) = id(view) - let (_, view) = consume(@lex.COLON, view) - let (_type, view) = _type(view) - let (_, view) = consume(@lex.EQ, view) - let (expr, view) = expression(view) - let (all_end, view) = consume(@lex.SEMICOL, view) - ( - Ok((LetDecl(name, _type, expr), { src_start: all_start, src_end: all_end })), - view, - ) -} - -fn params_typed( - view : ArrayView[(@lex.Token, @lex.Loc, @lex.Loc)] -) -> - ( - Result[Array[(ID, Type)], ParseError], - ArrayView[(@lex.Token, @lex.Loc, @lex.Loc)], - ) { - let view = match view { - [(@lex.LPAREN, _, _), .. as view] => view - [tok, .. as view] => return (Err(Unexpected(tok)), view) - [] => return (Err(EarlyEOF), view) - } - let result : Array[(ID, Type)] = [] - loop view { - [(@lex.RPAREN, _, _), .. as view] => break (Ok(result), view) - [(@lex.ID(_), _, _), ..] => { - let (name, view) = id(view) - let (_, view) = consume(@lex.COLON, view) - let (_type, view) = _type(view) - result.push((name, _type)) - continue view - } - [tok, .. as view] => break (Err(Unexpected(tok)), view) - [] => break (Err(ExpectButEOF(@lex.RPAREN)), view) - } -} -fn take_end_maybe[T](v : Result[(T, Ann), ParseError]) -> @lex.Loc? { - match v { - Ok((_, { src_end: Some(maybe_end), .. })) => Some(maybe_end) - _ => None - } -} - -//type Type Result[(TypeNaked, Ann), ParseError] -fn _type( - view : ArrayView[(@lex.Token, @lex.Loc, @lex.Loc)] -) -> (Type, ArrayView[(@lex.Token, @lex.Loc, @lex.Loc)]) { - match view { - [(@lex.UNIT_T, start, end), .. as rest] => - (Ok((TUnit, { src_start: start, src_end: Some(end) })), rest) - [(@lex.BOOL_T, start, end), .. as rest] => - (Ok((TBool, { src_start: start, src_end: Some(end) })), rest) - [(@lex.INT_T, start, end), .. as rest] => - (Ok((TInt, { src_start: start, src_end: Some(end) })), rest) - [(@lex.DOUBLE_T, start, end), .. as rest] => - (Ok((TDouble, { src_start: start, src_end: Some(end) })), rest) - [(@lex.ARRAY, start, _), .. as view] => { - let (_, view) = consume(@lex.LBKT, view) - let (type_inner, view) = _type(view) - let type_inner = type_inner - let (all_end, view) = consume(@lex.RBKT, view) - let type_array = ( - TArray(type_inner), - { src_start: start, src_end: all_end }, - ) - (Ok(type_array), view) - } - [(@lex.LPAREN, start, _), .. as view] => { - let (type_i, view) = _type(view) - let acc = [type_i] - let (all_end, view) = loop view { - [(@lex.RPAREN, _, all_end), .. as view] => break (Some(all_end), view) - [(@lex.COMMA, _, _), .. as view] => { - let (type_i, view) = _type(view) - acc.push(type_i) - continue view - } - [(tok, s, e), .. as view] => { - acc.push(Err(Unexpected((tok, s, e)))) - break (None, view) - } - [] => { - acc.push(Err(EarlyEOF)) - break (None, view) - } - } - match view { - [(@lex.ARROW, _, _), .. as view] => { - let (return_ty, view) = _type(view) - let all_end = take_end_maybe(return_ty._) - ( - Ok( - ( - TFunction(acc, return_ty), - { src_start: start, src_end: all_end }, - ), - ), - view, - ) - } - view => - (Ok((TTuple(acc), { src_start: start, src_end: all_end })), view) - } - } - [(tok, s, e), .. as view] => return (Err(Unexpected((tok, s, e))), view) - [] => return (Err(EarlyEOF), view) - } -} - -fn stmt( - view : ArrayView[(@lex.Token, @lex.Loc, @lex.Loc)] -) -> (Stmt, ArrayView[(@lex.Token, @lex.Loc, @lex.Loc)]) { - let non_exp_stmts : Array[StmtHead] = [] - let src_start = match view { - [(_, _all_start, _), ..] => _all_start - [] => return (Err(EarlyEOF), view) - } - let (last_exp, rest_view) = loop view { - [(@lex.LET, all_start, _), .. as view] => - match view { - [(@lex.ID(_), _, _), ..] => { - let (id, view) = id(view) - let (ty, view) = match view { - [(@lex.EQ, _, _), .. as view] => (None, view) - view => { - let (_, view) = consume(@lex.COLON, view) - let (ty, view) = _type(view) - let (_, view) = consume(@lex.EQ, view) - (Some(ty), view) - } - } - let (value_exp, view) = expression(view) - let (all_end, view) = consume(@lex.SEMICOL, view) - non_exp_stmts.push( - Ok( - ( - Let(id, ty, value_exp), - { src_start: all_start, src_end: all_end }, - ), - ), - ) - continue view - } - [(@lex.LPAREN, _, _), .. as view] => { - let id_tuples : Array[ID] = [] - let mut view = view - while true { - let (name, _view) = id(view) - id_tuples.push(name) - match _view { - [(@lex.RPAREN, _, _), .. as _view] => { - view = _view - break - } - [(@lex.COMMA, _, _), .. as _view] => view = _view - [(tok, s, e), .. as _view] => { - id_tuples.push(Err(Unexpected((tok, s, e)))) - view = _view - break - } - [] => { - id_tuples.push(Err(EarlyEOF)) - break - } - } - } - let (ty, view) = match view { - [(@lex.EQ, _, _), .. as view] => (None, view) - view => { - let (_, view) = consume(@lex.COLON, view) - let (ty, view) = _type(view) - let (_, view) = consume(@lex.EQ, view) - (Some(ty), view) - } - } - let (value_exp, view) = expression(view) - let (all_end, view) = consume(@lex.SEMICOL, view) - non_exp_stmts.push( - Ok( - ( - LetTuple(id_tuples, ty, value_exp), - { src_start: all_start, src_end: all_end }, - ), - ), - ) - continue view - } - [tok, .. as view] => { - non_exp_stmts.push(Err(Unexpected(tok))) - continue view - } - [] => { - non_exp_stmts.push(Err(EarlyEOF)) - break (Err(EarlyEOF), view) - } - } - [(@lex.FN, all_start, _), .. as view] => { - let (fn_id, view) = id(view) - let (_, view) = consume(@lex.LPAREN, view) - let params : Array[(ID, Type?)] = [] - let view = loop view { - [(@lex.RPAREN, _, _), .. as view] => break view - view => { - let (param_id, view) = id(view) - let (param_ty, view) = match view { - [(@lex.RPAREN, _, _), ..] => (None, view) // don't consume RPAREN - [(@lex.COMMA, _, _), .. as view] => (None, view) - [] as view => { - params.push((Err(EarlyEOF), None)) - break view - } - view => { - let (_, view) = consume(@lex.COLON, view) - let (ty, view) = _type(view) - (Some(ty), view) - } - } - params.push((param_id, param_ty)) - continue view - } - } - let (return_ty, view) = match view { - [(@lex.ARROW, _, _), .. as view] => { - let (ty, view) = _type(view) - (Some(ty), view) - } - view => (None, view) - } - let (_, view) = consume(@lex.LBRACE, view) - let (stmt, view) = stmt(view) - let (_, view) = consume(@lex.RBRACE, view) - let (all_end, view) = consume(@lex.SEMICOL, view) - //return (Err(EarlyEOF), view) - non_exp_stmts.push( - Ok( - ( - NontopFn(fn_id, params, return_ty, stmt), - { src_start: all_start, src_end: all_end }, - ), - ), - ) - continue view - } - [(_, all_start, _), ..] as view => { - // consumes expression - let (value_exp, view) = expression(view) - match view { - [(@lex.EQ, _, _), .. as view] => { - let (rhs, view) = expression(view) - let (all_end, view) = consume(@lex.SEMICOL, view) - non_exp_stmts.push( - Ok( - ( - Assign(value_exp, rhs), - { src_start: all_start, src_end: all_end }, - ), - ), - ) - continue view - } - view => break (value_exp._, view) - } - } - [] => (Err(EarlyEOF), view) - } - let src_end = take_end_maybe(last_exp) - (Ok((non_exp_stmts, last_exp, { src_start, src_end })), rest_view) -} - -fn expression( - view : ArrayView[(@lex.Token, @lex.Loc, @lex.Loc)] -) -> (Exp, ArrayView[(@lex.Token, @lex.Loc, @lex.Loc)]) { - let sub = add_expr - let all_start = match view { - [(_, all_start, _), ..] => all_start - _ => return (Err(EarlyEOF), view) - } - let (lhs, view) = sub(view) - let (op_rel, view) : (Binop, ArrayView[(@lex.Token, @lex.Loc, @lex.Loc)]) = match - view { - [(@lex.EQ, op_s, op_e), .. as view] => - (Ok((Eq, { src_start: op_s, src_end: Some(op_e) })), view) - [(@lex.LE, op_s, op_e), .. as view] => - (Ok((Le, { src_start: op_s, src_end: Some(op_e) })), view) - _ => return (lhs, view) - } - let (rhs, view) = sub(view) - let all_end = take_end_maybe(rhs._) - ( - Ok((Binary(op_rel, lhs, rhs), { src_start: all_start, src_end: all_end })), - view, + // Value + let value_ref : Ref[PS] = { val: empty() } + value_ref.val = ( + tok(@lex.LPAREN) >> tok(@lex.RPAREN).map(fn { _ => S::Unit }) + ) + + ( + tok(@lex.LPAREN) >> + sep_list1(tok(@lex.COMMA), ref(expr_ref)).map( + fn { + [x] => x + tuple => S::Tuple(tuple) + }, + ) << + tok(@lex.RPAREN) + ) + + block_expr + + bool.map(S::Bool) + + (tok(@lex.SUB) >> ref(value_ref).map(fn { x => S::Neg(x, kind=None) })) + + double.map(S::Double) + + int.map(S::Int) + + ( + tok(@lex.NOT) >> + tok(@lex.LPAREN) >> + ref(expr_ref).map(S::Not) << + tok(@lex.RPAREN) + ) + + ( + tok(@lex.ARRAY) >> + tok(@lex.COLON) >> + tok(@lex.COLON) >> + id_p(fn(s) { s == "make" }) >> + tok(@lex.LPAREN) >> + lift2( + fn(e1, e2) { S::Array(e1, e2) }, + ref(expr_ref), + tok(@lex.COMMA) >> ref(expr_ref), + ) << + tok(@lex.RPAREN) + ) + + id.map(S::Var) + + // Get or apply + let get_or_apply_postfix : Parser[GetApplyPostFix] = ( + tok(@lex.LBKT) >> + ref(expr_ref).map(GetApplyPostFix::Index) << + tok(@lex.RBKT) + ) + + ( + tok(@lex.LPAREN) >> + sep_list(tok(@lex.COMMA), ref(expr_ref)).map(GetApplyPostFix::Apply) << + tok(@lex.RPAREN) + ) + let get_or_apply : PS = lift2( + merge_postfix, + ref(value_ref), + many(get_or_apply_postfix), ) -} -fn add_expr( - view : ArrayView[(@lex.Token, @lex.Loc, @lex.Loc)] -) -> (Exp, ArrayView[(@lex.Token, @lex.Loc, @lex.Loc)]) { - let sub = mul_expr - let all_start = match view { - [(_, all_start, _), ..] => all_start - _ => return (Err(EarlyEOF), view) - } - let (lhs, view) = sub(view) - let mut lhs = lhs - let mut view = view - while true { - let (op_rel, _view) : (Binop, ArrayView[(@lex.Token, @lex.Loc, @lex.Loc)]) = match - view { - [(@lex.ADD, op_s, op_e), .. as _view] => - (Ok((Add, { src_start: op_s, src_end: Some(op_e) })), _view) - [(@lex.SUB, op_s, op_e), .. as _view] => - (Ok((Sub, { src_start: op_s, src_end: Some(op_e) })), _view) - _ => return (lhs, view) - } - let (rhs, _view) = sub(_view) - view = _view - let all_end = take_end_maybe(rhs._) - lhs = Ok( - (Binary(op_rel, lhs, rhs), { src_start: all_start, src_end: all_end }), + // If + let if_ : PS = get_or_apply + + lift3( + fn(_test, _then, _else) { S::If(_test, _then, _else) }, + tok(@lex.IF) >> ref(expr_ref), + block_expr, + (tok(@lex.ELSE) >> block_expr) + epsilon().map(fn { _ => S::Unit }), ) - } - (lhs, view) // this is not used at all but the type system requires it to function well -} -fn mul_expr( - view : ArrayView[(@lex.Token, @lex.Loc, @lex.Loc)] -) -> (Exp, ArrayView[(@lex.Token, @lex.Loc, @lex.Loc)]) { - let sub = if_expr - let all_start = match view { - [(_, all_start, _), ..] => all_start - _ => return (Err(EarlyEOF), view) - } - let (lhs, view) = sub(view) - let mut lhs = lhs - let mut view = view - while true { - let (op_rel, _view) : (Binop, ArrayView[(@lex.Token, @lex.Loc, @lex.Loc)]) = match - view { - [(@lex.MUL, op_s, op_e), .. as _view] => - (Ok((Mul, { src_start: op_s, src_end: Some(op_e) })), _view) - [(@lex.DIV, op_s, op_e), .. as _view] => - (Ok((Div, { src_start: op_s, src_end: Some(op_e) })), _view) - _ => return (lhs, view) - } - let (rhs, _view) = sub(_view) - view = _view - let all_end = take_end_maybe(rhs._) - lhs = Ok( - (Binary(op_rel, lhs, rhs), { src_start: all_start, src_end: all_end }), + // Mul + let mul_op = tok(@lex.MUL).map(fn { _ => B::Mul }) + + tok(@lex.DIV).map(fn { _ => B::Div }) + let mul_ : PS = tier_left(mul_op, if_) + + // Add + let add_op = tok(@lex.ADD).map(fn { _ => B::Add }) + + tok(@lex.SUB).map(fn { _ => B::Sub }) + let add_ : PS = tier_left(add_op, mul_) + + // Cmp + let cmp_op = tok(@lex.LE).map( + fn { _ => fn(lhs : S, rhs : S) { S::LE(lhs, rhs) } }, + ) + + tok(@lex.EQ).map(fn { _ => fn(lhs : S, rhs : S) { S::Eq(lhs, rhs) } }) + let cmp_ : PS = lift3(fn(lhs, op, rhs) { op(lhs, rhs) }, add_, cmp_op, add_) + + add_ + expr_ref.val = cmp_ + + // Statement + let type_annotation = maybe(tok(@lex.COLON) >> ref(type_ref)) + let param = lift2( + fn(id : String, ty : T?) { (id, fix_type(ty)) }, + id, + type_annotation, + ) + let nontop_head = lift2_maybe( + fn(get_expr, rhs) { + match get_expr { + S::Get(_, _) => () + _ => return None + } + Some(fn(rest) { S::Put(get_expr, rhs, rest) }) + }, + get_or_apply, + tok(@lex.ASSIGN) >> ref(expr_ref), + ) + + lift4( + fn(id : String, args : Array[(String, T)], ret_ty : T?, body : S) { + fn(rest) { + S::LetRec({ name: (id, fix_type(ret_ty)), args, body }, rest) + } + }, + tok(@lex.FN) >> id, + tok(@lex.LPAREN) >> sep_list(tok(@lex.COMMA), param) << tok(@lex.RPAREN), + maybe(tok(@lex.ARROW) >> ref(type_ref)), + block_expr, ) - } - (lhs, view) // this is not used at all but the type system requires it to function well -} - -test "how you return from a while" { - fn t() -> Int { - while true { - return 1 - } - 2 - } - - assert_eq!(t(), 1) -} - -fn block_expr( - view : ArrayView[(@lex.Token, @lex.Loc, @lex.Loc)] -) -> (Stmt, ArrayView[(@lex.Token, @lex.Loc, @lex.Loc)]) { - let (_, view) = consume(@lex.LBRACE, view) - let (_stmt, view) = stmt(view) - let (_, view) = consume(@lex.RBRACE, view) - (_stmt, view) -} - -fn if_expr( - view : ArrayView[(@lex.Token, @lex.Loc, @lex.Loc)] -) -> (Exp, ArrayView[(@lex.Token, @lex.Loc, @lex.Loc)]) { - match view { - [(@lex.IF, all_start, _), .. as view] => { - let (cond, view) = expression(view) - let (then_clause, view) = block_expr(view) - let (else_clause, view) = match view { - [(@lex.ELSE, _, _), .. as view] => { - let (else_clause, view) = block_expr(view) - (Some(else_clause), view) - } - view => (None, view) - } - let naked = If(cond, then_clause, else_clause) - (Ok((naked, { src_start: all_start, src_end: None })), view) - } - view => get_apply_expr(view) - } -} - -fn get_apply_expr( - view : ArrayView[(@lex.Token, @lex.Loc, @lex.Loc)] -) -> (Exp, ArrayView[(@lex.Token, @lex.Loc, @lex.Loc)]) { - let all_start = match view { - [(_, all_start, _), ..] => all_start - _ => return (Err(EarlyEOF), view) - } - let (_value, view) = value_expr(view) - let mut acc = _value - let mut view = view - while true { - match view { - [(@lex.LBKT, _, _), .. as _view] => { - let (accessor, _view) = expression(_view) - let (cur_end, _view) = consume(@lex.RBKT, _view) - acc = Ok( - (Index(acc, accessor), { src_start: all_start, src_end: cur_end }), - ) - view = _view - } - [(@lex.LPAREN, _, _), .. as _view] => { - let params : Array[Exp] = [] - let mut cur_end = None - match _view { - [(@lex.RPAREN, _, _end), .. as _view] => { - cur_end = Some(_end) - view = _view - } - _view => - while true { - let (exp, _view) = expression(_view) - params.push(exp) - match _view { - [(@lex.COMMA, _, _), .. as _view] => { - view = _view - continue - } - _view => { - // otherwise we assume we hit the end - let (_end, _view) = consume(@lex.RPAREN, _view) - cur_end = _end - view = _view - break - } - } + let stmt_head = lift3( + fn(id, ty, body) { fn(rest) { S::Let((id, fix_type(ty)), body, rest) } }, + tok(@lex.LET) >> id, + type_annotation, + tok(@lex.ASSIGN) >> ref(expr_ref), + ) + + lift3_maybe( + fn(ids : Array[String], ty : T?, rhs) -> ((S) -> S)? { + let ids_typed = match ty { + Some(T::Tuple(tys)) => + if tys.length() != ids.length() { + return None + } else { + ids.mapi(fn(i, name) { (name, tys[i]) }) } - } - acc = Ok( - (Apply(acc, params), { src_start: all_start, src_end: cur_end }), - ) - } - _ => break - } - } - (acc, view) -} - -fn value_expr( - view : ArrayView[(@lex.Token, @lex.Loc, @lex.Loc)] -) -> (Exp, ArrayView[(@lex.Token, @lex.Loc, @lex.Loc)]) { - match view { - [(@lex.LPAREN, all_start, _), (@lex.RPAREN, _, all_end), .. as view] => - (Ok((Atom(Unit), { src_start: all_start, src_end: Some(all_end) })), view) - [(@lex.LPAREN, all_start, _), .. as view] => { - let (t_first, view) = expression(view) - let tuple : Array[Exp] = [t_first] - let mut view = view - let mut all_end = None - while true { - match view { - [(@lex.RPAREN, _, _all_end), .. as _view] => { - all_end = Some(_all_end) - view = _view - break - } - _view => { - let (_, _view) = consume(@lex.COMMA, _view) - let (t_i, _view) = expression(view) - tuple.push(t_i) - view = _view - } - } - } - match tuple { - [single] => (single, view) - _ => - (Ok((Tuple(tuple), { src_start: all_start, src_end: all_end })), view) - } - } - [(@lex.BOOL(b), all_start, all_end), .. as view] => - ( - Ok((Atom(Bool(b)), { src_start: all_start, src_end: Some(all_end) })), - view, - ) - [(@lex.ID(_), _, _), ..] as view => { - let (_id, view) = id(view) - //let dummy_ann = { src_start: @lex.new_loc(), src_end: None } - //(Ok((Var(Ok(("wow", dummy_ann))), dummy_ann)), view) - match _id._ { - Ok((_, ann)) => (Ok((Var(_id), ann)), view) - Err(err) => (Err(err), view) - } - } - [(@lex.LBRACE, all_start, _), ..] as view => { - let (stmt, rest) = block_expr(view) - let all_end = match stmt._ { - Ok(a) => - match a.1._ { - Ok(b) => b.1.src_end - _ => None - } - _ => None - } - match stmt._ { - Err(e) => (Err(e), rest) - Ok(_stmt) => - (Ok((Block(stmt), { src_start: all_start, src_end: all_end })), rest) - } - } - [(@lex.SUB, all_start, _), .. as view] => { - let (inner, view) = value_expr(view) - let all_end = take_end_maybe(inner._) - ( - Ok((Unary(Neg, inner), { src_start: all_start, src_end: all_end })), - view, - ) - } - [(@lex.F64(f), all_start, all_end), .. as view] => - ( - Ok((Atom(F64(f)), { src_start: all_start, src_end: Some(all_end) })), - view, - ) - [(@lex.I32(i), all_start, all_end), .. as view] => - ( - Ok((Atom(I32(i)), { src_start: all_start, src_end: Some(all_end) })), - view, - ) - [(@lex.NOT, all_start, _), .. as view] => { - let (_, view) = consume(@lex.LPAREN, view) - let (inner, view) = expression(view) - let (all_end, view) = consume(@lex.RPAREN, view) - ( - Ok((Unary(Not, inner), { src_start: all_start, src_end: all_end })), - view, - ) - } - //'Array' ':' ':' 'make' '(' expr ',' expr ')'; // Array::make(x, y) - [(@lex.ARRAY, all_start, _), .. as view] => { - let (_, view) = consume(@lex.COLON, view) - let (_, view) = consume(@lex.COLON, view) - let (_, view) = consume(@lex.MAKE, view) - let (_, view) = consume(@lex.LPAREN, view) - let (len, view) = expression(view) - let (_, view) = consume(@lex.COMMA, view) - let (ele, view) = expression(view) - let (all_end, view) = consume(@lex.RPAREN, view) - ( - Ok((MakeArray(len, ele), { src_start: all_start, src_end: all_end })), - view, - ) - } - [(tok, s, e), .. as view] => (Err(Unexpected((tok, s, e))), view) - [] => (Err(EarlyEOF), view) - } + Some(_) => return None + None => ids.map(fn { name => (name, T::Var({ val: None })) }) + } + Some(fn(rest) { S::LetTuple(ids_typed, rhs, rest) }) + }, + tok(@lex.LET) >> + tok(@lex.LPAREN) >> + sep_list1(tok(@lex.COMMA), id) << + tok(@lex.RPAREN), + type_annotation, + tok(@lex.ASSIGN) >> ref(expr_ref), + ) + stmt_ref.val = fold_right( + ref(expr_ref), + stmt_head + nontop_head, + tok(@lex.SEMICOL).map(fn { _ => fn(u, v) { u(v) } }), + ) + let top_head = lift2( + fn(id : String, body : S) { + fn(rest) { S::LetRec({ name: (id, T::Unit), args: [], body }, rest) } + }, + tok(@lex.FN) >> id_p(fn(s) { s == "main" || s == "init" }), + block_expr, + ) + + lift4( + fn(id : String, args : Array[(String, T)], ret_ty : T?, body : S) { + fn(rest) { + S::LetRec({ name: (id, fix_type(ret_ty)), args, body }, rest) + } + }, + tok(@lex.FN) >> id_p(fn(s) { s != "main" && s != "init" }), + tok(@lex.LPAREN) >> sep_list(tok(@lex.COMMA), param) << tok(@lex.RPAREN), + maybe(tok(@lex.ARROW) >> ref(type_ref)), + block_expr, + ) + fold_right( + tok(@lex.EOF).map(fn { _ => S::Unit }), + // NOTE: top level definitions must start at the beginning of line + line_start >> (top_head + stmt_head), + tok(@lex.SEMICOL).map(fn { _ => fn(u, v) { u(v) } }), + ) } diff --git a/src/parser/parser.mbti b/src/parser/parser.mbti deleted file mode 100644 index 92ee7b1..0000000 --- a/src/parser/parser.mbti +++ /dev/null @@ -1,50 +0,0 @@ -package moonbitlang/minimbt/parser - -alias @moonbitlang/minimbt/lex as @lex - -// Values -fn program(ArrayView[(@lex.Token, @lex.Loc, @lex.Loc)]) -> Program - -let recoverable_errors : Array[ParseError] - -// Types and methods -type Ann - -type Binop - -type BinopTag - -type Exp - -type ExpNaked - -type ID - -type ParseError - -type Program - -type Stmt - -type StmtHead - -type StmtHeadNaked - -type Top - -type TopNaked - -type Type - -type TypeNaked - -type Unop - -type Value - -// Type aliases - -// Traits - -// Extension Methods - diff --git a/src/parser/parser_test_inline.mbt b/src/parser/parser_test_inline.mbt index bb3b383..a44ab3f 100644 --- a/src/parser/parser_test_inline.mbt +++ b/src/parser/parser_test_inline.mbt @@ -1,85 +1,121 @@ -test "array is mutable" { - let a = [1, 2, 3] - (fn(arr : Array[Int]) { - arr[0] = 3 - ignore(arr.pop()) - })(a) - assert_eq!(a, [3, 2]) -} - -test "deque is mutable" { - let q : @deque.T[Int] = @deque.of([1, 2, 3]) - (fn(q : @deque.T[Int]) { ignore(q.pop_back()) })(q) - assert_eq!(q.iter().collect(), [1, 2]) -} - -fn fst[U, V, W](pair : (U, V, W)) -> U { - match pair { - (a, _, _) => a - } -} - -test "parse a simple expression" { - let input = - #|x + y - let tokens = @lex.lex_string!(input) - inspect!( - tokens.map(fst), - content= - #|[ID("x"), ADD, ID("y")] - , - ) - let (expr, _) = expression(tokens[:]) - inspect!( - expr, - content= - #|(x+y) - , - ) -} - -test "parse a statement" { - let tokens = @lex.lex_string!( +test "parse simple program" { + let program = + #|fn make_adder(x: Int) -> (Int) -> Int { #| fn adder(y: Int) -> Int { #| x + y #| }; #| adder + #|}; + #| + #|fn main { + #| print_int((make_adder(3))(7)) + #|}; + let tokens = @lex.lex_string!(program) + inspect!( + tokens.map(fn { _1 => _1.0 }), + content= + #|[FN, ID("make_adder"), LPAREN, ID("x"), COLON, INT_T, RPAREN, ARROW, LPAREN, INT_T, RPAREN, ARROW, INT_T, LBRACE, FN, ID("adder"), LPAREN, ID("y"), COLON, INT_T, RPAREN, ARROW, INT_T, LBRACE, ID("x"), ADD, ID("y"), RBRACE, SEMICOL, ID("adder"), RBRACE, SEMICOL, FN, ID("main"), LBRACE, ID("print_int"), LPAREN, LPAREN, ID("make_adder"), LPAREN, I32(3), RPAREN, RPAREN, LPAREN, I32(7), RPAREN, RPAREN, RBRACE, SEMICOL, EOF] , ) + let (ast, _) = parser().parse(tokens[:]) inspect!( - tokens.map(fst), + ast, content= - #|[FN, ID("adder"), LPAREN, ID("y"), COLON, INT_T, RPAREN, ARROW, INT_T, LBRACE, ID("x"), ADD, ID("y"), RBRACE, SEMICOL, ID("adder")] + #|Some(LetRec({name: ("make_adder", Fun([Int], Int)), args: [("x", Int)], body: LetRec({name: ("adder", Int), args: [("y", Int)], body: Prim(Var("x"), Var("y"), Add, kind=None)}, Var("adder"))}, LetRec({name: ("main", Unit), args: [], body: App(Var("print_int"), [App(App(Var("make_adder"), [Int(3)]), [Int(7)])])}, Unit))) , ) - let (statement, _) = stmt(tokens[:]) +} + +test "parse inprod-loop.mbt" { + let src = + #|fn inprod(v1: Array[Double], v2: Array[Double], acc: Double, i: Int) -> Double { + #| if 0 <= i { + #| inprod(v1, v2, acc + v1[i] * v2[i], i - 1) + #| } else { + #| acc + #| } + #|}; + #| + #|fn main { + #| let v1 = Array::make(3, 1.23); + #| let v2 = Array::make(3, 4.56); + #| print_int(truncate(1000000.0 * inprod(v1, v2, 0.0, 2))) + #|}; inspect!( - statement, + parse_program(src), content= - #|fn adder(y: Int) -> Int{(x+y)}; adder + #|LetRec({name: ("inprod", Double), args: [("v1", Array(Double)), ("v2", Array(Double)), ("acc", Double), ("i", Int)], body: If(LE(Int(0), Var("i")), App(Var("inprod"), [Var("v1"), Var("v2"), Prim(Var("acc"), Prim(Get(Var("v1"), Var("i")), Get(Var("v2"), Var("i")), Mul, kind=None), Add, kind=None), Prim(Var("i"), Int(1), Sub, kind=None)]), Var("acc"))}, LetRec({name: ("main", Unit), args: [], body: Let(("v1", Var({val: None})), Array(Int(3), Double(1.23)), Let(("v2", Var({val: None})), Array(Int(3), Double(4.56)), App(Var("print_int"), [App(Var("truncate"), [Prim(Double(1000000), App(Var("inprod"), [Var("v1"), Var("v2"), Double(0), Int(2)]), Mul, kind=None)])])))}, Unit)) , ) } -test "parse a program" { - let tokens = @lex.lex_string!( - #|fn make_adder(x: Int) -> (Int) -> Int { - #| fn adder(y: Int) -> Int { - #| x + y +test "parse matmul.mbt" { + let src = + #|fn matmul(l: Int, m: Int, n: Int, a: Array[Array[Double]], b: Array[Array[Double]], c: Array[Array[Double]]) -> Unit { + #| fn loop1(i: Int) -> Unit { + #| if 0 <= i { + #| fn loop2(j: Int) -> Unit { + #| if 0 <= j { + #| fn loop3(k: Int) -> Unit { + #| if 0 <= k { + #| c[i][j] = c[i][j] + a[i][k] * b[k][j]; + #| loop3(k - 1) + #| } else { + #| () + #| } + #| }; + #| let _ = loop3(m - 1); + #| loop2(j - 1) + #| } else { + #| () + #| } + #| }; + #| let _ = loop2(n - 1); + #| loop1(i - 1) + #| } else { + #| () + #| } #| }; - #| adder + #| loop1(l - 1) #|}; #| #|fn main { - #| print_int((make_adder(3))(7)) + #| let dummy = Array::make(0, 0.0); + #| fn make(m: Int, n: Int) -> Array[Array[Double]] { + #| let mat = Array::make(m, dummy); + #| fn init(i: Int) -> Unit { + #| if 0 <= i { + #| mat[i] = Array::make(n, 0.0); + #| init(i - 1) + #| } else { + #| () + #| } + #| }; + #| let _ = init(m - 1); + #| mat + #| }; + #| let a = make(2, 3); + #| let b = make(3, 2); + #| let c = make(2, 2); + #| a[0][0] = 1.0; a[0][1] = 2.0; a[0][2] = 3.0; + #| a[1][0] = 4.0; a[1][1] = 5.0; a[1][2] = 6.0; + #| b[0][0] = 7.0; b[0][1] = 8.0; + #| b[1][0] = 9.0; b[1][1] = 10.0; + #| b[2][0] = 11.0; b[2][1] = 12.0; + #| let _ = matmul(2,3,2,a,b,c); + #| let _ = print_int(truncate(c[0][0])); + #| let _ = print_endline(); + #| let _ = print_int(truncate(c[0][1])); + #| let _ = print_endline(); + #| let _ = print_int(truncate(c[1][0])); + #| let _ = print_endline(); + #| let _ = print_int(truncate(c[1][1])); + #| () #|}; - , - ) - let program = program(tokens[:]) inspect!( - program, + parse_program(src), content= - #|[fn make_adder((x, Int)) -> (Int) -> Int {fn adder(y: Int) -> Int{(x+y)}; adder}, fn main {print_int(make_adder(3)(7))}] + #|LetRec({name: ("matmul", Unit), args: [("l", Int), ("m", Int), ("n", Int), ("a", Array(Array(Double))), ("b", Array(Array(Double))), ("c", Array(Array(Double)))], body: LetRec({name: ("loop1", Unit), args: [("i", Int)], body: If(LE(Int(0), Var("i")), LetRec({name: ("loop2", Unit), args: [("j", Int)], body: If(LE(Int(0), Var("j")), LetRec({name: ("loop3", Unit), args: [("k", Int)], body: If(LE(Int(0), Var("k")), Put(Get(Get(Var("c"), Var("i")), Var("j")), Prim(Get(Get(Var("c"), Var("i")), Var("j")), Prim(Get(Get(Var("a"), Var("i")), Var("k")), Get(Get(Var("b"), Var("k")), Var("j")), Mul, kind=None), Add, kind=None), App(Var("loop3"), [Prim(Var("k"), Int(1), Sub, kind=None)])), Unit)}, Let(("_", Var({val: None})), App(Var("loop3"), [Prim(Var("m"), Int(1), Sub, kind=None)]), App(Var("loop2"), [Prim(Var("j"), Int(1), Sub, kind=None)]))), Unit)}, Let(("_", Var({val: None})), App(Var("loop2"), [Prim(Var("n"), Int(1), Sub, kind=None)]), App(Var("loop1"), [Prim(Var("i"), Int(1), Sub, kind=None)]))), Unit)}, App(Var("loop1"), [Prim(Var("l"), Int(1), Sub, kind=None)]))}, LetRec({name: ("main", Unit), args: [], body: Let(("dummy", Var({val: None})), Array(Int(0), Double(0)), LetRec({name: ("make", Array(Array(Double))), args: [("m", Int), ("n", Int)], body: Let(("mat", Var({val: None})), Array(Var("m"), Var("dummy")), LetRec({name: ("init", Unit), args: [("i", Int)], body: If(LE(Int(0), Var("i")), Put(Get(Var("mat"), Var("i")), Array(Var("n"), Double(0)), App(Var("init"), [Prim(Var("i"), Int(1), Sub, kind=None)])), Unit)}, Let(("_", Var({val: None})), App(Var("init"), [Prim(Var("m"), Int(1), Sub, kind=None)]), Var("mat"))))}, Let(("a", Var({val: None})), App(Var("make"), [Int(2), Int(3)]), Let(("b", Var({val: None})), App(Var("make"), [Int(3), Int(2)]), Let(("c", Var({val: None})), App(Var("make"), [Int(2), Int(2)]), Put(Get(Get(Var("a"), Int(0)), Int(0)), Double(1), Put(Get(Get(Var("a"), Int(0)), Int(1)), Double(2), Put(Get(Get(Var("a"), Int(0)), Int(2)), Double(3), Put(Get(Get(Var("a"), Int(1)), Int(0)), Double(4), Put(Get(Get(Var("a"), Int(1)), Int(1)), Double(5), Put(Get(Get(Var("a"), Int(1)), Int(2)), Double(6), Put(Get(Get(Var("b"), Int(0)), Int(0)), Double(7), Put(Get(Get(Var("b"), Int(0)), Int(1)), Double(8), Put(Get(Get(Var("b"), Int(1)), Int(0)), Double(9), Put(Get(Get(Var("b"), Int(1)), Int(1)), Double(10), Put(Get(Get(Var("b"), Int(2)), Int(0)), Double(11), Put(Get(Get(Var("b"), Int(2)), Int(1)), Double(12), Let(("_", Var({val: None})), App(Var("matmul"), [Int(2), Int(3), Int(2), Var("a"), Var("b"), Var("c")]), Let(("_", Var({val: None})), App(Var("print_int"), [App(Var("truncate"), [Get(Get(Var("c"), Int(0)), Int(0))])]), Let(("_", Var({val: None})), App(Var("print_endline"), []), Let(("_", Var({val: None})), App(Var("print_int"), [App(Var("truncate"), [Get(Get(Var("c"), Int(0)), Int(1))])]), Let(("_", Var({val: None})), App(Var("print_endline"), []), Let(("_", Var({val: None})), App(Var("print_int"), [App(Var("truncate"), [Get(Get(Var("c"), Int(1)), Int(0))])]), Let(("_", Var({val: None})), App(Var("print_endline"), []), Let(("_", Var({val: None})), App(Var("print_int"), [App(Var("truncate"), [Get(Get(Var("c"), Int(1)), Int(1))])]), Unit)))))))))))))))))))))))))}, Unit)) , ) } diff --git a/src/parser/show_ast.mbt b/src/parser/show_ast.mbt deleted file mode 100644 index af3158d..0000000 --- a/src/parser/show_ast.mbt +++ /dev/null @@ -1,284 +0,0 @@ -impl Show for ID with output(id, logger) { - logger.write_string( - match id._ { - Ok((name, _)) => name - Err(_) => "!" - }, - ) -} - -impl Show for Value with output(v, logger) { - match v { - I32(i) => Show::output(i, logger) - F64(f) => Show::output(f, logger) - Bool(b) => Show::output(b, logger) - Unit => logger.write_string("()") - } -} - -impl Show for Binop with output(bop, logger) { - match bop._ { - Err(_) => logger.write_string("") - Ok((Eq, _)) => logger.write_string("==") - Ok((Le, _)) => logger.write_string("<=") - Ok((Add, _)) => logger.write_char('+') - Ok((Sub, _)) => logger.write_char('-') - Ok((Mul, _)) => logger.write_char('*') - Ok((Div, _)) => logger.write_char('/') - } -} - -impl Show for Exp with output(__exp, logger) { - match __exp._ { - Err(_) => logger.write_char('!') - Ok((Atom(v), _)) => Show::output(v, logger) - Ok((Tuple(exps), _)) => { - logger.write_char('(') - loop exps[:] { - [exp] => { - Show::output(exp, logger) - logger.write_char(')') - break - } - [exp, .. as rest] => { - Show::output(exp, logger) - logger.write_char(',') - continue rest - } - [] => break logger.write_char(')') - } - } - Ok((Unary(Not, inner), _)) => { - logger.write_string("not(") - Show::output(inner, logger) - logger.write_string(")") - } - Ok((Unary(Neg, inner), _)) => { - logger.write_string("-") - Show::output(inner, logger) - } - Ok((Binary(bop, lhs, rhs), _)) => { - logger.write_char('(') - Show::output(lhs, logger) - Show::output(bop, logger) - Show::output(rhs, logger) - logger.write_char(')') - } - Ok((Apply(f, args), _)) => { - Show::output(f, logger) - logger.write_char('(') - loop args[:] { - [arg] => { - Show::output(arg, logger) - logger.write_char(')') - break - } - [arg, .. as rest] => { - Show::output(arg, logger) - logger.write_char(',') - continue rest - } - [] => break logger.write_char(')') - } - } - Ok((If(cond, then_branch, else_branch), _)) => { - logger.write_string("if ") - Show::output(cond, logger) - logger.write_string(" {") - Show::output(then_branch, logger) - logger.write_string("} else {") - Show::output(else_branch, logger) - logger.write_string("}") - } - Ok((Block(stmt), _)) => { - logger.write_string("{") - Show::output(stmt, logger) - logger.write_string("}") - } - Ok((Var(id), _)) => Show::output(id, logger) - Ok((Index(exp, accessor), _)) => { - Show::output(exp, logger) - logger.write_string("[") - Show::output(accessor, logger) - logger.write_string("]") - } - Ok((MakeArray(len, ele), _)) => { - logger.write_string("Array::make(") - Show::output(len, logger) - logger.write_string(",") - Show::output(ele, logger) - logger.write_string(")") - } - } -} - -fn maybe_show_type_ann( - ty : Type?, - logger : Logger, - ~prefix : String = ": " -) -> Unit { - match ty { - Some(ty) => { - logger.write_string(prefix) - Show::output(ty, logger) - } - None => () - } -} - -impl Show for Stmt with output(stmt, logger) { - match stmt._ { - Err(_) => logger.write_string("!") - Ok((heads, last_exp, _)) => { - for head in heads.iter() { - match head._ { - Err(_) => logger.write_string("!;") - Ok((Assign(lhs, rhs), _)) => { - Show::output(lhs, logger) - logger.write_string(" = ") - Show::output(rhs, logger) - } - Ok((NontopFn(name, params, return_ty, body), _)) => { - logger.write_string("fn ") - Show::output(name, logger) - logger.write_string("(") - loop params[:] { - [] => break - [(id, maybe_type)] => { - Show::output(id, logger) - maybe_show_type_ann(maybe_type, logger) - break - } - [(id, maybe_type), .. as rest] => { - Show::output(id, logger) - maybe_show_type_ann(maybe_type, logger) - logger.write_string(", ") - continue rest - } - } - logger.write_string(") ") - maybe_show_type_ann(return_ty, logger, prefix="-> ") - logger.write_string("{") - Show::output(body, logger) - logger.write_string("}; ") - } - Ok((Let(name, ty, rhs), _)) => { - logger.write_string("let ") - Show::output(name, logger) - maybe_show_type_ann(ty, logger) - logger.write_string("= ") - Show::output(rhs, logger) - logger.write_string("; ") - } - Ok((LetTuple(tup, ty, rhs), _)) => { - logger.write_string("let (") - loop tup[:] { - [] => break - [id] => break Show::output(id, logger) - [id, .. as rest] => { - Show::output(id, logger) - logger.write_string(", ") - continue rest - } - } - logger.write_string(")") - maybe_show_type_ann(ty, logger) - logger.write_string("= ") - Show::output(rhs, logger) - logger.write_string("; ") - } - } - } - Show::output(last_exp, logger) - } - } -} - -impl Show for Type with output(ty, logger) { - match ty._ { - Err(_) => logger.write_string("!T") - Ok((TBool, _)) => logger.write_string("Bool") - Ok((TUnit, _)) => logger.write_string("Unit") - Ok((TInt, _)) => logger.write_string("Int") - Ok((TDouble, _)) => logger.write_string("Double") - Ok((TArray(inner), _)) => { - logger.write_string("Array[") - Show::output(inner, logger) - logger.write_string("]") - } - Ok((TTuple(inners), _)) => { - logger.write_string("(") - loop inners[:] { - [] => break - [single] => break Show::output(single, logger) - [hd, .. as rest] => { - Show::output(hd, logger) - logger.write_string(", ") - continue rest - } - } - logger.write_string(")") - } - Ok((TFunction(args, return_ty), _)) => { - logger.write_string("(") - loop args[:] { - [] => break - [single] => break Show::output(single, logger) - [hd, .. as rest] => { - Show::output(hd, logger) - logger.write_string(", ") - continue rest - } - } - logger.write_string(") -> ") - Show::output(return_ty, logger) - } - } -} - -impl Show for Program with output(prog, logger) { Show::output(prog._, logger) } - -impl Show for Top with output(top, logger) { - match top._ { - Err(_) => logger.write_string("!") - Ok((LetDecl(id, ty, exp), _)) => { - logger.write_string("let ") - Show::output(id, logger) - maybe_show_type_ann(Some(ty), logger) - logger.write_string(" = ") - Show::output(exp, logger) - } - Ok((MainDecl(exp), _)) => { - logger.write_string("fn main {") - Show::output(exp, logger) - logger.write_string("}") - } - Ok((InitDecl(exp), _)) => { - logger.write_string("fn init {") - Show::output(exp, logger) - logger.write_string("}") - } - Ok((FnDecl(name, args, return_ty, body), _)) => { - logger.write_string("fn ") - Show::output(name, logger) - logger.write_string("(") - match args { - Err(_) => logger.write_string("!") - Ok(args) => - loop args[:] { - [] => break - [arg] => break Show::output(arg, logger) - [arg, .. as args] => { - Show::output(arg, logger) - continue args - } - } - } - logger.write_string(")") - maybe_show_type_ann(Some(return_ty), logger, prefix=" -> ") - logger.write_string(" {") - Show::output(body, logger) - logger.write_string("}") - } - } -}