Skip to content

Instantly share code, notes, and snippets.

@appcypher
Last active September 14, 2024 21:58
Show Gist options
  • Save appcypher/eef96ea0a2b35b37abbeeabf67dc3a66 to your computer and use it in GitHub Desktop.
Save appcypher/eef96ea0a2b35b37abbeeabf67dc3a66 to your computer and use it in GitHub Desktop.
Slow Combinator lol
use crate::compiler::reversible::Reversible;
//--------------------------------------------------------------------------------------------------
// Types
//--------------------------------------------------------------------------------------------------
/// The result of a combinator expression.
#[derive(Debug, Clone, PartialEq, Eq)]
pub enum Combinator<T> {
/// A single `T` value.
Single(T),
/// A choice between two combinators.
Choice(Choice<T>),
/// A vector of repeated `T` values.
Many(Vec<Combinator<T>>),
/// A sequence of two `T` values.
Seq2(Box<Combinator<T>>, Box<Combinator<T>>),
/// A sequence of three `T` values.
Seq3(Box<Combinator<T>>, Box<Combinator<T>>, Box<Combinator<T>>),
/// A sequence of four `T` values.
Seq4(
Box<Combinator<T>>,
Box<Combinator<T>>,
Box<Combinator<T>>,
Box<Combinator<T>>,
),
/// A sequence of five `T` values.
Seq5(
Box<Combinator<T>>,
Box<Combinator<T>>,
Box<Combinator<T>>,
Box<Combinator<T>>,
Box<Combinator<T>>,
),
/// A sequence of six `T` values.
Seq6(
Box<Combinator<T>>,
Box<Combinator<T>>,
Box<Combinator<T>>,
Box<Combinator<T>>,
Box<Combinator<T>>,
Box<Combinator<T>>,
),
/// A sequence of seven `T` values.
Seq7(
Box<Combinator<T>>,
Box<Combinator<T>>,
Box<Combinator<T>>,
Box<Combinator<T>>,
Box<Combinator<T>>,
Box<Combinator<T>>,
Box<Combinator<T>>,
),
/// A sequence of eight `T` values.
Seq8(
Box<Combinator<T>>,
Box<Combinator<T>>,
Box<Combinator<T>>,
Box<Combinator<T>>,
Box<Combinator<T>>,
Box<Combinator<T>>,
Box<Combinator<T>>,
Box<Combinator<T>>,
),
/// An absent value for optional combinators.
Void,
}
/// A choice between multiple combinators.
#[derive(Debug, Clone, PartialEq, Eq)]
pub enum Choice<T> {
/// First alternative.
A(Box<Combinator<T>>),
/// Second alternative.
B(Box<Combinator<T>>),
/// Third alternative.
C(Box<Combinator<T>>),
/// Fourth alternative.
D(Box<Combinator<T>>),
/// Fifth alternative.
E(Box<Combinator<T>>),
/// Sixth alternative.
F(Box<Combinator<T>>),
/// Seventh alternative.
G(Box<Combinator<T>>),
/// Eighth alternative.
H(Box<Combinator<T>>),
/// Ninth alternative.
I(Box<Combinator<T>>),
/// Tenth alternative.
J(Box<Combinator<T>>),
}
//--------------------------------------------------------------------------------------------------
// Methods
//--------------------------------------------------------------------------------------------------
#[allow(clippy::type_complexity)]
impl<T> Combinator<T> {
/// Unwraps the combinator as a single value.
pub fn unwrap_single(self) -> T {
match self {
Combinator::Single(x) => x,
_ => panic!("Combinator::unwrap_single: combinator is not a single value"),
}
}
/// Unwraps the combinator as a choice between two values.
pub fn unwrap_choice(self) -> Choice<T> {
match self {
Combinator::Choice(x) => x,
_ => panic!("Combinator::unwrap_choice: combinator is not a choice between two values"),
}
}
/// Unwraps the combinator as a vector of repeated values.
pub fn unwrap_many(self) -> Vec<Combinator<T>> {
match self {
Combinator::Many(x) => x,
_ => panic!("Combinator::unwrap_many: combinator is not a vector of repeated values"),
}
}
/// Unwraps the combinator of a sequence of two values.
pub fn unwrap_seq2(self) -> (Box<Combinator<T>>, Box<Combinator<T>>) {
match self {
Combinator::Seq2(x, y) => (x, y),
_ => panic!("Combinator::unwrap_seq2: combinator is not a sequence of two values"),
}
}
/// Unwraps the combinator of a sequence of three values.
pub fn unwrap_seq3(self) -> (Box<Combinator<T>>, Box<Combinator<T>>, Box<Combinator<T>>) {
match self {
Combinator::Seq3(x, y, z) => (x, y, z),
_ => panic!("Combinator::unwrap_seq3: combinator is not a sequence of three values"),
}
}
/// Unwraps the combinator of a sequence of four values.
pub fn unwrap_seq4(
self,
) -> (
Box<Combinator<T>>,
Box<Combinator<T>>,
Box<Combinator<T>>,
Box<Combinator<T>>,
) {
match self {
Combinator::Seq4(x, y, z, w) => (x, y, z, w),
_ => panic!("Combinator::unwrap_seq4: combinator is not a sequence of four values"),
}
}
/// Unwraps the combinator of a sequence of five values.
pub fn unwrap_seq5(
self,
) -> (
Box<Combinator<T>>,
Box<Combinator<T>>,
Box<Combinator<T>>,
Box<Combinator<T>>,
Box<Combinator<T>>,
) {
match self {
Combinator::Seq5(x, y, z, w, v) => (x, y, z, w, v),
_ => panic!("Combinator::unwrap_seq5: combinator is not a sequence of five values"),
}
}
/// Unwraps the combinator of a sequence of six values.
pub fn unwrap_seq6(
self,
) -> (
Box<Combinator<T>>,
Box<Combinator<T>>,
Box<Combinator<T>>,
Box<Combinator<T>>,
Box<Combinator<T>>,
Box<Combinator<T>>,
) {
match self {
Combinator::Seq6(x, y, z, w, v, u) => (x, y, z, w, v, u),
_ => panic!("Combinator::unwrap_seq6: combinator is not a sequence of six values"),
}
}
/// Unwraps the combinator of a sequence of seven values.
pub fn unwrap_seq7(
self,
) -> (
Box<Combinator<T>>,
Box<Combinator<T>>,
Box<Combinator<T>>,
Box<Combinator<T>>,
Box<Combinator<T>>,
Box<Combinator<T>>,
Box<Combinator<T>>,
) {
match self {
Combinator::Seq7(x, y, z, w, v, u, t) => (x, y, z, w, v, u, t),
_ => panic!("Combinator::unwrap_seq7: combinator is not a sequence of seven values"),
}
}
/// Unwraps the combinator of a sequence of eight values.
pub fn unwrap_seq8(
self,
) -> (
Box<Combinator<T>>,
Box<Combinator<T>>,
Box<Combinator<T>>,
Box<Combinator<T>>,
Box<Combinator<T>>,
Box<Combinator<T>>,
Box<Combinator<T>>,
Box<Combinator<T>>,
) {
match self {
Combinator::Seq8(x, y, z, w, v, u, t, s) => (x, y, z, w, v, u, t, s),
_ => panic!("Combinator::unwrap_seq8: combinator is not a sequence of eight values"),
}
}
}
//--------------------------------------------------------------------------------------------------
// Functions
//--------------------------------------------------------------------------------------------------
/// Calls provided parser functions in different permutation sequences.
pub fn permute<T: Reversible, U, E>(
parser: &mut T,
mut parser_funcs: Vec<(
usize,
Box<dyn Fn(&mut T) -> Result<Option<Combinator<U>>, E>>,
)>,
) -> std::collections::HashMap<usize, Combinator<U>> {
let mut result_map = std::collections::HashMap::<usize, Combinator<U>>::new();
let mut prev_len = std::usize::MAX;
// Keep looping until the parser functions vector is exhausted.
while parser_funcs.len() < prev_len {
prev_len = parser_funcs.len();
// Remove parser functions that succeed and insert the result into the map.
parser_funcs.retain(|(index, f)| {
if let Ok(Some(result)) = f(parser) {
result_map.insert(*index, result);
return false;
}
true
});
}
result_map
}
/// Permutes parser functions with proper optional combinator support.
pub fn permute_opt<T: Reversible, U: Clone, E>(
index: usize,
parser: &mut T,
// Parser functions and their rule positions.
parser_funcs: Vec<(
usize,
Box<dyn Fn(&mut T) -> Result<Option<Combinator<U>>, E>>,
)>,
) -> Result<
(
std::collections::BTreeMap<usize, Combinator<U>>,
std::collections::HashSet<usize>,
),
E,
> {
let mut map = std::collections::BTreeMap::new();
// For each rule position, find the first parser function that succeeds and insert it into the map.
for _ in 0..index {
for (index, f) in parser_funcs.iter() {
if let Some(combinator) = f(parser)? {
map.insert(*index, combinator);
break;
}
}
}
// Collect map indices before further processing.
let map_indices = map
.keys()
.cloned()
.collect::<std::collections::HashSet<_>>();
// Fill unoccupied indices with void combinators.
for i in 0..index {
if map.get(&i).is_none() {
map.insert(i, Combinator::Void);
}
}
Ok((map, map_indices))
}
//--------------------------------------------------------------------------------------------------
// Macros
//--------------------------------------------------------------------------------------------------
/// A parser combinator macro for convenience.
///
/// ## Important
///
/// Single parsers are expected to backtrack when they fail.
#[macro_export(local_inner_macros)]
macro_rules! parse {
// a => a
($parser:expr $(, $path:ident)? => $parse:ident) => {{
// $( $path :: )? $parse($parser)?.map(|x| $crate::compiler::parser::Combinator::Single(x))
match $( $path :: )? $parse($parser) {
Ok(Some(x)) => Some($crate::compiler::parser::Combinator::Single(x)),
Ok(None) => None,
Err(e) => return Err(e),
}
}};
// (arg a b ...) => [ a(b, ...) ]
($parser:expr $(, $path:ident)? => (arg $parse:ident $( $parse_args:tt )+)) => {{
$( $path :: )? $parse($parser $(, $parse_args )+)?.map(|x| $crate::compiler::parser::Combinator::Single(x))
}};
// (opt a) => a?
($parser:expr $(, $path:ident)? => (opt $parse:tt)) => {{
match parse!($parser $(, $path)? => $parse) {
Some(x) => Some(x),
None => Some($crate::compiler::parser::Combinator::Void),
}
}};
// (many_0 a) => a*
($parser:expr $(, $path:ident)? => (many_0 $parse:tt)) => {{
let mut result = Vec::new();
while let Some(__result) = parse!($parser $(, $path)? => $parse) {
result.push(__result);
}
Some($crate::compiler::parser::Combinator::Many(result))
}};
// (many_1 a) => a+
($parser:expr $(, $path:ident)? => (many_1 $parse:tt)) => {{
let mut result = Vec::new();
while let Some(__result) = parse!($parser $(, $path)? => $parse) {
result.push(__result);
}
if !result.is_empty() {
Some($crate::compiler::parser::Combinator::Many(result))
} else {
None
}
}};
// (alt a b ...) => a | b | ...
($parser:expr $(, $path:ident)? => (alt $( $parse:tt )+)) => {{
$crate::compiler::parser::combinator::inner::alt!($parser $(, $path)? => $( $parse )+)
}};
// (seq a b ...) => a b ...
($parser:expr $(, $path:ident)? => (seq $( $parse:tt )+)) => {{
let state = <_ as $crate::compiler::reversible::Reversible>::get_state($parser);
if let Some(x) = $crate::compiler::parser::combinator::inner::seq!($parser $(, $path)? => $( $parse )+) {
Some(x)
} else {
<_ as $crate::compiler::reversible::Reversible>::set_state($parser, state);
None
}
}};
// (perm a b c) => << a b c >> // This won't work well with optional combinators
($parser:expr $(, $path:ident)? => (perm $( $parse:tt )+)) => {{
let mut index = 0;
let mut parser_funcs = std::vec::Vec::<(
usize,
Box<dyn Fn(&mut _) -> std::result::Result<std::option::Option<Combinator<_>>, _>>,
)>::new();
$(
let parser_func = |parser: &mut _| -> std::result::Result<std::option::Option<Combinator<_>>, _> {
Ok(parse!(parser, Parser => $parse))
};
parser_funcs.push((index, Box::new(parser_func)));
index += 1;
)+
let mut result = $crate::compiler::parser::combinator::permute($parser, parser_funcs);
tracing::trace!("result = {:?}", result);
if result.len() == index {
Some($crate::compiler::parser::combinator::inner::perm_result!(result, $( $parse )+))
} else {
None
}
}};
// (perm_opt (opt a) b (opt c)) => << a? b c? >>
// This macro supports optional combinators at the top-level for convenience.
// However, it comes at the cost of performance.
($parser:expr $(, $path:ident)? => (perm_opt $( $parse:tt )+)) => {{
let mut index = 0;
let mut non_optionals = std::collections::HashSet::<usize>::new();
let mut parser_funcs = std::vec::Vec::<(
usize,
Box<dyn Fn(&mut _) -> std::result::Result<std::option::Option<Combinator<_>>, _>>,
)>::new();
$crate::compiler::parser::combinator::inner::perm_opt_args!(index, parser_funcs, non_optionals, $parser $(, $path)? => $( $parse )+);
let (mut map, map_indices) = $crate::compiler::parser::combinator::permute_opt(index, $parser, parser_funcs)?;
if map_indices.is_superset(&non_optionals) {
Some($crate::compiler::parser::combinator::inner::perm_result!(map, $( $parse )+))
} else {
None
}
}}
}
pub(crate) mod inner {
/// Sequence combinator macro.
macro_rules! seq {
// Sequence(2) => a b
($parser:expr $(, $path:ident)? => $parse_a:tt $parse_b:tt) => {{
if let Some(__result_a) = parse!($parser $(, $path)? => $parse_a) {
if let Some(__result_b) = parse!($parser $(, $path)? => $parse_b) {
Some($crate::compiler::parser::Combinator::Seq2(Box::new(__result_a), Box::new(__result_b)))
} else {
None
}
} else {
None
}
}};
// Sequence(3) => a b c
($parser:expr $(, $path:ident)? => $parse_a:tt $parse_b:tt $parse_c:tt) => {{
if let Some(__result_a) = parse!($parser $(, $path)? => $parse_a) {
if let Some($crate::compiler::parser::Combinator::Seq2(__result_b, __result_c)) = $crate::compiler::parser::combinator::inner::seq!($parser $(, $path)? => $parse_b $parse_c) {
Some($crate::compiler::parser::Combinator::Seq3(Box::new(__result_a), __result_b, __result_c))
} else {
None
}
} else {
None
}
}};
// Sequence(4) => a b c d
($parser:expr $(, $path:ident)? => $parse_a:tt $parse_b:tt $parse_c:tt $parse_d:tt) => {{
if let Some(__result_a) = parse!($parser $(, $path)? => $parse_a) {
if let Some($crate::compiler::parser::Combinator::Seq3(__result_b, __result_c, __result_d)) = $crate::compiler::parser::combinator::inner::seq!($parser $(, $path)? => $parse_b $parse_c $parse_d) {
Some($crate::compiler::parser::Combinator::Seq4(Box::new(__result_a), __result_b, __result_c, __result_d))
} else {
None
}
} else {
None
}
}};
// Sequence(5) => a b c d e
($parser:expr $(, $path:ident)? => $parse_a:tt $parse_b:tt $parse_c:tt $parse_d:tt $parse_e:tt) => {{
if let Some(__result_a) = parse!($parser $(, $path)? => $parse_a) {
if let Some($crate::compiler::parser::Combinator::Seq4(__result_b, __result_c, __result_d, __result_e)) = $crate::compiler::parser::combinator::inner::seq!($parser $(, $path)? => $parse_b $parse_c $parse_d $parse_e) {
Some($crate::compiler::parser::Combinator::Seq5(Box::new(__result_a), __result_b, __result_c, __result_d, __result_e))
} else {
None
}
} else {
None
}
}};
// Sequence(6) => a b c d e f
($parser:expr $(, $path:ident)? => $parse_a:tt $parse_b:tt $parse_c:tt $parse_d:tt $parse_e:tt $parse_f:tt) => {{
if let Some(__result_a) = parse!($parser $(, $path)? => $parse_a) {
if let Some($crate::compiler::parser::Combinator::Seq5(__result_b, __result_c, __result_d, __result_e, __result_f)) = $crate::compiler::parser::combinator::inner::seq!($parser $(, $path)? => $parse_b $parse_c $parse_d $parse_e $parse_f) {
Some($crate::compiler::parser::Combinator::Seq6(Box::new(__result_a), __result_b, __result_c, __result_d, __result_e, __result_f))
} else {
None
}
} else {
None
}
}};
// Sequence(7) => a b c d e f g
($parser:expr $(, $path:ident)? => $parse_a:tt $parse_b:tt $parse_c:tt $parse_d:tt $parse_e:tt $parse_f:tt $parse_g:tt) => {{
if let Some(__result_a) = parse!($parser $(, $path)? => $parse_a) {
if let Some($crate::compiler::parser::Combinator::Seq6(__result_b, __result_c, __result_d, __result_e, __result_f, __result_g)) = $crate::compiler::parser::combinator::inner::seq!($parser $(, $path)? => $parse_b $parse_c $parse_d $parse_e $parse_f $parse_g) {
Some($crate::compiler::parser::Combinator::Seq7(Box::new(__result_a), __result_b, __result_c, __result_d, __result_e, __result_f, __result_g))
} else {
None
}
} else {
None
}
}};
// Sequence(8) => a b c d e f g h
($parser:expr $(, $path:ident)? => $parse_a:tt $parse_b:tt $parse_c:tt $parse_d:tt $parse_e:tt $parse_f:tt $parse_g:tt $parse_h:tt) => {{
if let Some(__result_a) = parse!($parser $(, $path)? => $parse_a) {
if let Some($crate::compiler::parser::Combinator::Seq7(__result_b, __result_c, __result_d, __result_e, __result_f, __result_g, __result_h)) = $crate::compiler::parser::combinator::inner::seq!($parser $(, $path)? => $parse_b $parse_c $parse_d $parse_e $parse_f $parse_g $parse_h) {
Some($crate::compiler::parser::Combinator::Seq8(Box::new(__result_a), __result_b, __result_c, __result_d, __result_e, __result_f, __result_g, __result_h))
} else {
None
}
} else {
None
}
}};
}
/// Alternative combinator macro.
macro_rules! alt {
// Alternative(2) => a | b
($parser:expr $(, $path:ident)? => $parse_a:tt $parse_b:tt) => {{
if let Some(__result_a) = parse!($parser $(, $path)? => $parse_a) {
Some($crate::compiler::parser::Combinator::Choice($crate::compiler::parser::combinator::Choice::A(Box::new(__result_a))))
} else if let Some(__result_b) = parse!($parser $(, $path)? => $parse_b) {
Some($crate::compiler::parser::Combinator::Choice($crate::compiler::parser::combinator::Choice::B(Box::new(__result_b))))
} else {
None
}
}};
// Alternative(3) => a | b | c
($parser:expr $(, $path:ident)? => $parse_a:tt $parse_b:tt $parse_c:tt) => {{
if let Some(__result) = $crate::compiler::parser::combinator::inner::alt!($parser $(, $path)? => $parse_a $parse_b) {
Some(__result)
} else if let Some(__result_c) = parse!($parser $(, $path)? => $parse_c) {
Some($crate::compiler::parser::Combinator::Choice($crate::compiler::parser::combinator::Choice::C(Box::new(__result_c))))
} else {
None
}
}};
// Alternative(4) => a | b | c | d
($parser:expr $(, $path:ident)? => $parse_a:tt $parse_b:tt $parse_c:tt $parse_d:tt) => {{
if let Some(__result) = $crate::compiler::parser::combinator::inner::alt!($parser $(, $path)? => $parse_a $parse_b $parse_c) {
Some(__result)
} else if let Some(__result_d) = parse!($parser $(, $path)? => $parse_d) {
Some($crate::compiler::parser::Combinator::Choice($crate::compiler::parser::combinator::Choice::D(Box::new(__result_d))))
} else {
None
}
}};
// Alternative(5) => a | b | c | d | e
($parser:expr $(, $path:ident)? => $parse_a:tt $parse_b:tt $parse_c:tt $parse_d:tt $parse_e:tt) => {{
if let Some(__result) = $crate::compiler::parser::combinator::inner::alt!($parser $(, $path)? => $parse_a $parse_b $parse_c $parse_d) {
Some(__result)
} else if let Some(__result_e) = parse!($parser $(, $path)? => $parse_e) {
Some($crate::compiler::parser::Combinator::Choice($crate::compiler::parser::combinator::Choice::E(Box::new(__result_e))))
} else {
None
}
}};
// Alternative(6) => a | b | c | d | e | f
($parser:expr $(, $path:ident)? => $parse_a:tt $parse_b:tt $parse_c:tt $parse_d:tt $parse_e:tt $parse_f:tt) => {{
if let Some(__result) = $crate::compiler::parser::combinator::inner::alt!($parser $(, $path)? => $parse_a $parse_b $parse_c $parse_d $parse_e) {
Some(__result)
} else if let Some(__result_f) = parse!($parser $(, $path)? => $parse_f) {
Some($crate::compiler::parser::Combinator::Choice($crate::compiler::parser::combinator::Choice::F(Box::new(__result_f))))
} else {
None
}
}};
// Alternative(7) => a | b | c | d | e | f | g
($parser:expr $(, $path:ident)? => $parse_a:tt $parse_b:tt $parse_c:tt $parse_d:tt $parse_e:tt $parse_f:tt $parse_g:tt) => {{
if let Some(__result) = $crate::compiler::parser::combinator::inner::alt!($parser $(, $path)? => $parse_a $parse_b $parse_c $parse_d $parse_e $parse_f) {
Some(__result)
} else if let Some(__result_g) = parse!($parser $(, $path)? => $parse_g) {
Some($crate::compiler::parser::Combinator::Choice($crate::compiler::parser::combinator::Choice::G(Box::new(__result_g))))
} else {
None
}
}};
// Alternative(8) => a | b | c | d | e | f | g | h
($parser:expr $(, $path:ident)? => $parse_a:tt $parse_b:tt $parse_c:tt $parse_d:tt $parse_e:tt $parse_f:tt $parse_g:tt $parse_h:tt) => {{
if let Some(__result) = $crate::compiler::parser::combinator::inner::alt!($parser $(, $path)? => $parse_a $parse_b $parse_c $parse_d $parse_e $parse_f $parse_g) {
Some(__result)
} else if let Some(__result_h) = parse!($parser $(, $path)? => $parse_h) {
Some($crate::compiler::parser::Combinator::Choice($crate::compiler::parser::combinator::Choice::H(Box::new(__result_h))))
} else {
None
}
}};
// Alternative(9) => a | b | c | d | e | f | g | h | i
($parser:expr $(, $path:ident)? => $parse_a:tt $parse_b:tt $parse_c:tt $parse_d:tt $parse_e:tt $parse_f:tt $parse_g:tt $parse_h:tt $parse_i:tt) => {{
if let Some(__result) = $crate::compiler::parser::combinator::inner::alt!($parser $(, $path)? => $parse_a $parse_b $parse_c $parse_d $parse_e $parse_f $parse_g $parse_h) {
Some(__result)
} else if let Some(__result_i) = parse!($parser $(, $path)? => $parse_i) {
Some($crate::compiler::parser::Combinator::Choice($crate::compiler::parser::combinator::Choice::I(Box::new(__result_i))))
} else {
None
}
}};
// Alternative(10) => a | b | c | d | e | f | g | h | i | j
($parser:expr $(, $path:ident)? => $parse_a:tt $parse_b:tt $parse_c:tt $parse_d:tt $parse_e:tt $parse_f:tt $parse_g:tt $parse_h:tt $parse_i:tt $parse_j:tt) => {{
if let Some(__result) = $crate::compiler::parser::combinator::inner::alt!($parser $(, $path)? => $parse_a $parse_b $parse_c $parse_d $parse_e $parse_f $parse_g $parse_h $parse_i) {
Some(__result)
} else if let Some(__result_j) = parse!($parser $(, $path)? => $parse_j) {
Some($crate::compiler::parser::Combinator::Choice($crate::compiler::parser::combinator::Choice::J(Box::new(__result_j))))
} else {
None
}
}};
}
/// Permutation combinator macro result.
macro_rules! perm_result {
($result:expr, $parse_a:tt $parse_b:tt) => {{
Combinator::Seq2(
Box::new($result.remove(&0).unwrap()),
Box::new($result.remove(&1).unwrap()),
)
}};
($result:expr, $parse_a:tt $parse_b:tt $parse_c:tt) => {{
Combinator::Seq3(
Box::new($result.remove(&0).unwrap()),
Box::new($result.remove(&1).unwrap()),
Box::new($result.remove(&2).unwrap()),
)
}};
($result:expr, $parse_a:tt $parse_b:tt $parse_c:tt $parse_d:tt) => {{
Combinator::Seq4(
Box::new($result.remove(&0).unwrap()),
Box::new($result.remove(&1).unwrap()),
Box::new($result.remove(&2).unwrap()),
Box::new($result.remove(&3).unwrap()),
)
}};
($result:expr, $parse_a:tt $parse_b:tt $parse_c:tt $parse_d:tt $parse_e:tt) => {{
Combinator::Seq5(
Box::new($result.remove(&0).unwrap()),
Box::new($result.remove(&1).unwrap()),
Box::new($result.remove(&2).unwrap()),
Box::new($result.remove(&3).unwrap()),
Box::new($result.remove(&4).unwrap()),
)
}};
($result:expr, $parse_a:tt $parse_b:tt $parse_c:tt $parse_d:tt $parse_e:tt $parse_f:tt) => {{
Combinator::Seq6(
Box::new($result.remove(&0).unwrap()),
Box::new($result.remove(&1).unwrap()),
Box::new($result.remove(&2).unwrap()),
Box::new($result.remove(&3).unwrap()),
Box::new($result.remove(&4).unwrap()),
Box::new($result.remove(&5).unwrap()),
)
}};
($result:expr, $parse_a:tt $parse_b:tt $parse_c:tt $parse_d:tt $parse_e:tt $parse_f:tt $parse_g:tt) => {{
Combinator::Seq7(
Box::new($result.remove(&0).unwrap()),
Box::new($result.remove(&1).unwrap()),
Box::new($result.remove(&2).unwrap()),
Box::new($result.remove(&3).unwrap()),
Box::new($result.remove(&4).unwrap()),
Box::new($result.remove(&5).unwrap()),
Box::new($result.remove(&6).unwrap()),
)
}};
($result:expr, $parse_a:tt $parse_b:tt $parse_c:tt $parse_d:tt $parse_e:tt $parse_f:tt $parse_g:tt $parse_h:tt) => {{
Combinator::Seq8(
Box::new($result.remove(&0).unwrap()),
Box::new($result.remove(&1).unwrap()),
Box::new($result.remove(&2).unwrap()),
Box::new($result.remove(&3).unwrap()),
Box::new($result.remove(&4).unwrap()),
Box::new($result.remove(&5).unwrap()),
Box::new($result.remove(&6).unwrap()),
Box::new($result.remove(&7).unwrap()),
)
}};
}
/// Permutation combinator macro.
macro_rules! perm_opt_args {
($index:expr, $parser_funcs:expr, $non_optionals:expr, $parser:expr, $path:ident => $parse_0:tt $( $parse_rest:tt )+) => {{
$crate::compiler::parser::combinator::inner::perm_opt_args!($index, $parser_funcs, $non_optionals, $parser, $path => $parse_0);
$(
$crate::compiler::parser::combinator::inner::perm_opt_args!($index, $parser_funcs, $non_optionals, $parser, $path => $parse_rest);
)+
}};
($index:expr, $parser_funcs:expr, $non_optionals:expr, $parser:expr => $parse_0:tt $( $parse_rest:tt )+) => {{
$crate::compiler::parser::combinator::inner::perm_opt_args!($index, $parser_funcs, $non_optionals, $parser => $parse_0);
$(
$crate::compiler::parser::combinator::inner::perm_opt_args!($index, $parser_funcs, $non_optionals, $parser => $parse_rest);
)+
}};
($index:expr, $parser_funcs:expr, $non_optionals:expr, $parser:expr $(, $path:ident)? => (opt $parse:tt)) => {{
{
let parser_func =
|parser: &mut _| -> std::result::Result<std::option::Option<Combinator<_>>, _> {
Ok(parse!(parser $(, $path)? => $parse))
};
$parser_funcs.push(($index, Box::new(parser_func)));
$index += 1;
}
}};
($index:expr, $parser_funcs:expr, $non_optionals:expr, $parser:expr $(, $path:ident)? => $parse:tt) => {{
{
let parser_func =
|parser: &mut _| -> std::result::Result<std::option::Option<Combinator<_>>, _> {
Ok(parse!(parser $(, $path)? => $parse))
};
$parser_funcs.push(($index, Box::new(parser_func)));
$non_optionals.insert($index);
$index += 1;
}
}}
}
pub(crate) use alt;
pub(crate) use perm_opt_args;
pub(crate) use perm_result;
pub(crate) use seq;
}
use crate::parse;
use super::*;
use itertools::Itertools;
use mock::*;
use tracing::info;
//--------------------------------------------------------------------------------------------------
// Tests
//--------------------------------------------------------------------------------------------------
fn test_(parser: &mut Parser) -> anyhow::Result<Option<Combinator<mock::Ast>>> {
let mut index = 0;
let mut parser_funcs = std::vec::Vec::<(
usize,
Box<
dyn Fn(
&mut _,
) -> std::result::Result<
std::option::Option<Combinator<mock::Ast>>,
anyhow::Error,
>,
>,
// Box<dyn Fn(&mut _) -> std::result::Result<std::option::Option<Combinator<_>>, _>>,
)>::new();
let mut non_optionals = std::collections::HashSet::<usize>::new();
// ---
{
let parser_func =
|parser: &mut _| -> std::result::Result<std::option::Option<Combinator<_>>, _> {
Ok(parse!(parser, Parser => parse_a))
};
parser_funcs.push((index, Box::new(parser_func)));
non_optionals.insert(index);
index += 1;
}
{
let parser_func =
|parser: &mut _| -> std::result::Result<std::option::Option<Combinator<_>>, _> {
Ok(parse!(parser, Parser => parse_b))
};
parser_funcs.push((index, Box::new(parser_func)));
index += 1;
}
{
let parser_func =
|parser: &mut _| -> std::result::Result<std::option::Option<Combinator<_>>, _> {
Ok(parse!(parser, Parser => parse_c))
};
parser_funcs.push((index, Box::new(parser_func)));
non_optionals.insert(index);
index += 1;
}
// ---
let mut map = std::collections::BTreeMap::new();
for _ in 0..index {
for (index, f) in parser_funcs.iter() {
println!("index = {}", index);
if let Some(combinator) = f(parser)? {
map.insert(*index, combinator);
break;
}
}
}
let map_indices = map
.keys()
.cloned()
.collect::<std::collections::HashSet<_>>();
// Non-optionals must be in the map
if map_indices.is_superset(&non_optionals) {
Ok(Some(Combinator::Many(
map.into_iter().map(|(_, combinator)| combinator).collect(),
)))
} else {
Ok(None)
}
}
#[test_log::test]
fn test_combinator_perm_optional() -> anyhow::Result<()> {
for i in ('a'..='d').permutations(4) {
let parser = &mut Parser::new(i);
let result = parse!(parser, Parser => (perm_opt parse_a parse_b parse_c parse_d));
info!(
"input = {:?} | (perm_opt parse_a parse_b parse_c parse_d) = {:?}",
parser.input, result
);
assert_eq!(
result,
Some(Combinator::Seq4(
Box::new(Combinator::Single(Ast::A)),
Box::new(Combinator::Single(Ast::B)),
Box::new(Combinator::Single(Ast::C)),
Box::new(Combinator::Single(Ast::D))
))
);
}
// Optional rules
let parser = &mut Parser::new(['b']);
let result = parse!(parser, Parser => (perm_opt (opt parse_c) parse_b (opt parse_a)));
info!(
"input = {:?} | (perm_opt (opt parse_c) parse_b (opt parse_a)) = {:?}",
parser.input, result
);
assert_eq!(
result,
Some(Combinator::Seq3(
Box::new(Combinator::Void),
Box::new(Combinator::Single(Ast::B)),
Box::new(Combinator::Void)
))
);
let parser = &mut Parser::new(['b', 'c']);
let result = parse!(parser, Parser => (perm_opt (opt parse_c) parse_b (opt parse_a)));
info!(
"input = {:?} | (perm_opt (opt parse_c) parse_b (opt parse_a)) = {:?}",
parser.input, result
);
assert_eq!(
result,
Some(Combinator::Seq3(
Box::new(Combinator::Single(Ast::C)),
Box::new(Combinator::Single(Ast::B)),
Box::new(Combinator::Void)
))
);
let parser = &mut Parser::new(['a', 'b', 'c']);
let result = parse!(parser, Parser => (perm_opt (opt parse_c) parse_b (opt parse_a)));
info!(
"input = {:?} | (perm_opt (opt parse_c) parse_b (opt parse_a)) = {:?}",
parser.input, result
);
assert_eq!(
result,
Some(Combinator::Seq3(
Box::new(Combinator::Single(Ast::C)),
Box::new(Combinator::Single(Ast::B)),
Box::new(Combinator::Single(Ast::A))
))
);
// Fail Cases
let parser = &mut Parser::new(['c', 'a']);
let result = parse!(parser, Parser => (perm_opt (opt parse_c) parse_b (opt parse_a)));
info!(
"input = {:?} | (perm_opt (opt parse_c) parse_b (opt parse_a)) = {:?}",
parser.input, result
);
assert_eq!(result, None);
let parser = &mut Parser::new(['a', 'b']);
let result = parse!(parser, Parser => (perm_opt parse_a parse_c));
info!(
"input = {:?} | (perm_opt parse_a parse_c) = {:?}",
parser.input, result
);
assert_eq!(result, None);
Ok(())
}
#[test_log::test]
fn test_combinator_perm() -> anyhow::Result<()> {
let parser = &mut Parser::new(['a', 'b']);
let result = parse!(parser, Parser => (perm parse_a parse_b));
info!(
"input = {:?} | (perm parse_a parse_b) = {:?}",
parser.input, result
);
assert_eq!(
result,
Some(Combinator::Seq2(
Box::new(Combinator::Single(Ast::A)),
Box::new(Combinator::Single(Ast::B))
))
);
let parser = &mut Parser::new(['b', 'a']);
let result = parse!(parser, Parser => (perm parse_a parse_b));
info!(
"input = {:?} | (perm parse_a parse_b) = {:?}",
parser.input, result
);
assert_eq!(
result,
Some(Combinator::Seq2(
Box::new(Combinator::Single(Ast::A)),
Box::new(Combinator::Single(Ast::B))
))
);
for i in ('a'..='c').permutations(3) {
let parser = &mut Parser::new(i);
let result = parse!(parser, Parser => (perm parse_a parse_b parse_c));
info!(
"input = {:?} | (perm parse_a parse_b parse_c) = {:?}",
parser.input, result
);
assert_eq!(
result,
Some(Combinator::Seq3(
Box::new(Combinator::Single(Ast::A)),
Box::new(Combinator::Single(Ast::B)),
Box::new(Combinator::Single(Ast::C))
))
);
}
for i in ('a'..='d').permutations(4) {
let parser = &mut Parser::new(i);
let result = parse!(parser, Parser => (perm parse_a parse_b parse_c parse_d));
info!(
"input = {:?} | (perm parse_a parse_b parse_c parse_d) = {:?}",
parser.input, result
);
assert_eq!(
result,
Some(Combinator::Seq4(
Box::new(Combinator::Single(Ast::A)),
Box::new(Combinator::Single(Ast::B)),
Box::new(Combinator::Single(Ast::C)),
Box::new(Combinator::Single(Ast::D))
))
);
}
// Fail Cases
let parser = &mut Parser::new(['a', 'b']);
let result = parse!(parser, Parser => (perm parse_a parse_c));
info!(
"input = {:?} | (perm parse_a parse_c) = {:?}",
parser.input, result
);
assert_eq!(result, None);
Ok(())
}
#[test_log::test]
fn test_combinator_single() -> anyhow::Result<()> {
let mut parser = Parser::new(['a']);
let result = parse!(&mut parser, Parser => parse_a);
info!("input = {:?} | parse_a = {:?}", parser.input, result);
assert_eq!(result, Some(Combinator::Single(Ast::A)));
// Fail Cases
let mut parser = Parser::new(['b']);
let result = parse!(&mut parser, Parser => parse_a);
info!("input = {:?} | parse_a = {:?}", parser.input, result);
assert_eq!(result, None);
Ok(())
}
#[test_log::test]
fn test_combinator_arg() -> anyhow::Result<()> {
let mut parser = Parser::new(['a']);
let result = parse!(&mut parser, Parser => (arg parse_char 'a'));
info!(
"input = {:?} | (arg parse_char 'a') = {:?}",
parser.input, result
);
assert_eq!(result, Some(Combinator::Single(Ast::Some('a'))));
// Fail Cases
let mut parser = Parser::new(['b']);
let result = parse!(&mut parser, Parser => (arg parse_char 'a'));
info!(
"input = {:?} | (arg parse_char 'a') = {:?}",
parser.input, result
);
assert_eq!(result, None);
Ok(())
}
#[test_log::test]
fn test_combinator_opt() -> anyhow::Result<()> {
let mut parser = Parser::new(['a']);
let result = parse!(&mut parser, Parser => (opt parse_a));
info!("input = {:?} | (opt parse_a) = {:?}", parser.input, result);
assert_eq!(result, Some(Combinator::Single(Ast::A)));
// Fail Cases
let mut parser = Parser::new(['b']);
let result = parse!(&mut parser, Parser => (opt parse_a));
info!("input = {:?} | (opt parse_a) = {:?}", parser.input, result);
assert_eq!(result, Some(Combinator::Void));
Ok(())
}
#[test_log::test]
fn test_combinator_many() -> anyhow::Result<()> {
let parser = &mut Parser::new(['b', 'b', 'b']);
let result = parse!(parser, Parser => (many_0 parse_b));
info!(
"input = {:?} | (many_0 parse_b) = {:?}",
parser.input, result
);
assert_eq!(
result,
Some(Combinator::Many(vec![
Combinator::Single(Ast::B),
Combinator::Single(Ast::B),
Combinator::Single(Ast::B),
]))
);
let parser = &mut Parser::new(['b', 'b']);
let result = parse!(parser, Parser => (many_1 parse_b));
info!(
"input = {:?} | (many_1 parse_b) = {:?}",
parser.input, result
);
assert_eq!(
result,
Some(Combinator::Many(vec![
Combinator::Single(Ast::B),
Combinator::Single(Ast::B),
]))
);
// Fail Cases
let parser = &mut Parser::new([]);
let result = parse!(parser, Parser => (many_0 parse_b));
info!(
"input = {:?} | (many_0 parse_b) = {:?}",
parser.input, result
);
assert_eq!(result, Some(Combinator::Many(vec![])));
let parser = &mut Parser::new([]);
let result = parse!(parser, Parser => (many_1 parse_b));
info!(
"input = {:?} | (many_1 parse_b) = {:?}",
parser.input, result
);
assert_eq!(result, None);
Ok(())
}
#[test_log::test]
fn test_combinator_alt() -> anyhow::Result<()> {
let parser = &mut Parser::new(['a']);
let result = parse!(parser, Parser => (alt parse_a parse_b));
info!(
"input = {:?} | (alt parse_a parse_b) = {:?}",
parser.input, result
);
assert_eq!(
result,
Some(Combinator::Choice(Choice::A(Box::new(Combinator::Single(
Ast::A
)))))
);
let parser = &mut Parser::new(['b']);
let result = parse!(parser, Parser => (alt parse_a parse_b parse_c));
info!(
"input = {:?} | (alt parse_a parse_b parse_c) = {:?}",
parser.input, result
);
assert_eq!(
result,
Some(Combinator::Choice(Choice::B(Box::new(Combinator::Single(
Ast::B
)))))
);
let parser = &mut Parser::new(['d']);
let result = parse!(parser, Parser => (alt parse_a parse_b parse_c parse_d));
info!(
"input = {:?} | (alt parse_a parse_b parse_c parse_d) = {:?}",
parser.input, result
);
assert_eq!(
result,
Some(Combinator::Choice(Choice::D(Box::new(Combinator::Single(
Ast::D
)))))
);
let parser = &mut Parser::new(['a']);
let result = parse!(parser, Parser => (alt parse_a parse_b parse_c parse_d parse_e));
info!(
"input = {:?} | (alt parse_a parse_b parse_c parse_d parse_e) = {:?}",
parser.input, result
);
assert_eq!(
result,
Some(Combinator::Choice(Choice::A(Box::new(Combinator::Single(
Ast::A
)))))
);
let parser = &mut Parser::new(['f']);
let result = parse!(parser, Parser => (alt parse_a parse_b parse_c parse_d parse_e parse_f));
info!(
"input = {:?} | (alt parse_a parse_b parse_c parse_d parse_e parse_f) = {:?}",
parser.input, result
);
assert_eq!(
result,
Some(Combinator::Choice(Choice::F(Box::new(Combinator::Single(
Ast::F
)))))
);
let parser = &mut Parser::new(['c']);
let result = parse!(parser, Parser => (alt parse_b parse_c parse_d));
info!(
"input = {:?} | (alt parse_b parse_c parse_d) = {:?}",
parser.input, result
);
assert_eq!(
result,
Some(Combinator::Choice(Choice::B(Box::new(Combinator::Single(
Ast::C
)))))
);
let parser = &mut Parser::new(['a']);
let result = parse!(parser, Parser => (alt parse_b parse_c));
info!(
"input = {:?} | (alt parse_b parse_c) = {:?}",
parser.input, result
);
assert_eq!(result, None);
Ok(())
}
#[test_log::test]
fn test_combinator_seq() -> anyhow::Result<()> {
let parser = &mut Parser::new(['a', 'b']);
let result = parse!(parser, Parser => (seq parse_a parse_b));
info!(
"input = {:?} | (seq parse_a parse_b) = {:?}",
parser.input, result
);
assert_eq!(
result,
Some(Combinator::Seq2(
Box::new(Combinator::Single(Ast::A)),
Box::new(Combinator::Single(Ast::B))
))
);
let parser = &mut Parser::new(['a', 'b', 'c']);
let result = parse!(parser, Parser => (seq parse_a parse_b parse_c));
info!(
"input = {:?} | (seq parse_a parse_b parse_c) = {:?}",
parser.input, result
);
assert_eq!(
result,
Some(Combinator::Seq3(
Box::new(Combinator::Single(Ast::A)),
Box::new(Combinator::Single(Ast::B)),
Box::new(Combinator::Single(Ast::C))
))
);
let parser = &mut Parser::new(['a', 'b', 'c', 'd']);
let result = parse!(parser, Parser => (seq parse_a parse_b parse_c parse_d));
info!(
"input = {:?} | (seq parse_a parse_b parse_c parse_d) = {:?}",
parser.input, result
);
assert_eq!(
result,
Some(Combinator::Seq4(
Box::new(Combinator::Single(Ast::A)),
Box::new(Combinator::Single(Ast::B)),
Box::new(Combinator::Single(Ast::C)),
Box::new(Combinator::Single(Ast::D))
))
);
let parser = &mut Parser::new(['a', 'b', 'c', 'd', 'a']);
let result = parse!(parser, Parser => (seq parse_a parse_b parse_c parse_d parse_a));
info!(
"input = {:?} | (seq parse_a parse_b parse_c parse_d parse_a) = {:?}",
parser.input, result
);
assert_eq!(
result,
Some(Combinator::Seq5(
Box::new(Combinator::Single(Ast::A)),
Box::new(Combinator::Single(Ast::B)),
Box::new(Combinator::Single(Ast::C)),
Box::new(Combinator::Single(Ast::D)),
Box::new(Combinator::Single(Ast::A))
))
);
let parser = &mut Parser::new(['a', 'b', 'c', 'd', 'a', 'b']);
let result = parse!(parser, Parser => (seq parse_a parse_b parse_c parse_d parse_a parse_b));
info!(
"input = {:?} | (seq parse_a parse_b parse_c parse_a parse_b) = {:?}",
parser.input, result
);
assert_eq!(
result,
Some(Combinator::Seq6(
Box::new(Combinator::Single(Ast::A)),
Box::new(Combinator::Single(Ast::B)),
Box::new(Combinator::Single(Ast::C)),
Box::new(Combinator::Single(Ast::D)),
Box::new(Combinator::Single(Ast::A)),
Box::new(Combinator::Single(Ast::B))
))
);
let parser = &mut Parser::new(['a', 'b', 'c', 'd', 'a', 'b', 'c']);
let result =
parse!(parser, Parser => (seq parse_a parse_b parse_c parse_d parse_a parse_b parse_c));
info!(
"input = {:?} | (seq parse_a parse_b parse_c parse_d parse_a parse_b parse_c) = {:?}",
parser.input, result
);
assert_eq!(
result,
Some(Combinator::Seq7(
Box::new(Combinator::Single(Ast::A)),
Box::new(Combinator::Single(Ast::B)),
Box::new(Combinator::Single(Ast::C)),
Box::new(Combinator::Single(Ast::D)),
Box::new(Combinator::Single(Ast::A)),
Box::new(Combinator::Single(Ast::B)),
Box::new(Combinator::Single(Ast::C))
))
);
let parser = &mut Parser::new(['a', 'b', 'c', 'd', 'a', 'b', 'c', 'd']);
let result = parse!(parser, Parser => (seq parse_a parse_b parse_c parse_d parse_a parse_b parse_c parse_d));
info!(
"input = {:?} | (seq parse_a parse_b parse_c parse_d parse_a parse_b parse_c parse_d) = {:?}",
parser.input, result
);
assert_eq!(
result,
Some(Combinator::Seq8(
Box::new(Combinator::Single(Ast::A)),
Box::new(Combinator::Single(Ast::B)),
Box::new(Combinator::Single(Ast::C)),
Box::new(Combinator::Single(Ast::D)),
Box::new(Combinator::Single(Ast::A)),
Box::new(Combinator::Single(Ast::B)),
Box::new(Combinator::Single(Ast::C)),
Box::new(Combinator::Single(Ast::D))
))
);
// Fail Cases
let parser = &mut Parser::new(['c', 'b']);
let result = parse!(parser, Parser => (seq parse_a parse_b));
info!(
"input = {:?} | (seq parse_a parse_b) = {:?}",
parser.input, result
);
assert_eq!(result, None);
let parser = &mut Parser::new(['a', 'c']);
let result = parse!(parser, Parser => (seq parse_a parse_b));
info!(
"input = {:?} | (seq parse_a parse_b) = {:?}",
parser.input, result
);
assert_eq!(result, None);
let parser = &mut Parser::new(['d', 'b', 'c']);
let result = parse!(parser, Parser => (seq parse_a parse_b parse_c));
info!(
"input = {:?} | (seq parse_a parse_b parse_c) = {:?}",
parser.input, result
);
assert_eq!(result, None);
let parser = &mut Parser::new(['a', 'b', 'c', 'a']);
let result = parse!(parser, Parser => (seq parse_a parse_b parse_c parse_d));
info!(
"input = {:?} | (seq parse_a parse_b parse_c parse_d) = {:?}",
parser.input, result
);
assert_eq!(result, None);
let parser = &mut Parser::new(['a', 'b', 'c', 'e', 'a', 'b', 'c', 'd']);
let result = parse!(parser, Parser => (seq parse_a parse_b parse_c parse_d parse_a parse_b parse_c parse_d));
info!(
"input = {:?} | (seq parse_a parse_b parse_c parse_d parse_a parse_b parse_c parse_d) = {:?}",
parser.input, result
);
assert_eq!(result, None);
Ok(())
}
#[test_log::test]
fn test_combinator_mix() -> anyhow::Result<()> {
// Simple alternative with left choice
let parser = &mut Parser::new(['a']);
let result = parse!(parser, Parser => (alt parse_a (seq parse_a parse_b)));
info!(
"input = {:?} | (alt parse_a (seq parse_a parse_b)) = {:?}",
parser.input, result
);
assert_eq!(
result,
Some(Combinator::Choice(Choice::A(Box::new(Combinator::Single(
Ast::A
)))))
);
// Sequence with nested sequence
let parser = &mut Parser::new(['a', 'b', 'c', 'd']);
let result = parse!(parser, Parser => (seq (opt parse_a) (seq (arg parse_char 'b') (arg parse_char 'c') parse_d)));
info!(
"input = {:?} | (seq (opt parse_a) (seq (arg parse_char 'b') (arg parse_char 'c') parse_d))) = {:?}",
parser.input, result
);
assert_eq!(
result,
Some(Combinator::Seq2(
Box::new(Combinator::Single(Ast::A)),
Box::new(Combinator::Seq3(
Box::new(Combinator::Single(Ast::Some('b'))),
Box::new(Combinator::Single(Ast::Some('c'))),
Box::new(Combinator::Single(Ast::D)),
))
))
);
// Sequence with alternative
let parser = &mut Parser::new(['c', 'a']);
let result = parse!(parser, Parser => (seq parse_c (alt parse_a parse_b)));
info!(
"input = {:?} | (seq parse_c (alt parse_a parse_b)) = {:?}",
parser.input, result
);
assert_eq!(
result,
Some(Combinator::Seq2(
Box::new(Combinator::Single(Ast::C)),
Box::new(Combinator::Choice(Choice::A(Box::new(Combinator::Single(
Ast::A
)))))
))
);
// Fail Cases
let parser = &mut Parser::new(['b', 'c']);
let result = parse!(parser, Parser => (alt parse_a (seq parse_b parse_c)));
info!(
"input = {:?} | (alt parse_a (seq parse_b parse_c)) = {:?}",
parser.input, result
);
assert_eq!(
result,
Some(Combinator::Choice(Choice::B(Box::new(Combinator::Seq2(
Box::new(Combinator::Single(Ast::B)),
Box::new(Combinator::Single(Ast::C))
)))))
);
let parser = &mut Parser::new(['a', 'd']);
let result = parse!(parser, Parser => (alt (seq parse_a parse_b) parse_a));
info!(
"input = {:?} | (alt (seq parse_a parse_b) parse_a) = {:?}",
parser.input, result
);
assert_eq!(
result,
Some(Combinator::Choice(Choice::B(Box::new(Combinator::Single(
Ast::A
)))))
);
let parser = &mut Parser::new(['a', 'a', 'c']);
let result = parse!(parser, Parser => (alt (seq parse_a parse_b parse_c) (alt (seq parse_a parse_b) parse_a)));
info!("input = {:?} | (alt (seq parse_a parse_b parse_c) (alt (seq parse_a parse_b) parse_a)) = {:?}", parser.input, result);
assert_eq!(
result,
Some(Combinator::Choice(Choice::B(Box::new(Combinator::Choice(
Choice::B(Box::new(Combinator::Single(Ast::A)))
)))))
);
let parser = &mut Parser::new(['b', 'b']);
let result = parse!(parser, Parser => (alt (seq parse_a parse_b) parse_a));
info!(
"input = {:?} | (alt (seq parse_a parse_b) parse_a) = {:?}",
parser.input, result
);
assert_eq!(result, None);
let parser = &mut Parser::new(['b', 'c']);
let result = parse!(parser, Parser => (seq (opt parse_a) (seq parse_b parse_c)));
info!(
"input = {:?} | (seq (opt parse_a) (seq parse_b parse_c)) = {:?}",
parser.input, result
);
assert_eq!(
result,
Some(Combinator::Seq2(
Box::new(Combinator::Void),
Box::new(Combinator::Seq2(
Box::new(Combinator::Single(Ast::B)),
Box::new(Combinator::Single(Ast::C))
))
))
);
let parser = &mut Parser::new(['a', 'd']);
let result = parse!(parser, Parser => (seq (opt (seq parse_a parse_b)) (seq parse_a parse_d)));
info!(
"input = {:?} | (seq (opt (seq parse_a parse_b)) (seq parse_a parse_d)) = {:?}",
parser.input, result
);
assert_eq!(
result,
Some(Combinator::Seq2(
Box::new(Combinator::Void),
Box::new(Combinator::Seq2(
Box::new(Combinator::Single(Ast::A)),
Box::new(Combinator::Single(Ast::D))
))
))
);
// Permutation in sequence
let parser = &mut Parser::new(['b', 'a', 'd', 'c']);
let result = parse!(parser, Parser => (seq (perm parse_a parse_b) (perm parse_c parse_d)));
info!(
"input = {:?} | (seq (perm parse_a parse_b) (perm parse_c parse_d)) = {:?}",
parser.input, result
);
assert_eq!(
result,
Some(Combinator::Seq2(
Box::new(Combinator::Seq2(
Box::new(Combinator::Single(Ast::A)),
Box::new(Combinator::Single(Ast::B))
)),
Box::new(Combinator::Seq2(
Box::new(Combinator::Single(Ast::C)),
Box::new(Combinator::Single(Ast::D))
))
))
);
// Sequence in permutation
let parser = &mut Parser::new(['c', 'd', 'a', 'b']);
let result = parse!(parser, Parser => (perm (seq parse_a parse_b) (seq parse_c parse_d)));
info!(
"input = {:?} | (perm (seq parse_a parse_b) (seq parse_c parse_d)) = {:?}",
parser.input, result
);
assert_eq!(
result,
Some(Combinator::Seq2(
Box::new(Combinator::Seq2(
Box::new(Combinator::Single(Ast::A)),
Box::new(Combinator::Single(Ast::B))
)),
Box::new(Combinator::Seq2(
Box::new(Combinator::Single(Ast::C)),
Box::new(Combinator::Single(Ast::D))
))
))
);
// Zero or more sequences
let parser = &mut Parser::new(['a', 'b', 'a', 'd']);
let result = parse!(parser, Parser => (many_0 (seq parse_a parse_b)));
info!(
"input = {:?} | (many_0 (seq parse_a parse_b)) = {:?}",
parser.input, result
);
assert_eq!(
result,
Some(Combinator::Many(vec![Combinator::Seq2(
Box::new(Combinator::Single(Ast::A)),
Box::new(Combinator::Single(Ast::B))
)]))
);
// Nested alternative
let parser = &mut Parser::new(['d']);
let result = parse!(parser, Parser => (alt
parse_a
(alt
parse_b
(alt
parse_c
parse_d
)
)
));
info!(
"input = {:?} | (alt parse_a (alt parse_b (alt parse_c parse_d))) = {:?}",
parser.input, result
);
assert_eq!(
result,
Some(Combinator::Choice(Choice::B(Box::new(Combinator::Choice(
Choice::B(Box::new(Combinator::Choice(Choice::B(Box::new(
Combinator::Single(Ast::D)
)))))
)))))
);
Ok(())
}
#[cfg(test)]
mod mock {
use crate::compiler::reversible::Reversible;
//--------------------------------------------------------------------------------------------------
// Types
//--------------------------------------------------------------------------------------------------
pub(super) struct Parser {
pub(super) input: Vec<char>,
pub(super) cursor: usize,
}
#[derive(Debug, Clone, Eq, PartialEq)]
pub enum Ast {
Some(char),
A,
B,
C,
D,
E,
F,
}
//--------------------------------------------------------------------------------------------------
// Methods
//--------------------------------------------------------------------------------------------------
impl Parser {
pub(super) fn new(input: impl Into<Vec<char>>) -> Self {
Self {
input: input.into(),
cursor: 0,
}
}
pub(super) fn parse_char(&mut self, c: char) -> anyhow::Result<Option<Ast>> {
if let Some(ch) = self.input.get(self.cursor) {
if ch == &c {
self.cursor += 1;
return Ok(Some(Ast::Some(c)));
}
}
Ok(None)
}
pub(super) fn parse_a(&mut self) -> anyhow::Result<Option<Ast>> {
match self.input.get(self.cursor) {
Some('a') => {
self.cursor += 1;
Ok(Some(Ast::A))
}
_ => Ok(None),
}
}
pub(super) fn parse_b(&mut self) -> anyhow::Result<Option<Ast>> {
match self.input.get(self.cursor) {
Some('b') => {
self.cursor += 1;
Ok(Some(Ast::B))
}
_ => Ok(None),
}
}
pub(super) fn parse_c(&mut self) -> anyhow::Result<Option<Ast>> {
match self.input.get(self.cursor) {
Some('c') => {
self.cursor += 1;
Ok(Some(Ast::C))
}
_ => Ok(None),
}
}
pub(super) fn parse_d(&mut self) -> anyhow::Result<Option<Ast>> {
match self.input.get(self.cursor) {
Some('d') => {
self.cursor += 1;
Ok(Some(Ast::D))
}
_ => Ok(None),
}
}
pub(super) fn parse_e(&mut self) -> anyhow::Result<Option<Ast>> {
match self.input.get(self.cursor) {
Some('e') => {
self.cursor += 1;
Ok(Some(Ast::E))
}
_ => Ok(None),
}
}
pub(super) fn parse_f(&mut self) -> anyhow::Result<Option<Ast>> {
match self.input.get(self.cursor) {
Some('f') => {
self.cursor += 1;
Ok(Some(Ast::F))
}
_ => Ok(None),
}
}
}
//--------------------------------------------------------------------------------------------------
// Trait Implementations
//--------------------------------------------------------------------------------------------------
impl Reversible for Parser {
type State = usize;
fn get_state(&self) -> Self::State {
self.cursor
}
fn set_state(&mut self, state: Self::State) {
self.cursor = state;
}
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment