tamer: ld::poc: Extract xmlo loading pipeline into new pipeline module

I want to clean this up a bit further.  The motivation is that we need this
for imports in `tamec`.

Eventually this will be cleaned up to the point where it's declarative and
easy to understand---there's a mess of types involved now and, when
something goes wrong, it can be brutally confusing.

DEV-13162
main
Mike Gerwitz 2023-05-25 16:38:41 -04:00
parent 4ac8bf5981
commit ea6259570e
6 changed files with 184 additions and 56 deletions

View File

@ -27,7 +27,7 @@ use super::xmle::{
};
use crate::{
asg::{
air::{Air, AirAggregate, AirAggregateCtx},
air::{Air, AirAggregateCtx},
AsgError, DefaultAsg,
},
diagnose::{AnnotatedSpan, Diagnostic},
@ -36,17 +36,12 @@ use crate::{
VisitOnceFilesystem,
},
ld::xmle::Sections,
obj::xmlo::{
XmloAirContext, XmloAirError, XmloError, XmloReader, XmloToAir,
XmloToken,
},
parse::{
lowerable, FinalizeError, Lower, ParseError, Parsed, ParsedObject,
UnknownToken,
},
obj::xmlo::{XmloAirContext, XmloAirError, XmloError, XmloToken},
parse::{lowerable, FinalizeError, ParseError, UnknownToken},
pipeline,
sym::{GlobalSymbolResolve, SymbolId},
xir::{
flat::{PartialXirToXirf, Text, XirToXirfError, XirfToken},
flat::{Text, XirToXirfError, XirfToken},
reader::XmlXirReader,
writer::{Error as XirWriterError, XmlWriter},
DefaultEscaper, Error as XirError, Escaper, Token as XirToken,
@ -108,48 +103,10 @@ fn load_xmlo<P: AsRef<Path>, S: Escaper>(
VisitOnceFile::Visited => return Ok((air_ctx, state)),
};
let src = &mut lowerable(XmlXirReader::new(file, escaper, ctx))
.map(|result| result.map_err(TameldError::from));
let src = &mut lowerable(XmlXirReader::new(file, escaper, ctx));
// TODO: This entire block is a WIP and will be incrementally
// abstracted away.
let (mut air_ctx, mut state) = Lower::<
ParsedObject<UnknownToken, XirToken, XirError>,
PartialXirToXirf<4, Text>,
_,
>::lower(src, |toks| {
Lower::<PartialXirToXirf<4, Text>, XmloReader, _>::lower(toks, |xmlo| {
let mut iter = xmlo.scan(false, |st, rtok| match st {
true => None,
false => {
*st =
matches!(rtok, Ok(Parsed::Object(XmloToken::Eoh(..))));
Some(rtok)
}
});
Lower::<XmloReader, XmloToAir, _>::lower_with_context(
&mut iter,
state,
|air| {
let (_, air_ctx) =
Lower::<XmloToAir, AirAggregate, _>::lower_with_context(
air,
air_ctx,
|end| {
for result in end {
let _ = result?;
}
Ok::<_, TameldError>(())
},
)?;
Ok::<_, TameldError>(air_ctx)
},
)
})
})?;
let (mut air_ctx, mut state) =
pipeline::load_xmlo::<TameldError>(src, air_ctx, state)?;
let mut dir = path;
dir.pop();
@ -196,9 +153,9 @@ fn output_xmle<'a, X: XmleSections<'a>, S: Escaper>(
/// This cannot include panics,
/// but efforts have been made to reduce panics to situations that
/// represent the equivalent of assertions.
#[derive(Debug)]
#[derive(Debug, PartialEq)]
pub enum TameldError {
Io(io::Error),
Io(NeqIoError),
SortError(SortError),
XirParseError(ParseError<UnknownToken, XirError>),
XirfParseError(ParseError<XirToken, XirToXirfError>),
@ -210,9 +167,34 @@ pub enum TameldError {
Fmt(fmt::Error),
}
#[derive(Debug)]
pub struct NeqIoError(io::Error);
impl PartialEq for NeqIoError {
fn eq(&self, _other: &Self) -> bool {
false
}
}
impl Display for NeqIoError {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match self {
Self(e) => e.fmt(f),
}
}
}
impl Error for NeqIoError {}
impl From<io::Error> for NeqIoError {
fn from(e: io::Error) -> Self {
Self(e)
}
}
impl From<io::Error> for TameldError {
fn from(e: io::Error) -> Self {
Self::Io(e)
Self::Io(e.into())
}
}

View File

@ -194,6 +194,7 @@ pub mod nir;
pub mod num;
pub mod obj;
pub mod parse;
pub mod pipeline;
pub mod span;
pub mod sym;

View File

@ -30,7 +30,9 @@ mod trace;
pub mod util;
pub use error::{FinalizeError, ParseError};
pub use lower::{lowerable, terminal, Lower, LowerIter, ParsedObject};
pub use lower::{
lowerable, terminal, Lower, LowerIter, LowerSource, ParsedObject,
};
pub use parser::{FinalizedParser, Parsed, ParsedResult, Parser};
pub use state::{
context::{Context, Empty as EmptyContext, NoContext},

View File

@ -243,6 +243,10 @@ pub trait WidenedError<S: ParseState, LS: ParseState> = Diagnostic
pub type WidenedParsedResult<S, E> =
Result<Parsed<<S as ParseState>::Object>, E>;
/// A source of a lowering operation.
pub trait LowerSource<T: Token, O: Object, E: Diagnostic + PartialEq> =
Iterator<Item = ParsedResult<ParsedObject<T, O, E>>>;
/// Make the provided [`Iterator`] `iter` usable in a `Lower` pipeline.
///
/// This will produce an iterator that shares the same output as a
@ -255,7 +259,7 @@ pub type WidenedParsedResult<S, E> =
/// This is the dual of [`terminal`].
pub fn lowerable<T: Token, O: Object, E: Diagnostic + PartialEq>(
iter: impl Iterator<Item = Result<O, E>>,
) -> impl Iterator<Item = ParsedResult<ParsedObject<T, O, E>>> {
) -> impl LowerSource<T, O, E> {
iter.map(|result| {
result.map(Parsed::Object).map_err(ParseError::StateError)
})

View File

@ -0,0 +1,124 @@
// Lowering pipelines
//
// Copyright (C) 2014-2023 Ryan Specialty, LLC.
//
// This file is part of TAME.
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program. If not, see <http://www.gnu.org/licenses/>.
//! Lowering pipelines.
//!
//! TAMER is composed of a series of IR lowering operations connected in
//! series as a pipeline of [`Parser`](crate::parse::Parser)s,
//! called the _lowering pipeline_.
//! Each parser in the pipeline produces a stream of tokens that is read and
//! acted upon by the next.
//! The system can therefore be reasoned about as a series of mappings
//! between IRs,
//! where each parser in the pipeline produces a lower-level IR.
//!
//! Portions of the pipeline require operating on data in aggregate.
//! Most notably,
//! the [ASG](crate::asg) aggregates data into a graph;
//! the graph acts as a _sink_ for the pipeline.
//! At the other end,
//! the ASG serves as a source for another lowering pipeline that emits
//! the target object.
//!
//! The module is responsible for pipeline composition.
//! For information on the lowering pipeline as an abstraction,
//! see [`Lower`].
use crate::{
asg::{
air::{Air, AirAggregate, AirAggregateCtx},
AsgError,
},
diagnose::Diagnostic,
obj::xmlo::{
XmloAirContext, XmloAirError, XmloError, XmloReader, XmloToAir,
XmloToken,
},
parse::{
FinalizeError, Lower, LowerSource, ParseError, Parsed, ParsedObject,
UnknownToken,
},
xir::{
flat::{PartialXirToXirf, Text, XirToXirfError, XirfToken},
Error as XirError, Token as XirToken,
},
};
/// Load an `xmlo` file represented by `src` into the graph held
/// by `air_ctx`.
///
/// Loading an object file will result in opaque objects being added to the
/// graph.
///
/// TODO: To re-use this in `tamec` we want to be able to ignore fragments.
///
/// TODO: More documentation once this has been further cleaned up.
pub fn load_xmlo<EO: Diagnostic + PartialEq>(
src: impl LowerSource<UnknownToken, XirToken, XirError>,
air_ctx: AirAggregateCtx,
xmlo_ctx: XmloAirContext,
) -> Result<(AirAggregateCtx, XmloAirContext), EO>
where
EO: From<ParseError<UnknownToken, XirError>>
+ From<ParseError<XirfToken<Text>, XmloError>>
+ From<ParseError<XirToken, XirToXirfError>>
+ From<ParseError<XmloToken, XmloAirError>>
+ From<ParseError<Air, AsgError>>
+ From<FinalizeError>,
{
// TODO: This entire block is a WIP and will be incrementally
// abstracted away.
Lower::<
ParsedObject<UnknownToken, XirToken, XirError>,
PartialXirToXirf<4, Text>,
EO,
>::lower(&mut src.map(|result| result.map_err(EO::from)), |toks| {
Lower::<PartialXirToXirf<4, Text>, XmloReader, _>::lower(toks, |xmlo| {
let mut iter = xmlo.scan(false, |st, rtok| match st {
true => None,
false => {
*st =
matches!(rtok, Ok(Parsed::Object(XmloToken::Eoh(..))));
Some(rtok)
}
});
Lower::<XmloReader, XmloToAir, _>::lower_with_context(
&mut iter,
xmlo_ctx,
|air| {
let (_, air_ctx) =
Lower::<XmloToAir, AirAggregate, _>::lower_with_context(
air,
air_ctx,
|end| {
for result in end {
let _ = result?;
}
Ok::<_, EO>(())
},
)?;
Ok::<_, EO>(air_ctx)
},
)
})
})
}

View File

@ -60,6 +60,21 @@ impl std::fmt::Display for Error {
}
}
impl PartialEq for Error {
fn eq(&self, other: &Self) -> bool {
match (self, other) {
(Error::Io(_), _) => false,
(Error::Xir(a), Error::Xir(b)) => a == b,
(
Error::UnexpectedToken(aa, ab),
Error::UnexpectedToken(ba, bb),
) => aa == ba && ab == bb,
(Error::Todo(aa, ab), Error::Todo(ba, bb)) => aa == ba && ab == bb,
_ => false,
}
}
}
impl std::error::Error for Error {
fn source(&self) -> Option<&(dyn std::error::Error + 'static)> {
match self {