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-13708
main
Mike Gerwitz 2023-03-07 16:28:32 -05:00
parent 266c9eb05a
commit fc1d55c4c5
4 changed files with 84 additions and 69 deletions

View File

@ -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,
)
}
}

View File

@ -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())
}
}

View File

@ -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)
}
}

View File

@ -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).
///