diff --git a/tamer/src/asg/air.rs b/tamer/src/asg/air.rs index 85733b44..6383b6fa 100644 --- a/tamer/src/asg/air.rs +++ b/tamer/src/asg/air.rs @@ -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 { 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 for AirAggregateCtx { + fn as_ref(&self) -> &Asg { + match self { + Self(asg) => asg, + } + } +} + +impl AsMut for AirAggregateCtx { + fn as_mut(&mut self) -> &mut Asg { + match self { + Self(asg) => asg, + } + } +} + +impl From for Asg { + fn from(ctx: AirAggregateCtx) -> Self { + match ctx { + AirAggregateCtx(asg) => asg, + } + } +} + +impl From for AirAggregateCtx { + fn from(asg: Asg) -> Self { + Self(asg) + } +} + #[cfg(test)] mod test; diff --git a/tamer/src/asg/air/expr.rs b/tamer/src/asg/air/expr.rs index b0106c18..8d30e509 100644 --- a/tamer/src/asg/air/expr.rs +++ b/tamer/src/asg/air/expr.rs @@ -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> ParseState for AirExprAggregate { 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 { 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)); diff --git a/tamer/src/asg/air/tpl.rs b/tamer/src/asg/air/tpl.rs index 55b80a49..ebf77c66 100644 --- a/tamer/src/asg/air/tpl.rs +++ b/tamer/src/asg/air/tpl.rs @@ -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 { 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))) => { diff --git a/tamer/src/parse/lower.rs b/tamer/src/parse/lower.rs index c1b5de54..a141dfa1 100644 --- a/tamer/src/parse/lower.rs +++ b/tamer/src/parse/lower.rs @@ -138,9 +138,9 @@ where #[inline] fn lower_with_context( &mut self, - ctx: impl Into, + ctx: impl Into, f: impl FnOnce(&mut LowerIter) -> Result, - ) -> Result<(U, LS::Context), E> + ) -> Result<(U, LS::PubContext), E> where Self: Iterator> + Sized, E: Diagnostic + From, diff --git a/tamer/src/parse/parser.rs b/tamer/src/parse/parser.rs index 17fd67a5..441df5de 100644 --- a/tamer/src/parse/parser.rs +++ b/tamer/src/parse/parser.rs @@ -497,9 +497,9 @@ pub struct FinalizedParser(S::Context); impl FinalizedParser { /// 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(), } } } diff --git a/tamer/src/parse/state.rs b/tamer/src/parse/state.rs index a08ef0fb..bc61a4da 100644 --- a/tamer/src/parse/state.rs +++ b/tamer/src/parse/state.rs @@ -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 + Into = + 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>( toks: I, - ctx: Self::Context, + ctx: Self::PubContext, ) -> Parser where Self: ClosedParseState + Default, { - Parser::from((toks, ctx)) + Parser::from((toks, ctx.into())) } /// Parse a single [`Token`] and optionally perform a state transition.