Create each main parser only once
This commit is contained in:
parent
b291619d10
commit
ea7518b183
10 changed files with 346 additions and 222 deletions
|
|
@ -1,11 +1,19 @@
|
||||||
//! Parse the ast over at [`crate::ast`].
|
//! Parse the ast over at [`crate::ast`].
|
||||||
//!
|
//!
|
||||||
//! Rules of thumb:
|
//! # Rules
|
||||||
//! - Everything `pub` should return a [`BoxedParser`].
|
//!
|
||||||
//! - Everything not used outside a module should not be `pub`. It can always be
|
//! - Public parser functions must return [`basic::EParser`].
|
||||||
//! made public later.
|
//! - 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 basic;
|
||||||
mod expr;
|
mod expr;
|
||||||
|
|
@ -24,5 +32,45 @@ use crate::ast::Expr;
|
||||||
use self::basic::Error;
|
use self::basic::Error;
|
||||||
|
|
||||||
pub fn parser() -> impl Parser<char, Expr, Error = Error> {
|
pub fn parser() -> impl Parser<char, Expr, Error = Error> {
|
||||||
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())
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -7,8 +7,7 @@ use crate::ast::{Ident, Line, Space};
|
||||||
use crate::span::Span;
|
use crate::span::Span;
|
||||||
|
|
||||||
pub type Error = Simple<char, Span>;
|
pub type Error = Simple<char, Span>;
|
||||||
|
pub type EParser<O> = BoxedParser<'static, char, O, Error>;
|
||||||
// TODO https://github.com/rust-lang/rust/issues/63063
|
|
||||||
|
|
||||||
fn inline() -> impl Parser<char, (), Error = Error> {
|
fn inline() -> impl Parser<char, (), Error = Error> {
|
||||||
filter(|c: &char| c.is_whitespace() && *c != '\n')
|
filter(|c: &char| c.is_whitespace() && *c != '\n')
|
||||||
|
|
@ -32,7 +31,7 @@ fn line() -> impl Parser<char, Line, Error = Error> {
|
||||||
empty.or(comment)
|
empty.or(comment)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn space() -> BoxedParser<'static, char, Space, Error> {
|
pub fn space() -> EParser<Space> {
|
||||||
inline()
|
inline()
|
||||||
.ignore_then(line())
|
.ignore_then(line())
|
||||||
.repeated()
|
.repeated()
|
||||||
|
|
@ -41,7 +40,7 @@ pub fn space() -> BoxedParser<'static, char, Space, Error> {
|
||||||
.boxed()
|
.boxed()
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn ident() -> BoxedParser<'static, char, Ident, Error> {
|
pub fn ident() -> EParser<Ident> {
|
||||||
text::ident()
|
text::ident()
|
||||||
.try_map(|name, span| {
|
.try_map(|name, span| {
|
||||||
if matches!(
|
if matches!(
|
||||||
|
|
@ -56,6 +55,6 @@ pub fn ident() -> BoxedParser<'static, char, Ident, Error> {
|
||||||
.boxed()
|
.boxed()
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn local() -> BoxedParser<'static, char, Option<Space>, Error> {
|
pub fn local(space: EParser<Space>) -> EParser<Option<Space>> {
|
||||||
text::keyword("local").ignore_then(space()).or_not().boxed()
|
text::keyword("local").ignore_then(space).or_not().boxed()
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -2,25 +2,19 @@
|
||||||
|
|
||||||
use chumsky::prelude::*;
|
use chumsky::prelude::*;
|
||||||
|
|
||||||
use crate::ast::{BinOp, Expr};
|
use crate::ast::{BinOp, Expr, FuncDef, Lit, Space, TableConstr, TableDestr, Var};
|
||||||
use crate::span::HasSpan;
|
use crate::span::HasSpan;
|
||||||
|
|
||||||
use super::basic::{space, Error};
|
use super::basic::{EParser, 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;
|
|
||||||
|
|
||||||
fn atom_paren(
|
fn atom_paren(
|
||||||
expr: impl Parser<char, Expr, Error = Error> + Clone,
|
space: EParser<Space>,
|
||||||
|
expr: EParser<Expr>,
|
||||||
) -> impl Parser<char, Expr, Error = Error> + Clone {
|
) -> impl Parser<char, Expr, Error = Error> + Clone {
|
||||||
just('(')
|
just('(')
|
||||||
.ignore_then(space())
|
.ignore_then(space.clone())
|
||||||
.then(expr)
|
.then(expr)
|
||||||
.then(space())
|
.then(space)
|
||||||
.then_ignore(just(')'))
|
.then_ignore(just(')'))
|
||||||
.map_with_span(|((s0, inner), s1), span| Expr::Paren {
|
.map_with_span(|((s0, inner), s1), span| Expr::Paren {
|
||||||
s0,
|
s0,
|
||||||
|
|
@ -30,33 +24,39 @@ fn atom_paren(
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
fn atom(
|
pub fn atom(
|
||||||
expr: impl Parser<char, Expr, Error = Error> + Clone + 'static,
|
space: EParser<Space>,
|
||||||
) -> impl Parser<char, Expr, Error = Error> + Clone {
|
lit: EParser<Lit>,
|
||||||
let lit = lit(expr.clone()).map(Expr::Lit);
|
var: EParser<Var>,
|
||||||
let var = var(expr.clone()).map(Expr::Var);
|
table_constr: EParser<TableConstr>,
|
||||||
let table_constr = table_constr(expr.clone()).map(Expr::TableConstr);
|
table_destr: EParser<TableDestr>,
|
||||||
let table_destr = table_destr(expr.clone()).map(Expr::TableDestr);
|
func_def: EParser<FuncDef>,
|
||||||
let func_def = func_def(expr.clone()).map(Expr::FuncDef);
|
expr: EParser<Expr>,
|
||||||
let paren = atom_paren(expr.clone());
|
) -> EParser<Expr> {
|
||||||
|
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
|
lit.or(paren)
|
||||||
.or(paren)
|
|
||||||
.or(table_destr)
|
.or(table_destr)
|
||||||
.or(table_constr)
|
.or(table_constr)
|
||||||
.or(func_def)
|
.or(func_def)
|
||||||
.or(var);
|
.or(var)
|
||||||
|
.boxed()
|
||||||
prefixed(suffixed(base, expr))
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn left_assoc(
|
fn left_assoc(
|
||||||
|
space: EParser<Space>,
|
||||||
op: impl Parser<char, BinOp, Error = Error> + 'static,
|
op: impl Parser<char, BinOp, Error = Error> + 'static,
|
||||||
over: impl Parser<char, Expr, Error = Error> + Clone + 'static,
|
over: impl Parser<char, Expr, Error = Error> + Clone + 'static,
|
||||||
) -> BoxedParser<'static, char, Expr, Error> {
|
) -> EParser<Expr> {
|
||||||
let op_over = space()
|
let op_over = space
|
||||||
|
.clone()
|
||||||
.then(op)
|
.then(op)
|
||||||
.then(space())
|
.then(space)
|
||||||
.then(over.clone())
|
.then(over.clone())
|
||||||
.map(|(((s0, op), s1), right)| (s0, op, s1, right));
|
.map(|(((s0, op), s1), right)| (s0, op, s1, right));
|
||||||
|
|
||||||
|
|
@ -73,14 +73,15 @@ fn left_assoc(
|
||||||
}
|
}
|
||||||
|
|
||||||
fn right_assoc(
|
fn right_assoc(
|
||||||
|
space: EParser<Space>,
|
||||||
op: impl Parser<char, BinOp, Error = Error> + 'static,
|
op: impl Parser<char, BinOp, Error = Error> + 'static,
|
||||||
over: impl Parser<char, Expr, Error = Error> + Clone + 'static,
|
over: impl Parser<char, Expr, Error = Error> + Clone + 'static,
|
||||||
) -> BoxedParser<'static, char, Expr, Error> {
|
) -> BoxedParser<'static, char, Expr, Error> {
|
||||||
let over_op = over
|
let over_op = over
|
||||||
.clone()
|
.clone()
|
||||||
.then(space())
|
.then(space.clone())
|
||||||
.then(op)
|
.then(op)
|
||||||
.then(space())
|
.then(space)
|
||||||
.map(|(((left, s0), op), s1)| (left, s0, op, s1));
|
.map(|(((left, s0), op), s1)| (left, s0, op, s1));
|
||||||
|
|
||||||
over_op
|
over_op
|
||||||
|
|
@ -97,9 +98,7 @@ fn right_assoc(
|
||||||
.boxed()
|
.boxed()
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn expr(
|
pub fn expr(space: EParser<Space>, prefixed: EParser<Expr>) -> EParser<Expr> {
|
||||||
expr: impl Parser<char, Expr, Error = Error> + Clone + 'static,
|
|
||||||
) -> BoxedParser<'static, char, Expr, Error> {
|
|
||||||
// * / %
|
// * / %
|
||||||
let op_prec_4 = (just('*').to(BinOp::Mul))
|
let op_prec_4 = (just('*').to(BinOp::Mul))
|
||||||
.or(just('/').to(BinOp::Div))
|
.or(just('/').to(BinOp::Div))
|
||||||
|
|
@ -123,12 +122,19 @@ pub fn expr(
|
||||||
let op_prec_0 = text::keyword("or").to(BinOp::Or);
|
let op_prec_0 = text::keyword("or").to(BinOp::Or);
|
||||||
|
|
||||||
right_assoc(
|
right_assoc(
|
||||||
|
space.clone(),
|
||||||
op_prec_0,
|
op_prec_0,
|
||||||
right_assoc(
|
right_assoc(
|
||||||
|
space.clone(),
|
||||||
op_prec_1,
|
op_prec_1,
|
||||||
left_assoc(
|
left_assoc(
|
||||||
|
space.clone(),
|
||||||
op_prec_2,
|
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),
|
||||||
|
),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
)
|
)
|
||||||
|
|
|
||||||
|
|
@ -1,19 +1,21 @@
|
||||||
|
// TODO Rename this module to func_def for consistency
|
||||||
|
|
||||||
use chumsky::prelude::*;
|
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::basic::{EParser, Error};
|
||||||
use super::table_destr::table_pattern;
|
|
||||||
|
|
||||||
fn func_def_anon_no_arg(
|
fn func_def_anon_no_arg(
|
||||||
expr: impl Parser<char, Expr, Error = Error>,
|
space: EParser<Space>,
|
||||||
|
expr: EParser<Expr>,
|
||||||
) -> impl Parser<char, FuncDef, Error = Error> {
|
) -> impl Parser<char, FuncDef, Error = Error> {
|
||||||
text::keyword("function")
|
text::keyword("function")
|
||||||
.ignore_then(space())
|
.ignore_then(space.clone())
|
||||||
.then_ignore(just('('))
|
.then_ignore(just('('))
|
||||||
.then(space())
|
.then(space.clone())
|
||||||
.then_ignore(just(')'))
|
.then_ignore(just(')'))
|
||||||
.then(space())
|
.then(space)
|
||||||
.then(expr)
|
.then(expr)
|
||||||
.map_with_span(|(((s0, s1), s2), body), span| FuncDef::AnonNoArg {
|
.map_with_span(|(((s0, s1), s2), body), span| FuncDef::AnonNoArg {
|
||||||
s0,
|
s0,
|
||||||
|
|
@ -25,16 +27,18 @@ fn func_def_anon_no_arg(
|
||||||
}
|
}
|
||||||
|
|
||||||
fn func_def_anon_arg(
|
fn func_def_anon_arg(
|
||||||
expr: impl Parser<char, Expr, Error = Error>,
|
space: EParser<Space>,
|
||||||
|
ident: EParser<Ident>,
|
||||||
|
expr: EParser<Expr>,
|
||||||
) -> impl Parser<char, FuncDef, Error = Error> {
|
) -> impl Parser<char, FuncDef, Error = Error> {
|
||||||
text::keyword("function")
|
text::keyword("function")
|
||||||
.ignore_then(space())
|
.ignore_then(space.clone())
|
||||||
.then_ignore(just('('))
|
.then_ignore(just('('))
|
||||||
.then(space())
|
.then(space.clone())
|
||||||
.then(ident())
|
.then(ident)
|
||||||
.then(space())
|
.then(space.clone())
|
||||||
.then_ignore(just(')'))
|
.then_ignore(just(')'))
|
||||||
.then(space())
|
.then(space)
|
||||||
.then(expr)
|
.then(expr)
|
||||||
.map_with_span(
|
.map_with_span(
|
||||||
|(((((s0, s1), arg), s2), s3), body), span| FuncDef::AnonArg {
|
|(((((s0, s1), arg), s2), s3), body), span| FuncDef::AnonArg {
|
||||||
|
|
@ -50,12 +54,14 @@ fn func_def_anon_arg(
|
||||||
}
|
}
|
||||||
|
|
||||||
fn func_def_anon_destr(
|
fn func_def_anon_destr(
|
||||||
expr: impl Parser<char, Expr, Error = Error>,
|
space: EParser<Space>,
|
||||||
|
table_pattern: EParser<TablePattern>,
|
||||||
|
expr: EParser<Expr>,
|
||||||
) -> impl Parser<char, FuncDef, Error = Error> {
|
) -> impl Parser<char, FuncDef, Error = Error> {
|
||||||
text::keyword("function")
|
text::keyword("function")
|
||||||
.ignore_then(space())
|
.ignore_then(space.clone())
|
||||||
.then(table_pattern())
|
.then(table_pattern)
|
||||||
.then(space())
|
.then(space)
|
||||||
.then(expr)
|
.then(expr)
|
||||||
.map_with_span(|(((s0, pattern), s1), body), span| FuncDef::AnonDestr {
|
.map_with_span(|(((s0, pattern), s1), body), span| FuncDef::AnonDestr {
|
||||||
s0,
|
s0,
|
||||||
|
|
@ -67,17 +73,20 @@ fn func_def_anon_destr(
|
||||||
}
|
}
|
||||||
|
|
||||||
fn func_def_named_no_arg(
|
fn func_def_named_no_arg(
|
||||||
expr: impl Parser<char, Expr, Error = Error>,
|
space: EParser<Space>,
|
||||||
|
ident: EParser<Ident>,
|
||||||
|
local: EParser<Option<Space>>,
|
||||||
|
expr: EParser<Expr>,
|
||||||
) -> impl Parser<char, FuncDef, Error = Error> {
|
) -> impl Parser<char, FuncDef, Error = Error> {
|
||||||
local()
|
local
|
||||||
.then_ignore(text::keyword("function"))
|
.then_ignore(text::keyword("function"))
|
||||||
.then(space())
|
.then(space.clone())
|
||||||
.then(ident())
|
.then(ident)
|
||||||
.then(space())
|
.then(space.clone())
|
||||||
.then_ignore(just('('))
|
.then_ignore(just('('))
|
||||||
.then(space())
|
.then(space.clone())
|
||||||
.then_ignore(just(')'))
|
.then_ignore(just(')'))
|
||||||
.then(space())
|
.then(space)
|
||||||
.then(expr)
|
.then(expr)
|
||||||
.map_with_span(
|
.map_with_span(
|
||||||
|((((((local, s0), name), s1), s2), s3), body), span| FuncDef::NamedNoArg {
|
|((((((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(
|
fn func_def_named_arg(
|
||||||
expr: impl Parser<char, Expr, Error = Error>,
|
space: EParser<Space>,
|
||||||
|
ident: EParser<Ident>,
|
||||||
|
local: EParser<Option<Space>>,
|
||||||
|
expr: EParser<Expr>,
|
||||||
) -> impl Parser<char, FuncDef, Error = Error> {
|
) -> impl Parser<char, FuncDef, Error = Error> {
|
||||||
local()
|
local
|
||||||
.then_ignore(text::keyword("function"))
|
.then_ignore(text::keyword("function"))
|
||||||
.then(space())
|
.then(space.clone())
|
||||||
.then(ident())
|
.then(ident.clone())
|
||||||
.then(space())
|
.then(space.clone())
|
||||||
.then_ignore(just('('))
|
.then_ignore(just('('))
|
||||||
.then(space())
|
.then(space.clone())
|
||||||
.then(ident())
|
.then(ident)
|
||||||
.then(space())
|
.then(space.clone())
|
||||||
.then_ignore(just(')'))
|
.then_ignore(just(')'))
|
||||||
.then(space())
|
.then(space)
|
||||||
.then(expr)
|
.then(expr)
|
||||||
.map_with_span(
|
.map_with_span(
|
||||||
|((((((((local, s0), name), s1), s2), arg), s3), s4), body), span| FuncDef::NamedArg {
|
|((((((((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(
|
fn func_def_named_destr(
|
||||||
expr: impl Parser<char, Expr, Error = Error>,
|
space: EParser<Space>,
|
||||||
|
ident: EParser<Ident>,
|
||||||
|
local: EParser<Option<Space>>,
|
||||||
|
table_pattern: EParser<TablePattern>,
|
||||||
|
expr: EParser<Expr>,
|
||||||
) -> impl Parser<char, FuncDef, Error = Error> {
|
) -> impl Parser<char, FuncDef, Error = Error> {
|
||||||
local()
|
local
|
||||||
.then_ignore(text::keyword("function"))
|
.then_ignore(text::keyword("function"))
|
||||||
.then(space())
|
.then(space.clone())
|
||||||
.then(ident())
|
.then(ident)
|
||||||
.then(space())
|
.then(space.clone())
|
||||||
.then(table_pattern())
|
.then(table_pattern)
|
||||||
.then(space())
|
.then(space)
|
||||||
.then(expr)
|
.then(expr)
|
||||||
.map_with_span(|((((((local, s0), name), s1), pattern), s2), body), span| {
|
.map_with_span(|((((((local, s0), name), s1), pattern), s2), body), span| {
|
||||||
FuncDef::NamedDestr {
|
FuncDef::NamedDestr {
|
||||||
|
|
@ -150,13 +166,35 @@ fn func_def_named_destr(
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn func_def(
|
pub fn func_def(
|
||||||
expr: impl Parser<char, Expr, Error = Error> + Clone + 'static,
|
space: EParser<Space>,
|
||||||
) -> BoxedParser<'static, char, FuncDef, Error> {
|
ident: EParser<Ident>,
|
||||||
func_def_anon_no_arg(expr.clone())
|
local: EParser<Option<Space>>,
|
||||||
.or(func_def_anon_arg(expr.clone()))
|
table_pattern: EParser<TablePattern>,
|
||||||
.or(func_def_anon_destr(expr.clone()))
|
expr: EParser<Expr>,
|
||||||
.or(func_def_named_no_arg(expr.clone()))
|
) -> EParser<FuncDef> {
|
||||||
.or(func_def_named_arg(expr.clone()))
|
let anon_no_arg = func_def_anon_no_arg(space.clone(), expr.clone());
|
||||||
.or(func_def_named_destr(expr))
|
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()
|
.boxed()
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -2,10 +2,10 @@
|
||||||
|
|
||||||
use chumsky::prelude::*;
|
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 crate::builtin::Builtin;
|
||||||
|
|
||||||
use super::basic::{ident, space, Error};
|
use super::basic::{EParser, Error};
|
||||||
|
|
||||||
fn builtin_lit() -> impl Parser<char, Builtin, Error = Error> {
|
fn builtin_lit() -> impl Parser<char, Builtin, Error = Error> {
|
||||||
just('\'').ignore_then(choice((
|
just('\'').ignore_then(choice((
|
||||||
|
|
@ -84,16 +84,18 @@ fn string_lit() -> impl Parser<char, StringLit, Error = Error> {
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn table_lit_elem(
|
pub fn table_lit_elem(
|
||||||
expr: impl Parser<char, Expr, Error = Error> + Clone + 'static,
|
space: EParser<Space>,
|
||||||
) -> BoxedParser<'static, char, TableLitElem, Error> {
|
ident: EParser<Ident>,
|
||||||
|
expr: EParser<Expr>,
|
||||||
|
) -> EParser<TableLitElem> {
|
||||||
let positional = expr
|
let positional = expr
|
||||||
.clone()
|
.clone()
|
||||||
.map(|value| TableLitElem::Positional(Box::new(value)));
|
.map(|value| TableLitElem::Positional(Box::new(value)));
|
||||||
|
|
||||||
let named = ident()
|
let named = ident
|
||||||
.then(space())
|
.then(space.clone())
|
||||||
.then_ignore(just(':'))
|
.then_ignore(just(':'))
|
||||||
.then(space())
|
.then(space)
|
||||||
.then(expr)
|
.then(expr)
|
||||||
.map_with_span(|(((name, s0), s1), value), span| TableLitElem::Named {
|
.map_with_span(|(((name, s0), s1), value), span| TableLitElem::Named {
|
||||||
name,
|
name,
|
||||||
|
|
@ -107,14 +109,16 @@ pub fn table_lit_elem(
|
||||||
}
|
}
|
||||||
|
|
||||||
fn table_lit(
|
fn table_lit(
|
||||||
expr: impl Parser<char, Expr, Error = Error> + Clone + 'static,
|
space: EParser<Space>,
|
||||||
|
table_lit_elem: EParser<TableLitElem>,
|
||||||
) -> impl Parser<char, TableLit, Error = Error> {
|
) -> impl Parser<char, TableLit, Error = Error> {
|
||||||
let elem = space()
|
let elem = space
|
||||||
.then(table_lit_elem(expr))
|
.clone()
|
||||||
.then(space())
|
.then(table_lit_elem)
|
||||||
|
.then(space.clone())
|
||||||
.map(|((s0, elem), s1)| (s0, elem, s1));
|
.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);
|
let elems = elem.separated_by(just(',')).then(trailing_comma);
|
||||||
|
|
||||||
|
|
@ -128,16 +132,14 @@ fn table_lit(
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn lit(
|
pub fn lit(space: EParser<Space>, table_lit_elem: EParser<TableLitElem>) -> EParser<Lit> {
|
||||||
expr: impl Parser<char, Expr, Error = Error> + Clone + 'static,
|
|
||||||
) -> BoxedParser<'static, char, Lit, Error> {
|
|
||||||
let nil = text::keyword("nil").map_with_span(|_, span| Lit::Nil(span));
|
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#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 r#false = text::keyword("false").map_with_span(|_, span| Lit::Bool(false, span));
|
||||||
let builtin = builtin_lit().map_with_span(Lit::Builtin);
|
let builtin = builtin_lit().map_with_span(Lit::Builtin);
|
||||||
let num = num_lit().map(Lit::Num);
|
let num = num_lit().map(Lit::Num);
|
||||||
let string = string_lit().map(Lit::String);
|
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)
|
nil.or(r#true)
|
||||||
.or(r#false)
|
.or(r#false)
|
||||||
|
|
|
||||||
|
|
@ -5,7 +5,7 @@ use chumsky::prelude::*;
|
||||||
use crate::ast::{Expr, Space};
|
use crate::ast::{Expr, Space};
|
||||||
use crate::span::{HasSpan, Span};
|
use crate::span::{HasSpan, Span};
|
||||||
|
|
||||||
use super::basic::{space, Error};
|
use super::basic::{EParser, Error};
|
||||||
|
|
||||||
enum Prefix {
|
enum Prefix {
|
||||||
/// See [`Expr::Neg`].
|
/// See [`Expr::Neg`].
|
||||||
|
|
@ -35,25 +35,23 @@ impl Prefix {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn prefix_neg() -> impl Parser<char, Prefix, Error = Error> {
|
fn prefix_neg(space: EParser<Space>) -> impl Parser<char, Prefix, Error = Error> {
|
||||||
just('-')
|
just('-')
|
||||||
.map_with_span(|_, span| span)
|
.map_with_span(|_, span| span)
|
||||||
.then(space())
|
.then(space)
|
||||||
.map(|(minus, s0)| Prefix::Neg { minus, s0 })
|
.map(|(minus, s0)| Prefix::Neg { minus, s0 })
|
||||||
}
|
}
|
||||||
|
|
||||||
fn prefix_not() -> impl Parser<char, Prefix, Error = Error> {
|
fn prefix_not(space: EParser<Space>) -> impl Parser<char, Prefix, Error = Error> {
|
||||||
text::keyword("not")
|
text::keyword("not")
|
||||||
.map_with_span(|_, span| span)
|
.map_with_span(|_, span| span)
|
||||||
.then(space())
|
.then(space)
|
||||||
.map(|(not, s0)| Prefix::Not { not, s0 })
|
.map(|(not, s0)| Prefix::Not { not, s0 })
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn prefixed(
|
pub fn prefixed(space: EParser<Space>, suffixed: EParser<Expr>) -> EParser<Expr> {
|
||||||
suffixed: impl Parser<char, Expr, Error = Error> + 'static,
|
let prefix = prefix_neg(space.clone())
|
||||||
) -> BoxedParser<'static, char, Expr, Error> {
|
.or(prefix_not(space))
|
||||||
let prefix = prefix_neg()
|
|
||||||
.or(prefix_not())
|
|
||||||
.map_with_span(|prefix, span| (prefix, span));
|
.map_with_span(|prefix, span| (prefix, span));
|
||||||
|
|
||||||
prefix
|
prefix
|
||||||
|
|
|
||||||
|
|
@ -5,8 +5,7 @@ use chumsky::prelude::*;
|
||||||
use crate::ast::{Call, Expr, Field, Ident, Space, TableConstr};
|
use crate::ast::{Call, Expr, Field, Ident, Space, TableConstr};
|
||||||
use crate::span::{HasSpan, Span};
|
use crate::span::{HasSpan, Span};
|
||||||
|
|
||||||
use super::basic::{ident, space, Error};
|
use super::basic::{EParser, Error};
|
||||||
use super::table_constr::table_constr;
|
|
||||||
|
|
||||||
enum Suffix {
|
enum Suffix {
|
||||||
/// See [`Call::Arg`].
|
/// See [`Call::Arg`].
|
||||||
|
|
@ -131,13 +130,15 @@ impl Suffix {
|
||||||
}
|
}
|
||||||
|
|
||||||
fn suffix_call_arg(
|
fn suffix_call_arg(
|
||||||
expr: impl Parser<char, Expr, Error = Error>,
|
space: EParser<Space>,
|
||||||
|
expr: EParser<Expr>,
|
||||||
) -> impl Parser<char, Suffix, Error = Error> {
|
) -> impl Parser<char, Suffix, Error = Error> {
|
||||||
space()
|
space
|
||||||
|
.clone()
|
||||||
.then_ignore(just('('))
|
.then_ignore(just('('))
|
||||||
.then(space())
|
.then(space.clone())
|
||||||
.then(expr)
|
.then(expr)
|
||||||
.then(space())
|
.then(space)
|
||||||
.then_ignore(just(')'))
|
.then_ignore(just(')'))
|
||||||
.map(|(((s0, s1), arg), s2)| Suffix::CallArg {
|
.map(|(((s0, s1), arg), s2)| Suffix::CallArg {
|
||||||
s0,
|
s0,
|
||||||
|
|
@ -147,30 +148,34 @@ fn suffix_call_arg(
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
fn suffix_call_no_arg() -> impl Parser<char, Suffix, Error = Error> {
|
fn suffix_call_no_arg(space: EParser<Space>) -> impl Parser<char, Suffix, Error = Error> {
|
||||||
space()
|
space
|
||||||
|
.clone()
|
||||||
.then_ignore(just('('))
|
.then_ignore(just('('))
|
||||||
.then(space())
|
.then(space)
|
||||||
.then_ignore(just(')'))
|
.then_ignore(just(')'))
|
||||||
.map(|(s0, s1)| Suffix::CallNoArg { s0, s1 })
|
.map(|(s0, s1)| Suffix::CallNoArg { s0, s1 })
|
||||||
}
|
}
|
||||||
|
|
||||||
fn suffix_call_constr(
|
fn suffix_call_constr(
|
||||||
expr: impl Parser<char, Expr, Error = Error> + Clone + 'static,
|
space: EParser<Space>,
|
||||||
|
table_constr: EParser<TableConstr>,
|
||||||
) -> impl Parser<char, Suffix, Error = Error> {
|
) -> impl Parser<char, Suffix, Error = Error> {
|
||||||
space()
|
space
|
||||||
.then(table_constr(expr))
|
.then(table_constr)
|
||||||
.map(|(s0, constr)| Suffix::CallConstr { s0, constr })
|
.map(|(s0, constr)| Suffix::CallConstr { s0, constr })
|
||||||
}
|
}
|
||||||
|
|
||||||
fn suffix_field_access(
|
fn suffix_field_access(
|
||||||
expr: impl Parser<char, Expr, Error = Error>,
|
space: EParser<Space>,
|
||||||
|
expr: EParser<Expr>,
|
||||||
) -> impl Parser<char, Suffix, Error = Error> {
|
) -> impl Parser<char, Suffix, Error = Error> {
|
||||||
space()
|
space
|
||||||
|
.clone()
|
||||||
.then_ignore(just('['))
|
.then_ignore(just('['))
|
||||||
.then(space())
|
.then(space.clone())
|
||||||
.then(expr)
|
.then(expr)
|
||||||
.then(space())
|
.then(space)
|
||||||
.then_ignore(just(']'))
|
.then_ignore(just(']'))
|
||||||
.map(|(((s0, s1), index), s2)| Suffix::FieldAccess {
|
.map(|(((s0, s1), index), s2)| Suffix::FieldAccess {
|
||||||
s0,
|
s0,
|
||||||
|
|
@ -181,17 +186,19 @@ fn suffix_field_access(
|
||||||
}
|
}
|
||||||
|
|
||||||
fn suffix_field_assign(
|
fn suffix_field_assign(
|
||||||
expr: impl Parser<char, Expr, Error = Error> + Clone,
|
space: EParser<Space>,
|
||||||
|
expr: EParser<Expr>,
|
||||||
) -> impl Parser<char, Suffix, Error = Error> {
|
) -> impl Parser<char, Suffix, Error = Error> {
|
||||||
space()
|
space
|
||||||
|
.clone()
|
||||||
.then_ignore(just('['))
|
.then_ignore(just('['))
|
||||||
.then(space())
|
.then(space.clone())
|
||||||
.then(expr.clone())
|
.then(expr.clone())
|
||||||
.then(space())
|
.then(space.clone())
|
||||||
.then_ignore(just(']'))
|
.then_ignore(just(']'))
|
||||||
.then(space())
|
.then(space.clone())
|
||||||
.then_ignore(just('='))
|
.then_ignore(just('='))
|
||||||
.then(space())
|
.then(space)
|
||||||
.then(expr)
|
.then(expr)
|
||||||
.map(
|
.map(
|
||||||
|((((((s0, s1), index), s2), s3), s4), value)| Suffix::FieldAssign {
|
|((((((s0, s1), index), s2), s3), s4), value)| Suffix::FieldAssign {
|
||||||
|
|
@ -206,24 +213,31 @@ fn suffix_field_assign(
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn suffix_field_access_ident() -> impl Parser<char, Suffix, Error = Error> {
|
fn suffix_field_access_ident(
|
||||||
space()
|
space: EParser<Space>,
|
||||||
|
ident: EParser<Ident>,
|
||||||
|
) -> impl Parser<char, Suffix, Error = Error> {
|
||||||
|
space
|
||||||
|
.clone()
|
||||||
.then_ignore(just('.'))
|
.then_ignore(just('.'))
|
||||||
.then(space())
|
.then(space)
|
||||||
.then(ident())
|
.then(ident)
|
||||||
.map(|((s0, s1), ident)| Suffix::FieldAccessIdent { s0, s1, ident })
|
.map(|((s0, s1), ident)| Suffix::FieldAccessIdent { s0, s1, ident })
|
||||||
}
|
}
|
||||||
|
|
||||||
fn suffix_field_assign_ident(
|
fn suffix_field_assign_ident(
|
||||||
expr: impl Parser<char, Expr, Error = Error>,
|
space: EParser<Space>,
|
||||||
|
ident: EParser<Ident>,
|
||||||
|
expr: EParser<Expr>,
|
||||||
) -> impl Parser<char, Suffix, Error = Error> {
|
) -> impl Parser<char, Suffix, Error = Error> {
|
||||||
space()
|
space
|
||||||
|
.clone()
|
||||||
.then_ignore(just('.'))
|
.then_ignore(just('.'))
|
||||||
.then(space())
|
.then(space.clone())
|
||||||
.then(ident())
|
.then(ident)
|
||||||
.then(space())
|
.then(space.clone())
|
||||||
.then_ignore(just('='))
|
.then_ignore(just('='))
|
||||||
.then(space())
|
.then(space)
|
||||||
.then(expr)
|
.then(expr)
|
||||||
.map(
|
.map(
|
||||||
|(((((s0, s1), ident), s2), s3), value)| Suffix::FieldAssignIdent {
|
|(((((s0, s1), ident), s2), s3), value)| Suffix::FieldAssignIdent {
|
||||||
|
|
@ -238,16 +252,19 @@ fn suffix_field_assign_ident(
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn suffixed(
|
pub fn suffixed(
|
||||||
atom: impl Parser<char, Expr, Error = Error> + 'static,
|
space: EParser<Space>,
|
||||||
expr: impl Parser<char, Expr, Error = Error> + Clone + 'static,
|
ident: EParser<Ident>,
|
||||||
) -> BoxedParser<'static, char, Expr, Error> {
|
table_constr: EParser<TableConstr>,
|
||||||
let call_arg = suffix_call_arg(expr.clone());
|
atom: EParser<Expr>,
|
||||||
let call_no_arg = suffix_call_no_arg();
|
expr: EParser<Expr>,
|
||||||
let call_constr = suffix_call_constr(expr.clone());
|
) -> EParser<Expr> {
|
||||||
let field_access = suffix_field_access(expr.clone());
|
let call_arg = suffix_call_arg(space.clone(), expr.clone());
|
||||||
let field_assign = suffix_field_assign(expr.clone());
|
let call_no_arg = suffix_call_no_arg(space.clone());
|
||||||
let field_access_ident = suffix_field_access_ident();
|
let call_constr = suffix_call_constr(space.clone(), table_constr);
|
||||||
let field_assign_ident = suffix_field_assign_ident(expr);
|
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
|
let suffix = call_arg
|
||||||
.or(call_no_arg)
|
.or(call_no_arg)
|
||||||
|
|
|
||||||
|
|
@ -2,24 +2,25 @@
|
||||||
|
|
||||||
use chumsky::prelude::*;
|
use chumsky::prelude::*;
|
||||||
|
|
||||||
use crate::ast::{Expr, TableConstr, TableConstrElem};
|
use crate::ast::{Expr, Space, TableConstr, TableConstrElem, TableLitElem};
|
||||||
|
|
||||||
use super::basic::{space, Error};
|
use super::basic::{EParser, Error};
|
||||||
use super::lit::table_lit_elem;
|
|
||||||
|
|
||||||
fn table_constr_elem(
|
fn table_constr_elem(
|
||||||
expr: impl Parser<char, Expr, Error = Error> + Clone + 'static,
|
space: EParser<Space>,
|
||||||
|
table_lit_elem: EParser<TableLitElem>,
|
||||||
|
expr: EParser<Expr>,
|
||||||
) -> impl Parser<char, TableConstrElem, Error = Error> {
|
) -> impl Parser<char, TableConstrElem, Error = Error> {
|
||||||
let lit = table_lit_elem(expr.clone()).map(TableConstrElem::Lit);
|
let lit = table_lit_elem.map(TableConstrElem::Lit);
|
||||||
|
|
||||||
let indexed = just('[')
|
let indexed = just('[')
|
||||||
.ignore_then(space())
|
.ignore_then(space.clone())
|
||||||
.then(expr.clone())
|
.then(expr.clone())
|
||||||
.then(space())
|
.then(space.clone())
|
||||||
.then_ignore(just(']'))
|
.then_ignore(just(']'))
|
||||||
.then(space())
|
.then(space.clone())
|
||||||
.then_ignore(just(':'))
|
.then_ignore(just(':'))
|
||||||
.then(space())
|
.then(space)
|
||||||
.then(expr)
|
.then(expr)
|
||||||
.map_with_span(
|
.map_with_span(
|
||||||
|(((((s0, index), s1), s2), s3), value), span| TableConstrElem::Indexed {
|
|(((((s0, index), s1), s2), s3), value), span| TableConstrElem::Indexed {
|
||||||
|
|
@ -37,14 +38,17 @@ fn table_constr_elem(
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn table_constr(
|
pub fn table_constr(
|
||||||
expr: impl Parser<char, Expr, Error = Error> + Clone + 'static,
|
space: EParser<Space>,
|
||||||
) -> BoxedParser<'static, char, TableConstr, Error> {
|
table_lit_elem: EParser<TableLitElem>,
|
||||||
let elem = space()
|
expr: EParser<Expr>,
|
||||||
.then(table_constr_elem(expr))
|
) -> EParser<TableConstr> {
|
||||||
.then(space())
|
let elem = space
|
||||||
|
.clone()
|
||||||
|
.then(table_constr_elem(space.clone(), table_lit_elem, expr))
|
||||||
|
.then(space.clone())
|
||||||
.map(|((s0, elem), s1)| (s0, elem, s1));
|
.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);
|
let elems = elem.separated_by(just(',')).then(trailing_comma);
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -2,18 +2,22 @@
|
||||||
|
|
||||||
use chumsky::prelude::*;
|
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<char, TablePatternElem, Error = Error> {
|
fn table_pattern_elem(
|
||||||
let positional = ident().map(TablePatternElem::Positional);
|
space: EParser<Space>,
|
||||||
|
ident: EParser<Ident>,
|
||||||
|
) -> impl Parser<char, TablePatternElem, Error = Error> {
|
||||||
|
let positional = ident.clone().map(TablePatternElem::Positional);
|
||||||
|
|
||||||
let named = ident()
|
let named = ident
|
||||||
.then(space())
|
.clone()
|
||||||
|
.then(space.clone())
|
||||||
.then_ignore(just(':'))
|
.then_ignore(just(':'))
|
||||||
.then(space())
|
.then(space)
|
||||||
.then(ident())
|
.then(ident)
|
||||||
.map_with_span(|(((name, s0), s1), ident), span| TablePatternElem::Named {
|
.map_with_span(|(((name, s0), s1), ident), span| TablePatternElem::Named {
|
||||||
name,
|
name,
|
||||||
s0,
|
s0,
|
||||||
|
|
@ -25,13 +29,14 @@ fn table_pattern_elem() -> impl Parser<char, TablePatternElem, Error = Error> {
|
||||||
named.or(positional)
|
named.or(positional)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn table_pattern() -> BoxedParser<'static, char, TablePattern, Error> {
|
pub fn table_pattern(space: EParser<Space>, ident: EParser<Ident>) -> EParser<TablePattern> {
|
||||||
let elem = space()
|
let elem = space
|
||||||
.then(table_pattern_elem())
|
.clone()
|
||||||
.then(space())
|
.then(table_pattern_elem(space.clone(), ident))
|
||||||
|
.then(space.clone())
|
||||||
.map(|((s0, elem), s1)| (s0, elem, s1));
|
.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);
|
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(
|
pub fn table_destr(
|
||||||
expr: impl Parser<char, Expr, Error = Error> + 'static,
|
space: EParser<Space>,
|
||||||
) -> BoxedParser<'static, char, TableDestr, Error> {
|
local: EParser<Option<Space>>,
|
||||||
let local = text::keyword("local").ignore_then(space()).or_not();
|
table_pattern: EParser<TablePattern>,
|
||||||
|
expr: EParser<Expr>,
|
||||||
|
) -> EParser<TableDestr> {
|
||||||
local
|
local
|
||||||
.then(table_pattern())
|
.then(table_pattern)
|
||||||
.then(space())
|
.then(space.clone())
|
||||||
.then_ignore(just('='))
|
.then_ignore(just('='))
|
||||||
.then(space())
|
.then(space)
|
||||||
.then(expr)
|
.then(expr)
|
||||||
.map_with_span(|((((local, pattern), s0), s1), value), span| TableDestr {
|
.map_with_span(|((((local, pattern), s0), s1), value), span| TableDestr {
|
||||||
local,
|
local,
|
||||||
|
|
|
||||||
|
|
@ -2,17 +2,15 @@
|
||||||
|
|
||||||
use chumsky::prelude::*;
|
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(
|
fn var_access(space: EParser<Space>, expr: EParser<Expr>) -> impl Parser<char, Var, Error = Error> {
|
||||||
expr: impl Parser<char, Expr, Error = Error>,
|
|
||||||
) -> impl Parser<char, Var, Error = Error> {
|
|
||||||
just('[')
|
just('[')
|
||||||
.ignore_then(space())
|
.ignore_then(space.clone())
|
||||||
.then(expr)
|
.then(expr)
|
||||||
.then(space())
|
.then(space)
|
||||||
.then_ignore(just(']'))
|
.then_ignore(just(']'))
|
||||||
.map_with_span(|((s0, index), s1), span| Var::Access {
|
.map_with_span(|((s0, index), s1), span| Var::Access {
|
||||||
s0,
|
s0,
|
||||||
|
|
@ -23,17 +21,19 @@ fn var_access(
|
||||||
}
|
}
|
||||||
|
|
||||||
fn var_assign(
|
fn var_assign(
|
||||||
expr: impl Parser<char, Expr, Error = Error> + Clone,
|
space: EParser<Space>,
|
||||||
|
local: EParser<Option<Space>>,
|
||||||
|
expr: EParser<Expr>,
|
||||||
) -> impl Parser<char, Var, Error = Error> {
|
) -> impl Parser<char, Var, Error = Error> {
|
||||||
local()
|
local
|
||||||
.then_ignore(just('['))
|
.then_ignore(just('['))
|
||||||
.then(space())
|
.then(space.clone())
|
||||||
.then(expr.clone())
|
.then(expr.clone())
|
||||||
.then(space())
|
.then(space.clone())
|
||||||
.then_ignore(just(']'))
|
.then_ignore(just(']'))
|
||||||
.then(space())
|
.then(space.clone())
|
||||||
.then_ignore(just('='))
|
.then_ignore(just('='))
|
||||||
.then(space())
|
.then(space)
|
||||||
.then(expr)
|
.then(expr)
|
||||||
.map_with_span(
|
.map_with_span(
|
||||||
|((((((local, s0), index), s1), s2), s3), value), span| Var::Assign {
|
|((((((local, s0), index), s1), s2), s3), value), span| Var::Assign {
|
||||||
|
|
@ -50,13 +50,16 @@ fn var_assign(
|
||||||
}
|
}
|
||||||
|
|
||||||
fn var_assign_ident(
|
fn var_assign_ident(
|
||||||
expr: impl Parser<char, Expr, Error = Error>,
|
space: EParser<Space>,
|
||||||
|
ident: EParser<Ident>,
|
||||||
|
local: EParser<Option<Space>>,
|
||||||
|
expr: EParser<Expr>,
|
||||||
) -> impl Parser<char, Var, Error = Error> {
|
) -> impl Parser<char, Var, Error = Error> {
|
||||||
local()
|
local
|
||||||
.then(ident())
|
.then(ident)
|
||||||
.then(space())
|
.then(space.clone())
|
||||||
.then_ignore(just('='))
|
.then_ignore(just('='))
|
||||||
.then(space())
|
.then(space)
|
||||||
.then(expr)
|
.then(expr)
|
||||||
.map_with_span(
|
.map_with_span(
|
||||||
|((((local, name), s0), s1), value), span| Var::AssignIdent {
|
|((((local, name), s0), s1), value), span| Var::AssignIdent {
|
||||||
|
|
@ -71,12 +74,15 @@ fn var_assign_ident(
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn var(
|
pub fn var(
|
||||||
expr: impl Parser<char, Expr, Error = Error> + Clone + 'static,
|
space: EParser<Space>,
|
||||||
) -> BoxedParser<'static, char, Var, Error> {
|
ident: EParser<Ident>,
|
||||||
let access = var_access(expr.clone());
|
local: EParser<Option<Space>>,
|
||||||
let assign = var_assign(expr.clone());
|
expr: EParser<Expr>,
|
||||||
let access_ident = ident().map(Var::AccessIdent);
|
) -> EParser<Var> {
|
||||||
let assign_ident = var_assign_ident(expr);
|
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()
|
assign.or(access).or(assign_ident).or(access_ident).boxed()
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue