tamer: asg::air::expr: Generic target ObjectKind
Expressions were previously tied to packages. This prepares for using a `Tpl` as a container for expressions. This does not yet handle the situation of auto-rooting dangling expressions within the container. DEV-13708main
parent
266c9eb05a
commit
fc1d55c4c5
|
@ -35,7 +35,10 @@
|
|||
//! but that would surely result in face-palming and so we're not going
|
||||
//! air such cringeworthy dad jokes here.
|
||||
|
||||
use super::{graph::object::Pkg, Asg, AsgError, ObjectIndex};
|
||||
use super::{
|
||||
graph::object::Pkg,
|
||||
Asg, AsgError, ObjectIndex,
|
||||
};
|
||||
use crate::{
|
||||
diagnose::Annotate, diagnostic_unreachable, parse::prelude::*,
|
||||
sym::SymbolId,
|
||||
|
@ -55,28 +58,28 @@ pub type IdentSym = SymbolId;
|
|||
pub type DepSym = SymbolId;
|
||||
|
||||
/// AIR parser state.
|
||||
#[derive(Debug, PartialEq, Eq, Default)]
|
||||
#[derive(Debug, PartialEq, Default)]
|
||||
pub enum AirAggregate {
|
||||
/// Parser is not currently performing any work.
|
||||
#[default]
|
||||
Empty,
|
||||
|
||||
/// Expecting a package-level token.
|
||||
PkgHead(ObjectIndex<Pkg>, AirExprAggregate),
|
||||
PkgHead(ObjectIndex<Pkg>, AirExprAggregate<Pkg>),
|
||||
|
||||
/// Parsing an expression.
|
||||
///
|
||||
/// 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>, AirExprAggregate),
|
||||
PkgExpr(ObjectIndex<Pkg>, AirExprAggregate<Pkg>),
|
||||
|
||||
/// Parser is in template parsing mode.
|
||||
///
|
||||
/// All objects encountered until the closing [`Air::TplClose`] will be
|
||||
/// parented to this template rather than the parent [`Pkg`].
|
||||
/// See [`Air::TplOpen`] for more information.
|
||||
PkgTpl(ObjectIndex<Pkg>, AirExprAggregate, AirTplAggregate),
|
||||
PkgTpl(ObjectIndex<Pkg>, AirExprAggregate<Pkg>, AirTplAggregate),
|
||||
}
|
||||
|
||||
impl Display for AirAggregate {
|
||||
|
@ -124,11 +127,8 @@ impl ParseState for AirAggregate {
|
|||
|
||||
(Empty, AirPkg(PkgOpen(span))) => {
|
||||
let oi_pkg = asg.create(Pkg::new(span)).root(asg);
|
||||
Transition(PkgHead(
|
||||
oi_pkg,
|
||||
AirExprAggregate::new_in_pkg(oi_pkg),
|
||||
))
|
||||
.incomplete()
|
||||
Transition(PkgHead(oi_pkg, AirExprAggregate::new_in(oi_pkg)))
|
||||
.incomplete()
|
||||
}
|
||||
|
||||
(PkgHead(oi_pkg, expr), AirPkg(PkgOpen(span))) => {
|
||||
|
@ -254,8 +254,8 @@ impl AirAggregate {
|
|||
fn delegate_expr(
|
||||
asg: &mut <Self as ParseState>::Context,
|
||||
oi_pkg: ObjectIndex<Pkg>,
|
||||
expr: AirExprAggregate,
|
||||
etok: impl Into<<AirExprAggregate as ParseState>::Token>,
|
||||
expr: AirExprAggregate<Pkg>,
|
||||
etok: impl Into<<AirExprAggregate<Pkg> as ParseState>::Token>,
|
||||
) -> TransitionResult<Self> {
|
||||
let tok = etok.into();
|
||||
let tokspan = tok.span();
|
||||
|
@ -292,23 +292,21 @@ impl AirAggregate {
|
|||
fn delegate_tpl(
|
||||
asg: &mut <Self as ParseState>::Context,
|
||||
oi_pkg: ObjectIndex<Pkg>,
|
||||
stored_expr: AirExprAggregate,
|
||||
stored_expr: AirExprAggregate<Pkg>,
|
||||
tplst: AirTplAggregate,
|
||||
tok: Air,
|
||||
) -> TransitionResult<Self> {
|
||||
tplst
|
||||
.parse_token(tok, asg)
|
||||
.branch_dead::<Self, AirExprAggregate>(
|
||||
|_, stored_expr| {
|
||||
Transition(Self::PkgExpr(oi_pkg, stored_expr)).incomplete()
|
||||
},
|
||||
|tplst, result, stored_expr| {
|
||||
result
|
||||
.map(ParseStatus::reflexivity)
|
||||
.transition(Self::PkgTpl(oi_pkg, stored_expr, tplst))
|
||||
},
|
||||
stored_expr,
|
||||
)
|
||||
tplst.parse_token(tok, asg).branch_dead::<Self, _>(
|
||||
|_, stored_expr| {
|
||||
Transition(Self::PkgExpr(oi_pkg, stored_expr)).incomplete()
|
||||
},
|
||||
|tplst, result, stored_expr| {
|
||||
result
|
||||
.map(ParseStatus::reflexivity)
|
||||
.transition(Self::PkgTpl(oi_pkg, stored_expr, tplst))
|
||||
},
|
||||
stored_expr,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -23,13 +23,13 @@
|
|||
|
||||
use super::{
|
||||
super::{
|
||||
graph::object::{Expr, Object, Pkg},
|
||||
graph::object::{Expr, Object},
|
||||
Asg, AsgError, ObjectIndex,
|
||||
},
|
||||
ir::AirBindableExpr,
|
||||
};
|
||||
use crate::{
|
||||
asg::ObjectKind,
|
||||
asg::{graph::object::ObjectRelTo, Ident, ObjectKind},
|
||||
f::Functor,
|
||||
parse::prelude::*,
|
||||
span::Span,
|
||||
|
@ -44,16 +44,17 @@ use crate::{
|
|||
/// This parser has no dead states---it
|
||||
/// handles each of its tokens and performs error recovery on invalid
|
||||
/// state transitions.
|
||||
#[derive(Debug, PartialEq, Eq)]
|
||||
pub enum AirExprAggregate {
|
||||
#[derive(Debug, PartialEq)]
|
||||
pub enum AirExprAggregate<OR: ObjectKind> {
|
||||
/// Ready for an expression;
|
||||
/// expression stack is empty.
|
||||
Ready(ObjectIndex<Pkg>, ExprStack<Dormant>),
|
||||
Ready(ObjectIndex<OR>, ExprStack<Dormant>),
|
||||
|
||||
/// Building an expression.
|
||||
BuildingExpr(ObjectIndex<Pkg>, ExprStack<Active>, ObjectIndex<Expr>),
|
||||
BuildingExpr(ObjectIndex<OR>, ExprStack<Active>, ObjectIndex<Expr>),
|
||||
}
|
||||
impl Display for AirExprAggregate {
|
||||
|
||||
impl<OR: ObjectKind> Display for AirExprAggregate<OR> {
|
||||
fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
|
||||
match self {
|
||||
Self::Ready(_, es) => write!(f, "ready for expression with {es}"),
|
||||
|
@ -64,7 +65,10 @@ impl Display for AirExprAggregate {
|
|||
}
|
||||
}
|
||||
|
||||
impl ParseState for AirExprAggregate {
|
||||
impl<OR: ObjectKind> ParseState for AirExprAggregate<OR>
|
||||
where
|
||||
OR: ObjectRelTo<Ident>,
|
||||
{
|
||||
type Token = AirBindableExpr;
|
||||
type Object = ();
|
||||
type Error = AsgError;
|
||||
|
@ -80,17 +84,19 @@ impl ParseState for AirExprAggregate {
|
|||
use AirExprAggregate::*;
|
||||
|
||||
match (self, tok) {
|
||||
(Ready(oi_pkg, es), AirExpr(ExprOpen(op, span))) => {
|
||||
(Ready(oi_target, es), AirExpr(ExprOpen(op, span))) => {
|
||||
let oi = asg.create(Expr::new(op, span));
|
||||
Transition(BuildingExpr(oi_pkg, es.activate(), oi)).incomplete()
|
||||
Transition(BuildingExpr(oi_target, es.activate(), oi))
|
||||
.incomplete()
|
||||
}
|
||||
|
||||
(BuildingExpr(oi_pkg, es, poi), AirExpr(ExprOpen(op, span))) => {
|
||||
(BuildingExpr(oi_target, es, poi), AirExpr(ExprOpen(op, span))) => {
|
||||
let oi = poi.create_subexpr(asg, Expr::new(op, span));
|
||||
Transition(BuildingExpr(oi_pkg, es.push(poi), oi)).incomplete()
|
||||
Transition(BuildingExpr(oi_target, es.push(poi), oi))
|
||||
.incomplete()
|
||||
}
|
||||
|
||||
(BuildingExpr(oi_pkg, es, oi), AirExpr(ExprClose(end))) => {
|
||||
(BuildingExpr(oi_target, es, oi), AirExpr(ExprClose(end))) => {
|
||||
let start: Span = oi.into();
|
||||
|
||||
let _ = oi.map_obj(asg, |expr| {
|
||||
|
@ -99,11 +105,12 @@ impl ParseState for AirExprAggregate {
|
|||
|
||||
match es.pop() {
|
||||
(es, Some(poi)) => {
|
||||
Transition(BuildingExpr(oi_pkg, es, poi)).incomplete()
|
||||
Transition(BuildingExpr(oi_target, es, poi))
|
||||
.incomplete()
|
||||
}
|
||||
(es, None) => {
|
||||
let dangling = es.is_dangling();
|
||||
let st = Ready(oi_pkg, es.done());
|
||||
let st = Ready(oi_target, es.done());
|
||||
|
||||
if dangling {
|
||||
Transition(st).err(AsgError::DanglingExpr(
|
||||
|
@ -116,25 +123,27 @@ impl ParseState for AirExprAggregate {
|
|||
}
|
||||
}
|
||||
|
||||
(BuildingExpr(oi_pkg, es, oi), AirBind(BindIdent(id))) => {
|
||||
(BuildingExpr(oi_target, es, oi), AirBind(BindIdent(id))) => {
|
||||
let oi_ident = asg.lookup_or_missing(id);
|
||||
oi_pkg.defines(asg, oi_ident);
|
||||
oi_target.add_edge_to(asg, oi_ident, None);
|
||||
|
||||
// It is important that we do not mark this expression as
|
||||
// reachable unless we successfully bind the identifier.
|
||||
match oi_ident.bind_definition(asg, id, oi) {
|
||||
Ok(_) => Transition(BuildingExpr(
|
||||
oi_pkg,
|
||||
oi_target,
|
||||
es.reachable_by(oi_ident),
|
||||
oi,
|
||||
))
|
||||
.incomplete(),
|
||||
Err(e) => Transition(BuildingExpr(oi_pkg, es, oi)).err(e),
|
||||
Err(e) => {
|
||||
Transition(BuildingExpr(oi_target, es, oi)).err(e)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
(BuildingExpr(oi_pkg, es, oi), AirBind(RefIdent(ident))) => {
|
||||
Transition(BuildingExpr(oi_pkg, es, oi.ref_expr(asg, ident)))
|
||||
(BuildingExpr(oi_target, es, oi), AirBind(RefIdent(ident))) => {
|
||||
Transition(BuildingExpr(oi_target, es, oi.ref_expr(asg, ident)))
|
||||
.incomplete()
|
||||
}
|
||||
|
||||
|
@ -157,8 +166,8 @@ impl ParseState for AirExprAggregate {
|
|||
}
|
||||
}
|
||||
|
||||
impl AirExprAggregate {
|
||||
pub(super) fn new_in_pkg(oi: ObjectIndex<Pkg>) -> Self {
|
||||
impl<O: ObjectKind> AirExprAggregate<O> {
|
||||
pub(super) fn new_in(oi: ObjectIndex<O>) -> Self {
|
||||
Self::Ready(oi, ExprStack::default())
|
||||
}
|
||||
}
|
||||
|
|
|
@ -46,31 +46,23 @@ use crate::{
|
|||
/// This contains an embedded [`AirExprAggregate`] parser for handling
|
||||
/// expressions just the same as [`super::AirAggregate`] does with
|
||||
/// packages.
|
||||
#[derive(Debug, PartialEq, Eq)]
|
||||
#[derive(Debug, PartialEq)]
|
||||
pub enum AirTplAggregate {
|
||||
/// Ready for a template,
|
||||
/// defined as part of the given package.
|
||||
///
|
||||
/// This state also include the template header;
|
||||
/// This state also includes the template header;
|
||||
/// unlike NIR,
|
||||
/// AIR has no restrictions on when template header tokens are
|
||||
/// provided,
|
||||
/// which simplifies AIR generation.
|
||||
///
|
||||
/// The expression parser [`AirExprAggregate`] is initialized at this
|
||||
/// state to avoid re-allocating its stack for adjacent templates.
|
||||
/// This will not save any allocations if,
|
||||
/// after reaching a dead state,
|
||||
/// the caller
|
||||
/// (or parent parser)
|
||||
/// chooses to deallocate us.
|
||||
Ready(ObjectIndex<Pkg>, AirExprAggregate),
|
||||
Ready(ObjectIndex<Pkg>),
|
||||
|
||||
/// Aggregating tokens into a template.
|
||||
BuildingTpl(
|
||||
ObjectIndex<Pkg>,
|
||||
ObjectIndex<Tpl>,
|
||||
AirExprAggregate,
|
||||
AirExprAggregate<Tpl>,
|
||||
Option<SPair>,
|
||||
),
|
||||
}
|
||||
|
@ -78,7 +70,7 @@ pub enum AirTplAggregate {
|
|||
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::BuildingTpl(_, expr, _, None) => {
|
||||
write!(f, "building anonymous template with {expr}")
|
||||
}
|
||||
|
@ -110,10 +102,16 @@ impl ParseState for AirTplAggregate {
|
|||
match (self, tok.into()) {
|
||||
(st, AirTodo(Todo(_))) => Transition(st).incomplete(),
|
||||
|
||||
(Ready(oi_pkg, expr), AirTpl(TplOpen(span))) => {
|
||||
(Ready(oi_pkg), AirTpl(TplOpen(span))) => {
|
||||
let oi_tpl = asg.create(Tpl::new(span));
|
||||
|
||||
Transition(BuildingTpl(oi_pkg, oi_tpl, expr, None)).incomplete()
|
||||
Transition(BuildingTpl(
|
||||
oi_pkg,
|
||||
oi_tpl,
|
||||
AirExprAggregate::new_in(oi_tpl),
|
||||
None,
|
||||
))
|
||||
.incomplete()
|
||||
}
|
||||
|
||||
(
|
||||
|
@ -126,9 +124,12 @@ impl ParseState for AirTplAggregate {
|
|||
.map(|_| ())
|
||||
.transition(BuildingTpl(oi_pkg, oi_tpl, expr, Some(name))),
|
||||
|
||||
(BuildingTpl(oi_pkg, oi_tpl, expr, _), AirTpl(TplClose(span))) => {
|
||||
(
|
||||
BuildingTpl(oi_pkg, oi_tpl, _expr_done, _),
|
||||
AirTpl(TplClose(span)),
|
||||
) => {
|
||||
oi_tpl.close(asg, span);
|
||||
Transition(Ready(oi_pkg, expr)).incomplete()
|
||||
Transition(Ready(oi_pkg)).incomplete()
|
||||
}
|
||||
|
||||
(BuildingTpl(..), AirPkg(_)) => {
|
||||
|
@ -155,7 +156,7 @@ impl ParseState for AirTplAggregate {
|
|||
|
||||
impl AirTplAggregate {
|
||||
pub(super) fn new_in_pkg(oi_pkg: ObjectIndex<Pkg>) -> Self {
|
||||
Self::Ready(oi_pkg, AirExprAggregate::new_in_pkg(oi_pkg))
|
||||
Self::Ready(oi_pkg)
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -115,7 +115,11 @@ use crate::{
|
|||
span::{Span, UNKNOWN_SPAN},
|
||||
};
|
||||
use petgraph::graph::NodeIndex;
|
||||
use std::{convert::Infallible, fmt::Display, marker::PhantomData};
|
||||
use std::{
|
||||
convert::Infallible,
|
||||
fmt::{Debug, Display},
|
||||
marker::PhantomData,
|
||||
};
|
||||
|
||||
#[macro_use]
|
||||
mod rel;
|
||||
|
@ -424,7 +428,10 @@ impl AsRef<Object> for Object {
|
|||
///
|
||||
/// Note that [`Object`] is also an [`ObjectKind`],
|
||||
/// if you do not desire narrowing.
|
||||
pub trait ObjectKind = Into<Object> where Object: Into<Self> + AsRef<Self>;
|
||||
pub trait ObjectKind = Into<Object>
|
||||
where
|
||||
Self: Debug + PartialEq,
|
||||
Object: Into<Self> + AsRef<Self>;
|
||||
|
||||
/// Index representing an [`Object`] stored on the [`Asg`](super::Asg).
|
||||
///
|
||||
|
|
Loading…
Reference in New Issue