diff --git a/example/data/hello_world.mc b/example/data/hello_world.mc new file mode 100644 index 0000000..d346023 --- /dev/null +++ b/example/data/hello_world.mc @@ -0,0 +1,4 @@ + +let msg = "hello world"; + +msg \ No newline at end of file diff --git a/example/data/loops.mc b/example/data/loops.mc new file mode 100644 index 0000000..1aaa011 --- /dev/null +++ b/example/data/loops.mc @@ -0,0 +1,22 @@ + +let i = 0; + +loop { + i = i + 1; + print("i", i); + if (i > 5) break; +} + +fn for(array, op) { + let index = 0; + loop { + let item = array[index]; + if (item == none) break; + op(item, index); + index = index + 1; + } +} + +for([1, 2, 3], (item, index) => { + print("at index", index, "item", item); +}); diff --git a/example/run.rs b/example/run.rs index 02e2eb8..0c08864 100644 --- a/example/run.rs +++ b/example/run.rs @@ -1,15 +1,21 @@ use std::{env::args, fs}; -use microlang::Context; +use microlang::{Context, Value}; pub fn main() { unsafe { backtrace_on_stack_overflow::enable() }; let mut context = Context::empty(); - let lines = fs::read_to_string(args().nth(1).expect("Pass a file as arg 1.")).expect("File could not be read."); - for line in lines.lines() { - match context.eval(line.into()) { - Err(err) => panic!("Failed : {err:?}"), - Ok((_, value)) => println!("{}", value.serialize()), + context.define_built("print", |values, _| { + for val in values { + print!("{} ", val.serialize()); } + println!(); + Ok(Value::None) + }); + + let lines = fs::read_to_string(args().nth(1).expect("Pass a file as arg 1.")).expect("File could not be read."); + match context.eval(lines) { + Err(err) => panic!("Failed : {err:?}"), + Ok((_, value)) => println!("{}", value.serialize()), } } diff --git a/src/ast.rs b/src/ast.rs index 0fa4fab..aa16224 100644 --- a/src/ast.rs +++ b/src/ast.rs @@ -6,7 +6,7 @@ use crate::{util::Boxable, Context, EvalError, FunImpl, Function, Value}; use chumsky::{ error::Simple, prelude::{end, just, none_of, one_of, recursive, Recursive}, - text::{whitespace, TextParser}, + text::TextParser, Parser, }; use hashbrown::HashMap; @@ -17,10 +17,7 @@ pub trait Parse: Parser> + Clone + 'static {} impl> + Clone + 'static, O> Parse for T {} fn lx(word: &'static str) -> impl Parse<&'static str> { - whitespace() - .ignore_then(just(word)) - .then_ignore(whitespace()) - .labelled("token") + just(word).padded().labelled("token") } fn id() -> impl Parse { @@ -41,8 +38,6 @@ pub struct Block { impl Block { pub fn parser(instr: impl Parse, expr: impl Parse) -> impl Parse { instr - .clone() - .then_ignore(lx(";")) .repeated() .then(expr.map(Boxable::to_box).or_not()) .map(|(instructions, expression)| Self { @@ -97,6 +92,7 @@ impl FunDef { pub fn parser_lamb(instr: impl Parse, expr: impl Parse) -> impl Parse { let arguments = id().padded().separated_by(lx(",")); (lx("(").ignore_then(arguments).then_ignore(lx(")"))) + .then_ignore(lx("=>")) .then(lx("{").ignore_then(Block::parser(instr, expr)).then_ignore(lx("}"))) .map(|(args, body)| Self { args, body }) .labelled("lambda") @@ -121,38 +117,42 @@ pub enum Instr { impl Instr { pub fn parser(expr: impl Parse) -> impl Parse { recursive(|instr: Recursive<'_, _, Self, _>| { - (lx("{") - .ignore_then(Block::parser(instr.clone(), expr.clone())) - .then_ignore(lx("}")) - .map(Self::Block)) - .labelled("block instruction") - .or(lx("let") - .ignore_then(id()) - .then_ignore(lx("=")) - .then(expr.clone()) - .map(|(id, ex)| Self::Init(id, ex))) - .labelled("variable initialization") - .or(lx("if") - .ignore_then(lx("(").ignore_then(expr.clone()).then_ignore(lx(")"))) - .then((instr.clone()).then((lx("else").ignore_then(instr.clone())).or_not())) - .map(|(cond, (then, els))| Self::Branch(cond, then.to_box(), els.unwrap_or(Instr::Nop).to_box()))) - .labelled("condition instruction") - .or(lx("loop") - .ignore_then(instr.clone()) - .map(|body| Self::Loop(body.to_box()))) - .labelled("loop instruction") - .or(ShortDef::parser(expr.clone()) - .map(Self::Short) - .labelled("shortcut instruction")) - .or(FunDef::parser_def(instr, expr.clone()) - .map(|(name, fun)| Self::FnDef(name, fun)) - .labelled("function definition")) - .or(id() - .then_ignore(lx("=")) - .then(expr.clone()) - .map(|(id, ex)| Self::Assign(id, ex)) - .labelled("variable assigniation.")) - .or(expr.map(Self::Expr)) + (lx(";").map(|_| Self::Nop).labelled("no operation")) + .or(lx("{") + .ignore_then(Block::parser(instr.clone(), expr.clone())) + .then_ignore(lx("}")) + .map(Self::Block) + .labelled("block instruction")) + .or(lx("let") + .ignore_then(id()) + .then_ignore(lx("=")) + .then(expr.clone()) + .then_ignore(lx(";")) + .map(|(id, ex)| Self::Init(id, ex)) + .labelled("variable initialization")) + .or(lx("if") + .ignore_then(lx("(").ignore_then(expr.clone()).then_ignore(lx(")"))) + .then((instr.clone()).then((lx("else").ignore_then(instr.clone())).or_not())) + .map(|(cond, (then, els))| Self::Branch(cond, then.to_box(), els.unwrap_or(Instr::Nop).to_box())) + .labelled("condition instruction")) + .or(lx("loop") + .ignore_then(instr.clone()) + .map(|body| Self::Loop(body.to_box())) + .labelled("loop instruction")) + .or(ShortDef::parser(expr.clone()) + .then_ignore(lx(";")) + .map(Self::Short) + .labelled("shortcut instruction")) + .or(FunDef::parser_def(instr, expr.clone()) + .map(|(name, fun)| Self::FnDef(name, fun)) + .labelled("function definition")) + .or(id() + .then_ignore(lx("=")) + .then(expr.clone()) + .then_ignore(lx(";")) + .map(|(id, ex)| Self::Assign(id, ex)) + .labelled("variable assigniation")) + .or(expr.then_ignore(lx(";")).map(Self::Expr)) }) .labelled("instruction") } @@ -164,7 +164,7 @@ impl Instr { Self::Expr(expr) => no_short(expr.eval(context)?), Self::Init(name, expr) => { let value = expr.eval(context)?; - context.scope().borrow_mut().append(name.clone(), value); + context.scope().borrow_mut().define(name.clone(), value); no_short(()) } Self::Assign(name, expr) => { @@ -262,7 +262,7 @@ impl Expr { .map(|(e, a)| Self::Access(e.to_box(), a))) .or((left.clone()) .then_ignore(lx("(")) - .then(expr.clone().then_ignore(lx(",")).repeated()) + .then(expr.clone().separated_by(lx(","))) .then_ignore(lx(")")) .map(|(e, a)| Self::Call(e.to_box(), a))) .or((left.clone()) @@ -354,6 +354,21 @@ impl Op { Ok(match (self, l, r) { (Self::Add, Value::Str(l), Value::Str(r)) => Value::Str(format!("{l}{r}")), (Self::Add, Value::Num(l), Value::Num(r)) => Value::Num(l + r), + (Self::Sub, Value::Num(l), Value::Num(r)) => Value::Num(l - r), + (Self::Div, Value::Num(l), Value::Num(r)) => Value::Num(l / r), + (Self::Prod, Value::Num(l), Value::Num(r)) => Value::Num(l * r), + (Self::Lt, Value::Num(l), Value::Num(r)) => Value::Bool(l < r), + (Self::Gt, Value::Num(l), Value::Num(r)) => Value::Bool(l > r), + (Self::Leq, Value::Num(l), Value::Num(r)) => Value::Bool(l <= r), + (Self::Geq, Value::Num(l), Value::Num(r)) => Value::Bool(l >= r), + (Self::Eq, Value::None, Value::None) => Value::Bool(true), + (Self::Eq, Value::Num(l), Value::Num(r)) => Value::Bool(l == r), + (Self::Eq, Value::Str(l), Value::Str(r)) => Value::Bool(l == r), + (Self::Eq, Value::Array(l), Value::Array(r)) => Value::Bool(Rc::ptr_eq(l, r)), + (Self::Eq, Value::Object(l), Value::Object(r)) => Value::Bool(Rc::ptr_eq(l, r)), + (Self::Eq, Value::Function(l), Value::Function(r)) => Value::Bool(Rc::ptr_eq(l, r)), + (Self::Eq, _, _) => Value::Bool(false), + (Self::Neq, _, _) => UniOp::Inv.apply(&Self::Eq.apply(l, r)?)?, _ => Err(EvalError::WrongType)?, }) } @@ -400,6 +415,7 @@ impl Litteral { .ignore_then(char.repeated()) .then_ignore(just("\"")) .map(|s| Self::Str(s.iter().collect()))) + .or(just("none").map(|_| Self::None)) .or(just("true") .map(|_| true) .or(just("false").map(|_| false)) diff --git a/src/lib.rs b/src/lib.rs index d762348..995aba6 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -53,6 +53,19 @@ impl Context { Ok((parsed, value)) } + pub fn define(&mut self, name: impl ToString, value: Value) { + self.scope().borrow_mut().define(name.to_string(), value) + } + + pub fn define_built(&mut self, name: impl ToString, op: impl Fn(Vec, &mut Context) -> FunRes + 'static) { + let def = FunImpl::Built(Rc::new(op) as Rc); + let function = Function { + capturing: Rc::new(RefCell::new(Scope::new(None))), + def, + }; + self.define(name.to_string(), Value::Function(Rc::new(RefCell::new(function)))) + } + pub fn scope(&self) -> Rc> { self.frame.clone() } @@ -88,7 +101,7 @@ impl Scope { result } - pub fn append(&mut self, name: String, value: Value) { + pub fn define(&mut self, name: String, value: Value) { self.defs.insert(name, value); } @@ -209,7 +222,7 @@ impl Function { FunImpl::Def(def) => Scope::alt(context, self.capturing.clone(), |context| { let names = def.args.iter().cloned(); for (name, value) in names.zip(args.into_iter().chain(repeat(Value::None))) { - context.scope().borrow_mut().append(name, value); + context.scope().borrow_mut().define(name, value); } match def.body.eval(context) { Err(err) => Err(err),