diff --git a/cspell.json b/cspell.json index f683c1ec..8396695f 100644 --- a/cspell.json +++ b/cspell.json @@ -44,6 +44,7 @@ "inodes", "insta", "interner", + "ints", "itertools", "ITRS", "kwarg", diff --git a/examples/all_tree.bend b/examples/all_tree.bend index d70dbd2b..8de2403f 100644 --- a/examples/all_tree.bend +++ b/examples/all_tree.bend @@ -16,7 +16,7 @@ def and(a, b): def all(tree): fold tree: case Tree/Node: - return and(tree.lft tree.rgt) + return and(tree.lft, tree.rgt) case Tree/Leaf: return tree.val diff --git a/src/imp/parser.rs b/src/imp/parser.rs index d3991324..b57d2b9e 100644 --- a/src/imp/parser.rs +++ b/src/imp/parser.rs @@ -96,6 +96,7 @@ impl<'a> PyParser<'a> { let ini_idx = *self.index(); let base = match head { + // Tuple or parenthesized expression '(' => { self.advance_one(); let head = self.parse_expr(false)?; @@ -114,41 +115,49 @@ impl<'a> PyParser<'a> { head } } + // Map or Sup '{' => { self.advance_one(); - self.skip_trivia(); - if self.try_consume_exactly("}") { - return Ok(Expr::MapInit { entries: Vec::new() }); + // Empty map + if self.try_consume("}") { + return Ok(Expr::MapInit { entries: vec![] }); } let head = self.parse_expr(false)?; self.skip_trivia(); if self.starts_with(":") { self.parse_map_init(head)? } else { self.parse_sup(head)? } } + // List or Comprehension '[' => self.list_or_comprehension()?, + // Symbol '`' => Expr::Num { val: Num::U24(self.parse_quoted_symbol()?) }, + // String '\"' => { let str = self.parse_quoted_string()?; let val = STRINGS.get(str); Expr::Str { val } } + // Char '\'' => { let chr = self.parse_quoted_char()?; Expr::Num { val: Num::U24(chr as u32 & 0x00ff_ffff) } } + // Unscoped var '$' => { self.advance_one(); let nam = self.parse_bend_name()?; Expr::Chn { nam } } + // Era '*' => { self.advance_one(); Expr::Eraser } + // Number c if is_num_char(c) => { let val = self.parse_number()?; Expr::Num { val } } - // var or postfix + // var _ => { let nam = self.labelled(|p| p.parse_bend_name(), "expression")?; Expr::Var { nam } @@ -178,7 +187,9 @@ impl<'a> PyParser<'a> { } else { args.push(arg); } - self.try_consume(","); + if !self.starts_with(")") { + self.consume(",")?; + } } if args.is_empty() && kwargs.is_empty() { return Ok(base); @@ -202,7 +213,7 @@ impl<'a> PyParser<'a> { // ctr if self.starts_with("{") { if let Expr::Var { nam } = base { - let kwargs = self.list_like(|p| p.data_kwarg(), "{", "}", ",", false, 0)?; + let kwargs = self.list_like(|p| p.data_kwarg(), "{", "}", ",", true, 0)?; return Ok(Expr::Constructor { name: nam, args: Vec::new(), kwargs }); } else { return self.expected_spanned("Constructor name", ini_idx, end_idx); @@ -218,15 +229,18 @@ impl<'a> PyParser<'a> { self.consume(":")?; let val = self.parse_expr(false)?; entries.push((head, val)); - self.try_consume(","); - let tail = self.list_like(|p| p.parse_map_entry(), "", "}", ",", false, 0)?; + self.skip_trivia(); + if !self.starts_with("}") { + self.consume(",")?; + } + let tail = self.list_like(|p| p.parse_map_entry(), "", "}", ",", true, 0)?; entries.extend(tail); Ok(Expr::MapInit { entries }) } fn parse_sup(&mut self, head: Expr) -> ParseResult { let mut els = vec![head]; - let tail = self.list_like(|p| p.parse_expr(false), "", "}", ",", false, 1)?; + let tail = self.list_like(|p| p.parse_expr(false), "", "}", ",", true, 1)?; els.extend(tail); Ok(Expr::Sup { els }) } @@ -274,8 +288,11 @@ impl<'a> PyParser<'a> { } else { // List let mut head = vec![head]; - self.try_consume(","); - let tail = self.list_like(|p| p.parse_expr(false), "", "]", ",", false, 0)?; + self.skip_trivia(); + if !self.starts_with("]") { + self.consume(",")?; + } + let tail = self.list_like(|p| p.parse_expr(false), "", "]", ",", true, 0)?; head.extend(tail); Ok(Expr::Lst { els: head }) } @@ -685,7 +702,9 @@ impl<'a> PyParser<'a> { while !self.starts_with(":") { with.push(self.parse_bend_name()?); self.skip_trivia_inline(); - self.try_consume_exactly(","); + if !self.starts_with(":") { + self.consume_exactly(",")?; + } self.skip_trivia_inline(); } with @@ -721,7 +740,7 @@ impl<'a> PyParser<'a> { /// "else" ":" /// fn parse_bend(&mut self, indent: &mut Indent) -> ParseResult<(Stmt, Indent)> { - let args = self.list_like(|p| p.parse_match_arg(), "", ":", ",", false, 1)?; + let args = self.list_like(|p| p.parse_match_arg(), "", ":", ",", true, 1)?; let (bind, init) = args.into_iter().unzip(); self.consume_new_line()?; indent.enter_level(); @@ -822,7 +841,7 @@ impl<'a> PyParser<'a> { } // Dup pattern if self.starts_with("{") { - let binds = self.list_like(|p| p.parse_assign_pattern(), "{", "}", "", false, 2)?; + let binds = self.list_like(|p| p.parse_assign_pattern(), "{", "}", ",", true, 2)?; return Ok(AssignPattern::Sup(binds)); } @@ -892,7 +911,7 @@ impl<'a> PyParser<'a> { let name = self.parse_bend_name()?; self.skip_trivia_inline(); let params = if self.starts_with("(") { - self.list_like(|p| p.parse_bend_name(), "(", ")", ",", false, 0)? + self.list_like(|p| p.parse_bend_name(), "(", ")", ",", true, 0)? } else { vec![] }; @@ -932,7 +951,7 @@ impl<'a> PyParser<'a> { let mut fields = Vec::new(); self.skip_trivia_inline(); if self.starts_with("{") { - fields = self.list_like(|p| p.parse_variant_field(), "{", "}", ",", false, 0)?; + fields = self.list_like(|p| p.parse_variant_field(), "{", "}", ",", true, 0)?; } variants.push(Variant { name: ctr_name, fields }); if !self.is_eof() { @@ -957,7 +976,7 @@ impl<'a> PyParser<'a> { let name = self.parse_top_level_name()?; self.skip_trivia_inline(); let fields = if self.starts_with("{") { - self.list_like(|p| p.parse_variant_field(), "{", "}", ",", false, 0)? + self.list_like(|p| p.parse_variant_field(), "{", "}", ",", true, 0)? } else { vec![] }; diff --git a/tests/golden_tests/parse_file/imp_program.bend b/tests/golden_tests/parse_file/imp_program.bend index 96bbe87c..fe4312dd 100644 --- a/tests/golden_tests/parse_file/imp_program.bend +++ b/tests/golden_tests/parse_file/imp_program.bend @@ -53,17 +53,17 @@ def swt(n): def fld(list): fold list: - case List/cons: + case List/Cons: return 1; - case List/nil: + case List/Nil: return 2; def bnd(): bend x = 0: when x < 10: - return List/cons(x fork(x + 1)); + return List/Cons(x, fork(x + 1)); else: - return List/nil(); + return List/Nil(); def era(): * = (2 + 3) diff --git a/tests/golden_tests/run_file/fold_with_state.bend b/tests/golden_tests/run_file/fold_with_state.bend index ee8b980e..c6fcf16a 100644 --- a/tests/golden_tests/run_file/fold_with_state.bend +++ b/tests/golden_tests/run_file/fold_with_state.bend @@ -1,7 +1,7 @@ def main: y = 1 - fold x = [0 0 0] with y: + fold x = [0, 0, 0] with y: case List/Cons: - return List/Cons(x.head + y x.tail(y + 1)) + return List/Cons(x.head + y, x.tail(y + 1)) case List/Nil: return List/Nil diff --git a/tests/golden_tests/run_file/imp_empty_list.bend b/tests/golden_tests/run_file/imp_empty_list.bend deleted file mode 100644 index 134f1b09..00000000 --- a/tests/golden_tests/run_file/imp_empty_list.bend +++ /dev/null @@ -1,2 +0,0 @@ -def main: - return [] \ No newline at end of file diff --git a/tests/golden_tests/run_file/imp_empty_literals.bend b/tests/golden_tests/run_file/imp_empty_literals.bend new file mode 100644 index 00000000..a8f235b8 --- /dev/null +++ b/tests/golden_tests/run_file/imp_empty_literals.bend @@ -0,0 +1,11 @@ +def list: + return [] + +def map: + return {} + +def str: + return "" + +def main: + return [] \ No newline at end of file diff --git a/tests/snapshots/parse_file__imp_program.bend.snap b/tests/snapshots/parse_file__imp_program.bend.snap index d9b6a29a..ab1d9e14 100644 --- a/tests/snapshots/parse_file__imp_program.bend.snap +++ b/tests/snapshots/parse_file__imp_program.bend.snap @@ -26,14 +26,18 @@ input_file: tests/golden_tests/parse_file/imp_program.bend (swt) = λ%arg0 use n = %arg0; switch n = n { 0: 42; _ n-1: 1; } -(fld) = λ%arg0 use list = %arg0; fold list = list { List/cons: 1; List/nil: 2; } +(fld) = λ%arg0 use list = %arg0; fold list = list { List/Cons: 1; List/Nil: 2; } -(bnd) = bend x = 0, { when (< x 10): (List/cons x (fork (+ x 1))); else: List/nil } +(bnd) = bend x = 0, { when (< x 10): (List/Cons x (fork (+ x 1))); else: List/Nil } (era) = let * = (+ 2 3); let the_expr_killer = *; (the_expr_killer 9) (main) = do IO { ask x = IO.read; x } +(List/Cons) = λhead λtail λList/Cons λList/Nil (List/Cons head tail) + +(List/Nil) = λList/Cons λList/Nil List/Nil + (Map/Node) = λvalue λleft λright λMap/Node λMap/Leaf (Map/Node value left right) (Map/Leaf) = λMap/Node λMap/Leaf Map/Leaf diff --git a/tests/snapshots/run_file__imp_empty_literals.bend.snap b/tests/snapshots/run_file__imp_empty_literals.bend.snap new file mode 100644 index 00000000..43a42a13 --- /dev/null +++ b/tests/snapshots/run_file__imp_empty_literals.bend.snap @@ -0,0 +1,5 @@ +--- +source: tests/golden_tests.rs +input_file: tests/golden_tests/run_file/imp_empty_literals.bend +--- +λ* λa a