| @@ -1,4 +1,4 @@ | |||||
| import ast, pygments.lexers as pgl, sys, socket, struct | |||||
| import json, pygments.lexers as pgl, sys, socket, struct | |||||
| from ..languages import LANGS | from ..languages import LANGS | ||||
| from .python import parse_py | from .python import parse_py | ||||
| @@ -19,13 +19,13 @@ def _lang(codelet): | |||||
| Modify function to incorporate tags from stackoverflow. | Modify function to incorporate tags from stackoverflow. | ||||
| """ | """ | ||||
| try: | |||||
| if codelet.filename is not None: | |||||
| if codelet.filename is not None: | |||||
| try: | |||||
| return pgl.guess_lexer_for_filename(codelet.filename, '').name | return pgl.guess_lexer_for_filename(codelet.filename, '').name | ||||
| except: | |||||
| raise UnsupportedFileError('Could not find a lexer for the codelet\'s filename') | |||||
| return LANGS.index(pgl.guess_lexer(codelet.code)) | |||||
| except: | |||||
| raise UnsupportedFileError('Could not find a lexer for the codelet\'s filename') | |||||
| return LANGS.index(pgl.guess_lexer(codelet.code)) | |||||
| def _recv_data(server_socket): | def _recv_data(server_socket): | ||||
| """ | """ | ||||
| @@ -88,6 +88,6 @@ def parse(codelet): | |||||
| server_socket.connect(("localhost", server_socket_number)) | server_socket.connect(("localhost", server_socket_number)) | ||||
| server_socket.send("%d\n%s" % (len(source), source)); | server_socket.send("%d\n%s" % (len(source), source)); | ||||
| symbols = ast.literal_eval(_recv_data(server_socket)) | |||||
| symbols = json.loads(_recv_data(server_socket)) | |||||
| codelet.symbols = symbols | codelet.symbols = symbols | ||||
| @@ -1,6 +1,6 @@ | |||||
| import ast | import ast | ||||
| class _TreeCutter(ast.NodeVisitor): | |||||
| class _CachedWalker(ast.NodeVisitor): | |||||
| """ | """ | ||||
| Local node visitor for python abstract syntax trees. | Local node visitor for python abstract syntax trees. | ||||
| @@ -22,9 +22,9 @@ class _TreeCutter(ast.NodeVisitor): | |||||
| """ | """ | ||||
| self.accum = {'vars': {}, 'functions': {}, 'classes': {}} | self.accum = {'vars': {}, 'functions': {}, 'classes': {}} | ||||
| self.cache = None | |||||
| self.cache = [] | |||||
| def start_n_end(self, node): | |||||
| def block_position(self, node): | |||||
| """ | """ | ||||
| Helper function to get the start and end lines of an AST node. | Helper function to get the start and end lines of an AST node. | ||||
| @@ -54,32 +54,19 @@ class _TreeCutter(ast.NodeVisitor): | |||||
| Add value and type metadata to accum. | Add value and type metadata to accum. | ||||
| """ | """ | ||||
| for t in node.targets: | |||||
| if isinstance(t, ast.Tuple): | |||||
| for n in t.elts: | |||||
| line, col = n.lineno, n.col_offset | |||||
| line, col = node.lineno, node.col_offset | |||||
| pos = (line, col, line, col) | |||||
| if not self.accum['vars'].has_key(node.name): | |||||
| self.accum['vars'][node.name] = {'declaration': {}, 'uses': []} | |||||
| pos = {'coord': {}} | |||||
| pos['coord']['start_line'] = line | |||||
| pos['coord']['start_col'] = col | |||||
| pos['coord']['end_line'] = line | |||||
| pos['coord']['end_col'] = col | |||||
| self.accum['vars'][n.id]['declaration'] = pos | |||||
| self.cache.append({'nodes': []}) | |||||
| self.generic_visit(node) | |||||
| last = self.cache.pop() | |||||
| else: | |||||
| line, col = t.lineno, t.col_offset | |||||
| for name in last['nodes']: | |||||
| if not self.accum['vars'].has_key(name): | |||||
| self.accum['vars'][name] = {'assignments': [], 'uses': []} | |||||
| pos = {'coord': {}} | |||||
| pos['coord']['start_line'] = line | |||||
| pos['coord']['start_col'] = col | |||||
| pos['coord']['end_line'] = line | |||||
| pos['coord']['end_col'] = col | |||||
| self.accum['vars'][t.id]['declaration'] = pos | |||||
| self.accum['vars'][name]['assignments'].append(pos) | |||||
| self.generic_visit(node) | |||||
| def visit_FunctionDef(self, node): | def visit_FunctionDef(self, node): | ||||
| """ | """ | ||||
| @@ -93,17 +80,13 @@ class _TreeCutter(ast.NodeVisitor): | |||||
| Add arguments and decorators metadata to accum. | Add arguments and decorators metadata to accum. | ||||
| """ | """ | ||||
| start_line, start_col, end_line, end_col = self.start_n_end(node) | |||||
| start_line, start_col, end_line, end_col = self.block_position(node) | |||||
| if not self.accum['functions'].has_key(node.name): | if not self.accum['functions'].has_key(node.name): | ||||
| self.accum['functions'][node.name] = {'declaration': {}, 'calls': []} | |||||
| self.accum['functions'][node.name] = {'assignments': [], 'uses': []} | |||||
| pos = {'coord': {}} | |||||
| pos['coord']['start_ln']= start_line | |||||
| pos['coord']['start_col'] = start_col | |||||
| pos['coord']['end_ln'] = end_line | |||||
| pos['coord']['end_col'] = end_col | |||||
| self.accum['functions'][node.name]['declaration'] = pos | |||||
| pos = (start_line, start_col, end_line, end_col) | |||||
| self.accum['functions'][node.name]['assignments'].append(pos) | |||||
| self.generic_visit(node) | self.generic_visit(node) | ||||
| @@ -120,20 +103,18 @@ class _TreeCutter(ast.NodeVisitor): | |||||
| Add arguments and decorators metadata to accum. | Add arguments and decorators metadata to accum. | ||||
| """ | """ | ||||
| line, col = node.line_no, node.col_offset | |||||
| line, col = node.lineno, node.col_offset | |||||
| pos = (line, col, line, col) | |||||
| if not self.accum['functions'].has_key(node.name): | |||||
| self.accum['functions'][node.name] = {'declaration': {}, 'calls': []} | |||||
| if isinstance(node.func, ast.Name): | |||||
| name = node.func.id | |||||
| else: | |||||
| name = node.func.attr | |||||
| pos = {'coord': {}} | |||||
| pos['coord']['start_line'] = line | |||||
| pos['coord']['start_col'] = col | |||||
| pos['coord']['end_line'] = line | |||||
| pos['coord']['end_col'] = col | |||||
| self.accum['functions'][node.name]['calls'].append(pos) | |||||
| self.generic_visit(node) | |||||
| if not self.accum['functions'].has_key(name): | |||||
| self.accum['functions'][name] = {'assignments': [], 'uses': []} | |||||
| self.accum['functions'][name]['uses'].append(pos) | |||||
| def visit_ClassDef(self, node): | def visit_ClassDef(self, node): | ||||
| """ | """ | ||||
| @@ -147,19 +128,22 @@ class _TreeCutter(ast.NodeVisitor): | |||||
| Add arguments, inherits, and decorators metadata to accum. | Add arguments, inherits, and decorators metadata to accum. | ||||
| """ | """ | ||||
| start_line, start_col, end_line, end_col = self.start_n_end(node) | |||||
| start_line, start_col, end_line, end_col = self.block_position(node) | |||||
| pos = {'coord': {}} | |||||
| pos['coord']['start_ln']= start_line | |||||
| pos['coord']['start_col'] = start_col | |||||
| pos['coord']['end_ln'] = end_line | |||||
| pos['coord']['end_col'] = end_col | |||||
| pos = (start_line, start_col, end_line, end_col) | |||||
| self.accum['classes'][node.name] = pos | self.accum['classes'][node.name] = pos | ||||
| self.generic_visit(node) | self.generic_visit(node) | ||||
| def visit_Name(self, node): | def visit_Name(self, node): | ||||
| pass | |||||
| if self.cache: | |||||
| last = self.cache[-1] | |||||
| last['nodes'].append(node.id) | |||||
| def visit_Attribute(self, node): | |||||
| if self.cache: | |||||
| last = self.cache[-1] | |||||
| last['nodes'].append(node.attr) | |||||
| def parse_py(codelet): | def parse_py(codelet): | ||||
| """ | """ | ||||
| @@ -171,6 +155,6 @@ def parse_py(codelet): | |||||
| """ | """ | ||||
| tree = ast.parse(codelet.code) | tree = ast.parse(codelet.code) | ||||
| cutter = _TreeCutter() | |||||
| cutter = _CachedWalker() | |||||
| cutter.visit(tree) | cutter.visit(tree) | ||||
| codelet.symbols = cutter.accum | codelet.symbols = cutter.accum | ||||
| @@ -16,8 +16,7 @@ | |||||
| <version>3.8.1</version> | <version>3.8.1</version> | ||||
| <scope>test</scope> | <scope>test</scope> | ||||
| </dependency> | </dependency> | ||||
| <dependency> | |||||
| <dependency> | |||||
| <groupId>org.eclipse.jdt</groupId> | <groupId>org.eclipse.jdt</groupId> | ||||
| <artifactId>core</artifactId> | <artifactId>core</artifactId> | ||||
| <version>3.3.0-v_771</version> | <version>3.3.0-v_771</version> | ||||
| @@ -42,9 +42,17 @@ public class JavaSymbols extends Symbols { | |||||
| HashMap<String, Object> method = this._methods.get(name); | HashMap<String, Object> method = this._methods.get(name); | ||||
| if (method == null) { | if (method == null) { | ||||
| method = new HashMap<String, Object>(); | method = new HashMap<String, Object>(); | ||||
| method.put("declaration", data); | |||||
| ArrayList<Object> assignments = new ArrayList<Object>(10); | |||||
| ArrayList<Object> uses = new ArrayList<Object>(10); | |||||
| assignments.add(data.get("coord")); | |||||
| method.put("assignments", assignments); | |||||
| method.put("uses", uses); | |||||
| } else { | } else { | ||||
| method.put("declaration", data); | |||||
| ArrayList<Object> assignments = (ArrayList<Object>)method.get("assignments"); | |||||
| assignments.add(data.get("coord")); | |||||
| method.put("assignments", assignments); | |||||
| } | } | ||||
| this._methods.put(name, method); | this._methods.put(name, method); | ||||
| @@ -54,14 +62,17 @@ public class JavaSymbols extends Symbols { | |||||
| HashMap<String, Object> method = this._methods.get(name); | HashMap<String, Object> method = this._methods.get(name); | ||||
| if (method == null) { | if (method == null) { | ||||
| method = new HashMap<String, Object>(); | method = new HashMap<String, Object>(); | ||||
| ArrayList<Object> calls = new ArrayList<Object>(10); | |||||
| calls.add(data); | |||||
| method.put("calls", calls); | |||||
| ArrayList<Object> assignments = new ArrayList<Object>(10); | |||||
| ArrayList<Object> uses = new ArrayList<Object>(10); | |||||
| uses.add(data.get("coord")); | |||||
| method.put("assignments", assignments); | |||||
| method.put("uses", uses); | |||||
| } else { | } else { | ||||
| ArrayList<Object> calls = (ArrayList<Object>)method.get("calls"); | |||||
| calls = (calls == null) ? new ArrayList<Object>(10) : calls; | |||||
| calls.add(data); | |||||
| method.put("calls", calls); | |||||
| ArrayList<Object> uses = (ArrayList<Object>)method.get("uses"); | |||||
| uses.add(data.get("coord")); | |||||
| method.put("uses", uses); | |||||
| } | } | ||||
| this._methods.put(name, method); | this._methods.put(name, method); | ||||
| @@ -77,9 +88,17 @@ public class JavaSymbols extends Symbols { | |||||
| HashMap<String, Object> var = this._vars.get(name); | HashMap<String, Object> var = this._vars.get(name); | ||||
| if (var == null) { | if (var == null) { | ||||
| var = new HashMap<String, Object>(); | var = new HashMap<String, Object>(); | ||||
| var.put("declaration", data); | |||||
| ArrayList<Object> assignments = new ArrayList<Object>(10); | |||||
| ArrayList<Object> uses = new ArrayList<Object>(10); | |||||
| assignments.add(data.get("coord")); | |||||
| var.put("assignments", assignments); | |||||
| var.put("uses", uses); | |||||
| } else { | } else { | ||||
| var.put("declaration", data); | |||||
| ArrayList<Object> assignments = (ArrayList<Object>)var.get("assignments"); | |||||
| assignments.add(data.get("coord")); | |||||
| var.put("assignments", assignments); | |||||
| } | } | ||||
| this._vars.put(name, var); | this._vars.put(name, var); | ||||
| @@ -89,13 +108,16 @@ public class JavaSymbols extends Symbols { | |||||
| HashMap<String, Object> var = this._vars.get(name); | HashMap<String, Object> var = this._vars.get(name); | ||||
| if (var == null) { | if (var == null) { | ||||
| var = new HashMap<String, Object>(); | var = new HashMap<String, Object>(); | ||||
| ArrayList<Object> assignments = new ArrayList<Object>(10); | |||||
| ArrayList<Object> uses = new ArrayList<Object>(10); | ArrayList<Object> uses = new ArrayList<Object>(10); | ||||
| uses.add(data); | |||||
| uses.add(data.get("coord")); | |||||
| var.put("assignments", assignments); | |||||
| var.put("uses", uses); | var.put("uses", uses); | ||||
| } else { | } else { | ||||
| ArrayList<Object> uses = (ArrayList<Object>)var.get("uses"); | ArrayList<Object> uses = (ArrayList<Object>)var.get("uses"); | ||||
| uses = (uses == null) ? new ArrayList<Object>(10) : uses; | |||||
| uses.add(data); | |||||
| uses.add(data.get("coord")); | |||||
| var.put("uses", uses); | var.put("uses", uses); | ||||
| } | } | ||||
| @@ -12,23 +12,23 @@ module Bitshift | |||||
| parser = RubyParser.new | parser = RubyParser.new | ||||
| tree = parser.parse(@source) | tree = parser.parse(@source) | ||||
| offset = tree.line - 1 | offset = tree.line - 1 | ||||
| processor = NodeVisitor.new offset, tree | |||||
| processor = CachedWalker.new offset, tree | |||||
| processor.process(tree) | processor.process(tree) | ||||
| return processor.to_s | return processor.to_s | ||||
| end | end | ||||
| end | end | ||||
| class NodeVisitor < SexpProcessor | |||||
| class CachedWalker < SexpProcessor | |||||
| attr_accessor :symbols | attr_accessor :symbols | ||||
| attr_accessor :offset | attr_accessor :offset | ||||
| def initialize(offset, tree) | def initialize(offset, tree) | ||||
| super() | super() | ||||
| module_hash = Hash.new {|hash, key| hash[key] = Hash.new} | |||||
| module_hash = Hash.new {|hash, key| hash[key] = { assignments: [], uses: [] }} | |||||
| class_hash = module_hash.clone | class_hash = module_hash.clone | ||||
| function_hash = Hash.new {|hash, key| hash[key] = { calls: [] } } | |||||
| var_hash = Hash.new {|hash, key| hash[key] = [] } | |||||
| function_hash = module_hash.clone | |||||
| var_hash = module_hash.clone | |||||
| @require_empty = false | @require_empty = false | ||||
| @offset = offset | @offset = offset | ||||
| @@ -41,7 +41,6 @@ module Bitshift | |||||
| end | end | ||||
| def block_position(exp) | def block_position(exp) | ||||
| pos = Hash.new | |||||
| end_ln = (start_ln = exp.line - offset) | end_ln = (start_ln = exp.line - offset) | ||||
| cur_exp = exp | cur_exp = exp | ||||
| @@ -51,9 +50,7 @@ module Bitshift | |||||
| break if cur_exp == nil | break if cur_exp == nil | ||||
| end | end | ||||
| pos[:coord] = { | |||||
| start_ln: start_ln, | |||||
| end_ln: end_ln } | |||||
| pos = [start_ln, -1, end_ln, -1] | |||||
| return pos | return pos | ||||
| end | end | ||||
| @@ -61,9 +58,7 @@ module Bitshift | |||||
| pos = Hash.new | pos = Hash.new | ||||
| end_ln = start_ln = exp.line - offset | end_ln = start_ln = exp.line - offset | ||||
| pos[:coord] = { | |||||
| start_ln: start_ln, | |||||
| end_ln: end_ln } | |||||
| pos = [start_ln, -1, end_ln, -1] | |||||
| return pos | return pos | ||||
| end | end | ||||
| @@ -71,7 +66,7 @@ module Bitshift | |||||
| pos = block_position(exp) | pos = block_position(exp) | ||||
| exp.shift | exp.shift | ||||
| name = exp.shift | name = exp.shift | ||||
| symbols[:modules][name] = pos | |||||
| symbols[:modules][name][:assignments] << pos | |||||
| exp.each_sexp {|s| process(s)} | exp.each_sexp {|s| process(s)} | ||||
| return exp.clear | return exp.clear | ||||
| end | end | ||||
| @@ -80,7 +75,7 @@ module Bitshift | |||||
| pos = block_position(exp) | pos = block_position(exp) | ||||
| exp.shift | exp.shift | ||||
| name = exp.shift | name = exp.shift | ||||
| symbols[:classes][name] = pos | |||||
| symbols[:classes][name][:assignments] << pos | |||||
| exp.each_sexp {|s| process(s)} | exp.each_sexp {|s| process(s)} | ||||
| return exp.clear | return exp.clear | ||||
| end | end | ||||
| @@ -89,7 +84,7 @@ module Bitshift | |||||
| pos = block_position(exp) | pos = block_position(exp) | ||||
| exp.shift | exp.shift | ||||
| name = exp.shift | name = exp.shift | ||||
| symbols[:functions][name][:declaration] = pos | |||||
| symbols[:functions][name][:assignments] << pos | |||||
| exp.each_sexp {|s| process(s)} | exp.each_sexp {|s| process(s)} | ||||
| return exp.clear | return exp.clear | ||||
| end | end | ||||
| @@ -99,7 +94,7 @@ module Bitshift | |||||
| exp.shift | exp.shift | ||||
| exp.shift | exp.shift | ||||
| name = exp.shift | name = exp.shift | ||||
| symbols[:functions][name][:calls] << pos | |||||
| symbols[:functions][name][:uses] << pos | |||||
| exp.each_sexp {|s| process(s)} | exp.each_sexp {|s| process(s)} | ||||
| return exp.clear | return exp.clear | ||||
| end | end | ||||
| @@ -108,7 +103,7 @@ module Bitshift | |||||
| pos = statement_position(exp) | pos = statement_position(exp) | ||||
| exp.shift | exp.shift | ||||
| name = exp.shift | name = exp.shift | ||||
| symbols[:vars][name] << pos | |||||
| symbols[:vars][name][:assignments] << pos | |||||
| exp.each_sexp {|s| process(s)} | exp.each_sexp {|s| process(s)} | ||||
| return exp.clear | return exp.clear | ||||
| end | end | ||||
| @@ -117,7 +112,7 @@ module Bitshift | |||||
| pos = statement_position(exp) | pos = statement_position(exp) | ||||
| exp.shift | exp.shift | ||||
| name = exp.shift | name = exp.shift | ||||
| symbols[:vars][name] << pos | |||||
| symbols[:vars][name][:assignments] << pos | |||||
| exp.each_sexp {|s| process(s)} | exp.each_sexp {|s| process(s)} | ||||
| return exp.clear | return exp.clear | ||||
| end | end | ||||