tamer: nir: Introduce disambiguating RefSubject

The alternative I was floating was a tagged `Ref` (that is, with an enum
within it), but I settled on this for now, in part for a more concise
notation with the mapping in nir::parse.

We'll see how this evolves.  For now, it's not important with the only thing
that uses ref in nir::parse, which is template application.

This was introduced for `match`, which is to come shortly.

DEV-13708
main
Mike Gerwitz 2023-04-06 10:27:02 -04:00
parent 7b2acb65c5
commit 1f2ead7f9b
4 changed files with 42 additions and 10 deletions

View File

@ -99,12 +99,40 @@ pub enum Nir {
/// Bind the given name as an identifier for the entity atop of the
/// stack.
///
/// [`Self::Ref`] references identifiers created using this token.
BindIdent(SPair),
/// Reference the value of the given identifier as the subject of the
/// current expression.
///
/// The source language of TAME is historically XML,
/// which permits attributes in any order.
/// If an expression contains multiple references that the user expects
/// to mean a particular thing depending on attribute name,
/// then this can be used to disambiguate.
/// Other references may use [`Self::Ref`].
///
/// In XML notation,
/// examples include `match/@on` and `c:value-of/@name`.
///
/// NIR may at its discretion use this token to impose ordering,
/// which would have the effect of imposing XML attribute order.
RefSubject(SPair),
/// Reference the value of the given identifier.
///
/// Permissible identifiers and values depend on the context in which
/// this appears.
/// Identifiers are defined using [`Self::BindIdent`].
///
/// This reference has no particular significance other than not being
/// the [`Self::RefSubject`] of the expression;
/// all [`Self::Ref`]s within a given expression are semantically
/// equivalent,
/// and so should not be distinguished to the user by different
/// attribute names unless those names are too semantically
/// equivalent.
Ref(SPair),
/// Describe the [`NirEntity`] atop of the stack.
@ -137,9 +165,8 @@ impl Nir {
Open(_, _) | Close(_, _) => None,
BindIdent(spair) | Ref(spair) | Desc(spair) | Text(spair) => {
Some(spair.symbol())
}
BindIdent(spair) | RefSubject(spair) | Ref(spair) | Desc(spair)
| Text(spair) => Some(spair.symbol()),
}
}
}
@ -169,6 +196,7 @@ impl Functor<SymbolId> for Nir {
Open(_, _) | Close(_, _) => self,
BindIdent(spair) => BindIdent(spair.map(f)),
RefSubject(spair) => RefSubject(spair.map(f)),
Ref(spair) => Ref(spair.map(f)),
Desc(spair) => Desc(spair.map(f)),
Text(spair) => Text(spair.map(f)),
@ -288,9 +316,8 @@ impl Token for Nir {
Open(_, span) => *span,
Close(_, span) => *span,
BindIdent(spair) | Ref(spair) | Desc(spair) | Text(spair) => {
spair.span()
}
BindIdent(spair) | RefSubject(spair) | Ref(spair) | Desc(spair)
| Text(spair) => spair.span(),
}
}
}
@ -310,6 +337,9 @@ impl Display for Nir {
BindIdent(spair) => {
write!(f, "bind identifier {}", TtQuote::wrap(spair))
}
RefSubject(spair) => {
write!(f, "subject ref {}", TtQuote::wrap(spair))
}
Ref(spair) => write!(f, "ref {}", TtQuote::wrap(spair)),
// TODO: TtQuote doesn't yet escape quotes at the time of writing!

View File

@ -173,7 +173,9 @@ impl ParseState for NirToAir {
(Ready, BindIdent(spair)) => {
Transition(Ready).ok(Air::BindIdent(spair))
}
(Ready, Ref(spair)) => Transition(Ready).ok(Air::RefIdent(spair)),
(Ready, Ref(spair) | RefSubject(spair)) => {
Transition(Ready).ok(Air::RefIdent(spair))
}
(Ready, Todo | TodoAttr(..) | Desc(..)) => {
Transition(Ready).ok(Air::Todo(UNKNOWN_SPAN))

View File

@ -153,7 +153,7 @@ fn apply_template_long_form_nullary() {
#[rustfmt::skip]
let toks = vec![
Open(TplApply, S1),
Ref(name),
RefSubject(name),
Close(TplApply, S3),
];
@ -179,7 +179,7 @@ fn apply_template_long_form_args() {
#[rustfmt::skip]
let toks = vec![
Open(TplApply, S1),
Ref(name),
RefSubject(name),
Open(TplParam, S3),
BindIdent(p1),

View File

@ -1678,7 +1678,7 @@ ele_parse! {
/// which gets desugared into this via [`super::tplshort`].
ApplyTemplate := QN_APPLY_TEMPLATE(_, ospan) {
@ {
QN_NAME => Ref,
QN_NAME => RefSubject,
} => Nir::Open(NirEntity::TplApply, ospan.into()),
/(cspan) => Nir::Close(NirEntity::TplApply, cspan.into()),