From 00492ace0198d6d64471a0888f570197838e3f09 Mon Sep 17 00:00:00 2001 From: Mike Gerwitz Date: Fri, 5 May 2023 10:22:12 -0400 Subject: [PATCH] tamer: obj::xmlo: Bind packages to canonical name NOTE: This fixes the aforementioned commit that caused the linker to temporarily fail (670c5d3a5d88b733a514ae09542b5cad30a77605 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 --- tamer/src/obj/xmlo/air.rs | 2 +- tamer/src/obj/xmlo/air/test.rs | 28 ++++++++++++++++------------ tamer/src/obj/xmlo/reader.rs | 30 ++++++++++++++++++++++++++---- tamer/src/obj/xmlo/reader/test.rs | 30 ++++++++++++++++++++++++++++-- 4 files changed, 71 insertions(+), 19 deletions(-) diff --git a/tamer/src/obj/xmlo/air.rs b/tamer/src/obj/xmlo/air.rs index bbd36fe8..fce131e7 100644 --- a/tamer/src/obj/xmlo/air.rs +++ b/tamer/src/obj/xmlo/air.rs @@ -125,7 +125,7 @@ impl ParseState for XmloToAir { ctx.prog_name = Some(name.symbol()); } - Transition(Package(name)).incomplete() + Transition(Package(name)).ok(Air::BindIdent(name)) } (st @ Package(..), PkgRootPath(relroot)) => { diff --git a/tamer/src/obj/xmlo/air/test.rs b/tamer/src/obj/xmlo/air/test.rs index e53b3aac..f8d94531 100644 --- a/tamer/src/obj/xmlo/air/test.rs +++ b/tamer/src/obj/xmlo/air/test.rs @@ -51,7 +51,7 @@ fn data_from_package_event() { #[rustfmt::skip] Ok(vec![ O(Air::PkgStart(S1)), - Incomplete, // PkgName + O(Air::BindIdent(SPair(name, S2))), Incomplete, // PkgRootPath O(Air::PkgEnd(S4)), ]), @@ -81,7 +81,7 @@ fn adds_elig_as_root() { #[rustfmt::skip] Ok(vec![ O(Air::PkgStart(S1)), - Incomplete, // PkgName + O(Air::BindIdent(SPair(name, S2))), O(Air::IdentRoot(SPair(elig_sym, S3))), O(Air::PkgEnd(S4)), // Eoh ]), @@ -91,6 +91,7 @@ fn adds_elig_as_root() { #[test] fn adds_sym_deps() { + let name = "name".into(); let sym_from = "from".into(); let sym_to1 = "to1".into(); let sym_to2 = "to2".into(); @@ -98,7 +99,7 @@ fn adds_sym_deps() { #[rustfmt::skip] let toks = vec![ PkgStart(S1), - PkgName(SPair("name".into(), S2)), + PkgName(SPair(name, S2)), SymDepStart(SPair(sym_from, S3)), Symbol(SPair(sym_to1, S4)), @@ -110,7 +111,7 @@ fn adds_sym_deps() { #[rustfmt::skip] Ok(vec![ O(Air::PkgStart(S1)), - Incomplete, // PkgName + O(Air::BindIdent(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))), @@ -122,6 +123,7 @@ fn adds_sym_deps() { #[test] fn sym_decl_with_src_not_added_and_populates_found() { + let name = "name".into(); let sym = "sym".into(); let src_a = "src_a".into(); let src_b = "src_b".into(); @@ -129,7 +131,7 @@ fn sym_decl_with_src_not_added_and_populates_found() { #[rustfmt::skip] let toks = vec![ PkgStart(S1), - PkgName(SPair("name".into(), S2)), + PkgName(SPair(name, S2)), SymDecl( SPair(sym, S3), @@ -154,7 +156,7 @@ fn sym_decl_with_src_not_added_and_populates_found() { #[rustfmt::skip] Ok(vec![ O(Air::PkgStart(S1)), - Incomplete, // PkgName + O(Air::BindIdent(SPair(name, S2))), Incomplete, // SymDecl (@src) Incomplete, // SymDecl (@src) O(Air::PkgEnd(S5)), @@ -174,6 +176,7 @@ fn sym_decl_with_src_not_added_and_populates_found() { #[test] fn sym_decl_added_to_graph() { + let name = "name".into(); let sym_extern = "sym_extern".into(); let sym_non_extern = "sym_non_extern".into(); let sym_map = "sym_map".into(); @@ -183,7 +186,7 @@ fn sym_decl_added_to_graph() { #[rustfmt::skip] let toks = vec![ PkgStart(S1), - PkgName(SPair("name".into(), S2)), + PkgName(SPair(name, S2)), SymDecl( 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 // 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(Incomplete)), sut.next()); // PkgName + assert_eq!(Some(Ok(O(Air::BindIdent(SPair(name, S2))))), sut.next()); assert_eq!( Some(Ok(O(Air::IdentExternDecl( SPair(sym_extern, S3), @@ -316,7 +319,7 @@ fn sym_decl_pkg_name_retained_if_not_first() { #[rustfmt::skip] Ok(vec![ O(Air::PkgStart(S1)), - Incomplete, // PkgName + O(Air::BindIdent(SPair(pkg_name, S2))), O(Air::IdentDecl( SPair(sym, S3), @@ -364,7 +367,7 @@ fn sym_decl_pkg_name_set_if_empty_and_not_first() { #[rustfmt::skip] Ok(vec![ O(Air::PkgStart(S1)), - Incomplete, // PkgName + O(Air::BindIdent(SPair(pkg_name, S2))), O(Air::IdentDecl( SPair(sym, S3), @@ -400,13 +403,14 @@ fn ident_kind_conversion_error_propagates() { #[test] fn sets_fragment() { + let name = "name".into(); let sym = "sym".into(); let frag = FragmentText::from("foo"); #[rustfmt::skip] let toks = vec![ PkgStart(S1), - PkgName(SPair("name".into(), S2)), + PkgName(SPair(name, S2)), Fragment(SPair(sym, S3), frag.clone()), Eoh(S4), ]; @@ -415,7 +419,7 @@ fn sets_fragment() { #[rustfmt::skip] Ok(vec![ O(Air::PkgStart(S1)), - Incomplete, // PkgName + O(Air::BindIdent(SPair(name, S2))), O(Air::IdentFragment(SPair(sym, S3), frag)), O(Air::PkgEnd(S4)), ]), diff --git a/tamer/src/obj/xmlo/reader.rs b/tamer/src/obj/xmlo/reader.rs index 89b2037a..50b1f61e 100644 --- a/tamer/src/obj/xmlo/reader.rs +++ b/tamer/src/obj/xmlo/reader.rs @@ -29,7 +29,7 @@ use crate::{ ParseState, Token, Transition, TransitionResult, Transitionable, }, span::Span, - sym::{st::raw, SymbolId}, + sym::{st::raw, GlobalSymbolIntern, GlobalSymbolResolve, SymbolId}, xir::{ attr::{Attr, AttrSpan}, flat::{Text, XirfToken as Xirf}, @@ -227,9 +227,10 @@ impl ParseState // which can result in confusing output depending on the context; // we ought to retain _both_ token- and value-spans. Transition(Package(span)).ok(match name { - QN_NAME => { - XmloToken::PkgName(SPair(value, aspan.value_span())) - } + QN_NAME => XmloToken::PkgName(SPair( + canonical_slash(value), + aspan.value_span(), + )), QN_UUROOTPATH => { XmloToken::PkgRootPath(SPair(value, aspan.value_span())) } @@ -321,6 +322,27 @@ impl 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 Display for XmloReader { diff --git a/tamer/src/obj/xmlo/reader/test.rs b/tamer/src/obj/xmlo/reader/test.rs index e15cd266..a784f3ba 100644 --- a/tamer/src/obj/xmlo/reader/test.rs +++ b/tamer/src/obj/xmlo/reader/test.rs @@ -54,7 +54,7 @@ fn fails_on_invalid_root() { } fn common_parses_package_attrs(package: QName) { - let name = "pkgroot".into(); + let name = "/pkgroot".into(); let relroot = "../../".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()); } +// 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, // but this ought to reject in the future. #[test] fn ignores_unknown_package_attr() { - let name = "pkgroot".into(); + let name = "/pkgroot".into(); #[rustfmt::skip] let toks = [