syntax v2
introduce a new, more ergonomic syntax for haku not all features are implemented just yet. still missing: - custom tags (non-True/False) - color literals - lists
This commit is contained in:
parent
a3e5e8bd10
commit
2595bf0d82
21 changed files with 2844 additions and 1062 deletions
|
@ -1,10 +1,14 @@
|
|||
use std::error::Error;
|
||||
|
||||
use haku::{
|
||||
ast::{dump::dump, Ast},
|
||||
bytecode::{Chunk, Defs},
|
||||
compiler::{compile_expr, Compiler, Source},
|
||||
sexp::{self, Ast, Parser, SourceCode},
|
||||
lexer::{lex, Lexer},
|
||||
parser::{self, Parser, ParserLimits},
|
||||
source::SourceCode,
|
||||
system::System,
|
||||
token::Lexis,
|
||||
value::{BytecodeLoc, Closure, FunctionName, Ref, RefId, Value},
|
||||
vm::{Vm, VmLimits},
|
||||
};
|
||||
|
@ -12,11 +16,16 @@ use haku::{
|
|||
fn eval(code: &str) -> Result<Value, Box<dyn Error>> {
|
||||
let mut system = System::new(1);
|
||||
|
||||
let ast = Ast::new(1024);
|
||||
let code = SourceCode::unlimited_len(code);
|
||||
let mut parser = Parser::new(ast, code);
|
||||
let root = sexp::parse_toplevel(&mut parser);
|
||||
let ast = parser.ast;
|
||||
|
||||
let mut lexer = Lexer::new(Lexis::new(1024), code);
|
||||
lex(&mut lexer)?;
|
||||
|
||||
let mut ast = Ast::new(1024);
|
||||
let mut parser = Parser::new(&lexer.lexis, &ParserLimits { max_events: 1024 });
|
||||
parser::toplevel(&mut parser);
|
||||
let (root, mut parser_diagnostics) = parser.into_ast(&mut ast)?;
|
||||
println!("{}", dump(&ast, root, Some(code)));
|
||||
let src = Source {
|
||||
code,
|
||||
ast: &ast,
|
||||
|
@ -27,21 +36,29 @@ fn eval(code: &str) -> Result<Value, Box<dyn Error>> {
|
|||
let mut chunk = Chunk::new(65536).unwrap();
|
||||
let mut compiler = Compiler::new(&mut defs, &mut chunk);
|
||||
compile_expr(&mut compiler, &src, root)?;
|
||||
let closure_spec = compiler.closure_spec();
|
||||
let defs = compiler.defs;
|
||||
|
||||
for diagnostic in &compiler.diagnostics {
|
||||
let mut diagnostics = lexer.diagnostics;
|
||||
diagnostics.append(&mut parser_diagnostics);
|
||||
diagnostics.append(&mut compiler.diagnostics);
|
||||
|
||||
for diagnostic in &diagnostics {
|
||||
println!(
|
||||
"{}..{}: {}",
|
||||
diagnostic.span.start, diagnostic.span.end, diagnostic.message
|
||||
"{}..{} {:?}: {}",
|
||||
diagnostic.span().start,
|
||||
diagnostic.span().end,
|
||||
diagnostic.span().slice(code),
|
||||
diagnostic.message()
|
||||
);
|
||||
}
|
||||
|
||||
if !compiler.diagnostics.is_empty() {
|
||||
panic!("compiler diagnostics were emitted")
|
||||
if !diagnostics.is_empty() {
|
||||
panic!("diagnostics were emitted")
|
||||
}
|
||||
|
||||
let limits = VmLimits {
|
||||
stack_capacity: 256,
|
||||
stack_capacity: 1024,
|
||||
call_stack_capacity: 256,
|
||||
ref_capacity: 256,
|
||||
fuel: 32768,
|
||||
|
@ -50,16 +67,9 @@ fn eval(code: &str) -> Result<Value, Box<dyn Error>> {
|
|||
let mut vm = Vm::new(defs, &limits);
|
||||
let chunk_id = system.add_chunk(chunk)?;
|
||||
println!("bytecode: {:?}", system.chunk(chunk_id));
|
||||
println!("closure spec: {closure_spec:?}");
|
||||
|
||||
let closure = vm.create_ref(Ref::Closure(Closure {
|
||||
start: BytecodeLoc {
|
||||
chunk_id,
|
||||
offset: 0,
|
||||
},
|
||||
name: FunctionName::Anonymous,
|
||||
param_count: 0,
|
||||
captures: Vec::new(),
|
||||
}))?;
|
||||
let closure = vm.create_ref(Ref::Closure(Closure::chunk(chunk_id, closure_spec)))?;
|
||||
let result = vm.run(&system, closure)?;
|
||||
|
||||
println!("used fuel: {}", limits.fuel - vm.remaining_fuel());
|
||||
|
@ -87,49 +97,52 @@ fn literal_number() {
|
|||
|
||||
#[test]
|
||||
fn literal_bool() {
|
||||
assert_eq!(eval("false").unwrap(), Value::False);
|
||||
assert_eq!(eval("true").unwrap(), Value::True);
|
||||
assert_eq!(eval("False").unwrap(), Value::False);
|
||||
assert_eq!(eval("True").unwrap(), Value::True);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn function_nil() {
|
||||
assert_eq!(eval("(fn () ())").unwrap(), Value::Ref(RefId::from_u32(1)));
|
||||
assert_eq!(
|
||||
eval(r#" \_ -> () "#).unwrap(),
|
||||
Value::Ref(RefId::from_u32(1))
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn function_nil_call() {
|
||||
assert_eq!(eval("((fn () ()))").unwrap(), Value::Nil);
|
||||
assert_eq!(eval(r#"(\_ -> ()) ()"#).unwrap(), Value::Nil);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn function_arithmetic() {
|
||||
expect_number("((fn (x) (+ x 2)) 2)", 4.0, 0.0001);
|
||||
expect_number(r#"(\x -> x + 2) 2"#, 4.0, 0.0001);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn function_let() {
|
||||
expect_number("((fn (add-two) (add-two 2)) (fn (x) (+ x 2)))", 4.0, 0.0001);
|
||||
expect_number(r#"(\addTwo -> addTwo 2) \x -> x + 2"#, 4.0, 0.0001);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn function_closure() {
|
||||
expect_number("(((fn (x) (fn (y) (+ x y))) 2) 2)", 4.0, 0.0001);
|
||||
expect_number(r#"((\x -> \y -> x + y) 2) 2"#, 4.0, 0.0001);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn if_literal() {
|
||||
expect_number("(if 1 1 2)", 1.0, 0.0001);
|
||||
expect_number("(if () 1 2)", 2.0, 0.0001);
|
||||
expect_number("(if false 1 2)", 2.0, 0.0001);
|
||||
expect_number("(if true 1 2)", 1.0, 0.0001);
|
||||
expect_number("if (1) 1 else 2", 1.0, 0.0001);
|
||||
expect_number("if (()) 1 else 2", 2.0, 0.0001);
|
||||
expect_number("if (False) 1 else 2", 2.0, 0.0001);
|
||||
expect_number("if (True) 1 else 2", 1.0, 0.0001);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn def_simple() {
|
||||
let code = r#"
|
||||
(def x 1)
|
||||
(def y 2)
|
||||
(+ x y)
|
||||
x = 1
|
||||
y = 2
|
||||
x + y
|
||||
"#;
|
||||
expect_number(code, 3.0, 0.0001);
|
||||
}
|
||||
|
@ -137,13 +150,13 @@ fn def_simple() {
|
|||
#[test]
|
||||
fn def_fib_recursive() {
|
||||
let code = r#"
|
||||
(def fib
|
||||
(fn (n)
|
||||
(if (< n 2)
|
||||
n
|
||||
(+ (fib (- n 1)) (fib (- n 2))))))
|
||||
|
||||
(fib 10)
|
||||
fib = \n ->
|
||||
if (n < 2)
|
||||
n
|
||||
else
|
||||
fib (n - 1) + fib (n - 2)
|
||||
|
||||
fib 10
|
||||
"#;
|
||||
expect_number(code, 55.0, 0.0001);
|
||||
}
|
||||
|
@ -151,27 +164,30 @@ fn def_fib_recursive() {
|
|||
#[test]
|
||||
fn def_mutually_recursive() {
|
||||
let code = r#"
|
||||
(def f
|
||||
(fn (x)
|
||||
(if (< x 10)
|
||||
(g (+ x 1))
|
||||
x)))
|
||||
f = \x ->
|
||||
if (x < 10)
|
||||
g (x + 1)
|
||||
else
|
||||
x
|
||||
|
||||
(def g
|
||||
(fn (x)
|
||||
(if (< x 10)
|
||||
(f (* x 2))
|
||||
x)))
|
||||
g = \x ->
|
||||
if (x < 10)
|
||||
f (x * 2)
|
||||
else
|
||||
x
|
||||
|
||||
(f 0)
|
||||
f 0
|
||||
"#;
|
||||
expect_number(code, 14.0, 0.0001);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn def_botsbuildbots() {
|
||||
let result = eval("(def botsbuildbots (fn () (botsbuildbots))) (botsbuildbots)");
|
||||
if let Err(error) = result {
|
||||
let code = r#"
|
||||
botsbuildbots = \_ -> botsbuildbots ()
|
||||
botsbuildbots ()
|
||||
"#;
|
||||
if let Err(error) = eval(code) {
|
||||
assert_eq!(
|
||||
error.to_string(),
|
||||
"Exception {\n message: \"too much recursion\",\n}"
|
||||
|
@ -184,8 +200,8 @@ fn def_botsbuildbots() {
|
|||
#[test]
|
||||
fn let_single() {
|
||||
let code = r#"
|
||||
(let ((x 1))
|
||||
(+ x 1))
|
||||
let x = 1
|
||||
x + 1
|
||||
"#;
|
||||
expect_number(code, 2.0, 0.0001);
|
||||
}
|
||||
|
@ -193,9 +209,9 @@ fn let_single() {
|
|||
#[test]
|
||||
fn let_many() {
|
||||
let code = r#"
|
||||
(let ((x 1)
|
||||
(y 2))
|
||||
(+ x y))
|
||||
let x = 1
|
||||
let y = 2
|
||||
x + y
|
||||
"#;
|
||||
expect_number(code, 3.0, 0.0001);
|
||||
}
|
||||
|
@ -203,9 +219,9 @@ fn let_many() {
|
|||
#[test]
|
||||
fn let_sequence() {
|
||||
let code = r#"
|
||||
(let ((x 1)
|
||||
(y (+ x 1)))
|
||||
(+ x y))
|
||||
let x = 1
|
||||
let y = x + 1
|
||||
x + y
|
||||
"#;
|
||||
expect_number(code, 3.0, 0.0001);
|
||||
}
|
||||
|
@ -213,59 +229,40 @@ fn let_sequence() {
|
|||
#[test]
|
||||
fn let_subexpr() {
|
||||
let code = r#"
|
||||
(+
|
||||
(let ((x 1)
|
||||
(y 2))
|
||||
(* x y)))
|
||||
(let x = 1
|
||||
let y = 2
|
||||
x * y) + 2
|
||||
"#;
|
||||
expect_number(code, 2.0, 0.0001);
|
||||
expect_number(code, 4.0, 0.0001);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn let_empty() {
|
||||
fn let_subexpr_two() {
|
||||
let code = r#"
|
||||
(let () 1)
|
||||
"#;
|
||||
expect_number(code, 1.0, 0.0001);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn let_subexpr_empty() {
|
||||
let code = r#"
|
||||
(+ (let () 1) (let () 1))
|
||||
"#;
|
||||
expect_number(code, 2.0, 0.0001);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn let_subexpr_many() {
|
||||
let code = r#"
|
||||
(+
|
||||
(let ((x 1)
|
||||
(y 2))
|
||||
(* x y))
|
||||
(let () 1)
|
||||
(let ((x 1)) x))
|
||||
(let x = 1
|
||||
2) +
|
||||
(let x = 1
|
||||
x)
|
||||
"#;
|
||||
expect_number(code, 3.0, 0.0001);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn system_arithmetic() {
|
||||
expect_number("(+ 1 2 3 4)", 10.0, 0.0001);
|
||||
expect_number("(+ (* 2 1) 1 (/ 6 2) (- 10 3))", 13.0, 0.0001);
|
||||
fn let_subexpr_many() {
|
||||
let code = r#"
|
||||
(let x = 1
|
||||
let y = 2
|
||||
x * y) +
|
||||
(let x = 1
|
||||
2) +
|
||||
(let x = 1
|
||||
x)
|
||||
"#;
|
||||
expect_number(code, 5.0, 0.0001);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn practical_fib_recursive() {
|
||||
let code = r#"
|
||||
((fn (fib)
|
||||
(fib fib 10))
|
||||
|
||||
(fn (fib n)
|
||||
(if (< n 2)
|
||||
n
|
||||
(+ (fib fib (- n 1)) (fib fib (- n 2))))))
|
||||
"#;
|
||||
expect_number(code, 55.0, 0.0001);
|
||||
fn system_arithmetic() {
|
||||
expect_number("1 + 2 + 3 + 4", 10.0, 0.0001);
|
||||
expect_number("(2 * 1) + 1 + (6 / 2) + (10 - 3)", 13.0, 0.0001);
|
||||
}
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue