Mike Gerwitz

Activist for User Freedom

aboutsummaryrefslogtreecommitdiffstats
path: root/tamer
diff options
context:
space:
mode:
authorMike Gerwitz <mike.gerwitz@ryansg.com>2022-03-30 12:06:38 -0400
committerMike Gerwitz <mike.gerwitz@ryansg.com>2022-03-30 12:06:38 -0400
commit3f8e397e57acd72483a82216698fee2fc1601779 (patch)
treede13a321775b05bbc3394cdd05bd5d5129c20c84 /tamer
parent9b429b6fc3a28789c7b2a8860b475ec0be97f3a7 (diff)
downloadtame-3f8e397e57acd72483a82216698fee2fc1601779.tar.gz
tame-3f8e397e57acd72483a82216698fee2fc1601779.tar.bz2
tame-3f8e397e57acd72483a82216698fee2fc1601779.zip
tamer: obj::xmlo::reader: Parse preproc:sym/preproc:from
Ideally this would just be an attribute, but I guess I never got around to making that change in the compiler and I don't want a detour right now. DEV-10863
Diffstat (limited to 'tamer')
-rw-r--r--tamer/src/obj/xmlo/error.rs21
-rw-r--r--tamer/src/obj/xmlo/reader.rs34
-rw-r--r--tamer/src/obj/xmlo/reader/quickxml.rs17
-rw-r--r--tamer/src/obj/xmlo/reader/quickxml/test.rs44
-rw-r--r--tamer/src/obj/xmlo/reader/test.rs96
5 files changed, 162 insertions, 50 deletions
diff --git a/tamer/src/obj/xmlo/error.rs b/tamer/src/obj/xmlo/error.rs
index d9b3deb..1e916fa 100644
--- a/tamer/src/obj/xmlo/error.rs
+++ b/tamer/src/obj/xmlo/error.rs
@@ -53,8 +53,10 @@ pub enum XmloError {
InvalidDim(SymbolId, Span),
/// A `preproc:sym-dep` element was found, but is missing `@name`.
UnassociatedSymDep,
- /// The `preproc:sym[@type="map"]` contains unexpected or invalid data.
- InvalidMapFrom(String),
+ /// The `preproc:sym[@type="map"]` is missing a @name.
+ MapFromNameMissing(SymbolId, Span),
+ /// Multiple `preproc:from` nodes found.
+ MapFromMultiple(SymbolId, Span),
/// Invalid dependency in adjacency list
/// (`preproc:sym-dep/preproc:sym-ref`).
MalformedSymRef(String),
@@ -100,8 +102,19 @@ impl Display for XmloError {
Self::InvalidDim(dim, span) => {
write!(fmt, "invalid preproc:sym/@dim `{dim}` at {span}")
}
- Self::InvalidMapFrom(msg) => {
- write!(fmt, "invalid preproc:sym[@type=\"map\"]: {}", msg)
+ Self::MapFromNameMissing(sym, span) => {
+ write!(
+ fmt,
+ "preproc:sym[@type=\"map\"]/preproc:from/@name missing \
+ for symbol `{sym}` at {span}"
+ )
+ }
+ Self::MapFromMultiple(sym, span) => {
+ write!(
+ fmt,
+ "preproc:sym[@type=\"map\"]/preproc:from must appear \
+ only once for symbol `{sym}` at {span}"
+ )
}
Self::UnassociatedSymDep => write!(
fmt,
diff --git a/tamer/src/obj/xmlo/reader.rs b/tamer/src/obj/xmlo/reader.rs
index 8f5f513..3e9b584 100644
--- a/tamer/src/obj/xmlo/reader.rs
+++ b/tamer/src/obj/xmlo/reader.rs
@@ -117,6 +117,7 @@ qname_const! {
QN_UUROOTPATH: :L_UUROOTPATH,
QN_VIRTUAL: :L_VIRTUAL,
QN_YIELDS: :L_YIELDS,
+ QN_FROM: L_PREPROC:L_FROM,
}
pub trait XmloSymtableState =
@@ -205,6 +206,8 @@ pub enum SymtableState {
Ready,
/// Processing a symbol.
Sym(Span, Option<SymbolId>, SymAttrs),
+ /// Awaiting a symbol map name.
+ SymMapFrom(Span, SymbolId, SymAttrs, Span),
}
impl parse::Object for (SymbolId, SymAttrs, Span) {}
@@ -243,6 +246,37 @@ impl ParseState for SymtableState {
) => Self::parse_sym_attr(&mut attrs, key, value, span_attrval)
.transition(Sym(span_sym, name, attrs)),
+ // `preproc:from` supported only for `type="map"`.
+ // TODO: The compiler really ought to just make this an
+ // attribute now so we can simplify parsing here.
+ (
+ Sym(span_sym, Some(name), attrs),
+ Xirf::Open(QN_FROM, span_from, _),
+ ) if attrs.ty == Some(SymType::Map) => {
+ Transition(SymMapFrom(span_sym, name, attrs, span_from))
+ .incomplete()
+ }
+
+ (
+ SymMapFrom(span_sym, name, mut attrs, span_from),
+ Xirf::Attr(Attr(QN_NAME, from_name, _)),
+ ) => match attrs.from.replace(from_name) {
+ Some(_) => Err(XmloError::MapFromMultiple(name, span_from)),
+ None => Ok(()),
+ }
+ .transition(SymMapFrom(span_sym, name, attrs, span_from)),
+
+ (SymMapFrom(span_sym, name, attrs, span_from), Xirf::Close(..)) => {
+ if attrs.from.is_none() {
+ return Transition(SymMapFrom(
+ span_sym, name, attrs, span_from,
+ ))
+ .err(XmloError::MapFromNameMissing(name, span_from));
+ }
+
+ Transition(Sym(span_sym, Some(name), attrs)).incomplete()
+ }
+
todo => todo!("{todo:?}"),
}
}
diff --git a/tamer/src/obj/xmlo/reader/quickxml.rs b/tamer/src/obj/xmlo/reader/quickxml.rs
index e01741b..b9bf905 100644
--- a/tamer/src/obj/xmlo/reader/quickxml.rs
+++ b/tamer/src/obj/xmlo/reader/quickxml.rs
@@ -231,12 +231,13 @@ where
let mut event = Self::process_sym(&self.pkg_name, &ele)?;
match &mut event {
- XmloEvent::SymDecl(_, attrs, _)
+ XmloEvent::SymDecl(name, attrs, _)
if attrs.ty == Some(SymType::Map) =>
{
attrs.from = Self::process_map_from(
&mut self.reader,
&mut self.sub_buffer,
+ *name,
)?;
Ok(event)
@@ -432,6 +433,7 @@ where
fn process_map_from<'a>(
reader: &mut XmlReader<B>,
buffer: &mut Vec<u8>,
+ name: SymbolId,
) -> XmloResult<Option<SymbolId>> {
let mut from = None;
@@ -441,9 +443,9 @@ where
if from.is_some() {
// This feature isn't actually utilized for the
// input map.
- return Err(XmloError::InvalidMapFrom(
- "multiple preproc:from found for input map entry"
- .into(),
+ return Err(XmloError::MapFromMultiple(
+ name,
+ UNKNOWN_SPAN,
));
}
@@ -453,8 +455,9 @@ where
.filter_map(Result::ok)
.find(|attr| attr.key == b"name")
.map_or(
- Err(XmloError::InvalidMapFrom(
- "preproc:from/@name missing".into(),
+ Err(XmloError::MapFromNameMissing(
+ name,
+ UNKNOWN_SPAN,
)),
|attr| {
Ok(unsafe {
@@ -470,7 +473,7 @@ where
// Note that whitespace counts as text
XmlEvent::Text(_) => (),
- _ => Err(XmloError::InvalidMapFrom("unexpected data".into()))?,
+ _ => todo!("unexpected preproc:sym[type=\"map\"] input"),
};
}
diff --git a/tamer/src/obj/xmlo/reader/quickxml/test.rs b/tamer/src/obj/xmlo/reader/quickxml/test.rs
index 6810af5..145bb44 100644
--- a/tamer/src/obj/xmlo/reader/quickxml/test.rs
+++ b/tamer/src/obj/xmlo/reader/quickxml/test.rs
@@ -463,6 +463,7 @@ xmlo_tests! {
assert_eq!(Some("preproc:sym".into()), sut.reader.read_to_end_name);
}
+ // DONE
// `map` symbols include information about their source
// fields.
fn sym_map_from(sut) {
@@ -525,6 +526,7 @@ xmlo_tests! {
assert_eq!(None, sut.reader.read_to_end_name);
}
+ // DONE
fn sym_map_from_missing_name(sut) {
sut.reader.next_event = Some(Box::new(|_, event_i| match event_i {
// Notice Start, not Empty
@@ -555,44 +557,10 @@ xmlo_tests! {
)),
}));
- match sut.read_event() {
- Err(XmloError::InvalidMapFrom(msg)) => {
- assert!(msg.contains("preproc:from"))
- }
- bad => panic!("expected XmloError: {:?}", bad),
- }
- }
-
- fn sym_map_from_unexpected_data(sut) {
- sut.reader.next_event = Some(Box::new(|_, event_i| match event_i {
- // Notice Start, not Empty
- 0 => Ok(XmlEvent::Start(MockBytesStart::new(
- b"preproc:sym",
- Some(MockAttributes::new(vec![
- MockAttribute::new(
- b"name", b"sym-map-from-bad",
- ),
- MockAttribute::new(
- b"type", b"map",
- ),
- ])),
- ))),
-
- // garbage
- 1 => Ok(XmlEvent::Empty(MockBytesStart::new(
- b"preproc:nonsense",
- Some(MockAttributes::new(vec![])),
- ))),
-
- _ => Err(InnerXmlError::UnexpectedEof(
- format!("MockXmlReader out of events: {}", event_i).into(),
- )),
- }));
-
- match sut.read_event() {
- Err(XmloError::InvalidMapFrom(_)) => (),
- bad => panic!("expected XmloError: {:?}", bad),
- }
+ assert_eq!(
+ sut.read_event(),
+ Err(XmloError::MapFromNameMissing("sym-map-from-bad".into(), UNKNOWN_SPAN))
+ );
}
fn read_events_via_iterator(sut) {
diff --git a/tamer/src/obj/xmlo/reader/test.rs b/tamer/src/obj/xmlo/reader/test.rs
index 83b8458..e2269ec 100644
--- a/tamer/src/obj/xmlo/reader/test.rs
+++ b/tamer/src/obj/xmlo/reader/test.rs
@@ -23,7 +23,7 @@ use super::*;
use crate::{
convert::ExpectInto,
obj::xmlo::{SymDtype, SymType},
- parse::{ParseError, ParseState, Parsed},
+ parse::{ParseError, ParseState, ParseStatus, Parsed},
span::{Span, DUMMY_SPAN},
sym::GlobalSymbolIntern,
xir::{
@@ -416,3 +416,97 @@ fn symtable_sym_generated_true() {
SymtableState::parse(toks).collect(),
);
}
+
+// `map` symbols include information about their source
+// fields.
+#[test]
+fn symtable_map_from() {
+ let name = "sym-map-from".into();
+ let map_from = "from-a".into();
+
+ let toks = [
+ Xirf::Open(QN_SYM, SSYM, Depth(0)),
+ Xirf::Attr(Attr(QN_NAME, name, (S2, S3))),
+ Xirf::Attr(Attr(QN_TYPE, raw::L_MAP, (S3, S4))),
+ // <preproc:from>
+ Xirf::Open(QN_FROM, S2, Depth(1)),
+ Xirf::Attr(Attr(QN_NAME, map_from, (S2, S3))),
+ Xirf::Close(None, S4, Depth(1)),
+ // />
+ Xirf::Close(Some(QN_SYM), S2, Depth(0)),
+ ]
+ .into_iter();
+
+ let expected = SymAttrs {
+ ty: Some(SymType::Map),
+ from: Some(map_from),
+ ..Default::default()
+ };
+
+ assert_eq!(
+ Ok(vec![
+ Parsed::Incomplete, // Opening tag
+ Parsed::Incomplete, // @name
+ Parsed::Incomplete, // @type
+ Parsed::Incomplete, // <preproc:from
+ Parsed::Incomplete, // @name
+ Parsed::Incomplete, // />
+ Parsed::Object((name, expected, SSYM)),
+ ]),
+ SymtableState::parse(toks).collect(),
+ );
+}
+
+#[test]
+fn symtable_map_from_missing_name() {
+ let name = "sym-map-from-missing".into();
+
+ let toks = [
+ Xirf::Open(QN_SYM, SSYM, Depth(0)),
+ Xirf::Attr(Attr(QN_NAME, name, (S2, S3))),
+ Xirf::Attr(Attr(QN_TYPE, raw::L_MAP, (S3, S4))),
+ // <preproc:from>
+ Xirf::Open(QN_FROM, S2, Depth(1)),
+ // @name missing
+ Xirf::Close(None, S4, Depth(1)),
+ // />
+ Xirf::Close(Some(QN_SYM), S2, Depth(0)),
+ ]
+ .into_iter();
+
+ assert_eq!(
+ Err(ParseError::StateError(XmloError::MapFromNameMissing(name, S2))), // />
+ SymtableState::parse(toks)
+ .collect::<Result<Vec<Parsed<<SymtableState as ParseState>::Object>>, _>>(),
+ );
+}
+
+// Multiple `from` nodes used to be a thing but are no longer utilized.
+#[test]
+fn symtable_map_from_multiple() {
+ let name = "sym-map-from-missing".into();
+
+ let toks = [
+ Xirf::Open(QN_SYM, SSYM, Depth(0)),
+ Xirf::Attr(Attr(QN_NAME, name, (S2, S3))),
+ Xirf::Attr(Attr(QN_TYPE, raw::L_MAP, (S3, S4))),
+ // <preproc:from>
+ Xirf::Open(QN_FROM, S2, Depth(1)),
+ Xirf::Attr(Attr(QN_NAME, "ok".into(), (S2, S3))),
+ Xirf::Close(None, S4, Depth(1)),
+ // />
+ // <preproc:from> again (err)
+ Xirf::Open(QN_FROM, S3, Depth(1)),
+ Xirf::Attr(Attr(QN_NAME, "bad".into(), (S2, S3))),
+ Xirf::Close(None, S4, Depth(1)),
+ // />
+ Xirf::Close(Some(QN_SYM), S2, Depth(0)),
+ ]
+ .into_iter();
+
+ assert_eq!(
+ Err(ParseError::StateError(XmloError::MapFromMultiple(name, S3))), // />
+ SymtableState::parse(toks)
+ .collect::<Result<Vec<Parsed<<SymtableState as ParseState>::Object>>, _>>(),
+ );
+}