Mike Gerwitz

Activist for User Freedom

aboutsummaryrefslogtreecommitdiffstats
path: root/tamer
diff options
context:
space:
mode:
authorMike Gerwitz <mike.gerwitz@ryansg.com>2022-03-25 16:45:32 -0400
committerMike Gerwitz <mike.gerwitz@ryansg.com>2022-03-25 16:45:32 -0400
commitf402e51d04969f3b7031d8d3aa63785583806052 (patch)
treeb0d0593497892d89c70d8e8a80407d0cea61e7c8 /tamer
parentc0fa89222e4877ed55f2fa1175758e841ce0df03 (diff)
downloadtame-f402e51d04969f3b7031d8d3aa63785583806052.tar.gz
tame-f402e51d04969f3b7031d8d3aa63785583806052.tar.bz2
tame-f402e51d04969f3b7031d8d3aa63785583806052.zip
tamer: parse: More flexible Transition API
This does some cleanup and adds `parse::Object` for use in disambiguating `From` for `ParseStatus`, allowing the `Transition` API to be much more flexible in the data it accepts and automatically converts. This allows us to concisely provide raw output data to be wrapped, or provide `ParseStatus` directly when more convenient. There aren't yet examples in the docs; I'll do so once I make sure this API is actually utilized as intended. DEV-10863
Diffstat (limited to 'tamer')
-rw-r--r--tamer/src/obj/xmlo/reader.rs6
-rw-r--r--tamer/src/parse.rs72
-rw-r--r--tamer/src/xir/attr.rs2
-rw-r--r--tamer/src/xir/attr/parse.rs2
-rw-r--r--tamer/src/xir/flat.rs22
-rw-r--r--tamer/src/xir/tree.rs8
6 files changed, 75 insertions, 37 deletions
diff --git a/tamer/src/obj/xmlo/reader.rs b/tamer/src/obj/xmlo/reader.rs
index 465bed8..0b90de6 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 e54740d..88cdc6b 100644
--- a/tamer/src/parse.rs
+++ b/tamer/src/parse.rs
@@ -54,6 +54,16 @@ impl<T: Token> From<T> 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<S> = Result<
- ParseStatus<<S as ParseState>::Token, <S as ParseState>::Object>,
- <S as ParseState>::Error,
->;
+pub type ParseStateResult<S> = Result<ParseStatus<S>, <S as ParseState>::Error>;
/// A state transition with associated data.
///
@@ -182,8 +189,31 @@ impl<S: ParseState> Transition<S> {
///
/// This allows [`ParseState::parse_token`] to emit a parsed object and
/// corresponds to [`ParseStatus::Object`].
- pub fn with(self, obj: S::Object) -> TransitionResult<S> {
- TransitionResult(self, Ok(ParseStatus::Object(obj)))
+ pub fn ok<T>(self, obj: T) -> TransitionResult<S>
+ where
+ T: Into<ParseStatus<S>>,
+ {
+ 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<E: Into<S::Error>>(self, err: E) -> TransitionResult<S> {
+ 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<T, E>(self, result: Result<T, E>) -> TransitionResult<S>
+ where
+ T: Into<ParseStatus<S>>,
+ E: Into<S::Error>,
+ {
+ 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<S: ParseState> Transition<S> {
pub fn dead(self, tok: S::Token) -> TransitionResult<S> {
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<E: Into<S::Error>>(self, err: E) -> TransitionResult<S> {
- TransitionResult(self, Err(err.into()))
- }
}
impl<S: ParseState> Into<(Transition<S>, ParseStateResult<S>)>
@@ -583,7 +605,7 @@ impl<S: ParseState, I: TokenStream<S::Token>> From<I> for Parser<S, I> {
/// Result of a parsing operation.
#[derive(Debug, PartialEq, Eq)]
-pub enum ParseStatus<T, O> {
+pub enum ParseStatus<S: ParseState> {
/// Additional tokens are needed to complete parsing of the next object.
Incomplete,
@@ -591,7 +613,7 @@ pub enum ParseStatus<T, O> {
///
/// 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<T, O> {
///
/// If there is no parent context to handle the token,
/// [`Parser`] must yield an error.
- Dead(T),
+ Dead(S::Token),
+}
+
+impl<S: ParseState<Object = T>, T: Object> From<T> for ParseStatus<S> {
+ fn from(obj: T) -> Self {
+ Self::Object(obj)
+ }
}
/// Result of a parsing operation.
@@ -636,8 +664,8 @@ pub enum Parsed<O> {
Object(O),
}
-impl<T: Token, O> From<ParseStatus<T, O>> for Parsed<O> {
- fn from(status: ParseStatus<T, O>) -> Self {
+impl<S: ParseState> From<ParseStatus<S>> for Parsed<S::Object> {
+ fn from(status: ParseStatus<S>) -> 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<Self> {
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 87d029a..d4b580e 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 d35ddf5..65d3b47 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 c3f4554..66cfbb9 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 74150aa..4a6e623 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<SA: StackAttrParseState> ParseState for Stack<SA> {
.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<SA: StackAttrParseState> ParseState for Stack<SA> {
.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(),
})