tamer: nir::tplshort: Desugar nested template applications
I'm happy with how this ended up turning out---I was able to accomplish this without having to introduce any additional state to the parser (I _removed_ a state, actually) by tweaking NIR a bit in a previous commit. We can't update the system test yet, though, because nested templates are not yet supported by asg::air::tpl; that'll come next. If you try, you'll be greeted with this error presently (which is worth showing since you'll never see it unless you're hacking TAMER): ,=====[ ./tests/xmli/template/ logs ]====== | | thread 'main' panicked at 'not yet implemented: internal error: | note: nested tpl open | --> ./tests/xmli/template/src.xml:129:5 | | | 129 | <t:inner-short /> | | -------------- note: for this template | | | !!! ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ !!! | !!! THIS IS AN UNFINISHED FEATURE IN TAMER !!! | !!! ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ !!! | !!! This message means that TAMER has encountered an !!! | !!! unrecoverable error that forced it to terminate !!! | !!! processing. !!! | !!! !!! | !!! TAMER has attempted to provide you with contextual !!! | !!! information above that might allow you to work around !!! | !!! this problem until it can be fixed. !!! | !!! !!! | !!! Please report this error, including the above !!! | !!! diagnostic output beginning with 'internal error:'. !!! | !!! ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ !!! | ', src/asg/air/tpl.rs:207:55 | note: run with `RUST_BACKTRACE=1` environment variable to display a backtrace | Command exited with non-zero status 101 | 0/165fault 0/8io 3528rss 14/2ctx | /home/[...]/tame/tamer/target/debug/tamec -o ./tests/xmli/template/out.xmli --emit xmlo ./tests/xmli/template/src.xml | `====[ end ./tests/xmli/template/ logs ]==== DEV-13708main
parent
6581c9946c
commit
e1c8e371d5
|
@ -19,6 +19,8 @@
|
|||
|
||||
//! Shorthand template application desugaring for NIR.
|
||||
//!
|
||||
//! Desugaring is performed by [`TplShortDesugar`].
|
||||
//!
|
||||
//! A shorthand template application looks something like this,
|
||||
//! in XML form:
|
||||
//!
|
||||
|
@ -90,21 +92,27 @@ use std::convert::Infallible;
|
|||
use Nir::*;
|
||||
use NirEntity::*;
|
||||
|
||||
/// Desugar shorthand template applications into long-form template
|
||||
/// applications.
|
||||
///
|
||||
/// This parser is able to handle nested applications without having to
|
||||
/// track nesting by taking advantage of the parsing that NIR has already
|
||||
/// performed.
|
||||
///
|
||||
/// See the [module-level documentation](super) for more information.
|
||||
#[derive(Debug, PartialEq, Eq, Default)]
|
||||
pub enum TplShortDesugar {
|
||||
/// Waiting for shorthand template application,
|
||||
/// passing tokens along in the meantime.
|
||||
///
|
||||
/// This state is also used when parsing the body of a shorthand
|
||||
/// template application.
|
||||
#[default]
|
||||
Scanning,
|
||||
|
||||
/// A shorthand template application associated with the provided
|
||||
/// [`Span`] was encountered and shorthand params are being desugared.
|
||||
DesugaringParams(Span),
|
||||
|
||||
/// A child element was encountered while desugaring params,
|
||||
/// indicating a body of the shorthand application that needs
|
||||
/// desugaring into `@values@`.
|
||||
DesugaringBody,
|
||||
}
|
||||
|
||||
impl Display for TplShortDesugar {
|
||||
|
@ -116,9 +124,6 @@ impl Display for TplShortDesugar {
|
|||
Self::DesugaringParams(_) => {
|
||||
write!(f, "desugaring shorthand template application params")
|
||||
}
|
||||
Self::DesugaringBody => {
|
||||
write!(f, "desugaring shorthand template application body")
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -192,7 +197,6 @@ impl ParseState for TplShortDesugar {
|
|||
// yet-to-be-defined means.
|
||||
//
|
||||
// note: reversed (stack)
|
||||
stack.push(tok);
|
||||
stack.push(BindIdent(SPair(gen_name, ospan)));
|
||||
stack.push(Open(Tpl, ospan));
|
||||
|
||||
|
@ -203,13 +207,23 @@ impl ParseState for TplShortDesugar {
|
|||
stack.push(Close(TplParam, ospan));
|
||||
stack.push(Text(SPair(gen_name, ospan)));
|
||||
stack.push(BindIdent(SPair(L_TPLP_VALUES, ospan)));
|
||||
Transition(DesugaringBody).ok(Open(TplParam, ospan))
|
||||
|
||||
// Note that we must have `tok` as lookahead instead of
|
||||
// pushing directly on the stack in case it's a
|
||||
// `TplApplyShort`.
|
||||
Transition(Scanning)
|
||||
.ok(Open(TplParam, ospan))
|
||||
.with_lookahead(tok)
|
||||
}
|
||||
|
||||
(DesugaringBody, Close(TplApplyShort(_), span)) => {
|
||||
// If we're scanning and find a closing shorthand application,
|
||||
// then we must have just finished with a shorthand body.
|
||||
(Scanning, Close(TplApplyShort(_), span)) => {
|
||||
Transition(Scanning).ok(Close(Tpl, span))
|
||||
}
|
||||
|
||||
// If we complete the shorthand template during param parsing,
|
||||
// then we have no body and must close the application.
|
||||
(DesugaringParams(_), Close(TplApplyShort(_), span)) => {
|
||||
Transition(Scanning).ok(Close(TplApply, span))
|
||||
}
|
||||
|
|
|
@ -162,6 +162,54 @@ fn desugars_body_into_tpl_with_ref_in_values_param() {
|
|||
);
|
||||
}
|
||||
|
||||
// Shorthand within a shorthand.
|
||||
#[test]
|
||||
fn desugar_nested_apply() {
|
||||
let qname_outer = ("t", "outer").unwrap_into();
|
||||
let name_outer = SPair("_outer_".into(), S1);
|
||||
|
||||
let qname_inner = ("t", "inner").unwrap_into();
|
||||
let name_inner = SPair("_inner_".into(), S2);
|
||||
|
||||
#[rustfmt::skip]
|
||||
let toks = vec![
|
||||
Open(TplApplyShort(qname_outer), S1),
|
||||
// Body is a second shorthand template application.
|
||||
Open(TplApplyShort(qname_inner), S2),
|
||||
Close(TplApplyShort(qname_inner), S3),
|
||||
Close(TplApplyShort(qname_outer), S4),
|
||||
];
|
||||
|
||||
let gen_name_outer = gen_tpl_name_at_offset(S1);
|
||||
|
||||
#[rustfmt::skip]
|
||||
assert_eq!(
|
||||
Ok(vec![
|
||||
O(Open(TplApply, S1)),
|
||||
O(Ref(name_outer)),
|
||||
|
||||
// @values@
|
||||
O(Open(TplParam, S1)),
|
||||
O(BindIdent(SPair(L_TPLP_VALUES, S1))),
|
||||
O(Text(SPair(gen_name_outer, S1))), //:-.
|
||||
O(Close(TplParam, S1)), // |
|
||||
O(Close(TplApply, S1)), // |
|
||||
// |
|
||||
O(Open(Tpl, S1)), // /
|
||||
O(BindIdent(SPair(gen_name_outer, S1))), //<`
|
||||
|
||||
// And within this template,
|
||||
// we generate another application.
|
||||
// This one has no body and so no `@values@`.
|
||||
O(Open(TplApply, S2)),
|
||||
O(Ref(name_inner)),
|
||||
O(Close(TplApply, S3)),
|
||||
O(Close(Tpl, S4)),
|
||||
]),
|
||||
Sut::parse(toks.into_iter()).collect(),
|
||||
);
|
||||
}
|
||||
|
||||
// Don't parse what we desugar into!
|
||||
#[test]
|
||||
fn does_not_desugar_long_form() {
|
||||
|
|
Loading…
Reference in New Issue