diff --git a/tamer/src/bin/tamec.rs b/tamer/src/bin/tamec.rs index 63e55339..18fd06e8 100644 --- a/tamer/src/bin/tamec.rs +++ b/tamer/src/bin/tamec.rs @@ -30,6 +30,7 @@ extern crate tamer; use getopts::{Fail, Options}; use std::{ + convert::Infallible, env, error::Error, fmt::{self, Display, Write}, @@ -50,7 +51,8 @@ use tamer::{ XirfToNirError, }, parse::{ - lowerable, FinalizeError, Lower, ParseError, ParsedObject, UnknownToken, + lowerable, FinalizeError, Lower, ParseError, ParsedObject, Token, + UnknownToken, }, xir::{ self, @@ -186,7 +188,7 @@ fn compile( false => { #[cfg(feature = "wip-asg-derived-xmli")] { - derive_xmli(asg, fout) + derive_xmli(asg, fout, &escaper) } #[cfg(not(feature = "wip-asg-derived-xmli"))] { @@ -215,8 +217,51 @@ fn compile( fn derive_xmli( _asg: tamer::asg::Asg, mut fout: impl std::io::Write, + escaper: &DefaultEscaper, ) -> Result<(), UnrecoverableError> { - fout.write_all(b"")?; + use tamer::{ + convert::ExpectInto, + iter::TrippableIterator, + parse::terminal, + span::UNKNOWN_SPAN, + xir::{ + autoclose::XirfAutoClose, + flat::{Depth, Text, XirfToXir}, + writer::XmlWriter, + OpenSpan, + }, + }; + + // Note how this does not contain a closing token; + // it is closed by `XirfAutoClose`. + let xir_toks = vec![XirfToken::Open( + "it-has-begun".unwrap_into(), + OpenSpan::without_name_span(UNKNOWN_SPAN), + Depth(0), + )]; + + let mut head = lowerable(xir_toks.into_iter().map(Ok)); + + // THIS IS A PROOF-OF-CONCEPT LOWERING PIPELINE. + Lower::< + ParsedObject, XirfToken, Infallible>, + XirfAutoClose, + _, + >::lower::<_, UnrecoverableError>(&mut head, |xirf| { + Lower::, _>::lower(xirf, |xir| { + terminal::, UnrecoverableError>(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(()) } @@ -391,6 +436,20 @@ impl From for UnrecoverableError { } } +impl From for UnrecoverableError { + fn from(_: Infallible) -> Self { + unreachable!(">::from") + } +} + +impl From> for UnrecoverableError { + fn from(_: ParseError) -> Self { + unreachable!( + ">>::from" + ) + } +} + impl From> for RecoverableError { fn from(e: ParseError) -> Self { Self::XirParseError(e) diff --git a/tamer/src/parse.rs b/tamer/src/parse.rs index d2f0235a..a8a15e56 100644 --- a/tamer/src/parse.rs +++ b/tamer/src/parse.rs @@ -30,7 +30,7 @@ mod trace; pub mod util; pub use error::{FinalizeError, ParseError}; -pub use lower::{lowerable, Lower, LowerIter, ParsedObject}; +pub use lower::{lowerable, terminal, Lower, LowerIter, ParsedObject}; pub use parser::{FinalizedParser, Parsed, ParsedResult, Parser}; pub use state::{ context::{Context, Empty as EmptyContext, NoContext}, diff --git a/tamer/src/parse/lower.rs b/tamer/src/parse/lower.rs index 320a0fac..b0c27e0f 100644 --- a/tamer/src/parse/lower.rs +++ b/tamer/src/parse/lower.rs @@ -257,6 +257,8 @@ pub type WidenedParsedResult = /// itself a [`ParseState`]. /// /// See [`ParsedObject`] for more information. +/// +/// This is the dual of [`terminal`]. pub fn lowerable( iter: impl Iterator>, ) -> impl Iterator>> { @@ -265,6 +267,28 @@ pub fn lowerable( }) } +/// Indicate a terminal parser in a lowering pipeline, +/// and unwrap the parse API. +/// +/// This is the dual of [`lowerable`], +/// responsible for breaking out of the pipeline for processing of the +/// final object stream. +/// +/// [`Parsed::Incomplete`] is filtered. +/// Errors are lifted into `E` just as would be expected by [`Lower`]. +pub fn terminal< + S: ParseState, + E: Diagnostic + From>, +>( + iter: impl Iterator>, +) -> impl Iterator> { + iter.filter_map(|result| match result { + Ok(Parsed::Incomplete) => None, + Ok(Parsed::Object(obj)) => Some(Ok(obj)), + Err(e) => Some(Err(e.into())), + }) +} + /// Representation of a [`ParseState`] producing some type of [`Object`]. /// /// This is intended to be used not as a value, diff --git a/tamer/src/xir/autoclose.rs b/tamer/src/xir/autoclose.rs index c05bcf93..6870543b 100644 --- a/tamer/src/xir/autoclose.rs +++ b/tamer/src/xir/autoclose.rs @@ -115,7 +115,7 @@ use XirfAutoClose::*; /// /// See the [module-level documentation](super) for more information. #[derive(Debug, PartialEq, Eq, Default)] -enum XirfAutoClose { +pub enum XirfAutoClose { /// Element contains no children and can be self-closing. #[default] EmptyEle, @@ -250,7 +250,7 @@ impl From for Depth { /// Stack of open elements and associated metadata. #[derive(Debug, PartialEq)] -struct AutoCloseStack(Vec); +pub struct AutoCloseStack(Vec); type StackItem = (QName, Span, VDepth, PDepth);