# HG changeset patch # User Paul Boddie # Date 1217634667 -7200 # Node ID cbca9c309a1bf088ff2a1accde62f559b145fc1a # Parent 1097b1921e565e6897d4916bef5956a314e9357b Changed temporary storage management to use a set of allocated positions. Improved comparison support, adding the irregular cases and making use of a temporary storage variable as the result of each comparison. Added a TestIdentity instruction. Made certain parts of the operator code generation more modular. Renamed _visitSequence to _generateSequence. diff -r 1097b1921e56 -r cbca9c309a1b micropython/ast.py --- a/micropython/ast.py Sat Aug 02 00:32:48 2008 +0200 +++ b/micropython/ast.py Sat Aug 02 01:51:07 2008 +0200 @@ -88,7 +88,7 @@ # being processed. Also retained is information about temporary values. self.code = None - self.temp_position = 0 + self.temp_positions = set() def __repr__(self): return "Translation(%r)" % self.module @@ -99,7 +99,7 @@ self.unit = self.module self.code = [] - self.temp_position = 0 + self.temp_positions = set() if self.module.module is not None: self.dispatch(self.module.module) @@ -112,7 +112,7 @@ self.unit = unit self.code = [] - self.temp_position = 0 + self.temp_positions = set() if unit.astnode is not None: self.dispatch(unit.astnode) @@ -218,22 +218,28 @@ sequence of access instructions. """ - temp_position = self.reserve_temp(1) + temp_position = self.reserve_temp() self.new_op(StoreTemp(temp_position)) return LoadTemp(temp_position) def ensure_temp(self): if isinstance(self.active, LoadTemp): - self.temp_position = max(self.temp_position, self.active.attr + 1) - - def reserve_temp(self, n): - temp_position = self.temp_position - self.temp_position += n + self.temp_positions.add(self.active.attr) + + def reserve_temp(self): + if not self.temp_positions: + temp_position = 0 + else: + temp_position = max(self.temp_positions) + 1 + self.temp_positions.add(temp_position) return temp_position - def discard_temp(self, instruction): + def discard_temp(self, instruction=None): if isinstance(instruction, LoadTemp): - self.temp_position -= 1 + self.temp_positions.remove(instruction.attr) + + def cancel_temp(self, temp_position): + self.temp_positions.remove(temp_position) # Code writing methods. @@ -325,7 +331,8 @@ return isinstance(instruction, ( StoreTemp, StoreFrame, StoreResult, StoreException, # as the value being stored LoadAddressContext, LoadAttr, LoadAttrIndex, # as the object being referenced - StoreAttr, StoreAttrIndex, StoreCallable # as the object being referenced + StoreAttr, StoreAttrIndex, StoreCallable, # as the object being referenced + TestIdentity # as one of the operands )) def _is_resultant_no_operation(self, instruction): @@ -1042,17 +1049,10 @@ # Get the method on temp. self._generateAttr(node, method, self.attribute_load_instructions) - - # Add exception handling to the method acquisition instructions where - # the attribute access cannot be resolved at compile-time. - - if not self._optimise_known_target(): - self.load_builtin("AttributeError", node) - self.new_op(CheckException()) - self.new_op(JumpIfTrue(end_call_label)) - temp_method = self._optimise_temp_storage() + self._handleAttributeError(node, end_call_label) + # Add arguments. # NOTE: No support for defaults. @@ -1120,6 +1120,13 @@ def _generateBinary(self, node, temp1, temp2, left_method, right_method): + """ + For the given 'node', generate the binary operator pattern for the + operands 'temp1' and 'temp2', employing 'left_method' and 'right_method' + as defined for binary operators, but also used in comparisons (for which + this method is provided). + """ + right_label = self.new_label() type_error_label = self.new_label() end_label = self.new_label() @@ -1144,6 +1151,13 @@ def _generateOpMethod(self, node, temp1, temp2, method_name, next_method_label, end_label): + """ + For the given 'node', generate the operator method invocation using the + operands 'temp1' and 'temp2', employing the given 'method_name', and + jumping appropriately to 'next_method_label' where a NotImplemented + result is returned, or to 'end_label' if the method call was successful. + """ + end_attempt_label = self.new_label() self._startCallFunc() @@ -1152,21 +1166,14 @@ # Get method on temp1. self._generateAttr(node, method_name, self.attribute_load_instructions) - - # Add exception handling to the method acquisition instructions where - # the attribute access cannot be resolved at compile-time. - - if not self._optimise_known_target(): - self.load_builtin("AttributeError", node) - self.new_op(CheckException()) - self.new_op(JumpIfTrue(end_attempt_label)) - temp_method = self._optimise_temp_storage() + self._handleAttributeError(node, end_attempt_label) + # Add arguments. # NOTE: No support for defaults. - self.new_op(temp1) # Explicit context as first argument. + self.new_op(temp1) self.new_op(StoreFrame(0)) self.new_op(temp2) self.new_op(StoreFrame(1)) @@ -1185,7 +1192,39 @@ self.set_label(end_attempt_label) self._endCallFunc(load_result=0) # From the method call. - def _visitSequence(self, sequence_type, node): + def _handleAttributeError(self, node, end_call_label): + + """ + Add exception handling to the method acquisition instructions where the + attribute access cannot be resolved at compile-time. + """ + + if not self._optimise_known_target(): + self.load_builtin("AttributeError", node) + self.new_op(CheckException()) + self.new_op(JumpIfTrue(end_call_label)) + + def _propagateAttributeError(self, node): + + """ + Add exception raising to the method acquisition instructions where the + attribute access cannot be resolved at compile-time. + """ + + if not self._optimise_known_target(): + continue_label = self.new_label() + + self.load_builtin("AttributeError", node) + self.new_op(CheckException()) + self.new_op(JumpIfFalse(continue_label)) + self.new_op(RaiseException()) + + self.set_label(continue_label) + + def _generateSequence(self, sequence_type, node): + + "Make a sequence of 'sequence_type' for the given program 'node'." + self.new_op(MakeObject((sequence_type, len(node.nodes)))) temp = self.get_temp() @@ -1301,6 +1340,7 @@ """ end_label = self.new_label() + temp_result_pos = self.reserve_temp() self.dispatch(node.expr) temp2 = self._optimise_temp_storage() @@ -1321,18 +1361,53 @@ # Generate method call using evaluated argument and next node. self._generateBinary(node, temp1, temp2, left_method, right_method) - - # Test the result and jump to the end label if false. - - if op is not last_op: - self.new_op(LoadResult()) - self.new_op(TestBoolean()) - self.new_op(JumpIfFalse(end_label)) + self.new_op(LoadResult()) else: - # NOTE: Deal with the special operators. - - pass + # Deal with the special operators. + + if op_name.startswith("is"): + self.new_op(temp1) + self.record_value() + self.new_op(temp2) + self.new_op(TestIdentity()) + self.set_source() + self.discard_value() + + elif op_name.endswith("in"): + self._startCallFunc() + self.new_op(temp2) + + # Get method on temp2. + + self._generateAttr(node, "__contains__", self.attribute_load_instructions) + temp_method = self._optimise_temp_storage() + + self._propagateAttributeError(node) + + # Add arguments. + # NOTE: No support for defaults. + + self.new_op(temp2) + self.new_op(StoreFrame(0)) + self.new_op(temp1) + self.new_op(StoreFrame(1)) + self._doCallFunc(temp_method) + self._endCallFunc(temp_method) + self.new_op(LoadResult()) + + if op_name.find("not") != -1: + self.new_op(InvertBoolean()) + + # Record the result in temporary storage. + + self.new_op(StoreTemp(temp_result_pos)) + + # Test the result and jump to the end label if false. + + if op is not last_op: + self.new_op(TestBoolean()) + self.new_op(JumpIfFalse(end_label)) # Compilation duties... @@ -1341,7 +1416,8 @@ self.discard_temp(temp2) self.set_label(end_label) - self.new_op(LoadResult()) + self.new_op(LoadTemp(temp_result_pos)) + self.cancel_temp(temp_result_pos) def visitConst(self, node): const = self.module.constant_values[node.value] @@ -1551,7 +1627,7 @@ self._visitBinary(node, "__lshift__", "__rlshift__") def visitList(self, node): - self._visitSequence("list", node) + self._generateSequence("list", node) def visitListComp(self, node): raise TranslationNotImplementedError(self.module.full_name(), node, "ListComp") @@ -1719,7 +1795,7 @@ def visitTryFinally(self, node): raise TranslationNotImplementedError(self.module.full_name(), node, "TryFinally") def visitTuple(self, node): - self._visitSequence("tuple", node) + self._generateSequence("tuple", node) def visitUnaryAdd(self, node): self._visitUnary(node, "__pos__") diff -r 1097b1921e56 -r cbca9c309a1b micropython/rsvp.py --- a/micropython/rsvp.py Sat Aug 02 00:32:48 2008 +0200 +++ b/micropython/rsvp.py Sat Aug 02 01:51:07 2008 +0200 @@ -207,7 +207,9 @@ # General instructions. +class InvertBoolean(Instruction): "Invert the current value." class TestBoolean(Instruction): "Test whether the current value is a true value." +class TestIdentity(Instruction): "Test whether the current value is identical to the source value." class TestIdentityAddress(Address): "Test whether the current value is identical to the given address." # vim: tabstop=4 expandtab shiftwidth=4