Parse suffixes

This commit is contained in:
Joscha 2022-11-19 11:22:49 +01:00
parent 3e2f118e2e
commit 94198d126f
2 changed files with 117 additions and 16 deletions

View file

@ -6,7 +6,7 @@ use super::{Expr, Space, TableConstr};
pub enum Call { pub enum Call {
/// `a(b)` /// `a(b)`
/// ///
/// Structure: `expr s0 ( s1 arg s2) /// Structure: `expr s0 ( s1 arg s2 )`
Arg { Arg {
expr: Box<Expr>, expr: Box<Expr>,
s0: Space, s0: Space,

View file

@ -5,9 +5,11 @@ 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::{space, Error}; use super::basic::{ident, space, Error};
use super::table_constr::table_constr;
enum Suffix { enum Suffix {
/// See [`Call::Arg`].
CallArg { CallArg {
s0: Space, s0: Space,
s1: Space, s1: Space,
@ -15,16 +17,13 @@ enum Suffix {
s2: Space, s2: Space,
}, },
CallNoArg { /// See [`Call::NoArg`].
s0: Space, CallNoArg { s0: Space, s1: Space },
s1: Space,
},
CallConstr { /// See [`Call::Constr`].
s0: Space, CallConstr { s0: Space, constr: TableConstr },
constr: TableConstr,
},
/// See [`Field::Access`].
FieldAccess { FieldAccess {
s0: Space, s0: Space,
s1: Space, s1: Space,
@ -32,6 +31,7 @@ enum Suffix {
s2: Space, s2: Space,
}, },
/// See [`Field::Assign`].
FieldAssign { FieldAssign {
s0: Space, s0: Space,
s1: Space, s1: Space,
@ -42,12 +42,10 @@ enum Suffix {
value: Box<Expr>, value: Box<Expr>,
}, },
FieldAccessIdent { /// See [`Field::AccessIdent`].
s0: Space, FieldAccessIdent { s0: Space, s1: Space, ident: Ident },
s1: Space,
ident: Ident,
},
/// See [`Field::AssignIdent`].
FieldAssignIdent { FieldAssignIdent {
s0: Space, s0: Space,
s1: Space, s1: Space,
@ -132,6 +130,39 @@ impl Suffix {
} }
} }
fn suffix_call_arg(
expr: impl Parser<char, Expr, Error = Error>,
) -> impl Parser<char, Suffix, Error = Error> {
space()
.then_ignore(just('('))
.then(space())
.then(expr)
.then(space())
.then_ignore(just(')'))
.map(|(((s0, s1), arg), s2)| Suffix::CallArg {
s0,
s1,
arg: Box::new(arg),
s2,
})
}
fn suffix_call_no_arg() -> impl Parser<char, Suffix, Error = Error> {
space()
.then_ignore(just('('))
.then(space())
.then_ignore(just(')'))
.map(|(s0, s1)| Suffix::CallNoArg { s0, s1 })
}
fn suffix_call_constr(
expr: impl Parser<char, Expr, Error = Error> + Clone,
) -> impl Parser<char, Suffix, Error = Error> {
space()
.then(table_constr(expr))
.map(|(s0, constr)| Suffix::CallConstr { s0, constr })
}
fn suffix_field_access( fn suffix_field_access(
expr: impl Parser<char, Expr, Error = Error> + Clone, expr: impl Parser<char, Expr, Error = Error> + Clone,
) -> impl Parser<char, Suffix, Error = Error> { ) -> impl Parser<char, Suffix, Error = Error> {
@ -149,13 +180,83 @@ fn suffix_field_access(
}) })
} }
fn suffix_field_assign(
expr: impl Parser<char, Expr, Error = Error> + Clone,
) -> impl Parser<char, Suffix, Error = Error> {
space()
.then_ignore(just('['))
.then(space())
.then(expr.clone())
.then(space())
.then_ignore(just(']'))
.then(space())
.then_ignore(just('='))
.then(space())
.then(expr)
.map(
|((((((s0, s1), index), s2), s3), s4), value)| Suffix::FieldAssign {
s0,
s1,
index: Box::new(index),
s2,
s3,
s4,
value: Box::new(value),
},
)
}
fn suffix_field_access_ident() -> impl Parser<char, Suffix, Error = Error> {
space()
.then_ignore(just('.'))
.then(space())
.then(ident())
.map(|((s0, s1), ident)| Suffix::FieldAccessIdent { s0, s1, ident })
}
fn suffix_field_assign_ident(
expr: impl Parser<char, Expr, Error = Error>,
) -> impl Parser<char, Suffix, Error = Error> {
space()
.then_ignore(just('.'))
.then(space())
.then(ident())
.then(space())
.then_ignore(just('='))
.then(space())
.then(expr)
.map(
|(((((s0, s1), ident), s2), s3), value)| Suffix::FieldAssignIdent {
s0,
s1,
ident,
s2,
s3,
value: Box::new(value),
},
)
}
pub fn suffixed( pub fn suffixed(
atom: impl Parser<char, Expr, Error = Error>, atom: impl Parser<char, Expr, Error = Error>,
expr: impl Parser<char, Expr, Error = Error> + Clone, expr: impl Parser<char, Expr, Error = Error> + Clone,
) -> impl Parser<char, Expr, Error = Error> { ) -> impl Parser<char, Expr, Error = 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_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);
let suffix = field_access.map_with_span(|suffix, span| (suffix, span)); let suffix = call_arg
.or(call_no_arg)
.or(call_constr)
.or(field_assign)
.or(field_access)
.or(field_assign_ident)
.or(field_access_ident)
.map_with_span(|suffix, span| (suffix, span));
atom.then(suffix.repeated()) atom.then(suffix.repeated())
.foldl(|expr, (suffix, span)| suffix.into_expr(expr.span().join(span), expr)) .foldl(|expr, (suffix, span)| suffix.into_expr(expr.span().join(span), expr))