2023-03-21 14:38:07 -04:00
|
|
|
|
// Shorthand template application desugaring for NIR
|
|
|
|
|
//
|
|
|
|
|
// Copyright (C) 2014-2023 Ryan Specialty, LLC.
|
|
|
|
|
//
|
|
|
|
|
// This file is part of TAME.
|
|
|
|
|
//
|
|
|
|
|
// This program is free software: you can redistribute it and/or modify
|
|
|
|
|
// it under the terms of the GNU General Public License as published by
|
|
|
|
|
// the Free Software Foundation, either version 3 of the License, or
|
|
|
|
|
// (at your option) any later version.
|
|
|
|
|
//
|
|
|
|
|
// This program is distributed in the hope that it will be useful,
|
|
|
|
|
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
|
|
|
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
|
|
|
// GNU General Public License for more details.
|
|
|
|
|
//
|
|
|
|
|
// You should have received a copy of the GNU General Public License
|
|
|
|
|
// along with this program. If not, see <http://www.gnu.org/licenses/>.
|
|
|
|
|
|
|
|
|
|
//! Shorthand template application desugaring for NIR.
|
|
|
|
|
//!
|
2023-03-23 22:43:55 -04:00
|
|
|
|
//! Desugaring is performed by [`TplShortDesugar`].
|
|
|
|
|
//!
|
2023-03-21 14:38:07 -04:00
|
|
|
|
//! A shorthand template application looks something like this,
|
|
|
|
|
//! in XML form:
|
|
|
|
|
//!
|
|
|
|
|
//! ```xml
|
|
|
|
|
//! <t:foo bar="baz">
|
|
|
|
|
//! <c:sum />
|
|
|
|
|
//! </t:foo>
|
|
|
|
|
//!
|
tamer: nir::tplshort: Desugar body into @values@
This represents a significant departure from how the XSLT-based TAME handles
the `@values@` param, but it will end up having the same effect. It builds
upon prior work, utilizing the fact that referencing a template in TAMER
will expand it.
The problem is this: allowing trees in `Meta` would add yet another
container; we have `Pkg` and `Tpl` already. This was the same problem with
template application---I didn't want to add support for binding arguments
separately, and so re-used templates themselves, reaching the generalization
I just mentioned above.
`Meta` is intended to be a lexical metasyntatic variable. That keeps its
implementation quite simple. But if we start allowing trees, that gets
rather complicated really quickly, and starts to require much more complex
AIR parser state.
But we can accomplish the same behavior by desugaring into an existing
container---a template---and placing the body within it. Then, in the
future, we'll parse `param-copy` into a simple `Air::RefIdent`, which will
expand the closed template and produce the same result as it does today in
the XSLT-based system.
This leaves open issues of closure (variable binding) in complex scenarios,
such as in templates that introduce metavariables to be utilized by the
body. That's never a practice I liked, but we'll see how things evolve.
Further, this does not yet handle nested template applications.
But this saved me a ton of work. Desugaring is much simpler.
The question is going to be how the XSLT-based compiler responds to this for
large packages with thousands of template applications. I'll have to see
if it's worth the hit at that time, or if we should inline it when
generating the `xmli` file, producing the same `@values@` as
before. But as it stands at this moment, the output is _not_ compatible
with the current compiler, as it expects `@values@` to be a tree, so a
modification would have to be made there.
DEV-13708
2023-03-23 14:40:40 -04:00
|
|
|
|
//! <!-- the above desugars into the below -->
|
|
|
|
|
//!
|
2023-03-21 14:38:07 -04:00
|
|
|
|
//! <apply-template name="_foo_">
|
|
|
|
|
//! <with-param name="@bar@" value="baz" />
|
tamer: nir::tplshort: Desugar body into @values@
This represents a significant departure from how the XSLT-based TAME handles
the `@values@` param, but it will end up having the same effect. It builds
upon prior work, utilizing the fact that referencing a template in TAMER
will expand it.
The problem is this: allowing trees in `Meta` would add yet another
container; we have `Pkg` and `Tpl` already. This was the same problem with
template application---I didn't want to add support for binding arguments
separately, and so re-used templates themselves, reaching the generalization
I just mentioned above.
`Meta` is intended to be a lexical metasyntatic variable. That keeps its
implementation quite simple. But if we start allowing trees, that gets
rather complicated really quickly, and starts to require much more complex
AIR parser state.
But we can accomplish the same behavior by desugaring into an existing
container---a template---and placing the body within it. Then, in the
future, we'll parse `param-copy` into a simple `Air::RefIdent`, which will
expand the closed template and produce the same result as it does today in
the XSLT-based system.
This leaves open issues of closure (variable binding) in complex scenarios,
such as in templates that introduce metavariables to be utilized by the
body. That's never a practice I liked, but we'll see how things evolve.
Further, this does not yet handle nested template applications.
But this saved me a ton of work. Desugaring is much simpler.
The question is going to be how the XSLT-based compiler responds to this for
large packages with thousands of template applications. I'll have to see
if it's worth the hit at that time, or if we should inline it when
generating the `xmli` file, producing the same `@values@` as
before. But as it stands at this moment, the output is _not_ compatible
with the current compiler, as it expects `@values@` to be a tree, so a
modification would have to be made there.
DEV-13708
2023-03-23 14:40:40 -04:00
|
|
|
|
//! <with-param name="@values@" value="___dsgr-01___" />
|
2023-03-21 14:38:07 -04:00
|
|
|
|
//! </apply-template>
|
tamer: nir::tplshort: Desugar body into @values@
This represents a significant departure from how the XSLT-based TAME handles
the `@values@` param, but it will end up having the same effect. It builds
upon prior work, utilizing the fact that referencing a template in TAMER
will expand it.
The problem is this: allowing trees in `Meta` would add yet another
container; we have `Pkg` and `Tpl` already. This was the same problem with
template application---I didn't want to add support for binding arguments
separately, and so re-used templates themselves, reaching the generalization
I just mentioned above.
`Meta` is intended to be a lexical metasyntatic variable. That keeps its
implementation quite simple. But if we start allowing trees, that gets
rather complicated really quickly, and starts to require much more complex
AIR parser state.
But we can accomplish the same behavior by desugaring into an existing
container---a template---and placing the body within it. Then, in the
future, we'll parse `param-copy` into a simple `Air::RefIdent`, which will
expand the closed template and produce the same result as it does today in
the XSLT-based system.
This leaves open issues of closure (variable binding) in complex scenarios,
such as in templates that introduce metavariables to be utilized by the
body. That's never a practice I liked, but we'll see how things evolve.
Further, this does not yet handle nested template applications.
But this saved me a ton of work. Desugaring is much simpler.
The question is going to be how the XSLT-based compiler responds to this for
large packages with thousands of template applications. I'll have to see
if it's worth the hit at that time, or if we should inline it when
generating the `xmli` file, producing the same `@values@` as
before. But as it stands at this moment, the output is _not_ compatible
with the current compiler, as it expects `@values@` to be a tree, so a
modification would have to be made there.
DEV-13708
2023-03-23 14:40:40 -04:00
|
|
|
|
//!
|
|
|
|
|
//! <template name="___dsgr-01___">
|
|
|
|
|
//! <c:sum />
|
|
|
|
|
//! </template>
|
2023-03-21 14:38:07 -04:00
|
|
|
|
//! ```
|
|
|
|
|
//!
|
|
|
|
|
//! The shorthand syntax makes templates look like another language
|
|
|
|
|
//! primitive,
|
|
|
|
|
//! with the exception of the namespace prefix.
|
|
|
|
|
//!
|
|
|
|
|
//! Note how desugaring also wraps template names in `'_'` and param names
|
|
|
|
|
//! in `'@'`.
|
|
|
|
|
//! These naming requirements were intended to eliminate conflicts with
|
|
|
|
|
//! other types of identifiers and to make it obvious when templates and
|
|
|
|
|
//! metavariables were being used,
|
|
|
|
|
//! but it works against the goal of making template applications look
|
|
|
|
|
//! like language primitives.
|
|
|
|
|
//! Shorthand form was added well after the long `apply-template` form.
|
|
|
|
|
//!
|
tamer: nir::tplshort: Desugar body into @values@
This represents a significant departure from how the XSLT-based TAME handles
the `@values@` param, but it will end up having the same effect. It builds
upon prior work, utilizing the fact that referencing a template in TAMER
will expand it.
The problem is this: allowing trees in `Meta` would add yet another
container; we have `Pkg` and `Tpl` already. This was the same problem with
template application---I didn't want to add support for binding arguments
separately, and so re-used templates themselves, reaching the generalization
I just mentioned above.
`Meta` is intended to be a lexical metasyntatic variable. That keeps its
implementation quite simple. But if we start allowing trees, that gets
rather complicated really quickly, and starts to require much more complex
AIR parser state.
But we can accomplish the same behavior by desugaring into an existing
container---a template---and placing the body within it. Then, in the
future, we'll parse `param-copy` into a simple `Air::RefIdent`, which will
expand the closed template and produce the same result as it does today in
the XSLT-based system.
This leaves open issues of closure (variable binding) in complex scenarios,
such as in templates that introduce metavariables to be utilized by the
body. That's never a practice I liked, but we'll see how things evolve.
Further, this does not yet handle nested template applications.
But this saved me a ton of work. Desugaring is much simpler.
The question is going to be how the XSLT-based compiler responds to this for
large packages with thousands of template applications. I'll have to see
if it's worth the hit at that time, or if we should inline it when
generating the `xmli` file, producing the same `@values@` as
before. But as it stands at this moment, the output is _not_ compatible
with the current compiler, as it expects `@values@` to be a tree, so a
modification would have to be made there.
DEV-13708
2023-03-23 14:40:40 -04:00
|
|
|
|
//! The body of a shorthand template becomes the body of a new template,
|
|
|
|
|
//! and its id referenced as the lexical value of the param `@values@`.
|
|
|
|
|
//! (This poor name is a historical artifact.)
|
|
|
|
|
//! Since the template is closed
|
|
|
|
|
//! (has no free metavariables),
|
|
|
|
|
//! it will be expanded on reference,
|
|
|
|
|
//! inlining its body into the reference site.
|
|
|
|
|
//! This is a different and generalized approach to the `param-copy`
|
|
|
|
|
//! behavior of the XLST-based TAME.
|
|
|
|
|
//!
|
2023-03-21 14:38:07 -04:00
|
|
|
|
//! This shorthand version does not permit metavariables for template or
|
|
|
|
|
//! param names,
|
|
|
|
|
//! so the long form is still a useful language feature for more
|
|
|
|
|
//! sophisticated cases.
|
|
|
|
|
//!
|
|
|
|
|
//! This was originally handled in the XSLT compiler in
|
|
|
|
|
//! `:src/current/include/preproc/template.xsl`.
|
|
|
|
|
//! You may need to consult the Git history if this file is no longer
|
|
|
|
|
//! available or if the XSLT template was since removed.
|
tamer: nir::tplshort: Desugar body into @values@
This represents a significant departure from how the XSLT-based TAME handles
the `@values@` param, but it will end up having the same effect. It builds
upon prior work, utilizing the fact that referencing a template in TAMER
will expand it.
The problem is this: allowing trees in `Meta` would add yet another
container; we have `Pkg` and `Tpl` already. This was the same problem with
template application---I didn't want to add support for binding arguments
separately, and so re-used templates themselves, reaching the generalization
I just mentioned above.
`Meta` is intended to be a lexical metasyntatic variable. That keeps its
implementation quite simple. But if we start allowing trees, that gets
rather complicated really quickly, and starts to require much more complex
AIR parser state.
But we can accomplish the same behavior by desugaring into an existing
container---a template---and placing the body within it. Then, in the
future, we'll parse `param-copy` into a simple `Air::RefIdent`, which will
expand the closed template and produce the same result as it does today in
the XSLT-based system.
This leaves open issues of closure (variable binding) in complex scenarios,
such as in templates that introduce metavariables to be utilized by the
body. That's never a practice I liked, but we'll see how things evolve.
Further, this does not yet handle nested template applications.
But this saved me a ton of work. Desugaring is much simpler.
The question is going to be how the XSLT-based compiler responds to this for
large packages with thousands of template applications. I'll have to see
if it's worth the hit at that time, or if we should inline it when
generating the `xmli` file, producing the same `@values@` as
before. But as it stands at this moment, the output is _not_ compatible
with the current compiler, as it expects `@values@` to be a tree, so a
modification would have to be made there.
DEV-13708
2023-03-23 14:40:40 -04:00
|
|
|
|
//! The XSLT-based compiler did not produce a separate template for
|
|
|
|
|
//! `@values@`.
|
2023-03-21 14:38:07 -04:00
|
|
|
|
|
|
|
|
|
use arrayvec::ArrayVec;
|
|
|
|
|
|
|
|
|
|
use super::{Nir, NirEntity};
|
|
|
|
|
use crate::{
|
2023-04-13 09:30:27 -04:00
|
|
|
|
fmt::{DisplayWrapper, TtQuote},
|
2023-03-21 14:38:07 -04:00
|
|
|
|
parse::prelude::*,
|
tamer: nir::tplshort: Desugar body into @values@
This represents a significant departure from how the XSLT-based TAME handles
the `@values@` param, but it will end up having the same effect. It builds
upon prior work, utilizing the fact that referencing a template in TAMER
will expand it.
The problem is this: allowing trees in `Meta` would add yet another
container; we have `Pkg` and `Tpl` already. This was the same problem with
template application---I didn't want to add support for binding arguments
separately, and so re-used templates themselves, reaching the generalization
I just mentioned above.
`Meta` is intended to be a lexical metasyntatic variable. That keeps its
implementation quite simple. But if we start allowing trees, that gets
rather complicated really quickly, and starts to require much more complex
AIR parser state.
But we can accomplish the same behavior by desugaring into an existing
container---a template---and placing the body within it. Then, in the
future, we'll parse `param-copy` into a simple `Air::RefIdent`, which will
expand the closed template and produce the same result as it does today in
the XSLT-based system.
This leaves open issues of closure (variable binding) in complex scenarios,
such as in templates that introduce metavariables to be utilized by the
body. That's never a practice I liked, but we'll see how things evolve.
Further, this does not yet handle nested template applications.
But this saved me a ton of work. Desugaring is much simpler.
The question is going to be how the XSLT-based compiler responds to this for
large packages with thousands of template applications. I'll have to see
if it's worth the hit at that time, or if we should inline it when
generating the `xmli` file, producing the same `@values@` as
before. But as it stands at this moment, the output is _not_ compatible
with the current compiler, as it expects `@values@` to be a tree, so a
modification would have to be made there.
DEV-13708
2023-03-23 14:40:40 -04:00
|
|
|
|
span::Span,
|
|
|
|
|
sym::{
|
|
|
|
|
st::raw::L_TPLP_VALUES, GlobalSymbolIntern, GlobalSymbolResolve,
|
|
|
|
|
SymbolId,
|
|
|
|
|
},
|
2023-03-21 14:38:07 -04:00
|
|
|
|
};
|
|
|
|
|
use std::convert::Infallible;
|
|
|
|
|
|
2023-03-23 11:41:52 -04:00
|
|
|
|
use Nir::*;
|
|
|
|
|
use NirEntity::*;
|
|
|
|
|
|
2023-03-23 22:43:55 -04:00
|
|
|
|
/// 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.
|
2023-03-21 14:38:07 -04:00
|
|
|
|
#[derive(Debug, PartialEq, Eq, Default)]
|
|
|
|
|
pub enum TplShortDesugar {
|
|
|
|
|
/// Waiting for shorthand template application,
|
|
|
|
|
/// passing tokens along in the meantime.
|
2023-03-23 22:43:55 -04:00
|
|
|
|
///
|
|
|
|
|
/// This state is also used when parsing the body of a shorthand
|
|
|
|
|
/// template application.
|
2023-03-21 14:38:07 -04:00
|
|
|
|
#[default]
|
|
|
|
|
Scanning,
|
tamer: nir::tplshort: Desugar body into @values@
This represents a significant departure from how the XSLT-based TAME handles
the `@values@` param, but it will end up having the same effect. It builds
upon prior work, utilizing the fact that referencing a template in TAMER
will expand it.
The problem is this: allowing trees in `Meta` would add yet another
container; we have `Pkg` and `Tpl` already. This was the same problem with
template application---I didn't want to add support for binding arguments
separately, and so re-used templates themselves, reaching the generalization
I just mentioned above.
`Meta` is intended to be a lexical metasyntatic variable. That keeps its
implementation quite simple. But if we start allowing trees, that gets
rather complicated really quickly, and starts to require much more complex
AIR parser state.
But we can accomplish the same behavior by desugaring into an existing
container---a template---and placing the body within it. Then, in the
future, we'll parse `param-copy` into a simple `Air::RefIdent`, which will
expand the closed template and produce the same result as it does today in
the XSLT-based system.
This leaves open issues of closure (variable binding) in complex scenarios,
such as in templates that introduce metavariables to be utilized by the
body. That's never a practice I liked, but we'll see how things evolve.
Further, this does not yet handle nested template applications.
But this saved me a ton of work. Desugaring is much simpler.
The question is going to be how the XSLT-based compiler responds to this for
large packages with thousands of template applications. I'll have to see
if it's worth the hit at that time, or if we should inline it when
generating the `xmli` file, producing the same `@values@` as
before. But as it stands at this moment, the output is _not_ compatible
with the current compiler, as it expects `@values@` to be a tree, so a
modification would have to be made there.
DEV-13708
2023-03-23 14:40:40 -04:00
|
|
|
|
|
|
|
|
|
/// A shorthand template application associated with the provided
|
2023-04-13 09:30:27 -04:00
|
|
|
|
/// [`SPair`] was encountered and shorthand params are being
|
|
|
|
|
/// desugared.
|
|
|
|
|
DesugaringParams(SPair),
|
2023-03-21 14:38:07 -04:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
impl Display for TplShortDesugar {
|
|
|
|
|
fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
|
|
|
|
|
match self {
|
|
|
|
|
Self::Scanning => {
|
|
|
|
|
write!(f, "awaiting shorthand template application")
|
|
|
|
|
}
|
tamer: nir::tplshort: Desugar body into @values@
This represents a significant departure from how the XSLT-based TAME handles
the `@values@` param, but it will end up having the same effect. It builds
upon prior work, utilizing the fact that referencing a template in TAMER
will expand it.
The problem is this: allowing trees in `Meta` would add yet another
container; we have `Pkg` and `Tpl` already. This was the same problem with
template application---I didn't want to add support for binding arguments
separately, and so re-used templates themselves, reaching the generalization
I just mentioned above.
`Meta` is intended to be a lexical metasyntatic variable. That keeps its
implementation quite simple. But if we start allowing trees, that gets
rather complicated really quickly, and starts to require much more complex
AIR parser state.
But we can accomplish the same behavior by desugaring into an existing
container---a template---and placing the body within it. Then, in the
future, we'll parse `param-copy` into a simple `Air::RefIdent`, which will
expand the closed template and produce the same result as it does today in
the XSLT-based system.
This leaves open issues of closure (variable binding) in complex scenarios,
such as in templates that introduce metavariables to be utilized by the
body. That's never a practice I liked, but we'll see how things evolve.
Further, this does not yet handle nested template applications.
But this saved me a ton of work. Desugaring is much simpler.
The question is going to be how the XSLT-based compiler responds to this for
large packages with thousands of template applications. I'll have to see
if it's worth the hit at that time, or if we should inline it when
generating the `xmli` file, producing the same `@values@` as
before. But as it stands at this moment, the output is _not_ compatible
with the current compiler, as it expects `@values@` to be a tree, so a
modification would have to be made there.
DEV-13708
2023-03-23 14:40:40 -04:00
|
|
|
|
Self::DesugaringParams(_) => {
|
|
|
|
|
write!(f, "desugaring shorthand template application params")
|
|
|
|
|
}
|
2023-03-21 14:38:07 -04:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
impl ParseState for TplShortDesugar {
|
|
|
|
|
type Token = Nir;
|
|
|
|
|
type Object = Nir;
|
|
|
|
|
type Error = Infallible;
|
|
|
|
|
type Context = Stack;
|
|
|
|
|
|
|
|
|
|
fn parse_token(
|
|
|
|
|
self,
|
|
|
|
|
tok: Self::Token,
|
|
|
|
|
stack: &mut Self::Context,
|
|
|
|
|
) -> TransitionResult<Self::Super> {
|
|
|
|
|
use TplShortDesugar::*;
|
|
|
|
|
|
|
|
|
|
if let Some(obj) = stack.pop() {
|
|
|
|
|
return Transition(self).ok(obj).with_lookahead(tok);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
match (self, tok) {
|
|
|
|
|
// Shorthand template applications are identified by a `Some`
|
|
|
|
|
// QName in the `TplApply` entity.
|
|
|
|
|
//
|
|
|
|
|
// The name of the template _without_ the underscore padding is
|
|
|
|
|
// the local part of the QName.
|
2023-03-23 22:08:21 -04:00
|
|
|
|
(Scanning, Open(TplApplyShort(qname), span)) => {
|
2023-03-21 14:38:07 -04:00
|
|
|
|
// TODO: Determine whether caching these has any notable
|
|
|
|
|
// benefit over repeated heap allocations,
|
|
|
|
|
// comparing packages with very few applications and
|
|
|
|
|
// packages with thousands
|
|
|
|
|
// (we'd still have to hit the heap for the cache).
|
|
|
|
|
let tpl_name =
|
|
|
|
|
format!("_{}_", qname.local_name().lookup_str()).intern();
|
|
|
|
|
|
2023-04-13 09:30:27 -04:00
|
|
|
|
let name = SPair(tpl_name, span);
|
|
|
|
|
stack.push(Ref(name));
|
2023-03-21 14:38:07 -04:00
|
|
|
|
|
2023-04-13 09:30:27 -04:00
|
|
|
|
Transition(DesugaringParams(name)).ok(Open(TplApply, span))
|
2023-03-21 14:38:07 -04:00
|
|
|
|
}
|
|
|
|
|
|
2023-03-22 10:07:16 -04:00
|
|
|
|
// Shorthand template params' names do not contain the
|
|
|
|
|
// surrounding `@`s.
|
2023-03-23 22:08:21 -04:00
|
|
|
|
(DesugaringParams(ospan), Open(TplParamShort(name, val), span)) => {
|
2023-03-22 10:07:16 -04:00
|
|
|
|
let pname = format!("@{name}@").intern();
|
|
|
|
|
|
tamer: nir::tplshort: Desugar body into @values@
This represents a significant departure from how the XSLT-based TAME handles
the `@values@` param, but it will end up having the same effect. It builds
upon prior work, utilizing the fact that referencing a template in TAMER
will expand it.
The problem is this: allowing trees in `Meta` would add yet another
container; we have `Pkg` and `Tpl` already. This was the same problem with
template application---I didn't want to add support for binding arguments
separately, and so re-used templates themselves, reaching the generalization
I just mentioned above.
`Meta` is intended to be a lexical metasyntatic variable. That keeps its
implementation quite simple. But if we start allowing trees, that gets
rather complicated really quickly, and starts to require much more complex
AIR parser state.
But we can accomplish the same behavior by desugaring into an existing
container---a template---and placing the body within it. Then, in the
future, we'll parse `param-copy` into a simple `Air::RefIdent`, which will
expand the closed template and produce the same result as it does today in
the XSLT-based system.
This leaves open issues of closure (variable binding) in complex scenarios,
such as in templates that introduce metavariables to be utilized by the
body. That's never a practice I liked, but we'll see how things evolve.
Further, this does not yet handle nested template applications.
But this saved me a ton of work. Desugaring is much simpler.
The question is going to be how the XSLT-based compiler responds to this for
large packages with thousands of template applications. I'll have to see
if it's worth the hit at that time, or if we should inline it when
generating the `xmli` file, producing the same `@values@` as
before. But as it stands at this moment, the output is _not_ compatible
with the current compiler, as it expects `@values@` to be a tree, so a
modification would have to be made there.
DEV-13708
2023-03-23 14:40:40 -04:00
|
|
|
|
// note: reversed (stack)
|
2023-03-23 22:08:21 -04:00
|
|
|
|
stack.push(Close(TplParam, span));
|
2023-03-23 11:41:52 -04:00
|
|
|
|
stack.push(Text(val));
|
|
|
|
|
stack.push(BindIdent(SPair(pname, name.span())));
|
2023-03-23 22:08:21 -04:00
|
|
|
|
Transition(DesugaringParams(ospan)).ok(Open(TplParam, span))
|
tamer: nir::tplshort: Desugar body into @values@
This represents a significant departure from how the XSLT-based TAME handles
the `@values@` param, but it will end up having the same effect. It builds
upon prior work, utilizing the fact that referencing a template in TAMER
will expand it.
The problem is this: allowing trees in `Meta` would add yet another
container; we have `Pkg` and `Tpl` already. This was the same problem with
template application---I didn't want to add support for binding arguments
separately, and so re-used templates themselves, reaching the generalization
I just mentioned above.
`Meta` is intended to be a lexical metasyntatic variable. That keeps its
implementation quite simple. But if we start allowing trees, that gets
rather complicated really quickly, and starts to require much more complex
AIR parser state.
But we can accomplish the same behavior by desugaring into an existing
container---a template---and placing the body within it. Then, in the
future, we'll parse `param-copy` into a simple `Air::RefIdent`, which will
expand the closed template and produce the same result as it does today in
the XSLT-based system.
This leaves open issues of closure (variable binding) in complex scenarios,
such as in templates that introduce metavariables to be utilized by the
body. That's never a practice I liked, but we'll see how things evolve.
Further, this does not yet handle nested template applications.
But this saved me a ton of work. Desugaring is much simpler.
The question is going to be how the XSLT-based compiler responds to this for
large packages with thousands of template applications. I'll have to see
if it's worth the hit at that time, or if we should inline it when
generating the `xmli` file, producing the same `@values@` as
before. But as it stands at this moment, the output is _not_ compatible
with the current compiler, as it expects `@values@` to be a tree, so a
modification would have to be made there.
DEV-13708
2023-03-23 14:40:40 -04:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// A child element while we're desugaring template params
|
|
|
|
|
// means that we have reached the body,
|
|
|
|
|
// which is to desugar into `@values@`.
|
|
|
|
|
// We generate a name for a new template,
|
|
|
|
|
// set `@values@` to the name of the template,
|
|
|
|
|
// close our active template application,
|
|
|
|
|
// and then place the body into that template.
|
|
|
|
|
//
|
|
|
|
|
// TODO: This does not handle nested template applications.
|
2023-04-13 09:30:27 -04:00
|
|
|
|
(DesugaringParams(name), tok @ Open(..)) => {
|
|
|
|
|
let ospan = name.span();
|
tamer: nir::tplshort: Desugar body into @values@
This represents a significant departure from how the XSLT-based TAME handles
the `@values@` param, but it will end up having the same effect. It builds
upon prior work, utilizing the fact that referencing a template in TAMER
will expand it.
The problem is this: allowing trees in `Meta` would add yet another
container; we have `Pkg` and `Tpl` already. This was the same problem with
template application---I didn't want to add support for binding arguments
separately, and so re-used templates themselves, reaching the generalization
I just mentioned above.
`Meta` is intended to be a lexical metasyntatic variable. That keeps its
implementation quite simple. But if we start allowing trees, that gets
rather complicated really quickly, and starts to require much more complex
AIR parser state.
But we can accomplish the same behavior by desugaring into an existing
container---a template---and placing the body within it. Then, in the
future, we'll parse `param-copy` into a simple `Air::RefIdent`, which will
expand the closed template and produce the same result as it does today in
the XSLT-based system.
This leaves open issues of closure (variable binding) in complex scenarios,
such as in templates that introduce metavariables to be utilized by the
body. That's never a practice I liked, but we'll see how things evolve.
Further, this does not yet handle nested template applications.
But this saved me a ton of work. Desugaring is much simpler.
The question is going to be how the XSLT-based compiler responds to this for
large packages with thousands of template applications. I'll have to see
if it's worth the hit at that time, or if we should inline it when
generating the `xmli` file, producing the same `@values@` as
before. But as it stands at this moment, the output is _not_ compatible
with the current compiler, as it expects `@values@` to be a tree, so a
modification would have to be made there.
DEV-13708
2023-03-23 14:40:40 -04:00
|
|
|
|
let gen_name = gen_tpl_name_at_offset(ospan);
|
2023-04-13 09:30:27 -04:00
|
|
|
|
let gen_desc = values_tpl_desc(name);
|
tamer: nir::tplshort: Desugar body into @values@
This represents a significant departure from how the XSLT-based TAME handles
the `@values@` param, but it will end up having the same effect. It builds
upon prior work, utilizing the fact that referencing a template in TAMER
will expand it.
The problem is this: allowing trees in `Meta` would add yet another
container; we have `Pkg` and `Tpl` already. This was the same problem with
template application---I didn't want to add support for binding arguments
separately, and so re-used templates themselves, reaching the generalization
I just mentioned above.
`Meta` is intended to be a lexical metasyntatic variable. That keeps its
implementation quite simple. But if we start allowing trees, that gets
rather complicated really quickly, and starts to require much more complex
AIR parser state.
But we can accomplish the same behavior by desugaring into an existing
container---a template---and placing the body within it. Then, in the
future, we'll parse `param-copy` into a simple `Air::RefIdent`, which will
expand the closed template and produce the same result as it does today in
the XSLT-based system.
This leaves open issues of closure (variable binding) in complex scenarios,
such as in templates that introduce metavariables to be utilized by the
body. That's never a practice I liked, but we'll see how things evolve.
Further, this does not yet handle nested template applications.
But this saved me a ton of work. Desugaring is much simpler.
The question is going to be how the XSLT-based compiler responds to this for
large packages with thousands of template applications. I'll have to see
if it's worth the hit at that time, or if we should inline it when
generating the `xmli` file, producing the same `@values@` as
before. But as it stands at this moment, the output is _not_ compatible
with the current compiler, as it expects `@values@` to be a tree, so a
modification would have to be made there.
DEV-13708
2023-03-23 14:40:40 -04:00
|
|
|
|
|
|
|
|
|
// The spans are awkward here because we are streaming,
|
|
|
|
|
// and so don't have much choice but to use the opening
|
|
|
|
|
// span for everything.
|
|
|
|
|
// If this ends up being unhelpful for diagnostics,
|
|
|
|
|
// we can have AIR do some adjustment through some
|
|
|
|
|
// yet-to-be-defined means.
|
|
|
|
|
//
|
|
|
|
|
// note: reversed (stack)
|
2023-04-13 09:30:27 -04:00
|
|
|
|
stack.push(Desc(gen_desc));
|
tamer: nir::tplshort: Desugar body into @values@
This represents a significant departure from how the XSLT-based TAME handles
the `@values@` param, but it will end up having the same effect. It builds
upon prior work, utilizing the fact that referencing a template in TAMER
will expand it.
The problem is this: allowing trees in `Meta` would add yet another
container; we have `Pkg` and `Tpl` already. This was the same problem with
template application---I didn't want to add support for binding arguments
separately, and so re-used templates themselves, reaching the generalization
I just mentioned above.
`Meta` is intended to be a lexical metasyntatic variable. That keeps its
implementation quite simple. But if we start allowing trees, that gets
rather complicated really quickly, and starts to require much more complex
AIR parser state.
But we can accomplish the same behavior by desugaring into an existing
container---a template---and placing the body within it. Then, in the
future, we'll parse `param-copy` into a simple `Air::RefIdent`, which will
expand the closed template and produce the same result as it does today in
the XSLT-based system.
This leaves open issues of closure (variable binding) in complex scenarios,
such as in templates that introduce metavariables to be utilized by the
body. That's never a practice I liked, but we'll see how things evolve.
Further, this does not yet handle nested template applications.
But this saved me a ton of work. Desugaring is much simpler.
The question is going to be how the XSLT-based compiler responds to this for
large packages with thousands of template applications. I'll have to see
if it's worth the hit at that time, or if we should inline it when
generating the `xmli` file, producing the same `@values@` as
before. But as it stands at this moment, the output is _not_ compatible
with the current compiler, as it expects `@values@` to be a tree, so a
modification would have to be made there.
DEV-13708
2023-03-23 14:40:40 -04:00
|
|
|
|
stack.push(BindIdent(SPair(gen_name, ospan)));
|
|
|
|
|
stack.push(Open(Tpl, ospan));
|
|
|
|
|
|
|
|
|
|
// Application ends here,
|
|
|
|
|
// and the new template (above) will absorb both this
|
|
|
|
|
// token `tok` and all tokens that come after.
|
2023-03-23 22:08:21 -04:00
|
|
|
|
stack.push(Close(TplApply, ospan));
|
|
|
|
|
stack.push(Close(TplParam, ospan));
|
tamer: nir::tplshort: Desugar body into @values@
This represents a significant departure from how the XSLT-based TAME handles
the `@values@` param, but it will end up having the same effect. It builds
upon prior work, utilizing the fact that referencing a template in TAMER
will expand it.
The problem is this: allowing trees in `Meta` would add yet another
container; we have `Pkg` and `Tpl` already. This was the same problem with
template application---I didn't want to add support for binding arguments
separately, and so re-used templates themselves, reaching the generalization
I just mentioned above.
`Meta` is intended to be a lexical metasyntatic variable. That keeps its
implementation quite simple. But if we start allowing trees, that gets
rather complicated really quickly, and starts to require much more complex
AIR parser state.
But we can accomplish the same behavior by desugaring into an existing
container---a template---and placing the body within it. Then, in the
future, we'll parse `param-copy` into a simple `Air::RefIdent`, which will
expand the closed template and produce the same result as it does today in
the XSLT-based system.
This leaves open issues of closure (variable binding) in complex scenarios,
such as in templates that introduce metavariables to be utilized by the
body. That's never a practice I liked, but we'll see how things evolve.
Further, this does not yet handle nested template applications.
But this saved me a ton of work. Desugaring is much simpler.
The question is going to be how the XSLT-based compiler responds to this for
large packages with thousands of template applications. I'll have to see
if it's worth the hit at that time, or if we should inline it when
generating the `xmli` file, producing the same `@values@` as
before. But as it stands at this moment, the output is _not_ compatible
with the current compiler, as it expects `@values@` to be a tree, so a
modification would have to be made there.
DEV-13708
2023-03-23 14:40:40 -04:00
|
|
|
|
stack.push(Text(SPair(gen_name, ospan)));
|
|
|
|
|
stack.push(BindIdent(SPair(L_TPLP_VALUES, ospan)));
|
2023-03-23 22:43:55 -04:00
|
|
|
|
|
|
|
|
|
// 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)
|
tamer: nir::tplshort: Desugar body into @values@
This represents a significant departure from how the XSLT-based TAME handles
the `@values@` param, but it will end up having the same effect. It builds
upon prior work, utilizing the fact that referencing a template in TAMER
will expand it.
The problem is this: allowing trees in `Meta` would add yet another
container; we have `Pkg` and `Tpl` already. This was the same problem with
template application---I didn't want to add support for binding arguments
separately, and so re-used templates themselves, reaching the generalization
I just mentioned above.
`Meta` is intended to be a lexical metasyntatic variable. That keeps its
implementation quite simple. But if we start allowing trees, that gets
rather complicated really quickly, and starts to require much more complex
AIR parser state.
But we can accomplish the same behavior by desugaring into an existing
container---a template---and placing the body within it. Then, in the
future, we'll parse `param-copy` into a simple `Air::RefIdent`, which will
expand the closed template and produce the same result as it does today in
the XSLT-based system.
This leaves open issues of closure (variable binding) in complex scenarios,
such as in templates that introduce metavariables to be utilized by the
body. That's never a practice I liked, but we'll see how things evolve.
Further, this does not yet handle nested template applications.
But this saved me a ton of work. Desugaring is much simpler.
The question is going to be how the XSLT-based compiler responds to this for
large packages with thousands of template applications. I'll have to see
if it's worth the hit at that time, or if we should inline it when
generating the `xmli` file, producing the same `@values@` as
before. But as it stands at this moment, the output is _not_ compatible
with the current compiler, as it expects `@values@` to be a tree, so a
modification would have to be made there.
DEV-13708
2023-03-23 14:40:40 -04:00
|
|
|
|
}
|
2023-03-22 10:07:16 -04:00
|
|
|
|
|
2023-03-23 22:43:55 -04:00
|
|
|
|
// If we're scanning and find a closing shorthand application,
|
|
|
|
|
// then we must have just finished with a shorthand body.
|
|
|
|
|
(Scanning, Close(TplApplyShort(_), span)) => {
|
tamer: nir::tplshort: Desugar body into @values@
This represents a significant departure from how the XSLT-based TAME handles
the `@values@` param, but it will end up having the same effect. It builds
upon prior work, utilizing the fact that referencing a template in TAMER
will expand it.
The problem is this: allowing trees in `Meta` would add yet another
container; we have `Pkg` and `Tpl` already. This was the same problem with
template application---I didn't want to add support for binding arguments
separately, and so re-used templates themselves, reaching the generalization
I just mentioned above.
`Meta` is intended to be a lexical metasyntatic variable. That keeps its
implementation quite simple. But if we start allowing trees, that gets
rather complicated really quickly, and starts to require much more complex
AIR parser state.
But we can accomplish the same behavior by desugaring into an existing
container---a template---and placing the body within it. Then, in the
future, we'll parse `param-copy` into a simple `Air::RefIdent`, which will
expand the closed template and produce the same result as it does today in
the XSLT-based system.
This leaves open issues of closure (variable binding) in complex scenarios,
such as in templates that introduce metavariables to be utilized by the
body. That's never a practice I liked, but we'll see how things evolve.
Further, this does not yet handle nested template applications.
But this saved me a ton of work. Desugaring is much simpler.
The question is going to be how the XSLT-based compiler responds to this for
large packages with thousands of template applications. I'll have to see
if it's worth the hit at that time, or if we should inline it when
generating the `xmli` file, producing the same `@values@` as
before. But as it stands at this moment, the output is _not_ compatible
with the current compiler, as it expects `@values@` to be a tree, so a
modification would have to be made there.
DEV-13708
2023-03-23 14:40:40 -04:00
|
|
|
|
Transition(Scanning).ok(Close(Tpl, span))
|
|
|
|
|
}
|
|
|
|
|
|
2023-03-23 22:43:55 -04:00
|
|
|
|
// If we complete the shorthand template during param parsing,
|
|
|
|
|
// then we have no body and must close the application.
|
2023-03-23 22:08:21 -04:00
|
|
|
|
(DesugaringParams(_), Close(TplApplyShort(_), span)) => {
|
|
|
|
|
Transition(Scanning).ok(Close(TplApply, span))
|
2023-03-22 10:07:16 -04:00
|
|
|
|
}
|
|
|
|
|
|
2023-03-21 14:38:07 -04:00
|
|
|
|
// Any tokens that we don't recognize will be passed on unchanged.
|
2023-03-22 10:07:16 -04:00
|
|
|
|
(st, tok) => Transition(st).ok(tok),
|
2023-03-21 14:38:07 -04:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
fn is_accepting(&self, stack: &Self::Context) -> bool {
|
|
|
|
|
matches!(self, Self::Scanning) && stack.is_empty()
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
tamer: nir::tplshort: Desugar body into @values@
This represents a significant departure from how the XSLT-based TAME handles
the `@values@` param, but it will end up having the same effect. It builds
upon prior work, utilizing the fact that referencing a template in TAMER
will expand it.
The problem is this: allowing trees in `Meta` would add yet another
container; we have `Pkg` and `Tpl` already. This was the same problem with
template application---I didn't want to add support for binding arguments
separately, and so re-used templates themselves, reaching the generalization
I just mentioned above.
`Meta` is intended to be a lexical metasyntatic variable. That keeps its
implementation quite simple. But if we start allowing trees, that gets
rather complicated really quickly, and starts to require much more complex
AIR parser state.
But we can accomplish the same behavior by desugaring into an existing
container---a template---and placing the body within it. Then, in the
future, we'll parse `param-copy` into a simple `Air::RefIdent`, which will
expand the closed template and produce the same result as it does today in
the XSLT-based system.
This leaves open issues of closure (variable binding) in complex scenarios,
such as in templates that introduce metavariables to be utilized by the
body. That's never a practice I liked, but we'll see how things evolve.
Further, this does not yet handle nested template applications.
But this saved me a ton of work. Desugaring is much simpler.
The question is going to be how the XSLT-based compiler responds to this for
large packages with thousands of template applications. I'll have to see
if it's worth the hit at that time, or if we should inline it when
generating the `xmli` file, producing the same `@values@` as
before. But as it stands at this moment, the output is _not_ compatible
with the current compiler, as it expects `@values@` to be a tree, so a
modification would have to be made there.
DEV-13708
2023-03-23 14:40:40 -04:00
|
|
|
|
type Stack = ArrayVec<Nir, 7>;
|
|
|
|
|
|
|
|
|
|
/// Generate a deterministic template identifier name that is unique
|
|
|
|
|
/// relative to the offset in the source context (file) of the given
|
|
|
|
|
/// [`Span`].
|
|
|
|
|
///
|
|
|
|
|
/// Hygiene is not a concern since identifiers cannot be redeclared,
|
|
|
|
|
/// so conflicts with manually-created identifiers will result in a
|
|
|
|
|
/// compilation error
|
|
|
|
|
/// (albeit a cryptic one);
|
|
|
|
|
/// the hope is that the informally-compiler-reserved `___` convention
|
|
|
|
|
/// mitigates that unlikely occurrence.
|
|
|
|
|
/// Consequently,
|
|
|
|
|
/// we _must_ intern to ensure that error can occur
|
|
|
|
|
/// (we cannot use [`GlobalSymbolIntern::clone_uninterned`]).
|
|
|
|
|
#[inline]
|
|
|
|
|
fn gen_tpl_name_at_offset(span: Span) -> SymbolId {
|
|
|
|
|
format!("___dsgr-{:x}___", span.offset()).intern()
|
|
|
|
|
}
|
2023-03-21 14:38:07 -04:00
|
|
|
|
|
2023-04-13 09:30:27 -04:00
|
|
|
|
/// Generate a description for the template generated from the body of a
|
|
|
|
|
/// shorthand template application.
|
|
|
|
|
///
|
|
|
|
|
/// Descriptions are required on templates,
|
|
|
|
|
/// but we should also provide something that is useful in debugging.
|
|
|
|
|
/// The description will contain the name of the template being applied and
|
|
|
|
|
/// will share the same span as the provided [`SPair`] `applying`'s,
|
|
|
|
|
/// having been derived from it.
|
|
|
|
|
fn values_tpl_desc(applying: SPair) -> SPair {
|
|
|
|
|
SPair(
|
|
|
|
|
format!(
|
|
|
|
|
"Desugared body of shorthand template application of {}",
|
|
|
|
|
TtQuote::wrap(applying.symbol())
|
|
|
|
|
)
|
|
|
|
|
.intern(),
|
|
|
|
|
applying.span(),
|
|
|
|
|
)
|
|
|
|
|
}
|
|
|
|
|
|
2023-03-21 14:38:07 -04:00
|
|
|
|
#[cfg(test)]
|
|
|
|
|
mod test;
|