tamer: asg::air: Begin to derive context from stack

This begins to introduce `AirStack` and starts to migrate context away from
the individual `ParseState`s onto the stack.

I should have started to commit earlier; this is getting a bit large and
makes it hard to follow what I'm doing so, hopefully stopping a little bit
short will allow the following commit to show that.

This is a work-in-progress change.  All tests pass, but the refactoring is
incomplete.  The `AirStack` abstraction is _also_ incomplete and will have
better, more domain-specific operations that make it harder to mess up
pairing pushes with pops.

The purpose of doing this is to allow `AirAggregate` to serve exclusively as
a sum state, which can then become a SuperState, much like `ele_parse!`'s
approach.

The _end_ goal of all of this is arbitrary template nesting.

DEV-13708
main
Mike Gerwitz 2023-03-28 16:14:09 -04:00
parent 2ae33a1dfa
commit 1ef1290ee9
4 changed files with 197 additions and 192 deletions

View File

@ -37,7 +37,10 @@
use self::expr::AirExprAggregateReachable;
use super::{graph::object::Pkg, Asg, AsgError, ObjectIndex};
use super::{
graph::object::{ObjectIndexTo, Pkg, Tpl},
Asg, AsgError, Ident, ObjectIndex,
};
use crate::{
diagnose::Annotate, diagnostic_todo, parse::prelude::*, sym::SymbolId,
};
@ -77,11 +80,7 @@ pub enum AirAggregate {
/// 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>,
AirExprAggregateReachable<Pkg>,
AirTplAggregate<Pkg>,
),
PkgTpl(ObjectIndex<Pkg>, AirTplAggregate),
}
impl Display for AirAggregate {
@ -96,7 +95,7 @@ impl Display for AirAggregate {
PkgExpr(_, expr) => {
write!(f, "defining a package expression: {expr}")
}
PkgTpl(_, _, tpl) => {
PkgTpl(_, tpl) => {
write!(f, "building a template: {tpl}",)
}
}
@ -159,6 +158,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()
@ -167,23 +167,23 @@ impl ParseState for AirAggregate {
// TODO: This is temporary during refactoring
// (creating an AirExprAggregate just to pass to this).
(Toplevel(oi_pkg), tok @ AirTpl(..)) => Transition(PkgTpl(
oi_pkg,
AirExprAggregate::new_in(oi_pkg),
AirTplAggregate::new(oi_pkg, oi_pkg),
))
.incomplete()
.with_lookahead(tok),
(Toplevel(oi_pkg), tok @ AirTpl(..)) => {
ctx.stack_mut().push(Toplevel(oi_pkg));
Transition(PkgTpl(oi_pkg, 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(..)) => Transition(PkgTpl(
oi_pkg,
expr,
AirTplAggregate::new(oi_pkg, oi_pkg),
))
.incomplete()
.with_lookahead(tok),
(PkgExpr(oi_pkg, expr), tok @ AirTpl(..)) => {
ctx.stack_mut().push(PkgExpr(oi_pkg, expr));
Transition(PkgTpl(oi_pkg, AirTplAggregate::new()))
.incomplete()
.with_lookahead(tok)
}
// Note: We unfortunately can't match on `AirExpr | AirBind`
// and delegate in the same block
@ -198,14 +198,14 @@ impl ParseState for AirAggregate {
}
// Template parsing.
(PkgTpl(oi_pkg, stored_expr, tplst), AirExpr(ttok)) => {
Self::delegate_tpl(ctx, oi_pkg, stored_expr, tplst, ttok)
(PkgTpl(oi_pkg, tplst), AirExpr(ttok)) => {
Self::delegate_tpl(ctx, oi_pkg, tplst, ttok)
}
(PkgTpl(oi_pkg, stored_expr, tplst), AirBind(ttok)) => {
Self::delegate_tpl(ctx, oi_pkg, stored_expr, tplst, ttok)
(PkgTpl(oi_pkg, tplst), AirBind(ttok)) => {
Self::delegate_tpl(ctx, oi_pkg, tplst, ttok)
}
(PkgTpl(oi_pkg, stored_expr, tplst), AirTpl(ttok)) => {
Self::delegate_tpl(ctx, oi_pkg, stored_expr, tplst, ttok)
(PkgTpl(oi_pkg, tplst), AirTpl(ttok)) => {
Self::delegate_tpl(ctx, oi_pkg, tplst, ttok)
}
(PkgTpl(..), tok @ AirPkg(PkgStart(..))) => {
@ -231,12 +231,13 @@ impl ParseState for AirAggregate {
}
}
(PkgTpl(oi_pkg, stored_expr, tplst), AirPkg(PkgEnd(span))) => {
(PkgTpl(oi_pkg, tplst), AirPkg(PkgEnd(span))) => {
match tplst.is_accepting(ctx) {
true => Transition(PkgExpr(oi_pkg, stored_expr))
// TODO
true => Transition(ctx.stack_mut().pop().expect("TODO"))
.incomplete()
.with_lookahead(AirPkg(PkgEnd(span))),
false => Transition(PkgTpl(oi_pkg, stored_expr, tplst))
false => Transition(PkgTpl(oi_pkg, tplst))
.err(AsgError::InvalidPkgEndContext(span)),
}
}
@ -291,15 +292,17 @@ impl AirAggregate {
/// TODO: This ought to be further reduced into primitives in the core
/// [`crate::parse`] framework.
fn delegate_expr(
asg: &mut <Self as ParseState>::Context,
ctx: &mut <Self as ParseState>::Context,
oi_pkg: ObjectIndex<Pkg>,
expr: AirExprAggregateReachable<Pkg>,
etok: impl Into<<AirExprAggregateReachable<Pkg> as ParseState>::Token>,
) -> TransitionResult<Self> {
let tok = etok.into();
expr.parse_token(tok, asg).branch_dead::<Self, _>(
|_, ()| Transition(Self::Toplevel(oi_pkg)).incomplete(),
expr.parse_token(tok, ctx).branch_dead::<Self, _>(
|_, ()| {
Transition(ctx.stack_mut().pop().expect("TODO")).incomplete()
},
|expr, result, ()| {
result
.map(ParseStatus::reflexivity)
@ -317,22 +320,21 @@ impl AirAggregate {
/// allowing parsing to continue where it left off before being
/// preempted by template parsing.
fn delegate_tpl(
asg: &mut <Self as ParseState>::Context,
ctx: &mut <Self as ParseState>::Context,
oi_pkg: ObjectIndex<Pkg>,
stored_expr: AirExprAggregateReachable<Pkg>,
tplst: AirTplAggregate<Pkg>,
ttok: impl Into<<AirTplAggregate<Pkg> as ParseState>::Token>,
tplst: AirTplAggregate,
ttok: impl Into<<AirTplAggregate as ParseState>::Token>,
) -> TransitionResult<Self> {
tplst.parse_token(ttok.into(), asg).branch_dead::<Self, _>(
|_, stored_expr| {
Transition(Self::PkgExpr(oi_pkg, stored_expr)).incomplete()
tplst.parse_token(ttok.into(), ctx).branch_dead::<Self, _>(
|_, ()| {
Transition(ctx.stack_mut().pop().expect("TODO")).incomplete()
},
|tplst, result, stored_expr| {
|tplst, result, ()| {
result
.map(ParseStatus::reflexivity)
.transition(Self::PkgTpl(oi_pkg, stored_expr, tplst))
.transition(Self::PkgTpl(oi_pkg, tplst))
},
stored_expr,
(),
)
}
}
@ -342,18 +344,22 @@ impl AirAggregate {
/// TODO: This was introduced to hold additional context;
/// see future commit.
#[derive(Debug, Default)]
pub struct AirAggregateCtx(Asg);
pub struct AirAggregateCtx(Asg, AirStack);
impl AirAggregateCtx {
fn asg_mut(&mut self) -> &mut Asg {
self.as_mut()
}
fn stack_mut(&mut self) -> &mut AirStack {
self.as_mut()
}
}
impl AsRef<Asg> for AirAggregateCtx {
fn as_ref(&self) -> &Asg {
match self {
Self(asg) => asg,
Self(asg, _) => asg,
}
}
}
@ -361,7 +367,15 @@ impl AsRef<Asg> for AirAggregateCtx {
impl AsMut<Asg> for AirAggregateCtx {
fn as_mut(&mut self) -> &mut Asg {
match self {
Self(asg) => asg,
Self(asg, _) => asg,
}
}
}
impl AsMut<AirStack> for AirAggregateCtx {
fn as_mut(&mut self) -> &mut AirStack {
match self {
Self(_, stack) => stack,
}
}
}
@ -369,14 +383,66 @@ impl AsMut<Asg> for AirAggregateCtx {
impl From<AirAggregateCtx> for Asg {
fn from(ctx: AirAggregateCtx) -> Self {
match ctx {
AirAggregateCtx(asg) => asg,
AirAggregateCtx(asg, _) => asg,
}
}
}
impl From<Asg> for AirAggregateCtx {
fn from(asg: Asg) -> Self {
Self(asg)
Self(asg, Default::default())
}
}
/// Held parser stack frames.
///
/// TODO: This is still under development.
#[derive(Debug, Default)]
pub struct AirStack(Vec<AirAggregate>);
impl AirStack {
fn push(&mut self, st: AirAggregate) {
let Self(stack) = self;
stack.push(st);
}
fn pop(&mut self) -> Option<AirAggregate> {
let Self(stack) = self;
stack.pop()
}
/// The active container (binding context) for [`Ident`]s.
///
/// A value of [`None`] indicates that no bindings are permitted in the
/// current context.
fn rooting_oi(&self) -> Option<ObjectIndexTo<Ident>> {
let Self(stack) = self;
match *stack.last()? {
AirAggregate::Empty => None,
AirAggregate::Toplevel(pkg_oi) => Some(pkg_oi.into()),
AirAggregate::PkgExpr(pkg_oi, _) => Some(pkg_oi.into()),
AirAggregate::PkgTpl(_, _) => {
diagnostic_todo!(vec![], "PkgTpl rooting_oi")
}
}
}
/// The active expansion target (splicing context) for [`Tpl`]s.
///
/// A value of [`None`] indicates that template expansion is not
/// permitted in this current context.
fn expansion_oi(&self) -> Option<ObjectIndexTo<Tpl>> {
let Self(stack) = self;
match *stack.last()? {
AirAggregate::Empty => None,
AirAggregate::Toplevel(pkg_oi) => Some(pkg_oi.into()),
AirAggregate::PkgExpr(pkg_oi, _) => Some(pkg_oi.into()),
AirAggregate::PkgTpl(_, _) => {
diagnostic_todo!(vec![], "PkgTpl expansion_oi")
}
}
}
}

View File

@ -31,7 +31,7 @@ use super::{
};
use crate::{
asg::{
graph::object::{ObjectIndexRelTo, ObjectRelTo},
graph::object::{ObjectIndexRelTo, ObjectIndexTo, ObjectRelTo},
Ident, ObjectKind,
},
f::Functor,
@ -102,7 +102,7 @@ impl<O: ObjectKind, S: RootStrategy<O>> ParseState for AirExprAggregate<O, S> {
use AirBindableExpr::*;
use AirExprAggregate::*;
let asg = ctx.asg_mut();
let AirAggregateCtx(asg, stack) = ctx;
match (self, tok) {
(Ready(root, es, _), AirExpr(ExprStart(op, span))) => {
@ -143,7 +143,8 @@ impl<O: ObjectKind, S: RootStrategy<O>> ParseState for AirExprAggregate<O, S> {
}
(BuildingExpr(root, es, oi), AirBind(BindIdent(id))) => {
let oi_ident = root.defines(asg, id);
let oi_root = stack.rooting_oi().expect("TODO");
let oi_ident = root.defines(asg, oi_root, id);
// It is important that we do not mark this expression as
// reachable unless we successfully bind the identifier.
@ -399,7 +400,12 @@ mod root {
///
/// This is invoked for _all_ identifiers,
/// including sub-expressions.
fn defines(&self, asg: &mut Asg, id: SPair) -> ObjectIndex<Ident>;
fn defines(
&self,
asg: &mut Asg,
oi_root: ObjectIndexTo<Ident>,
id: SPair,
) -> ObjectIndex<Ident>;
/// Hold or reject a [`Dangling`] root [`Expr`].
///
@ -442,11 +448,16 @@ mod root {
Self(oi)
}
fn defines(&self, asg: &mut Asg, id: SPair) -> ObjectIndex<Ident> {
fn defines(
&self,
asg: &mut Asg,
oi_root: ObjectIndexTo<Ident>,
id: SPair,
) -> ObjectIndex<Ident> {
match self {
Self(oi_root) => asg
Self(_oi_root) => asg
.lookup_global_or_missing(id)
.add_edge_from(asg, *oi_root, None),
.add_edge_from(asg, oi_root, None),
}
}
@ -485,7 +496,12 @@ mod root {
Self(oi)
}
fn defines(&self, asg: &mut Asg, name: SPair) -> ObjectIndex<Ident> {
fn defines(
&self,
asg: &mut Asg,
_oi_root: ObjectIndexTo<Ident>,
name: SPair,
) -> ObjectIndex<Ident> {
// This cannot simply call [`ReachableOnly`]'s `defines` because
// we cannot cache in the global environment.
// This can be realized once caching is generalized;

View File

@ -28,10 +28,7 @@ use super::{
AirAggregateCtx, AirExprAggregate,
};
use crate::{
asg::{
graph::object::{Meta, ObjectIndexRelTo, ObjectRelTo},
Ident,
},
asg::graph::object::{Meta, ObjectIndexRelTo},
diagnose::Annotate,
diagnostic_todo,
fmt::{DisplayWrapper, TtQuote},
@ -53,10 +50,7 @@ use crate::{
/// expressions just the same as [`super::AirAggregate`] does with
/// packages.
#[derive(Debug, PartialEq)]
pub enum AirTplAggregate<OR, OT = OR>
where
Self: TplEnvCtxPair<OR, OT>,
{
pub enum AirTplAggregate {
/// Ready for a template,
/// defined as part of the given package.
///
@ -65,7 +59,7 @@ where
/// AIR has no restrictions on when template header tokens are
/// provided,
/// which simplifies AIR generation.
Ready(TplEnvCtx<OR, OT>),
Ready,
/// Toplevel template context.
///
@ -73,101 +67,35 @@ where
/// tokens that are received in this state are interpreted as directly
/// applying to the template itself,
/// or creating an object directly owned by the template.
Toplevel(
TplEnvCtx<OR, OT>,
TplState,
AirExprAggregateStoreDangling<Tpl>,
),
Toplevel(TplState, AirExprAggregateStoreDangling<Tpl>),
/// Defining a template metavariable.
TplMeta(
TplEnvCtx<OR, OT>,
TplState,
AirExprAggregateStoreDangling<Tpl>,
ObjectIndex<Meta>,
),
/// Aggregating tokens into a template.
TplExpr(
TplEnvCtx<OR, OT>,
TplState,
AirExprAggregateStoreDangling<Tpl>,
),
TplExpr(TplState, AirExprAggregateStoreDangling<Tpl>),
}
impl<OR, OT> Display for AirTplAggregate<OR, OT>
where
Self: TplEnvCtxPair<OR, OT>,
{
impl Display for AirTplAggregate {
fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
match self {
Self::Ready(_) => write!(f, "ready for template definition"),
Self::Ready => write!(f, "ready for template definition"),
Self::Toplevel(_, tpl, expr) | Self::TplExpr(_, tpl, expr) => {
Self::Toplevel(tpl, expr) | Self::TplExpr(tpl, expr) => {
write!(f, "building {tpl} with {expr}")
}
Self::TplMeta(_, tpl, _, _) => {
Self::TplMeta(tpl, _, _) => {
write!(f, "building {tpl} metavariable")
}
}
}
}
/// Environment context for template application.
///
/// The _root_ `OR` represents a container for [`Ident`]s to named templates
/// produced by [`AirTplAggregate`].
///
/// The _expansion target_ `OT` is where template applications will expand
/// into when referenced.
/// Note that templates defined _within_ a template will receive a different
/// expansion target,
/// determined by [`AirTplAggregate``].
#[derive(Debug, PartialEq)]
pub struct TplEnvCtx<OR, OT>(ObjectIndex<OR>, ObjectIndex<OT>)
where
Self: TplEnvCtxPair<OR, OT>;
// At the time of writing (2023-03),
// deriving these macros places `Clone`/`Copy` trait bounds on each of
// `OR` and `OT`,
// which is nonsense.
impl<OR, OT> Clone for TplEnvCtx<OR, OT>
where
Self: TplEnvCtxPair<OR, OT>,
{
fn clone(&self) -> Self {
Self(self.0, self.1)
}
}
impl<OR, OT> Copy for TplEnvCtx<OR, OT> where Self: TplEnvCtxPair<OR, OT> {}
impl<OR, OT> TplEnvCtx<OR, OT>
where
Self: TplEnvCtxPair<OR, OT>,
{
pub fn defines(self, asg: &mut Asg, oi: ObjectIndex<Ident>) -> Self {
match self {
Self(oi_root, oi_target) => {
Self(oi_root.defines(asg, oi), oi_target)
}
}
}
pub fn oi_target(&self) -> ObjectIndex<OT> {
match self {
Self(_, oi_target) => *oi_target,
}
}
}
/// More concisely represent trait bounds for [`TplEnvCtx`].
pub trait TplEnvCtxPair<OR, OT> = Sized
where
OR: ObjectRelTo<Ident>,
OT: ObjectRelTo<Tpl>;
/// The current reachability status of the template.
#[derive(Debug, PartialEq, Eq, Clone, Copy)]
pub enum TplState {
@ -237,10 +165,7 @@ impl Display for TplState {
}
}
impl<OR, OT> ParseState for AirTplAggregate<OR, OT>
where
Self: TplEnvCtxPair<OR, OT>,
{
impl ParseState for AirTplAggregate {
type Token = AirTemplatable;
type Object = ();
type Error = AsgError;
@ -256,11 +181,10 @@ where
use AirTplAggregate::*;
match (self, tok) {
(Ready(ois), AirTpl(TplStart(span))) => {
(Ready, AirTpl(TplStart(span))) => {
let oi_tpl = ctx.asg_mut().create(Tpl::new(span));
Transition(Toplevel(
ois,
TplState::Dangling(oi_tpl),
AirExprAggregate::new_in(oi_tpl),
))
@ -272,33 +196,33 @@ where
"nested tpl open"
),
(Toplevel(ois, tpl, expr), AirBind(BindIdent(id))) => {
(Toplevel(tpl, expr), AirBind(BindIdent(id))) => {
let oi_root = ctx.stack_mut().rooting_oi().expect("TODO");
let asg = ctx.asg_mut();
asg.lookup_global_or_missing(id)
.bind_definition(asg, id, tpl.oi())
.map(|oi_ident| ois.defines(asg, oi_ident))
.map(|oi_ident| oi_root.defines(asg, oi_ident))
.map(|_| ())
.transition(Toplevel(ois, tpl.identify(id), expr))
.transition(Toplevel(tpl.identify(id), expr))
}
(Toplevel(ois, tpl, expr), AirBind(RefIdent(id))) => {
(Toplevel(tpl, expr), AirBind(RefIdent(id))) => {
tpl.oi().apply_named_tpl(ctx.asg_mut(), id);
Transition(Toplevel(ois, tpl, expr)).incomplete()
Transition(Toplevel(tpl, expr)).incomplete()
}
(Toplevel(ois, tpl, expr), AirTpl(TplMetaStart(span))) => {
(Toplevel(tpl, expr), AirTpl(TplMetaStart(span))) => {
let oi_meta = ctx.asg_mut().create(Meta::new_required(span));
Transition(TplMeta(ois, tpl, expr, oi_meta)).incomplete()
Transition(TplMeta(tpl, expr, oi_meta)).incomplete()
}
(TplMeta(ois, tpl, expr, oi_meta), AirTpl(TplMetaEnd(cspan))) => {
(TplMeta(tpl, expr, oi_meta), AirTpl(TplMetaEnd(cspan))) => {
oi_meta.close(ctx.asg_mut(), cspan);
Transition(Toplevel(ois, tpl, expr)).incomplete()
Transition(Toplevel(tpl, expr)).incomplete()
}
(TplMeta(ois, tpl, expr, oi_meta), AirTpl(TplLexeme(lexeme))) => {
(TplMeta(tpl, expr, oi_meta), AirTpl(TplLexeme(lexeme))) => {
Transition(TplMeta(
ois,
tpl,
expr,
oi_meta.assign_lexeme(ctx.asg_mut(), lexeme),
@ -306,9 +230,9 @@ where
.incomplete()
}
(TplMeta(ois, tpl, expr, oi_meta), AirBind(BindIdent(name))) => {
(TplMeta(tpl, expr, oi_meta), AirBind(BindIdent(name))) => {
oi_meta.identify_as_tpl_param(ctx.asg_mut(), tpl.oi(), name);
Transition(TplMeta(ois, tpl, expr, oi_meta)).incomplete()
Transition(TplMeta(tpl, expr, oi_meta)).incomplete()
}
(TplMeta(..), tok @ AirBind(RefIdent(..))) => {
@ -349,43 +273,49 @@ where
)
}
(Toplevel(ois, tpl, _expr_done), AirTpl(TplEnd(span))) => {
tpl.close(ctx.asg_mut(), span).transition(Ready(ois))
(Toplevel(tpl, _expr_done), AirTpl(TplEnd(span))) => {
tpl.close(ctx.asg_mut(), span).transition(Ready)
}
(TplExpr(ois, tpl, expr), AirTpl(TplEnd(span))) => {
(TplExpr(tpl, expr), AirTpl(TplEnd(span))) => {
// TODO: duplicated with AirAggregate
if expr.is_accepting(ctx) {
tpl.close(ctx.asg_mut(), span).transition(Ready(ois))
tpl.close(ctx.asg_mut(), span).transition(Ready)
} else {
Transition(TplExpr(ois, tpl, expr))
Transition(TplExpr(tpl, expr))
.err(AsgError::InvalidTplEndContext(span))
}
}
(Toplevel(ois, tpl, expr_done), AirTpl(TplEndRef(span))) => {
tpl.oi().expand_into(ctx.asg_mut(), ois.oi_target());
(Toplevel(tpl, expr_done), AirTpl(TplEndRef(span))) => {
let oi_target = ctx.stack_mut().expansion_oi().expect("TODO");
tpl.oi().expand_into(ctx.asg_mut(), oi_target);
Transition(Toplevel(ois, tpl.anonymous_reachable(), expr_done))
Transition(Toplevel(tpl.anonymous_reachable(), expr_done))
.incomplete()
.with_lookahead(AirTpl(TplEnd(span)))
}
(TplExpr(ois, tpl, expr_done), AirTpl(TplEndRef(span))) => {
tpl.oi().expand_into(ctx.asg_mut(), ois.oi_target());
(TplExpr(tpl, expr_done), AirTpl(TplEndRef(span))) => {
let oi_target = ctx.stack_mut().expansion_oi().expect("TODO");
tpl.oi().expand_into(ctx.asg_mut(), oi_target);
Transition(TplExpr(ois, tpl.anonymous_reachable(), expr_done))
// TODO: We have to make sure the expression ended first!
Transition(TplExpr(tpl.anonymous_reachable(), expr_done))
.incomplete()
.with_lookahead(AirTpl(TplEnd(span)))
}
(
Toplevel(ois, tpl, expr) | TplExpr(ois, tpl, expr),
AirExpr(etok),
) => Self::delegate_expr(ctx, ois, tpl, expr, etok),
(Toplevel(tpl, expr), AirExpr(etok)) => {
Self::delegate_expr(ctx, tpl, expr, etok)
}
(TplExpr(ois, tpl, expr), AirBind(etok)) => {
Self::delegate_expr(ctx, ois, tpl, expr, etok)
(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))) => {
@ -396,7 +326,7 @@ where
}
(
Ready(..) | TplExpr(..),
Ready | TplExpr(..),
tok @ AirTpl(TplMetaStart(..) | TplLexeme(..) | TplMetaEnd(..)),
) => {
diagnostic_todo!(
@ -405,36 +335,29 @@ where
)
}
(st @ Ready(..), AirTpl(TplEnd(span) | TplEndRef(span))) => {
(st @ Ready, AirTpl(TplEnd(span) | TplEndRef(span))) => {
Transition(st).err(AsgError::UnbalancedTpl(span))
}
(st @ Ready(..), tok @ (AirExpr(..) | AirBind(..))) => {
(st @ Ready, tok @ (AirExpr(..) | AirBind(..))) => {
Transition(st).dead(tok)
}
}
}
fn is_accepting(&self, _: &Self::Context) -> bool {
matches!(self, Self::Ready(..))
matches!(self, Self::Ready)
}
}
impl<OR, OT> AirTplAggregate<OR, OT>
where
Self: TplEnvCtxPair<OR, OT>,
{
pub(super) fn new(
oi_root: ObjectIndex<OR>,
oi_target: ObjectIndex<OT>,
) -> Self {
Self::Ready(TplEnvCtx(oi_root, oi_target))
impl AirTplAggregate {
pub(super) fn new() -> Self {
Self::Ready
}
/// Delegate to the expression parser [`AirExprAggregate`].
fn delegate_expr(
asg: &mut <Self as ParseState>::Context,
ois: TplEnvCtx<OR, OT>,
tpl: TplState,
expr: AirExprAggregateStoreDangling<Tpl>,
etok: impl Into<<AirExprAggregateStoreDangling<Tpl> as ParseState>::Token>,
@ -442,11 +365,11 @@ where
let tok = etok.into();
expr.parse_token(tok, asg).branch_dead::<Self, _>(
|expr, ()| Transition(Self::Toplevel(ois, tpl, expr)).incomplete(),
|expr, ()| Transition(Self::Toplevel(tpl, expr)).incomplete(),
|expr, result, ()| {
result
.map(ParseStatus::reflexivity)
.transition(Self::TplExpr(ois, tpl, expr))
.transition(Self::TplExpr(tpl, expr))
},
(),
)

View File

@ -23,7 +23,7 @@ use std::fmt::Display;
use super::{
Expr, Ident, Object, ObjectIndex, ObjectIndexRelTo, ObjectRel,
ObjectRelFrom, ObjectRelTo, ObjectRelTy, ObjectRelatable,
ObjectRelFrom, ObjectRelTy, ObjectRelatable,
};
use crate::{
asg::Asg,
@ -109,10 +109,10 @@ impl ObjectIndex<Tpl> {
/// template.
/// If this template is _not_ closed,
/// it will result in an error during evaluation.
pub fn expand_into<O: ObjectRelTo<Tpl>>(
pub fn expand_into<OP: ObjectIndexRelTo<Tpl>>(
self,
asg: &mut Asg,
oi_target_parent: ObjectIndex<O>,
oi_target_parent: OP,
) -> Self {
self.add_edge_from(asg, oi_target_parent, None)
}