mirror of
https://github.com/HigherOrderCO/Bend.git
synced 2024-09-11 03:45:29 +03:00
Merge pull request #546 from HigherOrderCO/528-add-syntax-for-a-builtin-tree-type
528 Add syntax for a builtin Tree type
This commit is contained in:
commit
c97e47107d
11
CHANGELOG.md
Normal file
11
CHANGELOG.md
Normal file
@ -0,0 +1,11 @@
|
||||
# Changelog
|
||||
|
||||
## 0.2.32
|
||||
|
||||
- Added the built-in `Tree` datatype.
|
||||
- Added `![]` and `!` syntax for `Tree` literals.
|
||||
- Moved the builtins documentation to `/docs`.
|
||||
- Created the changelog.
|
||||
|
||||
## 0.2.0
|
||||
- Initial public release of Bend.
|
2
Cargo.lock
generated
2
Cargo.lock
generated
@ -62,7 +62,7 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "bend-lang"
|
||||
version = "0.2.31"
|
||||
version = "0.2.32"
|
||||
dependencies = [
|
||||
"TSPL",
|
||||
"clap",
|
||||
|
@ -2,7 +2,7 @@
|
||||
name = "bend-lang"
|
||||
description = "A high-level, massively parallel programming language"
|
||||
license = "Apache-2.0"
|
||||
version = "0.2.31"
|
||||
version = "0.2.32"
|
||||
edition = "2021"
|
||||
rust-version = "1.74"
|
||||
exclude = ["tests/"]
|
||||
|
@ -414,7 +414,7 @@ Other features are described in the following documentation files:
|
||||
- 📗 Data types: [Defining data types](docs/defining-data-types.md)
|
||||
- 📗 Pattern matching: [Pattern matching](docs/pattern-matching.md)
|
||||
- 📗 Native numbers and operations: [Native numbers](docs/native-numbers.md)
|
||||
- 📗 Builtin definitions: _Documentation coming soon_
|
||||
- 📗 Builtin definitions: [Builtins](docs/builtins.md)
|
||||
- 📗 CLI arguments: [CLI arguments](docs/cli-arguments.md)
|
||||
- 📙 Duplications and superpositions: [Dups and sups](docs/dups-and-sups.md)
|
||||
- 📙 Scopeless lambdas: [Using scopeless lambdas](docs/using-scopeless-lambdas.md)
|
||||
|
63
GUIDE.md
63
GUIDE.md
@ -309,8 +309,8 @@ Let's start by implementing a recursive datatype in Bend:
|
||||
|
||||
```python
|
||||
type Tree:
|
||||
Node { ~lft, ~rgt }
|
||||
Leaf { val }
|
||||
Node { ~left, ~right }
|
||||
Leaf { value }
|
||||
```
|
||||
|
||||
This defines a binary tree, with elements on leaves. Here, `~` flags a field as
|
||||
@ -326,18 +326,18 @@ Could be represented as:
|
||||
|
||||
```
|
||||
tree = Tree/Node {
|
||||
lft: Tree/Node { lft: Tree/Leaf { val: 1 }, rgt: Tree/Leaf { val: 2 } },
|
||||
rgt: Tree/Node { lft: Tree/Leaf { val: 3 }, rgt: Tree/Leaf { val: 4 } }
|
||||
lft: Tree/Node { left: Tree/Leaf { val: 1 }, right: Tree/Leaf { val: 2 } },
|
||||
rgt: Tree/Node { left: Tree/Leaf { val: 3 }, right: Tree/Leaf { val: 4 } }
|
||||
}
|
||||
```
|
||||
|
||||
That's ugly. Very soon, we'll add a syntax sugar to make this shorter:
|
||||
|
||||
Binary trees are so useful in Bend that this type is already pre-defined in the
|
||||
language and has its own dedicated syntax:
|
||||
```py
|
||||
# ![a, b] => Equivalent to Tree/Node { left: a, right: b }
|
||||
# !x => Equivalent to Tree/Leaf { value: x }
|
||||
tree = ![![!1, !2],![!3, !4]]
|
||||
```
|
||||
tree = ![![1,2],![3,4]]
|
||||
```
|
||||
|
||||
As usual, for now, we'll live with the longer version.
|
||||
|
||||
### Fold: consuming recursive datatypes
|
||||
|
||||
@ -348,27 +348,20 @@ and replace* for datatypes. For example, consider the code below:
|
||||
|
||||
|
||||
```python
|
||||
type Tree:
|
||||
Node { ~lft, ~rgt }
|
||||
Leaf { val }
|
||||
|
||||
def sum(tree):
|
||||
fold tree:
|
||||
case Tree/Node:
|
||||
return tree.lft + tree.rgt
|
||||
return tree.left + tree.right
|
||||
case Tree/Leaf:
|
||||
return tree.val
|
||||
return tree.value
|
||||
|
||||
def main:
|
||||
tree = Tree/Node {
|
||||
lft: Tree/Node { lft: Tree/Leaf { val: 1 }, rgt: Tree/Leaf { val: 2 } },
|
||||
rgt: Tree/Node { lft: Tree/Leaf { val: 3 }, rgt: Tree/Leaf { val: 4 } }
|
||||
}
|
||||
tree = ![![!1, !2],![!3, !4]]
|
||||
return sum(tree)
|
||||
```
|
||||
|
||||
It accomplishes the task by replacing every `Tree/Node { lft, rgt }` by `lft +
|
||||
rgt`, and replacing every `Tree/Leaf` by `val`. As a result, the entire "tree of
|
||||
It accomplishes the task by replacing every `Tree/Node { left, right }` by `left +
|
||||
right`, and replacing every `Tree/Leaf` by `value`. As a result, the entire "tree of
|
||||
values" is turned into a "tree of additions", and it evaluates as follows:
|
||||
|
||||
```python
|
||||
@ -384,26 +377,16 @@ implemented with a fold*. So, we can do much more than just compute an
|
||||
into a tuple of `(index,value)`, returning a new tree. Here's how to do it:
|
||||
|
||||
```python
|
||||
type Tree:
|
||||
Node { ~lft, ~rgt }
|
||||
Leaf { val }
|
||||
|
||||
def enum(tree):
|
||||
idx = 0
|
||||
fold tree with idx:
|
||||
case Tree/Node:
|
||||
return Tree/Node {
|
||||
lft: tree.lft(idx * 2 + 0),
|
||||
rgt: tree.rgt(idx * 2 + 1),
|
||||
}
|
||||
return ![tree.left(idx * 2 + 0), tree.right(idx * 2 + 1)]
|
||||
case Tree/Leaf:
|
||||
return Tree/Leaf { val: (idx, tree.val) }
|
||||
return !(idx, tree.value)
|
||||
|
||||
def main:
|
||||
tree = Tree/Node {
|
||||
lft: Tree/Node { lft: Tree/Leaf { val: 1 }, rgt: Tree/Leaf { val: 2 }, },
|
||||
rgt: Tree/Node { lft: Tree/Leaf { val: 3 }, rgt: Tree/Leaf { val: 4 }, }
|
||||
}
|
||||
tree = ![![!1, !2],![!3, !4]]
|
||||
return enum(tree)
|
||||
```
|
||||
|
||||
@ -440,16 +423,12 @@ can "grow" a recursive structure, layer by layer, until the condition is met.
|
||||
For example, consider the code below:
|
||||
|
||||
```python
|
||||
type Tree:
|
||||
Node { ~lft, ~rgt }
|
||||
Leaf { val }
|
||||
|
||||
def main():
|
||||
bend x = 0:
|
||||
when x < 3:
|
||||
tree = Tree/Node { lft: fork(x + 1), rgt: fork(x + 1) }
|
||||
tree = ![fork(x + 1), fork(x + 1)]
|
||||
else:
|
||||
tree = Tree/Leaf { val: 7 }
|
||||
tree = !7
|
||||
return tree
|
||||
```
|
||||
|
||||
@ -463,7 +442,7 @@ tree = fork(0)
|
||||
tree = ![fork(1), fork(1)]
|
||||
tree = ![![fork(2),fork(2)], ![fork(2),fork(2)]]
|
||||
tree = ![![![fork(3),fork(3)], ![fork(3),fork(3)]], ![![fork(3),fork(3)], ![fork(3),fork(3)]]]
|
||||
tree = ![![![7,7], ![7,7]], ![![7,7], ![7,7]]]
|
||||
tree = ![![![!7, !7], ![!7, !7]], ![![!7, !7], ![!7, !7]]]
|
||||
```
|
||||
|
||||
With some imagination, we can easily see that, by recursively unrolling a state
|
||||
|
@ -19,8 +19,6 @@ A String literal is surrounded with `"`. Accepts the same values as characters l
|
||||
```
|
||||
|
||||
|
||||
|
||||
|
||||
## List
|
||||
```python
|
||||
type List = (Cons head ~tail) | (Nil)
|
||||
@ -37,46 +35,64 @@ A List of values can be written using `[ ]`, it can have multiple values inside,
|
||||
```
|
||||
|
||||
|
||||
|
||||
|
||||
## Nat
|
||||
## Tree
|
||||
```python
|
||||
type Nat = (Succ ~pred) | (Zero)
|
||||
```
|
||||
- **Succ ~pred**: Represents a natural number successor.
|
||||
- **Zero**: Represents the natural number zero.
|
||||
|
||||
### Syntax
|
||||
A Natural Number can be written with literals with a `#` before the literal number.
|
||||
|
||||
```
|
||||
#1337
|
||||
type Tree:
|
||||
Node { ~left, ~right }
|
||||
Leaf { value }
|
||||
```
|
||||
|
||||
**`Tree`** represents a tree with values stored in the leaves.
|
||||
Trees are a structure that naturally lends itself to parallel recursion, so writing your problem in terms of trees is a good first approach to parallelize your code.
|
||||
|
||||
- **Node { ~left ~right }**: Represents a tree node with `left` and `right` subtrees.
|
||||
- **Leaf { value }**: Represents one of the ends of the tree, storing `value`.
|
||||
|
||||
## Result
|
||||
```python
|
||||
type Result = (Ok val) | (Err val)
|
||||
#### Syntax
|
||||
**Bend** provides the `![]` operator to create tree branches and the `!` operator to create a tree leaf.
|
||||
```py
|
||||
# ![a, b] => Equivalent to Tree/Node { left: a, right: b }
|
||||
# !x => Equivalent to Tree/Leaf { value: x }
|
||||
tree = ![![!1, !2],![!3, !4]]
|
||||
```
|
||||
|
||||
- **Ok val**: Represents a successful result with value `val`.
|
||||
- **Err val**: Represents an error with value `val`.
|
||||
Technically your trees don't need to end with leaves, but if you don't, your program will be very hard to reason about.
|
||||
|
||||
## Map
|
||||
```python
|
||||
type Map = (Node value ~left ~right) | (Leaf)
|
||||
type Map:
|
||||
Node { value ~left ~right }
|
||||
Leaf
|
||||
```
|
||||
|
||||
- **Node value ~left ~right**: Represents a map node with a `value` and `left` and `right` subtrees.
|
||||
- **Leaf**: Represents an empty map.
|
||||
**`Map`** represents a tree with values stored in the branches.
|
||||
It is meant to be used as an efficient map data structure with integer keys and O(log n) read and write operations.
|
||||
|
||||
- **Node { value ~left ~right }**: Represents a map node with a `value` and `left` and `right` subtrees. Empty nodes have `*` stored in the `value` field.
|
||||
- **Leaf**: Represents an unwritten, empty portion of the map.
|
||||
|
||||
#### Syntax
|
||||
**Bend** has a built-in binary tree map data structure where the key is a `u24`, meaning you can use numbers, characters, and symbols as keys.
|
||||
Here's how you create a new `Map` with some initial values.:
|
||||
```python
|
||||
{ 0: 4, `hi`: "bye", 'c': 2 + 3 }
|
||||
```
|
||||
|
||||
The keys must be `U24` numbers, and can be given as literals or any other expression that evaluates to a `U24`.
|
||||
|
||||
The values can be anything, but storing data of different types in a `Map` will make it harder for you to reason about it.
|
||||
|
||||
You can read and write a value of a map with the `[]` operator:
|
||||
```python
|
||||
map = { 0: "zero", 1: "one", 2: "two", 3: "three" }
|
||||
map[0] = "not zero"
|
||||
map[1] = 2
|
||||
map[2] = 3
|
||||
map[3] = map[1] + map[map[1]]
|
||||
```
|
||||
|
||||
Here, `map` must be the name of the `Map` variable, and the keys inside `[]` can be any expression that evaluates to a `U24`.
|
||||
|
||||
|
||||
## Map functions
|
||||
|
||||
### Map/empty
|
||||
Initializes an empty map.
|
||||
@ -86,6 +102,7 @@ Map/empty = Map/Leaf
|
||||
|
||||
### Map/get
|
||||
Retrieves a `value` from the `map` based on the `key`.
|
||||
Returns a tuple with the value and the `map` unchanged.
|
||||
```rust
|
||||
Map/get map key =
|
||||
match map {
|
||||
@ -105,9 +122,8 @@ Map/get map key =
|
||||
}
|
||||
```
|
||||
|
||||
|
||||
#### Syntax
|
||||
Considering the following tree
|
||||
Considering the following map
|
||||
```python
|
||||
{ 0: "hello", 1: "bye", 2: "maybe", 3: "yes"}
|
||||
```
|
||||
@ -122,6 +138,7 @@ And the value resultant from the get function would be:
|
||||
|
||||
### Map/set
|
||||
Sets a `value` in the `map` at the specified `key`.
|
||||
Returns the map with the new value.
|
||||
```rust
|
||||
Map/set map key value =
|
||||
match map {
|
||||
@ -149,22 +166,63 @@ Considering the following tree
|
||||
{ 0: "hello", 1: "bye", 2: "maybe", 3: "yes"}
|
||||
```
|
||||
The `set` function can be written as
|
||||
```
|
||||
```py
|
||||
x[0] = "swapped" # Assigns the key 0 to the value "swapped"
|
||||
```
|
||||
And the value resultant from the get function would be:
|
||||
```
|
||||
```py
|
||||
{ 0: "swapped", 1: "bye", 2: "maybe", 3: "yes"}
|
||||
```
|
||||
If there's no matching `key` in the tree, it would add a new branch to that tree with the value `set`
|
||||
|
||||
```
|
||||
```py
|
||||
x[4] = "added" # Assigns the key 4 to the value "added"
|
||||
```
|
||||
The new tree
|
||||
```
|
||||
```py
|
||||
{ 0: "swapped", 1: "bye", 2: "maybe", 3: "yes", 4: "added"}
|
||||
```
|
||||
|
||||
### Map/map
|
||||
Applies a function to a value in the map.
|
||||
Returns the map with the value mapped.
|
||||
```rust
|
||||
Map/map (Map/Leaf) key f = Map/Leaf
|
||||
Map/map (Map/Node value left right) key f =
|
||||
switch _ = (== 0 key) {
|
||||
0: switch _ = (% key 2) {
|
||||
0:
|
||||
(Map/Node value (Map/map left (/ key 2) f) right)
|
||||
_:
|
||||
(Map/Node value left (Map/map right (/ key 2) f))
|
||||
}
|
||||
_: (Map/Node (f value) left right)
|
||||
}
|
||||
```
|
||||
|
||||
#### Syntax
|
||||
With the same map that we `set` in the previous section, we can map it's values with `@=`:
|
||||
```py
|
||||
x[0] @= lambda y: String/concat(y, " and mapped")
|
||||
# x[0] now contains "swapped and mapped"
|
||||
```
|
||||
|
||||
|
||||
## Nat
|
||||
```python
|
||||
type Nat = (Succ ~pred) | (Zero)
|
||||
```
|
||||
- **Succ ~pred**: Represents a natural number successor.
|
||||
- **Zero**: Represents the natural number zero.
|
||||
|
||||
### Syntax
|
||||
A Natural Number can be written with literals with a `#` before the literal number.
|
||||
|
||||
```
|
||||
#1337
|
||||
```
|
||||
|
||||
|
||||
|
||||
## IO
|
||||
IO Functions are in the **next milestone**!
|
@ -11,7 +11,7 @@ Both syntaxes can be mixed in the same file like the example below:
|
||||
```python
|
||||
object Point { x, y }
|
||||
|
||||
type Tree = (Node ~left ~right) | (Leaf value)
|
||||
type MyTree = (Node ~left ~right) | (Leaf value)
|
||||
|
||||
type Bool:
|
||||
True
|
||||
@ -622,6 +622,18 @@ A List literal is surrounded by `[` `]`. The elements must be separated by `,`.
|
||||
|
||||
It is desugared to constructor calls of the built-in type List, `List/cons(head, ~tail)` and `List/nil` .
|
||||
|
||||
### Tree Literals
|
||||
|
||||
```python
|
||||
![![1, 2], ![3, 4]]
|
||||
```
|
||||
|
||||
The Tree literals `![]` and `!` are used to create values of the built-in type `Tree`.
|
||||
|
||||
`![a b]` is equivalent to `Tree/Node(a, b)`.
|
||||
|
||||
`!x` is equivalent to `Tree/Leaf(x)`.
|
||||
|
||||
### Map Literals
|
||||
|
||||
```python
|
||||
@ -1131,6 +1143,18 @@ The syntax above is desugared to:
|
||||
|
||||
Using `,` is optional.
|
||||
|
||||
### Tree Literals
|
||||
|
||||
```python
|
||||
![![1, 2], ![3, 4]]
|
||||
```
|
||||
|
||||
The Tree literals `![]` and `!` are used to create values of the built-in type `Tree`.
|
||||
|
||||
`![a b]` is equivalent to `Tree/Node(a, b)`.
|
||||
|
||||
`!x` is equivalent to `Tree/Leaf(x)`.
|
||||
|
||||
### Nat Literal
|
||||
|
||||
```rust
|
||||
|
@ -1,14 +1,14 @@
|
||||
# Generates a tree with numbers in the nodes using 'bend'
|
||||
type Tree:
|
||||
type MyTree:
|
||||
Node { val, ~left, ~right }
|
||||
Leaf
|
||||
|
||||
def tree_gen(n, x):
|
||||
bend n, x:
|
||||
when n != 0:
|
||||
return Tree/Node(x, fork(n - 1, x*2+1), fork(n - 1, x*2+2))
|
||||
return MyTree/Node(x, fork(n - 1, x*2+1), fork(n - 1, x*2+2))
|
||||
else:
|
||||
return Tree/Leaf
|
||||
return MyTree/Leaf
|
||||
|
||||
def main:
|
||||
depth = 4
|
||||
|
@ -3,10 +3,6 @@ type Bool:
|
||||
True
|
||||
False
|
||||
|
||||
type Tree:
|
||||
Node { ~lft, ~rgt }
|
||||
Leaf { val }
|
||||
|
||||
def and(a, b):
|
||||
match a:
|
||||
case Bool/True:
|
||||
@ -17,16 +13,16 @@ def and(a, b):
|
||||
def all(tree):
|
||||
fold tree:
|
||||
case Tree/Node:
|
||||
return and(tree.lft, tree.rgt)
|
||||
return and(tree.left, tree.right)
|
||||
case Tree/Leaf:
|
||||
return tree.val
|
||||
return tree.value
|
||||
|
||||
def gen(n):
|
||||
switch n:
|
||||
case 0:
|
||||
return Tree/Leaf(Bool/True)
|
||||
case _:
|
||||
return Tree/Node { lft: gen(n-1), rgt: gen(n-1) }
|
||||
return Tree/Node { left: gen(n-1), right: gen(n-1) }
|
||||
|
||||
def main():
|
||||
return all(gen(8))
|
||||
|
@ -1,32 +1,32 @@
|
||||
type Tree = Leaf | (Node l m r)
|
||||
type MyTree = Leaf | (Node lft val rgt)
|
||||
|
||||
# Parallel QuickSort
|
||||
(Sort List/Nil) = Tree/Leaf
|
||||
(Sort (List/Cons x xs)) =
|
||||
((Part x xs) λmin λmax
|
||||
(Sort List/Nil) = MyTree/Leaf
|
||||
(Sort (List/Cons head tail)) =
|
||||
((Part head tail) λmin λmax
|
||||
let lft = (Sort min)
|
||||
let rgt = (Sort max)
|
||||
(Tree/Node lft x rgt))
|
||||
(MyTree/Node lft head rgt))
|
||||
|
||||
# Partitions a list in two halves, less-than-p and greater-than-p
|
||||
(Part p List/Nil) = λt (t List/Nil List/Nil)
|
||||
(Part p (List/Cons x xs)) = (Push (> x p) x (Part p xs))
|
||||
(Part p List/Nil) = λt (t List/Nil List/Nil)
|
||||
(Part p (List/Cons head tail)) = (Push (> head p) head (Part p tail))
|
||||
|
||||
# Pushes a value to the first or second list of a pair
|
||||
(Push 0 x pair) = (pair λmin λmax λp (p (List/Cons x min) max))
|
||||
(Push _ x pair) = (pair λmin λmax λp (p min (List/Cons x max)))
|
||||
|
||||
# Generates a random list
|
||||
(Rnd 0 s) = List/Nil
|
||||
(Rnd n s) =
|
||||
let s = (^ s (* s 0b10000000000000))
|
||||
let s = (^ s (/ s 0b100000000000000000))
|
||||
let s = (^ s (* s 0b100000))
|
||||
(List/Cons s (Rnd (- n 1) s))
|
||||
# Generates a random list with xorshift
|
||||
(Rnd 0 state) = List/Nil
|
||||
(Rnd n state) =
|
||||
let state = (^ state (<< state 13))
|
||||
let state = (^ state (>> state 17))
|
||||
let state = (^ state (<< state 5))
|
||||
(List/Cons state (Rnd (- n 1) state))
|
||||
|
||||
# Sums all elements in a concatenation tree
|
||||
(Sum Tree/Leaf) = 0
|
||||
(Sum (Tree/Node l m r)) = (+ m (+ (Sum l) (Sum r)))
|
||||
(Sum MyTree/Leaf) = 0
|
||||
(Sum (MyTree/Node lft val rgt)) = (+ val (+ (Sum lft) (Sum rgt)))
|
||||
|
||||
# Sorts and sums n random numbers
|
||||
(Main) =
|
||||
|
@ -1,7 +1,14 @@
|
||||
type String = (Nil) | (Cons head ~tail)
|
||||
|
||||
type List = (Nil) | (Cons head ~tail)
|
||||
|
||||
type Nat = (Succ ~pred) | (Zero)
|
||||
|
||||
type Tree:
|
||||
Node { ~left, ~right }
|
||||
Leaf { value }
|
||||
|
||||
|
||||
# MAP Impl
|
||||
|
||||
type Map = (Node value ~left ~right) | (Leaf)
|
||||
|
@ -316,12 +316,10 @@ impl<'a> TermParser<'a> {
|
||||
|
||||
// Opr but maybe a tup
|
||||
self.skip_trivia();
|
||||
let starts_with_oper = self.peek_one().map_or(false, |c| "+-*/%&|<>^=!".contains(c));
|
||||
if starts_with_oper {
|
||||
let opr = self.parse_oper()?;
|
||||
if let Some(opr) = self.try_parse_oper() {
|
||||
self.skip_trivia();
|
||||
|
||||
// jk, actually a tuple
|
||||
self.skip_trivia();
|
||||
if self.starts_with(",") && opr == Op::MUL {
|
||||
let mut els = vec![Term::Era];
|
||||
while self.try_consume(",") {
|
||||
@ -370,6 +368,26 @@ impl<'a> TermParser<'a> {
|
||||
return Ok(Term::List { els });
|
||||
}
|
||||
|
||||
// Tree Node
|
||||
if self.starts_with("![") {
|
||||
self.advance_one();
|
||||
self.advance_one();
|
||||
unexpected_tag(self)?;
|
||||
let lft = self.parse_term()?;
|
||||
self.try_consume(",");
|
||||
let rgt = self.parse_term()?;
|
||||
self.labelled(|p| p.consume("]"), "Only two children in a Tree/Node")?;
|
||||
return Ok(Term::call(Term::r#ref("Tree/Node"), [lft, rgt]));
|
||||
}
|
||||
|
||||
// Tree Leaf
|
||||
if self.starts_with("!") {
|
||||
self.advance_one();
|
||||
unexpected_tag(self)?;
|
||||
let val = self.parse_term()?;
|
||||
return Ok(Term::app(Term::r#ref("Tree/Leaf"), val));
|
||||
}
|
||||
|
||||
// Sup
|
||||
if self.starts_with("{") {
|
||||
let els = self.list_like(|p| p.parse_term(), "{", "}", ",", false, 2)?;
|
||||
@ -1022,7 +1040,7 @@ pub trait ParserCommons<'a>: Parser<'a> {
|
||||
Ok(els)
|
||||
}
|
||||
|
||||
fn parse_oper(&mut self) -> ParseResult<Op> {
|
||||
fn try_parse_oper(&mut self) -> Option<Op> {
|
||||
let opr = if self.try_consume_exactly("+") {
|
||||
Op::ADD
|
||||
} else if self.try_consume_exactly("-") {
|
||||
@ -1054,9 +1072,9 @@ pub trait ParserCommons<'a>: Parser<'a> {
|
||||
} else if self.try_consume_exactly("^") {
|
||||
Op::XOR
|
||||
} else {
|
||||
return self.expected("numeric operator");
|
||||
return None;
|
||||
};
|
||||
Ok(opr)
|
||||
Some(opr)
|
||||
}
|
||||
|
||||
fn peek_oper(&mut self) -> Option<Op> {
|
||||
|
@ -190,6 +190,13 @@ impl Expr {
|
||||
go(entry, substitutions, id);
|
||||
}
|
||||
}
|
||||
Expr::TreeNode { left, right } => {
|
||||
go(left, substitutions, id);
|
||||
go(right, substitutions, id);
|
||||
}
|
||||
Expr::TreeLeaf { val } => {
|
||||
go(val, substitutions, id);
|
||||
}
|
||||
Expr::Era | Expr::Str { .. } | Expr::Var { .. } | Expr::Chn { .. } | Expr::Num { .. } => {}
|
||||
}
|
||||
}
|
||||
|
@ -38,6 +38,10 @@ pub enum Expr {
|
||||
Map { entries: Vec<(Expr, Expr)> },
|
||||
// {map} "[" {key} "]"
|
||||
MapGet { nam: Name, key: Box<Expr> },
|
||||
// "![" {left} "," {right} "]"
|
||||
TreeNode { left: Box<Expr>, right: Box<Expr> },
|
||||
// "!" {val}
|
||||
TreeLeaf { val: Box<Expr> },
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug)]
|
||||
|
@ -156,12 +156,17 @@ impl Expr {
|
||||
entry.1.order_kwargs(book)?;
|
||||
}
|
||||
}
|
||||
Expr::MapGet { .. }
|
||||
| Expr::Era
|
||||
| Expr::Var { .. }
|
||||
| Expr::Chn { .. }
|
||||
| Expr::Num { .. }
|
||||
| Expr::Str { .. } => {}
|
||||
Expr::MapGet { nam: _, key } => {
|
||||
key.order_kwargs(book)?;
|
||||
}
|
||||
Expr::TreeNode { left, right } => {
|
||||
left.order_kwargs(book)?;
|
||||
right.order_kwargs(book)?;
|
||||
}
|
||||
Expr::TreeLeaf { val } => {
|
||||
val.order_kwargs(book)?;
|
||||
}
|
||||
Expr::Era | Expr::Var { .. } | Expr::Chn { .. } | Expr::Num { .. } | Expr::Str { .. } => {}
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
@ -83,87 +83,54 @@ impl<'a> PyParser<'a> {
|
||||
} else {
|
||||
self.skip_trivia();
|
||||
}
|
||||
let Some(head) = self.peek_one() else { return self.expected("expression")? };
|
||||
|
||||
let ini_idx = *self.index();
|
||||
|
||||
let base = match head {
|
||||
let base = if self.starts_with("(") {
|
||||
// Tuple or parenthesized expression
|
||||
'(' => {
|
||||
self.advance_one();
|
||||
let head = self.parse_expr(false)?;
|
||||
self.skip_trivia();
|
||||
if self.starts_with(",") {
|
||||
// A Tuple
|
||||
let mut els = vec![head];
|
||||
while self.try_consume(",") {
|
||||
els.push(self.parse_expr(false)?);
|
||||
}
|
||||
self.consume(")")?;
|
||||
Expr::Tup { els }
|
||||
} else {
|
||||
self.consume(")")?;
|
||||
// A parenthesized expression
|
||||
head
|
||||
}
|
||||
}
|
||||
self.parse_tuple_or_parens()?
|
||||
} else if self.starts_with("{") {
|
||||
// Map or Sup
|
||||
'{' => {
|
||||
self.advance_one();
|
||||
// Empty map
|
||||
if self.try_consume("}") {
|
||||
return Ok(Expr::Map { entries: vec![] });
|
||||
}
|
||||
let head = self.parse_expr(false)?;
|
||||
self.skip_trivia();
|
||||
if self.try_consume(",") {
|
||||
self.parse_sup(head)?
|
||||
} else if self.try_consume(":") {
|
||||
self.parse_map_init(head)?
|
||||
} else {
|
||||
self.expected("',' or ':'")?
|
||||
}
|
||||
}
|
||||
self.parse_map_or_sup()?
|
||||
} else if self.starts_with("[") {
|
||||
// List or Comprehension
|
||||
'[' => self.parse_list_or_comprehension()?,
|
||||
self.parse_list_or_comprehension()?
|
||||
} else if self.starts_with("![") {
|
||||
// Tree Node
|
||||
self.parse_tree_node()?
|
||||
} else if self.starts_with("!") {
|
||||
// Tree Leaf
|
||||
self.parse_tree_leaf(inline)?
|
||||
} else if self.starts_with("`") {
|
||||
// Symbol
|
||||
'`' => Expr::Num { val: Num::U24(self.parse_quoted_symbol()?) },
|
||||
Expr::Num { val: Num::U24(self.parse_quoted_symbol()?) }
|
||||
} else if self.starts_with("\"") {
|
||||
// String
|
||||
'\"' => {
|
||||
let str = self.parse_quoted_string()?;
|
||||
let val = STRINGS.get(str);
|
||||
Expr::Str { val }
|
||||
}
|
||||
Expr::Str { val: STRINGS.get(self.parse_quoted_string()?) }
|
||||
} else if self.starts_with("'") {
|
||||
// Char
|
||||
'\'' => {
|
||||
let chr = self.parse_quoted_char()?;
|
||||
Expr::Num { val: Num::U24(chr as u32 & 0x00ff_ffff) }
|
||||
}
|
||||
Expr::Num { val: Num::U24(self.parse_quoted_char()? as u32 & 0x00ff_ffff) }
|
||||
} else if self.starts_with("$") {
|
||||
// Unscoped var
|
||||
'$' => {
|
||||
self.advance_one();
|
||||
let nam = self.parse_bend_name()?;
|
||||
Expr::Chn { nam }
|
||||
}
|
||||
self.advance_one();
|
||||
Expr::Chn { nam: self.parse_bend_name()? }
|
||||
} else if self.starts_with("*") {
|
||||
// Era
|
||||
'*' => {
|
||||
self.advance_one();
|
||||
Expr::Era
|
||||
}
|
||||
// Number
|
||||
c if is_num_char(c) => {
|
||||
let val = self.parse_number()?;
|
||||
Expr::Num { val }
|
||||
}
|
||||
// var
|
||||
_ => {
|
||||
self.advance_one();
|
||||
Expr::Era
|
||||
} else if let Some(c) = self.peek_one() {
|
||||
if is_num_char(c) {
|
||||
// Number
|
||||
Expr::Num { val: self.parse_number()? }
|
||||
} else {
|
||||
// Var
|
||||
let nam = self.labelled(|p| p.parse_bend_name(), "expression")?;
|
||||
Expr::Var { nam }
|
||||
}
|
||||
} else {
|
||||
self.expected("expression")?
|
||||
};
|
||||
|
||||
let end_idx = *self.index();
|
||||
|
||||
// postfixes
|
||||
if inline {
|
||||
self.skip_trivia_inline();
|
||||
@ -202,12 +169,13 @@ impl<'a> PyParser<'a> {
|
||||
|
||||
// map get
|
||||
if self.starts_with("[") {
|
||||
self.advance_one();
|
||||
if let Expr::Var { nam } = base {
|
||||
self.advance_one();
|
||||
let key = self.parse_expr(false)?;
|
||||
self.consume("]")?;
|
||||
return Ok(Expr::MapGet { nam, key: Box::new(key) });
|
||||
} else {
|
||||
let end_idx = *self.index();
|
||||
return self.expected_spanned("Map variable name", ini_idx, end_idx);
|
||||
}
|
||||
}
|
||||
@ -218,6 +186,7 @@ impl<'a> PyParser<'a> {
|
||||
let kwargs = self.list_like(|p| p.data_kwarg(), "{", "}", ",", true, 0)?;
|
||||
return Ok(Expr::Ctr { name: nam, args: Vec::new(), kwargs });
|
||||
} else {
|
||||
let end_idx = *self.index();
|
||||
return self.expected_spanned("Constructor name", ini_idx, end_idx);
|
||||
}
|
||||
}
|
||||
@ -226,6 +195,43 @@ impl<'a> PyParser<'a> {
|
||||
Ok(base)
|
||||
}
|
||||
|
||||
fn parse_tuple_or_parens(&mut self) -> ParseResult<Expr> {
|
||||
self.advance_one();
|
||||
let head = self.parse_expr(false)?;
|
||||
self.skip_trivia();
|
||||
let term = if self.starts_with(",") {
|
||||
// A Tuple
|
||||
let mut els = vec![head];
|
||||
while self.try_consume(",") {
|
||||
els.push(self.parse_expr(false)?);
|
||||
}
|
||||
self.consume(")")?;
|
||||
Expr::Tup { els }
|
||||
} else {
|
||||
self.consume(")")?;
|
||||
// A parenthesized expression
|
||||
head
|
||||
};
|
||||
Ok(term)
|
||||
}
|
||||
|
||||
fn parse_map_or_sup(&mut self) -> ParseResult<Expr> {
|
||||
self.advance_one();
|
||||
// Empty map
|
||||
if self.try_consume("}") {
|
||||
return Ok(Expr::Map { entries: vec![] });
|
||||
}
|
||||
let head = self.parse_expr(false)?;
|
||||
self.skip_trivia();
|
||||
if self.try_consume(",") {
|
||||
self.parse_sup(head)
|
||||
} else if self.try_consume(":") {
|
||||
self.parse_map_init(head)
|
||||
} else {
|
||||
self.expected("',' or ':'")
|
||||
}
|
||||
}
|
||||
|
||||
fn parse_map_init(&mut self, head: Expr) -> ParseResult<Expr> {
|
||||
let mut entries = Vec::new();
|
||||
let val = self.parse_expr(false)?;
|
||||
@ -246,6 +252,22 @@ impl<'a> PyParser<'a> {
|
||||
Ok(Expr::Sup { els })
|
||||
}
|
||||
|
||||
fn parse_tree_node(&mut self) -> ParseResult<Expr> {
|
||||
self.advance_one();
|
||||
self.advance_one();
|
||||
let left = self.parse_expr(false)?;
|
||||
self.consume(",")?;
|
||||
let right = self.parse_expr(false)?;
|
||||
self.consume("]")?;
|
||||
Ok(Expr::TreeNode { left: Box::new(left), right: Box::new(right) })
|
||||
}
|
||||
|
||||
fn parse_tree_leaf(&mut self, inline: bool) -> ParseResult<Expr> {
|
||||
self.advance_one();
|
||||
let val = self.parse_expr(inline)?;
|
||||
Ok(Expr::TreeLeaf { val: Box::new(val) })
|
||||
}
|
||||
|
||||
fn data_kwarg(&mut self) -> ParseResult<(Name, Expr)> {
|
||||
self.skip_trivia();
|
||||
let nam = self.parse_bend_name()?;
|
||||
@ -366,7 +388,7 @@ impl<'a> PyParser<'a> {
|
||||
}
|
||||
while let Some(op) = self.peek_oper() {
|
||||
if op.precedence() == prec {
|
||||
self.parse_oper()?;
|
||||
self.try_parse_oper().unwrap();
|
||||
let rhs = self.parse_infix_expr(prec + 1, inline)?;
|
||||
lhs = Expr::Opr { op, lhs: Box::new(lhs), rhs: Box::new(rhs) };
|
||||
self.skip_trivia_inline();
|
||||
|
@ -448,6 +448,15 @@ impl Expr {
|
||||
}
|
||||
Expr::Map { entries } => map_init(entries),
|
||||
Expr::MapGet { .. } => unreachable!(),
|
||||
Expr::TreeNode { left, right } => {
|
||||
let left = left.to_fun();
|
||||
let right = right.to_fun();
|
||||
fun::Term::call(fun::Term::r#ref("Tree/Node"), [left, right])
|
||||
}
|
||||
Expr::TreeLeaf { val } => {
|
||||
let val = val.to_fun();
|
||||
fun::Term::app(fun::Term::r#ref("Tree/Leaf"), val)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1,5 +1,3 @@
|
||||
type Tree = (node lft rgt) | (leaf val)
|
||||
|
||||
tail_recursive = @x (x @pred @acc (tail_recursive pred (+ 1 acc)) @acc 0)
|
||||
|
||||
fold_ = @bm (bm
|
||||
@ -60,23 +58,23 @@ List.reverse_over xs ys = match xs {
|
||||
}
|
||||
|
||||
Tree.leaves tree = match tree {
|
||||
Tree/leaf: 1
|
||||
Tree/node: (+ (Tree.leaves tree.lft) (Tree.leaves tree.rgt))
|
||||
Tree/Leaf: 1
|
||||
Tree/Node: (+ (Tree.leaves tree.left) (Tree.leaves tree.right))
|
||||
}
|
||||
|
||||
Tree.nodes tree = match tree {
|
||||
Tree/leaf: 0
|
||||
Tree/node: (+ 1 (+ (Tree.nodes tree.lft) (Tree.nodes tree.rgt)))
|
||||
Tree/Leaf: 0
|
||||
Tree/Node: (+ 1 (+ (Tree.nodes tree.left) (Tree.nodes tree.right)))
|
||||
}
|
||||
|
||||
Tree.height tree = match tree {
|
||||
Tree/leaf: 0
|
||||
Tree/node: (+ 1 (max (Tree.height tree.lft) (Tree.height tree.rgt)))
|
||||
Tree/Leaf: 0
|
||||
Tree/Node: (+ 1 (max (Tree.height tree.left) (Tree.height tree.right)))
|
||||
}
|
||||
|
||||
Tree.map tree f = match tree {
|
||||
Tree/leaf: (Tree/leaf (f tree.val))
|
||||
Tree/node: (Tree/node (Tree.map tree.lft f) (Tree.map tree.rgt f))
|
||||
Tree/Leaf: (Tree/Leaf (f tree.value))
|
||||
Tree/Node: (Tree/Node (Tree.map tree.left f) (Tree.map tree.right f))
|
||||
}
|
||||
|
||||
max a b = switch (> a b) {
|
||||
@ -85,8 +83,8 @@ max a b = switch (> a b) {
|
||||
}
|
||||
|
||||
Tree.flip tree = match tree {
|
||||
Tree/leaf: tree
|
||||
Tree/node: (Tree/node (Tree.flip tree.rgt) (Tree.flip tree.lft))
|
||||
Tree/Leaf: tree
|
||||
Tree/Node: (Tree/Node (Tree.flip tree.right) (Tree.flip tree.left))
|
||||
}
|
||||
|
||||
calc =
|
||||
|
@ -1,5 +1,4 @@
|
||||
type Tree = (Leaf a) | (Both a b)
|
||||
(Warp s (Tree/Leaf a) (Tree/Leaf b)) = 0
|
||||
(Warp s (Tree/Both a b) (Tree/Both c d)) = 1
|
||||
(Warp s (Tree/Node a b) (Tree/Node c d)) = 1
|
||||
|
||||
main = *
|
||||
|
@ -1,45 +1,44 @@
|
||||
type Tree = (Leaf a) | (Both a b)
|
||||
type Error = Err
|
||||
|
||||
# Atomic Swapper
|
||||
(Swap n a b) = switch n {
|
||||
0: (Tree/Both a b)
|
||||
_: (Tree/Both b a)
|
||||
0: (Tree/Node a b)
|
||||
_: (Tree/Node b a)
|
||||
}
|
||||
|
||||
# Swaps distant values in parallel; corresponds to a Red Box
|
||||
(Warp s (Tree/Leaf a) (Tree/Leaf b)) = (Swap (^ (> a b) s) (Tree/Leaf a) (Tree/Leaf b))
|
||||
(Warp s (Tree/Both a b) (Tree/Both c d)) = (Join (Warp s a c) (Warp s b d))
|
||||
(Warp s (Tree/Node a b) (Tree/Node c d)) = (Join (Warp s a c) (Warp s b d))
|
||||
(Warp s a b) = Error/Err
|
||||
|
||||
# Rebuilds the warped tree in the original order
|
||||
(Join (Tree/Both a b) (Tree/Both c d)) = (Tree/Both (Tree/Both a c) (Tree/Both b d))
|
||||
(Join (Tree/Node a b) (Tree/Node c d)) = (Tree/Node (Tree/Node a c) (Tree/Node b d))
|
||||
(Join a b) = Error/Err
|
||||
|
||||
# Recursively warps each sub-tree; corresponds to a Blue/Green Box
|
||||
(Flow s (Tree/Leaf a)) = (Tree/Leaf a)
|
||||
(Flow s (Tree/Both a b)) = (Down s (Warp s a b))
|
||||
(Flow s (Tree/Node a b)) = (Down s (Warp s a b))
|
||||
|
||||
# Propagates Flow downwards
|
||||
(Down s (Tree/Leaf a)) = (Tree/Leaf a)
|
||||
(Down s (Tree/Both a b)) = (Tree/Both (Flow s a) (Flow s b))
|
||||
(Down s (Tree/Node a b)) = (Tree/Node (Flow s a) (Flow s b))
|
||||
|
||||
# Bitonic Sort
|
||||
(Sort s (Tree/Leaf a)) = (Tree/Leaf a)
|
||||
(Sort s (Tree/Both a b)) = (Flow s (Tree/Both (Sort 0 a) (Sort 1 b)))
|
||||
(Sort s (Tree/Node a b)) = (Flow s (Tree/Node (Sort 0 a) (Sort 1 b)))
|
||||
|
||||
# Generates a tree of depth `n`
|
||||
(Gen n x) = switch n {
|
||||
0: (Tree/Leaf x)
|
||||
_: (Tree/Both (Gen n-1 (* x 2)) (Gen n-1 (+ (* x 2) 1)))
|
||||
_: (Tree/Node (Gen n-1 (* x 2)) (Gen n-1 (+ (* x 2) 1)))
|
||||
}
|
||||
|
||||
# Reverses a tree
|
||||
(Rev (Tree/Leaf x)) = (Tree/Leaf x)
|
||||
(Rev (Tree/Both a b)) = (Tree/Both (Rev b) (Rev a))
|
||||
(Rev (Tree/Node a b)) = (Tree/Node (Rev b) (Rev a))
|
||||
|
||||
# Sums a tree
|
||||
(Sum (Tree/Leaf x)) = x
|
||||
(Sum (Tree/Both a b)) = (+ (Sum a) (Sum b))
|
||||
(Sum (Tree/Node a b)) = (+ (Sum a) (Sum b))
|
||||
|
||||
Main = (Sum (Sort 0 (Rev (Gen 4 0))))
|
||||
|
@ -1,5 +1,3 @@
|
||||
type Tree = (Leaf x) | (Node x0 x1)
|
||||
|
||||
add = λa λb (+ a b)
|
||||
|
||||
gen = λn switch n {
|
||||
@ -9,8 +7,8 @@ gen = λn switch n {
|
||||
|
||||
sum = λt
|
||||
match t {
|
||||
Tree/Leaf: t.x
|
||||
Tree/Node: (add (sum t.x0) (sum t.x1))
|
||||
Tree/Leaf: t.value
|
||||
Tree/Node: (add (sum t.left) (sum t.right))
|
||||
}
|
||||
|
||||
main = (sum (gen 8))
|
||||
|
File diff suppressed because one or more lines are too long
25
tests/golden_tests/desugar_file/tree_syntax.bend
Normal file
25
tests/golden_tests/desugar_file/tree_syntax.bend
Normal file
@ -0,0 +1,25 @@
|
||||
fun0 = ![!0 ![!1 ![!2, !3]]]
|
||||
fun1 = !(![!*!*])
|
||||
fun2 = !!!*
|
||||
fun3 = !1
|
||||
fun4 = @n switch n {
|
||||
0: !0
|
||||
_: ![(fun4 n-1) (fun4 n-1)]
|
||||
}
|
||||
|
||||
def imp0:
|
||||
return ![!0, ![!1, ![!2, !3]]]
|
||||
def imp1:
|
||||
return !(![!*,!*])
|
||||
def imp2:
|
||||
return !!!*
|
||||
def imp3:
|
||||
return !1
|
||||
def imp4(n):
|
||||
switch n:
|
||||
case 0:
|
||||
return !0
|
||||
case _:
|
||||
return ![imp4(n-1), imp4(n-1)]
|
||||
|
||||
main = *
|
@ -1,6 +1,4 @@
|
||||
# should return (a+b+c) * 2^depth
|
||||
type Tree = (node ~lft ~rgt) | (leaf val)
|
||||
|
||||
main =
|
||||
let depth = 2
|
||||
let a = 1;
|
||||
@ -9,11 +7,11 @@ main =
|
||||
let n = 0;
|
||||
let tree = bend n {
|
||||
when (< n depth):
|
||||
(Tree/node (fork (+ n 1)) (fork (+ n 1)))
|
||||
![(fork (+ n 1)) (fork (+ n 1))]
|
||||
else:
|
||||
(Tree/leaf c)
|
||||
!c
|
||||
}
|
||||
fold tree {
|
||||
Tree/node: (+ tree.lft tree.rgt)
|
||||
Tree/leaf: (+ tree.val (+ a b))
|
||||
Tree/Node: (+ tree.left tree.right)
|
||||
Tree/Leaf: (+ tree.value (+ a b))
|
||||
}
|
||||
|
@ -1,45 +1,44 @@
|
||||
type Tree = (Leaf a) | (Both a b)
|
||||
type Error = Err
|
||||
|
||||
# Atomic Swapper
|
||||
(Swap n a b) = switch n {
|
||||
0: (Tree/Both a b)
|
||||
_: (Tree/Both b a)
|
||||
0: (Tree/Node a b)
|
||||
_: (Tree/Node b a)
|
||||
}
|
||||
|
||||
# Swaps distant values in parallel; corresponds to a Red Box
|
||||
(Warp s (Tree/Leaf a) (Tree/Leaf b)) = (Swap (^ (> a b) s) (Tree/Leaf a) (Tree/Leaf b))
|
||||
(Warp s (Tree/Both a b) (Tree/Both c d)) = (Join (Warp s a c) (Warp s b d))
|
||||
(Warp s (Tree/Node a b) (Tree/Node c d)) = (Join (Warp s a c) (Warp s b d))
|
||||
(Warp s a b) = Error/Err
|
||||
|
||||
# Rebuilds the warped tree in the original order
|
||||
(Join (Tree/Both a b) (Tree/Both c d)) = (Tree/Both (Tree/Both a c) (Tree/Both b d))
|
||||
(Join (Tree/Node a b) (Tree/Node c d)) = (Tree/Node (Tree/Node a c) (Tree/Node b d))
|
||||
(Join a b) = Error/Err
|
||||
|
||||
# Recursively warps each sub-tree; corresponds to a Blue/Green Box
|
||||
(Flow s (Tree/Leaf a)) = (Tree/Leaf a)
|
||||
(Flow s (Tree/Both a b)) = (Down s (Warp s a b))
|
||||
(Flow s (Tree/Node a b)) = (Down s (Warp s a b))
|
||||
|
||||
# Propagates Flow downwards
|
||||
(Down s (Tree/Leaf a)) = (Tree/Leaf a)
|
||||
(Down s (Tree/Both a b)) = (Tree/Both (Flow s a) (Flow s b))
|
||||
(Down s (Tree/Node a b)) = (Tree/Node (Flow s a) (Flow s b))
|
||||
|
||||
# Bitonic Sort
|
||||
(Sort s (Tree/Leaf a)) = (Tree/Leaf a)
|
||||
(Sort s (Tree/Both a b)) = (Flow s (Tree/Both (Sort 0 a) (Sort 1 b)))
|
||||
(Sort s (Tree/Node a b)) = (Flow s (Tree/Node (Sort 0 a) (Sort 1 b)))
|
||||
|
||||
# Generates a tree of depth `n`
|
||||
(Gen n x) = switch n {
|
||||
0: (Tree/Leaf x)
|
||||
_: (Tree/Both (Gen n-1 (* x 2)) (Gen n-1 (+ (* x 2) 1)))
|
||||
_: (Tree/Node (Gen n-1 (* x 2)) (Gen n-1 (+ (* x 2) 1)))
|
||||
}
|
||||
|
||||
# Reverses a tree
|
||||
(Rev (Tree/Leaf x)) = (Tree/Leaf x)
|
||||
(Rev (Tree/Both a b)) = (Tree/Both (Rev b) (Rev a))
|
||||
(Rev (Tree/Node a b)) = (Tree/Node (Rev b) (Rev a))
|
||||
|
||||
# Sums a tree
|
||||
(Sum (Tree/Leaf x)) = x
|
||||
(Sum (Tree/Both a b)) = (+ (Sum a) (Sum b))
|
||||
(Sum (Tree/Node a b)) = (+ (Sum a) (Sum b))
|
||||
|
||||
Main = (Sum (Sort 0 (Rev (Gen 4 0))))
|
||||
|
@ -1,5 +1,5 @@
|
||||
# Test that branching statements can end with an assignment
|
||||
type Tree:
|
||||
type MyTree:
|
||||
node { val, ~lft, ~rgt }
|
||||
leaf
|
||||
|
||||
@ -13,14 +13,14 @@ def main:
|
||||
|
||||
bend x = 1, h = 0:
|
||||
when h < n:
|
||||
y = Tree/node { val: x, lft: fork(2 * x, h + 1), rgt: fork(2 * x + 1, h + 1) }
|
||||
y = MyTree/node { val: x, lft: fork(2 * x, h + 1), rgt: fork(2 * x + 1, h + 1) }
|
||||
else:
|
||||
y = Tree/leaf
|
||||
y = MyTree/leaf
|
||||
|
||||
fold y:
|
||||
case Tree/node:
|
||||
case MyTree/node:
|
||||
z = y.val + y.lft + y.rgt
|
||||
case Tree/leaf:
|
||||
case MyTree/leaf:
|
||||
z = 0
|
||||
|
||||
return z
|
@ -1,11 +1,7 @@
|
||||
type Tree:
|
||||
Node { ~lft, ~rgt }
|
||||
Leaf { val }
|
||||
|
||||
def main():
|
||||
bend x = 0:
|
||||
when x < 3:
|
||||
tree = Tree/Node { lft: fork(x + 1), rgt: fork(x + 1) }
|
||||
tree = ![fork(x + 1), fork(x + 1)]
|
||||
else:
|
||||
tree = Tree/Leaf { val: 7 }
|
||||
tree = !7
|
||||
return tree
|
@ -1,21 +1,11 @@
|
||||
type Tree:
|
||||
Node { ~lft, ~rgt }
|
||||
Leaf { val }
|
||||
|
||||
def enum(tree):
|
||||
idx = 0
|
||||
fold tree with idx:
|
||||
case Tree/Node:
|
||||
return Tree/Node {
|
||||
lft: tree.lft(idx * 2 + 0),
|
||||
rgt: tree.rgt(idx * 2 + 1),
|
||||
}
|
||||
return ![tree.left(idx * 2 + 0), tree.right(idx * 2 + 1)]
|
||||
case Tree/Leaf:
|
||||
return Tree/Leaf { val: (idx, tree.val) }
|
||||
return !(idx, tree.value)
|
||||
|
||||
def main:
|
||||
tree = Tree/Node {
|
||||
lft: Tree/Node { lft: Tree/Leaf { val: 1 }, rgt: Tree/Leaf { val: 2 }, },
|
||||
rgt: Tree/Node { lft: Tree/Leaf { val: 3 }, rgt: Tree/Leaf { val: 4 }, }
|
||||
}
|
||||
tree = ![![!1, !2], ![!3, !4]]
|
||||
return enum(tree)
|
@ -1,17 +1,10 @@
|
||||
type Tree:
|
||||
Node { ~lft, ~rgt }
|
||||
Leaf { val }
|
||||
|
||||
def sum(tree):
|
||||
fold tree:
|
||||
case Tree/Node:
|
||||
return tree.lft + tree.rgt
|
||||
return tree.left + tree.right
|
||||
case Tree/Leaf:
|
||||
return tree.val
|
||||
return tree.value
|
||||
|
||||
def main:
|
||||
tree = Tree/Node {
|
||||
lft: Tree/Node { lft: Tree/Leaf { val: 1 }, rgt: Tree/Leaf { val: 2 } },
|
||||
rgt: Tree/Node { lft: Tree/Leaf { val: 3 }, rgt: Tree/Leaf { val: 4 } }
|
||||
}
|
||||
tree = ![![!1, !2], ![!3, !4]]
|
||||
return sum(tree)
|
@ -1,23 +1,20 @@
|
||||
type Tree = (Leaf x) | (Node x0 x1)
|
||||
type List_ = Nil | (Cons h t)
|
||||
|
||||
sort (Tree/Leaf v) = (List_/Cons v List_/Nil)
|
||||
sort (Tree/Leaf v) = (List/Cons v List/Nil)
|
||||
sort (Tree/Node a b) = (merge (sort a) (sort b))
|
||||
|
||||
merge (List_/Nil) b = b
|
||||
merge (List_/Cons x xs) (List_/Nil) = (List_/Cons x xs)
|
||||
merge (List_/Cons x xs) (List_/Cons y ys) =
|
||||
merge (List/Nil) b = b
|
||||
merge (List/Cons x xs) (List/Nil) = (List/Cons x xs)
|
||||
merge (List/Cons x xs) (List/Cons y ys) =
|
||||
let t = switch _ = (< x y) {
|
||||
0: λaλbλcλt(t c a b)
|
||||
_: λaλbλcλt(t a b c)
|
||||
}
|
||||
|
||||
let t = (t (List_/Cons x) λx(x) (List_/Cons y))
|
||||
let t = (t (List/Cons x) λx(x) (List/Cons y))
|
||||
|
||||
(t λa λb λc (a (merge (b xs) (c ys))))
|
||||
|
||||
sum List_/Nil = 0
|
||||
sum (List_/Cons h t) = (+ h (sum t))
|
||||
sum List/Nil = 0
|
||||
sum (List/Cons h t) = (+ h (sum t))
|
||||
|
||||
range n = switch n {
|
||||
0: λx (Tree/Leaf x)
|
||||
|
@ -2,13 +2,13 @@ type Bool:
|
||||
True
|
||||
False
|
||||
|
||||
type Tree = (node ~lft ~rgt) | (leaf val)
|
||||
type MyTree = (node ~lft ~rgt) | (leaf val)
|
||||
|
||||
def tree_xor(tree):
|
||||
fold tree:
|
||||
case Tree/node:
|
||||
case MyTree/node:
|
||||
return xor(tree.lft, tree.rgt);
|
||||
case Tree/leaf:
|
||||
case MyTree/leaf:
|
||||
return tree.val;
|
||||
|
||||
(xor Bool/True Bool/False) = Bool/True
|
||||
@ -19,8 +19,8 @@ main =
|
||||
let depth = 10
|
||||
let tree = bend n = 0 {
|
||||
when (< n depth):
|
||||
(Tree/node (fork (+ n 1)) (fork (+ n 1)))
|
||||
(MyTree/node (fork (+ n 1)) (fork (+ n 1)))
|
||||
else:
|
||||
if (% n 2) { (Tree/leaf Bool/True) } else { (Tree/leaf Bool/False) }
|
||||
if (% n 2) { (MyTree/leaf Bool/True) } else { (MyTree/leaf Bool/False) }
|
||||
}
|
||||
(tree_xor tree)
|
||||
|
@ -1,5 +1,3 @@
|
||||
type Tree = (Leaf x) | (Node x0 x1)
|
||||
|
||||
add = λa λb (+ a b)
|
||||
|
||||
gen = λn switch n {
|
||||
@ -9,8 +7,8 @@ gen = λn switch n {
|
||||
|
||||
sum = λt
|
||||
match t {
|
||||
Tree/Leaf: t.x
|
||||
Tree/Node: (add (sum t.x0) (sum t.x1))
|
||||
Tree/Leaf: t.value
|
||||
Tree/Node: (add (sum t.left) (sum t.right))
|
||||
}
|
||||
|
||||
main = (sum (gen 8))
|
||||
|
@ -1,11 +1,11 @@
|
||||
type Tree = (Node lt rt rd ld) | (Leaf val)
|
||||
type Tree_ = (Node lt rt rd ld) | (Leaf val)
|
||||
|
||||
(map) =
|
||||
λarg1 λarg2 use tree = arg2;
|
||||
use f = arg1;
|
||||
match tree with f {
|
||||
Tree/Node: (Tree/Node (map f tree.lt) (map f tree.rt) (map f tree.rd) (map f tree.ld));
|
||||
Tree/Leaf: (Tree/Leaf (f tree.val));
|
||||
Tree_/Node: (Tree_/Node (map f tree.lt) (map f tree.rt) (map f tree.rd) (map f tree.ld));
|
||||
Tree_/Leaf: (Tree_/Leaf (f tree.val));
|
||||
}
|
||||
|
||||
main = map
|
||||
|
@ -88,12 +88,12 @@ input_file: tests/golden_tests/compile_file/redex_order_recursive.bend
|
||||
@Tree.flip = ((@Tree.flip__C2 a) a)
|
||||
|
||||
@Tree.flip__C0 = (c (a e))
|
||||
& @Tree/node ~ (b (d e))
|
||||
& @Tree/Node ~ (b (d e))
|
||||
&!@Tree.flip ~ (a b)
|
||||
&!@Tree.flip ~ (c d)
|
||||
|
||||
@Tree.flip__C1 = (* a)
|
||||
& @Tree/leaf ~ a
|
||||
& @Tree/Leaf ~ a
|
||||
|
||||
@Tree.flip__C2 = (?((@Tree.flip__C0 @Tree.flip__C1) a) a)
|
||||
|
||||
@ -118,12 +118,12 @@ input_file: tests/golden_tests/compile_file/redex_order_recursive.bend
|
||||
@Tree.map = ((@Tree.map__C2 a) a)
|
||||
|
||||
@Tree.map__C0 = (a (d ({b e} g)))
|
||||
& @Tree/node ~ (c (f g))
|
||||
& @Tree/Node ~ (c (f g))
|
||||
&!@Tree.map ~ (a (b c))
|
||||
&!@Tree.map ~ (d (e f))
|
||||
|
||||
@Tree.map__C1 = (* (a ((a b) c)))
|
||||
& @Tree/leaf ~ (b c)
|
||||
& @Tree/Leaf ~ (b c)
|
||||
|
||||
@Tree.map__C2 = (?((@Tree.map__C0 @Tree.map__C1) a) a)
|
||||
|
||||
@ -136,13 +136,13 @@ input_file: tests/golden_tests/compile_file/redex_order_recursive.bend
|
||||
|
||||
@Tree.nodes__C1 = (?((@Tree.nodes__C0 (* (* 0))) a) a)
|
||||
|
||||
@Tree/leaf = (a ((@Tree/leaf/tag (a b)) b))
|
||||
@Tree/Leaf = (a ((@Tree/Leaf/tag (a b)) b))
|
||||
|
||||
@Tree/leaf/tag = 1
|
||||
@Tree/Leaf/tag = 1
|
||||
|
||||
@Tree/node = (a (b ((@Tree/node/tag (a (b c))) c)))
|
||||
@Tree/Node = (a (b ((@Tree/Node/tag (a (b c))) c)))
|
||||
|
||||
@Tree/node/tag = 0
|
||||
@Tree/Node/tag = 0
|
||||
|
||||
@add = ((@add__C0 ((a a) b)) b)
|
||||
|
||||
|
@ -4,4 +4,4 @@ input_file: tests/golden_tests/compile_file_o_all/non_exhaustive_tree.bend
|
||||
---
|
||||
[4m[1m[31mErrors:[0m
|
||||
[1mIn definition '[4mWarp[0m[1m':[0m
|
||||
Non-exhaustive pattern matching rule. Constructor 'Tree/Both' of type 'Tree' not covered
|
||||
Non-exhaustive pattern matching rule. Constructor 'Tree/Leaf' of type 'Tree' not covered
|
||||
|
37
tests/snapshots/desugar_file__tree_syntax.bend.snap
Normal file
37
tests/snapshots/desugar_file__tree_syntax.bend.snap
Normal file
@ -0,0 +1,37 @@
|
||||
---
|
||||
source: tests/golden_tests.rs
|
||||
input_file: tests/golden_tests/desugar_file/tree_syntax.bend
|
||||
---
|
||||
(fun0) = (Tree/Node (Tree/Leaf 0) (Tree/Node (Tree/Leaf 1) (Tree/Node (Tree/Leaf 2) (Tree/Leaf 3))))
|
||||
|
||||
(fun1) = (Tree/Leaf (Tree/Node (Tree/Leaf *) (Tree/Leaf *)))
|
||||
|
||||
(fun2) = (Tree/Leaf (Tree/Leaf (Tree/Leaf *)))
|
||||
|
||||
(fun3) = (Tree/Leaf 1)
|
||||
|
||||
(fun4) = λa switch a { 0: (Tree/Leaf 0); _: fun4__C0; }
|
||||
|
||||
(imp0) = (Tree/Node (Tree/Leaf 0) (Tree/Node (Tree/Leaf 1) (Tree/Node (Tree/Leaf 2) (Tree/Leaf 3))))
|
||||
|
||||
(imp1) = (Tree/Leaf (Tree/Node (Tree/Leaf *) (Tree/Leaf *)))
|
||||
|
||||
(imp2) = (Tree/Leaf (Tree/Leaf (Tree/Leaf *)))
|
||||
|
||||
(imp3) = (Tree/Leaf 1)
|
||||
|
||||
(imp4) = λa switch a { 0: (Tree/Leaf 0); _: imp4__C0; }
|
||||
|
||||
(main) = *
|
||||
|
||||
(Tree/Node) = λa λb λc (c Tree/Node/tag a b)
|
||||
|
||||
(Tree/Leaf) = λa λb (b Tree/Leaf/tag a)
|
||||
|
||||
(Tree/Node/tag) = 0
|
||||
|
||||
(Tree/Leaf/tag) = 1
|
||||
|
||||
(fun4__C0) = λa let {b c} = a; (Tree/Node (fun4 b) (fun4 c))
|
||||
|
||||
(imp4__C0) = λa let {b c} = a; (Tree/Node (imp4 b) (imp4 c))
|
@ -2,4 +2,4 @@
|
||||
source: tests/golden_tests.rs
|
||||
input_file: examples/gen_tree.bend
|
||||
---
|
||||
λa (a Tree/Node/tag 1 λb (b Tree/Node/tag 3 λc (c Tree/Node/tag 7 λd (d Tree/Node/tag 15 Tree/Leaf Tree/Leaf) λe (e Tree/Node/tag 16 Tree/Leaf Tree/Leaf)) λf (f Tree/Node/tag 8 λg (g Tree/Node/tag 17 Tree/Leaf Tree/Leaf) λh (h Tree/Node/tag 18 Tree/Leaf Tree/Leaf))) λi (i Tree/Node/tag 4 λj (j Tree/Node/tag 9 λk (k Tree/Node/tag 19 Tree/Leaf Tree/Leaf) λl (l Tree/Node/tag 20 Tree/Leaf Tree/Leaf)) λm (m Tree/Node/tag 10 λn (n Tree/Node/tag 21 Tree/Leaf Tree/Leaf) λo (o Tree/Node/tag 22 Tree/Leaf Tree/Leaf))))
|
||||
λa (a MyTree/Node/tag 1 λb (b MyTree/Node/tag 3 λc (c MyTree/Node/tag 7 λd (d MyTree/Node/tag 15 MyTree/Leaf MyTree/Leaf) λe (e MyTree/Node/tag 16 MyTree/Leaf MyTree/Leaf)) λf (f MyTree/Node/tag 8 λg (g MyTree/Node/tag 17 MyTree/Leaf MyTree/Leaf) λh (h MyTree/Node/tag 18 MyTree/Leaf MyTree/Leaf))) λi (i MyTree/Node/tag 4 λj (j MyTree/Node/tag 9 λk (k MyTree/Node/tag 19 MyTree/Leaf MyTree/Leaf) λl (l MyTree/Node/tag 20 MyTree/Leaf MyTree/Leaf)) λm (m MyTree/Node/tag 10 λn (n MyTree/Node/tag 21 MyTree/Leaf MyTree/Leaf) λo (o MyTree/Node/tag 22 MyTree/Leaf MyTree/Leaf))))
|
||||
|
@ -2,14 +2,14 @@
|
||||
source: tests/golden_tests.rs
|
||||
input_file: tests/golden_tests/simplify_matches/complex_with_case.bend
|
||||
---
|
||||
(map) = λa λb (match b { Tree/Node c d e f: λg (Tree/Node (map g c) (map g d) (map g e) (map g f)); Tree/Leaf h: λi (Tree/Leaf (i h)); } a)
|
||||
(map) = λa λb (match b { Tree_/Node c d e f: λg (Tree_/Node (map g c) (map g d) (map g e) (map g f)); Tree_/Leaf h: λi (Tree_/Leaf (i h)); } a)
|
||||
|
||||
(main) = map
|
||||
|
||||
(Tree/Node) = λa λb λc λd λe (e Tree/Node/tag a b c d)
|
||||
(Tree_/Node) = λa λb λc λd λe (e Tree_/Node/tag a b c d)
|
||||
|
||||
(Tree/Leaf) = λa λb (b Tree/Leaf/tag a)
|
||||
(Tree_/Leaf) = λa λb (b Tree_/Leaf/tag a)
|
||||
|
||||
(Tree/Node/tag) = 0
|
||||
(Tree_/Node/tag) = 0
|
||||
|
||||
(Tree/Leaf/tag) = 1
|
||||
(Tree_/Leaf/tag) = 1
|
||||
|
Loading…
Reference in New Issue
Block a user