diff --git a/src/parser.rs b/src/parser.rs index 7f4a722..e42452b 100644 --- a/src/parser.rs +++ b/src/parser.rs @@ -1,11 +1,19 @@ //! Parse the ast over at [`crate::ast`]. //! -//! Rules of thumb: -//! - Everything `pub` should return a [`BoxedParser`]. -//! - Everything not used outside a module should not be `pub`. It can always be -//! made public later. +//! # Rules +//! +//! - Public parser functions must return [`basic::EParser`]. +//! - Public parser functions must receive public subparsers via their arguments. +//! - Each public parser function must be called exactly once, inside this file. +//! - Non-public parser functions may receive and return `impl Parser<...>`. +//! +//! # Warning +//! +//! `clippy::redundant_clone` has stopped working in this module and its +//! submodules. I have no idea why. -// TODO Turn multiple calls to subparsers into clone-s +// TODO https://github.com/rust-lang/rust/issues/63063 +// TODO Find out why clippy::redundant_clone stopped working mod basic; mod expr; @@ -24,5 +32,45 @@ use crate::ast::Expr; use self::basic::Error; pub fn parser() -> impl Parser { - recursive(expr::expr).padded().then_ignore(end()) + let space = basic::space(); + let ident = basic::ident(); + let local = basic::local(space.clone()); + let table_pattern = table_destr::table_pattern(space.clone(), ident.clone()); + + let expr = recursive(|expr| { + let expr = expr.boxed(); + + let table_lit_elem = lit::table_lit_elem(space.clone(), ident.clone(), expr.clone()); + let lit = lit::lit(space.clone(), table_lit_elem.clone()); + let var = var::var(space.clone(), ident.clone(), local.clone(), expr.clone()); + let table_constr = table_constr::table_constr(space.clone(), table_lit_elem, expr.clone()); + let table_destr = table_destr::table_destr( + space.clone(), + local.clone(), + table_pattern.clone(), + expr.clone(), + ); + let func_def = func_defs::func_def( + space.clone(), + ident.clone(), + local, + table_pattern, + expr.clone(), + ); + let atom = expr::atom( + space.clone(), + lit, + var, + table_constr.clone(), + table_destr, + func_def, + expr.clone(), + ); + let suffixed = suffix::suffixed(space.clone(), ident, table_constr, atom, expr); + let prefixed = prefix::prefixed(space.clone(), suffixed); + + expr::expr(space, prefixed) + }); + + expr.padded().then_ignore(end()) } diff --git a/src/parser/basic.rs b/src/parser/basic.rs index d40bc0e..5a951dd 100644 --- a/src/parser/basic.rs +++ b/src/parser/basic.rs @@ -7,8 +7,7 @@ use crate::ast::{Ident, Line, Space}; use crate::span::Span; pub type Error = Simple; - -// TODO https://github.com/rust-lang/rust/issues/63063 +pub type EParser = BoxedParser<'static, char, O, Error>; fn inline() -> impl Parser { filter(|c: &char| c.is_whitespace() && *c != '\n') @@ -32,7 +31,7 @@ fn line() -> impl Parser { empty.or(comment) } -pub fn space() -> BoxedParser<'static, char, Space, Error> { +pub fn space() -> EParser { inline() .ignore_then(line()) .repeated() @@ -41,7 +40,7 @@ pub fn space() -> BoxedParser<'static, char, Space, Error> { .boxed() } -pub fn ident() -> BoxedParser<'static, char, Ident, Error> { +pub fn ident() -> EParser { text::ident() .try_map(|name, span| { if matches!( @@ -56,6 +55,6 @@ pub fn ident() -> BoxedParser<'static, char, Ident, Error> { .boxed() } -pub fn local() -> BoxedParser<'static, char, Option, Error> { - text::keyword("local").ignore_then(space()).or_not().boxed() +pub fn local(space: EParser) -> EParser> { + text::keyword("local").ignore_then(space).or_not().boxed() } diff --git a/src/parser/expr.rs b/src/parser/expr.rs index 2636268..3bae445 100644 --- a/src/parser/expr.rs +++ b/src/parser/expr.rs @@ -2,25 +2,19 @@ use chumsky::prelude::*; -use crate::ast::{BinOp, Expr}; +use crate::ast::{BinOp, Expr, FuncDef, Lit, Space, TableConstr, TableDestr, Var}; use crate::span::HasSpan; -use super::basic::{space, Error}; -use super::func_defs::func_def; -use super::lit::lit; -use super::prefix::prefixed; -use super::suffix::suffixed; -use super::table_constr::table_constr; -use super::table_destr::table_destr; -use super::var::var; +use super::basic::{EParser, Error}; fn atom_paren( - expr: impl Parser + Clone, + space: EParser, + expr: EParser, ) -> impl Parser + Clone { just('(') - .ignore_then(space()) + .ignore_then(space.clone()) .then(expr) - .then(space()) + .then(space) .then_ignore(just(')')) .map_with_span(|((s0, inner), s1), span| Expr::Paren { s0, @@ -30,33 +24,39 @@ fn atom_paren( }) } -fn atom( - expr: impl Parser + Clone + 'static, -) -> impl Parser + Clone { - let lit = lit(expr.clone()).map(Expr::Lit); - let var = var(expr.clone()).map(Expr::Var); - let table_constr = table_constr(expr.clone()).map(Expr::TableConstr); - let table_destr = table_destr(expr.clone()).map(Expr::TableDestr); - let func_def = func_def(expr.clone()).map(Expr::FuncDef); - let paren = atom_paren(expr.clone()); +pub fn atom( + space: EParser, + lit: EParser, + var: EParser, + table_constr: EParser, + table_destr: EParser, + func_def: EParser, + expr: EParser, +) -> EParser { + let lit = lit.map(Expr::Lit); + let var = var.map(Expr::Var); + let table_constr = table_constr.map(Expr::TableConstr); + let table_destr = table_destr.map(Expr::TableDestr); + let func_def = func_def.map(Expr::FuncDef); + let paren = atom_paren(space, expr); - let base = lit - .or(paren) + lit.or(paren) .or(table_destr) .or(table_constr) .or(func_def) - .or(var); - - prefixed(suffixed(base, expr)) + .or(var) + .boxed() } fn left_assoc( + space: EParser, op: impl Parser + 'static, over: impl Parser + Clone + 'static, -) -> BoxedParser<'static, char, Expr, Error> { - let op_over = space() +) -> EParser { + let op_over = space + .clone() .then(op) - .then(space()) + .then(space) .then(over.clone()) .map(|(((s0, op), s1), right)| (s0, op, s1, right)); @@ -73,14 +73,15 @@ fn left_assoc( } fn right_assoc( + space: EParser, op: impl Parser + 'static, over: impl Parser + Clone + 'static, ) -> BoxedParser<'static, char, Expr, Error> { let over_op = over .clone() - .then(space()) + .then(space.clone()) .then(op) - .then(space()) + .then(space) .map(|(((left, s0), op), s1)| (left, s0, op, s1)); over_op @@ -97,9 +98,7 @@ fn right_assoc( .boxed() } -pub fn expr( - expr: impl Parser + Clone + 'static, -) -> BoxedParser<'static, char, Expr, Error> { +pub fn expr(space: EParser, prefixed: EParser) -> EParser { // * / % let op_prec_4 = (just('*').to(BinOp::Mul)) .or(just('/').to(BinOp::Div)) @@ -123,12 +122,19 @@ pub fn expr( let op_prec_0 = text::keyword("or").to(BinOp::Or); right_assoc( + space.clone(), op_prec_0, right_assoc( + space.clone(), op_prec_1, left_assoc( + space.clone(), op_prec_2, - left_assoc(op_prec_3, left_assoc(op_prec_4, atom(expr))), + left_assoc( + space.clone(), + op_prec_3, + left_assoc(space, op_prec_4, prefixed), + ), ), ), ) diff --git a/src/parser/func_defs.rs b/src/parser/func_defs.rs index 0662aed..e290b95 100644 --- a/src/parser/func_defs.rs +++ b/src/parser/func_defs.rs @@ -1,19 +1,21 @@ +// TODO Rename this module to func_def for consistency + use chumsky::prelude::*; -use crate::ast::{Expr, FuncDef}; +use crate::ast::{Expr, FuncDef, Ident, Space, TablePattern}; -use super::basic::{ident, local, space, Error}; -use super::table_destr::table_pattern; +use super::basic::{EParser, Error}; fn func_def_anon_no_arg( - expr: impl Parser, + space: EParser, + expr: EParser, ) -> impl Parser { text::keyword("function") - .ignore_then(space()) + .ignore_then(space.clone()) .then_ignore(just('(')) - .then(space()) + .then(space.clone()) .then_ignore(just(')')) - .then(space()) + .then(space) .then(expr) .map_with_span(|(((s0, s1), s2), body), span| FuncDef::AnonNoArg { s0, @@ -25,16 +27,18 @@ fn func_def_anon_no_arg( } fn func_def_anon_arg( - expr: impl Parser, + space: EParser, + ident: EParser, + expr: EParser, ) -> impl Parser { text::keyword("function") - .ignore_then(space()) + .ignore_then(space.clone()) .then_ignore(just('(')) - .then(space()) - .then(ident()) - .then(space()) + .then(space.clone()) + .then(ident) + .then(space.clone()) .then_ignore(just(')')) - .then(space()) + .then(space) .then(expr) .map_with_span( |(((((s0, s1), arg), s2), s3), body), span| FuncDef::AnonArg { @@ -50,12 +54,14 @@ fn func_def_anon_arg( } fn func_def_anon_destr( - expr: impl Parser, + space: EParser, + table_pattern: EParser, + expr: EParser, ) -> impl Parser { text::keyword("function") - .ignore_then(space()) - .then(table_pattern()) - .then(space()) + .ignore_then(space.clone()) + .then(table_pattern) + .then(space) .then(expr) .map_with_span(|(((s0, pattern), s1), body), span| FuncDef::AnonDestr { s0, @@ -67,17 +73,20 @@ fn func_def_anon_destr( } fn func_def_named_no_arg( - expr: impl Parser, + space: EParser, + ident: EParser, + local: EParser>, + expr: EParser, ) -> impl Parser { - local() + local .then_ignore(text::keyword("function")) - .then(space()) - .then(ident()) - .then(space()) + .then(space.clone()) + .then(ident) + .then(space.clone()) .then_ignore(just('(')) - .then(space()) + .then(space.clone()) .then_ignore(just(')')) - .then(space()) + .then(space) .then(expr) .map_with_span( |((((((local, s0), name), s1), s2), s3), body), span| FuncDef::NamedNoArg { @@ -94,19 +103,22 @@ fn func_def_named_no_arg( } fn func_def_named_arg( - expr: impl Parser, + space: EParser, + ident: EParser, + local: EParser>, + expr: EParser, ) -> impl Parser { - local() + local .then_ignore(text::keyword("function")) - .then(space()) - .then(ident()) - .then(space()) + .then(space.clone()) + .then(ident.clone()) + .then(space.clone()) .then_ignore(just('(')) - .then(space()) - .then(ident()) - .then(space()) + .then(space.clone()) + .then(ident) + .then(space.clone()) .then_ignore(just(')')) - .then(space()) + .then(space) .then(expr) .map_with_span( |((((((((local, s0), name), s1), s2), arg), s3), s4), body), span| FuncDef::NamedArg { @@ -125,15 +137,19 @@ fn func_def_named_arg( } fn func_def_named_destr( - expr: impl Parser, + space: EParser, + ident: EParser, + local: EParser>, + table_pattern: EParser, + expr: EParser, ) -> impl Parser { - local() + local .then_ignore(text::keyword("function")) - .then(space()) - .then(ident()) - .then(space()) - .then(table_pattern()) - .then(space()) + .then(space.clone()) + .then(ident) + .then(space.clone()) + .then(table_pattern) + .then(space) .then(expr) .map_with_span(|((((((local, s0), name), s1), pattern), s2), body), span| { FuncDef::NamedDestr { @@ -150,13 +166,35 @@ fn func_def_named_destr( } pub fn func_def( - expr: impl Parser + Clone + 'static, -) -> BoxedParser<'static, char, FuncDef, Error> { - func_def_anon_no_arg(expr.clone()) - .or(func_def_anon_arg(expr.clone())) - .or(func_def_anon_destr(expr.clone())) - .or(func_def_named_no_arg(expr.clone())) - .or(func_def_named_arg(expr.clone())) - .or(func_def_named_destr(expr)) + space: EParser, + ident: EParser, + local: EParser>, + table_pattern: EParser, + expr: EParser, +) -> EParser { + let anon_no_arg = func_def_anon_no_arg(space.clone(), expr.clone()); + let anon_arg = func_def_anon_arg(space.clone(), ident.clone(), expr.clone()); + let anon_destr = + func_def_anon_destr(space.clone(), table_pattern.clone(), expr.clone().clone()); + let named_no_arg = func_def_named_no_arg( + space.clone(), + ident.clone(), + local.clone(), + expr.clone().clone(), + ); + let named_arg = func_def_named_arg( + space.clone(), + ident.clone(), + local.clone(), + expr.clone().clone(), + ); + let named_destr = func_def_named_destr(space, ident, local, table_pattern, expr); + + anon_no_arg + .or(anon_arg) + .or(anon_destr) + .or(named_no_arg) + .or(named_arg) + .or(named_destr) .boxed() } diff --git a/src/parser/lit.rs b/src/parser/lit.rs index 8325a38..206fb41 100644 --- a/src/parser/lit.rs +++ b/src/parser/lit.rs @@ -2,10 +2,10 @@ use chumsky::prelude::*; -use crate::ast::{Expr, Lit, NumLit, NumLitStr, StringLit, TableLit, TableLitElem}; +use crate::ast::{Expr, Ident, Lit, NumLit, NumLitStr, Space, StringLit, TableLit, TableLitElem}; use crate::builtin::Builtin; -use super::basic::{ident, space, Error}; +use super::basic::{EParser, Error}; fn builtin_lit() -> impl Parser { just('\'').ignore_then(choice(( @@ -84,16 +84,18 @@ fn string_lit() -> impl Parser { } pub fn table_lit_elem( - expr: impl Parser + Clone + 'static, -) -> BoxedParser<'static, char, TableLitElem, Error> { + space: EParser, + ident: EParser, + expr: EParser, +) -> EParser { let positional = expr .clone() .map(|value| TableLitElem::Positional(Box::new(value))); - let named = ident() - .then(space()) + let named = ident + .then(space.clone()) .then_ignore(just(':')) - .then(space()) + .then(space) .then(expr) .map_with_span(|(((name, s0), s1), value), span| TableLitElem::Named { name, @@ -107,14 +109,16 @@ pub fn table_lit_elem( } fn table_lit( - expr: impl Parser + Clone + 'static, + space: EParser, + table_lit_elem: EParser, ) -> impl Parser { - let elem = space() - .then(table_lit_elem(expr)) - .then(space()) + let elem = space + .clone() + .then(table_lit_elem) + .then(space.clone()) .map(|((s0, elem), s1)| (s0, elem, s1)); - let trailing_comma = just(',').ignore_then(space()).or_not(); + let trailing_comma = just(',').ignore_then(space).or_not(); let elems = elem.separated_by(just(',')).then(trailing_comma); @@ -128,16 +132,14 @@ fn table_lit( }) } -pub fn lit( - expr: impl Parser + Clone + 'static, -) -> BoxedParser<'static, char, Lit, Error> { +pub fn lit(space: EParser, table_lit_elem: EParser) -> EParser { let nil = text::keyword("nil").map_with_span(|_, span| Lit::Nil(span)); let r#true = text::keyword("true").map_with_span(|_, span| Lit::Bool(true, span)); let r#false = text::keyword("false").map_with_span(|_, span| Lit::Bool(false, span)); let builtin = builtin_lit().map_with_span(Lit::Builtin); let num = num_lit().map(Lit::Num); let string = string_lit().map(Lit::String); - let table = table_lit(expr).map(Lit::Table); + let table = table_lit(space, table_lit_elem).map(Lit::Table); nil.or(r#true) .or(r#false) diff --git a/src/parser/prefix.rs b/src/parser/prefix.rs index fadb81d..ddae0bd 100644 --- a/src/parser/prefix.rs +++ b/src/parser/prefix.rs @@ -5,7 +5,7 @@ use chumsky::prelude::*; use crate::ast::{Expr, Space}; use crate::span::{HasSpan, Span}; -use super::basic::{space, Error}; +use super::basic::{EParser, Error}; enum Prefix { /// See [`Expr::Neg`]. @@ -35,25 +35,23 @@ impl Prefix { } } -fn prefix_neg() -> impl Parser { +fn prefix_neg(space: EParser) -> impl Parser { just('-') .map_with_span(|_, span| span) - .then(space()) + .then(space) .map(|(minus, s0)| Prefix::Neg { minus, s0 }) } -fn prefix_not() -> impl Parser { +fn prefix_not(space: EParser) -> impl Parser { text::keyword("not") .map_with_span(|_, span| span) - .then(space()) + .then(space) .map(|(not, s0)| Prefix::Not { not, s0 }) } -pub fn prefixed( - suffixed: impl Parser + 'static, -) -> BoxedParser<'static, char, Expr, Error> { - let prefix = prefix_neg() - .or(prefix_not()) +pub fn prefixed(space: EParser, suffixed: EParser) -> EParser { + let prefix = prefix_neg(space.clone()) + .or(prefix_not(space)) .map_with_span(|prefix, span| (prefix, span)); prefix diff --git a/src/parser/suffix.rs b/src/parser/suffix.rs index 00436f3..6c10491 100644 --- a/src/parser/suffix.rs +++ b/src/parser/suffix.rs @@ -5,8 +5,7 @@ use chumsky::prelude::*; use crate::ast::{Call, Expr, Field, Ident, Space, TableConstr}; use crate::span::{HasSpan, Span}; -use super::basic::{ident, space, Error}; -use super::table_constr::table_constr; +use super::basic::{EParser, Error}; enum Suffix { /// See [`Call::Arg`]. @@ -131,13 +130,15 @@ impl Suffix { } fn suffix_call_arg( - expr: impl Parser, + space: EParser, + expr: EParser, ) -> impl Parser { - space() + space + .clone() .then_ignore(just('(')) - .then(space()) + .then(space.clone()) .then(expr) - .then(space()) + .then(space) .then_ignore(just(')')) .map(|(((s0, s1), arg), s2)| Suffix::CallArg { s0, @@ -147,30 +148,34 @@ fn suffix_call_arg( }) } -fn suffix_call_no_arg() -> impl Parser { - space() +fn suffix_call_no_arg(space: EParser) -> impl Parser { + space + .clone() .then_ignore(just('(')) - .then(space()) + .then(space) .then_ignore(just(')')) .map(|(s0, s1)| Suffix::CallNoArg { s0, s1 }) } fn suffix_call_constr( - expr: impl Parser + Clone + 'static, + space: EParser, + table_constr: EParser, ) -> impl Parser { - space() - .then(table_constr(expr)) + space + .then(table_constr) .map(|(s0, constr)| Suffix::CallConstr { s0, constr }) } fn suffix_field_access( - expr: impl Parser, + space: EParser, + expr: EParser, ) -> impl Parser { - space() + space + .clone() .then_ignore(just('[')) - .then(space()) + .then(space.clone()) .then(expr) - .then(space()) + .then(space) .then_ignore(just(']')) .map(|(((s0, s1), index), s2)| Suffix::FieldAccess { s0, @@ -181,17 +186,19 @@ fn suffix_field_access( } fn suffix_field_assign( - expr: impl Parser + Clone, + space: EParser, + expr: EParser, ) -> impl Parser { - space() + space + .clone() .then_ignore(just('[')) - .then(space()) + .then(space.clone()) .then(expr.clone()) - .then(space()) + .then(space.clone()) .then_ignore(just(']')) - .then(space()) + .then(space.clone()) .then_ignore(just('=')) - .then(space()) + .then(space) .then(expr) .map( |((((((s0, s1), index), s2), s3), s4), value)| Suffix::FieldAssign { @@ -206,24 +213,31 @@ fn suffix_field_assign( ) } -fn suffix_field_access_ident() -> impl Parser { - space() +fn suffix_field_access_ident( + space: EParser, + ident: EParser, +) -> impl Parser { + space + .clone() .then_ignore(just('.')) - .then(space()) - .then(ident()) + .then(space) + .then(ident) .map(|((s0, s1), ident)| Suffix::FieldAccessIdent { s0, s1, ident }) } fn suffix_field_assign_ident( - expr: impl Parser, + space: EParser, + ident: EParser, + expr: EParser, ) -> impl Parser { - space() + space + .clone() .then_ignore(just('.')) - .then(space()) - .then(ident()) - .then(space()) + .then(space.clone()) + .then(ident) + .then(space.clone()) .then_ignore(just('=')) - .then(space()) + .then(space) .then(expr) .map( |(((((s0, s1), ident), s2), s3), value)| Suffix::FieldAssignIdent { @@ -238,16 +252,19 @@ fn suffix_field_assign_ident( } pub fn suffixed( - atom: impl Parser + 'static, - expr: impl Parser + Clone + 'static, -) -> BoxedParser<'static, char, Expr, Error> { - let call_arg = suffix_call_arg(expr.clone()); - let call_no_arg = suffix_call_no_arg(); - let call_constr = suffix_call_constr(expr.clone()); - let field_access = suffix_field_access(expr.clone()); - let field_assign = suffix_field_assign(expr.clone()); - let field_access_ident = suffix_field_access_ident(); - let field_assign_ident = suffix_field_assign_ident(expr); + space: EParser, + ident: EParser, + table_constr: EParser, + atom: EParser, + expr: EParser, +) -> EParser { + let call_arg = suffix_call_arg(space.clone(), expr.clone()); + let call_no_arg = suffix_call_no_arg(space.clone()); + let call_constr = suffix_call_constr(space.clone(), table_constr); + let field_access = suffix_field_access(space.clone(), expr.clone()); + let field_assign = suffix_field_assign(space.clone(), expr.clone()); + let field_access_ident = suffix_field_access_ident(space.clone(), ident.clone()); + let field_assign_ident = suffix_field_assign_ident(space, ident, expr); let suffix = call_arg .or(call_no_arg) diff --git a/src/parser/table_constr.rs b/src/parser/table_constr.rs index 25cf684..ac0bb04 100644 --- a/src/parser/table_constr.rs +++ b/src/parser/table_constr.rs @@ -2,24 +2,25 @@ use chumsky::prelude::*; -use crate::ast::{Expr, TableConstr, TableConstrElem}; +use crate::ast::{Expr, Space, TableConstr, TableConstrElem, TableLitElem}; -use super::basic::{space, Error}; -use super::lit::table_lit_elem; +use super::basic::{EParser, Error}; fn table_constr_elem( - expr: impl Parser + Clone + 'static, + space: EParser, + table_lit_elem: EParser, + expr: EParser, ) -> impl Parser { - let lit = table_lit_elem(expr.clone()).map(TableConstrElem::Lit); + let lit = table_lit_elem.map(TableConstrElem::Lit); let indexed = just('[') - .ignore_then(space()) + .ignore_then(space.clone()) .then(expr.clone()) - .then(space()) + .then(space.clone()) .then_ignore(just(']')) - .then(space()) + .then(space.clone()) .then_ignore(just(':')) - .then(space()) + .then(space) .then(expr) .map_with_span( |(((((s0, index), s1), s2), s3), value), span| TableConstrElem::Indexed { @@ -37,14 +38,17 @@ fn table_constr_elem( } pub fn table_constr( - expr: impl Parser + Clone + 'static, -) -> BoxedParser<'static, char, TableConstr, Error> { - let elem = space() - .then(table_constr_elem(expr)) - .then(space()) + space: EParser, + table_lit_elem: EParser, + expr: EParser, +) -> EParser { + let elem = space + .clone() + .then(table_constr_elem(space.clone(), table_lit_elem, expr)) + .then(space.clone()) .map(|((s0, elem), s1)| (s0, elem, s1)); - let trailing_comma = just(',').ignore_then(space()).or_not(); + let trailing_comma = just(',').ignore_then(space).or_not(); let elems = elem.separated_by(just(',')).then(trailing_comma); diff --git a/src/parser/table_destr.rs b/src/parser/table_destr.rs index eda0532..dfde71e 100644 --- a/src/parser/table_destr.rs +++ b/src/parser/table_destr.rs @@ -2,18 +2,22 @@ use chumsky::prelude::*; -use crate::ast::{Expr, TableDestr, TablePattern, TablePatternElem}; +use crate::ast::{Expr, Ident, Space, TableDestr, TablePattern, TablePatternElem}; -use super::basic::{ident, space, Error}; +use super::basic::{EParser, Error}; -fn table_pattern_elem() -> impl Parser { - let positional = ident().map(TablePatternElem::Positional); +fn table_pattern_elem( + space: EParser, + ident: EParser, +) -> impl Parser { + let positional = ident.clone().map(TablePatternElem::Positional); - let named = ident() - .then(space()) + let named = ident + .clone() + .then(space.clone()) .then_ignore(just(':')) - .then(space()) - .then(ident()) + .then(space) + .then(ident) .map_with_span(|(((name, s0), s1), ident), span| TablePatternElem::Named { name, s0, @@ -25,13 +29,14 @@ fn table_pattern_elem() -> impl Parser { named.or(positional) } -pub fn table_pattern() -> BoxedParser<'static, char, TablePattern, Error> { - let elem = space() - .then(table_pattern_elem()) - .then(space()) +pub fn table_pattern(space: EParser, ident: EParser) -> EParser { + let elem = space + .clone() + .then(table_pattern_elem(space.clone(), ident)) + .then(space.clone()) .map(|((s0, elem), s1)| (s0, elem, s1)); - let trailing_comma = just(',').ignore_then(space()).or_not(); + let trailing_comma = just(',').ignore_then(space).or_not(); let elems = elem.separated_by(just(',')).then(trailing_comma); @@ -47,15 +52,16 @@ pub fn table_pattern() -> BoxedParser<'static, char, TablePattern, Error> { } pub fn table_destr( - expr: impl Parser + 'static, -) -> BoxedParser<'static, char, TableDestr, Error> { - let local = text::keyword("local").ignore_then(space()).or_not(); - + space: EParser, + local: EParser>, + table_pattern: EParser, + expr: EParser, +) -> EParser { local - .then(table_pattern()) - .then(space()) + .then(table_pattern) + .then(space.clone()) .then_ignore(just('=')) - .then(space()) + .then(space) .then(expr) .map_with_span(|((((local, pattern), s0), s1), value), span| TableDestr { local, diff --git a/src/parser/var.rs b/src/parser/var.rs index 9946d87..80722e1 100644 --- a/src/parser/var.rs +++ b/src/parser/var.rs @@ -2,17 +2,15 @@ use chumsky::prelude::*; -use crate::ast::{Expr, Var}; +use crate::ast::{Expr, Ident, Space, Var}; -use super::basic::{ident, local, space, Error}; +use super::basic::{EParser, Error}; -fn var_access( - expr: impl Parser, -) -> impl Parser { +fn var_access(space: EParser, expr: EParser) -> impl Parser { just('[') - .ignore_then(space()) + .ignore_then(space.clone()) .then(expr) - .then(space()) + .then(space) .then_ignore(just(']')) .map_with_span(|((s0, index), s1), span| Var::Access { s0, @@ -23,17 +21,19 @@ fn var_access( } fn var_assign( - expr: impl Parser + Clone, + space: EParser, + local: EParser>, + expr: EParser, ) -> impl Parser { - local() + local .then_ignore(just('[')) - .then(space()) + .then(space.clone()) .then(expr.clone()) - .then(space()) + .then(space.clone()) .then_ignore(just(']')) - .then(space()) + .then(space.clone()) .then_ignore(just('=')) - .then(space()) + .then(space) .then(expr) .map_with_span( |((((((local, s0), index), s1), s2), s3), value), span| Var::Assign { @@ -50,13 +50,16 @@ fn var_assign( } fn var_assign_ident( - expr: impl Parser, + space: EParser, + ident: EParser, + local: EParser>, + expr: EParser, ) -> impl Parser { - local() - .then(ident()) - .then(space()) + local + .then(ident) + .then(space.clone()) .then_ignore(just('=')) - .then(space()) + .then(space) .then(expr) .map_with_span( |((((local, name), s0), s1), value), span| Var::AssignIdent { @@ -71,12 +74,15 @@ fn var_assign_ident( } pub fn var( - expr: impl Parser + Clone + 'static, -) -> BoxedParser<'static, char, Var, Error> { - let access = var_access(expr.clone()); - let assign = var_assign(expr.clone()); - let access_ident = ident().map(Var::AccessIdent); - let assign_ident = var_assign_ident(expr); + space: EParser, + ident: EParser, + local: EParser>, + expr: EParser, +) -> EParser { + let access = var_access(space.clone(), expr.clone()); + let assign = var_assign(space.clone(), local.clone(), expr.clone()); + let access_ident = ident.clone().map(Var::AccessIdent); + let assign_ident = var_assign_ident(space, ident, local, expr); assign.or(access).or(assign_ident).or(access_ident).boxed() }