[sc-699] Require , in list-like things in imp syntax

This commit is contained in:
Nicolas Abril 2024-05-17 18:08:51 +02:00
parent 8a137b0d87
commit 1585d2d5bc
9 changed files with 66 additions and 28 deletions

View File

@ -44,6 +44,7 @@
"inodes", "inodes",
"insta", "insta",
"interner", "interner",
"ints",
"itertools", "itertools",
"ITRS", "ITRS",
"kwarg", "kwarg",

View File

@ -16,7 +16,7 @@ def and(a, b):
def all(tree): def all(tree):
fold tree: fold tree:
case Tree/Node: case Tree/Node:
return and(tree.lft tree.rgt) return and(tree.lft, tree.rgt)
case Tree/Leaf: case Tree/Leaf:
return tree.val return tree.val

View File

@ -96,6 +96,7 @@ impl<'a> PyParser<'a> {
let ini_idx = *self.index(); let ini_idx = *self.index();
let base = match head { let base = match head {
// Tuple or parenthesized expression
'(' => { '(' => {
self.advance_one(); self.advance_one();
let head = self.parse_expr(false)?; let head = self.parse_expr(false)?;
@ -114,41 +115,49 @@ impl<'a> PyParser<'a> {
head head
} }
} }
// Map or Sup
'{' => { '{' => {
self.advance_one(); self.advance_one();
self.skip_trivia(); // Empty map
if self.try_consume_exactly("}") { if self.try_consume("}") {
return Ok(Expr::MapInit { entries: Vec::new() }); return Ok(Expr::MapInit { entries: vec![] });
} }
let head = self.parse_expr(false)?; let head = self.parse_expr(false)?;
self.skip_trivia(); self.skip_trivia();
if self.starts_with(":") { self.parse_map_init(head)? } else { self.parse_sup(head)? } if self.starts_with(":") { self.parse_map_init(head)? } else { self.parse_sup(head)? }
} }
// List or Comprehension
'[' => self.list_or_comprehension()?, '[' => self.list_or_comprehension()?,
// Symbol
'`' => Expr::Num { val: Num::U24(self.parse_quoted_symbol()?) }, '`' => Expr::Num { val: Num::U24(self.parse_quoted_symbol()?) },
// String
'\"' => { '\"' => {
let str = self.parse_quoted_string()?; let str = self.parse_quoted_string()?;
let val = STRINGS.get(str); let val = STRINGS.get(str);
Expr::Str { val } Expr::Str { val }
} }
// Char
'\'' => { '\'' => {
let chr = self.parse_quoted_char()?; let chr = self.parse_quoted_char()?;
Expr::Num { val: Num::U24(chr as u32 & 0x00ff_ffff) } Expr::Num { val: Num::U24(chr as u32 & 0x00ff_ffff) }
} }
// Unscoped var
'$' => { '$' => {
self.advance_one(); self.advance_one();
let nam = self.parse_bend_name()?; let nam = self.parse_bend_name()?;
Expr::Chn { nam } Expr::Chn { nam }
} }
// Era
'*' => { '*' => {
self.advance_one(); self.advance_one();
Expr::Eraser Expr::Eraser
} }
// Number
c if is_num_char(c) => { c if is_num_char(c) => {
let val = self.parse_number()?; let val = self.parse_number()?;
Expr::Num { val } Expr::Num { val }
} }
// var or postfix // var
_ => { _ => {
let nam = self.labelled(|p| p.parse_bend_name(), "expression")?; let nam = self.labelled(|p| p.parse_bend_name(), "expression")?;
Expr::Var { nam } Expr::Var { nam }
@ -178,7 +187,9 @@ impl<'a> PyParser<'a> {
} else { } else {
args.push(arg); args.push(arg);
} }
self.try_consume(","); if !self.starts_with(")") {
self.consume(",")?;
}
} }
if args.is_empty() && kwargs.is_empty() { if args.is_empty() && kwargs.is_empty() {
return Ok(base); return Ok(base);
@ -202,7 +213,7 @@ impl<'a> PyParser<'a> {
// ctr // ctr
if self.starts_with("{") { if self.starts_with("{") {
if let Expr::Var { nam } = base { 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 }); return Ok(Expr::Constructor { name: nam, args: Vec::new(), kwargs });
} else { } else {
return self.expected_spanned("Constructor name", ini_idx, end_idx); return self.expected_spanned("Constructor name", ini_idx, end_idx);
@ -218,15 +229,18 @@ impl<'a> PyParser<'a> {
self.consume(":")?; self.consume(":")?;
let val = self.parse_expr(false)?; let val = self.parse_expr(false)?;
entries.push((head, val)); entries.push((head, val));
self.try_consume(","); self.skip_trivia();
let tail = self.list_like(|p| p.parse_map_entry(), "", "}", ",", false, 0)?; if !self.starts_with("}") {
self.consume(",")?;
}
let tail = self.list_like(|p| p.parse_map_entry(), "", "}", ",", true, 0)?;
entries.extend(tail); entries.extend(tail);
Ok(Expr::MapInit { entries }) Ok(Expr::MapInit { entries })
} }
fn parse_sup(&mut self, head: Expr) -> ParseResult<Expr> { fn parse_sup(&mut self, head: Expr) -> ParseResult<Expr> {
let mut els = vec![head]; 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); els.extend(tail);
Ok(Expr::Sup { els }) Ok(Expr::Sup { els })
} }
@ -274,8 +288,11 @@ impl<'a> PyParser<'a> {
} else { } else {
// List // List
let mut head = vec![head]; let mut head = vec![head];
self.try_consume(","); self.skip_trivia();
let tail = self.list_like(|p| p.parse_expr(false), "", "]", ",", false, 0)?; if !self.starts_with("]") {
self.consume(",")?;
}
let tail = self.list_like(|p| p.parse_expr(false), "", "]", ",", true, 0)?;
head.extend(tail); head.extend(tail);
Ok(Expr::Lst { els: head }) Ok(Expr::Lst { els: head })
} }
@ -685,7 +702,9 @@ impl<'a> PyParser<'a> {
while !self.starts_with(":") { while !self.starts_with(":") {
with.push(self.parse_bend_name()?); with.push(self.parse_bend_name()?);
self.skip_trivia_inline(); self.skip_trivia_inline();
self.try_consume_exactly(","); if !self.starts_with(":") {
self.consume_exactly(",")?;
}
self.skip_trivia_inline(); self.skip_trivia_inline();
} }
with with
@ -721,7 +740,7 @@ impl<'a> PyParser<'a> {
/// "else" ":" /// "else" ":"
/// <base> /// <base>
fn parse_bend(&mut self, indent: &mut Indent) -> ParseResult<(Stmt, Indent)> { 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(); let (bind, init) = args.into_iter().unzip();
self.consume_new_line()?; self.consume_new_line()?;
indent.enter_level(); indent.enter_level();
@ -822,7 +841,7 @@ impl<'a> PyParser<'a> {
} }
// Dup pattern // Dup pattern
if self.starts_with("{") { 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)); return Ok(AssignPattern::Sup(binds));
} }
@ -892,7 +911,7 @@ impl<'a> PyParser<'a> {
let name = self.parse_bend_name()?; let name = self.parse_bend_name()?;
self.skip_trivia_inline(); self.skip_trivia_inline();
let params = if self.starts_with("(") { 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 { } else {
vec![] vec![]
}; };
@ -932,7 +951,7 @@ impl<'a> PyParser<'a> {
let mut fields = Vec::new(); let mut fields = Vec::new();
self.skip_trivia_inline(); self.skip_trivia_inline();
if self.starts_with("{") { 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 }); variants.push(Variant { name: ctr_name, fields });
if !self.is_eof() { if !self.is_eof() {
@ -957,7 +976,7 @@ impl<'a> PyParser<'a> {
let name = self.parse_top_level_name()?; let name = self.parse_top_level_name()?;
self.skip_trivia_inline(); self.skip_trivia_inline();
let fields = if self.starts_with("{") { 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 { } else {
vec![] vec![]
}; };

View File

@ -53,17 +53,17 @@ def swt(n):
def fld(list): def fld(list):
fold list: fold list:
case List/cons: case List/Cons:
return 1; return 1;
case List/nil: case List/Nil:
return 2; return 2;
def bnd(): def bnd():
bend x = 0: bend x = 0:
when x < 10: when x < 10:
return List/cons(x fork(x + 1)); return List/Cons(x, fork(x + 1));
else: else:
return List/nil(); return List/Nil();
def era(): def era():
* = (2 + 3) * = (2 + 3)

View File

@ -1,7 +1,7 @@
def main: def main:
y = 1 y = 1
fold x = [0 0 0] with y: fold x = [0, 0, 0] with y:
case List/Cons: 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: case List/Nil:
return List/Nil return List/Nil

View File

@ -1,2 +0,0 @@
def main:
return []

View File

@ -0,0 +1,11 @@
def list:
return []
def map:
return {}
def str:
return ""
def main:
return []

View File

@ -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; } (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) (era) = let * = (+ 2 3); let the_expr_killer = *; (the_expr_killer 9)
(main) = do IO { ask x = IO.read; x } (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/Node) = λvalue λleft λright λMap/Node λMap/Leaf (Map/Node value left right)
(Map/Leaf) = λMap/Node λMap/Leaf Map/Leaf (Map/Leaf) = λMap/Node λMap/Leaf Map/Leaf

View File

@ -0,0 +1,5 @@
---
source: tests/golden_tests.rs
input_file: tests/golden_tests/run_file/imp_empty_literals.bend
---
λ* λa a