Skip to content

Commit

Permalink
Partially updates doc and follows requests from PR review
Browse files Browse the repository at this point in the history
  • Loading branch information
In-Veritas committed Dec 20, 2024
1 parent 6d699c4 commit 8d9a7e0
Show file tree
Hide file tree
Showing 49 changed files with 316 additions and 249 deletions.
27 changes: 26 additions & 1 deletion docs/builtins.md
Original file line number Diff line number Diff line change
Expand Up @@ -161,7 +161,32 @@ tree = ![![!1, !2],![!3, !4]]
```

Technically your trees don't need to end with leaves, but if you don't, your program will be very hard to reason about.
## Maybe

```python
type Maybe(T):
Some{ value }
None
```
**`Maybe`** is a structure that may or not contain a value. It is meant to be used as a return type for functions that can fail. This way you don't need to resort to unreachable() in order to handle errors.

#### Syntax
Here's how you create a new `Maybe` containing the Nat value of 1:
```python
maybe = Maybe/Some(Nat/Succ(Nat/Zero))
```
## Maybe functions

### Maybe/unwrap
Maybe has a builtin function that returns the value inside the `Maybe` if it is `Some`, and returns `unreachable()` if it is `None`.
```python
def Maybe/unwrap(m: Maybe(T)) -> T:
match m:
case Maybe/Some:
return m.val
case Maybe/None:
return unreachable()
```
## Map

```python
Expand All @@ -173,7 +198,7 @@ type 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.
- **Node { value ~left ~right }**: Represents a map node with a `Maybe` and `left` and `right` subtrees. Empty nodes have `Maybe/None` stored in the `value` field, whislt non-empty nodes have `Maybe/Some` stored in the `value` field.
- **Leaf**: Represents an unwritten, empty portion of the map.

#### Syntax
Expand Down
6 changes: 4 additions & 2 deletions examples/parallel_and.bend
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
type Bool = True | False

# This program allocates a tree with True at the leaves then parallel ANDs them.
type Bool:
True
False

def and(a: Bool, b: Bool) -> Bool:
match a:
case Bool/True:
Expand Down
43 changes: 22 additions & 21 deletions src/fun/builtins.bend
Original file line number Diff line number Diff line change
Expand Up @@ -173,21 +173,21 @@ def Tree/reverse(tree: Tree(T)) -> Tree(T):
# MAYBE Impl

type Maybe(T):
Some{val: T}
Some { value: T }
None

# Removes the value on a Maybe
def Maybe/unwrap(m: Maybe(T)) -> T:
match m:
case Maybe/Some:
return m.val
return m.value
case Maybe/None:
return unreachable()

# MAP Impl

type Map(T):
Node {value: Maybe(T), ~left: Map(T), ~right: Map(T)}
Node { value: Maybe(T), ~left: Map(T), ~right: Map(T)}
Leaf

# Creates an empty Map
Expand All @@ -197,6 +197,8 @@ def Map/empty() -> Map(T):
# Gets a value on a Map
def Map/get (map: Map(T), key: u24) -> (T, Map(T)):
match map:
case Map/Leaf:
return (unreachable(), map)
case Map/Node:
if (0 == key):
return (Maybe/unwrap(map.value), map)
Expand All @@ -205,24 +207,23 @@ def Map/get (map: Map(T), key: u24) -> (T, Map(T)):
return(got, Map/Node(map.value, rest, map.right))
else:
(got, rest) = Map/get(map.right, (key / 2))
return(got, Map/Node(map.value, rest, map.left))
case Map/Leaf:
return (unreachable(), map)
return(got, Map/Node(map.value, map.left, rest))


# Checks if a node has a value on a given key, returning Maybe/Some if it does, Maybe/None otherwise
def Map/get_check (map: Map(T), key: u24) -> (Map(T), Maybe(T)):
def Map/get_check (map: Map(T), key: u24) -> (Maybe(T), Map(T)):
match map:
case Map/Leaf:
return (map, Maybe/None)
return (Maybe/None, map)
case Map/Node:
if (0 == key):
return (map, map.value)
return (map.value, map)
elif (key % 2 == 0):
(new_map, new_value) = Map/get_check(map.left, (key / 2))
return (Map/Node(map.value, new_map, map.right), new_value)
(new_value, new_map) = Map/get_check(map.left, (key / 2))
return (new_value, Map/Node(map.value, new_map, map.right))
else:
(new_map, new_value) = Map/get_check(map.right, (key / 2))
return (Map/Node(map.value, map.left, new_map), new_value)
(new_value, new_map) = Map/get_check(map.right, (key / 2))
return (new_value, Map/Node(map.value, map.left, new_map))

# Sets a value on a Map
def Map/set (map: Map(T), key: u24, value: T) -> Map(T):
Expand All @@ -244,23 +245,23 @@ def Map/set (map: Map(T), key: u24, value: T) -> Map(T):


# Checks if a Map contains a given key
def Map/contains (map: Map(T), key: u24) -> (Map(T), u24):
def Map/contains (map: Map(T), key: u24) -> (u24, Map(T)):
match map:
case Map/Leaf:
return (map, 0)
return (0, map)
case Map/Node:
if (0 == key):
match map.value:
case Maybe/Some:
return (map, 1)
return (1, map)
case Maybe/None:
return (map, 0)
return (0, map)
elif ((key % 2) == 0):
(new_map, new_value) = Map/contains(map.left, (key / 2))
return (Map/Node(map.value, new_map, map.right), new_value)
(new_value, new_map) = Map/contains(map.left, (key / 2))
return (new_value, Map/Node(map.value, new_map, map.right))
else:
(new_map, new_value) = Map/contains(map.right, (key / 2))
return (Map/Node(map.value, map.left, new_map), new_value)
(new_value, new_map) = Map/contains(map.right, (key / 2))
return (new_value, Map/Node(map.value, map.left, new_map))

# Applies a funtion to a value on a Map
def Map/map (map: Map(T), key: u24, f: T -> T) -> Map(T):
Expand Down
2 changes: 1 addition & 1 deletion tests/golden_tests.rs
Original file line number Diff line number Diff line change
Expand Up @@ -478,7 +478,7 @@ fn prelude() {
let _guard = RUN_MUTEX.lock().unwrap();
let book = parse_book_single_file(code, path)?;
let compile_opts = CompileOpts::default();
let diagnostics_cfg = DiagnosticsConfig::default();
let diagnostics_cfg = DiagnosticsConfig::new(Severity::Error, true);
let (term, _, diags) =
run_book(book, RunOpts::default(), compile_opts, diagnostics_cfg, None, "run-c")?.unwrap();
let res = format!("{diags}{term}");
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,4 +9,4 @@ def main:
x <- wrap(0)
case Bool/F:
x = wrap(0)
return wrap(x)
return wrap(x)
3 changes: 1 addition & 2 deletions tests/golden_tests/compile_file_o_all/list_merge_sort.bend
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
type List_ = (Cons head tail) | Nil

type Bool = True | False
type List_ = (Cons head tail) | Nil

If Bool/True then else = then
If Bool/False then else = else
Expand Down
7 changes: 4 additions & 3 deletions tests/golden_tests/compile_file_o_all/non_exhaustive_and.bend
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
type Bool = True | False
Bool.and Bool/True Bool/True = Bool/True
Bool.and Bool/False Bool/False = Bool/False
type Bool = T | F

Bool.and Bool/T Bool/T = Bool/T
Bool.and Bool/F Bool/F = Bool/F

Main = *
11 changes: 7 additions & 4 deletions tests/golden_tests/desugar_file/ask_branch.bend
Original file line number Diff line number Diff line change
@@ -1,9 +1,12 @@
type Bool = True | False
type Bool:
T
F

def main:
with IO:
match _ = Bool/True:
case Bool/True:
match _ = Bool/T:
case Bool/T:
x <- wrap(0)
case Bool/False:
case Bool/F:
x <- wrap(0)
return wrap(x)
8 changes: 4 additions & 4 deletions tests/golden_tests/encode_pattern_match/and3.bend
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
type Bool = True | False
type Bool = T | F

And (Bool/True, Bool/True, Bool/True) = Bool/True
And * = Bool/False
And (Bool/T, Bool/T, Bool/T) = Bool/T
And * = Bool/F

main = (And (Bool/False, Bool/True, Bool/False))
main = (And (Bool/F, Bool/T, Bool/F))
9 changes: 5 additions & 4 deletions tests/golden_tests/encode_pattern_match/bool_tup.bend
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
type Bool = True | False
foo (Bool/True, x) = x
foo * = Bool/False
type Bool = T | F

main = (foo (Bool/False, Bool/True))
foo (Bool/T, x) = x
foo * = Bool/F

main = (foo (Bool/F, Bool/T))
2 changes: 2 additions & 0 deletions tests/golden_tests/encode_pattern_match/common.bend
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,8 @@ type List_
= (Cons x xs)
| Nil

type Bool = True | False

type Light = Red | Yellow | Green

type Direction
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
type Bool = True | False
type Either = (Left value) | (Right value)
type Bool = True | False

Foo (Either/Left Bool/False) (Either/Left Bool/False) = 1
Foo (Either/Left Bool/False) (Either/Left Bool/True) = 1
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
type List_ = (Cons head tail) | Nil
type Bool = True | False
type List_ = (Cons head tail) | Nil

If Bool/True then else = then
If Bool/False then else = else
Expand Down
2 changes: 2 additions & 0 deletions tests/golden_tests/encode_pattern_match/var_only.bend
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
type Bool = False | True

(Foo a b) = λf (f a)
(Foo a b) = b

Expand Down
1 change: 1 addition & 0 deletions tests/golden_tests/mutual_recursion/odd_even.bend
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
type Bool = True | False

(if_ 0 then else) = else
(if_ _ then else) = then

Expand Down
5 changes: 4 additions & 1 deletion tests/golden_tests/parse_file/imp_program.bend
Original file line number Diff line number Diff line change
@@ -1,6 +1,9 @@
type Point:
Point { x, y }
type Bool = True | False

type Bool:
True
False


def symbols():
Expand Down
13 changes: 13 additions & 0 deletions tests/golden_tests/prelude/applies_function_to_map.bend
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
# Checks if a generic map contains a given key, and if it does, applies a function to the value, otherwise it returns the map
def test(m: Map(u24), key: u24) -> Map(u24):
def addtwo (x: u24) -> u24:
return (x + 2)
(num, map) = Map/contains(m, key)
if (num == 0):
return m
else:
return Map/map(m, key, addtwo())

def main() -> _:
m = {3: 255}
return test(m, 3)
9 changes: 9 additions & 0 deletions tests/golden_tests/prelude/get_values_from_map.bend
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
def test1() -> (u24, Map(u24)):
m = {}
m = Map/set(Map/set(Map/set(Map/empty, 3, 4), 2, 3), 1, 2)
(val, map) = Map/get(m, 1)
return Map/get(map, val)


def main() -> _:
return test1()
14 changes: 14 additions & 0 deletions tests/golden_tests/prelude/lists_to_map.bend
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
# Takes two lists and uses one as keys and the other as values, returning a map
def test(m: Map(T), xs: List(u24), ys: List(T)) -> Map(T):
match xs:
case List/Nil:
return Map/Leaf
case List/Cons:
match ys:
case List/Nil:
return Map/Leaf
case List/Cons:
return test(Map/set(m, xs.head, ys.head), xs.tail, ys.tail)

def main() -> _:
return test(Map/Leaf, List/Cons(1, List/Nil), List/Cons(2, List/Nil))
4 changes: 2 additions & 2 deletions tests/golden_tests/prelude/map_checked_test.bend
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@

def main():
def main() -> _:
m1 = {0: 42, 1: 7, 2: 13, 3: 255, 4: 100}
return Map/get_check(m1, 3)

4 changes: 2 additions & 2 deletions tests/golden_tests/prelude/map_contains_test.bend
Original file line number Diff line number Diff line change
@@ -1,3 +1,3 @@
def main():
def main() -> _:
m1 = {0: 42, 1: 7, 2: 13, 3: 255, 4: 100}
return Map/contains(m1, 3)
return Map/contains(m1, 3)
Loading

0 comments on commit 8d9a7e0

Please sign in to comment.