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-13162main
parent
4ac8bf5981
commit
ea6259570e
|
@ -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())
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -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;
|
||||
|
||||
|
|
|
@ -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},
|
||||
|
|
|
@ -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)
|
||||
})
|
||||
|
|
|
@ -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)
|
||||
},
|
||||
)
|
||||
})
|
||||
})
|
||||
}
|
|
@ -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 {
|
||||
|
|
Loading…
Reference in New Issue