tamer: nir: Sugared and plain flavors

This introduces the concept of sugared NIR and provides the boilerplate for
a desugaring pass.  The earlier commits dealing with cleaning up the
lowering pipeline were to support this work, in particular to ensure that
reporting and recovery properly applied to this lowering operation without
adding a ton more boilerplate.

DEV-13158
main
Mike Gerwitz 2022-10-19 10:00:08 -04:00
parent dbe834b48a
commit d195eedacb
5 changed files with 317 additions and 124 deletions

View File

@ -37,7 +37,7 @@ use tamer::{
diagnose::{
AnnotatedSpan, Diagnostic, FsSpanResolver, Reporter, VisualReporter,
},
nir::{XirfToNir, XirfToNirError},
nir::{DesugarNir, DesugarNirError, SugaredNir, XirfToNir, XirfToNirError},
parse::{
Lower, ParseError, Parsed, ParsedObject, ParsedResult, UnknownToken,
},
@ -135,13 +135,15 @@ fn compile<R: Reporter>(
XirToXirf<64, RefinedText>,
_,
>::lower::<_, UnrecoverableError>(src, |toks| {
Lower::<XirToXirf<64, RefinedText>, XirfToNir, _>::lower(toks, |nir| {
nir.fold(Ok(()), |x, result| match result {
Ok(_) => x,
Err(e) => {
report_err(&e, reporter, &mut ebuf)?;
x
}
Lower::<XirToXirf<64, RefinedText>, XirfToNir, _>::lower(toks, |snir| {
Lower::<XirfToNir, DesugarNir, _>::lower(snir, |nir| {
nir.fold(Ok(()), |x, result| match result {
Ok(_) => x,
Err(e) => {
report_err(&e, reporter, &mut ebuf)?;
x
}
})
})
})
})?;
@ -295,6 +297,7 @@ pub enum RecoverableError {
XirParseError(ParseError<UnknownToken, xir::Error>),
XirfParseError(ParseError<XirToken, XirToXirfError>),
NirParseError(ParseError<XirfToken<RefinedText>, XirfToNirError>),
DesugarNirError(ParseError<SugaredNir, DesugarNirError>),
}
impl From<io::Error> for UnrecoverableError {
@ -327,12 +330,20 @@ impl From<ParseError<XirToken, XirToXirfError>> for RecoverableError {
}
}
impl From<ParseError<XirfToken<RefinedText>, XirfToNirError>> for RecoverableError {
impl From<ParseError<XirfToken<RefinedText>, XirfToNirError>>
for RecoverableError
{
fn from(e: ParseError<XirfToken<RefinedText>, XirfToNirError>) -> Self {
Self::NirParseError(e)
}
}
impl From<ParseError<SugaredNir, DesugarNirError>> for RecoverableError {
fn from(e: ParseError<SugaredNir, DesugarNirError>) -> Self {
Self::DesugarNirError(e)
}
}
impl Display for UnrecoverableError {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
match self {
@ -354,6 +365,7 @@ impl Display for RecoverableError {
Self::XirParseError(e) => Display::fmt(e, f),
Self::XirfParseError(e) => Display::fmt(e, f),
Self::NirParseError(e) => Display::fmt(e, f),
Self::DesugarNirError(e) => Display::fmt(e, f),
}
}
}
@ -375,6 +387,7 @@ impl Error for RecoverableError {
Self::XirParseError(e) => Some(e),
Self::XirfParseError(e) => Some(e),
Self::NirParseError(e) => Some(e),
Self::DesugarNirError(e) => Some(e),
}
}
}
@ -394,6 +407,7 @@ impl Diagnostic for RecoverableError {
Self::XirParseError(e) => e.describe(),
Self::XirfParseError(e) => e.describe(),
Self::NirParseError(e) => e.describe(),
Self::DesugarNirError(e) => e.describe(),
}
}
}

View File

@ -1,4 +1,4 @@
// Normalized source IR
// IR that is "near" the source code.
//
// Copyright (C) 2014-2022 Ryan Specialty Group, LLC.
//
@ -49,9 +49,14 @@
//! The entry point for NIR in the lowering pipeline is exported as
//! [`XirfToNir`].
mod desugar;
mod parse;
use std::{convert::Infallible, error::Error, fmt::Display};
use std::{
convert::Infallible,
error::Error,
fmt::{Debug, Display},
};
use crate::{
diagnose::{Annotate, Diagnostic},
@ -62,22 +67,33 @@ use crate::{
xir::{attr::Attr, fmt::TtXmlAttr, QName},
};
pub use desugar::{DesugarNir, DesugarNirError};
pub use parse::{
NirParseState as XirfToNir, NirParseStateError_ as XirfToNirError,
};
/// IR that is "near" the source code,
/// without its syntactic sugar.
///
/// This form contains only primitives that cannot be reasonably represented
/// by other primitives.
/// This is somewhat arbitrary and may change over time,
/// but represents a balance between the level of abstraction of the IR
/// and performance of lowering operations.
///
/// See [`SugaredNir`] for more information about the sugared form.
#[derive(Debug, PartialEq, Eq)]
pub enum Nir {
pub enum PlainNir {
Todo,
}
impl Token for Nir {
impl Token for PlainNir {
fn ir_name() -> &'static str {
"NIR"
"Plain NIR"
}
fn span(&self) -> crate::span::Span {
use Nir::*;
fn span(&self) -> Span {
use PlainNir::*;
match self {
Todo => UNKNOWN_SPAN,
@ -85,11 +101,11 @@ impl Token for Nir {
}
}
impl Object for Nir {}
impl Object for PlainNir {}
impl Display for Nir {
impl Display for PlainNir {
fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
use Nir::*;
use PlainNir::*;
match self {
Todo => write!(f, "TODO"),
@ -97,6 +113,58 @@ impl Display for Nir {
}
}
/// Syntactic sugar atop of [`PlainNir`].
///
/// NIR contains various syntax features that serve as mere quality-of-life
/// conveniences for users
/// ("sugar" to sweeten the experience).
/// These features do not add an expressiveness to the language,
/// and are able to be lowered into other primitives without changing
/// its meaning.
///
/// The process of lowering syntactic sugar into primitives is called
/// "desugaring" and is carried out by the [`DesugarNir`] lowering
/// operation,
/// producing [`PlainNir`].
/// Tokens that do not require desugaring are already represented as
/// [`PlainNir`] in the [`SugaredNir::Plain`] variant.
#[derive(Debug, PartialEq, Eq)]
pub enum SugaredNir {
Plain(PlainNir),
}
impl Token for SugaredNir {
fn ir_name() -> &'static str {
"Sugared NIR"
}
fn span(&self) -> Span {
use SugaredNir::*;
match self {
Plain(nir) => nir.span(),
}
}
}
impl Object for SugaredNir {}
impl Display for SugaredNir {
fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
use SugaredNir::*;
match self {
Plain(nir) => Display::fmt(nir, f),
}
}
}
impl From<PlainNir> for SugaredNir {
fn from(nir: PlainNir) -> Self {
Self::Plain(nir)
}
}
// TODO
type PkgPath = SymbolId;
type PkgTitle = SymbolId;

View File

@ -0,0 +1,108 @@
// Normalized (desugared) IR that is "near" the source code.
//
// Copyright (C) 2014-2022 Ryan Specialty Group, 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/>.
//! Desugaring of [`SugaredNir`] into the normalized [`PlainNir`] form.
//!
//! For more information on the flavors of NIR,
//! see [the parent module](super).
use std::{error::Error, fmt::Display};
use crate::{
diagnose::{AnnotatedSpan, Diagnostic},
parse::{NoContext, ParseState, Transition, TransitionResult},
};
use super::{PlainNir, SugaredNir};
#[derive(Debug, PartialEq, Eq, Default)]
pub enum DesugarNir {
#[default]
Ready,
}
impl Display for DesugarNir {
fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
match self {
Self::Ready => write!(f, "ready for next token"),
}
}
}
impl ParseState for DesugarNir {
type Token = SugaredNir;
type Object = PlainNir;
type Error = DesugarNirError;
fn parse_token(
self,
tok: Self::Token,
_: NoContext,
) -> TransitionResult<Self::Super> {
use SugaredNir::*;
match tok {
Plain(nir) => Transition(self).ok(nir),
}
}
fn is_accepting(&self, _: &Self::Context) -> bool {
self == &Self::Ready
}
}
#[derive(Debug, PartialEq)]
pub enum DesugarNirError {}
impl Display for DesugarNirError {
fn fmt(&self, _f: &mut std::fmt::Formatter) -> std::fmt::Result {
// No errors yet.
Ok(())
}
}
impl Error for DesugarNirError {}
impl Diagnostic for DesugarNirError {
fn describe(&self) -> Vec<AnnotatedSpan> {
// No errors yet.
vec![]
}
}
#[cfg(test)]
mod test {
use super::*;
use crate::parse::Parsed;
type Sut = DesugarNir;
// Given the simplicity,
// this just really ensures that the parser terminates.
#[test]
fn maps_plain_nir() {
let toks = vec![SugaredNir::Plain(PlainNir::Todo)];
use Parsed::*;
assert_eq!(
Ok(vec![Object(PlainNir::Todo)]),
Sut::parse(toks.into_iter()).collect(),
);
}
}

View File

@ -114,7 +114,7 @@ use crate::{
};
ele_parse! {
/// Parser lowering [XIR](crate::xir) into [NIR](crate::nir).
/// Parser lowering [XIR](crate::xir) into [`SugaredNir`].
///
/// TAME's grammar is embedded within XML.
/// The outer XML document has its own grammar,
@ -156,13 +156,13 @@ ele_parse! {
pub enum NirParseState;
type AttrValueError = NirAttrParseError;
type Object = Nir;
type Object = SugaredNir;
// Text and template expressions may appear at any point within the
// program;
// see [`NirParseState`] for more information.
[super] {
[text](_sym, _span) => Nir::Todo,
[text](_sym, _span) => PlainNir::Todo,
TplKw
};
@ -204,7 +204,7 @@ ele_parse! {
// TODO: Is this still needed?
// TODO: PkgName type
_name: (QN_NAME) => PkgPath,
} => Nir::Todo,
} => PlainNir::Todo,
ImportStmt,
PkgBodyStmt,
@ -237,7 +237,7 @@ ele_parse! {
// TODO: Can this go away now?
_name: (QN_NAME?) => Option<PkgPath>,
} => Nir::Todo,
} => PlainNir::Todo,
ImportStmt,
PkgBodyStmt,
@ -251,7 +251,7 @@ ele_parse! {
@ {
_pkg: (QN_PACKAGE) => PkgPath,
_export: (QN_EXPORT?) => Option<BooleanLiteral>,
} => Nir::Todo,
} => PlainNir::Todo,
};
/// A statement that is accepted within the body of a package.
@ -299,7 +299,7 @@ ele_parse! {
_dim: (QN_DIM) => NumLiteral,
_parent: (QN_PARENT?) => Option<AnyIdent>,
_yields: (QN_YIELDS?) => Option<ValueIdent>,
} => Nir::Todo,
} => PlainNir::Todo,
};
/// Define an input parameter accepting data from an external system.
@ -315,7 +315,7 @@ ele_parse! {
_set: (QN_SET?) => Option<Dim>,
_default: (QN_DEFAULT?) => Option<ParamDefault>,
_sym: (QN_SYM?) => Option<TexMathLiteral>,
} => Nir::Todo,
} => PlainNir::Todo,
};
/// Associate static data with an identifier.
@ -340,7 +340,7 @@ ele_parse! {
_sym: (QN_SYM?) => Option<TexMathLiteral>,
// TODO: Misnomer
_set: (QN_SET?) => Option<Dim>,
} => Nir::Todo,
} => PlainNir::Todo,
ConstStmtBody,
};
@ -360,7 +360,7 @@ ele_parse! {
ConstMatrixRow := QN_SET {
@ {
_desc: (QN_DESC) => DescLiteral,
} => Nir::Todo,
} => PlainNir::Todo,
ConstVectorItem,
};
@ -370,7 +370,7 @@ ele_parse! {
@ {
_value: (QN_VALUE) => NumLiteral,
_desc: (QN_DESC) => DescLiteral,
} => Nir::Todo,
} => PlainNir::Todo,
};
/// Define a classification and associate it with an identifier.
@ -386,7 +386,7 @@ ele_parse! {
_yields: (QN_YIELDS?) => Option<ValueIdent>,
_sym: (QN_SYM?) => Option<TexMathLiteral>,
_terminate: (QN_TERMINATE?) => Option<BooleanLiteral>,
} => Nir::Todo,
} => PlainNir::Todo,
LogExpr,
};
@ -413,7 +413,7 @@ ele_parse! {
// TODO: We'll have private-by-default later.
// This is a kludge.
_local: (QN_LOCAL?) => Option<BooleanLiteral>,
} => Nir::Todo,
} => PlainNir::Todo,
CalcExpr,
};
@ -433,7 +433,7 @@ ele_parse! {
_yields: (QN_YIELDS?) => Option<ValueIdent>,
_sym: (QN_SYM?) => Option<TexMathLiteral>,
_gensym: (QN_GENSYM?) => Option<TexMathLiteral>,
} => Nir::Todo,
} => PlainNir::Todo,
CalcExpr,
};
@ -444,7 +444,7 @@ ele_parse! {
_name: (QN_NAME) => TypeIdent,
_desc: (QN_DESC) => DescLiteral,
_sym: (QN_SYM?) => Option<TexMathLiteral>,
} => Nir::Todo,
} => PlainNir::Todo,
InnerTypedefStmt,
};
@ -457,7 +457,7 @@ ele_parse! {
/// This is used for primitives and allows for core types to be exposed
/// to the user.
BaseTypeStmt := QN_BASE_TYPE {
@ {} => Nir::Todo,
@ {} => PlainNir::Todo,
};
/// Define an enumerated type.
@ -467,7 +467,7 @@ ele_parse! {
EnumStmt := QN_ENUM {
@ {
_ty: (QN_TYPE) => TypeIdent,
} => Nir::Todo,
} => PlainNir::Todo,
ItemEnumStmt,
};
@ -479,13 +479,13 @@ ele_parse! {
_name: (QN_NAME) => ConstIdent,
_value: (QN_VALUE) => NumLiteral,
_desc: (QN_DESC) => DescLiteral,
} => Nir::Todo,
} => PlainNir::Todo,
};
/// Define a type whose domain is the union of the domains of multiple
/// other types.
UnionStmt := QN_UNION {
@ {} => Nir::Todo,
@ {} => PlainNir::Todo,
TypedefStmt,
};
@ -500,7 +500,7 @@ ele_parse! {
/// This is being replaced with the `__yield__` template in `core`
/// (this statement predates the template system in TAME).
YieldStmt := QN_YIELD {
@ {} => Nir::Todo,
@ {} => PlainNir::Todo,
CalcExpr,
};
@ -522,7 +522,7 @@ ele_parse! {
SectionStmt := QN_SECTION {
@ {
_title: (QN_TITLE) => Title,
} => Nir::Todo,
} => PlainNir::Todo,
PkgBodyStmt,
};
@ -533,7 +533,7 @@ ele_parse! {
_name: (QN_NAME) => FuncIdent,
_desc: (QN_DESC) => DescLiteral,
_sym: (QN_SYM?) => Option<TexMathLiteral>,
} => Nir::Todo,
} => PlainNir::Todo,
FunctionParamStmt,
CalcExpr,
@ -548,7 +548,7 @@ ele_parse! {
// _TODO: This is a misnomer.
_set: (QN_SET?) => Option<Dim>,
_desc: (QN_DESC) => DescLiteral,
} => Nir::Todo,
} => PlainNir::Todo,
};
@ -574,7 +574,7 @@ ele_parse! {
_value: (QN_VALUE?) => Option<ValueIdent>,
_index: (QN_INDEX?) => Option<ValueIdent>,
_anyof: (QN_ANY_OF?) => Option<TypeIdent>,
} => Nir::Todo,
} => PlainNir::Todo,
CalcPredExpr,
};
@ -584,7 +584,7 @@ ele_parse! {
/// This represents an expression that matches when _any_ of its inner
/// [`LogExpr`] expressions match.
AnyExpr := QN_ANY {
@ {} => Nir::Todo,
@ {} => PlainNir::Todo,
LogExpr,
};
@ -594,7 +594,7 @@ ele_parse! {
/// This represents an expression that matches when _all_ of its inner
/// [`LogExpr`] expressions match.
AllExpr := QN_ALL {
@ {} => Nir::Todo,
@ {} => PlainNir::Todo,
LogExpr,
};
@ -661,7 +661,7 @@ ele_parse! {
_label: (QN_LABEL?) => Option<DescLiteral>,
_sym: (QN_SYM?) => Option<TexMathLiteral>,
_dim: (QN_DIM?) => Option<Dim>,
} => Nir::Todo,
} => PlainNir::Todo,
WhenExpr,
CalcExpr,
@ -683,7 +683,7 @@ ele_parse! {
_dot: (QN_DOT?) => Option<BooleanLiteral>,
_sym: (QN_SYM?) => Option<TexMathLiteral>,
_dim: (QN_DIM?) => Option<Dim>,
} => Nir::Todo,
} => PlainNir::Todo,
WhenExpr,
CalcExpr,
@ -699,7 +699,7 @@ ele_parse! {
QuotientExpr := QN_C_QUOTIENT {
@ {
_label: (QN_LABEL?) => Option<DescLiteral>,
} => Nir::Todo,
} => PlainNir::Todo,
CalcExpr,
};
@ -715,7 +715,7 @@ ele_parse! {
/// (respectively),
/// but TAMER will be relaxing that restriction.
ExptExpr := QN_C_EXPT {
@ {} => Nir::Todo,
@ {} => PlainNir::Todo,
CalcExpr,
};
@ -730,7 +730,7 @@ ele_parse! {
_name: (QN_NAME) => ValueIdent,
_index: (QN_INDEX?) => Option<ValueIdent>,
_label: (QN_LABEL?) => Option<DescLiteral>,
} => Nir::Todo,
} => PlainNir::Todo,
IndexExpr,
WhenExpr,
@ -746,7 +746,7 @@ ele_parse! {
IndexExpr := QN_C_INDEX {
@ {
_label: (QN_LABEL?) => Option<DescLiteral>,
} => Nir::Todo,
} => PlainNir::Todo,
CalcExpr,
};
@ -765,7 +765,7 @@ ele_parse! {
_desc: (QN_DESC?) => Option<DescLiteral>,
// _TODO: deprecate?
_ty: (QN_TYPE?) => Option<TypeIdent>,
} => Nir::Todo,
} => PlainNir::Todo,
WhenExpr,
};
@ -774,7 +774,7 @@ ele_parse! {
CeilExpr := QN_C_CEIL {
@ {
_label: (QN_LABEL?) => Option<DescLiteral>,
} => Nir::Todo,
} => PlainNir::Todo,
CalcExpr,
};
@ -782,7 +782,7 @@ ele_parse! {
FloorExpr := QN_C_FLOOR {
@ {
_label: (QN_LABEL?) => Option<DescLiteral>,
} => Nir::Todo,
} => PlainNir::Todo,
CalcExpr,
};
@ -802,7 +802,7 @@ ele_parse! {
CasesExpr := QN_C_CASES {
@ {
_label: (QN_LABEL?) => Option<DescLiteral>,
} => Nir::Todo,
} => PlainNir::Todo,
CaseExpr,
OtherwiseExpr,
@ -822,7 +822,7 @@ ele_parse! {
CaseExpr := QN_C_CASE {
@ {
_label: (QN_LABEL?) => Option<DescLiteral>,
} => Nir::Todo,
} => PlainNir::Todo,
WhenExpr,
CalcExpr,
@ -845,7 +845,7 @@ ele_parse! {
OtherwiseExpr := QN_C_OTHERWISE {
@ {
_label: (QN_LABEL?) => Option<DescLiteral>,
} => Nir::Todo,
} => PlainNir::Todo,
CalcExpr,
};
@ -856,7 +856,7 @@ ele_parse! {
/// which are vectors of vectors.
/// It is not defined for scalars.
LengthOfExpr := QN_C_LENGTH_OF {
@ {} => Nir::Todo,
@ {} => PlainNir::Todo,
CalcExpr,
};
@ -870,7 +870,7 @@ ele_parse! {
/// The result of the let expression is the result of the inner
/// [`CalcExpr`].
LetExpr := QN_C_LET {
@ {} => Nir::Todo,
@ {} => PlainNir::Todo,
LetValues,
CalcExpr,
};
@ -880,7 +880,7 @@ ele_parse! {
///
/// See [`LetExpr`] for more information.
LetValues := QN_C_VALUES {
@ {} => Nir::Todo,
@ {} => PlainNir::Todo,
LetValue,
};
@ -897,7 +897,7 @@ ele_parse! {
// Misnomer
_set: (QN_SET?) => Option<Dim>,
_desc: (QN_DESC?) => Option<DescLiteral>,
} => Nir::Todo,
} => PlainNir::Todo,
CalcExpr,
};
@ -907,7 +907,7 @@ ele_parse! {
VectorExpr := QN_C_VECTOR {
@ {
_label: (QN_LABEL?) => Option<DescLiteral>,
} => Nir::Todo,
} => PlainNir::Todo,
CalcExpr,
};
@ -924,9 +924,9 @@ ele_parse! {
/// `<`[`c:arg`](QN_C_ARG)` name="α"><`[`c:value-of`](QN_C_VALUE_OF)
/// `name="x" /></c:arg>`.
ApplyExpr := QN_C_APPLY {
@ {} => Nir::Todo,
@ {} => PlainNir::Todo,
[attr](_attr) => Nir::Todo,
[attr](_attr) => PlainNir::Todo,
ApplyArg,
};
@ -939,7 +939,7 @@ ele_parse! {
ApplyArg := QN_C_ARG {
@ {
_name: (QN_NAME) => ParamIdent,
} => Nir::Todo,
} => PlainNir::Todo,
CalcExpr,
};
@ -954,9 +954,9 @@ ele_parse! {
/// allowing for concise recursion in terms of only what has changed
/// in that recursive step.
RecurseExpr := QN_C_RECURSE {
@ {} => Nir::Todo,
@ {} => PlainNir::Todo,
[attr](_attr) => Nir::Todo,
[attr](_attr) => PlainNir::Todo,
ApplyArg,
};
@ -967,7 +967,7 @@ ele_parse! {
/// This terminology originates from Lisp.
/// It is equivalent to an `unshift` operation.
ConsExpr := QN_C_CONS {
@ {} => Nir::Todo,
@ {} => PlainNir::Todo,
CalcExpr,
};
@ -977,7 +977,7 @@ ele_parse! {
CarExpr := QN_C_CAR {
@ {
_label: (QN_LABEL?) => Option<DescLiteral>,
} => Nir::Todo,
} => PlainNir::Todo,
CalcExpr,
};
@ -989,7 +989,7 @@ ele_parse! {
CdrExpr := QN_C_CDR {
@ {
_label: (QN_LABEL?) => Option<DescLiteral>,
} => Nir::Todo,
} => PlainNir::Todo,
CalcExpr,
};
@ -1011,7 +1011,7 @@ ele_parse! {
_name: (QN_NAME) => ValueIdent,
_index: (QN_INDEX?) => Option<ValueIdent>,
_value: (QN_VALUE?) => Option<ValueIdent>,
} => Nir::Todo,
} => PlainNir::Todo,
CalcPredExpr,
};
@ -1031,37 +1031,37 @@ ele_parse! {
/// Equality predicate (=).
EqCalcPredExpr := QN_C_EQ {
@ {} => Nir::Todo,
@ {} => PlainNir::Todo,
CalcExpr,
};
/// Non-equality predicate (≠).
NeCalcPredExpr := QN_C_NE {
@ {} => Nir::Todo,
@ {} => PlainNir::Todo,
CalcExpr,
};
/// Less-than predicate (<).
LtCalcPredExpr := QN_C_LT {
@ {} => Nir::Todo,
@ {} => PlainNir::Todo,
CalcExpr,
};
/// Greater-than predicate (>).
GtCalcPredExpr := QN_C_GT {
@ {} => Nir::Todo,
@ {} => PlainNir::Todo,
CalcExpr,
};
/// Less-than or equality predicate (≤).
LteCalcPredExpr := QN_C_LTE {
@ {} => Nir::Todo,
@ {} => PlainNir::Todo,
CalcExpr,
};
/// Greater-than or equality predicate (≥).
GteCalcPredExpr := QN_C_GTE {
@ {} => Nir::Todo,
@ {} => PlainNir::Todo,
CalcExpr,
};
@ -1088,7 +1088,7 @@ ele_parse! {
_xmlns: (QN_XMLNS) => Literal<URI_LV_PROGRAM_MAP>,
_xmlnslv: (QN_XMLNS_LV) => Literal<URI_LV_RATER>,
_src: (QN_SRC) => PkgPath,
} => Nir::Todo,
} => PlainNir::Todo,
MapPkgImportStmt,
MapImportStmt,
@ -1106,7 +1106,7 @@ ele_parse! {
@ {
_xmlns: (QN_XMLNS) => Literal<URI_LV_PROGRAM_MAP>,
_xmlnslv: (QN_XMLNS_LV) => Literal<URI_LV_RATER>,
} => Nir::Todo,
} => PlainNir::Todo,
MapPkgImportStmt,
MapImportStmt,
@ -1122,7 +1122,7 @@ ele_parse! {
@ {
_package: (QN_PACKAGE) => PkgPath,
_export: (QN_EXPORT?) => Option<BooleanLiteral>,
} => Nir::Todo,
} => PlainNir::Todo,
};
/// Import a map package.
@ -1133,7 +1133,7 @@ ele_parse! {
MapImportStmt := QN_IMPORT {
@ {
_path: (QN_PATH) => PkgPath,
} => Nir::Todo,
} => PlainNir::Todo,
};
/// Define the value of a key in the destination.
@ -1149,7 +1149,7 @@ ele_parse! {
_scalar: (QN_SCALAR?) => Option<BooleanLiteral>,
_override: (QN_OVERRIDE?) => Option<BooleanLiteral>,
_novalidate: (QN_NOVALIDATE?) => Option<BooleanLiteral>,
} => Nir::Todo,
} => PlainNir::Todo,
};
/// Map a value into a key of the destination.
@ -1168,7 +1168,7 @@ ele_parse! {
_scalar: (QN_SCALAR?) => Option<BooleanLiteral>,
_override: (QN_OVERRIDE?) => Option<BooleanLiteral>,
_novalidate: (QN_NOVALIDATE?) => Option<BooleanLiteral>,
} => Nir::Todo,
} => PlainNir::Todo,
MapStmtBody,
};
@ -1183,7 +1183,7 @@ ele_parse! {
_default: (QN_DEFAULT?) => Option<NumLiteral>,
_scalar: (QN_SCALAR?) => Option<BooleanLiteral>,
_novalidate: (QN_NOVALIDATE?) => Option<BooleanLiteral>,
} => Nir::Todo,
} => PlainNir::Todo,
MapTranslateStmt,
};
@ -1193,7 +1193,7 @@ ele_parse! {
@ {
_key: (QN_KEY) => StringLiteral,
_value: (QN_VALUE) => NumLiteral,
} => Nir::Todo,
} => PlainNir::Todo,
};
/// Yield a vector of values where each item corresponds to the
@ -1203,7 +1203,7 @@ ele_parse! {
/// since the result is a vector,
/// not a set.
MapSetStmt := QN_SET {
@ {} => Nir::Todo,
@ {} => PlainNir::Todo,
MapSetBody,
};
@ -1215,7 +1215,7 @@ ele_parse! {
MapConstStmt := QN_CONST {
@ {
_value: (QN_VALUE) => StringLiteral,
} => Nir::Todo,
} => PlainNir::Todo,
};
/// Transform a value using some function.
@ -1227,7 +1227,7 @@ ele_parse! {
MapTransformStmt := QN_TRANSFORM {
@ {
_method: (QN_METHOD) => MapTransformLiteral,
} => Nir::Todo,
} => PlainNir::Todo,
MapStmtBody,
};
@ -1259,7 +1259,7 @@ ele_parse! {
_name: (QN_NAME) => PkgPath,
_pkg: (QN_PACKAGE) => PkgPath,
} => Nir::Todo,
} => PlainNir::Todo,
ExpandFunctionStmt,
DisplayStmt,
@ -1276,7 +1276,7 @@ ele_parse! {
ExpandFunctionStmt := QN_EXPAND_FUNCTION {
@ {
_name: (QN_NAME) => FuncIdent,
} => Nir::Todo,
} => PlainNir::Todo,
};
/// Render a simplified, human-readable display of the calculation,
@ -1284,7 +1284,7 @@ ele_parse! {
DisplayStmt := QN_DISPLAY {
@ {
_name: (QN_NAME) => ValueIdent,
} => Nir::Todo,
} => PlainNir::Todo,
};
@ -1377,7 +1377,7 @@ ele_parse! {
@ {
_name: (QN_NAME) => TplName,
_desc: (QN_DESC) => DescLiteral,
} => Nir::Todo,
} => PlainNir::Todo,
TplHeading,
AnyStmtOrExpr,
@ -1402,7 +1402,7 @@ ele_parse! {
@ {
_name: (QN_NAME) => TplParamIdent,
_desc: (QN_DESC) => DescLiteral,
} => Nir::Todo,
} => PlainNir::Todo,
TplParamDefault,
};
@ -1435,7 +1435,7 @@ ele_parse! {
TplText := QN_TEXT {
@ {
_unique: (QN_UNIQUE?) => Option<BooleanLiteral>,
} => Nir::Todo,
} => PlainNir::Todo,
};
/// Default the param to the value of another template param,
@ -1458,7 +1458,7 @@ ele_parse! {
_rmunderscore: (QN_RMUNDERSCORE?) => Option<BooleanLiteral>,
_identifier: (QN_IDENTIFIER?) => Option<BooleanLiteral>,
_snake: (QN_SNAKE?) => Option<BooleanLiteral>,
} => Nir::Todo,
} => PlainNir::Todo,
};
/// Inherit a default value from a metavalue.
@ -1473,7 +1473,7 @@ ele_parse! {
TplParamInherit := QN_PARAM_INHERIT {
@ {
_meta: (QN_META) => TplMetaIdent,
} => Nir::Todo,
} => PlainNir::Todo,
};
/// Sum a numeric value with a numeric template parameter.
@ -1484,7 +1484,7 @@ ele_parse! {
@ {
_name: (QN_NAME) => TplParamIdent,
_value: (QN_VALUE) => NumLiteral,
} => Nir::Todo,
} => PlainNir::Todo,
};
/// Look up the [`@yields`](QN_YIELDS) of a [`ClassifyStmt`].
@ -1505,7 +1505,7 @@ ele_parse! {
TplParamClassToYields := QN_PARAM_CLASS_TO_YIELDS {
@ {
_name: (QN_NAME) => ClassIdent,
} => Nir::Todo,
} => PlainNir::Todo,
};
/// Given a numeric literal,
@ -1550,7 +1550,7 @@ ele_parse! {
@ {
_name: (QN_NAME) => TypeIdent,
_value: (QN_VALUE) => NumLiteral,
} => Nir::Todo,
} => PlainNir::Todo,
};
/// Look up an attribute from the symbol table for a given identifier.
@ -1560,7 +1560,7 @@ ele_parse! {
_value: (QN_VALUE) => SymbolTableKey,
_prefix: (QN_PREFIX?) => Option<AnyIdent>,
_ignore_missing: (QN_IGNORE_MISSING?) => Option<BooleanLiteral>,
} => Nir::Todo,
} => PlainNir::Todo,
};
/// Keywords that trigger template expansion.
@ -1603,7 +1603,7 @@ ele_parse! {
DynNode := QN_DYN_NODE {
@ {
_name: (QN_NAME) => DynNodeLiteral,
} => Nir::Todo,
} => PlainNir::Todo,
// But we can at least restrict it for now by ensuring that it's
// used only to contain expressions.
@ -1619,7 +1619,7 @@ ele_parse! {
/// See also [`WarningKw`] to provide a message to the user as
/// compiler output without failing compilation.
ErrorKw := QN_ERROR {
@ {} => Nir::Todo,
@ {} => PlainNir::Todo,
// In addition to text that is globally permitted.
TplParamValue,
@ -1635,7 +1635,7 @@ ele_parse! {
/// you should consider using [`ErrorKw`] whenever possible to
/// ensure that problems are immediately resolved.
WarningKw := QN_WARNING {
@ {} => Nir::Todo,
@ {} => PlainNir::Todo,
// In addition to text that is globally permitted.
TplParamValue,
@ -1657,7 +1657,7 @@ ele_parse! {
/// but this is still needed to support dynamic template application
/// (templates whose names are derived from other template inputs).
ApplyTemplate := QN_APPLY_TEMPLATE {
@ {} => Nir::Todo,
@ {} => PlainNir::Todo,
// TODO
};
@ -1670,12 +1670,12 @@ ele_parse! {
/// template argument.
/// See [`ApplyTemplate`] for more information.
TplApplyShort := NS_T {
@ {} => Nir::Todo,
@ {} => PlainNir::Todo,
// Streaming attribute parsing;
// this takes precedence over any attribute parsing above
// (which is used only for emitting the opening object).
[attr](_attr) => Nir::Todo,
[attr](_attr) => PlainNir::Todo,
// Template bodies depend on context,
// so we have to just accept everything and defer to a future
@ -1695,7 +1695,7 @@ ele_parse! {
/// and have the unique ability to perform symbol table
/// introspection using [`InlineTemplateSymSet`].
InlineTemplate := QN_INLINE_TEMPLATE {
@ {} => Nir::Todo,
@ {} => PlainNir::Todo,
InlineTemplateForEach,
AnyStmtOrExpr,
@ -1710,7 +1710,7 @@ ele_parse! {
/// each with the respective [`InlineTemplateArgs`] set as its
/// arguments.
InlineTemplateForEach := QN_FOR_EACH {
@ {} => Nir::Todo,
@ {} => PlainNir::Todo,
InlineTemplateArgs,
};
@ -1727,10 +1727,10 @@ ele_parse! {
///
/// See also parent [`InlineTemplateForEach`].
InlineTemplateArgSet := QN_SET {
@ {} => Nir::Todo,
@ {} => PlainNir::Todo,
// Streaming attribute parsing.
[attr](_attr) => Nir::Todo,
[attr](_attr) => PlainNir::Todo,
// TODO: REMOVE ME
// (bug in `ele_parse!` requiring at least one NT in this
@ -1755,7 +1755,7 @@ ele_parse! {
_name_prefix: (QN_NAME_PREFIX?) => Option<StringLiteral>,
_type: (QN_TYPE?) => Option<IdentType>,
// TODO: Look at XSL sources for others
} => Nir::Todo,
} => PlainNir::Todo,
};
/// Perform template expansion on each successive child node in order,
@ -1785,7 +1785,7 @@ ele_parse! {
/// The concept originates from TeX's `\expandafter`, `\edef`, and
/// related macros.
ExpandSequence := QN_EXPAND_SEQUENCE {
@ {} => Nir::Todo,
@ {} => PlainNir::Todo,
AnyStmtOrExpr,
};
@ -1795,7 +1795,7 @@ ele_parse! {
/// implementation of [`ExpandSequence`];
/// see that NT for more information.
ExpandGroup := QN_EXPAND_GROUP {
@ {} => Nir::Todo,
@ {} => PlainNir::Todo,
AnyStmtOrExpr,
};
@ -1805,7 +1805,7 @@ ele_parse! {
/// template system from expanding its body beyond a certain point,
/// which is sometimes needed for template-producing templates.
ExpandBarrier := QN_EXPAND_BARRIER {
@ {} => Nir::Todo,
@ {} => PlainNir::Todo,
AnyStmtOrExpr,
};
@ -1818,7 +1818,7 @@ ele_parse! {
TplParamCopy := QN_PARAM_COPY {
@ {
_name: (QN_NAME) => TplParamIdent,
} => Nir::Todo,
} => PlainNir::Todo,
};
/// Define a metavalue at this point in the expansion environment.
@ -1829,7 +1829,7 @@ ele_parse! {
@ {
_name: (QN_NAME) => TplParamIdent,
_value: (QN_VALUE) => StringLiteral,
} => Nir::Todo,
} => PlainNir::Todo,
};
/// Conditionally expand the body if the provided predicate matches.
@ -1843,7 +1843,7 @@ ele_parse! {
_lte: (QN_LTE?) => Option<NumLiteral>,
_prefix: (QN_PREFIX?) => Option<StringLiteral>,
_suffix: (QN_SUFFIX?) => Option<StringLiteral>,
} => Nir::Todo,
} => PlainNir::Todo,
AnyStmtOrExpr,
};
@ -1863,7 +1863,7 @@ ele_parse! {
_lte: (QN_LTE?) => Option<NumLiteral>,
_prefix: (QN_PREFIX?) => Option<StringLiteral>,
_suffix: (QN_SUFFIX?) => Option<StringLiteral>,
} => Nir::Todo,
} => PlainNir::Todo,
AnyStmtOrExpr,
};

View File

@ -582,7 +582,7 @@ macro_rules! ele_parse {
impl std::fmt::Display for $nt {
fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
match self {
Self(st) => st.fmt(f),
Self(st) => std::fmt::Display::fmt(st, f),
}
}
}
@ -636,7 +636,7 @@ macro_rules! ele_parse {
$(
// Used only to match on `[attr]`.
let [<_ $attr_stream_binding>] = ();
return transition.ok($attrmap);
return transition.ok(<$objty>::from($attrmap));
)?
// If the `[attr]` special form was _not_
@ -693,7 +693,10 @@ macro_rules! ele_parse {
(
st @ Attrs(..),
XirfToken::Attr($attr_stream_binding),
) => Transition(Self(st)).ok($attr_stream_map),
) => {
Transition(Self(st))
.ok(<$objty>::from($attr_stream_map))
},
// Override the aggregate attribute parser
// delegation by forcing the below match to become
@ -748,7 +751,7 @@ macro_rules! ele_parse {
let $open_span = sa.element_span();
)?
$attrmap
<$objty>::from($attrmap)
},
};
@ -1013,7 +1016,7 @@ macro_rules! ele_parse {
impl std::fmt::Display for $nt {
fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
match self {
Self(st) => st.fmt(f),
Self(st) => std::fmt::Display::fmt(st, f),
}
}
}
@ -1321,7 +1324,7 @@ macro_rules! ele_parse {
_,
)
) if st.can_preempt_node() => {
Transition(st).ok($text_map)
Transition(st).ok(<$objty>::from($text_map))
},
)?