tamer: asg::air: Restrict AirTplAggregate token domain to new AirTemplatable

This removes special cases, but it does complicate the parent `AirAggregate`
parser.  A pattern of delegation is forming, though abstracting it may be an
interesting challenge, given Rust's limitation on macro invocations as match
arms.  But, I think I can manage by generating the entire match using a
macro with a match-compatible syntax, augmenting where
needed...maybe.  This'll be messy.

...but if I can write the nightmare that is `ele_parse!`, I'm sure I can
manage this.  I just prefer to avoid complex macros unless I really need
them.

DEV-13708
main
Mike Gerwitz 2023-03-11 00:40:54 -05:00
parent 2233c69bbf
commit 0e42788dcc
3 changed files with 50 additions and 27 deletions

View File

@ -187,10 +187,19 @@ impl ParseState for AirAggregate {
Self::delegate_expr(asg, oi_pkg, expr, etok)
}
// Templates can contain just about anything,
// so completely hand over parsing when we're in template mode.
(PkgTpl(oi_pkg, stored_expr, tplst), tok) => {
Self::delegate_tpl(asg, oi_pkg, stored_expr, tplst, tok.into())
// Template parsing.
(PkgTpl(oi_pkg, stored_expr, tplst), AirExpr(ttok)) => {
Self::delegate_tpl(asg, oi_pkg, stored_expr, tplst, ttok)
}
(PkgTpl(oi_pkg, stored_expr, tplst), AirBind(ttok)) => {
Self::delegate_tpl(asg, oi_pkg, stored_expr, tplst, ttok)
}
(PkgTpl(oi_pkg, stored_expr, tplst), AirTpl(ttok)) => {
Self::delegate_tpl(asg, oi_pkg, stored_expr, tplst, ttok)
}
(PkgTpl(..), AirPkg(PkgOpen(..))) => {
todo!("templates cannot contain packages")
}
(Empty, AirTpl(TplClose(..))) => {
@ -213,6 +222,16 @@ impl ParseState for AirAggregate {
}
}
(PkgTpl(oi_pkg, stored_expr, tplst), AirPkg(PkgClose(span))) => {
match tplst.is_accepting(asg) {
true => Transition(PkgExpr(oi_pkg, stored_expr))
.incomplete()
.with_lookahead(AirPkg(PkgClose(span))),
false => Transition(PkgTpl(oi_pkg, stored_expr, tplst))
.err(AsgError::InvalidPkgCloseContext(span)),
}
}
(Empty, tok @ (AirExpr(..) | AirBind(..) | AirTpl(TplOpen(_)))) => {
Transition(Empty).err(AsgError::PkgExpected(tok.span()))
}
@ -287,9 +306,9 @@ impl AirAggregate {
oi_pkg: ObjectIndex<Pkg>,
stored_expr: AirExprAggregateReachable<Pkg>,
tplst: AirTplAggregate,
tok: Air,
ttok: impl Into<<AirTplAggregate as ParseState>::Token>,
) -> TransitionResult<Self> {
tplst.parse_token(tok, asg).branch_dead::<Self, _>(
tplst.parse_token(ttok.into(), asg).branch_dead::<Self, _>(
|_, stored_expr| {
Transition(Self::PkgExpr(oi_pkg, stored_expr)).incomplete()
},

View File

@ -334,6 +334,7 @@ macro_rules! sum_ir {
// subtypes.
$(
$(#[$sumattr])*
#[allow(clippy::enum_variant_names)] // intentional consistency
#[derive(Debug, PartialEq)]
$sumvis enum $sumsub {
$(
@ -637,4 +638,16 @@ sum_ir! {
/// This is the primary token set when parsing packages,
/// since most everything in TAMER is an expression.
pub sum enum AirBindableExpr = AirExpr | AirBind;
/// Tokens that may be used to define or apply templates.
pub sum enum AirTemplatable = AirExpr | AirBind | AirTpl;
}
impl From<AirBindableExpr> for AirTemplatable {
fn from(expr: AirBindableExpr) -> Self {
match expr {
AirBindableExpr::AirExpr(x) => Self::AirExpr(x),
AirBindableExpr::AirBind(x) => Self::AirBind(x),
}
}
}

View File

@ -27,7 +27,8 @@ use super::{
Asg, AsgError, ObjectIndex,
},
expr::AirExprAggregateStoreDangling,
Air, AirExprAggregate,
ir::AirTemplatable,
AirExprAggregate,
};
use crate::{
fmt::{DisplayWrapper, TtQuote},
@ -40,9 +41,9 @@ use crate::{
///
/// - Metadata about the template,
/// including its parameters; and
/// - A collection of [`Air`] tokens representing the body of the
/// template that will be expanded into the application site when the
/// template is applied.
/// - A collection of [`AirTemplatable`] tokens representing the body of
/// the template that will be expanded into the application site when
/// the template is applied.
///
/// This contains an embedded [`AirExprAggregate`] parser for handling
/// expressions just the same as [`super::AirAggregate`] does with
@ -98,7 +99,7 @@ impl Display for AirTplAggregate {
}
impl ParseState for AirTplAggregate {
type Token = Air;
type Token = AirTemplatable;
type Object = ();
type Error = AsgError;
type Context = Asg;
@ -108,12 +109,11 @@ impl ParseState for AirTplAggregate {
tok: Self::Token,
asg: &mut Self::Context,
) -> TransitionResult<Self::Super> {
use super::ir::{AirBind::*, AirSubsets::*, AirTodo::*, AirTpl::*};
use super::ir::{AirBind::*, AirTpl::*};
use AirTemplatable::*;
use AirTplAggregate::*;
match (self, tok.into()) {
(st, AirTodo(Todo(_))) => Transition(st).incomplete(),
match (self, tok) {
(Ready(oi_pkg), AirTpl(TplOpen(span))) => {
let oi_tpl = asg.create(Tpl::new(span));
@ -161,14 +161,6 @@ impl ParseState for AirTplAggregate {
}
}
(Toplevel(..) | TplExpr(..), AirPkg(_)) => {
todo!("template cannot define packages")
}
(Toplevel(..) | TplExpr(..), AirIdent(_)) => {
todo!("linker token cannot be used in templates")
}
(
Toplevel(oi_pkg, oi_tpl, expr, name)
| TplExpr(oi_pkg, oi_tpl, expr, name),
@ -187,10 +179,9 @@ impl ParseState for AirTplAggregate {
Transition(st).err(AsgError::UnbalancedTpl(span))
}
(
st @ Ready(..),
tok @ (AirPkg(..) | AirExpr(..) | AirBind(..) | AirIdent(..)),
) => Transition(st).dead(tok.into()),
(st @ Ready(..), tok @ (AirExpr(..) | AirBind(..))) => {
Transition(st).dead(tok)
}
}
}