[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
parent
323ea79bf8
commit
ecc2e33ba7
|
@ -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();
|
||||
|
|
|
@ -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",
|
||||
));
|
||||
}
|
||||
|
|
|
@ -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 {
|
||||
|
|
Loading…
Reference in New Issue