tamer: asg::air: AirAggregateCtx: New AirAggregate::Context
Future changes to `AirAggregate` are going to require additional context (a stack, specifically), but the `Context` is currently utilized by `Asg`. This introduces a layer of abstraction that will allow us to add the stack. Alongside these changes, `ParseState` has been augmented with a `PubContext` type that is utilized on public APIs, both maintaining BC with existing code and keeping these implementation details encapsulated. This does make a bit of a mess of the internal implementation, though, with `asg_mut()` sprinkled about, so maybe the next commit can clean that up a bit. EDIT: After adding `AsMut` to a bunch of asg::graph::object::* methods, I decided against it, because it messes with the inferred ownership, requiring explicit borrows via `as_mut()` where they were not required before. I think the existing code is easier to reason about than what would otherwise result from having `mut asg: impl AsMut<Asg>` everwhere. DEV-13708main
parent
fc569f7551
commit
b1ce7aaf29
|
@ -107,16 +107,17 @@ impl ParseState for AirAggregate {
|
|||
type Token = Air;
|
||||
type Object = ();
|
||||
type Error = AsgError;
|
||||
type Context = AirAggregateCtx;
|
||||
|
||||
/// Destination [`Asg`] that this parser lowers into.
|
||||
///
|
||||
/// This ASG will be yielded by [`crate::parse::Parser::finalize`].
|
||||
type Context = Asg;
|
||||
type PubContext = Asg;
|
||||
|
||||
fn parse_token(
|
||||
self,
|
||||
tok: Self::Token,
|
||||
asg: &mut Self::Context,
|
||||
ctx: &mut Self::Context,
|
||||
) -> crate::parse::TransitionResult<Self> {
|
||||
use ir::{
|
||||
AirBind::*, AirIdent::*, AirPkg::*, AirSubsets::*, AirTodo::*,
|
||||
|
@ -128,7 +129,8 @@ impl ParseState for AirAggregate {
|
|||
(st, AirTodo(Todo(_))) => Transition(st).incomplete(),
|
||||
|
||||
(Empty, AirPkg(PkgStart(span))) => {
|
||||
let oi_pkg = asg.create(Pkg::new(span)).root(asg);
|
||||
let oi_pkg =
|
||||
ctx.asg_mut().create(Pkg::new(span)).root(ctx.asg_mut());
|
||||
Transition(Toplevel(oi_pkg, AirExprAggregate::new_in(oi_pkg)))
|
||||
.incomplete()
|
||||
}
|
||||
|
@ -145,7 +147,7 @@ impl ParseState for AirAggregate {
|
|||
|
||||
// No expression was started.
|
||||
(Toplevel(oi_pkg, _expr), AirPkg(PkgEnd(span))) => {
|
||||
oi_pkg.close(asg, span);
|
||||
oi_pkg.close(ctx.asg_mut(), span);
|
||||
Transition(Empty).incomplete()
|
||||
}
|
||||
|
||||
|
@ -182,21 +184,21 @@ impl ParseState for AirAggregate {
|
|||
// unreachable paths)
|
||||
// because of the different inner types.
|
||||
(PkgExpr(oi_pkg, expr), AirExpr(etok)) => {
|
||||
Self::delegate_expr(asg, oi_pkg, expr, etok)
|
||||
Self::delegate_expr(ctx, oi_pkg, expr, etok)
|
||||
}
|
||||
(PkgExpr(oi_pkg, expr), AirBind(etok)) => {
|
||||
Self::delegate_expr(asg, oi_pkg, expr, etok)
|
||||
Self::delegate_expr(ctx, oi_pkg, expr, etok)
|
||||
}
|
||||
|
||||
// Template parsing.
|
||||
(PkgTpl(oi_pkg, stored_expr, tplst), AirExpr(ttok)) => {
|
||||
Self::delegate_tpl(asg, oi_pkg, stored_expr, tplst, ttok)
|
||||
Self::delegate_tpl(ctx, oi_pkg, stored_expr, tplst, ttok)
|
||||
}
|
||||
(PkgTpl(oi_pkg, stored_expr, tplst), AirBind(ttok)) => {
|
||||
Self::delegate_tpl(asg, oi_pkg, stored_expr, tplst, ttok)
|
||||
Self::delegate_tpl(ctx, oi_pkg, stored_expr, tplst, ttok)
|
||||
}
|
||||
(PkgTpl(oi_pkg, stored_expr, tplst), AirTpl(ttok)) => {
|
||||
Self::delegate_tpl(asg, oi_pkg, stored_expr, tplst, ttok)
|
||||
Self::delegate_tpl(ctx, oi_pkg, stored_expr, tplst, ttok)
|
||||
}
|
||||
|
||||
(PkgTpl(..), tok @ AirPkg(PkgStart(..))) => {
|
||||
|
@ -211,10 +213,10 @@ impl ParseState for AirAggregate {
|
|||
}
|
||||
|
||||
(PkgExpr(oi_pkg, expr), AirPkg(PkgEnd(span))) => {
|
||||
match expr.is_accepting(asg) {
|
||||
match expr.is_accepting(ctx) {
|
||||
true => {
|
||||
// TODO: this is duplicated with the above
|
||||
oi_pkg.close(asg, span);
|
||||
oi_pkg.close(ctx.asg_mut(), span);
|
||||
Transition(Empty).incomplete()
|
||||
}
|
||||
false => Transition(PkgExpr(oi_pkg, expr))
|
||||
|
@ -223,7 +225,7 @@ impl ParseState for AirAggregate {
|
|||
}
|
||||
|
||||
(PkgTpl(oi_pkg, stored_expr, tplst), AirPkg(PkgEnd(span))) => {
|
||||
match tplst.is_accepting(asg) {
|
||||
match tplst.is_accepting(ctx) {
|
||||
true => Transition(PkgExpr(oi_pkg, stored_expr))
|
||||
.incomplete()
|
||||
.with_lookahead(AirPkg(PkgEnd(span))),
|
||||
|
@ -236,25 +238,31 @@ impl ParseState for AirAggregate {
|
|||
Transition(Empty).err(AsgError::PkgExpected(tok.span()))
|
||||
}
|
||||
|
||||
(Empty, AirIdent(IdentDecl(name, kind, src))) => {
|
||||
asg.declare(name, kind, src).map(|_| ()).transition(Empty)
|
||||
}
|
||||
(Empty, AirIdent(IdentDecl(name, kind, src))) => ctx
|
||||
.asg_mut()
|
||||
.declare(name, kind, src)
|
||||
.map(|_| ())
|
||||
.transition(Empty),
|
||||
|
||||
(Empty, AirIdent(IdentExternDecl(name, kind, src))) => asg
|
||||
(Empty, AirIdent(IdentExternDecl(name, kind, src))) => ctx
|
||||
.asg_mut()
|
||||
.declare_extern(name, kind, src)
|
||||
.map(|_| ())
|
||||
.transition(Empty),
|
||||
|
||||
(Empty, AirIdent(IdentDep(sym, dep))) => {
|
||||
asg.add_dep_lookup_global(sym, dep);
|
||||
ctx.asg_mut().add_dep_lookup_global(sym, dep);
|
||||
Transition(Empty).incomplete()
|
||||
}
|
||||
|
||||
(Empty, AirIdent(IdentFragment(sym, text))) => {
|
||||
asg.set_fragment(sym, text).map(|_| ()).transition(Empty)
|
||||
}
|
||||
(Empty, AirIdent(IdentFragment(sym, text))) => ctx
|
||||
.asg_mut()
|
||||
.set_fragment(sym, text)
|
||||
.map(|_| ())
|
||||
.transition(Empty),
|
||||
|
||||
(Empty, AirIdent(IdentRoot(sym))) => {
|
||||
let asg = ctx.asg_mut();
|
||||
let obj = asg.lookup_global_or_missing(sym);
|
||||
asg.add_root(obj);
|
||||
|
||||
|
@ -322,5 +330,48 @@ impl AirAggregate {
|
|||
}
|
||||
}
|
||||
|
||||
/// Additional parser context.
|
||||
///
|
||||
/// TODO: This was introduced to hold additional context;
|
||||
/// see future commit.
|
||||
#[derive(Debug, Default)]
|
||||
pub struct AirAggregateCtx(Asg);
|
||||
|
||||
impl AirAggregateCtx {
|
||||
fn asg_mut(&mut self) -> &mut Asg {
|
||||
self.as_mut()
|
||||
}
|
||||
}
|
||||
|
||||
impl AsRef<Asg> for AirAggregateCtx {
|
||||
fn as_ref(&self) -> &Asg {
|
||||
match self {
|
||||
Self(asg) => asg,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl AsMut<Asg> for AirAggregateCtx {
|
||||
fn as_mut(&mut self) -> &mut Asg {
|
||||
match self {
|
||||
Self(asg) => asg,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl From<AirAggregateCtx> for Asg {
|
||||
fn from(ctx: AirAggregateCtx) -> Self {
|
||||
match ctx {
|
||||
AirAggregateCtx(asg) => asg,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl From<Asg> for AirAggregateCtx {
|
||||
fn from(asg: Asg) -> Self {
|
||||
Self(asg)
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod test;
|
||||
|
|
|
@ -27,6 +27,7 @@ use super::{
|
|||
Asg, AsgError, ObjectIndex,
|
||||
},
|
||||
ir::AirBindableExpr,
|
||||
AirAggregateCtx,
|
||||
};
|
||||
use crate::{
|
||||
asg::{graph::object::ObjectRelTo, Ident, ObjectKind},
|
||||
|
@ -87,17 +88,19 @@ impl<O: ObjectKind, S: RootStrategy<O>> ParseState for AirExprAggregate<O, S> {
|
|||
type Token = AirBindableExpr;
|
||||
type Object = ();
|
||||
type Error = AsgError;
|
||||
type Context = Asg;
|
||||
type Context = AirAggregateCtx;
|
||||
|
||||
fn parse_token(
|
||||
self,
|
||||
tok: Self::Token,
|
||||
asg: &mut Self::Context,
|
||||
ctx: &mut Self::Context,
|
||||
) -> crate::parse::TransitionResult<Self::Super> {
|
||||
use super::ir::{AirBind::*, AirExpr::*};
|
||||
use AirBindableExpr::*;
|
||||
use AirExprAggregate::*;
|
||||
|
||||
let asg = ctx.asg_mut();
|
||||
|
||||
match (self, tok) {
|
||||
(Ready(root, es, _), AirExpr(ExprStart(op, span))) => {
|
||||
let oi = asg.create(Expr::new(op, span));
|
||||
|
|
|
@ -25,7 +25,7 @@ use super::{
|
|||
super::{graph::object::Tpl, Asg, AsgError, ObjectIndex},
|
||||
expr::AirExprAggregateStoreDangling,
|
||||
ir::AirTemplatable,
|
||||
AirExprAggregate,
|
||||
AirAggregateCtx, AirExprAggregate,
|
||||
};
|
||||
use crate::{
|
||||
asg::{
|
||||
|
@ -244,12 +244,12 @@ where
|
|||
type Token = AirTemplatable;
|
||||
type Object = ();
|
||||
type Error = AsgError;
|
||||
type Context = Asg;
|
||||
type Context = AirAggregateCtx;
|
||||
|
||||
fn parse_token(
|
||||
self,
|
||||
tok: Self::Token,
|
||||
asg: &mut Self::Context,
|
||||
ctx: &mut Self::Context,
|
||||
) -> TransitionResult<Self::Super> {
|
||||
use super::ir::{AirBind::*, AirTpl::*};
|
||||
use AirTemplatable::*;
|
||||
|
@ -257,7 +257,7 @@ where
|
|||
|
||||
match (self, tok) {
|
||||
(Ready(ois), AirTpl(TplStart(span))) => {
|
||||
let oi_tpl = asg.create(Tpl::new(span));
|
||||
let oi_tpl = ctx.asg_mut().create(Tpl::new(span));
|
||||
|
||||
Transition(Toplevel(
|
||||
ois,
|
||||
|
@ -272,24 +272,27 @@ where
|
|||
"nested tpl open"
|
||||
),
|
||||
|
||||
(Toplevel(ois, tpl, expr), AirBind(BindIdent(id))) => asg
|
||||
.lookup_global_or_missing(id)
|
||||
.bind_definition(asg, id, tpl.oi())
|
||||
.map(|oi_ident| ois.defines(asg, oi_ident))
|
||||
.map(|_| ())
|
||||
.transition(Toplevel(ois, tpl.identify(id), expr)),
|
||||
(Toplevel(ois, tpl, expr), AirBind(BindIdent(id))) => {
|
||||
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(|_| ())
|
||||
.transition(Toplevel(ois, tpl.identify(id), expr))
|
||||
}
|
||||
|
||||
(Toplevel(ois, tpl, expr), AirBind(RefIdent(id))) => {
|
||||
tpl.oi().apply_named_tpl(asg, id);
|
||||
tpl.oi().apply_named_tpl(ctx.asg_mut(), id);
|
||||
Transition(Toplevel(ois, tpl, expr)).incomplete()
|
||||
}
|
||||
|
||||
(Toplevel(ois, tpl, expr), AirTpl(TplMetaStart(span))) => {
|
||||
let oi_meta = asg.create(Meta::new_required(span));
|
||||
let oi_meta = ctx.asg_mut().create(Meta::new_required(span));
|
||||
Transition(TplMeta(ois, tpl, expr, oi_meta)).incomplete()
|
||||
}
|
||||
(TplMeta(ois, tpl, expr, oi_meta), AirTpl(TplMetaEnd(cspan))) => {
|
||||
oi_meta.close(asg, cspan);
|
||||
oi_meta.close(ctx.asg_mut(), cspan);
|
||||
Transition(Toplevel(ois, tpl, expr)).incomplete()
|
||||
}
|
||||
|
||||
|
@ -298,13 +301,13 @@ where
|
|||
ois,
|
||||
tpl,
|
||||
expr,
|
||||
oi_meta.assign_lexeme(asg, lexeme),
|
||||
oi_meta.assign_lexeme(ctx.asg_mut(), lexeme),
|
||||
))
|
||||
.incomplete()
|
||||
}
|
||||
|
||||
(TplMeta(ois, tpl, expr, oi_meta), AirBind(BindIdent(name))) => {
|
||||
oi_meta.identify_as_tpl_param(asg, tpl.oi(), name);
|
||||
oi_meta.identify_as_tpl_param(ctx.asg_mut(), tpl.oi(), name);
|
||||
Transition(TplMeta(ois, tpl, expr, oi_meta)).incomplete()
|
||||
}
|
||||
|
||||
|
@ -347,13 +350,13 @@ where
|
|||
}
|
||||
|
||||
(Toplevel(ois, tpl, _expr_done), AirTpl(TplEnd(span))) => {
|
||||
tpl.close(asg, span).transition(Ready(ois))
|
||||
tpl.close(ctx.asg_mut(), span).transition(Ready(ois))
|
||||
}
|
||||
|
||||
(TplExpr(ois, tpl, expr), AirTpl(TplEnd(span))) => {
|
||||
// TODO: duplicated with AirAggregate
|
||||
if expr.is_accepting(asg) {
|
||||
tpl.close(asg, span).transition(Ready(ois))
|
||||
if expr.is_accepting(ctx) {
|
||||
tpl.close(ctx.asg_mut(), span).transition(Ready(ois))
|
||||
} else {
|
||||
Transition(TplExpr(ois, tpl, expr))
|
||||
.err(AsgError::InvalidTplEndContext(span))
|
||||
|
@ -361,7 +364,7 @@ where
|
|||
}
|
||||
|
||||
(Toplevel(ois, tpl, expr_done), AirTpl(TplEndRef(span))) => {
|
||||
tpl.oi().expand_into(asg, ois.oi_target());
|
||||
tpl.oi().expand_into(ctx.asg_mut(), ois.oi_target());
|
||||
|
||||
Transition(Toplevel(ois, tpl.anonymous_reachable(), expr_done))
|
||||
.incomplete()
|
||||
|
@ -369,7 +372,7 @@ where
|
|||
}
|
||||
|
||||
(TplExpr(ois, tpl, expr_done), AirTpl(TplEndRef(span))) => {
|
||||
tpl.oi().expand_into(asg, ois.oi_target());
|
||||
tpl.oi().expand_into(ctx.asg_mut(), ois.oi_target());
|
||||
|
||||
Transition(TplExpr(ois, tpl.anonymous_reachable(), expr_done))
|
||||
.incomplete()
|
||||
|
@ -379,10 +382,10 @@ where
|
|||
(
|
||||
Toplevel(ois, tpl, expr) | TplExpr(ois, tpl, expr),
|
||||
AirExpr(etok),
|
||||
) => Self::delegate_expr(asg, ois, tpl, expr, etok),
|
||||
) => Self::delegate_expr(ctx, ois, tpl, expr, etok),
|
||||
|
||||
(TplExpr(ois, tpl, expr), AirBind(etok)) => {
|
||||
Self::delegate_expr(asg, ois, tpl, expr, etok)
|
||||
Self::delegate_expr(ctx, ois, tpl, expr, etok)
|
||||
}
|
||||
|
||||
(TplExpr(..), AirTpl(TplStart(span))) => {
|
||||
|
|
|
@ -138,9 +138,9 @@ where
|
|||
#[inline]
|
||||
fn lower_with_context<U, E>(
|
||||
&mut self,
|
||||
ctx: impl Into<LS::Context>,
|
||||
ctx: impl Into<LS::PubContext>,
|
||||
f: impl FnOnce(&mut LowerIter<S, Self, LS, EW>) -> Result<U, E>,
|
||||
) -> Result<(U, LS::Context), E>
|
||||
) -> Result<(U, LS::PubContext), E>
|
||||
where
|
||||
Self: Iterator<Item = WidenedParsedResult<S, EW>> + Sized,
|
||||
E: Diagnostic + From<FinalizeError>,
|
||||
|
|
|
@ -497,9 +497,9 @@ pub struct FinalizedParser<S: ParseState>(S::Context);
|
|||
|
||||
impl<S: ParseState> FinalizedParser<S> {
|
||||
/// Take ownership over the inner [`ParseState::Context`].
|
||||
pub fn into_context(self) -> S::Context {
|
||||
pub fn into_context(self) -> S::PubContext {
|
||||
match self {
|
||||
Self(ctx) => ctx,
|
||||
Self(ctx) => ctx.into(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -169,6 +169,16 @@ where
|
|||
/// otherwise-immutable [`ParseState`].
|
||||
type Context: Debug = context::Empty;
|
||||
|
||||
/// Public representation of [`Self::Context`].
|
||||
///
|
||||
/// If [`Self::Context`] holds internal state that isn't intended to be
|
||||
/// exposed via a public API,
|
||||
/// this represents the type that should be used in its place.
|
||||
/// Since public APIs include both input and output,
|
||||
/// this type must be convertable to _and_ from [`Self::Context`].
|
||||
type PubContext: Debug + From<Self::Context> + Into<Self::Context> =
|
||||
Self::Context;
|
||||
|
||||
/// Construct a parser with a [`Default`] state.
|
||||
///
|
||||
/// Whether this method is helpful or provides any clarity depends on
|
||||
|
@ -198,12 +208,12 @@ where
|
|||
/// see [`Parser::finalize`].
|
||||
fn parse_with_context<I: TokenStream<Self::Token>>(
|
||||
toks: I,
|
||||
ctx: Self::Context,
|
||||
ctx: Self::PubContext,
|
||||
) -> Parser<Self, I>
|
||||
where
|
||||
Self: ClosedParseState + Default,
|
||||
{
|
||||
Parser::from((toks, ctx))
|
||||
Parser::from((toks, ctx.into()))
|
||||
}
|
||||
|
||||
/// Parse a single [`Token`] and optionally perform a state transition.
|
||||
|
|
Loading…
Reference in New Issue