#![macro_use]
use middle::analysis::ast::*;
use self::PredicateOrRepeat::*;
#[derive(PartialEq, Eq, Clone, Copy)]
enum PredicateOrRepeat {
PAnd,
PNot,
POptional,
POneOrMore,
PZeroOrMore,
PNothing
}
impl Default for PredicateOrRepeat {
fn default() -> Self { PNothing }
}
pub struct UselessChaining<'a>
{
grammar: &'a AGrammar
}
impl <'a> UselessChaining<'a>
{
pub fn analyse(grammar: AGrammar) -> Partial<AGrammar> {
UselessChaining::check_chaining(&grammar);
Partial::Value(grammar)
}
fn check_chaining(grammar: &'a AGrammar){
let mut analyser = UselessChaining{ grammar };
for rule in &grammar.rules {
analyser.visit_expr(rule.expr_idx)
}
}
fn warn_useless_chaining(&self, span: Span, pattern_detected: &'static str, how_to_rewrite: &'static str) -> bool {
span.unstable().warning(format!(
"unnecessary chaining of predicates of the form `{}`\n\
You can rewrite this expression to the equivalent one `{}`.\n\
({} ~~~> {})",
pattern_detected, how_to_rewrite, pattern_detected, how_to_rewrite))
.emit();
true
}
fn check_chain(&mut self, this: usize, outer: PredicateOrRepeat, inner: PredicateOrRepeat, crossed_rule: bool) -> bool {
let span = self.grammar[this].span();
match (outer, inner, crossed_rule) {
(PNot, PNot, false)=> self.warn_useless_chaining(span, "!(!e)", "&e"),
(PAnd, PAnd, _) => self.warn_useless_chaining(span, "&(&e)", "&e"),
(PNot, PAnd, false) => self.warn_useless_chaining(span, "!(&e)", "!e"),
(PAnd, PNot, _) => self.warn_useless_chaining(span, "&(!e)", "!e"),
(POptional, POptional, _) => self.warn_useless_chaining(span, "(e?)?", "e?"),
(POptional, POneOrMore, false) => self.warn_useless_chaining(span, "(e+)?", "e*"),
(POptional, PZeroOrMore, _) => self.warn_useless_chaining(span, "(e*)?", "e*"),
(POneOrMore, POneOrMore, _) => self.warn_useless_chaining(span, "(e+)+", "e+"),
(PZeroOrMore, POneOrMore, _) => self.warn_useless_chaining(span, "(e+)*", "e+"),
(PZeroOrMore, PZeroOrMore, _) => self.warn_useless_chaining(span, "(e*)*", "e*"),
(_, _, _) => false }
}
fn check_chain_and_visit(&mut self, outer: PredicateOrRepeat, this: usize, child: usize) {
let (inner, crossed_rule) = InnerPredicateOrRepeat::new(self.grammar).visit_expr(child);
if !self.check_chain(this, outer, inner, crossed_rule) {
self.visit_expr(child)
}
}
}
struct InnerPredicateOrRepeat<'a> {
grammar: &'a AGrammar
}
impl<'a> InnerPredicateOrRepeat<'a> {
fn new(grammar: &'a AGrammar) -> Self {
InnerPredicateOrRepeat { grammar }
}
}
impl<'a> ExprByIndex for InnerPredicateOrRepeat<'a> {
fn expr_by_index(&self, index: usize) -> Expression {
self.grammar.expr_by_index(index).clone()
}
}
impl<'a> Visitor<(PredicateOrRepeat, bool)> for InnerPredicateOrRepeat<'a> {
fn visit_non_terminal_symbol(&mut self, _this: usize, rule: &Ident) -> (PredicateOrRepeat, bool) {
let expr_idx = self.grammar.expr_index_of_rule(rule);
(self.visit_expr(expr_idx).0, true)
}
fn visit_optional(&mut self, _this: usize, _child: usize) -> (PredicateOrRepeat, bool) {
(POptional, false)
}
fn visit_one_or_more(&mut self, _this: usize, _child: usize) -> (PredicateOrRepeat, bool) {
(POneOrMore, false)
}
fn visit_zero_or_more(&mut self, _this: usize, _child: usize) -> (PredicateOrRepeat, bool) {
(PZeroOrMore, false)
}
fn visit_not_predicate(&mut self, _this: usize, _child: usize) -> (PredicateOrRepeat, bool) {
(PNot, false)
}
fn visit_and_predicate(&mut self, _this: usize, _child: usize) -> (PredicateOrRepeat, bool) {
(PAnd, false)
}
fn visit_sequence(&mut self, _: usize, children: Vec<usize>) -> (PredicateOrRepeat, bool) {
self.visit_expr(children[0])
}
fn visit_choice(&mut self, _: usize, children: Vec<usize>) -> (PredicateOrRepeat, bool) {
let (pred_or_repeat, mut crossed_rule) = self.visit_expr(children[0]);
for child in children {
let (pred_or_repeat2, crossed_rule2) = self.visit_expr(child);
if pred_or_repeat != pred_or_repeat2 {
return (PNothing, false)
}
crossed_rule |= crossed_rule2;
}
(pred_or_repeat, crossed_rule)
}
}
impl<'a> ExprByIndex for UselessChaining<'a>
{
fn expr_by_index(&self, index: usize) -> Expression {
self.grammar.expr_by_index(index).clone()
}
}
impl<'a> Visitor<()> for UselessChaining<'a>
{
unit_visitor_impl!(choice);
unit_visitor_impl!(sequence);
fn visit_one_or_more(&mut self, this: usize, child: usize) {
self.check_chain_and_visit(POneOrMore, this, child)
}
fn visit_zero_or_more(&mut self, this: usize, child: usize){
self.check_chain_and_visit(PZeroOrMore, this, child)
}
fn visit_optional(&mut self, this: usize, child: usize){
self.check_chain_and_visit(POptional, this, child)
}
fn visit_not_predicate(&mut self, this: usize, child: usize){
self.check_chain_and_visit(PNot, this, child)
}
fn visit_and_predicate(&mut self, this: usize, child: usize){
self.check_chain_and_visit(PAnd, this, child)
}
}