[sc-667] Switch to new syntax by default

This commit is contained in:
Nicolas Abril 2024-05-09 21:11:20 +02:00
parent fe3a83d4a9
commit b5e89aa129
42 changed files with 254 additions and 93 deletions

32
examples/all_tree.bend Normal file
View 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));

View File

@ -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))

View File

@ -1,3 +1,4 @@
#flavor core
T = λt λf t
F = λt λf f
And = λpλq (p q F)

View File

@ -1,3 +1,4 @@
#flavor core
data Tree = (Leaf val) | (Both lft rgt)
(U60.swap 0 a b) = (Both a b)

View File

@ -1,3 +1,4 @@
#flavor core
// Sorts a list
// sort : List -> List

View File

@ -1,3 +1,4 @@
#flavor core
// This program is an example that shows how scopeless lambdas can be used.
Seq a b = a

View File

@ -1,3 +1,4 @@
#flavor core
// Write definitions like this
(Def1) = ((λa a) (λb b))

View File

@ -1,3 +1,4 @@
#flavor core
add = λa λb (+ a b)
fib = λx switch x {

View File

@ -1,3 +1,4 @@
#flavor core
zero = λs λz z
succ = λpred λs λz (s pred) // Creates a Scott number out of its predecessor

View File

@ -1,3 +1,4 @@
#flavor core
true = λt λf t
false = λt λf f
not = λboolean (boolean false true)

View File

@ -1,3 +1,4 @@
#flavor core
Tree.leaf = λnode λleaf leaf
Tree.node = λval λlft λrgt λnode λleaf (node val lft rgt)

View File

@ -1,3 +1,4 @@
#flavor core
// size = 1 << 8
Mul = λn λm λs (n (m s))

View File

@ -1,3 +1,4 @@
#flavor core
// A cool trick involving HVM's scopeless lambdas is linear qs:
// Qnew : Queue a

View File

@ -1,3 +1,4 @@
#flavor core
data Tree = Leaf | (Node l m r)
// Parallel QuickSort

View File

@ -1,3 +1,4 @@
#flavor core
data Map = Free | Used | (Both a b)
data Arr = Null | (Leaf x) | (Node a b)

View File

@ -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)
}

View File

@ -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 {

View File

@ -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)]

View File

@ -87,6 +87,7 @@ impl Stmt {
}
}
Stmt::Return { term } => term.order_kwargs(ctx),
Stmt::Err => {}
}
}
}

View File

@ -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());

View File

@ -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,
}
}
}

View File

@ -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() };

View File

@ -1,3 +1,4 @@
#flavor core
data Pair
= (Pair fst snd)

View File

@ -1,3 +1,4 @@
#flavor core
(Num) = 42
(Era) = *

View File

@ -1 +1,2 @@
#flavor core
main = *

View File

@ -1,3 +1,4 @@
#flavor core
I = (+ 2 3)
main = *

View File

@ -1,3 +1,4 @@
#flavor core
A = @a match a {
List.cons: (A a.tail)
List.nil: 0

View File

@ -1 +1,2 @@
#flavor core
main = *

View File

@ -1,3 +1,4 @@
#flavor core
(Map f []) = []
(Map f (List.cons head tail)) = (List.cons (f head) (Map f tail))

View File

@ -1,3 +1,4 @@
#flavor core
data Nat_ = (Z) | (S nat)
U60ToNat n = switch n {

View File

@ -1,3 +1,4 @@
#flavor core
data Boolean = True | False
main = True

View File

@ -1,3 +1,4 @@
#flavor core
data Boolean = True | False
main = True

View File

@ -1,3 +1,4 @@
#flavor core
Z = @s @z z
S = @x @s @z (s (x s z))

View File

@ -1 +1,2 @@
#flavor core
main = λa λb λc switch a { 0: b; _: c }

View File

@ -1 +1,2 @@
#flavor core
main = λa λb switch a { 0: b; _: b }

View File

@ -1,3 +1,4 @@
#flavor core
F = @t @f f
Z = @s @z z

View File

@ -1,3 +1,4 @@
#flavor core
id x = x
main = *

View File

@ -1 +1,2 @@
#flavor core
main a b = (+ a b)

View File

@ -1,3 +1,4 @@
#flavor core
main a b =
switch a {
0: switch b {

View File

@ -1,3 +1,4 @@
#flavor core
Foo a a = a
Main = (Foo a)

View File

@ -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 {

View File

@ -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 \""