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-10863main
parent
9b429b6fc3
commit
3f8e397e57
|
@ -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,
|
||||
|
|
|
@ -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:?}"),
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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"),
|
||||
};
|
||||
}
|
||||
|
||||
|
|
|
@ -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) {
|
||||
|
|
|
@ -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>>, _>>(),
|
||||
);
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue