tamer: obj::xmlo: Bind packages to canonical name
NOTE: This fixes the aforementioned commit that caused the linker to
temporarily fail (670c5d3a5d
at time of
writing). This does introduce an extra forward slash into
`l:dep/preproc:sym/@src`, but that does not appear to cause any
problems. That will eventually go away, so I'm not going to bother with it
any further.
As the `xmlo` file is lowered into AIR, the name will be prefixed with a
leading slash (if necessary, which it is atm) and will emit an
`Air::BindIdent`.
This means that packages will be properly indexed by their canonical name on
load, which will be important when we share this with tamec.
DEV-13162
main
parent
13bac8382f
commit
00492ace01
|
@ -125,7 +125,7 @@ impl ParseState for XmloToAir {
|
||||||
ctx.prog_name = Some(name.symbol());
|
ctx.prog_name = Some(name.symbol());
|
||||||
}
|
}
|
||||||
|
|
||||||
Transition(Package(name)).incomplete()
|
Transition(Package(name)).ok(Air::BindIdent(name))
|
||||||
}
|
}
|
||||||
|
|
||||||
(st @ Package(..), PkgRootPath(relroot)) => {
|
(st @ Package(..), PkgRootPath(relroot)) => {
|
||||||
|
|
|
@ -51,7 +51,7 @@ fn data_from_package_event() {
|
||||||
#[rustfmt::skip]
|
#[rustfmt::skip]
|
||||||
Ok(vec![
|
Ok(vec![
|
||||||
O(Air::PkgStart(S1)),
|
O(Air::PkgStart(S1)),
|
||||||
Incomplete, // PkgName
|
O(Air::BindIdent(SPair(name, S2))),
|
||||||
Incomplete, // PkgRootPath
|
Incomplete, // PkgRootPath
|
||||||
O(Air::PkgEnd(S4)),
|
O(Air::PkgEnd(S4)),
|
||||||
]),
|
]),
|
||||||
|
@ -81,7 +81,7 @@ fn adds_elig_as_root() {
|
||||||
#[rustfmt::skip]
|
#[rustfmt::skip]
|
||||||
Ok(vec![
|
Ok(vec![
|
||||||
O(Air::PkgStart(S1)),
|
O(Air::PkgStart(S1)),
|
||||||
Incomplete, // PkgName
|
O(Air::BindIdent(SPair(name, S2))),
|
||||||
O(Air::IdentRoot(SPair(elig_sym, S3))),
|
O(Air::IdentRoot(SPair(elig_sym, S3))),
|
||||||
O(Air::PkgEnd(S4)), // Eoh
|
O(Air::PkgEnd(S4)), // Eoh
|
||||||
]),
|
]),
|
||||||
|
@ -91,6 +91,7 @@ fn adds_elig_as_root() {
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn adds_sym_deps() {
|
fn adds_sym_deps() {
|
||||||
|
let name = "name".into();
|
||||||
let sym_from = "from".into();
|
let sym_from = "from".into();
|
||||||
let sym_to1 = "to1".into();
|
let sym_to1 = "to1".into();
|
||||||
let sym_to2 = "to2".into();
|
let sym_to2 = "to2".into();
|
||||||
|
@ -98,7 +99,7 @@ fn adds_sym_deps() {
|
||||||
#[rustfmt::skip]
|
#[rustfmt::skip]
|
||||||
let toks = vec![
|
let toks = vec![
|
||||||
PkgStart(S1),
|
PkgStart(S1),
|
||||||
PkgName(SPair("name".into(), S2)),
|
PkgName(SPair(name, S2)),
|
||||||
|
|
||||||
SymDepStart(SPair(sym_from, S3)),
|
SymDepStart(SPair(sym_from, S3)),
|
||||||
Symbol(SPair(sym_to1, S4)),
|
Symbol(SPair(sym_to1, S4)),
|
||||||
|
@ -110,7 +111,7 @@ fn adds_sym_deps() {
|
||||||
#[rustfmt::skip]
|
#[rustfmt::skip]
|
||||||
Ok(vec![
|
Ok(vec![
|
||||||
O(Air::PkgStart(S1)),
|
O(Air::PkgStart(S1)),
|
||||||
Incomplete, // PkgName
|
O(Air::BindIdent(SPair(name, S2))),
|
||||||
Incomplete, // SymDepStart
|
Incomplete, // SymDepStart
|
||||||
O(Air::IdentDep(SPair(sym_from, S3), SPair(sym_to1, S4))),
|
O(Air::IdentDep(SPair(sym_from, S3), SPair(sym_to1, S4))),
|
||||||
O(Air::IdentDep(SPair(sym_from, S3), SPair(sym_to2, S5))),
|
O(Air::IdentDep(SPair(sym_from, S3), SPair(sym_to2, S5))),
|
||||||
|
@ -122,6 +123,7 @@ fn adds_sym_deps() {
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn sym_decl_with_src_not_added_and_populates_found() {
|
fn sym_decl_with_src_not_added_and_populates_found() {
|
||||||
|
let name = "name".into();
|
||||||
let sym = "sym".into();
|
let sym = "sym".into();
|
||||||
let src_a = "src_a".into();
|
let src_a = "src_a".into();
|
||||||
let src_b = "src_b".into();
|
let src_b = "src_b".into();
|
||||||
|
@ -129,7 +131,7 @@ fn sym_decl_with_src_not_added_and_populates_found() {
|
||||||
#[rustfmt::skip]
|
#[rustfmt::skip]
|
||||||
let toks = vec![
|
let toks = vec![
|
||||||
PkgStart(S1),
|
PkgStart(S1),
|
||||||
PkgName(SPair("name".into(), S2)),
|
PkgName(SPair(name, S2)),
|
||||||
|
|
||||||
SymDecl(
|
SymDecl(
|
||||||
SPair(sym, S3),
|
SPair(sym, S3),
|
||||||
|
@ -154,7 +156,7 @@ fn sym_decl_with_src_not_added_and_populates_found() {
|
||||||
#[rustfmt::skip]
|
#[rustfmt::skip]
|
||||||
Ok(vec![
|
Ok(vec![
|
||||||
O(Air::PkgStart(S1)),
|
O(Air::PkgStart(S1)),
|
||||||
Incomplete, // PkgName
|
O(Air::BindIdent(SPair(name, S2))),
|
||||||
Incomplete, // SymDecl (@src)
|
Incomplete, // SymDecl (@src)
|
||||||
Incomplete, // SymDecl (@src)
|
Incomplete, // SymDecl (@src)
|
||||||
O(Air::PkgEnd(S5)),
|
O(Air::PkgEnd(S5)),
|
||||||
|
@ -174,6 +176,7 @@ fn sym_decl_with_src_not_added_and_populates_found() {
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn sym_decl_added_to_graph() {
|
fn sym_decl_added_to_graph() {
|
||||||
|
let name = "name".into();
|
||||||
let sym_extern = "sym_extern".into();
|
let sym_extern = "sym_extern".into();
|
||||||
let sym_non_extern = "sym_non_extern".into();
|
let sym_non_extern = "sym_non_extern".into();
|
||||||
let sym_map = "sym_map".into();
|
let sym_map = "sym_map".into();
|
||||||
|
@ -183,7 +186,7 @@ fn sym_decl_added_to_graph() {
|
||||||
#[rustfmt::skip]
|
#[rustfmt::skip]
|
||||||
let toks = vec![
|
let toks = vec![
|
||||||
PkgStart(S1),
|
PkgStart(S1),
|
||||||
PkgName(SPair("name".into(), S2)),
|
PkgName(SPair(name, S2)),
|
||||||
|
|
||||||
SymDecl(
|
SymDecl(
|
||||||
SPair(sym_extern, S3),
|
SPair(sym_extern, S3),
|
||||||
|
@ -226,7 +229,7 @@ fn sym_decl_added_to_graph() {
|
||||||
// Note that each of these will have their package names cleared
|
// Note that each of these will have their package names cleared
|
||||||
// since this is considered to be the first package encountered.
|
// 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::PkgStart(S1)))), sut.next()); // PkgStart
|
||||||
assert_eq!(Some(Ok(Incomplete)), sut.next()); // PkgName
|
assert_eq!(Some(Ok(O(Air::BindIdent(SPair(name, S2))))), sut.next());
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
Some(Ok(O(Air::IdentExternDecl(
|
Some(Ok(O(Air::IdentExternDecl(
|
||||||
SPair(sym_extern, S3),
|
SPair(sym_extern, S3),
|
||||||
|
@ -316,7 +319,7 @@ fn sym_decl_pkg_name_retained_if_not_first() {
|
||||||
#[rustfmt::skip]
|
#[rustfmt::skip]
|
||||||
Ok(vec![
|
Ok(vec![
|
||||||
O(Air::PkgStart(S1)),
|
O(Air::PkgStart(S1)),
|
||||||
Incomplete, // PkgName
|
O(Air::BindIdent(SPair(pkg_name, S2))),
|
||||||
|
|
||||||
O(Air::IdentDecl(
|
O(Air::IdentDecl(
|
||||||
SPair(sym, S3),
|
SPair(sym, S3),
|
||||||
|
@ -364,7 +367,7 @@ fn sym_decl_pkg_name_set_if_empty_and_not_first() {
|
||||||
#[rustfmt::skip]
|
#[rustfmt::skip]
|
||||||
Ok(vec![
|
Ok(vec![
|
||||||
O(Air::PkgStart(S1)),
|
O(Air::PkgStart(S1)),
|
||||||
Incomplete, // PkgName
|
O(Air::BindIdent(SPair(pkg_name, S2))),
|
||||||
|
|
||||||
O(Air::IdentDecl(
|
O(Air::IdentDecl(
|
||||||
SPair(sym, S3),
|
SPair(sym, S3),
|
||||||
|
@ -400,13 +403,14 @@ fn ident_kind_conversion_error_propagates() {
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn sets_fragment() {
|
fn sets_fragment() {
|
||||||
|
let name = "name".into();
|
||||||
let sym = "sym".into();
|
let sym = "sym".into();
|
||||||
let frag = FragmentText::from("foo");
|
let frag = FragmentText::from("foo");
|
||||||
|
|
||||||
#[rustfmt::skip]
|
#[rustfmt::skip]
|
||||||
let toks = vec![
|
let toks = vec![
|
||||||
PkgStart(S1),
|
PkgStart(S1),
|
||||||
PkgName(SPair("name".into(), S2)),
|
PkgName(SPair(name, S2)),
|
||||||
Fragment(SPair(sym, S3), frag.clone()),
|
Fragment(SPair(sym, S3), frag.clone()),
|
||||||
Eoh(S4),
|
Eoh(S4),
|
||||||
];
|
];
|
||||||
|
@ -415,7 +419,7 @@ fn sets_fragment() {
|
||||||
#[rustfmt::skip]
|
#[rustfmt::skip]
|
||||||
Ok(vec![
|
Ok(vec![
|
||||||
O(Air::PkgStart(S1)),
|
O(Air::PkgStart(S1)),
|
||||||
Incomplete, // PkgName
|
O(Air::BindIdent(SPair(name, S2))),
|
||||||
O(Air::IdentFragment(SPair(sym, S3), frag)),
|
O(Air::IdentFragment(SPair(sym, S3), frag)),
|
||||||
O(Air::PkgEnd(S4)),
|
O(Air::PkgEnd(S4)),
|
||||||
]),
|
]),
|
||||||
|
|
|
@ -29,7 +29,7 @@ use crate::{
|
||||||
ParseState, Token, Transition, TransitionResult, Transitionable,
|
ParseState, Token, Transition, TransitionResult, Transitionable,
|
||||||
},
|
},
|
||||||
span::Span,
|
span::Span,
|
||||||
sym::{st::raw, SymbolId},
|
sym::{st::raw, GlobalSymbolIntern, GlobalSymbolResolve, SymbolId},
|
||||||
xir::{
|
xir::{
|
||||||
attr::{Attr, AttrSpan},
|
attr::{Attr, AttrSpan},
|
||||||
flat::{Text, XirfToken as Xirf},
|
flat::{Text, XirfToken as Xirf},
|
||||||
|
@ -227,9 +227,10 @@ impl<SS: XmloState, SD: XmloState, SF: XmloState> ParseState
|
||||||
// which can result in confusing output depending on the context;
|
// which can result in confusing output depending on the context;
|
||||||
// we ought to retain _both_ token- and value-spans.
|
// we ought to retain _both_ token- and value-spans.
|
||||||
Transition(Package(span)).ok(match name {
|
Transition(Package(span)).ok(match name {
|
||||||
QN_NAME => {
|
QN_NAME => XmloToken::PkgName(SPair(
|
||||||
XmloToken::PkgName(SPair(value, aspan.value_span()))
|
canonical_slash(value),
|
||||||
}
|
aspan.value_span(),
|
||||||
|
)),
|
||||||
QN_UUROOTPATH => {
|
QN_UUROOTPATH => {
|
||||||
XmloToken::PkgRootPath(SPair(value, aspan.value_span()))
|
XmloToken::PkgRootPath(SPair(value, aspan.value_span()))
|
||||||
}
|
}
|
||||||
|
@ -321,6 +322,27 @@ impl<SS: XmloState, SD: XmloState, SF: XmloState> ParseState
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Introduce a leading `/` to `name` if missing.
|
||||||
|
///
|
||||||
|
/// A new [`SymbolId`] will be allocated if the leading slash is missing
|
||||||
|
/// from `name.
|
||||||
|
///
|
||||||
|
/// The XSLT-based compiler at the time of writing produced canonical names
|
||||||
|
/// _without_ a leading slash.
|
||||||
|
/// This convention was not changed until TAMER,
|
||||||
|
/// so that canonical paths could be used as namespecs for import in an
|
||||||
|
/// unambiguous way.
|
||||||
|
/// We want to support both,
|
||||||
|
/// so that TAMER-compiled object files will also work.
|
||||||
|
fn canonical_slash(name: SymbolId) -> SymbolId {
|
||||||
|
let s = name.lookup_str();
|
||||||
|
|
||||||
|
match s.starts_with('/') {
|
||||||
|
true => name,
|
||||||
|
false => format!("/{s}").intern(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
impl<SS: XmloState, SD: XmloState, SF: XmloState> Display
|
impl<SS: XmloState, SD: XmloState, SF: XmloState> Display
|
||||||
for XmloReader<SS, SD, SF>
|
for XmloReader<SS, SD, SF>
|
||||||
{
|
{
|
||||||
|
|
|
@ -54,7 +54,7 @@ fn fails_on_invalid_root() {
|
||||||
}
|
}
|
||||||
|
|
||||||
fn common_parses_package_attrs(package: QName) {
|
fn common_parses_package_attrs(package: QName) {
|
||||||
let name = "pkgroot".into();
|
let name = "/pkgroot".into();
|
||||||
let relroot = "../../".into();
|
let relroot = "../../".into();
|
||||||
let elig = "elig-class-yields".into();
|
let elig = "elig-class-yields".into();
|
||||||
|
|
||||||
|
@ -101,11 +101,37 @@ fn parses_package_attrs_with_ns_prefix() {
|
||||||
common_parses_package_attrs(("lv", "package").unwrap_into());
|
common_parses_package_attrs(("lv", "package").unwrap_into());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// For compatibility with XSLT-based compiler.
|
||||||
|
#[test]
|
||||||
|
fn adds_missing_leading_slash_to_canonical_name() {
|
||||||
|
let name = "needs/leading".into();
|
||||||
|
|
||||||
|
#[rustfmt::skip]
|
||||||
|
let toks = [
|
||||||
|
open(QN_PACKAGE, S1, Depth(0)),
|
||||||
|
attr("name", name, (S2, S3)),
|
||||||
|
close(Some(QN_PACKAGE), S2, Depth(0)),
|
||||||
|
]
|
||||||
|
.into_iter();
|
||||||
|
|
||||||
|
let sut = Sut::parse(toks);
|
||||||
|
|
||||||
|
assert_eq!(
|
||||||
|
#[rustfmt::skip]
|
||||||
|
Ok(vec![
|
||||||
|
O(PkgStart(S1)),
|
||||||
|
O(PkgName(SPair("/needs/leading".into(), S3))),
|
||||||
|
Incomplete,
|
||||||
|
]),
|
||||||
|
sut.collect(),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
// Maintains BC with existing system,
|
// Maintains BC with existing system,
|
||||||
// but this ought to reject in the future.
|
// but this ought to reject in the future.
|
||||||
#[test]
|
#[test]
|
||||||
fn ignores_unknown_package_attr() {
|
fn ignores_unknown_package_attr() {
|
||||||
let name = "pkgroot".into();
|
let name = "/pkgroot".into();
|
||||||
|
|
||||||
#[rustfmt::skip]
|
#[rustfmt::skip]
|
||||||
let toks = [
|
let toks = [
|
||||||
|
|
Loading…
Reference in New Issue