tamer: parse::state: Superstate support for Token type lifting

What hell have I gotten myself into.

In the end, this wasn't too bad, but the initial batch of errors was really
demotivating; the diff does this no justice.  `Lookahead::into_super` was
created to help tame those errors.

...now I can move forward.  Imagine my disappointment when I ran into this
when expecting from previous work that superstates would now work properly
for the AirAggregate parsers.

(The reason this was needed is because AirAggregate splits tokens into
subtypes for child parsers.)

DEV-13708
main
Mike Gerwitz 2023-03-29 15:47:12 -04:00
parent 68e2d5d10e
commit c59b92370c
2 changed files with 36 additions and 19 deletions

View File

@ -129,7 +129,7 @@ where
Self::Error: Into<<Self::Super as ParseState>::Error>,
{
/// Input tokens to the parser.
type Token: Token;
type Token: Token + Into<<Self::Super as ParseState>::Token>;
/// Objects produced by a parser utilizing these states.
type Object: Object;
@ -156,11 +156,8 @@ where
/// This is the same concept as [`StitchableParseState`],
/// but operating in reverse
/// (delegation via trampoline instead of direct function call).
type Super: ClosedParseState<
Token = Self::Token,
Object = Self::Object,
Context = Self::Context,
> = Self;
type Super: ClosedParseState<Object = Self::Object, Context = Self::Context> =
Self;
/// Object provided to parser alongside each token.
///
@ -359,7 +356,7 @@ where
mut context: C,
dead: impl FnOnce(
Self::Super,
Self::Token,
<Self::Super as ParseState>::Token,
C,
) -> TransitionResult<Self::Super>,
) -> TransitionResult<Self::Super>
@ -460,7 +457,7 @@ where
into(newst, Some(obj), env),
TransitionData::Result(
Ok(Incomplete),
lookahead.map(Lookahead::inner_into),
lookahead.map(Lookahead::into_super::<SP>),
),
)
}
@ -472,7 +469,7 @@ where
Ok(_) => Ok(Incomplete),
Err(e) => Err(e.into()),
},
lookahead.map(Lookahead::inner_into),
lookahead.map(Lookahead::into_super::<SP>),
),
),
}
@ -511,7 +508,8 @@ pub trait StitchableParseState<SP: ParseState> =
pub trait PartiallyStitchableParseState<SP: ParseState> = ClosedParseState
where
<SP as ParseState>::Token: From<<Self as ParseState>::Token>,
<<SP as ParseState>::Super as ParseState>::Token:
From<<<Self as ParseState>::Super as ParseState>::Token>,
<Self as ParseState>::Error: Into<<SP as ParseState>::Error>;
pub mod context {

View File

@ -206,13 +206,13 @@ impl<S: ParseState> TransitionResult<S> {
S: PartiallyStitchableParseState<SB>,
{
self.branch_dead_la(
|st, Lookahead(la), bctx| {
|st, la, bctx| {
fdead(st, bctx)
.with_lookahead(<SB as ParseState>::Token::from(la))
.maybe_with_lookahead(Some(la.into_super::<SB>()))
},
|st, result, la, bctx| {
falive(st, result, bctx)
.maybe_with_lookahead(la.map(Lookahead::inner_into))
.maybe_with_lookahead(la.map(Lookahead::into_super::<SB>))
},
bctx,
)
@ -294,6 +294,22 @@ impl<T: Token> Lookahead<T> {
Self(tok) => Lookahead(tok.into()),
}
}
/// Convert the inner [`Token`] of lookahead into the token expected by
/// the superstate [`S::Super`](ParseState::Super).
///
/// This simply sets strict trait bounds to serve as a checkpoint where
/// we know for certain what types are involved;
/// there's a whole lot of types involved in the parsing framework
/// and it gets very difficult to understand when errors occur.
pub fn into_super<S: ParseState>(
self,
) -> Lookahead<<S::Super as ParseState>::Token>
where
T: Into<<S::Super as ParseState>::Token>,
{
self.inner_into::<<S::Super as ParseState>::Token>()
}
}
/// Information about the state transition.
@ -340,9 +356,9 @@ impl<S: ParseState> TransitionData<S> {
match self {
Self::Result(st_result, ola) => TransitionData::Result(
st_result.map(ParseStatus::into_super).map_err(|e| e.into()),
ola,
ola.map(Lookahead::inner_into),
),
Self::Dead(la) => TransitionData::Dead(la),
Self::Dead(la) => TransitionData::Dead(la.inner_into()),
}
}
@ -438,7 +454,7 @@ impl<S: ParseState> TransitionData<S> {
use TransitionData::*;
match self {
Dead(la) => Dead(la.inner_into()),
Dead(la) => Dead(la.into_super::<SB>()),
Result(result, la) => Result(
match result {
Ok(status) => Ok(status.inner_into()),
@ -447,7 +463,7 @@ impl<S: ParseState> TransitionData<S> {
// (which will be the same type if SB is closed).
Err(e) => Err(e.into().into()),
},
la.map(Lookahead::inner_into),
la.map(Lookahead::into_super::<SB>),
),
}
}
@ -567,10 +583,13 @@ impl<S: ParseState> Transition<S> {
/// object first,
/// use [`Transition::result`] or other methods along with a token
/// of [`Lookahead`].
pub fn dead(self, tok: S::Token) -> TransitionResult<S::Super> {
pub fn dead<T: Token + Into<<S::Super as ParseState>::Token>>(
self,
tok: T,
) -> TransitionResult<S::Super> {
TransitionResult(
self.into_super(),
TransitionData::Dead(Lookahead(tok)),
TransitionData::Dead(Lookahead(tok).into_super::<S>()),
)
}