# HG changeset patch # User Paul Boddie # Date 1224964283 -7200 # Node ID b21ccdf5fb579ce095febf4151426a44ad198c98 # Parent 9156ef49a20f93050b3264934866ca781d533d7a Introduced code blocks in place of labels, potentially leading to increased code manipulation possibilities. diff -r 9156ef49a20f -r b21ccdf5fb57 micropython/ast.py --- a/micropython/ast.py Fri Oct 10 00:56:20 2008 +0200 +++ b/micropython/ast.py Sat Oct 25 21:51:23 2008 +0200 @@ -76,8 +76,8 @@ self.labels = {} self.label_number = 0 - self.loop_labels = [] - self.exception_labels = [] + self.loop_blocks = [] + self.exception_blocks = [] self.reset() @@ -91,7 +91,7 @@ # The code itself. This is limited to the code for a particular block # being processed. - self.code = [] + self.blocks = [] # Information about temporary values. @@ -116,6 +116,9 @@ self.unit = self.module self.reset() + block = self.new_block() + self.set_block(block) + if self.module.module is not None: self.dispatch(self.module.module) @@ -125,7 +128,7 @@ self.new_op(Return()) self.unit.temp_usage = self.max_temp_position + 1 - return self.code + return self.blocks def get_code(self, unit): @@ -134,11 +137,14 @@ self.unit = unit self.reset() + block = self.new_block() + self.set_block(block) + if unit.astnode is not None: self.dispatch(unit.astnode) self.unit.temp_usage = self.max_temp_position + 1 - return self.code + return self.blocks def get_instantiator_code(self, cls): @@ -147,6 +153,9 @@ self.unit = cls.get_instantiator() self.reset() + block = self.new_block() + self.set_block(block) + init_method = cls.get_init_method() # Convert this frame back to being an invocation frame. @@ -174,7 +183,7 @@ self.new_op(StoreResult()) self.new_op(Return()) - return self.code + return self.blocks # Allocation-related methods. @@ -231,6 +240,37 @@ # Code feature methods. + def new_block(self): + + "Return a new code block." + + return Block() + + def set_block(self, block): + + "Add the given 'block' to the unit's list of blocks." + + self.optimiser.reset() + self.blocks.append(block) + + def get_loop_blocks(self): + return self.loop_blocks[-1] + + def add_loop_blocks(self, next_block, exit_block): + self.loop_blocks.append((next_block, exit_block)) + + def drop_loop_blocks(self): + self.loop_blocks.pop() + + def get_exception_blocks(self): + return self.exception_blocks[-1] + + def add_exception_blocks(self, handler_block, exit_block): + self.exception_blocks.append((handler_block, exit_block)) + + def drop_exception_blocks(self): + self.exception_blocks.pop() + def new_label(self): "Return a new label object for use with set_label." @@ -250,24 +290,6 @@ label.location = len(self.code) + self.unit.code_location - def get_loop_labels(self): - return self.loop_labels[-1] - - def add_loop_labels(self, next_label, exit_label): - self.loop_labels.append((next_label, exit_label)) - - def drop_loop_labels(self): - self.loop_labels.pop() - - def get_exception_labels(self): - return self.exception_labels[-1] - - def add_exception_labels(self, handler_label, exit_label): - self.exception_labels.append((handler_label, exit_label)) - - def drop_exception_labels(self): - self.exception_labels.pop() - # Assignment expression values. def record_value(self, immediate=1): @@ -401,14 +423,16 @@ if self.optimiser.optimise_away_no_operations(op): return - self.code.append(op) + # Add the operation to the current block. + + self.blocks[-1].code.append(op) self.optimiser.set_new(op) def remove_op(self): "Remove the last instruction." - op = self.code.pop() + op = self.blocks[-1].code.pop() self.optimiser.clear_active() def replace_op(self, op): @@ -432,7 +456,7 @@ "Return the last added instruction." try: - return self.code[-1] + return self.blocks[-1].code[-1] except IndexError: return None @@ -774,10 +798,11 @@ if not self.optimiser.have_correct_self_for_target(context, self.unit): - continue_label = self.new_label() + continue_block = self.new_block() + self.new_op(CheckSelf()) self.optimiser.set_source(temp) - self.new_op(JumpIfTrue(continue_label)) + self.new_op(JumpIfTrue(continue_block)) # Where the context is inappropriate, drop the incomplete frame and # raise an exception. @@ -788,7 +813,8 @@ self.load_builtin("TypeError", node) self.new_op(StoreException()) self.new_op(RaiseException()) - self.set_label(continue_label) + + self.set_block(continue_block) first = 0 frame_pos += 1 @@ -996,8 +1022,8 @@ raise TypeError """ - type_error_label = self.new_label() - end_label = self.new_label() + type_error_block = self.new_block() + end_block = self.new_block() # Evaluate and store the operand in temporary storage. @@ -1011,7 +1037,7 @@ self._generateAttr(node, method, self.attribute_load_instructions) temp_method = self.optimiser.optimise_temp_storage() - self._handleAttributeError(node, type_error_label) + self._handleAttributeError(node, type_error_block) # Add arguments. # NOTE: No support for defaults. @@ -1022,7 +1048,7 @@ self._endCallFuncArgs(1) self._doCallFunc(temp_method) self._endCallFunc(temp_method) - self.new_op(Jump(end_label)) + self.new_op(Jump(end_block)) # Store the result. @@ -1030,16 +1056,12 @@ # Raise a TypeError. - self.set_label(type_error_label) + self.set_block(type_error_block) self.load_builtin("TypeError", node) self.new_op(StoreException()) self.new_op(RaiseException()) - # Prevent incorrect optimisation. - - self.optimiser.reset() - - self.set_label(end_label) + self.set_block(end_block) # Produce the result. @@ -1101,46 +1123,42 @@ A temporary storage reference is returned from this method. """ - right_label = self.new_label() - type_error_label = self.new_label() - end_label = self.new_label() + right_block = self.new_block() + type_error_block = self.new_block() + end_block = self.new_block() # Left method. - temp_out = self._generateOpMethod(node, temp1, temp2, left_method, right_label, end_label) + temp_out = self._generateOpMethod(node, temp1, temp2, left_method, right_block, end_block) self.discard_temp(temp_out) # NOTE: Will re-use the same storage. # Right method. - self.set_label(right_label) - temp_out = self._generateOpMethod(node, temp2, temp1, right_method, type_error_label, end_label) + self.set_block(right_block) + temp_out = self._generateOpMethod(node, temp2, temp1, right_method, type_error_block, end_block) # Raise a TypeError. - self.set_label(type_error_label) + self.set_block(type_error_block) self.load_builtin("TypeError", node) self.new_op(StoreException()) self.new_op(RaiseException()) - # Prevent incorrect optimisation. - - self.optimiser.reset() - - self.set_label(end_label) + self.set_block(end_block) return temp_out - def _generateOpMethod(self, node, temp1, temp2, method_name, next_method_label, end_label): + def _generateOpMethod(self, node, temp1, temp2, method_name, next_method_block, end_block): """ 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. + jumping appropriately to 'next_method_block' where a NotImplemented + result is returned, or to 'end_block' if the method call was successful. A temporary storage reference is returned from this method. """ - end_attempt_label = self.new_label() + end_attempt_block = self.new_block() self.new_op(temp1) @@ -1149,7 +1167,7 @@ self._generateAttr(node, method_name, self.attribute_load_instructions) temp_method = self.optimiser.optimise_temp_storage() - self._handleAttributeError(node, end_attempt_label) + self._handleAttributeError(node, end_attempt_block) # Add arguments. # NOTE: No support for defaults. @@ -1171,15 +1189,15 @@ # Don't actually raise an exception. self.new_op(TestIdentityAddress(self.get_builtin("NotImplemented", node))) - self.new_op(JumpIfTrue(next_method_label)) - self.new_op(Jump(end_label)) + self.new_op(JumpIfTrue(next_method_block)) + self.new_op(Jump(end_block)) # End method attempt. - self.set_label(end_attempt_label) + self.set_block(end_attempt_block) return temp_out - def _handleAttributeError(self, node, end_call_label): + def _handleAttributeError(self, node, end_call_block): """ Add exception handling to the method acquisition instructions where the @@ -1189,7 +1207,7 @@ if not self.optimiser.optimise_known_target(): self.load_builtin("AttributeError", node) self.new_op(CheckException()) - self.new_op(JumpIfTrue(end_call_label)) + self.new_op(JumpIfTrue(end_call_block)) def _generateSequence(self, sequence_type, node): @@ -1242,17 +1260,17 @@ boolean status. """ - true_label = self.new_label() - end_label = self.new_label() - - self.new_op(JumpIfTrue(true_label)) + true_block = self.new_block() + end_block = self.new_block() + + self.new_op(JumpIfTrue(true_block)) self.load_builtin("False", node) - self.new_op(Jump(end_label)) - - self.set_label(true_label) + self.new_op(Jump(end_block)) + + self.set_block(true_block) self.load_builtin("True", node) - self.set_label(end_label) + self.set_block(end_block) # Concrete visitor methods. @@ -1308,7 +1326,7 @@ # Logical operators. def visitAnd(self, node): - end_label = self.new_label() + end_block = self.new_block() temp_pos = self.reserve_temp() temp = LoadTemp(temp_pos) @@ -1317,16 +1335,12 @@ self.new_op(StoreTemp(temp_pos)) self._generateTestBoolean(n, temp) - self.new_op(JumpIfFalse(end_label)) + self.new_op(JumpIfFalse(end_block)) self.dispatch(node.nodes[-1]) self.new_op(StoreTemp(temp_pos)) - self.set_label(end_label) - - # Prevent incorrect optimisation. - - self.optimiser.reset() + self.set_block(end_block) self.new_op(temp) self.discard_temp(temp) @@ -1341,12 +1355,8 @@ self.new_op(InvertBoolean()) self._generateLoadBoolean(node) - # Prevent incorrect optimisation. - - self.optimiser.reset() - def visitOr(self, node): - end_label = self.new_label() + end_block = self.new_block() temp_pos = self.reserve_temp() temp = LoadTemp(temp_pos) @@ -1355,16 +1365,12 @@ self.new_op(StoreTemp(temp_pos)) self._generateTestBoolean(n, temp) - self.new_op(JumpIfTrue(end_label)) + self.new_op(JumpIfTrue(end_block)) self.dispatch(node.nodes[-1]) self.new_op(StoreTemp(temp_pos)) - self.set_label(end_label) - - # Prevent incorrect optimisation. - - self.optimiser.reset() + self.set_block(end_block) self.new_op(temp) self.discard_temp(temp) @@ -1378,7 +1384,7 @@ _t1 op1 _t2 and _t2 op2 _t3 and ... """ - end_label = self.new_label() + end_block = self.new_block() self.dispatch(node.expr) temp2 = self.optimiser.optimise_temp_storage() @@ -1446,10 +1452,10 @@ if op_name.find("not") != -1: self.new_op(InvertBoolean()) - # Test the result and jump to the end label if false. + # Test the result and jump to the end block if false. if op is not last_op: - self.new_op(JumpIfFalse(end_label)) + self.new_op(JumpIfFalse(end_block)) # Compilation duties... @@ -1459,11 +1465,7 @@ # With the status set above, produce a boolean result. - self.set_label(end_label) - - # Prevent incorrect optimisation. - - self.optimiser.reset() + self.set_block(end_block) # Yield the appropriate value. @@ -1595,8 +1597,8 @@ visitAssTuple = visitAssList def visitAugAssign(self, node): - use_binary_label = self.new_label() - end_label = self.new_label() + use_binary_block = self.new_block() + end_block = self.new_block() # Evaluate the expression. @@ -1611,17 +1613,17 @@ # Find the augmented assignment method and attempt to use it. aug_method, (left_method, right_method) = self.augassign_methods[node.op] - temp_out = self._generateOpMethod(node, temp1, temp2, aug_method, use_binary_label, end_label) + temp_out = self._generateOpMethod(node, temp1, temp2, aug_method, use_binary_block, end_block) self.discard_temp(temp_out) # NOTE: Will re-use the same storage. # Where no such method exists, use the binary operator methods. - self.set_label(use_binary_label) + self.set_block(use_binary_block) temp_out = self._generateBinary(node, temp1, temp2, left_method, right_method) # Assign the result to the name. - self.set_label(end_label) + self.set_block(end_block) self.new_op(temp_out) self.record_value(1) @@ -1766,23 +1768,23 @@ def visitAssert(self, node): raise TranslationNotImplementedError(self.module.full_name(), node, "Assert") def visitBreak(self, node): - next_label, exit_label = self.get_loop_labels() - self.new_op(Jump(exit_label)) + next_block, exit_block = self.get_loop_blocks() + self.new_op(Jump(exit_block)) def visitContinue(self, node): - next_label, exit_label = self.get_loop_labels() - self.new_op(Jump(next_label)) + next_block, exit_block = self.get_loop_blocks() + self.new_op(Jump(next_block)) def visitDiscard(self, node): self.dispatch(node.expr) self.optimiser.optimise_unused_results() def visitFor(self, node): - next_handler_label = self.new_label() - end_handler_label = self.new_label() - exit_label = self.new_label() - next_label = self.new_label() - else_label = self.new_label() + next_handler_block = self.new_block() + end_handler_block = self.new_block() + exit_block = self.new_block() + next_block = self.new_block() + else_block = self.new_block() # Get the "list" to be iterated over, obtain its iterator. @@ -1797,11 +1799,11 @@ # In the loop... - self.set_label(next_label) + self.set_block(next_block) # Handle exceptions when calling "next"... - self.new_op(PushHandler(next_handler_label)) + self.new_op(PushHandler(next_handler_block)) # Use the iterator to get the next value. @@ -1818,11 +1820,11 @@ # Skip the handler where the call was successful. - self.new_op(Jump(end_handler_label)) + self.new_op(Jump(end_handler_block)) # Enter the exception handler. - self.set_label(next_handler_label) + self.set_block(next_handler_block) self.new_op(PopHandler()) # Test for StopIteration. @@ -1830,9 +1832,9 @@ self.load_builtin("StopIteration", node) self.new_op(CheckException()) if node.else_ is not None: - self.new_op(JumpIfTrue(else_label)) + self.new_op(JumpIfTrue(else_block)) else: - self.new_op(JumpIfTrue(exit_label)) + self.new_op(JumpIfTrue(exit_block)) # Re-raise the exception otherwise. @@ -1840,7 +1842,7 @@ # After the handler. - self.set_label(end_handler_label) + self.set_block(end_handler_block) # Assign to the target. @@ -1849,28 +1851,24 @@ # Process the body with the current next and exit points. - self.add_loop_labels(next_label, exit_label) + self.add_loop_blocks(next_block, exit_block) self.dispatch(node.body) - self.drop_loop_labels() + self.drop_loop_blocks() # Repeat the loop. - self.new_op(Jump(next_label)) + self.new_op(Jump(next_block)) # Produce the "else" section. if node.else_ is not None: - self.set_label(exit_label) - - # Prevent incorrect optimisation. - - self.optimiser.reset() + self.set_block(exit_block) self.dispatch(node.else_) # After the loop... - self.set_label(exit_label) + self.set_block(exit_block) # Compilation duties... @@ -1878,7 +1876,7 @@ def visitIf(self, node): first = 1 - exit_label = self.new_label() + exit_block = self.new_block() clauses = node.tests + [(None, node.else_)] last_clause = clauses[-1] @@ -1888,22 +1886,18 @@ if body is None: break if not first: - self.set_label(next_label) + self.set_block(next_block) if test is not None: self.dispatch(test) - next_label = self.new_label() - self.new_op(JumpIfFalse(next_label)) + next_block = self.new_block() + self.new_op(JumpIfFalse(next_block)) self.dispatch(body) if clause is not last_clause: - self.new_op(Jump(exit_label)) - - # Prevent incorrect optimisation. - - self.optimiser.reset() + self.new_op(Jump(exit_block)) first = 0 - self.set_label(exit_label) + self.set_block(exit_block) def visitPass(self, node): pass @@ -1943,36 +1937,32 @@ self.new_op(Return()) def visitTryExcept(self, node): - exit_label = self.new_label() - else_label = self.new_label() - handler_label = self.new_label() - - self.add_exception_labels(handler_label, exit_label) + exit_block = self.new_block() + else_block = self.new_block() + handler_block = self.new_block() + + self.add_exception_blocks(handler_block, exit_block) # Try... # Produce the code, then jump to the exit. - self.new_op(PushHandler(handler_label)) + self.new_op(PushHandler(handler_block)) self.dispatch(node.body) self.new_op(PopHandler()) if node.else_ is not None: - self.new_op(Jump(else_label)) + self.new_op(Jump(else_block)) else: - self.new_op(Jump(exit_label)) + self.new_op(Jump(exit_block)) # Start of handlers. - self.set_label(handler_label) - - # Prevent incorrect optimisation. - - self.optimiser.reset() + self.set_block(handler_block) self.new_op(PopHandler()) for name, assignment, handler in node.handlers: - next_label = self.new_label() + next_block = self.new_block() # Test the given exception against the current exception. @@ -1980,7 +1970,7 @@ self.dispatch(name) self.new_op(CheckException()) - self.new_op(JumpIfFalse(next_label)) + self.new_op(JumpIfFalse(next_block)) # Handle assignment to exception variable. @@ -1996,13 +1986,9 @@ # Produce the handler code, then jump to the exit. self.dispatch(handler) - self.new_op(Jump(exit_label)) - - self.set_label(next_label) - - # Prevent incorrect optimisation. - - self.optimiser.reset() + self.new_op(Jump(exit_block)) + + self.set_block(next_block) # Unhandled exceptions. @@ -2011,52 +1997,40 @@ # Optional else clause. if node.else_ is not None: - self.set_label(else_label) - - # Prevent incorrect optimisation. - - self.optimiser.reset() + self.set_block(else_block) self.dispatch(node.else_) - self.set_label(exit_label) - self.drop_exception_labels() + self.set_block(exit_block) + self.drop_exception_blocks() def visitTryFinally(self, node): raise TranslationNotImplementedError(self.module.full_name(), node, "TryFinally") def visitWhile(self, node): - exit_label = self.new_label() - next_label = self.new_label() - else_label = self.new_label() - - self.set_label(next_label) + exit_block = self.new_block() + next_block = self.new_block() + else_block = self.new_block() + + self.set_block(next_block) self.dispatch(node.test) if node.else_ is not None: - self.new_op(JumpIfFalse(else_label)) + self.new_op(JumpIfFalse(else_block)) else: - self.new_op(JumpIfFalse(exit_label)) - - self.add_loop_labels(next_label, exit_label) + self.new_op(JumpIfFalse(exit_block)) + + self.add_loop_blocks(next_block, exit_block) self.dispatch(node.body) - self.new_op(Jump(next_label)) + self.new_op(Jump(next_block)) if node.else_ is not None: - self.set_label(else_label) - - # Prevent incorrect optimisation. - - self.optimiser.reset() + self.set_block(else_block) self.dispatch(node.else_) - self.set_label(exit_label) - - # Prevent incorrect optimisation. - - self.optimiser.reset() - - self.drop_loop_labels() + self.set_block(exit_block) + + self.drop_loop_blocks() def visitWith(self, node): raise TranslationNotImplementedError(self.module.full_name(), node, "With") diff -r 9156ef49a20f -r b21ccdf5fb57 micropython/common.py --- a/micropython/common.py Fri Oct 10 00:56:20 2008 +0200 +++ b/micropython/common.py Sat Oct 25 21:51:23 2008 +0200 @@ -73,6 +73,16 @@ # Program code representations. +class Block: + + "A code block." + + def __init__(self): + self.code = [] + + def __repr__(self): + return "Block(%r)" % id(self) + class Label: "A reference to a location."