# HG changeset patch # User Paul Boddie # Date 1243883447 -7200 # Node ID 77038806cb4024f974353e8c3ecacf7c268843c2 # Parent 8abc113da24ca0e7fb646a1942edda4620609758 Moved context verification back into the invocation code, as opposed to residing in the function body code. This is required because keyword arguments need to operate on adjusted frames, and such adjustments must therefore occur because keyword arguments are stored in their invocation frames. Renamed CheckClassContext to the more general CheckClass instruction. Made AdjustFrame operate on invocation frames again. Introduced explicit tests for class invocation since instantiators require an extra slot for each new instance. Fixed the "if" statement to employ conversion of expression results to boolean values. Split and improved test programs. diff -r 8abc113da24c -r 77038806cb40 docs/invocation.txt --- a/docs/invocation.txt Mon Jun 01 02:41:57 2009 +0200 +++ b/docs/invocation.txt Mon Jun 01 21:10:47 2009 +0200 @@ -71,7 +71,7 @@ f(obj, 1, 2) # f known as function at compile-time - f -> don't get any context information + f -> f (context is null) obj -> argument #1 1 -> argument #2 2 -> argument #3 @@ -80,8 +80,8 @@ f(obj, 1, 2) # f known as C.m at compile-time (context is C) - f -> C.m - don't get any context information - obj -> argument #1 + f -> C.m (context is class C) + obj -> argument #1 (must be tested against the context) 1 -> argument #2 2 -> argument #3 @@ -99,13 +99,13 @@ f(obj, 1, 2) # f known as C at compile-time - f -> C.__init__ - -> new instance is argument #1 + f -> instantiator of C + -> (argument #1 reserved for a new instance made by the instantiator) obj -> argument #2 1 -> argument #3 2 -> argument #4 - The new instance must be manually provided as the result after the call. + The new instance must be provided as the result of the call. Argument lists for unknown callables: @@ -119,7 +119,9 @@ Then, check the context and shift the frame if necessary: - is module or class: + f is class: no change + + is class: (, obj, 1, 2) -> (obj, 1, 2) is instance: no change @@ -143,8 +145,6 @@ 2 -> argument #4 Then jump without switching frames. - It should be possible to replace the old, tentative context information in the - frame. Defaults for unknown callables: diff -r 8abc113da24c -r 77038806cb40 micropython/ast.py --- a/micropython/ast.py Mon Jun 01 02:41:57 2009 +0200 +++ b/micropython/ast.py Mon Jun 01 21:10:47 2009 +0200 @@ -384,9 +384,9 @@ self._startCallFunc() self.dispatch(node.node) - temp, target = self._generateCallFunc(node.args, node) - self._doCallFunc(temp, target) - self._endCallFunc(temp, target) + temp_target, target, temp_context = self._generateCallFunc(node.args, node) + self._doCallFunc(temp_target, target) + self._endCallFunc(temp_target, target, temp_context) def visitConst(self, node): const = self.importer.get_constant(node.value) @@ -433,9 +433,9 @@ self.dispatch(node.expr) self._startCallFunc() self._generateAttr(node, "__getitem__", self.attribute_load_instructions) - temp, target = self._generateCallFunc(node.subs, node) - self._doCallFunc(temp, target) - self._endCallFunc(temp, target) + temp_target, target, temp_context = self._generateCallFunc(node.subs, node) + self._doCallFunc(temp_target, target) + self._endCallFunc(temp_target, target, temp_context) def visitTuple(self, node): self._generateSequence("tuple", node) @@ -478,9 +478,9 @@ self._startCallFunc() self.new_op(self.expr_temp[-1]) self._generateAttr(node, "__getitem__", self.attribute_load_instructions) - temp, target = self._generateCallFunc([compiler.ast.Const(i)], node) - self._doCallFunc(temp, target) - self._endCallFunc(temp, target) + temp_target, target, temp_context = self._generateCallFunc([compiler.ast.Const(i)], node) + self._doCallFunc(temp_target, target) + self._endCallFunc(temp_target, target, temp_context) # Provide a different source value. # NOTE: Permitting immediate usage given that neither name nor @@ -594,14 +594,9 @@ ndefaults = len(fn.defaults) fn.body_block = self.new_block() - check_block = self.new_block() - - self._generateFunctionContextTest(node, check_block) # Check the number of parameters and defaults. - self.set_block(check_block) - self.new_op(CheckFrame((nparams, ndefaults, fn.has_star))) if ndefaults > 0: self.new_op(LoadFunction(fn)) @@ -649,8 +644,14 @@ # outside. if self.unit is not node.unit: - temp = self._generateFunctionDefaults(node.unit) - self.new_op(LoadFunction(node.unit)) + fn = node.unit + ndefaults = len(fn.defaults) + temp = self._generateFunctionDefaults(fn) + + if ndefaults > 0: + self.new_op(LoadConst(fn)) + else: + self.new_op(LoadFunction(fn)) # Populate the new object required for the function. @@ -672,14 +673,9 @@ ndefaults = len(fn.defaults) fn.body_block = self.new_block() - check_block = self.new_block() - - self._generateFunctionContextTest(node, check_block) # Check the number of parameters and defaults. - self.set_block(check_block) - self.new_op(CheckFrame((nparams, ndefaults, fn.has_star))) if ndefaults > 0: self.new_op(LoadTemp(0)) # context provides storage @@ -756,9 +752,9 @@ self._startCallFunc() self.dispatch(node.list) self._generateAttr(node, "__iter__", self.attribute_load_instructions) - temp, target = self._generateCallFunc([], node) - self._doCallFunc(temp, target) - self._endCallFunc(temp, target) + temp_target, target, temp_context = self._generateCallFunc([], node) + self._doCallFunc(temp_target, target) + self._endCallFunc(temp_target, target, temp_context) temp_iterator = self.optimiser.optimise_temp_storage() @@ -775,9 +771,9 @@ self._startCallFunc() self.new_op(temp_iterator) self._generateAttr(node, "next", self.attribute_load_instructions) - temp, target = self._generateCallFunc([], node) - self._doCallFunc(temp, target) - self._endCallFunc(temp, target) + temp_target, target, temp_context = self._generateCallFunc([], node) + self._doCallFunc(temp_target, target) + self._endCallFunc(temp_target, target, temp_context) # Record the value to be assigned. @@ -860,6 +856,10 @@ if test is not None: self.dispatch(test) + + temp = self.optimiser.optimise_temp_storage() + self._generateTestBoolean(node, temp) + next_block = self.new_block() self.new_op(JumpIfFalse(next_block)) diff -r 8abc113da24c -r 77038806cb40 micropython/opt.py --- a/micropython/opt.py Mon Jun 01 02:41:57 2009 +0200 +++ b/micropython/opt.py Mon Jun 01 21:10:47 2009 +0200 @@ -195,7 +195,7 @@ TestIdentity, TestIdentityAddress, CheckSelf, # as one of the operands CheckException, CheckFrame, FillDefaults, MakeInstance, - CheckContext, CheckClassContext, + CheckContext, CheckClass, LoadContext # as the object providing the result )) diff -r 8abc113da24c -r 77038806cb40 micropython/rsvp.py --- a/micropython/rsvp.py Mon Jun 01 02:41:57 2009 +0200 +++ b/micropython/rsvp.py Mon Jun 01 21:10:47 2009 +0200 @@ -175,13 +175,12 @@ context if the attribute is compatible.""" class MakeInstance(Immediate): "Make a new instance." -# Access to address-relative data. +# Access to address-relative data. (LoadAttrIndexContext not defined.) class LoadAttr(AR): "Load into the current value the given attribute of the object referenced by the current value." class StoreAttr(AR): "Store the source value into the given attribute of the object referenced by the current value." class LoadAttrIndex(Immediate): "Load into the current value the attribute of the current value with the given index." class StoreAttrIndex(Immediate): "Store the source value into the attribute of the current value with the given index." -##### LoadAttrIndexContext not defined. class LoadAttrIndexContextCond(Immediate): """Load into the current value the attribute of the current value with the given index, only making the current value the context if the attribute is compatible.""" @@ -194,27 +193,29 @@ # Access to invocation frames in preparation. class MakeFrame(Immediate): "Make a new invocation frame." +class AdjustFrame(Immediate): "Adjust the current invocation frame for corrected invocations." class DropFrame(Instruction): "Drop an invocation frame." class StoreFrame(Immediate): "Store the current value as an argument for the parameter with the given position." class StoreFrameIndex(Immediate): "Store the source value as an argument of the current value for the parameter with the given index." class LoadContext(Instruction): "Load the context of an invocation." -class CheckSelf(Instruction): "Check the first argument of an invocation against the target." -# Access to invocation frames upon dispatch. +# Context-related tests. class CheckContext(Instruction): "Check to see if the context is valid." -class CheckClassContext(Instruction): - "Check the context to see if it should be used to validate the first argument." -class CheckFrame(Immediate): "Check the invocation frame and context for the target." +class CheckClass(Instruction): "Check the current value to determine whether it is a class." +class CheckSelf(Instruction): "Check the first argument of an invocation against the target." + +# Access to frames upon invocation. + +class CheckFrame(Immediate): "Check the frame for the correct number of arguments." class FillDefaults(Immediate): "Fill frame positions with defaults, if appropriate." +class ExtendFrame(Immediate): "Extend the current frame for temporary storage use." # Invocation-related instructions, using a special result "register". class JumpInFrame(Instruction): "Jump, using the current locals, to the current callable." class JumpWithFrame(Instruction): "Jump, adopting the invocation frame, to the current callable." class JumpWithFrameDirect(Target): "Jump to the specified address, adopting the invocation frame." -class ExtendFrame(Immediate): "Extend the current frame for temporary storage use." -class AdjustFrame(Immediate): "Adjust the current frame for corrected invocations." class Return(Instruction): "Return from a subprogram." class LoadResult(Instruction): "Load into the current value a returned value." class StoreResult(Instruction): "Store the current value as a value to be returned." @@ -241,8 +242,7 @@ class TestIdentityAddress(Address): "Test whether the current value is identical to the given address, setting the boolean status." class InvertBoolean(Instruction): "Invert the boolean status." -# Instructions which affect the current value. -# LoadAttrIndexContext not defined. +# Instructions which affect the current value. (LoadAttrIndexContext not defined.) current_value_instructions = ( LoadConst, LoadFunction, LoadName, LoadTemp, diff -r 8abc113da24c -r 77038806cb40 micropython/trans.py --- a/micropython/trans.py Mon Jun 01 02:41:57 2009 +0200 +++ b/micropython/trans.py Mon Jun 01 21:10:47 2009 +0200 @@ -489,9 +489,9 @@ need to support the same things as the more general invocations. """ - target, context, temp = self._generateCallFuncContext() - self._generateCallFuncArgs(target, context, temp, args, node) - return temp, target + target, context, temp_target, temp_context = self._generateCallFuncContext() + self._generateCallFuncArgs(target, context, temp_target, temp_context, args, node) + return temp_target, target, temp_context def _generateCallFuncContext(self): @@ -511,33 +511,41 @@ target, context = None, None # Store the target in temporary storage for subsequent referencing. - # NOTE: This may not be appropriate for class invocations - # NOTE: (instantiation). - temp = self.optimiser.optimise_temp_storage() + temp_target = self.optimiser.optimise_temp_storage() # Where a target or context are not known or where an instance is known # to be the context, load the context. if target is None or isinstance(context, Instance): - self.new_op(temp) + self.new_op(temp_target) self.new_op(LoadContext()) + temp_context = self.optimiser.optimise_temp_storage() self.new_op(StoreFrame(0)) + # Class contexts should be made available for testing of the first + # argument. + # NOTE: Class methods should eventually be supported. + + elif isinstance(context, Class): + self.new_op(temp_target) + self.new_op(LoadContext()) + temp_context = self.optimiser.optimise_temp_storage() + # Otherwise omit the context. else: - pass # NOTE: Class methods should be supported. + temp_context = None - return target, context, temp + return target, context, temp_target, temp_context - def _generateCallFuncArgs(self, target, context, temp, args, node): + def _generateCallFuncArgs(self, target, context, temp_target, temp_context, args, node): """ - Given invocation 'target' and 'context' information, the 'temp' - reference to the target, a list of nodes representing the 'args' - (arguments), generate instructions which load the arguments for the - invocation defined by the given 'node'. + Given invocation 'target' and 'context' information, the 'temp_target' + reference to the target, the 'temp_context' reference to the context, a + list of nodes representing the 'args' (arguments), generate instructions + which load the arguments for the invocation defined by the given 'node'. """ # Evaluate the arguments. @@ -545,165 +553,173 @@ employed_positions = set() employed_keywords = set() extra_keywords = [] + positional_args = [] + keyword_args = [] # Find keyword arguments in advance in order to help resolve targets. + have_keywords = 0 + for arg in args: if isinstance(arg, compiler.ast.Keyword): employed_keywords.add(arg.name) + keyword_args.append(arg) + have_keywords = 1 + elif not have_keywords: + positional_args.append(arg) possible_targets = self.paramtable.all_possible_objects(employed_keywords) # Note the presence of the context in the frame where appropriate. + # For unknown invocations and method invocations. + if target is None or isinstance(context, Instance): ncontext = 1 - expect_context = 0 + expect_testable_self = 0 - # Handle calls to classes. - # The resulting target must match that used in the actual invocation. + # Handle calls to classes by obtaining the instantiator function. # A context is reserved for the new instance, but this is not provided # in the invocation (since the instantiator will fill the locals slot # concerned). elif isinstance(target, Class): ncontext = 1 - expect_context = 0 + expect_testable_self = 0 target = target.get_instantiator() # Method calls via classes. elif isinstance(context, Class): ncontext = 0 - expect_context = 1 + expect_testable_self = 1 # Function calls. else: ncontext = 0 - expect_context = 0 + expect_testable_self = 0 + + # Traverse the positional arguments adding them using the incrementing + # frame position. first = 1 frame_pos = ncontext - max_keyword_pos = -1 - - for arg in args: - - # Handle positional and keyword arguments separately. - - if isinstance(arg, compiler.ast.Keyword): - - # Optimise where the target is known now. - - if target is not None: - - # Find the parameter table entry for the target. - - target_name = target.full_name() - - # Look for a callable with the precise target name. - - table_entry = self.paramtable.table[target_name] - - # Look the name up in the parameter table entry. - - try: - pos = table_entry[arg.name] - - # Where no position is found, this could be an extra keyword - # argument. - - except KeyError: - extra_keywords.append(arg) - continue - - # Test for illegal conditions. - - if pos in employed_positions: - raise TranslateError(self.module.full_name(), node, - "Keyword argument %r overwrites parameter %r." % (arg.name, pos)) - - employed_positions.add(pos) - - # Generate code for the keyword and the positioning - # operation. + temp_first_argument = None - self.dispatch(arg.expr) - self.new_op(StoreFrame(pos)) - - # Otherwise, generate the code needed to obtain the details of - # the parameter location. - - else: - - # Combine the target details with the name to get the location. - # See the access method on the List class. - - try: - paramindex = self.paramtable.get_index(arg.name) - - # Where no position is found, this could be an extra keyword - # argument. - - except self.paramtable.TableError: - extra_keywords.append(arg) - continue - - # Generate code for the keyword and the positioning - # operation. Get the value as the source of the assignment. - - self.dispatch(arg.expr) - self.record_value() - - # Store the source value using the callable's parameter - # table information. - - self.new_op(temp) - self.new_op(StoreFrameIndex(paramindex)) - - self.set_source() - self.discard_value() - - # Record the highest possible frame position for this argument. - - max_keyword_pos = max(max_keyword_pos, max(self.paramtable.all_attribute_positions(arg.name))) - - else: - self.dispatch(arg) - self.new_op(StoreFrame(frame_pos)) - - employed_positions.add(frame_pos) + for arg in positional_args: + self.dispatch(arg) + self.new_op(StoreFrame(frame_pos)) + employed_positions.add(frame_pos) # Check to see if the first argument is appropriate (compatible with # the target where methods are being invoked via classes). - if first and expect_context: + if first and (expect_testable_self or target is None): # Drop any test if the target and the context are known. if not self.optimiser.have_correct_self_for_target(context, self.unit): - continue_block = self.new_block() - - self.new_op(CheckSelf()) - self.optimiser.set_source(temp) - self.new_op(JumpIfTrue(continue_block)) - - # Where the context is inappropriate, drop the incomplete frame and - # raise an exception. + # Otherwise, remember the first argument for a subsequent + # test. - self.new_op(DropFrame()) - self.new_op(LoadResult()) - - self.make_exception("TypeError", node) - self.new_op(StoreException()) - self.new_op(RaiseException()) - - self.set_block(continue_block) + temp_first_argument = self.optimiser.optimise_temp_storage() first = 0 frame_pos += 1 + # Adjust the invocation frame for unknown invocations. + # Test the first argument if appropriate. + + self._generateCallFuncContextTest(temp_target, target, temp_context, temp_first_argument, node) + + # Traverse the keyword arguments adding them at the appropriate frame + # positions. + + max_keyword_pos = -1 + + for arg in keyword_args: + + # Optimise where the target is known now. + + if target is not None: + + # Find the parameter table entry for the target. + + target_name = target.full_name() + + # Look for a callable with the precise target name. + + table_entry = self.paramtable.table[target_name] + + # Look the name up in the parameter table entry. + + try: + pos = table_entry[arg.name] + + # Where no position is found, this could be an extra keyword + # argument. + + except KeyError: + extra_keywords.append(arg) + continue + + # Test for illegal conditions. + + if pos in employed_positions: + raise TranslateError(self.module.full_name(), node, + "Keyword argument %r overwrites parameter %r." % (arg.name, pos)) + + employed_positions.add(pos) + + # Generate code for the keyword and the positioning + # operation. + + self.dispatch(arg.expr) + self.new_op(StoreFrame(pos)) + + # Otherwise, generate the code needed to obtain the details of + # the parameter location. + + else: + + # Combine the target details with the name to get the location. + # See the access method on the List class. + + try: + paramindex = self.paramtable.get_index(arg.name) + + # Where no position is found, this could be an extra keyword + # argument. + + except self.paramtable.TableError: + extra_keywords.append(arg) + continue + + # Generate code for the keyword and the positioning + # operation. Get the value as the source of the assignment. + + self.dispatch(arg.expr) + self.record_value() + + # Store the source value using the callable's parameter + # table information. + + self.new_op(temp_target) + self.new_op(StoreFrameIndex(paramindex)) + + self.set_source() + self.discard_value() + + # Record the highest possible frame position for this argument. + + max_keyword_pos = max(max_keyword_pos, max(self.paramtable.all_attribute_positions(arg.name))) + + # Use the frame position counter as a general argument counter. + + frame_pos += 1 + # NOTE: Extra keywords are not supported. # NOTE: Somehow, the above needs to be combined with * arguments. @@ -753,7 +769,7 @@ # Where defaults are involved, put them into the frame. - self._generateCallFuncDefaultArgs(target, temp, nargs_min, nargs_max, employed_positions) + self._generateCallFuncDefaultArgs(target, temp_target, nargs_min, nargs_max, employed_positions) # Set the frame size. @@ -765,13 +781,13 @@ max_pos = max(max(employed_positions or [-1]), max_keyword_pos, frame_pos - 1) self._endCallFuncArgs(max_pos + 1) - def _generateCallFuncDefaultArgs(self, target, temp, nargs_min, nargs_max, employed_positions): + def _generateCallFuncDefaultArgs(self, target, temp_target, nargs_min, nargs_max, employed_positions): """ - For the given 'target' and 'temp' reference to the target, generate - default arguments for those positions in the range 'nargs_min'... - 'nargs_max' which are not present in the 'employed_positions' - collection. + For the given 'target' and 'temp_target' reference to the target, + generate default arguments for those positions in the range + 'nargs_min'...'nargs_max' which are not present in the + 'employed_positions' collection. """ # Where a lambda is involved, construct a dynamic object to hold the @@ -785,13 +801,77 @@ for pos in range(nargs_min, nargs_max): if pos not in employed_positions: if dynamic: - self.new_op(temp) + self.new_op(temp_target) self.new_op(LoadAttr(target.default_attrs[pos - nargs_min])) else: self.new_op(LoadAddress(target.default_attrs[pos - nargs_min])) self.new_op(StoreFrame(pos)) - def _doCallFunc(self, instruction, target=None): + def _generateCallFuncContextTest(self, temp_target, target, temp_context, temp_first_argument, node): + + """ + Generate code to test for 'temp_target', representing the given + 'target', the context provided by 'temp_context' against + 'temp_first_argument', and to signal an exception (using 'node') if the + context is incompatible with the first frame argument. + + In addition, the invocation frame will be shifted if 'temp_context' + indicates a function or a class. + """ + + adjust_block = self.new_block() + continue_block = self.new_block() + + # Add some preliminary tests where the target is not known. + + if target is None: + + # Skip adjustment and tests if a class is being invoked. + + self.new_op(temp_target) + self.new_op(CheckClass()) + self.new_op(JumpIfTrue(continue_block)) + + # Adjust the frame is no usable context is provided. + + self.new_op(temp_context) + self.new_op(CheckContext()) + self.new_op(JumpIfFalse(adjust_block)) + + # Skip adjustment and tests if the context is not a class. + + self.new_op(temp_context) + self.new_op(CheckClass()) + self.new_op(JumpIfFalse(continue_block)) + + if temp_first_argument is not None: + self.new_op(temp_first_argument) + + # Check the current value (the argument) against the known context + # (given as the source). + + self.new_op(CheckSelf()) + self.optimiser.set_source(temp_context) + + self.new_op(JumpIfTrue(adjust_block)) + + # Where the context is inappropriate, drop the incomplete frame and + # raise an exception. + + self.new_op(DropFrame()) + self.new_op(LoadResult()) + + self.make_exception("TypeError", node) + self.new_op(StoreException()) + self.new_op(RaiseException()) + + if target is None or temp_first_argument is not None: + self.set_block(adjust_block) + self.new_op(AdjustFrame(1)) + + self.set_block(continue_block) + + def _doCallFunc(self, temp_target, target=None): "Make the invocation." @@ -801,7 +881,7 @@ if isinstance(target, (Class, Function)): self.new_op(JumpWithFrameDirect(target)) else: - self.new_op(instruction) + self.new_op(temp_target) self.new_op(LoadCallable()) self.new_op(JumpWithFrame()) @@ -812,7 +892,7 @@ self.frame_makers[-1].attr = nargs self.frame_makers.pop() - def _endCallFunc(self, instruction=None, target=None, load_result=1): + def _endCallFunc(self, temp_target=None, target=None, temp_context=None, load_result=1): "Finish the invocation and tidy up afterwards." @@ -822,8 +902,11 @@ # Discard any temporary storage instructions. - if instruction is not None: - self.discard_temp(instruction) + if temp_target is not None: + self.discard_temp(temp_target) + + if temp_context is not None: + self.discard_temp(temp_context) def _generateFunctionDefaults(self, function): @@ -863,52 +946,6 @@ else: return None - def _generateFunctionContextTest(self, node, check_block): - - """ - Generate code to test the context for 'node', jumping to 'check_block' - from this code. - """ - - adjust_block = self.new_block() - - # Check the context. - - temp = LoadName(Attr(0, None, None)) - - # No usable context => remove the context and continue. - - self.new_op(temp) - self.new_op(CheckContext()) - self.new_op(JumpIfFalse(adjust_block)) - - # Check for a class as the context. - # Not a class as context => preserve the context and continue. - - self.new_op(temp) - self.new_op(CheckClassContext()) - self.new_op(JumpIfFalse(check_block)) - - # Check the context's compatibility with the first parameter. - # Compatible class => remove the context and continue. - # NOTE: Handle insufficient arguments. - - self.new_op(LoadName(Attr(1, None, None))) - self.new_op(CheckSelf()) - self.optimiser.set_source(temp) - self.new_op(JumpIfTrue(adjust_block)) - - # Incompatible class => type error. - - self.make_exception("TypeError", node) - self.new_op(StoreException()) - self.new_op(RaiseException()) - - # Remove the context from the parameters. - - self.set_block(adjust_block) - self.new_op(AdjustFrame(1)) - def _visitName(self, node, classes): """ diff -r 8abc113da24c -r 77038806cb40 rsvp.py --- a/rsvp.py Mon Jun 01 02:41:57 2009 +0200 +++ b/rsvp.py Mon Jun 01 21:10:47 2009 +0200 @@ -387,7 +387,7 @@ self.value = self.operand, self.operand def LoadFunction(self): - self.value = None, self.operand # context of constant is not interesting + self.value = None, self.operand def LoadName(self): frame = self.local_sp_stack[-1] @@ -523,7 +523,7 @@ # NOTE: Need to ensure correct positioning where a context has been generated. param_index, offset = element if param_index == self.operand: - self.frame_stack[frame + offset + 1] = self.source # add 1 to skip the context always generated + self.frame_stack[frame + offset] = self.source else: self.exception = self._MakeObject(2, self.type_error_instance) return self.RaiseException() @@ -548,16 +548,16 @@ def CheckContext(self): self.status = self.value[1] is not None - def CheckClassContext(self): - context_context, context_ref = self.value - context_data = self.load(context_ref) + def CheckClass(self): + context, ref = self.value + data = self.load(ref) # Classes are not themselves usable as the self argument. # NOTE: This may change at some point. # However, where classes appear as the context, instance # compatibility is required in the first argument. - self.status = context_data.attrcode is None # absent attrcode == class + self.status = data.attrcode is None # absent attrcode == class def CheckFrame(self): (nargs, ndefaults, has_star) = self.operand @@ -568,8 +568,11 @@ frame = self.local_sp_stack[-1] nlocals = len(self.frame_stack[frame:]) - if not ((nargs - ndefaults) <= nlocals and (nlocals <= nargs or has_star)): - #raise Exception, "CheckFrame %r (%r <= %r <= %r)" % (self.operand, nargs - ndefaults, nlocals, nargs) + # NOTE: Not testing (nlocals <= nargs or has_star) due to imprecise + # NOTE: invocation frame removal (after frame adjustment). + + if not ((nargs - ndefaults) <= nlocals): + raise Exception, "CheckFrame %r (%r <= %r <= %r)" % (self.operand, nargs - ndefaults, nlocals, nargs) self.exception = self._MakeObject(2, self.type_error_instance) return self.RaiseException() @@ -596,11 +599,11 @@ def CheckSelf(self): context, ref = self.value - target_context, target_ref = self.source + context_context, context_ref = self.source # Check the details of the proposed context and the target's context. - self.status = self._CheckInstance(ref, target_context) + self.status = self._CheckInstance(ref, context_ref) def JumpInFrame(self): codeaddr = self.callable @@ -620,7 +623,7 @@ self.frame_stack.extend([None] * self.operand) def AdjustFrame(self): - self.local_sp_stack[-1] += self.operand + self.invocation_sp_stack[-1] += self.operand def Return(self): return self.pull_pc() diff -r 8abc113da24c -r 77038806cb40 tests/attributes_instance_bind_initialiser.py --- a/tests/attributes_instance_bind_initialiser.py Mon Jun 01 02:41:57 2009 +0200 +++ b/tests/attributes_instance_bind_initialiser.py Mon Jun 01 21:10:47 2009 +0200 @@ -8,7 +8,6 @@ c1 = B def __init__(self, b): self.c2 = B - self.c3 = b b = B(789) a = A(b) diff -r 8abc113da24c -r 77038806cb40 tests/cond_if.py --- a/tests/cond_if.py Mon Jun 01 02:41:57 2009 +0200 +++ b/tests/cond_if.py Mon Jun 01 21:10:47 2009 +0200 @@ -1,11 +1,12 @@ #!/usr/bin/env python a = 1 + if a: b = 1 else: b = 2 -a -b + +result_1 = b # vim: tabstop=4 expandtab shiftwidth=4 diff -r 8abc113da24c -r 77038806cb40 tests/lambda.py --- a/tests/lambda.py Mon Jun 01 02:41:57 2009 +0200 +++ b/tests/lambda.py Mon Jun 01 21:10:47 2009 +0200 @@ -1,18 +1,11 @@ #!/usr/bin/env python -identity = lambda x: x -add_2 = lambda a, b=2: a + b - def f(c): return lambda a, b=c: a + b def g(f, x): return f(x) -result_1 = identity(1) -result_3 = add_2(1) -result2_1 = g(identity, 1) -result2_3 = g(add_2, 1) result_4 = g(f(3), 1) # vim: tabstop=4 expandtab shiftwidth=4 diff -r 8abc113da24c -r 77038806cb40 tests/lambda_defaults.py --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/tests/lambda_defaults.py Mon Jun 01 21:10:47 2009 +0200 @@ -0,0 +1,11 @@ +#!/usr/bin/env python + +add_2 = lambda a, b=2: a + b + +def g(f, x): + return f(x) + +result_3 = add_2(1) +result2_3 = g(add_2, 1) + +# vim: tabstop=4 expandtab shiftwidth=4 diff -r 8abc113da24c -r 77038806cb40 tests/lambda_simple.py --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/tests/lambda_simple.py Mon Jun 01 21:10:47 2009 +0200 @@ -0,0 +1,11 @@ +#!/usr/bin/env python + +identity = lambda x: x + +def g(f, x): + return f(x) + +result_1 = identity(1) +result2_1 = g(identity, 1) + +# vim: tabstop=4 expandtab shiftwidth=4