tamer: asg::graph::xmli: Extract xmli generation from parse_token

This begins to develop a pattern for doing these transformations.  I had
tried a number of things using iterators, but I wasn't satisfied with either
how they were turning out; had to fight too much with the type system; or
had to resort to heap allocations.  Sticking with an explicit
`push`/`push_all` for now works just fine.

Almost done cleaning up `AsgTreeToXirf::parse_token`, and then I can move on
to introducing more objects.

DEV-13708
main
Mike Gerwitz 2023-02-24 13:17:16 -05:00
parent 9eb1d226b2
commit e3e50c38c7
2 changed files with 73 additions and 23 deletions

View File

@ -30,7 +30,8 @@
//! or observing template expansions.
use super::object::{
DynObjectRel, Expr, Object, ObjectIndex, ObjectRelTy, Pkg,
DynObjectRel, Expr, Object, ObjectIndex, ObjectRelTy, OiPairObjectInner,
Pkg,
};
use crate::{
asg::{
@ -39,7 +40,7 @@ use crate::{
},
diagnose::Annotate,
diagnostic_panic, diagnostic_unreachable,
parse::{prelude::*, util::SPair},
parse::{prelude::*, util::SPair, Transitionable},
span::{Span, UNKNOWN_SPAN},
sym::{
st::{URI_LV_CALC, URI_LV_RATER, URI_LV_TPL},
@ -99,36 +100,24 @@ impl<'a> ParseState for AsgTreeToXirf<'a> {
// resolution in branches that do not utilize the source.
let paired_rel = dyn_rel.resolve_oi_pairs(asg);
match paired_rel.target() {
Object::Pkg((pkg, _)) => {
let span = pkg.span();
toks.push_all([
ns(QN_XMLNS_T, URI_LV_TPL, span),
ns(QN_XMLNS_C, URI_LV_CALC, span),
ns(QN_XMLNS, URI_LV_RATER, span),
]);
Transition(self).ok(package(pkg, depth))
}
let xirf_tok = match paired_rel.target() {
Object::Pkg((pkg, _)) => emit_package(toks, pkg, depth),
// Identifiers will be considered in context;
// pass over it for now.
Object::Ident(..) => Transition(self).incomplete(),
Object::Ident(..) => None,
Object::Expr((expr, _)) => match paired_rel.source() {
Object::Ident((ident, _)) => {
toks.push(yields(ident.name(), expr.span()));
Transition(self).ok(stmt(expr, depth))
}
_ => Transition(self).ok(expr_ele(expr, depth)),
},
Object::Expr((expr, _)) => {
emit_expr(toks, expr, paired_rel.source(), depth)
}
Object::Root(..) => diagnostic_unreachable!(
vec![tok_span.error("unexpected Root")],
"tree walk is not expected to emit Root",
),
}
};
xirf_tok.transition(self)
}
fn is_accepting(&self, TreeContext(toks, _): &Self::Context) -> bool {
@ -157,6 +146,55 @@ impl<'a> ParseState for AsgTreeToXirf<'a> {
}
}
/// Emit tokens representing the root package element.
fn emit_package(
toks: &mut TokenStack,
pkg: &Pkg,
depth: Depth,
) -> Option<Xirf> {
let span = pkg.span();
toks.push_all([
ns(QN_XMLNS_T, URI_LV_TPL, span),
ns(QN_XMLNS_C, URI_LV_CALC, span),
ns(QN_XMLNS, URI_LV_RATER, span),
]);
Some(package(pkg, depth))
}
/// Emit an expression as a legacy TAME statement or expression.
///
/// Identified expressions must be represented using statements in
/// legacy TAME,
/// such as `<rate>`.
/// Anonymous expressions are nested within statements.
///
/// This system will emit statements and expressions that are compatible
/// with the information on the [ASG](crate::asg) and recognized by the
/// downstream XSLT-based compiler.
/// There is no guarantee,
/// however,
/// that what is emitted is exactly representative of what the user
/// originally entered.
///
/// Please ensure that the system matches your expectations using the system
/// tests in `:tamer/tests/xmli`.
fn emit_expr(
toks: &mut TokenStack,
expr: &Expr,
src: &Object<OiPairObjectInner>,
depth: Depth,
) -> Option<Xirf> {
match src {
Object::Ident((ident, _)) => {
toks.push(yields(ident.name(), expr.span()));
Some(stmt(expr, depth))
}
_ => Some(expr_ele(expr, depth)),
}
}
fn package(pkg: &Pkg, depth: Depth) -> Xirf {
Xirf::open(QN_PACKAGE, OpenSpan::without_name_span(pkg.span()), depth)
}

View File

@ -681,6 +681,18 @@ where
}
}
impl<S> Transitionable<S> for Option<S::Object>
where
S: ParseState,
{
fn transition(self, to: S) -> TransitionResult<S::Super> {
match self {
Some(obj) => Transition(to).ok(obj),
None => Transition(to).incomplete(),
}
}
}
impl<S: ParseState> Transitionable<S> for ParseStatus<S> {
fn transition(self, to: S) -> TransitionResult<S::Super> {
Transition(to).ok(self.into_super())