diff --git a/tamer/src/obj/xmlo/reader.rs b/tamer/src/obj/xmlo/reader.rs index 465bed82..0b90de6e 100644 --- a/tamer/src/obj/xmlo/reader.rs +++ b/tamer/src/obj/xmlo/reader.rs @@ -19,7 +19,7 @@ use super::{SymAttrs, XmloError}; use crate::{ - parse::{ParseState, Transition, TransitionResult}, + parse::{self, ParseState, Transition, TransitionResult}, sym::{st::*, SymbolId}, xir::{attr::Attr, flat::Object as Xirf}, }; @@ -87,6 +87,8 @@ pub enum XmloEvent { Eoh, } +impl parse::Object for XmloEvent {} + /// A [`Result`] with a hard-coded [`XmloError`] error type. /// /// This is the result of every [`XmloReader`] operation that could @@ -126,7 +128,7 @@ impl ParseState for XmloReaderState { (Ready, _) => Transition(Ready).err(XmloError::UnexpectedRoot), (Package, Xirf::Attr(Attr(name, value, _))) => { - Transition(Package).with(match name { + Transition(Package).ok(match name { QN_NAME => XmloEvent::PkgName(value), QN_UUROOTPATH => XmloEvent::PkgRootPath(value), QN_PROGRAM => XmloEvent::PkgProgramFlag, diff --git a/tamer/src/parse.rs b/tamer/src/parse.rs index e54740d1..88cdc6bd 100644 --- a/tamer/src/parse.rs +++ b/tamer/src/parse.rs @@ -54,6 +54,16 @@ impl From for Span { } } +/// An IR object produced by a lowering operation on one or more [`Token`]s. +/// +/// Note that an [`Object`] may also be a [`Token`] if it will be in turn +/// fed to another [`Parser`] for lowering. +/// +/// This trait exists to disambiguate an otherwise unbounded type for +/// [`From`] conversions, +/// used in the [`Transition`] API to provide greater flexibility. +pub trait Object: Debug + PartialEq + Eq {} + /// An infallible [`Token`] stream. /// /// If the token stream originates from an operation that could potentially @@ -96,7 +106,7 @@ pub trait ParseState: Default + PartialEq + Eq + Debug { type Token: Token; /// Objects produced by a parser utilizing these states. - type Object: Debug + PartialEq + Eq; + type Object: Object; /// Errors specific to this set of states. type Error: Debug + Error + PartialEq + Eq; @@ -150,10 +160,7 @@ pub trait ParseState: Default + PartialEq + Eq + Debug { /// /// This is used by [`ParseState::parse_token`]; /// see that function for rationale. -pub type ParseStateResult = Result< - ParseStatus<::Token, ::Object>, - ::Error, ->; +pub type ParseStateResult = Result, ::Error>; /// A state transition with associated data. /// @@ -182,8 +189,31 @@ impl Transition { /// /// This allows [`ParseState::parse_token`] to emit a parsed object and /// corresponds to [`ParseStatus::Object`]. - pub fn with(self, obj: S::Object) -> TransitionResult { - TransitionResult(self, Ok(ParseStatus::Object(obj))) + pub fn ok(self, obj: T) -> TransitionResult + where + T: Into>, + { + TransitionResult(self, Ok(obj.into())) + } + + /// A transition with corresponding error. + /// + /// This indicates a parsing failure. + /// The state ought to be suitable for error recovery. + pub fn err>(self, err: E) -> TransitionResult { + TransitionResult(self, Err(err.into())) + } + + /// A state transition with corresponding [`Result`]. + /// + /// This translates the provided [`Result`] in a manner equivalent to + /// [`Transition::ok`] and [`Transition::err`]. + pub fn result(self, result: Result) -> TransitionResult + where + T: Into>, + E: Into, + { + TransitionResult(self, result.map(Into::into).map_err(Into::into)) } /// A state transition indicating that more data is needed before an @@ -202,14 +232,6 @@ impl Transition { pub fn dead(self, tok: S::Token) -> TransitionResult { TransitionResult(self, Ok(ParseStatus::Dead(tok))) } - - /// A transition with corresponding error. - /// - /// This indicates a parsing failure. - /// The state ought to be suitable for error recovery. - pub fn err>(self, err: E) -> TransitionResult { - TransitionResult(self, Err(err.into())) - } } impl Into<(Transition, ParseStateResult)> @@ -583,7 +605,7 @@ impl> From for Parser { /// Result of a parsing operation. #[derive(Debug, PartialEq, Eq)] -pub enum ParseStatus { +pub enum ParseStatus { /// Additional tokens are needed to complete parsing of the next object. Incomplete, @@ -591,7 +613,7 @@ pub enum ParseStatus { /// /// This does not indicate that the parser is complete, /// as more objects may be able to be emitted. - Object(O), + Object(S::Object), /// Parser encountered a dead state relative to the given token. /// @@ -616,7 +638,13 @@ pub enum ParseStatus { /// /// If there is no parent context to handle the token, /// [`Parser`] must yield an error. - Dead(T), + Dead(S::Token), +} + +impl, T: Object> From for ParseStatus { + fn from(obj: T) -> Self { + Self::Object(obj) + } } /// Result of a parsing operation. @@ -636,8 +664,8 @@ pub enum Parsed { Object(O), } -impl From> for Parsed { - fn from(status: ParseStatus) -> Self { +impl From> for Parsed { + fn from(status: ParseStatus) -> Self { match status { ParseStatus::Incomplete => Parsed::Incomplete, ParseStatus::Object(x) => Parsed::Object(x), @@ -677,6 +705,8 @@ pub mod test { } } + impl Object for TestToken {} + #[derive(Debug, PartialEq, Eq)] enum EchoState { Empty, @@ -696,7 +726,7 @@ pub mod test { fn parse_token(self, tok: TestToken) -> TransitionResult { match tok { - TestToken::Comment(..) => Transition(Self::Done).with(tok), + TestToken::Comment(..) => Transition(Self::Done).ok(tok), TestToken::Close(..) => { Transition(self).err(EchoStateError::InnerError(tok)) } diff --git a/tamer/src/xir/attr.rs b/tamer/src/xir/attr.rs index 87d029a1..d4b580e6 100644 --- a/tamer/src/xir/attr.rs +++ b/tamer/src/xir/attr.rs @@ -68,6 +68,8 @@ impl Token for Attr { } } +impl crate::parse::Object for Attr {} + impl Display for Attr { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { write!(f, "`@{}=\"{}\"` at {}", self.0, self.1, self.2 .0) diff --git a/tamer/src/xir/attr/parse.rs b/tamer/src/xir/attr/parse.rs index d35ddf50..65d3b47f 100644 --- a/tamer/src/xir/attr/parse.rs +++ b/tamer/src/xir/attr/parse.rs @@ -58,7 +58,7 @@ impl ParseState for AttrParseState { (Empty, invalid) => Transition(Empty).dead(invalid), (Name(name, nspan), XirToken::AttrValue(value, vspan)) => { - Transition(Empty).with(Attr::new(name, value, (nspan, vspan))) + Transition(Empty).ok(Attr::new(name, value, (nspan, vspan))) } (Name(name, nspan), invalid) => { diff --git a/tamer/src/xir/flat.rs b/tamer/src/xir/flat.rs index c3f4554f..66cfbb95 100644 --- a/tamer/src/xir/flat.rs +++ b/tamer/src/xir/flat.rs @@ -44,7 +44,7 @@ use super::{ }; use crate::{ parse::{ - ParseState, ParseStatus, ParsedResult, Token, Transition, + self, ParseState, ParseStatus, ParsedResult, Token, Transition, TransitionResult, }, span::Span, @@ -131,6 +131,8 @@ impl Token for Object { } } +impl parse::Object for Object {} + impl Display for Object { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { use Object::*; @@ -204,7 +206,7 @@ where match (self, tok) { // Comments are permitted before and after the first root element. (st @ (PreRoot | Done), XirToken::Comment(sym, span)) => { - Transition(st).with(Object::Comment(sym, span)) + Transition(st).ok(Object::Comment(sym, span)) } (PreRoot, tok @ XirToken::Open(..)) => { @@ -224,7 +226,7 @@ where } (Transition(sa), Ok(Obj(attr))) => { Transition(AttrExpected(stack, sa)) - .with(Object::Attr(attr)) + .ok(Object::Attr(attr)) } (_, Ok(Dead(lookahead))) => { Self::parse_node(stack, lookahead) @@ -280,7 +282,7 @@ where stack.push((qname, span)); // Delegate to the attribute parser until it is complete. - Transition(AttrExpected(stack, SA::default())).with(Open( + Transition(AttrExpected(stack, SA::default())).ok(Open( qname, span, Depth(depth), @@ -303,7 +305,7 @@ where } // Final closing tag (for root node) completes the document. - (..) if stack.len() == 0 => Transition(Done).with(Close( + (..) if stack.len() == 0 => Transition(Done).ok(Close( close_oqname, close_span, Depth(0), @@ -312,7 +314,7 @@ where (..) => { let depth = stack.len(); - Transition(NodeExpected(stack)).with(Close( + Transition(NodeExpected(stack)).ok(Close( close_oqname, close_span, Depth(depth), @@ -322,16 +324,16 @@ where } XirToken::Comment(sym, span) => { - Transition(NodeExpected(stack)).with(Comment(sym, span)) + Transition(NodeExpected(stack)).ok(Comment(sym, span)) } XirToken::Text(sym, span) => { - Transition(NodeExpected(stack)).with(Text(sym, span)) + Transition(NodeExpected(stack)).ok(Text(sym, span)) } XirToken::CData(sym, span) => { - Transition(NodeExpected(stack)).with(CData(sym, span)) + Transition(NodeExpected(stack)).ok(CData(sym, span)) } XirToken::Whitespace(ws, span) => { - Transition(NodeExpected(stack)).with(Whitespace(ws, span)) + Transition(NodeExpected(stack)).ok(Whitespace(ws, span)) } // We should transition to `State::Attr` before encountering any diff --git a/tamer/src/xir/tree.rs b/tamer/src/xir/tree.rs index 74150aa7..4a6e6234 100644 --- a/tamer/src/xir/tree.rs +++ b/tamer/src/xir/tree.rs @@ -180,7 +180,7 @@ use super::{ use crate::{ parse::{ - ParseError, ParseResult, ParseState, ParseStatus, ParsedResult, + self, ParseError, ParseResult, ParseState, ParseStatus, ParsedResult, Transition, TransitionResult, }, span::Span, @@ -282,6 +282,8 @@ impl Tree { } } +impl parse::Object for Tree {} + /// Element node. /// /// This represents an [XML element] beginning with an opening tag that is @@ -564,7 +566,7 @@ impl ParseState for Stack { .map(ElementStack::consume_child_or_complete) .map(|new_stack| match new_stack { Stack::ClosedElement(ele) => { - Transition(Empty).with(Tree::Element(ele)) + Transition(Empty).ok(Tree::Element(ele)) } _ => Transition(new_stack).incomplete(), }) @@ -577,7 +579,7 @@ impl ParseState for Stack { .map(ElementStack::consume_child_or_complete) .map(|new_stack| match new_stack { Stack::ClosedElement(ele) => { - Transition(Empty).with(Tree::Element(ele)) + Transition(Empty).ok(Tree::Element(ele)) } _ => Transition(new_stack).incomplete(), })