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) Self::delegate_expr(asg, oi_pkg, expr, etok)
} }
// Templates can contain just about anything, // Template parsing.
// so completely hand over parsing when we're in template mode. (PkgTpl(oi_pkg, stored_expr, tplst), AirExpr(ttok)) => {
(PkgTpl(oi_pkg, stored_expr, tplst), tok) => { Self::delegate_tpl(asg, oi_pkg, stored_expr, tplst, ttok)
Self::delegate_tpl(asg, oi_pkg, stored_expr, tplst, tok.into()) }
(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(..))) => { (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(_)))) => { (Empty, tok @ (AirExpr(..) | AirBind(..) | AirTpl(TplOpen(_)))) => {
Transition(Empty).err(AsgError::PkgExpected(tok.span())) Transition(Empty).err(AsgError::PkgExpected(tok.span()))
} }
@ -287,9 +306,9 @@ impl AirAggregate {
oi_pkg: ObjectIndex<Pkg>, oi_pkg: ObjectIndex<Pkg>,
stored_expr: AirExprAggregateReachable<Pkg>, stored_expr: AirExprAggregateReachable<Pkg>,
tplst: AirTplAggregate, tplst: AirTplAggregate,
tok: Air, ttok: impl Into<<AirTplAggregate as ParseState>::Token>,
) -> TransitionResult<Self> { ) -> TransitionResult<Self> {
tplst.parse_token(tok, asg).branch_dead::<Self, _>( tplst.parse_token(ttok.into(), asg).branch_dead::<Self, _>(
|_, stored_expr| { |_, stored_expr| {
Transition(Self::PkgExpr(oi_pkg, stored_expr)).incomplete() Transition(Self::PkgExpr(oi_pkg, stored_expr)).incomplete()
}, },

View File

@ -334,6 +334,7 @@ macro_rules! sum_ir {
// subtypes. // subtypes.
$( $(
$(#[$sumattr])* $(#[$sumattr])*
#[allow(clippy::enum_variant_names)] // intentional consistency
#[derive(Debug, PartialEq)] #[derive(Debug, PartialEq)]
$sumvis enum $sumsub { $sumvis enum $sumsub {
$( $(
@ -637,4 +638,16 @@ sum_ir! {
/// This is the primary token set when parsing packages, /// This is the primary token set when parsing packages,
/// since most everything in TAMER is an expression. /// since most everything in TAMER is an expression.
pub sum enum AirBindableExpr = AirExpr | AirBind; 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, Asg, AsgError, ObjectIndex,
}, },
expr::AirExprAggregateStoreDangling, expr::AirExprAggregateStoreDangling,
Air, AirExprAggregate, ir::AirTemplatable,
AirExprAggregate,
}; };
use crate::{ use crate::{
fmt::{DisplayWrapper, TtQuote}, fmt::{DisplayWrapper, TtQuote},
@ -40,9 +41,9 @@ use crate::{
/// ///
/// - Metadata about the template, /// - Metadata about the template,
/// including its parameters; and /// including its parameters; and
/// - A collection of [`Air`] tokens representing the body of the /// - A collection of [`AirTemplatable`] tokens representing the body of
/// template that will be expanded into the application site when the /// the template that will be expanded into the application site when
/// template is applied. /// the template is applied.
/// ///
/// This contains an embedded [`AirExprAggregate`] parser for handling /// This contains an embedded [`AirExprAggregate`] parser for handling
/// expressions just the same as [`super::AirAggregate`] does with /// expressions just the same as [`super::AirAggregate`] does with
@ -98,7 +99,7 @@ impl Display for AirTplAggregate {
} }
impl ParseState for AirTplAggregate { impl ParseState for AirTplAggregate {
type Token = Air; type Token = AirTemplatable;
type Object = (); type Object = ();
type Error = AsgError; type Error = AsgError;
type Context = Asg; type Context = Asg;
@ -108,12 +109,11 @@ impl ParseState for AirTplAggregate {
tok: Self::Token, tok: Self::Token,
asg: &mut Self::Context, asg: &mut Self::Context,
) -> TransitionResult<Self::Super> { ) -> TransitionResult<Self::Super> {
use super::ir::{AirBind::*, AirSubsets::*, AirTodo::*, AirTpl::*}; use super::ir::{AirBind::*, AirTpl::*};
use AirTemplatable::*;
use AirTplAggregate::*; use AirTplAggregate::*;
match (self, tok.into()) { match (self, tok) {
(st, AirTodo(Todo(_))) => Transition(st).incomplete(),
(Ready(oi_pkg), AirTpl(TplOpen(span))) => { (Ready(oi_pkg), AirTpl(TplOpen(span))) => {
let oi_tpl = asg.create(Tpl::new(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) Toplevel(oi_pkg, oi_tpl, expr, name)
| TplExpr(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)) Transition(st).err(AsgError::UnbalancedTpl(span))
} }
( (st @ Ready(..), tok @ (AirExpr(..) | AirBind(..))) => {
st @ Ready(..), Transition(st).dead(tok)
tok @ (AirPkg(..) | AirExpr(..) | AirBind(..) | AirIdent(..)), }
) => Transition(st).dead(tok.into()),
} }
} }