spidior 0.2.2

A tool for handling sed-like substitution tasks where pesky source code semantics are getting in the way.
use std::collections::HashMap;

use crate::languages::parsing::{Functions, Identifier, Identifiers};
pub struct QueryEngine {
    idents: Vec<Identifier>,
    function_locations: HashMap<String, (usize, usize)>,
    offset: usize,
}

impl QueryEngine {
    #[cfg(test)]
    pub fn new() -> Self {
        Self {
            idents: vec![],
            function_locations: HashMap::new(),
            offset: 0,
        }
    }

    pub fn set_offset(&mut self, offset: usize) {
        self.offset = offset;
    }

    pub fn build(s: &String, i: Box<dyn Identifiers>, f: Box<dyn Functions>) -> Self {
        let functs = f.read_functions(s);
        let mut function_locations = HashMap::new();
        for fun in &functs {
            function_locations.insert(fun.name.clone(), (fun.start, fun.end));
        }
        Self {
            idents: i.read_identifiers(s),
            function_locations,
            offset: 0,
        }
    }

    pub fn function_location(&self, name: &String) -> Option<(usize, usize)> {
        self.function_locations.get(name).copied()
    }

    pub fn query(&self, position: usize, query: &String) -> Option<usize> {
        let mut c = crate::regexparser::query::QueriesParser::new()
            .parse(query)
            .unwrap();
        let mut name = None;
        let mut kind = None;
        loop {
            match *c {
                crate::regexparser::ast::Queries::Query(x) => {
                    match *x {
                        crate::regexparser::ast::Query::Kv(k, v) if k == "type" => {
                            kind = Some(v);
                        }
                        crate::regexparser::ast::Query::Kv(k, v) if k == "name" => {
                            name = Some(v);
                        }
                        crate::regexparser::ast::Query::Kv(k, v) if k == "pos" => {
                            let mut s = v.split(":");
                            let (pos_str, len_str) = (s.next()?, s.next()?);
                            let (pos, len) = (pos_str.parse::<usize>().ok()?, len_str.parse::<usize>().ok()?);
                            if position + self.offset == pos {
                                return Some(len);
                            } else {
                                return None;
                            }
                        }
                        _ => {}
                    }
                    break;
                }
                crate::regexparser::ast::Queries::Queries(x, r) => {
                    match *x {
                        crate::regexparser::ast::Query::Kv(k, v) if k == "type" => {
                            kind = Some(v);
                        }
                        crate::regexparser::ast::Query::Kv(k, v) if k == "name" => {
                            name = Some(v);
                        }
                        crate::regexparser::ast::Query::Kv(k, v) if k == "pos" => {
                            let mut s = v.split(":");
                            let (pos_str, len_str) = (s.next()?, s.next()?);
                            let (pos, len) = (pos_str.parse::<usize>().ok()?, len_str.parse::<usize>().ok()?);
                            if position + self.offset == pos {
                                return Some(len);
                            } else {
                                return None;
                            }
                        }
                        _ => {}
                    }
                    c = r;
                }
            }
        }
        for ident in &self.idents {
            if match name {
                Some(ref y) => *y == ident.name,
                None => true,
            } && match kind {
                Some(ref y) => *y == ident.type_name,
                None => true,
            } && position + self.offset == ident.start
            {
                return Some(ident.end - self.offset);
            }
        }
        None
    }
}