mirror of
https://github.com/HigherOrderCO/Bend.git
synced 2024-09-11 03:45:29 +03:00
[sc-667] Switch to new syntax by default
This commit is contained in:
parent
fe3a83d4a9
commit
b5e89aa129
32
examples/all_tree.bend
Normal file
32
examples/all_tree.bend
Normal file
@ -0,0 +1,32 @@
|
||||
enum Bool:
|
||||
Bool/true()
|
||||
Bool/false()
|
||||
|
||||
enum Tree:
|
||||
Tree/node(~lft, ~rgt)
|
||||
Tree/leaf(val)
|
||||
|
||||
def and(a, b):
|
||||
match a:
|
||||
Bool/true:
|
||||
return b;
|
||||
Bool/false:
|
||||
return Bool/false;
|
||||
|
||||
def all(tree):
|
||||
fold tree:
|
||||
Tree/node:
|
||||
return and(tree.lft tree.rgt);
|
||||
Tree/leaf:
|
||||
return tree.val;
|
||||
|
||||
def gen(n):
|
||||
switch n:
|
||||
0:
|
||||
return Tree/leaf(Bool/true);
|
||||
_:
|
||||
return Tree/node(gen(n-1), gen(n-1));
|
||||
|
||||
def main():
|
||||
return all(gen(8));
|
||||
|
@ -1,23 +0,0 @@
|
||||
data Bool = Bool/true | Bool/false
|
||||
|
||||
data Tree
|
||||
= (Tree/node ~lft ~rgt)
|
||||
| (Tree/leaf val)
|
||||
|
||||
and a b = match a {
|
||||
true: b
|
||||
false: false
|
||||
}
|
||||
|
||||
all tree = fold tree {
|
||||
Tree/node: (and tree.lft tree.rgt)
|
||||
Tree/leaf: tree.val
|
||||
}
|
||||
|
||||
gen n = switch n {
|
||||
0: (Tree/leaf Bool/true)
|
||||
_: (Tree/node (gen n-1) (gen n-1))
|
||||
}
|
||||
|
||||
main = (all (gen 8))
|
||||
|
@ -1,3 +1,4 @@
|
||||
#flavor core
|
||||
T = λt λf t
|
||||
F = λt λf f
|
||||
And = λpλq (p q F)
|
@ -1,3 +1,4 @@
|
||||
#flavor core
|
||||
data Tree = (Leaf val) | (Both lft rgt)
|
||||
|
||||
(U60.swap 0 a b) = (Both a b)
|
@ -1,3 +1,4 @@
|
||||
#flavor core
|
||||
// Sorts a list
|
||||
|
||||
// sort : List -> List
|
@ -1,3 +1,4 @@
|
||||
#flavor core
|
||||
// This program is an example that shows how scopeless lambdas can be used.
|
||||
|
||||
Seq a b = a
|
@ -1,3 +1,4 @@
|
||||
#flavor core
|
||||
// Write definitions like this
|
||||
(Def1) = ((λa a) (λb b))
|
||||
|
@ -1,3 +1,4 @@
|
||||
#flavor core
|
||||
add = λa λb (+ a b)
|
||||
|
||||
fib = λx switch x {
|
@ -1,3 +1,4 @@
|
||||
#flavor core
|
||||
zero = λs λz z
|
||||
succ = λpred λs λz (s pred) // Creates a Scott number out of its predecessor
|
||||
|
@ -1,3 +1,4 @@
|
||||
#flavor core
|
||||
true = λt λf t
|
||||
false = λt λf f
|
||||
not = λboolean (boolean false true)
|
@ -1,3 +1,4 @@
|
||||
#flavor core
|
||||
Tree.leaf = λnode λleaf leaf
|
||||
Tree.node = λval λlft λrgt λnode λleaf (node val lft rgt)
|
||||
|
@ -1,3 +1,4 @@
|
||||
#flavor core
|
||||
// size = 1 << 8
|
||||
|
||||
Mul = λn λm λs (n (m s))
|
@ -1,3 +1,4 @@
|
||||
#flavor core
|
||||
// A cool trick involving HVM's scopeless lambdas is linear qs:
|
||||
|
||||
// Qnew : Queue a
|
@ -1,3 +1,4 @@
|
||||
#flavor core
|
||||
data Tree = Leaf | (Node l m r)
|
||||
|
||||
// Parallel QuickSort
|
@ -1,3 +1,4 @@
|
||||
#flavor core
|
||||
data Map = Free | Used | (Both a b)
|
||||
data Arr = Null | (Leaf x) | (Node a b)
|
||||
|
@ -1,14 +1,41 @@
|
||||
use super::{parser::TermParser, Book};
|
||||
use std::path::Path;
|
||||
use crate::{
|
||||
fun::{self, parser::TermParser},
|
||||
imp::parser::PyParser,
|
||||
};
|
||||
use std::{collections::HashSet, path::Path};
|
||||
|
||||
// TODO: Refactor so that we don't mix the two syntaxes here.
|
||||
|
||||
/// Reads a file and parses to a definition book.
|
||||
pub fn load_file_to_book(path: &Path) -> Result<Book, String> {
|
||||
pub fn load_file_to_book(path: &Path) -> Result<fun::Book, String> {
|
||||
let builtins = fun::Book::builtins();
|
||||
let code = std::fs::read_to_string(path).map_err(|e| e.to_string())?;
|
||||
do_parse_book(&code, path)
|
||||
if let Some(("", code)) = code.split_once("#flavor core") {
|
||||
do_parse_core_book(code, path, builtins)
|
||||
} else if let Some(("", code)) = code.split_once("#flavor bend") {
|
||||
do_parse_bend_book(code, path, builtins)
|
||||
} else {
|
||||
do_parse_bend_book(&code, path, builtins)
|
||||
}
|
||||
}
|
||||
|
||||
pub fn do_parse_book(code: &str, path: &Path) -> Result<Book, String> {
|
||||
TermParser::new(code)
|
||||
.parse_book(Book::builtins(), false)
|
||||
.map_err(|e| format!("In {} :\n{}", path.display(), e))
|
||||
pub fn do_parse_core_book(code: &str, path: &Path, builtins: fun::Book) -> Result<fun::Book, String> {
|
||||
TermParser::new(code).parse_book(builtins, false).map_err(|e| format!("In {} :\n{}", path.display(), e))
|
||||
}
|
||||
|
||||
pub fn do_parse_bend_book(code: &str, path: &Path, builtins: fun::Book) -> Result<fun::Book, String> {
|
||||
let mut builtin_names = builtins.defs.keys().cloned().collect::<HashSet<_>>();
|
||||
builtin_names.extend(builtins.adts.keys().cloned());
|
||||
for adt in builtins.adts.values() {
|
||||
builtin_names.extend(adt.ctrs.keys().cloned());
|
||||
}
|
||||
let mut book = PyParser::new(code)
|
||||
.parse_program(&builtin_names)
|
||||
.map_err(|e| format!("In {} :\n{}", path.display(), e))?;
|
||||
|
||||
// TODO: This should go somewhere else.
|
||||
book.order_kwargs();
|
||||
let book = book.to_fun(builtins);
|
||||
|
||||
Ok(book)
|
||||
}
|
||||
|
@ -19,14 +19,14 @@ impl Stmt {
|
||||
nxt.gen_map_get(id);
|
||||
let substitutions = val.substitute_map_gets(id);
|
||||
if !substitutions.is_empty() {
|
||||
*self = gen_get(self.clone(), substitutions);
|
||||
*self = gen_get(self, substitutions);
|
||||
}
|
||||
}
|
||||
Stmt::InPlace { val, nxt, .. } => {
|
||||
nxt.gen_map_get(id);
|
||||
let substitutions = val.substitute_map_gets(id);
|
||||
if !substitutions.is_empty() {
|
||||
*self = gen_get(self.clone(), substitutions);
|
||||
*self = gen_get(self, substitutions);
|
||||
}
|
||||
}
|
||||
Stmt::If { cond, then, otherwise } => {
|
||||
@ -34,7 +34,7 @@ impl Stmt {
|
||||
otherwise.gen_map_get(id);
|
||||
let substitutions = cond.substitute_map_gets(id);
|
||||
if !substitutions.is_empty() {
|
||||
*self = gen_get(self.clone(), substitutions);
|
||||
*self = gen_get(self, substitutions);
|
||||
}
|
||||
}
|
||||
Stmt::Match { arg, arms, .. } | Stmt::Fold { arg, arms, .. } => {
|
||||
@ -43,7 +43,7 @@ impl Stmt {
|
||||
}
|
||||
let substitutions = arg.substitute_map_gets(id);
|
||||
if !substitutions.is_empty() {
|
||||
*self = gen_get(self.clone(), substitutions);
|
||||
*self = gen_get(self, substitutions);
|
||||
}
|
||||
}
|
||||
Stmt::Switch { arg, arms, .. } => {
|
||||
@ -52,17 +52,28 @@ impl Stmt {
|
||||
}
|
||||
let substitutions = arg.substitute_map_gets(id);
|
||||
if !substitutions.is_empty() {
|
||||
*self = gen_get(self.clone(), substitutions);
|
||||
*self = gen_get(self, substitutions);
|
||||
}
|
||||
}
|
||||
Stmt::Bend { bind: _, init, cond, step, base } => {
|
||||
step.gen_map_get(id);
|
||||
base.gen_map_get(id);
|
||||
let mut substitutions = cond.substitute_map_gets(id);
|
||||
for init in init {
|
||||
substitutions.extend(init.substitute_map_gets(id));
|
||||
}
|
||||
if !substitutions.is_empty() {
|
||||
*self = gen_get(self, substitutions);
|
||||
}
|
||||
}
|
||||
Stmt::Bend { .. } => todo!(),
|
||||
Stmt::Do { fun: _, block: _ } => todo!(),
|
||||
Stmt::Return { term } => {
|
||||
let substitutions = term.substitute_map_gets(id);
|
||||
if !substitutions.is_empty() {
|
||||
*self = gen_get(self.clone(), substitutions);
|
||||
*self = gen_get(self, substitutions);
|
||||
}
|
||||
}
|
||||
Stmt::Err => {}
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -118,8 +129,8 @@ impl Expr {
|
||||
}
|
||||
}
|
||||
|
||||
fn gen_get(current: Stmt, substitutions: HashMap<Name, (Name, MapKey)>) -> Stmt {
|
||||
substitutions.into_iter().fold(current, |acc, next| {
|
||||
fn gen_get(current: &mut Stmt, substitutions: HashMap<Name, (Name, MapKey)>) -> Stmt {
|
||||
substitutions.into_iter().fold(std::mem::take(current), |acc, next| {
|
||||
let (var, (map_var, key)) = next;
|
||||
let map_get_call = Expr::Var { nam: Name::new("Map/get") };
|
||||
let map_get_call = Expr::Call {
|
||||
|
@ -63,35 +63,73 @@ pub enum InPlaceOp {
|
||||
Div,
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug)]
|
||||
#[derive(Clone, Debug, Default)]
|
||||
pub enum Stmt {
|
||||
// {pat} = {val} ";" {nxt}
|
||||
Assign { pat: AssignPattern, val: Box<Expr>, nxt: Box<Stmt> },
|
||||
Assign {
|
||||
pat: AssignPattern,
|
||||
val: Box<Expr>,
|
||||
nxt: Box<Stmt>,
|
||||
},
|
||||
// {var} += {val} ";" {nxt}
|
||||
InPlace { op: InPlaceOp, var: Name, val: Box<Expr>, nxt: Box<Stmt> },
|
||||
InPlace {
|
||||
op: InPlaceOp,
|
||||
var: Name,
|
||||
val: Box<Expr>,
|
||||
nxt: Box<Stmt>,
|
||||
},
|
||||
// "if" {cond} ":"
|
||||
// {then}
|
||||
// "else" ":"
|
||||
// {otherwise}
|
||||
If { cond: Box<Expr>, then: Box<Stmt>, otherwise: Box<Stmt> },
|
||||
If {
|
||||
cond: Box<Expr>,
|
||||
then: Box<Stmt>,
|
||||
otherwise: Box<Stmt>,
|
||||
},
|
||||
// "match" {arg} ":" ("as" {bind})?
|
||||
// case {lft} ":" {rgt}
|
||||
Match { arg: Box<Expr>, bind: Option<Name>, arms: Vec<MatchArm> },
|
||||
Match {
|
||||
arg: Box<Expr>,
|
||||
bind: Option<Name>,
|
||||
arms: Vec<MatchArm>,
|
||||
},
|
||||
// "switch" {arg} ("as" {bind})?
|
||||
// case 0..wildcard ":" {rgt}
|
||||
Switch { arg: Box<Expr>, bind: Option<Name>, arms: Vec<Stmt> },
|
||||
Switch {
|
||||
arg: Box<Expr>,
|
||||
bind: Option<Name>,
|
||||
arms: Vec<Stmt>,
|
||||
},
|
||||
// "bend" ({bind} ("="" {init})?)* "while" {cond} ":"
|
||||
// {step}
|
||||
// "then" ":"
|
||||
// {base}
|
||||
Bend { bind: Vec<Option<Name>>, init: Vec<Expr>, cond: Box<Expr>, step: Box<Stmt>, base: Box<Stmt> },
|
||||
Bend {
|
||||
bind: Vec<Option<Name>>,
|
||||
init: Vec<Expr>,
|
||||
cond: Box<Expr>,
|
||||
step: Box<Stmt>,
|
||||
base: Box<Stmt>,
|
||||
},
|
||||
// "fold" {arg} ("as" {bind})? ":" {arms}
|
||||
// case {lft} ":" {rgt}
|
||||
Fold { arg: Box<Expr>, bind: Option<Name>, arms: Vec<MatchArm> },
|
||||
Fold {
|
||||
arg: Box<Expr>,
|
||||
bind: Option<Name>,
|
||||
arms: Vec<MatchArm>,
|
||||
},
|
||||
// "do" {fun} ":" {block}
|
||||
Do { fun: Name, block: Vec<MBind> },
|
||||
Do {
|
||||
fun: Name,
|
||||
block: Vec<MBind>,
|
||||
},
|
||||
// "return" {expr} ";"
|
||||
Return { term: Box<Expr> },
|
||||
Return {
|
||||
term: Box<Expr>,
|
||||
},
|
||||
#[default]
|
||||
Err,
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug)]
|
||||
|
@ -87,6 +87,7 @@ impl Stmt {
|
||||
}
|
||||
}
|
||||
Stmt::Return { term } => term.order_kwargs(ctx),
|
||||
Stmt::Err => {}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1,3 +1,5 @@
|
||||
use std::collections::HashSet;
|
||||
|
||||
use indexmap::IndexMap;
|
||||
use TSPL::Parser;
|
||||
|
||||
@ -111,15 +113,10 @@ impl<'a> PyParser<'a> {
|
||||
Expr::Str { val }
|
||||
}
|
||||
c if c.is_ascii_digit() => {
|
||||
let val = self.parse_u64()?;
|
||||
Expr::Num { val: val as u32 }
|
||||
let val = self.parse_u32()?;
|
||||
Expr::Num { val }
|
||||
}
|
||||
_ => {
|
||||
if self.try_consume("True") {
|
||||
return Ok(Expr::Num { val: 1 });
|
||||
} else if self.try_consume("False") {
|
||||
return Ok(Expr::Num { val: 0 });
|
||||
}
|
||||
let nam = self.parse_bend_name()?;
|
||||
if self.skip_starts_with("[") {
|
||||
self.consume("[")?;
|
||||
@ -163,7 +160,6 @@ impl<'a> PyParser<'a> {
|
||||
}
|
||||
|
||||
fn parse_infix_or_lambda(&mut self) -> Result<Expr, String> {
|
||||
self.skip_trivia();
|
||||
if self.try_consume_keyword("lambda") {
|
||||
let names = self.list_like(|p| p.parse_bend_name(), "", ":", ",", true, 1)?;
|
||||
let bod = self.parse_infix_or_lambda()?;
|
||||
@ -221,7 +217,7 @@ impl<'a> PyParser<'a> {
|
||||
|
||||
fn parse_infix(&mut self, prec: usize) -> Result<Expr, String> {
|
||||
maybe_grow(|| {
|
||||
self.skip_trivia();
|
||||
self.advance_inline_trivia();
|
||||
if prec > PREC.len() - 1 {
|
||||
return self.parse_call();
|
||||
}
|
||||
@ -230,7 +226,7 @@ impl<'a> PyParser<'a> {
|
||||
if PREC[prec].iter().any(|r| *r == op) {
|
||||
let op = self.parse_oper()?;
|
||||
let rhs = self.parse_infix(prec + 1)?;
|
||||
self.skip_trivia();
|
||||
self.advance_inline_trivia();
|
||||
lhs = Expr::Bin { op, lhs: Box::new(lhs), rhs: Box::new(rhs) };
|
||||
} else {
|
||||
break;
|
||||
@ -450,7 +446,7 @@ impl<'a> PyParser<'a> {
|
||||
}
|
||||
|
||||
fn parse_match(&mut self, indent: &mut Indent) -> Result<Stmt, String> {
|
||||
let (bind, arg) = self.parse_named_arg()?;
|
||||
let (bind, arg) = self.parse_match_arg()?;
|
||||
self.consume(":")?;
|
||||
let mut arms = Vec::new();
|
||||
indent.enter_level();
|
||||
@ -464,6 +460,23 @@ impl<'a> PyParser<'a> {
|
||||
Ok(Stmt::Match { arg: Box::new(arg), bind, arms })
|
||||
}
|
||||
|
||||
fn parse_match_arg(&mut self) -> Result<(Option<Name>, Expr), String> {
|
||||
let ini_idx = *self.index();
|
||||
let arg = self.parse_infix_or_lambda()?;
|
||||
let end_idx = *self.index();
|
||||
|
||||
self.advance_inline_trivia();
|
||||
match (arg, self.starts_with("=")) {
|
||||
(Expr::Var { nam }, true) => {
|
||||
self.consume("=")?;
|
||||
Ok((Some(nam), self.parse_infix_or_lambda()?))
|
||||
}
|
||||
(Expr::Var { nam }, false) => Ok((Some(nam.clone()), Expr::Var { nam })),
|
||||
(_, true) => self.expected_spanned("argument name", ini_idx, end_idx),
|
||||
(arg, false) => Ok((Some(Name::new("%arg")), arg)),
|
||||
}
|
||||
}
|
||||
|
||||
fn name_or_wildcard(&mut self) -> Result<Option<Name>, String> {
|
||||
self.labelled(
|
||||
|p| {
|
||||
@ -488,7 +501,7 @@ impl<'a> PyParser<'a> {
|
||||
}
|
||||
|
||||
fn parse_switch(&mut self, indent: &mut Indent) -> Result<Stmt, String> {
|
||||
let (bind, arg) = self.parse_named_arg()?;
|
||||
let (bind, arg) = self.parse_match_arg()?;
|
||||
self.consume(":")?;
|
||||
let mut arms = Vec::new();
|
||||
|
||||
@ -529,7 +542,7 @@ impl<'a> PyParser<'a> {
|
||||
}
|
||||
|
||||
fn parse_fold(&mut self, indent: &mut Indent) -> Result<Stmt, String> {
|
||||
let (bind, arg) = self.parse_named_arg()?;
|
||||
let (bind, arg) = self.parse_match_arg()?;
|
||||
self.consume(":")?;
|
||||
let mut arms = Vec::new();
|
||||
indent.enter_level();
|
||||
@ -544,7 +557,7 @@ impl<'a> PyParser<'a> {
|
||||
}
|
||||
|
||||
fn parse_bend(&mut self, indent: &mut Indent) -> Result<Stmt, String> {
|
||||
let args = self.list_like(|p| p.parse_named_arg(), "", "while", ",", true, 0)?;
|
||||
let args = self.list_like(|p| p.parse_match_arg(), "", "while", ",", true, 1)?;
|
||||
let (bind, init) = args.into_iter().unzip();
|
||||
let cond = self.parse_infix_or_lambda()?;
|
||||
self.consume(":")?;
|
||||
@ -655,7 +668,7 @@ impl<'a> PyParser<'a> {
|
||||
Ok(Enum { name, variants })
|
||||
}
|
||||
|
||||
pub fn parse_program(&mut self) -> Result<Program, String> {
|
||||
pub fn parse_program(&mut self, builtins: &HashSet<Name>) -> Result<Program, String> {
|
||||
let mut enums = IndexMap::<Name, Enum>::new();
|
||||
let mut defs = IndexMap::<Name, Definition>::new();
|
||||
let mut variants = IndexMap::<Name, Name>::new();
|
||||
@ -669,17 +682,24 @@ impl<'a> PyParser<'a> {
|
||||
self.expected("Indentation error")?;
|
||||
}
|
||||
match self.parse_top_level(&mut Indent(0))? {
|
||||
TopLevel::Def(def) => Self::add_def_py(&mut defs, def)?,
|
||||
TopLevel::Enum(r#enum) => Self::add_enum_py(&mut enums, &mut variants, r#enum)?,
|
||||
TopLevel::Def(def) => Self::add_def(&mut defs, def, builtins)?,
|
||||
TopLevel::Enum(r#enum) => Self::add_enum(&mut enums, &mut variants, r#enum, builtins)?,
|
||||
}
|
||||
}
|
||||
|
||||
Ok(Program { enums, defs, variants })
|
||||
}
|
||||
|
||||
fn add_def_py(defs: &mut IndexMap<Name, Definition>, def: Definition) -> Result<(), String> {
|
||||
fn add_def(
|
||||
defs: &mut IndexMap<Name, Definition>,
|
||||
def: Definition,
|
||||
builtins: &HashSet<Name>,
|
||||
) -> Result<(), String> {
|
||||
if builtins.contains(&def.name) {
|
||||
return Err(format!("Built-in function '{}' cannot be overridden.", def.name));
|
||||
}
|
||||
match defs.entry(def.name.clone()) {
|
||||
indexmap::map::Entry::Occupied(o) => Err(format!("Repeated definition '{}'.", o.get().name)),
|
||||
indexmap::map::Entry::Occupied(o) => Err(format!("Repeated function definition '{}'.", o.get().name)),
|
||||
indexmap::map::Entry::Vacant(v) => {
|
||||
v.insert(def);
|
||||
Ok(())
|
||||
@ -687,15 +707,22 @@ impl<'a> PyParser<'a> {
|
||||
}
|
||||
}
|
||||
|
||||
fn add_enum_py(
|
||||
fn add_enum(
|
||||
enums: &mut IndexMap<Name, Enum>,
|
||||
variants: &mut IndexMap<Name, Name>,
|
||||
r#enum: Enum,
|
||||
builtins: &HashSet<Name>,
|
||||
) -> Result<(), String> {
|
||||
if builtins.contains(&r#enum.name) {
|
||||
return Err(format!("Built-in type '{}' cannot be overridden.", r#enum.name));
|
||||
}
|
||||
match enums.entry(r#enum.name.clone()) {
|
||||
indexmap::map::Entry::Occupied(o) => return Err(format!("Repeated enum '{}'.", o.key())),
|
||||
indexmap::map::Entry::Vacant(v) => {
|
||||
for (name, variant) in r#enum.variants.iter() {
|
||||
if builtins.contains(name) {
|
||||
return Err(format!("Built-in constructor '{}' cannot be overridden.", name));
|
||||
}
|
||||
match variants.entry(name.clone()) {
|
||||
indexmap::map::Entry::Occupied(_) => {
|
||||
return Err(format!("Repeated variant '{}'.", variant.name));
|
||||
@ -724,7 +751,7 @@ def main():
|
||||
return y + x[3];
|
||||
"#;
|
||||
let mut parser = PyParser::new(src);
|
||||
let mut program = parser.parse_program().inspect_err(|e| println!("{e}")).unwrap();
|
||||
let mut program = parser.parse_program(&Default::default()).inspect_err(|e| println!("{e}")).unwrap();
|
||||
program.gen_map_get();
|
||||
let out = program.to_fun(crate::Book::builtins());
|
||||
println!("{}", out.display_pretty());
|
||||
@ -805,7 +832,7 @@ def bnd():
|
||||
// return x;
|
||||
"#;
|
||||
let mut parser = PyParser::new(src);
|
||||
let mut program = parser.parse_program().inspect_err(|e| println!("{e}")).unwrap();
|
||||
let mut program = parser.parse_program(&Default::default()).inspect_err(|e| println!("{e}")).unwrap();
|
||||
program.order_kwargs();
|
||||
program.gen_map_get();
|
||||
let out = program.to_fun(crate::Book::builtins());
|
||||
|
@ -1,5 +1,5 @@
|
||||
use super::{AssignPattern, Definition, Expr, MapKey, Program, Stmt};
|
||||
use crate::fun;
|
||||
use crate::fun::{self, Name};
|
||||
|
||||
impl Program {
|
||||
pub fn to_fun(self, mut book: fun::Book) -> fun::Book {
|
||||
@ -48,6 +48,15 @@ impl AssignPattern {
|
||||
impl Stmt {
|
||||
pub fn to_fun(self) -> fun::Term {
|
||||
match self {
|
||||
Stmt::Assign { pat: AssignPattern::MapSet(map, key), val, nxt } => fun::Term::Let {
|
||||
pat: Box::new(fun::Pattern::Var(Some(map.clone()))),
|
||||
val: Box::new(fun::Term::call(fun::Term::Ref { nam: fun::Name::new("Map/set") }, [
|
||||
fun::Term::Var { nam: map },
|
||||
fun::Term::Num { val: fun::Num::U24(key.0) },
|
||||
val.to_fun(),
|
||||
])),
|
||||
nxt: Box::new(nxt.to_fun()),
|
||||
},
|
||||
Stmt::Assign { pat, val, nxt } => {
|
||||
let pat = pat.to_fun();
|
||||
let val = val.to_fun();
|
||||
@ -74,8 +83,9 @@ impl Stmt {
|
||||
}
|
||||
Stmt::Switch { arg, bind, arms } => {
|
||||
let arg = arg.to_fun();
|
||||
let pred = Some(Name::new(format!("{}-{}", bind.clone().unwrap(), arms.len() - 1)));
|
||||
let arms = arms.into_iter().map(Stmt::to_fun).collect();
|
||||
fun::Term::Swt { arg: Box::new(arg), bnd: bind, with: Vec::new(), pred: None, arms }
|
||||
fun::Term::Swt { arg: Box::new(arg), bnd: bind, with: Vec::new(), pred, arms }
|
||||
}
|
||||
Stmt::Fold { arg, bind, arms } => {
|
||||
let arg = arg.to_fun();
|
||||
@ -91,6 +101,7 @@ impl Stmt {
|
||||
}
|
||||
Stmt::Do { .. } => todo!(),
|
||||
Stmt::Return { term } => term.to_fun(),
|
||||
Stmt::Err => fun::Term::Err,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -2,8 +2,8 @@ use bend::{
|
||||
compile_book, desugar_book,
|
||||
diagnostics::{Diagnostics, DiagnosticsConfig, Severity},
|
||||
fun::{
|
||||
load_book::do_parse_book, net_to_term::net_to_term, parser::TermParser, term_to_net::Labels, Book, Ctx,
|
||||
Name,
|
||||
load_book::do_parse_core_book, net_to_term::net_to_term, parser::TermParser, term_to_net::Labels, Book,
|
||||
Ctx, Name,
|
||||
},
|
||||
net::hvmc_to_net::hvmc_to_net,
|
||||
run_book, CompileOpts, RunOpts,
|
||||
@ -115,7 +115,7 @@ fn compile_term() {
|
||||
#[test]
|
||||
fn compile_file() {
|
||||
run_golden_test_dir(function_name!(), &|code, path| {
|
||||
let mut book = do_parse_book(code, path)?;
|
||||
let mut book = do_parse_core_book(code, path, Book::builtins())?;
|
||||
let compile_opts = CompileOpts::default();
|
||||
let diagnostics_cfg = DiagnosticsConfig { unused_definition: Severity::Allow, ..Default::default() };
|
||||
|
||||
@ -127,7 +127,7 @@ fn compile_file() {
|
||||
#[test]
|
||||
fn compile_file_o_all() {
|
||||
run_golden_test_dir(function_name!(), &|code, path| {
|
||||
let mut book = do_parse_book(code, path)?;
|
||||
let mut book = do_parse_core_book(code, path, Book::builtins())?;
|
||||
let opts = CompileOpts::default().set_all();
|
||||
let diagnostics_cfg = DiagnosticsConfig {
|
||||
recursion_cycle: Severity::Warning,
|
||||
@ -143,7 +143,7 @@ fn compile_file_o_all() {
|
||||
#[test]
|
||||
fn compile_file_o_no_all() {
|
||||
run_golden_test_dir(function_name!(), &|code, path| {
|
||||
let mut book = do_parse_book(code, path)?;
|
||||
let mut book = do_parse_core_book(code, path, Book::builtins())?;
|
||||
let compile_opts = CompileOpts::default().set_no_all();
|
||||
let diagnostics_cfg = DiagnosticsConfig::default();
|
||||
let res = compile_book(&mut book, compile_opts, diagnostics_cfg, None)?;
|
||||
@ -155,7 +155,7 @@ fn compile_file_o_no_all() {
|
||||
fn linear_readback() {
|
||||
run_golden_test_dir(function_name!(), &|code, path| {
|
||||
let _guard = RUN_MUTEX.lock().unwrap();
|
||||
let book = do_parse_book(code, path)?;
|
||||
let book = do_parse_core_book(code, path, Book::builtins())?;
|
||||
let compile_opts = CompileOpts::default().set_all();
|
||||
let diagnostics_cfg = DiagnosticsConfig::default();
|
||||
let (term, _, diags) = run_book(
|
||||
@ -174,7 +174,7 @@ fn linear_readback() {
|
||||
fn run_file() {
|
||||
run_golden_test_dir_multiple(function_name!(), &[(&|code, path| {
|
||||
let _guard = RUN_MUTEX.lock().unwrap();
|
||||
let book = do_parse_book(code, path)?;
|
||||
let book = do_parse_core_book(code, path, Book::builtins())?;
|
||||
let compile_opts = CompileOpts::default();
|
||||
let diagnostics_cfg = DiagnosticsConfig {
|
||||
unused_definition: Severity::Allow,
|
||||
@ -225,7 +225,7 @@ fn readback_lnet() {
|
||||
fn simplify_matches() {
|
||||
run_golden_test_dir(function_name!(), &|code, path| {
|
||||
let diagnostics_cfg = DiagnosticsConfig::new(Severity::Error, true);
|
||||
let mut book = do_parse_book(code, path)?;
|
||||
let mut book = do_parse_core_book(code, path, Book::builtins())?;
|
||||
let mut ctx = Ctx::new(&mut book, diagnostics_cfg);
|
||||
|
||||
ctx.check_shared_names();
|
||||
@ -253,7 +253,7 @@ fn simplify_matches() {
|
||||
#[test]
|
||||
fn parse_file() {
|
||||
run_golden_test_dir(function_name!(), &|code, path| {
|
||||
let book = do_parse_book(code, path)?;
|
||||
let book = do_parse_core_book(code, path, Book::builtins())?;
|
||||
Ok(book.to_string())
|
||||
})
|
||||
}
|
||||
@ -263,7 +263,7 @@ fn encode_pattern_match() {
|
||||
run_golden_test_dir(function_name!(), &|code, path| {
|
||||
let mut result = String::new();
|
||||
let diagnostics_cfg = DiagnosticsConfig::default();
|
||||
let mut book = do_parse_book(code, path)?;
|
||||
let mut book = do_parse_core_book(code, path, Book::builtins())?;
|
||||
let mut ctx = Ctx::new(&mut book, diagnostics_cfg);
|
||||
ctx.check_shared_names();
|
||||
ctx.set_entrypoint();
|
||||
@ -298,7 +298,7 @@ fn desugar_file() {
|
||||
unused_definition: Severity::Allow,
|
||||
..DiagnosticsConfig::new(Severity::Error, true)
|
||||
};
|
||||
let mut book = do_parse_book(code, path)?;
|
||||
let mut book = do_parse_core_book(code, path, Book::builtins())?;
|
||||
desugar_book(&mut book, compile_opts, diagnostics_cfg, None)?;
|
||||
Ok(book.to_string())
|
||||
})
|
||||
@ -311,7 +311,7 @@ fn hangs() {
|
||||
|
||||
run_golden_test_dir(function_name!(), &move |code, path| {
|
||||
let _guard = RUN_MUTEX.lock().unwrap();
|
||||
let book = do_parse_book(code, path)?;
|
||||
let book = do_parse_core_book(code, path, Book::builtins())?;
|
||||
let compile_opts = CompileOpts::default().set_all();
|
||||
let diagnostics_cfg = DiagnosticsConfig::new(Severity::Allow, false);
|
||||
|
||||
@ -332,7 +332,7 @@ fn hangs() {
|
||||
#[test]
|
||||
fn compile_entrypoint() {
|
||||
run_golden_test_dir(function_name!(), &|code, path| {
|
||||
let mut book = do_parse_book(code, path)?;
|
||||
let mut book = do_parse_core_book(code, path, Book::builtins())?;
|
||||
book.entrypoint = Some(Name::new("foo"));
|
||||
let diagnostics_cfg = DiagnosticsConfig { ..DiagnosticsConfig::new(Severity::Error, true) };
|
||||
let res = compile_book(&mut book, CompileOpts::default(), diagnostics_cfg, None)?;
|
||||
@ -345,7 +345,7 @@ fn compile_entrypoint() {
|
||||
fn run_entrypoint() {
|
||||
run_golden_test_dir(function_name!(), &|code, path| {
|
||||
let _guard = RUN_MUTEX.lock().unwrap();
|
||||
let mut book = do_parse_book(code, path)?;
|
||||
let mut book = do_parse_core_book(code, path, Book::builtins())?;
|
||||
book.entrypoint = Some(Name::new("foo"));
|
||||
let compile_opts = CompileOpts::default().set_all();
|
||||
let diagnostics_cfg = DiagnosticsConfig { ..DiagnosticsConfig::new(Severity::Error, true) };
|
||||
@ -380,7 +380,7 @@ fn mutual_recursion() {
|
||||
run_golden_test_dir(function_name!(), &|code, path| {
|
||||
let diagnostics_cfg =
|
||||
DiagnosticsConfig { recursion_cycle: Severity::Error, ..DiagnosticsConfig::new(Severity::Allow, true) };
|
||||
let mut book = do_parse_book(code, path)?;
|
||||
let mut book = do_parse_core_book(code, path, Book::builtins())?;
|
||||
let opts = CompileOpts { merge: true, ..CompileOpts::default() };
|
||||
let res = compile_book(&mut book, opts, diagnostics_cfg, None)?;
|
||||
Ok(format!("{}{}", res.diagnostics, res.core_book))
|
||||
@ -405,7 +405,7 @@ fn io() {
|
||||
}), */
|
||||
(&|code, path| {
|
||||
let _guard = RUN_MUTEX.lock().unwrap();
|
||||
let book = do_parse_book(code, path)?;
|
||||
let book = do_parse_core_book(code, path, Book::builtins())?;
|
||||
let compile_opts = CompileOpts::default();
|
||||
let diagnostics_cfg = DiagnosticsConfig::default();
|
||||
let (term, _, diags) = run_book(book, RunOpts::default(), compile_opts, diagnostics_cfg, None)?;
|
||||
@ -430,7 +430,7 @@ fn examples() -> Result<(), Diagnostics> {
|
||||
eprintln!("Testing {}", path.display());
|
||||
let code = std::fs::read_to_string(path).map_err(|e| e.to_string())?;
|
||||
|
||||
let book = do_parse_book(&code, path).unwrap();
|
||||
let book = do_parse_core_book(&code, path, Book::builtins()).unwrap();
|
||||
let compile_opts = CompileOpts::default();
|
||||
let diagnostics_cfg = DiagnosticsConfig::default();
|
||||
let (term, _, diags) = run_book(book, RunOpts::default(), compile_opts, diagnostics_cfg, None)?;
|
||||
@ -452,7 +452,7 @@ fn examples() -> Result<(), Diagnostics> {
|
||||
#[test]
|
||||
fn scott_triggers_unused() {
|
||||
run_golden_test_dir(function_name!(), &|code, path| {
|
||||
let mut book = do_parse_book(code, path)?;
|
||||
let mut book = do_parse_core_book(code, path, Book::builtins())?;
|
||||
let opts = CompileOpts::default();
|
||||
let diagnostics_cfg =
|
||||
DiagnosticsConfig { unused_definition: Severity::Error, ..DiagnosticsConfig::default() };
|
||||
|
@ -1,3 +1,4 @@
|
||||
#flavor core
|
||||
data Pair
|
||||
= (Pair fst snd)
|
||||
|
||||
|
@ -1,3 +1,4 @@
|
||||
#flavor core
|
||||
(Num) = 42
|
||||
|
||||
(Era) = *
|
||||
|
@ -1 +1,2 @@
|
||||
#flavor core
|
||||
main = *
|
||||
|
@ -1,3 +1,4 @@
|
||||
#flavor core
|
||||
I = (+ 2 3)
|
||||
|
||||
main = *
|
||||
|
@ -1,3 +1,4 @@
|
||||
#flavor core
|
||||
A = @a match a {
|
||||
List.cons: (A a.tail)
|
||||
List.nil: 0
|
||||
|
@ -1 +1,2 @@
|
||||
#flavor core
|
||||
main = *
|
||||
|
@ -1,3 +1,4 @@
|
||||
#flavor core
|
||||
(Map f []) = []
|
||||
(Map f (List.cons head tail)) = (List.cons (f head) (Map f tail))
|
||||
|
||||
|
@ -1,3 +1,4 @@
|
||||
#flavor core
|
||||
data Nat_ = (Z) | (S nat)
|
||||
|
||||
U60ToNat n = switch n {
|
||||
|
@ -1,3 +1,4 @@
|
||||
#flavor core
|
||||
data Boolean = True | False
|
||||
|
||||
main = True
|
||||
|
@ -1,3 +1,4 @@
|
||||
#flavor core
|
||||
data Boolean = True | False
|
||||
|
||||
main = True
|
||||
|
@ -1,3 +1,4 @@
|
||||
#flavor core
|
||||
Z = @s @z z
|
||||
S = @x @s @z (s (x s z))
|
||||
|
||||
|
@ -1 +1,2 @@
|
||||
#flavor core
|
||||
main = λa λb λc switch a { 0: b; _: c }
|
||||
|
@ -1 +1,2 @@
|
||||
#flavor core
|
||||
main = λa λb switch a { 0: b; _: b }
|
||||
|
@ -1,3 +1,4 @@
|
||||
#flavor core
|
||||
F = @t @f f
|
||||
Z = @s @z z
|
||||
|
||||
|
@ -1,3 +1,4 @@
|
||||
#flavor core
|
||||
id x = x
|
||||
|
||||
main = *
|
||||
|
@ -1 +1,2 @@
|
||||
#flavor core
|
||||
main a b = (+ a b)
|
||||
|
@ -1,3 +1,4 @@
|
||||
#flavor core
|
||||
main a b =
|
||||
switch a {
|
||||
0: switch b {
|
||||
|
@ -1,3 +1,4 @@
|
||||
#flavor core
|
||||
Foo a a = a
|
||||
|
||||
Main = (Foo a)
|
@ -1,4 +1,4 @@
|
||||
data Map = Free | Used | (Both a b)
|
||||
data Map_ = Free | Used | (Both a b)
|
||||
data Arr = Null | (Leaf x) | (Node a b)
|
||||
|
||||
(Swap s a b) = switch s {
|
||||
|
@ -2,4 +2,10 @@
|
||||
source: tests/golden_tests.rs
|
||||
input_file: tests/golden_tests/parse_file/scape_chars.hvm
|
||||
---
|
||||
(Map/empty) = Map.leaf
|
||||
|
||||
(Map/get map key) = match map = map { Map.leaf: (*, map); Map.node: switch _ = (== 0 key) { 0: switch _ = (% key 2) { 0: let (got, rest) = (Map/get map.left (/ key 2)); (got, (Map.node map.value rest map.right)); _ _-1: let (got, rest) = (Map/get map.right (/ key 2)); (got, (Map.node map.value map.left rest)); }; _ _-1: (map.value, map); }; }
|
||||
|
||||
(Map/set map key value) = match map = map { Map.node: switch _ = (== 0 key) { 0: switch _ = (% key 2) { 0: (Map.node map.value (Map/set map.left (/ key 2) value) map.right); _ _-1: (Map.node map.value map.left (Map/set map.right (/ key 2) value)); }; _ _-1: (Map.node value map.left map.right); }; Map.leaf: switch _ = (== 0 key) { 0: switch _ = (% key 2) { 0: (Map.node * (Map/set Map.leaf (/ key 2) value) Map.leaf); _ _-1: (Map.node * Map.leaf (Map/set Map.leaf (/ key 2) value)); }; _ _-1: (Map.node value Map.leaf Map.leaf); }; }
|
||||
|
||||
(main) = "\\ \n \t \""
|
||||
|
Loading…
Reference in New Issue
Block a user