# HG changeset patch # User Paul Boddie # Date 1216334993 -7200 # Node ID 915efb9687433c0e95cf52238d2798c0f5f1b589 # Parent 00ce6c2f044010d5e8b8dc02eaf4083bef131774 Removed the value stack mechanisms. Added and/not/or support. Added a test of logical operators. diff -r 00ce6c2f0440 -r 915efb968743 micropython/ast.py --- a/micropython/ast.py Tue Jul 15 21:16:17 2008 +0200 +++ b/micropython/ast.py Fri Jul 18 00:49:53 2008 +0200 @@ -31,7 +31,7 @@ "A translated module." - supported_optimisations = ["constant_storage", "known_target", "self_access", "temp_storage", "constant_test", "stack_access"] + supported_optimisations = ["constant_storage", "known_target", "self_access", "temp_storage"] attribute_load_instructions = (LoadAddress, LoadAddressContext, LoadAttr, LoadAttrIndex) attribute_store_instructions = (StoreAddress, StoreAddressContext, StoreAttr, StoreAttrIndex) @@ -63,6 +63,12 @@ self.unit = None + # The current "active" instruction. + # As a rule, this will become the last instruction, but some + # control-flow operations will flush the "active" instruction. + + self.active = None + # Wiring within the code. self.labels = {} @@ -71,15 +77,10 @@ self.exception_labels = [] # The code itself. This is limited to the code for a particular block - # being processed. Also retained is information about temporary values - # and the presumed state of the value stack. + # being processed. Also retained is information about temporary values. self.code = None - self.last_invocation = None self.temp_position = 0 - self.stack = [] - self.suspended_frame = [] - self.frame_positions = [] def __repr__(self): return "Translation(%r)" % self.module @@ -90,9 +91,7 @@ self.unit = self.module self.code = [] - self.last_invocation = None - self.temp_position = self.unit.stack_local_usage - self.stack = [] + self.temp_position = 0 if self.module.module is not None: self.dispatch(self.module.module) @@ -105,15 +104,15 @@ self.unit = unit self.code = [] - self.last_invocation = None - self.temp_position = self.unit.stack_local_usage - self.stack = [] + self.temp_position = 0 if unit.astnode is not None: self.dispatch(unit.astnode) return self.code + # Name-related methods. + def get_scope(self, name): "Return the scope for the given 'name'." @@ -125,61 +124,28 @@ else: return "builtins" - # Code feature methods. - - def reset_stack(self): - - "Reset the stack for the current unit." + def load_builtin(self, name, node): - self.stack = [] - - def adjust_stack(self, op): - - "Adjust the stack according to the effect of 'op'." + "Generate an instruction loading 'name' for the given 'node'." - position = len(self.code) - stack_level = len(self.stack) - - op.fix_stack(stack_level) - effect = op.get_effect() + self.new_op(LoadAddress(self.get_builtin(name, node))) - if effect == 1: - self.stack.append((position, op)) - elif effect < 0: - while effect != 0: - self.stack.pop() - effect += 1 - - # Update the stack levels. + def get_builtin(self, name, node): - self.unit.stack_usage = max(self.unit.stack_usage, stack_level) - - def revert_stack(self, op): - - "Revert the stack affected by 'op'." - - effect = op.get_effect() + """ + Return the built-in module definition for the given 'name', used by the + given 'node'. + """ - if effect > 0: - while effect != 0: - self.stack.pop() - effect -= 1 - elif effect < 0: - raise ProcessingError, "Cannot remove instructions which reduce the stack." - - def make_frame(self): - self.frame_positions.append(len(self.stack)) + if self.builtins is not None: + try: + return self.builtins[name] + except KeyError: + raise TranslateError(self.module.full_name(), node, "No __builtins__ definition is available for name %r." % name) + else: + raise TranslateError(self.module.full_name(), node, "No __builtins__ module is available for name %r." % name) - def suspend_frame(self): - self.suspended_frame = self.stack[self.frame_positions[-1]:] - self.stack = self.stack[:self.frame_positions[-1]] - - def resume_frame(self): - self.stack += self.suspended_frame - self.suspended_frame = [] - - def drop_frame(self): - self.stack = self.stack[:self.frame_positions.pop()] + # Code feature methods. def new_label(self): @@ -218,10 +184,20 @@ def drop_exception_labels(self): self.exception_labels.pop() + def get_temp(self): + + """ + Add a temporary storage instruction for the current value and return a + sequence of access instructions. + """ + + temp_position = self.reserve_temp(1) + self.new_op(StoreTemp(temp_position)) + return [LoadTemp(temp_position)] + def reserve_temp(self, n): temp_position = self.temp_position self.temp_position += n - self.unit.stack_temp_usage = max(self.unit.stack_temp_usage, self.temp_position) return temp_position def discard_temp(self, instructions): @@ -235,19 +211,14 @@ "Add 'op' to the generated code." - # Optimise stack access by incorporating the source data directly into - # instructions. - - self._optimise_stack_access(op) - # Optimise away constant storage if appropriate. # The target and value loading operations are also removed. if self._optimise_constant_storage(op): return - self.adjust_stack(op) self.code.append(op) + self.active = op def new_ops(self, ops): @@ -259,43 +230,20 @@ for op in ops: self.new_op(op.copy()) - def remove_ops(self, n): - - "Remove the last 'n' instructions." + def remove_op(self): - for i in range(0, n): - op = self.code.pop() - self.revert_stack(op) + "Remove the last instruction." + + op = self.code.pop() + self.active = None def replace_op(self, op): "Replace the last added instruction with 'op'." - self.remove_ops(1) + self.remove_op() self.new_op(op) - def remove_op_using_stack(self, op): - - "Remove the instruction which created the top stack position." - - position, op = self.stack[-1] - - # NOTE: Prevent removal of non-end instructions. - - if position < len(self.code) - 1: - return 0 - else: - self.remove_ops(1) - return 1 - - def last_ops(self, n): - - "Return the last 'n' added instructions in reverse chronological order." - - ops = self.code[-n:] - ops.reverse() - return ops - def last_op(self): "Return the last added instruction." @@ -305,12 +253,6 @@ except IndexError: return None - def set_last_invocation(self): - - "Set this location as the point after the last invocation." - - self.last_invocation = len(self.code) - # Internal helper methods. def _visitAttr(self, node, classes): @@ -331,12 +273,11 @@ AddressInstruction, AddressContextInstruction, AttrInstruction, AttrIndexInstruction = classes - last = self.last_op() - # Where the last operation (defining the attribute owner) yields a # constant... - if self._have_constant_input(0): + if self._have_constant_input(): + last = self.active # Get the details of the access. @@ -392,12 +333,23 @@ self.new_op(AttrIndexInstruction(index)) + # Invocations involve the following: + # + # 1. Reservation of a frame for the arguments + # 2. Identification of the target which is then held in temporary storage + # 3. Optional inclusion of a context (important for methods) + # 4. Preparation of the argument frame + # 5. Invocation of the target + # 6. Discarding of the frame + # + # In order to support nested invocations - eg. a(b(c)) - use of the + # temporary storage is essential. + def _startCallFunc(self): "Record the location of the invocation." self.new_op(MakeFrame()) # records the start of the frame - self.make_frame() def _generateCallFunc(self, args, node): @@ -549,7 +501,7 @@ # use (callable+0)+paramindex+table # checks embedded offset against (callable+0) - # moves the top of stack to frame+position + # moves the current value to frame+position else: self.dispatch(arg) @@ -569,20 +521,12 @@ self.new_op(DropFrame()) - # Pretend that the frame is now gone, generating suitable stack - # operations. - - self.suspend_frame() self.new_op(LoadResult()) - self.dispatch(compiler.ast.Name("TypeError")) + self.load_builtin("TypeError", node) self.new_op(RaiseException()) self.set_label(continue_label) - # Obtain the suspended frame for subsequent outcomes. - - self.resume_frame() - first = 0 frame_pos += 1 @@ -636,24 +580,12 @@ self.new_ops(instructions) self.new_op(JumpWithFrame()) - def _endCallFunc(self, instructions=None, keep_frame=0): + def _endCallFunc(self, instructions=None): "Finish the invocation and tidy up afterwards." - # NOTE: Exception handling required. - - # Note this as the most recent invocation. - - self.set_last_invocation() - self.new_op(DropFrame()) - if keep_frame: - self.suspend_frame() - else: - self.drop_frame() self.new_op(LoadResult()) - if keep_frame: - self.resume_frame() # Discard any temporary storage instructions. @@ -700,25 +632,13 @@ raise TranslateError(self.module.full_name(), node, "Module %r has no attribute %r." % (self.module, name)) else: - self.new_op(AddressInstruction(self._get_builtin(name, node))) - - def _get_builtin(self, name, node): - if self.builtins is not None: - try: - return self.builtins[name] - except KeyError: - raise TranslateError(self.module.full_name(), node, "No __builtins__ definition is available for name %r." % name) - else: - raise TranslateError(self.module.full_name(), node, "No __builtins__ module is available for name %r." % name) + self.new_op(AddressInstruction(self.get_builtin(name, node))) # Optimisation tests. def _should_optimise_constant_storage(self): return "constant_storage" in self.optimisations - def _should_optimise_constant_test(self): - return "constant_test" in self.optimisations - def _should_optimise_known_target(self): return "known_target" in self.optimisations @@ -728,9 +648,6 @@ def _should_optimise_temp_storage(self): return "temp_storage" in self.optimisations - def _should_optimise_stack_access(self): - return "stack_access" in self.optimisations - # Simple tests. def _is_constant_input(self, instruction): @@ -740,84 +657,45 @@ return isinstance(instruction, LoadAddress) and instruction.attr.assignments == 1 or \ isinstance(instruction, LoadConst) + def _is_constant_target(self, instruction): + + "Return whether 'instruction' provides a constant target." + + return isinstance(instruction, (StoreName, StoreAddress)) and \ + instruction.attr.assignments == 1 + def _is_local_input(self, instruction): "Return whether 'instruction' provides a local input." return isinstance(instruction, (LoadName, LoadTemp)) - def _is_unaffected(self, instruction, position): - - """ - Return whether 'instruction' is unaffected by side-effects since it - occurs at a 'position' later than the last invocation. - """ - - return isinstance(instruction, (LoadResult, LoadAddress)) and ( - self.last_invocation is None or position >= self.last_invocation) - # Convenience tests. - def _have_constant_input(self, n): + def _have_constant_input(self): - "Return whether the last 'n' instructions provide constant inputs." + "Return whether the active instruction provides a constant input." - last = self.last_ops(n+1) - return len(last) > n and self._is_constant_input(last[n]) + return self._is_constant_input(self.active) - def _have_known_target(self): - - "Return whether the last instruction is a known target." - - return self._have_constant_input(0) + _have_known_target = _have_constant_input def _have_self_input(self): - "Return whether the last instruction is a reference to self." + "Return whether the active instruction is a reference to self." - last = self.last_op() return isinstance(self.unit, Function) and \ - self.unit.is_method() and isinstance(last, LoadName) and \ - last.attr.name == "self" + self.unit.is_method() and isinstance(self.active, LoadName) and \ + self.active.attr.name == "self" def _have_temp_compatible_access(self): """ - Indicate whether the last instruction can be used in place of access to - a temporary variable retaining the result of the last instruction. + Indicate whether the active instruction can be used in place of access + to a temporary variable retaining the result of the last instruction. """ - last = self.last_op() - # NOTE: Should expand to cover LoadAttr and LoadAttrIndex, but this - # NOTE: would require inspection of the stack operations. - return isinstance(last, (LoadName, LoadTemp, LoadAddress, LoadConst)) - - def _get_access_instructions(self, instruction): - - """ - Get the stack access instructions employed by the given 'instruction'. - It is assumed that the source of the data communicated through the stack - is not modified since the storage of the data. However, since the stack - should only be employed within statements, there should be no risk of - side-effects for local storage. - """ - - access_ops = [] - for stack_op in instruction.accesses: - if isinstance(stack_op, (StackLoad, StackPull)): - position, op = self.stack[stack_op.n] - - # Insist on constants, locals or other things which should not - # have been changed. - - if not self._is_constant_input(op) and not self._is_local_input(op) and \ - not self._is_unaffected(op, position): - - return None - - access_ops.append((op, stack_op)) - - return access_ops + return isinstance(self.active, (LoadName, LoadTemp, LoadAddress, LoadConst)) # Optimisation methods. See the supported_optimisations class attribute. @@ -843,12 +721,10 @@ self._have_temp_compatible_access(): last = self.last_op() - self.remove_ops(1) + self.remove_op() return [last] else: - temp_position = self.reserve_temp(1) - self.new_op(StoreTemp(temp_position)) - return [LoadTemp(temp_position)] + return self.get_temp() def _optimise_constant_storage(self, instruction): @@ -858,27 +734,10 @@ """ if self._should_optimise_constant_storage() and \ - isinstance(instruction, (StoreName, StoreAddress)) and \ - instruction.attr.assignments == 1: - - return 1 - else: - return 0 - - def _optimise_constant_test(self, instruction): + self._is_constant_target(instruction) and \ + self._have_constant_input(): - """ - Where this operation tests the topmost stack value which happens to be - a constant against another stack value, merge the last instruction which - loaded the constant into the current 'instruction'. - """ - - if self._should_optimise_constant_test() and \ - instruction is TestIdentity and \ - self._have_constant_input(0): - - last = self.last_op() - self.replace_op(TestIdentityAddress(last.attr)) + self.remove_op() return 1 else: return 0 @@ -940,27 +799,6 @@ else: return 0 - def _optimise_stack_access(self, instruction): - - """ - Optimise stack access for the given 'instruction', replacing stack - operations with instructions directly accessing the required data. - """ - - if self._should_optimise_stack_access(): - ops = self._get_access_instructions(instruction) - if ops is not None: - instruction.accesses = [] - for op, stack_op in ops: - if self.remove_op_using_stack(op): - instruction.accesses.append(op) - - # Remove the stack side-effects of these accesses. - - op.remove_results() - else: - instruction.accesses.append(stack_op) - # Visitor methods. def default(self, node, *args): @@ -1000,7 +838,7 @@ # the attribute access cannot be resolved at compile-time. if not self._optimise_known_target(): - self.dispatch(compiler.ast.Name("AttributeError")) + self.load_builtin("AttributeError", node) self.new_op(CheckException()) self.new_op(JumpIfTrue(end_call_label)) @@ -1011,7 +849,7 @@ self.new_ops(temp) # Explicit context as first argument. self._doCallFunc(temp_method) - self._endCallFunc(temp_method, keep_frame=1) + self._endCallFunc(temp_method) self.new_op(Jump(end_label)) # End method attempt. @@ -1021,7 +859,7 @@ # Raise a TypeError. - self.dispatch(compiler.ast.Name("TypeError")) + self.load_builtin("TypeError", node) self.new_op(RaiseException()) self.set_label(end_label) @@ -1077,7 +915,7 @@ # the attribute access cannot be resolved at compile-time. if not self._optimise_known_target(): - self.dispatch(compiler.ast.Name("AttributeError")) + self.load_builtin("AttributeError", node) self.new_op(CheckException()) self.new_op(JumpIfTrue(end_left_label)) @@ -1089,14 +927,12 @@ self.new_ops(temp1) # Explicit context as first argument. self.new_ops(temp2) self._doCallFunc(temp_method) - self._endCallFunc(temp_method, keep_frame=1) + self._endCallFunc(temp_method) # Test for NotImplemented. # Don't actually raise an exception. - self.dispatch(compiler.ast.Name("NotImplemented")) - if not self._optimise_constant_test(TestIdentity): - self.new_op(TestIdentity()) + self.new_op(TestIdentityAddress(self.get_builtin("NotImplemented", node))) self.new_op(JumpIfTrue(right_label)) self.new_op(Jump(end_label)) @@ -1119,7 +955,7 @@ # the attribute access cannot be resolved at compile-time. if not self._optimise_known_target(): - self.dispatch(compiler.ast.Name("AttributeError")) + self.load_builtin("AttributeError", node) self.new_op(CheckException()) self.new_op(JumpIfTrue(end_right_label)) @@ -1131,14 +967,12 @@ self.new_ops(temp2) # Explicit context as first argument. self.new_ops(temp1) self._doCallFunc(temp_method) - self._endCallFunc(temp_method, keep_frame=1) + self._endCallFunc(temp_method) # Test for NotImplemented. # Don't actually raise an exception. - self.dispatch(compiler.ast.Name("NotImplemented")) - if not self._optimise_constant_test(TestIdentity): - self.new_op(TestIdentity()) + self.new_op(TestIdentityAddress(self.get_builtin("NotImplemented", node))) self.new_op(JumpIfTrue(type_error_label)) self.new_op(Jump(end_label)) @@ -1150,7 +984,7 @@ # Raise a TypeError. self.set_label(type_error_label) - self.dispatch(compiler.ast.Name("TypeError")) + self.load_builtin("TypeError", node) self.new_op(RaiseException()) self.set_label(end_label) @@ -1163,15 +997,32 @@ def visitAdd(self, node): self._visitBinary(node, "__add__", "__radd__") - def visitAnd(self, node): raise TranslationNotImplementedError(self.module.full_name(), node, "And") + def visitAnd(self, node): + next_label = self.new_label() + + for n in node.nodes[:-1]: + self.dispatch(n) + self.new_op(TestBoolean()) + self.new_op(JumpIfFalse(next_label)) + + self.dispatch(node.nodes[-1]) + self.set_label(next_label) + + # Prevent incorrect optimisation. + + self.active = None def visitAssert(self, node): raise TranslationNotImplementedError(self.module.full_name(), node, "Assert") def visitAssign(self, node): self.dispatch(node.expr) + temp = self.get_temp() + for n in node.nodes: self.dispatch(n) + self.discard_temp(temp) + def visitAssAttr(self, node): self._visitAttr(node, self.attribute_store_instructions) @@ -1283,12 +1134,7 @@ self._doCallFunc(temp) self._endCallFunc(temp) - # Iterator on stack. - - temp_iterator_position = self.reserve_temp(1) - temp_iterator = [LoadTemp(temp_iterator_position)] - - self.new_op(StoreTemp(temp_iterator_position)) + temp_iterator = self._optimise_temp_storage() # In the loop... @@ -1305,7 +1151,7 @@ # Test for StopIteration. - self.dispatch(compiler.ast.Name("StopIteration")) + self.load_builtin("StopIteration", node) self.new_op(CheckException()) if node.else_ is not None: self.new_op(JumpIfTrue(else_label)) @@ -1432,9 +1278,38 @@ else: self._visitName(node, (LoadName, LoadAddress)) - def visitNot(self, node): raise TranslationNotImplementedError(self.module.full_name(), node, "Not") + def visitNot(self, node): + next_label = self.new_label() + true_label = self.new_label() + + self.dispatch(node.expr) + self.new_op(TestBoolean()) + self.new_op(JumpIfTrue(true_label)) + self.load_builtin("True", node) + self.new_op(Jump(next_label)) + + self.set_label(true_label) + self.load_builtin("False", node) + self.set_label(next_label) + + # Prevent incorrect optimisation. - def visitOr(self, node): raise TranslationNotImplementedError(self.module.full_name(), node, "Or") + self.active = None + + def visitOr(self, node): + next_label = self.new_label() + + for n in node.nodes[:-1]: + self.dispatch(n) + self.new_op(TestBoolean()) + self.new_op(JumpIfTrue(next_label)) + + self.dispatch(node.nodes[-1]) + self.set_label(next_label) + + # Prevent incorrect optimisation. + + self.active = None def visitPass(self, node): pass @@ -1470,7 +1345,6 @@ def visitStmt(self, node): for n in node.nodes: self.dispatch(n) - self.reset_stack() def visitSub(self, node): self._visitBinary(node, "__sub__", "__rsub__") @@ -1564,6 +1438,10 @@ self.set_label(exit_label) self.drop_loop_labels() + # Prevent incorrect optimisation. + + self.active = None + def visitWith(self, node): raise TranslationNotImplementedError(self.module.full_name(), node, "With") def visitYield(self, node): raise TranslationNotImplementedError(self.module.full_name(), node, "Yield") diff -r 00ce6c2f0440 -r 915efb968743 micropython/rsvp.py --- a/micropython/rsvp.py Tue Jul 15 21:16:17 2008 +0200 +++ b/micropython/rsvp.py Fri Jul 18 00:49:53 2008 +0200 @@ -41,68 +41,29 @@ "A generic instruction." - stack_storage = [] - stack_access = [] - def __init__(self, attr=None): self.attr = attr - self.accesses = [op(-1 - n) for n, op in enumerate(self.stack_access)] - self.results = [op(n) for n, op in enumerate(self.stack_storage)] def copy(self): return self.__class__(self.attr) - def remove_results(self): - - "Remove the stack side-effects for instructions replacing stack operations." - - self.results = [] - - def fix_stack(self, level): - - """ - Use the given 'level' to fix the details of this instruction's internal - stack operations. - """ + def __repr__(self): + if self.attr is not None: + return "%s(%r)" % (self.__class__.__name__, self.attr) + else: + return "%s()" % (self.__class__.__name__) - effect = 0 - for stack_op in self.accesses: - stack_op.fix_stack(level) - effect += stack_op.get_effect() - - level += effect - for stack_op in self.results: - stack_op.fix_stack(level) +class FrameRelativeInstruction(Instruction): - def get_effect(self): - effect = 0 - for stack_op in self.accesses + self.results: - effect += stack_op.get_effect() - return effect - - def show_stack_ops(self): - return "%s%s" % ( - self.accesses and (" <- %s" % self.accesses) or "", - self.results and (" -> %s" % self.results) or "" - ) + "An instruction operating on the current frame." def __repr__(self): - if self.attr is not None: - return "%s(%r)%s" % (self.__class__.__name__, self.attr, self.show_stack_ops()) - else: - return "%s()%s" % (self.__class__.__name__, self.show_stack_ops()) - -class StackRelativeInstruction(Instruction): - - "An instruction operating on the local value stack." - - def __repr__(self): - return "%s(%r)%s" % (self.__class__.__name__, self.get_operand(), self.show_stack_ops()) + return "%s(%r)" % (self.__class__.__name__, self.get_operand()) def get_operand(self): return self.attr.position -SR = StackRelativeInstruction +FR = FrameRelativeInstruction class AddressRelativeInstruction(Instruction): @@ -111,9 +72,9 @@ def __repr__(self): position = self.get_operand() if position is not None: - return "%s(%r)%s # %s" % (self.__class__.__name__, position, self.show_stack_ops(), name(self.attr)) + return "%s(%r) # %s" % (self.__class__.__name__, position, name(self.attr)) else: - return "%s(%r)%s" % (self.__class__.__name__, self.show_stack_ops(), name(self.attr)) + return "%s(%r)" % (self.__class__.__name__, name(self.attr)) def get_operand(self): return self.attr.position @@ -127,14 +88,14 @@ def __repr__(self): location, position, result = self.get_operands() if location is not None: - return "%s(%r)%s # %r, %r (%s)" % ( - self.__class__.__name__, result, self.show_stack_ops(), location, position, name(self.attr)) + return "%s(%r) # %r, %r (%s)" % ( + self.__class__.__name__, result, location, position, name(self.attr)) elif result is not None: - return "%s(%r)%s # %s" % ( - self.__class__.__name__, result, self.show_stack_ops(), name(self.attr)) + return "%s(%r) # %s" % ( + self.__class__.__name__, result, name(self.attr)) else: - return "%s(...)%s # %s" % ( - self.__class__.__name__, self.show_stack_ops(), name(self.attr)) + return "%s(...) # %s" % ( + self.__class__.__name__, name(self.attr)) def get_operands(self): if isinstance(self.attr, Attr): @@ -165,146 +126,71 @@ "An instruction employing a constant." def __repr__(self): - return "%s(%r)%s" % (self.__class__.__name__, self.attr, self.show_stack_ops()) + return "%s(%r)" % (self.__class__.__name__, self.attr) def get_operand(self): return self.attr Immediate = ImmediateInstruction -# Internal stack and frame operations for instructions. - -class StackOp: - - "A generic stack operation." - - def __init__(self, n): - self.n = n - self.level = None - - def fix_stack(self, level): - self.level = self.n + level - - def __repr__(self): - return "%s(%s)" % (self.__class__.__name__, self.level == 0 and "0" or self.level or self.n) - -class StackPull(StackOp): - - "Load a value from the stack." - - def get_effect(self): - return -1 - -class StackPush(StackOp): - - "Save a value onto the stack." - - def get_effect(self): - return 1 - -class StackLoad(StackOp): - - "Load a value from the stack." - - def get_effect(self): - return 0 - -# Mix-in classes for stack effects. - -class StackAdd: - - """ - Indicate that the stack must grow to accommodate the result of this - instruction. - """ - - stack_storage = [StackPush] - -class StackRemove: - - "Indicate that the stack must shrink as an effect of this instruction." - - stack_access = [StackPull] - -class StackRemove2: - - "Indicate that the stack must shrink as an effect of this instruction." - - stack_access = [StackPull, StackPull] - -class StackReplace(StackAdd, StackRemove): - - """ - Indicate that the stack remains at the same level due to the replacement of - the topmost element. - """ - - pass - -class StackInspect: - - "Indicate that the stack is inspected but unchanged by this instruction." - - stack_access = [StackLoad] - # Access to stored constant data. -class LoadConst(StackAdd, Address): "Load the constant, class, function, module from the specified location." +class LoadConst(Address): "Load the constant, class, function, module from the specified location." # Access within an invocation frame. -class LoadName(StackAdd, SR): "Load the object from the given local attribute/variable." -class StoreName(StackRemove, SR): "Store the object in the given local attribute/variable." -class LoadTemp(StackAdd, Immediate): "Load the object from the given temporary location." -class StoreTemp(StackRemove, Immediate): "Store the object in the given temporary location." +class LoadName(FR): "Load the object from the given local attribute/variable." +class StoreName(FR): "Store the object in the given local attribute/variable." +class LoadTemp(Immediate): "Load the object from the given temporary location." +class StoreTemp(Immediate): "Store the object in the given temporary location." # Access to static data. -class LoadAddress(StackAdd, Address): "Load the object from the given fixed attribute address." -class StoreAddress(StackRemove, Address): "Store an object in the given fixed attribute address." -class LoadAddressContext(StackReplace, Address):"Load the object from the given fixed attribute address, changing the context." -class StoreAddressContext(StackRemove2, Address):"Store an object in the given fixed attribute address, changing the context." -class MakeObject(StackAdd, Instruction): "Make a new object. There isn't a complementary DropObject." +class LoadAddress(Address): "Load the object from the given fixed attribute address." +class StoreAddress(Address): "Store an object in the given fixed attribute address." +class LoadAddressContext(Address): "Load the object from the given fixed attribute address, changing the context." +class StoreAddressContext(Address): "Store an object in the given fixed attribute address, changing the context." +class MakeObject(Instruction): "Make a new object. There isn't a complementary DropObject." # Access to address-relative data. -class LoadAttr(StackReplace, AR): "Load the object from the given attribute." -class StoreAttr(StackRemove2, AR): "Store an object in the given attribute." -class LoadAttrIndex(StackReplace, Immediate): "Load the object for the attribute with the given index." -class StoreAttrIndex(StackRemove2, Immediate): "Store an object in the attribute with the given index." +class LoadAttr(AR): "Load the object from the given attribute." +class StoreAttr(AR): "Store an object in the given attribute." +class LoadAttrIndex(Immediate): "Load the object for the attribute with the given index." +class StoreAttrIndex(Immediate): "Store an object in the attribute with the given index." # Access to invocation frames in preparation. -class MakeFrame(Instruction): "Make a new invocation frame." -class DropFrame(Instruction): "Drop an invocation frame." -class StoreFrame(StackRemove, Immediate): "Store an argument for the parameter with the given position." -class StoreFrameIndex(StackRemove, Immediate): "Store an argument for the parameter with the given index." -class LoadCallable(StackInspect, Instruction): "Load the target of an invocation." -class LoadContext(StackReplace, Instruction): "Load the context of an invocation." -class CheckFrame(Instruction): "Check the invocation frame and context for the target." -class CheckSelf(StackAdd, Instruction): "Check the first argument of an invocation against the target." +class MakeFrame(Instruction): "Make a new invocation frame." +class DropFrame(Instruction): "Drop an invocation frame." +class StoreFrame(Immediate): "Store an argument for the parameter with the given position." +class StoreFrameIndex(Immediate): "Store an argument for the parameter with the given index." +class LoadCallable(Instruction): "Load the target of an invocation." +class LoadContext(Instruction): "Load the context of an invocation." +class CheckFrame(Instruction): "Check the invocation frame and context for the target." +class CheckSelf(Instruction): "Check the first argument of an invocation against the target." # Invocation-related instructions, using a special result "register". -class JumpWithFrame(StackRemove, Instruction): "Jump, adopting the invocation frame, to the callable found on the stack." -class Return(StackRemove, Instruction): "Return a value from a subprogram." -class LoadResult(StackAdd, Instruction): "Load a returned value." +class JumpWithFrame(Instruction): "Jump, adopting the invocation frame, to the callable found as the current value." +class Return(Instruction): "Return a value from a subprogram." +class LoadResult(Instruction): "Load a returned value." # Branch-related instructions. -class Jump(Address): "Jump unconditionally." -class JumpIfFalse(StackRemove, Address): "Jump if the last evaluation gave a false result." -class JumpIfTrue(StackRemove, Address): "Jump if the last evaluation gave a true result." +class Jump(Address): "Jump unconditionally." +class JumpIfFalse(Address): "Jump if the last evaluation gave a false result." +class JumpIfTrue(Address): "Jump if the last evaluation gave a true result." # Exception-related instructions, using a special exception "register". -class LoadException(StackAdd, Instruction): "Load the raised exception." -class RaiseException(StackRemove, Instruction): "Raise an exception." -class CheckException(Instruction): "Check the raised exception against another." +class LoadException(Instruction): "Load the raised exception." +class RaiseException(Instruction): "Raise an exception." +class CheckException(Instruction): "Check the raised exception against another." # General instructions. -class TestIdentity(Instruction): "Test whether the two topmost stack values are identical." -class TestIdentityAddress(Address): "Test whether the topmost stack value is identical to the given address." +class TestBoolean(Instruction): "Test whether the current value is a true value." +class TestIdentityAddress(Address): "Test whether the current value is identical to the given address." # vim: tabstop=4 expandtab shiftwidth=4 diff -r 00ce6c2f0440 -r 915efb968743 tests/logical.py --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/tests/logical.py Fri Jul 18 00:49:53 2008 +0200 @@ -0,0 +1,9 @@ +#!/usr/bin/env python + +a = 1 +b = 0 +c = a and b +d = a or b +e = a and b or not a and not b + +# vim: tabstop=4 expandtab shiftwidth=4