diff --git a/example/data/fibo.mc b/example/data/fibo.mc index 3086e76..f551b63 100644 --- a/example/data/fibo.mc +++ b/example/data/fibo.mc @@ -1,7 +1,9 @@ +// recursion fn fibo(n) { - if (n < 1) return n; + if (n <= 0) return 0; + if (n <= 1) return 1; return fibo(n - 1) + fibo(n - 2); } -fibo(3) \ No newline at end of file +fibo(10) diff --git a/src/ast.rs b/src/ast.rs index f67e374..a7a4536 100644 --- a/src/ast.rs +++ b/src/ast.rs @@ -6,8 +6,8 @@ use libm::floor; use crate::{util::Boxable, Context, EvalError, FunImpl, Function, Value}; use chumsky::{ error::Simple, - prelude::{end, just, none_of, one_of, recursive, Recursive}, - text::TextParser, + prelude::{end, filter, just, none_of, one_of, recursive, Recursive}, + text::whitespace, Parser, }; use hashbrown::HashMap; @@ -17,8 +17,23 @@ extern crate alloc; pub trait Parse: Parser> + Clone + 'static {} impl> + Clone + 'static, O> Parse for T {} +fn pad(parser: impl Parse) -> impl Parse { + let comment = just("//") + .ignore_then(none_of("\n").repeated()) + .ignore_then(just("\n")) + .ignored(); + + let padding = filter(|c| char::is_whitespace(*c)) + .ignored() + .or(comment) + .repeated() + .ignored() + .or(whitespace().ignored()); + padding.clone().ignore_then(parser).then_ignore(padding) +} + fn lx(word: &'static str) -> impl Parse<&'static str> { - just(word).padded().labelled("token") + pad(just(word)).labelled("token") } fn id() -> impl Parse { @@ -82,8 +97,8 @@ pub struct FunDef { impl FunDef { pub fn parser_def(instr: impl Parse, expr: impl Parse) -> impl Parse<(String, Self)> { - let arguments = id().padded().separated_by(lx(",")); - (lx("fn").ignore_then(id().padded())) + let arguments = pad(id()).separated_by(lx(",")); + (lx("fn").ignore_then(pad(id()))) .then(lx("(").ignore_then(arguments).then_ignore(lx(")"))) .then(lx("{").ignore_then(Block::parser(instr, expr)).then_ignore(lx("}"))) .map(|((id, args), body)| (id, Self { args, body })) @@ -91,7 +106,7 @@ impl FunDef { } pub fn parser_lamb(instr: impl Parse, expr: impl Parse) -> impl Parse { - let arguments = id().padded().separated_by(lx(",")); + let arguments = pad(id()).separated_by(lx(",")); (lx("(").ignore_then(arguments).then_ignore(lx(")"))) .then_ignore(lx("=>")) .then(lx("{").ignore_then(Block::parser(instr, expr)).then_ignore(lx("}"))) @@ -248,31 +263,41 @@ pub enum Expr { impl Expr { pub fn parser(instr: impl Parse) -> impl Parse { recursive(|expr: Recursive<'_, _, Self, _>| { - let left = (Litteral::parser(instr, expr.clone()).map(Self::Litteral)) + let atom = (Litteral::parser(instr, expr.clone()).map(Self::Litteral)) .or((lx("(").ignore_then(expr.clone()).then_ignore(lx(")"))).map(|e| Self::Parens(e.to_box()))) .or((UniOp::parser().then(expr.clone())).map(|(o, e)| Self::UniOp(o, e.to_box()))) - .or(id().map(Self::Var).padded()); + .or(pad(id()).map(Self::Var)); - (left + let call = atom .clone() - .then(Op::parser().then(expr.clone()).repeated().at_least(1))) - .map(|(f, o)| Self::BinOps(f.to_box(), o)) - .or((left.clone()) - .then_ignore(lx(".")) - .then(id().padded()) - .map(|(e, a)| Self::Access(e.to_box(), a))) - .or((left.clone()) .then_ignore(lx("(")) .then(expr.clone().separated_by(lx(","))) .then_ignore(lx(")")) - .map(|(e, a)| Self::Call(e.to_box(), a))) - .or((left.clone()) + .map(|(e, a)| Self::Call(e.to_box(), a)) + .or(atom); + + let index = call + .clone() .then_ignore(lx("[")) .then(expr.clone()) .then_ignore(lx("]")) - .map(|(e, i)| Self::Index(e.to_box(), i.to_box()))) - .or(left) - .labelled("expression") + .map(|(e, i)| Self::Index(e.to_box(), i.to_box())) + .or(call); + + let access = index + .clone() + .then_ignore(lx(".")) + .then(pad(id())) + .map(|(e, a)| Self::Access(e.to_box(), a)) + .or(index); + + let ops = access + .clone() + .then(Op::parser().then(expr.clone()).repeated().at_least(1)) + .map(|(f, o)| Self::BinOps(f.to_box(), o)) + .or(access); + + ops.labelled("expression") }) }