tamer: asg::air::ir::Air: Open/Close => Start/End in token names
See the Air docblock for more information. I'm introducing new tokens for the template system, which uses the terms "free" and "closed". I prefer open/close for delimiters, as I've expressed elsewhere, but unfortunately it conflicts too much (and too confusingly) with other standard terminology as we get more into the formal side of the language. DEV-13708main
parent
0e42788dcc
commit
9e5958d89e
|
@ -72,9 +72,9 @@ pub enum AirAggregate {
|
|||
|
||||
/// Parser is in template parsing mode.
|
||||
///
|
||||
/// All objects encountered until the closing [`Air::TplClose`] will be
|
||||
/// All objects encountered until the closing [`Air::TplEnd`] will be
|
||||
/// parented to this template rather than the parent [`Pkg`].
|
||||
/// See [`Air::TplOpen`] for more information.
|
||||
/// See [`Air::TplStart`] for more information.
|
||||
PkgTpl(
|
||||
ObjectIndex<Pkg>,
|
||||
AirExprAggregateReachable<Pkg>,
|
||||
|
@ -126,24 +126,24 @@ impl ParseState for AirAggregate {
|
|||
match (self, tok.into()) {
|
||||
(st, AirTodo(Todo(_))) => Transition(st).incomplete(),
|
||||
|
||||
(Empty, AirPkg(PkgOpen(span))) => {
|
||||
(Empty, AirPkg(PkgStart(span))) => {
|
||||
let oi_pkg = asg.create(Pkg::new(span)).root(asg);
|
||||
Transition(Toplevel(oi_pkg, AirExprAggregate::new_in(oi_pkg)))
|
||||
.incomplete()
|
||||
}
|
||||
|
||||
(Toplevel(oi_pkg, expr), AirPkg(PkgOpen(span))) => {
|
||||
(Toplevel(oi_pkg, expr), AirPkg(PkgStart(span))) => {
|
||||
Transition(Toplevel(oi_pkg, expr))
|
||||
.err(AsgError::NestedPkgOpen(span, oi_pkg.span()))
|
||||
.err(AsgError::NestedPkgStart(span, oi_pkg.span()))
|
||||
}
|
||||
|
||||
(PkgExpr(oi_pkg, expr), AirPkg(PkgOpen(span))) => {
|
||||
(PkgExpr(oi_pkg, expr), AirPkg(PkgStart(span))) => {
|
||||
Transition(PkgExpr(oi_pkg, expr))
|
||||
.err(AsgError::NestedPkgOpen(span, oi_pkg.span()))
|
||||
.err(AsgError::NestedPkgStart(span, oi_pkg.span()))
|
||||
}
|
||||
|
||||
// No expression was started.
|
||||
(Toplevel(oi_pkg, _expr), AirPkg(PkgClose(span))) => {
|
||||
(Toplevel(oi_pkg, _expr), AirPkg(PkgEnd(span))) => {
|
||||
oi_pkg.close(asg, span);
|
||||
Transition(Empty).incomplete()
|
||||
}
|
||||
|
@ -198,19 +198,19 @@ impl ParseState for AirAggregate {
|
|||
Self::delegate_tpl(asg, oi_pkg, stored_expr, tplst, ttok)
|
||||
}
|
||||
|
||||
(PkgTpl(..), AirPkg(PkgOpen(..))) => {
|
||||
(PkgTpl(..), AirPkg(PkgStart(..))) => {
|
||||
todo!("templates cannot contain packages")
|
||||
}
|
||||
|
||||
(Empty, AirTpl(TplClose(..))) => {
|
||||
todo!("Empty AirTpl::TplClose")
|
||||
(Empty, AirTpl(TplEnd(..))) => {
|
||||
todo!("Empty AirTpl::TplEnd")
|
||||
}
|
||||
|
||||
(Empty, AirPkg(PkgClose(span))) => {
|
||||
Transition(Empty).err(AsgError::InvalidPkgCloseContext(span))
|
||||
(Empty, AirPkg(PkgEnd(span))) => {
|
||||
Transition(Empty).err(AsgError::InvalidPkgEndContext(span))
|
||||
}
|
||||
|
||||
(PkgExpr(oi_pkg, expr), AirPkg(PkgClose(span))) => {
|
||||
(PkgExpr(oi_pkg, expr), AirPkg(PkgEnd(span))) => {
|
||||
match expr.is_accepting(asg) {
|
||||
true => {
|
||||
// TODO: this is duplicated with the above
|
||||
|
@ -218,23 +218,24 @@ impl ParseState for AirAggregate {
|
|||
Transition(Empty).incomplete()
|
||||
}
|
||||
false => Transition(PkgExpr(oi_pkg, expr))
|
||||
.err(AsgError::InvalidPkgCloseContext(span)),
|
||||
.err(AsgError::InvalidPkgEndContext(span)),
|
||||
}
|
||||
}
|
||||
|
||||
(PkgTpl(oi_pkg, stored_expr, tplst), AirPkg(PkgClose(span))) => {
|
||||
(PkgTpl(oi_pkg, stored_expr, tplst), AirPkg(PkgEnd(span))) => {
|
||||
match tplst.is_accepting(asg) {
|
||||
true => Transition(PkgExpr(oi_pkg, stored_expr))
|
||||
.incomplete()
|
||||
.with_lookahead(AirPkg(PkgClose(span))),
|
||||
.with_lookahead(AirPkg(PkgEnd(span))),
|
||||
false => Transition(PkgTpl(oi_pkg, stored_expr, tplst))
|
||||
.err(AsgError::InvalidPkgCloseContext(span)),
|
||||
.err(AsgError::InvalidPkgEndContext(span)),
|
||||
}
|
||||
}
|
||||
|
||||
(Empty, tok @ (AirExpr(..) | AirBind(..) | AirTpl(TplOpen(_)))) => {
|
||||
Transition(Empty).err(AsgError::PkgExpected(tok.span()))
|
||||
}
|
||||
(
|
||||
Empty,
|
||||
tok @ (AirExpr(..) | AirBind(..) | AirTpl(TplStart(_))),
|
||||
) => Transition(Empty).err(AsgError::PkgExpected(tok.span())),
|
||||
|
||||
(Empty, AirIdent(IdentDecl(name, kind, src))) => {
|
||||
asg.declare(name, kind, src).map(|_| ()).transition(Empty)
|
||||
|
|
|
@ -99,17 +99,17 @@ impl<O: ObjectKind, S: RootStrategy<O>> ParseState for AirExprAggregate<O, S> {
|
|||
use AirExprAggregate::*;
|
||||
|
||||
match (self, tok) {
|
||||
(Ready(root, es, _), AirExpr(ExprOpen(op, span))) => {
|
||||
(Ready(root, es, _), AirExpr(ExprStart(op, span))) => {
|
||||
let oi = asg.create(Expr::new(op, span));
|
||||
Transition(BuildingExpr(root, es.activate(), oi)).incomplete()
|
||||
}
|
||||
|
||||
(BuildingExpr(root, es, poi), AirExpr(ExprOpen(op, span))) => {
|
||||
(BuildingExpr(root, es, poi), AirExpr(ExprStart(op, span))) => {
|
||||
let oi = poi.create_subexpr(asg, Expr::new(op, span));
|
||||
Transition(BuildingExpr(root, es.push(poi), oi)).incomplete()
|
||||
}
|
||||
|
||||
(BuildingExpr(root, es, oi), AirExpr(ExprClose(end))) => {
|
||||
(BuildingExpr(root, es, oi), AirExpr(ExprEnd(end))) => {
|
||||
let _ = oi.map_obj(asg, |expr| {
|
||||
expr.map(|span| span.merge(end).unwrap_or(span))
|
||||
});
|
||||
|
@ -157,7 +157,7 @@ impl<O: ObjectKind, S: RootStrategy<O>> ParseState for AirExprAggregate<O, S> {
|
|||
.incomplete()
|
||||
}
|
||||
|
||||
(st @ Ready(..), AirExpr(ExprClose(span))) => {
|
||||
(st @ Ready(..), AirExpr(ExprEnd(span))) => {
|
||||
Transition(st).err(AsgError::UnbalancedExpr(span))
|
||||
}
|
||||
|
||||
|
|
|
@ -46,9 +46,9 @@ fn expr_empty_ident() {
|
|||
let id = SPair("foo".into(), S2);
|
||||
|
||||
let toks = vec![
|
||||
Air::ExprOpen(ExprOp::Sum, S1),
|
||||
Air::ExprStart(ExprOp::Sum, S1),
|
||||
Air::BindIdent(id),
|
||||
Air::ExprClose(S3),
|
||||
Air::ExprEnd(S3),
|
||||
];
|
||||
|
||||
let mut sut = parse_as_pkg_body(toks);
|
||||
|
@ -67,18 +67,18 @@ fn expr_without_pkg() {
|
|||
let toks = vec![
|
||||
// No package
|
||||
// (because we're not parsing with `parse_as_pkg_body` below)
|
||||
Air::ExprOpen(ExprOp::Sum, S1),
|
||||
Air::ExprStart(ExprOp::Sum, S1),
|
||||
// RECOVERY
|
||||
Air::PkgOpen(S2),
|
||||
Air::PkgClose(S3),
|
||||
Air::PkgStart(S2),
|
||||
Air::PkgEnd(S3),
|
||||
];
|
||||
|
||||
assert_eq!(
|
||||
vec![
|
||||
Err(ParseError::StateError(AsgError::PkgExpected(S1))),
|
||||
// RECOVERY
|
||||
Ok(Parsed::Incomplete), // PkgOpen
|
||||
Ok(Parsed::Incomplete), // PkgClose
|
||||
Ok(Parsed::Incomplete), // PkgStart
|
||||
Ok(Parsed::Incomplete), // PkgEnd
|
||||
],
|
||||
Sut::parse(toks.into_iter()).collect::<Vec<_>>(),
|
||||
);
|
||||
|
@ -90,28 +90,28 @@ fn close_pkg_mid_expr() {
|
|||
let id = SPair("foo".into(), S4);
|
||||
|
||||
let toks = vec![
|
||||
Air::PkgOpen(S1),
|
||||
Air::ExprOpen(ExprOp::Sum, S2),
|
||||
Air::PkgClose(S3),
|
||||
Air::PkgStart(S1),
|
||||
Air::ExprStart(ExprOp::Sum, S2),
|
||||
Air::PkgEnd(S3),
|
||||
// RECOVERY: Let's finish the expression first...
|
||||
Air::BindIdent(id),
|
||||
Air::ExprClose(S5),
|
||||
Air::ExprEnd(S5),
|
||||
// ...and then try to close again.
|
||||
Air::PkgClose(S6),
|
||||
Air::PkgEnd(S6),
|
||||
];
|
||||
|
||||
assert_eq!(
|
||||
vec![
|
||||
Ok(Parsed::Incomplete), // PkgOpen
|
||||
Ok(Parsed::Incomplete), // ExprOpen
|
||||
Err(ParseError::StateError(AsgError::InvalidPkgCloseContext(S3))),
|
||||
Ok(Parsed::Incomplete), // PkgStart
|
||||
Ok(Parsed::Incomplete), // ExprStart
|
||||
Err(ParseError::StateError(AsgError::InvalidPkgEndContext(S3))),
|
||||
// RECOVERY: We should be able to close the package if we just
|
||||
// finish the expression first,
|
||||
// demonstrating that recovery properly maintains all state.
|
||||
Ok(Parsed::Incomplete), // BindIdent
|
||||
Ok(Parsed::Incomplete), // ExprClose
|
||||
Ok(Parsed::Incomplete), // ExprEnd
|
||||
// Successful close here.
|
||||
Ok(Parsed::Incomplete), // PkgClose
|
||||
Ok(Parsed::Incomplete), // PkgEnd
|
||||
],
|
||||
Sut::parse(toks.into_iter()).collect::<Vec<_>>(),
|
||||
);
|
||||
|
@ -122,29 +122,29 @@ fn open_pkg_mid_expr() {
|
|||
let id = SPair("foo".into(), S4);
|
||||
|
||||
let toks = vec![
|
||||
Air::PkgOpen(S1),
|
||||
Air::ExprOpen(ExprOp::Sum, S2),
|
||||
Air::PkgOpen(S3),
|
||||
Air::PkgStart(S1),
|
||||
Air::ExprStart(ExprOp::Sum, S2),
|
||||
Air::PkgStart(S3),
|
||||
// RECOVERY: We should still be able to complete successfully.
|
||||
Air::BindIdent(id),
|
||||
Air::ExprClose(S5),
|
||||
Air::ExprEnd(S5),
|
||||
// Closes the _original_ package.
|
||||
Air::PkgClose(S6),
|
||||
Air::PkgEnd(S6),
|
||||
];
|
||||
|
||||
assert_eq!(
|
||||
vec![
|
||||
Ok(Parsed::Incomplete), // PkgOpen
|
||||
Ok(Parsed::Incomplete), // ExprOpen
|
||||
Err(ParseError::StateError(AsgError::NestedPkgOpen(S3, S1))),
|
||||
Ok(Parsed::Incomplete), // PkgStart
|
||||
Ok(Parsed::Incomplete), // ExprStart
|
||||
Err(ParseError::StateError(AsgError::NestedPkgStart(S3, S1))),
|
||||
// RECOVERY: Ignore the open and continue.
|
||||
// Of course,
|
||||
// this means that any identifiers would be defined in a
|
||||
// different package than was likely intended,
|
||||
// but at least we'll be able to keep processing.
|
||||
Ok(Parsed::Incomplete), // BindIdent
|
||||
Ok(Parsed::Incomplete), // ExprClose
|
||||
Ok(Parsed::Incomplete), // PkgClose
|
||||
Ok(Parsed::Incomplete), // ExprEnd
|
||||
Ok(Parsed::Incomplete), // PkgEnd
|
||||
],
|
||||
Sut::parse(toks.into_iter()).collect::<Vec<_>>(),
|
||||
);
|
||||
|
@ -156,15 +156,15 @@ fn expr_non_empty_ident_root() {
|
|||
let id_b = SPair("bar".into(), S2);
|
||||
|
||||
let toks = vec![
|
||||
Air::ExprOpen(ExprOp::Sum, S1),
|
||||
Air::ExprStart(ExprOp::Sum, S1),
|
||||
// Identifier while still empty...
|
||||
Air::BindIdent(id_a),
|
||||
Air::ExprOpen(ExprOp::Sum, S3),
|
||||
Air::ExprStart(ExprOp::Sum, S3),
|
||||
// (note that the inner expression _does not_ have an ident binding)
|
||||
Air::ExprClose(S4),
|
||||
Air::ExprEnd(S4),
|
||||
// ...and an identifier non-empty.
|
||||
Air::BindIdent(id_b),
|
||||
Air::ExprClose(S6),
|
||||
Air::ExprEnd(S6),
|
||||
];
|
||||
|
||||
let mut sut = parse_as_pkg_body(toks);
|
||||
|
@ -194,15 +194,15 @@ fn expr_non_empty_bind_only_after() {
|
|||
let id = SPair("foo".into(), S2);
|
||||
|
||||
let toks = vec![
|
||||
Air::ExprOpen(ExprOp::Sum, S1),
|
||||
Air::ExprStart(ExprOp::Sum, S1),
|
||||
// Expression root is still dangling at this point.
|
||||
Air::ExprOpen(ExprOp::Sum, S2),
|
||||
Air::ExprClose(S3),
|
||||
Air::ExprStart(ExprOp::Sum, S2),
|
||||
Air::ExprEnd(S3),
|
||||
// We only bind an identifier _after_ we've created the expression,
|
||||
// which should cause the still-dangling root to become
|
||||
// reachable.
|
||||
Air::BindIdent(id),
|
||||
Air::ExprClose(S5),
|
||||
Air::ExprEnd(S5),
|
||||
];
|
||||
|
||||
let mut sut = parse_as_pkg_body(toks);
|
||||
|
@ -221,10 +221,10 @@ fn expr_non_empty_bind_only_after() {
|
|||
#[test]
|
||||
fn expr_dangling_no_subexpr() {
|
||||
let toks = vec![
|
||||
Air::ExprOpen(ExprOp::Sum, S1),
|
||||
Air::ExprStart(ExprOp::Sum, S1),
|
||||
// No `BindIdent`,
|
||||
// so this expression is dangling.
|
||||
Air::ExprClose(S2),
|
||||
Air::ExprEnd(S2),
|
||||
];
|
||||
|
||||
// The error span should encompass the entire expression.
|
||||
|
@ -232,11 +232,11 @@ fn expr_dangling_no_subexpr() {
|
|||
|
||||
assert_eq!(
|
||||
vec![
|
||||
Ok(Parsed::Incomplete), // PkgOpen
|
||||
Ok(Parsed::Incomplete), // PkgStart
|
||||
Ok(Parsed::Incomplete),
|
||||
Err(ParseError::StateError(AsgError::DanglingExpr(full_span))),
|
||||
// RECOVERY
|
||||
Ok(Parsed::Incomplete), // PkgClose
|
||||
Ok(Parsed::Incomplete), // PkgEnd
|
||||
],
|
||||
parse_as_pkg_body(toks).collect::<Vec<_>>(),
|
||||
);
|
||||
|
@ -245,26 +245,26 @@ fn expr_dangling_no_subexpr() {
|
|||
#[test]
|
||||
fn expr_dangling_with_subexpr() {
|
||||
let toks = vec![
|
||||
Air::ExprOpen(ExprOp::Sum, S1),
|
||||
Air::ExprStart(ExprOp::Sum, S1),
|
||||
// Expression root is still dangling at this point.
|
||||
Air::ExprOpen(ExprOp::Sum, S2),
|
||||
Air::ExprClose(S3),
|
||||
Air::ExprStart(ExprOp::Sum, S2),
|
||||
Air::ExprEnd(S3),
|
||||
// Still no ident binding,
|
||||
// so root should still be dangling.
|
||||
Air::ExprClose(S4),
|
||||
Air::ExprEnd(S4),
|
||||
];
|
||||
|
||||
let full_span = S1.merge(S4).unwrap();
|
||||
|
||||
assert_eq!(
|
||||
vec![
|
||||
Ok(Parsed::Incomplete), // PkgOpen
|
||||
Ok(Parsed::Incomplete), // PkgStart
|
||||
Ok(Parsed::Incomplete),
|
||||
Ok(Parsed::Incomplete),
|
||||
Ok(Parsed::Incomplete),
|
||||
Err(ParseError::StateError(AsgError::DanglingExpr(full_span))),
|
||||
// RECOVERY
|
||||
Ok(Parsed::Incomplete), // PkgClose
|
||||
Ok(Parsed::Incomplete), // PkgEnd
|
||||
],
|
||||
parse_as_pkg_body(toks).collect::<Vec<_>>(),
|
||||
);
|
||||
|
@ -275,33 +275,33 @@ fn expr_dangling_with_subexpr_ident() {
|
|||
let id = SPair("foo".into(), S3);
|
||||
|
||||
let toks = vec![
|
||||
Air::ExprOpen(ExprOp::Sum, S1),
|
||||
Air::ExprStart(ExprOp::Sum, S1),
|
||||
// Expression root is still dangling at this point.
|
||||
Air::ExprOpen(ExprOp::Sum, S2),
|
||||
Air::ExprStart(ExprOp::Sum, S2),
|
||||
// The _inner_ expression receives an identifier,
|
||||
// but that should have no impact on the dangling status of the
|
||||
// root,
|
||||
// especially given that subexpressions are always reachable
|
||||
// anyway.
|
||||
Air::BindIdent(id),
|
||||
Air::ExprClose(S4),
|
||||
Air::ExprEnd(S4),
|
||||
// But the root still has no ident binding,
|
||||
// and so should still be dangling.
|
||||
Air::ExprClose(S5),
|
||||
Air::ExprEnd(S5),
|
||||
];
|
||||
|
||||
let full_span = S1.merge(S5).unwrap();
|
||||
|
||||
assert_eq!(
|
||||
vec![
|
||||
Ok(Parsed::Incomplete), // PkgOpen
|
||||
Ok(Parsed::Incomplete), // PkgStart
|
||||
Ok(Parsed::Incomplete),
|
||||
Ok(Parsed::Incomplete),
|
||||
Ok(Parsed::Incomplete),
|
||||
Ok(Parsed::Incomplete),
|
||||
Err(ParseError::StateError(AsgError::DanglingExpr(full_span))),
|
||||
// RECOVERY
|
||||
Ok(Parsed::Incomplete), // PkgClose
|
||||
Ok(Parsed::Incomplete), // PkgEnd
|
||||
],
|
||||
parse_as_pkg_body(toks).collect::<Vec<_>>(),
|
||||
);
|
||||
|
@ -316,12 +316,12 @@ fn expr_reachable_subsequent_dangling() {
|
|||
let id = SPair("foo".into(), S2);
|
||||
let toks = vec![
|
||||
// Reachable
|
||||
Air::ExprOpen(ExprOp::Sum, S1),
|
||||
Air::ExprStart(ExprOp::Sum, S1),
|
||||
Air::BindIdent(id),
|
||||
Air::ExprClose(S3),
|
||||
Air::ExprEnd(S3),
|
||||
// Dangling
|
||||
Air::ExprOpen(ExprOp::Sum, S4),
|
||||
Air::ExprClose(S5),
|
||||
Air::ExprStart(ExprOp::Sum, S4),
|
||||
Air::ExprEnd(S5),
|
||||
];
|
||||
|
||||
// The error span should encompass the entire expression.
|
||||
|
@ -330,14 +330,14 @@ fn expr_reachable_subsequent_dangling() {
|
|||
|
||||
assert_eq!(
|
||||
vec![
|
||||
Ok(Parsed::Incomplete), // PkgOpen
|
||||
Ok(Parsed::Incomplete), // PkgStart
|
||||
Ok(Parsed::Incomplete),
|
||||
Ok(Parsed::Incomplete),
|
||||
Ok(Parsed::Incomplete),
|
||||
Ok(Parsed::Incomplete),
|
||||
Err(ParseError::StateError(AsgError::DanglingExpr(second_span))),
|
||||
// RECOVERY
|
||||
Ok(Parsed::Incomplete), // PkgClose
|
||||
Ok(Parsed::Incomplete), // PkgEnd
|
||||
],
|
||||
parse_as_pkg_body(toks).collect::<Vec<_>>(),
|
||||
);
|
||||
|
@ -349,12 +349,12 @@ fn recovery_expr_reachable_after_dangling() {
|
|||
let id = SPair("foo".into(), S4);
|
||||
let toks = vec![
|
||||
// Dangling
|
||||
Air::ExprOpen(ExprOp::Sum, S1),
|
||||
Air::ExprClose(S2),
|
||||
Air::ExprStart(ExprOp::Sum, S1),
|
||||
Air::ExprEnd(S2),
|
||||
// Reachable, after error from dangling.
|
||||
Air::ExprOpen(ExprOp::Sum, S3),
|
||||
Air::ExprStart(ExprOp::Sum, S3),
|
||||
Air::BindIdent(id),
|
||||
Air::ExprClose(S5),
|
||||
Air::ExprEnd(S5),
|
||||
];
|
||||
|
||||
// The error span should encompass the entire expression.
|
||||
|
@ -364,14 +364,14 @@ fn recovery_expr_reachable_after_dangling() {
|
|||
|
||||
assert_eq!(
|
||||
vec![
|
||||
Ok(Parsed::Incomplete), // PkgOpen
|
||||
Ok(Parsed::Incomplete), // PkgStart
|
||||
Ok(Parsed::Incomplete),
|
||||
Err(ParseError::StateError(AsgError::DanglingExpr(err_span))),
|
||||
// RECOVERY: continue at this point with the next expression.
|
||||
Ok(Parsed::Incomplete),
|
||||
Ok(Parsed::Incomplete),
|
||||
Ok(Parsed::Incomplete),
|
||||
Ok(Parsed::Incomplete), // PkgClose
|
||||
Ok(Parsed::Incomplete), // PkgEnd
|
||||
],
|
||||
sut.by_ref().collect::<Vec<_>>(),
|
||||
);
|
||||
|
@ -398,30 +398,30 @@ fn expr_close_unbalanced() {
|
|||
|
||||
let toks = vec![
|
||||
// Close before _any_ open.
|
||||
Air::ExprClose(S1),
|
||||
Air::ExprEnd(S1),
|
||||
// Should recover,
|
||||
// allowing for a normal expr.
|
||||
Air::ExprOpen(ExprOp::Sum, S2),
|
||||
Air::ExprStart(ExprOp::Sum, S2),
|
||||
Air::BindIdent(id),
|
||||
Air::ExprClose(S4),
|
||||
Air::ExprEnd(S4),
|
||||
// And now an extra close _after_ a valid expr.
|
||||
Air::ExprClose(S5),
|
||||
Air::ExprEnd(S5),
|
||||
];
|
||||
|
||||
let mut sut = parse_as_pkg_body(toks);
|
||||
|
||||
assert_eq!(
|
||||
vec![
|
||||
Ok(Parsed::Incomplete), // PkgOpen
|
||||
Ok(Parsed::Incomplete), // PkgStart
|
||||
Err(ParseError::StateError(AsgError::UnbalancedExpr(S1))),
|
||||
// RECOVERY
|
||||
Ok(Parsed::Incomplete), // ExprOpen
|
||||
Ok(Parsed::Incomplete), // ExprStart
|
||||
Ok(Parsed::Incomplete), // BindIdent
|
||||
Ok(Parsed::Incomplete), // ExprClose
|
||||
Ok(Parsed::Incomplete), // ExprEnd
|
||||
// Another error after a successful expression.
|
||||
Err(ParseError::StateError(AsgError::UnbalancedExpr(S5))),
|
||||
// RECOVERY
|
||||
Ok(Parsed::Incomplete), // PkgClose
|
||||
Ok(Parsed::Incomplete), // PkgEnd
|
||||
],
|
||||
sut.by_ref().collect::<Vec<_>>(),
|
||||
);
|
||||
|
@ -445,15 +445,15 @@ fn expr_bind_to_empty() {
|
|||
// package header,
|
||||
// otherwise the bind will be interpreted as a bind to the
|
||||
// package itself.
|
||||
Air::ExprOpen(ExprOp::Sum, S1),
|
||||
Air::ExprStart(ExprOp::Sum, S1),
|
||||
Air::BindIdent(id_pre),
|
||||
Air::ExprClose(S3),
|
||||
Air::ExprEnd(S3),
|
||||
// No open expression to bind to.
|
||||
Air::BindIdent(id_noexpr_a),
|
||||
// Post-recovery create an expression.
|
||||
Air::ExprOpen(ExprOp::Sum, S5),
|
||||
Air::ExprStart(ExprOp::Sum, S5),
|
||||
Air::BindIdent(id_good),
|
||||
Air::ExprClose(S7),
|
||||
Air::ExprEnd(S7),
|
||||
// Once again we have nothing to bind to.
|
||||
Air::BindIdent(id_noexpr_b),
|
||||
];
|
||||
|
@ -462,11 +462,11 @@ fn expr_bind_to_empty() {
|
|||
|
||||
assert_eq!(
|
||||
vec![
|
||||
Ok(Parsed::Incomplete), // PkgOpen
|
||||
Ok(Parsed::Incomplete), // PkgStart
|
||||
// Just to get out of a package header context
|
||||
Ok(Parsed::Incomplete), // ExprOpen (pre)
|
||||
Ok(Parsed::Incomplete), // ExprStart (pre)
|
||||
Ok(Parsed::Incomplete), // BindIdent (pre)
|
||||
Ok(Parsed::Incomplete), // ExprClose (pre)
|
||||
Ok(Parsed::Incomplete), // ExprEnd (pre)
|
||||
// Now that we've encountered an expression,
|
||||
// we want an error specific to expression binding,
|
||||
// since it's likely that a bind token was issued too late,
|
||||
|
@ -476,15 +476,15 @@ fn expr_bind_to_empty() {
|
|||
id_noexpr_a
|
||||
))),
|
||||
// RECOVERY
|
||||
Ok(Parsed::Incomplete), // ExprOpen
|
||||
Ok(Parsed::Incomplete), // ExprStart
|
||||
Ok(Parsed::Incomplete), // BindIdent
|
||||
Ok(Parsed::Incomplete), // ExprClose
|
||||
Ok(Parsed::Incomplete), // ExprEnd
|
||||
// Another error after a successful expression.
|
||||
Err(ParseError::StateError(AsgError::InvalidExprBindContext(
|
||||
id_noexpr_b
|
||||
))),
|
||||
// RECOVERY
|
||||
Ok(Parsed::Incomplete), // PkgClose
|
||||
Ok(Parsed::Incomplete), // PkgEnd
|
||||
],
|
||||
sut.by_ref().collect::<Vec<_>>(),
|
||||
);
|
||||
|
@ -511,19 +511,19 @@ fn sibling_subexprs_have_ordered_edges_to_parent() {
|
|||
let id_root = SPair("root".into(), S1);
|
||||
|
||||
let toks = vec![
|
||||
Air::ExprOpen(ExprOp::Sum, S1),
|
||||
Air::ExprStart(ExprOp::Sum, S1),
|
||||
// Identify the root so that it is not dangling.
|
||||
Air::BindIdent(id_root),
|
||||
// Sibling A
|
||||
Air::ExprOpen(ExprOp::Sum, S3),
|
||||
Air::ExprClose(S4),
|
||||
Air::ExprStart(ExprOp::Sum, S3),
|
||||
Air::ExprEnd(S4),
|
||||
// Sibling B
|
||||
Air::ExprOpen(ExprOp::Sum, S5),
|
||||
Air::ExprClose(S6),
|
||||
Air::ExprStart(ExprOp::Sum, S5),
|
||||
Air::ExprEnd(S6),
|
||||
// Sibling C
|
||||
Air::ExprOpen(ExprOp::Sum, S7),
|
||||
Air::ExprClose(S8),
|
||||
Air::ExprClose(S9),
|
||||
Air::ExprStart(ExprOp::Sum, S7),
|
||||
Air::ExprEnd(S8),
|
||||
Air::ExprEnd(S9),
|
||||
];
|
||||
|
||||
let asg = asg_from_toks(toks);
|
||||
|
@ -556,14 +556,14 @@ fn nested_subexprs_related_to_relative_parent() {
|
|||
let id_suba = SPair("suba".into(), S2);
|
||||
|
||||
let toks = vec![
|
||||
Air::ExprOpen(ExprOp::Sum, S1), // 0
|
||||
Air::ExprStart(ExprOp::Sum, S1), // 0
|
||||
Air::BindIdent(id_root),
|
||||
Air::ExprOpen(ExprOp::Sum, S2), // 1
|
||||
Air::ExprStart(ExprOp::Sum, S2), // 1
|
||||
Air::BindIdent(id_suba),
|
||||
Air::ExprOpen(ExprOp::Sum, S3), // 2
|
||||
Air::ExprClose(S4),
|
||||
Air::ExprClose(S5),
|
||||
Air::ExprClose(S6),
|
||||
Air::ExprStart(ExprOp::Sum, S3), // 2
|
||||
Air::ExprEnd(S4),
|
||||
Air::ExprEnd(S5),
|
||||
Air::ExprEnd(S6),
|
||||
];
|
||||
|
||||
let asg = asg_from_toks(toks);
|
||||
|
@ -592,30 +592,30 @@ fn expr_redefine_ident() {
|
|||
let id_dup = SPair("foo".into(), S3);
|
||||
|
||||
let toks = vec![
|
||||
Air::ExprOpen(ExprOp::Sum, S1),
|
||||
Air::ExprStart(ExprOp::Sum, S1),
|
||||
Air::BindIdent(id_first),
|
||||
Air::ExprOpen(ExprOp::Sum, S3),
|
||||
Air::ExprStart(ExprOp::Sum, S3),
|
||||
Air::BindIdent(id_dup),
|
||||
Air::ExprClose(S4),
|
||||
Air::ExprClose(S5),
|
||||
Air::ExprEnd(S4),
|
||||
Air::ExprEnd(S5),
|
||||
];
|
||||
|
||||
let mut sut = parse_as_pkg_body(toks);
|
||||
|
||||
assert_eq!(
|
||||
vec![
|
||||
Ok(Parsed::Incomplete), // PkgOpen
|
||||
Ok(Parsed::Incomplete), // ExprOpen
|
||||
Ok(Parsed::Incomplete), // PkgStart
|
||||
Ok(Parsed::Incomplete), // ExprStart
|
||||
Ok(Parsed::Incomplete), // BindIdent (first)
|
||||
Ok(Parsed::Incomplete), // ExprOpen
|
||||
Ok(Parsed::Incomplete), // ExprStart
|
||||
Err(ParseError::StateError(AsgError::IdentRedefine(
|
||||
id_first,
|
||||
id_dup.span(),
|
||||
))),
|
||||
// RECOVERY: Ignore the attempt to redefine and continue.
|
||||
Ok(Parsed::Incomplete), // ExprClose
|
||||
Ok(Parsed::Incomplete), // ExprClose
|
||||
Ok(Parsed::Incomplete), // PkgClose
|
||||
Ok(Parsed::Incomplete), // ExprEnd
|
||||
Ok(Parsed::Incomplete), // ExprEnd
|
||||
Ok(Parsed::Incomplete), // PkgEnd
|
||||
],
|
||||
sut.by_ref().collect::<Vec<_>>(),
|
||||
);
|
||||
|
@ -642,34 +642,34 @@ fn expr_still_dangling_on_redefine() {
|
|||
|
||||
let toks = vec![
|
||||
// First expr (OK)
|
||||
Air::ExprOpen(ExprOp::Sum, S1),
|
||||
Air::ExprStart(ExprOp::Sum, S1),
|
||||
Air::BindIdent(id_first),
|
||||
Air::ExprClose(S3),
|
||||
Air::ExprEnd(S3),
|
||||
// Second expr should still dangle due to use of duplicate
|
||||
// identifier
|
||||
Air::ExprOpen(ExprOp::Sum, S4),
|
||||
Air::ExprStart(ExprOp::Sum, S4),
|
||||
Air::BindIdent(id_dup),
|
||||
Air::ExprClose(S6),
|
||||
Air::ExprEnd(S6),
|
||||
// Third expr will error on redefine but then be successful.
|
||||
// This probably won't happen in practice with TAME's original
|
||||
// source language,
|
||||
// but could happen at e.g. a REPL.
|
||||
Air::ExprOpen(ExprOp::Sum, S7),
|
||||
Air::ExprStart(ExprOp::Sum, S7),
|
||||
Air::BindIdent(id_dup2), // fail
|
||||
Air::BindIdent(id_second), // succeed
|
||||
Air::ExprClose(S10),
|
||||
Air::ExprEnd(S10),
|
||||
];
|
||||
|
||||
let mut sut = parse_as_pkg_body(toks);
|
||||
|
||||
assert_eq!(
|
||||
vec![
|
||||
Ok(Parsed::Incomplete), // PkgOpen
|
||||
Ok(Parsed::Incomplete), // ExprOpen
|
||||
Ok(Parsed::Incomplete), // PkgStart
|
||||
Ok(Parsed::Incomplete), // ExprStart
|
||||
Ok(Parsed::Incomplete), // BindIdent (first)
|
||||
Ok(Parsed::Incomplete), // ExprClose
|
||||
Ok(Parsed::Incomplete), // ExprEnd
|
||||
// Beginning of second expression
|
||||
Ok(Parsed::Incomplete), // ExprOpen
|
||||
Ok(Parsed::Incomplete), // ExprStart
|
||||
Err(ParseError::StateError(AsgError::IdentRedefine(
|
||||
id_first,
|
||||
id_dup.span(),
|
||||
|
@ -683,7 +683,7 @@ fn expr_still_dangling_on_redefine() {
|
|||
// RECOVERY: But we'll continue onto one final expression,
|
||||
// which we will fail to define but then subsequently define
|
||||
// successfully.
|
||||
Ok(Parsed::Incomplete), // ExprOpen
|
||||
Ok(Parsed::Incomplete), // ExprStart
|
||||
Err(ParseError::StateError(AsgError::IdentRedefine(
|
||||
id_first,
|
||||
id_dup2.span(),
|
||||
|
@ -691,8 +691,8 @@ fn expr_still_dangling_on_redefine() {
|
|||
// RECOVERY: Despite the initial failure,
|
||||
// we can now re-attempt to bind with a unique id.
|
||||
Ok(Parsed::Incomplete), // BindIdent (second)
|
||||
Ok(Parsed::Incomplete), // ExprClose
|
||||
Ok(Parsed::Incomplete), // PkgClose
|
||||
Ok(Parsed::Incomplete), // ExprEnd
|
||||
Ok(Parsed::Incomplete), // PkgEnd
|
||||
],
|
||||
sut.by_ref().collect::<Vec<_>>(),
|
||||
);
|
||||
|
@ -718,20 +718,20 @@ fn expr_ref_to_ident() {
|
|||
let id_bar = SPair("bar".into(), S6);
|
||||
|
||||
let toks = vec![
|
||||
Air::ExprOpen(ExprOp::Sum, S1),
|
||||
Air::ExprStart(ExprOp::Sum, S1),
|
||||
Air::BindIdent(id_foo),
|
||||
// Reference to an as-of-yet-undefined id (okay),
|
||||
// with a different span than `id_bar`.
|
||||
Air::RefIdent(SPair("bar".into(), S3)),
|
||||
Air::ExprClose(S4),
|
||||
Air::ExprEnd(S4),
|
||||
//
|
||||
// Another expression to reference the first
|
||||
// (we don't handle cyclic references until a topological sort,
|
||||
// so no point in referencing ourselves;
|
||||
// it'd work just fine here.)
|
||||
Air::ExprOpen(ExprOp::Sum, S5),
|
||||
Air::ExprStart(ExprOp::Sum, S5),
|
||||
Air::BindIdent(id_bar),
|
||||
Air::ExprClose(S7),
|
||||
Air::ExprEnd(S7),
|
||||
];
|
||||
|
||||
let asg = asg_from_toks(toks);
|
||||
|
@ -779,34 +779,34 @@ fn expr_ref_outside_of_expr_context() {
|
|||
let toks = vec![
|
||||
// We need to first bring ourselves out of the context of the
|
||||
// package header.
|
||||
Air::ExprOpen(ExprOp::Sum, S1),
|
||||
Air::ExprStart(ExprOp::Sum, S1),
|
||||
Air::BindIdent(id_pre),
|
||||
Air::ExprClose(S3),
|
||||
Air::ExprEnd(S3),
|
||||
// This will fail since we're not in an expression context.
|
||||
Air::RefIdent(id_foo),
|
||||
// RECOVERY: Simply ignore the above.
|
||||
Air::ExprOpen(ExprOp::Sum, S1),
|
||||
Air::ExprStart(ExprOp::Sum, S1),
|
||||
Air::BindIdent(id_foo),
|
||||
Air::ExprClose(S3),
|
||||
Air::ExprEnd(S3),
|
||||
];
|
||||
|
||||
let mut sut = parse_as_pkg_body(toks);
|
||||
|
||||
assert_eq!(
|
||||
vec![
|
||||
Ok(Parsed::Incomplete), // PkgOpen
|
||||
Ok(Parsed::Incomplete), // ExprOpen
|
||||
Ok(Parsed::Incomplete), // PkgStart
|
||||
Ok(Parsed::Incomplete), // ExprStart
|
||||
Ok(Parsed::Incomplete), // BindIdent
|
||||
Ok(Parsed::Incomplete), // ExprClose
|
||||
Ok(Parsed::Incomplete), // ExprEnd
|
||||
// Now we're past the header and in expression parsing mode.
|
||||
Err(ParseError::StateError(AsgError::InvalidExprRefContext(
|
||||
id_foo
|
||||
))),
|
||||
// RECOVERY: Proceed as normal
|
||||
Ok(Parsed::Incomplete), // ExprOpen
|
||||
Ok(Parsed::Incomplete), // ExprStart
|
||||
Ok(Parsed::Incomplete), // BindIdent
|
||||
Ok(Parsed::Incomplete), // ExprClose
|
||||
Ok(Parsed::Incomplete), // PkgClose
|
||||
Ok(Parsed::Incomplete), // ExprEnd
|
||||
Ok(Parsed::Incomplete), // PkgEnd
|
||||
],
|
||||
sut.by_ref().collect::<Vec<_>>(),
|
||||
);
|
||||
|
@ -827,15 +827,15 @@ fn idents_share_defining_pkg() {
|
|||
|
||||
// An expression nested within another.
|
||||
let toks = vec![
|
||||
Air::PkgOpen(S1),
|
||||
Air::ExprOpen(ExprOp::Sum, S2),
|
||||
Air::PkgStart(S1),
|
||||
Air::ExprStart(ExprOp::Sum, S2),
|
||||
Air::BindIdent(id_foo),
|
||||
Air::ExprOpen(ExprOp::Sum, S4),
|
||||
Air::ExprStart(ExprOp::Sum, S4),
|
||||
Air::BindIdent(id_bar),
|
||||
Air::RefIdent(id_baz),
|
||||
Air::ExprClose(S7),
|
||||
Air::ExprClose(S8),
|
||||
Air::PkgClose(S9),
|
||||
Air::ExprEnd(S7),
|
||||
Air::ExprEnd(S8),
|
||||
Air::PkgEnd(S9),
|
||||
];
|
||||
|
||||
let mut sut = Sut::parse(toks.into_iter());
|
||||
|
|
|
@ -406,6 +406,20 @@ sum_ir! {
|
|||
/// populating the ASG with the raw data that that will be
|
||||
/// subsequently analyzed and rewritten.
|
||||
///
|
||||
/// Terminology
|
||||
/// ===========
|
||||
/// AIR uses the terms _start_ and _end_ to refer to tokens that act as
|
||||
/// delimiters,
|
||||
/// which is in contrast to other IRs of this system.
|
||||
/// This is to avoid confusing terminology conflicts with the term
|
||||
/// _closed_—an
|
||||
/// object is _closed_ if it contains no free variables.
|
||||
/// A variable is _free_ in some object if it has no value.
|
||||
/// For example,
|
||||
/// a template is closed iff all of its parameters have been bound to
|
||||
/// values
|
||||
/// (have received arguments or have assumed their defaults).
|
||||
///
|
||||
/// Implementation Notes
|
||||
/// ====================
|
||||
/// [`Air`] is a public token type;
|
||||
|
@ -453,13 +467,13 @@ sum_ir! {
|
|||
/// TODO: The package needs a name,
|
||||
/// and we'll need to determine how to best represent that relative to
|
||||
/// the project root and be considerate of symlinks.
|
||||
PkgOpen(span: Span) => {
|
||||
PkgStart(span: Span) => {
|
||||
span: span,
|
||||
display: |f| write!(f, "open package"),
|
||||
},
|
||||
|
||||
/// Complete processing of the current package.
|
||||
PkgClose(span: Span) => {
|
||||
PkgEnd(span: Span) => {
|
||||
span: span,
|
||||
display: |f| write!(f, "close package"),
|
||||
},
|
||||
|
@ -486,14 +500,14 @@ sum_ir! {
|
|||
/// [`Air::BindIdent`].
|
||||
///
|
||||
/// Expressions are composed of references to other expressions.
|
||||
ExprOpen(op: ExprOp, span: Span) => {
|
||||
ExprStart(op: ExprOp, span: Span) => {
|
||||
span: span,
|
||||
display: |f| write!(f, "open {op} expression"),
|
||||
},
|
||||
|
||||
/// Complete the expression atop of the expression stack and pop it from
|
||||
/// the stack.
|
||||
ExprClose(span: Span) => {
|
||||
ExprEnd(span: Span) => {
|
||||
span: span,
|
||||
display: |f| write!(f, "close expression"),
|
||||
},
|
||||
|
@ -610,7 +624,7 @@ sum_ir! {
|
|||
enum AirTpl {
|
||||
/// Create a new [`Tpl`] on the graph and switch to template parsing.
|
||||
///
|
||||
/// Until [`Self::TplClose`] is found,
|
||||
/// Until [`Self::TplEnd`] is found,
|
||||
/// all parsed objects will be parented to the [`Tpl`] rather than the
|
||||
/// parent [`Pkg`].
|
||||
/// Template parsing also recognizes additional nodes that can appear
|
||||
|
@ -618,7 +632,7 @@ sum_ir! {
|
|||
///
|
||||
/// The active expression stack will be restored after template
|
||||
/// parsing has concluded.
|
||||
TplOpen(span: Span) => {
|
||||
TplStart(span: Span) => {
|
||||
span: span,
|
||||
display: |f| write!(f, "open template"),
|
||||
},
|
||||
|
@ -626,7 +640,7 @@ sum_ir! {
|
|||
/// Close the active [`Tpl`] and exit template parsing.
|
||||
///
|
||||
/// The expression stack will be restored to its prior state.
|
||||
TplClose(span: Span) => {
|
||||
TplEnd(span: Span) => {
|
||||
span: span,
|
||||
display: |f| write!(f, "close template"),
|
||||
},
|
||||
|
|
|
@ -246,7 +246,7 @@ fn ident_root_existing() {
|
|||
|
||||
#[test]
|
||||
fn pkg_is_rooted() {
|
||||
let toks = vec![Air::PkgOpen(S1), Air::PkgClose(S2)];
|
||||
let toks = vec![Air::PkgStart(S1), Air::PkgEnd(S2)];
|
||||
|
||||
let mut sut = Sut::parse(toks.into_iter());
|
||||
assert!(sut.all(|x| x.is_ok()));
|
||||
|
@ -266,18 +266,18 @@ fn pkg_is_rooted() {
|
|||
#[test]
|
||||
fn close_pkg_without_open() {
|
||||
let toks = vec![
|
||||
Air::PkgClose(S1),
|
||||
Air::PkgEnd(S1),
|
||||
// RECOVERY: Try again.
|
||||
Air::PkgOpen(S2),
|
||||
Air::PkgClose(S3),
|
||||
Air::PkgStart(S2),
|
||||
Air::PkgEnd(S3),
|
||||
];
|
||||
|
||||
assert_eq!(
|
||||
vec![
|
||||
Err(ParseError::StateError(AsgError::InvalidPkgCloseContext(S1))),
|
||||
Err(ParseError::StateError(AsgError::InvalidPkgEndContext(S1))),
|
||||
// RECOVERY
|
||||
Ok(Parsed::Incomplete), // PkgOpen
|
||||
Ok(Parsed::Incomplete), // PkgClose
|
||||
Ok(Parsed::Incomplete), // PkgStart
|
||||
Ok(Parsed::Incomplete), // PkgEnd
|
||||
],
|
||||
Sut::parse(toks.into_iter()).collect::<Vec<_>>(),
|
||||
);
|
||||
|
@ -286,18 +286,18 @@ fn close_pkg_without_open() {
|
|||
#[test]
|
||||
fn nested_open_pkg() {
|
||||
let toks = vec![
|
||||
Air::PkgOpen(S1),
|
||||
Air::PkgOpen(S2),
|
||||
Air::PkgStart(S1),
|
||||
Air::PkgStart(S2),
|
||||
// RECOVERY
|
||||
Air::PkgClose(S3),
|
||||
Air::PkgEnd(S3),
|
||||
];
|
||||
|
||||
assert_eq!(
|
||||
vec![
|
||||
Ok(Parsed::Incomplete), // PkgOpen
|
||||
Err(ParseError::StateError(AsgError::NestedPkgOpen(S2, S1))),
|
||||
Ok(Parsed::Incomplete), // PkgStart
|
||||
Err(ParseError::StateError(AsgError::NestedPkgStart(S2, S1))),
|
||||
// RECOVERY
|
||||
Ok(Parsed::Incomplete), // PkgClose
|
||||
Ok(Parsed::Incomplete), // PkgEnd
|
||||
],
|
||||
Sut::parse(toks.into_iter()).collect::<Vec<_>>(),
|
||||
);
|
||||
|
@ -313,9 +313,9 @@ where
|
|||
use std::iter;
|
||||
|
||||
Sut::parse(
|
||||
iter::once(Air::PkgOpen(S1))
|
||||
iter::once(Air::PkgStart(S1))
|
||||
.chain(toks.into_iter())
|
||||
.chain(iter::once(Air::PkgClose(S1))),
|
||||
.chain(iter::once(Air::PkgEnd(S1))),
|
||||
)
|
||||
}
|
||||
|
||||
|
|
|
@ -114,7 +114,7 @@ impl ParseState for AirTplAggregate {
|
|||
use AirTplAggregate::*;
|
||||
|
||||
match (self, tok) {
|
||||
(Ready(oi_pkg), AirTpl(TplOpen(span))) => {
|
||||
(Ready(oi_pkg), AirTpl(TplStart(span))) => {
|
||||
let oi_tpl = asg.create(Tpl::new(span));
|
||||
|
||||
Transition(Toplevel(
|
||||
|
@ -126,7 +126,7 @@ impl ParseState for AirTplAggregate {
|
|||
.incomplete()
|
||||
}
|
||||
|
||||
(Toplevel(..), AirTpl(TplOpen(_span))) => todo!("nested tpl open"),
|
||||
(Toplevel(..), AirTpl(TplStart(_span))) => todo!("nested tpl open"),
|
||||
|
||||
(Toplevel(oi_pkg, oi_tpl, expr, _), AirBind(BindIdent(name))) => {
|
||||
asg.lookup_or_missing(name)
|
||||
|
@ -140,15 +140,12 @@ impl ParseState for AirTplAggregate {
|
|||
todo!("tpl Toplevel RefIdent")
|
||||
}
|
||||
|
||||
(
|
||||
Toplevel(oi_pkg, oi_tpl, _expr_done, _),
|
||||
AirTpl(TplClose(span)),
|
||||
) => {
|
||||
(Toplevel(oi_pkg, oi_tpl, _expr_done, _), AirTpl(TplEnd(span))) => {
|
||||
oi_tpl.close(asg, span);
|
||||
Transition(Ready(oi_pkg)).incomplete()
|
||||
}
|
||||
|
||||
(TplExpr(oi_pkg, oi_tpl, expr, name), AirTpl(TplClose(span))) => {
|
||||
(TplExpr(oi_pkg, oi_tpl, expr, name), AirTpl(TplEnd(span))) => {
|
||||
// TODO: duplicated with AirAggregate
|
||||
match expr.is_accepting(asg) {
|
||||
true => {
|
||||
|
@ -157,7 +154,7 @@ impl ParseState for AirTplAggregate {
|
|||
Transition(Ready(oi_pkg)).incomplete()
|
||||
}
|
||||
false => Transition(TplExpr(oi_pkg, oi_tpl, expr, name))
|
||||
.err(AsgError::InvalidTplCloseContext(span)),
|
||||
.err(AsgError::InvalidTplEndContext(span)),
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -171,11 +168,11 @@ impl ParseState for AirTplAggregate {
|
|||
Self::delegate_expr(asg, oi_pkg, oi_tpl, expr, name, etok)
|
||||
}
|
||||
|
||||
(TplExpr(..), AirTpl(TplOpen(_))) => {
|
||||
(TplExpr(..), AirTpl(TplStart(_))) => {
|
||||
todo!("nested template (template-generated template)")
|
||||
}
|
||||
|
||||
(st @ Ready(..), AirTpl(TplClose(span))) => {
|
||||
(st @ Ready(..), AirTpl(TplEnd(span))) => {
|
||||
Transition(st).err(AsgError::UnbalancedTpl(span))
|
||||
}
|
||||
|
||||
|
|
|
@ -37,12 +37,12 @@ fn tpl_defining_pkg() {
|
|||
let id_tpl = SPair("_tpl_".into(), S3);
|
||||
|
||||
let toks = vec![
|
||||
Air::PkgOpen(S1),
|
||||
Air::PkgStart(S1),
|
||||
// This also tests tpl as a transition away from the package header.
|
||||
Air::TplOpen(S2),
|
||||
Air::TplStart(S2),
|
||||
Air::BindIdent(id_tpl),
|
||||
Air::TplClose(S4),
|
||||
Air::PkgClose(S5),
|
||||
Air::TplEnd(S4),
|
||||
Air::PkgEnd(S5),
|
||||
];
|
||||
|
||||
let mut sut = Sut::parse(toks.into_iter());
|
||||
|
@ -66,18 +66,18 @@ fn tpl_after_expr() {
|
|||
|
||||
#[rustfmt::skip]
|
||||
let toks = vec![
|
||||
Air::PkgOpen(S1),
|
||||
Air::PkgStart(S1),
|
||||
// This expression is incidental to this test;
|
||||
// it need only parse.
|
||||
Air::ExprOpen(ExprOp::Sum, S2),
|
||||
Air::ExprStart(ExprOp::Sum, S2),
|
||||
Air::BindIdent(id_expr),
|
||||
Air::ExprClose(S4),
|
||||
Air::ExprEnd(S4),
|
||||
|
||||
// Open after an expression.
|
||||
Air::TplOpen(S5),
|
||||
Air::TplStart(S5),
|
||||
Air::BindIdent(id_tpl),
|
||||
Air::TplClose(S7),
|
||||
Air::PkgClose(S8),
|
||||
Air::TplEnd(S7),
|
||||
Air::PkgEnd(S8),
|
||||
];
|
||||
|
||||
let mut sut = Sut::parse(toks.into_iter());
|
||||
|
@ -105,27 +105,27 @@ fn tpl_within_expr() {
|
|||
|
||||
#[rustfmt::skip]
|
||||
let toks = vec![
|
||||
Air::PkgOpen(S1),
|
||||
Air::ExprOpen(ExprOp::Sum, S2),
|
||||
Air::PkgStart(S1),
|
||||
Air::ExprStart(ExprOp::Sum, S2),
|
||||
Air::BindIdent(id_expr),
|
||||
|
||||
// Child expression before the template to ensure that the
|
||||
// context is properly restored after template parsing.
|
||||
Air::ExprOpen(ExprOp::Sum, S4),
|
||||
Air::ExprClose(S5),
|
||||
Air::ExprStart(ExprOp::Sum, S4),
|
||||
Air::ExprEnd(S5),
|
||||
|
||||
// Template _within_ an expression.
|
||||
// This will not be present in the final expression,
|
||||
// as if it were hoisted out.
|
||||
Air::TplOpen(S6),
|
||||
Air::TplStart(S6),
|
||||
Air::BindIdent(id_tpl),
|
||||
Air::TplClose(S8),
|
||||
Air::TplEnd(S8),
|
||||
|
||||
// Child expression _after_ the template for the same reason.
|
||||
Air::ExprOpen(ExprOp::Sum, S9),
|
||||
Air::ExprClose(S10),
|
||||
Air::ExprClose(S11),
|
||||
Air::PkgClose(S12),
|
||||
Air::ExprStart(ExprOp::Sum, S9),
|
||||
Air::ExprEnd(S10),
|
||||
Air::ExprEnd(S11),
|
||||
Air::PkgEnd(S12),
|
||||
];
|
||||
|
||||
let mut sut = Sut::parse(toks.into_iter());
|
||||
|
@ -159,20 +159,20 @@ fn tpl_within_expr() {
|
|||
#[test]
|
||||
fn close_tpl_without_open() {
|
||||
let toks = vec![
|
||||
Air::TplClose(S1),
|
||||
Air::TplEnd(S1),
|
||||
// RECOVERY: Try again.
|
||||
Air::TplOpen(S2),
|
||||
Air::TplClose(S3),
|
||||
Air::TplStart(S2),
|
||||
Air::TplEnd(S3),
|
||||
];
|
||||
|
||||
assert_eq!(
|
||||
vec![
|
||||
Ok(Parsed::Incomplete), // PkgOpen
|
||||
Ok(Parsed::Incomplete), // PkgStart
|
||||
Err(ParseError::StateError(AsgError::UnbalancedTpl(S1))),
|
||||
// RECOVERY
|
||||
Ok(Parsed::Incomplete), // TplOpen
|
||||
Ok(Parsed::Incomplete), // TplClose
|
||||
Ok(Parsed::Incomplete), // PkgClose
|
||||
Ok(Parsed::Incomplete), // TplStart
|
||||
Ok(Parsed::Incomplete), // TplEnd
|
||||
Ok(Parsed::Incomplete), // PkgEnd
|
||||
],
|
||||
parse_as_pkg_body(toks).collect::<Vec<_>>(),
|
||||
);
|
||||
|
@ -186,17 +186,17 @@ fn tpl_with_reachable_expression() {
|
|||
|
||||
#[rustfmt::skip]
|
||||
let toks = vec![
|
||||
Air::TplOpen(S1),
|
||||
Air::TplStart(S1),
|
||||
Air::BindIdent(id_tpl),
|
||||
|
||||
Air::ExprOpen(ExprOp::Sum, S3),
|
||||
Air::ExprStart(ExprOp::Sum, S3),
|
||||
Air::BindIdent(id_expr_a),
|
||||
Air::ExprClose(S5),
|
||||
Air::ExprEnd(S5),
|
||||
|
||||
Air::ExprOpen(ExprOp::Sum, S6),
|
||||
Air::ExprStart(ExprOp::Sum, S6),
|
||||
Air::BindIdent(id_expr_b),
|
||||
Air::ExprClose(S8),
|
||||
Air::TplClose(S9),
|
||||
Air::ExprEnd(S8),
|
||||
Air::TplEnd(S9),
|
||||
];
|
||||
|
||||
let asg = asg_from_toks(toks);
|
||||
|
@ -240,17 +240,17 @@ fn tpl_holds_dangling_expressions() {
|
|||
|
||||
#[rustfmt::skip]
|
||||
let toks = vec![
|
||||
Air::TplOpen(S1),
|
||||
Air::TplStart(S1),
|
||||
Air::BindIdent(id_tpl),
|
||||
|
||||
// Dangling
|
||||
Air::ExprOpen(ExprOp::Sum, S3),
|
||||
Air::ExprClose(S4),
|
||||
Air::ExprStart(ExprOp::Sum, S3),
|
||||
Air::ExprEnd(S4),
|
||||
|
||||
// Dangling
|
||||
Air::ExprOpen(ExprOp::Sum, S5),
|
||||
Air::ExprClose(S6),
|
||||
Air::TplClose(S7),
|
||||
Air::ExprStart(ExprOp::Sum, S5),
|
||||
Air::ExprEnd(S6),
|
||||
Air::TplEnd(S7),
|
||||
];
|
||||
|
||||
let asg = asg_from_toks(toks);
|
||||
|
@ -272,30 +272,30 @@ fn close_tpl_mid_open() {
|
|||
|
||||
#[rustfmt::skip]
|
||||
let toks = vec![
|
||||
Air::TplOpen(S1),
|
||||
Air::ExprOpen(ExprOp::Sum, S2),
|
||||
Air::TplStart(S1),
|
||||
Air::ExprStart(ExprOp::Sum, S2),
|
||||
Air::BindIdent(id_expr),
|
||||
// This is misplaced.
|
||||
Air::TplClose(S4),
|
||||
Air::TplEnd(S4),
|
||||
// RECOVERY: Close the expression and try again.
|
||||
Air::ExprClose(S5),
|
||||
Air::TplClose(S6),
|
||||
Air::ExprEnd(S5),
|
||||
Air::TplEnd(S6),
|
||||
];
|
||||
|
||||
assert_eq!(
|
||||
#[rustfmt::skip]
|
||||
vec![
|
||||
Ok(Parsed::Incomplete), // PkgOpen
|
||||
Ok(Parsed::Incomplete), // TplOpen
|
||||
Ok(Parsed::Incomplete), // ExprOpen
|
||||
Ok(Parsed::Incomplete), // PkgStart
|
||||
Ok(Parsed::Incomplete), // TplStart
|
||||
Ok(Parsed::Incomplete), // ExprStart
|
||||
Ok(Parsed::Incomplete), // BindIdent
|
||||
Err(ParseError::StateError(
|
||||
AsgError::InvalidTplCloseContext(S4))
|
||||
AsgError::InvalidTplEndContext(S4))
|
||||
),
|
||||
// RECOVERY
|
||||
Ok(Parsed::Incomplete), // ExprClose
|
||||
Ok(Parsed::Incomplete), // TplClose
|
||||
Ok(Parsed::Incomplete), // PkgClose
|
||||
Ok(Parsed::Incomplete), // ExprEnd
|
||||
Ok(Parsed::Incomplete), // TplEnd
|
||||
Ok(Parsed::Incomplete), // PkgEnd
|
||||
],
|
||||
parse_as_pkg_body(toks).collect::<Vec<_>>(),
|
||||
);
|
||||
|
|
|
@ -67,10 +67,10 @@ pub enum AsgError {
|
|||
/// The first span represents the location of the second package open,
|
||||
/// and the second span represents the location of the package already
|
||||
/// being defined.
|
||||
NestedPkgOpen(Span, Span),
|
||||
NestedPkgStart(Span, Span),
|
||||
|
||||
/// Attempted to close a package when not in a package toplevel context.
|
||||
InvalidPkgCloseContext(Span),
|
||||
InvalidPkgEndContext(Span),
|
||||
|
||||
/// Attempted to open an expression in an invalid context.
|
||||
PkgExpected(Span),
|
||||
|
@ -111,7 +111,7 @@ pub enum AsgError {
|
|||
|
||||
/// Attempted to close a template when not in a template toplevel
|
||||
/// context.
|
||||
InvalidTplCloseContext(Span),
|
||||
InvalidTplEndContext(Span),
|
||||
}
|
||||
|
||||
impl Display for AsgError {
|
||||
|
@ -123,8 +123,8 @@ impl Display for AsgError {
|
|||
IdentRedefine(spair, _) => {
|
||||
write!(f, "cannot redefine {}", TtQuote::wrap(spair))
|
||||
}
|
||||
NestedPkgOpen(_, _) => write!(f, "cannot nest packages"),
|
||||
InvalidPkgCloseContext(_) => {
|
||||
NestedPkgStart(_, _) => write!(f, "cannot nest packages"),
|
||||
InvalidPkgEndContext(_) => {
|
||||
write!(f, "invalid context for package close",)
|
||||
}
|
||||
PkgExpected(_) => write!(f, "expected package definition"),
|
||||
|
@ -144,7 +144,7 @@ impl Display for AsgError {
|
|||
TtQuote::wrap(ident)
|
||||
)
|
||||
}
|
||||
InvalidTplCloseContext(_) => {
|
||||
InvalidTplEndContext(_) => {
|
||||
write!(f, "invalid context for template close",)
|
||||
}
|
||||
}
|
||||
|
@ -188,7 +188,7 @@ impl Diagnostic for AsgError {
|
|||
.help(" defined and its definition cannot be changed."),
|
||||
],
|
||||
|
||||
NestedPkgOpen(second, first) => vec![
|
||||
NestedPkgStart(second, first) => vec![
|
||||
first.note("this package is still being defined"),
|
||||
second.error("attempted to open another package here"),
|
||||
second.help(
|
||||
|
@ -197,7 +197,7 @@ impl Diagnostic for AsgError {
|
|||
),
|
||||
],
|
||||
|
||||
InvalidPkgCloseContext(span) => vec![
|
||||
InvalidPkgEndContext(span) => vec![
|
||||
span.error("package close was not expected here"),
|
||||
span.help(
|
||||
"a package must be closed at the same level of nesting \
|
||||
|
@ -244,7 +244,7 @@ impl Diagnostic for AsgError {
|
|||
of an expression context",
|
||||
)],
|
||||
|
||||
InvalidTplCloseContext(span) => vec![
|
||||
InvalidTplEndContext(span) => vec![
|
||||
span.error("template close was not expected here"),
|
||||
span.help(
|
||||
"a template must be closed at the same level of nesting \
|
||||
|
|
|
@ -63,20 +63,20 @@ fn traverses_ontological_tree() {
|
|||
|
||||
#[rustfmt::skip]
|
||||
let toks = vec![
|
||||
PkgOpen(S1),
|
||||
ExprOpen(ExprOp::Sum, S2),
|
||||
PkgStart(S1),
|
||||
ExprStart(ExprOp::Sum, S2),
|
||||
BindIdent(id_a),
|
||||
|
||||
ExprOpen(ExprOp::Sum, S4),
|
||||
ExprClose(S5),
|
||||
ExprStart(ExprOp::Sum, S4),
|
||||
ExprEnd(S5),
|
||||
|
||||
RefIdent(SPair(id_b.symbol(), S6)),
|
||||
ExprClose(S7),
|
||||
ExprEnd(S7),
|
||||
|
||||
ExprOpen(ExprOp::Sum, S8),
|
||||
ExprStart(ExprOp::Sum, S8),
|
||||
BindIdent(id_b),
|
||||
ExprClose(S10),
|
||||
PkgClose(S11),
|
||||
ExprEnd(S10),
|
||||
PkgEnd(S11),
|
||||
];
|
||||
|
||||
let asg = asg_from_toks(toks);
|
||||
|
@ -140,20 +140,20 @@ fn traverses_ontological_tree_tpl_with_sibling_at_increasing_depth() {
|
|||
|
||||
#[rustfmt::skip]
|
||||
let toks = vec![
|
||||
PkgOpen(S1),
|
||||
TplOpen(S2),
|
||||
PkgStart(S1),
|
||||
TplStart(S2),
|
||||
BindIdent(id_tpl),
|
||||
|
||||
// Dangling
|
||||
ExprOpen(ExprOp::Sum, S4),
|
||||
ExprClose(S5),
|
||||
ExprStart(ExprOp::Sum, S4),
|
||||
ExprEnd(S5),
|
||||
|
||||
// Reachable
|
||||
ExprOpen(ExprOp::Sum, S6),
|
||||
ExprStart(ExprOp::Sum, S6),
|
||||
BindIdent(id_expr),
|
||||
ExprClose(S8),
|
||||
TplClose(S9),
|
||||
PkgClose(S10),
|
||||
ExprEnd(S8),
|
||||
TplEnd(S9),
|
||||
PkgEnd(S10),
|
||||
];
|
||||
|
||||
let asg = asg_from_toks(toks);
|
||||
|
|
|
@ -68,38 +68,38 @@ impl ParseState for NirToAir {
|
|||
#[allow(unreachable_code)] // due to wip-nir-to-air
|
||||
match (self, tok) {
|
||||
(Ready, Nir::Open(NirEntity::Package, span)) => {
|
||||
Transition(Ready).ok(Air::PkgOpen(span))
|
||||
Transition(Ready).ok(Air::PkgStart(span))
|
||||
}
|
||||
|
||||
(Ready, Nir::Close(NirEntity::Package, span)) => {
|
||||
Transition(Ready).ok(Air::PkgClose(span))
|
||||
Transition(Ready).ok(Air::PkgEnd(span))
|
||||
}
|
||||
|
||||
(Ready, Nir::Open(NirEntity::Rate | NirEntity::Sum, span)) => {
|
||||
Transition(Ready).ok(Air::ExprOpen(ExprOp::Sum, span))
|
||||
Transition(Ready).ok(Air::ExprStart(ExprOp::Sum, span))
|
||||
}
|
||||
(Ready, Nir::Open(NirEntity::Product, span)) => {
|
||||
Transition(Ready).ok(Air::ExprOpen(ExprOp::Product, span))
|
||||
Transition(Ready).ok(Air::ExprStart(ExprOp::Product, span))
|
||||
}
|
||||
(Ready, Nir::Open(NirEntity::Ceil, span)) => {
|
||||
Transition(Ready).ok(Air::ExprOpen(ExprOp::Ceil, span))
|
||||
Transition(Ready).ok(Air::ExprStart(ExprOp::Ceil, span))
|
||||
}
|
||||
(Ready, Nir::Open(NirEntity::Floor, span)) => {
|
||||
Transition(Ready).ok(Air::ExprOpen(ExprOp::Floor, span))
|
||||
Transition(Ready).ok(Air::ExprStart(ExprOp::Floor, span))
|
||||
}
|
||||
(Ready, Nir::Open(NirEntity::Classify | NirEntity::All, span)) => {
|
||||
Transition(Ready).ok(Air::ExprOpen(ExprOp::Conj, span))
|
||||
Transition(Ready).ok(Air::ExprStart(ExprOp::Conj, span))
|
||||
}
|
||||
(Ready, Nir::Open(NirEntity::Any, span)) => {
|
||||
Transition(Ready).ok(Air::ExprOpen(ExprOp::Disj, span))
|
||||
Transition(Ready).ok(Air::ExprStart(ExprOp::Disj, span))
|
||||
}
|
||||
|
||||
(Ready, Nir::Open(NirEntity::Tpl, span)) => {
|
||||
Transition(Ready).ok(Air::TplOpen(span))
|
||||
Transition(Ready).ok(Air::TplStart(span))
|
||||
}
|
||||
|
||||
(Ready, Nir::Close(NirEntity::Tpl, span)) => {
|
||||
Transition(Ready).ok(Air::TplClose(span))
|
||||
Transition(Ready).ok(Air::TplEnd(span))
|
||||
}
|
||||
|
||||
(
|
||||
|
@ -115,7 +115,7 @@ impl ParseState for NirToAir {
|
|||
| NirEntity::Any,
|
||||
span,
|
||||
),
|
||||
) => Transition(Ready).ok(Air::ExprClose(span)),
|
||||
) => Transition(Ready).ok(Air::ExprEnd(span)),
|
||||
|
||||
(Ready, Nir::BindIdent(spair)) => {
|
||||
Transition(Ready).ok(Air::BindIdent(spair))
|
||||
|
|
|
@ -32,7 +32,7 @@ fn package_to_pkg() {
|
|||
];
|
||||
|
||||
assert_eq!(
|
||||
Ok(vec![O(Air::PkgOpen(S1)), O(Air::PkgClose(S2)),]),
|
||||
Ok(vec![O(Air::PkgStart(S1)), O(Air::PkgEnd(S2)),]),
|
||||
Sut::parse(toks.into_iter()).collect(),
|
||||
);
|
||||
}
|
||||
|
@ -49,9 +49,9 @@ fn rate_to_sum_expr() {
|
|||
|
||||
assert_eq!(
|
||||
Ok(vec![
|
||||
O(Air::ExprOpen(ExprOp::Sum, S1)),
|
||||
O(Air::ExprStart(ExprOp::Sum, S1)),
|
||||
O(Air::BindIdent(id)),
|
||||
O(Air::ExprClose(S3)),
|
||||
O(Air::ExprEnd(S3)),
|
||||
]),
|
||||
Sut::parse(toks.into_iter()).collect(),
|
||||
);
|
||||
|
@ -68,10 +68,10 @@ fn calc_exprs() {
|
|||
|
||||
assert_eq!(
|
||||
Ok(vec![
|
||||
O(Air::ExprOpen(ExprOp::Sum, S1)),
|
||||
O(Air::ExprOpen(ExprOp::Product, S2)),
|
||||
O(Air::ExprClose(S3)),
|
||||
O(Air::ExprClose(S4)),
|
||||
O(Air::ExprStart(ExprOp::Sum, S1)),
|
||||
O(Air::ExprStart(ExprOp::Product, S2)),
|
||||
O(Air::ExprEnd(S3)),
|
||||
O(Air::ExprEnd(S4)),
|
||||
]),
|
||||
Sut::parse(toks.into_iter()).collect(),
|
||||
);
|
||||
|
@ -89,9 +89,9 @@ fn classify_to_conj_expr() {
|
|||
|
||||
assert_eq!(
|
||||
Ok(vec![
|
||||
O(Air::ExprOpen(ExprOp::Conj, S1)),
|
||||
O(Air::ExprStart(ExprOp::Conj, S1)),
|
||||
O(Air::BindIdent(id)),
|
||||
O(Air::ExprClose(S3)),
|
||||
O(Air::ExprEnd(S3)),
|
||||
]),
|
||||
Sut::parse(toks.into_iter()).collect(),
|
||||
);
|
||||
|
@ -108,10 +108,10 @@ fn logic_exprs() {
|
|||
|
||||
assert_eq!(
|
||||
Ok(vec![
|
||||
O(Air::ExprOpen(ExprOp::Conj, S1)),
|
||||
O(Air::ExprOpen(ExprOp::Disj, S2)),
|
||||
O(Air::ExprClose(S3)),
|
||||
O(Air::ExprClose(S4)),
|
||||
O(Air::ExprStart(ExprOp::Conj, S1)),
|
||||
O(Air::ExprStart(ExprOp::Disj, S2)),
|
||||
O(Air::ExprEnd(S3)),
|
||||
O(Air::ExprEnd(S4)),
|
||||
]),
|
||||
Sut::parse(toks.into_iter()).collect(),
|
||||
);
|
||||
|
@ -130,9 +130,9 @@ fn tpl_with_name() {
|
|||
#[rustfmt::skip]
|
||||
assert_eq!(
|
||||
Ok(vec![
|
||||
O(Air::TplOpen(S1)),
|
||||
O(Air::TplStart(S1)),
|
||||
O(Air::BindIdent(name)),
|
||||
O(Air::TplClose(S3)),
|
||||
O(Air::TplEnd(S3)),
|
||||
]),
|
||||
Sut::parse(toks.into_iter()).collect(),
|
||||
);
|
||||
|
|
Loading…
Reference in New Issue