1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
1.2 +++ b/micropython/trans.py Sun Apr 05 03:05:59 2009 +0200
1.3 @@ -0,0 +1,1148 @@
1.4 +#!/usr/bin/env python
1.5 +
1.6 +"""
1.7 +Translate the AST of a Python program into a more interpretable representation.
1.8 +
1.9 +Copyright (C) 2007, 2008, 2009 Paul Boddie <paul@boddie.org.uk>
1.10 +
1.11 +This program is free software; you can redistribute it and/or modify it under
1.12 +the terms of the GNU General Public License as published by the Free Software
1.13 +Foundation; either version 3 of the License, or (at your option) any later
1.14 +version.
1.15 +
1.16 +This program is distributed in the hope that it will be useful, but WITHOUT
1.17 +ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
1.18 +FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
1.19 +details.
1.20 +
1.21 +You should have received a copy of the GNU General Public License along with
1.22 +this program. If not, see <http://www.gnu.org/licenses/>.
1.23 +"""
1.24 +
1.25 +from micropython.common import *
1.26 +from micropython.data import *
1.27 +from micropython.rsvp import *
1.28 +import compiler.ast
1.29 +
1.30 +class Helper:
1.31 +
1.32 + "Internal helper methods for AST visitors."
1.33 +
1.34 + # Allocation-related methods.
1.35 +
1.36 + def make_object(self, cls, n):
1.37 +
1.38 + """
1.39 + Request a new object with the given class 'cls' and with 'n' attributes.
1.40 + """
1.41 +
1.42 + # Load the class in order to locate the instance template.
1.43 +
1.44 + self.new_op(LoadConst(cls))
1.45 +
1.46 + # NOTE: Object headers are one location.
1.47 +
1.48 + self.new_op(MakeObject(n + 1))
1.49 +
1.50 + # Name-related methods.
1.51 +
1.52 + def get_scope(self, name):
1.53 +
1.54 + "Return the scope for the given 'name'."
1.55 +
1.56 + if self.unit.has_key(name):
1.57 + return "local"
1.58 + elif self.module.has_key(name):
1.59 + return "global"
1.60 + else:
1.61 + return "builtins"
1.62 +
1.63 + def load_builtin(self, name, node):
1.64 +
1.65 + "Generate an instruction loading 'name' for the given 'node'."
1.66 +
1.67 + self.new_op(LoadAddress(self.get_builtin(name, node)))
1.68 +
1.69 + def get_builtin_class(self, name, node):
1.70 +
1.71 + "Return the built-in class with the given 'name' for the given 'node'."
1.72 +
1.73 + return self.get_builtin(name, node).get_value()
1.74 +
1.75 + def get_builtin(self, name, node):
1.76 +
1.77 + """
1.78 + Return the built-in module definition for the given 'name', used by the
1.79 + given 'node'.
1.80 + """
1.81 +
1.82 + if self.builtins is not None:
1.83 + try:
1.84 + return self.builtins[name]
1.85 + except KeyError:
1.86 + raise TranslateError(self.module.full_name(), node, "No __builtins__ definition is available for name %r." % name)
1.87 + else:
1.88 + raise TranslateError(self.module.full_name(), node, "No __builtins__ module is available for name %r." % name)
1.89 +
1.90 + # Code feature methods.
1.91 +
1.92 + def new_block(self):
1.93 +
1.94 + "Return a new code block."
1.95 +
1.96 + return Block()
1.97 +
1.98 + def set_block(self, block):
1.99 +
1.100 + "Add the given 'block' to the unit's list of blocks."
1.101 +
1.102 + self.optimiser.reset()
1.103 + self.blocks.append(block)
1.104 +
1.105 + def get_loop_blocks(self):
1.106 + return self.loop_blocks[-1]
1.107 +
1.108 + def add_loop_blocks(self, next_block, exit_block):
1.109 + self.loop_blocks.append((next_block, exit_block))
1.110 +
1.111 + def drop_loop_blocks(self):
1.112 + self.loop_blocks.pop()
1.113 +
1.114 + def get_exception_blocks(self):
1.115 + return self.exception_blocks[-1]
1.116 +
1.117 + def add_exception_blocks(self, handler_block, exit_block):
1.118 + self.exception_blocks.append((handler_block, exit_block))
1.119 +
1.120 + def drop_exception_blocks(self):
1.121 + self.exception_blocks.pop()
1.122 +
1.123 + # Assignment expression values.
1.124 +
1.125 + def record_value(self, immediate=1):
1.126 +
1.127 + """
1.128 + Record the current active value for an assignment. If the optional
1.129 + 'immediate' parameter if set to a false value always allocates new
1.130 + temporary storage to hold the recorded value; otherwise, the
1.131 + value-providing instruction may be replicated in order to provide the
1.132 + active value later on.
1.133 + """
1.134 +
1.135 + if immediate:
1.136 + temp = self.optimiser.optimise_temp_storage()
1.137 + else:
1.138 + temp = self.get_temp()
1.139 + self.expr_temp.append(temp)
1.140 +
1.141 + def discard_value(self):
1.142 +
1.143 + "Discard any temporary storage in use for the current assignment value."
1.144 +
1.145 + self.discard_temp(self.expr_temp.pop())
1.146 +
1.147 + def set_source(self):
1.148 +
1.149 + "Set the source of an assignment using the current assignment value."
1.150 +
1.151 + self.optimiser.set_source(self.expr_temp[-1])
1.152 +
1.153 + # Optimise away constant storage if appropriate.
1.154 +
1.155 + if self.optimiser.optimise_constant_storage():
1.156 + self.remove_op()
1.157 +
1.158 + def is_immediate_user(self, node):
1.159 +
1.160 + """
1.161 + Return whether 'node' is an immediate user of an assignment expression.
1.162 + """
1.163 +
1.164 + return isinstance(node, (compiler.ast.AssName, compiler.ast.AssAttr))
1.165 +
1.166 + def has_immediate_usage(self, nodes):
1.167 +
1.168 + """
1.169 + Return whether 'nodes' are all immediate users of an assignment expression.
1.170 + """
1.171 +
1.172 + for n in nodes:
1.173 + if not self.is_immediate_user(n):
1.174 + return 0
1.175 + return 1
1.176 +
1.177 + # Temporary storage administration.
1.178 +
1.179 + def get_temp(self):
1.180 +
1.181 + """
1.182 + Add a temporary storage instruction for the current value and return a
1.183 + sequence of access instructions.
1.184 + """
1.185 +
1.186 + position_in_frame = self.reserve_temp()
1.187 + self.new_op(StoreTemp(position_in_frame))
1.188 + return LoadTemp(position_in_frame)
1.189 +
1.190 + def reserve_temp(self, temp_position=None):
1.191 +
1.192 + """
1.193 + Reserve a new temporary storage position, or if the optional
1.194 + 'temp_position' is specified, ensure that this particular position is
1.195 + reserved.
1.196 + """
1.197 +
1.198 + if temp_position is not None:
1.199 + pass
1.200 + elif not self.temp_positions:
1.201 + temp_position = 0
1.202 + else:
1.203 + temp_position = max(self.temp_positions) + 1
1.204 + self.temp_positions.add(temp_position)
1.205 + self.max_temp_position = max(self.max_temp_position, temp_position)
1.206 + return self.unit.all_local_usage + temp_position # position in frame
1.207 +
1.208 + def ensure_temp(self, instruction=None):
1.209 +
1.210 + """
1.211 + Ensure that the 'instruction' is using a reserved temporary storage
1.212 + position.
1.213 + """
1.214 +
1.215 + if isinstance(instruction, LoadTemp):
1.216 + temp_position = instruction.attr - self.unit.all_local_usage
1.217 + self.reserve_temp(temp_position)
1.218 +
1.219 + def discard_temp(self, instruction=None):
1.220 +
1.221 + "Discard any temporary storage position used by 'instruction'."
1.222 +
1.223 + if isinstance(instruction, LoadTemp):
1.224 + temp_position = instruction.attr - self.unit.all_local_usage
1.225 + self.free_temp(temp_position)
1.226 +
1.227 + def free_temp(self, temp_position):
1.228 +
1.229 + "Free the temporary storage position specified by 'temp_position'."
1.230 +
1.231 + if temp_position in self.temp_positions:
1.232 + self.temp_positions.remove(temp_position)
1.233 +
1.234 + def set_frame_usage(self, node, extend):
1.235 +
1.236 + """
1.237 + Ensure that the frame usage for the unit associated with 'node' is set
1.238 + on the 'extend' instruction.
1.239 + """
1.240 +
1.241 + ntemp = self.max_temp_position + 1
1.242 + extend.attr = ntemp + node.unit.local_usage # NOTE: See get_code for similar code.
1.243 +
1.244 + # Code writing methods.
1.245 +
1.246 + def new_op(self, op):
1.247 +
1.248 + "Add 'op' to the generated code."
1.249 +
1.250 + # Optimise load operations employed by this instruction.
1.251 +
1.252 + self.optimiser.optimise_load_operations(op)
1.253 + if self.optimiser.optimise_away_no_operations(op):
1.254 + return
1.255 +
1.256 + # Add the operation to the current block.
1.257 +
1.258 + self.blocks[-1].code.append(op)
1.259 + self.optimiser.set_new(op)
1.260 +
1.261 + def remove_op(self):
1.262 +
1.263 + "Remove the last instruction."
1.264 +
1.265 + op = self.blocks[-1].code.pop()
1.266 + self.optimiser.clear_active()
1.267 +
1.268 + def replace_op(self, op):
1.269 +
1.270 + "Replace the last added instruction with 'op'."
1.271 +
1.272 + self.remove_op()
1.273 + self.new_op(op)
1.274 +
1.275 + def replace_active_value(self, op):
1.276 +
1.277 + """
1.278 + Replace the value-providing active instruction with 'op' if appropriate.
1.279 + """
1.280 +
1.281 + self.optimiser.remove_active_value()
1.282 + self.new_op(op)
1.283 +
1.284 + def last_op(self):
1.285 +
1.286 + "Return the last added instruction."
1.287 +
1.288 + try:
1.289 + return self.blocks[-1].code[-1]
1.290 + except IndexError:
1.291 + return None
1.292 +
1.293 + # Common methods.
1.294 +
1.295 + def _visitAttr(self, node, classes):
1.296 +
1.297 + """
1.298 + Visit the attribute-related 'node', generating instructions based on the
1.299 + given 'classes'.
1.300 + """
1.301 +
1.302 + self.dispatch(node.expr)
1.303 + self._generateAttr(node, node.attrname, classes)
1.304 +
1.305 + def _generateAttr(self, node, attrname, classes):
1.306 +
1.307 + """
1.308 + Generate code for the access to 'attrname' using the given 'classes'.
1.309 + """
1.310 +
1.311 + AddressInstruction, AddressContextInstruction, AddressContextCondInstruction, \
1.312 + AttrInstruction, AttrIndexInstruction, AttrIndexContextInstruction, \
1.313 + AttrIndexContextCondInstruction = classes
1.314 +
1.315 + # Where the last operation (defining the attribute owner) yields a
1.316 + # constant...
1.317 +
1.318 + target_name = self.optimiser.optimise_constant_accessor()
1.319 +
1.320 + # Only try and discover the position if the target can be resolved.
1.321 + # Since instances cannot be constants, this involves classes and
1.322 + # modules.
1.323 +
1.324 + if target_name is not None:
1.325 +
1.326 + # Access the object table to get the attribute position.
1.327 +
1.328 + try:
1.329 + table_entry = self.objtable.table[target_name]
1.330 + except KeyError:
1.331 + raise TranslateError(self.module.full_name(), node,
1.332 + "No object entry exists for target %r." % target_name)
1.333 +
1.334 + try:
1.335 + pos = table_entry[attrname]
1.336 + except KeyError:
1.337 + raise TranslateError(self.module.full_name(), node,
1.338 + "No attribute entry exists for name %r in target %r." % (attrname, target_name))
1.339 +
1.340 + # Produce a suitable instruction.
1.341 +
1.342 + if AddressInstruction is not None:
1.343 + self.replace_active_value(AddressInstruction(pos))
1.344 + else:
1.345 + raise TranslateError(self.module.full_name(), node,
1.346 + "Storing of class or module attribute %r via an object is not permitted." % attrname)
1.347 +
1.348 + return
1.349 +
1.350 + # Where the last operation involves the special 'self' name, check to
1.351 + # see if the attribute is acceptably positioned and produce a direct
1.352 + # access to the attribute.
1.353 +
1.354 + # This is the only reliable way of detecting instance accesses at
1.355 + # compile-time since in general, objects could be classes or modules,
1.356 + # but 'self' should only refer to instances.
1.357 +
1.358 + elif self.optimiser.optimise_self_access(self.unit, attrname):
1.359 +
1.360 + # Either generate an instruction operating on an instance attribute.
1.361 +
1.362 + try:
1.363 + attr = self.unit.parent.instance_attributes()[attrname]
1.364 + self.new_op(AttrInstruction(attr))
1.365 + return
1.366 +
1.367 + # Or generate an instruction operating on a class attribute.
1.368 + # NOTE: Any simple instruction providing self is not removed.
1.369 +
1.370 + except KeyError:
1.371 +
1.372 + try:
1.373 + attr = self.unit.parent.all_attributes()[attrname]
1.374 +
1.375 + # Switch the context if the class attribute is compatible with
1.376 + # the instance.
1.377 +
1.378 + if attr.defined_within_hierarchy():
1.379 +
1.380 + # Only permit loading (not storing) of class attributes via self.
1.381 +
1.382 + if AddressContextInstruction is not None:
1.383 + self.new_op(AddressContextInstruction(attr))
1.384 + else:
1.385 + raise TranslateError(self.module.full_name(), node,
1.386 + "Storing of class attribute %r via self not permitted." % attrname)
1.387 +
1.388 + # Preserve the context if the class attribute comes from an
1.389 + # incompatible class.
1.390 +
1.391 + elif attr.defined_outside_hierarchy():
1.392 +
1.393 + # Only permit loading (not storing) of class attributes via self.
1.394 +
1.395 + if AddressInstruction is not None:
1.396 + self.new_op(AddressInstruction(attr))
1.397 + else:
1.398 + raise TranslateError(self.module.full_name(), node,
1.399 + "Storing of class attribute %r via self not permitted." % attrname)
1.400 +
1.401 + # Otherwise, test for a suitable context at run-time.
1.402 +
1.403 + else:
1.404 +
1.405 + # Only permit loading (not storing) of class attributes via self.
1.406 +
1.407 + if AddressContextCondInstruction is not None:
1.408 + self.new_op(AddressContextCondInstruction(attr))
1.409 + else:
1.410 + raise TranslateError(self.module.full_name(), node,
1.411 + "Storing of class attribute %r via self not permitted." % attrname)
1.412 +
1.413 + return
1.414 +
1.415 + # Or delegate the attribute access to a general instruction
1.416 + # since the kind of attribute cannot be deduced.
1.417 +
1.418 + except KeyError:
1.419 + pass
1.420 +
1.421 + # Otherwise, perform a normal operation.
1.422 +
1.423 + try:
1.424 + index = self.objtable.get_index(attrname)
1.425 +
1.426 + except self.objtable.TableError:
1.427 +
1.428 + # If this error arises on generated code, check the names_used
1.429 + # attribute on the Importer.
1.430 +
1.431 + raise TranslateError(self.module.full_name(), node,
1.432 + "No attribute entry exists for name %r." % attrname)
1.433 +
1.434 + # NOTE: Test for class vs. instance attributes, generating
1.435 + # NOTE: context-related instructions.
1.436 +
1.437 + if AttrIndexContextCondInstruction is not None:
1.438 + self.new_op(AttrIndexContextCondInstruction(index))
1.439 +
1.440 + # Store instructions do not need to consider context modifications.
1.441 +
1.442 + else:
1.443 + self.new_op(AttrIndexInstruction(index))
1.444 +
1.445 + # Invocations involve the following:
1.446 + #
1.447 + # 1. Reservation of a frame for the arguments
1.448 + # 2. Identification of the target which is then held in temporary storage
1.449 + # 3. Optional inclusion of a context (important for methods)
1.450 + # 4. Preparation of the argument frame
1.451 + # 5. Invocation of the target
1.452 + # 6. Discarding of the frame
1.453 + #
1.454 + # In order to support nested invocations - such as a(b(c)) - use of the
1.455 + # temporary storage is essential.
1.456 +
1.457 + def _startCallFunc(self):
1.458 +
1.459 + "Record the location of the invocation."
1.460 +
1.461 + op = MakeFrame()
1.462 + self.new_op(op) # records the start of the frame
1.463 + self.frame_makers.append(op)
1.464 +
1.465 + def _generateCallFunc(self, args, node):
1.466 +
1.467 + """
1.468 + Support a generic function invocation using the given 'args', occurring
1.469 + on the given 'node', where the expression providing the invocation
1.470 + target has just been generated.
1.471 +
1.472 + In other situations, the invocation is much simpler and does not need to
1.473 + handle the full flexibility of a typical Python invocation. Internal
1.474 + invocations, such as those employed by operators and certain
1.475 + control-flow mechanisms, use predetermined arguments and arguably do not
1.476 + need to support the same things as the more general invocations.
1.477 + """
1.478 +
1.479 + target, context, temp = self._generateCallFuncContext()
1.480 + self._generateCallFuncArgs(target, context, temp, args, node)
1.481 + return temp, target
1.482 +
1.483 + def _generateCallFuncContext(self):
1.484 +
1.485 + """
1.486 + Produce code which loads and checks the context of the current
1.487 + invocation, the instructions for whose target have already been
1.488 + produced, returning a list of instructions which reference the
1.489 + invocation target.
1.490 + """
1.491 +
1.492 + t = self.optimiser.optimise_known_target()
1.493 + if t:
1.494 + target, context = t
1.495 + if isinstance(target, Instance): # lambda object
1.496 + target, context = None, None
1.497 + else:
1.498 + target, context = None, None
1.499 +
1.500 + # Store the target in temporary storage for subsequent referencing.
1.501 + # NOTE: This may not be appropriate for class invocations
1.502 + # NOTE: (instantiation).
1.503 +
1.504 + temp = self.optimiser.optimise_temp_storage()
1.505 +
1.506 + # Where a target or context are not known or where an instance is known
1.507 + # to be the context, load the context.
1.508 +
1.509 + if target is None or isinstance(context, Instance):
1.510 + self.new_op(temp)
1.511 + self.new_op(LoadContext())
1.512 + self.new_op(StoreFrame(0))
1.513 +
1.514 + # For known instantiations, provide a new object as the first argument
1.515 + # to the __init__ method.
1.516 +
1.517 + elif isinstance(target, Class):
1.518 + self.make_object(target, len(target.instance_attributes()))
1.519 + self.new_op(StoreFrame(0))
1.520 +
1.521 + # Otherwise omit the context.
1.522 +
1.523 + else:
1.524 + pass # NOTE: Class methods should be supported.
1.525 +
1.526 + return target, context, temp
1.527 +
1.528 + def _generateCallFuncArgs(self, target, context, temp, args, node):
1.529 +
1.530 + """
1.531 + Given invocation 'target' and 'context' information, the 'temp'
1.532 + reference to the target, a list of nodes representing the 'args'
1.533 + (arguments), generate instructions which load the arguments for the
1.534 + invocation defined by the given 'node'.
1.535 + """
1.536 +
1.537 + # Evaluate the arguments.
1.538 +
1.539 + employed_positions = set()
1.540 + employed_keywords = set()
1.541 + extra_keywords = []
1.542 +
1.543 + # Find keyword arguments in advance in order to help resolve targets.
1.544 +
1.545 + for arg in args:
1.546 + if isinstance(arg, compiler.ast.Keyword):
1.547 + employed_keywords.add(arg.name)
1.548 +
1.549 + possible_targets = self.paramtable.all_possible_objects(employed_keywords)
1.550 +
1.551 + # Note the presence of the context in the frame where appropriate.
1.552 +
1.553 + if target is None or isinstance(context, Instance):
1.554 + ncontext = 1
1.555 + expect_context = 0
1.556 +
1.557 + # Handle calls to classes.
1.558 +
1.559 + elif isinstance(target, Class):
1.560 + ncontext = 1
1.561 + expect_context = 0
1.562 + target = target.get_init_method()
1.563 +
1.564 + # Method calls via classes.
1.565 +
1.566 + elif isinstance(context, Class):
1.567 + ncontext = 0
1.568 + expect_context = 1
1.569 +
1.570 + # Function calls.
1.571 +
1.572 + else:
1.573 + ncontext = 0
1.574 + expect_context = 0
1.575 +
1.576 + first = 1
1.577 + frame_pos = ncontext
1.578 + max_keyword_pos = -1
1.579 +
1.580 + for arg in args:
1.581 +
1.582 + # Handle positional and keyword arguments separately.
1.583 +
1.584 + if isinstance(arg, compiler.ast.Keyword):
1.585 +
1.586 + # Optimise where the target is known now.
1.587 +
1.588 + if target is not None:
1.589 +
1.590 + # Find the parameter table entry for the target.
1.591 +
1.592 + target_name = target.full_name()
1.593 +
1.594 + # Look for a callable with the precise target name.
1.595 +
1.596 + table_entry = self.paramtable.table[target_name]
1.597 +
1.598 + # Look the name up in the parameter table entry.
1.599 +
1.600 + try:
1.601 + pos = table_entry[arg.name]
1.602 +
1.603 + # Where no position is found, this could be an extra keyword
1.604 + # argument.
1.605 +
1.606 + except KeyError:
1.607 + extra_keywords.append(arg)
1.608 + continue
1.609 +
1.610 + # Test for illegal conditions.
1.611 +
1.612 + if pos in employed_positions:
1.613 + raise TranslateError(self.module.full_name(), node,
1.614 + "Keyword argument %r overwrites parameter %r." % (arg.name, pos))
1.615 +
1.616 + employed_positions.add(pos)
1.617 +
1.618 + # Generate code for the keyword and the positioning
1.619 + # operation.
1.620 +
1.621 + self.dispatch(arg.expr)
1.622 + self.new_op(StoreFrame(pos))
1.623 +
1.624 + # Otherwise, generate the code needed to obtain the details of
1.625 + # the parameter location.
1.626 +
1.627 + else:
1.628 +
1.629 + # Combine the target details with the name to get the location.
1.630 + # See the access method on the List class.
1.631 +
1.632 + try:
1.633 + paramindex = self.paramtable.get_index(arg.name)
1.634 +
1.635 + # Where no position is found, this could be an extra keyword
1.636 + # argument.
1.637 +
1.638 + except self.paramtable.TableError:
1.639 + extra_keywords.append(arg)
1.640 + continue
1.641 +
1.642 + # Generate code for the keyword and the positioning
1.643 + # operation. Get the value as the source of the assignment.
1.644 +
1.645 + self.dispatch(arg.expr)
1.646 + self.record_value()
1.647 +
1.648 + # Store the source value using the callable's parameter
1.649 + # table information.
1.650 +
1.651 + self.new_op(temp)
1.652 + self.new_op(StoreFrameIndex(paramindex))
1.653 +
1.654 + self.set_source()
1.655 + self.discard_value()
1.656 +
1.657 + # Record the highest possible frame position for this argument.
1.658 +
1.659 + max_keyword_pos = max(max_keyword_pos, max(self.paramtable.all_attribute_positions(arg.name)))
1.660 +
1.661 + else:
1.662 + self.dispatch(arg)
1.663 + self.new_op(StoreFrame(frame_pos))
1.664 +
1.665 + employed_positions.add(frame_pos)
1.666 +
1.667 + # Check to see if the first argument is appropriate (compatible with
1.668 + # the target where methods are being invoked via classes).
1.669 +
1.670 + if first and expect_context:
1.671 +
1.672 + # Drop any test if the target and the context are known.
1.673 +
1.674 + if not self.optimiser.have_correct_self_for_target(context, self.unit):
1.675 +
1.676 + continue_block = self.new_block()
1.677 +
1.678 + self.new_op(CheckSelf())
1.679 + self.optimiser.set_source(temp)
1.680 + self.new_op(JumpIfTrue(continue_block))
1.681 +
1.682 + # Where the context is inappropriate, drop the incomplete frame and
1.683 + # raise an exception.
1.684 +
1.685 + self.new_op(DropFrame())
1.686 + self.new_op(LoadResult())
1.687 +
1.688 + self.load_builtin("TypeError", node)
1.689 + self.new_op(StoreException())
1.690 + self.new_op(RaiseException())
1.691 +
1.692 + self.set_block(continue_block)
1.693 +
1.694 + first = 0
1.695 + frame_pos += 1
1.696 +
1.697 + # NOTE: Extra keywords are not supported.
1.698 + # NOTE: Somehow, the above needs to be combined with * arguments.
1.699 +
1.700 + if extra_keywords:
1.701 + print "Warning: extra keyword argument(s) %s not handled." % ", ".join([arg.name for arg in extra_keywords])
1.702 +
1.703 + # Either test for a complete set of arguments.
1.704 +
1.705 + if target is not None:
1.706 +
1.707 + # Make sure that enough arguments have been given.
1.708 +
1.709 + nargs_max = len(target.positional_names)
1.710 + ndefaults = len(target.defaults)
1.711 + nargs_min = nargs_max - ndefaults
1.712 +
1.713 + for i in range(ncontext, nargs_min):
1.714 + if i not in employed_positions:
1.715 + raise TranslateError(self.module.full_name(), node,
1.716 + "Argument %r not supplied for %r: need at least %d argument(s)." % (i+1, target.name, nargs_min))
1.717 +
1.718 + nargs = frame_pos
1.719 +
1.720 + if nargs > nargs_max and not target.has_star and not target.has_dstar:
1.721 + raise TranslateError(self.module.full_name(), node,
1.722 + "Too many arguments for %r: need at most %d argument(s)." % (target.name, nargs_max))
1.723 +
1.724 + # Where defaults are involved, put them into the frame.
1.725 +
1.726 + self._generateCallFuncDefaultArgs(target, temp, nargs_min, nargs_max, employed_positions)
1.727 +
1.728 + # Set the frame size.
1.729 +
1.730 + self._endCallFuncArgs(nargs_max)
1.731 +
1.732 + # Or generate instructions to do this at run-time.
1.733 +
1.734 + else:
1.735 + max_pos = max(max(employed_positions or [-1]), max_keyword_pos, frame_pos - 1)
1.736 +
1.737 + # Only check non-empty frames (using the callable's details).
1.738 +
1.739 + if employed_positions or max_pos >= 0:
1.740 + self.new_op(temp)
1.741 + self.new_op(CheckFrame(max_pos + 1))
1.742 +
1.743 + # Set the frame size.
1.744 +
1.745 + self._endCallFuncArgs(max_pos + 1)
1.746 +
1.747 + def _generateCallFuncDefaultArgs(self, target, temp, nargs_min, nargs_max, employed_positions):
1.748 +
1.749 + """
1.750 + For the given 'target' and 'temp' reference to the target, generate
1.751 + default arguments for those positions in the range 'nargs_min'...
1.752 + 'nargs_max' which are not present in the 'employed_positions'
1.753 + collection.
1.754 + """
1.755 +
1.756 + # Where a lambda is involved, construct a dynamic object to hold the
1.757 + # defaults.
1.758 +
1.759 + dynamic = target.name is None
1.760 +
1.761 + # Here, we use negative index values to visit the right hand end of
1.762 + # the defaults list.
1.763 +
1.764 + for pos in range(nargs_min, nargs_max):
1.765 + if pos not in employed_positions:
1.766 + if dynamic:
1.767 + self.new_op(temp)
1.768 + self.new_op(LoadAttr(target.default_attrs[pos - nargs_min]))
1.769 + else:
1.770 + self.new_op(LoadAddress(target.default_attrs[pos - nargs_min]))
1.771 + self.new_op(StoreFrame(pos))
1.772 +
1.773 + def _doCallFunc(self, instruction, target=None):
1.774 +
1.775 + "Make the invocation."
1.776 +
1.777 + if isinstance(target, Class):
1.778 + self.new_op(LoadConst(target.get_init_method()))
1.779 + else:
1.780 + self.new_op(instruction)
1.781 + self.new_op(LoadCallable())
1.782 + self.new_op(JumpWithFrame())
1.783 +
1.784 + def _endCallFuncArgs(self, nargs):
1.785 +
1.786 + "Set the frame size."
1.787 +
1.788 + self.frame_makers[-1].attr = nargs
1.789 + self.frame_makers.pop()
1.790 +
1.791 + def _endCallFunc(self, instruction=None, target=None, load_result=1):
1.792 +
1.793 + "Finish the invocation and tidy up afterwards."
1.794 +
1.795 + if isinstance(target, Class):
1.796 + self.new_op(LoadName(target.get_init_method().all_locals()["self"])) # load the context in the invocation frame
1.797 + self.new_op(StoreResult())
1.798 + self.new_op(DropFrame())
1.799 + if load_result:
1.800 + self.new_op(LoadResult())
1.801 +
1.802 + # Discard any temporary storage instructions.
1.803 +
1.804 + if instruction is not None:
1.805 + self.discard_temp(instruction)
1.806 +
1.807 + def _generateFunctionDefaults(self, function):
1.808 +
1.809 + """
1.810 + Generate the default initialisation code for 'function', returning
1.811 + a temporary storage reference if a dynamic object was created for the
1.812 + function.
1.813 + """
1.814 +
1.815 + attr_to_default = zip(function.default_attrs, function.defaults)
1.816 + if not attr_to_default:
1.817 + return None
1.818 +
1.819 + # Where a lambda is involved, construct a dynamic object to hold the
1.820 + # defaults.
1.821 +
1.822 + dynamic = function.name is None
1.823 +
1.824 + if dynamic:
1.825 + self.make_object(self.get_builtin_class("function", function), len(attr_to_default))
1.826 + temp = self.get_temp()
1.827 +
1.828 + for attr, default in attr_to_default:
1.829 + self.dispatch(default)
1.830 +
1.831 + self.record_value()
1.832 + if dynamic:
1.833 + self.new_op(temp)
1.834 + self.new_op(StoreAttr(attr))
1.835 + else:
1.836 + self.new_op(StoreAddress(attr))
1.837 + self.set_source()
1.838 + self.discard_value()
1.839 +
1.840 + if dynamic:
1.841 + return temp
1.842 + else:
1.843 + return None
1.844 +
1.845 + def _visitName(self, node, classes):
1.846 +
1.847 + """
1.848 + Visit the name-related 'node', generating instructions based on the
1.849 + given 'classes'.
1.850 + """
1.851 +
1.852 + name = node.name
1.853 + scope = self.get_scope(name)
1.854 + #print self.module.name, node.lineno, name, scope
1.855 + self._generateName(name, scope, classes, node)
1.856 +
1.857 + def _generateName(self, name, scope, classes, node):
1.858 +
1.859 + """
1.860 + Generate code for the access to 'name' in 'scope' using the given
1.861 + 'classes', and using the given 'node' as the source of the access.
1.862 + """
1.863 +
1.864 + NameInstruction, AddressInstruction = classes
1.865 +
1.866 + if scope == "local":
1.867 + unit = self.unit
1.868 + if isinstance(unit, Function):
1.869 + self.new_op(NameInstruction(unit.all_locals()[name]))
1.870 + elif isinstance(unit, Class):
1.871 + self.new_op(AddressInstruction(unit.all_class_attributes()[name]))
1.872 + elif isinstance(unit, Module):
1.873 + self.new_op(AddressInstruction(unit.module_attributes()[name]))
1.874 + else:
1.875 + raise TranslateError(self.module.full_name(), node, "Program unit %r has no local %r." % (unit, name))
1.876 +
1.877 + elif scope == "global":
1.878 + globals = self.module.module_attributes()
1.879 + if globals.has_key(name):
1.880 + self.new_op(AddressInstruction(globals[name]))
1.881 + else:
1.882 + raise TranslateError(self.module.full_name(), node, "Module %r has no attribute %r." % (self.module, name))
1.883 +
1.884 + else:
1.885 + self.new_op(AddressInstruction(self.get_builtin(name, node)))
1.886 +
1.887 + def _visitUnary(self, node):
1.888 +
1.889 + """
1.890 + _t = node.expr
1.891 + try:
1.892 + _result = _t.__pos__()
1.893 + except AttributeError:
1.894 + raise TypeError
1.895 + """
1.896 +
1.897 + method = unary_methods[node.__class__.__name__]
1.898 +
1.899 + type_error_block = self.new_block()
1.900 + end_block = self.new_block()
1.901 +
1.902 + # Evaluate and store the operand in temporary storage.
1.903 +
1.904 + self.dispatch(node.expr)
1.905 + temp = self.optimiser.optimise_temp_storage()
1.906 +
1.907 + self.new_op(temp)
1.908 +
1.909 + # Get the method on temp.
1.910 +
1.911 + self._generateAttr(node, method, self.attribute_load_instructions)
1.912 + temp_method = self.optimiser.optimise_temp_storage()
1.913 +
1.914 + self._handleAttributeError(node, type_error_block)
1.915 +
1.916 + # Add arguments.
1.917 + # NOTE: No support for defaults.
1.918 +
1.919 + self._startCallFunc()
1.920 + self.new_op(temp) # Explicit context as first argument.
1.921 + self.new_op(StoreFrame(0))
1.922 + self._endCallFuncArgs(1)
1.923 + self._doCallFunc(temp_method)
1.924 + self._endCallFunc(temp_method)
1.925 + self.new_op(Jump(end_block))
1.926 +
1.927 + # Store the result.
1.928 +
1.929 + temp_out = self.get_temp()
1.930 +
1.931 + # Raise a TypeError.
1.932 +
1.933 + self.set_block(type_error_block)
1.934 + self.load_builtin("TypeError", node)
1.935 + self.new_op(StoreException())
1.936 + self.new_op(RaiseException())
1.937 +
1.938 + self.set_block(end_block)
1.939 +
1.940 + # Produce the result.
1.941 +
1.942 + self.new_op(temp_out)
1.943 +
1.944 + # Compilation duties...
1.945 +
1.946 + self.discard_temp(temp)
1.947 + self.discard_temp(temp_out)
1.948 +
1.949 + def _visitBinary(self, node):
1.950 +
1.951 + """
1.952 + _t1 = node.left
1.953 + _t2 = node.right
1.954 + try:
1.955 + _result = _t1.__add__(_t2)
1.956 + if _result is NotImplemented:
1.957 + raise AttributeError
1.958 + except AttributeError:
1.959 + try:
1.960 + _result = _t2.__radd__(_t1)
1.961 + if _result is NotImplemented:
1.962 + raise AttributeError
1.963 + except AttributeError:
1.964 + raise TypeError
1.965 + """
1.966 +
1.967 + left_method, right_method = binary_methods[node.__class__.__name__]
1.968 +
1.969 + # Evaluate and store the left operand in temporary storage.
1.970 +
1.971 + self.dispatch(node.left)
1.972 + temp1 = self.optimiser.optimise_temp_storage()
1.973 +
1.974 + # Evaluate and store the right operand in temporary storage.
1.975 +
1.976 + self.dispatch(node.right)
1.977 + temp2 = self.optimiser.optimise_temp_storage()
1.978 +
1.979 + temp_out = self._generateBinary(node, temp1, temp2, left_method, right_method)
1.980 +
1.981 + # Produce the result.
1.982 +
1.983 + self.new_op(temp_out)
1.984 +
1.985 + # Compilation duties...
1.986 +
1.987 + self.discard_temp(temp1)
1.988 + self.discard_temp(temp2)
1.989 + self.discard_temp(temp_out)
1.990 +
1.991 + def _generateBinary(self, node, temp1, temp2, left_method, right_method):
1.992 +
1.993 + """
1.994 + For the given 'node', generate the binary operator pattern for the
1.995 + operands 'temp1' and 'temp2', employing 'left_method' and 'right_method'
1.996 + as defined for binary operators, but also used in comparisons (for which
1.997 + this method is provided).
1.998 +
1.999 + A temporary storage reference is returned from this method.
1.1000 + """
1.1001 +
1.1002 + right_block = self.new_block()
1.1003 + type_error_block = self.new_block()
1.1004 + end_block = self.new_block()
1.1005 +
1.1006 + # Left method.
1.1007 +
1.1008 + temp_out = self._generateOpMethod(node, temp1, temp2, left_method, right_block, end_block)
1.1009 + self.discard_temp(temp_out) # NOTE: Will re-use the same storage.
1.1010 +
1.1011 + # Right method.
1.1012 +
1.1013 + self.set_block(right_block)
1.1014 + temp_out = self._generateOpMethod(node, temp2, temp1, right_method, type_error_block, end_block)
1.1015 +
1.1016 + # Raise a TypeError.
1.1017 +
1.1018 + self.set_block(type_error_block)
1.1019 + self.load_builtin("TypeError", node)
1.1020 + self.new_op(StoreException())
1.1021 + self.new_op(RaiseException())
1.1022 +
1.1023 + self.set_block(end_block)
1.1024 + return temp_out
1.1025 +
1.1026 + def _generateOpMethod(self, node, temp1, temp2, method_name, next_method_block, end_block):
1.1027 +
1.1028 + """
1.1029 + For the given 'node', generate the operator method invocation using the
1.1030 + operands 'temp1' and 'temp2', employing the given 'method_name', and
1.1031 + jumping appropriately to 'next_method_block' where a NotImplemented
1.1032 + result is returned, or to 'end_block' if the method call was successful.
1.1033 +
1.1034 + A temporary storage reference is returned from this method.
1.1035 + """
1.1036 +
1.1037 + end_attempt_block = self.new_block()
1.1038 +
1.1039 + self.new_op(temp1)
1.1040 +
1.1041 + # Get method on temp1.
1.1042 +
1.1043 + self._generateAttr(node, method_name, self.attribute_load_instructions)
1.1044 + temp_method = self.optimiser.optimise_temp_storage()
1.1045 +
1.1046 + self._handleAttributeError(node, end_attempt_block)
1.1047 +
1.1048 + # Add arguments.
1.1049 + # NOTE: No support for defaults.
1.1050 +
1.1051 + self._startCallFunc()
1.1052 + self.new_op(temp1)
1.1053 + self.new_op(StoreFrame(0))
1.1054 + self.new_op(temp2)
1.1055 + self.new_op(StoreFrame(1))
1.1056 + self._endCallFuncArgs(2)
1.1057 + self._doCallFunc(temp_method)
1.1058 + self._endCallFunc(temp_method)
1.1059 +
1.1060 + # Store the result.
1.1061 +
1.1062 + temp_out = self.get_temp()
1.1063 +
1.1064 + # Test for NotImplemented.
1.1065 + # Don't actually raise an exception.
1.1066 +
1.1067 + self.new_op(TestIdentityAddress(self.importer.get_predefined_constant("NotImplemented")))
1.1068 + self.new_op(JumpIfTrue(next_method_block))
1.1069 + self.new_op(Jump(end_block))
1.1070 +
1.1071 + # End method attempt.
1.1072 +
1.1073 + self.set_block(end_attempt_block)
1.1074 + return temp_out
1.1075 +
1.1076 + def _handleAttributeError(self, node, end_call_block):
1.1077 +
1.1078 + """
1.1079 + Add exception handling to the method acquisition instructions where the
1.1080 + attribute access cannot be resolved at compile-time.
1.1081 + """
1.1082 +
1.1083 + if not self.optimiser.optimise_known_target():
1.1084 + self.load_builtin("AttributeError", node)
1.1085 + self.new_op(CheckException())
1.1086 + self.new_op(JumpIfTrue(end_call_block))
1.1087 +
1.1088 + def _generateSequence(self, sequence_type, node):
1.1089 +
1.1090 + "Make a sequence of 'sequence_type' for the given program 'node'."
1.1091 +
1.1092 + self.make_object(self.get_builtin_class(sequence_type, node), len(node.nodes))
1.1093 + temp = self.get_temp()
1.1094 +
1.1095 + for i, n in enumerate(node.nodes):
1.1096 + self.dispatch(n)
1.1097 + self.record_value()
1.1098 + self.new_op(temp)
1.1099 + self.new_op(StoreAttr(Attr(i, None, None)))
1.1100 + self.set_source()
1.1101 + self.discard_value()
1.1102 +
1.1103 + self.new_op(temp)
1.1104 + self.discard_temp(temp)
1.1105 +
1.1106 + def _generateTestBoolean(self, node, temp):
1.1107 +
1.1108 + """
1.1109 + Generate a test of the boolean status of the current value for the given
1.1110 + program 'node'.
1.1111 + """
1.1112 +
1.1113 + # Get method on temp.
1.1114 + # NOTE: Using __bool__ instead of __nonzero__.
1.1115 +
1.1116 + self._generateAttr(node, "__bool__", self.attribute_load_instructions)
1.1117 + temp_method = self.optimiser.optimise_temp_storage()
1.1118 +
1.1119 + self._startCallFunc()
1.1120 + self.new_op(temp)
1.1121 + self.new_op(StoreFrame(0))
1.1122 + self._endCallFuncArgs(1)
1.1123 + self._doCallFunc(temp_method)
1.1124 + self._endCallFunc(temp_method)
1.1125 +
1.1126 + self.discard_temp(temp_method)
1.1127 +
1.1128 + # Convert result to boolean (a StoreBoolean operation).
1.1129 +
1.1130 + self.new_op(TestIdentityAddress(self.importer.get_predefined_constant("True")))
1.1131 +
1.1132 + def _generateLoadBoolean(self, node):
1.1133 +
1.1134 + """
1.1135 + Generate instructions to load the appropriate value given the current
1.1136 + boolean status.
1.1137 + """
1.1138 +
1.1139 + true_block = self.new_block()
1.1140 + end_block = self.new_block()
1.1141 +
1.1142 + self.new_op(JumpIfTrue(true_block))
1.1143 + self.new_op(LoadAddress(self.importer.get_predefined_constant("False")))
1.1144 + self.new_op(Jump(end_block))
1.1145 +
1.1146 + self.set_block(true_block)
1.1147 + self.new_op(LoadAddress(self.importer.get_predefined_constant("True")))
1.1148 +
1.1149 + self.set_block(end_block)
1.1150 +
1.1151 +# vim: tabstop=4 expandtab shiftwidth=4