tame: obj::xmlo: Use SPair where applicable

This simply pairs the individual `SymbolId` and `Span`.  Rationale for this
pairing was added as documentation to `SPair`.

DEV-13430
main
Mike Gerwitz 2022-12-15 21:27:57 -05:00
parent c71f3247b1
commit af91857746
4 changed files with 168 additions and 155 deletions

View File

@ -84,7 +84,7 @@ impl XmloAirContext {
}
}
type PackageName = SymbolId;
type PackageSPair = SPair;
/// State machine for lowering into the [`Asg`](crate::asg::Asg) via
/// [`Air`].
@ -92,8 +92,8 @@ type PackageName = SymbolId;
pub enum XmloToAir {
#[default]
PackageExpected,
Package(PackageName, Span),
SymDep(PackageName, Span, SPair),
Package(PackageSPair),
SymDep(PackageSPair, SPair),
/// End of header (EOH) reached.
Done(Span),
}
@ -113,17 +113,17 @@ impl ParseState for XmloToAir {
use XmloToAir::*;
match (self, tok) {
(PackageExpected, XmloToken::PkgName(name, span)) => {
(PackageExpected, XmloToken::PkgName(name)) => {
if ctx.is_first() {
ctx.prog_name = Some(name);
ctx.prog_name = Some(name.symbol());
}
Transition(Package(name, span)).incomplete()
Transition(Package(name)).incomplete()
}
(st @ Package(..), XmloToken::PkgRootPath(relroot, _)) => {
(st @ Package(..), XmloToken::PkgRootPath(relroot)) => {
if ctx.is_first() {
ctx.relroot = Some(relroot);
ctx.relroot = Some(relroot.symbol());
}
Transition(st).incomplete()
@ -135,16 +135,12 @@ impl ParseState for XmloToAir {
// definition is encountered later within the same file.
// TODO: Let's remove the need for this special root handling
// here.
(
Package(pkg_name, span),
XmloToken::PkgEligClassYields(pkg_elig, elig_span),
) => {
(Package(name), XmloToken::PkgEligClassYields(pkg_elig)) => {
// The span for this is a bit awkward,
// given that rooting is automatic,
// but it it should never have to be utilized in
// diagnostics unless there is a compiler bug.
Transition(Package(pkg_name, span))
.ok(Air::IdentRoot(SPair(pkg_elig, elig_span)))
Transition(Package(name)).ok(Air::IdentRoot(pkg_elig))
}
(
@ -156,35 +152,29 @@ impl ParseState for XmloToAir {
}
(
Package(pkg_name, span) | SymDep(pkg_name, span, ..),
XmloToken::SymDepStart(sym, sym_span),
) => Transition(SymDep(pkg_name, span, SPair(sym, sym_span)))
.incomplete(),
Package(pkg_name) | SymDep(pkg_name, ..),
XmloToken::SymDepStart(sym),
) => Transition(SymDep(pkg_name, sym)).incomplete(),
(
SymDep(pkg_name, span, sym),
XmloToken::Symbol(dep_sym, dep_span),
) => Transition(SymDep(pkg_name, span, sym))
.ok(Air::IdentDep(sym, SPair(dep_sym, dep_span))),
(
Package(pkg_name, span),
XmloToken::SymDecl(
_sym,
SymAttrs {
src: Some(sym_src), ..
},
_span,
),
) => {
ctx.found.get_or_insert(Default::default()).insert(sym_src);
Transition(Package(pkg_name, span)).incomplete()
(SymDep(pkg_name, sym), XmloToken::Symbol(dep_sym)) => {
Transition(SymDep(pkg_name, sym))
.ok(Air::IdentDep(sym, dep_sym))
}
(
Package(pkg_name, span),
XmloToken::SymDecl(sym, attrs, sym_span),
Package(pkg_name),
XmloToken::SymDecl(
_name,
SymAttrs {
src: Some(sym_src), ..
},
),
) => {
ctx.found.get_or_insert(Default::default()).insert(sym_src);
Transition(Package(pkg_name)).incomplete()
}
(Package(pkg_name), XmloToken::SymDecl(name, attrs)) => {
let extern_ = attrs.extern_;
// TODO: This attr/source separation is a mess,
@ -197,7 +187,7 @@ impl ParseState for XmloToAir {
// This used to come from SymAttrs in the old XmloReader.
if src.pkg_name.is_none() {
src.pkg_name.replace(pkg_name);
src.pkg_name.replace(pkg_name.symbol());
}
// Existing convention is to omit @src of local package
@ -208,26 +198,23 @@ impl ParseState for XmloToAir {
if extern_ {
Ok(ParseStatus::Object(Air::IdentExternDecl(
SPair(sym, sym_span),
kindval,
src,
name, kindval, src,
)))
} else {
Ok(ParseStatus::Object(Air::IdentDecl(
SPair(sym, sym_span),
kindval,
src,
name, kindval, src,
)))
}
})
.transition(Package(pkg_name, span))
.transition(Package(pkg_name))
}
(
Package(pkg_name, span) | SymDep(pkg_name, span, _),
XmloToken::Fragment(sym, text, frag_span),
) => Transition(Package(pkg_name, span))
.ok(Air::IdentFragment(SPair(sym, frag_span), text)),
Package(pkg_name) | SymDep(pkg_name, _),
XmloToken::Fragment(name, text),
) => {
Transition(Package(pkg_name)).ok(Air::IdentFragment(name, text))
}
// We don't need to read any further than the end of the
// header (symtable, sym-deps, fragments).
@ -257,10 +244,10 @@ impl Display for XmloToAir {
match self {
PackageExpected => write!(f, "expecting package definition"),
Package(name, _) => {
Package(name) => {
write!(f, "expecting package `/{name}` declarations")
}
SymDep(pkg_name, _, sym) => {
SymDep(pkg_name, sym) => {
write!(f, "expecting dependency for symbol `/{pkg_name}/{sym}`")
}
Done(_) => write!(f, "done lowering xmlo into AIR"),
@ -423,8 +410,8 @@ mod test {
let relroot = "some/path".into();
let toks = vec![
XmloToken::PkgName(name, S1),
XmloToken::PkgRootPath(relroot, S2),
XmloToken::PkgName(SPair(name, S1)),
XmloToken::PkgRootPath(SPair(relroot, S2)),
XmloToken::Eoh(S3),
]
.into_iter();
@ -447,8 +434,8 @@ mod test {
let elig_sym = "elig".into();
let toks = vec![
XmloToken::PkgName(name, S1),
XmloToken::PkgEligClassYields(elig_sym, S2),
XmloToken::PkgName(SPair(name, S1)),
XmloToken::PkgEligClassYields(SPair(elig_sym, S2)),
XmloToken::Eoh(S3),
];
@ -469,10 +456,10 @@ mod test {
let sym_to2 = "to2".into();
let toks = vec![
XmloToken::PkgName("name".into(), S1),
XmloToken::SymDepStart(sym_from, S2),
XmloToken::Symbol(sym_to1, S3),
XmloToken::Symbol(sym_to2, S4),
XmloToken::PkgName(SPair("name".into(), S1)),
XmloToken::SymDepStart(SPair(sym_from, S2)),
XmloToken::Symbol(SPair(sym_to1, S3)),
XmloToken::Symbol(SPair(sym_to2, S4)),
XmloToken::Eoh(S1),
];
@ -501,22 +488,20 @@ mod test {
let src_b = "src_b".into();
let toks = vec![
XmloToken::PkgName("name".into(), S1),
XmloToken::PkgName(SPair("name".into(), S1)),
XmloToken::SymDecl(
sym,
SPair(sym, S2),
SymAttrs {
src: Some(src_a),
..Default::default()
},
S2,
),
XmloToken::SymDecl(
sym,
SPair(sym, S3),
SymAttrs {
src: Some(src_b),
..Default::default()
},
S3,
),
XmloToken::Eoh(S1),
];
@ -547,43 +532,39 @@ mod test {
let pkg_name = "pkg name".into();
let toks = vec![
XmloToken::PkgName("name".into(), S1),
XmloToken::PkgName(SPair("name".into(), S1)),
XmloToken::SymDecl(
sym_extern,
SPair(sym_extern, S1),
SymAttrs {
pkg_name: Some(pkg_name),
extern_: true,
ty: Some(SymType::Meta),
..Default::default()
},
S1,
),
XmloToken::SymDecl(
sym_non_extern,
SPair(sym_non_extern, S2),
SymAttrs {
pkg_name: Some(pkg_name),
ty: Some(SymType::Meta),
..Default::default()
},
S2,
),
XmloToken::SymDecl(
sym_map,
SPair(sym_map, S3),
SymAttrs {
pkg_name: Some(pkg_name),
ty: Some(SymType::Map),
..Default::default()
},
S3,
),
XmloToken::SymDecl(
sym_retmap,
SPair(sym_retmap, S4),
SymAttrs {
pkg_name: Some(pkg_name),
ty: Some(SymType::RetMap),
..Default::default()
},
S4,
),
XmloToken::Eoh(S1),
];
@ -662,15 +643,14 @@ mod test {
};
let toks = vec![
XmloToken::PkgName(pkg_name, S1),
XmloToken::PkgName(SPair(pkg_name, S1)),
XmloToken::SymDecl(
sym,
SPair(sym, S2),
SymAttrs {
pkg_name: Some(pkg_name),
ty: Some(SymType::Meta),
..Default::default()
},
S2,
),
XmloToken::Eoh(S1),
];
@ -705,15 +685,14 @@ mod test {
};
let toks = vec![
XmloToken::PkgName(pkg_name, S1),
XmloToken::PkgName(SPair(pkg_name, S1)),
XmloToken::SymDecl(
sym,
SPair(sym, S2),
SymAttrs {
// No name
ty: Some(SymType::Meta),
..Default::default()
},
S2,
),
XmloToken::Eoh(S1),
];
@ -741,8 +720,8 @@ mod test {
let bad_attrs = SymAttrs::default();
let toks = vec![
XmloToken::PkgName("name".into(), S1),
XmloToken::SymDecl(sym, bad_attrs, S2),
XmloToken::PkgName(SPair("name".into(), S1)),
XmloToken::SymDecl(SPair(sym, S2), bad_attrs),
XmloToken::Eoh(S1),
];
@ -757,8 +736,8 @@ mod test {
let frag = FragmentText::from("foo");
let toks = vec![
XmloToken::PkgName("name".into(), S1),
XmloToken::Fragment(sym, frag.clone(), S2),
XmloToken::PkgName(SPair("name".into(), S1)),
XmloToken::Fragment(SPair(sym, S2), frag.clone()),
XmloToken::Eoh(S1),
];

View File

@ -21,11 +21,12 @@ use std::fmt::Display;
use super::{SymAttrs, XmloError};
use crate::{
fmt::{DisplayWrapper, TtQuote},
num::{Dim, Dtype},
obj::xmlo::SymType,
parse::{
self, ClosedParseState, EmptyContext, NoContext, ParseState, Token,
Transition, TransitionResult, Transitionable,
self, util::SPair, ClosedParseState, EmptyContext, NoContext,
ParseState, Token, Transition, TransitionResult, Transitionable,
},
span::Span,
sym::{st::raw, SymbolId},
@ -49,24 +50,24 @@ use crate::{
#[derive(Debug, PartialEq, Eq)]
pub enum XmloToken {
/// Canonical package name.
PkgName(SymbolId, Span),
PkgName(SPair),
/// Relative path from package to project root.
PkgRootPath(SymbolId, Span),
PkgRootPath(SPair),
/// Indicates that the package is a program.
PkgProgramFlag(Span),
/// Name of package eligibility classification.
PkgEligClassYields(SymbolId, Span),
PkgEligClassYields(SPair),
/// Symbol declaration.
///
/// This represents an entry in the symbol table,
/// which includes a symbol along with its variable metadata as
/// [`SymAttrs`].
SymDecl(SymbolId, SymAttrs, Span),
SymDecl(SPair, SymAttrs),
/// Begin adjacency list for a given symbol and interpret subsequent
/// symbols as edges (dependencies).
SymDepStart(SymbolId, Span),
SymDepStart(SPair),
/// A symbol reference whose interpretation is dependent on the current
/// state.
@ -74,7 +75,7 @@ pub enum XmloToken {
/// The span currently references the object file itself,
/// but in the future this will resolve to a span stored within the
/// object file representing the source location of this symbol.
Symbol(SymbolId, Span),
Symbol(SPair),
/// Text (compiled code) fragment for a given symbol.
///
@ -83,7 +84,7 @@ pub enum XmloToken {
/// Given that fragments can be quite large,
/// a caller not interested in these data should choose to skip
/// fragments entirely rather than simply ignoring fragment events.
Fragment(SymbolId, SymbolId, Span),
Fragment(SPair, SymbolId),
/// End-of-header.
///
@ -108,14 +109,14 @@ impl Token for XmloToken {
// important since these initial tokens seed
// `Parser::last_span`,
// which is used for early error messages.
PkgName(_, span)
| PkgRootPath(_, span)
PkgName(SPair(_, span))
| PkgRootPath(SPair(_, span))
| PkgProgramFlag(span)
| PkgEligClassYields(_, span)
| SymDecl(.., span)
| SymDepStart(.., span)
| Symbol(.., span)
| Fragment(.., span)
| PkgEligClassYields(SPair(_, span))
| SymDecl(SPair(_, span), _)
| SymDepStart(SPair(_, span))
| Symbol(SPair(_, span))
| Fragment(SPair(_, span), _)
| Eoh(span) => *span,
}
}
@ -126,18 +127,32 @@ impl Display for XmloToken {
use XmloToken::*;
match self {
PkgName(sym, _) => write!(f, "package name `{sym}`"),
PkgRootPath(sym, _) => write!(f, "package root path `{sym}`"),
PkgName(sym) => write!(f, "package of name {}", TtQuote::wrap(sym)),
PkgRootPath(sym) => {
write!(f, "package root path {}", TtQuote::wrap(sym))
}
PkgProgramFlag(_) => write!(f, "package program flag"),
PkgEligClassYields(sym, _) => {
write!(f, "package eligibility classification `{sym}`")
PkgEligClassYields(sym) => {
write!(
f,
"package eligibility classification {}",
TtQuote::wrap(sym)
)
}
SymDecl(sym, ..) => write!(f, "symbol `{sym}` declaration"),
SymDepStart(sym, ..) => {
write!(f, "beginning of symbol `{sym}` dependency list")
SymDecl(sym, ..) => {
write!(f, "symbol {} declaration", TtQuote::wrap(sym))
}
SymDepStart(sym) => {
write!(
f,
"beginning of symbol {} dependency list",
TtQuote::wrap(sym)
)
}
Symbol(sym) => write!(f, "symbol {}", TtQuote::wrap(sym)),
Fragment(sym, _) => {
write!(f, "symbol {} code fragment", TtQuote::wrap(sym))
}
Symbol(sym, ..) => write!(f, "symbol `{sym}`"),
Fragment(sym, ..) => write!(f, "symbol `{sym}` code fragment"),
Eoh(..) => write!(f, "end of header"),
}
}
@ -206,12 +221,16 @@ impl<SS: XmloState, SD: XmloState, SF: XmloState> 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(value, aspan.1),
QN_UUROOTPATH => XmloToken::PkgRootPath(value, aspan.1),
QN_PROGRAM => XmloToken::PkgProgramFlag(aspan.0), // yes 0
QN_P_ELIG_CLASS_YIELDS => {
XmloToken::PkgEligClassYields(value, aspan.1)
QN_NAME => {
XmloToken::PkgName(SPair(value, aspan.value_span()))
}
QN_UUROOTPATH => {
XmloToken::PkgRootPath(SPair(value, aspan.value_span()))
}
QN_PROGRAM => XmloToken::PkgProgramFlag(aspan.key_span()),
QN_P_ELIG_CLASS_YIELDS => XmloToken::PkgEligClassYields(
SPair(value, aspan.value_span()),
),
// Ignore unknown attributes for now to maintain BC,
// since no strict xmlo schema has been defined.
_ => return Transition(Package(span)).incomplete(),
@ -335,11 +354,9 @@ pub enum SymtableState {
SymRef(Span, SymbolId, SymAttrs, Span),
}
impl parse::Object for (SymbolId, SymAttrs, Span) {}
impl ParseState for SymtableState {
type Token = Xirf<Text>;
type Object = (SymbolId, SymAttrs, Span);
type Object = XmloToken;
type Error = XmloError;
fn parse_token(
@ -364,7 +381,8 @@ impl ParseState for SymtableState {
// Completed symbol.
(Sym(span, Some(name), attrs), Xirf::Close(..)) => {
Transition(Ready).ok((name, attrs, span))
Transition(Ready)
.ok(XmloToken::SymDecl(SPair(name, span), attrs))
}
// Symbol @name found.
@ -597,14 +615,6 @@ impl Display for SymtableState {
}
}
impl From<(SymbolId, SymAttrs, Span)> for XmloToken {
fn from(tup: (SymbolId, SymAttrs, Span)) -> Self {
match tup {
(sym, attrs, span) => Self::SymDecl(sym, attrs, span),
}
}
}
/// Symbol dependency list (graph adjacency list) parser for
/// `preproc:sym-deps` children.
///
@ -645,7 +655,7 @@ impl ParseState for SymDepsState {
(SymUnnamed(span), Xirf::Attr(Attr(QN_NAME, name, _))) => {
Transition(Sym(span, name))
.ok(XmloToken::SymDepStart(name, span))
.ok(XmloToken::SymDepStart(SPair(name, span)))
}
(SymUnnamed(span), _) => Transition(SymUnnamed(span))
@ -660,7 +670,7 @@ impl ParseState for SymDepsState {
SymRefUnnamed(span, name, span_ref),
Xirf::Attr(Attr(QN_NAME, ref_name, AttrSpan(_, span_ref_name))),
) => Transition(SymRefDone(span, name, span_ref))
.ok(XmloToken::Symbol(ref_name, span_ref_name)),
.ok(XmloToken::Symbol(SPair(ref_name, span_ref_name))),
// TODO: For xmlns attributes, which will go away in XIRF.
(SymRefUnnamed(span, name, span_ref), Xirf::Attr(..)) => {
@ -731,8 +741,8 @@ pub enum FragmentsState {
#[default]
Ready,
FragmentUnnamed(Span),
Fragment(Span, SymbolId),
FragmentDone(Span, SymbolId),
Fragment(SPair),
FragmentDone(SPair),
}
impl ParseState for FragmentsState {
@ -763,7 +773,7 @@ impl ParseState for FragmentsState {
raw::WS_EMPTY => {
Transition(FragmentUnnamed(span)).incomplete()
}
id => Transition(Fragment(span, id)).incomplete(),
id => Transition(Fragment(SPair(id, span))).incomplete(),
}
}
@ -781,14 +791,14 @@ impl ParseState for FragmentsState {
(FragmentUnnamed(span), _) => Transition(FragmentUnnamed(span))
.err(XmloError::UnassociatedFragment(span)),
(Fragment(span, id), Xirf::Text(Text(text, _), _)) => {
Transition(FragmentDone(span, id))
.ok(XmloToken::Fragment(id, text, span))
(Fragment(name), Xirf::Text(Text(text, _), _)) => {
Transition(FragmentDone(name))
.ok(XmloToken::Fragment(name, text))
}
// TODO: Also a compiler bug, for some generated classes.
// This needs fixing in the compiler.
(Fragment(_span, _id), Xirf::Close(..)) => {
(Fragment(_), Xirf::Close(..)) => {
//eprintln!("warning: empty fragment text for {id} at {span}");
Transition(Ready).incomplete()
}
@ -817,11 +827,19 @@ impl Display for FragmentsState {
FragmentUnnamed(_) => {
write!(f, "expecting fragment association id")
}
Fragment(_, sym) => {
write!(f, "expecting fragment text for symbol `{sym}`")
Fragment(name) => {
write!(
f,
"expecting fragment text for symbol {}",
TtQuote::wrap(name)
)
}
FragmentDone(_, sym) => {
write!(f, "expecting end of fragment for symbol `{sym}`")
FragmentDone(name) => {
write!(
f,
"expecting end of fragment for symbol {}",
TtQuote::wrap(name)
)
}
}
}

View File

@ -79,14 +79,14 @@ fn common_parses_package_attrs(package: QName) {
assert_eq!(
Ok(vec![
Parsed::Incomplete,
Parsed::Object(XmloToken::PkgName(name, S3)),
Parsed::Object(XmloToken::PkgRootPath(relroot, S3)),
Parsed::Object(XmloToken::PkgName(SPair(name, S3))),
Parsed::Object(XmloToken::PkgRootPath(SPair(relroot, S3))),
// Span for the program flag is the attr name,
// rather than the value,
// since the value is just a boolean and does not provide as
// useful of context.
Parsed::Object(XmloToken::PkgProgramFlag(S3)),
Parsed::Object(XmloToken::PkgEligClassYields(elig, S4)),
Parsed::Object(XmloToken::PkgEligClassYields(SPair(elig, S4))),
Parsed::Incomplete,
]),
sut.collect(),
@ -125,7 +125,7 @@ fn ignores_unknown_package_attr() {
assert_eq!(
Ok(vec![
Parsed::Incomplete,
Parsed::Object(XmloToken::PkgName(name, S3)),
Parsed::Object(XmloToken::PkgName(SPair(name, S3))),
Parsed::Incomplete, // The unknown attribute
Parsed::Incomplete,
]),
@ -191,7 +191,10 @@ macro_rules! symtable_tests {
#[doc=stringify!($key)]
Parsed::Incomplete,
)*
Parsed::Object((name, expected, S3)),
Parsed::Object(XmloToken::SymDecl(
SPair(name, S3),
expected
)),
]),
Err(expected) => Err(ParseError::StateError(expected)),
},
@ -345,7 +348,7 @@ fn symtable_sym_generated_true() {
Parsed::Incomplete, // Opening tag
Parsed::Incomplete, // @name
Parsed::Incomplete, // @preproc:generated
Parsed::Object((name, expected, S3)),
Parsed::Object(XmloToken::SymDecl(SPair(name, S3), expected)),
]),
SymtableState::parse(toks).collect(),
);
@ -385,7 +388,7 @@ fn symtable_map_from() {
Parsed::Incomplete, // <preproc:from
Parsed::Incomplete, // @name
Parsed::Incomplete, // />
Parsed::Object((name, expected, S3)),
Parsed::Object(XmloToken::SymDecl(SPair(name, S3), expected)),
]),
SymtableState::parse(toks).collect(),
);
@ -471,12 +474,12 @@ fn sym_dep_event() {
assert_eq!(
Ok(vec![
Parsed::Incomplete, // <preproc:sym-ref
Parsed::Object(XmloToken::SymDepStart(name, S1)), // @name
Parsed::Object(XmloToken::SymDepStart(SPair(name, S1))), // @name
Parsed::Incomplete, // <preproc:sym-ref
Parsed::Object(XmloToken::Symbol(dep1, S4)), // @name
Parsed::Object(XmloToken::Symbol(SPair(dep1, S4))), // @name
Parsed::Incomplete, // />
Parsed::Incomplete, // <preproc:sym-ref
Parsed::Object(XmloToken::Symbol(dep2, S5)), // @name
Parsed::Object(XmloToken::Symbol(SPair(dep2, S5))), // @name
Parsed::Incomplete, // />
Parsed::Incomplete, // </preproc:sym-dep>
]),
@ -545,11 +548,11 @@ fn sym_fragment_event() {
Ok(vec![
Parsed::Incomplete, // <preproc:fragment
Parsed::Incomplete, // @id
Parsed::Object(XmloToken::Fragment(id1, frag1, S1)), // text
Parsed::Object(XmloToken::Fragment(SPair(id1, S1), frag1)), // text
Parsed::Incomplete, // </preproc:fragment>
Parsed::Incomplete, // <preproc:fragment
Parsed::Incomplete, // @id
Parsed::Object(XmloToken::Fragment(id2, frag2, S2)), // text
Parsed::Object(XmloToken::Fragment(SPair(id2, S2), frag2)), // text
Parsed::Incomplete, // </preproc:fragment>
]),
FragmentsState::parse(toks).collect()
@ -664,12 +667,11 @@ fn xmlo_composite_parsers_header() {
assert_eq!(
Ok(vec![
Parsed::Object(XmloToken::SymDecl(
sym_name,
SPair(sym_name, S3),
Default::default(),
S3
)),
Parsed::Object(XmloToken::SymDepStart(symdep_name, S3)),
Parsed::Object(XmloToken::Fragment(symfrag_id, frag, S4)),
Parsed::Object(XmloToken::SymDepStart(SPair(symdep_name, S3))),
Parsed::Object(XmloToken::Fragment(SPair(symfrag_id, S4), frag)),
Parsed::Object(XmloToken::Eoh(S3)),
]),
sut.filter(|parsed| match parsed {

View File

@ -37,6 +37,20 @@ use std::fmt::Display;
/// (such as [`Display`])
/// cannot be implemented on tuples at the time of writing.
///
/// This type provides some notable benefits:
///
/// - [`Display`]ing an [`SPair`] will render the [`SymbolId`]'s
/// interned string,
/// and the same [`SPair`] when used with
/// [`crate::diagnose::Annotate`] will provide annotated spans;
/// this allows [`SPair`] to be used without destructuring in
/// diagnostic messages.
/// - [`Span`]s are explicitly coupled with their corresponding
/// [`SymbolId`],
/// reducing complexity when many spans are in play.
/// - [`SPair`] implements [`Token`],
/// and so can serve as an ad-hoc IR if appropriate.
///
/// This implements [`Copy`] because each inner type is small
/// (and itself [`Copy`]),
/// and in practice,