# HG changeset patch # User Paul Boddie # Date 1222639204 -7200 # Node ID 588a63ef527511acaec8ab20f182331636ac81b1 # Parent bde27c59cb8498be571bf9aa9cec97ef2d8d0039 Re-ordered the methods according to corresponding node type. Fixed binary operator results in comparisons. Added some optimiser reset operations in various control-flow statements. diff -r bde27c59cb84 -r 588a63ef5275 micropython/ast.py --- a/micropython/ast.py Sun Sep 28 23:14:54 2008 +0200 +++ b/micropython/ast.py Mon Sep 29 00:00:04 2008 +0200 @@ -1251,9 +1251,57 @@ # Concrete visitor methods. + # Binary operators. + def visitAdd(self, node): self._visitBinary(node, "__add__", "__radd__") + def visitBitand(self, node): + self._visitBinary(node, "__and__", "__rand__") + + def visitBitor(self, node): + self._visitBinary(node, "__or__", "__ror__") + + def visitBitxor(self, node): + self._visitBinary(node, "__xor__", "__rxor__") + + def visitDiv(self, node): + self._visitBinary(node, "__div__", "__rdiv__") + + def visitFloorDiv(self, node): + self._visitBinary(node, "__floordiv__", "__rfloordiv__") + + def visitLeftShift(self, node): + self._visitBinary(node, "__lshift__", "__rlshift__") + + def visitMod(self, node): + self._visitBinary(node, "__mod__", "__rmod__") + + def visitMul(self, node): + self._visitBinary(node, "__mul__", "__rmul__") + + def visitPower(self, node): + self._visitBinary(node, "__pow__", "__rpow__") + + def visitRightShift(self, node): + self._visitBinary(node, "__rshift__", "__rrshift__") + + def visitSub(self, node): + self._visitBinary(node, "__sub__", "__rsub__") + + # Unary operators. + + def visitInvert(self, node): + self._visitUnary(node, "__invert__") + + def visitUnaryAdd(self, node): + self._visitUnary(node, "__pos__") + + def visitUnarySub(self, node): + self._visitUnary(node, "__neg__") + + # Logical operators. + def visitAnd(self, node): end_label = self.new_label() temp_pos = self.reserve_temp() @@ -1278,7 +1326,201 @@ self.new_op(temp) self.discard_temp(temp) - def visitAssert(self, node): raise TranslationNotImplementedError(self.module.full_name(), node, "Assert") + def visitNot(self, node): + self.dispatch(node.expr) + + temp = self.optimiser.optimise_temp_storage() + self._generateTestBoolean(node.expr, temp) + self.discard_temp(temp) + + self.new_op(InvertBoolean()) + self._generateLoadBoolean(node) + + # Prevent incorrect optimisation. + + self.optimiser.reset() + + def visitOr(self, node): + end_label = self.new_label() + temp_pos = self.reserve_temp() + temp = LoadTemp(temp_pos) + + for n in node.nodes[:-1]: + self.dispatch(n) + self.new_op(StoreTemp(temp_pos)) + + self._generateTestBoolean(n, temp) + self.new_op(JumpIfTrue(end_label)) + + self.dispatch(node.nodes[-1]) + self.new_op(StoreTemp(temp_pos)) + + self.set_label(end_label) + + # Prevent incorrect optimisation. + + self.optimiser.reset() + + self.new_op(temp) + self.discard_temp(temp) + + # Comparisons. + + def visitCompare(self, node): + + """ + _t1 = node.expr + _t1 op1 _t2 and _t2 op2 _t3 and ... + """ + + end_label = self.new_label() + + self.dispatch(node.expr) + temp2 = self.optimiser.optimise_temp_storage() + + last_op = node.ops[-1] + + for op in node.ops: + op_name, next_node = op + methods = self.comparison_methods[op_name] + + temp1 = temp2 + self.dispatch(next_node) + temp2 = self.optimiser.optimise_temp_storage() + + # Use the appropriate mechanism, setting the boolean status for the + # comparison. + + if methods is not None: + left_method, right_method = methods + + # Generate method call using evaluated argument and next node. + + temp_result = self._generateBinary(node, temp1, temp2, left_method, right_method) + self.new_op(temp_result) + self._generateTestBoolean(node, temp_result) + self.discard_temp(temp_result) + + else: + # 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.optimiser.optimise_temp_storage() + + # 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._endCallFuncArgs(2) + self._doCallFunc(temp_method) + self._endCallFunc(temp_method) + + temp_result = self.get_temp() + self._generateTestBoolean(node, temp_result) + self.discard_temp(temp_result) + + if op_name.find("not") != -1: + self.new_op(InvertBoolean()) + + # Test the result and jump to the end label if false. + + if op is not last_op: + self.new_op(JumpIfFalse(end_label)) + + # Compilation duties... + + self.discard_temp(temp1) + + self.discard_temp(temp2) + self.set_label(end_label) + + # Yield the appropriate value. + + self._generateLoadBoolean(node) + + # Expressions. + + def visitBackquote(self, node): raise TranslationNotImplementedError(self.module.full_name(), node, "Backquote") + + def visitCallFunc(self, node): + + """ + Evaluate positional arguments, evaluate and store keyword arguments in + the correct location, then invoke the function. + """ + + # Mark the frame, evaluate the target, generate the call. + + self._startCallFunc() + self.dispatch(node.node) + temp, target = self._generateCallFunc(node.args, node) + self._doCallFunc(temp, target) + self._endCallFunc(temp, target) + + def visitConst(self, node): + const = self.module.constant_values[node.value] + self.new_op(LoadConst(const)) + + def visitDict(self, node): raise TranslationNotImplementedError(self.module.full_name(), node, "Dict") + + def visitEllipsis(self, node): raise TranslationNotImplementedError(self.module.full_name(), node, "Ellipsis") + + def visitExec(self, node): raise TranslationNotImplementedError(self.module.full_name(), node, "Exec") + + def visitExpression(self, node): raise TranslationNotImplementedError(self.module.full_name(), node, "Expression") + + def visitGenExpr(self, node): raise TranslationNotImplementedError(self.module.full_name(), node, "GenExpr") + + def visitGenExprFor(self, node): raise TranslationNotImplementedError(self.module.full_name(), node, "GenExprFor") + + def visitGenExprIf(self, node): raise TranslationNotImplementedError(self.module.full_name(), node, "GenExprIf") + + def visitGenExprInner(self, node): raise TranslationNotImplementedError(self.module.full_name(), node, "GenExprInner") + + def visitGetattr(self, node): + self._visitAttr(node, self.attribute_load_instructions) + + def visitList(self, node): + self._generateSequence("list", node) + + def visitListComp(self, node): raise TranslationNotImplementedError(self.module.full_name(), node, "ListComp") + + def visitListCompFor(self, node): raise TranslationNotImplementedError(self.module.full_name(), node, "ListCompFor") + + def visitListCompIf(self, node): raise TranslationNotImplementedError(self.module.full_name(), node, "ListCompIf") + + def visitName(self, node): + if node.name == "None": + const = self.module.constant_values[None] + self.new_op(LoadConst(const)) + else: + self._visitName(node, self.name_load_instructions) + + def visitSlice(self, node): raise TranslationNotImplementedError(self.module.full_name(), node, "Slice") + + def visitSubscript(self, node): raise TranslationNotImplementedError(self.module.full_name(), node, "Subscript") + + def visitTuple(self, node): + self._generateSequence("tuple", node) + + # Definitions. def visitAssign(self, node): @@ -1383,36 +1625,6 @@ self.discard_temp(temp1) self.discard_temp(temp2) - def visitBackquote(self, node): raise TranslationNotImplementedError(self.module.full_name(), node, "Backquote") - - def visitBitand(self, node): - self._visitBinary(node, "__and__", "__rand__") - - def visitBitor(self, node): - self._visitBinary(node, "__or__", "__ror__") - - def visitBitxor(self, node): - self._visitBinary(node, "__xor__", "__rxor__") - - def visitBreak(self, node): - next_label, exit_label = self.get_loop_labels() - self.new_op(Jump(exit_label)) - - def visitCallFunc(self, node): - - """ - Evaluate positional arguments, evaluate and store keyword arguments in - the correct location, then invoke the function. - """ - - # Mark the frame, evaluate the target, generate the call. - - self._startCallFunc() - self.dispatch(node.node) - temp, target = self._generateCallFunc(node.args, node) - self._doCallFunc(temp, target) - self._endCallFunc(temp, target) - def visitClass(self, node): # Store the name. @@ -1431,122 +1643,126 @@ self.dispatch(node.code) self.unit = unit - def visitCompare(self, node): + def visitDecorators(self, node): raise TranslationNotImplementedError(self.module.full_name(), node, "Decorators") + + def visitFrom(self, node): pass + + def visitFunction(self, node): + + # Only store the name when visiting this node from outside. + + if self.unit is not node.unit: + self.new_op(LoadConst(node.unit)) + + self.record_value() + self._visitName(node, self.name_store_instructions) # AssName equivalent + self.set_source() + self.discard_value() + + self._generateFunctionDefaults(node.unit) + + # Visiting of the code occurs when get_code is invoked on this node. + + else: + extend = ExtendFrame() + self.new_op(extend) + + self.dispatch(node.code) + if not isinstance(self.last_op(), Return): + self.dispatch(compiler.ast.Name("None")) + self.new_op(StoreResult()) + + self.new_op(Return()) + + self.set_frame_usage(node, extend) + + def visitGlobal(self, node): pass + + def visitImport(self, node): pass + + def visitKeyword(self, node): pass + + def visitLambda(self, node): """ - _t1 = node.expr - _t1 op1 _t2 and _t2 op2 _t3 and ... + Lambda functions can be represented as globally defined functions + provided they do not define any default parameter values, since these + may defined in a non-global scope. + + Where defaults are defined, an object must be created and its content + defined: the callable member of the object's structure must be set to + the lambda function definition; each default must be attached to the + object as an attribute, as is the case with normal functions and + methods. """ - end_label = self.new_label() - - self.dispatch(node.expr) - temp2 = self.optimiser.optimise_temp_storage() - - last_op = node.ops[-1] - - for op in node.ops: - op_name, next_node = op - methods = self.comparison_methods[op_name] - - temp1 = temp2 - self.dispatch(next_node) - temp2 = self.optimiser.optimise_temp_storage() - - # Use the appropriate mechanism, setting the boolean status for the - # comparison. - - if methods is not None: - left_method, right_method = methods - - # Generate method call using evaluated argument and next node. - - temp_result = self._generateBinary(node, temp1, temp2, left_method, right_method) - self._generateTestBoolean(node, temp_result) - self.discard_temp(temp_result) - - else: - # 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.optimiser.optimise_temp_storage() - - # 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._endCallFuncArgs(2) - self._doCallFunc(temp_method) - self._endCallFunc(temp_method) - - temp_result = self.get_temp() - self._generateTestBoolean(node, temp_result) - self.discard_temp(temp_result) - - if op_name.find("not") != -1: - self.new_op(InvertBoolean()) - - # Test the result and jump to the end label if false. - - if op is not last_op: - self.new_op(JumpIfFalse(end_label)) - - # Compilation duties... - - self.discard_temp(temp1) - - self.discard_temp(temp2) - self.set_label(end_label) - - # Yield the appropriate value. - - self._generateLoadBoolean(node) - - def visitConst(self, node): - const = self.module.constant_values[node.value] - self.new_op(LoadConst(const)) + # Produce the reference to this function when visiting this node from + # outside. + + if self.unit is not node.unit: + temp = self._generateFunctionDefaults(node.unit) + self.new_op(LoadConst(node.unit)) + + # Populate the new object required for the function. + + if temp is not None: + self.new_op(LoadCallable()) + self.new_op(temp) + self.new_op(StoreCallable()) + + self.new_op(temp) + #self.discard_temp(temp) + + # Visiting of the code occurs when get_code is invoked on this node. + + else: + self.dispatch(node.code) + self.new_op(StoreResult()) + self.new_op(Return()) + + def visitModule(self, node): + extend = ExtendFrame() + self.new_op(extend) + self.dispatch(node.node) + self.set_frame_usage(node, extend) + + # Statements. + + def visitStmt(self, node): + + "Process the collection of statements provided by 'node'." + + for n in node.nodes: + + # Process the statement. + + self.dispatch(n) + + # Discard temporary storage. + + if self.temp_positions: + #print "Had temp", self.temp_positions + self.temp_positions = set() + + # Prevent incorrect optimisation by resetting the optimiser after + # each statement. + + self.optimiser.reset() + + 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)) def visitContinue(self, node): next_label, exit_label = self.get_loop_labels() self.new_op(Jump(next_label)) - def visitDecorators(self, node): raise TranslationNotImplementedError(self.module.full_name(), node, "Decorators") - - def visitDict(self, node): raise TranslationNotImplementedError(self.module.full_name(), node, "Dict") - def visitDiscard(self, node): self.dispatch(node.expr) self.optimiser.optimise_unused_results() - def visitDiv(self, node): - self._visitBinary(node, "__div__", "__rdiv__") - - def visitEllipsis(self, node): raise TranslationNotImplementedError(self.module.full_name(), node, "Ellipsis") - - def visitExec(self, node): raise TranslationNotImplementedError(self.module.full_name(), node, "Exec") - - def visitExpression(self, node): raise TranslationNotImplementedError(self.module.full_name(), node, "Expression") - - def visitFloorDiv(self, node): - self._visitBinary(node, "__floordiv__", "__rfloordiv__") - def visitFor(self, node): next_handler_label = self.new_label() end_handler_label = self.new_label() @@ -1631,6 +1847,11 @@ if node.else_ is not None: self.set_label(exit_label) + + # Prevent incorrect optimisation. + + self.optimiser.reset() + self.dispatch(node.else_) # After the loop... @@ -1641,50 +1862,6 @@ self.discard_temp(temp_iterator) - def visitFrom(self, node): pass - - def visitFunction(self, node): - - # Only store the name when visiting this node from outside. - - if self.unit is not node.unit: - self.new_op(LoadConst(node.unit)) - - self.record_value() - self._visitName(node, self.name_store_instructions) # AssName equivalent - self.set_source() - self.discard_value() - - self._generateFunctionDefaults(node.unit) - - # Visiting of the code occurs when get_code is invoked on this node. - - else: - extend = ExtendFrame() - self.new_op(extend) - - self.dispatch(node.code) - if not isinstance(self.last_op(), Return): - self.dispatch(compiler.ast.Name("None")) - self.new_op(StoreResult()) - - self.new_op(Return()) - - self.set_frame_usage(node, extend) - - def visitGenExpr(self, node): raise TranslationNotImplementedError(self.module.full_name(), node, "GenExpr") - - def visitGenExprFor(self, node): raise TranslationNotImplementedError(self.module.full_name(), node, "GenExprFor") - - def visitGenExprIf(self, node): raise TranslationNotImplementedError(self.module.full_name(), node, "GenExprIf") - - def visitGenExprInner(self, node): raise TranslationNotImplementedError(self.module.full_name(), node, "GenExprInner") - - def visitGetattr(self, node): - self._visitAttr(node, self.attribute_load_instructions) - - def visitGlobal(self, node): pass - def visitIf(self, node): first = 1 exit_label = self.new_label() @@ -1705,129 +1882,17 @@ self.dispatch(body) if clause is not last_clause: self.new_op(Jump(exit_label)) + + # Prevent incorrect optimisation. + + self.optimiser.reset() + first = 0 self.set_label(exit_label) - def visitImport(self, node): pass - - def visitInvert(self, node): - self._visitUnary(node, "__invert__") - - def visitKeyword(self, node): pass - - def visitLambda(self, node): - - """ - Lambda functions can be represented as globally defined functions - provided they do not define any default parameter values, since these - may defined in a non-global scope. - - Where defaults are defined, an object must be created and its content - defined: the callable member of the object's structure must be set to - the lambda function definition; each default must be attached to the - object as an attribute, as is the case with normal functions and - methods. - """ - - # Produce the reference to this function when visiting this node from - # outside. - - if self.unit is not node.unit: - temp = self._generateFunctionDefaults(node.unit) - self.new_op(LoadConst(node.unit)) - - # Populate the new object required for the function. - - if temp is not None: - self.new_op(LoadCallable()) - self.new_op(temp) - self.new_op(StoreCallable()) - - self.new_op(temp) - #self.discard_temp(temp) - - # Visiting of the code occurs when get_code is invoked on this node. - - else: - self.dispatch(node.code) - self.new_op(StoreResult()) - self.new_op(Return()) - - def visitLeftShift(self, node): - self._visitBinary(node, "__lshift__", "__rlshift__") - - def visitList(self, node): - self._generateSequence("list", node) - - def visitListComp(self, node): raise TranslationNotImplementedError(self.module.full_name(), node, "ListComp") - - def visitListCompFor(self, node): raise TranslationNotImplementedError(self.module.full_name(), node, "ListCompFor") - - def visitListCompIf(self, node): raise TranslationNotImplementedError(self.module.full_name(), node, "ListCompIf") - - def visitMod(self, node): - self._visitBinary(node, "__mod__", "__rmod__") - - def visitModule(self, node): - extend = ExtendFrame() - self.new_op(extend) - self.dispatch(node.node) - self.set_frame_usage(node, extend) - - def visitMul(self, node): - self._visitBinary(node, "__mul__", "__rmul__") - - def visitName(self, node): - if node.name == "None": - const = self.module.constant_values[None] - self.new_op(LoadConst(const)) - else: - self._visitName(node, self.name_load_instructions) - - def visitNot(self, node): - self.dispatch(node.expr) - - temp = self.optimiser.optimise_temp_storage() - self._generateTestBoolean(node.expr, temp) - self.discard_temp(temp) - - self.new_op(InvertBoolean()) - self._generateLoadBoolean(node) - - # Prevent incorrect optimisation. - - self.optimiser.reset() - - def visitOr(self, node): - end_label = self.new_label() - temp_pos = self.reserve_temp() - temp = LoadTemp(temp_pos) - - for n in node.nodes[:-1]: - self.dispatch(n) - self.new_op(StoreTemp(temp_pos)) - - self._generateTestBoolean(n, temp) - self.new_op(JumpIfTrue(end_label)) - - self.dispatch(node.nodes[-1]) - self.new_op(StoreTemp(temp_pos)) - - self.set_label(end_label) - - # Prevent incorrect optimisation. - - self.optimiser.reset() - - self.new_op(temp) - self.discard_temp(temp) - def visitPass(self, node): pass - def visitPower(self, node): - self._visitBinary(node, "__pow__", "__rpow__") - def visitPrint(self, node): raise TranslationNotImplementedError(self.module.full_name(), node, "Print") def visitPrintnl(self, node): raise TranslationNotImplementedError(self.module.full_name(), node, "Printnl") @@ -1863,40 +1928,9 @@ self.new_op(StoreResult()) self.new_op(Return()) - def visitRightShift(self, node): - self._visitBinary(node, "__rshift__", "__rrshift__") - - def visitSlice(self, node): raise TranslationNotImplementedError(self.module.full_name(), node, "Slice") - - def visitStmt(self, node): - - "Process the collection of statements provided by 'node'." - - for n in node.nodes: - - # Process the statement. - - self.dispatch(n) - - # Discard temporary storage. - - if self.temp_positions: - #print "Had temp", self.temp_positions - self.temp_positions = set() - - # Prevent incorrect optimisation by resetting the optimiser after - # each statement. - - self.optimiser.reset() - - def visitSub(self, node): - self._visitBinary(node, "__sub__", "__rsub__") - - def visitSubscript(self, node): raise TranslationNotImplementedError(self.module.full_name(), node, "Subscript") - def visitTryExcept(self, node): exit_label = self.new_label() - success_label = self.new_label() + else_label = self.new_label() handler_label = self.new_label() self.add_exception_labels(handler_label, exit_label) @@ -1907,11 +1941,20 @@ self.new_op(PushHandler(handler_label)) self.dispatch(node.body) self.new_op(PopHandler()) - self.new_op(Jump(exit_label)) + + if node.else_ is not None: + self.new_op(Jump(else_label)) + else: + self.new_op(Jump(exit_label)) # Start of handlers. self.set_label(handler_label) + + # Prevent incorrect optimisation. + + self.optimiser.reset() + self.new_op(PopHandler()) for name, assignment, handler in node.handlers: @@ -1943,6 +1986,10 @@ self.set_label(next_label) + # Prevent incorrect optimisation. + + self.optimiser.reset() + # Unhandled exceptions. self.new_op(RaiseException()) @@ -1950,6 +1997,12 @@ # Optional else clause. if node.else_ is not None: + self.set_label(else_label) + + # Prevent incorrect optimisation. + + self.optimiser.reset() + self.dispatch(node.else_) self.set_label(exit_label) @@ -1957,15 +2010,6 @@ def visitTryFinally(self, node): raise TranslationNotImplementedError(self.module.full_name(), node, "TryFinally") - def visitTuple(self, node): - self._generateSequence("tuple", node) - - def visitUnaryAdd(self, node): - self._visitUnary(node, "__pos__") - - def visitUnarySub(self, node): - self._visitUnary(node, "__neg__") - def visitWhile(self, node): exit_label = self.new_label() next_label = self.new_label() @@ -1985,9 +2029,19 @@ if node.else_ is not None: self.set_label(else_label) + + # Prevent incorrect optimisation. + + self.optimiser.reset() + self.dispatch(node.else_) self.set_label(exit_label) + + # Prevent incorrect optimisation. + + self.optimiser.reset() + self.drop_loop_labels() def visitWith(self, node): raise TranslationNotImplementedError(self.module.full_name(), node, "With")