tamer: tamec: Extract xmli lowering into pipeline module

This is the same idea as the previous two commits: get all the lowering
pipelines into the same place so that we can observe commonalities and
attempt to derive an appropriate abstraction.

`lower_xmli` could have invoked `tree_reconstruction` itself, since it has
all the information that it needs to do so, but the idea is that these will
accept sources from the caller.  This also demonstrates that sinks need to
be flexible.  In an ideal abstraction, perhaps this would be able to produce
an iterator that accepts the first token type and yields the last, which can
then be directed to a sink, but that's not compatible with how the lowering
operations currently work, which requires a single value to be
returned.  But if it did work that way, then they'd be able to compose just
as any other parser.

Maybe for the future.

DEV-13162
Mike Gerwitz 2023-05-26 23:25:08 -04:00
parent 61753d77aa
commit db1d64f6fc
2 changed files with 61 additions and 60 deletions

View File

@ -44,10 +44,7 @@ use tamer::{
AnnotatedSpan, Diagnostic, FsSpanResolver, Reporter, VisualReporter,
},
nir::{InterpError, Nir, NirToAirError, XirfToNirError},
parse::{
lowerable, FinalizeError, Lower, ParseError, ParsedObject, Token,
UnknownToken,
},
parse::{lowerable, FinalizeError, ParseError, Token, UnknownToken},
pipeline::parse_package_xml,
xir::{
self,
@ -189,61 +186,16 @@ fn derive_xmli(
escaper: &DefaultEscaper,
) -> Result<(), UnrecoverableError> {
use tamer::{
asg::{
visit::{tree_reconstruction, TreeWalkRel},
AsgTreeToXirf,
},
iter::TrippableIterator,
parse::terminal,
xir::{
autoclose::XirfAutoClose,
flat::{Text, XirfToXir},
writer::XmlWriter,
},
asg::visit::tree_reconstruction, pipeline, xir::writer::XmlWriter,
};
let mut head =
lowerable::<UnknownToken, _, _>(tree_reconstruction(&asg).map(Ok))
.map(|result| result.map_err(UnrecoverableError::from));
let src = lowerable(tree_reconstruction(&asg).map(Ok));
// THIS IS A PROOF-OF-CONCEPT LOWERING PIPELINE.
Lower::<
ParsedObject<UnknownToken, TreeWalkRel, Infallible>,
AsgTreeToXirf,
_,
>::lower_with_context::<_, UnrecoverableError>(
&mut head,
&asg,
|xirf_unclosed| {
Lower::<AsgTreeToXirf, XirfAutoClose, _>::lower(
xirf_unclosed,
|xirf| {
Lower::<XirfAutoClose, XirfToXir<Text>, _>::lower(
xirf,
|xir| {
terminal::<XirfToXir<Text>, _>(xir).while_ok(
|toks| {
// Write failures should immediately bail out;
// we can't skip writing portions of the file and
// just keep going!
toks.write(
&mut fout,
Default::default(),
escaper,
)?;
Ok::<_, UnrecoverableError>(())
},
// TODO: Remove bad file?
// Let make do it?
)
},
)
},
)
},
)?;
Ok(())
// TODO: Remove bad file?
// Let make do it?
pipeline::lower_xmli(src, &asg, |st, tok| {
tok.write(&mut fout, st, escaper).map_err(Into::into)
})
}
/// Entrypoint for the compiler

View File

@ -40,17 +40,26 @@
//! For information on the lowering pipeline as an abstraction,
//! see [`Lower`].
use std::convert::Infallible;
use crate::{
asg::air::{AirAggregate, AirAggregateCtx},
asg::{
air::{AirAggregate, AirAggregateCtx},
visit::TreeWalkRel,
Asg, AsgTreeToXirf,
},
diagnose::Diagnostic,
iter::TrippableIterator,
nir::{InterpolateNir, NirToAir, TplShortDesugar, XirfToNir},
obj::xmlo::{XmloAirContext, XmloReader, XmloToAir, XmloToken},
parse::{
FinalizeError, FromParseError, Lower, LowerSource, ParseError, Parsed,
ParsedObject, UnknownToken,
terminal, FinalizeError, FromParseError, Lower, LowerSource,
ParseError, Parsed, ParsedObject, UnknownToken,
},
xir::{
flat::{PartialXirToXirf, RefinedText, Text, XirToXirf},
autoclose::XirfAutoClose,
flat::{PartialXirToXirf, RefinedText, Text, XirToXirf, XirfToXir},
writer::WriterState,
Error as XirError, Token as XirToken,
},
};
@ -164,3 +173,43 @@ where
Ok(air_ctx)
}
/// Lower an [`Asg`]-derived token stream into an `xmli` file.
///
/// TODO: More documentation once this has been further cleaned up.
pub fn lower_xmli<EU: Diagnostic>(
src: impl LowerSource<UnknownToken, TreeWalkRel, Infallible>,
asg: &Asg,
sink: impl FnMut(WriterState, XirToken) -> Result<WriterState, EU>,
) -> Result<(), EU>
where
EU: From<ParseError<UnknownToken, Infallible>>
+ From<ParseError<TreeWalkRel, Infallible>> // see note above
+ FromParseError<XirfAutoClose>
+ FromParseError<XirfToXir<Text>>
+ From<FinalizeError>,
{
#[rustfmt::skip] // better visualize the structure despite the line length
Lower::<
ParsedObject<UnknownToken, TreeWalkRel, Infallible>,
AsgTreeToXirf,
_,
>::lower_with_context::<_, EU>(
&mut src.map(|result| result.map_err(EU::from)),
asg,
|xirf_unclosed| {
Lower::<AsgTreeToXirf, XirfAutoClose, _>::lower(xirf_unclosed, |xirf| {
Lower::<XirfAutoClose, XirfToXir<Text>, _>::lower(xirf, |xir| {
terminal::<XirfToXir<Text>, _>(xir).while_ok(|toks| {
// Write failures should immediately bail out;
// we can't skip writing portions of the file and
// just keep going!
toks.try_fold(Default::default(), sink)
})
})
})
}
)?;
Ok(())
}