From ea6259570e4e749ce8e9e83c78fc52b46998f06f Mon Sep 17 00:00:00 2001 From: Mike Gerwitz Date: Thu, 25 May 2023 16:38:41 -0400 Subject: [PATCH] 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 --- tamer/src/ld/poc.rs | 90 ++++++++++++---------------- tamer/src/lib.rs | 1 + tamer/src/parse.rs | 4 +- tamer/src/parse/lower.rs | 6 +- tamer/src/pipeline.rs | 124 +++++++++++++++++++++++++++++++++++++++ tamer/src/xir/writer.rs | 15 +++++ 6 files changed, 184 insertions(+), 56 deletions(-) create mode 100644 tamer/src/pipeline.rs diff --git a/tamer/src/ld/poc.rs b/tamer/src/ld/poc.rs index 5879dea7..e2209d19 100644 --- a/tamer/src/ld/poc.rs +++ b/tamer/src/ld/poc.rs @@ -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, 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, - PartialXirToXirf<4, Text>, - _, - >::lower(src, |toks| { - Lower::, 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::::lower_with_context( - &mut iter, - state, - |air| { - let (_, air_ctx) = - Lower::::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::(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), XirfParseError(ParseError), @@ -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 for NeqIoError { + fn from(e: io::Error) -> Self { + Self(e) + } +} + impl From for TameldError { fn from(e: io::Error) -> Self { - Self::Io(e) + Self::Io(e.into()) } } diff --git a/tamer/src/lib.rs b/tamer/src/lib.rs index 5b514001..4a83093b 100644 --- a/tamer/src/lib.rs +++ b/tamer/src/lib.rs @@ -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; diff --git a/tamer/src/parse.rs b/tamer/src/parse.rs index b877f683..681e0697 100644 --- a/tamer/src/parse.rs +++ b/tamer/src/parse.rs @@ -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}, diff --git a/tamer/src/parse/lower.rs b/tamer/src/parse/lower.rs index a141dfa1..322a921e 100644 --- a/tamer/src/parse/lower.rs +++ b/tamer/src/parse/lower.rs @@ -243,6 +243,10 @@ pub trait WidenedError = Diagnostic pub type WidenedParsedResult = Result::Object>, E>; +/// A source of a lowering operation. +pub trait LowerSource = + Iterator>>; + /// 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 = /// This is the dual of [`terminal`]. pub fn lowerable( iter: impl Iterator>, -) -> impl Iterator>> { +) -> impl LowerSource { iter.map(|result| { result.map(Parsed::Object).map_err(ParseError::StateError) }) diff --git a/tamer/src/pipeline.rs b/tamer/src/pipeline.rs new file mode 100644 index 00000000..f360e649 --- /dev/null +++ b/tamer/src/pipeline.rs @@ -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 . + +//! 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( + src: impl LowerSource, + air_ctx: AirAggregateCtx, + xmlo_ctx: XmloAirContext, +) -> Result<(AirAggregateCtx, XmloAirContext), EO> +where + EO: From> + + From, XmloError>> + + From> + + From> + + From> + + From, +{ + // TODO: This entire block is a WIP and will be incrementally + // abstracted away. + Lower::< + ParsedObject, + PartialXirToXirf<4, Text>, + EO, + >::lower(&mut src.map(|result| result.map_err(EO::from)), |toks| { + Lower::, 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::::lower_with_context( + &mut iter, + xmlo_ctx, + |air| { + let (_, air_ctx) = + Lower::::lower_with_context( + air, + air_ctx, + |end| { + for result in end { + let _ = result?; + } + + Ok::<_, EO>(()) + }, + )?; + + Ok::<_, EO>(air_ctx) + }, + ) + }) + }) +} diff --git a/tamer/src/xir/writer.rs b/tamer/src/xir/writer.rs index b9814968..183db33e 100644 --- a/tamer/src/xir/writer.rs +++ b/tamer/src/xir/writer.rs @@ -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 {