tamer: asg::air::AirAggregate: Remove Pkg context from child parser states

This is more of the same of the previous commit, but in a more digestable
chunk.  We now have child states that are able to be constructed using a
simple `From`, which is important to making `AirAggregate` a `SuperState`.

This also makes `AirStack` act like a prototype chain for `ObjectIndex`es,
creating environments where context shadows.  The linear search should only
have to check the last two frames (e.g. an Expr has a parent Pkg or Tpl
context which will have a `rooting_oi` value), and this is only done during
a rooting operation.

DEV-13708
main
Mike Gerwitz 2023-03-29 09:33:40 -04:00
parent 1ef1290ee9
commit a5b4eda369
2 changed files with 70 additions and 42 deletions

View File

@ -73,14 +73,14 @@ pub enum AirAggregate {
/// This expects to inherit an [`AirExprAggregate`] from the prior state
/// so that we are not continuously re-allocating its stack for each
/// new expression root.
PkgExpr(ObjectIndex<Pkg>, AirExprAggregateReachable<Pkg>),
PkgExpr(AirExprAggregateReachable<Pkg>),
/// Parser is in template parsing mode.
///
/// All objects encountered until the closing [`Air::TplEnd`] will be
/// parented to this template rather than the parent [`Pkg`].
/// See [`Air::TplStart`] for more information.
PkgTpl(ObjectIndex<Pkg>, AirTplAggregate),
PkgTpl(AirTplAggregate),
}
impl Display for AirAggregate {
@ -92,10 +92,10 @@ impl Display for AirAggregate {
Toplevel(_) => {
write!(f, "expecting package header or an expression")
}
PkgExpr(_, expr) => {
PkgExpr(expr) => {
write!(f, "defining a package expression: {expr}")
}
PkgTpl(_, tpl) => {
PkgTpl(tpl) => {
write!(f, "building a template: {tpl}",)
}
}
@ -138,8 +138,9 @@ impl ParseState for AirAggregate {
.err(AsgError::NestedPkgStart(span, oi_pkg.span()))
}
(PkgExpr(oi_pkg, expr), AirPkg(PkgStart(span))) => {
Transition(PkgExpr(oi_pkg, expr))
(PkgExpr(expr), AirPkg(PkgStart(span))) => {
let oi_pkg = ctx.stack_mut().rooting_oi().expect("TODO");
Transition(PkgExpr(expr))
.err(AsgError::NestedPkgStart(span, oi_pkg.span()))
}
@ -160,9 +161,7 @@ impl ParseState for AirAggregate {
(Toplevel(oi_pkg), tok @ AirExpr(..)) => {
ctx.stack_mut().push(Toplevel(oi_pkg));
let expr = AirExprAggregate::new_in(oi_pkg);
Transition(PkgExpr(oi_pkg, expr))
.incomplete()
.with_lookahead(tok)
Transition(PkgExpr(expr)).incomplete().with_lookahead(tok)
}
// TODO: This is temporary during refactoring
@ -170,17 +169,17 @@ impl ParseState for AirAggregate {
(Toplevel(oi_pkg), tok @ AirTpl(..)) => {
ctx.stack_mut().push(Toplevel(oi_pkg));
Transition(PkgTpl(oi_pkg, AirTplAggregate::new()))
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(oi_pkg, expr), tok @ AirTpl(..)) => {
ctx.stack_mut().push(PkgExpr(oi_pkg, expr));
(PkgExpr(expr), tok @ AirTpl(..)) => {
ctx.stack_mut().push(PkgExpr(expr));
Transition(PkgTpl(oi_pkg, AirTplAggregate::new()))
Transition(PkgTpl(AirTplAggregate::new()))
.incomplete()
.with_lookahead(tok)
}
@ -190,22 +189,22 @@ impl ParseState for AirAggregate {
// (without having to duplicate type checks and then handle
// unreachable paths)
// because of the different inner types.
(PkgExpr(oi_pkg, expr), AirExpr(etok)) => {
Self::delegate_expr(ctx, oi_pkg, expr, etok)
(PkgExpr(expr), AirExpr(etok)) => {
Self::delegate_expr(ctx, expr, etok)
}
(PkgExpr(oi_pkg, expr), AirBind(etok)) => {
Self::delegate_expr(ctx, oi_pkg, expr, etok)
(PkgExpr(expr), AirBind(etok)) => {
Self::delegate_expr(ctx, expr, etok)
}
// Template parsing.
(PkgTpl(oi_pkg, tplst), AirExpr(ttok)) => {
Self::delegate_tpl(ctx, oi_pkg, tplst, ttok)
(PkgTpl(tplst), AirExpr(ttok)) => {
Self::delegate_tpl(ctx, tplst, ttok)
}
(PkgTpl(oi_pkg, tplst), AirBind(ttok)) => {
Self::delegate_tpl(ctx, oi_pkg, tplst, ttok)
(PkgTpl(tplst), AirBind(ttok)) => {
Self::delegate_tpl(ctx, tplst, ttok)
}
(PkgTpl(oi_pkg, tplst), AirTpl(ttok)) => {
Self::delegate_tpl(ctx, oi_pkg, tplst, ttok)
(PkgTpl(tplst), AirTpl(ttok)) => {
Self::delegate_tpl(ctx, tplst, ttok)
}
(PkgTpl(..), tok @ AirPkg(PkgStart(..))) => {
@ -219,25 +218,26 @@ impl ParseState for AirAggregate {
Transition(Empty).err(AsgError::InvalidPkgEndContext(span))
}
(PkgExpr(oi_pkg, expr), AirPkg(PkgEnd(span))) => {
(PkgExpr(expr), AirPkg(PkgEnd(span))) => {
match expr.is_accepting(ctx) {
true => {
// TODO: this is duplicated with the above
oi_pkg.close(ctx.asg_mut(), span);
Transition(Empty).incomplete()
// TODO: this is duplicated
Transition(ctx.stack_mut().pop().expect("TODO"))
.incomplete()
.with_lookahead(AirPkg(PkgEnd(span)))
}
false => Transition(PkgExpr(oi_pkg, expr))
false => Transition(PkgExpr(expr))
.err(AsgError::InvalidPkgEndContext(span)),
}
}
(PkgTpl(oi_pkg, tplst), AirPkg(PkgEnd(span))) => {
(PkgTpl(tplst), AirPkg(PkgEnd(span))) => {
match tplst.is_accepting(ctx) {
// TODO
true => Transition(ctx.stack_mut().pop().expect("TODO"))
.incomplete()
.with_lookahead(AirPkg(PkgEnd(span))),
false => Transition(PkgTpl(oi_pkg, tplst))
false => Transition(PkgTpl(tplst))
.err(AsgError::InvalidPkgEndContext(span)),
}
}
@ -293,7 +293,6 @@ impl AirAggregate {
/// [`crate::parse`] framework.
fn delegate_expr(
ctx: &mut <Self as ParseState>::Context,
oi_pkg: ObjectIndex<Pkg>,
expr: AirExprAggregateReachable<Pkg>,
etok: impl Into<<AirExprAggregateReachable<Pkg> as ParseState>::Token>,
) -> TransitionResult<Self> {
@ -306,7 +305,7 @@ impl AirAggregate {
|expr, result, ()| {
result
.map(ParseStatus::reflexivity)
.transition(Self::PkgExpr(oi_pkg, expr))
.transition(Self::PkgExpr(expr))
},
(),
)
@ -321,7 +320,6 @@ impl AirAggregate {
/// preempted by template parsing.
fn delegate_tpl(
ctx: &mut <Self as ParseState>::Context,
oi_pkg: ObjectIndex<Pkg>,
tplst: AirTplAggregate,
ttok: impl Into<<AirTplAggregate as ParseState>::Token>,
) -> TransitionResult<Self> {
@ -332,7 +330,7 @@ impl AirAggregate {
|tplst, result, ()| {
result
.map(ParseStatus::reflexivity)
.transition(Self::PkgTpl(oi_pkg, tplst))
.transition(Self::PkgTpl(tplst))
},
(),
)
@ -396,6 +394,14 @@ impl From<Asg> for AirAggregateCtx {
/// Held parser stack frames.
///
/// [`ObjectIndex`] lookups perform reverse linear searches beginning from
/// the last stack frame until a non-[`None`] value is found;
/// this creates an environment whereby inner contexts shadow outer.
/// Missing values create holes,
/// much like a prototype chain.
/// In practice,
/// this should only have to search the last two frames.
///
/// TODO: This is still under development.
#[derive(Debug, Default)]
pub struct AirStack(Vec<AirAggregate>);
@ -418,14 +424,20 @@ impl AirStack {
fn rooting_oi(&self) -> Option<ObjectIndexTo<Ident>> {
let Self(stack) = self;
match *stack.last()? {
stack.iter().rev().find_map(|st| match *st {
AirAggregate::Empty => None,
AirAggregate::Toplevel(pkg_oi) => Some(pkg_oi.into()),
AirAggregate::PkgExpr(pkg_oi, _) => Some(pkg_oi.into()),
AirAggregate::PkgTpl(_, _) => {
// Expressions never serve as roots for identifiers;
// this will always fall through to the parent context.
// Since the parent context is a package or a template,
// the next frame should succeed.
AirAggregate::PkgExpr(_) => None,
AirAggregate::PkgTpl(_) => {
diagnostic_todo!(vec![], "PkgTpl rooting_oi")
}
}
})
}
/// The active expansion target (splicing context) for [`Tpl`]s.
@ -435,14 +447,16 @@ impl AirStack {
fn expansion_oi(&self) -> Option<ObjectIndexTo<Tpl>> {
let Self(stack) = self;
match *stack.last()? {
stack.iter().rev().find_map(|st| match *st {
AirAggregate::Empty => None,
AirAggregate::Toplevel(pkg_oi) => Some(pkg_oi.into()),
AirAggregate::PkgExpr(pkg_oi, _) => Some(pkg_oi.into()),
AirAggregate::PkgTpl(_, _) => {
AirAggregate::PkgExpr(_) => {
diagnostic_todo!(vec![], "PkgExpr expansion_oi")
}
AirAggregate::PkgTpl(_) => {
diagnostic_todo!(vec![], "PkgTpl expansion_oi")
}
}
})
}
}

View File

@ -715,6 +715,12 @@ mod private {
}
}
impl<OB: ObjectRelatable> ObjectIndexTo<OB> {
pub fn span(&self) -> Span {
(*self).into()
}
}
// Deriving `Clone`/`Copy` as of 2023-03 was introducing a
// `Clone`/`Copy` bound on `OB`.
impl<OB: ObjectRelatable> Clone for ObjectIndexTo<OB> {
@ -724,4 +730,12 @@ mod private {
}
impl<OB: ObjectRelatable> Copy for ObjectIndexTo<OB> {}
impl<OB: ObjectRelatable> From<ObjectIndexTo<OB>> for Span {
fn from(oi: ObjectIndexTo<OB>) -> Self {
match oi {
ObjectIndexTo((oi, _), _) => oi.span(),
}
}
}
}