diff --git a/Cargo.toml b/Cargo.toml index e700f56..e76b3b8 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -10,5 +10,5 @@ ariadne = { git = "https://github.com/zesterer/ariadne" } chumsky = { git = "https://github.com/zesterer/chumsky", features = ["label"] } imbl = "3.0.0" struct_scalpel = "0.1.1" -tailcall = "1.0.1" ran = "2.0.1" +rust-embed = "8.5.0" diff --git a/src/base.rs b/src/base.rs index ddc8be4..0bf0993 100644 --- a/src/base.rs +++ b/src/base.rs @@ -571,62 +571,61 @@ pub fn r#mod<'src>(x: &Value, y: &Value) -> Value<'src> { } pub fn base<'src>() -> Vec<(String, Value<'src>)> { - vec![ - ("add".to_string(), Value::Base(Base::Binary(add))), - ("and".to_string(), Value::Base(Base::Binary(and))), - ("append".to_string(), Value::Base(Base::Binary(append))), - ("assoc".to_string(), Value::Base(Base::Ternary(assoc))), - ("at".to_string(), Value::Base(Base::Binary(at))), - ("atan_2".to_string(), Value::Base(Base::Binary(atan_2))), - ("bool".to_string(), Value::Base(Base::Unary(r#bool))), - ("ceil".to_string(), Value::Base(Base::Unary(ceil))), - ("chars".to_string(), Value::Base(Base::Unary(chars))), - ("concat".to_string(), Value::Base(Base::Binary(concat))), - ("cos".to_string(), Value::Base(Base::Unary(cos))), - ("count".to_string(), Value::Base(Base::Unary(count))), - ("dec".to_string(), Value::Base(Base::Unary(dec))), - ("dissoc".to_string(), Value::Base(Base::Binary(dissoc))), - ("div".to_string(), Value::Base(Base::Binary(div))), - ("doc!".to_string(), Value::Base(Base::Unary(doc))), - ("downcase".to_string(), Value::Base(Base::Unary(downcase))), - ("eq?".to_string(), Value::Base(Base::Binary(eq))), - ("first".to_string(), Value::Base(Base::Unary(first))), - ("floor".to_string(), Value::Base(Base::Unary(floor))), - ("get".to_string(), Value::Base(Base::Binary(get))), - ("gt?".to_string(), Value::Base(Base::Binary(gt))), - ("gte?".to_string(), Value::Base(Base::Binary(gte))), - ("inc".to_string(), Value::Base(Base::Unary(inc))), - ("last".to_string(), Value::Base(Base::Unary(last))), - ("list".to_string(), Value::Base(Base::Unary(list))), - ("lt?".to_string(), Value::Base(Base::Binary(lt))), - ("lte?".to_string(), Value::Base(Base::Binary(lte))), - ("mod".to_string(), Value::Base(Base::Binary(r#mod))), - ("mult".to_string(), Value::Base(Base::Binary(mult))), - ("number".to_string(), Value::Base(Base::Unary(number))), - ("or".to_string(), Value::Base(Base::Binary(or))), - ("pi".to_string(), Value::Number(std::f64::consts::PI)), - ("print!".to_string(), Value::Base(Base::Unary(print))), - ("random".to_string(), Value::Base(Base::Nullary(random))), - ("range".to_string(), Value::Base(Base::Binary(range))), - ("rest".to_string(), Value::Base(Base::Unary(rest))), - ("round".to_string(), Value::Base(Base::Unary(round))), - ("show".to_string(), Value::Base(Base::Unary(show))), - ("sin".to_string(), Value::Base(Base::Unary(sin))), - ("slice".to_string(), Value::Base(Base::Ternary(slice))), - ("split".to_string(), Value::Base(Base::Binary(split))), - ("sqrt".to_string(), Value::Base(Base::Unary(sqrt))), - ( - "sqrt_2".to_string(), - Value::Number(std::f64::consts::SQRT_2), - ), - ("store!".to_string(), Value::Base(Base::Binary(store))), - ("sub".to_string(), Value::Base(Base::Binary(sub))), - ("tan".to_string(), Value::Base(Base::Unary(tan))), - ("trim".to_string(), Value::Base(Base::Unary(trim))), - ("triml".to_string(), Value::Base(Base::Unary(triml))), - ("trimr".to_string(), Value::Base(Base::Unary(trimr))), - ("type".to_string(), Value::Base(Base::Unary(r#type))), - ("unbox".to_string(), Value::Base(Base::Unary(unbox))), - ("upcase".to_string(), Value::Base(Base::Unary(upcase))), - ] + let members = vec![ + ("add", Value::Base(Base::Binary(add))), + ("and", Value::Base(Base::Binary(and))), + ("append", Value::Base(Base::Binary(append))), + ("assoc", Value::Base(Base::Ternary(assoc))), + ("at", Value::Base(Base::Binary(at))), + ("atan_2", Value::Base(Base::Binary(atan_2))), + ("bool", Value::Base(Base::Unary(r#bool))), + ("ceil", Value::Base(Base::Unary(ceil))), + ("chars", Value::Base(Base::Unary(chars))), + ("concat", Value::Base(Base::Binary(concat))), + ("cos", Value::Base(Base::Unary(cos))), + ("count", Value::Base(Base::Unary(count))), + ("dec", Value::Base(Base::Unary(dec))), + ("dissoc", Value::Base(Base::Binary(dissoc))), + ("div", Value::Base(Base::Binary(div))), + ("doc!", Value::Base(Base::Unary(doc))), + ("downcase", Value::Base(Base::Unary(downcase))), + ("eq?", Value::Base(Base::Binary(eq))), + ("first", Value::Base(Base::Unary(first))), + ("floor", Value::Base(Base::Unary(floor))), + ("get", Value::Base(Base::Binary(get))), + ("gt?", Value::Base(Base::Binary(gt))), + ("gte?", Value::Base(Base::Binary(gte))), + ("inc", Value::Base(Base::Unary(inc))), + ("last", Value::Base(Base::Unary(last))), + ("list", Value::Base(Base::Unary(list))), + ("lt?", Value::Base(Base::Binary(lt))), + ("lte?", Value::Base(Base::Binary(lte))), + ("mod", Value::Base(Base::Binary(r#mod))), + ("mult", Value::Base(Base::Binary(mult))), + ("number", Value::Base(Base::Unary(number))), + ("or", Value::Base(Base::Binary(or))), + ("pi", Value::Number(std::f64::consts::PI)), + ("print!", Value::Base(Base::Unary(print))), + ("random", Value::Base(Base::Nullary(random))), + ("range", Value::Base(Base::Binary(range))), + ("rest", Value::Base(Base::Unary(rest))), + ("round", Value::Base(Base::Unary(round))), + ("show", Value::Base(Base::Unary(show))), + ("sin", Value::Base(Base::Unary(sin))), + ("slice", Value::Base(Base::Ternary(slice))), + ("split", Value::Base(Base::Binary(split))), + ("sqrt", Value::Base(Base::Unary(sqrt))), + ("sqrt_2", Value::Number(std::f64::consts::SQRT_2)), + ("store!", Value::Base(Base::Binary(store))), + ("sub", Value::Base(Base::Binary(sub))), + ("tan", Value::Base(Base::Unary(tan))), + ("trim", Value::Base(Base::Unary(trim))), + ("triml", Value::Base(Base::Unary(triml))), + ("trimr", Value::Base(Base::Unary(trimr))), + ("type", Value::Base(Base::Unary(r#type))), + ("unbox", Value::Base(Base::Unary(unbox))), + ("upcase", Value::Base(Base::Unary(upcase))), + ]; + let pkg = Value::Dict(HashMap::from(members)); + vec![("base".to_string(), pkg)] } diff --git a/src/main.rs b/src/main.rs index 9a5d2c5..4e51887 100644 --- a/src/main.rs +++ b/src/main.rs @@ -37,7 +37,7 @@ // * [ ] perf testing use chumsky::{input::Stream, prelude::*}; -// use std::rc::Rc; +use rust_embed::Embed; mod spans; @@ -45,21 +45,88 @@ mod lexer; use crate::lexer::*; mod value; -// use crate::value::*; +use crate::value::*; mod parser; use crate::parser::*; -mod vm; -use crate::vm::*; +// mod vm; +// use crate::vm::*; mod base; use crate::base::*; -pub fn main() { - let src = " -let \"foo {bar} baz\" = \"foo bar baz\" - "; +mod context; +use crate::context::*; + +#[derive(Embed)] +#[folder = "assets/"] +struct Asset; + +pub fn prelude<'src>() -> Context<'src> { + let prelude = Asset::get("prelude.ld").unwrap().data.into_owned(); + // we know for sure Prelude should live through the whole run of the program + let leaked = Box::leak(Box::new(prelude)); + let prelude = std::str::from_utf8(leaked).unwrap(); + + let (ptoks, perrs) = lexer().parse(prelude).into_output_errors(); + if !perrs.is_empty() { + println!("Errors lexing Prelude"); + println!("{:?}", perrs); + panic!(); + } + + let ptoks = ptoks.unwrap(); + + let (p_ast, perrs) = parser() + .parse(Stream::from_iter(ptoks).map((0..prelude.len()).into(), |(t, s)| (t, s))) + .into_output_errors(); + if !perrs.is_empty() { + println!("Errors parsing Prelude"); + println!("{:?}", perrs); + panic!(); + } + + let p_ast = Box::leak(Box::new(p_ast.unwrap().0)); + let base_pkg = base(); + + let mut base_ctx = Context::<'src> { + locals: vec![], + ast: p_ast, + prelude: base_pkg, + prelude_ast: &Ast::Nil, + }; + + let prelude = base_ctx.eval(); + + let mut p_ctx = vec![]; + + match prelude { + Ok(Value::Dict(p_dict)) => { + for (key, value) in p_dict.iter() { + p_ctx.push((key.to_string(), value.clone())) + } + } + Ok(_) => { + println!("Bad Prelude export"); + panic!(); + } + Err(LErr { msg, .. }) => { + println!("Error running Prelude"); + println!("{:?}", msg); + panic!(); + } + }; + + Context { + locals: vec![], + ast: &Ast::Nil, + prelude: p_ctx, + prelude_ast: p_ast, + } +} + +pub fn run(src: &'static str) { let (tokens, lex_errs) = lexer().parse(src).into_output_errors(); if !lex_errs.is_empty() { println!("{:?}", lex_errs); @@ -67,20 +134,42 @@ let \"foo {bar} baz\" = \"foo bar baz\" } let tokens = tokens.unwrap(); let to_parse = tokens.clone(); - // for (token, _) in tokens { - // println!("{}", token) - // } - let (ast, _) = parser() + + let (ast, parse_errors) = parser() .parse(Stream::from_iter(to_parse).map((0..src.len()).into(), |(t, s)| (t, s))) - .unwrap(); - // println!("{}", ast); + .into_output_errors(); + if !parse_errors.is_empty() { + println!("{:?}", parse_errors); + return; + } - let mut ctx = base(); + let ast = ast.unwrap().0; - let result = eval(&ast, &mut ctx).unwrap(); + let mut ctx = prelude(); + ctx.ast = * - println!("{}", result); + let result = ctx.eval(); + match result { + Ok(result) => println!("{}", result), + Err(LErr { msg, .. }) => println!("Errors!\n{}", msg), + } +} + +pub fn main() { + let src = " +fn fib { + (1) -> 1 + (2) -> 1 + (n) -> add ( + fib (dec (n)) + fib (sub (n, 2)) + ) +} + +fib (25) + "; + run(src); // struct_scalpel::print_dissection_info::() // struct_scalpel::print_dissection_info::(); // println!("{}", std::mem::size_of::()) diff --git a/src/parser.rs b/src/parser.rs index 8bd03fd..b16c934 100644 --- a/src/parser.rs +++ b/src/parser.rs @@ -713,19 +713,6 @@ where (Ast::Recur(args), e.span()) }); - simple.define( - synthetic - .or(recur) - .or(word) - .or(keyword) - .or(value) - .or(tuple.clone()) - .or(list) - .or(dict) - .or(string) - .labelled("simple expression"), - ); - let block = expr .clone() .separated_by(terminators.clone()) @@ -746,8 +733,10 @@ where let if_ = just(Token::Reserved("if")) .ignore_then(simple.clone()) + .then_ignore(terminators.clone().or_not()) .then_ignore(just(Token::Reserved("then"))) .then(expr.clone()) + .then_ignore(terminators.clone().or_not()) .then_ignore(just(Token::Reserved("else"))) .then(expr.clone()) .map_with(|((condition, then_branch), else_branch), e| { @@ -886,12 +875,25 @@ where .then(loop_multiclause.clone().or(fn_single_clause.clone())) .map_with(|(init, body), e| (Ast::Loop(Box::new(init), body), e.span())); + simple.define( + synthetic + .or(recur) + .or(word) + .or(keyword) + .or(value) + .or(tuple.clone()) + .or(list) + .or(dict) + .or(string) + .or(lambda.clone()) + .labelled("simple expression"), + ); + nonbinding.define( simple .clone() .or(conditional) .or(block) - .or(lambda) .or(panic) .or(do_) .or(repeat) diff --git a/src/vm.rs b/src/vm.rs index fcdedc6..2e108b9 100644 --- a/src/vm.rs +++ b/src/vm.rs @@ -236,7 +236,7 @@ pub fn match_clauses<'src>( pub fn apply<'src>( callee: Value<'src>, caller: Value<'src>, - ctx: &mut Context<'src>, + ctx: &mut Context, ) -> Result, LudusError> { match (callee, caller) { (Value::Keyword(kw), Value::Dict(dict)) => { @@ -306,7 +306,7 @@ pub fn apply<'src>( pub fn eval<'src, 'a>( ast: &'src Ast, - ctx: &'a mut Context<'src>, + ctx: &'a mut Vec<(String, Value<'src>)>, ) -> Result, LudusError> { match ast { Ast::Nil => Ok(Value::Nil),