# HG changeset patch # User Paul Boddie # Date 1217547842 -7200 # Node ID 76c0d6737c11a65a86df4c91b523f33df8a43f9f # Parent c849c63e54522bb66ebbb1b918c734bf88055148 Fixed CheckFrame production, employing the proper argument count. Added some support for lists. Tidied up binary operator support, adding the beginnings of comparison support. diff -r c849c63e5452 -r 76c0d6737c11 micropython/ast.py --- a/micropython/ast.py Tue Jul 29 00:20:23 2008 +0200 +++ b/micropython/ast.py Fri Aug 01 01:44:02 2008 +0200 @@ -702,7 +702,7 @@ first = 1 frame_pos = ncontext - max_keyword_pos = 0 + max_keyword_pos = -1 for arg in args: @@ -812,6 +812,9 @@ # NOTE: Extra keywords are not supported. # NOTE: Somehow, the above needs to be combined with * arguments. + if extra_keywords: + print "Warning: extra keyword argument(s) %s not handled." % ", ".join([arg.name for arg in extra_keywords]) + # Either test for a complete set of arguments. if target is not None: @@ -843,7 +846,12 @@ # NOTE: the context in use. else: - self.new_op(CheckFrame(max(max(employed_positions), max_keyword_pos))) + + # Only check non-empty frames. + + if employed_positions or max_keyword_pos >= 0: + max_pos = max(max(employed_positions), max_keyword_pos, frame_pos - 1) + self.new_op(CheckFrame(max_pos + 1)) def _generateCallFuncDefaultArgs(self, target, temp, nargs_min, nargs_max, employed_positions): @@ -908,7 +916,7 @@ dynamic = function.name is None if dynamic: - self.new_op(MakeObject(len(attr_to_default))) + self.new_op(MakeObject(("function", len(attr_to_default)))) temp = self.get_temp() for attr, default in attr_to_default: @@ -1050,12 +1058,6 @@ raise TypeError """ - end_left_label = self.new_label() - right_label = self.new_label() - end_right_label = self.new_label() - type_error_label = self.new_label() - end_label = self.new_label() - # Evaluate and store the left operand in temporary storage. self.dispatch(node.left) @@ -1066,14 +1068,47 @@ self.dispatch(node.right) temp2 = self._optimise_temp_storage() + self._generateBinary(temp1, temp2, left_method, right_method) + + # Compilation duties... + + self.discard_temp(temp1) + self.discard_temp(temp2) + + def _generateBinary(self, temp1, temp2, left_method, right_method): + + right_label = self.new_label() + type_error_label = self.new_label() + end_label = self.new_label() + # Left method. + self._generateOpMethod(temp1, temp2, left_method, right_label, end_label) + + # Right method. + + self.set_label(right_label) + self._generateOpMethod(temp2, temp1, right_method, type_error_label, end_label) + + # Raise a TypeError. + + self.set_label(type_error_label) + self.load_builtin("TypeError", node) + self.new_op(StoreException()) + self.new_op(RaiseException()) + + self.set_label(end_label) + + def _generateOpMethod(self, temp1, temp2, method_name, next_method_label, end_label): + + end_attempt_label = self.new_label() + self._startCallFunc() self.new_op(temp1) - # Get left method on temp1. + # Get method on temp1. - self._generateAttr(node, left_method, self.attribute_load_instructions) + 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. @@ -1081,7 +1116,7 @@ if not self._optimise_known_target(): self.load_builtin("AttributeError", node) self.new_op(CheckException()) - self.new_op(JumpIfTrue(end_left_label)) + self.new_op(JumpIfTrue(end_attempt_label)) temp_method = self._optimise_temp_storage() @@ -1097,67 +1132,28 @@ # Don't actually raise an exception. self.new_op(TestIdentityAddress(self.get_builtin("NotImplemented", node))) - self.new_op(JumpIfTrue(right_label)) + self.new_op(JumpIfTrue(next_method_label)) self.new_op(Jump(end_label)) - # End left method attempt. + # End method attempt. - self.set_label(end_left_label) + self.set_label(end_attempt_label) self._endCallFunc() # From the left method call. - # Right method. - - self.set_label(right_label) - self._startCallFunc() - self.new_op(temp2) - - # Get right method on temp2. - - self._generateAttr(node, right_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_right_label)) - - temp_method = self._optimise_temp_storage() - - # Add arguments. - # NOTE: No support for defaults. + def _visitSequence(self, sequence_type, node): + self.new_op(MakeObject((sequence_type, len(node.nodes)))) + temp = self.get_temp() - self.new_op(temp2) # Explicit context as first argument. - self.new_op(temp1) - self._doCallFunc(temp_method) - self._endCallFunc(temp_method) - - # Test for NotImplemented. - # Don't actually raise an exception. - - self.new_op(TestIdentityAddress(self.get_builtin("NotImplemented", node))) - self.new_op(JumpIfTrue(type_error_label)) - self.new_op(Jump(end_label)) - - # End right method attempt. + for i, n in enumerate(node.nodes): + self.dispatch(n) + self.record_value() + self.new_op(temp) + self.new_op(StoreAttr(Attr(i, None, None, None))) + self.set_source() + self.discard_value() - self.set_label(end_right_label) - self._endCallFunc() # From the right method call. - - # Raise a TypeError. - - self.set_label(type_error_label) - self.load_builtin("TypeError", node) - self.new_op(StoreException()) - self.new_op(RaiseException()) - - self.set_label(end_label) - - # Compilation duties... - - self.discard_temp(temp1) - self.discard_temp(temp2) + self.new_op(temp) + self.discard_temp(temp) # Concrete visitor methods. @@ -1255,15 +1251,45 @@ 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._optimise_temp_storage() + for op_name, next_node in compare.ops: - methods = self.comparison_methods[op_name] + left_method, right_method = self.comparison_methods[op_name] + + temp1 = temp2 + self.dispatch(next_node) + temp2 = self._optimise_temp_storage() + if methods is not None: + # Generate method call using evaluated argument and next node. + + self._generateBinary(temp1, temp2, left_method, right_method) + + # Test the result and jump to the end label if false. + + self.new_op(LoadResult()) + self.new_op(TestBoolean()) + self.new_op(JumpIfFalse(end_label)) + else: - # Deal with the special operators. - # Provide short-circuiting. - """ + # NOTE: Deal with the special operators. + + pass + + # Compilation duties... + + self.discard_temp(temp1) + + self.discard_temp(temp2) + self.set_label(end_label) def visitConst(self, node): const = self.module.constant_values[node.value] @@ -1431,6 +1457,18 @@ 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. @@ -1460,7 +1498,8 @@ def visitLeftShift(self, node): self._visitBinary(node, "__lshift__", "__rlshift__") - def visitList(self, node): raise TranslationNotImplementedError(self.module.full_name(), node, "List") + def visitList(self, node): + self._visitSequence("list", node) def visitListComp(self, node): raise TranslationNotImplementedError(self.module.full_name(), node, "ListComp") @@ -1628,19 +1667,7 @@ def visitTryFinally(self, node): raise TranslationNotImplementedError(self.module.full_name(), node, "TryFinally") def visitTuple(self, node): - self.new_op(MakeObject(len(node.nodes))) - temp = self.get_temp() - - for i, n in enumerate(node.nodes): - self.dispatch(n) - self.record_value() - self.new_op(temp) - self.new_op(StoreAttr(Attr(i, None, None, None))) - self.set_source() - self.discard_value() - - self.new_op(temp) - self.discard_temp(temp) + self._visitSequence("tuple", node) def visitUnaryAdd(self, node): self._visitUnary(node, "__pos__") diff -r c849c63e5452 -r 76c0d6737c11 tests/list.py --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/tests/list.py Fri Aug 01 01:44:02 2008 +0200 @@ -0,0 +1,7 @@ +#!/usr/bin/env python + +[1, 2, 3] +a = [1, 2, 3] +[1, [2, 3], 4, 5] + +# vim: tabstop=4 expandtab shiftwidth=4