1.1 --- a/micropython/ast.py Sun May 04 20:11:46 2008 +0200
1.2 +++ b/micropython/ast.py Mon May 05 00:37:53 2008 +0200
1.3 @@ -89,6 +89,7 @@
1.4
1.5 self.code = None
1.6 self.temp_position = 0
1.7 + self.capture_start = None
1.8
1.9 def calculate_stack_usage(self):
1.10 max_stack_usage = 0
1.11 @@ -195,6 +196,12 @@
1.12
1.13 self.code.append(op)
1.14
1.15 + def new_ops(self, ops):
1.16 +
1.17 + "Add 'ops' to the generated code."
1.18 +
1.19 + self.code += ops
1.20 +
1.21 def replace_op(self, op):
1.22
1.23 "Replace the last added instruction with 'op'."
1.24 @@ -207,23 +214,31 @@
1.25
1.26 del self.code[-n:]
1.27
1.28 - def last_ops(self, n):
1.29 + def last_ops(self, n, ops=None):
1.30
1.31 "Return the last 'n' added instructions in reverse chronological order."
1.32
1.33 - ops = self.code[-n:]
1.34 + ops = (ops or self.code)[-n:]
1.35 ops.reverse()
1.36 return ops
1.37
1.38 - def last_op(self):
1.39 + def last_op(self, ops=None):
1.40
1.41 "Return the last added instruction."
1.42
1.43 try:
1.44 - return self.code[-1]
1.45 + return (ops or self.code)[-1]
1.46 except IndexError:
1.47 return None
1.48
1.49 + def capture_ops(self):
1.50 + self.capture_start = len(self.code)
1.51 +
1.52 + def get_captured_ops(self):
1.53 + l = self.code[self.capture_start:]
1.54 + del self.code[self.capture_start:]
1.55 + return l
1.56 +
1.57 # Internal helper methods.
1.58
1.59 def _visitAttr(self, node, classes):
1.60 @@ -484,13 +499,13 @@
1.61
1.62 "Make the invocation and tidy up afterwards."
1.63
1.64 - self.new_op(temp)
1.65 + self.new_ops(temp)
1.66 self.new_op(JumpWithFrame())
1.67
1.68 # NOTE: Exception handling required.
1.69
1.70 self.new_op(DropFrame())
1.71 - self.discard_temp([temp])
1.72 + self.discard_temp(temp)
1.73
1.74 def _visitName(self, node, classes):
1.75
1.76 @@ -563,13 +578,13 @@
1.77 def _should_optimise_temp_storage(self):
1.78 return "temp_storage" in self.optimisations
1.79
1.80 - def _have_constant_input(self, n):
1.81 - last = self.last_ops(n+1)
1.82 + def _have_constant_input(self, n, ops=None):
1.83 + last = self.last_ops(n+1, ops)
1.84 return len(last) > n and (isinstance(last[n], LoadAddress) and last[n].attr.assignments == 1 or
1.85 isinstance(last[n], LoadConst)) # and not isinstance(last[n].attr, micropython.inspect.Instance)
1.86
1.87 - def _have_known_target(self):
1.88 - return self._have_constant_input(0)
1.89 + def _have_known_target(self, ops=None):
1.90 + return self._have_constant_input(0, ops)
1.91
1.92 def _have_self_input(self):
1.93 last = self.last_op()
1.94 @@ -595,6 +610,8 @@
1.95
1.96 If no optimisation can be achieved, a StoreTemp instruction is produced
1.97 and the appropriate LoadTemp instruction is returned.
1.98 +
1.99 + All returned instructions are provided in a list.
1.100 """
1.101
1.102 if self._should_optimise_temp_storage() and \
1.103 @@ -602,11 +619,11 @@
1.104
1.105 last = self.last_op()
1.106 self.remove_ops(1)
1.107 - return last
1.108 + return [last]
1.109 else:
1.110 temp_position = self.reserve_temp(1)
1.111 self.new_op(StoreTemp(temp_position))
1.112 - return LoadTemp(temp_position)
1.113 + return [LoadTemp(temp_position)]
1.114
1.115 def _optimise_constant_storage(self, instruction, n):
1.116
1.117 @@ -643,7 +660,7 @@
1.118 else:
1.119 return 0
1.120
1.121 - def _optimise_known_target(self):
1.122 + def _optimise_known_target(self, ops=None):
1.123
1.124 """
1.125 Where the target of an invocation is known, provide information about it
1.126 @@ -651,8 +668,8 @@
1.127 appropriate, get information about the specific initialiser.
1.128 """
1.129
1.130 - if self._should_optimise_known_target() and self._have_known_target():
1.131 - last = self.last_op()
1.132 + if self._should_optimise_known_target() and self._have_known_target(ops):
1.133 + last = self.last_op(ops)
1.134 target = last.attr.value
1.135 context = last.attr.parent
1.136
1.137 @@ -730,22 +747,27 @@
1.138 # Left method.
1.139
1.140 self._startCallFunc()
1.141 - self.new_op(temp1)
1.142 + self.new_ops(temp1)
1.143
1.144 # Get left method on temp1.
1.145
1.146 self._generateAttr(node, left_method, (LoadAddress, LoadAttr, LoadAttrIndex))
1.147 temp_method = self._optimise_temp_storage()
1.148
1.149 - if not self._optimise_known_target():
1.150 + # Add exception handling to the method acquisition instructions where
1.151 + # the attribute access cannot be resolved at compile-time.
1.152 +
1.153 + if not self._optimise_known_target(temp_method):
1.154 + self.capture_ops()
1.155 self.dispatch(compiler.ast.Name("AttributeError"))
1.156 - self.new_op(CheckException())
1.157 - self.new_op(JumpIfTrue(end_left_label))
1.158 + temp_method += self.get_captured_ops()
1.159 + temp_method.append(CheckException())
1.160 + temp_method.append(JumpIfTrue(end_left_label))
1.161
1.162 # Add arguments.
1.163
1.164 - self.new_op(temp1) # Explicit context as first argument.
1.165 - self.new_op(temp2)
1.166 + self.new_ops(temp1) # Explicit context as first argument.
1.167 + self.new_ops(temp2)
1.168 self._endCallFunc(temp_method)
1.169
1.170 # Test for NotImplemented.
1.171 @@ -766,22 +788,27 @@
1.172
1.173 self.set_label(right_label)
1.174 self._startCallFunc()
1.175 - self.new_op(temp2)
1.176 + self.new_ops(temp2)
1.177
1.178 # Get right method on temp2.
1.179
1.180 self._generateAttr(node, right_method, (LoadAddress, LoadAttr, LoadAttrIndex))
1.181 temp_method = self._optimise_temp_storage()
1.182
1.183 - if not self._optimise_known_target():
1.184 + # Add exception handling to the method acquisition instructions where
1.185 + # the attribute access cannot be resolved at compile-time.
1.186 +
1.187 + if not self._optimise_known_target(temp_method):
1.188 + self.capture_ops()
1.189 self.dispatch(compiler.ast.Name("AttributeError"))
1.190 - self.new_op(CheckException())
1.191 - self.new_op(JumpIfTrue(type_error_label))
1.192 + temp_method += self.get_captured_ops()
1.193 + temp_method.append(CheckException())
1.194 + temp_method.append(JumpIfTrue(type_error_label))
1.195
1.196 # Add arguments.
1.197
1.198 - self.new_op(temp2) # Explicit context as first argument.
1.199 - self.new_op(temp1)
1.200 + self.new_ops(temp2) # Explicit context as first argument.
1.201 + self.new_ops(temp1)
1.202 self._endCallFunc(temp_method)
1.203
1.204 # Test for NotImplemented.
1.205 @@ -802,9 +829,9 @@
1.206 self.set_label(end_label)
1.207
1.208 # Compilation duties...
1.209 - # NOTE: Potentially remove this when optimised away.
1.210
1.211 - self.discard_temp([temp1, temp2])
1.212 + self.discard_temp(temp1)
1.213 + self.discard_temp(temp2)
1.214
1.215 def visitAdd(self, node):
1.216 self._visitBinary(node, "__add__", "__radd__")