diff options
author | Mike Gerwitz <mike.gerwitz@ryansg.com> | 2022-03-30 12:06:38 -0400 |
---|---|---|
committer | Mike Gerwitz <mike.gerwitz@ryansg.com> | 2022-03-30 12:06:38 -0400 |
commit | 3f8e397e57acd72483a82216698fee2fc1601779 (patch) | |
tree | de13a321775b05bbc3394cdd05bd5d5129c20c84 /tamer | |
parent | 9b429b6fc3a28789c7b2a8860b475ec0be97f3a7 (diff) | |
download | tame-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.rs | 21 | ||||
-rw-r--r-- | tamer/src/obj/xmlo/reader.rs | 34 | ||||
-rw-r--r-- | tamer/src/obj/xmlo/reader/quickxml.rs | 17 | ||||
-rw-r--r-- | tamer/src/obj/xmlo/reader/quickxml/test.rs | 44 | ||||
-rw-r--r-- | tamer/src/obj/xmlo/reader/test.rs | 96 |
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>>, _>>(), + ); +} |