[DEV-7084] TAMER: xmlo::AsgBuilder: Accept XmloResult iterator

This flips the API from using XmloWriter as the context to using Asg and
consuming anything that can produce XmloResults.  This not only makes more
sense, but avoids having to create a trait for XmloReader, and simplifies
the trait bounds we have to concern ourselves with.
master
Mike Gerwitz 2020-04-14 16:20:13 -04:00
parent 323ea79bf8
commit ecc2e33ba7
3 changed files with 59 additions and 20 deletions

View File

@ -127,7 +127,7 @@ fn load_xmlo<'a, 'i, I: Interner<'i>, P: AsRef<Path>>(
let xmlo: XmloReader<'_, _, _> = (file, interner).into();
let mut state = xmlo.build(depgraph, state)?;
let mut state = depgraph.import_xmlo(xmlo, state)?;
let mut dir: PathBuf = path.clone();
dir.pop();

View File

@ -17,16 +17,15 @@
// You should have received a copy of the GNU General Public License
// along with this program. If not, see <http://www.gnu.org/licenses/>.
use super::reader::{XmloError, XmloEvent, XmloReader};
use super::reader::{XmloError, XmloEvent, XmloResult};
use crate::ir::asg::{
Asg, IdentKind, IdentObjectState, IndexType, ObjectRef, Source,
};
use crate::sym::{Interner, Symbol};
use crate::sym::Symbol;
use std::collections::HashSet;
use std::convert::TryInto;
use std::error::Error;
use std::hash::BuildHasher;
use std::io::BufRead;
// TODO error type
pub type Result<'i, S, Ix> =
@ -50,24 +49,23 @@ where
S: BuildHasher,
Ix: IndexType,
{
fn build<G: Asg<'i, O, Ix>>(
self,
graph: &mut G,
fn import_xmlo(
&mut self,
xmlo: impl Iterator<Item = XmloResult<XmloEvent<'i>>>,
state: AsgBuilderState<'i, S, Ix>,
) -> Result<'i, S, Ix>;
}
impl<'i, B, I, O, S, Ix> AsgBuilder<'i, O, S, Ix> for XmloReader<'i, B, I>
impl<'i, O, S, Ix, G> AsgBuilder<'i, O, S, Ix> for G
where
B: BufRead,
I: Interner<'i>,
O: IdentObjectState<'i, O>,
S: BuildHasher + Default,
Ix: IndexType,
G: Asg<'i, O, Ix>,
{
fn build<G: Asg<'i, O, Ix>>(
mut self,
graph: &mut G,
fn import_xmlo(
&mut self,
mut xmlo: impl Iterator<Item = XmloResult<XmloEvent<'i>>>,
mut state: AsgBuilderState<'i, S, Ix>,
) -> Result<'i, S, Ix> {
let mut elig = None;
@ -75,7 +73,7 @@ where
let found = state.found.get_or_insert(Default::default());
loop {
match self.read_event()? {
match xmlo.next().unwrap()? {
XmloEvent::Package(attrs) => {
if first {
state.name = attrs.name;
@ -90,7 +88,7 @@ where
// mapping to params that are never actually used
if !sym.starts_with(":map:") {
for dep_sym in deps {
graph.add_dep_lookup(sym, dep_sym);
self.add_dep_lookup(sym, dep_sym);
}
}
}
@ -123,9 +121,9 @@ where
);
if extern_ {
graph.declare_extern(sym, kindval, src)?;
self.declare_extern(sym, kindval, src)?;
} else {
let node = graph.declare(sym, kindval, src)?;
let node = self.declare(sym, kindval, src)?;
if link_root {
state.roots.push(node);
@ -136,11 +134,11 @@ where
XmloEvent::Fragment(sym, text) => {
let frag =
graph.lookup(sym).ok_or(XmloError::MissingFragment(
self.lookup(sym).ok_or(XmloError::MissingFragment(
String::from("missing fragment"),
))?;
graph.set_fragment(frag, text)?;
self.set_fragment(frag, text)?;
}
// We don't need to read any further than the end of the
@ -150,7 +148,7 @@ where
}
if let Some(elig_sym) = elig {
state.roots.push(graph.lookup(elig_sym).expect(
state.roots.push(self.lookup(elig_sym).expect(
"internal error: package elig references nonexistant symbol",
));
}

View File

@ -149,6 +149,7 @@ use quick_xml::Reader as XmlReader;
use std::convert::TryInto;
use std::fmt::Display;
use std::io::BufRead;
use std::iter::Iterator;
use std::result::Result;
/// A [`Result`] with a hard-coded [`XmloError`] error type.
@ -684,6 +685,27 @@ impl<'i, B: BufRead, I: Interner<'i>> XmloReader<'i, B, I> {
}
}
impl<'i, B, I> Iterator for XmloReader<'i, B, I>
where
B: BufRead,
I: Interner<'i>,
{
type Item = XmloResult<XmloEvent<'i>>;
/// Invoke [`XmloReader::read_event`] and yield the result via an
/// [`Iterator`] API.
///
/// *Warning*: This will always return [`Some`] for now.
/// Future changes may alter this behavior.
/// To terminate the iterator,
/// it's recommended that you use [`Iterator::take_while`] to filter
/// on the desired predicate,
/// such as [`XmloEvent::Eoh`].
fn next(&mut self) -> Option<Self::Item> {
Some(self.read_event())
}
}
impl<'i, B, I> From<(B, &'i I)> for XmloReader<'i, B, I>
where
B: BufRead,
@ -1521,6 +1543,25 @@ mod test {
bad => panic!("expected XmloError: {:?}", bad),
}
}
fn read_events_via_iterator(sut, interner) {
sut.reader.next_event = Some(Box::new(|_, _| {
Ok(XmlEvent::Start(MockBytesStart::new(
b"package",
Some(MockAttributes::new(vec![])),
)))
}));
let result = sut.next().unwrap()?;
assert_eq!(
XmloEvent::Package(PackageAttrs {
program: false,
..Default::default()
}),
result
);
}
}
macro_rules! sym_test_reader_event {