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