tamer: asg::air::ir::AirPkg::PkgStart: Require name
This requires the name as part of the package definition, which in turn removes a state (and all the combinations resulting from it) from AirAggregate, which results in significant complexity reduction for a very complex part of the system. Pushing this complexity outward results in a reduction of overall complexity, and obviates the question of where NIR will receive a generated name. DEV-13162main
parent
7a6aef00b2
commit
dd6a6dd196
|
@ -138,25 +138,13 @@ impl ParseState for AirAggregate {
|
|||
tok: Self::Token,
|
||||
ctx: &mut Self::Context,
|
||||
) -> crate::parse::TransitionResult<Self> {
|
||||
use ir::{AirBind::BindIdent, AirSubsets::*, AirTodo::*};
|
||||
use ir::{AirSubsets::*, AirTodo::*};
|
||||
use AirAggregate::*;
|
||||
use AirPkgAggregate::{Toplevel, UnnamedPkg};
|
||||
|
||||
match (self, tok.into()) {
|
||||
(st, AirTodo(Todo(_))) => Transition(st).incomplete(),
|
||||
|
||||
// TODO: Remove this kluge; transitionary (no package name required)
|
||||
(Pkg(UnnamedPkg(span)), tok)
|
||||
if !matches!(tok, AirBind(BindIdent(..))) =>
|
||||
{
|
||||
match ctx.pkg_begin(span, SPair("/TODO".into(), span)) {
|
||||
Ok(oi_pkg) => Transition(Pkg(Toplevel(oi_pkg)))
|
||||
.incomplete()
|
||||
.with_lookahead(tok),
|
||||
Err(e) => Transition(Pkg(UnnamedPkg(span))).err(e),
|
||||
}
|
||||
}
|
||||
|
||||
// Package
|
||||
(st @ (Empty | PkgExpr(..) | PkgTpl(..)), tok @ AirPkg(..)) => {
|
||||
ctx.ret_or_transfer(st, tok, AirPkgAggregate::new())
|
||||
}
|
||||
|
@ -165,6 +153,7 @@ impl ParseState for AirAggregate {
|
|||
(Pkg(pkg), AirIdent(etok)) => ctx.proxy(pkg, etok),
|
||||
(Pkg(pkg), AirDoc(etok)) => ctx.proxy(pkg, etok),
|
||||
|
||||
// Expression
|
||||
(st @ (Pkg(_) | PkgTpl(_)), tok @ AirExpr(..)) => {
|
||||
ctx.ret_or_transfer(st, tok, AirExprAggregate::new())
|
||||
}
|
||||
|
@ -172,7 +161,7 @@ impl ParseState for AirAggregate {
|
|||
(PkgExpr(expr), AirBind(etok)) => ctx.proxy(expr, etok),
|
||||
(PkgExpr(expr), AirDoc(etok)) => ctx.proxy(expr, etok),
|
||||
|
||||
// Template parsing.
|
||||
// Template
|
||||
(st @ (Pkg(_) | PkgExpr(_)), tok @ AirTpl(..)) => {
|
||||
ctx.ret_or_transfer(st, tok, AirTplAggregate::new())
|
||||
}
|
||||
|
@ -303,6 +292,10 @@ impl AirAggregateCtx {
|
|||
self.as_mut()
|
||||
}
|
||||
|
||||
fn asg_ref(&self) -> &Asg {
|
||||
self.as_ref()
|
||||
}
|
||||
|
||||
fn stack(&mut self) -> &mut AirStack {
|
||||
let Self(_, stack, _) = self;
|
||||
stack
|
||||
|
|
|
@ -73,7 +73,7 @@ fn expr_without_pkg() {
|
|||
// (because we're not parsing with `parse_as_pkg_body` below)
|
||||
Air::ExprStart(ExprOp::Sum, S1),
|
||||
// RECOVERY
|
||||
Air::PkgStart(S2),
|
||||
Air::PkgStart(S2, SPair("/pkg".into(), S2)),
|
||||
Air::PkgEnd(S3),
|
||||
];
|
||||
|
||||
|
@ -95,7 +95,7 @@ fn close_pkg_mid_expr() {
|
|||
|
||||
#[rustfmt::skip]
|
||||
let toks = vec![
|
||||
Air::PkgStart(S1),
|
||||
Air::PkgStart(S1, SPair("/pkg".into(), S1)),
|
||||
Air::ExprStart(ExprOp::Sum, S2),
|
||||
Air::PkgEnd(S3),
|
||||
// RECOVERY: Let's finish the expression first...
|
||||
|
@ -126,13 +126,15 @@ fn close_pkg_mid_expr() {
|
|||
|
||||
#[test]
|
||||
fn open_pkg_mid_expr() {
|
||||
let pkg_a = SPair("/pkg".into(), S1);
|
||||
let pkg_nested = SPair("/pkg-nested".into(), S3);
|
||||
let id = SPair("foo".into(), S4);
|
||||
|
||||
#[rustfmt::skip]
|
||||
let toks = vec![
|
||||
Air::PkgStart(S1),
|
||||
Air::PkgStart(S1, pkg_a),
|
||||
Air::ExprStart(ExprOp::Sum, S2),
|
||||
Air::PkgStart(S3),
|
||||
Air::PkgStart(S3, pkg_nested),
|
||||
// RECOVERY: We should still be able to complete successfully.
|
||||
Air::BindIdent(id),
|
||||
Air::ExprEnd(S5),
|
||||
|
@ -145,7 +147,10 @@ fn open_pkg_mid_expr() {
|
|||
vec![
|
||||
Ok(Parsed::Incomplete), // PkgStart
|
||||
Ok(Parsed::Incomplete), // ExprStart
|
||||
Err(ParseError::StateError(AsgError::NestedPkgStart(S3, S1))),
|
||||
Err(ParseError::StateError(AsgError::NestedPkgStart(
|
||||
(S3, pkg_nested),
|
||||
(S1, pkg_a),
|
||||
))),
|
||||
// RECOVERY: Ignore the open and continue.
|
||||
// Of course,
|
||||
// this means that any identifiers would be defined in a
|
||||
|
@ -756,7 +761,7 @@ fn idents_share_defining_pkg() {
|
|||
// An expression nested within another.
|
||||
#[rustfmt::skip]
|
||||
let toks = vec![
|
||||
Air::PkgStart(S1),
|
||||
Air::PkgStart(S1, SPair("/pkg".into(), S1)),
|
||||
Air::ExprStart(ExprOp::Sum, S2),
|
||||
Air::BindIdent(id_foo),
|
||||
|
||||
|
|
|
@ -466,10 +466,18 @@ sum_ir! {
|
|||
/// within a given package,
|
||||
/// but we have no such restriction.
|
||||
///
|
||||
/// 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.
|
||||
PkgStart(span: Span) => {
|
||||
/// Packages are assigned unique names in a similar way to
|
||||
/// identifiers.
|
||||
/// This name is generally expected to be generated from the
|
||||
/// path to the package on the host filesystem,
|
||||
/// so no guarantees are made as to the [`Span`] associated
|
||||
/// with the provided `name`.
|
||||
/// For clarity,
|
||||
/// the first [`Span`] is intended to represent the start of
|
||||
/// the package declaration,
|
||||
/// however that is represented by the source stream;
|
||||
/// the `name` [`Span`] may or may not duplicate it.
|
||||
PkgStart(span: Span, name: SPair) => {
|
||||
span: span,
|
||||
display: |f| write!(f, "open package"),
|
||||
},
|
||||
|
|
|
@ -26,9 +26,7 @@ use super::{
|
|||
ir::AirLoadablePkg,
|
||||
AirAggregate, AirAggregateCtx,
|
||||
};
|
||||
use crate::{
|
||||
diagnose::Annotate, diagnostic_todo, parse::prelude::*, span::Span,
|
||||
};
|
||||
use crate::{diagnose::Annotate, diagnostic_todo, parse::prelude::*};
|
||||
|
||||
/// Package parsing with support for loaded identifiers.
|
||||
///
|
||||
|
@ -41,10 +39,6 @@ pub enum AirPkgAggregate {
|
|||
/// expression stack is empty.
|
||||
Ready,
|
||||
|
||||
/// Package definition or declaration started,
|
||||
/// but the name is not yet known.
|
||||
UnnamedPkg(Span),
|
||||
|
||||
/// Expecting a package-level token.
|
||||
Toplevel(ObjectIndex<Pkg>),
|
||||
}
|
||||
|
@ -57,9 +51,6 @@ impl Display for AirPkgAggregate {
|
|||
Ready => {
|
||||
write!(f, "expecting package definition")
|
||||
}
|
||||
UnnamedPkg(_) => {
|
||||
write!(f, "expecting canonical package name")
|
||||
}
|
||||
Toplevel(_) => {
|
||||
write!(f, "expecting package header or an expression")
|
||||
}
|
||||
|
@ -84,34 +75,28 @@ impl ParseState for AirPkgAggregate {
|
|||
use AirPkgAggregate::*;
|
||||
|
||||
match (self, tok) {
|
||||
(Ready, AirPkg(PkgStart(span))) => {
|
||||
if let Some(first_span) = ctx.pkg_oi().map(|oi| oi.span()) {
|
||||
Transition(Ready)
|
||||
.err(AsgError::NestedPkgStart(span, first_span))
|
||||
(st @ (Ready | Toplevel(..)), AirPkg(PkgStart(span, name))) => {
|
||||
if let Some(first) =
|
||||
ctx.pkg_oi().map(|oi| oi.resolve(ctx.asg_ref()))
|
||||
{
|
||||
let first_span = first.span();
|
||||
let first_name = first.canonical_name();
|
||||
|
||||
Transition(st).err(AsgError::NestedPkgStart(
|
||||
(span, name),
|
||||
(first_span, first_name),
|
||||
))
|
||||
} else {
|
||||
Transition(UnnamedPkg(span)).incomplete()
|
||||
match ctx.pkg_begin(span, name) {
|
||||
Ok(oi_pkg) => Transition(Toplevel(oi_pkg)).incomplete(),
|
||||
Err(e) => Transition(Ready).err(e),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
(Toplevel(oi_pkg), AirPkg(PkgStart(span))) => {
|
||||
(Toplevel(oi_pkg), AirBind(BindIdent(name))) => {
|
||||
Transition(Toplevel(oi_pkg))
|
||||
.err(AsgError::NestedPkgStart(span, oi_pkg.span()))
|
||||
}
|
||||
|
||||
// Packages are identified by canonical paths relative to the
|
||||
// project root.
|
||||
(UnnamedPkg(span), AirBind(BindIdent(name))) => {
|
||||
match ctx.pkg_begin(span, name) {
|
||||
Ok(oi_pkg) => Transition(Toplevel(oi_pkg)).incomplete(),
|
||||
Err(e) => Transition(UnnamedPkg(span)).err(e),
|
||||
}
|
||||
}
|
||||
|
||||
(Toplevel(oi_pkg), AirBind(BindIdent(rename))) => {
|
||||
let name = oi_pkg.resolve(ctx.asg_mut()).canonical_name();
|
||||
|
||||
Transition(Toplevel(oi_pkg))
|
||||
.err(AsgError::PkgRename(name, rename))
|
||||
.err(AsgError::InvalidBindContext(name))
|
||||
}
|
||||
|
||||
(Toplevel(oi_pkg), AirPkg(PkgEnd(span))) => {
|
||||
|
@ -195,19 +180,6 @@ impl ParseState for AirPkgAggregate {
|
|||
Transition(Ready).err(AsgError::InvalidPkgEndContext(span))
|
||||
}
|
||||
|
||||
// TODO: See superstate
|
||||
(UnnamedPkg(span), tok) => {
|
||||
diagnostic_todo!(
|
||||
vec![
|
||||
span.note("for this package"),
|
||||
tok.internal_error(
|
||||
"package name expected before this token"
|
||||
),
|
||||
],
|
||||
"package name expected",
|
||||
)
|
||||
}
|
||||
|
||||
// Token may refer to a parent context.
|
||||
(st @ Ready, tok @ (AirBind(..) | AirIdent(..) | AirDoc(..))) => {
|
||||
Transition(st).dead(tok)
|
||||
|
@ -231,7 +203,7 @@ impl AirPkgAggregate {
|
|||
use AirPkgAggregate::*;
|
||||
|
||||
match self {
|
||||
Ready | UnnamedPkg(_) => None,
|
||||
Ready => None,
|
||||
Toplevel(oi_pkg) => Some(*oi_pkg),
|
||||
}
|
||||
}
|
||||
|
|
|
@ -46,7 +46,7 @@ fn ident_decl() {
|
|||
|
||||
#[rustfmt::skip]
|
||||
let toks = vec![
|
||||
PkgStart(S1),
|
||||
PkgStart(S1, SPair("/pkg".into(), S1)),
|
||||
IdentDecl(id, kind.clone(), src.clone()),
|
||||
// Attempt re-declaration.
|
||||
IdentDecl(id, kind.clone(), src.clone()),
|
||||
|
@ -97,7 +97,7 @@ fn ident_extern_decl() {
|
|||
|
||||
#[rustfmt::skip]
|
||||
let toks = vec![
|
||||
PkgStart(S1),
|
||||
PkgStart(S1, SPair("/pkg".into(), S1)),
|
||||
IdentExternDecl(id, kind.clone(), src.clone()),
|
||||
// Redeclare with a different kind
|
||||
IdentExternDecl(re_id, different_kind.clone(), src.clone()),
|
||||
|
@ -144,7 +144,7 @@ fn ident_dep() {
|
|||
|
||||
#[rustfmt::skip]
|
||||
let toks = vec![
|
||||
PkgStart(S1),
|
||||
PkgStart(S1, SPair("/pkg".into(), S1)),
|
||||
IdentDep(id, dep),
|
||||
PkgEnd(S4),
|
||||
].into_iter();
|
||||
|
@ -182,7 +182,7 @@ fn ident_fragment() {
|
|||
|
||||
#[rustfmt::skip]
|
||||
let toks = vec![
|
||||
PkgStart(S1),
|
||||
PkgStart(S1, SPair("/pkg".into(), S1)),
|
||||
// Identifier must be declared before it can be given a
|
||||
// fragment.
|
||||
IdentDecl(id, kind.clone(), src.clone()),
|
||||
|
@ -234,7 +234,7 @@ fn ident_root_missing() {
|
|||
|
||||
#[rustfmt::skip]
|
||||
let toks = vec![
|
||||
PkgStart(S1),
|
||||
PkgStart(S1, SPair("/pkg".into(), S1)),
|
||||
IdentRoot(id),
|
||||
PkgEnd(S3),
|
||||
].into_iter();
|
||||
|
@ -280,7 +280,7 @@ fn ident_root_existing() {
|
|||
|
||||
#[rustfmt::skip]
|
||||
let toks = vec![
|
||||
PkgStart(S1),
|
||||
PkgStart(S1, SPair("/pkg".into(), S1)),
|
||||
IdentDecl(id, kind.clone(), src.clone()),
|
||||
IdentRoot(SPair(id.symbol(), S3)),
|
||||
PkgEnd(S3),
|
||||
|
@ -337,7 +337,7 @@ fn declare_kind_auto_root() {
|
|||
|
||||
#[rustfmt::skip]
|
||||
let toks = [
|
||||
PkgStart(S1),
|
||||
PkgStart(S1, SPair("/pkg".into(), S1)),
|
||||
// auto-rooting
|
||||
IdentDecl(id_auto, auto_kind, src.clone()),
|
||||
// non-auto-rooting
|
||||
|
@ -369,7 +369,11 @@ fn declare_kind_auto_root() {
|
|||
|
||||
#[test]
|
||||
fn pkg_is_rooted() {
|
||||
let toks = vec![PkgStart(S1), PkgEnd(S2)];
|
||||
#[rustfmt::skip]
|
||||
let toks = vec![
|
||||
PkgStart(S1, SPair("/pkg".into(), S1)),
|
||||
PkgEnd(S2),
|
||||
];
|
||||
|
||||
let mut sut = Sut::parse(toks.into_iter());
|
||||
assert!(sut.all(|x| x.is_ok()));
|
||||
|
@ -391,7 +395,7 @@ fn close_pkg_without_open() {
|
|||
let toks = vec![
|
||||
PkgEnd(S1),
|
||||
// RECOVERY: Try again.
|
||||
PkgStart(S2),
|
||||
PkgStart(S2, SPair("/pkg".into(), S2)),
|
||||
PkgEnd(S3),
|
||||
];
|
||||
|
||||
|
@ -408,23 +412,25 @@ fn close_pkg_without_open() {
|
|||
|
||||
#[test]
|
||||
fn nested_open_pkg() {
|
||||
let name_a = SPair("/pkg-a".into(), S2);
|
||||
let name_b = SPair("/pkg-b".into(), S4);
|
||||
|
||||
#[rustfmt::skip]
|
||||
let toks = vec![
|
||||
PkgStart(S1),
|
||||
BindIdent(SPair("/foo".into(), S2)),
|
||||
|
||||
PkgStart(S1, name_a),
|
||||
// Cannot nest package
|
||||
PkgStart(S3),
|
||||
PkgStart(S3, name_b),
|
||||
// RECOVERY
|
||||
PkgEnd(S4),
|
||||
PkgEnd(S5),
|
||||
];
|
||||
|
||||
assert_eq!(
|
||||
#[rustfmt::skip]
|
||||
vec![
|
||||
Ok(Incomplete), // PkgStart
|
||||
Ok(Incomplete), // BindIdent
|
||||
Err(ParseError::StateError(AsgError::NestedPkgStart(S3, S1))),
|
||||
Err(ParseError::StateError(AsgError::NestedPkgStart(
|
||||
(S3, name_b), (S1, name_a),
|
||||
))),
|
||||
// RECOVERY
|
||||
Ok(Incomplete), // PkgEnd
|
||||
],
|
||||
|
@ -438,8 +444,7 @@ fn pkg_canonical_name() {
|
|||
|
||||
#[rustfmt::skip]
|
||||
let toks = vec![
|
||||
PkgStart(S1),
|
||||
BindIdent(name),
|
||||
PkgStart(S1, name),
|
||||
PkgEnd(S3),
|
||||
];
|
||||
|
||||
|
@ -472,21 +477,19 @@ fn pkg_canonical_name() {
|
|||
fn pkg_cannot_redeclare() {
|
||||
let name = SPair("/foo/bar".into(), S2);
|
||||
let name2 = SPair("/foo/bar".into(), S5);
|
||||
let namefix = SPair("/foo/fix".into(), S6);
|
||||
let namefix = SPair("/foo/fix".into(), S7);
|
||||
|
||||
#[rustfmt::skip]
|
||||
let toks = vec![
|
||||
PkgStart(S1),
|
||||
BindIdent(name),
|
||||
PkgStart(S1, name),
|
||||
PkgEnd(S3),
|
||||
|
||||
PkgStart(S4),
|
||||
// Attempt to define a package of the same name.
|
||||
BindIdent(name2),
|
||||
// Attempt to define a package of the same name.
|
||||
PkgStart(S4, name2),
|
||||
|
||||
// RECOVERY: Use a proper name.
|
||||
BindIdent(namefix),
|
||||
PkgEnd(S7),
|
||||
// RECOVERY: Use a proper name.
|
||||
PkgStart(S6, namefix),
|
||||
PkgEnd(S8),
|
||||
];
|
||||
|
||||
let mut sut = Sut::parse(toks.into_iter());
|
||||
|
@ -495,15 +498,14 @@ fn pkg_cannot_redeclare() {
|
|||
#[rustfmt::skip]
|
||||
vec![
|
||||
Ok(Incomplete), // PkgStart
|
||||
Ok(Incomplete), // BindIdent
|
||||
Ok(Incomplete), // PkgEnd
|
||||
|
||||
Err(ParseError::StateError(
|
||||
AsgError::PkgRedeclare(name, name2)
|
||||
)),
|
||||
|
||||
// RECOVERY: Retry with a proper name
|
||||
Ok(Incomplete), // PkgStart
|
||||
Err(ParseError::StateError(
|
||||
AsgError::PkgRedeclare(name, name2)
|
||||
)),
|
||||
// RECOVERY: Ignore the attempted name
|
||||
Ok(Incomplete), // BindIdent
|
||||
Ok(Incomplete), // PkgEnd
|
||||
],
|
||||
sut.by_ref().collect::<Vec<_>>(),
|
||||
|
@ -516,45 +518,37 @@ fn pkg_cannot_redeclare() {
|
|||
let oi_pkg = asg
|
||||
.lookup::<Pkg>(oi_root, namefix)
|
||||
.expect("failed to locate package by its recovery name");
|
||||
assert_eq!(S4.merge(S7).unwrap(), oi_pkg.resolve(&asg).span());
|
||||
assert_eq!(S6.merge(S8).unwrap(), oi_pkg.resolve(&asg).span());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn pkg_cannot_rename() {
|
||||
let name = SPair("/foo/bar".into(), S2);
|
||||
let name2 = SPair("/bad/rename".into(), S3);
|
||||
let pkg_name = SPair("/foo/bar".into(), S1);
|
||||
let name = SPair("baz".into(), S2);
|
||||
|
||||
#[rustfmt::skip]
|
||||
let toks = vec![
|
||||
PkgStart(S1),
|
||||
PkgStart(S1, pkg_name),
|
||||
BindIdent(name),
|
||||
// Attempt to provide a name a second time.
|
||||
BindIdent(name2),
|
||||
// RECOVERY: Just ignore it.
|
||||
PkgEnd(S4),
|
||||
PkgEnd(S3),
|
||||
];
|
||||
|
||||
let mut sut = Sut::parse(toks.into_iter());
|
||||
let sut = Sut::parse(toks.into_iter());
|
||||
|
||||
assert_eq!(
|
||||
#[rustfmt::skip]
|
||||
vec![
|
||||
Ok(Incomplete), // PkgStart
|
||||
Ok(Incomplete), // BindIdent
|
||||
Err(ParseError::StateError(AsgError::PkgRename(name, name2))),
|
||||
// RECOVERY: Ignore the attempted rename
|
||||
Ok(Incomplete), // PkgEnd
|
||||
Ok(Incomplete), // PkgStart
|
||||
|
||||
Err(ParseError::StateError(
|
||||
AsgError::InvalidBindContext(name),
|
||||
)),
|
||||
|
||||
// RECOVERY
|
||||
Ok(Incomplete), // PkgEnd
|
||||
],
|
||||
sut.by_ref().collect::<Vec<_>>(),
|
||||
sut.collect::<Vec<_>>(),
|
||||
);
|
||||
|
||||
let asg = sut.finalize().unwrap().into_context();
|
||||
|
||||
// The original name should have been kept.
|
||||
let oi_root = asg.root(S1);
|
||||
let oi_pkg = asg
|
||||
.lookup::<Pkg>(oi_root, name)
|
||||
.expect("failed to locate package by its original name");
|
||||
assert_eq!(S1.merge(S4).unwrap(), oi_pkg.resolve(&asg).span());
|
||||
}
|
||||
|
||||
#[test]
|
||||
|
@ -564,8 +558,7 @@ fn pkg_import_canonicalized_against_current_pkg() {
|
|||
|
||||
#[rustfmt::skip]
|
||||
let toks = vec![
|
||||
PkgStart(S1),
|
||||
BindIdent(pkg_name),
|
||||
PkgStart(S1, pkg_name),
|
||||
RefIdent(pkg_rel),
|
||||
PkgEnd(S3),
|
||||
];
|
||||
|
@ -634,7 +627,7 @@ where
|
|||
use std::iter;
|
||||
|
||||
Sut::parse(
|
||||
iter::once(PkgStart(S1))
|
||||
iter::once(PkgStart(S1, SPair("/pkg".into(), S1)))
|
||||
.chain(toks.into_iter())
|
||||
.chain(iter::once(PkgEnd(S1))),
|
||||
)
|
||||
|
|
|
@ -42,7 +42,7 @@ fn tpl_defining_pkg() {
|
|||
|
||||
#[rustfmt::skip]
|
||||
let toks = vec![
|
||||
Air::PkgStart(S1),
|
||||
Air::PkgStart(S1, SPair("/pkg".into(), S1)),
|
||||
// This also tests tpl as a transition away from the package header.
|
||||
Air::TplStart(S2),
|
||||
Air::BindIdent(id_tpl),
|
||||
|
@ -71,7 +71,7 @@ fn tpl_after_expr() {
|
|||
|
||||
#[rustfmt::skip]
|
||||
let toks = vec![
|
||||
Air::PkgStart(S1),
|
||||
Air::PkgStart(S1, SPair("/pkg".into(), S1)),
|
||||
// This expression is incidental to this test;
|
||||
// it need only parse.
|
||||
Air::ExprStart(ExprOp::Sum, S2),
|
||||
|
@ -110,7 +110,7 @@ fn tpl_within_expr() {
|
|||
|
||||
#[rustfmt::skip]
|
||||
let toks = vec![
|
||||
Air::PkgStart(S1),
|
||||
Air::PkgStart(S1, SPair("/pkg".into(), S1)),
|
||||
Air::ExprStart(ExprOp::Sum, S2),
|
||||
Air::BindIdent(id_expr),
|
||||
|
||||
|
|
|
@ -72,21 +72,14 @@ pub enum AsgError {
|
|||
/// respectively.
|
||||
PkgRedeclare(SPair, SPair),
|
||||
|
||||
/// Attempted to rename a package from the first [`SPair`] to the
|
||||
/// second.
|
||||
///
|
||||
/// "Rename" here means that the package already had a name and we were
|
||||
/// provided another,
|
||||
/// which is almost certainly a mistake.
|
||||
PkgRename(SPair, SPair),
|
||||
|
||||
/// Attempted to open a package while defining another package.
|
||||
///
|
||||
/// Packages cannot be nested.
|
||||
/// The first span represents the location of the second package open,
|
||||
/// and the second span represents the location of the package already
|
||||
/// being defined.
|
||||
NestedPkgStart(Span, Span),
|
||||
/// The [`SPair`]s are the respective package names.
|
||||
NestedPkgStart((Span, SPair), (Span, SPair)),
|
||||
|
||||
/// Attempted to close a package when not in a package toplevel context.
|
||||
InvalidPkgEndContext(Span),
|
||||
|
@ -175,13 +168,12 @@ impl Display for AsgError {
|
|||
"attempted to redeclare or redefine package {}",
|
||||
TtQuote::wrap(orig),
|
||||
),
|
||||
PkgRename(from, to) => write!(
|
||||
NestedPkgStart((_, child), (_, parent)) => write!(
|
||||
f,
|
||||
"attempted to rename package {} to {}",
|
||||
TtQuote::wrap(from),
|
||||
TtQuote::wrap(to)
|
||||
"cannot define package {} while defining package {}",
|
||||
TtQuote::wrap(child),
|
||||
TtQuote::wrap(parent),
|
||||
),
|
||||
NestedPkgStart(_, _) => write!(f, "cannot nest packages"),
|
||||
InvalidPkgEndContext(_) => {
|
||||
write!(f, "invalid context for package close",)
|
||||
}
|
||||
|
@ -197,7 +189,7 @@ impl Display for AsgError {
|
|||
UnbalancedExpr(_) => write!(f, "unbalanced expression"),
|
||||
UnbalancedTpl(_) => write!(f, "unbalanced template definition"),
|
||||
InvalidBindContext(_) => {
|
||||
write!(f, "invalid expression identifier binding context")
|
||||
write!(f, "invalid identifier binding context")
|
||||
}
|
||||
InvalidRefContext(ident) => {
|
||||
write!(
|
||||
|
@ -276,19 +268,15 @@ impl Diagnostic for AsgError {
|
|||
redef.error("attempting to redeclare or redefine package here"),
|
||||
],
|
||||
|
||||
PkgRename(from, to) => vec![
|
||||
from.note("package was originally named here"),
|
||||
to.error("attempted to rename package here"),
|
||||
to.help("a package cannot have its name changed"),
|
||||
],
|
||||
|
||||
NestedPkgStart(second, first) => vec![
|
||||
NestedPkgStart((second, sname), (first, fname)) => vec![
|
||||
first.note("this package is still being defined"),
|
||||
second.error("attempted to open another package here"),
|
||||
second.help(
|
||||
"close the package to complete its definition before \
|
||||
attempting to open another",
|
||||
),
|
||||
second.help(format!(
|
||||
"end the package {} complete its definition before \
|
||||
attempting to start the definition of {}",
|
||||
TtQuote::wrap(fname),
|
||||
TtQuote::wrap(sname),
|
||||
)),
|
||||
],
|
||||
|
||||
InvalidPkgEndContext(span) => vec![
|
||||
|
@ -334,8 +322,8 @@ impl Diagnostic for AsgError {
|
|||
vec![span.error("there is no open template to close here")]
|
||||
}
|
||||
|
||||
InvalidBindContext(span) => vec![span
|
||||
.error("there is no active object to bind this identifier to")],
|
||||
InvalidBindContext(name) => vec![name
|
||||
.error("an identifier binding is not valid in this context")],
|
||||
|
||||
InvalidRefContext(ident) => vec![ident.error(
|
||||
"cannot reference the value of an expression from outside \
|
||||
|
|
|
@ -77,7 +77,7 @@ fn traverses_ontological_tree() {
|
|||
|
||||
#[rustfmt::skip]
|
||||
let toks = vec![
|
||||
PkgStart(S1),
|
||||
PkgStart(S1, SPair("/pkg".into(), S1)),
|
||||
ExprStart(ExprOp::Sum, S2),
|
||||
BindIdent(id_a),
|
||||
|
||||
|
@ -141,7 +141,7 @@ fn traverses_ontological_tree_tpl_with_sibling_at_increasing_depth() {
|
|||
|
||||
#[rustfmt::skip]
|
||||
let toks = vec![
|
||||
PkgStart(S1),
|
||||
PkgStart(S1, SPair("/pkg".into(), S1)),
|
||||
TplStart(S2),
|
||||
BindIdent(id_tpl),
|
||||
|
||||
|
@ -201,7 +201,7 @@ fn traverses_ontological_tree_tpl_apply() {
|
|||
|
||||
#[rustfmt::skip]
|
||||
let toks = vec![
|
||||
PkgStart(S1),
|
||||
PkgStart(S1, SPair("/pkg".into(), S1)),
|
||||
// The template that will be applied.
|
||||
TplStart(S2),
|
||||
BindIdent(id_tpl),
|
||||
|
@ -260,7 +260,7 @@ fn traverses_ontological_tree_tpl_within_template() {
|
|||
|
||||
#[rustfmt::skip]
|
||||
let toks = vec![
|
||||
PkgStart(S1),
|
||||
PkgStart(S1, SPair("/pkg".into(), S1)),
|
||||
TplStart(S2),
|
||||
BindIdent(id_tpl_outer),
|
||||
|
||||
|
|
|
@ -86,7 +86,7 @@ fn sorts_objects_given_single_root() {
|
|||
let toks = vec![
|
||||
// Packages are auto-rooted as part of the graph's ontology.
|
||||
// There is only one for this test.
|
||||
PkgStart(S1),
|
||||
PkgStart(S1, SPair("/pkg".into(), S1)),
|
||||
// Before this can be computed,
|
||||
// its dependencies must be.
|
||||
ExprStart(ExprOp::Sum, S2), // -.
|
||||
|
@ -173,7 +173,7 @@ fn sorts_objects_given_single_root_more_complex() {
|
|||
|
||||
#[rustfmt::skip]
|
||||
let toks = vec![
|
||||
PkgStart(S1),
|
||||
PkgStart(S1, SPair("/pkg".into(), S1)),
|
||||
ExprStart(ExprOp::Sum, S2),
|
||||
BindIdent(id_a),
|
||||
RefIdent(SPair(id_b.symbol(), S4)), // ---.
|
||||
|
@ -233,7 +233,7 @@ fn omits_unreachable() {
|
|||
// We will only use a portion of this graph.
|
||||
#[rustfmt::skip]
|
||||
let toks = vec![
|
||||
PkgStart(S1),
|
||||
PkgStart(S1, SPair("/pkg".into(), S1)),
|
||||
ExprStart(ExprOp::Sum, S2),
|
||||
BindIdent(id_a),
|
||||
RefIdent(SPair(id_b.symbol(), S4)), // ---.
|
||||
|
@ -310,9 +310,7 @@ fn sorts_objects_given_multiple_roots() {
|
|||
#[rustfmt::skip]
|
||||
let toks = vec![
|
||||
// First root
|
||||
PkgStart(S1),
|
||||
BindIdent(pkg_a_name),
|
||||
|
||||
PkgStart(S1, pkg_a_name),
|
||||
ExprStart(ExprOp::Sum, S3),
|
||||
BindIdent(id_a),
|
||||
ExprEnd(S5),
|
||||
|
@ -320,9 +318,7 @@ fn sorts_objects_given_multiple_roots() {
|
|||
|
||||
// Second root,
|
||||
// independent of the first.
|
||||
PkgStart(S7),
|
||||
BindIdent(pkg_b_name),
|
||||
|
||||
PkgStart(S7, pkg_b_name),
|
||||
ExprStart(ExprOp::Sum, S9),
|
||||
BindIdent(id_b),
|
||||
ExprEnd(S11),
|
||||
|
@ -361,7 +357,7 @@ fn unsupported_cycles_with_recovery() {
|
|||
|
||||
#[rustfmt::skip]
|
||||
let toks = vec![
|
||||
PkgStart(S1),
|
||||
PkgStart(S1, SPair("/pkg-a".into(), S1)),
|
||||
ExprStart(ExprOp::Sum, S2),
|
||||
BindIdent(id_a), // <----. self-cycle
|
||||
RefIdent(SPair(id_a.symbol(), S4)), // ____/ \
|
||||
|
@ -434,7 +430,7 @@ fn supported_cycles() {
|
|||
|
||||
#[rustfmt::skip]
|
||||
let toks = vec![
|
||||
PkgStart(S1),
|
||||
PkgStart(S1, SPair("/pkg-a".into(), S1)),
|
||||
// Two mutually recursive functions.
|
||||
IdentDecl(id_a, kind.clone(), Default::default()), // <--.
|
||||
IdentDep(id_a, id_b), // -. |
|
||||
|
|
|
@ -119,7 +119,10 @@ impl ParseState for NirToAir {
|
|||
// responsibilities betwen XIR->NIR, NIR->AIR, and AIR->ASG.
|
||||
match (self, tok) {
|
||||
(Ready, Open(Package, span)) => {
|
||||
Transition(Ready).ok(Air::PkgStart(span))
|
||||
// TODO: Package name needs to be generated and provided to us;
|
||||
// this is transitionary.
|
||||
Transition(Ready)
|
||||
.ok(Air::PkgStart(span, SPair("/TODO".into(), span)))
|
||||
}
|
||||
|
||||
(Ready, Close(Package, span)) => {
|
||||
|
|
|
@ -29,7 +29,10 @@ fn package_to_pkg() {
|
|||
let toks = vec![Open(Package, S1), Close(Package, S2)];
|
||||
|
||||
assert_eq!(
|
||||
Ok(vec![O(Air::PkgStart(S1)), O(Air::PkgEnd(S2)),]),
|
||||
Ok(vec![
|
||||
O(Air::PkgStart(S1, SPair("/TODO".into(), S1))),
|
||||
O(Air::PkgEnd(S2)),
|
||||
]),
|
||||
Sut::parse(toks.into_iter()).collect(),
|
||||
);
|
||||
}
|
||||
|
@ -388,7 +391,7 @@ fn text_as_arbitrary_doc() {
|
|||
assert_eq!(
|
||||
#[rustfmt::skip]
|
||||
Ok(vec![
|
||||
O(Air::PkgStart(S1)),
|
||||
O(Air::PkgStart(S1, SPair("/TODO".into(), S1))),
|
||||
O(Air::DocText(text)),
|
||||
O(Air::PkgEnd(S3)),
|
||||
]),
|
||||
|
|
|
@ -115,17 +115,17 @@ impl ParseState for XmloToAir {
|
|||
|
||||
match (self, tok) {
|
||||
(PackageExpected, PkgStart(span)) => {
|
||||
Transition(PackageFound(span)).ok(Air::PkgStart(span))
|
||||
Transition(PackageFound(span)).incomplete()
|
||||
}
|
||||
|
||||
(PackageExpected, tok) => Transition(PackageExpected).dead(tok),
|
||||
|
||||
(PackageFound(_), PkgName(name)) => {
|
||||
(PackageFound(span), PkgName(name)) => {
|
||||
if ctx.is_first() {
|
||||
ctx.prog_name = Some(name.symbol());
|
||||
}
|
||||
|
||||
Transition(Package(name)).ok(Air::BindIdent(name))
|
||||
Transition(Package(name)).ok(Air::PkgStart(span, name))
|
||||
}
|
||||
|
||||
(st @ Package(..), PkgRootPath(relroot)) => {
|
||||
|
|
|
@ -50,8 +50,8 @@ fn data_from_package_event() {
|
|||
assert_eq!(
|
||||
#[rustfmt::skip]
|
||||
Ok(vec![
|
||||
O(Air::PkgStart(S1)),
|
||||
O(Air::BindIdent(SPair(name, S2))),
|
||||
Incomplete, // PkgStart
|
||||
O(Air::PkgStart(S1, SPair(name, S2))),
|
||||
Incomplete, // PkgRootPath
|
||||
O(Air::PkgEnd(S4)),
|
||||
]),
|
||||
|
@ -80,8 +80,8 @@ fn adds_elig_as_root() {
|
|||
assert_eq!(
|
||||
#[rustfmt::skip]
|
||||
Ok(vec![
|
||||
O(Air::PkgStart(S1)),
|
||||
O(Air::BindIdent(SPair(name, S2))),
|
||||
Incomplete, // PkgStart
|
||||
O(Air::PkgStart(S1, SPair(name, S2))),
|
||||
O(Air::IdentRoot(SPair(elig_sym, S3))),
|
||||
O(Air::PkgEnd(S4)), // Eoh
|
||||
]),
|
||||
|
@ -110,8 +110,8 @@ fn adds_sym_deps() {
|
|||
assert_eq!(
|
||||
#[rustfmt::skip]
|
||||
Ok(vec![
|
||||
O(Air::PkgStart(S1)),
|
||||
O(Air::BindIdent(SPair(name, S2))),
|
||||
Incomplete, // PkgStart
|
||||
O(Air::PkgStart(S1, SPair(name, S2))),
|
||||
Incomplete, // SymDepStart
|
||||
O(Air::IdentDep(SPair(sym_from, S3), SPair(sym_to1, S4))),
|
||||
O(Air::IdentDep(SPair(sym_from, S3), SPair(sym_to2, S5))),
|
||||
|
@ -155,8 +155,8 @@ fn sym_decl_with_src_not_added_and_populates_found() {
|
|||
assert_eq!(
|
||||
#[rustfmt::skip]
|
||||
Ok(vec![
|
||||
O(Air::PkgStart(S1)),
|
||||
O(Air::BindIdent(SPair(name, S2))),
|
||||
Incomplete, // PkgStart
|
||||
O(Air::PkgStart(S1, SPair(name, S2))),
|
||||
Incomplete, // SymDecl (@src)
|
||||
Incomplete, // SymDecl (@src)
|
||||
O(Air::PkgEnd(S5)),
|
||||
|
@ -228,8 +228,8 @@ fn sym_decl_added_to_graph() {
|
|||
|
||||
// Note that each of these will have their package names cleared
|
||||
// since this is considered to be the first package encountered.
|
||||
assert_eq!(Some(Ok(O(Air::PkgStart(S1)))), sut.next()); // PkgStart
|
||||
assert_eq!(Some(Ok(O(Air::BindIdent(SPair(name, S2))))), sut.next());
|
||||
assert_eq!(Some(Ok(Incomplete)), sut.next()); // PkgStart
|
||||
assert_eq!(Some(Ok(O(Air::PkgStart(S1, SPair(name, S2))))), sut.next()); // PkgName
|
||||
assert_eq!(
|
||||
Some(Ok(O(Air::IdentExternDecl(
|
||||
SPair(sym_extern, S3),
|
||||
|
@ -318,9 +318,8 @@ fn sym_decl_pkg_name_retained_if_not_first() {
|
|||
assert_eq!(
|
||||
#[rustfmt::skip]
|
||||
Ok(vec![
|
||||
O(Air::PkgStart(S1)),
|
||||
O(Air::BindIdent(SPair(pkg_name, S2))),
|
||||
|
||||
Incomplete, // PkgStart
|
||||
O(Air::PkgStart(S1, SPair(pkg_name, S2))),
|
||||
O(Air::IdentDecl(
|
||||
SPair(sym, S3),
|
||||
IdentKind::Meta,
|
||||
|
@ -366,9 +365,8 @@ fn sym_decl_pkg_name_set_if_empty_and_not_first() {
|
|||
assert_eq!(
|
||||
#[rustfmt::skip]
|
||||
Ok(vec![
|
||||
O(Air::PkgStart(S1)),
|
||||
O(Air::BindIdent(SPair(pkg_name, S2))),
|
||||
|
||||
Incomplete, // PkgStart
|
||||
O(Air::PkgStart(S1, SPair(pkg_name, S2))),
|
||||
O(Air::IdentDecl(
|
||||
SPair(sym, S3),
|
||||
IdentKind::Meta,
|
||||
|
@ -418,8 +416,8 @@ fn sets_fragment() {
|
|||
assert_eq!(
|
||||
#[rustfmt::skip]
|
||||
Ok(vec![
|
||||
O(Air::PkgStart(S1)),
|
||||
O(Air::BindIdent(SPair(name, S2))),
|
||||
Incomplete, // PkgStart
|
||||
O(Air::PkgStart(S1, SPair(name, S2))),
|
||||
O(Air::IdentFragment(SPair(sym, S3), frag)),
|
||||
O(Air::PkgEnd(S4)),
|
||||
]),
|
||||
|
|
Loading…
Reference in New Issue