tamer: asg::air::expr: Dead states for AirBind
This hoists the errors back into `AirAggregate`; I need dead states for the `AirTplAggregate` parser so that it will know when to (and not to) interpret tokens in the context of the template itself. In a previous commit message, I had pondered whether it may be possible to eliminate the dead state transition, and yet here I've used it with both of the sub-parsers now. So it seems like the better option in the future may be to narrow the type further---to say precisely _what_ types of tokens may yield a dead state transition; otherwise you lose the match information from the parser that yielded it. A stubbornly persistent problem in Rust, this magical and hidden match knowledge. DEV-13708main
parent
1770949b9a
commit
431df6cecb
|
@ -39,7 +39,7 @@ use self::expr::AirExprAggregateReachable;
|
|||
|
||||
use super::{graph::object::Pkg, Asg, AsgError, ObjectIndex};
|
||||
use crate::{
|
||||
diagnose::Annotate, diagnostic_unreachable, parse::prelude::*,
|
||||
parse::prelude::*,
|
||||
sym::SymbolId,
|
||||
};
|
||||
use std::fmt::{Debug, Display};
|
||||
|
@ -64,7 +64,7 @@ pub enum AirAggregate {
|
|||
Empty,
|
||||
|
||||
/// Expecting a package-level token.
|
||||
PkgHead(ObjectIndex<Pkg>, AirExprAggregateReachable<Pkg>),
|
||||
Toplevel(ObjectIndex<Pkg>, AirExprAggregateReachable<Pkg>),
|
||||
|
||||
/// Parsing an expression.
|
||||
///
|
||||
|
@ -91,7 +91,7 @@ impl Display for AirAggregate {
|
|||
|
||||
match self {
|
||||
Empty => write!(f, "awaiting AIR input for ASG"),
|
||||
PkgHead(_, _) => {
|
||||
Toplevel(_, _) => {
|
||||
write!(f, "expecting package header or an expression")
|
||||
}
|
||||
PkgExpr(_, expr) => {
|
||||
|
@ -120,7 +120,8 @@ impl ParseState for AirAggregate {
|
|||
asg: &mut Self::Context,
|
||||
) -> crate::parse::TransitionResult<Self> {
|
||||
use ir::{
|
||||
AirIdent::*, AirPkg::*, AirSubsets::*, AirTodo::*, AirTpl::*,
|
||||
AirBind::*, AirIdent::*, AirPkg::*, AirSubsets::*, AirTodo::*,
|
||||
AirTpl::*,
|
||||
};
|
||||
use AirAggregate::*;
|
||||
|
||||
|
@ -130,12 +131,12 @@ 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(oi_pkg)))
|
||||
Transition(Toplevel(oi_pkg, AirExprAggregate::new_in(oi_pkg)))
|
||||
.incomplete()
|
||||
}
|
||||
|
||||
(PkgHead(oi_pkg, expr), AirPkg(PkgOpen(span))) => {
|
||||
Transition(PkgHead(oi_pkg, expr))
|
||||
(Toplevel(oi_pkg, expr), AirPkg(PkgOpen(span))) => {
|
||||
Transition(Toplevel(oi_pkg, expr))
|
||||
.err(AsgError::NestedPkgOpen(span, oi_pkg.span()))
|
||||
}
|
||||
|
||||
|
@ -145,16 +146,20 @@ impl ParseState for AirAggregate {
|
|||
}
|
||||
|
||||
// No expression was started.
|
||||
(PkgHead(oi_pkg, _expr), AirPkg(PkgClose(span))) => {
|
||||
(Toplevel(oi_pkg, _expr), AirPkg(PkgClose(span))) => {
|
||||
oi_pkg.close(asg, span);
|
||||
Transition(Empty).incomplete()
|
||||
}
|
||||
|
||||
(PkgHead(..), AirBind(ident)) => {
|
||||
todo!("PkgBody AirBind {ident:?}")
|
||||
// TODO: We don't support package ids yet
|
||||
(st @ Toplevel(..), AirBind(BindIdent(id))) => {
|
||||
Transition(st).err(AsgError::InvalidExprBindContext(id))
|
||||
}
|
||||
(st @ Toplevel(..), AirBind(RefIdent(id))) => {
|
||||
Transition(st).err(AsgError::InvalidExprRefContext(id))
|
||||
}
|
||||
|
||||
(PkgHead(oi_pkg, expr), tok @ AirExpr(..)) => {
|
||||
(Toplevel(oi_pkg, expr), tok @ AirExpr(..)) => {
|
||||
Transition(PkgExpr(oi_pkg, expr))
|
||||
.incomplete()
|
||||
.with_lookahead(tok)
|
||||
|
@ -163,7 +168,7 @@ impl ParseState for AirAggregate {
|
|||
// Note that templates may preempt expressions at any point,
|
||||
// unlike in NIR at the time of writing.
|
||||
(
|
||||
PkgHead(oi_pkg, expr) | PkgExpr(oi_pkg, expr),
|
||||
Toplevel(oi_pkg, expr) | PkgExpr(oi_pkg, expr),
|
||||
tok @ AirTpl(..),
|
||||
) => Transition(PkgTpl(
|
||||
oi_pkg,
|
||||
|
@ -261,21 +266,9 @@ impl AirAggregate {
|
|||
etok: impl Into<<AirExprAggregateReachable<Pkg> as ParseState>::Token>,
|
||||
) -> TransitionResult<Self> {
|
||||
let tok = etok.into();
|
||||
let tokspan = tok.span();
|
||||
|
||||
expr.parse_token(tok, asg).branch_dead::<Self, _>(
|
||||
// TODO: Enforce using type system to avoid need for this
|
||||
// runtime check and prove that it is indeed impossible
|
||||
// (which otherwise could fail to be the case due to changes
|
||||
// since this was written).
|
||||
|_, ()| {
|
||||
diagnostic_unreachable!(
|
||||
vec![tokspan.internal_error(
|
||||
"unexpected dead state transition at this token"
|
||||
)],
|
||||
"AirExprAggregate should not have dead states"
|
||||
)
|
||||
},
|
||||
|expr, ()| Transition(Self::Toplevel(oi_pkg, expr)).incomplete(),
|
||||
|expr, result, ()| {
|
||||
result
|
||||
.map(ParseStatus::reflexivity)
|
||||
|
|
|
@ -157,17 +157,12 @@ impl<O: ObjectKind, S: RootStrategy<O>> ParseState for AirExprAggregate<O, S> {
|
|||
.incomplete()
|
||||
}
|
||||
|
||||
(st @ Ready(..), AirBind(BindIdent(id))) => {
|
||||
Transition(st).err(AsgError::InvalidExprBindContext(id))
|
||||
}
|
||||
|
||||
(st @ Ready(..), AirBind(RefIdent(id))) => {
|
||||
Transition(st).err(AsgError::InvalidExprRefContext(id))
|
||||
}
|
||||
|
||||
(st @ Ready(..), AirExpr(ExprClose(span))) => {
|
||||
Transition(st).err(AsgError::UnbalancedExpr(span))
|
||||
}
|
||||
|
||||
// The binding may refer to a parent context.
|
||||
(st @ Ready(..), tok @ AirBind(..)) => Transition(st).dead(tok),
|
||||
}
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in New Issue