1.1 --- a/docs/invocation.txt Mon Jun 01 02:41:57 2009 +0200
1.2 +++ b/docs/invocation.txt Mon Jun 01 21:10:47 2009 +0200
1.3 @@ -71,7 +71,7 @@
1.4
1.5 f(obj, 1, 2) # f known as function at compile-time
1.6
1.7 - f -> don't get any context information
1.8 + f -> f (context is null)
1.9 obj -> argument #1
1.10 1 -> argument #2
1.11 2 -> argument #3
1.12 @@ -80,8 +80,8 @@
1.13
1.14 f(obj, 1, 2) # f known as C.m at compile-time (context is C)
1.15
1.16 - f -> C.m - don't get any context information
1.17 - obj -> argument #1
1.18 + f -> C.m (context is class C)
1.19 + obj -> argument #1 (must be tested against the context)
1.20 1 -> argument #2
1.21 2 -> argument #3
1.22
1.23 @@ -99,13 +99,13 @@
1.24
1.25 f(obj, 1, 2) # f known as C at compile-time
1.26
1.27 - f -> C.__init__
1.28 - -> new instance is argument #1
1.29 + f -> instantiator of C
1.30 + -> (argument #1 reserved for a new instance made by the instantiator)
1.31 obj -> argument #2
1.32 1 -> argument #3
1.33 2 -> argument #4
1.34
1.35 - The new instance must be manually provided as the result after the call.
1.36 + The new instance must be provided as the result of the call.
1.37
1.38 Argument lists for unknown callables:
1.39
1.40 @@ -119,7 +119,9 @@
1.41
1.42 Then, check the context and shift the frame if necessary:
1.43
1.44 - <context> is module or class:
1.45 + f is class: no change
1.46 +
1.47 + <context> is class:
1.48 (<context>, obj, 1, 2) -> (obj, 1, 2)
1.49
1.50 <context> is instance: no change
1.51 @@ -143,8 +145,6 @@
1.52 2 -> argument #4
1.53
1.54 Then jump without switching frames.
1.55 - It should be possible to replace the old, tentative context information in the
1.56 - frame.
1.57
1.58 Defaults for unknown callables:
1.59
2.1 --- a/micropython/ast.py Mon Jun 01 02:41:57 2009 +0200
2.2 +++ b/micropython/ast.py Mon Jun 01 21:10:47 2009 +0200
2.3 @@ -384,9 +384,9 @@
2.4
2.5 self._startCallFunc()
2.6 self.dispatch(node.node)
2.7 - temp, target = self._generateCallFunc(node.args, node)
2.8 - self._doCallFunc(temp, target)
2.9 - self._endCallFunc(temp, target)
2.10 + temp_target, target, temp_context = self._generateCallFunc(node.args, node)
2.11 + self._doCallFunc(temp_target, target)
2.12 + self._endCallFunc(temp_target, target, temp_context)
2.13
2.14 def visitConst(self, node):
2.15 const = self.importer.get_constant(node.value)
2.16 @@ -433,9 +433,9 @@
2.17 self.dispatch(node.expr)
2.18 self._startCallFunc()
2.19 self._generateAttr(node, "__getitem__", self.attribute_load_instructions)
2.20 - temp, target = self._generateCallFunc(node.subs, node)
2.21 - self._doCallFunc(temp, target)
2.22 - self._endCallFunc(temp, target)
2.23 + temp_target, target, temp_context = self._generateCallFunc(node.subs, node)
2.24 + self._doCallFunc(temp_target, target)
2.25 + self._endCallFunc(temp_target, target, temp_context)
2.26
2.27 def visitTuple(self, node):
2.28 self._generateSequence("tuple", node)
2.29 @@ -478,9 +478,9 @@
2.30 self._startCallFunc()
2.31 self.new_op(self.expr_temp[-1])
2.32 self._generateAttr(node, "__getitem__", self.attribute_load_instructions)
2.33 - temp, target = self._generateCallFunc([compiler.ast.Const(i)], node)
2.34 - self._doCallFunc(temp, target)
2.35 - self._endCallFunc(temp, target)
2.36 + temp_target, target, temp_context = self._generateCallFunc([compiler.ast.Const(i)], node)
2.37 + self._doCallFunc(temp_target, target)
2.38 + self._endCallFunc(temp_target, target, temp_context)
2.39
2.40 # Provide a different source value.
2.41 # NOTE: Permitting immediate usage given that neither name nor
2.42 @@ -594,14 +594,9 @@
2.43 ndefaults = len(fn.defaults)
2.44
2.45 fn.body_block = self.new_block()
2.46 - check_block = self.new_block()
2.47 -
2.48 - self._generateFunctionContextTest(node, check_block)
2.49
2.50 # Check the number of parameters and defaults.
2.51
2.52 - self.set_block(check_block)
2.53 -
2.54 self.new_op(CheckFrame((nparams, ndefaults, fn.has_star)))
2.55 if ndefaults > 0:
2.56 self.new_op(LoadFunction(fn))
2.57 @@ -649,8 +644,14 @@
2.58 # outside.
2.59
2.60 if self.unit is not node.unit:
2.61 - temp = self._generateFunctionDefaults(node.unit)
2.62 - self.new_op(LoadFunction(node.unit))
2.63 + fn = node.unit
2.64 + ndefaults = len(fn.defaults)
2.65 + temp = self._generateFunctionDefaults(fn)
2.66 +
2.67 + if ndefaults > 0:
2.68 + self.new_op(LoadConst(fn))
2.69 + else:
2.70 + self.new_op(LoadFunction(fn))
2.71
2.72 # Populate the new object required for the function.
2.73
2.74 @@ -672,14 +673,9 @@
2.75 ndefaults = len(fn.defaults)
2.76
2.77 fn.body_block = self.new_block()
2.78 - check_block = self.new_block()
2.79 -
2.80 - self._generateFunctionContextTest(node, check_block)
2.81
2.82 # Check the number of parameters and defaults.
2.83
2.84 - self.set_block(check_block)
2.85 -
2.86 self.new_op(CheckFrame((nparams, ndefaults, fn.has_star)))
2.87 if ndefaults > 0:
2.88 self.new_op(LoadTemp(0)) # context provides storage
2.89 @@ -756,9 +752,9 @@
2.90 self._startCallFunc()
2.91 self.dispatch(node.list)
2.92 self._generateAttr(node, "__iter__", self.attribute_load_instructions)
2.93 - temp, target = self._generateCallFunc([], node)
2.94 - self._doCallFunc(temp, target)
2.95 - self._endCallFunc(temp, target)
2.96 + temp_target, target, temp_context = self._generateCallFunc([], node)
2.97 + self._doCallFunc(temp_target, target)
2.98 + self._endCallFunc(temp_target, target, temp_context)
2.99
2.100 temp_iterator = self.optimiser.optimise_temp_storage()
2.101
2.102 @@ -775,9 +771,9 @@
2.103 self._startCallFunc()
2.104 self.new_op(temp_iterator)
2.105 self._generateAttr(node, "next", self.attribute_load_instructions)
2.106 - temp, target = self._generateCallFunc([], node)
2.107 - self._doCallFunc(temp, target)
2.108 - self._endCallFunc(temp, target)
2.109 + temp_target, target, temp_context = self._generateCallFunc([], node)
2.110 + self._doCallFunc(temp_target, target)
2.111 + self._endCallFunc(temp_target, target, temp_context)
2.112
2.113 # Record the value to be assigned.
2.114
2.115 @@ -860,6 +856,10 @@
2.116
2.117 if test is not None:
2.118 self.dispatch(test)
2.119 +
2.120 + temp = self.optimiser.optimise_temp_storage()
2.121 + self._generateTestBoolean(node, temp)
2.122 +
2.123 next_block = self.new_block()
2.124 self.new_op(JumpIfFalse(next_block))
2.125
3.1 --- a/micropython/opt.py Mon Jun 01 02:41:57 2009 +0200
3.2 +++ b/micropython/opt.py Mon Jun 01 21:10:47 2009 +0200
3.3 @@ -195,7 +195,7 @@
3.4 TestIdentity, TestIdentityAddress, CheckSelf, # as one of the operands
3.5 CheckException, CheckFrame, FillDefaults,
3.6 MakeInstance,
3.7 - CheckContext, CheckClassContext,
3.8 + CheckContext, CheckClass,
3.9 LoadContext # as the object providing the result
3.10 ))
3.11
4.1 --- a/micropython/rsvp.py Mon Jun 01 02:41:57 2009 +0200
4.2 +++ b/micropython/rsvp.py Mon Jun 01 21:10:47 2009 +0200
4.3 @@ -175,13 +175,12 @@
4.4 context if the attribute is compatible."""
4.5 class MakeInstance(Immediate): "Make a new instance."
4.6
4.7 -# Access to address-relative data.
4.8 +# Access to address-relative data. (LoadAttrIndexContext not defined.)
4.9
4.10 class LoadAttr(AR): "Load into the current value the given attribute of the object referenced by the current value."
4.11 class StoreAttr(AR): "Store the source value into the given attribute of the object referenced by the current value."
4.12 class LoadAttrIndex(Immediate): "Load into the current value the attribute of the current value with the given index."
4.13 class StoreAttrIndex(Immediate): "Store the source value into the attribute of the current value with the given index."
4.14 -##### LoadAttrIndexContext not defined.
4.15 class LoadAttrIndexContextCond(Immediate):
4.16 """Load into the current value the attribute of the current value with the given index, only making the
4.17 current value the context if the attribute is compatible."""
4.18 @@ -194,27 +193,29 @@
4.19 # Access to invocation frames in preparation.
4.20
4.21 class MakeFrame(Immediate): "Make a new invocation frame."
4.22 +class AdjustFrame(Immediate): "Adjust the current invocation frame for corrected invocations."
4.23 class DropFrame(Instruction): "Drop an invocation frame."
4.24 class StoreFrame(Immediate): "Store the current value as an argument for the parameter with the given position."
4.25 class StoreFrameIndex(Immediate): "Store the source value as an argument of the current value for the parameter with the given index."
4.26 class LoadContext(Instruction): "Load the context of an invocation."
4.27 -class CheckSelf(Instruction): "Check the first argument of an invocation against the target."
4.28
4.29 -# Access to invocation frames upon dispatch.
4.30 +# Context-related tests.
4.31
4.32 class CheckContext(Instruction): "Check to see if the context is valid."
4.33 -class CheckClassContext(Instruction):
4.34 - "Check the context to see if it should be used to validate the first argument."
4.35 -class CheckFrame(Immediate): "Check the invocation frame and context for the target."
4.36 +class CheckClass(Instruction): "Check the current value to determine whether it is a class."
4.37 +class CheckSelf(Instruction): "Check the first argument of an invocation against the target."
4.38 +
4.39 +# Access to frames upon invocation.
4.40 +
4.41 +class CheckFrame(Immediate): "Check the frame for the correct number of arguments."
4.42 class FillDefaults(Immediate): "Fill frame positions with defaults, if appropriate."
4.43 +class ExtendFrame(Immediate): "Extend the current frame for temporary storage use."
4.44
4.45 # Invocation-related instructions, using a special result "register".
4.46
4.47 class JumpInFrame(Instruction): "Jump, using the current locals, to the current callable."
4.48 class JumpWithFrame(Instruction): "Jump, adopting the invocation frame, to the current callable."
4.49 class JumpWithFrameDirect(Target): "Jump to the specified address, adopting the invocation frame."
4.50 -class ExtendFrame(Immediate): "Extend the current frame for temporary storage use."
4.51 -class AdjustFrame(Immediate): "Adjust the current frame for corrected invocations."
4.52 class Return(Instruction): "Return from a subprogram."
4.53 class LoadResult(Instruction): "Load into the current value a returned value."
4.54 class StoreResult(Instruction): "Store the current value as a value to be returned."
4.55 @@ -241,8 +242,7 @@
4.56 class TestIdentityAddress(Address): "Test whether the current value is identical to the given address, setting the boolean status."
4.57 class InvertBoolean(Instruction): "Invert the boolean status."
4.58
4.59 -# Instructions which affect the current value.
4.60 -# LoadAttrIndexContext not defined.
4.61 +# Instructions which affect the current value. (LoadAttrIndexContext not defined.)
4.62
4.63 current_value_instructions = (
4.64 LoadConst, LoadFunction, LoadName, LoadTemp,
5.1 --- a/micropython/trans.py Mon Jun 01 02:41:57 2009 +0200
5.2 +++ b/micropython/trans.py Mon Jun 01 21:10:47 2009 +0200
5.3 @@ -489,9 +489,9 @@
5.4 need to support the same things as the more general invocations.
5.5 """
5.6
5.7 - target, context, temp = self._generateCallFuncContext()
5.8 - self._generateCallFuncArgs(target, context, temp, args, node)
5.9 - return temp, target
5.10 + target, context, temp_target, temp_context = self._generateCallFuncContext()
5.11 + self._generateCallFuncArgs(target, context, temp_target, temp_context, args, node)
5.12 + return temp_target, target, temp_context
5.13
5.14 def _generateCallFuncContext(self):
5.15
5.16 @@ -511,33 +511,41 @@
5.17 target, context = None, None
5.18
5.19 # Store the target in temporary storage for subsequent referencing.
5.20 - # NOTE: This may not be appropriate for class invocations
5.21 - # NOTE: (instantiation).
5.22
5.23 - temp = self.optimiser.optimise_temp_storage()
5.24 + temp_target = self.optimiser.optimise_temp_storage()
5.25
5.26 # Where a target or context are not known or where an instance is known
5.27 # to be the context, load the context.
5.28
5.29 if target is None or isinstance(context, Instance):
5.30 - self.new_op(temp)
5.31 + self.new_op(temp_target)
5.32 self.new_op(LoadContext())
5.33 + temp_context = self.optimiser.optimise_temp_storage()
5.34 self.new_op(StoreFrame(0))
5.35
5.36 + # Class contexts should be made available for testing of the first
5.37 + # argument.
5.38 + # NOTE: Class methods should eventually be supported.
5.39 +
5.40 + elif isinstance(context, Class):
5.41 + self.new_op(temp_target)
5.42 + self.new_op(LoadContext())
5.43 + temp_context = self.optimiser.optimise_temp_storage()
5.44 +
5.45 # Otherwise omit the context.
5.46
5.47 else:
5.48 - pass # NOTE: Class methods should be supported.
5.49 + temp_context = None
5.50
5.51 - return target, context, temp
5.52 + return target, context, temp_target, temp_context
5.53
5.54 - def _generateCallFuncArgs(self, target, context, temp, args, node):
5.55 + def _generateCallFuncArgs(self, target, context, temp_target, temp_context, args, node):
5.56
5.57 """
5.58 - Given invocation 'target' and 'context' information, the 'temp'
5.59 - reference to the target, a list of nodes representing the 'args'
5.60 - (arguments), generate instructions which load the arguments for the
5.61 - invocation defined by the given 'node'.
5.62 + Given invocation 'target' and 'context' information, the 'temp_target'
5.63 + reference to the target, the 'temp_context' reference to the context, a
5.64 + list of nodes representing the 'args' (arguments), generate instructions
5.65 + which load the arguments for the invocation defined by the given 'node'.
5.66 """
5.67
5.68 # Evaluate the arguments.
5.69 @@ -545,165 +553,173 @@
5.70 employed_positions = set()
5.71 employed_keywords = set()
5.72 extra_keywords = []
5.73 + positional_args = []
5.74 + keyword_args = []
5.75
5.76 # Find keyword arguments in advance in order to help resolve targets.
5.77
5.78 + have_keywords = 0
5.79 +
5.80 for arg in args:
5.81 if isinstance(arg, compiler.ast.Keyword):
5.82 employed_keywords.add(arg.name)
5.83 + keyword_args.append(arg)
5.84 + have_keywords = 1
5.85 + elif not have_keywords:
5.86 + positional_args.append(arg)
5.87
5.88 possible_targets = self.paramtable.all_possible_objects(employed_keywords)
5.89
5.90 # Note the presence of the context in the frame where appropriate.
5.91
5.92 + # For unknown invocations and method invocations.
5.93 +
5.94 if target is None or isinstance(context, Instance):
5.95 ncontext = 1
5.96 - expect_context = 0
5.97 + expect_testable_self = 0
5.98
5.99 - # Handle calls to classes.
5.100 - # The resulting target must match that used in the actual invocation.
5.101 + # Handle calls to classes by obtaining the instantiator function.
5.102 # A context is reserved for the new instance, but this is not provided
5.103 # in the invocation (since the instantiator will fill the locals slot
5.104 # concerned).
5.105
5.106 elif isinstance(target, Class):
5.107 ncontext = 1
5.108 - expect_context = 0
5.109 + expect_testable_self = 0
5.110 target = target.get_instantiator()
5.111
5.112 # Method calls via classes.
5.113
5.114 elif isinstance(context, Class):
5.115 ncontext = 0
5.116 - expect_context = 1
5.117 + expect_testable_self = 1
5.118
5.119 # Function calls.
5.120
5.121 else:
5.122 ncontext = 0
5.123 - expect_context = 0
5.124 + expect_testable_self = 0
5.125 +
5.126 + # Traverse the positional arguments adding them using the incrementing
5.127 + # frame position.
5.128
5.129 first = 1
5.130 frame_pos = ncontext
5.131 - max_keyword_pos = -1
5.132 -
5.133 - for arg in args:
5.134 -
5.135 - # Handle positional and keyword arguments separately.
5.136 -
5.137 - if isinstance(arg, compiler.ast.Keyword):
5.138 -
5.139 - # Optimise where the target is known now.
5.140 -
5.141 - if target is not None:
5.142 -
5.143 - # Find the parameter table entry for the target.
5.144 -
5.145 - target_name = target.full_name()
5.146 -
5.147 - # Look for a callable with the precise target name.
5.148 -
5.149 - table_entry = self.paramtable.table[target_name]
5.150 -
5.151 - # Look the name up in the parameter table entry.
5.152 -
5.153 - try:
5.154 - pos = table_entry[arg.name]
5.155 -
5.156 - # Where no position is found, this could be an extra keyword
5.157 - # argument.
5.158 -
5.159 - except KeyError:
5.160 - extra_keywords.append(arg)
5.161 - continue
5.162 -
5.163 - # Test for illegal conditions.
5.164 -
5.165 - if pos in employed_positions:
5.166 - raise TranslateError(self.module.full_name(), node,
5.167 - "Keyword argument %r overwrites parameter %r." % (arg.name, pos))
5.168 -
5.169 - employed_positions.add(pos)
5.170 -
5.171 - # Generate code for the keyword and the positioning
5.172 - # operation.
5.173 + temp_first_argument = None
5.174
5.175 - self.dispatch(arg.expr)
5.176 - self.new_op(StoreFrame(pos))
5.177 -
5.178 - # Otherwise, generate the code needed to obtain the details of
5.179 - # the parameter location.
5.180 -
5.181 - else:
5.182 -
5.183 - # Combine the target details with the name to get the location.
5.184 - # See the access method on the List class.
5.185 -
5.186 - try:
5.187 - paramindex = self.paramtable.get_index(arg.name)
5.188 -
5.189 - # Where no position is found, this could be an extra keyword
5.190 - # argument.
5.191 -
5.192 - except self.paramtable.TableError:
5.193 - extra_keywords.append(arg)
5.194 - continue
5.195 -
5.196 - # Generate code for the keyword and the positioning
5.197 - # operation. Get the value as the source of the assignment.
5.198 -
5.199 - self.dispatch(arg.expr)
5.200 - self.record_value()
5.201 -
5.202 - # Store the source value using the callable's parameter
5.203 - # table information.
5.204 -
5.205 - self.new_op(temp)
5.206 - self.new_op(StoreFrameIndex(paramindex))
5.207 -
5.208 - self.set_source()
5.209 - self.discard_value()
5.210 -
5.211 - # Record the highest possible frame position for this argument.
5.212 -
5.213 - max_keyword_pos = max(max_keyword_pos, max(self.paramtable.all_attribute_positions(arg.name)))
5.214 -
5.215 - else:
5.216 - self.dispatch(arg)
5.217 - self.new_op(StoreFrame(frame_pos))
5.218 -
5.219 - employed_positions.add(frame_pos)
5.220 + for arg in positional_args:
5.221 + self.dispatch(arg)
5.222 + self.new_op(StoreFrame(frame_pos))
5.223 + employed_positions.add(frame_pos)
5.224
5.225 # Check to see if the first argument is appropriate (compatible with
5.226 # the target where methods are being invoked via classes).
5.227
5.228 - if first and expect_context:
5.229 + if first and (expect_testable_self or target is None):
5.230
5.231 # Drop any test if the target and the context are known.
5.232
5.233 if not self.optimiser.have_correct_self_for_target(context, self.unit):
5.234
5.235 - continue_block = self.new_block()
5.236 -
5.237 - self.new_op(CheckSelf())
5.238 - self.optimiser.set_source(temp)
5.239 - self.new_op(JumpIfTrue(continue_block))
5.240 -
5.241 - # Where the context is inappropriate, drop the incomplete frame and
5.242 - # raise an exception.
5.243 + # Otherwise, remember the first argument for a subsequent
5.244 + # test.
5.245
5.246 - self.new_op(DropFrame())
5.247 - self.new_op(LoadResult())
5.248 -
5.249 - self.make_exception("TypeError", node)
5.250 - self.new_op(StoreException())
5.251 - self.new_op(RaiseException())
5.252 -
5.253 - self.set_block(continue_block)
5.254 + temp_first_argument = self.optimiser.optimise_temp_storage()
5.255
5.256 first = 0
5.257 frame_pos += 1
5.258
5.259 + # Adjust the invocation frame for unknown invocations.
5.260 + # Test the first argument if appropriate.
5.261 +
5.262 + self._generateCallFuncContextTest(temp_target, target, temp_context, temp_first_argument, node)
5.263 +
5.264 + # Traverse the keyword arguments adding them at the appropriate frame
5.265 + # positions.
5.266 +
5.267 + max_keyword_pos = -1
5.268 +
5.269 + for arg in keyword_args:
5.270 +
5.271 + # Optimise where the target is known now.
5.272 +
5.273 + if target is not None:
5.274 +
5.275 + # Find the parameter table entry for the target.
5.276 +
5.277 + target_name = target.full_name()
5.278 +
5.279 + # Look for a callable with the precise target name.
5.280 +
5.281 + table_entry = self.paramtable.table[target_name]
5.282 +
5.283 + # Look the name up in the parameter table entry.
5.284 +
5.285 + try:
5.286 + pos = table_entry[arg.name]
5.287 +
5.288 + # Where no position is found, this could be an extra keyword
5.289 + # argument.
5.290 +
5.291 + except KeyError:
5.292 + extra_keywords.append(arg)
5.293 + continue
5.294 +
5.295 + # Test for illegal conditions.
5.296 +
5.297 + if pos in employed_positions:
5.298 + raise TranslateError(self.module.full_name(), node,
5.299 + "Keyword argument %r overwrites parameter %r." % (arg.name, pos))
5.300 +
5.301 + employed_positions.add(pos)
5.302 +
5.303 + # Generate code for the keyword and the positioning
5.304 + # operation.
5.305 +
5.306 + self.dispatch(arg.expr)
5.307 + self.new_op(StoreFrame(pos))
5.308 +
5.309 + # Otherwise, generate the code needed to obtain the details of
5.310 + # the parameter location.
5.311 +
5.312 + else:
5.313 +
5.314 + # Combine the target details with the name to get the location.
5.315 + # See the access method on the List class.
5.316 +
5.317 + try:
5.318 + paramindex = self.paramtable.get_index(arg.name)
5.319 +
5.320 + # Where no position is found, this could be an extra keyword
5.321 + # argument.
5.322 +
5.323 + except self.paramtable.TableError:
5.324 + extra_keywords.append(arg)
5.325 + continue
5.326 +
5.327 + # Generate code for the keyword and the positioning
5.328 + # operation. Get the value as the source of the assignment.
5.329 +
5.330 + self.dispatch(arg.expr)
5.331 + self.record_value()
5.332 +
5.333 + # Store the source value using the callable's parameter
5.334 + # table information.
5.335 +
5.336 + self.new_op(temp_target)
5.337 + self.new_op(StoreFrameIndex(paramindex))
5.338 +
5.339 + self.set_source()
5.340 + self.discard_value()
5.341 +
5.342 + # Record the highest possible frame position for this argument.
5.343 +
5.344 + max_keyword_pos = max(max_keyword_pos, max(self.paramtable.all_attribute_positions(arg.name)))
5.345 +
5.346 + # Use the frame position counter as a general argument counter.
5.347 +
5.348 + frame_pos += 1
5.349 +
5.350 # NOTE: Extra keywords are not supported.
5.351 # NOTE: Somehow, the above needs to be combined with * arguments.
5.352
5.353 @@ -753,7 +769,7 @@
5.354
5.355 # Where defaults are involved, put them into the frame.
5.356
5.357 - self._generateCallFuncDefaultArgs(target, temp, nargs_min, nargs_max, employed_positions)
5.358 + self._generateCallFuncDefaultArgs(target, temp_target, nargs_min, nargs_max, employed_positions)
5.359
5.360 # Set the frame size.
5.361
5.362 @@ -765,13 +781,13 @@
5.363 max_pos = max(max(employed_positions or [-1]), max_keyword_pos, frame_pos - 1)
5.364 self._endCallFuncArgs(max_pos + 1)
5.365
5.366 - def _generateCallFuncDefaultArgs(self, target, temp, nargs_min, nargs_max, employed_positions):
5.367 + def _generateCallFuncDefaultArgs(self, target, temp_target, nargs_min, nargs_max, employed_positions):
5.368
5.369 """
5.370 - For the given 'target' and 'temp' reference to the target, generate
5.371 - default arguments for those positions in the range 'nargs_min'...
5.372 - 'nargs_max' which are not present in the 'employed_positions'
5.373 - collection.
5.374 + For the given 'target' and 'temp_target' reference to the target,
5.375 + generate default arguments for those positions in the range
5.376 + 'nargs_min'...'nargs_max' which are not present in the
5.377 + 'employed_positions' collection.
5.378 """
5.379
5.380 # Where a lambda is involved, construct a dynamic object to hold the
5.381 @@ -785,13 +801,77 @@
5.382 for pos in range(nargs_min, nargs_max):
5.383 if pos not in employed_positions:
5.384 if dynamic:
5.385 - self.new_op(temp)
5.386 + self.new_op(temp_target)
5.387 self.new_op(LoadAttr(target.default_attrs[pos - nargs_min]))
5.388 else:
5.389 self.new_op(LoadAddress(target.default_attrs[pos - nargs_min]))
5.390 self.new_op(StoreFrame(pos))
5.391
5.392 - def _doCallFunc(self, instruction, target=None):
5.393 + def _generateCallFuncContextTest(self, temp_target, target, temp_context, temp_first_argument, node):
5.394 +
5.395 + """
5.396 + Generate code to test for 'temp_target', representing the given
5.397 + 'target', the context provided by 'temp_context' against
5.398 + 'temp_first_argument', and to signal an exception (using 'node') if the
5.399 + context is incompatible with the first frame argument.
5.400 +
5.401 + In addition, the invocation frame will be shifted if 'temp_context'
5.402 + indicates a function or a class.
5.403 + """
5.404 +
5.405 + adjust_block = self.new_block()
5.406 + continue_block = self.new_block()
5.407 +
5.408 + # Add some preliminary tests where the target is not known.
5.409 +
5.410 + if target is None:
5.411 +
5.412 + # Skip adjustment and tests if a class is being invoked.
5.413 +
5.414 + self.new_op(temp_target)
5.415 + self.new_op(CheckClass())
5.416 + self.new_op(JumpIfTrue(continue_block))
5.417 +
5.418 + # Adjust the frame is no usable context is provided.
5.419 +
5.420 + self.new_op(temp_context)
5.421 + self.new_op(CheckContext())
5.422 + self.new_op(JumpIfFalse(adjust_block))
5.423 +
5.424 + # Skip adjustment and tests if the context is not a class.
5.425 +
5.426 + self.new_op(temp_context)
5.427 + self.new_op(CheckClass())
5.428 + self.new_op(JumpIfFalse(continue_block))
5.429 +
5.430 + if temp_first_argument is not None:
5.431 + self.new_op(temp_first_argument)
5.432 +
5.433 + # Check the current value (the argument) against the known context
5.434 + # (given as the source).
5.435 +
5.436 + self.new_op(CheckSelf())
5.437 + self.optimiser.set_source(temp_context)
5.438 +
5.439 + self.new_op(JumpIfTrue(adjust_block))
5.440 +
5.441 + # Where the context is inappropriate, drop the incomplete frame and
5.442 + # raise an exception.
5.443 +
5.444 + self.new_op(DropFrame())
5.445 + self.new_op(LoadResult())
5.446 +
5.447 + self.make_exception("TypeError", node)
5.448 + self.new_op(StoreException())
5.449 + self.new_op(RaiseException())
5.450 +
5.451 + if target is None or temp_first_argument is not None:
5.452 + self.set_block(adjust_block)
5.453 + self.new_op(AdjustFrame(1))
5.454 +
5.455 + self.set_block(continue_block)
5.456 +
5.457 + def _doCallFunc(self, temp_target, target=None):
5.458
5.459 "Make the invocation."
5.460
5.461 @@ -801,7 +881,7 @@
5.462 if isinstance(target, (Class, Function)):
5.463 self.new_op(JumpWithFrameDirect(target))
5.464 else:
5.465 - self.new_op(instruction)
5.466 + self.new_op(temp_target)
5.467 self.new_op(LoadCallable())
5.468 self.new_op(JumpWithFrame())
5.469
5.470 @@ -812,7 +892,7 @@
5.471 self.frame_makers[-1].attr = nargs
5.472 self.frame_makers.pop()
5.473
5.474 - def _endCallFunc(self, instruction=None, target=None, load_result=1):
5.475 + def _endCallFunc(self, temp_target=None, target=None, temp_context=None, load_result=1):
5.476
5.477 "Finish the invocation and tidy up afterwards."
5.478
5.479 @@ -822,8 +902,11 @@
5.480
5.481 # Discard any temporary storage instructions.
5.482
5.483 - if instruction is not None:
5.484 - self.discard_temp(instruction)
5.485 + if temp_target is not None:
5.486 + self.discard_temp(temp_target)
5.487 +
5.488 + if temp_context is not None:
5.489 + self.discard_temp(temp_context)
5.490
5.491 def _generateFunctionDefaults(self, function):
5.492
5.493 @@ -863,52 +946,6 @@
5.494 else:
5.495 return None
5.496
5.497 - def _generateFunctionContextTest(self, node, check_block):
5.498 -
5.499 - """
5.500 - Generate code to test the context for 'node', jumping to 'check_block'
5.501 - from this code.
5.502 - """
5.503 -
5.504 - adjust_block = self.new_block()
5.505 -
5.506 - # Check the context.
5.507 -
5.508 - temp = LoadName(Attr(0, None, None))
5.509 -
5.510 - # No usable context => remove the context and continue.
5.511 -
5.512 - self.new_op(temp)
5.513 - self.new_op(CheckContext())
5.514 - self.new_op(JumpIfFalse(adjust_block))
5.515 -
5.516 - # Check for a class as the context.
5.517 - # Not a class as context => preserve the context and continue.
5.518 -
5.519 - self.new_op(temp)
5.520 - self.new_op(CheckClassContext())
5.521 - self.new_op(JumpIfFalse(check_block))
5.522 -
5.523 - # Check the context's compatibility with the first parameter.
5.524 - # Compatible class => remove the context and continue.
5.525 - # NOTE: Handle insufficient arguments.
5.526 -
5.527 - self.new_op(LoadName(Attr(1, None, None)))
5.528 - self.new_op(CheckSelf())
5.529 - self.optimiser.set_source(temp)
5.530 - self.new_op(JumpIfTrue(adjust_block))
5.531 -
5.532 - # Incompatible class => type error.
5.533 -
5.534 - self.make_exception("TypeError", node)
5.535 - self.new_op(StoreException())
5.536 - self.new_op(RaiseException())
5.537 -
5.538 - # Remove the context from the parameters.
5.539 -
5.540 - self.set_block(adjust_block)
5.541 - self.new_op(AdjustFrame(1))
5.542 -
5.543 def _visitName(self, node, classes):
5.544
5.545 """
6.1 --- a/rsvp.py Mon Jun 01 02:41:57 2009 +0200
6.2 +++ b/rsvp.py Mon Jun 01 21:10:47 2009 +0200
6.3 @@ -387,7 +387,7 @@
6.4 self.value = self.operand, self.operand
6.5
6.6 def LoadFunction(self):
6.7 - self.value = None, self.operand # context of constant is not interesting
6.8 + self.value = None, self.operand
6.9
6.10 def LoadName(self):
6.11 frame = self.local_sp_stack[-1]
6.12 @@ -523,7 +523,7 @@
6.13 # NOTE: Need to ensure correct positioning where a context has been generated.
6.14 param_index, offset = element
6.15 if param_index == self.operand:
6.16 - self.frame_stack[frame + offset + 1] = self.source # add 1 to skip the context always generated
6.17 + self.frame_stack[frame + offset] = self.source
6.18 else:
6.19 self.exception = self._MakeObject(2, self.type_error_instance)
6.20 return self.RaiseException()
6.21 @@ -548,16 +548,16 @@
6.22 def CheckContext(self):
6.23 self.status = self.value[1] is not None
6.24
6.25 - def CheckClassContext(self):
6.26 - context_context, context_ref = self.value
6.27 - context_data = self.load(context_ref)
6.28 + def CheckClass(self):
6.29 + context, ref = self.value
6.30 + data = self.load(ref)
6.31
6.32 # Classes are not themselves usable as the self argument.
6.33 # NOTE: This may change at some point.
6.34 # However, where classes appear as the context, instance
6.35 # compatibility is required in the first argument.
6.36
6.37 - self.status = context_data.attrcode is None # absent attrcode == class
6.38 + self.status = data.attrcode is None # absent attrcode == class
6.39
6.40 def CheckFrame(self):
6.41 (nargs, ndefaults, has_star) = self.operand
6.42 @@ -568,8 +568,11 @@
6.43 frame = self.local_sp_stack[-1]
6.44 nlocals = len(self.frame_stack[frame:])
6.45
6.46 - if not ((nargs - ndefaults) <= nlocals and (nlocals <= nargs or has_star)):
6.47 - #raise Exception, "CheckFrame %r (%r <= %r <= %r)" % (self.operand, nargs - ndefaults, nlocals, nargs)
6.48 + # NOTE: Not testing (nlocals <= nargs or has_star) due to imprecise
6.49 + # NOTE: invocation frame removal (after frame adjustment).
6.50 +
6.51 + if not ((nargs - ndefaults) <= nlocals):
6.52 + raise Exception, "CheckFrame %r (%r <= %r <= %r)" % (self.operand, nargs - ndefaults, nlocals, nargs)
6.53 self.exception = self._MakeObject(2, self.type_error_instance)
6.54 return self.RaiseException()
6.55
6.56 @@ -596,11 +599,11 @@
6.57
6.58 def CheckSelf(self):
6.59 context, ref = self.value
6.60 - target_context, target_ref = self.source
6.61 + context_context, context_ref = self.source
6.62
6.63 # Check the details of the proposed context and the target's context.
6.64
6.65 - self.status = self._CheckInstance(ref, target_context)
6.66 + self.status = self._CheckInstance(ref, context_ref)
6.67
6.68 def JumpInFrame(self):
6.69 codeaddr = self.callable
6.70 @@ -620,7 +623,7 @@
6.71 self.frame_stack.extend([None] * self.operand)
6.72
6.73 def AdjustFrame(self):
6.74 - self.local_sp_stack[-1] += self.operand
6.75 + self.invocation_sp_stack[-1] += self.operand
6.76
6.77 def Return(self):
6.78 return self.pull_pc()
7.1 --- a/tests/attributes_instance_bind_initialiser.py Mon Jun 01 02:41:57 2009 +0200
7.2 +++ b/tests/attributes_instance_bind_initialiser.py Mon Jun 01 21:10:47 2009 +0200
7.3 @@ -8,7 +8,6 @@
7.4 c1 = B
7.5 def __init__(self, b):
7.6 self.c2 = B
7.7 - self.c3 = b
7.8
7.9 b = B(789)
7.10 a = A(b)
8.1 --- a/tests/cond_if.py Mon Jun 01 02:41:57 2009 +0200
8.2 +++ b/tests/cond_if.py Mon Jun 01 21:10:47 2009 +0200
8.3 @@ -1,11 +1,12 @@
8.4 #!/usr/bin/env python
8.5
8.6 a = 1
8.7 +
8.8 if a:
8.9 b = 1
8.10 else:
8.11 b = 2
8.12 -a
8.13 -b
8.14 +
8.15 +result_1 = b
8.16
8.17 # vim: tabstop=4 expandtab shiftwidth=4
9.1 --- a/tests/lambda.py Mon Jun 01 02:41:57 2009 +0200
9.2 +++ b/tests/lambda.py Mon Jun 01 21:10:47 2009 +0200
9.3 @@ -1,18 +1,11 @@
9.4 #!/usr/bin/env python
9.5
9.6 -identity = lambda x: x
9.7 -add_2 = lambda a, b=2: a + b
9.8 -
9.9 def f(c):
9.10 return lambda a, b=c: a + b
9.11
9.12 def g(f, x):
9.13 return f(x)
9.14
9.15 -result_1 = identity(1)
9.16 -result_3 = add_2(1)
9.17 -result2_1 = g(identity, 1)
9.18 -result2_3 = g(add_2, 1)
9.19 result_4 = g(f(3), 1)
9.20
9.21 # vim: tabstop=4 expandtab shiftwidth=4
10.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
10.2 +++ b/tests/lambda_defaults.py Mon Jun 01 21:10:47 2009 +0200
10.3 @@ -0,0 +1,11 @@
10.4 +#!/usr/bin/env python
10.5 +
10.6 +add_2 = lambda a, b=2: a + b
10.7 +
10.8 +def g(f, x):
10.9 + return f(x)
10.10 +
10.11 +result_3 = add_2(1)
10.12 +result2_3 = g(add_2, 1)
10.13 +
10.14 +# vim: tabstop=4 expandtab shiftwidth=4
11.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
11.2 +++ b/tests/lambda_simple.py Mon Jun 01 21:10:47 2009 +0200
11.3 @@ -0,0 +1,11 @@
11.4 +#!/usr/bin/env python
11.5 +
11.6 +identity = lambda x: x
11.7 +
11.8 +def g(f, x):
11.9 + return f(x)
11.10 +
11.11 +result_1 = identity(1)
11.12 +result2_1 = g(identity, 1)
11.13 +
11.14 +# vim: tabstop=4 expandtab shiftwidth=4