#![warn(missing_docs)]
use super::super::idata::{
cont::IVec,
tc::{tail_call, TailCall},
};
use ast;
use parser::{atom, atom::Atom, ErrPriority, Error, Result, Status};
use std::collections::HashMap;
use std::result;
#[cfg(test)]
mod test;
#[derive(Clone, Copy, Debug)]
pub(crate) struct Started(usize);
pub(crate) type ResultExpr<'a> = result::Result<(Status<'a>, Vec<ast::Node>), Error>;
#[derive(Debug)]
pub struct SetOfRules(pub(crate) HashMap<String, Expression>);
impl SetOfRules {
pub fn new(mrules: HashMap<String, Expression>) -> Self {
SetOfRules(mrules)
}
pub fn add(mut self, name: &str, expr: Expression) -> Self {
self.0.insert(name.to_owned(), expr);
self
}
pub fn merge(self, rules2merge: Self) -> Self {
SetOfRules(rules2merge.0.into_iter().chain(self.0).collect())
}
}
#[allow(missing_docs)]
#[derive(Debug)]
pub enum Expression {
Simple(Atom),
And(MultiExpr),
Or(MultiExpr),
Not(Box<Expression>),
Repeat(RepInfo),
RuleName(String),
}
#[derive(Debug)]
pub struct MultiExpr(pub(crate) Vec<Expression>);
impl MultiExpr {
pub fn new(v: Vec<Expression>) -> Self {
MultiExpr(v)
}
}
#[derive(Debug)]
pub struct RepInfo {
pub(crate) expression: Box<Expression>,
pub(crate) min: NRep,
pub(crate) max: Option<NRep>,
}
impl RepInfo {
pub fn new(expression: Box<Expression>, min: usize, max: Option<usize>) -> Self {
RepInfo {
expression,
min: NRep(min),
max: max.map(NRep),
}
}
}
#[derive(Debug)]
pub(crate) struct NRep(pub(crate) usize);
pub(crate) fn parse(status: Status) -> Result {
parse_rule_name(status, "main")
}
fn parse_rule_name<'a>(status: Status<'a>, rule_name: &str) -> Result<'a> {
let status = if status.trace_rules {
status.push_rule(&format!("r:{}", rule_name))
} else {
status
};
let rules = &status.rules.0;
let expression = rules.get(rule_name).ok_or_else(|| {
Error::from_status(
&status,
&format!("Missing rule: {}", rule_name),
ErrPriority::Critical,
)
})?;
let (st, nodes) = parse_expr(status, &expression)?;
Ok((st, ast::Node::Rule((rule_name.to_owned(), nodes))))
}
fn parse_atom_as_expr<'a>(status: Status<'a>, a: &'a Atom) -> ResultExpr<'a> {
let (st, node) = atom::parse(status, a)?;
Ok((st, vec![node]))
}
fn parse_rule_name_as_expr<'a>(status: Status<'a>, rule_name: &str) -> ResultExpr<'a> {
let (st, ast) = parse_rule_name(status, rule_name)?;
Ok((st, vec![ast]))
}
fn parse_expr<'a>(status: Status<'a>, expression: &'a Expression) -> ResultExpr<'a> {
match *expression {
Expression::Simple(ref val) => parse_atom_as_expr(status, &val),
Expression::And(ref val) => parse_and(status, &val),
Expression::Or(ref val) => parse_or(&status, &val),
Expression::Not(ref val) => parse_not(status, &val),
Expression::Repeat(ref val) => parse_repeat(status, &val),
Expression::RuleName(ref val) => parse_rule_name_as_expr(status, &val),
}
}
fn parse_and<'a>(status: Status<'a>, multi_expr: &'a MultiExpr) -> ResultExpr<'a> {
let init_tc: (_, &[Expression], Vec<ast::Node>) = (status, &(multi_expr.0), vec![]);
tail_call(init_tc, |acc| {
if acc.1.is_empty() {
TailCall::Return(Ok((acc.0, acc.2)))
} else {
let result_parse = parse_expr(acc.0, &acc.1[0]);
match result_parse {
Ok((status, vnodes)) => {
TailCall::Call((status, &acc.1[1..], acc.2.iappend(vnodes)))
}
Err(err) => TailCall::Return(Err(err)),
}
}
})
}
fn parse_or<'a>(status: &Status<'a>, multi_expr: &'a MultiExpr) -> ResultExpr<'a> {
let deep_err = |oe1: Option<Error>, e2: Error| match oe1 {
Some(e1) => match (e1.priority > e2.priority, e1.pos.n > e2.pos.n) {
(true, _) => Some(e1),
(false, true) => Some(e1),
(false, false) => Some(e2),
},
None => Some(e2),
};
let init_tc: (_, &[Expression], _) = (status.clone(), &(multi_expr.0), None);
tail_call(init_tc, |acc| {
if acc.1.is_empty() {
TailCall::Return(Err(match acc.2 {
Some(err) => err,
_ => Error::from_st_errs(
&status,
"LOGIC ERROR!!! checked all options in or with ¿NO? errors",
vec![],
),
}))
} else {
let try_parse = parse_expr(acc.0.clone(), &acc.1[0]);
match try_parse {
Ok(result) => TailCall::Return(Ok(result)),
Err(e) => {
if e.priority == ErrPriority::Critical {
TailCall::Return(Err(e))
} else {
TailCall::Call((acc.0, &acc.1[1..], deep_err(acc.2, e)))
}
}
}
}
})
}
fn parse_not<'a>(status: Status<'a>, expression: &'a Expression) -> ResultExpr<'a> {
match parse_expr(status.clone(), expression) {
Ok(_) => Err(Error::from_status_normal(&status, "not")),
Err(_) => Ok((status, vec![])),
}
}
fn parse_repeat<'a>(status: Status<'a>, rep_info: &'a RepInfo) -> ResultExpr<'a> {
let big_min_bound = |counter| counter >= rep_info.min.0;
let touch_max_bound = |counter: usize| match rep_info.max {
Some(ref m) => counter + 1 == m.0,
None => false,
};
let init_tc: (_, _, Vec<ast::Node>) = (status, 0, vec![]);
Ok(tail_call(init_tc, |acc| {
let try_parse = parse_expr(acc.0.clone(), &rep_info.expression);
match (try_parse, big_min_bound(acc.1), touch_max_bound(acc.1)) {
(Err(e), true, _) => if e.priority == ErrPriority::Critical {
TailCall::Return(Err(e))
} else {
TailCall::Return(Ok((acc.0.set_potential_error(e), acc.2)))
},
(Err(e), false, _) => TailCall::Return(Err(e)),
(Ok((status, vnodes)), _, false) => {
TailCall::Call((status, acc.1 + 1, acc.2.iappend(vnodes)))
}
(Ok((status, vnodes)), _, true) => {
TailCall::Return(Ok((status, acc.2.iappend(vnodes))))
}
}
})?)
}