pub use std::collections::HashMap;
use middle::analysis::ast::*;
use partial::Partial::*;
pub fn rule_duplicate(mut grammar: AGrammar, rules: Vec<Rule>) -> Partial<AGrammar>
{
DuplicateItem::analyse(rules.into_iter(), String::from("rule"))
.map(move |rules| {
grammar.rules = rules.into_iter().map(|x| x.1).collect();
grammar
})
}
pub fn rust_functions_duplicate(mut grammar: AGrammar, items: Vec<syn::Item>) -> Partial<AGrammar>
{
let mut functions = vec![];
let mut others = vec![];
for item in items {
if let syn::Item::Fn(fun) = item {
functions.push(fun);
}
else {
others.push(item);
}
}
DuplicateItem::analyse(functions.into_iter(), String::from("rust function"))
.map(move |functions| {
grammar.rust_functions = functions.into_iter().collect();
grammar.rust_items = others;
grammar
})
}
struct DuplicateItem<Item>
{
items: Vec<(Ident, Item)>,
has_duplicate: bool,
what_is_duplicated: String
}
impl<Item> DuplicateItem<Item> where
Item: ItemIdent + Spanned
{
pub fn analyse<ItemIter>(iter: ItemIter, item_kind: String)
-> Partial<Vec<(Ident, Item)>> where
ItemIter: Iterator<Item=Item>
{
DuplicateItem {
items: vec![],
has_duplicate: false,
what_is_duplicated: item_kind
}.populate(iter)
.make()
}
fn populate<ItemIter: Iterator<Item=Item>>(mut self, iter: ItemIter)
-> DuplicateItem<Item>
{
for item in iter {
let ident = item.ident();
if self.items.iter().any(|&(ref id,_)| *id == ident) {
let &(_, ref dup_item) = self.items.iter().find(|&&(ref id,_)| *id == ident).unwrap();
self.duplicate_items(dup_item, item);
self.has_duplicate = true;
}
else {
self.items.push((ident, item));
}
}
self
}
fn duplicate_items(&self, pre: &Item, current: Item) {
current.span().unstable()
.error(format!("duplicate definition of {} with name `{}`", self.what_is_duplicated, current.ident()))
.span_note(pre.span().unstable(), format!("previous definition of `{}` here", pre.ident()))
.emit();
}
fn make(self) -> Partial<Vec<(Ident, Item)>> {
if self.has_duplicate {
Fake(self.items)
} else {
Value(self.items)
}
}
}