Mike Gerwitz

Activist for User Freedom

aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorMike Gerwitz <mike.gerwitz@ryansg.com>2020-04-14 16:20:13 -0400
committerMike Gerwitz <mike.gerwitz@ryansg.com>2020-04-28 09:06:25 -0400
commitecc2e33ba77a19478d935973f6760af0f4961468 (patch)
treecde37396ff0b993e559e88ac9c8e10885a5deadd
parent323ea79bf8b15a573b3cc0bffb157ba7b5f99276 (diff)
downloadtame-ecc2e33ba77a19478d935973f6760af0f4961468.tar.gz
tame-ecc2e33ba77a19478d935973f6760af0f4961468.tar.bz2
tame-ecc2e33ba77a19478d935973f6760af0f4961468.zip
[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.
-rw-r--r--tamer/src/ld/poc.rs2
-rw-r--r--tamer/src/obj/xmlo/asg_builder.rs36
-rw-r--r--tamer/src/obj/xmlo/reader.rs41
3 files changed, 59 insertions, 20 deletions
diff --git a/tamer/src/ld/poc.rs b/tamer/src/ld/poc.rs
index 0a395ba..32a965a 100644
--- a/tamer/src/ld/poc.rs
+++ b/tamer/src/ld/poc.rs
@@ -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();
diff --git a/tamer/src/obj/xmlo/asg_builder.rs b/tamer/src/obj/xmlo/asg_builder.rs
index de834b6..24c51fe 100644
--- a/tamer/src/obj/xmlo/asg_builder.rs
+++ b/tamer/src/obj/xmlo/asg_builder.rs
@@ -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",
));
}
diff --git a/tamer/src/obj/xmlo/reader.rs b/tamer/src/obj/xmlo/reader.rs
index ee944a8..491d29e 100644
--- a/tamer/src/obj/xmlo/reader.rs
+++ b/tamer/src/obj/xmlo/reader.rs
@@ -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 {