tamer: NIR->xmli interpolation and template param
The fixpoint tests for `meta-interp` are finally working. I could have broken this up more, but I'm exhausted with this process, so, you get what you get. NIR will now recognize basic `<text>` and `<param-value>` nodes (note the caveat for `<text>` in the comment, for now), and I finally include abstract binding in the lowering pipeline. `xmli` output is also now able to cope with metavariables with a single lexical association, and continues to become more of a mess. DEV-13163main
parent
85b08eb45e
commit
0f93f3a498
|
@ -167,7 +167,7 @@ impl ParseState for AirExprAggregate {
|
||||||
}
|
}
|
||||||
|
|
||||||
(BuildingExpr(es, oi), AirDoc(DocIndepClause(clause))) => {
|
(BuildingExpr(es, oi), AirDoc(DocIndepClause(clause))) => {
|
||||||
oi.desc_short(ctx.asg_mut(), clause);
|
oi.add_desc_short(ctx.asg_mut(), clause);
|
||||||
Transition(BuildingExpr(es, oi)).incomplete()
|
Transition(BuildingExpr(es, oi)).incomplete()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -102,7 +102,7 @@ impl ParseState for AirMetaAggregate {
|
||||||
}
|
}
|
||||||
|
|
||||||
(TplMeta(oi_meta), AirDoc(DocIndepClause(clause))) => {
|
(TplMeta(oi_meta), AirDoc(DocIndepClause(clause))) => {
|
||||||
oi_meta.desc_short(ctx.asg_mut(), clause);
|
oi_meta.add_desc_short(ctx.asg_mut(), clause);
|
||||||
Transition(TplMeta(oi_meta)).incomplete()
|
Transition(TplMeta(oi_meta)).incomplete()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -205,7 +205,7 @@ impl ParseState for AirTplAggregate {
|
||||||
}
|
}
|
||||||
|
|
||||||
(Toplevel(tpl), AirDoc(DocIndepClause(clause))) => {
|
(Toplevel(tpl), AirDoc(DocIndepClause(clause))) => {
|
||||||
tpl.oi().desc_short(ctx.asg_mut(), clause);
|
tpl.oi().add_desc_short(ctx.asg_mut(), clause);
|
||||||
Transition(Toplevel(tpl)).incomplete()
|
Transition(Toplevel(tpl)).incomplete()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -837,13 +837,27 @@ impl<O: ObjectKind> ObjectIndex<O> {
|
||||||
/// simple sentence or as part of a compound sentence.
|
/// simple sentence or as part of a compound sentence.
|
||||||
/// There should only be one such clause for any given object,
|
/// There should only be one such clause for any given object,
|
||||||
/// but that is not enforced here.
|
/// but that is not enforced here.
|
||||||
pub fn desc_short(&self, asg: &mut Asg, clause: SPair) -> Self
|
pub fn add_desc_short(&self, asg: &mut Asg, clause: SPair) -> Self
|
||||||
where
|
where
|
||||||
O: ObjectRelTo<Doc>,
|
O: ObjectRelTo<Doc>,
|
||||||
{
|
{
|
||||||
let oi_doc = asg.create(Doc::new_indep_clause(clause));
|
let oi_doc = asg.create(Doc::new_indep_clause(clause));
|
||||||
self.add_edge_to(asg, oi_doc, None)
|
self.add_edge_to(asg, oi_doc, None)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Retrieve a description of this expression using a short independent
|
||||||
|
/// clause,
|
||||||
|
/// if one has been set.
|
||||||
|
///
|
||||||
|
/// See [`Self::add_desc_short`] to add such a description.
|
||||||
|
pub fn desc_short(&self, asg: &Asg) -> Option<SPair>
|
||||||
|
where
|
||||||
|
O: ObjectRelTo<Doc>,
|
||||||
|
{
|
||||||
|
self.edges_filtered::<Doc>(asg)
|
||||||
|
.map(ObjectIndex::cresolve(asg))
|
||||||
|
.find_map(Doc::indep_clause)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl ObjectIndex<Object> {
|
impl ObjectIndex<Object> {
|
||||||
|
|
|
@ -476,6 +476,28 @@ impl<'a> TreeContext<'a> {
|
||||||
if let Some(pname) =
|
if let Some(pname) =
|
||||||
oi_meta.ident(self.asg).map(|oi| oi.name_or_meta(self.asg))
|
oi_meta.ident(self.asg).map(|oi| oi.name_or_meta(self.asg))
|
||||||
{
|
{
|
||||||
|
// This may have a body that is a single lexeme,
|
||||||
|
// representing a default value for the parameter.
|
||||||
|
if let Some(lexeme) = meta.lexeme() {
|
||||||
|
let open = self.emit_text_node(
|
||||||
|
lexeme,
|
||||||
|
lexeme.span(),
|
||||||
|
depth.child_depth(),
|
||||||
|
);
|
||||||
|
self.push(open);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Because of the above,
|
||||||
|
// we must check here if we have a description rather than
|
||||||
|
// waiting to encounter it during the traversal;
|
||||||
|
// otherwise we'd be outputting child nodes before a
|
||||||
|
// description attribute,
|
||||||
|
// which would result in invalid XML that is rejected by
|
||||||
|
// the XIR writer.
|
||||||
|
if let Some(desc_short) = oi_meta.desc_short(self.asg) {
|
||||||
|
self.push(attr_desc(desc_short));
|
||||||
|
}
|
||||||
|
|
||||||
self.push(attr_name(pname));
|
self.push(attr_name(pname));
|
||||||
|
|
||||||
Some(Xirf::open(
|
Some(Xirf::open(
|
||||||
|
@ -484,22 +506,7 @@ impl<'a> TreeContext<'a> {
|
||||||
depth,
|
depth,
|
||||||
))
|
))
|
||||||
} else if let Some(lexeme) = meta.lexeme() {
|
} else if let Some(lexeme) = meta.lexeme() {
|
||||||
self.push(Xirf::close(
|
Some(self.emit_text_node(lexeme, meta.span(), depth))
|
||||||
Some(QN_TEXT),
|
|
||||||
CloseSpan::without_name_span(meta.span()),
|
|
||||||
depth,
|
|
||||||
));
|
|
||||||
|
|
||||||
self.push(Xirf::text(
|
|
||||||
Text(lexeme.symbol(), lexeme.span()),
|
|
||||||
depth.child_depth(),
|
|
||||||
));
|
|
||||||
|
|
||||||
Some(Xirf::open(
|
|
||||||
QN_TEXT,
|
|
||||||
OpenSpan::without_name_span(meta.span()),
|
|
||||||
depth,
|
|
||||||
))
|
|
||||||
} else {
|
} else {
|
||||||
// TODO: Rewrite the above to be an exhaustive match, perhaps,
|
// TODO: Rewrite the above to be an exhaustive match, perhaps,
|
||||||
// so we know what we'll error on.
|
// so we know what we'll error on.
|
||||||
|
@ -510,6 +517,27 @@ impl<'a> TreeContext<'a> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Emit a `<text>` node containing a lexeme.
|
||||||
|
fn emit_text_node(
|
||||||
|
&mut self,
|
||||||
|
lexeme: SPair,
|
||||||
|
node_span: Span,
|
||||||
|
depth: Depth,
|
||||||
|
) -> Xirf {
|
||||||
|
self.push(Xirf::close(
|
||||||
|
Some(QN_TEXT),
|
||||||
|
CloseSpan::without_name_span(node_span),
|
||||||
|
depth,
|
||||||
|
));
|
||||||
|
|
||||||
|
self.push(Xirf::text(
|
||||||
|
Text(lexeme.symbol(), lexeme.span()),
|
||||||
|
depth.child_depth(),
|
||||||
|
));
|
||||||
|
|
||||||
|
Xirf::open(QN_TEXT, OpenSpan::without_name_span(node_span), depth)
|
||||||
|
}
|
||||||
|
|
||||||
/// Emit a `<param-value>` node assumed to be within a template param
|
/// Emit a `<param-value>` node assumed to be within a template param
|
||||||
/// body.
|
/// body.
|
||||||
fn emit_tpl_param_value(
|
fn emit_tpl_param_value(
|
||||||
|
@ -586,10 +614,11 @@ impl<'a> TreeContext<'a> {
|
||||||
}
|
}
|
||||||
|
|
||||||
// template/param/@desc
|
// template/param/@desc
|
||||||
(Object::Meta(_), Doc::IndepClause(desc))
|
(Object::Meta(_), Doc::IndepClause(_desc))
|
||||||
if self.tpl_apply.is_none() =>
|
if self.tpl_apply.is_none() =>
|
||||||
{
|
{
|
||||||
Some(attr_desc(*desc))
|
// This is already covered in `emit_tpl_param`
|
||||||
|
None
|
||||||
}
|
}
|
||||||
|
|
||||||
(_, Doc::Text(_text)) => {
|
(_, Doc::Text(_text)) => {
|
||||||
|
|
|
@ -1458,10 +1458,16 @@ ele_parse! {
|
||||||
/// providing constant values.
|
/// providing constant values.
|
||||||
/// The result will be as if the user typed the text themselves in the
|
/// The result will be as if the user typed the text themselves in the
|
||||||
/// associated template application argument.
|
/// associated template application argument.
|
||||||
|
///
|
||||||
|
/// TODO: This just produces a no-op right now and lets the text hander
|
||||||
|
/// produce text for the inner character data.
|
||||||
|
/// This is consequently ambiguous with omitting this node entirely;
|
||||||
|
/// this might be okay,
|
||||||
|
/// but this needs explicit design.
|
||||||
TplText := QN_TEXT(_, ospan) {
|
TplText := QN_TEXT(_, ospan) {
|
||||||
@ {
|
@ {
|
||||||
QN_UNIQUE => TodoAttr,
|
QN_UNIQUE => TodoAttr,
|
||||||
} => Todo(ospan.into()),
|
} => Noop(ospan.into()),
|
||||||
};
|
};
|
||||||
|
|
||||||
/// Default the param to the value of another template param,
|
/// Default the param to the value of another template param,
|
||||||
|
@ -1475,7 +1481,7 @@ ele_parse! {
|
||||||
/// cumbersome and slow
|
/// cumbersome and slow
|
||||||
TplParamValue := QN_PARAM_VALUE(_, ospan) {
|
TplParamValue := QN_PARAM_VALUE(_, ospan) {
|
||||||
@ {
|
@ {
|
||||||
QN_NAME => TodoAttr,
|
QN_NAME => Ref,
|
||||||
QN_DASH => TodoAttr,
|
QN_DASH => TodoAttr,
|
||||||
QN_UPPER => TodoAttr,
|
QN_UPPER => TodoAttr,
|
||||||
QN_LOWER => TodoAttr,
|
QN_LOWER => TodoAttr,
|
||||||
|
@ -1484,7 +1490,7 @@ ele_parse! {
|
||||||
QN_RMUNDERSCORE => TodoAttr,
|
QN_RMUNDERSCORE => TodoAttr,
|
||||||
QN_IDENTIFIER => TodoAttr,
|
QN_IDENTIFIER => TodoAttr,
|
||||||
QN_SNAKE => TodoAttr,
|
QN_SNAKE => TodoAttr,
|
||||||
} => Todo(ospan.into()),
|
} => Noop(ospan.into()),
|
||||||
};
|
};
|
||||||
|
|
||||||
/// Inherit a default value from a metavalue.
|
/// Inherit a default value from a metavalue.
|
||||||
|
|
|
@ -110,7 +110,10 @@
|
||||||
use crate::{
|
use crate::{
|
||||||
asg::{air::AirAggregate, AsgTreeToXirf},
|
asg::{air::AirAggregate, AsgTreeToXirf},
|
||||||
diagnose::Diagnostic,
|
diagnose::Diagnostic,
|
||||||
nir::{InterpolateNir, NirToAir, TplShortDesugar, XirfToNir},
|
nir::{
|
||||||
|
AbstractBindTranslate, InterpolateNir, NirToAir, TplShortDesugar,
|
||||||
|
XirfToNir,
|
||||||
|
},
|
||||||
obj::xmlo::{XmloReader, XmloToAir, XmloToken},
|
obj::xmlo::{XmloReader, XmloToAir, XmloToken},
|
||||||
parse::{
|
parse::{
|
||||||
terminal, FinalizeError, Lower, LowerSource, ParseError, ParseState,
|
terminal, FinalizeError, Lower, LowerSource, ParseError, ParseState,
|
||||||
|
@ -150,6 +153,7 @@ lower_pipeline! {
|
||||||
|> XirfToNir
|
|> XirfToNir
|
||||||
|> TplShortDesugar
|
|> TplShortDesugar
|
||||||
|> InterpolateNir
|
|> InterpolateNir
|
||||||
|
|> AbstractBindTranslate
|
||||||
|> NirToAir[nir_air_ty]
|
|> NirToAir[nir_air_ty]
|
||||||
|> AirAggregate[air_ctx];
|
|> AirAggregate[air_ctx];
|
||||||
|
|
||||||
|
|
|
@ -195,5 +195,23 @@
|
||||||
<param name="@foo@" desc="A parameter" />
|
<param name="@foo@" desc="A parameter" />
|
||||||
<param name="@bar@" desc="Another parameter" />
|
<param name="@bar@" desc="Another parameter" />
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
|
|
||||||
|
<template name="_tpl-param_body_"
|
||||||
|
desc="Template with params with bodies">
|
||||||
|
<param name="@text@" desc="A param with a literal">
|
||||||
|
<text>lonely foo</text>
|
||||||
|
</param>
|
||||||
|
|
||||||
|
<param name="@ref@" desc="A param with a ref">
|
||||||
|
<param-value name="@text@" />
|
||||||
|
</param>
|
||||||
|
|
||||||
|
<param name="@both@" desc="A param with both literal and ref">
|
||||||
|
<text>foo </text>
|
||||||
|
<param-value name="@text@" />
|
||||||
|
<text> bar</text>
|
||||||
|
</param>
|
||||||
|
</template>
|
||||||
</package>
|
</package>
|
||||||
|
|
||||||
|
|
|
@ -186,6 +186,7 @@
|
||||||
we cannot support the generation of each of those things within
|
we cannot support the generation of each of those things within
|
||||||
templates.
|
templates.
|
||||||
|
|
||||||
|
|
||||||
<template name="_match-child_" desc="Template with a match child">
|
<template name="_match-child_" desc="Template with a match child">
|
||||||
<match on="foo" />
|
<match on="foo" />
|
||||||
</template>
|
</template>
|
||||||
|
@ -194,5 +195,23 @@
|
||||||
<param name="@foo@" desc="A parameter" />
|
<param name="@foo@" desc="A parameter" />
|
||||||
<param name="@bar@" desc="Another parameter" />
|
<param name="@bar@" desc="Another parameter" />
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
|
|
||||||
|
<template name="_tpl-param_body_"
|
||||||
|
desc="Template with params with bodies">
|
||||||
|
<param name="@text@" desc="A param with a literal">
|
||||||
|
<text>lonely foo</text>
|
||||||
|
</param>
|
||||||
|
|
||||||
|
<param name="@ref@" desc="A param with a ref">
|
||||||
|
<param-value name="@text@" />
|
||||||
|
</param>
|
||||||
|
|
||||||
|
<param name="@both@" desc="A param with both literal and ref">
|
||||||
|
<text>foo </text>
|
||||||
|
<param-value name="@text@" />
|
||||||
|
<text> bar</text>
|
||||||
|
</param>
|
||||||
|
</template>
|
||||||
</package>
|
</package>
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue