1.1 --- a/micropython/ast.py Sat Aug 02 00:32:48 2008 +0200
1.2 +++ b/micropython/ast.py Sat Aug 02 01:51:07 2008 +0200
1.3 @@ -88,7 +88,7 @@
1.4 # being processed. Also retained is information about temporary values.
1.5
1.6 self.code = None
1.7 - self.temp_position = 0
1.8 + self.temp_positions = set()
1.9
1.10 def __repr__(self):
1.11 return "Translation(%r)" % self.module
1.12 @@ -99,7 +99,7 @@
1.13
1.14 self.unit = self.module
1.15 self.code = []
1.16 - self.temp_position = 0
1.17 + self.temp_positions = set()
1.18
1.19 if self.module.module is not None:
1.20 self.dispatch(self.module.module)
1.21 @@ -112,7 +112,7 @@
1.22
1.23 self.unit = unit
1.24 self.code = []
1.25 - self.temp_position = 0
1.26 + self.temp_positions = set()
1.27
1.28 if unit.astnode is not None:
1.29 self.dispatch(unit.astnode)
1.30 @@ -218,22 +218,28 @@
1.31 sequence of access instructions.
1.32 """
1.33
1.34 - temp_position = self.reserve_temp(1)
1.35 + temp_position = self.reserve_temp()
1.36 self.new_op(StoreTemp(temp_position))
1.37 return LoadTemp(temp_position)
1.38
1.39 def ensure_temp(self):
1.40 if isinstance(self.active, LoadTemp):
1.41 - self.temp_position = max(self.temp_position, self.active.attr + 1)
1.42 -
1.43 - def reserve_temp(self, n):
1.44 - temp_position = self.temp_position
1.45 - self.temp_position += n
1.46 + self.temp_positions.add(self.active.attr)
1.47 +
1.48 + def reserve_temp(self):
1.49 + if not self.temp_positions:
1.50 + temp_position = 0
1.51 + else:
1.52 + temp_position = max(self.temp_positions) + 1
1.53 + self.temp_positions.add(temp_position)
1.54 return temp_position
1.55
1.56 - def discard_temp(self, instruction):
1.57 + def discard_temp(self, instruction=None):
1.58 if isinstance(instruction, LoadTemp):
1.59 - self.temp_position -= 1
1.60 + self.temp_positions.remove(instruction.attr)
1.61 +
1.62 + def cancel_temp(self, temp_position):
1.63 + self.temp_positions.remove(temp_position)
1.64
1.65 # Code writing methods.
1.66
1.67 @@ -325,7 +331,8 @@
1.68 return isinstance(instruction, (
1.69 StoreTemp, StoreFrame, StoreResult, StoreException, # as the value being stored
1.70 LoadAddressContext, LoadAttr, LoadAttrIndex, # as the object being referenced
1.71 - StoreAttr, StoreAttrIndex, StoreCallable # as the object being referenced
1.72 + StoreAttr, StoreAttrIndex, StoreCallable, # as the object being referenced
1.73 + TestIdentity # as one of the operands
1.74 ))
1.75
1.76 def _is_resultant_no_operation(self, instruction):
1.77 @@ -1042,17 +1049,10 @@
1.78 # Get the method on temp.
1.79
1.80 self._generateAttr(node, method, self.attribute_load_instructions)
1.81 -
1.82 - # Add exception handling to the method acquisition instructions where
1.83 - # the attribute access cannot be resolved at compile-time.
1.84 -
1.85 - if not self._optimise_known_target():
1.86 - self.load_builtin("AttributeError", node)
1.87 - self.new_op(CheckException())
1.88 - self.new_op(JumpIfTrue(end_call_label))
1.89 -
1.90 temp_method = self._optimise_temp_storage()
1.91
1.92 + self._handleAttributeError(node, end_call_label)
1.93 +
1.94 # Add arguments.
1.95 # NOTE: No support for defaults.
1.96
1.97 @@ -1120,6 +1120,13 @@
1.98
1.99 def _generateBinary(self, node, temp1, temp2, left_method, right_method):
1.100
1.101 + """
1.102 + For the given 'node', generate the binary operator pattern for the
1.103 + operands 'temp1' and 'temp2', employing 'left_method' and 'right_method'
1.104 + as defined for binary operators, but also used in comparisons (for which
1.105 + this method is provided).
1.106 + """
1.107 +
1.108 right_label = self.new_label()
1.109 type_error_label = self.new_label()
1.110 end_label = self.new_label()
1.111 @@ -1144,6 +1151,13 @@
1.112
1.113 def _generateOpMethod(self, node, temp1, temp2, method_name, next_method_label, end_label):
1.114
1.115 + """
1.116 + For the given 'node', generate the operator method invocation using the
1.117 + operands 'temp1' and 'temp2', employing the given 'method_name', and
1.118 + jumping appropriately to 'next_method_label' where a NotImplemented
1.119 + result is returned, or to 'end_label' if the method call was successful.
1.120 + """
1.121 +
1.122 end_attempt_label = self.new_label()
1.123
1.124 self._startCallFunc()
1.125 @@ -1152,21 +1166,14 @@
1.126 # Get method on temp1.
1.127
1.128 self._generateAttr(node, method_name, self.attribute_load_instructions)
1.129 -
1.130 - # Add exception handling to the method acquisition instructions where
1.131 - # the attribute access cannot be resolved at compile-time.
1.132 -
1.133 - if not self._optimise_known_target():
1.134 - self.load_builtin("AttributeError", node)
1.135 - self.new_op(CheckException())
1.136 - self.new_op(JumpIfTrue(end_attempt_label))
1.137 -
1.138 temp_method = self._optimise_temp_storage()
1.139
1.140 + self._handleAttributeError(node, end_attempt_label)
1.141 +
1.142 # Add arguments.
1.143 # NOTE: No support for defaults.
1.144
1.145 - self.new_op(temp1) # Explicit context as first argument.
1.146 + self.new_op(temp1)
1.147 self.new_op(StoreFrame(0))
1.148 self.new_op(temp2)
1.149 self.new_op(StoreFrame(1))
1.150 @@ -1185,7 +1192,39 @@
1.151 self.set_label(end_attempt_label)
1.152 self._endCallFunc(load_result=0) # From the method call.
1.153
1.154 - def _visitSequence(self, sequence_type, node):
1.155 + def _handleAttributeError(self, node, end_call_label):
1.156 +
1.157 + """
1.158 + Add exception handling to the method acquisition instructions where the
1.159 + attribute access cannot be resolved at compile-time.
1.160 + """
1.161 +
1.162 + if not self._optimise_known_target():
1.163 + self.load_builtin("AttributeError", node)
1.164 + self.new_op(CheckException())
1.165 + self.new_op(JumpIfTrue(end_call_label))
1.166 +
1.167 + def _propagateAttributeError(self, node):
1.168 +
1.169 + """
1.170 + Add exception raising to the method acquisition instructions where the
1.171 + attribute access cannot be resolved at compile-time.
1.172 + """
1.173 +
1.174 + if not self._optimise_known_target():
1.175 + continue_label = self.new_label()
1.176 +
1.177 + self.load_builtin("AttributeError", node)
1.178 + self.new_op(CheckException())
1.179 + self.new_op(JumpIfFalse(continue_label))
1.180 + self.new_op(RaiseException())
1.181 +
1.182 + self.set_label(continue_label)
1.183 +
1.184 + def _generateSequence(self, sequence_type, node):
1.185 +
1.186 + "Make a sequence of 'sequence_type' for the given program 'node'."
1.187 +
1.188 self.new_op(MakeObject((sequence_type, len(node.nodes))))
1.189 temp = self.get_temp()
1.190
1.191 @@ -1301,6 +1340,7 @@
1.192 """
1.193
1.194 end_label = self.new_label()
1.195 + temp_result_pos = self.reserve_temp()
1.196
1.197 self.dispatch(node.expr)
1.198 temp2 = self._optimise_temp_storage()
1.199 @@ -1321,18 +1361,53 @@
1.200 # Generate method call using evaluated argument and next node.
1.201
1.202 self._generateBinary(node, temp1, temp2, left_method, right_method)
1.203 -
1.204 - # Test the result and jump to the end label if false.
1.205 -
1.206 - if op is not last_op:
1.207 - self.new_op(LoadResult())
1.208 - self.new_op(TestBoolean())
1.209 - self.new_op(JumpIfFalse(end_label))
1.210 + self.new_op(LoadResult())
1.211
1.212 else:
1.213 - # NOTE: Deal with the special operators.
1.214 -
1.215 - pass
1.216 + # Deal with the special operators.
1.217 +
1.218 + if op_name.startswith("is"):
1.219 + self.new_op(temp1)
1.220 + self.record_value()
1.221 + self.new_op(temp2)
1.222 + self.new_op(TestIdentity())
1.223 + self.set_source()
1.224 + self.discard_value()
1.225 +
1.226 + elif op_name.endswith("in"):
1.227 + self._startCallFunc()
1.228 + self.new_op(temp2)
1.229 +
1.230 + # Get method on temp2.
1.231 +
1.232 + self._generateAttr(node, "__contains__", self.attribute_load_instructions)
1.233 + temp_method = self._optimise_temp_storage()
1.234 +
1.235 + self._propagateAttributeError(node)
1.236 +
1.237 + # Add arguments.
1.238 + # NOTE: No support for defaults.
1.239 +
1.240 + self.new_op(temp2)
1.241 + self.new_op(StoreFrame(0))
1.242 + self.new_op(temp1)
1.243 + self.new_op(StoreFrame(1))
1.244 + self._doCallFunc(temp_method)
1.245 + self._endCallFunc(temp_method)
1.246 + self.new_op(LoadResult())
1.247 +
1.248 + if op_name.find("not") != -1:
1.249 + self.new_op(InvertBoolean())
1.250 +
1.251 + # Record the result in temporary storage.
1.252 +
1.253 + self.new_op(StoreTemp(temp_result_pos))
1.254 +
1.255 + # Test the result and jump to the end label if false.
1.256 +
1.257 + if op is not last_op:
1.258 + self.new_op(TestBoolean())
1.259 + self.new_op(JumpIfFalse(end_label))
1.260
1.261 # Compilation duties...
1.262
1.263 @@ -1341,7 +1416,8 @@
1.264 self.discard_temp(temp2)
1.265 self.set_label(end_label)
1.266
1.267 - self.new_op(LoadResult())
1.268 + self.new_op(LoadTemp(temp_result_pos))
1.269 + self.cancel_temp(temp_result_pos)
1.270
1.271 def visitConst(self, node):
1.272 const = self.module.constant_values[node.value]
1.273 @@ -1551,7 +1627,7 @@
1.274 self._visitBinary(node, "__lshift__", "__rlshift__")
1.275
1.276 def visitList(self, node):
1.277 - self._visitSequence("list", node)
1.278 + self._generateSequence("list", node)
1.279
1.280 def visitListComp(self, node): raise TranslationNotImplementedError(self.module.full_name(), node, "ListComp")
1.281
1.282 @@ -1719,7 +1795,7 @@
1.283 def visitTryFinally(self, node): raise TranslationNotImplementedError(self.module.full_name(), node, "TryFinally")
1.284
1.285 def visitTuple(self, node):
1.286 - self._visitSequence("tuple", node)
1.287 + self._generateSequence("tuple", node)
1.288
1.289 def visitUnaryAdd(self, node):
1.290 self._visitUnary(node, "__pos__")