tamer: asg::air::tpl: Remove Expr delegation (move to parent)

`AirAggregate` now handles all delegation to `AirExprAggregate`.  This is
possible because `AirAggregate` is now the superstate for each of these
parsers, so `AirTplAggregate` is able to transition to a state that is not
its own.

This does not go so far as reaching the ultimate objective---having nested
template support---even though it'd be fairly simple to do now; there's
going to be a number of interesting consequences to these changes, and a bit
of cleanup is still needed, and I want tests observing this functionality to
accompany those changes.  That is: let's keep this a refactoring, to the
extent that it's possible.

Things are getting much easier to understand now, and much cleaner.

DEV-13708
main
Mike Gerwitz 2023-03-30 09:20:34 -04:00
parent c59b92370c
commit d091103983
5 changed files with 51 additions and 123 deletions

View File

@ -174,24 +174,19 @@ impl ParseState for AirAggregate {
Transition(PkgExpr(expr)).incomplete().with_lookahead(tok)
}
// TODO: This is temporary during refactoring
// (creating an AirExprAggregate just to pass to this).
(Toplevel(oi_pkg), tok @ AirTpl(..)) => {
ctx.push(Toplevel(oi_pkg));
(st @ (Toplevel(_) | PkgExpr(_)), tok @ AirTpl(..)) => {
// TODO: this call/ret needs to be part of `ctx`
if st.active_is_accepting(ctx) {
Transition(ctx.pop().expect("TODO"))
.incomplete()
.with_lookahead(tok)
} else {
ctx.push(st);
Transition(PkgTpl(AirTplAggregate::new()))
.incomplete()
.with_lookahead(tok)
}
// Note that templates may preempt expressions at any point,
// unlike in NIR at the time of writing.
(PkgExpr(expr), tok @ AirTpl(..)) => {
ctx.push(PkgExpr(expr));
Transition(PkgTpl(AirTplAggregate::new()))
.incomplete()
.with_lookahead(tok)
Transition(PkgTpl(AirTplAggregate::new()))
.incomplete()
.with_lookahead(tok)
}
}
// Note: We unfortunately can't match on `AirExpr | AirBind`
@ -306,17 +301,11 @@ impl AirAggregate {
expr: AirExprAggregate,
etok: impl Into<<AirExprAggregate as ParseState>::Token>,
) -> TransitionResult<Self> {
let tok = etok.into();
expr.parse_token(tok, ctx).branch_dead::<Self, _>(
|_, ()| Transition(ctx.pop().expect("TODO")).incomplete(),
|expr, result, ()| {
result
.map(ParseStatus::reflexivity)
.transition(Self::PkgExpr(expr))
},
(),
)
expr.delegate_child(etok.into(), ctx, |_deadst, tok, ctx| {
Transition(ctx.pop().expect("TODO"))
.incomplete()
.with_lookahead(tok)
})
}
/// Delegate to the expression parser [`AirTplAggregate`].
@ -331,15 +320,26 @@ impl AirAggregate {
tplst: AirTplAggregate,
ttok: impl Into<<AirTplAggregate as ParseState>::Token>,
) -> TransitionResult<Self> {
tplst.parse_token(ttok.into(), ctx).branch_dead::<Self, _>(
|_, ()| Transition(ctx.pop().expect("TODO")).incomplete(),
|tplst, result, ()| {
result
.map(ParseStatus::reflexivity)
.transition(Self::PkgTpl(tplst))
},
(),
)
tplst.delegate_child(ttok.into(), ctx, |_deadst, tok, ctx| {
Transition(ctx.pop().expect("TODO"))
.incomplete()
.with_lookahead(tok)
})
}
/// Whether the active parser is in an accepting state.
///
/// If a child parser is active,
/// then its [`ParseState::is_accepting`] will be consulted.
fn active_is_accepting(&self, ctx: &<Self as ParseState>::Context) -> bool {
use AirAggregate::*;
match self {
Empty => true,
Toplevel(_) => self.is_accepting(ctx),
PkgExpr(st) => st.is_accepting(ctx),
PkgTpl(st) => st.is_accepting(ctx),
}
}
}
@ -483,6 +483,12 @@ impl AirAggregateCtx {
}
}
impl AsMut<AirAggregateCtx> for AirAggregateCtx {
fn as_mut(&mut self) -> &mut AirAggregateCtx {
self
}
}
impl AsRef<Asg> for AirAggregateCtx {
fn as_ref(&self) -> &Asg {
match self {

View File

@ -27,7 +27,7 @@ use super::{
Asg, AsgError, ObjectIndex,
},
ir::AirBindableExpr,
AirAggregateCtx,
AirAggregate, AirAggregateCtx,
};
use crate::{
asg::{
@ -78,6 +78,7 @@ impl ParseState for AirExprAggregate {
type Object = ();
type Error = AsgError;
type Context = AirAggregateCtx;
type Super = AirAggregate;
fn parse_token(
self,

View File

@ -24,7 +24,7 @@
use super::{
super::{graph::object::Tpl, Asg, AsgError, ObjectIndex},
ir::AirTemplatable,
AirAggregateCtx, AirExprAggregate,
AirAggregate, AirAggregateCtx, AirExprAggregate,
};
use crate::{
asg::graph::object::{Meta, ObjectIndexRelTo},
@ -70,9 +70,6 @@ pub enum AirTplAggregate {
/// Defining a template metavariable.
TplMeta(TplState, ObjectIndex<Meta>),
/// Aggregating tokens into a template.
TplExpr(TplState, AirExprAggregate),
}
impl Display for AirTplAggregate {
@ -82,10 +79,6 @@ impl Display for AirTplAggregate {
Self::Toplevel(tpl) => write!(f, "building {tpl} at toplevel"),
Self::TplExpr(tpl, expr) => {
write!(f, "building {tpl} with {expr}")
}
Self::TplMeta(tpl, _) => {
write!(f, "building {tpl} metavariable")
}
@ -167,6 +160,7 @@ impl ParseState for AirTplAggregate {
type Object = ();
type Error = AsgError;
type Context = AirAggregateCtx;
type Super = AirAggregate;
fn parse_token(
self,
@ -266,17 +260,6 @@ impl ParseState for AirTplAggregate {
tpl.close(ctx.asg_mut(), span).transition(Ready)
}
(TplExpr(tpl, expr), AirTpl(TplEnd(span))) => {
// TODO: duplicated with AirAggregate
if expr.is_accepting(ctx) {
ctx.pop();
tpl.close(ctx.asg_mut(), span).transition(Ready)
} else {
Transition(TplExpr(tpl, expr))
.err(AsgError::InvalidTplEndContext(span))
}
}
(Toplevel(tpl), AirTpl(TplEndRef(span))) => {
let oi_target = ctx.expansion_oi().expect("TODO");
tpl.oi().expand_into(ctx.asg_mut(), oi_target);
@ -286,41 +269,16 @@ impl ParseState for AirTplAggregate {
.with_lookahead(AirTpl(TplEnd(span)))
}
(TplExpr(tpl, expr_done), AirTpl(TplEndRef(span))) => {
let oi_target = ctx.expansion_oi().expect("TODO");
tpl.oi().expand_into(ctx.asg_mut(), oi_target);
// TODO: We have to make sure the expression ended first!
Transition(TplExpr(tpl.anonymous_reachable(), expr_done))
.incomplete()
.with_lookahead(AirTpl(TplEnd(span)))
}
(Toplevel(tpl), tok @ AirExpr(_)) => {
ctx.push(Toplevel(tpl));
Transition(TplExpr(tpl, AirExprAggregate::new()))
Transition(AirExprAggregate::new())
.incomplete()
.with_lookahead(tok)
}
(TplExpr(tpl, expr), AirExpr(etok)) => {
Self::delegate_expr(ctx, tpl, expr, etok)
}
(TplExpr(tpl, expr), AirBind(etok)) => {
Self::delegate_expr(ctx, tpl, expr, etok)
}
(TplExpr(..), AirTpl(TplStart(span))) => {
diagnostic_todo!(
vec![span.note("for this token")],
"nested template (template-generated template)"
)
}
(
Ready | TplExpr(..),
Ready,
tok @ AirTpl(TplMetaStart(..) | TplLexeme(..) | TplMetaEnd(..)),
) => {
diagnostic_todo!(
@ -354,31 +312,9 @@ impl AirTplAggregate {
match self {
Ready => None,
Toplevel(tplst) | TplMeta(tplst, _) | TplExpr(tplst, _) => {
Some(tplst.oi())
}
Toplevel(tplst) | TplMeta(tplst, _) => Some(tplst.oi()),
}
}
/// Delegate to the expression parser [`AirExprAggregate`].
fn delegate_expr(
asg: &mut <Self as ParseState>::Context,
tpl: TplState,
expr: AirExprAggregate,
etok: impl Into<<AirExprAggregate as ParseState>::Token>,
) -> TransitionResult<Self> {
let tok = etok.into();
expr.parse_token(tok, asg).branch_dead::<Self, _>(
|_, ()| Transition(Self::Toplevel(tpl)).incomplete(),
|expr, result, ()| {
result
.map(ParseStatus::reflexivity)
.transition(Self::TplExpr(tpl, expr))
},
(),
)
}
}
#[cfg(test)]

View File

@ -320,7 +320,7 @@ fn close_tpl_mid_open() {
Ok(Parsed::Incomplete), // ExprStart
Ok(Parsed::Incomplete), // BindIdent
Err(ParseError::StateError(
AsgError::InvalidTplEndContext(S5))
AsgError::UnbalancedTpl(S5))
),
// RECOVERY
Ok(Parsed::Incomplete), // ExprEnd

View File

@ -114,10 +114,6 @@ pub enum AsgError {
///
/// Ideally this situation is syntactically invalid in a source IR.
InvalidExprRefContext(SPair),
/// Attempted to close a template when not in a template toplevel
/// context.
InvalidTplEndContext(Span),
}
impl Display for AsgError {
@ -154,9 +150,6 @@ impl Display for AsgError {
TtQuote::wrap(ident)
)
}
InvalidTplEndContext(_) => {
write!(f, "invalid context for template close",)
}
}
}
}
@ -264,14 +257,6 @@ impl Diagnostic for AsgError {
"cannot reference the value of an expression from outside \
of an expression context",
)],
InvalidTplEndContext(span) => vec![
span.error("template close was not expected here"),
span.help(
"a template must be closed at the same level of nesting \
that it was opened",
),
],
}
}
}