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))) => {
|
||||
oi.desc_short(ctx.asg_mut(), clause);
|
||||
oi.add_desc_short(ctx.asg_mut(), clause);
|
||||
Transition(BuildingExpr(es, oi)).incomplete()
|
||||
}
|
||||
|
||||
|
|
|
@ -102,7 +102,7 @@ impl ParseState for AirMetaAggregate {
|
|||
}
|
||||
|
||||
(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()
|
||||
}
|
||||
|
||||
|
|
|
@ -205,7 +205,7 @@ impl ParseState for AirTplAggregate {
|
|||
}
|
||||
|
||||
(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()
|
||||
}
|
||||
|
||||
|
|
|
@ -837,13 +837,27 @@ impl<O: ObjectKind> ObjectIndex<O> {
|
|||
/// simple sentence or as part of a compound sentence.
|
||||
/// There should only be one such clause for any given object,
|
||||
/// 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
|
||||
O: ObjectRelTo<Doc>,
|
||||
{
|
||||
let oi_doc = asg.create(Doc::new_indep_clause(clause));
|
||||
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> {
|
||||
|
|
|
@ -476,6 +476,28 @@ impl<'a> TreeContext<'a> {
|
|||
if let Some(pname) =
|
||||
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));
|
||||
|
||||
Some(Xirf::open(
|
||||
|
@ -484,22 +506,7 @@ impl<'a> TreeContext<'a> {
|
|||
depth,
|
||||
))
|
||||
} else if let Some(lexeme) = meta.lexeme() {
|
||||
self.push(Xirf::close(
|
||||
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,
|
||||
))
|
||||
Some(self.emit_text_node(lexeme, meta.span(), depth))
|
||||
} else {
|
||||
// TODO: Rewrite the above to be an exhaustive match, perhaps,
|
||||
// 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
|
||||
/// body.
|
||||
fn emit_tpl_param_value(
|
||||
|
@ -586,10 +614,11 @@ impl<'a> TreeContext<'a> {
|
|||
}
|
||||
|
||||
// template/param/@desc
|
||||
(Object::Meta(_), Doc::IndepClause(desc))
|
||||
(Object::Meta(_), Doc::IndepClause(_desc))
|
||||
if self.tpl_apply.is_none() =>
|
||||
{
|
||||
Some(attr_desc(*desc))
|
||||
// This is already covered in `emit_tpl_param`
|
||||
None
|
||||
}
|
||||
|
||||
(_, Doc::Text(_text)) => {
|
||||
|
|
|
@ -1458,10 +1458,16 @@ ele_parse! {
|
|||
/// providing constant values.
|
||||
/// The result will be as if the user typed the text themselves in the
|
||||
/// 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) {
|
||||
@ {
|
||||
QN_UNIQUE => TodoAttr,
|
||||
} => Todo(ospan.into()),
|
||||
} => Noop(ospan.into()),
|
||||
};
|
||||
|
||||
/// Default the param to the value of another template param,
|
||||
|
@ -1475,7 +1481,7 @@ ele_parse! {
|
|||
/// cumbersome and slow
|
||||
TplParamValue := QN_PARAM_VALUE(_, ospan) {
|
||||
@ {
|
||||
QN_NAME => TodoAttr,
|
||||
QN_NAME => Ref,
|
||||
QN_DASH => TodoAttr,
|
||||
QN_UPPER => TodoAttr,
|
||||
QN_LOWER => TodoAttr,
|
||||
|
@ -1484,7 +1490,7 @@ ele_parse! {
|
|||
QN_RMUNDERSCORE => TodoAttr,
|
||||
QN_IDENTIFIER => TodoAttr,
|
||||
QN_SNAKE => TodoAttr,
|
||||
} => Todo(ospan.into()),
|
||||
} => Noop(ospan.into()),
|
||||
};
|
||||
|
||||
/// Inherit a default value from a metavalue.
|
||||
|
|
|
@ -110,7 +110,10 @@
|
|||
use crate::{
|
||||
asg::{air::AirAggregate, AsgTreeToXirf},
|
||||
diagnose::Diagnostic,
|
||||
nir::{InterpolateNir, NirToAir, TplShortDesugar, XirfToNir},
|
||||
nir::{
|
||||
AbstractBindTranslate, InterpolateNir, NirToAir, TplShortDesugar,
|
||||
XirfToNir,
|
||||
},
|
||||
obj::xmlo::{XmloReader, XmloToAir, XmloToken},
|
||||
parse::{
|
||||
terminal, FinalizeError, Lower, LowerSource, ParseError, ParseState,
|
||||
|
@ -150,6 +153,7 @@ lower_pipeline! {
|
|||
|> XirfToNir
|
||||
|> TplShortDesugar
|
||||
|> InterpolateNir
|
||||
|> AbstractBindTranslate
|
||||
|> NirToAir[nir_air_ty]
|
||||
|> AirAggregate[air_ctx];
|
||||
|
||||
|
|
|
@ -195,5 +195,23 @@
|
|||
<param name="@foo@" desc="A parameter" />
|
||||
<param name="@bar@" desc="Another parameter" />
|
||||
</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>
|
||||
|
||||
|
|
|
@ -186,6 +186,7 @@
|
|||
we cannot support the generation of each of those things within
|
||||
templates.
|
||||
|
||||
|
||||
<template name="_match-child_" desc="Template with a match child">
|
||||
<match on="foo" />
|
||||
</template>
|
||||
|
@ -194,5 +195,23 @@
|
|||
<param name="@foo@" desc="A parameter" />
|
||||
<param name="@bar@" desc="Another parameter" />
|
||||
</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>
|
||||
|
||||
|
|
Loading…
Reference in New Issue