use crate::mplg::MplgVariable;
use mpl::choices::{Choice, First, Second};
use mpl::output::Output;
use mpl::rules::{RightRule, Rule};
use mpl::span::{Span, StartAndLenSpan};
use mpl::symbols::{Metasymbol, TerminalSymbol, E};
use mpl::trees::{Node, AST, CST};
#[derive(Clone, Debug)]
pub enum MplgOutput<'a> {
Lines(Vec<MplgOutput<'a>>),
Rule(Rule<&'a str, &'a str>),
Str(&'a str),
E(E<&'a str, &'a str>),
}
impl<'a> MplgOutput<'a> {
pub fn into_lines(self) -> Vec<MplgOutput<'a>> {
match self {
MplgOutput::Lines(l) => l,
_ => panic!("expect lines"),
}
}
fn into_str(self) -> &'a str {
match self {
MplgOutput::Str(s) => s,
_ => panic!("expect str"),
}
}
fn into_e(self) -> E<&'a str, &'a str> {
match self {
MplgOutput::E(e) => e,
_ => panic!("expect E"),
}
}
}
impl<'i> Output<'i, [u8], MplgVariable, StartAndLenSpan<u32, u32>> for MplgOutput<'i> {
fn output_ast(
input: &'i [u8],
cst: CST<MplgVariable, StartAndLenSpan<u32, u32>, Self>,
) -> AST<MplgVariable, StartAndLenSpan<u32, u32>, Self> {
match cst.node.value {
MplgVariable::Mplg => {
let span = cst.span;
let mut lines = Vec::new();
let mut zero_or_more_lines = cst.node.equal.into_first().unwrap().lhs;
loop {
match zero_or_more_lines.node {
Node::Internal(internal) => {
let first = internal.into_first().expect("first");
if let Some(o) = first.lhs.into_original() {
lines.push(o);
}
zero_or_more_lines = first.rhs;
}
Node::Leaf(_) => {
return AST::from_leaf(
TerminalSymbol::Original(MplgOutput::Lines(lines)),
span,
);
}
}
}
}
MplgVariable::Line => {
let span = cst.span;
let first = cst.node.equal.into_first().unwrap();
let line1 = first.lhs.node.into_internal().unwrap();
match *line1.equal {
Choice::First(first) => {
let mut line_comment = first.lhs;
line_comment.span = span;
line_comment
}
Choice::Second(second) => {
let line2 = second.0;
match line2.node {
Node::Internal(internal) => {
let mut rule = internal.into_first().unwrap().lhs;
rule.span = span;
rule
}
Node::Leaf(leaf) => AST::from_leaf(leaf, span),
}
}
}
}
MplgVariable::LineComment | MplgVariable::Variable => {
let lo = cst.span.start as usize;
let hi = cst.span.hi(input) as usize;
let s = std::str::from_utf8(&input[lo..hi]).expect("str");
AST::from_leaf(TerminalSymbol::from_original(MplgOutput::Str(s)), cst.span)
}
MplgVariable::Rule => {
let span = cst.span;
let first = cst.node.equal.into_first().unwrap();
let variable = first.lhs.into_original().unwrap().into_str();
let rule2 = first.rhs.into_first().unwrap().rhs.into_first().unwrap();
let fl = rule2.lhs.into_original().unwrap().into_e();
let rule4 = rule2.rhs.into_first().unwrap().rhs.into_first().unwrap();
let fr = rule4.lhs.into_original().unwrap().into_e();
let rule6 = rule4.rhs.into_first().unwrap().rhs.into_first().unwrap();
let s = rule6.lhs.into_original().unwrap().into_e();
let rule = Rule::new(variable, RightRule::new(First::new(fl, fr), Second::new(s)));
AST::from_leaf(TerminalSymbol::from_original(MplgOutput::Rule(rule)), span)
}
MplgVariable::E => {
let span = cst.span;
match cst.node.equal {
Choice::First(first) => {
let e = first.lhs.into_original().expect("Terminal symbol");
AST::from_leaf(TerminalSymbol::from_original(e), span)
}
Choice::Second(second) => {
let s = second.0.into_original().expect("Variable");
AST::from_leaf(
TerminalSymbol::from_original(MplgOutput::E(E::V(s.into_str()))),
span,
)
}
}
}
MplgVariable::TerminalSymbol => {
let span = cst.span;
let e = match cst.node.equal {
Choice::First(first) => first.lhs.into_original().expect("Metasymbol literal"),
Choice::Second(second) => {
second.0.into_original().expect("Original symbol expr")
}
};
AST::from_leaf(TerminalSymbol::from_original(e), span)
}
MplgVariable::EmptyLiteral => AST::from_leaf(
TerminalSymbol::from_original(MplgOutput::E(Metasymbol::Empty.into())),
cst.span,
),
MplgVariable::FailureLiteral => AST::from_leaf(
TerminalSymbol::from_original(MplgOutput::E(Metasymbol::Failure.into())),
cst.span,
),
MplgVariable::AnyLiteral => {
let n = cst.span.len as usize;
AST::from_leaf(
TerminalSymbol::from_original(MplgOutput::E(Metasymbol::Any(n).into())),
cst.span,
)
}
MplgVariable::AllLiteral => AST::from_leaf(
TerminalSymbol::from_original(MplgOutput::E(Metasymbol::All.into())),
cst.span,
),
MplgVariable::MetasymbolLiteral => {
let span = cst.span;
let mut choice = cst.node.equal;
loop {
match choice {
Choice::First(first) => {
let meta = first.lhs.into_original().expect("Metasymbol");
return AST::from_leaf(TerminalSymbol::from_original(meta), span);
}
Choice::Second(second) => {
choice = *second.0.node.into_internal().expect("internal").equal;
}
}
}
}
MplgVariable::OriginalSymbolExpr => {
let lo = cst.span.start as usize;
let hi = cst.span.hi(input) as usize;
let s = std::str::from_utf8(&input[lo + 2..hi - 2]).expect("str");
AST::from_leaf(
TerminalSymbol::from_original(MplgOutput::E(
TerminalSymbol::Original(s).into(),
)),
cst.span,
)
}
_ => AST::from_cst(cst),
}
}
}