1.1 --- a/branching.py Thu Sep 08 18:39:38 2016 +0200
1.2 +++ b/branching.py Thu Sep 08 21:36:58 2016 +0200
1.3 @@ -180,10 +180,6 @@
1.4
1.5 self.loop_branches = []
1.6
1.7 - # Inherited usage.
1.8 -
1.9 - self.inherited = None
1.10 -
1.11 # Structure assembly methods.
1.12
1.13 def new_branchpoint(self, loop_node=False):
1.14 @@ -452,63 +448,6 @@
1.15 for branch in branches:
1.16 branch.contributors.add(contributor)
1.17
1.18 - # Namespace methods.
1.19 -
1.20 - def inherit_branches(self, tracker, names):
1.21 -
1.22 - """
1.23 - Propagate branches from the given 'tracker' excluding those associated
1.24 - with 'names'.
1.25 - """
1.26 -
1.27 - # For each inherited name, create a branch connected to the inherited
1.28 - # branches.
1.29 -
1.30 - self.inherited = {}
1.31 -
1.32 - for name, branches in tracker.attribute_branches[-1].items():
1.33 -
1.34 - # Do not inherit any listed names (typically parameters) or any
1.35 - # special names.
1.36 -
1.37 - if name in names or name.startswith("$"):
1.38 - continue
1.39 -
1.40 - # Make a tentative assignment for the name.
1.41 -
1.42 - contributor = Branch([name], True)
1.43 - init_item(self.assignments, name, list)
1.44 - self.assignments[name].append(contributor)
1.45 -
1.46 - # Connect the inherited branch to the new one.
1.47 -
1.48 - for branch in branches:
1.49 - init_item(contributor.suppliers, name, set)
1.50 - contributor.suppliers[name].add(branch)
1.51 - branch.contributors.add(contributor)
1.52 -
1.53 - # Record the inherited branch.
1.54 -
1.55 - self.inherited[name] = [contributor]
1.56 -
1.57 - self.attribute_branches[-1].update(self.inherited)
1.58 -
1.59 - def disconnect_name(self, name):
1.60 -
1.61 - "Disconnect inherited branches for 'name'."
1.62 -
1.63 - if not self.inherited or not self.inherited.has_key(name):
1.64 - return
1.65 -
1.66 - # Remove the new branch from the inherited branches for the name.
1.67 -
1.68 - for contributor in self.inherited[name]:
1.69 - for supplier in contributor.suppliers[name]:
1.70 - supplier.contributors.remove(contributor)
1.71 - del contributor.suppliers[name]
1.72 -
1.73 - del self.inherited[name]
1.74 -
1.75 # Attribute usage methods.
1.76
1.77 def tracking_name(self, name):
1.78 @@ -518,13 +457,11 @@
1.79 if it is.
1.80 """
1.81
1.82 - return self.assignments.has_key(name) and \
1.83 - (not self.inherited or not self.inherited.has_key(name)) and \
1.84 - self.have_name(name)
1.85 + return self.assignments.has_key(name) and self.have_name(name)
1.86
1.87 def have_name(self, name):
1.88
1.89 - "Return whether 'name' is known, perhaps having been inherited."
1.90 + "Return whether 'name' is known."
1.91
1.92 return self.attribute_branches[-1].get(name)
1.93
1.94 @@ -539,8 +476,6 @@
1.95 branch = Branch(names, True, values)
1.96
1.97 for name in names:
1.98 - self.disconnect_name(name)
1.99 -
1.100 branches[name] = [branch]
1.101 init_item(self.assignments, name, list)
1.102 self.assignments[name].append(branch)
2.1 --- a/common.py Thu Sep 08 18:39:38 2016 +0200
2.2 +++ b/common.py Thu Sep 08 21:36:58 2016 +0200
2.3 @@ -472,125 +472,6 @@
2.4 self.next_iterator()
2.5 self.process_structure_node(node)
2.6
2.7 - # Node rewriting, without processing.
2.8 -
2.9 - def convert_ifexp_node(self, n):
2.10 -
2.11 - """
2.12 - Convert the given if expression node 'n'. An if expression is considered
2.13 - as mapping to a function body containing an if statement as follows:
2.14 -
2.15 - <expr> if <test> else <altexpr>
2.16 -
2.17 - lambda <argnames>:
2.18 - if <test>:
2.19 - return <expr>
2.20 - else:
2.21 - return <altexpr>
2.22 -
2.23 - The <argnames> are populated with defaults after the node has been
2.24 - processed.
2.25 - """
2.26 -
2.27 - node = compiler.ast.Lambda(
2.28 - [], [], 0,
2.29 - compiler.ast.If([
2.30 - (n.test, compiler.ast.Return(n.then))
2.31 - ],
2.32 - compiler.ast.Return(n.else_)
2.33 - ))
2.34 -
2.35 - return node
2.36 -
2.37 - def convert_listcomp_node(self, n):
2.38 -
2.39 - """
2.40 - Convert the given list comprehension node 'n'. A list comprehension is
2.41 - considered as mapping to a function body containing a for loop as
2.42 - follows:
2.43 -
2.44 - [<expr> for <varexpr1> in <list1> if <ifexpr1> for <varexpr2> in <list2> if <ifexpr2> if <ifexpr3>]
2.45 -
2.46 - lambda <argnames>:
2.47 - <result> = []
2.48 - for <varexpr1> in <list1>:
2.49 - if <ifexpr1>:
2.50 - for <varexpr2> in <list2>:
2.51 - if <ifexpr2>:
2.52 - if <ifexpr3>:
2.53 - <result>.append(<expr>)
2.54 - return <result>
2.55 -
2.56 - The <argnames> are populated with defaults after the node has been
2.57 - processed.
2.58 - """
2.59 -
2.60 - temp = "$tr"
2.61 -
2.62 - node = compiler.ast.Lambda(
2.63 - [], [], 0,
2.64 - compiler.ast.Stmt([
2.65 -
2.66 - # <result> = []
2.67 -
2.68 - compiler.ast.Assign([compiler.ast.AssName(temp, "OP_ASSIGN")],
2.69 - compiler.ast.List([])
2.70 - ),
2.71 -
2.72 - # for ...
2.73 -
2.74 - self.convert_listcomp_for_node(n.quals[0], n.quals[1:], n.expr, temp),
2.75 -
2.76 - # return <result>
2.77 -
2.78 - compiler.ast.Return(compiler.ast.Name(temp))
2.79 - ]))
2.80 -
2.81 - return node
2.82 -
2.83 - def convert_listcomp_for_node(self, loop, following_loops, expr, temp):
2.84 -
2.85 - """
2.86 - Return a node representing 'loop', encapsulating 'following_loops' and
2.87 - employing 'expr' in the innermost loop body appending to 'temp'.
2.88 - """
2.89 -
2.90 - if loop.ifs:
2.91 - body = self.convert_listcomp_if_node(loop.ifs[0], loop.ifs[1:], following_loops, expr, temp)
2.92 - elif following_loops:
2.93 - body = self.convert_listcomp_for_node(following_loops[0], following_loops[1:], expr, temp)
2.94 - else:
2.95 - body = self.convert_listcomp_body_node(expr, temp)
2.96 -
2.97 - return compiler.ast.For(loop.assign, loop.list, compiler.ast.Stmt([body]), None)
2.98 -
2.99 - def convert_listcomp_if_node(self, if_, following_ifs, following_loops, expr, temp):
2.100 -
2.101 - """
2.102 - Return a node representing 'if_', encapsulating the 'following_ifs' and
2.103 - 'following_loops' and employing 'expr' in the innermost loop body
2.104 - appending to 'temp'.
2.105 - """
2.106 -
2.107 - if following_ifs:
2.108 - body = self.convert_listcomp_if_node(following_ifs[0], following_ifs[1:], following_loops, expr, temp)
2.109 - elif following_loops:
2.110 - body = self.convert_listcomp_for_node(following_loops[0], following_loops[1:], expr, temp)
2.111 - else:
2.112 - body = self.convert_listcomp_body_node(expr, temp)
2.113 -
2.114 - return compiler.ast.If([(if_.test, compiler.ast.Stmt([body]))], None)
2.115 -
2.116 - def convert_listcomp_body_node(self, expr, temp):
2.117 -
2.118 - "Return a node appending 'expr' to 'temp'."
2.119 -
2.120 - return compiler.ast.Discard(
2.121 - compiler.ast.CallFunc(
2.122 - compiler.ast.Getattr(compiler.ast.Name(temp), "append"), [expr]))
2.123 -
2.124 - # More node processing.
2.125 -
2.126 def process_literal_sequence_node(self, n, name, ref, cls):
2.127
2.128 """
3.1 --- a/inspector.py Thu Sep 08 18:39:38 2016 +0200
3.2 +++ b/inspector.py Thu Sep 08 21:36:58 2016 +0200
3.3 @@ -23,6 +23,7 @@
3.4 from branching import BranchTracker
3.5 from common import get_argnames, init_item, predefined_constants
3.6 from modules import BasicModule, CacheWritingModule, InspectionNaming
3.7 +from errors import InspectError
3.8 from referencing import Reference
3.9 from resolving import NameResolving
3.10 from results import AccessRef, InstanceRef, InvocationRef, LiteralSequenceRef, \
3.11 @@ -44,11 +45,6 @@
3.12 self.in_conditional = False
3.13 self.global_attr_accesses = {}
3.14
3.15 - # Nested scope handling.
3.16 -
3.17 - self.parent_function = None
3.18 - self.propagated_names = {}
3.19 -
3.20 # Usage tracking.
3.21
3.22 self.trackers = []
3.23 @@ -300,13 +296,16 @@
3.24 elif isinstance(n, compiler.ast.Tuple):
3.25 return self.get_literal_instance(n, "tuple")
3.26
3.27 - # List comprehensions and if expressions.
3.28 + # Unsupported nodes.
3.29 +
3.30 + elif isinstance(n, compiler.ast.GenExpr):
3.31 + raise InspectError("Generator expressions are not supported.", self.get_namespace_path(), n)
3.32 +
3.33 + elif isinstance(n, compiler.ast.IfExp):
3.34 + raise InspectError("If-else expressions are not supported.", self.get_namespace_path(), n)
3.35
3.36 elif isinstance(n, compiler.ast.ListComp):
3.37 - self.process_listcomp_node(n)
3.38 -
3.39 - elif isinstance(n, compiler.ast.IfExp):
3.40 - self.process_ifexp_node(n)
3.41 + raise InspectError("List comprehensions are not supported.", self.get_namespace_path(), n)
3.42
3.43 # All other nodes are processed depth-first.
3.44
3.45 @@ -580,9 +579,6 @@
3.46
3.47 # Reset conditional tracking to focus on the function contents.
3.48
3.49 - parent_function = self.parent_function
3.50 - self.parent_function = self.in_function and self.get_namespace_path() or None
3.51 -
3.52 in_conditional = self.in_conditional
3.53 self.in_conditional = False
3.54
3.55 @@ -594,34 +590,19 @@
3.56 # Track attribute usage within the namespace.
3.57
3.58 path = self.get_namespace_path()
3.59 - init_item(self.propagated_names, path, set)
3.60
3.61 self.start_tracking(locals)
3.62 self.process_structure_node(n.code)
3.63 self.stop_tracking()
3.64
3.65 - # Propagate names from parent scopes.
3.66 -
3.67 - for local in self.propagated_names[path]:
3.68 - if not local in argnames and self.trackers[-1].have_name(local):
3.69 - argnames.append(local)
3.70 - defaults.append((local, Reference("<var>")))
3.71 - self.set_function_local(local)
3.72 -
3.73 - # Exit to the parent and note propagated names.
3.74 + # Exit to the parent.
3.75
3.76 self.exit_namespace()
3.77
3.78 - parent = self.get_namespace_path()
3.79 - if self.propagated_names.has_key(parent):
3.80 - for local in self.propagated_names[path]:
3.81 - self.propagated_names[parent].add(local)
3.82 -
3.83 # Update flags.
3.84
3.85 self.in_function = in_function
3.86 self.in_conditional = in_conditional
3.87 - self.parent_function = parent_function
3.88
3.89 # Define the function using the appropriate name.
3.90
3.91 @@ -673,18 +654,6 @@
3.92
3.93 tracker.merge_branches()
3.94
3.95 - def process_ifexp_node(self, n):
3.96 -
3.97 - "Process the given if expression node 'n'."
3.98 -
3.99 - name_ref = self.process_structure_node(self.convert_ifexp_node(n))
3.100 -
3.101 - path = self.get_namespace_path()
3.102 - self.allocate_arguments(path, self.function_defaults[name_ref.get_origin()])
3.103 - self.deallocate_arguments(path, self.function_defaults[name_ref.get_origin()])
3.104 -
3.105 - return InvocationRef(name_ref)
3.106 -
3.107 def process_import_node(self, n):
3.108
3.109 "Process the given import node 'n'."
3.110 @@ -743,18 +712,6 @@
3.111 origin = self.get_object_path(name)
3.112 return ResolvedNameRef(name, Reference("<function>", origin))
3.113
3.114 - def process_listcomp_node(self, n):
3.115 -
3.116 - "Process the given list comprehension node 'n'."
3.117 -
3.118 - name_ref = self.process_structure_node(self.convert_listcomp_node(n))
3.119 -
3.120 - path = self.get_namespace_path()
3.121 - self.allocate_arguments(path, self.function_defaults[name_ref.get_origin()])
3.122 - self.deallocate_arguments(path, self.function_defaults[name_ref.get_origin()])
3.123 -
3.124 - return InvocationRef(name_ref)
3.125 -
3.126 def process_logical_node(self, n):
3.127
3.128 "Process the given operator node 'n'."
3.129 @@ -820,14 +777,7 @@
3.130
3.131 branches = tracker.tracking_name(n.name)
3.132
3.133 - # Find names inherited from a parent scope.
3.134 -
3.135 - if not branches and self.parent_function:
3.136 - branches = tracker.have_name(n.name)
3.137 - if branches:
3.138 - self.propagate_name(n.name)
3.139 -
3.140 - # Local or inherited name.
3.141 + # Local name.
3.142
3.143 if branches:
3.144 self.record_branches_for_access(branches, n.name, None)
3.145 @@ -990,12 +940,6 @@
3.146 tracker = BranchTracker()
3.147 self.trackers.append(tracker)
3.148
3.149 - # For functions created from expressions or for functions within
3.150 - # functions, propagate usage to the new namespace.
3.151 -
3.152 - if self.parent_function:
3.153 - tracker.inherit_branches(parent, names)
3.154 -
3.155 # Record the given names established as new branches.
3.156
3.157 tracker.assign_names(names)
3.158 @@ -1037,13 +981,6 @@
3.159 self.attr_usage[self.name] = tracker.get_all_usage()
3.160 self.name_initialisers[self.name] = tracker.get_all_values()
3.161
3.162 - def propagate_name(self, name):
3.163 -
3.164 - "Propagate the given 'name' into the current namespace."
3.165 -
3.166 - path = self.get_namespace_path()
3.167 - self.propagated_names[path].add(name)
3.168 -
3.169 def record_assignments_for_access(self, tracker):
3.170
3.171 """