| @@ -63,7 +63,7 @@ def crawl(): | |||||
| for thread in threads: | for thread in threads: | ||||
| thread.join() | thread.join() | ||||
| for server in parse_servers: | for server in parse_servers: | ||||
| server.kill() | |||||
| server.terminate() | |||||
| def _configure_logging(): | def _configure_logging(): | ||||
| # This isn't ideal, since it means the bitshift python package must be kept | # This isn't ideal, since it means the bitshift python package must be kept | ||||
| @@ -153,13 +153,14 @@ class Database(object): | |||||
| query1 = "INSERT INTO symbols VALUES (DEFAULT, ?, ?, ?)" | query1 = "INSERT INTO symbols VALUES (DEFAULT, ?, ?, ?)" | ||||
| query2 = """INSERT INTO symbol_locations VALUES | query2 = """INSERT INTO symbol_locations VALUES | ||||
| (DEFAULT, ?, ?, ?, ?, ?, ?)""" | (DEFAULT, ?, ?, ?, ?, ?, ?)""" | ||||
| build = lambda id, L, typ: [tuple([id, typ] + list(loc)) for loc in L] | |||||
| type_id = Symbol.TYPES.index(sym_type) | type_id = Symbol.TYPES.index(sym_type) | ||||
| for (name, assigns, uses) in symbols: | for (name, assigns, uses) in symbols: | ||||
| cursor.execute(query1, (code_id, type_id, name)) | cursor.execute(query1, (code_id, type_id, name)) | ||||
| sym_id = cursor.lastrowid | sym_id = cursor.lastrowid | ||||
| params = ([tuple([sym_id, 0] + list(loc)) for loc in assigns] + | |||||
| [tuple([sym_id, 1] + list(loc)) for loc in uses]) | |||||
| params = [build(sym_id, assigns, Symbol.ASSIGN), | |||||
| build(sym_id, uses, Symbol.USE)] | |||||
| cursor.executemany(query2, params) | cursor.executemany(query2, params) | ||||
| def close(self): | def close(self): | ||||
| @@ -170,15 +170,26 @@ class _QueryParser(object): | |||||
| def _parse_symbol(self, term, stype=Symbol.ALL): | def _parse_symbol(self, term, stype=Symbol.ALL): | ||||
| """Parse part of a query into a symbol node and return it.""" | """Parse part of a query into a symbol node and return it.""" | ||||
| assigns = ("a:", "assign:", "assignment:", "d:", "def:", "definition:", | |||||
| "decl:", "declare:", "declaration:") | |||||
| uses = ("u:", "use:", "c:", "call:") | |||||
| if term.startswith(assigns) or term.startswith(uses): | |||||
| context = Symbol.ASSIGN if term.startswith(assigns) else Symbol.USE | |||||
| term_part = term.split(":", 1)[1] | |||||
| if not term_part: | |||||
| raise QueryParseException('Incomplete query term: "%s"' % term) | |||||
| term = term_part | |||||
| else: | |||||
| context = Symbol.ALL | |||||
| literal = self._parse_literal(term) | literal = self._parse_literal(term) | ||||
| if isinstance(literal, String): | if isinstance(literal, String): | ||||
| make_symbol = lambda lit: Symbol(stype, String(lit)) | |||||
| make_symbol = lambda lit: Symbol(context, stype, String(lit)) | |||||
| symbols = self._split_query(literal.string, " \"'") | symbols = self._split_query(literal.string, " \"'") | ||||
| node = make_symbol(symbols.pop()) | node = make_symbol(symbols.pop()) | ||||
| while symbols: | while symbols: | ||||
| node = BinaryOp(make_symbol(symbols.pop()), BinaryOp.OR, node) | node = BinaryOp(make_symbol(symbols.pop()), BinaryOp.OR, node) | ||||
| return node | return node | ||||
| return Symbol(stype, literal) | |||||
| return Symbol(context, stype, literal) | |||||
| def _parse_function(self, term): | def _parse_function(self, term): | ||||
| """Parse part of a query into a function node and return it.""" | """Parse part of a query into a function node and return it.""" | ||||
| @@ -191,6 +191,9 @@ class Symbol(_Node): | |||||
| Searches in symbol_type and symbol_name. | Searches in symbol_type and symbol_name. | ||||
| """ | """ | ||||
| ALL = -1 | ALL = -1 | ||||
| ASSIGN = 0 | |||||
| USE = 1 | |||||
| FUNCTION = 0 | FUNCTION = 0 | ||||
| CLASS = 1 | CLASS = 1 | ||||
| VARIABLE = 2 | VARIABLE = 2 | ||||
| @@ -202,17 +205,20 @@ class Symbol(_Node): | |||||
| TYPE_REPR = ["FUNCTION", "CLASS", "VARIABLE", "NAMESPACE", "INTERFACE", | TYPE_REPR = ["FUNCTION", "CLASS", "VARIABLE", "NAMESPACE", "INTERFACE", | ||||
| "IMPORT"] | "IMPORT"] | ||||
| def __init__(self, type_, name): | |||||
| def __init__(self, context, type_, name): | |||||
| """ | """ | ||||
| :type context: int (``ASSIGN`` or ``USE``) | |||||
| :type type_: int (``ALL``, ``FUNCTION``, ``CLASS``, etc.) | :type type_: int (``ALL``, ``FUNCTION``, ``CLASS``, etc.) | ||||
| :type name: :py:class:`._Literal` | :type name: :py:class:`._Literal` | ||||
| """ | """ | ||||
| self.context = context | |||||
| self.type = type_ | self.type = type_ | ||||
| self.name = name | self.name = name | ||||
| def __repr__(self): | def __repr__(self): | ||||
| context = ["ASSIGN", "USE", "ALL"][self.context] | |||||
| type_ = self.TYPE_REPR[self.type] if self.type >= 0 else "ALL" | type_ = self.TYPE_REPR[self.type] if self.type >= 0 else "ALL" | ||||
| return "Symbol({0}, {1})".format(type_, self.name) | |||||
| return "Symbol({0}, {1}, {2})".format(context, type_, self.name) | |||||
| def sortkey(self): | def sortkey(self): | ||||
| return self.name.sortkey() | return self.name.sortkey() | ||||
| @@ -228,6 +234,9 @@ class Symbol(_Node): | |||||
| cond += " AND symbol_type IN (%s)" % types | cond += " AND symbol_type IN (%s)" % types | ||||
| if self.type != self.ALL: | if self.type != self.ALL: | ||||
| cond += " AND symbol_type = %d" % self.type | cond += " AND symbol_type = %d" % self.type | ||||
| if self.context != self.ALL: | |||||
| tables |= {"symbol_locations"} | |||||
| cond += " AND sloc_type = %d" % self.context | |||||
| return "(" + cond + ")", [name], [], False | return "(" + cond + ")", [name], [], False | ||||
| @@ -2,7 +2,7 @@ from . import nodes | |||||
| __all__ = ["Tree"] | __all__ = ["Tree"] | ||||
| QUERY_TEMPLATE = """SELECT codelet_id, (codelet_rank%s) AS score | |||||
| QUERY_TEMPLATE = """SELECT codelet_id, MAX(codelet_rank%s) AS score | |||||
| FROM codelets %s | FROM codelets %s | ||||
| WHERE %s | WHERE %s | ||||
| GROUP BY codelet_id | GROUP BY codelet_id | ||||
| @@ -59,13 +59,14 @@ class Tree(object): | |||||
| :rtype: 2-tuple of (SQL statement string, query parameter tuple) | :rtype: 2-tuple of (SQL statement string, query parameter tuple) | ||||
| """ | """ | ||||
| def get_table_joins(tables): | def get_table_joins(tables): | ||||
| data = [ | |||||
| joins = [ | |||||
| ("code", "codelet_code_id", "code_id"), | ("code", "codelet_code_id", "code_id"), | ||||
| ("authors", "author_codelet", "codelet_id"), | ("authors", "author_codelet", "codelet_id"), | ||||
| ("symbols", "symbol_code", "code_id") | |||||
| ("symbols", "symbol_code", "code_id"), | |||||
| ("symbol_locations", "sloc_symbol", "symbol_id") | |||||
| ] | ] | ||||
| tmpl = "INNER JOIN %s ON %s = %s" | tmpl = "INNER JOIN %s ON %s = %s" | ||||
| for args in data: | |||||
| for args in joins: | |||||
| if args[0] in tables: | if args[0] in tables: | ||||
| yield tmpl % args | yield tmpl % args | ||||