tamer: parse::state: EchoState and TransitionResult constituent primitives
This beings to introduce more primitive operations to `TransitionResult` and its components so that I can actually work with them without having to write a bunch of concrete, boilerplate implementations. This is demonstrated in part by `EchoState` (which is nearly all boilerplate, but whose correctness should be verifiable at a glance), which will be used going forward as a basis for default implementations for parsers (e.g. expansion delegation). DEV-13156main
parent
55c55cabd3
commit
fc425ff1d5
|
@ -54,6 +54,20 @@ impl<S: ParseState> ParseStatus<S> {
|
|||
Self::Object(obj) => ParseStatus::Object(obj),
|
||||
}
|
||||
}
|
||||
|
||||
/// Asserts a reflexive relationship between the [`ParseStatus`]es of
|
||||
/// of `S` and `SB`.
|
||||
pub fn reflexivity<SB: ParseState>(self) -> ParseStatus<SB>
|
||||
where
|
||||
SB: ParseState<Object = <S as ParseState>::Object>,
|
||||
{
|
||||
use ParseStatus::*;
|
||||
|
||||
match self {
|
||||
Incomplete => Incomplete,
|
||||
Object(obj) => Object(obj),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<S: ParseState<Object = T>, T: Object> From<T> for ParseStatus<S> {
|
||||
|
|
|
@ -116,6 +116,30 @@ impl<S: ParseState> TransitionResult<S> {
|
|||
None => self,
|
||||
}
|
||||
}
|
||||
|
||||
/// Map over both the [`Transition`] and its associated
|
||||
/// [`TransitionData`],
|
||||
/// translating to another [`ParseState`] `SB`.
|
||||
///
|
||||
/// The inner [`Transition`]'s [`ParseState`] is mapped over for
|
||||
/// convenience and brevity,
|
||||
/// despite the verbose convention of mandating the use of
|
||||
/// [`Transition`] elsewhere.
|
||||
/// However,
|
||||
/// [`TransitionData`] is too complex of a structure,
|
||||
/// so determining how to map over its data is left as an exercise
|
||||
/// for `fdata`.
|
||||
pub(in super::super) fn bimap<SB: ParseState>(
|
||||
self,
|
||||
fst: impl FnOnce(S) -> SB,
|
||||
fdata: impl FnOnce(TransitionData<S>) -> TransitionData<SB>,
|
||||
) -> TransitionResult<SB> {
|
||||
match self {
|
||||
Self(Transition(st), data) => {
|
||||
TransitionResult(Transition(fst(st)), fdata(data))
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Token to use as a lookahead token in place of the next token from the
|
||||
|
@ -246,6 +270,42 @@ impl<S: ParseState> TransitionData<S> {
|
|||
TransitionData::Dead(la) => TransitionData::Dead(la),
|
||||
}
|
||||
}
|
||||
|
||||
/// Asserts a reflexive relationship between the [`TransitionData`] of
|
||||
/// our own [`ParseState`] `S` and a target [`ParseState`] `SB`.
|
||||
///
|
||||
/// This is intended not just for translating between types,
|
||||
/// but also documentation,
|
||||
/// as an affirmative way to state "these two [`ParseState`]s
|
||||
/// represent the same underlying data".
|
||||
/// For example,
|
||||
/// this may be appropriate when `SB` wraps `S`.
|
||||
///
|
||||
/// This is a stronger statement than saying two [`ParseState`]s are
|
||||
/// _compatible_ withe one-another in some way,
|
||||
/// which is the assertion made by
|
||||
/// [`StitchableParseState`](super::StitchableParseState) and may
|
||||
/// require data to be translated.
|
||||
///
|
||||
/// While this method refers to the mathematical reflexive relation,
|
||||
/// its exact name originates from the Coq tactic.
|
||||
pub fn reflexivity<SB: ParseState>(self) -> TransitionData<SB>
|
||||
where
|
||||
SB: ParseState<
|
||||
Token = <S as ParseState>::Token,
|
||||
Object = <S as ParseState>::Object,
|
||||
Error = <S as ParseState>::Error,
|
||||
>,
|
||||
{
|
||||
use TransitionData::*;
|
||||
|
||||
match self {
|
||||
Result(result, la) => {
|
||||
Result(result.map(ParseStatus::reflexivity), la)
|
||||
}
|
||||
Dead(la) => Dead(la),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// A verb denoting a state transition.
|
||||
|
@ -362,6 +422,27 @@ impl<S: ParseState> Transition<S> {
|
|||
TransitionData::Dead(Lookahead(tok)),
|
||||
)
|
||||
}
|
||||
|
||||
/// Map over the inner [`ParseState`] `S` to another
|
||||
/// [`ParseState`] `SB`.
|
||||
///
|
||||
/// Unlike other parts of this API which mandate explicit instantiation
|
||||
/// of [`Transition`] for self-documentation,
|
||||
/// this maps over the inner value since [`Transition`] is already
|
||||
/// apparent.
|
||||
/// This is consequently much less verbose,
|
||||
/// as it allows using tuple constructions for `f`,
|
||||
/// and most [`ParseState`]s are implemented as tuples
|
||||
/// (or tuple enums)
|
||||
/// in practice.
|
||||
pub fn map<SB: ParseState>(
|
||||
self,
|
||||
f: impl FnOnce(S) -> SB,
|
||||
) -> Transition<SB> {
|
||||
match self {
|
||||
Self(st) => Transition(f(st)),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<S: ClosedParseState> FromResidual<(Transition<S>, ParseStateResult<S>)>
|
||||
|
|
|
@ -27,7 +27,7 @@
|
|||
|
||||
pub mod expand;
|
||||
|
||||
use super::prelude::*;
|
||||
use super::{prelude::*, state::TransitionData};
|
||||
use crate::{span::Span, sym::SymbolId};
|
||||
use std::fmt::Display;
|
||||
|
||||
|
@ -72,3 +72,39 @@ impl Into<(SymbolId, Span)> for SPair {
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, PartialEq, Eq)]
|
||||
pub struct EchoParseState<S: ClosedParseState>(S);
|
||||
|
||||
impl<S: ClosedParseState> ParseState for EchoParseState<S> {
|
||||
type Token = S::Token;
|
||||
type Object = S::Object;
|
||||
type Error = S::Error;
|
||||
type Context = S::Context;
|
||||
|
||||
fn parse_token(
|
||||
self,
|
||||
tok: Self::Token,
|
||||
ctx: &mut Self::Context,
|
||||
) -> TransitionResult<Self::Super> {
|
||||
match self {
|
||||
Self(st) => st
|
||||
.parse_token(tok, ctx)
|
||||
.bimap(Self, TransitionData::reflexivity),
|
||||
}
|
||||
}
|
||||
|
||||
fn is_accepting(&self, ctx: &Self::Context) -> bool {
|
||||
match self {
|
||||
Self(st) => st.is_accepting(ctx),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<S: ClosedParseState> Display for EchoParseState<S> {
|
||||
fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
|
||||
match self {
|
||||
Self(st) => Display::fmt(st, f),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue