1.1 --- a/docs/related.txt Thu Sep 16 20:02:26 2010 +0200
1.2 +++ b/docs/related.txt Fri Sep 17 00:48:32 2010 +0200
1.3 @@ -7,6 +7,7 @@
1.4 other languages:
1.5
1.6 http://codespeak.net/pypy/dist/pypy/doc/coding-guide.html#restricted-python
1.7 +http://groups.google.com/group/shedskin-discuss/msg/3f6a4ff34561a97c?dmode=source&output=gplain
1.8
1.9 CapPython limits attribute access in order to facilitate code verification:
1.10
2.1 --- a/micropython/common.py Thu Sep 16 20:02:26 2010 +0200
2.2 +++ b/micropython/common.py Fri Sep 17 00:48:32 2010 +0200
2.3 @@ -26,6 +26,21 @@
2.4 except NameError:
2.5 from sets import Set as set
2.6
2.7 +def merge_set_dicts(dicts):
2.8 +
2.9 + "Merge the given 'dicts' mapping keys to sets of objects."
2.10 +
2.11 + new_dict = {}
2.12 +
2.13 + for old_dict in dicts:
2.14 + for key, values in old_dict.items():
2.15 + if not new_dict.has_key(key):
2.16 + new_dict[key] = set(values)
2.17 + else:
2.18 + new_dict[key].update(values)
2.19 +
2.20 + return new_dict
2.21 +
2.22 # Visitors and activities related to node annotations.
2.23
2.24 class ASTVisitor(compiler.visitor.ASTVisitor):
3.1 --- a/micropython/data.py Thu Sep 16 20:02:26 2010 +0200
3.2 +++ b/micropython/data.py Fri Sep 17 00:48:32 2010 +0200
3.3 @@ -53,7 +53,7 @@
3.4 """
3.5
3.6 from micropython.program import DataObject, DataValue, ReplaceableContext, PlaceholderContext
3.7 -from micropython.common import AtLeast, InspectError
3.8 +from micropython.common import AtLeast, InspectError, merge_set_dicts
3.9
3.10 def shortrepr(obj):
3.11 if obj is None:
3.12 @@ -103,6 +103,10 @@
3.13 self.attribute_users = [{}] # stack of assignments and branches
3.14 self.attribute_user_shelves = []
3.15
3.16 + # Suspended user details plus loop details.
3.17 +
3.18 + self.suspended_users = [] # stack of lists of users
3.19 +
3.20 # Scope usage, indicating the origin of names.
3.21
3.22 self.scope_usage = [{}] # stack of scope usage
3.23 @@ -580,7 +584,7 @@
3.24
3.25 # Branch management methods.
3.26
3.27 - def _new_branchpoint(self):
3.28 + def _new_branchpoint(self, is_loop=0):
3.29
3.30 """
3.31 Establish a new branchpoint where several control-flow branches diverge
3.32 @@ -590,6 +594,9 @@
3.33 self.attribute_user_shelves.append([])
3.34 self.scope_shelves.append([])
3.35
3.36 + if is_loop:
3.37 + self.suspended_users.append([])
3.38 +
3.39 def _new_branch(self, node):
3.40
3.41 """
3.42 @@ -641,6 +648,16 @@
3.43 self.attribute_users[-1] = AbandonedBranchUsers()
3.44 self.scope_usage[-1] = AbandonedBranchScope()
3.45
3.46 + def _suspend_branch(self):
3.47 +
3.48 + """
3.49 + Suspend a branch for resumption after the current loop.
3.50 + """
3.51 +
3.52 + users = self.suspended_users[-1]
3.53 + users.append(self.attribute_users[-1])
3.54 + self._abandon_branch()
3.55 +
3.56 def _shelve_branch(self):
3.57
3.58 """
3.59 @@ -667,29 +684,8 @@
3.60 # Combine the attribute users. This ensures that a list of users
3.61 # affected by attribute usage is maintained for the current branch.
3.62
3.63 - new_users = {}
3.64 -
3.65 all_shelved_users = self.attribute_user_shelves.pop()
3.66 - all_user_names = set()
3.67 -
3.68 - # Find all the names defined by the branches.
3.69 -
3.70 - for shelved_users in all_shelved_users:
3.71 - all_user_names.update(shelved_users.keys())
3.72 -
3.73 - # Copy all definitions from the branches for the names.
3.74 -
3.75 - for shelved_users in all_shelved_users:
3.76 - for name in all_user_names:
3.77 -
3.78 - if shelved_users.has_key(name):
3.79 - nodes = shelved_users[name]
3.80 -
3.81 - if not new_users.has_key(name):
3.82 - new_users[name] = set(nodes)
3.83 - else:
3.84 - new_users[name].update(nodes)
3.85 -
3.86 + new_users = merge_set_dicts(all_shelved_users)
3.87 self.attribute_users[-1] = new_users
3.88
3.89 # Combine the scope usage.
3.90 @@ -735,6 +731,18 @@
3.91
3.92 self.scope_usage[-1] = new_scope_usage
3.93
3.94 + def _resume_branches(self):
3.95 +
3.96 + """
3.97 + Incorporate users from suspended branches into the current set of active
3.98 + users.
3.99 + """
3.100 +
3.101 + users = self.suspended_users.pop()
3.102 + current_users = self.attribute_users[-1]
3.103 + new_users = merge_set_dicts(users + [current_users])
3.104 + self.attribute_users[-1] = new_users
3.105 +
3.106 # Scope usage methods.
3.107
3.108 def define_scope(self, name, scope):
4.1 --- a/micropython/inspect.py Thu Sep 16 20:02:26 2010 +0200
4.2 +++ b/micropython/inspect.py Fri Sep 17 00:48:32 2010 +0200
4.3 @@ -347,8 +347,8 @@
4.4 # These are convenience methods which refer to the specific namespace's
4.5 # implementation of these operations.
4.6
4.7 - def new_branchpoint(self):
4.8 - self.get_namespace()._new_branchpoint()
4.9 + def new_branchpoint(self, is_loop=0):
4.10 + self.get_namespace()._new_branchpoint(is_loop)
4.11
4.12 def new_branch(self, node):
4.13 self.get_namespace()._new_branch(node)
4.14 @@ -356,12 +356,18 @@
4.15 def abandon_branch(self):
4.16 self.get_namespace()._abandon_branch()
4.17
4.18 + def suspend_branch(self):
4.19 + self.get_namespace()._suspend_branch()
4.20 +
4.21 def shelve_branch(self):
4.22 self.get_namespace()._shelve_branch()
4.23
4.24 def merge_branches(self):
4.25 self.get_namespace()._merge_branches()
4.26
4.27 + def resume_branches(self):
4.28 + self.get_namespace()._resume_branches()
4.29 +
4.30 def define_attribute_user(self, node):
4.31
4.32 """
4.33 @@ -401,6 +407,10 @@
4.34 self.NOP(node)
4.35 self.abandon_branch()
4.36
4.37 + def NOP_SUSPEND(self, node):
4.38 + self.NOP(node)
4.39 + self.suspend_branch()
4.40 +
4.41 def OP(self, node):
4.42 for n in node.getChildNodes():
4.43 self.dispatch(n)
4.44 @@ -654,7 +664,7 @@
4.45
4.46 visitBitxor = _visitBinary
4.47
4.48 - visitBreak = NOP_ABANDON
4.49 + visitBreak = NOP_SUSPEND
4.50
4.51 visitCallFunc = OP
4.52
4.53 @@ -782,7 +792,7 @@
4.54 visitFloorDiv = _visitBinary
4.55
4.56 def visitFor(self, node):
4.57 - self.new_branchpoint()
4.58 + self.new_branchpoint(is_loop=1)
4.59
4.60 # Declare names which will be used by generated code.
4.61
4.62 @@ -822,6 +832,10 @@
4.63 if node.else_ is not None:
4.64 self.dispatch(node.else_)
4.65
4.66 + # Any suspended branches from the loop can now be resumed.
4.67 +
4.68 + self.resume_branches()
4.69 +
4.70 return None
4.71
4.72 def visitFrom(self, node):
4.73 @@ -1048,7 +1062,7 @@
4.74 visitUnarySub = _visitUnary
4.75
4.76 def visitWhile(self, node):
4.77 - self.new_branchpoint()
4.78 + self.new_branchpoint(is_loop=1)
4.79
4.80 # Propagate attribute usage to branches.
4.81
4.82 @@ -1078,6 +1092,10 @@
4.83 if node.else_ is not None:
4.84 self.dispatch(node.else_)
4.85
4.86 + # Any suspended branches from the loop can now be resumed.
4.87 +
4.88 + self.resume_branches()
4.89 +
4.90 return None
4.91
4.92 visitWith = NOP
5.1 --- a/tests/abandoned_attribute_usage_multiple_candidates_nested.py Thu Sep 16 20:02:26 2010 +0200
5.2 +++ b/tests/abandoned_attribute_usage_multiple_candidates_nested.py Fri Sep 17 00:48:32 2010 +0200
5.3 @@ -8,9 +8,12 @@
5.4
5.5 class C:
5.6 def f(self):
5.7 + return 0
5.8 +
5.9 +class D:
5.10 + def f(self):
5.11 return 1
5.12
5.13 -class D:
5.14 def g(self):
5.15 return 2
5.16
6.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
6.2 +++ b/tests/attribute_access_type_restriction_loop_break.py Fri Sep 17 00:48:32 2010 +0200
6.3 @@ -0,0 +1,41 @@
6.4 +#!/usr/bin/env python
6.5 +
6.6 +class C:
6.7 + def e(self):
6.8 + return 2
6.9 +
6.10 + def f(self):
6.11 + return 1
6.12 +
6.13 +class D:
6.14 + def e(self):
6.15 + return 6
6.16 +
6.17 + def f(self):
6.18 + return 0 # stops the test loop
6.19 +
6.20 + def g(self):
6.21 + return 3
6.22 +
6.23 +class E:
6.24 + def f(self):
6.25 + return 4
6.26 +
6.27 + def g(self):
6.28 + return 5
6.29 +
6.30 +def test_loop(obj, obj2):
6.31 + while obj.f():
6.32 + obj = obj2
6.33 + obj.g()
6.34 + break
6.35 + else:
6.36 + obj.e()
6.37 + return obj.f()
6.38 +
6.39 +c = C()
6.40 +d = D()
6.41 +e = E()
6.42 +result1_4 = test_loop(c, e)
6.43 +
6.44 +# vim: tabstop=4 expandtab shiftwidth=4