@@ -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 | ||||