mirror of
https://github.com/HigherOrderCO/Bend.git
synced 2024-09-11 11:56:54 +03:00
Merge branch 'main' into netsize
This commit is contained in:
commit
8a394fc4e9
@ -14,6 +14,7 @@ and this project does not currently adhere to a particular versioning scheme.
|
||||
- Fix local definitions not being desugared properly. ([#623][gh-623])
|
||||
- Expand references to functions generated by the `float_combinators` pass inside the main function. ([#642][gh-642])
|
||||
- Expand references inside constructors in the main function. ([#643][gh-643])
|
||||
- Fix readback when hvm net has `a{n}` or `x{n}` vars. ([#659][gh-659])
|
||||
|
||||
### Added
|
||||
|
||||
@ -27,6 +28,8 @@ and this project does not currently adhere to a particular versioning scheme.
|
||||
|
||||
- Change tuple syntax to not require parentheses in some cases. ([#554][gh-554])
|
||||
- Improve error messages in branching statements. ([#464][gh-464])
|
||||
- Change branches to support ending with ask statements. ([#629][gh-629])
|
||||
- Improve hexadecimal and binary floating numbers. ([#648][gh-648])
|
||||
|
||||
## [0.2.36] - 2024-07-04
|
||||
|
||||
@ -410,6 +413,9 @@ and this project does not currently adhere to a particular versioning scheme.
|
||||
[gh-620]: https://github.com/HigherOrderCO/Bend/issues/620
|
||||
[gh-621]: https://github.com/HigherOrderCO/Bend/issues/621
|
||||
[gh-623]: https://github.com/HigherOrderCO/Bend/issues/623
|
||||
[gh-629]: https://github.com/HigherOrderCO/Bend/issues/629
|
||||
[gh-642]: https://github.com/HigherOrderCO/Bend/issues/642
|
||||
[gh-643]: https://github.com/HigherOrderCO/Bend/issues/643
|
||||
[gh-648]: https://github.com/HigherOrderCO/Bend/issues/648
|
||||
[gh-659]: https://github.com/HigherOrderCO/Bend/pull/659
|
||||
[Unreleased]: https://github.com/HigherOrderCO/Bend/compare/0.2.36...HEAD
|
||||
|
@ -580,6 +580,18 @@ Currently, the 3 number types cannot be mixed.
|
||||
| Bitwise Or | x \| y | int, uint |
|
||||
| Bitwise Xor | x ^ y | int, uint |
|
||||
|
||||
Hexadecimal and binary floating-point literals are also supported.
|
||||
|
||||
In these representations, each digit after the point is divided according to the base’s power of the digit's position.
|
||||
Specifically, for hexadecimal floating-point numbers, each place after the dot represents a fraction of 16 to the power of the digit's depth.
|
||||
Similarly, for binary floating-point numbers, each place after the dot represents a fraction of 2 to the power of the digit's depth.
|
||||
|
||||
```python
|
||||
0xA.A == 10.625
|
||||
|
||||
0b111.111 == 7.875
|
||||
```
|
||||
|
||||
### Constructor Literals
|
||||
|
||||
Constructors are just functions.
|
||||
@ -1093,7 +1105,7 @@ Result/wrap x = (Result/Ok x)
|
||||
with Result {
|
||||
ask x = (some_operation ...)
|
||||
ask y = (some_operation ...)
|
||||
wrap(x * y)
|
||||
(wrap (* x y))
|
||||
}
|
||||
```
|
||||
|
||||
@ -1141,6 +1153,18 @@ Currently, the 3 number types cannot be mixed.
|
||||
| Bitwise Or | (\| x y) | int, uint |
|
||||
| Bitwise Xor | (^ x y) | int, uint |
|
||||
|
||||
Hexadecimal and binary floating-point literals are also supported.
|
||||
|
||||
In these representations, each digit after the point is divided according to the base’s power of the digit's position.
|
||||
Specifically, for hexadecimal floating-point numbers, each place after the dot represents a fraction of 16 to the negative power of the digit's depth.
|
||||
Similarly, for binary floating-point numbers, each place after the dot represents a fraction of 2 to the negative power of the digit's depth.
|
||||
|
||||
```python
|
||||
(== 0xA.A 10.625)
|
||||
|
||||
(== 0b111.111 7.875)
|
||||
```
|
||||
|
||||
### Character Literal
|
||||
|
||||
```rust
|
||||
@ -1240,14 +1264,17 @@ changed or optimized by the compiler.
|
||||
# Import Syntax
|
||||
|
||||
### Import Relative to the File
|
||||
|
||||
Paths starting with `./` or `../` are imported relative to the file.
|
||||
|
||||
### Import Relative to the Main Folder
|
||||
|
||||
Paths that do not start with `./` or `../` are relative to the folder of the main file.
|
||||
|
||||
## Syntax
|
||||
|
||||
### Import Specific Names from a File, or Files from a Folder
|
||||
|
||||
```py
|
||||
from path import name
|
||||
from path import (name1, name2)
|
||||
@ -1255,11 +1282,13 @@ import (path/name1, path/name2)
|
||||
```
|
||||
|
||||
### Import All Names from a File, or All Files from a Folder
|
||||
|
||||
```py
|
||||
from path import *
|
||||
```
|
||||
|
||||
### Aliasing Imports
|
||||
|
||||
```py
|
||||
from path import name as alias
|
||||
from path import (name1 as Alias1, name2 as Alias2)
|
||||
|
@ -76,10 +76,20 @@ String/split s delim = (String/split.go s delim (List/Cons String/Nil List/Nil))
|
||||
# Create a new difference list
|
||||
DiffList/new = λx x
|
||||
|
||||
# DiffList/wrap(head: T) -> (List(T) -> List(T)
|
||||
# Creates a new difference list with just the given value.
|
||||
def DiffList/wrap(head):
|
||||
return lambda tail: List/Cons(head, tail)
|
||||
|
||||
# DiffList/append(diff: List(T) -> List(T), val: T) -> (List(T) -> List(T))
|
||||
# Append a value to the end of the difference list
|
||||
DiffList/append diff val = λx (diff (List/Cons val x))
|
||||
|
||||
# DiffList/append(left: List(T) -> List(T), right: List(T) -> List(T)) -> (List(T) -> List(T))
|
||||
# Concatenates two difference lists.
|
||||
def DiffList/concat(left, right):
|
||||
return lambda x: left(right(x))
|
||||
|
||||
# DiffList/cons(diff: List(T) -> List(T), val: T) -> (List(T) -> List(T))
|
||||
# Append a value to the beginning of the difference list
|
||||
DiffList/cons diff val = λx (List/Cons val (diff x))
|
||||
@ -96,6 +106,22 @@ type Tree:
|
||||
Node { ~left, ~right }
|
||||
Leaf { value }
|
||||
|
||||
# Returns a List converted from a Tree.
|
||||
def Tree/to_list(tree):
|
||||
fold tree:
|
||||
case Tree/Leaf:
|
||||
list = DiffList/wrap(tree.value)
|
||||
case Tree/Node:
|
||||
list = DiffList/concat(tree.left, tree.right)
|
||||
return DiffList/to_list(list)
|
||||
|
||||
# Reverses a tree swapping right and left leaves.
|
||||
def Tree/reverse(tree):
|
||||
fold tree:
|
||||
case Tree/Leaf:
|
||||
return !tree.value
|
||||
case Tree/Node:
|
||||
return ![tree.right, tree.left]
|
||||
|
||||
# MAP Impl
|
||||
|
||||
@ -217,11 +243,11 @@ IO/FS/STDOUT = 1
|
||||
IO/FS/STDERR = 2
|
||||
|
||||
### Seek modes
|
||||
# Seek from start of file
|
||||
# Seek from start of file.
|
||||
IO/FS/SEEK_SET = +0
|
||||
# Seek from current position
|
||||
# Seek from current position.
|
||||
IO/FS/SEEK_CUR = +1
|
||||
# Seek from end of file
|
||||
# Seek from end of file.
|
||||
IO/FS/SEEK_END = +2
|
||||
|
||||
### File utilities
|
||||
|
@ -326,24 +326,28 @@ impl<'a> TermParser<'a> {
|
||||
Ok(vec![import])
|
||||
}
|
||||
|
||||
fn parse_rule(&mut self) -> ParseResult<(Name, Rule)> {
|
||||
// (name pat*) = term
|
||||
// name pat* = term
|
||||
let (name, pats) = if self.try_consume_exactly("(") {
|
||||
fn parse_rule_lhs(&mut self) -> ParseResult<(Name, Vec<Pattern>)> {
|
||||
if self.try_consume_exactly("(") {
|
||||
self.skip_trivia();
|
||||
let name = self.labelled(|p| p.parse_top_level_name(), "function name")?;
|
||||
let pats = self.list_like(|p| p.parse_pattern(false), "", ")", "", false, 0)?;
|
||||
self.consume("=")?;
|
||||
(name, pats)
|
||||
Ok((name, pats))
|
||||
} else {
|
||||
let name = self.labelled(|p| p.parse_top_level_name(), "top-level definition")?;
|
||||
let mut pats = vec![];
|
||||
while !self.try_consume("=") {
|
||||
self.skip_trivia();
|
||||
while !self.starts_with("=") {
|
||||
pats.push(self.parse_pattern(false)?);
|
||||
self.skip_trivia();
|
||||
}
|
||||
(name, pats)
|
||||
};
|
||||
Ok((name, pats))
|
||||
}
|
||||
}
|
||||
|
||||
fn parse_rule(&mut self) -> ParseResult<(Name, Rule)> {
|
||||
let (name, pats) = self.parse_rule_lhs()?;
|
||||
|
||||
self.consume("=")?;
|
||||
|
||||
let body = self.parse_term()?;
|
||||
|
||||
@ -425,9 +429,23 @@ impl<'a> TermParser<'a> {
|
||||
}
|
||||
|
||||
// Var
|
||||
unexpected_tag(self)?;
|
||||
let nam = self.labelled(|p| p.parse_name_or_era(), "pattern-matching pattern")?;
|
||||
Ok(Pattern::Var(nam))
|
||||
if self.starts_with("*")
|
||||
|| self
|
||||
.peek_one()
|
||||
.is_some_and(|c| c.is_ascii_alphanumeric() || c == '_' || c == '.' || c == '-' || c == '/')
|
||||
{
|
||||
unexpected_tag(self)?;
|
||||
let nam = self.parse_name_or_era()?;
|
||||
return Ok(Pattern::Var(nam));
|
||||
}
|
||||
|
||||
let ini_idx = *self.index();
|
||||
while !(self.is_eof() || self.starts_with("=")) {
|
||||
self.advance_one();
|
||||
}
|
||||
let cur_idx = *self.index();
|
||||
|
||||
self.expected_spanned("pattern or '='", ini_idx..cur_idx)
|
||||
})
|
||||
}
|
||||
|
||||
@ -1500,80 +1518,85 @@ pub trait ParserCommons<'a>: Parser<'a> {
|
||||
let radix = match self.peek_many(2) {
|
||||
Some("0x") => {
|
||||
self.advance_many(2);
|
||||
16
|
||||
Radix::Hex
|
||||
}
|
||||
Some("0b") => {
|
||||
self.advance_many(2);
|
||||
2
|
||||
Radix::Bin
|
||||
}
|
||||
_ => 10,
|
||||
_ => Radix::Dec,
|
||||
};
|
||||
let num_str = self.take_while(move |c| c.is_digit(radix) || c == '_');
|
||||
let num_str = self.take_while(move |c| c.is_digit(radix as u32) || c == '_');
|
||||
let num_str = num_str.chars().filter(|c| *c != '_').collect::<String>();
|
||||
|
||||
let next_is_hex = self.peek_one().map_or(false, |c| "0123456789abcdefABCDEF".contains(c));
|
||||
if next_is_hex || num_str.is_empty() {
|
||||
let base = match radix {
|
||||
16 => "hexadecimal",
|
||||
10 => "decimal",
|
||||
2 => "binary",
|
||||
_ => unreachable!(),
|
||||
};
|
||||
self.expected(format!("valid {base} digit").as_str())
|
||||
self.expected(format!("valid {radix} digit").as_str())
|
||||
} else {
|
||||
u32::from_str_radix(&num_str, radix).map_err(|e| e.to_string())
|
||||
u32::from_str_radix(&num_str, radix as u32).map_err(|e| e.to_string())
|
||||
}
|
||||
}
|
||||
|
||||
fn u32_with_radix(&mut self, radix: Radix) -> ParseResult<u32> {
|
||||
let num_str = self.take_while(move |c| c.is_digit(radix as u32) || c == '_');
|
||||
let num_str = num_str.chars().filter(|c| *c != '_').collect::<String>();
|
||||
let next_is_hex = self.peek_one().map_or(false, |c| "0123456789abcdefABCDEF".contains(c));
|
||||
if next_is_hex || num_str.is_empty() {
|
||||
self.expected(format!("valid {radix} digit").as_str())
|
||||
} else {
|
||||
u32::from_str_radix(&num_str, radix as u32).map_err(|e| e.to_string())
|
||||
}
|
||||
}
|
||||
|
||||
fn parse_number(&mut self) -> ParseResult<Num> {
|
||||
let ini_idx = *self.index();
|
||||
|
||||
// Parses sign
|
||||
let sgn = if self.try_consume_exactly("+") {
|
||||
let sign = if self.try_consume_exactly("+") {
|
||||
Some(1)
|
||||
} else if self.try_consume_exactly("-") {
|
||||
Some(-1)
|
||||
} else {
|
||||
None
|
||||
};
|
||||
|
||||
// Parses main value
|
||||
let num = self.parse_u32()?;
|
||||
|
||||
// Parses frac value (Float type)
|
||||
// TODO: Will lead to some rounding errors
|
||||
// TODO: Doesn't cover very large/small numbers
|
||||
let fra = if let Some('.') = self.peek_one() {
|
||||
let radix = match self.peek_many(2) {
|
||||
Some("0x") => {
|
||||
self.advance_many(2);
|
||||
Radix::Hex
|
||||
}
|
||||
Some("0b") => {
|
||||
self.advance_many(2);
|
||||
Radix::Bin
|
||||
}
|
||||
_ => Radix::Dec,
|
||||
};
|
||||
let num = self.u32_with_radix(radix)?;
|
||||
let frac = if let Some('.') = self.peek_one() {
|
||||
self.advance_one();
|
||||
let ini_idx = *self.index();
|
||||
let fra = self.parse_u32()? as f32;
|
||||
let end_idx = *self.index();
|
||||
let fra = fra / 10f32.powi((end_idx - ini_idx) as i32);
|
||||
let fra_str = self.take_while(|c| c.is_digit(radix as u32) || c == '_');
|
||||
let fra_str = fra_str.chars().filter(|c| *c != '_').collect::<String>();
|
||||
let fra = u32::from_str_radix(&fra_str, radix as u32).map_err(|e| e.to_string())?;
|
||||
let fra = fra as f32 / (radix.to_f32()).powi(fra_str.len() as i32);
|
||||
Some(fra)
|
||||
} else {
|
||||
None
|
||||
};
|
||||
|
||||
// F24
|
||||
if let Some(fra) = fra {
|
||||
let sgn = sgn.unwrap_or(1);
|
||||
return Ok(Num::F24(sgn as f32 * (num as f32 + fra)));
|
||||
if let Some(frac) = frac {
|
||||
let sign = sign.unwrap_or(1);
|
||||
return Ok(Num::F24(sign as f32 * (num as f32 + frac)));
|
||||
}
|
||||
|
||||
// I24
|
||||
if let Some(sgn) = sgn {
|
||||
let num = sgn * num as i32;
|
||||
if let Some(sign) = sign {
|
||||
let num = sign * num as i32;
|
||||
if !(-0x00800000..=0x007fffff).contains(&num) {
|
||||
return self.num_range_err(ini_idx, "I24");
|
||||
}
|
||||
return Ok(Num::I24(num));
|
||||
Ok(Num::I24(num))
|
||||
} else {
|
||||
if num >= 1 << 24 {
|
||||
return self.num_range_err(ini_idx, "U24");
|
||||
}
|
||||
Ok(Num::U24(num))
|
||||
}
|
||||
|
||||
// U24
|
||||
if num >= 1 << 24 {
|
||||
return self.num_range_err(ini_idx, "U24");
|
||||
}
|
||||
Ok(Num::U24(num))
|
||||
}
|
||||
|
||||
fn num_range_err<T>(&mut self, ini_idx: usize, typ: &str) -> ParseResult<T> {
|
||||
@ -1641,3 +1664,30 @@ pub trait ParserCommons<'a>: Parser<'a> {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
|
||||
pub enum Radix {
|
||||
Bin = 2,
|
||||
Dec = 10,
|
||||
Hex = 16,
|
||||
}
|
||||
|
||||
impl Radix {
|
||||
fn to_f32(self) -> f32 {
|
||||
match self {
|
||||
Radix::Bin => 2.,
|
||||
Radix::Dec => 10.,
|
||||
Radix::Hex => 16.,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl std::fmt::Display for Radix {
|
||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||
match self {
|
||||
Radix::Bin => write!(f, "binary"),
|
||||
Radix::Dec => write!(f, "decimal"),
|
||||
Radix::Hex => write!(f, "hexadecimal"),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -37,7 +37,9 @@ impl Stmt {
|
||||
}
|
||||
}
|
||||
Stmt::Ask { pat: _, val, nxt } => {
|
||||
nxt.gen_map_get(id);
|
||||
if let Some(nxt) = nxt {
|
||||
nxt.gen_map_get(id);
|
||||
}
|
||||
let substitutions = val.substitute_map_gets(id);
|
||||
if !substitutions.is_empty() {
|
||||
*self = gen_get(self, substitutions);
|
||||
|
@ -174,7 +174,7 @@ pub enum Stmt {
|
||||
Ask {
|
||||
pat: AssignPattern,
|
||||
val: Box<Expr>,
|
||||
nxt: Box<Stmt>,
|
||||
nxt: Option<Box<Stmt>>,
|
||||
},
|
||||
// "return" {expr} ";"?
|
||||
Return {
|
||||
|
@ -28,7 +28,9 @@ impl Stmt {
|
||||
}
|
||||
Stmt::Ask { val, nxt, .. } => {
|
||||
val.order_kwargs(book, use_map)?;
|
||||
nxt.order_kwargs(book, use_map)?;
|
||||
if let Some(nxt) = nxt {
|
||||
nxt.order_kwargs(book, use_map)?;
|
||||
}
|
||||
}
|
||||
Stmt::InPlace { val, nxt, .. } => {
|
||||
val.order_kwargs(book, use_map)?;
|
||||
|
@ -496,10 +496,15 @@ impl<'a> PyParser<'a> {
|
||||
let val = self.parse_expr(true, true)?;
|
||||
self.skip_trivia_inline()?;
|
||||
self.try_consume_exactly(";");
|
||||
self.consume_indent_exactly(*indent)?;
|
||||
let (nxt, nxt_indent) = self.parse_statement(indent)?;
|
||||
let stmt = Stmt::Ask { pat, val: Box::new(val), nxt: Box::new(nxt) };
|
||||
return Ok((stmt, nxt_indent));
|
||||
let nxt_indent = self.advance_newlines()?;
|
||||
if nxt_indent == *indent {
|
||||
let (nxt, nxt_indent) = self.parse_statement(indent)?;
|
||||
let stmt = Stmt::Ask { pat, val: Box::new(val), nxt: Some(Box::new(nxt)) };
|
||||
return Ok((stmt, nxt_indent));
|
||||
} else {
|
||||
let stmt = Stmt::Ask { pat, val: Box::new(val), nxt: None };
|
||||
return Ok((stmt, nxt_indent));
|
||||
}
|
||||
}
|
||||
// In-place
|
||||
|
||||
|
@ -61,9 +61,25 @@ impl AssignPattern {
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
enum StmtToFun {
|
||||
Return(fun::Term),
|
||||
Assign(fun::Pattern, fun::Term),
|
||||
Assign(bool, fun::Pattern, fun::Term),
|
||||
}
|
||||
|
||||
fn take(t: Stmt) -> Result<(bool, Option<fun::Pattern>, fun::Term), String> {
|
||||
match t.into_fun()? {
|
||||
StmtToFun::Return(ret) => Ok((false, None, ret)),
|
||||
StmtToFun::Assign(x, pat, val) => Ok((x, Some(pat), val)),
|
||||
}
|
||||
}
|
||||
|
||||
fn wrap(nxt: Option<fun::Pattern>, term: fun::Term, ask: bool) -> StmtToFun {
|
||||
if let Some(pat) = nxt {
|
||||
StmtToFun::Assign(ask, pat, term)
|
||||
} else {
|
||||
StmtToFun::Return(term)
|
||||
}
|
||||
}
|
||||
|
||||
impl Stmt {
|
||||
@ -72,10 +88,7 @@ impl Stmt {
|
||||
// TODO: When we have an error with an assignment, we should show the offending assignment (eg. "{pat} = ...").
|
||||
let stmt_to_fun = match self {
|
||||
Stmt::Assign { pat: AssignPattern::MapSet(map, key), val, nxt: Some(nxt) } => {
|
||||
let (nxt_pat, nxt) = match nxt.into_fun()? {
|
||||
StmtToFun::Return(term) => (None, term),
|
||||
StmtToFun::Assign(pat, term) => (Some(pat), term),
|
||||
};
|
||||
let (ask, nxt_pat, nxt) = take(*nxt)?;
|
||||
let term = fun::Term::Let {
|
||||
pat: Box::new(fun::Pattern::Var(Some(map.clone()))),
|
||||
val: Box::new(fun::Term::call(
|
||||
@ -84,11 +97,7 @@ impl Stmt {
|
||||
)),
|
||||
nxt: Box::new(nxt),
|
||||
};
|
||||
if let Some(pat) = nxt_pat {
|
||||
StmtToFun::Assign(pat, term)
|
||||
} else {
|
||||
StmtToFun::Return(term)
|
||||
}
|
||||
wrap(nxt_pat, term, ask)
|
||||
}
|
||||
Stmt::Assign { pat: AssignPattern::MapSet(..), val: _, nxt: None } => {
|
||||
return Err("Branch ends with map assignment.".to_string());
|
||||
@ -96,28 +105,17 @@ impl Stmt {
|
||||
Stmt::Assign { pat, val, nxt: Some(nxt) } => {
|
||||
let pat = pat.into_fun();
|
||||
let val = val.to_fun();
|
||||
let (nxt_pat, nxt) = match nxt.into_fun()? {
|
||||
StmtToFun::Return(term) => (None, term),
|
||||
StmtToFun::Assign(pat, term) => (Some(pat), term),
|
||||
};
|
||||
let (ask, nxt_pat, nxt) = take(*nxt)?;
|
||||
let term = fun::Term::Let { pat: Box::new(pat), val: Box::new(val), nxt: Box::new(nxt) };
|
||||
if let Some(pat) = nxt_pat {
|
||||
StmtToFun::Assign(pat, term)
|
||||
} else {
|
||||
StmtToFun::Return(term)
|
||||
}
|
||||
wrap(nxt_pat, term, ask)
|
||||
}
|
||||
Stmt::Assign { pat, val, nxt: None } => {
|
||||
let pat = pat.into_fun();
|
||||
let val = val.to_fun();
|
||||
StmtToFun::Assign(pat, val)
|
||||
StmtToFun::Assign(false, pat, val)
|
||||
}
|
||||
Stmt::InPlace { op, pat, val, nxt } => {
|
||||
let (nxt_pat, nxt) = match nxt.into_fun()? {
|
||||
StmtToFun::Return(term) => (None, term),
|
||||
StmtToFun::Assign(pat, term) => (Some(pat), term),
|
||||
};
|
||||
|
||||
let (ask, nxt_pat, nxt) = take(*nxt)?;
|
||||
// if it is a mapper operation
|
||||
if let InPlaceOp::Map = op {
|
||||
let term = match &*pat {
|
||||
@ -138,11 +136,7 @@ impl Stmt {
|
||||
}
|
||||
};
|
||||
|
||||
if let Some(pat) = nxt_pat {
|
||||
return Ok(StmtToFun::Assign(pat, term));
|
||||
} else {
|
||||
return Ok(StmtToFun::Return(term));
|
||||
}
|
||||
return Ok(wrap(nxt_pat, term, ask));
|
||||
}
|
||||
|
||||
// otherwise
|
||||
@ -157,11 +151,7 @@ impl Stmt {
|
||||
}),
|
||||
nxt: Box::new(nxt),
|
||||
};
|
||||
if let Some(pat) = nxt_pat {
|
||||
StmtToFun::Assign(pat, term)
|
||||
} else {
|
||||
StmtToFun::Return(term)
|
||||
}
|
||||
wrap(nxt_pat, term, ask)
|
||||
}
|
||||
AssignPattern::MapSet(map, key) => {
|
||||
let temp = Name::new("%0");
|
||||
@ -177,19 +167,17 @@ impl Stmt {
|
||||
val: Box::new(map_term),
|
||||
nxt: Box::new(nxt),
|
||||
};
|
||||
if let Some(pat) = nxt_pat {
|
||||
StmtToFun::Assign(pat, term)
|
||||
} else {
|
||||
StmtToFun::Return(term)
|
||||
}
|
||||
wrap(nxt_pat, term, ask)
|
||||
}
|
||||
_ => unreachable!(),
|
||||
}
|
||||
}
|
||||
Stmt::If { cond, then, otherwise, nxt } => {
|
||||
let (pat, then, else_) = match (then.into_fun()?, otherwise.into_fun()?) {
|
||||
(StmtToFun::Return(t), StmtToFun::Return(e)) => (None, t, e),
|
||||
(StmtToFun::Assign(tp, t), StmtToFun::Assign(ep, e)) if tp == ep => (Some(tp), t, e),
|
||||
let (ask, pat, then, else_) = match (then.into_fun()?, otherwise.into_fun()?) {
|
||||
(StmtToFun::Return(t), StmtToFun::Return(e)) => (false, None, t, e),
|
||||
(StmtToFun::Assign(ask, tp, t), StmtToFun::Assign(ask_, ep, e)) if tp == ep => {
|
||||
(ask && ask_, Some(tp), t, e)
|
||||
}
|
||||
(StmtToFun::Assign(..), StmtToFun::Assign(..)) => {
|
||||
return Err("'if' branches end with different assignments.".to_string());
|
||||
}
|
||||
@ -213,26 +201,20 @@ impl Stmt {
|
||||
pred: Some(Name::new("%pred-1")),
|
||||
arms,
|
||||
};
|
||||
wrap_nxt_assign_stmt(term, nxt, pat)?
|
||||
wrap_nxt_assign_stmt(term, nxt, pat, ask)?
|
||||
}
|
||||
Stmt::Match { arg, bnd, with_bnd, with_arg, arms, nxt } => {
|
||||
let arg = arg.to_fun();
|
||||
let mut fun_arms = vec![];
|
||||
let mut arms = arms.into_iter();
|
||||
let fst = arms.next().unwrap();
|
||||
let (fst_pat, fst_rgt) = match fst.rgt.into_fun()? {
|
||||
StmtToFun::Return(term) => (None, term),
|
||||
StmtToFun::Assign(pat, term) => (Some(pat), term),
|
||||
};
|
||||
let (fst_ask, fst_pat, fst_rgt) = take(fst.rgt)?;
|
||||
let with_arg = with_arg.into_iter().map(Expr::to_fun).collect();
|
||||
fun_arms.push((fst.lft, vec![], fst_rgt));
|
||||
for arm in arms {
|
||||
let (arm_pat, arm_rgt) = match arm.rgt.into_fun()? {
|
||||
StmtToFun::Return(term) => (None, term),
|
||||
StmtToFun::Assign(pat, term) => (Some(pat), term),
|
||||
};
|
||||
let (arm_ask, arm_pat, arm_rgt) = take(arm.rgt)?;
|
||||
match (&arm_pat, &fst_pat) {
|
||||
(Some(arm_pat), Some(fst_pat)) if arm_pat != fst_pat => {
|
||||
(Some(arm_pat), Some(fst_pat)) if arm_pat != fst_pat || arm_ask != fst_ask => {
|
||||
return Err("'match' arms end with different assignments.".to_string());
|
||||
}
|
||||
(Some(_), None) => {
|
||||
@ -246,26 +228,20 @@ impl Stmt {
|
||||
}
|
||||
}
|
||||
let term = fun::Term::Mat { arg: Box::new(arg), bnd, with_bnd, with_arg, arms: fun_arms };
|
||||
wrap_nxt_assign_stmt(term, nxt, fst_pat)?
|
||||
wrap_nxt_assign_stmt(term, nxt, fst_pat, fst_ask)?
|
||||
}
|
||||
Stmt::Switch { arg, bnd, with_bnd, with_arg, arms, nxt } => {
|
||||
let arg = arg.to_fun();
|
||||
let mut fun_arms = vec![];
|
||||
let mut arms = arms.into_iter();
|
||||
let fst = arms.next().unwrap();
|
||||
let (fst_pat, fst) = match fst.into_fun()? {
|
||||
StmtToFun::Return(term) => (None, term),
|
||||
StmtToFun::Assign(pat, term) => (Some(pat), term),
|
||||
};
|
||||
let (fst_ask, fst_pat, fst) = take(fst)?;
|
||||
let with_arg = with_arg.into_iter().map(Expr::to_fun).collect();
|
||||
fun_arms.push(fst);
|
||||
for arm in arms {
|
||||
let (arm_pat, arm) = match arm.into_fun()? {
|
||||
StmtToFun::Return(term) => (None, term),
|
||||
StmtToFun::Assign(pat, term) => (Some(pat), term),
|
||||
};
|
||||
let (arm_ask, arm_pat, arm) = take(arm)?;
|
||||
match (&arm_pat, &fst_pat) {
|
||||
(Some(arm_pat), Some(fst_pat)) if arm_pat != fst_pat => {
|
||||
(Some(arm_pat), Some(fst_pat)) if arm_pat != fst_pat || arm_ask != fst_ask => {
|
||||
return Err("'switch' arms end with different assignments.".to_string());
|
||||
}
|
||||
(Some(_), None) => {
|
||||
@ -280,26 +256,20 @@ impl Stmt {
|
||||
}
|
||||
let pred = Some(Name::new(format!("{}-{}", bnd.clone().unwrap(), fun_arms.len() - 1)));
|
||||
let term = fun::Term::Swt { arg: Box::new(arg), bnd, with_bnd, with_arg, pred, arms: fun_arms };
|
||||
wrap_nxt_assign_stmt(term, nxt, fst_pat)?
|
||||
wrap_nxt_assign_stmt(term, nxt, fst_pat, fst_ask)?
|
||||
}
|
||||
Stmt::Fold { arg, bnd, with_bnd, with_arg, arms, nxt } => {
|
||||
let arg = arg.to_fun();
|
||||
let mut fun_arms = vec![];
|
||||
let mut arms = arms.into_iter();
|
||||
let fst = arms.next().unwrap();
|
||||
let (fst_pat, fst_rgt) = match fst.rgt.into_fun()? {
|
||||
StmtToFun::Return(term) => (None, term),
|
||||
StmtToFun::Assign(pat, term) => (Some(pat), term),
|
||||
};
|
||||
let (fst_ask, fst_pat, fst_rgt) = take(fst.rgt)?;
|
||||
fun_arms.push((fst.lft, vec![], fst_rgt));
|
||||
let with_arg = with_arg.into_iter().map(Expr::to_fun).collect();
|
||||
for arm in arms {
|
||||
let (arm_pat, arm_rgt) = match arm.rgt.into_fun()? {
|
||||
StmtToFun::Return(term) => (None, term),
|
||||
StmtToFun::Assign(pat, term) => (Some(pat), term),
|
||||
};
|
||||
let (arm_ask, arm_pat, arm_rgt) = take(arm.rgt)?;
|
||||
match (&arm_pat, &fst_pat) {
|
||||
(Some(arm_pat), Some(fst_pat)) if arm_pat != fst_pat => {
|
||||
(Some(arm_pat), Some(fst_pat)) if arm_pat != fst_pat || arm_ask != fst_ask => {
|
||||
return Err("'fold' arms end with different assignments.".to_string());
|
||||
}
|
||||
(Some(_), None) => {
|
||||
@ -313,14 +283,16 @@ impl Stmt {
|
||||
}
|
||||
}
|
||||
let term = fun::Term::Fold { arg: Box::new(arg), bnd, with_bnd, with_arg, arms: fun_arms };
|
||||
wrap_nxt_assign_stmt(term, nxt, fst_pat)?
|
||||
wrap_nxt_assign_stmt(term, nxt, fst_pat, fst_ask)?
|
||||
}
|
||||
Stmt::Bend { bnd, arg, cond, step, base, nxt } => {
|
||||
let arg = arg.into_iter().map(Expr::to_fun).collect();
|
||||
let cond = cond.to_fun();
|
||||
let (pat, step, base) = match (step.into_fun()?, base.into_fun()?) {
|
||||
(StmtToFun::Return(s), StmtToFun::Return(b)) => (None, s, b),
|
||||
(StmtToFun::Assign(sp, s), StmtToFun::Assign(bp, b)) if sp == bp => (Some(sp), s, b),
|
||||
let (ask, pat, step, base) = match (step.into_fun()?, base.into_fun()?) {
|
||||
(StmtToFun::Return(s), StmtToFun::Return(b)) => (false, None, s, b),
|
||||
(StmtToFun::Assign(aa, sp, s), StmtToFun::Assign(ba, bp, b)) if sp == bp => {
|
||||
(aa && ba, Some(sp), s, b)
|
||||
}
|
||||
(StmtToFun::Assign(..), StmtToFun::Assign(..)) => {
|
||||
return Err("'bend' branches end with different assignments.".to_string());
|
||||
}
|
||||
@ -337,66 +309,40 @@ impl Stmt {
|
||||
};
|
||||
let term =
|
||||
fun::Term::Bend { bnd, arg, cond: Box::new(cond), step: Box::new(step), base: Box::new(base) };
|
||||
wrap_nxt_assign_stmt(term, nxt, pat)?
|
||||
wrap_nxt_assign_stmt(term, nxt, pat, ask)?
|
||||
}
|
||||
Stmt::With { typ, bod, nxt } => {
|
||||
let (pat, bod) = match bod.into_fun()? {
|
||||
StmtToFun::Return(term) => (None, term),
|
||||
StmtToFun::Assign(pat, term) => (Some(pat), term),
|
||||
};
|
||||
let (ask, pat, bod) = take(*bod)?;
|
||||
let term = fun::Term::With { typ, bod: Box::new(bod) };
|
||||
wrap_nxt_assign_stmt(term, nxt, pat)?
|
||||
wrap_nxt_assign_stmt(term, nxt, pat, ask)?
|
||||
}
|
||||
Stmt::Ask { pat, val, nxt } => {
|
||||
let (nxt_pat, nxt) = match nxt.into_fun()? {
|
||||
StmtToFun::Return(term) => (None, term),
|
||||
StmtToFun::Assign(pat, term) => (Some(pat), term),
|
||||
};
|
||||
Stmt::Ask { pat, val, nxt: Some(nxt) } => {
|
||||
let (ask, nxt_pat, nxt) = take(*nxt)?;
|
||||
let term =
|
||||
fun::Term::Ask { pat: Box::new(pat.into_fun()), val: Box::new(val.to_fun()), nxt: Box::new(nxt) };
|
||||
if let Some(pat) = nxt_pat {
|
||||
StmtToFun::Assign(pat, term)
|
||||
} else {
|
||||
StmtToFun::Return(term)
|
||||
}
|
||||
wrap(nxt_pat, term, ask)
|
||||
}
|
||||
Stmt::Ask { pat, val, nxt: None } => {
|
||||
let pat = pat.into_fun();
|
||||
let val = val.to_fun();
|
||||
StmtToFun::Assign(true, pat, val)
|
||||
}
|
||||
Stmt::Open { typ, var, nxt } => {
|
||||
let (nxt_pat, nxt) = match nxt.into_fun()? {
|
||||
StmtToFun::Return(term) => (None, term),
|
||||
StmtToFun::Assign(pat, term) => (Some(pat), term),
|
||||
};
|
||||
let (ask, nxt_pat, nxt) = take(*nxt)?;
|
||||
let term = fun::Term::Open { typ, var, bod: Box::new(nxt) };
|
||||
if let Some(pat) = nxt_pat {
|
||||
StmtToFun::Assign(pat, term)
|
||||
} else {
|
||||
StmtToFun::Return(term)
|
||||
}
|
||||
wrap(nxt_pat, term, ask)
|
||||
}
|
||||
Stmt::Use { nam, val, nxt } => {
|
||||
let (nxt_pat, nxt) = match nxt.into_fun()? {
|
||||
StmtToFun::Return(term) => (None, term),
|
||||
StmtToFun::Assign(pat, term) => (Some(pat), term),
|
||||
};
|
||||
let (ask, nxt_pat, nxt) = take(*nxt)?;
|
||||
let term = fun::Term::Use { nam: Some(nam), val: Box::new(val.to_fun()), nxt: Box::new(nxt) };
|
||||
if let Some(pat) = nxt_pat {
|
||||
StmtToFun::Assign(pat, term)
|
||||
} else {
|
||||
StmtToFun::Return(term)
|
||||
}
|
||||
wrap(nxt_pat, term, ask)
|
||||
}
|
||||
Stmt::Return { term } => StmtToFun::Return(term.to_fun()),
|
||||
Stmt::LocalDef { def, nxt } => {
|
||||
let (nxt_pat, nxt) = match nxt.into_fun()? {
|
||||
StmtToFun::Return(term) => (None, term),
|
||||
StmtToFun::Assign(pat, term) => (Some(pat), term),
|
||||
};
|
||||
let (ask, nxt_pat, nxt) = take(*nxt)?;
|
||||
let def = def.to_fun()?;
|
||||
let term = fun::Term::Def { def, nxt: Box::new(nxt) };
|
||||
if let Some(pat) = nxt_pat {
|
||||
StmtToFun::Assign(pat, term)
|
||||
} else {
|
||||
StmtToFun::Return(term)
|
||||
}
|
||||
wrap(nxt_pat, term, ask)
|
||||
}
|
||||
Stmt::Err => unreachable!(),
|
||||
};
|
||||
@ -508,24 +454,22 @@ fn wrap_nxt_assign_stmt(
|
||||
term: fun::Term,
|
||||
nxt: Option<Box<Stmt>>,
|
||||
pat: Option<fun::Pattern>,
|
||||
ask: bool,
|
||||
) -> Result<StmtToFun, String> {
|
||||
if let Some(nxt) = nxt {
|
||||
if let Some(pat) = pat {
|
||||
let (nxt_pat, nxt) = match nxt.into_fun()? {
|
||||
StmtToFun::Return(term) => (None, term),
|
||||
StmtToFun::Assign(pat, term) => (Some(pat), term),
|
||||
};
|
||||
let term = fun::Term::Let { pat: Box::new(pat), val: Box::new(term), nxt: Box::new(nxt) };
|
||||
if let Some(pat) = nxt_pat {
|
||||
Ok(StmtToFun::Assign(pat, term))
|
||||
let (ask_nxt, nxt_pat, nxt) = take(*nxt)?;
|
||||
let term = if ask {
|
||||
fun::Term::Ask { pat: Box::new(pat), val: Box::new(term), nxt: Box::new(nxt) }
|
||||
} else {
|
||||
Ok(StmtToFun::Return(term))
|
||||
}
|
||||
fun::Term::Let { pat: Box::new(pat), val: Box::new(term), nxt: Box::new(nxt) }
|
||||
};
|
||||
Ok(wrap(nxt_pat, term, ask_nxt))
|
||||
} else {
|
||||
Err("Statement ends with return but is not at end of function.".to_string())
|
||||
}
|
||||
} else if let Some(pat) = pat {
|
||||
Ok(StmtToFun::Assign(pat, term))
|
||||
Ok(StmtToFun::Assign(ask, pat, term))
|
||||
} else {
|
||||
Ok(StmtToFun::Return(term))
|
||||
}
|
||||
|
@ -114,6 +114,7 @@ impl ParseBook {
|
||||
let main_imports = main_imports.unwrap_or(&self.import_ctx.map);
|
||||
|
||||
let mut local_imports = BindMap::new();
|
||||
let mut adt_imports = BindMap::new();
|
||||
|
||||
// Collect local imports binds, starting with `__` if not imported by the main book.
|
||||
'outer: for (bind, src) in self.import_ctx.map.binds.iter().rev() {
|
||||
@ -128,7 +129,6 @@ impl ParseBook {
|
||||
|
||||
// Checks if the bind is an loaded ADT name,
|
||||
// If so, add the constructors binds as `bind/ctr` instead.
|
||||
// As ADTs names are not used in the syntax, we don't bind their names.
|
||||
for pkg in self.import_ctx.sources() {
|
||||
if let Some(book) = pkgs.loaded_adts.get(pkg) {
|
||||
if let Some(ctrs) = book.get(&nam) {
|
||||
@ -138,6 +138,8 @@ impl ParseBook {
|
||||
let bind = Name::new(format!("{}{}", bind, ctr_name));
|
||||
local_imports.insert(bind, ctr.clone());
|
||||
}
|
||||
// Add a mapping of the ADT name
|
||||
adt_imports.insert(bind.clone(), nam.clone());
|
||||
continue 'outer;
|
||||
}
|
||||
}
|
||||
@ -149,6 +151,7 @@ impl ParseBook {
|
||||
|
||||
for (_, def) in self.local_defs_mut() {
|
||||
def.apply_binds(true, &local_imports);
|
||||
def.apply_types(&adt_imports);
|
||||
}
|
||||
}
|
||||
|
||||
@ -306,6 +309,8 @@ trait Def {
|
||||
/// and if there are possible constructor names on it, rename rule patterns.
|
||||
fn apply_binds(&mut self, maybe_constructor: bool, binds: &BindMap);
|
||||
|
||||
fn apply_types(&mut self, types: &BindMap);
|
||||
|
||||
fn source(&self) -> &Source;
|
||||
fn source_mut(&mut self) -> &mut Source;
|
||||
fn name_mut(&mut self) -> &mut Name;
|
||||
@ -332,6 +337,22 @@ impl Def for Definition {
|
||||
}
|
||||
}
|
||||
|
||||
fn apply_types(&mut self, types: &BindMap) {
|
||||
fn rename_with_type(bod: &mut Term, types: &BindMap) {
|
||||
if let Term::With { typ, .. } = bod {
|
||||
if let Some(alias) = types.get(typ).cloned() {
|
||||
*typ = alias;
|
||||
}
|
||||
}
|
||||
for child in bod.children_mut() {
|
||||
rename_with_type(child, types);
|
||||
}
|
||||
}
|
||||
for rule in self.rules.iter_mut() {
|
||||
rename_with_type(&mut rule.body, types);
|
||||
}
|
||||
}
|
||||
|
||||
fn source(&self) -> &Source {
|
||||
&self.source
|
||||
}
|
||||
@ -351,6 +372,86 @@ impl Def for imp::Definition {
|
||||
self.body = bod.fold_uses(binds.iter().rev());
|
||||
}
|
||||
|
||||
fn apply_types(&mut self, types: &BindMap) {
|
||||
fn rename_with_type(bod: &mut Stmt, types: &BindMap) {
|
||||
match bod {
|
||||
Stmt::With { typ, bod, nxt } => {
|
||||
if let Some(alias) = types.get(typ).cloned() {
|
||||
*typ = alias
|
||||
}
|
||||
rename_with_type(bod, types);
|
||||
if let Some(nxt) = nxt {
|
||||
rename_with_type(nxt, types);
|
||||
}
|
||||
}
|
||||
Stmt::Assign { nxt, .. } => {
|
||||
if let Some(nxt) = nxt {
|
||||
rename_with_type(nxt, types);
|
||||
}
|
||||
}
|
||||
Stmt::InPlace { nxt, .. } => {
|
||||
rename_with_type(nxt, types);
|
||||
}
|
||||
Stmt::If { then, otherwise, nxt, .. } => {
|
||||
rename_with_type(then, types);
|
||||
rename_with_type(otherwise, types);
|
||||
if let Some(nxt) = nxt {
|
||||
rename_with_type(nxt, types);
|
||||
}
|
||||
}
|
||||
Stmt::Match { arms, nxt, .. } => {
|
||||
for arm in arms {
|
||||
rename_with_type(&mut arm.rgt, types);
|
||||
}
|
||||
if let Some(nxt) = nxt {
|
||||
rename_with_type(nxt, types);
|
||||
}
|
||||
}
|
||||
Stmt::Switch { arms, nxt, .. } => {
|
||||
for arm in arms {
|
||||
rename_with_type(arm, types);
|
||||
}
|
||||
if let Some(nxt) = nxt {
|
||||
rename_with_type(nxt, types);
|
||||
}
|
||||
}
|
||||
Stmt::Bend { step, base, nxt, .. } => {
|
||||
rename_with_type(step, types);
|
||||
rename_with_type(base, types);
|
||||
if let Some(nxt) = nxt {
|
||||
rename_with_type(nxt, types);
|
||||
}
|
||||
}
|
||||
Stmt::Fold { arms, nxt, .. } => {
|
||||
for arm in arms {
|
||||
rename_with_type(&mut arm.rgt, types);
|
||||
}
|
||||
if let Some(nxt) = nxt {
|
||||
rename_with_type(nxt, types);
|
||||
}
|
||||
}
|
||||
Stmt::Ask { nxt, .. } => {
|
||||
if let Some(nxt) = nxt {
|
||||
rename_with_type(nxt, types);
|
||||
}
|
||||
}
|
||||
Stmt::Return { .. } => {}
|
||||
Stmt::Open { nxt, .. } => {
|
||||
rename_with_type(nxt, types);
|
||||
}
|
||||
Stmt::Use { nxt, .. } => {
|
||||
rename_with_type(nxt, types);
|
||||
}
|
||||
Stmt::LocalDef { def, nxt } => {
|
||||
def.apply_types(types);
|
||||
rename_with_type(nxt, types);
|
||||
}
|
||||
Stmt::Err => {}
|
||||
}
|
||||
}
|
||||
rename_with_type(&mut self.body, types);
|
||||
}
|
||||
|
||||
fn source(&self) -> &Source {
|
||||
&self.source
|
||||
}
|
||||
@ -368,6 +469,8 @@ impl Def for HvmDefinition {
|
||||
/// Do nothing, can not apply binds to a HvmDefinition.
|
||||
fn apply_binds(&mut self, _maybe_constructor: bool, _binds: &BindMap) {}
|
||||
|
||||
fn apply_types(&mut self, _types: &BindMap) {}
|
||||
|
||||
fn source(&self) -> &Source {
|
||||
&self.source
|
||||
}
|
||||
@ -379,6 +482,18 @@ impl Def for HvmDefinition {
|
||||
fn name_mut(&mut self) -> &mut Name {
|
||||
&mut self.name
|
||||
}
|
||||
|
||||
fn canonicalize_name(&mut self, src: &Name, main_imports: &ImportsMap, binds: &mut BindMap) {
|
||||
let def_name = self.name_mut();
|
||||
let mut new_name = Name::new(std::format!("{}/{}", src, def_name));
|
||||
|
||||
if !main_imports.contains_source(&new_name) {
|
||||
new_name = Name::new(std::format!("__{}", new_name));
|
||||
}
|
||||
|
||||
binds.insert(def_name.clone(), new_name.clone());
|
||||
*def_name = new_name;
|
||||
}
|
||||
}
|
||||
|
||||
impl Term {
|
||||
|
@ -23,7 +23,8 @@ fn hvm_to_inodes(net: &Net) -> INodes {
|
||||
|
||||
// Convert all the trees forming active pairs.
|
||||
for (i, (_, tree1, tree2)) in net.rbag.iter().enumerate() {
|
||||
let tree_root = format!("a{i}");
|
||||
// This name cannot appear anywhere in the original net
|
||||
let tree_root = format!("%a{i}");
|
||||
let mut tree1 = tree_to_inodes(tree1, tree_root.clone(), net_root, &mut n_vars);
|
||||
inodes.append(&mut tree1);
|
||||
let mut tree2 = tree_to_inodes(tree2, tree_root, net_root, &mut n_vars);
|
||||
@ -33,7 +34,8 @@ fn hvm_to_inodes(net: &Net) -> INodes {
|
||||
}
|
||||
|
||||
fn new_var(n_vars: &mut NodeId) -> String {
|
||||
let new_var = format!("x{n_vars}");
|
||||
// This name cannot appear anywhere in the original net
|
||||
let new_var = format!("%x{n_vars}");
|
||||
*n_vars += 1;
|
||||
new_var
|
||||
}
|
||||
@ -46,7 +48,6 @@ fn tree_to_inodes(tree: &Tree, tree_root: String, net_root: &str, n_vars: &mut N
|
||||
n_vars: &mut NodeId,
|
||||
) -> String {
|
||||
if let Tree::Var { nam } = subtree {
|
||||
//
|
||||
if nam == net_root {
|
||||
"_".to_string()
|
||||
} else {
|
||||
|
@ -0,0 +1,12 @@
|
||||
type Bool:
|
||||
T
|
||||
F
|
||||
|
||||
def main:
|
||||
with IO:
|
||||
match _ = Bool/T:
|
||||
case Bool/T:
|
||||
x <- wrap(0)
|
||||
case Bool/F:
|
||||
x = wrap(0)
|
||||
return wrap(x)
|
12
tests/golden_tests/desugar_file/ask_branch.bend
Normal file
12
tests/golden_tests/desugar_file/ask_branch.bend
Normal file
@ -0,0 +1,12 @@
|
||||
type Bool:
|
||||
T
|
||||
F
|
||||
|
||||
def main:
|
||||
with IO:
|
||||
match _ = Bool/T:
|
||||
case Bool/T:
|
||||
x <- wrap(0)
|
||||
case Bool/F:
|
||||
x <- wrap(0)
|
||||
return wrap(x)
|
7
tests/golden_tests/import_system/import_type.bend
Normal file
7
tests/golden_tests/import_system/import_type.bend
Normal file
@ -0,0 +1,7 @@
|
||||
from lib/MyOption import (MyOption, MyOption/bind, MyOption/wrap)
|
||||
|
||||
def main():
|
||||
with MyOption:
|
||||
a <- MyOption/Some(1)
|
||||
b <- MyOption/Some(2)
|
||||
return wrap((a, b))
|
12
tests/golden_tests/import_system/lib/MyOption.bend
Normal file
12
tests/golden_tests/import_system/lib/MyOption.bend
Normal file
@ -0,0 +1,12 @@
|
||||
type MyOption = (Some val) | (None)
|
||||
|
||||
def MyOption/bind(val, nxt):
|
||||
match val:
|
||||
case MyOption/Some:
|
||||
nxt = undefer(nxt)
|
||||
return nxt(val.val)
|
||||
case MyOption/None:
|
||||
return MyOption/None
|
||||
|
||||
def MyOption/wrap(val):
|
||||
return MyOption/Some(val)
|
2
tests/golden_tests/parse_file/bad_floating.bend
Normal file
2
tests/golden_tests/parse_file/bad_floating.bend
Normal file
@ -0,0 +1,2 @@
|
||||
def main:
|
||||
return 0xA.0xA
|
1
tests/golden_tests/parse_file/strange_pattern.bend
Normal file
1
tests/golden_tests/parse_file/strange_pattern.bend
Normal file
@ -0,0 +1 @@
|
||||
main & = (a b c)
|
2
tests/golden_tests/run_file/floating_numbers.bend
Normal file
2
tests/golden_tests/run_file/floating_numbers.bend
Normal file
@ -0,0 +1,2 @@
|
||||
def main:
|
||||
return [0x12.129, 0x0.2, 0b101.101, 0xAAAAAAAA.AAAAAAAA, 0xA.__A__]
|
4
tests/golden_tests/run_file/tree_to_list.bend
Normal file
4
tests/golden_tests/run_file/tree_to_list.bend
Normal file
@ -0,0 +1,4 @@
|
||||
def main:
|
||||
var = Tree/reverse(![![!1, !2],![!3, !4]])
|
||||
return Tree/to_list(var)
|
||||
|
@ -4,6 +4,6 @@ input_file: tests/golden_tests/compile_file/just_a_name.bend
|
||||
---
|
||||
[4m[1m[31mErrors:[0m
|
||||
In tests/golden_tests/compile_file/just_a_name.bend :
|
||||
[1m- expected:[0m pattern-matching pattern
|
||||
[1m- expected:[0m pattern or '='
|
||||
[1m- detected:[0m end of input
|
||||
[0m 1 | asdf[4m[31m [0m
|
||||
[0m 1 | asdf[0m
|
||||
|
@ -0,0 +1,6 @@
|
||||
---
|
||||
source: tests/golden_tests.rs
|
||||
input_file: tests/golden_tests/compile_file/mismatched_ask_statements.bend
|
||||
---
|
||||
[4m[1m[31mErrors:[0m
|
||||
In function 'main': 'match' arms end with different assignments.
|
35
tests/snapshots/desugar_file__ask_branch.bend.snap
Normal file
35
tests/snapshots/desugar_file__ask_branch.bend.snap
Normal file
@ -0,0 +1,35 @@
|
||||
---
|
||||
source: tests/golden_tests.rs
|
||||
input_file: tests/golden_tests/desugar_file/ask_branch.bend
|
||||
---
|
||||
(undefer) = λa (a λb b)
|
||||
|
||||
(IO/MAGIC) = (13683217, 16719857)
|
||||
|
||||
(IO/wrap) = λa (IO/Done IO/MAGIC a)
|
||||
|
||||
(IO/bind) = λa λb (a IO/bind__C2 b)
|
||||
|
||||
(main) = (IO/bind (Bool/T λa switch a { 0: (IO/wrap 0); _: λ* (IO/wrap 0); }) λb (b λc λd (c d) IO/wrap))
|
||||
|
||||
(IO/Done) = λa λb λc (c IO/Done/tag a b)
|
||||
|
||||
(IO/Call) = λa λb λc λd λe (e IO/Call/tag a b c d)
|
||||
|
||||
(Bool/T) = λa (a Bool/T/tag)
|
||||
|
||||
(Bool/F) = λa (a Bool/F/tag)
|
||||
|
||||
(IO/Done/tag) = 0
|
||||
|
||||
(IO/Call/tag) = 1
|
||||
|
||||
(Bool/T/tag) = 0
|
||||
|
||||
(Bool/F/tag) = 1
|
||||
|
||||
(IO/bind__C0) = λ* λa λb (undefer b a)
|
||||
|
||||
(IO/bind__C1) = λ* λ* λa λb λc λd (IO/Call IO/MAGIC a b λe (IO/bind (c e) d))
|
||||
|
||||
(IO/bind__C2) = λa switch a { 0: IO/bind__C0; _: IO/bind__C1; }
|
5
tests/snapshots/import_system__import_type.bend.snap
Normal file
5
tests/snapshots/import_system__import_type.bend.snap
Normal file
@ -0,0 +1,5 @@
|
||||
---
|
||||
source: tests/golden_tests.rs
|
||||
input_file: tests/golden_tests/import_system/import_type.bend
|
||||
---
|
||||
λa (a lib/MyOption/MyOption/Some/tag (1, 2))
|
9
tests/snapshots/parse_file__bad_floating.bend.snap
Normal file
9
tests/snapshots/parse_file__bad_floating.bend.snap
Normal file
@ -0,0 +1,9 @@
|
||||
---
|
||||
source: tests/golden_tests.rs
|
||||
input_file: tests/golden_tests/parse_file/bad_floating.bend
|
||||
---
|
||||
[4m[1m[31mErrors:[0m
|
||||
In tests/golden_tests/parse_file/bad_floating.bend :
|
||||
[1m- expected:[0m newline
|
||||
[1m- detected:[0m
|
||||
[0m 2 | return 0xA.0[4m[31mx[0mA[0m
|
9
tests/snapshots/parse_file__strange_pattern.bend.snap
Normal file
9
tests/snapshots/parse_file__strange_pattern.bend.snap
Normal file
@ -0,0 +1,9 @@
|
||||
---
|
||||
source: tests/golden_tests.rs
|
||||
input_file: tests/golden_tests/parse_file/strange_pattern.bend
|
||||
---
|
||||
[4m[1m[31mErrors:[0m
|
||||
In tests/golden_tests/parse_file/strange_pattern.bend :
|
||||
[1m- expected:[0m pattern or '='
|
||||
[1m- detected:[0m
|
||||
[0m 1 | main [4m[31m& [0m= (a b c)[0m
|
9
tests/snapshots/run_file__floating_numbers.bend.snap
Normal file
9
tests/snapshots/run_file__floating_numbers.bend.snap
Normal file
@ -0,0 +1,9 @@
|
||||
---
|
||||
source: tests/golden_tests.rs
|
||||
input_file: tests/golden_tests/run_file/floating_numbers.bend
|
||||
---
|
||||
NumScott:
|
||||
[18.072, 0.125, 5.625, 2863333376.000, 10.625]
|
||||
|
||||
Scott:
|
||||
[18.072, 0.125, 5.625, 2863333376.000, 10.625]
|
9
tests/snapshots/run_file__tree_to_list.bend.snap
Normal file
9
tests/snapshots/run_file__tree_to_list.bend.snap
Normal file
@ -0,0 +1,9 @@
|
||||
---
|
||||
source: tests/golden_tests.rs
|
||||
input_file: tests/golden_tests/run_file/tree_to_list.bend
|
||||
---
|
||||
NumScott:
|
||||
[4, 3, 2, 1]
|
||||
|
||||
Scott:
|
||||
[4, 3, 2, 1]
|
Loading…
Reference in New Issue
Block a user