use smallvec::SmallVec;
use syntax::ast::Mac;
use syntax::ast::{Expr, ExprKind, Ident, ImplItem, Item, Label, Pat, Path, Stmt, Ty};
use syntax::mut_visit::{self, MutVisitor};
use syntax::ptr::P;
use smallvec::smallvec;
use crate::ast_manip::util::PatternSymbol;
use crate::ast_manip::{AstNode, MutVisit};
use crate::command::CommandState;
use crate::matcher::Bindings;
use crate::RefactorCtxt;
#[allow(unused)]
struct SubstFolder<'a, 'tcx: 'a> {
st: &'a CommandState,
cx: &'a RefactorCtxt<'a, 'tcx>,
bindings: &'a Bindings,
}
impl<'a, 'tcx> SubstFolder<'a, 'tcx> {
fn subst_opt_label(&mut self, ol: &mut Option<Label>) {
if let Some(l) = ol {
let ps = l.ident.pattern_symbol();
if let Some(i) = ps.and_then(|sym| self.bindings.get::<_, Ident>(sym)) {
l.ident = *i;
} else {
let i = ps.and_then(|sym| self.bindings.get_opt::<_, Ident>(sym));
match i {
Some(Some(i)) => l.ident = *i,
Some(None) => {
*ol = None;
return;
}
None => {}
}
}
}
}
}
impl<'a, 'tcx> MutVisitor for SubstFolder<'a, 'tcx> {
fn visit_ident(&mut self, i: &mut Ident) {
if let Some(sym) = i.pattern_symbol() {
if let Some(binding) = self.bindings.get::<_, Ident>(sym) {
*i = *binding;
} else if let Some(ty) = self.bindings.get::<_, P<Ty>>(sym) {
panic!(
"binding {:?} (of type {:?}) has wrong type for hole",
sym, ty
);
}
}
mut_visit::noop_visit_ident(i, self)
}
fn visit_path(&mut self, p: &mut Path) {
if let Some(binding) = p
.pattern_symbol()
.and_then(|sym| self.bindings.get::<_, Path>(sym))
{
*p = binding.clone();
}
mut_visit::noop_visit_path(p, self);
}
fn visit_expr(&mut self, e: &mut P<Expr>) {
if let Some(sym) = e.pattern_symbol() {
if let Some(binding) = self.bindings.get::<_, P<Expr>>(sym) {
*e = binding.clone();
} else if let Some(Some(binding)) = self.bindings.get_opt::<_, P<Expr>>(sym) {
*e = binding.clone();
}
}
match e.kind {
ExprKind::While(_, _, ref mut label) |
ExprKind::ForLoop(_, _, _, ref mut label) |
ExprKind::Loop(_, ref mut label) |
ExprKind::Block(_, ref mut label) |
ExprKind::Break(ref mut label, _) |
ExprKind::Continue(ref mut label) => {
self.subst_opt_label(label);
}
_ => {}
}
mut_visit::noop_visit_expr(e, self);
}
fn visit_pat(&mut self, p: &mut P<Pat>) {
if let Some(binding) = p
.pattern_symbol()
.and_then(|sym| self.bindings.get::<_, P<Pat>>(sym))
{
*p = binding.clone();
}
mut_visit::noop_visit_pat(p, self);
}
fn visit_ty(&mut self, ty: &mut P<Ty>) {
if let Some(sym) = ty.pattern_symbol() {
if let Some(binding) = self.bindings.get::<_, P<Ty>>(sym) {
*ty = binding.clone();
} else if let Some(Some(binding)) = self.bindings.get_opt::<_, P<Ty>>(sym) {
*ty = binding.clone();
}
}
mut_visit::noop_visit_ty(ty, self)
}
fn flat_map_stmt(&mut self, s: Stmt) -> SmallVec<[Stmt; 1]> {
if let Some(stmt) = s
.pattern_symbol()
.and_then(|sym| self.bindings.get::<_, Stmt>(sym))
{
smallvec![stmt.clone()]
} else if let Some(stmts) = s
.pattern_symbol()
.and_then(|sym| self.bindings.get::<_, Vec<Stmt>>(sym))
{
SmallVec::from_vec(stmts.clone())
} else {
mut_visit::noop_flat_map_stmt(s, self)
}
}
fn flat_map_item(&mut self, i: P<Item>) -> SmallVec<[P<Item>; 1]> {
if let Some(item) = i
.pattern_symbol()
.and_then(|sym| self.bindings.get::<_, P<Item>>(sym))
{
smallvec![item.clone()]
} else {
mut_visit::noop_flat_map_item(i, self)
}
}
fn visit_mac(&mut self, mac: &mut Mac) {
mut_visit::noop_visit_mac(mac, self)
}
}
pub trait Subst {
fn subst(self, st: &CommandState, cx: &RefactorCtxt, bindings: &Bindings) -> Self;
}
impl Subst for AstNode {
fn subst(self, st: &CommandState, cx: &RefactorCtxt, bindings: &Bindings) -> Self {
match self {
AstNode::Crate(_) => panic!("Can't subst Crates"),
AstNode::Expr(x) => AstNode::Expr(x.subst(st, cx, bindings)),
AstNode::Pat(x) => AstNode::Pat(x.subst(st, cx, bindings)),
AstNode::Ty(x) => AstNode::Ty(x.subst(st, cx, bindings)),
AstNode::Stmts(x) => AstNode::Stmts(x.subst(st, cx, bindings)),
AstNode::Stmt(x) => AstNode::Stmt(x.subst(st, cx, bindings)),
AstNode::Item(x) => AstNode::Item(x.subst(st, cx, bindings)),
}
}
}
macro_rules! subst_impl {
($ty:ty, $fold_func:ident) => {
impl Subst for $ty {
fn subst(mut self, st: &CommandState, cx: &RefactorCtxt, bindings: &Bindings) -> Self {
let mut f = SubstFolder {
st: st,
cx: cx,
bindings: bindings,
};
self.visit(&mut f);
self
}
}
};
}
macro_rules! multi_subst_impl {
($ty:ty, $fold_func:ident) => {
impl Subst for Vec<$ty> {
fn subst(self, st: &CommandState, cx: &RefactorCtxt, bindings: &Bindings) -> Self {
let mut f = SubstFolder {
st: st,
cx: cx,
bindings: bindings,
};
let mut results = Vec::with_capacity(self.len());
for x in self {
results.extend_from_slice(&x.flat_map(&mut f));
}
results
}
}
};
}
subst_impl!(Ident, fold_ident);
subst_impl!(P<Expr>, fold_expr);
subst_impl!(P<Pat>, fold_pat);
subst_impl!(P<Ty>, fold_ty);
subst_impl!(Stmt, fold_stmt);
subst_impl!(P<Item>, fold_item);
subst_impl!(ImplItem, fold_impl_item);
multi_subst_impl!(Stmt, fold_stmt);
multi_subst_impl!(P<Item>, fold_item);
multi_subst_impl!(ImplItem, fold_impl_item);