tamer: parse::util::expand: Delete module
Oh, boy, I had forgotten about this, until I started working on some SuperState stuff and discovered this again due to a compiler error. Don't want to fix something that isn't used. But this does not bring back great memories. It's unfortunate that it didn't work out; I'm pretty sure this was part of ~1mo of wasted effort going down a path that I ultimately had to abort. Not good times. I'm still behind from it. DEV-13708main
parent
15fd2de437
commit
68e2d5d10e
|
@ -257,42 +257,6 @@ impl<S: ParseState> TransitionResult<S> {
|
|||
Result(result, la) => falive(st, result, la, bctx),
|
||||
}
|
||||
}
|
||||
|
||||
/// Conditionally map to a [`TransitionResult`] based on whether the
|
||||
/// inner [`TransitionData`] represents an object.
|
||||
pub(in super::super) fn branch_obj_la<SB: ParseState>(
|
||||
self,
|
||||
fobj: impl FnOnce(
|
||||
Transition<S>,
|
||||
<S as ParseState>::Object,
|
||||
Option<Lookahead<<S as ParseState>::Token>>,
|
||||
) -> TransitionResult<<SB as ParseState>::Super>,
|
||||
fother: impl FnOnce(Transition<S>) -> Transition<SB>,
|
||||
) -> TransitionResult<<SB as ParseState>::Super>
|
||||
where
|
||||
S: PartiallyStitchableParseState<SB>,
|
||||
{
|
||||
use ParseStatus::{Incomplete, Object};
|
||||
use TransitionData::{Dead, Result};
|
||||
|
||||
let Self(st, data) = self;
|
||||
|
||||
match data {
|
||||
Result(Ok(Object(obj)), la) => fobj(st, obj, la).into_super(),
|
||||
|
||||
// Can't use `TransitionData::inner_into` since we only have a
|
||||
// `PartiallyStitchableParseState`,
|
||||
// and `into_inner` requires being able to convert the inner
|
||||
// object that we handled above.
|
||||
Result(Ok(Incomplete), la) => fother(st)
|
||||
.incomplete()
|
||||
.maybe_with_lookahead(la.map(Lookahead::inner_into)),
|
||||
Result(Err(e), la) => fother(st)
|
||||
.err(e)
|
||||
.maybe_with_lookahead(la.map(Lookahead::inner_into)),
|
||||
Dead(Lookahead(la)) => fother(st).dead(la.into()),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Token to use as a lookahead token in place of the next token from the
|
||||
|
|
|
@ -25,8 +25,6 @@
|
|||
//! they provide wrappers around core functionality that make it easier
|
||||
//! to use outside of the domain of the parsing system itself.
|
||||
|
||||
pub mod expand;
|
||||
|
||||
use super::{prelude::*, state::TransitionData};
|
||||
use crate::{f::Functor, span::Span, sym::SymbolId};
|
||||
use std::fmt::Display;
|
||||
|
|
|
@ -1,145 +0,0 @@
|
|||
// TAMER parsing framework utilities for token expansion
|
||||
//
|
||||
// Copyright (C) 2014-2023 Ryan Specialty, LLC.
|
||||
//
|
||||
// This file is part of TAME.
|
||||
//
|
||||
// This program is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
//
|
||||
// This program is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
//! Token expansion utilities.
|
||||
//!
|
||||
//! _Expansion_ refers to the production of many [`Object`]s that are
|
||||
//! derived from a single [`Token`].
|
||||
//! An [`ExpandableParseState`] is a [`ClosedParseState`] that,
|
||||
//! provided a [`Token`],
|
||||
//! produces an [`Expansion`] of zero or more [`Expansion::Expanded`]
|
||||
//! [`Object`]s before terminating with a [`Expansion::DoneExpanding`]
|
||||
//! [`Token`] intended to replace the originally provided [`Token`].
|
||||
//!
|
||||
//! An [`ExpandableParseState`] can be stitched with a parent parser using
|
||||
//! [`StitchExpansion`],
|
||||
//! giving the perception of expanding into that parent's token stream.
|
||||
|
||||
use super::super::{prelude::*, state::Lookahead};
|
||||
use crate::{
|
||||
diagnose::{panic::DiagnosticOptionPanic, Annotate},
|
||||
parse::state::PartiallyStitchableParseState,
|
||||
};
|
||||
|
||||
/// Represents an expansion operation on some source token of type `T`.
|
||||
///
|
||||
/// See variants and [`ExpandableParseState`] for more information.
|
||||
#[derive(Debug, PartialEq, Eq)]
|
||||
pub enum Expansion<T, O: Object> {
|
||||
/// A token of type `O` has been derived from the source token and
|
||||
/// should be merged into the target token stream.
|
||||
Expanded(O),
|
||||
|
||||
/// Expansion is complete and the source token should be replaced with
|
||||
/// the inner `T`.
|
||||
///
|
||||
/// Since the expectation is that the parser has completed parsing and
|
||||
/// no longer requires the token provided to it,
|
||||
/// the parser yielding this variant _must not_ yield a token of
|
||||
/// lookahead,
|
||||
/// otherwise the system assume that the parser has an
|
||||
/// implementation defect (bug) and will be forced to panic rather
|
||||
/// than discard it.
|
||||
DoneExpanding(T),
|
||||
}
|
||||
|
||||
impl<T: Token, O: Object> Object for Expansion<T, O> {}
|
||||
|
||||
/// A [`ClosedParseState`] that is able to serve as an expansion parser.
|
||||
///
|
||||
/// An expansion parser is a parser yielding [`Expansion`],
|
||||
/// intended to be integrated into another token stream.
|
||||
pub trait ExpandableParseState<O: Object> = ClosedParseState
|
||||
where
|
||||
O: Token + Eq,
|
||||
Self: ParseState<Object = Expansion<<Self as ParseState>::Token, O>>;
|
||||
|
||||
/// An [`ExpandableParseState`] capable of expanding into the token stream
|
||||
/// of a parent [`ParseState`] `SP`.
|
||||
pub trait ExpandableInto<SP: ParseState> =
|
||||
ExpandableParseState<<SP as ParseState>::Object>
|
||||
where
|
||||
Self: ExpandableParseState<<SP as ParseState>::Object>
|
||||
+ PartiallyStitchableParseState<SP>;
|
||||
|
||||
/// [`ExpandableParseState`] state stitching.
|
||||
///
|
||||
/// See [`Self::stitch_expansion`] for more information.
|
||||
pub trait StitchExpansion: ClosedParseState {
|
||||
/// Stitch a [`ExpandableParseState`] that is
|
||||
/// [`ExpandableInto<SP>`](ExpandableInto).
|
||||
///
|
||||
/// This combines the state machine of an [`ExpandableParseState`],
|
||||
/// allowing that parser to expand into the token stream of [`Self`].
|
||||
///
|
||||
/// Panics
|
||||
/// ======
|
||||
/// This will panic with diagnostic information if a token of lookahead
|
||||
/// is provided with a [`Expansion::DoneExpanding`] variant.
|
||||
/// See that variant for more information.
|
||||
fn stitch_expansion<SP: ParseState, C>(
|
||||
self,
|
||||
tok: <Self as ParseState>::Token,
|
||||
mut ctx: C,
|
||||
into: impl Fn(Transition<Self>) -> Transition<SP>,
|
||||
done: impl FnOnce(
|
||||
Transition<Self>,
|
||||
<SP as ParseState>::Token,
|
||||
) -> TransitionResult<SP>,
|
||||
) -> TransitionResult<<SP as ParseState>::Super>
|
||||
where
|
||||
Self: ExpandableInto<SP>,
|
||||
C: AsMut<<Self as ParseState>::Context>,
|
||||
{
|
||||
use Expansion::{DoneExpanding, Expanded};
|
||||
|
||||
self.parse_token(tok, ctx.as_mut()).branch_obj_la(
|
||||
|st, obj, la| match (obj, la) {
|
||||
(Expanded(obj), la) => into(st)
|
||||
.ok(obj)
|
||||
.maybe_with_lookahead(la.map(Lookahead::inner_into)),
|
||||
|
||||
(DoneExpanding(tok), la) => {
|
||||
// Uphold parser lookahead invariant.
|
||||
la.diagnostic_expect_none(
|
||||
|Lookahead(la_tok)| {
|
||||
vec![
|
||||
la_tok.span().note(
|
||||
"this token of lookahead would be lost",
|
||||
),
|
||||
tok.span().internal_error(
|
||||
"unexpected token of lookahead while \
|
||||
completing expansion of this token",
|
||||
),
|
||||
]
|
||||
},
|
||||
"cannot provide lookahead token with \
|
||||
Expansion::DoneExpanding",
|
||||
);
|
||||
|
||||
done(st, tok.into()).into_super()
|
||||
}
|
||||
},
|
||||
&into,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
pub mod test;
|
|
@ -1,258 +0,0 @@
|
|||
// Tests for TAMER parsing framework utilities
|
||||
//
|
||||
// Copyright (C) 2014-2023 Ryan Specialty, LLC.
|
||||
//
|
||||
// This file is part of TAME.
|
||||
//
|
||||
// This program is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
//
|
||||
// This program is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
use super::super::SPair;
|
||||
use super::*;
|
||||
use crate::{
|
||||
span::{dummy::*, Span},
|
||||
sym::{st::raw, SymbolId},
|
||||
};
|
||||
use std::{
|
||||
assert_matches::assert_matches, convert::Infallible, fmt::Display,
|
||||
marker::PhantomData,
|
||||
};
|
||||
|
||||
#[derive(Debug, PartialEq, Eq)]
|
||||
pub struct StitchableExpansionState<S: ClosedParseState, O: Object> {
|
||||
st: S,
|
||||
_phantom: PhantomData<O>,
|
||||
}
|
||||
|
||||
impl<S: ClosedParseState, O: Object> Default for StitchableExpansionState<S, O>
|
||||
where
|
||||
S: Default,
|
||||
{
|
||||
fn default() -> Self {
|
||||
Self {
|
||||
st: Default::default(),
|
||||
_phantom: Default::default(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<S: ClosedParseState, O: Object> ParseState
|
||||
for StitchableExpansionState<S, O>
|
||||
where
|
||||
S: ExpandableParseState<O> + StitchExpansion,
|
||||
<S as ParseState>::Context: AsMut<<S as ParseState>::Context>,
|
||||
{
|
||||
type Token = S::Token;
|
||||
type Object = O;
|
||||
type Error = S::Error;
|
||||
type Context = S::Context;
|
||||
|
||||
#[inline]
|
||||
fn parse_token(
|
||||
self,
|
||||
tok: Self::Token,
|
||||
ctx: &mut Self::Context,
|
||||
) -> TransitionResult<Self::Super> {
|
||||
let Self { st, _phantom } = self;
|
||||
|
||||
st.stitch_expansion(
|
||||
tok,
|
||||
ctx,
|
||||
Transition::fmap(|st| Self { st, _phantom }),
|
||||
|Transition(st), tok| Transition(Self { st, _phantom }).dead(tok),
|
||||
)
|
||||
}
|
||||
|
||||
fn is_accepting(&self, ctx: &Self::Context) -> bool {
|
||||
self.st.is_accepting(ctx)
|
||||
}
|
||||
}
|
||||
|
||||
impl<S: ClosedParseState, O: Object> Display
|
||||
for StitchableExpansionState<S, O>
|
||||
{
|
||||
fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
|
||||
match self {
|
||||
Self {
|
||||
st: parser,
|
||||
_phantom,
|
||||
} => {
|
||||
write!(f, "{parser}, with Expansion stripped")
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, PartialEq, Eq)]
|
||||
struct TestObject(SPair);
|
||||
|
||||
impl Token for TestObject {
|
||||
fn ir_name() -> &'static str {
|
||||
"TestObject"
|
||||
}
|
||||
|
||||
fn span(&self) -> Span {
|
||||
match self {
|
||||
Self(SPair(_, span)) => *span,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Display for TestObject {
|
||||
fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
|
||||
match self {
|
||||
Self(spair) => Display::fmt(spair, f),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Object for TestObject {}
|
||||
|
||||
/// Just some parser to wrap for our tests.
|
||||
///
|
||||
/// Eventually we'll be able to more easily create these on-demand without so
|
||||
/// so much boilerplate,
|
||||
/// but that hasn't evolved yet.
|
||||
#[derive(Debug, PartialEq, Eq, Default)]
|
||||
struct TestParseState;
|
||||
|
||||
impl ParseState for TestParseState {
|
||||
type Token = SPair;
|
||||
type Object = Expansion<Self::Token, TestObject>;
|
||||
type Error = Infallible;
|
||||
|
||||
fn parse_token(
|
||||
self,
|
||||
tok: Self::Token,
|
||||
_ctx: &mut Self::Context,
|
||||
) -> TransitionResult<Self::Super> {
|
||||
match tok {
|
||||
tok @ SPair(sym @ (STOP | DEAD_SYM), span) => {
|
||||
let st = Transition(self).ok(Expansion::DoneExpanding(tok));
|
||||
|
||||
st.maybe_with_lookahead(if sym == DEAD_SYM {
|
||||
// It doesn't matter what this token is for our tests.
|
||||
Some(Lookahead(SPair(sym, span)))
|
||||
} else {
|
||||
None
|
||||
})
|
||||
}
|
||||
_ => Transition(self).ok(Expansion::Expanded(TestObject(tok))),
|
||||
}
|
||||
}
|
||||
|
||||
fn is_accepting(&self, _ctx: &Self::Context) -> bool {
|
||||
true
|
||||
}
|
||||
}
|
||||
|
||||
impl Display for TestParseState {
|
||||
fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
|
||||
write!(f, "doing its thing") // well, it is
|
||||
}
|
||||
}
|
||||
|
||||
impl StitchExpansion for TestParseState {}
|
||||
|
||||
const STOP: SymbolId = raw::L_YIELD;
|
||||
const DEAD_SYM: SymbolId = raw::L_WARNING;
|
||||
|
||||
type ExpansionSut = StitchableExpansionState<TestParseState, TestObject>;
|
||||
|
||||
#[test]
|
||||
fn expansion_can_be_stripped_for_stitching() {
|
||||
let syma = "foo".into();
|
||||
let symb = "bar".into();
|
||||
|
||||
let toks = vec![SPair(syma, S1), SPair(symb, S2), SPair(STOP, S3)];
|
||||
|
||||
// The wraps the above TestParseState to strip Expansion.
|
||||
let mut sut = ExpansionSut::parse(toks.into_iter());
|
||||
|
||||
// Our test parser echoes back the tokens wrapped in an "expanded"
|
||||
// `TestObject` until we reach `STOP`.
|
||||
// The first two are expanded,
|
||||
// and our SUT strips the expansion.
|
||||
assert_eq!(
|
||||
sut.next(),
|
||||
Some(Ok(Parsed::Object(TestObject(SPair(syma, S1))))),
|
||||
);
|
||||
assert_eq!(
|
||||
sut.next(),
|
||||
Some(Ok(Parsed::Object(TestObject(SPair(symb, S2))))),
|
||||
);
|
||||
|
||||
// The final `Expansion::DoneExpanding` is converted into a dead state
|
||||
// transition.
|
||||
// That manifests here as an `UnexpectedToken` error because nothing
|
||||
// handled it within our parser,
|
||||
// but this is expected to stitched via delegation,
|
||||
// which _would_ handle this case.
|
||||
assert_matches!(
|
||||
sut.next(),
|
||||
Some(Err(ParseError::UnexpectedToken(dead_tok, _)))
|
||||
if dead_tok == SPair(STOP, S3)
|
||||
);
|
||||
}
|
||||
|
||||
// We must not lose lookahead tokens;
|
||||
// see SUT for more information.
|
||||
#[should_panic]
|
||||
#[test]
|
||||
fn expansion_stripping_panics_if_lookahead() {
|
||||
let toks = vec![SPair(DEAD_SYM, S1)];
|
||||
|
||||
// The above token will trigger the panic on the first call.
|
||||
let _ = ExpansionSut::parse(toks.into_iter()).next();
|
||||
}
|
||||
|
||||
// This test would fail at compile-time.
|
||||
#[test]
|
||||
fn expandable_into_is_stitchable_with_target() {
|
||||
// This is utilized only for its types in the below assertions.
|
||||
#[derive(Debug, PartialEq, Eq)]
|
||||
struct TargetParseState;
|
||||
|
||||
impl ParseState for TargetParseState {
|
||||
type Token = SPair;
|
||||
type Object = TestObject;
|
||||
type Error = Infallible;
|
||||
|
||||
fn parse_token(
|
||||
self,
|
||||
_tok: Self::Token,
|
||||
_ctx: &mut Self::Context,
|
||||
) -> TransitionResult<Self::Super> {
|
||||
unimplemented!()
|
||||
}
|
||||
|
||||
fn is_accepting(&self, _ctx: &Self::Context) -> bool {
|
||||
unimplemented!()
|
||||
}
|
||||
}
|
||||
|
||||
impl Display for TargetParseState {
|
||||
fn fmt(&self, _f: &mut std::fmt::Formatter) -> std::fmt::Result {
|
||||
unimplemented!()
|
||||
}
|
||||
}
|
||||
|
||||
// The `ExpandableInto` trait alias is responsible for asserting that a
|
||||
// given parser is an expansion parser that is able to be converted
|
||||
// into a parser stitchable with the target.
|
||||
//
|
||||
// If this fails but the above assertion succeeds,
|
||||
// then the compatibility is working but something is wrong with the
|
||||
// definition of `ExpandableInto`.
|
||||
assert_impl_all!(TestParseState: ExpandableInto<TargetParseState>);
|
||||
}
|
Loading…
Reference in New Issue