mirror of
https://github.com/HigherOrderCO/Bend.git
synced 2024-09-11 19:57:20 +03:00
Merge pull request #327 from HigherOrderCO/feature/sc-699/enable-obligatory-in-imp-syntax
[sc-699] Require , in list-like things in imp syntax
This commit is contained in:
commit
a2c5c81b79
@ -13,7 +13,7 @@ the [HVM2](https://github.com/HigherOrderCO/hvm) runtime.
|
||||
A Quick Demo
|
||||
------------
|
||||
|
||||
![bendlivedemo](https://github.com/VictorTaelin/media/blob/main/bend_live_demo.gif?raw=true)
|
||||
![Bend live demo](https://github.com/VictorTaelin/media/blob/main/bend_live_demo.gif?raw=true)
|
||||
|
||||
## Using Bend
|
||||
|
||||
|
@ -44,6 +44,7 @@
|
||||
"inodes",
|
||||
"insta",
|
||||
"interner",
|
||||
"ints",
|
||||
"itertools",
|
||||
"ITRS",
|
||||
"kwarg",
|
||||
|
@ -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
|
||||
|
||||
|
@ -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<Expr> {
|
||||
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" ":"
|
||||
/// <base>
|
||||
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![]
|
||||
};
|
||||
|
@ -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)
|
||||
|
@ -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
|
||||
|
@ -1,2 +0,0 @@
|
||||
def main:
|
||||
return []
|
11
tests/golden_tests/run_file/imp_empty_literals.bend
Normal file
11
tests/golden_tests/run_file/imp_empty_literals.bend
Normal file
@ -0,0 +1,11 @@
|
||||
def list:
|
||||
return []
|
||||
|
||||
def map:
|
||||
return {}
|
||||
|
||||
def str:
|
||||
return ""
|
||||
|
||||
def main:
|
||||
return []
|
@ -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
|
||||
|
5
tests/snapshots/run_file__imp_empty_literals.bend.snap
Normal file
5
tests/snapshots/run_file__imp_empty_literals.bend.snap
Normal file
@ -0,0 +1,5 @@
|
||||
---
|
||||
source: tests/golden_tests.rs
|
||||
input_file: tests/golden_tests/run_file/imp_empty_literals.bend
|
||||
---
|
||||
λ* λa a
|
Loading…
Reference in New Issue
Block a user