use regex::Regex;
use std::collections::HashSet;
use syntax::ast::*;
use syntax::ptr::P;
use syntax::symbol::Symbol;
use crate::command::CommandState;
use crate::command::{DriverCommand, Registry};
use crate::driver::Phase;
use crate::pick_node::NodeKind;
use crate::resolve;
use crate::RefactorCtxt;
use c2rust_ast_builder::IntoSymbol;
pub use self::filter::ItemLikeKind;
pub mod filter;
pub mod parse;
pub mod visitor;
#[derive(Clone, Debug)]
pub enum SelectOp {
Marked(Symbol),
Mark(Symbol),
Unmark(Symbol),
Reset,
Crate,
Item(Path),
ChildMatch(Filter),
DescMatch(Filter),
Filter(Filter),
First,
Last,
}
#[derive(Clone, Debug)]
pub enum Filter {
Kind(NodeKind),
ItemKind(ItemLikeKind),
Public,
Mutable,
Name(Regex),
PathPrefix(usize, Box<Path>),
HasAttr(Symbol),
Matches(AnyPattern),
Marked(Symbol),
AnyChild(Box<Filter>),
AllChild(Box<Filter>),
AnyDesc(Box<Filter>),
AllDesc(Box<Filter>),
And(Vec<Filter>),
Or(Vec<Filter>),
Not(Box<Filter>),
}
#[derive(Clone, Debug)]
pub enum AnyPattern {
Expr(P<Expr>),
Pat(P<Pat>),
Ty(P<Ty>),
Stmt(Stmt),
}
pub fn run_select<S: IntoSymbol>(st: &CommandState, cx: &RefactorCtxt, ops: &[SelectOp], label: S) {
let mut sel = HashSet::new();
for op in ops {
match *op {
SelectOp::Marked(label) => {
for &(id, mark_label) in st.marks().iter() {
if mark_label == label {
sel.insert(id);
}
}
}
SelectOp::Mark(label) => {
for &id in &sel {
st.add_mark(id, label);
}
}
SelectOp::Unmark(label) => {
for &id in &sel {
st.remove_mark(id, label);
}
}
SelectOp::Reset => {
sel = HashSet::new();
}
SelectOp::Crate => {
sel.insert(CRATE_NODE_ID);
}
SelectOp::Item(ref path) => {
let segs = path
.segments
.iter()
.map(|seg| seg.ident)
.collect::<Vec<_>>();
let def = resolve::resolve_absolute(cx.ty_ctxt(), &segs);
let node_id = cx.hir_map().as_local_node_id(def.def_id()).unwrap();
sel.insert(node_id);
}
SelectOp::ChildMatch(ref filt) => {
sel = visitor::matching_children(st, cx, &st.krate(), sel, filt);
}
SelectOp::DescMatch(ref filt) => {
sel = visitor::matching_descendants(st, cx, &st.krate(), sel, filt);
}
SelectOp::Filter(ref filt) => {
sel = visitor::filter(st, cx, &st.krate(), sel, filt);
}
SelectOp::First => {
sel = sel.into_iter().min().into_iter().collect();
}
SelectOp::Last => {
sel = sel.into_iter().max().into_iter().collect();
}
}
}
let label = label.into_symbol();
for id in sel {
st.add_mark(id, label);
}
}
fn register_select(reg: &mut Registry) {
reg.register("select", |args| {
let label = (&args[0]).into_symbol();
let ops_str = args[1].clone();
Box::new(DriverCommand::new(Phase::Phase3, move |st, cx| {
let ops = parse::parse(cx.session(), &ops_str);
eprintln!("running select: {:?} -> {}", ops, label);
run_select(st, cx, &ops, label);
}))
});
}
fn register_select_phase2(reg: &mut Registry) {
reg.register("select_phase2", |args| {
let label = (&args[0]).into_symbol();
let ops_str = args[1].clone();
Box::new(DriverCommand::new(Phase::Phase2, move |st, cx| {
let ops = parse::parse(cx.session(), &ops_str);
eprintln!("running select (phase2): {:?} -> {}", ops, label);
run_select(st, cx, &ops, label);
}))
});
}
pub fn register_commands(reg: &mut Registry) {
register_select(reg);
register_select_phase2(reg);
}