Index: tools/telemetry/third_party/rope/rope/base/evaluate.py |
diff --git a/tools/telemetry/third_party/rope/rope/base/evaluate.py b/tools/telemetry/third_party/rope/rope/base/evaluate.py |
new file mode 100644 |
index 0000000000000000000000000000000000000000..faf094075f6ce34770695fb25e4359c342fe7ef7 |
--- /dev/null |
+++ b/tools/telemetry/third_party/rope/rope/base/evaluate.py |
@@ -0,0 +1,327 @@ |
+import rope.base.builtins |
+import rope.base.pynames |
+import rope.base.pyobjects |
+from rope.base import ast, astutils, exceptions, pyobjects, arguments, worder |
+ |
+ |
+BadIdentifierError = exceptions.BadIdentifierError |
+ |
+ |
+def eval_location(pymodule, offset): |
+ """Find the pyname at the offset""" |
+ return eval_location2(pymodule, offset)[1] |
+ |
+ |
+def eval_location2(pymodule, offset): |
+ """Find the primary and pyname at offset""" |
+ pyname_finder = ScopeNameFinder(pymodule) |
+ return pyname_finder.get_primary_and_pyname_at(offset) |
+ |
+ |
+def eval_node(scope, node): |
+ """Evaluate a `ast.AST` node and return a PyName |
+ |
+ Return `None` if the expression cannot be evaluated. |
+ """ |
+ return eval_node2(scope, node)[1] |
+ |
+ |
+def eval_node2(scope, node): |
+ evaluator = StatementEvaluator(scope) |
+ ast.walk(node, evaluator) |
+ return evaluator.old_result, evaluator.result |
+ |
+ |
+def eval_str(holding_scope, name): |
+ return eval_str2(holding_scope, name)[1] |
+ |
+ |
+def eval_str2(holding_scope, name): |
+ try: |
+ # parenthesizing for handling cases like 'a_var.\nattr' |
+ node = ast.parse('(%s)' % name) |
+ except SyntaxError: |
+ raise BadIdentifierError( |
+ 'Not a resolvable python identifier selected.') |
+ return eval_node2(holding_scope, node) |
+ |
+ |
+class ScopeNameFinder(object): |
+ |
+ def __init__(self, pymodule): |
+ self.module_scope = pymodule.get_scope() |
+ self.lines = pymodule.lines |
+ self.worder = worder.Worder(pymodule.source_code, True) |
+ |
+ def _is_defined_in_class_body(self, holding_scope, offset, lineno): |
+ if lineno == holding_scope.get_start() and \ |
+ holding_scope.parent is not None and \ |
+ holding_scope.parent.get_kind() == 'Class' and \ |
+ self.worder.is_a_class_or_function_name_in_header(offset): |
+ return True |
+ if lineno != holding_scope.get_start() and \ |
+ holding_scope.get_kind() == 'Class' and \ |
+ self.worder.is_name_assigned_in_class_body(offset): |
+ return True |
+ return False |
+ |
+ def _is_function_name_in_function_header(self, scope, offset, lineno): |
+ if scope.get_start() <= lineno <= scope.get_body_start() and \ |
+ scope.get_kind() == 'Function' and \ |
+ self.worder.is_a_class_or_function_name_in_header(offset): |
+ return True |
+ return False |
+ |
+ def get_pyname_at(self, offset): |
+ return self.get_primary_and_pyname_at(offset)[1] |
+ |
+ def get_primary_and_pyname_at(self, offset): |
+ lineno = self.lines.get_line_number(offset) |
+ holding_scope = self.module_scope.get_inner_scope_for_line(lineno) |
+ # function keyword parameter |
+ if self.worder.is_function_keyword_parameter(offset): |
+ keyword_name = self.worder.get_word_at(offset) |
+ pyobject = self.get_enclosing_function(offset) |
+ if isinstance(pyobject, pyobjects.PyFunction): |
+ return (None, |
+ pyobject.get_parameters().get(keyword_name, None)) |
+ # class body |
+ if self._is_defined_in_class_body(holding_scope, offset, lineno): |
+ class_scope = holding_scope |
+ if lineno == holding_scope.get_start(): |
+ class_scope = holding_scope.parent |
+ name = self.worder.get_primary_at(offset).strip() |
+ try: |
+ return (None, class_scope.pyobject[name]) |
+ except rope.base.exceptions.AttributeNotFoundError: |
+ return (None, None) |
+ # function header |
+ if self._is_function_name_in_function_header(holding_scope, |
+ offset, lineno): |
+ name = self.worder.get_primary_at(offset).strip() |
+ return (None, holding_scope.parent[name]) |
+ # from statement module |
+ if self.worder.is_from_statement_module(offset): |
+ module = self.worder.get_primary_at(offset) |
+ module_pyname = self._find_module(module) |
+ return (None, module_pyname) |
+ if self.worder.is_from_aliased(offset): |
+ name = self.worder.get_from_aliased(offset) |
+ else: |
+ name = self.worder.get_primary_at(offset) |
+ return eval_str2(holding_scope, name) |
+ |
+ def get_enclosing_function(self, offset): |
+ function_parens = self.worder.find_parens_start_from_inside(offset) |
+ try: |
+ function_pyname = self.get_pyname_at(function_parens - 1) |
+ except BadIdentifierError: |
+ function_pyname = None |
+ if function_pyname is not None: |
+ pyobject = function_pyname.get_object() |
+ if isinstance(pyobject, pyobjects.AbstractFunction): |
+ return pyobject |
+ elif isinstance(pyobject, pyobjects.AbstractClass) and \ |
+ '__init__' in pyobject: |
+ return pyobject['__init__'].get_object() |
+ elif '__call__' in pyobject: |
+ return pyobject['__call__'].get_object() |
+ return None |
+ |
+ def _find_module(self, module_name): |
+ dots = 0 |
+ while module_name[dots] == '.': |
+ dots += 1 |
+ return rope.base.pynames.ImportedModule( |
+ self.module_scope.pyobject, module_name[dots:], dots) |
+ |
+ |
+class StatementEvaluator(object): |
+ |
+ def __init__(self, scope): |
+ self.scope = scope |
+ self.result = None |
+ self.old_result = None |
+ |
+ def _Name(self, node): |
+ self.result = self.scope.lookup(node.id) |
+ |
+ def _Attribute(self, node): |
+ pyname = eval_node(self.scope, node.value) |
+ if pyname is None: |
+ pyname = rope.base.pynames.UnboundName() |
+ self.old_result = pyname |
+ if pyname.get_object() != rope.base.pyobjects.get_unknown(): |
+ try: |
+ self.result = pyname.get_object()[node.attr] |
+ except exceptions.AttributeNotFoundError: |
+ self.result = None |
+ |
+ def _Call(self, node): |
+ primary, pyobject = self._get_primary_and_object_for_node(node.func) |
+ if pyobject is None: |
+ return |
+ |
+ def _get_returned(pyobject): |
+ args = arguments.create_arguments(primary, pyobject, |
+ node, self.scope) |
+ return pyobject.get_returned_object(args) |
+ if isinstance(pyobject, rope.base.pyobjects.AbstractClass): |
+ result = None |
+ if '__new__' in pyobject: |
+ new_function = pyobject['__new__'].get_object() |
+ result = _get_returned(new_function) |
+ if result is None or \ |
+ result == rope.base.pyobjects.get_unknown(): |
+ result = rope.base.pyobjects.PyObject(pyobject) |
+ self.result = rope.base.pynames.UnboundName(pyobject=result) |
+ return |
+ |
+ pyfunction = None |
+ if isinstance(pyobject, rope.base.pyobjects.AbstractFunction): |
+ pyfunction = pyobject |
+ elif '__call__' in pyobject: |
+ pyfunction = pyobject['__call__'].get_object() |
+ if pyfunction is not None: |
+ self.result = rope.base.pynames.UnboundName( |
+ pyobject=_get_returned(pyfunction)) |
+ |
+ def _Str(self, node): |
+ self.result = rope.base.pynames.UnboundName( |
+ pyobject=rope.base.builtins.get_str()) |
+ |
+ def _Num(self, node): |
+ type_name = type(node.n).__name__ |
+ self.result = self._get_builtin_name(type_name) |
+ |
+ def _get_builtin_name(self, type_name): |
+ pytype = rope.base.builtins.builtins[type_name].get_object() |
+ return rope.base.pynames.UnboundName( |
+ rope.base.pyobjects.PyObject(pytype)) |
+ |
+ def _BinOp(self, node): |
+ self.result = rope.base.pynames.UnboundName( |
+ self._get_object_for_node(node.left)) |
+ |
+ def _BoolOp(self, node): |
+ pyobject = self._get_object_for_node(node.values[0]) |
+ if pyobject is None: |
+ pyobject = self._get_object_for_node(node.values[1]) |
+ self.result = rope.base.pynames.UnboundName(pyobject) |
+ |
+ def _Repr(self, node): |
+ self.result = self._get_builtin_name('str') |
+ |
+ def _UnaryOp(self, node): |
+ self.result = rope.base.pynames.UnboundName( |
+ self._get_object_for_node(node.operand)) |
+ |
+ def _Compare(self, node): |
+ self.result = self._get_builtin_name('bool') |
+ |
+ def _Dict(self, node): |
+ keys = None |
+ values = None |
+ if node.keys: |
+ keys = self._get_object_for_node(node.keys[0]) |
+ values = self._get_object_for_node(node.values[0]) |
+ self.result = rope.base.pynames.UnboundName( |
+ pyobject=rope.base.builtins.get_dict(keys, values)) |
+ |
+ def _List(self, node): |
+ holding = None |
+ if node.elts: |
+ holding = self._get_object_for_node(node.elts[0]) |
+ self.result = rope.base.pynames.UnboundName( |
+ pyobject=rope.base.builtins.get_list(holding)) |
+ |
+ def _ListComp(self, node): |
+ pyobject = self._what_does_comprehension_hold(node) |
+ self.result = rope.base.pynames.UnboundName( |
+ pyobject=rope.base.builtins.get_list(pyobject)) |
+ |
+ def _GeneratorExp(self, node): |
+ pyobject = self._what_does_comprehension_hold(node) |
+ self.result = rope.base.pynames.UnboundName( |
+ pyobject=rope.base.builtins.get_iterator(pyobject)) |
+ |
+ def _what_does_comprehension_hold(self, node): |
+ scope = self._make_comprehension_scope(node) |
+ pyname = eval_node(scope, node.elt) |
+ return pyname.get_object() if pyname is not None else None |
+ |
+ def _make_comprehension_scope(self, node): |
+ scope = self.scope |
+ module = scope.pyobject.get_module() |
+ names = {} |
+ for comp in node.generators: |
+ new_names = _get_evaluated_names(comp.target, comp.iter, module, |
+ '.__iter__().next()', node.lineno) |
+ names.update(new_names) |
+ return rope.base.pyscopes.TemporaryScope(scope.pycore, scope, names) |
+ |
+ def _Tuple(self, node): |
+ objects = [] |
+ if len(node.elts) < 4: |
+ for stmt in node.elts: |
+ pyobject = self._get_object_for_node(stmt) |
+ objects.append(pyobject) |
+ else: |
+ objects.append(self._get_object_for_node(node.elts[0])) |
+ self.result = rope.base.pynames.UnboundName( |
+ pyobject=rope.base.builtins.get_tuple(*objects)) |
+ |
+ def _get_object_for_node(self, stmt): |
+ pyname = eval_node(self.scope, stmt) |
+ pyobject = None |
+ if pyname is not None: |
+ pyobject = pyname.get_object() |
+ return pyobject |
+ |
+ def _get_primary_and_object_for_node(self, stmt): |
+ primary, pyname = eval_node2(self.scope, stmt) |
+ pyobject = None |
+ if pyname is not None: |
+ pyobject = pyname.get_object() |
+ return primary, pyobject |
+ |
+ def _Subscript(self, node): |
+ if isinstance(node.slice, ast.Index): |
+ self._call_function(node.value, '__getitem__', |
+ [node.slice.value]) |
+ elif isinstance(node.slice, ast.Slice): |
+ self._call_function(node.value, '__getslice__') |
+ |
+ def _call_function(self, node, function_name, other_args=None): |
+ pyname = eval_node(self.scope, node) |
+ if pyname is not None: |
+ pyobject = pyname.get_object() |
+ else: |
+ return |
+ if function_name in pyobject: |
+ called = pyobject[function_name].get_object() |
+ if not called or \ |
+ not isinstance(called, pyobjects.AbstractFunction): |
+ return |
+ args = [node] |
+ if other_args: |
+ args += other_args |
+ arguments_ = arguments.Arguments(args, self.scope) |
+ self.result = rope.base.pynames.UnboundName( |
+ pyobject=called.get_returned_object(arguments_)) |
+ |
+ def _Lambda(self, node): |
+ self.result = rope.base.pynames.UnboundName( |
+ pyobject=rope.base.builtins.Lambda(node, self.scope)) |
+ |
+ |
+def _get_evaluated_names(targets, assigned, module, evaluation, lineno): |
+ result = {} |
+ for name, levels in astutils.get_name_levels(targets): |
+ assignment = rope.base.pynames.AssignmentValue(assigned, levels, |
+ evaluation) |
+ # XXX: this module should not access `rope.base.pynamesdef`! |
+ pyname = rope.base.pynamesdef.AssignedName(lineno, module) |
+ pyname.assignments.append(assignment) |
+ result[name] = pyname |
+ return result |