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::{
|
use crate::{
|
||||||
asg::{
|
asg::{
|
||||||
air::{Air, AirAggregate, AirAggregateCtx},
|
air::{Air, AirAggregateCtx},
|
||||||
AsgError, DefaultAsg,
|
AsgError, DefaultAsg,
|
||||||
},
|
},
|
||||||
diagnose::{AnnotatedSpan, Diagnostic},
|
diagnose::{AnnotatedSpan, Diagnostic},
|
||||||
|
@ -36,17 +36,12 @@ use crate::{
|
||||||
VisitOnceFilesystem,
|
VisitOnceFilesystem,
|
||||||
},
|
},
|
||||||
ld::xmle::Sections,
|
ld::xmle::Sections,
|
||||||
obj::xmlo::{
|
obj::xmlo::{XmloAirContext, XmloAirError, XmloError, XmloToken},
|
||||||
XmloAirContext, XmloAirError, XmloError, XmloReader, XmloToAir,
|
parse::{lowerable, FinalizeError, ParseError, UnknownToken},
|
||||||
XmloToken,
|
pipeline,
|
||||||
},
|
|
||||||
parse::{
|
|
||||||
lowerable, FinalizeError, Lower, ParseError, Parsed, ParsedObject,
|
|
||||||
UnknownToken,
|
|
||||||
},
|
|
||||||
sym::{GlobalSymbolResolve, SymbolId},
|
sym::{GlobalSymbolResolve, SymbolId},
|
||||||
xir::{
|
xir::{
|
||||||
flat::{PartialXirToXirf, Text, XirToXirfError, XirfToken},
|
flat::{Text, XirToXirfError, XirfToken},
|
||||||
reader::XmlXirReader,
|
reader::XmlXirReader,
|
||||||
writer::{Error as XirWriterError, XmlWriter},
|
writer::{Error as XirWriterError, XmlWriter},
|
||||||
DefaultEscaper, Error as XirError, Escaper, Token as XirToken,
|
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)),
|
VisitOnceFile::Visited => return Ok((air_ctx, state)),
|
||||||
};
|
};
|
||||||
|
|
||||||
let src = &mut lowerable(XmlXirReader::new(file, escaper, ctx))
|
let src = &mut lowerable(XmlXirReader::new(file, escaper, ctx));
|
||||||
.map(|result| result.map_err(TameldError::from));
|
|
||||||
|
|
||||||
// TODO: This entire block is a WIP and will be incrementally
|
let (mut air_ctx, mut state) =
|
||||||
// abstracted away.
|
pipeline::load_xmlo::<TameldError>(src, air_ctx, state)?;
|
||||||
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 dir = path;
|
let mut dir = path;
|
||||||
dir.pop();
|
dir.pop();
|
||||||
|
@ -196,9 +153,9 @@ fn output_xmle<'a, X: XmleSections<'a>, S: Escaper>(
|
||||||
/// This cannot include panics,
|
/// This cannot include panics,
|
||||||
/// but efforts have been made to reduce panics to situations that
|
/// but efforts have been made to reduce panics to situations that
|
||||||
/// represent the equivalent of assertions.
|
/// represent the equivalent of assertions.
|
||||||
#[derive(Debug)]
|
#[derive(Debug, PartialEq)]
|
||||||
pub enum TameldError {
|
pub enum TameldError {
|
||||||
Io(io::Error),
|
Io(NeqIoError),
|
||||||
SortError(SortError),
|
SortError(SortError),
|
||||||
XirParseError(ParseError<UnknownToken, XirError>),
|
XirParseError(ParseError<UnknownToken, XirError>),
|
||||||
XirfParseError(ParseError<XirToken, XirToXirfError>),
|
XirfParseError(ParseError<XirToken, XirToXirfError>),
|
||||||
|
@ -210,9 +167,34 @@ pub enum TameldError {
|
||||||
Fmt(fmt::Error),
|
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 {
|
impl From<io::Error> for TameldError {
|
||||||
fn from(e: io::Error) -> Self {
|
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 num;
|
||||||
pub mod obj;
|
pub mod obj;
|
||||||
pub mod parse;
|
pub mod parse;
|
||||||
|
pub mod pipeline;
|
||||||
pub mod span;
|
pub mod span;
|
||||||
pub mod sym;
|
pub mod sym;
|
||||||
|
|
||||||
|
|
|
@ -30,7 +30,9 @@ mod trace;
|
||||||
pub mod util;
|
pub mod util;
|
||||||
|
|
||||||
pub use error::{FinalizeError, ParseError};
|
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 parser::{FinalizedParser, Parsed, ParsedResult, Parser};
|
||||||
pub use state::{
|
pub use state::{
|
||||||
context::{Context, Empty as EmptyContext, NoContext},
|
context::{Context, Empty as EmptyContext, NoContext},
|
||||||
|
|
|
@ -243,6 +243,10 @@ pub trait WidenedError<S: ParseState, LS: ParseState> = Diagnostic
|
||||||
pub type WidenedParsedResult<S, E> =
|
pub type WidenedParsedResult<S, E> =
|
||||||
Result<Parsed<<S as ParseState>::Object>, 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.
|
/// Make the provided [`Iterator`] `iter` usable in a `Lower` pipeline.
|
||||||
///
|
///
|
||||||
/// This will produce an iterator that shares the same output as a
|
/// 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`].
|
/// This is the dual of [`terminal`].
|
||||||
pub fn lowerable<T: Token, O: Object, E: Diagnostic + PartialEq>(
|
pub fn lowerable<T: Token, O: Object, E: Diagnostic + PartialEq>(
|
||||||
iter: impl Iterator<Item = Result<O, E>>,
|
iter: impl Iterator<Item = Result<O, E>>,
|
||||||
) -> impl Iterator<Item = ParsedResult<ParsedObject<T, O, E>>> {
|
) -> impl LowerSource<T, O, E> {
|
||||||
iter.map(|result| {
|
iter.map(|result| {
|
||||||
result.map(Parsed::Object).map_err(ParseError::StateError)
|
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 {
|
impl std::error::Error for Error {
|
||||||
fn source(&self) -> Option<&(dyn std::error::Error + 'static)> {
|
fn source(&self) -> Option<&(dyn std::error::Error + 'static)> {
|
||||||
match self {
|
match self {
|
||||||
|
|
Loading…
Reference in New Issue