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-13708main
parent
c59b92370c
commit
d091103983
|
@ -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 {
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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)]
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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",
|
||||
),
|
||||
],
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue