Browse Source

start to implement basic matching

Getty Ritter 2 years ago
parent
commit
c93f657683
3 changed files with 210 additions and 16 deletions
  1. 3 0
      Cargo.toml
  2. 26 11
      src/main.rs
  3. 181 5
      src/pattern.rs

+ 3 - 0
Cargo.toml

@@ -11,3 +11,6 @@ clap = "*"
 fehler = "*"
 walkdir = "*"
 crossbeam = "*"
+
+[profile.release]
+debug = true

+ 26 - 11
src/main.rs

@@ -1,3 +1,5 @@
+mod pattern;
+
 use walkdir::WalkDir;
 
 #[derive(Debug)]
@@ -57,14 +59,22 @@ fn main() {
         num_threads,
     } = args;
 
+    let p = pattern::Pattern {
+        node_type: pattern::NodeType::Send,
+        name: Some("ActiveRecord".to_owned()),
+        children: vec![],
+        rest: false,
+    };
+
     let (work_send, work_recv) = crossbeam::channel::unbounded();
+    let (result_send, result_recv) = crossbeam::channel::unbounded();
 
     // produce a thread which populates the channel with work
     let producer = std::thread::spawn(move || {
         for target in targets {
             for entry in WalkDir::new(target).into_iter().filter_map(|e| e.ok()) {
                 if is_ruby_source(entry.path()) {
-                    work_send.send(entry).expect("Unable to send work from producer thread");
+                    work_send.send(entry.into_path()).expect("Unable to send work from producer thread");
                 }
             }
         }
@@ -73,30 +83,35 @@ fn main() {
     // produce a set of threads which can grab work to be done
     let workers: Vec<std::thread::JoinHandle<()>> = (0..num_threads).map(|id| {
         let receiver = work_recv.clone();
+        let sender = result_send.clone();
+        let pat = p.clone();
         std::thread::spawn(move || {
-            while let Ok(msg) = receiver.recv() {
+            while let Ok(ref msg) = receiver.recv() {
                 use std::io::Read;
 
-                // println!("thread {} processing {:?}", id, msg);
                 let mut buf = Vec::new();
                 {
-                    let mut f = std::fs::File::open(msg.path()).expect("Unable to read file");
+                    let mut f = std::fs::File::open(msg).expect("Unable to read file");
                     f.read_to_end(&mut buf).expect("Unable to read file");
                 }
                 let parser = lib_ruby_parser::Parser::new(buf, std::default::Default::default());
                 let lib_ruby_parser::ParserResult { ast, diagnostics, .. } = parser.do_parse();
-                if let Some(_ast) = ast {
-                    // println!("Got ast: {:?}", ast);
-                } else {
-                    println!("Unable to parse {:?}", msg.path());
-                    for d in diagnostics {
-                        println!("  - {:?}", d);
+                if let Some(ast) = ast {
+                    let matches = pat.find_matches(&*ast);
+                    if matches.len() > 0 {
+                        sender.send(format!("{:?}: found matches: {:?}", msg, matches)).unwrap();
                     }
+                } else {
+                    // sender.send(format!("Unable to parse {:?}", msg)).unwrap();
                 }
             }
-            println!("thread {} done", id);
         })
     }).collect();
+    drop(result_send);
+
+    while let Ok(msg) = result_recv.recv() {
+        println!("{}", msg);
+    }
 
     // join all the threads
     producer.join().expect("Producer thread panicked!");

+ 181 - 5
src/pattern.rs

@@ -1,12 +1,188 @@
-#[derive(Eq, PartialEq)]
-enum NodeType {
+use lib_ruby_parser as p;
+
+#[derive(Eq, PartialEq, Copy, Clone)]
+pub enum NodeType {
     Send,
     Local,
     Const,
     Anything,
 }
 
-#[derive(Eq, PartialEq)]
-struct Pattern {
-    node_type: NodeType,
+#[derive(Eq, PartialEq, Clone)]
+pub struct Pattern {
+    pub node_type: NodeType,
+    pub name: Option<String>,
+    pub children: Vec<Pattern>,
+    pub rest: bool,
+}
+
+impl Pattern {
+    pub fn matches(&self, p: &p::Node) -> bool {
+        match p {
+            p::Node::Const(cnst) => {
+                if let Some(name) = &self.name {
+                    &cnst.name == name
+                } else {
+                    false
+                }
+            }
+            _ => false,
+        }
+    }
+
+    pub fn find_matches<'a>(&self, p: &'a p::Node) -> Vec<&'a p::Node> {
+        let mut matches = Vec::new();
+        self.find_matches_ref(p, &mut matches);
+        matches
+    }
+
+    fn find_matches_ref<'a, 'b>(&self, p: &'a p::Node, res: &'b mut Vec<&'a p::Node>) {
+        if self.matches(p) {
+            res.push(p);
+        }
+
+        match p {
+            p::Node::Alias(_) => {}
+            p::Node::AndAsgn(_) => {}
+            p::Node::And(_) => {}
+            p::Node::Arg(_) => {}
+            p::Node::Args(_) => {}
+            p::Node::Array(_) => {}
+            p::Node::ArrayPattern(_) => {}
+            p::Node::ArrayPatternWithTail(_) => {}
+            p::Node::BackRef(_) => {}
+            p::Node::Begin(begin) => {
+                for stmt in begin.statements.iter() {
+                    self.find_matches_ref(stmt, res);
+                }
+            }
+            p::Node::Block(_) => {}
+            p::Node::BlockPass(_) => {}
+            p::Node::Blockarg(_) => {}
+            p::Node::Break(_) => {}
+            p::Node::Case(_) => {}
+            p::Node::CaseMatch(_) => {}
+            p::Node::Casgn(_) => {}
+            p::Node::Cbase(_) => {}
+            p::Node::Class(class) => {
+                self.find_matches_ref(&class.name, res);
+                if let Some(ref superclass) = class.superclass {
+                    self.find_matches_ref(superclass, res);
+                }
+                if let Some(ref body) = class.body {
+                    self.find_matches_ref(body, res);
+                }
+            }
+            p::Node::Complex(_) => {}
+            p::Node::Const(_) => {}
+            p::Node::ConstPattern(_) => {}
+            p::Node::CSend(_) => {}
+            p::Node::Cvar(_) => {}
+            p::Node::Cvasgn(_) => {}
+            p::Node::Def(_) => {}
+            p::Node::Defined(_) => {}
+            p::Node::Defs(_) => {}
+            p::Node::Dstr(_) => {}
+            p::Node::Dsym(_) => {}
+            p::Node::EFlipFlop(_) => {}
+            p::Node::EmptyElse(_) => {}
+            p::Node::Encoding(_) => {}
+            p::Node::Ensure(_) => {}
+            p::Node::Erange(_) => {}
+            p::Node::False(_) => {}
+            p::Node::File(_) => {}
+            p::Node::FindPattern(_) => {}
+            p::Node::Float(_) => {}
+            p::Node::For(_) => {}
+            p::Node::ForwardArg(_) => {}
+            p::Node::ForwardedArgs(_) => {}
+            p::Node::Gvar(_) => {}
+            p::Node::Gvasgn(_) => {}
+            p::Node::Hash(_) => {}
+            p::Node::Kwargs(_) => {}
+            p::Node::HashPattern(_) => {}
+            p::Node::Heredoc(_) => {}
+            p::Node::If(_) => {}
+            p::Node::IfGuard(_) => {}
+            p::Node::IfMod(_) => {}
+            p::Node::IfTernary(_) => {}
+            p::Node::IFlipFlop(_) => {}
+            p::Node::MatchPattern(_) => {}
+            p::Node::MatchPatternP(_) => {}
+            p::Node::InPattern(_) => {}
+            p::Node::Index(_) => {}
+            p::Node::IndexAsgn(_) => {}
+            p::Node::Int(_) => {}
+            p::Node::Irange(_) => {}
+            p::Node::Ivar(_) => {}
+            p::Node::Ivasgn(_) => {}
+            p::Node::Kwarg(_) => {}
+            p::Node::KwBegin(_) => {}
+            p::Node::Kwnilarg(_) => {}
+            p::Node::Kwoptarg(_) => {}
+            p::Node::Kwrestarg(_) => {}
+            p::Node::Kwsplat(_) => {}
+            p::Node::Lambda(_) => {}
+            p::Node::Line(_) => {}
+            p::Node::Lvar(_) => {}
+            p::Node::Lvasgn(_) => {}
+            p::Node::Masgn(_) => {}
+            p::Node::MatchAlt(_) => {}
+            p::Node::MatchAs(_) => {}
+            p::Node::MatchCurrentLine(_) => {}
+            p::Node::MatchNilPattern(_) => {}
+            p::Node::MatchRest(_) => {}
+            p::Node::MatchVar(_) => {}
+            p::Node::MatchWithLvasgn(_) => {}
+            p::Node::Mlhs(_) => {}
+            p::Node::Module(module) => {
+                self.find_matches_ref(&module.name, res);
+                if let Some(ref body) = module.body {
+                    self.find_matches_ref(body, res);
+                }
+            }
+            p::Node::Next(_) => {}
+            p::Node::Nil(_) => {}
+            p::Node::NthRef(_) => {}
+            p::Node::Numblock(_) => {}
+            p::Node::OpAsgn(_) => {}
+            p::Node::Optarg(_) => {}
+            p::Node::Or(_) => {}
+            p::Node::OrAsgn(_) => {}
+            p::Node::Pair(_) => {}
+            p::Node::Pin(_) => {}
+            p::Node::Postexe(_) => {}
+            p::Node::Preexe(_) => {}
+            p::Node::Procarg0(_0) => {}
+            p::Node::Rational(_) => {}
+            p::Node::Redo(_) => {}
+            p::Node::RegOpt(_) => {}
+            p::Node::Regexp(_) => {}
+            p::Node::Rescue(_) => {}
+            p::Node::RescueBody(_) => {}
+            p::Node::Restarg(_) => {}
+            p::Node::Retry(_) => {}
+            p::Node::Return(_) => {}
+            p::Node::SClass(_) => {}
+            p::Node::Self_(__) => {}
+            p::Node::Send(_) => {}
+            p::Node::Shadowarg(_) => {}
+            p::Node::Splat(_) => {}
+            p::Node::Str(_) => {}
+            p::Node::Super(_) => {}
+            p::Node::Sym(_) => {}
+            p::Node::True(_) => {}
+            p::Node::Undef(_) => {}
+            p::Node::UnlessGuard(_) => {}
+            p::Node::Until(_) => {}
+            p::Node::UntilPost(_) => {}
+            p::Node::When(_) => {}
+            p::Node::While(_) => {}
+            p::Node::WhilePost(_) => {}
+            p::Node::XHeredoc(_) => {}
+            p::Node::Xstr(_) => {}
+            p::Node::Yield(_) => {}
+            p::Node::ZSuper(_) => {}
+        }
+    }
 }