use mpl::output::Output;
use mpl::parser::Parser;
use mpl::rules::{RightRule, RightRuleKind, Rules};
use mpl::span::{Len, Start, StartAndLenSpan};
use mpl::symbols::{StrTerminal, U8SliceTerminal, Variable};
use mpl::trees::{AST, CST};
use std::collections::HashMap;
#[derive(Clone, Debug, Hash, Eq, PartialEq)]
enum ParenthesesVariable {
Open,
Parentheses,
Close,
}
impl Variable for ParenthesesVariable {}
type ParenthesesSpan = StartAndLenSpan<u32, u16>;
type ParenthesesStringAst = AST<ParenthesesVariable, ParenthesesSpan, String>;
type ParenthesesUnitAst = AST<ParenthesesVariable, ParenthesesSpan, ()>;
type ParenthesesStringResult = Result<ParenthesesStringAst, ParenthesesStringAst>;
type ParenthesesUnitResult = Result<ParenthesesUnitAst, ParenthesesUnitAst>;
impl<'i> Output<'i, str, ParenthesesVariable, ParenthesesSpan> for String {
fn output_ast(
_input: &'i str,
cst: CST<ParenthesesVariable, ParenthesesSpan, Self>,
) -> ParenthesesStringAst {
match cst.node.value {
ParenthesesVariable::Open => AST::from_cst_and_output(cst, Some(String::from("open"))),
ParenthesesVariable::Parentheses => {
AST::from_cst_and_output(cst, Some(String::from("paren")))
}
ParenthesesVariable::Close => {
AST::from_cst_and_output(cst, Some(String::from("close")))
}
}
}
}
enum ParseResult {
Ok,
Err,
}
const INPUTS: [(&str, ParseResult); 8] = [
("", ParseResult::Ok),
("()", ParseResult::Ok),
("()(())", ParseResult::Ok),
("(()(()))", ParseResult::Ok),
("(", ParseResult::Err),
(")", ParseResult::Err),
("()())", ParseResult::Err),
("(()(())))", ParseResult::Err),
];
struct ParenthesesParser;
impl<'i, V, P, L, R, O> Parser<'i, str, StrTerminal<'i>, V, StartAndLenSpan<P, L>, P, R, O>
for ParenthesesParser
where
V: Variable,
P: Start<str, L>,
L: Len<str, P>,
R: Rules<StrTerminal<'i>, V>,
O: Output<'i, str, V, StartAndLenSpan<P, L>>,
{
}
impl<'i, P, L, O>
Parser<
'i,
[u8],
U8SliceTerminal<'i>,
ParenthesesVariable,
StartAndLenSpan<P, L>,
P,
HashMap<ParenthesesVariable, RightRule<U8SliceTerminal<'i>, ParenthesesVariable>>,
O,
> for ParenthesesParser
where
P: Start<[u8], L>,
L: Len<[u8], P>,
O: Output<'i, [u8], ParenthesesVariable, StartAndLenSpan<P, L>>,
{
}
#[test]
fn str_parentheses() {
let mut rules = HashMap::new();
rules.insert(
ParenthesesVariable::Open,
RightRule::from_right_rule_kind(
(
RightRuleKind::T(StrTerminal::Char('(')),
RightRuleKind::V(ParenthesesVariable::Parentheses),
),
RightRuleKind::Empty,
),
);
rules.insert(
ParenthesesVariable::Parentheses,
RightRule::from_right_rule_kind(
(
RightRuleKind::V(ParenthesesVariable::Open),
RightRuleKind::V(ParenthesesVariable::Close),
),
RightRuleKind::Failure,
),
);
rules.insert(
ParenthesesVariable::Close,
RightRule::from_right_rule_kind(
(
RightRuleKind::T(StrTerminal::Str(")")),
RightRuleKind::V(ParenthesesVariable::Open),
),
RightRuleKind::Failure,
),
);
let parser = ParenthesesParser;
for input in INPUTS {
let input_data = input.0;
let parse_result = input.1;
let all_of_the_span =
StartAndLenSpan::<u32, u16>::from_start_len(0, input_data.len() as u16);
let result: ParenthesesStringResult = parser.parse(
input_data,
&rules,
&ParenthesesVariable::Open,
&all_of_the_span,
);
match parse_result {
ParseResult::Ok => assert!(result.is_ok()),
ParseResult::Err => assert!(result.is_err()),
}
}
}
#[test]
fn str_parentheses_squirrel_matches_parse() {
let mut rules = HashMap::new();
rules.insert(
ParenthesesVariable::Open,
RightRule::from_right_rule_kind(
(
RightRuleKind::T(StrTerminal::Char('(')),
RightRuleKind::V(ParenthesesVariable::Parentheses),
),
RightRuleKind::Empty,
),
);
rules.insert(
ParenthesesVariable::Parentheses,
RightRule::from_right_rule_kind(
(
RightRuleKind::V(ParenthesesVariable::Open),
RightRuleKind::V(ParenthesesVariable::Close),
),
RightRuleKind::Failure,
),
);
rules.insert(
ParenthesesVariable::Close,
RightRule::from_right_rule_kind(
(
RightRuleKind::T(StrTerminal::Str(")")),
RightRuleKind::V(ParenthesesVariable::Open),
),
RightRuleKind::Failure,
),
);
let parser = ParenthesesParser;
for input in INPUTS {
let input_data = input.0;
let parse_result = input.1;
let all_of_the_span =
StartAndLenSpan::<u32, u16>::from_start_len(0, input_data.len() as u16);
let plain: ParenthesesStringResult = parser.parse(
input_data,
&rules,
&ParenthesesVariable::Open,
&all_of_the_span,
);
let squirrel: ParenthesesStringResult = parser.squirrel_parse(
input_data,
&rules,
&ParenthesesVariable::Open,
&all_of_the_span,
);
match parse_result {
ParseResult::Ok => assert!(squirrel.is_ok()),
ParseResult::Err => assert!(squirrel.is_err()),
}
assert_eq!(plain.is_ok(), squirrel.is_ok(), "input = {:?}", input_data);
}
}
#[test]
fn str_parentheses_packrat_matches_parse() {
let mut rules = HashMap::new();
rules.insert(
ParenthesesVariable::Open,
RightRule::from_right_rule_kind(
(
RightRuleKind::T(StrTerminal::Char('(')),
RightRuleKind::V(ParenthesesVariable::Parentheses),
),
RightRuleKind::Empty,
),
);
rules.insert(
ParenthesesVariable::Parentheses,
RightRule::from_right_rule_kind(
(
RightRuleKind::V(ParenthesesVariable::Open),
RightRuleKind::V(ParenthesesVariable::Close),
),
RightRuleKind::Failure,
),
);
rules.insert(
ParenthesesVariable::Close,
RightRule::from_right_rule_kind(
(
RightRuleKind::T(StrTerminal::Str(")")),
RightRuleKind::V(ParenthesesVariable::Open),
),
RightRuleKind::Failure,
),
);
let parser = ParenthesesParser;
for input in INPUTS {
let input_data = input.0;
let parse_result = input.1;
let all_of_the_span =
StartAndLenSpan::<u32, u16>::from_start_len(0, input_data.len() as u16);
let plain: ParenthesesStringResult = parser.parse(
input_data,
&rules,
&ParenthesesVariable::Open,
&all_of_the_span,
);
let packrat: ParenthesesStringResult = parser.packrat_parse(
input_data,
&rules,
&ParenthesesVariable::Open,
&all_of_the_span,
);
match parse_result {
ParseResult::Ok => assert!(packrat.is_ok()),
ParseResult::Err => assert!(packrat.is_err()),
}
assert_eq!(plain, packrat, "input = {:?}", input_data);
}
}
#[test]
fn u8_slice_parentheses() {
let mut rules = HashMap::new();
rules.insert(
ParenthesesVariable::Open,
RightRule::from_right_rule_kind(
(
RightRuleKind::T(U8SliceTerminal::Char('(')),
RightRuleKind::V(ParenthesesVariable::Parentheses),
),
RightRuleKind::Empty,
),
);
rules.insert(
ParenthesesVariable::Parentheses,
RightRule::from_right_rule_kind(
(
RightRuleKind::V(ParenthesesVariable::Open),
RightRuleKind::V(ParenthesesVariable::Close),
),
RightRuleKind::Failure,
),
);
rules.insert(
ParenthesesVariable::Close,
RightRule::from_right_rule_kind(
(
RightRuleKind::T(U8SliceTerminal::Str(")")),
RightRuleKind::V(ParenthesesVariable::Open),
),
RightRuleKind::Failure,
),
);
let parser = ParenthesesParser;
for input in INPUTS {
let input_data = input.0.as_bytes();
let parse_result = input.1;
let all_of_the_span =
StartAndLenSpan::<u32, u16>::from_start_len(0, input_data.len() as u16);
let result: ParenthesesUnitResult = parser.parse(
input_data,
&rules,
&ParenthesesVariable::Open,
&all_of_the_span,
);
match parse_result {
ParseResult::Ok => assert!(result.is_ok()),
ParseResult::Err => assert!(result.is_err()),
}
}
}