1.1 --- a/README.txt Fri Jun 28 21:17:02 2013 +0200
1.2 +++ b/README.txt Sat Jun 29 01:28:12 2013 +0200
1.3 @@ -1,3 +1,6 @@
1.4 +NOTE: This document needs updating for the separation of micropython and
1.5 +NOTE: syspython functionality.
1.6 +
1.7 Introduction
1.8 ------------
1.9
2.1 --- a/micropython/__init__.py Fri Jun 28 21:17:02 2013 +0200
2.2 +++ b/micropython/__init__.py Sat Jun 29 01:28:12 2013 +0200
2.3 @@ -28,10 +28,9 @@
2.4 importer = Importer(sys.path)
2.5
2.6 To generate programs, the above importer should be supplied in the
2.7 -initialisation of a program instance, and then various methods are called:
2.8 +initialisation of a program instance:
2.9
2.10 program = Program(importer)
2.11 -image = program.get_raw_image()
2.12
2.13 Such importer and program objects are the most convenient mechanism through
2.14 which the functionality of the micropython package may be accessed.
2.15 @@ -40,14 +39,9 @@
2.16 from micropython.data import *
2.17 from micropython.errors import *
2.18 from micropython.objectset import ObjectSet
2.19 -from micropython.program import Location
2.20 from micropython.types import *
2.21 -import micropython.ast
2.22 -import micropython.native
2.23 -import micropython.opt
2.24 import micropython.inspect
2.25 import micropython.table
2.26 -import bisect
2.27 import os
2.28 import sys
2.29
2.30 @@ -60,32 +54,20 @@
2.31
2.32 "This class supports the generation of a program image."
2.33
2.34 - supported_optimisations = micropython.opt.Optimiser.supported_optimisations
2.35 -
2.36 - def __init__(self, importer, optimisations=None):
2.37 + def __init__(self, importer):
2.38
2.39 """
2.40 Initialise the program representation with an 'importer' which is able
2.41 to locate and load Python modules.
2.42 -
2.43 - The optional 'optimisations' cause certain techniques to be used in
2.44 - reducing program size and improving program efficiency.
2.45 """
2.46
2.47 self.importer = importer
2.48 - self.optimisations = optimisations or set()
2.49 - self.native = micropython.native.NativeLibrary(self)
2.50
2.51 # Remember the tables once generated.
2.52
2.53 self.objtable = None
2.54 self.paramtable = None
2.55
2.56 - # Main program information.
2.57 -
2.58 - self.code = None
2.59 - self.code_location = None
2.60 -
2.61 # A record of nodes for which no attribute target could be found.
2.62
2.63 self.unknown_target_nodes = []
2.64 @@ -116,166 +98,6 @@
2.65
2.66 self.importer.finalise(objtable)
2.67
2.68 - def get_image(self, with_builtins=0):
2.69 -
2.70 - """
2.71 - Return the program image including built-in objects if 'with_builtins'
2.72 - is specified and set to a true value.
2.73 - """
2.74 -
2.75 - if self.code is not None:
2.76 - return self.code
2.77 -
2.78 - # Optimise and regenerate the object table.
2.79 -
2.80 - self.finalise()
2.81 - self.code = []
2.82 -
2.83 - # Append constants to the image.
2.84 -
2.85 - for const in self.importer.constants():
2.86 - self.code.append(const)
2.87 -
2.88 - # Generate each module.
2.89 -
2.90 - last_module = self.importer.modules_ordered[-1]
2.91 -
2.92 - for module in self.importer.modules_ordered:
2.93 - suppress_builtins = not with_builtins and module.name in ("__builtins__", "native")
2.94 -
2.95 - # Position the module in the image and make a translation.
2.96 -
2.97 - trans = micropython.ast.Translation(module, self)
2.98 -
2.99 - # Add header details.
2.100 -
2.101 - self.code.append(module)
2.102 -
2.103 - # Append module attributes to the image.
2.104 -
2.105 - attributes = module.module_attributes()
2.106 - self.code += module.attributes_as_list()
2.107 -
2.108 - # Append classes and functions to the image.
2.109 -
2.110 - for obj in module.all_objects:
2.111 - if isinstance(obj, Class):
2.112 -
2.113 - # Add header details.
2.114 -
2.115 - self.code.append(obj)
2.116 -
2.117 - # Append class attributes to the image.
2.118 -
2.119 - attributes = obj.class_attributes()
2.120 - self.code += obj.attributes_as_list()
2.121 -
2.122 - # Omit built-in function code where requested.
2.123 -
2.124 - if suppress_builtins and obj.astnode.doc is None:
2.125 - continue
2.126 -
2.127 - # Generate the instantiator/initialiser.
2.128 - # Append the function code to the image.
2.129 -
2.130 - code = trans.get_instantiator_code(obj)
2.131 - self.code += code
2.132 -
2.133 - # Class-level code is generated separately at the module
2.134 - # level, and the code location is set within the code
2.135 - # generation process for the module.
2.136 -
2.137 - elif isinstance(obj, Function):
2.138 -
2.139 - # Add header details.
2.140 -
2.141 - self.code.append(obj)
2.142 -
2.143 - # Append any default values to the image.
2.144 - # Only do this for functions which are not dynamic.
2.145 -
2.146 - if not obj.is_dynamic():
2.147 - self.code += obj.default_attrs
2.148 -
2.149 - # Omit built-in function code where requested.
2.150 -
2.151 - if suppress_builtins and obj.astnode.doc is None:
2.152 - pass
2.153 -
2.154 - # Append the function code to the image.
2.155 -
2.156 - else:
2.157 - code = trans.get_code(obj)
2.158 - self.code += code
2.159 -
2.160 - # Omit built-in module code where requested.
2.161 -
2.162 - if suppress_builtins:
2.163 - pass
2.164 -
2.165 - # Append the module top-level code to the image.
2.166 -
2.167 - else:
2.168 - code = trans.get_module_code()
2.169 - self.code += code
2.170 -
2.171 - # Generate the native library once we know how much of it is used.
2.172 -
2.173 - self.code += self.native.get_native_code()
2.174 -
2.175 - return self.code
2.176 -
2.177 - def get_raw_image(self, architecture=None, with_builtins=0):
2.178 -
2.179 - "Return the raw image representation of the program."
2.180 -
2.181 - architecture = architecture or micropython.rsvp
2.182 -
2.183 - self.get_image(with_builtins)
2.184 -
2.185 - objtable = self.get_object_table()
2.186 - paramtable = self.get_parameter_table()
2.187 -
2.188 - # Position the objects.
2.189 -
2.190 - pos = 0
2.191 -
2.192 - for item in self.code:
2.193 - arch_item = architecture.get_object(item)
2.194 -
2.195 - # Get the raw version for the architecture.
2.196 -
2.197 - if arch_item is not None:
2.198 - pos = arch_item.set_location(pos, objtable, with_builtins)
2.199 - else:
2.200 - pos += 1
2.201 -
2.202 - # Generate the raw code.
2.203 -
2.204 - self.raw_code = []
2.205 -
2.206 - for item in self.code:
2.207 - arch_item = architecture.get_object(item)
2.208 -
2.209 - # Get the raw version for the architecture.
2.210 -
2.211 - if arch_item is not None:
2.212 - arch_item.finalise_location(with_builtins)
2.213 - self.raw_code += arch_item.as_raw(objtable, paramtable, with_builtins)
2.214 - arch_item.finalise_body_location(with_builtins)
2.215 - else:
2.216 - self.raw_code.append(item)
2.217 -
2.218 - # Fix the module locations.
2.219 -
2.220 - for module in self.importer.modules_ordered:
2.221 -
2.222 - if not with_builtins and module.name in ("__builtins__", "native"):
2.223 - continue
2.224 -
2.225 - self.code_location = self.importer.modules["__main__"].code_location
2.226 - return self.raw_code
2.227 -
2.228 def get_object_table(self, reset=0):
2.229
2.230 "Return a table with details of attributes for classes and modules."
2.231 @@ -380,16 +202,6 @@
2.232
2.233 return self.paramtable
2.234
2.235 - def object_at(self, pos):
2.236 -
2.237 - "Return the object whose code can be found at 'pos'."
2.238 -
2.239 - i = bisect.bisect_left(self.code, Location(pos))
2.240 - if i > 0:
2.241 - return self.code[i-1]
2.242 - else:
2.243 - return None
2.244 -
2.245 class Importer:
2.246
2.247 "An import machine, searching for and loading modules."
2.248 @@ -406,7 +218,7 @@
2.249 "__call__"
2.250 ]
2.251
2.252 - def __init__(self, path=None, verbose=0, optimisations=None):
2.253 + def __init__(self, path=None, verbose=0):
2.254
2.255 """
2.256 Initialise the importer with the given search 'path' - a list of
2.257 @@ -414,14 +226,10 @@
2.258
2.259 The optional 'verbose' parameter causes output concerning the activities
2.260 of the object to be produced if set to a true value (not the default).
2.261 -
2.262 - The optional 'optimisations' cause certain techniques to be used in
2.263 - reducing program size and improving program efficiency.
2.264 """
2.265
2.266 self.path = path or [os.getcwd()]
2.267 self.verbose = verbose
2.268 - self.optimisations = optimisations or set()
2.269
2.270 self.modules = {}
2.271 self.modules_ordered = []
3.1 --- a/micropython/ast.py Fri Jun 28 21:17:02 2013 +0200
3.2 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000
3.3 @@ -1,941 +0,0 @@
3.4 -#!/usr/bin/env python
3.5 -
3.6 -"""
3.7 -Translate the AST of a Python program into a more interpretable representation.
3.8 -
3.9 -Copyright (C) 2007, 2008, 2009, 2010, 2011, 2012 Paul Boddie <paul@boddie.org.uk>
3.10 -
3.11 -This program is free software; you can redistribute it and/or modify it under
3.12 -the terms of the GNU General Public License as published by the Free Software
3.13 -Foundation; either version 3 of the License, or (at your option) any later
3.14 -version.
3.15 -
3.16 -This program is distributed in the hope that it will be useful, but WITHOUT
3.17 -ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
3.18 -FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
3.19 -details.
3.20 -
3.21 -You should have received a copy of the GNU General Public License along with
3.22 -this program. If not, see <http://www.gnu.org/licenses/>.
3.23 -"""
3.24 -
3.25 -from micropython.common import *
3.26 -from micropython.data import *
3.27 -from micropython.errors import *
3.28 -from micropython.rsvp import *
3.29 -from micropython.trans import Helper
3.30 -from micropython.code import Assembler
3.31 -import compiler.ast
3.32 -
3.33 -# Program visitors.
3.34 -
3.35 -class Translation(ASTVisitor, Assembler, Helper):
3.36 -
3.37 - "A module translator."
3.38 -
3.39 - # Attribute access instructions, for use with the appropriate handlers.
3.40 -
3.41 - attribute_load_instructions = (
3.42 - LoadAddress, LoadAddressContext, LoadAddressContextCond,
3.43 - LoadAttr, LoadAttrIndex, LoadAttrIndexContextCond
3.44 - )
3.45 - # attribute_store_instructions are defined by the optimiser
3.46 -
3.47 - # Name access instructions, for use with the appropriate handlers.
3.48 -
3.49 - name_load_instructions = (LoadName, LoadAddress, None)
3.50 - name_store_instructions = (StoreName, StoreAddress, StoreAddressContext)
3.51 -
3.52 - def __init__(self, module, program):
3.53 -
3.54 - """
3.55 - Initialise the translation with an inspected 'module' and the 'program'
3.56 - container.
3.57 - """
3.58 -
3.59 - Assembler.__init__(self, program)
3.60 - self.visitor = self
3.61 - self.module = module
3.62 -
3.63 - # Global program dependencies.
3.64 -
3.65 - self.native = program.native
3.66 - self.objtable = self.program.get_object_table()
3.67 - self.paramtable = self.program.get_parameter_table()
3.68 - self.importer = self.program.get_importer()
3.69 - self.builtins = self.importer.modules.get("__builtins__")
3.70 -
3.71 - # Status flags.
3.72 -
3.73 - self.in_exception_handler = False
3.74 - self.in_assignment = False # for slicing and subscript
3.75 -
3.76 - # Reset the assembler.
3.77 -
3.78 - self.reset()
3.79 -
3.80 - def __repr__(self):
3.81 - return "Translation(%r)" % self.module
3.82 -
3.83 - def get_unit(self):
3.84 - return self.unit
3.85 -
3.86 - def get_module_code(self):
3.87 -
3.88 - """
3.89 - Return the top-level module code.
3.90 - """
3.91 -
3.92 - self.unit = self.module
3.93 - self.reset()
3.94 - self.add_exception_unit()
3.95 -
3.96 - block = self.new_block()
3.97 - self.set_block(block)
3.98 -
3.99 - # Handle exceptions for the program.
3.100 -
3.101 - if self.module.name == "__main__":
3.102 - handler_block = self.new_block()
3.103 - self.new_op(PushHandler(handler_block))
3.104 -
3.105 - # Generate code for the module.
3.106 -
3.107 - if self.module.astnode is not None:
3.108 - self.dispatch(self.module.astnode)
3.109 -
3.110 - # Finish off the translated program if appropriate.
3.111 -
3.112 - if self.module.name == "__main__":
3.113 - self.set_block(handler_block)
3.114 - self.new_op(PopHandler(1))
3.115 -
3.116 - # All modules return if invoked.
3.117 -
3.118 - self.new_op(Return())
3.119 -
3.120 - self.drop_exception_unit()
3.121 - self.unit.temp_usage = self.max_temp_position + 1
3.122 - self.unit.blocks = self.blocks
3.123 - return self.blocks
3.124 -
3.125 - def get_code(self, unit):
3.126 -
3.127 - "Return the code for the given 'unit'."
3.128 -
3.129 - self.unit = unit
3.130 - self.reset()
3.131 - self.add_exception_unit()
3.132 -
3.133 - block = self.new_block()
3.134 - self.set_block(block)
3.135 -
3.136 - if unit.astnode is not None:
3.137 - self.dispatch(unit.astnode)
3.138 -
3.139 - self.drop_exception_unit()
3.140 - self.unit.temp_usage = self.max_temp_position + 2 # include space for instantiators to expand backwards
3.141 - self.unit.blocks = self.blocks
3.142 - return self.blocks
3.143 -
3.144 - def get_instantiator_code(self, cls):
3.145 -
3.146 - "Return the code for the given class 'cls'."
3.147 -
3.148 - # Obtain the function object to be populated.
3.149 -
3.150 - self.unit = cls.get_instantiator()
3.151 - self.reset()
3.152 -
3.153 - block = self.new_block()
3.154 - self.set_block(block)
3.155 -
3.156 - init_method = cls.get_init_method()
3.157 -
3.158 - # Make an object and store it in the unused first slot.
3.159 -
3.160 - self.make_instance(cls, len(cls.instance_attributes()))
3.161 - self.new_op(StoreTemp(0))
3.162 -
3.163 - # Invoke the appropriate initialiser.
3.164 -
3.165 - self.new_op(LoadFunction(init_method))
3.166 - self.new_op(LoadCallable())
3.167 - self.new_op(JumpInFrame())
3.168 -
3.169 - # Store the object as the result.
3.170 -
3.171 - self.new_op(LoadTemp(0)) # load the context from the locals
3.172 - self.new_op(Return())
3.173 -
3.174 - self.unit.blocks = self.blocks
3.175 - return self.blocks
3.176 -
3.177 - # Visitor methods.
3.178 -
3.179 - def default(self, node, *args):
3.180 - raise TranslateError("Node class %r is not supported." % node.__class__)
3.181 -
3.182 - # Concrete visitor methods.
3.183 -
3.184 - # Binary operators.
3.185 -
3.186 - visitBitand = \
3.187 - visitBitor = \
3.188 - visitBitxor = Helper._visitBinaryBit
3.189 -
3.190 - visitAdd = \
3.191 - visitDiv = \
3.192 - visitFloorDiv = \
3.193 - visitLeftShift = \
3.194 - visitMod = \
3.195 - visitMul = \
3.196 - visitPower = \
3.197 - visitRightShift = \
3.198 - visitSub = Helper._visitBinary
3.199 -
3.200 - # Unary operators.
3.201 -
3.202 - visitInvert = \
3.203 - visitUnaryAdd = \
3.204 - visitUnarySub = Helper._visitUnary
3.205 -
3.206 - # Logical operators.
3.207 -
3.208 - def visitAnd(self, node):
3.209 - end_block = self.new_block()
3.210 - temp_pos = self.reserve_temp()
3.211 -
3.212 - for n in node.nodes[:-1]:
3.213 - self.dispatch(n)
3.214 - self.new_op(StoreTemp(temp_pos))
3.215 -
3.216 - self._generateTestBoolean(n, LoadTemp(temp_pos))
3.217 - self.new_op(JumpIfFalse(end_block, working="status"))
3.218 -
3.219 - self.dispatch(node.nodes[-1])
3.220 - self.new_op(StoreTemp(temp_pos))
3.221 -
3.222 - self.set_block(end_block)
3.223 -
3.224 - temp = LoadTemp(temp_pos)
3.225 - self.new_op(temp)
3.226 - self.discard_temp(temp)
3.227 -
3.228 - def visitNot(self, node):
3.229 - self.dispatch(node.expr)
3.230 -
3.231 - temp = self.optimiser.optimise_temp_storage()
3.232 - self.new_op(temp)
3.233 - self._generateTestBoolean(node.expr, temp)
3.234 - self.discard_temp(temp)
3.235 -
3.236 - self.new_op(InvertBoolean(source="status", target="status"))
3.237 - self._generateLoadBoolean(node)
3.238 -
3.239 - def visitOr(self, node):
3.240 - end_block = self.new_block()
3.241 - temp_pos = self.reserve_temp()
3.242 -
3.243 - for n in node.nodes[:-1]:
3.244 - self.dispatch(n)
3.245 - self.new_op(StoreTemp(temp_pos))
3.246 -
3.247 - self._generateTestBoolean(n, LoadTemp(temp_pos))
3.248 - self.new_op(JumpIfTrue(end_block, working="status"))
3.249 -
3.250 - self.dispatch(node.nodes[-1])
3.251 - self.new_op(StoreTemp(temp_pos))
3.252 -
3.253 - self.set_block(end_block)
3.254 -
3.255 - temp = LoadTemp(temp_pos)
3.256 - self.new_op(temp)
3.257 - self.discard_temp(temp)
3.258 -
3.259 - # Comparisons.
3.260 -
3.261 - def visitCompare(self, node):
3.262 -
3.263 - """
3.264 - _t1 = node.expr
3.265 - _t1 op1 _t2 and _t2 op2 _t3 and ...
3.266 - """
3.267 -
3.268 - end_block = self.new_block()
3.269 -
3.270 - self.dispatch(node.expr)
3.271 - temp2 = self.optimiser.optimise_temp_storage()
3.272 -
3.273 - # NOTE: Replicated by some code in micropython.inspect.visitCompare.
3.274 -
3.275 - last_op = node.ops[-1]
3.276 -
3.277 - for op in node.ops:
3.278 - op_name, next_node = op
3.279 - operator_fn = operator_functions.get(op_name)
3.280 -
3.281 - # Propagate the arguments as we traverse the construct.
3.282 -
3.283 - temp1 = temp2
3.284 - self.dispatch(next_node)
3.285 - temp2 = self.optimiser.optimise_temp_storage()
3.286 -
3.287 - # Use the appropriate mechanism, setting the boolean status for the
3.288 - # comparison.
3.289 -
3.290 - if operator_fn is not None:
3.291 -
3.292 - # Generate function call using evaluated argument and next node.
3.293 -
3.294 - temp_fn = self._generateOperatorFunction(op_name)
3.295 - self._generateInvocation(temp_fn, (temp1, temp2))
3.296 - self.discard_temp(temp_fn)
3.297 -
3.298 - temp_result = self.optimiser.optimise_temp_storage()
3.299 - self._generateTestBoolean(node, temp_result)
3.300 - self.discard_temp(temp_result)
3.301 -
3.302 - else:
3.303 - # Deal with the special operators.
3.304 -
3.305 - if op_name.startswith("is"):
3.306 - self.new_op(temp1)
3.307 - self.record_value()
3.308 - self.start_target()
3.309 - self.new_op(temp2)
3.310 - self.new_op(TestIdentity(target="status"))
3.311 - self.assign_value()
3.312 - self.discard_value()
3.313 -
3.314 - elif op_name.endswith("in"):
3.315 - self.new_op(temp2)
3.316 -
3.317 - # Get method on temp2.
3.318 -
3.319 - self._generateAttr(node, "__contains__", self.attribute_load_instructions)
3.320 - temp_method = self.optimiser.optimise_temp_storage()
3.321 -
3.322 - # Add arguments.
3.323 - # NOTE: No support for defaults.
3.324 -
3.325 - self._generateInvocation(temp_method, (temp2, temp1))
3.326 -
3.327 - temp_result = self.get_temp()
3.328 - self._generateTestBoolean(node, temp_result)
3.329 - self.discard_temp(temp_result)
3.330 -
3.331 - if op_name.find("not") != -1:
3.332 - self.new_op(InvertBoolean(source="status", target="status"))
3.333 -
3.334 - # Test the result and jump to the end block if false.
3.335 -
3.336 - if op is not last_op:
3.337 - self.new_op(JumpIfFalse(end_block, working="status"))
3.338 -
3.339 - # Compilation duties...
3.340 -
3.341 - self.discard_temp(temp1)
3.342 -
3.343 - self.discard_temp(temp2)
3.344 -
3.345 - # With the status set above, produce a boolean result.
3.346 -
3.347 - self.set_block(end_block)
3.348 -
3.349 - # Yield the appropriate value.
3.350 -
3.351 - self._generateLoadBoolean(node)
3.352 -
3.353 - # Expressions.
3.354 -
3.355 - def visitBackquote(self, node): raise TranslationNotImplementedError("Backquote")
3.356 -
3.357 - def visitCallFunc(self, node):
3.358 -
3.359 - """
3.360 - Evaluate positional arguments, evaluate and store keyword arguments in
3.361 - the correct location, then invoke the function.
3.362 - """
3.363 -
3.364 - # Mark the frame, evaluate the target, generate the call.
3.365 -
3.366 - self._startCallFunc()
3.367 - self.dispatch(node.node)
3.368 - temp_target, target, temp_context = self._generateCallFunc(node.args, node)
3.369 - self._doCallFunc(temp_target, target)
3.370 - self._endCallFunc(temp_target, temp_context)
3.371 -
3.372 - def visitConst(self, node):
3.373 - const = self.importer.get_constant(node.value)
3.374 - self.new_op(LoadConst(const))
3.375 -
3.376 - def visitDict(self, node): raise TranslationNotImplementedError("Dict")
3.377 -
3.378 - def visitEllipsis(self, node): raise TranslationNotImplementedError("Ellipsis")
3.379 -
3.380 - def visitExec(self, node): raise TranslationNotImplementedError("Exec")
3.381 -
3.382 - def visitExpression(self, node): raise TranslationNotImplementedError("Expression")
3.383 -
3.384 - def visitGenExpr(self, node): raise TranslationNotImplementedError("GenExpr")
3.385 -
3.386 - def visitGenExprFor(self, node): raise TranslationNotImplementedError("GenExprFor")
3.387 -
3.388 - def visitGenExprIf(self, node): raise TranslationNotImplementedError("GenExprIf")
3.389 -
3.390 - def visitGenExprInner(self, node): raise TranslationNotImplementedError("GenExprInner")
3.391 -
3.392 - def visitGetattr(self, node):
3.393 - self._visitAttr(node, self.attribute_load_instructions)
3.394 -
3.395 - def visitList(self, node):
3.396 - self._generateList(node, node.nodes)
3.397 -
3.398 - def visitListComp(self, node):
3.399 - self._generateList(node)
3.400 - temp_list = self.optimiser.optimise_temp_storage()
3.401 -
3.402 - # Get the list's append method.
3.403 -
3.404 - self._generateAttr(node, "append", self.attribute_load_instructions)
3.405 - temp_method = self.optimiser.optimise_temp_storage()
3.406 -
3.407 - self.visitListCompFor(node.quals[0], node.quals[1:], node.expr, temp_list, temp_method)
3.408 -
3.409 - # Generate a reference to the list.
3.410 -
3.411 - self.new_op(temp_list)
3.412 -
3.413 - self.discard_temp(temp_method)
3.414 - self.discard_temp(temp_list)
3.415 -
3.416 - def visitListCompFor(self, node, following_quals, expr, temp_list, temp_method):
3.417 - temp_iterator, next_block, exit_block, else_block = self._startFor(node)
3.418 -
3.419 - # Explicit dispatch to tests, following loops, expression.
3.420 -
3.421 - if node.ifs:
3.422 - self.visitListCompIf(node.ifs[0], node.ifs[1:], following_quals, expr, temp_list, temp_method)
3.423 -
3.424 - # Explicit dispatch to following loops, expression.
3.425 -
3.426 - elif following_quals:
3.427 - self.visitListCompFor(following_quals[0], following_quals[1:], expr, temp_list, temp_method)
3.428 -
3.429 - # Explicit dispatch to the expression.
3.430 -
3.431 - else:
3.432 - self.dispatch(expr)
3.433 -
3.434 - # Append the value to the list.
3.435 -
3.436 - temp_value = self.optimiser.optimise_temp_storage()
3.437 - self._generateInvocation(temp_method, (temp_list, temp_value,))
3.438 -
3.439 - self._endFor(node, temp_iterator, next_block, exit_block, else_block)
3.440 -
3.441 - def visitListCompIf(self, node, following_tests, following_quals, expr, temp_list, temp_method):
3.442 - exit_block = self.new_block()
3.443 -
3.444 - # Evaluate the test and jump beyond the body if it is not satisfied.
3.445 -
3.446 - self.dispatch(node.test)
3.447 -
3.448 - temp = self.optimiser.optimise_temp_storage()
3.449 - self.new_op(temp)
3.450 - self._generateTestBoolean(node, temp)
3.451 - self.new_op(JumpIfFalse(exit_block, working="status"))
3.452 -
3.453 - # Explicit dispatch to tests, following loops, expression.
3.454 -
3.455 - if following_tests:
3.456 - self.visitListCompIf(following_tests[0], following_tests[1:], following_quals, expr, temp_list, temp_method)
3.457 -
3.458 - # Explicit dispatch to following loops, expression.
3.459 -
3.460 - elif following_quals:
3.461 - self.visitListCompFor(following_quals[0], following_quals[1:], expr, temp_list, temp_method)
3.462 -
3.463 - # Explicit dispatch to the expression.
3.464 -
3.465 - else:
3.466 - self.dispatch(expr)
3.467 -
3.468 - # Append the value to the list.
3.469 -
3.470 - temp_value = self.optimiser.optimise_temp_storage()
3.471 - self._generateInvocation(temp_method, (temp_list, temp_value,))
3.472 -
3.473 - self.set_block(exit_block)
3.474 -
3.475 - def visitName(self, node):
3.476 - self._visitName(node, self.name_load_instructions)
3.477 -
3.478 - def visitSlice(self, node):
3.479 - args = [node.expr]
3.480 -
3.481 - if node.lower is None:
3.482 - args.append(compiler.ast.Name("None"))
3.483 - if node.upper is None:
3.484 - args.append(compiler.ast.Name("None"))
3.485 - else:
3.486 - args.append(node.upper)
3.487 - else:
3.488 - args.append(node.lower)
3.489 - if node.upper is None:
3.490 - args.append(compiler.ast.Name("None"))
3.491 - else:
3.492 - args.append(node.upper)
3.493 -
3.494 - temp_fn = self._getOperatorFunction(node, self.in_assignment and "AssSlice" or "Slice")
3.495 - self._visitCall(node, temp_fn, args)
3.496 - self.discard_temp(temp_fn)
3.497 -
3.498 - def visitSubscript(self, node):
3.499 - temp_fn = self._getOperatorFunction(node, self.in_assignment and "AssSubscript" or "Subscript")
3.500 - self._visitCall(node, temp_fn, [node.expr] + node.subs)
3.501 - self.discard_temp(temp_fn)
3.502 -
3.503 - def visitTuple(self, node):
3.504 - self._generateTuple(node)
3.505 -
3.506 - # Definitions.
3.507 -
3.508 - def visitAssign(self, node):
3.509 -
3.510 - """
3.511 - Evaluate the expression from the given 'node' and assign it to the
3.512 - associated recipients.
3.513 - """
3.514 -
3.515 - self.dispatch(node.expr)
3.516 -
3.517 - # Record the value and then dispatch to the assignment targets.
3.518 -
3.519 - self.record_value(self.has_immediate_usage(node.nodes))
3.520 -
3.521 - self.in_assignment = True
3.522 -
3.523 - for n in node.nodes:
3.524 - self.dispatch(n)
3.525 -
3.526 - self.in_assignment = False
3.527 - self.discard_value()
3.528 -
3.529 - def visitAssAttr(self, node):
3.530 -
3.531 - "Assign the assignment expression to the recipient 'node'."
3.532 -
3.533 - self.start_target()
3.534 - self._visitAttr(node, self.optimiser.get_attribute_store_instructions())
3.535 - self.assign_value()
3.536 -
3.537 - def visitAssList(self, node):
3.538 -
3.539 - """
3.540 - Assign items from the assignment expression to each of the recipients
3.541 - found within the given 'node'.
3.542 - """
3.543 -
3.544 - self.new_op(self.expr_temp[-1])
3.545 - self._generateAttr(node, "__getitem__", self.attribute_load_instructions)
3.546 - temp_getitem = self.optimiser.optimise_temp_storage()
3.547 -
3.548 - for i, n in enumerate(node.nodes):
3.549 - self._startCallFunc()
3.550 - self.new_op(temp_getitem)
3.551 - temp_target, target, temp_context = self._generateCallFunc([compiler.ast.Const(i)], node)
3.552 - self._doCallFunc(temp_target, target)
3.553 - self._endCallFunc(temp_context=temp_context)
3.554 -
3.555 - # Provide a different source value.
3.556 - # NOTE: Permitting immediate usage given that neither name nor
3.557 - # NOTE: attribute accesses should involve a function call
3.558 - # NOTE: overwriting the above result.
3.559 -
3.560 - self.record_value(self.is_immediate_user(n))
3.561 - self.dispatch(n)
3.562 - self.discard_value()
3.563 -
3.564 - self.discard_temp(temp_getitem)
3.565 -
3.566 - def visitAssName(self, node):
3.567 -
3.568 - "Assign the assignment expression to the recipient 'node'."
3.569 -
3.570 - if node.flags == "OP_DELETE":
3.571 - raise TranslationNotImplementedError("AssName(OP_DELETE)")
3.572 - self._visitAssName(node)
3.573 -
3.574 - def _visitAssName(self, node):
3.575 - self.start_target()
3.576 - self._visitName(node, self.name_store_instructions)
3.577 - self.assign_value()
3.578 -
3.579 - # Add any attribute usage guards.
3.580 -
3.581 - self._generateGuards(node)
3.582 -
3.583 - visitAssTuple = visitAssList
3.584 -
3.585 - def visitAugAssign(self, node):
3.586 -
3.587 - # Find the augmented assignment function and attempt to use it.
3.588 -
3.589 - temp_fn = self._getOperatorAugAssignFunction(node)
3.590 - self._visitCall(node, temp_fn, (node.node, node.expr))
3.591 - self.discard_temp(temp_fn)
3.592 -
3.593 - # Assign the result to the name.
3.594 -
3.595 - self.record_value(1)
3.596 -
3.597 - if isinstance(node.node, compiler.ast.Name):
3.598 - self._visitAssName(node.node)
3.599 - elif isinstance(node.node, compiler.ast.Getattr):
3.600 - self.visitAssAttr(node.node)
3.601 - else:
3.602 - raise TranslationNotImplementedError("AugAssign(Slice or Subscript)")
3.603 -
3.604 - self.discard_value()
3.605 -
3.606 - def visitClass(self, node):
3.607 - if not used_by_unit(node):
3.608 - return
3.609 -
3.610 - # Store the name.
3.611 -
3.612 - self.new_op(LoadClass(node.unit))
3.613 - self._storeName(node)
3.614 -
3.615 - # Visit the code.
3.616 -
3.617 - unit = self.unit
3.618 - self.unit = node.unit
3.619 - self.dispatch(node.code)
3.620 - self.unit = unit
3.621 -
3.622 - def visitDecorators(self, node): raise TranslationNotImplementedError("Decorators")
3.623 -
3.624 - def visitFrom(self, node):
3.625 - self._visitImport(node)
3.626 -
3.627 - # Store each imported name if its reference is not set as a constant
3.628 - # module global.
3.629 -
3.630 - module = self.importer.get_module(node.modname)
3.631 -
3.632 - for name, alias in node.names:
3.633 - if name != "*":
3.634 - self._importName(module, name, alias, node)
3.635 - else:
3.636 - for attrname in module.module_attributes().keys():
3.637 - self._importName(module, attrname, None, node)
3.638 -
3.639 - def visitFunction(self, node):
3.640 - if not used_by_unit(node):
3.641 - return
3.642 -
3.643 - # Only store the name when visiting this node from outside.
3.644 -
3.645 - if self.unit is not node.unit:
3.646 - self._visitFunctionDeclaration(node)
3.647 -
3.648 - # Record the declared function.
3.649 -
3.650 - self._storeName(node)
3.651 -
3.652 - # Visiting of the code occurs when get_code is invoked on this node.
3.653 -
3.654 - else:
3.655 - self._visitFunctionDefinition(node)
3.656 -
3.657 - def visitGlobal(self, node): pass
3.658 -
3.659 - def visitImport(self, node):
3.660 - self._visitImport(node)
3.661 -
3.662 - for name, alias in node.names:
3.663 - module = self.importer.get_module(name)
3.664 - self.new_op(LoadConst(module))
3.665 - self._storeName(node, alias or name)
3.666 -
3.667 - def visitKeyword(self, node): pass
3.668 -
3.669 - def visitLambda(self, node):
3.670 -
3.671 - """
3.672 - Lambda functions can be represented as globally defined functions
3.673 - provided they do not define any default parameter values, since these
3.674 - may defined in a non-global scope.
3.675 -
3.676 - Where defaults are defined, an object must be created and its content
3.677 - defined: the callable member of the object's structure must be set to
3.678 - the lambda function definition; each default must be attached to the
3.679 - object as an attribute, as is the case with normal functions and
3.680 - methods.
3.681 - """
3.682 -
3.683 - # Produce the reference to this function when visiting this node from
3.684 - # outside.
3.685 -
3.686 - if self.unit is not node.unit:
3.687 -
3.688 - # Provide the declared function.
3.689 -
3.690 - self._visitFunctionDeclaration(node)
3.691 -
3.692 - # Visiting of the code occurs when get_code is invoked on this node.
3.693 -
3.694 - else:
3.695 - self._visitFunctionDefinition(node)
3.696 -
3.697 - def visitModule(self, node):
3.698 - extend = ExtendFrame()
3.699 - self.new_op(extend)
3.700 - self.dispatch(node.node)
3.701 - self.set_frame_usage(node, extend)
3.702 -
3.703 - # Statements.
3.704 -
3.705 - def visitStmt(self, node):
3.706 -
3.707 - "Process the collection of statements provided by 'node'."
3.708 -
3.709 - for n in node.nodes:
3.710 -
3.711 - # Process the statement.
3.712 -
3.713 - self.dispatch(n)
3.714 -
3.715 - # Prevent incorrect optimisation by resetting the optimiser after
3.716 - # each statement.
3.717 -
3.718 - self.optimiser.reset()
3.719 -
3.720 - def visitAssert(self, node): raise TranslationNotImplementedError("Assert")
3.721 -
3.722 - def visitBreak(self, node):
3.723 - next_block, exit_block = self.get_loop_blocks()
3.724 - self.new_op(Jump(exit_block))
3.725 -
3.726 - def visitContinue(self, node):
3.727 - next_block, exit_block = self.get_loop_blocks()
3.728 - self.new_op(Jump(next_block))
3.729 -
3.730 - def visitDiscard(self, node):
3.731 - self.dispatch(node.expr)
3.732 - self.optimiser.optimise_unused_results()
3.733 -
3.734 - def visitFor(self, node):
3.735 - temp_iterator, next_block, exit_block, else_block = self._startFor(node, node.else_)
3.736 - self.dispatch(node.body)
3.737 - self._endFor(node, temp_iterator, next_block, exit_block, else_block, node.else_)
3.738 -
3.739 - def visitIf(self, node):
3.740 - first = True
3.741 - next_block = None
3.742 - exit_block = self.new_block()
3.743 -
3.744 - clauses = node.tests + [(None, node.else_)]
3.745 -
3.746 - for clause in clauses:
3.747 - test, body = clause
3.748 - if body is None:
3.749 - break
3.750 -
3.751 - if not first:
3.752 - self.new_op(Jump(exit_block)) # finish last body
3.753 - self.set_block(next_block) # start next test
3.754 - next_block = None
3.755 -
3.756 - if test is not None:
3.757 - self.dispatch(test)
3.758 -
3.759 - temp = self.optimiser.optimise_temp_storage()
3.760 - self.new_op(temp)
3.761 - self._generateTestBoolean(node, temp)
3.762 -
3.763 - next_block = self.new_block()
3.764 - self.new_op(JumpIfFalse(next_block, working="status"))
3.765 -
3.766 - self.dispatch(body)
3.767 - first = False
3.768 -
3.769 - if next_block is not None:
3.770 - self.set_block(next_block)
3.771 -
3.772 - self.set_block(exit_block)
3.773 -
3.774 - def visitIfExp(self, node): raise TranslationNotImplementedError("IfExp")
3.775 -
3.776 - def visitPass(self, node): pass
3.777 -
3.778 - def visitPrint(self, node):
3.779 - self._visitPrint(node, "_print")
3.780 -
3.781 - def visitPrintnl(self, node):
3.782 - self._visitPrint(node, "_printnl")
3.783 -
3.784 - def visitRaise(self, node):
3.785 -
3.786 - if node.expr1 is not None:
3.787 -
3.788 - # NOTE: expr1 only => instance provided
3.789 -
3.790 - self.dispatch(node.expr1)
3.791 -
3.792 - if node.expr2 is not None:
3.793 - temp = self.optimiser.optimise_temp_storage()
3.794 -
3.795 - self.dispatch(node.expr2)
3.796 - temp_arg = self.optimiser.optimise_temp_storage()
3.797 -
3.798 - self._generateInvocation(temp, (temp_arg,))
3.799 -
3.800 - self.discard_temp(temp_arg)
3.801 -
3.802 - self.new_op(Transfer(source="working", target="exception"))
3.803 -
3.804 - self.new_op(RaiseException())
3.805 -
3.806 - def visitReturn(self, node):
3.807 - if node.value is not None:
3.808 - self.dispatch(node.value)
3.809 - else:
3.810 - self.dispatch(compiler.ast.Name("None"))
3.811 -
3.812 - if self.in_exception_handler:
3.813 - self.new_op(ClearException(target="exception"))
3.814 -
3.815 - # NOTE: Support finally blocks here.
3.816 -
3.817 - if self.exception_blocks[-1]:
3.818 - self.new_op(PopHandler(len(self.exception_blocks[-1])))
3.819 -
3.820 - self.new_op(Return())
3.821 -
3.822 - def visitTryExcept(self, node):
3.823 - exit_block = self.new_block()
3.824 - else_block = self.new_block()
3.825 - handler_block = self.new_block()
3.826 -
3.827 - self.add_exception_blocks(handler_block, exit_block)
3.828 -
3.829 - # Try...
3.830 - # Produce the code, then jump to the exit.
3.831 -
3.832 - self.new_op(PushHandler(handler_block))
3.833 - self.dispatch(node.body)
3.834 - self.new_op(PopHandler(1))
3.835 -
3.836 - if node.else_ is not None:
3.837 - self.new_op(Jump(else_block))
3.838 - else:
3.839 - self.new_op(Jump(exit_block))
3.840 -
3.841 - # Start of handlers.
3.842 -
3.843 - self.set_block(handler_block)
3.844 - self.new_op(PopHandler(1))
3.845 -
3.846 - # Disable the handlers.
3.847 -
3.848 - self.drop_exception_blocks()
3.849 -
3.850 - for name, assignment, handler in node.handlers:
3.851 - next_block = self.new_block()
3.852 -
3.853 - # Test the given exception against the current exception.
3.854 -
3.855 - if name is not None:
3.856 - self.dispatch(name)
3.857 -
3.858 - self.new_op(CheckException(target="status"))
3.859 - self.new_op(JumpIfFalse(next_block, working="status"))
3.860 -
3.861 - # Handle assignment to exception variable.
3.862 -
3.863 - if assignment is not None:
3.864 - self.new_op(Transfer(source="working", target="exception"))
3.865 -
3.866 - # Record the value to be assigned.
3.867 -
3.868 - self.record_value()
3.869 - self.dispatch(assignment)
3.870 - self.discard_value()
3.871 -
3.872 - # Produce the handler code, then jump to the exit.
3.873 -
3.874 - self.in_exception_handler = True
3.875 - self.dispatch(handler)
3.876 - self.in_exception_handler = False
3.877 -
3.878 - self.new_op(Jump(exit_block))
3.879 -
3.880 - self.set_block(next_block)
3.881 -
3.882 - # Unhandled exceptions.
3.883 -
3.884 - self.new_op(RaiseException())
3.885 -
3.886 - # Optional else clause.
3.887 -
3.888 - if node.else_ is not None:
3.889 - self.set_block(else_block)
3.890 - self.dispatch(node.else_)
3.891 -
3.892 - # Clear the exception.
3.893 -
3.894 - self.set_block(exit_block)
3.895 - self.new_op(ClearException(target="exception"))
3.896 -
3.897 - def visitTryFinally(self, node):
3.898 -
3.899 - """
3.900 - Add finally handler, potentially as an exception handler.
3.901 - Generate body, potentially changing return statements so that they do
3.902 - not return immediately.
3.903 - Generate handler, removing the handler from the active handler list,
3.904 - adding instructions which raise active exceptions.
3.905 - """
3.906 -
3.907 - raise TranslationNotImplementedError("TryFinally")
3.908 -
3.909 - def visitWhile(self, node):
3.910 - exit_block = self.new_block()
3.911 - next_block = self.new_block()
3.912 - else_block = self.new_block()
3.913 -
3.914 - self.set_block(next_block)
3.915 - self.dispatch(node.test)
3.916 -
3.917 - temp = self.optimiser.optimise_temp_storage()
3.918 - self.new_op(temp)
3.919 - self._generateTestBoolean(node, temp)
3.920 -
3.921 - if node.else_ is not None:
3.922 - self.new_op(JumpIfFalse(else_block, working="status"))
3.923 - else:
3.924 - self.new_op(JumpIfFalse(exit_block, working="status"))
3.925 -
3.926 - self.add_loop_blocks(next_block, exit_block)
3.927 -
3.928 - self.dispatch(node.body)
3.929 - self.new_op(Jump(next_block))
3.930 -
3.931 - if node.else_ is not None:
3.932 - self.set_block(else_block)
3.933 -
3.934 - self.dispatch(node.else_)
3.935 -
3.936 - self.set_block(exit_block)
3.937 -
3.938 - self.drop_loop_blocks()
3.939 -
3.940 - def visitWith(self, node): raise TranslationNotImplementedError("With")
3.941 -
3.942 - def visitYield(self, node): raise TranslationNotImplementedError("Yield")
3.943 -
3.944 -# vim: tabstop=4 expandtab shiftwidth=4
4.1 --- a/micropython/cmd.py Fri Jun 28 21:17:02 2013 +0200
4.2 +++ b/micropython/cmd.py Sat Jun 29 01:28:12 2013 +0200
4.3 @@ -4,7 +4,7 @@
4.4 Command option processing and other utilities for compiling and testing
4.5 programs.
4.6
4.7 -Copyright (C) 2009 Paul Boddie <paul@boddie.org.uk>
4.8 +Copyright (C) 2009, 2013 Paul Boddie <paul@boddie.org.uk>
4.9
4.10 This program is free software; you can redistribute it and/or modify it under
4.11 the terms of the GNU General Public License as published by the Free Software
4.12 @@ -23,36 +23,14 @@
4.13 from os.path import exists, join
4.14 import micropython
4.15
4.16 -def parse_optimisations(args):
4.17 -
4.18 - "Parse 'args' for optimisation flags."
4.19 -
4.20 - if "-omax" in args:
4.21 - requested_optimisations = micropython.Program.supported_optimisations
4.22 - else:
4.23 - requested_optimisations = []
4.24 - for arg in args:
4.25 - if arg.startswith("-o"):
4.26 - for arg_part in arg[2:].split(","):
4.27 - requested_optimisations.append(arg_part)
4.28 -
4.29 - return requested_optimisations
4.30 -
4.31 -def show_optimisations():
4.32 -
4.33 - "Show available optimisation flags."
4.34 -
4.35 - return ",".join(micropython.Program.supported_optimisations)
4.36 -
4.37 -def program(path, requested_optimisations, verbose=0):
4.38 +def program(path, verbose=0):
4.39
4.40 """
4.41 - Return a program object for the given module search 'path' and
4.42 - 'requested_optimisations'.
4.43 + Return a program object for the given module search 'path'.
4.44 """
4.45
4.46 - i = micropython.Importer(path, verbose, requested_optimisations)
4.47 - p = micropython.Program(i, requested_optimisations)
4.48 + i = micropython.Importer(path, verbose)
4.49 + p = micropython.Program(i)
4.50
4.51 for d in path:
4.52 builtins = join(d, "builtins.py")
4.53 @@ -70,7 +48,6 @@
4.54 'args'.
4.55 """
4.56
4.57 - requested_optimisations = parse_optimisations(args)
4.58 - return program(path, requested_optimisations, "-v" in args)
4.59 + return program(path, "-v" in args)
4.60
4.61 # vim: tabstop=4 expandtab shiftwidth=4
5.1 --- a/micropython/code.py Fri Jun 28 21:17:02 2013 +0200
5.2 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000
5.3 @@ -1,492 +0,0 @@
5.4 -#!/usr/bin/env python
5.5 -
5.6 -"""
5.7 -Generate low-level code.
5.8 -
5.9 -Copyright (C) 2007, 2008, 2009, 2010, 2011, 2012 Paul Boddie <paul@boddie.org.uk>
5.10 -
5.11 -This program is free software; you can redistribute it and/or modify it under
5.12 -the terms of the GNU General Public License as published by the Free Software
5.13 -Foundation; either version 3 of the License, or (at your option) any later
5.14 -version.
5.15 -
5.16 -This program is distributed in the hope that it will be useful, but WITHOUT
5.17 -ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
5.18 -FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
5.19 -details.
5.20 -
5.21 -You should have received a copy of the GNU General Public License along with
5.22 -this program. If not, see <http://www.gnu.org/licenses/>.
5.23 -"""
5.24 -
5.25 -from micropython.opt import Optimiser
5.26 -from micropython.data import *
5.27 -from micropython.errors import *
5.28 -from micropython.rsvp import *
5.29 -import compiler.ast
5.30 -
5.31 -class Assembler:
5.32 -
5.33 - "Support for generating low-level code."
5.34 -
5.35 - def __init__(self, program):
5.36 -
5.37 - """
5.38 - Initialise the assembler with a program, optimiser and status
5.39 - attributes.
5.40 - """
5.41 -
5.42 - self.program = program
5.43 -
5.44 - # Optimisation.
5.45 -
5.46 - self.optimiser = Optimiser(self, program.optimisations)
5.47 -
5.48 - # The current unit being translated.
5.49 -
5.50 - self.unit = None
5.51 -
5.52 - # The temporary storage used by the current assignment expression.
5.53 -
5.54 - self.expr_temp = []
5.55 -
5.56 - # The start of the current assignment target instructions.
5.57 -
5.58 - self.target_start = None
5.59 -
5.60 - # Wiring within the code.
5.61 -
5.62 - self.labels = {}
5.63 - self.label_number = 0
5.64 - self.loop_blocks = []
5.65 - self.exception_blocks = []
5.66 -
5.67 - def reset(self):
5.68 -
5.69 - "Reset the state of the assembler."
5.70 -
5.71 - # The code itself. This is limited to the code for a particular block
5.72 - # being processed.
5.73 -
5.74 - self.blocks = []
5.75 -
5.76 - # Information about temporary values.
5.77 -
5.78 - self.temp_positions = set()
5.79 - self.max_temp_position = -1
5.80 -
5.81 - # Information about instructions which construct frames.
5.82 -
5.83 - self.frame_makers = []
5.84 -
5.85 - # Optimiser state must be reset for each unit.
5.86 -
5.87 - self.optimiser.reset()
5.88 -
5.89 - def new_block(self):
5.90 -
5.91 - "Return a new code block."
5.92 -
5.93 - return Block(self.unit)
5.94 -
5.95 - def get_block(self):
5.96 -
5.97 - "Return the current block."
5.98 -
5.99 - return self.blocks[-1]
5.100 -
5.101 - def set_block(self, block, preceding=None):
5.102 -
5.103 - """
5.104 - Add the given 'block' to the unit's list of blocks, noting any active
5.105 - value information from 'preceding' blocks on the new block.
5.106 - """
5.107 -
5.108 - self.optimiser.reset(block, preceding)
5.109 - self.blocks.append(block)
5.110 -
5.111 - def get_loop_blocks(self):
5.112 - return self.loop_blocks[-1]
5.113 -
5.114 - def add_loop_blocks(self, next_block, exit_block):
5.115 - self.loop_blocks.append((next_block, exit_block))
5.116 -
5.117 - def drop_loop_blocks(self):
5.118 - self.loop_blocks.pop()
5.119 -
5.120 - def add_exception_unit(self):
5.121 - self.exception_blocks.append([])
5.122 -
5.123 - def get_exception_blocks(self):
5.124 - return self.exception_blocks[-1][-1]
5.125 -
5.126 - def add_exception_blocks(self, handler_block, exit_block):
5.127 - self.exception_blocks[-1].append((handler_block, exit_block))
5.128 -
5.129 - def drop_exception_blocks(self):
5.130 - self.exception_blocks[-1].pop()
5.131 -
5.132 - def drop_exception_unit(self):
5.133 - self.exception_blocks.pop()
5.134 -
5.135 - # Assignment expression values.
5.136 -
5.137 - def record_value(self, immediate=1):
5.138 -
5.139 - """
5.140 - Record the current active value for an assignment. If the optional
5.141 - 'immediate' parameter is set to a false value, new temporary storage to
5.142 - hold the recorded value will be allocated; otherwise, the
5.143 - value-providing instruction may be replicated in order to provide the
5.144 - active value later on.
5.145 - """
5.146 -
5.147 - if immediate:
5.148 - temp = self.optimiser.optimise_temp_storage()
5.149 - else:
5.150 - temp = self.get_temp()
5.151 - self.expr_temp.append(temp)
5.152 -
5.153 - def discard_value(self):
5.154 -
5.155 - "Discard any temporary storage in use for the current assignment value."
5.156 -
5.157 - self.discard_temp(self.expr_temp.pop())
5.158 -
5.159 - def start_target(self):
5.160 -
5.161 - """
5.162 - Start recording instructions used to define the target of an assignment.
5.163 - """
5.164 -
5.165 - self.target_start = len(self.blocks[-1])
5.166 -
5.167 - def remove_target_ops(self):
5.168 -
5.169 - "Remove the assignment target instructions."
5.170 -
5.171 - del self.blocks[-1].code[self.target_start:]
5.172 - self.target_start = None
5.173 - self.optimiser.clear_active()
5.174 -
5.175 - def get_target_ops(self):
5.176 -
5.177 - "Return the assignment target instructions."
5.178 -
5.179 - return self.blocks[-1].code[self.target_start:]
5.180 -
5.181 - def assign_value(self, expr=None):
5.182 -
5.183 - """
5.184 - Set the source of an assignment using 'expr' or the current assignment
5.185 - value. This may set the source register of the current instruction.
5.186 - """
5.187 -
5.188 - expr = expr or self.expr_temp[-1]
5.189 -
5.190 - # Optimise away constant storage if appropriate.
5.191 -
5.192 - if self.optimiser.optimise_constant_storage(expr):
5.193 - self.remove_target_ops()
5.194 - return
5.195 -
5.196 - # Otherwise, insert the assignment source.
5.197 -
5.198 - expr_copy = expr.copy()
5.199 - assign_ops = self.get_target_ops()
5.200 -
5.201 - if not assign_ops:
5.202 - self.target_start = None
5.203 - return
5.204 -
5.205 - assign_op = assign_ops[-1]
5.206 -
5.207 - # Either insert the instruction yielding the value and adjust the
5.208 - # assignment source.
5.209 -
5.210 - expr_copy.target = "source"
5.211 -
5.212 - if self.insert_op(-1, expr_copy):
5.213 - assign_op.source = "source"
5.214 - self.update_temp(expr, expr_copy)
5.215 -
5.216 - # (Now, the instruction need not be inserted.)
5.217 -
5.218 - # Or transfer the working value to the source register.
5.219 -
5.220 - elif assign_op.working == "working":
5.221 - self.insert_op(-1, Transfer(source="working_context", target="source_context"))
5.222 - self.insert_op(-1, Transfer(source="working", target="source"))
5.223 - assign_op.source = "source"
5.224 -
5.225 - # Or let the assignment use the working register.
5.226 -
5.227 - else:
5.228 - assign_op.source = "working"
5.229 -
5.230 - self.target_start = None
5.231 -
5.232 - def set_target(self, target):
5.233 -
5.234 - "Reset the target of the active instruction to 'target'."
5.235 -
5.236 - self.optimiser.set_target("working", target)
5.237 -
5.238 - def is_immediate_user(self, node):
5.239 -
5.240 - """
5.241 - Return whether 'node' is an immediate user of an assignment expression.
5.242 - """
5.243 -
5.244 - return isinstance(node, (compiler.ast.AssName, compiler.ast.AssAttr))
5.245 -
5.246 - def has_immediate_usage(self, nodes):
5.247 -
5.248 - """
5.249 - Return whether 'nodes' are all immediate users of an assignment expression.
5.250 - """
5.251 -
5.252 - for n in nodes:
5.253 - if not self.is_immediate_user(n):
5.254 - return False
5.255 - return True
5.256 -
5.257 - # Temporary storage administration.
5.258 -
5.259 - def get_temp(self):
5.260 -
5.261 - """
5.262 - Return a temporary storage access instruction for the current value.
5.263 - Initially, this instruction is not associated with an allocated unit of
5.264 - temporary storage, and if used as a new instruction will not be added to
5.265 - the code, but if the current value changes, the 'set_temp' method will
5.266 - be called by the optimiser and a unit of storage will be allocated.
5.267 - """
5.268 -
5.269 - temp = LoadTemp(None)
5.270 - self.optimiser.request_active_value("working", temp, self.blocks[-1], len(self.blocks[-1].code))
5.271 - return temp
5.272 -
5.273 - def set_temp(self, temp, block, pos):
5.274 -
5.275 - """
5.276 - Emit a storage instruction for the given 'temp' loading instruction,
5.277 - reserving a new temporary storage location.
5.278 - """
5.279 -
5.280 - if temp.attr is None:
5.281 - temp.attr = self.reserve_temp()
5.282 - block.insert(pos, StoreTemp(temp.attr))
5.283 -
5.284 - def update_temp(self, temp, updated):
5.285 -
5.286 - "Update 'temp' using the given 'updated' instruction."
5.287 -
5.288 - if isinstance(temp, LoadTemp):
5.289 - temp.attr = updated.attr
5.290 -
5.291 - def reserve_temp(self, temp_position=None):
5.292 -
5.293 - """
5.294 - Reserve a new temporary storage position, or if the optional
5.295 - 'temp_position' is specified, ensure that this particular position is
5.296 - reserved.
5.297 - """
5.298 -
5.299 - if temp_position is not None:
5.300 - pass
5.301 - elif not self.temp_positions:
5.302 - temp_position = 0
5.303 - else:
5.304 - temp_position = max(self.temp_positions) + 1
5.305 -
5.306 - self.temp_positions.add(temp_position)
5.307 - self.max_temp_position = max(self.max_temp_position, temp_position)
5.308 - return self.unit.all_local_usage + temp_position # position in frame
5.309 -
5.310 - def ensure_temp(self, instruction=None):
5.311 -
5.312 - """
5.313 - Ensure that the 'instruction' is using a reserved temporary storage
5.314 - position.
5.315 - """
5.316 -
5.317 - if isinstance(instruction, LoadTemp):
5.318 - temp_position = instruction.attr - self.unit.all_local_usage
5.319 - self.reserve_temp(temp_position)
5.320 -
5.321 - def discard_temp(self, instruction=None):
5.322 -
5.323 - "Discard any temporary storage position used by 'instruction'."
5.324 -
5.325 - if isinstance(instruction, LoadTemp) and instruction.attr is not None:
5.326 - temp_position = instruction.attr - self.unit.all_local_usage
5.327 - self.free_temp(temp_position)
5.328 -
5.329 - # Prevent any requested active value from generating instructions now
5.330 - # that our interest in it has passed.
5.331 -
5.332 - self.optimiser.ignore_active_value("working")
5.333 -
5.334 - def free_temp(self, temp_position):
5.335 -
5.336 - "Free the temporary storage position specified by 'temp_position'."
5.337 -
5.338 - if temp_position in self.temp_positions:
5.339 - self.temp_positions.remove(temp_position)
5.340 -
5.341 - def set_frame_usage(self, node, extend):
5.342 -
5.343 - """
5.344 - Ensure that the frame usage for the unit associated with 'node' is set
5.345 - on the 'extend' instruction.
5.346 - """
5.347 -
5.348 - # Remove any ExtendFrame instructions which do nothing.
5.349 -
5.350 - if self.last_op() is extend:
5.351 - self.remove_op()
5.352 - return
5.353 -
5.354 - ntemp = self.max_temp_position + 1
5.355 - extend.attr = ntemp + node.unit.local_usage # NOTE: See get_code for similar code.
5.356 -
5.357 - # Code writing methods.
5.358 -
5.359 - def new_op(self, op):
5.360 -
5.361 - """
5.362 - Add 'op' to the generated code, returning a true value if an instruction
5.363 - was added.
5.364 - """
5.365 -
5.366 - if not self.check_op(op):
5.367 - return False
5.368 -
5.369 - # Add the operation to the current block.
5.370 -
5.371 - self.optimiser.set_new("working", op)
5.372 - self.blocks[-1].append(op)
5.373 - return True
5.374 -
5.375 - def insert_op(self, i, op):
5.376 -
5.377 - "Insert at index 'i' in the current block the instruction 'op'."
5.378 -
5.379 - if not self.check_op(op):
5.380 - return False
5.381 -
5.382 - self.blocks[-1].insert(i, op)
5.383 - return True
5.384 -
5.385 - def check_op(self, op):
5.386 -
5.387 - "Return whether the given 'op' is to be added to the code."
5.388 -
5.389 - # Optimise away temporary storage instructions where the active value is
5.390 - # still available and was not recorded.
5.391 -
5.392 - if isinstance(op, LoadTemp) and op.attr is None:
5.393 - return False
5.394 -
5.395 - # Optimise load operations employed by this instruction.
5.396 -
5.397 - if self.optimiser.optimise_away_no_operations(op) or self.optimiser.optimise_unused_handlers(op):
5.398 - return False
5.399 -
5.400 - return True
5.401 -
5.402 - def remove_op(self):
5.403 -
5.404 - "Remove the last instruction."
5.405 -
5.406 - op = self.blocks[-1].code.pop()
5.407 - self.optimiser.clear_active()
5.408 - return op
5.409 -
5.410 - def replace_op(self, op):
5.411 -
5.412 - "Replace the last added instruction with 'op'."
5.413 -
5.414 - self.remove_op()
5.415 - self.new_op(op)
5.416 -
5.417 - def replace_active_value(self, register, op):
5.418 -
5.419 - """
5.420 - Replace the active instruction providing 'register' with its value with
5.421 - the given 'op' if appropriate.
5.422 - """
5.423 -
5.424 - removed = self.optimiser.remove_active_value(register)
5.425 - self.new_op(op)
5.426 - return removed
5.427 -
5.428 - def last_op(self):
5.429 -
5.430 - "Return the last added instruction."
5.431 -
5.432 - try:
5.433 - return self.blocks[-1].code[-1]
5.434 - except IndexError:
5.435 - return None
5.436 -
5.437 - # Allocation-related methods.
5.438 -
5.439 - def make_instance(self, cls, n):
5.440 -
5.441 - """
5.442 - Request a new instance using the given class 'cls' and with 'n'
5.443 - attributes.
5.444 - """
5.445 -
5.446 - # Load the class in order to locate the instance template.
5.447 -
5.448 - self.new_op(LoadConst(cls))
5.449 -
5.450 - # NOTE: Instance headers are one location.
5.451 -
5.452 - self.new_op(MakeInstance(n + 1))
5.453 -
5.454 - def make_exception(self, name):
5.455 -
5.456 - "Make an exception of the given 'name' using 'node'."
5.457 -
5.458 - # NOTE: Reserving an attribute.
5.459 -
5.460 - self.make_instance(self.get_builtin_class(name), 1)
5.461 -
5.462 - # Name-related methods.
5.463 -
5.464 - def get_scope(self, name):
5.465 -
5.466 - "Return the scope for the given 'name'."
5.467 -
5.468 - attr, scope, from_name = self.unit._get_with_scope(name)
5.469 - return scope
5.470 -
5.471 - def load_builtin(self, name, node):
5.472 -
5.473 - "Generate an instruction loading 'name' for the given 'node'."
5.474 -
5.475 - self.new_op(LoadAddress(self.get_builtin(name)))
5.476 -
5.477 - def get_builtin_class(self, name):
5.478 -
5.479 - "Return the built-in class with the given 'name'."
5.480 -
5.481 - return self.get_builtin(name).get_value()
5.482 -
5.483 - def get_builtin(self, name):
5.484 -
5.485 - "Return the built-in module definition for the given 'name'."
5.486 -
5.487 - if self.builtins is not None:
5.488 - try:
5.489 - return self.builtins[name]
5.490 - except KeyError:
5.491 - raise TranslateError("No __builtins__ definition is available for name %r." % name)
5.492 - else:
5.493 - raise TranslateError("No __builtins__ module is available for name %r." % name)
5.494 -
5.495 -# vim: tabstop=4 expandtab shiftwidth=4
6.1 --- a/micropython/inspect.py Fri Jun 28 21:17:02 2013 +0200
6.2 +++ b/micropython/inspect.py Sat Jun 29 01:28:12 2013 +0200
6.3 @@ -115,7 +115,6 @@
6.4
6.5 # Import machinery links.
6.6
6.7 - self.optimisations = self.importer.optimisations
6.8 self.builtins = self.importer.modules.get("__builtins__")
6.9 self.loaded = False
6.10 self.completed = False
6.11 @@ -316,13 +315,12 @@
6.12 names.
6.13 """
6.14
6.15 - if self.should_optimise_unused_objects():
6.16 - self.vacuum_object(self)
6.17 + self.vacuum_object(self)
6.18
6.19 - all_objects = list(self.all_objects)
6.20 + all_objects = list(self.all_objects)
6.21
6.22 - for obj in all_objects:
6.23 - self.vacuum_object(obj)
6.24 + for obj in all_objects:
6.25 + self.vacuum_object(obj)
6.26
6.27 def vacuum_object(self, obj, delete_all=0):
6.28
6.29 @@ -399,11 +397,6 @@
6.30 if any_scope or not (self.namespaces and isinstance(self.namespaces[-1], Function)):
6.31 self.all_objects.add(obj)
6.32
6.33 - # Optimisation tests.
6.34 -
6.35 - def should_optimise_unused_objects(self):
6.36 - return "unused_objects" in self.optimisations
6.37 -
6.38 # Namespace methods.
6.39
6.40 def in_class(self, namespaces=None):
7.1 --- a/micropython/native.py Fri Jun 28 21:17:02 2013 +0200
7.2 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000
7.3 @@ -1,156 +0,0 @@
7.4 -#!/usr/bin/env python
7.5 -
7.6 -"""
7.7 -Native library generation.
7.8 -
7.9 -Copyright (C) 2007, 2008, 2009, 2010, 2011 Paul Boddie <paul@boddie.org.uk>
7.10 -
7.11 -This program is free software; you can redistribute it and/or modify it under
7.12 -the terms of the GNU General Public License as published by the Free Software
7.13 -Foundation; either version 3 of the License, or (at your option) any later
7.14 -version.
7.15 -
7.16 -This program is distributed in the hope that it will be useful, but WITHOUT
7.17 -ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
7.18 -FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
7.19 -details.
7.20 -
7.21 -You should have received a copy of the GNU General Public License along with
7.22 -this program. If not, see <http://www.gnu.org/licenses/>.
7.23 -"""
7.24 -
7.25 -from micropython.code import Assembler
7.26 -from micropython.rsvp import *
7.27 -
7.28 -class NativeLibrary(Assembler):
7.29 -
7.30 - "A native library generator providing common routines."
7.31 -
7.32 - def __init__(self, program):
7.33 -
7.34 - """
7.35 - Initialise a native library for the given 'program'.
7.36 - """
7.37 -
7.38 - Assembler.__init__(self, program)
7.39 -
7.40 - self.importer = self.program.get_importer()
7.41 - self.builtins = None
7.42 -
7.43 - self.unknown_target_block = None
7.44 - self.unknown_target_testable_self_block = None
7.45 - self.known_target_testable_self_block = None
7.46 -
7.47 - # Reset the assembler.
7.48 -
7.49 - self.reset()
7.50 -
7.51 - def get_native_code(self):
7.52 - self.builtins = self.importer.modules.get("__builtins__")
7.53 -
7.54 - if self.unknown_target_block is not None:
7.55 - self._generateCallFuncUnknownTarget()
7.56 -
7.57 - if self.unknown_target_testable_self_block is not None:
7.58 - self._generateCallFuncUnknownTargetTestableSelf()
7.59 -
7.60 - if self.known_target_testable_self_block is not None:
7.61 - self._generateCallFuncKnownTargetTestableSelf()
7.62 -
7.63 - return self.blocks
7.64 -
7.65 - def _commonCallFunc(self, adjust_block, continue_block):
7.66 - self.new_op(CheckContext(working="source", target="status"))
7.67 - self.new_op(JumpIfFalse(adjust_block, working="status"))
7.68 -
7.69 - # Skip adjustment and tests if the context is not a class.
7.70 - # Classes themselves employ a placeholder context so that
7.71 - # instantiators can be callable with a context which will be
7.72 - # overwritten in the frame.
7.73 -
7.74 - # Here, the source value should still refer to the context.
7.75 -
7.76 - self.new_op(CheckClass(working="source", target="status"))
7.77 - self.new_op(JumpIfFalse(continue_block, working="status"))
7.78 -
7.79 - def _commonTestContext(self, success_block):
7.80 - self.new_op(CheckInstance(source="source", target="status"))
7.81 - self.new_op(JumpIfTrue(success_block, working="status"))
7.82 -
7.83 - # Where the context is inappropriate, drop the incomplete frame and
7.84 - # raise an exception.
7.85 -
7.86 - self.new_op(DropFrame())
7.87 -
7.88 - self.make_exception("TypeError")
7.89 - self.set_target("exception")
7.90 - self.new_op(RaiseException())
7.91 -
7.92 - def _commonAdjustFrame(self, adjust_block, continue_block):
7.93 - self.set_block(adjust_block)
7.94 - self.new_op(AdjustFrame(1))
7.95 - self.set_block(continue_block)
7.96 -
7.97 - def getCallFuncUnknownTarget(self):
7.98 - if self.unknown_target_block is None:
7.99 - self.unknown_target_block = self.new_block()
7.100 -
7.101 - return self.unknown_target_block
7.102 -
7.103 - def _generateCallFuncUnknownTarget(self):
7.104 -
7.105 - """
7.106 - Some preliminary tests where the target of an invocation is not known.
7.107 - Requires the context in the working value register.
7.108 - """
7.109 -
7.110 - adjust_block = self.new_block()
7.111 - continue_block = self.new_block()
7.112 -
7.113 - self.set_block(self.unknown_target_block)
7.114 - self._commonCallFunc(adjust_block, continue_block)
7.115 - self._commonAdjustFrame(adjust_block, continue_block)
7.116 - self.new_op(Return())
7.117 -
7.118 - def getCallFuncUnknownTargetTestableSelf(self):
7.119 - if self.unknown_target_testable_self_block is None:
7.120 - self.unknown_target_testable_self_block = self.new_block()
7.121 -
7.122 - return self.unknown_target_testable_self_block
7.123 -
7.124 - def _generateCallFuncUnknownTargetTestableSelf(self):
7.125 -
7.126 - """
7.127 - Test any explicit first argument against the context.
7.128 - """
7.129 -
7.130 - adjust_block = self.new_block()
7.131 - continue_block = self.new_block()
7.132 -
7.133 - self.set_block(self.unknown_target_testable_self_block)
7.134 - self._commonCallFunc(adjust_block, continue_block)
7.135 - self._commonTestContext(adjust_block)
7.136 - self._commonAdjustFrame(adjust_block, continue_block)
7.137 - self.new_op(Return())
7.138 -
7.139 - def getCallFuncKnownTargetTestableSelf(self):
7.140 - if self.known_target_testable_self_block is None:
7.141 - self.known_target_testable_self_block = self.new_block()
7.142 -
7.143 - return self.known_target_testable_self_block
7.144 -
7.145 - def _generateCallFuncKnownTargetTestableSelf(self):
7.146 -
7.147 - """
7.148 - Test any explicit first argument against the context.
7.149 - """
7.150 -
7.151 - adjust_block = self.new_block()
7.152 - continue_block = self.new_block()
7.153 -
7.154 - self.set_block(self.known_target_testable_self_block)
7.155 - self._commonTestContext(continue_block)
7.156 - self._commonAdjustFrame(adjust_block, continue_block)
7.157 - self.new_op(Return())
7.158 -
7.159 -# vim: tabstop=4 expandtab shiftwidth=4
8.1 --- a/micropython/opt.py Fri Jun 28 21:17:02 2013 +0200
8.2 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000
8.3 @@ -1,538 +0,0 @@
8.4 -#!/usr/bin/env python
8.5 -
8.6 -"""
8.7 -Optimise code produced by the AST translator.
8.8 -
8.9 -Copyright (C) 2007, 2008, 2009, 2010, 2011 Paul Boddie <paul@boddie.org.uk>
8.10 -
8.11 -This program is free software; you can redistribute it and/or modify it under
8.12 -the terms of the GNU General Public License as published by the Free Software
8.13 -Foundation; either version 3 of the License, or (at your option) any later
8.14 -version.
8.15 -
8.16 -This program is distributed in the hope that it will be useful, but WITHOUT
8.17 -ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
8.18 -FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
8.19 -details.
8.20 -
8.21 -You should have received a copy of the GNU General Public License along with
8.22 -this program. If not, see <http://www.gnu.org/licenses/>.
8.23 -"""
8.24 -
8.25 -from micropython.common import *
8.26 -from micropython.data import *
8.27 -from micropython.rsvp import *
8.28 -
8.29 -class Optimiser:
8.30 -
8.31 - "A code optimiser."
8.32 -
8.33 - supported_optimisations = [
8.34 - # Code generation optimisations:
8.35 - "constant_storage", "constant_accessor", "known_target", "self_access",
8.36 - "temp_storage", "no_operations", "unused_results",
8.37 - "unused_handlers", "accesses_by_usage",
8.38 - # Inspection optimisations:
8.39 - "unused_objects"
8.40 - ]
8.41 -
8.42 - def __init__(self, translation, optimisations=None):
8.43 -
8.44 - """
8.45 - Provide for the given 'translation' an optimiser for the desired
8.46 - 'optimisations'. See the 'supported_optimisations' attribute of this
8.47 - class for permitted values.
8.48 - """
8.49 -
8.50 - self.translation = translation
8.51 - self.optimisations = set(optimisations or [])
8.52 -
8.53 - # The current "active" instruction.
8.54 - # As a rule, this will become the last instruction, but some
8.55 - # control-flow operations will flush the "active" instruction.
8.56 -
8.57 - self.active = None
8.58 -
8.59 - # Information about instructions providing the active values for
8.60 - # registers.
8.61 -
8.62 - self.saved_value_op = {}
8.63 - self.saved_value_block = {}
8.64 - self.saved_value_pos = {}
8.65 -
8.66 - # Sets of instructions providing the active value for each register.
8.67 -
8.68 - self.active_values = {}
8.69 -
8.70 - def get_attribute_store_instructions(self):
8.71 -
8.72 - """
8.73 - Return an appropriate set of instructions available when storing
8.74 - attributes.
8.75 - """
8.76 -
8.77 - ca = self.should_optimise_accesses_by_attribute_usage()
8.78 -
8.79 - return (
8.80 - ca and StoreAddress or None, # plain assignment
8.81 - ca and StoreAddressContext or None, # assignment via class
8.82 - ca and StoreAddressContext or None, # assignment via class (never via instance)
8.83 - StoreAttr, # assignment via instance
8.84 - StoreAttrIndex, # special assignment via instance
8.85 - None
8.86 - )
8.87 -
8.88 - def reset(self, block=None, blocks=None):
8.89 -
8.90 - """
8.91 - Reset the optimiser for the given 'block' (or the current block),
8.92 - clearing the active value instructions if no 'blocks' are given, or
8.93 - collecting the active instructions from each of the blocks otherwise.
8.94 - """
8.95 -
8.96 - self.store_active_values()
8.97 - self.clear_active()
8.98 -
8.99 - # Make a new collection of instructions for a new block.
8.100 -
8.101 - if block:
8.102 - self.active_values = {}
8.103 - block.set_active_values(self.active_values)
8.104 -
8.105 - # Otherwise, clear the collection for an existing block.
8.106 -
8.107 - else:
8.108 - self.active_values.clear()
8.109 -
8.110 - if blocks:
8.111 - for b in blocks:
8.112 - self.active_values.update(b.get_active_values())
8.113 -
8.114 - def set_new(self, register, op):
8.115 -
8.116 - "For 'register', set the latest 'op' as the active instruction."
8.117 -
8.118 - self.set_active(op)
8.119 - self.set_active_value(register, op)
8.120 -
8.121 - def set_active_value(self, register, op):
8.122 -
8.123 - "For 'register', set 'op' as the value-providing active instruction."
8.124 -
8.125 - # Since the current value provider may eventually be used, it needs to
8.126 - # store its output if appropriate.
8.127 -
8.128 - self.store_active_value(register)
8.129 - self.active_values[register] = set([op])
8.130 -
8.131 - def get_active_value(self, register):
8.132 -
8.133 - """
8.134 - Get any single active value for the given 'register' or None if none or
8.135 - more than one exist.
8.136 - """
8.137 -
8.138 - if self.active_values.has_key(register) and \
8.139 - len(self.active_values[register]) == 1:
8.140 -
8.141 - return list(self.active_values[register])[0]
8.142 -
8.143 - else:
8.144 - return None
8.145 -
8.146 - def remove_active_value(self, register):
8.147 -
8.148 - """
8.149 - Remove the active instruction providing 'register' with its value from
8.150 - the generated code, if appropriate, and return the active instruction.
8.151 - """
8.152 -
8.153 - if self.active_values.has_key(register) and \
8.154 - self.active in self.active_values[register]:
8.155 -
8.156 - removed = self.translation.remove_op()
8.157 - self.active_values[register].remove(removed)
8.158 - return removed
8.159 -
8.160 - else:
8.161 - return None
8.162 -
8.163 - def set_target(self, register, target):
8.164 -
8.165 - """
8.166 - Set the target of the active instruction involving 'register' to
8.167 - 'target'.
8.168 - """
8.169 -
8.170 - if self.active_values.has_key(register):
8.171 - for expr in self.active_values[register]:
8.172 - expr.target = target
8.173 -
8.174 - # Transfer the active instructions to their new target.
8.175 -
8.176 - if not self.active_values.has_key(target):
8.177 - self.active_values[target] = self.active_values[register]
8.178 - else:
8.179 - self.active_values[target].update(self.active_values[register])
8.180 -
8.181 - # Remove the association between the instructions and the specified
8.182 - # register.
8.183 -
8.184 - del self.active_values[register]
8.185 -
8.186 - def set_active(self, op):
8.187 -
8.188 - "Set the active instruction."
8.189 -
8.190 - self.active = op
8.191 -
8.192 - def clear_active(self):
8.193 -
8.194 - "Clear the active instructions."
8.195 -
8.196 - self.active = None
8.197 -
8.198 - # Permit the active value to be requested and restored.
8.199 -
8.200 - def request_active_value(self, register, temp, block, pos):
8.201 -
8.202 - """
8.203 - Request the current active value for 'register' so that if the value is
8.204 - changed, a temporary storage element or equivalent will be allocated.
8.205 - """
8.206 -
8.207 - # Cause any previously active value for the register to be saved.
8.208 -
8.209 - self.store_active_value(register)
8.210 -
8.211 - # Redefine the active value for the register.
8.212 -
8.213 - self.saved_value_op[register] = temp
8.214 - self.saved_value_block[register] = block
8.215 - self.saved_value_pos[register] = pos
8.216 -
8.217 - def store_active_values(self):
8.218 -
8.219 - "Store all active values."
8.220 -
8.221 - for register in self.active_values.keys():
8.222 - self.store_active_value(register)
8.223 -
8.224 - def store_active_value(self, register):
8.225 -
8.226 - "Store the requested active value for 'register'."
8.227 -
8.228 - if self.saved_value_op.has_key(register):
8.229 -
8.230 - # Cause an instruction to be inserted to store the active value for
8.231 - # the register, thus keeping it available for any subsequent usage.
8.232 -
8.233 - self.translation.set_temp(
8.234 - self.saved_value_op[register], # cause the storage of the value
8.235 - self.saved_value_block[register], # in the appropriate block
8.236 - self.saved_value_pos[register] # at the appropriate location
8.237 - )
8.238 -
8.239 - # Discard the existing active value information.
8.240 -
8.241 - self.ignore_active_value(register)
8.242 -
8.243 - def ignore_active_value(self, register):
8.244 -
8.245 - "Ignore the active value in 'register'."
8.246 -
8.247 - if self.saved_value_op.has_key(register):
8.248 - del self.saved_value_op[register]
8.249 - del self.saved_value_block[register]
8.250 - del self.saved_value_pos[register]
8.251 -
8.252 - # Optimisation tests.
8.253 -
8.254 - def should_optimise_constant_storage(self):
8.255 - return "constant_storage" in self.optimisations
8.256 -
8.257 - def should_optimise_constant_accessor(self):
8.258 - return "constant_accessor" in self.optimisations
8.259 -
8.260 - def should_optimise_known_target(self):
8.261 - return "known_target" in self.optimisations
8.262 -
8.263 - def should_optimise_self_access(self):
8.264 - return "self_access" in self.optimisations
8.265 -
8.266 - def should_optimise_temp_storage(self):
8.267 - return "temp_storage" in self.optimisations
8.268 -
8.269 - def should_optimise_away_no_operations(self):
8.270 - return "no_operations" in self.optimisations
8.271 -
8.272 - def should_optimise_unused_results(self):
8.273 - return "unused_results" in self.optimisations
8.274 -
8.275 - def should_optimise_unused_handlers(self):
8.276 - return "unused_handlers" in self.optimisations
8.277 -
8.278 - def should_optimise_accesses_by_attribute_usage(self):
8.279 - return "accesses_by_usage" in self.optimisations
8.280 -
8.281 - # Simple tests.
8.282 -
8.283 - def is_constant_input(self, instruction):
8.284 -
8.285 - "Return whether 'instruction' provides a constant input."
8.286 -
8.287 - return isinstance(instruction, LoadAddress) and instruction.attr.assignments == 1 and \
8.288 - isinstance(instruction.attr.get_value(), Constant) or \
8.289 - isinstance(instruction, (LoadConst, LoadClass, LoadFunction))
8.290 -
8.291 - def is_constant_target(self, instruction):
8.292 -
8.293 - "Return whether 'instruction' provides a constant target."
8.294 -
8.295 - # NOTE: Removed StoreName, since this would then demand population of
8.296 - # NOTE: locals/frames.
8.297 -
8.298 - return isinstance(instruction, (StoreAddress, StoreAddressContext)) and \
8.299 - instruction.attr.is_constant() and \
8.300 - instruction.attr.is_strict_constant()
8.301 -
8.302 - def is_simple_input(self, instruction):
8.303 -
8.304 - """
8.305 - Return whether 'instruction' provides a simple input (typically a load
8.306 - instruction). A simple input is something which would be represented by
8.307 - a load operation from a CPU register or special memory location.
8.308 - """
8.309 -
8.310 - return isinstance(instruction, (LoadConst, LoadClass, LoadFunction,
8.311 - LoadName, LoadTemp, LoadAddress
8.312 - ))
8.313 -
8.314 - def is_resultant_no_operation(self, instruction, last_op=None):
8.315 -
8.316 - """
8.317 - Return whether 'instruction' merely stores its input where the input
8.318 - originally came from.
8.319 - """
8.320 -
8.321 - last_op = last_op or self.translation.last_op()
8.322 - return last_op and last_op.attr == instruction.attr and (
8.323 - isinstance(instruction, StoreTemp) and isinstance(last_op, LoadTemp) or
8.324 - isinstance(instruction, StoreAddress) and isinstance(last_op, LoadAddress) or
8.325 - last_op.source == instruction.target and (
8.326 - isinstance(instruction, LoadTemp) and isinstance(last_op, StoreTemp) or
8.327 - isinstance(instruction, LoadAddress) and isinstance(last_op, StoreAddress)
8.328 - ))
8.329 -
8.330 - # Convenience tests on outputs.
8.331 -
8.332 - def have_constant_target(self):
8.333 -
8.334 - "Return whether the active instruction provides a constant target."
8.335 -
8.336 - return self.is_constant_target(self.active)
8.337 -
8.338 - def have_constant_source(self, expr):
8.339 -
8.340 - "Return whether the active assignment source instruction is constant."
8.341 -
8.342 - return self.is_constant_input(expr)
8.343 -
8.344 - # Convenience tests on inputs.
8.345 -
8.346 - def have_constant_input(self):
8.347 -
8.348 - "Return whether the active instruction provides a constant input."
8.349 -
8.350 - return self.get_active_value("working") and self.is_constant_input(self.get_active_value("working"))
8.351 -
8.352 - def have_simple_input(self):
8.353 -
8.354 - "Return whether the active instruction provides a simple input."
8.355 -
8.356 - return self.get_active_value("working") and self.is_simple_input(self.get_active_value("working"))
8.357 -
8.358 - # Indicate whether the active instruction can be used in place of access
8.359 - # to a temporary variable retaining the result of the last instruction.
8.360 -
8.361 - have_temp_compatible_access = have_simple_input
8.362 -
8.363 - def have_self_input(self, unit):
8.364 -
8.365 - """
8.366 - Return whether the active instruction is a reference to self in the
8.367 - given 'unit'.
8.368 - """
8.369 -
8.370 - if not (isinstance(unit, Function) and unit.is_method()):
8.371 - return False
8.372 -
8.373 - expr = self.get_active_value("working")
8.374 - return expr and isinstance(expr, LoadName) and expr.attr.name == "self"
8.375 -
8.376 - def have_correct_self_for_target(self, context, unit):
8.377 -
8.378 - "Return whether the 'context' is compatible with the given 'unit'."
8.379 -
8.380 - if context is not None and self.have_self_input(unit):
8.381 -
8.382 - parent = unit.parent
8.383 - if parent is context or parent.has_subclass(context) or context.has_subclass(parent):
8.384 - return True
8.385 -
8.386 - return False
8.387 -
8.388 - def have_empty_handler(self, instruction):
8.389 -
8.390 - """
8.391 - Return whether the active instruction defined a handler for exceptions
8.392 - which is then discarded by the given 'instruction'.
8.393 - """
8.394 -
8.395 - return isinstance(self.translation.last_op(), PushHandler) and isinstance(instruction, PopHandler)
8.396 -
8.397 - # Optimisation methods. See the supported_optimisations class attribute.
8.398 -
8.399 - def optimise_constant_storage(self, expr):
8.400 -
8.401 - """
8.402 - Where the last operation stores a constant into a target which is also
8.403 - constant, indicate that both operations should be optimised away.
8.404 - """
8.405 -
8.406 - return self.should_optimise_constant_storage() and \
8.407 - self.have_constant_target() and \
8.408 - self.have_constant_source(expr)
8.409 -
8.410 - def optimise_constant_accessor(self):
8.411 -
8.412 - """
8.413 - Where the object whose attribute is being accessed is constant, provide
8.414 - information about the object and its full name.
8.415 - """
8.416 -
8.417 - if self.should_optimise_constant_accessor() and self.have_constant_input():
8.418 - value = self.get_active_value("working")
8.419 -
8.420 - # Get the details of the access.
8.421 -
8.422 - if isinstance(value.attr, Const):
8.423 - return value.attr, value.attr.value_type_name()
8.424 - else:
8.425 - target = value.attr.get_value()
8.426 -
8.427 - if target is None:
8.428 - return None # no clearly defined target
8.429 - elif isinstance(target, Const):
8.430 - return target, target.value_type_name()
8.431 - elif isinstance(target, Instance):
8.432 - return None # skip production of optimised code
8.433 - else:
8.434 - return target, target.full_name()
8.435 -
8.436 - else:
8.437 - return None
8.438 -
8.439 - def optimise_known_target(self):
8.440 -
8.441 - """
8.442 - Where the target of an invocation is known, provide information about it
8.443 - and its context. If a class is being invoked and the conditions are
8.444 - appropriate, get information about the specific initialiser.
8.445 - """
8.446 -
8.447 - if self.should_optimise_known_target() and self.have_constant_input():
8.448 - value = self.get_active_value("working")
8.449 - target = value.attr.get_value()
8.450 - context = value.attr.get_context()
8.451 -
8.452 - # Return target details only if this is clearly defined.
8.453 -
8.454 - if target is not None:
8.455 - return target, context
8.456 -
8.457 - return None
8.458 -
8.459 - def optimise_self_access(self, unit, attrname):
8.460 -
8.461 - """
8.462 - Return whether code in the given 'unit' is able to access the given
8.463 - 'attrname' through the same position in all possible objects which might
8.464 - be accessed.
8.465 - """
8.466 -
8.467 - return self.should_optimise_self_access() and \
8.468 - self.have_self_input(unit) and not unit.is_relocated(attrname)
8.469 -
8.470 - def optimise_temp_storage(self):
8.471 -
8.472 - """
8.473 - Where the next operation would involve storing a value into temporary
8.474 - storage, record and remove any simple instruction which produced the
8.475 - value to be stored such that instead of subsequently accessing the
8.476 - temporary storage, that instruction is substituted.
8.477 -
8.478 - If no optimisation can be achieved, temporary storage is requested
8.479 - and the appropriate LoadTemp instruction is returned.
8.480 -
8.481 - Restriction: for use only in situations where the source of the
8.482 - temporary data will not be disturbed between its first access and its
8.483 - subsequent use.
8.484 - """
8.485 -
8.486 - if self.should_optimise_temp_storage():
8.487 -
8.488 - # Emitted instructions can be obtained.
8.489 -
8.490 - if self.have_temp_compatible_access():
8.491 -
8.492 - # Remove the active value contributor if possible.
8.493 -
8.494 - removed = self.remove_active_value("working")
8.495 - if removed is not None:
8.496 -
8.497 - # Extend the lifetime of any temporary storage location.
8.498 -
8.499 - self.translation.ensure_temp(removed)
8.500 - return removed
8.501 -
8.502 - # Otherwise, just leave it in place, but return the instruction.
8.503 -
8.504 - else:
8.505 - return self.get_active_value("working")
8.506 -
8.507 - # Or provisional temporary instructions.
8.508 -
8.509 - elif self.saved_value_op.has_key("working"):
8.510 - return self.saved_value_op["working"]
8.511 -
8.512 - return self.translation.get_temp()
8.513 -
8.514 - def optimise_away_no_operations(self, instruction, last_op=None):
8.515 -
8.516 - """
8.517 - Optimise away operations which just store their inputs in the place
8.518 - the inputs originally came from.
8.519 - """
8.520 -
8.521 - return self.should_optimise_away_no_operations() and \
8.522 - self.is_resultant_no_operation(instruction, last_op)
8.523 -
8.524 - def optimise_unused_results(self):
8.525 -
8.526 - "Discard results which will not be used."
8.527 -
8.528 - if self.should_optimise_unused_results() and self.have_simple_input():
8.529 - self.remove_active_value("working")
8.530 -
8.531 - def optimise_unused_handlers(self, instruction):
8.532 -
8.533 - "Discard handlers which will not be used."
8.534 -
8.535 - if self.should_optimise_unused_handlers() and self.have_empty_handler(instruction):
8.536 - self.translation.remove_op()
8.537 - return True
8.538 - else:
8.539 - return False
8.540 -
8.541 -# vim: tabstop=4 expandtab shiftwidth=4
9.1 --- a/micropython/program.py Fri Jun 28 21:17:02 2013 +0200
9.2 +++ b/micropython/program.py Sat Jun 29 01:28:12 2013 +0200
9.3 @@ -3,7 +3,7 @@
9.4 """
9.5 Program code and data representations.
9.6
9.7 -Copyright (C) 2007, 2008, 2009, 2010, 2011, 2012 Paul Boddie <paul@boddie.org.uk>
9.8 +Copyright (C) 2007, 2008, 2009, 2010, 2011, 2012, 2013 Paul Boddie <paul@boddie.org.uk>
9.9
9.10 This program is free software; you can redistribute it and/or modify it under
9.11 the terms of the GNU General Public License as published by the Free Software
9.12 @@ -19,123 +19,6 @@
9.13 this program. If not, see <http://www.gnu.org/licenses/>.
9.14 """
9.15
9.16 -try:
9.17 - set
9.18 -except NameError:
9.19 - from sets import Set as set
9.20 -
9.21 -class Location:
9.22 -
9.23 - """
9.24 - A special representation for locations which are to be compared to program
9.25 - objects.
9.26 - """
9.27 -
9.28 - def __init__(self, location):
9.29 - self.location = location
9.30 -
9.31 - def _op(self, other, op):
9.32 - if hasattr(other, "location"):
9.33 - return op(self.location, other.location)
9.34 - else:
9.35 - raise NotImplemented
9.36 -
9.37 - def __eq__(self, other):
9.38 - return self._op(other, operator.eq)
9.39 -
9.40 - def __ne__(self, other):
9.41 - return self._op(other, operator.ne)
9.42 -
9.43 - def __lt__(self, other):
9.44 - return self._op(other, operator.lt)
9.45 -
9.46 - def __le__(self, other):
9.47 - return self._op(other, operator.le)
9.48 -
9.49 - def __gt__(self, other):
9.50 - return self._op(other, operator.gt)
9.51 -
9.52 - def __ge__(self, other):
9.53 - return self._op(other, operator.ge)
9.54 -
9.55 - def __repr__(self):
9.56 - return "Location(%r)" % self.location
9.57 -
9.58 -class Block:
9.59 -
9.60 - "A code block."
9.61 -
9.62 - def __init__(self, unit):
9.63 - self.unit = unit
9.64 - self.code = []
9.65 - self.location = None
9.66 - self.active_values = set()
9.67 -
9.68 - def __repr__(self):
9.69 - return "Block(%r, id=%r, location=%r)" % (self.unit, id(self), self.location)
9.70 -
9.71 - def set_active_values(self, values):
9.72 - self.active_values = values
9.73 -
9.74 - def get_active_values(self):
9.75 - return self.active_values
9.76 -
9.77 - def insert(self, pos, op):
9.78 - self.code.insert(pos, op)
9.79 -
9.80 - def append(self, op):
9.81 - self.code.append(op)
9.82 -
9.83 - def __len__(self):
9.84 - return len(self.code)
9.85 -
9.86 -class DataValue:
9.87 -
9.88 - "A representation of a raw program value."
9.89 -
9.90 - def __init__(self, context, ref):
9.91 - self.context = context
9.92 - self.ref = ref
9.93 -
9.94 - def __repr__(self):
9.95 - return "value: (%r, %r)" % (
9.96 - self.context, self.ref
9.97 - )
9.98 -
9.99 -class DataObject:
9.100 -
9.101 - "A representation of a raw program data object."
9.102 -
9.103 - def __init__(self, classcode, attrcode, codeaddr, name, size, funccode=None):
9.104 - self.classcode = classcode
9.105 - self.attrcode = attrcode
9.106 - self.codeaddr = codeaddr
9.107 - self.name = name
9.108 - self.size = size
9.109 - self.funccode = funccode
9.110 -
9.111 - def with_size(self, size):
9.112 - return DataObject(self.classcode, self.attrcode, self.codeaddr, self.name, size, self.funccode)
9.113 -
9.114 - def with_callable(self, codeaddr):
9.115 - return DataObject(self.classcode, self.attrcode, codeaddr, self.name, self.size, self.funccode)
9.116 -
9.117 - def __repr__(self):
9.118 - return "object: %r # %s" % (
9.119 - (self.classcode, self.attrcode, self.codeaddr, self.funccode, self.size), self.name
9.120 - )
9.121 -
9.122 -class FragmentObject:
9.123 -
9.124 - "A representation of a list fragment, used by list instances."
9.125 -
9.126 - def __init__(self, occupied_size, allocated_size):
9.127 - self.occupied_size = occupied_size
9.128 - self.allocated_size = allocated_size
9.129 -
9.130 - def __repr__(self):
9.131 - return "%r" % ((self.occupied_size, self.allocated_size),)
9.132 -
9.133 class Context:
9.134
9.135 """
10.1 --- a/micropython/raw.py Fri Jun 28 21:17:02 2013 +0200
10.2 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000
10.3 @@ -1,77 +0,0 @@
10.4 -#!/usr/bin/env python
10.5 -
10.6 -"""
10.7 -Classes used to help with the generation of raw image data.
10.8 -
10.9 -Copyright (C) 2009, 2010, 2011, 2012 Paul Boddie <paul@boddie.org.uk>
10.10 -
10.11 -This program is free software; you can redistribute it and/or modify it under
10.12 -the terms of the GNU General Public License as published by the Free Software
10.13 -Foundation; either version 3 of the License, or (at your option) any later
10.14 -version.
10.15 -
10.16 -This program is distributed in the hope that it will be useful, but WITHOUT
10.17 -ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
10.18 -FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
10.19 -details.
10.20 -
10.21 -You should have received a copy of the GNU General Public License along with
10.22 -this program. If not, see <http://www.gnu.org/licenses/>.
10.23 -"""
10.24 -
10.25 -class RawObject:
10.26 -
10.27 - "The basis for serialised program objects."
10.28 -
10.29 - def __init__(self, item):
10.30 - self.item = item
10.31 -
10.32 - def set_location(self, location, objtable, with_builtins):
10.33 - self.item.location = location
10.34 - return location + 1
10.35 -
10.36 - def finalise_location(self, with_builtins):
10.37 - pass
10.38 -
10.39 - def finalise_body_location(self, with_builtins):
10.40 - pass
10.41 -
10.42 - def is_generated(self, with_builtins):
10.43 - return with_builtins or self.item.module.name not in ("__builtins__", "native") or self.item.astnode.doc is not None
10.44 -
10.45 -class UntranslatableInstruction(Exception):
10.46 - pass
10.47 -
10.48 -class RSVPTranslator:
10.49 -
10.50 - "A class which provides the basis for the translation of RSVP instructions."
10.51 -
10.52 - def get_method(self, instruction):
10.53 -
10.54 - "Return the handler method for the given 'instruction'."
10.55 -
10.56 - instruction_name = instruction.__class__.__name__
10.57 - method = getattr(self, instruction_name, None)
10.58 - if method is None:
10.59 - raise UntranslatableInstruction, instruction_name
10.60 - return method
10.61 -
10.62 - def perform(self, instruction):
10.63 -
10.64 - "Perform the 'instruction', returning the next PC value or None."
10.65 -
10.66 - self.get_method(instruction)()
10.67 -
10.68 - def translate(self, code):
10.69 -
10.70 - "Translate the given 'code'."
10.71 -
10.72 - self.output_code = []
10.73 -
10.74 - for instruction in code:
10.75 - self.perform(instruction)
10.76 -
10.77 - def new_op(self, op):
10.78 - self.output_code.append(op)
10.79 -
10.80 -# vim: tabstop=4 expandtab shiftwidth=4
11.1 --- a/micropython/rsvp.py Fri Jun 28 21:17:02 2013 +0200
11.2 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000
11.3 @@ -1,729 +0,0 @@
11.4 -#!/usr/bin/env python
11.5 -
11.6 -"""
11.7 -RSVP instruction and serialisation classes.
11.8 -
11.9 -Copyright (C) 2007, 2008, 2009, 2010, 2011, 2012 Paul Boddie <paul@boddie.org.uk>
11.10 -
11.11 -This program is free software; you can redistribute it and/or modify it under
11.12 -the terms of the GNU General Public License as published by the Free Software
11.13 -Foundation; either version 3 of the License, or (at your option) any later
11.14 -version.
11.15 -
11.16 -This program is distributed in the hope that it will be useful, but WITHOUT
11.17 -ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
11.18 -FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
11.19 -details.
11.20 -
11.21 -You should have received a copy of the GNU General Public License along with
11.22 -this program. If not, see <http://www.gnu.org/licenses/>.
11.23 -"""
11.24 -
11.25 -from micropython.data import Attr, Const, Class, Function, Module
11.26 -from micropython.program import Block, DataObject, DataValue, PlaceholderContext
11.27 -from micropython.raw import RawObject
11.28 -
11.29 -def name(attr):
11.30 - if isinstance(attr, Attr):
11.31 - return attr.name or "<unnamed>"
11.32 - elif isinstance(attr, (Block, Const)):
11.33 - return attr
11.34 - else:
11.35 - return attr.full_name() or "<unnamed>"
11.36 -
11.37 -# Serialisation-related classes.
11.38 -
11.39 -class RSVPObject(RawObject):
11.40 -
11.41 - "A generic data object wrapper."
11.42 -
11.43 - def _finalise_location(self, with_builtins):
11.44 -
11.45 - """
11.46 - Set the code body location for items now that the code blocks have been
11.47 - positioned.
11.48 - """
11.49 -
11.50 - item = self.item
11.51 -
11.52 - if not self.is_generated(with_builtins):
11.53 - item.code_body_location = item.full_name()
11.54 - else:
11.55 - item.code_body_location = item.get_body_block().location
11.56 -
11.57 -class RSVPAttr(RSVPObject):
11.58 -
11.59 - "A wrapper for attributes/values."
11.60 -
11.61 - def as_raw(self, objtable, paramtable, with_builtins):
11.62 - item = self.item
11.63 - return [
11.64 - DataValue(
11.65 - item.get_context() and item.get_context().location,
11.66 - item.get_value() and item.get_value().location
11.67 - )
11.68 - ]
11.69 -
11.70 -class RSVPBlock(RSVPObject):
11.71 -
11.72 - "A wrapper for blocks."
11.73 -
11.74 - def set_location(self, location, objtable, with_builtins):
11.75 - item = self.item
11.76 - item.location = location
11.77 - return location + len(item.code)
11.78 -
11.79 - def as_raw(self, objtable, paramtable, with_builtins):
11.80 - return self.item.code
11.81 -
11.82 -class RSVPClass(RSVPObject):
11.83 -
11.84 - "A wrapper for classes."
11.85 -
11.86 - def set_location(self, location, objtable, with_builtins):
11.87 - self.item.instance_template_location = location
11.88 -
11.89 - # Include the instance template and __class__ attribute in the size.
11.90 -
11.91 - return RSVPObject.set_location(self, location + 1, objtable, with_builtins)
11.92 -
11.93 - def finalise_body_location(self, with_builtins):
11.94 - self._finalise_location(with_builtins)
11.95 -
11.96 - def as_raw(self, objtable, paramtable, with_builtins):
11.97 - item = self.item
11.98 - classcode = objtable.as_list().get_code(item.full_name())
11.99 - attrcode = objtable.get_index("#" + item.full_name())
11.100 -
11.101 - # Include a template of an instance for use when instantiating classes.
11.102 -
11.103 - call_method = item.all_class_attributes().get("__call__")
11.104 - call_method_value = call_method and call_method.get_value()
11.105 - call_method_code_location = call_method_value and call_method_value.code_location
11.106 - call_method_funccode = call_method_value and paramtable.as_list().get_code(call_method_value.full_name())
11.107 -
11.108 - instantiator_funccode = paramtable.as_list().get_code(item.get_instantiator().full_name())
11.109 -
11.110 - # NOTE: The instantiator code is the first block of the class.
11.111 -
11.112 - if not self.is_generated(with_builtins):
11.113 - instantiator_code_location = item.full_name()
11.114 - else:
11.115 - instantiator_code_location = item.get_instantiator().blocks[0].location
11.116 -
11.117 - return [
11.118 -
11.119 - # Template instance...
11.120 -
11.121 - DataObject(
11.122 - classcode,
11.123 - attrcode, # is instance
11.124 - call_method_code_location,
11.125 - item.full_name(),
11.126 - len(item.instance_attributes()), # size (excluding __class__)
11.127 - call_method_funccode # funccode
11.128 - ),
11.129 -
11.130 - # Class...
11.131 -
11.132 - DataObject(
11.133 - classcode,
11.134 - None, # is not instance
11.135 - instantiator_code_location,
11.136 - item.full_name(),
11.137 - len(item.class_attributes()) + 1, # size
11.138 - instantiator_funccode # funccode
11.139 - )
11.140 - ]
11.141 -
11.142 -class RSVPConst(RSVPObject):
11.143 -
11.144 - "A wrapper for constants."
11.145 -
11.146 - def set_location(self, location, objtable, with_builtins):
11.147 - item = self.item
11.148 - value = item.get_value()
11.149 - type_name = self.type_name(item.value_type_name(), value, objtable)
11.150 -
11.151 - location = RSVPObject.set_location(self, location, objtable, with_builtins)
11.152 - return location + self.raw_size(type_name, value)
11.153 -
11.154 - def as_raw(self, objtable, paramtable, with_builtins):
11.155 - item = self.item
11.156 - value = item.get_value()
11.157 - type_name = self.type_name(item.value_type_name(), value, objtable)
11.158 - raw_data = self.raw_data(type_name, value, objtable)
11.159 - size = self.raw_size(type_name, value) + 1
11.160 -
11.161 - # Generate the footprint of the constant.
11.162 -
11.163 - classcode = objtable.as_list().get_code(type_name)
11.164 - attrcode = objtable.get_index("#" + type_name)
11.165 -
11.166 - return [
11.167 - DataObject(
11.168 - classcode,
11.169 - attrcode, # is instance
11.170 - None,
11.171 - type_name,
11.172 - size # header plus data
11.173 - )
11.174 -
11.175 - # NOTE: The RSVP library needs changing if more attributes are added
11.176 - # NOTE: here (such as a __class__ attribute for all instances).
11.177 -
11.178 - ] + raw_data
11.179 -
11.180 - def type_name(self, type_name, value, objtable):
11.181 -
11.182 - # Change the type of string constants if they might be used as attribute
11.183 - # accessors.
11.184 -
11.185 - accessor_cls = "__builtins__._accessor"
11.186 -
11.187 - if type_name == "__builtins__.str" and value in objtable.attribute_names() and \
11.188 - accessor_cls in objtable.object_names():
11.189 -
11.190 - return accessor_cls
11.191 - else:
11.192 - return type_name
11.193 -
11.194 - def raw_data(self, type_name, value, objtable):
11.195 -
11.196 - # NOTE: Start simple and use single entries for most types, even though
11.197 - # NOTE: a concrete representation may use multiple memory words to
11.198 - # NOTE: represent the data.
11.199 -
11.200 - if type_name in ("__builtins__.tuple", "__builtins__.list"):
11.201 - return [len(value)] + list(value)
11.202 - elif type_name == "__builtins__._accessor":
11.203 - return [value, objtable.get_index(value)]
11.204 - else:
11.205 - return [value]
11.206 -
11.207 - def raw_size(self, type_name, value):
11.208 - if type_name in ("__builtins__.tuple", "__builtins__.list"):
11.209 - return 1 + len(value)
11.210 - elif type_name == "__builtins__._accessor":
11.211 - return 2
11.212 - else:
11.213 - return 1
11.214 -
11.215 -class RSVPFunction(RSVPObject):
11.216 -
11.217 - "A wrapper for functions."
11.218 -
11.219 - def set_location(self, location, objtable, with_builtins):
11.220 - item = self.item
11.221 - location = RSVPObject.set_location(self, location, objtable, with_builtins)
11.222 -
11.223 - # Set the code location only where the code has been
11.224 - # generated.
11.225 -
11.226 - if not self.is_generated(with_builtins):
11.227 - item.code_location = item.full_name()
11.228 -
11.229 - # Skip any defaults for static functions.
11.230 -
11.231 - elif not item.is_dynamic():
11.232 - item.code_location = location + len(item.defaults)
11.233 -
11.234 - # Skip any defaults for dynamic functions.
11.235 -
11.236 - else:
11.237 - item.code_location = location
11.238 -
11.239 - return location
11.240 -
11.241 - def finalise_body_location(self, with_builtins):
11.242 - self._finalise_location(with_builtins)
11.243 -
11.244 - def as_raw(self, objtable, paramtable, with_builtins):
11.245 - item = self.item
11.246 - # NOTE: Need class and parameter details! Should arguably be an instance of types.FunctionType.
11.247 - return [
11.248 - DataObject(
11.249 - objtable.as_list().get_code("__builtins__.function"),
11.250 - objtable.get_index("#__builtins__.function"), # is instance
11.251 - item.code_location,
11.252 - "__builtins__.function",
11.253 - len(item.defaults) + 1, # size (not accurate for lambda functions before instantiation)
11.254 - paramtable.as_list().get_code(item.full_name()) # funccode
11.255 - )
11.256 - ]
11.257 -
11.258 -class RSVPModule(RSVPObject):
11.259 -
11.260 - "A wrapper for modules."
11.261 -
11.262 - def finalise_location(self, with_builtins):
11.263 - item = self.item
11.264 - if item.blocks:
11.265 - item.code_location = item.blocks[0].location
11.266 -
11.267 - def as_raw(self, objtable, paramtable, with_builtins):
11.268 - item = self.item
11.269 - return [
11.270 - DataObject(
11.271 - objtable.as_list().get_code(item.full_name()),
11.272 - None, # modules treated like classes
11.273 - item.code_location,
11.274 - item.full_name(),
11.275 - len(item.module_attributes()) + 1 # size
11.276 - )
11.277 - ]
11.278 -
11.279 -# Serialisation-related data and functions.
11.280 -
11.281 -def get_object(item):
11.282 - if isinstance(item, Attr):
11.283 - cls = RSVPAttr
11.284 - elif isinstance(item, Block):
11.285 - cls = RSVPBlock
11.286 - elif isinstance(item, Class):
11.287 - cls = RSVPClass
11.288 - elif isinstance(item, Const):
11.289 - cls = RSVPConst
11.290 - elif isinstance(item, Function):
11.291 - cls = RSVPFunction
11.292 - elif isinstance(item, Module):
11.293 - cls = RSVPModule
11.294 - else:
11.295 - cls = None
11.296 -
11.297 - if cls is not None:
11.298 - return cls(item)
11.299 - else:
11.300 - return None
11.301 -
11.302 -# Instruction-related classes.
11.303 -
11.304 -class Instruction:
11.305 -
11.306 - "A generic instruction."
11.307 -
11.308 - default_working = "working"
11.309 - default_target = "working"
11.310 - default_source = None
11.311 -
11.312 - # NOTE: Ultimately, instructions apart from Transfer will use specific
11.313 - # NOTE: registers such as "working_value" and "working_context".
11.314 -
11.315 - def __init__(self, attr=None, working=None, target=None, source=None):
11.316 - self.attr = attr
11.317 - self.working = working or self.default_working
11.318 - self.target = target or self.default_target
11.319 - self.source = source or self.default_source
11.320 -
11.321 - def get_details(self):
11.322 - return self.__class__, self.attr, self.working, self.target, self.source
11.323 -
11.324 - def copy(self):
11.325 - return self.__class__(self.attr, self.working, self.target, self.source)
11.326 -
11.327 - def __repr__(self):
11.328 - return "%s(%s)" % (self.__class__.__name__,
11.329 - ", ".join(
11.330 - self.format_operand() +
11.331 - self.format_working() +
11.332 - self.format_source() +
11.333 - self.format_target()
11.334 - ))
11.335 -
11.336 - def __hash__(self):
11.337 - return hash(self.get_details())
11.338 -
11.339 - def __eq__(self, other):
11.340 - return self.get_details() == other.get_details()
11.341 -
11.342 - def __ne__(self, other):
11.343 - return not self.__eq__(other)
11.344 -
11.345 - def format_operand(self):
11.346 - operand = self.get_operand()
11.347 - return operand is not None and [repr(operand)] or []
11.348 -
11.349 - def format_working(self):
11.350 - return self.working != self.default_working and ["working=%r" % self.working] or []
11.351 -
11.352 - def format_source(self):
11.353 - return self.source != self.default_source and ["source=%r" % self.source] or []
11.354 -
11.355 - def format_target(self):
11.356 - return self.target != self.default_target and ["target=%r" % self.target] or []
11.357 -
11.358 - def get_operand(self):
11.359 - return None
11.360 -
11.361 -class FrameRelativeInstruction(Instruction):
11.362 -
11.363 - "An instruction operating on the current frame."
11.364 -
11.365 - def get_operand(self):
11.366 - return self.attr.position
11.367 -
11.368 -FR = FrameRelativeInstruction
11.369 -
11.370 -class AddressRelativeInstruction(Instruction):
11.371 -
11.372 - "An instruction accessing an object's attribute."
11.373 -
11.374 - def format_operand(self):
11.375 - return Instruction.format_operand(self) + ["name=%r" % name(self.attr)]
11.376 -
11.377 - def get_operand(self):
11.378 - return self.attr.position
11.379 -
11.380 -AR = AddressRelativeInstruction
11.381 -
11.382 -class AddressInstruction(Instruction):
11.383 -
11.384 - "An instruction loading an address directly."
11.385 -
11.386 - def format_operand(self):
11.387 - location, position, result = self.get_operands()
11.388 - if location is not None:
11.389 - return ["%s" % result, "location=%s" % location, "position=%s" % position,
11.390 - "name=%s" % name(self.attr)]
11.391 - elif result is not None:
11.392 - return ["%s" % result, "name=%s" % name(self.attr)]
11.393 - else:
11.394 - return ["name=%s" % name(self.attr)]
11.395 -
11.396 - def get_operands(self):
11.397 - if isinstance(self.attr, Attr):
11.398 - position = self.attr.position
11.399 - location = self.attr.parent.location
11.400 -
11.401 - # NOTE: Unpositioned attributes are handled here.
11.402 -
11.403 - if location is not None and position is not None:
11.404 - result = location + position + 1
11.405 - else:
11.406 - location = self.attr.parent.name
11.407 - position = self.attr.name
11.408 - result = None
11.409 - return location, position, result
11.410 - else:
11.411 - return None, None, self.attr.location
11.412 -
11.413 - def get_operand(self):
11.414 - return self.get_operands()[-1]
11.415 -
11.416 -Address = AddressInstruction
11.417 -
11.418 -class TargetInstruction(Instruction):
11.419 -
11.420 - "An instruction loading the address of a direct invocation target."
11.421 -
11.422 - def format_operand(self):
11.423 - return Instruction.format_operand(self) + ["name=%r" % name(self.attr)]
11.424 -
11.425 - def get_operand(self):
11.426 - return self.attr.code_body_location
11.427 -
11.428 -Target = TargetInstruction
11.429 -
11.430 -class ImmediateInstruction(Instruction):
11.431 -
11.432 - "An instruction employing a constant."
11.433 -
11.434 - def get_operand(self):
11.435 - return self.attr
11.436 -
11.437 -Immediate = ImmediateInstruction
11.438 -
11.439 -# Low-level instructions.
11.440 -
11.441 -class Transfer(Instruction):
11.442 - "Transfer a register's contents into another."
11.443 - cost = 1
11.444 -
11.445 -class LoadMemory(Instruction):
11.446 - "Load a value from a memory address given by a register, optionally adding the operand."
11.447 - cost = 1
11.448 -
11.449 -class Add(Instruction):
11.450 - "Add the value given by the working register to the operand."
11.451 - cost = 1
11.452 -
11.453 -class Multiply(Instruction):
11.454 - "Multiply the value given by the working register by the operand."
11.455 - cost = 1
11.456 -
11.457 -# Access to stored constant data.
11.458 -
11.459 -class LoadConst(Address):
11.460 - "Load the constant or module from the specified location."
11.461 - cost = 1
11.462 -
11.463 -class LoadClass(Address):
11.464 - "Load the class from the specified location."
11.465 - cost = 1
11.466 -
11.467 -class LoadFunction(Address):
11.468 - "Load the function from the specified location."
11.469 - cost = 1
11.470 -
11.471 -# Access within an invocation frame.
11.472 -
11.473 -class LoadName(FR):
11.474 - "Load the current value from the given local attribute/variable."
11.475 - cost = 2
11.476 -
11.477 -class StoreName(FR):
11.478 - "Store the source value into the given local attribute/variable."
11.479 - cost = 2
11.480 - default_target = None
11.481 -
11.482 -class LoadTemp(Immediate):
11.483 - "Load the current value from the given temporary location."
11.484 - cost = 2
11.485 -
11.486 -class StoreTemp(Immediate):
11.487 - "Store the current value into the given temporary location."
11.488 - cost = 2
11.489 - default_target = None
11.490 -
11.491 -# Access to static data.
11.492 -
11.493 -class LoadAddress(Address):
11.494 - "Load the current value from the given fixed attribute address."
11.495 - cost = 1
11.496 -
11.497 -class StoreAddress(Address):
11.498 - "Store the source value into the given fixed attribute address."
11.499 - cost = 1
11.500 - default_working = None
11.501 - default_target = None
11.502 -
11.503 -class LoadAddressContext(Address):
11.504 - "Load the current value from the given fixed attribute address, using the current value as context."
11.505 - cost = 2
11.506 -
11.507 -class StoreAddressContext(Address):
11.508 - "Store the current value into the given fixed attribute address, using the current value as context."
11.509 - cost = 2
11.510 - default_target = None
11.511 -
11.512 -class LoadAddressContextCond(Address):
11.513 - """
11.514 - Load the current value from the given fixed attribute address, only using the current value as
11.515 - context if the attribute is compatible.
11.516 - """
11.517 - cost = 4
11.518 -
11.519 -class MakeInstance(Immediate):
11.520 - "Make a new instance using the current value as a reference to a template."
11.521 - cost = 5
11.522 -
11.523 -class MakeFragment(Immediate):
11.524 - "Make a new list fragment."
11.525 - cost = 5
11.526 -
11.527 -# Access to address-relative data. (LoadAttrIndexContext not defined.)
11.528 -
11.529 -class LoadAttr(AR):
11.530 - "Load into the current value the given attribute of the object referenced by the current value."
11.531 - cost = 2
11.532 -
11.533 -class StoreAttr(AR):
11.534 - "Store the source value into the given attribute of the object referenced by the current value."
11.535 - cost = 2
11.536 - default_target = None
11.537 -
11.538 -class LoadAttrIndex(Immediate):
11.539 - "Load into the current value the attribute of the current value with the given index."
11.540 - cost = 6
11.541 -
11.542 -class StoreAttrIndex(Immediate):
11.543 - "Store the source value into the attribute of the current value with the given index."
11.544 - cost = 6
11.545 - default_target = None
11.546 -
11.547 -class LoadAttrIndexContextCond(Immediate):
11.548 - """
11.549 - Load into the current value the attribute of the current value with the given index, only making the
11.550 - current value the context if the attribute is compatible.
11.551 - """
11.552 - cost = 8
11.553 -
11.554 -# Access to object details.
11.555 -
11.556 -class LoadCallable(Instruction):
11.557 - "Load the target of an invocation."
11.558 - cost = 2
11.559 -
11.560 -class StoreCallable(Instruction):
11.561 - "Store the source value into the object referenced by the current value."
11.562 - cost = 3
11.563 - default_target = None
11.564 -
11.565 -# Access to invocation frames in preparation.
11.566 -
11.567 -class MakeFrame(Immediate):
11.568 - "Make a new invocation frame."
11.569 - cost = 2
11.570 - default_target = None
11.571 -
11.572 -class AdjustFrame(Immediate):
11.573 - "Adjust the current invocation frame for corrected invocations."
11.574 - cost = 2
11.575 - default_target = None
11.576 -
11.577 -class DropFrame(Instruction):
11.578 - "Drop an invocation frame."
11.579 - cost = 2
11.580 - default_target = None
11.581 -
11.582 -class StoreFrame(Immediate):
11.583 - "Store the current value as an argument for the parameter with the given position."
11.584 - cost = 2
11.585 - default_target = None
11.586 -
11.587 -class StoreFrameIndex(Immediate):
11.588 - "Store the source value as an argument of the current value for the parameter with the given index."
11.589 - cost = 6
11.590 - default_target = None
11.591 -
11.592 -# Context-related tests.
11.593 -
11.594 -class CheckContext(Instruction):
11.595 - "Check to see if the context is valid."
11.596 - cost = 2
11.597 -
11.598 -class CheckClass(Instruction):
11.599 - "Check the current value to determine whether it is a class."
11.600 - cost = 2
11.601 -
11.602 -class CheckInstance(Instruction):
11.603 - """
11.604 - Check the current value as an instance of a class or its subclasses (used with 'self' in an
11.605 - invocation).
11.606 - """
11.607 - cost = 6
11.608 -
11.609 -# Access to frames upon invocation.
11.610 -
11.611 -class CheckFrame(Immediate):
11.612 - "Check the frame for the correct number of arguments."
11.613 - cost = 3
11.614 -
11.615 -class CheckExtra(Immediate):
11.616 - "Ensure that the frame can provide extra arguments."
11.617 - cost = 3
11.618 -
11.619 -class FillDefaults(Immediate):
11.620 - "Fill frame positions with defaults, if appropriate."
11.621 - cost = 8 # variable
11.622 - default_target = None
11.623 -
11.624 -class ExtendFrame(Immediate):
11.625 - "Extend the current frame for temporary storage use."
11.626 - cost = 1
11.627 - default_target = None
11.628 -
11.629 -class CopyExtra(Immediate):
11.630 - "Copy extra arguments into a separate sequence, starting from the given position."
11.631 - cost = 10
11.632 -
11.633 -# Invocation-related instructions, using a special result "register".
11.634 -
11.635 -class JumpInFrame(Instruction):
11.636 - "Jump, using the current locals, to the current callable."
11.637 - cost = 2
11.638 - default_target = None
11.639 -
11.640 -class JumpInFrameDirect(Address):
11.641 - "Jump, using the current locals, to the specified address."
11.642 - cost = 2
11.643 - default_target = None
11.644 -
11.645 -class JumpWithFrame(Instruction):
11.646 - "Jump, adopting the invocation frame, to the current callable."
11.647 - cost = 3
11.648 - default_target = None
11.649 -
11.650 -class JumpWithFrameDirect(Target):
11.651 - "Jump to the specified address, adopting the invocation frame."
11.652 - cost = 3
11.653 - default_target = None
11.654 -
11.655 -class Return(Instruction):
11.656 - "Return from a subprogram."
11.657 - cost = 2
11.658 - default_target = None
11.659 -
11.660 -# Branch-related instructions.
11.661 -
11.662 -class Jump(Address):
11.663 - "Jump unconditionally."
11.664 - cost = 1
11.665 - default_target = None
11.666 -
11.667 -class JumpIfFalse(Address):
11.668 - "Jump if the last evaluation gave a false result."
11.669 - cost = 2
11.670 - default_target = None
11.671 -
11.672 -class JumpIfTrue(Address):
11.673 - "Jump if the last evaluation gave a true result."
11.674 - cost = 2
11.675 - default_target = None
11.676 -
11.677 -# Exception-related instructions, using a special exception "register".
11.678 -
11.679 -class RaiseException(Instruction):
11.680 - "Raise an exception, jumping to the active handler."
11.681 - cost = 2
11.682 - default_target = None
11.683 -
11.684 -class PushHandler(Address):
11.685 - "Push an exception handler onto the handler stack."
11.686 - cost = 3
11.687 - default_target = None
11.688 -
11.689 -class PopHandler(Immediate):
11.690 - "Pop exception handlers from the handler stack."
11.691 - cost = 3
11.692 - default_target = None
11.693 -
11.694 -class CheckException(Instruction):
11.695 - "Check the raised exception against another."
11.696 - cost = 6
11.697 -
11.698 -class ClearException(Instruction):
11.699 - "Clear any raised exception."
11.700 - cost = 1
11.701 -
11.702 -# Test instructions, operating on the boolean status register.
11.703 -
11.704 -class TestIdentity(Instruction):
11.705 - "Test whether the current value is identical to the source value, setting the boolean status."
11.706 - cost = 2
11.707 -
11.708 -class TestIdentityAddress(Address):
11.709 - "Test whether the current value is identical to the given address, setting the boolean status."
11.710 - cost = 2
11.711 -
11.712 -class InvertBoolean(Instruction):
11.713 - "Invert the boolean status."
11.714 - cost = 1
11.715 -
11.716 -# Instructions which can affect the current value. (LoadAttrIndexContext not defined.)
11.717 -
11.718 -def affects_register(instruction, register):
11.719 -
11.720 - """
11.721 - Returns whether 'instruction' affects the given 'register', either directly
11.722 - or as a consequence of its execution.
11.723 - """
11.724 -
11.725 - return instruction.target == register or isinstance(instruction, (
11.726 - JumpInFrame, JumpInFrameDirect,
11.727 - JumpWithFrame, JumpWithFrameDirect,
11.728 - JumpIfTrue, JumpIfFalse,
11.729 - Jump
11.730 - ))
11.731 -
11.732 -# vim: tabstop=4 expandtab shiftwidth=4
12.1 --- a/micropython/trans.py Fri Jun 28 21:17:02 2013 +0200
12.2 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000
12.3 @@ -1,1423 +0,0 @@
12.4 -#!/usr/bin/env python
12.5 -
12.6 -"""
12.7 -Translate the AST of a Python program into a more interpretable representation.
12.8 -
12.9 -Copyright (C) 2007, 2008, 2009, 2010, 2011, 2012 Paul Boddie <paul@boddie.org.uk>
12.10 -
12.11 -This program is free software; you can redistribute it and/or modify it under
12.12 -the terms of the GNU General Public License as published by the Free Software
12.13 -Foundation; either version 3 of the License, or (at your option) any later
12.14 -version.
12.15 -
12.16 -This program is distributed in the hope that it will be useful, but WITHOUT
12.17 -ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
12.18 -FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
12.19 -details.
12.20 -
12.21 -You should have received a copy of the GNU General Public License along with
12.22 -this program. If not, see <http://www.gnu.org/licenses/>.
12.23 -"""
12.24 -
12.25 -from micropython.common import operator_functions
12.26 -from micropython.data import *
12.27 -from micropython.errors import *
12.28 -from micropython.rsvp import *
12.29 -import compiler.ast
12.30 -
12.31 -class Helper:
12.32 -
12.33 - "Internal helper methods for AST visitors."
12.34 -
12.35 - # Common methods.
12.36 -
12.37 - def _generateGuards(self, node):
12.38 -
12.39 - if not (self.optimiser.should_optimise_accesses_by_attribute_usage() and node._attrtypes):
12.40 - return
12.41 -
12.42 - # For each name, attempt to restrict the type employed.
12.43 -
12.44 - for name, targets in node._attrtypes.items():
12.45 -
12.46 - # NOTE: Need to merge targets using the same type but suggesting
12.47 - # NOTE: different kinds of attributes (instance vs. class).
12.48 -
12.49 - # Where only one object type is suggested, produce a guard.
12.50 - # NOTE: This only supports classes as types, not modules.
12.51 -
12.52 - if len(targets) == 1:
12.53 - target_name, is_static = list(targets)[0]
12.54 -
12.55 - # Access the object table to get the attribute.
12.56 - # This depends on a special entry in the table for class
12.57 - # equivalence tests.
12.58 -
12.59 - try:
12.60 - obj = self.objtable.get_object(target_name)
12.61 -
12.62 - # Where no attribute entry exists, the target could be a module.
12.63 - # NOTE: Should perhaps raise an error.
12.64 -
12.65 - except TableError, exc:
12.66 - print "Possible guard for", target_name, "not enforceable."
12.67 - continue
12.68 -
12.69 - # NOTE: Could test the correctness of the guard where the nature
12.70 - # NOTE: of the name is known.
12.71 - # NOTE: The known value would be retrieved from the unit's
12.72 - # NOTE: locals and tested as being a class or an instance of a
12.73 - # NOTE: particular class.
12.74 -
12.75 - # Generate the guard by loading a reference to the class.
12.76 -
12.77 - after_test_block = self.new_block()
12.78 -
12.79 - self.new_op(LoadClass(obj, target="source"))
12.80 -
12.81 - # For only static attributes, classes are acceptable.
12.82 -
12.83 - if is_static:
12.84 -
12.85 - # Generate name is target (for classes).
12.86 -
12.87 - self.dispatch(compiler.ast.Name(name))
12.88 - self.new_op(TestIdentity(source="source", target="status"))
12.89 -
12.90 - # Jump to the next guard or the code if successful.
12.91 -
12.92 - self.new_op(JumpIfTrue(after_test_block, working="status"))
12.93 -
12.94 - # Where instance attributes are involved, only instances are
12.95 - # acceptable.
12.96 -
12.97 - if not isinstance(obj, Module):
12.98 -
12.99 - # Generate isinstance(name, target).
12.100 -
12.101 - self.dispatch(compiler.ast.Name(name))
12.102 - self.new_op(CheckInstance(source="source", target="status"))
12.103 -
12.104 - # Jump to the next guard or the code if successful.
12.105 -
12.106 - self.new_op(JumpIfTrue(after_test_block, working="status"))
12.107 -
12.108 - # Where the type is inappropriate, raise an exception.
12.109 -
12.110 - self.make_exception("TypeError")
12.111 - self.set_target("exception")
12.112 - self.new_op(RaiseException())
12.113 -
12.114 - self.set_block(after_test_block)
12.115 -
12.116 - def _visitAttr(self, node, classes):
12.117 -
12.118 - """
12.119 - Visit the attribute-related 'node', generating instructions based on the
12.120 - given 'classes'.
12.121 - """
12.122 -
12.123 - self.dispatch(node.expr)
12.124 - self._generateAttr(node, node.attrname, classes)
12.125 -
12.126 - def _generateAttr(self, node, attrname, classes):
12.127 -
12.128 - """
12.129 - Generate code for the access to 'attrname' using the given 'classes'.
12.130 - """
12.131 -
12.132 - AddressInstruction, AddressContextInstruction, AddressContextCondInstruction, \
12.133 - AttrInstruction, AttrIndexInstruction, AttrIndexContextCondInstruction = classes
12.134 -
12.135 - # Where the last operation (defining the attribute owner) yields a
12.136 - # constant...
12.137 -
12.138 - target_plus_name = self.optimiser.optimise_constant_accessor()
12.139 -
12.140 - # Only try and discover the position if the target can be resolved.
12.141 - # Since instances cannot be constants in general, this involves classes
12.142 - # and modules, but constants known at compile-time must also be handled.
12.143 -
12.144 - if target_plus_name is not None:
12.145 - target, target_name = target_plus_name
12.146 -
12.147 - # Check for class.__class__.
12.148 -
12.149 - if attrname == "__class__":
12.150 - if isinstance(target, Class):
12.151 - if AddressInstruction is LoadAddress:
12.152 - self.replace_active_value("working", LoadAddress(self.get_builtin("type")))
12.153 - return
12.154 - else:
12.155 - raise TranslateError("Assigning to __class__ is not permitted.")
12.156 -
12.157 - # Access the object table to get the attribute.
12.158 -
12.159 - try:
12.160 - attr = self.objtable.access(target_name, attrname)
12.161 - except TableError, exc:
12.162 - raise TranslateError(exc.args[0])
12.163 -
12.164 - # Produce a suitable instruction.
12.165 -
12.166 - if AddressInstruction is not None:
12.167 -
12.168 - # Where the target is a constant instance, the constant input
12.169 - # needs to be retained as the context of the resulting
12.170 - # attribute.
12.171 -
12.172 - if isinstance(target, Instance):
12.173 - self.new_op(AddressContextInstruction(attr))
12.174 -
12.175 - # It is acceptable to replace the instruction providing the
12.176 - # constant input because doing so does not lose any input
12.177 - # information required by the replacement instructions.
12.178 -
12.179 - else:
12.180 - self.replace_active_value("working", AddressInstruction(attr))
12.181 - else:
12.182 - raise TranslateError("Storing of class or module attribute %r via an object is not permitted." % attrname)
12.183 -
12.184 - return
12.185 -
12.186 - # Where the last operation involves the special 'self' name, check to
12.187 - # see if the attribute is acceptably positioned and produce a direct
12.188 - # access to the attribute.
12.189 -
12.190 - # This is the only reliable way of detecting instance accesses at
12.191 - # compile-time since in general, objects could be classes or modules,
12.192 - # but 'self' should only refer to instances.
12.193 -
12.194 - elif self.optimiser.optimise_self_access(self.unit, attrname):
12.195 -
12.196 - # Either generate an instruction operating on an instance attribute.
12.197 -
12.198 - try:
12.199 - attr = self.unit.parent.instance_attributes()[attrname]
12.200 - self.new_op(AttrInstruction(attr))
12.201 - return
12.202 -
12.203 - # Or generate an instruction operating on a class attribute.
12.204 - # NOTE: Any simple instruction providing self is not removed.
12.205 -
12.206 - except KeyError:
12.207 -
12.208 - try:
12.209 - attr = self.unit.parent.all_attributes()[attrname]
12.210 -
12.211 - # Switch the context if the class attribute is compatible with
12.212 - # the instance.
12.213 -
12.214 - if attr.defined_within_hierarchy():
12.215 -
12.216 - # Only permit loading (not storing) of class attributes via self.
12.217 -
12.218 - if AddressContextInstruction is not None:
12.219 - self.new_op(AddressContextInstruction(attr))
12.220 - else:
12.221 - raise TranslateError("Storing of class attribute %r via self not permitted." % attrname)
12.222 -
12.223 - # Preserve the context if the class attribute comes from an
12.224 - # incompatible class.
12.225 -
12.226 - elif attr.defined_outside_hierarchy():
12.227 -
12.228 - # Only permit loading (not storing) of class attributes via self.
12.229 -
12.230 - if AddressInstruction is not None:
12.231 - self.new_op(AddressInstruction(attr))
12.232 - else:
12.233 - raise TranslateError("Storing of class attribute %r via self not permitted." % attrname)
12.234 -
12.235 - # Otherwise, test for a suitable context at run-time.
12.236 -
12.237 - else:
12.238 -
12.239 - # Only permit loading (not storing) of class attributes via self.
12.240 -
12.241 - if AddressContextCondInstruction is not None:
12.242 - self.new_op(AddressContextCondInstruction(attr))
12.243 - else:
12.244 - raise TranslateError("Storing of class attribute %r via self not permitted." % attrname)
12.245 -
12.246 - return
12.247 -
12.248 - # Or delegate the attribute access to a general instruction
12.249 - # since the kind of attribute cannot be deduced.
12.250 -
12.251 - except KeyError:
12.252 - pass
12.253 -
12.254 - # Attempt to deduce the target of an attribute access by searching for a
12.255 - # unique type providing the names associated with the accessed object.
12.256 -
12.257 - elif self.optimiser.should_optimise_accesses_by_attribute_usage() and \
12.258 - isinstance(node, compiler.ast.AttributeAccessor):
12.259 -
12.260 - targets = self.possible_accessors_from_usage(node)
12.261 -
12.262 - if targets and len(targets) == 1:
12.263 - target = list(targets)[0]
12.264 - attr = target.all_attributes().get(attrname)
12.265 -
12.266 - # Produce a suitable instruction.
12.267 -
12.268 - if attr:
12.269 - if AddressContextCondInstruction is not None and attr.is_static_attribute():
12.270 - self.new_op(AddressContextCondInstruction(attr))
12.271 - elif AttrInstruction is not None and not attr.is_static_attribute():
12.272 - self.new_op(AttrInstruction(attr))
12.273 - else:
12.274 - raise TranslateError("Storing of class or module attribute %r via an object is not permitted." % attrname)
12.275 -
12.276 - return
12.277 -
12.278 - # Check for class.__class__.
12.279 -
12.280 - if attrname == "__class__":
12.281 -
12.282 - # Remember the accessor.
12.283 -
12.284 - temp_accessor = self.get_temp()
12.285 -
12.286 - attr_block = self.new_block()
12.287 - end_block = self.new_block()
12.288 -
12.289 - self.new_op(CheckClass(target="status"))
12.290 - self.new_op(JumpIfFalse(attr_block, working="status"))
12.291 - self.load_builtin("type", node)
12.292 - self.new_op(Jump(end_block))
12.293 - self.set_block(attr_block)
12.294 -
12.295 - # Recall the accessor.
12.296 -
12.297 - self.new_op(temp_accessor)
12.298 -
12.299 - # Otherwise, perform a normal operation.
12.300 -
12.301 - try:
12.302 - index = self.objtable.get_index(attrname)
12.303 -
12.304 - except self.objtable.TableError:
12.305 -
12.306 - # If this error arises on generated code, check the names_used
12.307 - # attribute on the Importer.
12.308 -
12.309 - raise TranslateError("No attribute entry exists for name %r." % attrname)
12.310 -
12.311 - # NOTE: Test for class vs. instance attributes, generating
12.312 - # NOTE: context-related instructions.
12.313 -
12.314 - if AttrIndexContextCondInstruction is not None:
12.315 - self.new_op(AttrIndexContextCondInstruction(index))
12.316 -
12.317 - # Store instructions do not need to consider context modifications.
12.318 -
12.319 - else:
12.320 - self.new_op(AttrIndexInstruction(index))
12.321 -
12.322 - # Where __class__ was involved, define the start of the following code.
12.323 -
12.324 - if attrname == "__class__":
12.325 - self.set_block(end_block)
12.326 - self.discard_temp(temp_accessor)
12.327 -
12.328 - # Invocations involve the following:
12.329 - #
12.330 - # 1. Reservation of a frame for the arguments
12.331 - # 2. Identification of the target which is then held in temporary storage
12.332 - # 3. Optional inclusion of a context (important for methods)
12.333 - # 4. Preparation of the argument frame
12.334 - # 5. Invocation of the target
12.335 - # 6. Discarding of the frame
12.336 - #
12.337 - # In order to support nested invocations - such as a(b(c)) - use of the
12.338 - # temporary storage is essential.
12.339 -
12.340 - def _startCallFunc(self):
12.341 -
12.342 - "Record the location of the invocation."
12.343 -
12.344 - op = MakeFrame()
12.345 - self.new_op(op) # records the start of the frame
12.346 - self.frame_makers.append(op)
12.347 -
12.348 - def _generateCallFunc(self, args, node):
12.349 -
12.350 - """
12.351 - Support a generic function invocation using the given 'args', occurring
12.352 - on the given 'node', where the expression providing the invocation
12.353 - target has just been generated.
12.354 -
12.355 - In other situations, the invocation is much simpler and does not need to
12.356 - handle the full flexibility of a typical Python invocation. Internal
12.357 - invocations, such as those employed by operators and certain
12.358 - control-flow mechanisms, use predetermined arguments and arguably do not
12.359 - need to support the same things as the more general invocations.
12.360 - """
12.361 -
12.362 - target, context, temp_target, temp_context = self._generateCallFuncContext()
12.363 - self._generateCallFuncArgs(target, context, temp_target, temp_context, args, node)
12.364 - return temp_target, target, temp_context
12.365 -
12.366 - def _generateCallFuncContext(self):
12.367 -
12.368 - """
12.369 - Produce code which loads and checks the context of the current
12.370 - invocation, the instructions for whose target have already been
12.371 - produced, returning a list of instructions which reference the
12.372 - invocation target.
12.373 - """
12.374 -
12.375 - t = self.optimiser.optimise_known_target()
12.376 - if t:
12.377 - target, context = t
12.378 -
12.379 - # Detect dynamic functions acting like instances.
12.380 -
12.381 - if isinstance(target, Function) and target.is_dynamic():
12.382 - target, context = None, None
12.383 - else:
12.384 - target, context = None, None
12.385 -
12.386 - # Store the target in temporary storage for subsequent referencing.
12.387 -
12.388 - temp_target = self.optimiser.optimise_temp_storage()
12.389 -
12.390 - # Where a target or context are not known or where an instance is known
12.391 - # to be the context, load the context.
12.392 -
12.393 - if target is None or isinstance(context, Instance):
12.394 - self.new_op(temp_target)
12.395 - self.new_op(Transfer(source="working_context", target="working"))
12.396 - temp_context = self.optimiser.optimise_temp_storage()
12.397 - self.new_op(StoreFrame(0))
12.398 -
12.399 - # Class contexts should be made available for testing of the first
12.400 - # argument.
12.401 - # NOTE: Class methods should eventually be supported.
12.402 -
12.403 - elif isinstance(context, Class):
12.404 - self.new_op(temp_target)
12.405 - self.new_op(Transfer(source="working_context", target="working"))
12.406 - temp_context = self.optimiser.optimise_temp_storage()
12.407 -
12.408 - # Otherwise omit the context.
12.409 -
12.410 - else:
12.411 - temp_context = None
12.412 -
12.413 - return target, context, temp_target, temp_context
12.414 -
12.415 - def _generateCallFuncArgs(self, target, context, temp_target, temp_context, args, node):
12.416 -
12.417 - """
12.418 - Given invocation 'target' and 'context' information, the 'temp_target'
12.419 - reference to the target, the 'temp_context' reference to the context, a
12.420 - list of nodes representing the 'args' (arguments), generate instructions
12.421 - which load the arguments for the invocation defined by the given 'node'.
12.422 - """
12.423 -
12.424 - # Evaluate the arguments.
12.425 -
12.426 - employed_positions = set()
12.427 - employed_keywords = set()
12.428 - extra_keywords = []
12.429 - positional_args = []
12.430 - keyword_args = []
12.431 -
12.432 - # Find keyword arguments in advance in order to help resolve targets.
12.433 -
12.434 - have_keywords = False
12.435 -
12.436 - for arg in args:
12.437 - if isinstance(arg, compiler.ast.Keyword):
12.438 - employed_keywords.add(arg.name)
12.439 - keyword_args.append(arg)
12.440 - have_keywords = True
12.441 - elif not have_keywords:
12.442 - positional_args.append(arg)
12.443 -
12.444 - possible_targets = self.paramtable.all_possible_objects(employed_keywords)
12.445 -
12.446 - # Note the presence of the context in the frame where appropriate.
12.447 -
12.448 - # For unknown invocations and method invocations.
12.449 -
12.450 - if target is None or isinstance(context, Instance):
12.451 - ncontext = 1
12.452 - expect_testable_self = False
12.453 -
12.454 - # Handle calls to classes by obtaining the instantiator function.
12.455 - # A context is reserved for the new instance, but this is not provided
12.456 - # in the invocation (since the instantiator will fill the locals slot
12.457 - # concerned).
12.458 -
12.459 - elif isinstance(target, Class):
12.460 - ncontext = 1
12.461 - expect_testable_self = False
12.462 - target = target.get_instantiator()
12.463 -
12.464 - # Method calls via classes.
12.465 -
12.466 - elif isinstance(context, Class):
12.467 - ncontext = 0
12.468 - expect_testable_self = True
12.469 -
12.470 - # Function calls.
12.471 -
12.472 - else:
12.473 - ncontext = 0
12.474 - expect_testable_self = False
12.475 -
12.476 - # Traverse the positional arguments adding them using the incrementing
12.477 - # frame position.
12.478 -
12.479 - first = True
12.480 - frame_pos = ncontext
12.481 - temp_first_argument = None
12.482 -
12.483 - for arg in positional_args:
12.484 - self.dispatch(arg)
12.485 - self.new_op(StoreFrame(frame_pos))
12.486 - employed_positions.add(frame_pos)
12.487 -
12.488 - # Check to see if the first argument is appropriate (compatible with
12.489 - # the target where methods are being invoked via classes).
12.490 -
12.491 - if first and (expect_testable_self or target is None):
12.492 -
12.493 - # Drop any test if the target and the context are known.
12.494 -
12.495 - if not self.optimiser.have_correct_self_for_target(context, self.unit):
12.496 -
12.497 - # Otherwise, remember the first argument for a subsequent
12.498 - # test.
12.499 -
12.500 - temp_first_argument = self.optimiser.optimise_temp_storage()
12.501 -
12.502 - first = False
12.503 - frame_pos += 1
12.504 -
12.505 - # Adjust the invocation frame for unknown invocations.
12.506 - # Test the first argument if appropriate.
12.507 -
12.508 - self._generateCallFuncContextTest(target, temp_context, temp_first_argument, node)
12.509 -
12.510 - # Traverse the keyword arguments adding them at the appropriate frame
12.511 - # positions.
12.512 -
12.513 - max_keyword_pos = -1
12.514 -
12.515 - for arg in keyword_args:
12.516 -
12.517 - # Optimise where the target is known now.
12.518 -
12.519 - if target is not None:
12.520 -
12.521 - # Find the parameter table entry for the target.
12.522 -
12.523 - target_name = target.full_name()
12.524 -
12.525 - # Look for a callable with the precise target name.
12.526 -
12.527 - table_entry = self.paramtable.table[target_name]
12.528 -
12.529 - # Look the name up in the parameter table entry.
12.530 -
12.531 - try:
12.532 - pos = table_entry[arg.name]
12.533 -
12.534 - # Where no position is found, this could be an extra keyword
12.535 - # argument.
12.536 -
12.537 - except KeyError:
12.538 - extra_keywords.append(arg)
12.539 - continue
12.540 -
12.541 - # Test for illegal conditions.
12.542 -
12.543 - if pos in employed_positions:
12.544 - raise TranslateError("Keyword argument %r overwrites parameter %r." % (arg.name, pos))
12.545 -
12.546 - employed_positions.add(pos)
12.547 -
12.548 - # Generate code for the keyword and the positioning
12.549 - # operation.
12.550 -
12.551 - self.dispatch(arg.expr)
12.552 - self.new_op(StoreFrame(pos))
12.553 -
12.554 - # Otherwise, generate the code needed to obtain the details of
12.555 - # the parameter location.
12.556 -
12.557 - else:
12.558 -
12.559 - # Combine the target details with the name to get the location.
12.560 - # See the access method on the List class.
12.561 -
12.562 - try:
12.563 - paramindex = self.paramtable.get_index(arg.name)
12.564 -
12.565 - # Where no position is found, this could be an extra keyword
12.566 - # argument.
12.567 -
12.568 - except self.paramtable.TableError:
12.569 - extra_keywords.append(arg)
12.570 - continue
12.571 -
12.572 - # Generate code for the keyword and the positioning
12.573 - # operation. Get the value as the source of the assignment.
12.574 -
12.575 - self.dispatch(arg.expr)
12.576 - self.record_value()
12.577 - self.start_target()
12.578 -
12.579 - # Store the source value using the callable's parameter
12.580 - # table information.
12.581 -
12.582 - self.new_op(temp_target)
12.583 - self.new_op(StoreFrameIndex(paramindex))
12.584 -
12.585 - self.assign_value()
12.586 - self.discard_value()
12.587 -
12.588 - # Record the highest possible frame position for this argument.
12.589 -
12.590 - max_keyword_pos = max(max_keyword_pos, max(self.paramtable.all_attribute_positions(arg.name)))
12.591 -
12.592 - # Use the frame position counter as a general argument counter.
12.593 -
12.594 - frame_pos += 1
12.595 -
12.596 - # NOTE: Extra keywords are not supported.
12.597 - # NOTE: Somehow, the above needs to be combined with * arguments.
12.598 -
12.599 - if extra_keywords:
12.600 - print "Warning: extra keyword argument(s) %s not handled." % ", ".join([arg.name for arg in extra_keywords])
12.601 -
12.602 - # Either test for a complete set of arguments.
12.603 -
12.604 - if target is not None:
12.605 -
12.606 - # Make sure that enough arguments have been given.
12.607 -
12.608 - nargs_max = len(target.positional_names)
12.609 - ndefaults = len(target.defaults)
12.610 - nargs_min = nargs_max - ndefaults
12.611 -
12.612 - # Visit each argument position and look for a supplied argument.
12.613 -
12.614 - for i in range(ncontext, nargs_min):
12.615 - if i not in employed_positions:
12.616 - raise TranslateError(
12.617 - "Argument %r not supplied for %r: need at least %d argument(s)." % (i+1, target.name, nargs_min))
12.618 -
12.619 - nargs = frame_pos
12.620 -
12.621 - # Determine whether too many arguments have been given and how big
12.622 - # the frame should be.
12.623 -
12.624 - # For parameter lists with * or ** parameters, accept as many
12.625 - # arguments as are allowed or as many as we have.
12.626 -
12.627 - if target.has_star or target.has_dstar:
12.628 - frame_size = max(nargs, nargs_max)
12.629 -
12.630 - # NOTE: We now need to pack these arguments into a suitable
12.631 - # NOTE: structure for the * parameter.
12.632 -
12.633 - # For other parameter lists, only accept as many arguments as we are
12.634 - # allowed.
12.635 -
12.636 - elif nargs > nargs_max:
12.637 - raise TranslateError(
12.638 - "Too many arguments for %r: need at most %d argument(s)." % (target.name, nargs_max))
12.639 -
12.640 - else:
12.641 - frame_size = nargs_max
12.642 -
12.643 - # Where defaults are involved, put them into the frame.
12.644 -
12.645 - self._generateCallFuncDefaultArgs(target, temp_target, nargs_min, nargs_max, employed_positions)
12.646 -
12.647 - # Set the frame size.
12.648 -
12.649 - self._endCallFuncArgs(frame_size)
12.650 -
12.651 - # Or just set the frame size and have the function check the arguments.
12.652 -
12.653 - else:
12.654 - max_pos = max(max(employed_positions or [-1]), max_keyword_pos, frame_pos - 1)
12.655 - self._endCallFuncArgs(max_pos + 1)
12.656 -
12.657 - def _generateCallFuncDefaultArgs(self, target, temp_target, nargs_min, nargs_max, employed_positions):
12.658 -
12.659 - """
12.660 - For the given 'target' and 'temp_target' reference to the target,
12.661 - generate default arguments for those positions in the range
12.662 - 'nargs_min'...'nargs_max' which are not present in the
12.663 - 'employed_positions' collection.
12.664 - """
12.665 -
12.666 - # Where appropriate, construct a dynamic object to hold the defaults.
12.667 -
12.668 - dynamic = target.is_dynamic()
12.669 -
12.670 - # Here, we use negative index values to visit the right hand end of
12.671 - # the defaults list.
12.672 -
12.673 - for pos in range(nargs_min, nargs_max):
12.674 - if pos not in employed_positions:
12.675 - if dynamic:
12.676 - self.new_op(temp_target)
12.677 - self.new_op(LoadAttr(target.default_attrs[pos - nargs_min]))
12.678 - else:
12.679 - self.new_op(LoadAddress(target.default_attrs[pos - nargs_min]))
12.680 - self.new_op(StoreFrame(pos))
12.681 -
12.682 - def _generateCallFuncContextTest(self, target, temp_context, temp_first_argument, node):
12.683 -
12.684 - """
12.685 - Generate code involved in a call to the given 'target' to test the
12.686 - context provided by 'temp_context' against 'temp_first_argument', and to
12.687 - signal an exception if the context is incompatible with the first frame
12.688 - argument.
12.689 -
12.690 - In addition, the invocation frame will be shifted if 'temp_context'
12.691 - indicates a function or a class.
12.692 - """
12.693 -
12.694 - # Need to store the explicit first argument in the working register for
12.695 - # the eventual test.
12.696 -
12.697 - if temp_first_argument is not None:
12.698 - self.new_op(temp_first_argument)
12.699 -
12.700 - # Put the context in the source register.
12.701 -
12.702 - if target is None or temp_first_argument is not None:
12.703 - if self.new_op(temp_context.copy()):
12.704 - self.last_op().target = "source"
12.705 - else:
12.706 - self.new_op(Transfer(source="working", target="source"))
12.707 -
12.708 - # Add some preliminary tests where the target is not known.
12.709 -
12.710 - if target is None:
12.711 - if temp_first_argument is not None:
12.712 - self.new_op(JumpInFrameDirect(self.native.getCallFuncUnknownTargetTestableSelf()))
12.713 - else:
12.714 - self.new_op(JumpInFrameDirect(self.native.getCallFuncUnknownTarget()))
12.715 -
12.716 - elif temp_first_argument is not None:
12.717 - self.new_op(JumpInFrameDirect(self.native.getCallFuncKnownTargetTestableSelf()))
12.718 -
12.719 - def _doCallFunc(self, temp_target, target=None):
12.720 -
12.721 - "Make the invocation."
12.722 -
12.723 - # For classes, the target itself is used, since the instantiator will be
12.724 - # obtained via the class.
12.725 -
12.726 - if isinstance(target, (Class, Function)):
12.727 - self.new_op(JumpWithFrameDirect(target, working="status"))
12.728 - else:
12.729 - self.new_op(temp_target)
12.730 - self.new_op(LoadCallable())
12.731 - self.new_op(JumpWithFrame())
12.732 -
12.733 - def _endCallFuncArgs(self, nargs):
12.734 -
12.735 - "Set the frame size."
12.736 -
12.737 - self.frame_makers[-1].attr = nargs
12.738 - self.frame_makers.pop()
12.739 -
12.740 - def _endCallFunc(self, temp_target=None, temp_context=None):
12.741 -
12.742 - "Finish the invocation and tidy up afterwards."
12.743 -
12.744 - self.new_op(DropFrame())
12.745 -
12.746 - # Discard any temporary storage instructions.
12.747 -
12.748 - if temp_target is not None:
12.749 - self.discard_temp(temp_target)
12.750 -
12.751 - if temp_context is not None:
12.752 - self.discard_temp(temp_context)
12.753 -
12.754 - def _visitFunctionDeclaration(self, node):
12.755 -
12.756 - """
12.757 - Visit the function declaration at 'node', which can be a lambda or a
12.758 - named function. As a consequence an instruction will be generated which
12.759 - provides a reference to the function.
12.760 - """
12.761 -
12.762 - fn = node.unit
12.763 - ndefaults = len(fn.defaults)
12.764 - temp = self._generateFunctionDefaults(fn)
12.765 -
12.766 - # Populate the new object required for the function.
12.767 -
12.768 - if temp is not None:
12.769 - self.new_op(LoadConst(fn))
12.770 - self.new_op(LoadCallable(target="source"))
12.771 - self.new_op(temp)
12.772 - self.new_op(StoreCallable(source="source"))
12.773 - self.new_op(temp)
12.774 - #self.discard_temp(temp)
12.775 - else:
12.776 - self.new_op(LoadFunction(fn))
12.777 -
12.778 - def _visitFunctionDefinition(self, node):
12.779 -
12.780 - """
12.781 - Visit the function definition at 'node', which can be a lambda or a
12.782 - named function, generating the prelude with argument and default
12.783 - checking, plus the body of the function itself.
12.784 - """
12.785 -
12.786 - # Check frames using the function's details.
12.787 -
12.788 - fn = node.unit
12.789 - nparams = len(fn.positional_names)
12.790 - ndefaults = len(fn.defaults)
12.791 -
12.792 - fn.body_block = self.new_block()
12.793 -
12.794 - # Check the number of parameters and defaults.
12.795 -
12.796 - self.new_op(CheckFrame((nparams, ndefaults), target="status"))
12.797 -
12.798 - if ndefaults > 0:
12.799 - if fn.is_dynamic():
12.800 - self.new_op(LoadTemp(0)) # context provides storage
12.801 - else:
12.802 - self.new_op(LoadFunction(fn))
12.803 -
12.804 - self.new_op(FillDefaults((nparams, ndefaults)))
12.805 -
12.806 - # Produce the body.
12.807 -
12.808 - self.set_block(fn.body_block)
12.809 -
12.810 - # For functions with star parameters, make a special list for the
12.811 - # extra arguments and re-map the parameter.
12.812 -
12.813 - if fn.has_star:
12.814 - self.new_op(CopyExtra(nparams))
12.815 -
12.816 - # Ensure that the star parameter has a slot in the frame.
12.817 -
12.818 - self.new_op(CheckExtra(nparams, target="status"))
12.819 - self.new_op(StoreTemp(nparams))
12.820 -
12.821 - # Extend the frame for local usage.
12.822 -
12.823 - extend = ExtendFrame()
12.824 - self.new_op(extend)
12.825 -
12.826 - # Perform tuple assignment for any tuple parameters.
12.827 -
12.828 - self._visitFunctionTupleParameters(fn, node)
12.829 -
12.830 - # Add any attribute usage guards.
12.831 -
12.832 - self._generateGuards(node)
12.833 -
12.834 - # Visit the actual code.
12.835 -
12.836 - self.dispatch(node.code)
12.837 -
12.838 - # Add a return statement where one is not already produced.
12.839 -
12.840 - if not isinstance(self.last_op(), Return):
12.841 -
12.842 - # Return None for normal functions without explicit return
12.843 - # statements.
12.844 -
12.845 - if not fn.is_lambda():
12.846 - self.dispatch(compiler.ast.Name("None"))
12.847 -
12.848 - self.new_op(Return())
12.849 -
12.850 - # Make sure that enough frame space is reserved from the start.
12.851 -
12.852 - self.set_frame_usage(node, extend)
12.853 -
12.854 - def _visitFunctionTupleParameters(self, fn, node, parameters=None):
12.855 -
12.856 - """
12.857 - Visit the tuple parameters for function 'fn', obtaining the appropriate
12.858 - elements from each supplied argument and assigning them to the specified
12.859 - names for each parameter.
12.860 - """
12.861 -
12.862 - if parameters is not None:
12.863 - self._generateAttr(node, "__getitem__", self.attribute_load_instructions)
12.864 - temp_getitem = self.optimiser.optimise_temp_storage()
12.865 -
12.866 - for i, parameter in parameters or fn.tuple_parameters():
12.867 -
12.868 - # Either load the parameter from the frame.
12.869 -
12.870 - if parameters is None:
12.871 - self.new_op(LoadName(Attr(i, None, None)))
12.872 -
12.873 - # Or load a value from the current collection.
12.874 -
12.875 - else:
12.876 - self._startCallFunc()
12.877 - self.new_op(temp_getitem)
12.878 - temp_target, target, temp_context = self._generateCallFunc([compiler.ast.Const(i)], node)
12.879 - self._doCallFunc(temp_target, target)
12.880 - self._endCallFunc()
12.881 -
12.882 - # Where a tuple is the target, attempt to descend into the value
12.883 - # obtained.
12.884 -
12.885 - if isinstance(parameter, list):
12.886 - self._visitFunctionTupleParameters(fn, node, parameter)
12.887 -
12.888 - # Store the item in the namespace entry for the given name.
12.889 -
12.890 - else:
12.891 - self.record_value()
12.892 - self.start_target()
12.893 - self.new_op(StoreName(fn[parameter]))
12.894 - self.assign_value()
12.895 - self.discard_value()
12.896 -
12.897 - if parameters is not None:
12.898 - self.discard_temp(temp_getitem)
12.899 -
12.900 - def _generateFunctionDefaults(self, function):
12.901 -
12.902 - """
12.903 - Generate the default initialisation code for 'function', returning
12.904 - a temporary storage reference if a dynamic object was created for the
12.905 - function.
12.906 - """
12.907 -
12.908 - attr_to_default = zip(function.default_attrs, function.defaults)
12.909 - if not attr_to_default:
12.910 - return None
12.911 -
12.912 - # Where non-constant defaults are involved, construct a dynamic object
12.913 - # to hold the defaults.
12.914 -
12.915 - dynamic = function.is_dynamic()
12.916 -
12.917 - if dynamic:
12.918 - self.make_instance(self.get_builtin_class("function"), len(attr_to_default))
12.919 - temp = self.get_temp()
12.920 -
12.921 - for attr, default in attr_to_default:
12.922 - self.dispatch(default)
12.923 -
12.924 - self.record_value()
12.925 - self.start_target()
12.926 - if dynamic:
12.927 - self.new_op(temp)
12.928 - self.new_op(StoreAttr(attr))
12.929 - else:
12.930 - self.new_op(StoreAddress(attr))
12.931 - self.assign_value()
12.932 - self.discard_value()
12.933 -
12.934 - if dynamic:
12.935 - return temp
12.936 - else:
12.937 - return None
12.938 -
12.939 - def _storeName(self, node, name=None):
12.940 -
12.941 - """
12.942 - A convenience method that stores the current working value using the
12.943 - name provided by the given 'node' or the specified 'name' if provided.
12.944 - """
12.945 -
12.946 - self.record_value()
12.947 - self.start_target()
12.948 - self._generateName(name or node.name, self.name_store_instructions, node)
12.949 - self.assign_value()
12.950 - self.discard_value()
12.951 -
12.952 - def _visitName(self, node, classes):
12.953 -
12.954 - """
12.955 - Visit the name-related 'node', generating instructions based on the
12.956 - given 'classes'.
12.957 - """
12.958 -
12.959 - name = node.name
12.960 - self._generateName(name, classes, node)
12.961 -
12.962 - def _generateName(self, name, classes, node):
12.963 -
12.964 - """
12.965 - Generate code for the access to 'name' in 'scope' using the given
12.966 - 'classes', and using the given 'node' as the source of the access.
12.967 - """
12.968 -
12.969 - NameInstruction, AddressInstruction, AddressContextInstruction = classes
12.970 -
12.971 - # Get the expected scope of the name.
12.972 -
12.973 - scope = getattr(node, "_scope", None) or self.get_scope(name)
12.974 -
12.975 - # Handle names referring to constants.
12.976 -
12.977 - if scope == "constant":
12.978 - const = self.importer.get_predefined_constant(name)
12.979 - self.new_op(LoadConst(const))
12.980 -
12.981 - # Handle all other names.
12.982 -
12.983 - elif scope == "local":
12.984 - unit = self.unit
12.985 - if isinstance(unit, Function):
12.986 - self.new_op(NameInstruction(unit.all_locals()[name]))
12.987 - elif isinstance(unit, Class):
12.988 - if AddressContextInstruction is not None:
12.989 - self.new_op(LoadConst(unit))
12.990 - self.new_op(AddressContextInstruction(unit.all_class_attributes()[name]))
12.991 - else:
12.992 - self.new_op(AddressInstruction(unit.all_class_attributes()[name]))
12.993 - elif isinstance(unit, Module):
12.994 - self.new_op(AddressInstruction(unit.module_attributes()[name]))
12.995 - else:
12.996 - raise TranslateError("Program unit has no local %r." % name)
12.997 -
12.998 - elif scope == "global":
12.999 - globals = self.module.module_attributes()
12.1000 - if globals.has_key(name):
12.1001 - self.new_op(AddressInstruction(globals[name]))
12.1002 - else:
12.1003 - raise TranslateError("Module has no attribute %r." % name)
12.1004 -
12.1005 - elif scope == "builtins":
12.1006 - self.new_op(AddressInstruction(self.get_builtin(name)))
12.1007 -
12.1008 - else:
12.1009 - # NOTE: This may happen because a class attribute is optimised away.
12.1010 - print >>sys.stderr, "Program unit uses unknown name %r." % name
12.1011 -
12.1012 - def _visitUnary(self, node):
12.1013 -
12.1014 - """
12.1015 - Invoke the appropriate operator module function for the operation
12.1016 - represented by 'node'.
12.1017 - """
12.1018 -
12.1019 - temp_fn = self._getOperatorFunction(node)
12.1020 - self._visitCall(node, temp_fn, (node.expr,))
12.1021 - self.discard_temp(temp_fn)
12.1022 -
12.1023 - def _visitBinaryBit(self, node):
12.1024 -
12.1025 - """
12.1026 - Need to impose binary rules over a sequence of nodes. The
12.1027 - short-circuiting of the similar logical operators is not imposed by the
12.1028 - bitwise operators.
12.1029 - """
12.1030 -
12.1031 - temp_fn = self._getOperatorFunction(node)
12.1032 - left = None
12.1033 -
12.1034 - for right in node.nodes:
12.1035 - if left is not None:
12.1036 - self._visitCall(node, temp_fn, (left, right))
12.1037 - left = right
12.1038 -
12.1039 - self.discard_temp(temp_fn)
12.1040 -
12.1041 - def _visitBinary(self, node):
12.1042 -
12.1043 - """
12.1044 - Invoke the appropriate operator module function for the operation
12.1045 - represented by 'node'.
12.1046 - """
12.1047 -
12.1048 - temp_fn = self._getOperatorFunction(node)
12.1049 - self._visitCall(node, temp_fn, (node.left, node.right))
12.1050 - self.discard_temp(temp_fn)
12.1051 -
12.1052 - def _visitCall(self, node, temp_fn, args):
12.1053 -
12.1054 - """
12.1055 - Invoke the appropriate operator module function for the operation
12.1056 - represented by 'node', given a 'temp_fn' reference to a function, along
12.1057 - with the 'args' (the operand nodes).
12.1058 - """
12.1059 -
12.1060 - # Evaluate and store the operands in temporary storage.
12.1061 -
12.1062 - temp_list = []
12.1063 -
12.1064 - for arg in args:
12.1065 - self.dispatch(arg)
12.1066 - temp_list.append(self.optimiser.optimise_temp_storage())
12.1067 -
12.1068 - self._generateInvocation(temp_fn, temp_list)
12.1069 -
12.1070 - # Compilation duties...
12.1071 -
12.1072 - for temp in temp_list:
12.1073 - self.discard_temp(temp)
12.1074 -
12.1075 - def _generateInvocation(self, temp_fn, temp_list):
12.1076 -
12.1077 - """
12.1078 - Invoke the function 'temp_fn' using the operands from 'temp_list' as
12.1079 - arguments.
12.1080 - """
12.1081 -
12.1082 - self._startCallFunc()
12.1083 -
12.1084 - for i, temp in enumerate(temp_list):
12.1085 - self.new_op(temp)
12.1086 - self.new_op(StoreFrame(i))
12.1087 -
12.1088 - self._endCallFuncArgs(len(temp_list))
12.1089 - self._doCallFunc(temp_fn)
12.1090 - self._endCallFunc(temp_fn)
12.1091 -
12.1092 - def _getOperatorFunction(self, node, operator_name=None):
12.1093 -
12.1094 - "Return an operator function reference for the given 'node'."
12.1095 -
12.1096 - return self._generateOperatorFunction(operator_name or node.__class__.__name__)
12.1097 -
12.1098 - def _getOperatorAugAssignFunction(self, node):
12.1099 -
12.1100 - """
12.1101 - Return an operator augmented assignment function reference for the given
12.1102 - 'node'.
12.1103 - """
12.1104 -
12.1105 - return self._generateOperatorFunction(node.op)
12.1106 -
12.1107 - def _generateOperatorFunction(self, opname):
12.1108 -
12.1109 - "Return an operator function reference for the given 'opname'."
12.1110 -
12.1111 - operator_fn = operator_functions[opname]
12.1112 -
12.1113 - # Get the operator module.
12.1114 -
12.1115 - operator_module = self.importer.get_module("operator")
12.1116 -
12.1117 - # Get the appropriate function from the operator module.
12.1118 -
12.1119 - self.new_op(LoadAddress(operator_module[operator_fn]))
12.1120 - return self.optimiser.optimise_temp_storage()
12.1121 -
12.1122 - def _handleAttributeError(self, node, temp_method, handled_block):
12.1123 -
12.1124 - """
12.1125 - Add exception handling to the method acquisition instructions where the
12.1126 - attribute access cannot be resolved at compile-time.
12.1127 - """
12.1128 -
12.1129 - if not (self.optimiser.should_optimise_known_target() and self.optimiser.is_constant_input(temp_method)):
12.1130 - self.load_builtin("AttributeError", node)
12.1131 - self.new_op(CheckException(target="status"))
12.1132 - self.new_op(JumpIfTrue(handled_block, working="status"))
12.1133 - self.new_op(RaiseException())
12.1134 -
12.1135 - def _generateTuple(self, node):
12.1136 -
12.1137 - "Make a tuple using the given program 'node'."
12.1138 -
12.1139 - # Reserve space for the elements themselves.
12.1140 -
12.1141 - self.make_instance(self.get_builtin_class("tuple"), len(node.nodes))
12.1142 - temp = self.get_temp()
12.1143 -
12.1144 - # Store using 0-based index values.
12.1145 -
12.1146 - self._populateSequence(temp, node.nodes)
12.1147 -
12.1148 - self.new_op(temp)
12.1149 - self.discard_temp(temp)
12.1150 -
12.1151 - def _generateList(self, node, nodes=None):
12.1152 -
12.1153 - "Make a list using the given program 'node' and optional 'nodes'."
12.1154 -
12.1155 - nodes = nodes or []
12.1156 -
12.1157 - # Make a fragment containing the list elements.
12.1158 -
12.1159 - self.new_op(MakeFragment(len(nodes) + 1))
12.1160 - temp = self.get_temp()
12.1161 - self._populateSequence(temp, nodes)
12.1162 - self.new_op(temp)
12.1163 - self.record_value()
12.1164 -
12.1165 - # Reserve space for _elements (the fragment reference).
12.1166 -
12.1167 - self.make_instance(self.get_builtin_class("list"), 1)
12.1168 - list_temp = self.get_temp()
12.1169 -
12.1170 - self.start_target()
12.1171 - self.new_op(list_temp)
12.1172 - self.new_op(StoreAttr(Attr(0, None, None))) # _elements is at position 0
12.1173 - self.assign_value()
12.1174 - self.discard_value()
12.1175 -
12.1176 - self.new_op(list_temp)
12.1177 - self.discard_temp(temp)
12.1178 - self.discard_temp(list_temp)
12.1179 -
12.1180 - def _populateSequence(self, temp, nodes, offset=0):
12.1181 -
12.1182 - """
12.1183 - Populate a sequence using the given 'temp' reference and 'nodes'.
12.1184 - """
12.1185 -
12.1186 - for i, n in enumerate(nodes):
12.1187 - self.dispatch(n)
12.1188 - self.record_value()
12.1189 - self._storeInSequence(temp, i, offset)
12.1190 - self.discard_value()
12.1191 -
12.1192 - def _storeInSequence(self, temp, i, offset=0):
12.1193 -
12.1194 - """
12.1195 - Store the current active value in the fragment referenced by 'temp' at
12.1196 - position 'i' with the given starting 'offset'.
12.1197 - """
12.1198 -
12.1199 - self.start_target()
12.1200 - self.new_op(temp)
12.1201 - self.new_op(StoreAttr(Attr(i + offset, None, None)))
12.1202 - self.assign_value()
12.1203 -
12.1204 - def _generateTestBoolean(self, node, temp):
12.1205 -
12.1206 - """
12.1207 - Generate a test of the boolean status of the current value for the given
12.1208 - program 'node'.
12.1209 - """
12.1210 -
12.1211 - # Get method on temp.
12.1212 - # NOTE: Using __bool__ instead of __nonzero__.
12.1213 -
12.1214 - self._generateAttr(node, "__bool__", self.attribute_load_instructions)
12.1215 - temp_method = self.optimiser.optimise_temp_storage()
12.1216 -
12.1217 - self._generateInvocation(temp_method, (temp,))
12.1218 -
12.1219 - self.discard_temp(temp_method)
12.1220 -
12.1221 - # Convert result to boolean (a StoreBoolean operation).
12.1222 -
12.1223 - self.new_op(TestIdentityAddress(self.importer.get_predefined_constant("True"), target="status"))
12.1224 -
12.1225 - def _generateLoadBoolean(self, node):
12.1226 -
12.1227 - """
12.1228 - Generate instructions to load the appropriate value given the current
12.1229 - boolean status.
12.1230 - """
12.1231 -
12.1232 - false_block = self.get_block()
12.1233 - true_block = self.new_block()
12.1234 - end_block = self.new_block()
12.1235 -
12.1236 - self.new_op(JumpIfTrue(true_block, working="status"))
12.1237 - self.new_op(LoadConst(self.importer.get_predefined_constant("False")))
12.1238 - self.new_op(Jump(end_block))
12.1239 -
12.1240 - self.set_block(true_block)
12.1241 - self.new_op(LoadConst(self.importer.get_predefined_constant("True")))
12.1242 -
12.1243 - self.set_block(end_block, [false_block, true_block])
12.1244 -
12.1245 - # Common AST operations.
12.1246 -
12.1247 - def _startFor(self, node, else_=None):
12.1248 -
12.1249 - """
12.1250 - Generate the start of a loop using the given 'node' and 'else_' clause,
12.1251 - if defined. The iterator and next, exit and else blocks are returned.
12.1252 - """
12.1253 -
12.1254 - next_handler_block = self.new_block()
12.1255 - end_handler_block = self.new_block()
12.1256 - exit_block = self.new_block()
12.1257 - next_block = self.new_block()
12.1258 - else_block = self.new_block()
12.1259 -
12.1260 - temp_iterator = self._visitForList(node)
12.1261 -
12.1262 - # In the loop...
12.1263 -
12.1264 - self.set_block(next_block)
12.1265 -
12.1266 - # Handle exceptions when calling "next"...
12.1267 -
12.1268 - self.add_exception_blocks(next_handler_block, end_handler_block)
12.1269 - self.new_op(PushHandler(next_handler_block))
12.1270 -
12.1271 - # Invoke the next method.
12.1272 -
12.1273 - self._visitForNext(node, temp_iterator)
12.1274 -
12.1275 - # Record the value to be assigned.
12.1276 -
12.1277 - self.record_value()
12.1278 -
12.1279 - # Skip the handler where the call was successful.
12.1280 -
12.1281 - self.new_op(PopHandler(1))
12.1282 - self.new_op(Jump(end_handler_block))
12.1283 -
12.1284 - # Enter the exception handler.
12.1285 -
12.1286 - self.set_block(next_handler_block)
12.1287 - self.new_op(PopHandler(1))
12.1288 -
12.1289 - # Disable the handlers.
12.1290 -
12.1291 - self.drop_exception_blocks()
12.1292 -
12.1293 - # Test for StopIteration.
12.1294 -
12.1295 - self.load_builtin("StopIteration", node)
12.1296 - self.new_op(CheckException(target="status"))
12.1297 - if else_ is not None:
12.1298 - self.new_op(JumpIfTrue(else_block, working="status"))
12.1299 - else:
12.1300 - self.new_op(JumpIfTrue(exit_block, working="status"))
12.1301 -
12.1302 - # Re-raise the exception otherwise.
12.1303 -
12.1304 - self.new_op(RaiseException())
12.1305 -
12.1306 - # After the handler, clear the exception.
12.1307 -
12.1308 - self.set_block(end_handler_block)
12.1309 -
12.1310 - # Assign to the target.
12.1311 -
12.1312 - self.dispatch(node.assign)
12.1313 - self.discard_value()
12.1314 -
12.1315 - # Process the body with the current next and exit points.
12.1316 -
12.1317 - self.add_loop_blocks(next_block, exit_block)
12.1318 -
12.1319 - return temp_iterator, next_block, exit_block, else_block
12.1320 -
12.1321 - def _endFor(self, node, temp_iterator, next_block, exit_block, else_block=None, else_=None):
12.1322 -
12.1323 - """
12.1324 - Generate the end of a loop for the given 'node' using the given
12.1325 - 'temp_iterator' and 'next_block', 'exit_block' and 'else_block'
12.1326 - definitions, together with an 'else_' clause, if defined.
12.1327 - """
12.1328 -
12.1329 - self.drop_loop_blocks()
12.1330 -
12.1331 - # Repeat the loop.
12.1332 -
12.1333 - self.new_op(Jump(next_block))
12.1334 -
12.1335 - # Produce the "else" section.
12.1336 -
12.1337 - if else_ is not None:
12.1338 - self.set_block(else_block)
12.1339 - self.new_op(ClearException(target="exception"))
12.1340 - self.dispatch(else_)
12.1341 -
12.1342 - # After the loop...
12.1343 -
12.1344 - self.set_block(exit_block)
12.1345 -
12.1346 - else:
12.1347 - # After the loop...
12.1348 -
12.1349 - self.set_block(exit_block)
12.1350 - self.new_op(ClearException(target="exception"))
12.1351 -
12.1352 - # Compilation duties...
12.1353 -
12.1354 - self.discard_temp(temp_iterator)
12.1355 -
12.1356 - def _visitForList(self, node):
12.1357 -
12.1358 - "Get the list to be iterated over, returning its iterator."
12.1359 -
12.1360 - self._startCallFunc()
12.1361 - self.dispatch(node.list)
12.1362 - self._generateAttr(node, "__iter__", self.attribute_load_instructions)
12.1363 - temp_target, target, temp_context = self._generateCallFunc([], node)
12.1364 - self._doCallFunc(temp_target, target)
12.1365 - self._endCallFunc(temp_target, temp_context)
12.1366 -
12.1367 - # Use a long-lasting temporary storage slot, since any result from the
12.1368 - # __iter__ method will not remain around for long.
12.1369 -
12.1370 - return self.get_temp()
12.1371 -
12.1372 - def _visitForNext(self, node, temp_iterator):
12.1373 -
12.1374 - "Use the iterator to get the next value."
12.1375 -
12.1376 - self._startCallFunc()
12.1377 - self.new_op(temp_iterator)
12.1378 - self._generateAttr(node, "next", self.attribute_load_instructions)
12.1379 - temp_target, target, temp_context = self._generateCallFunc([], node)
12.1380 - self._doCallFunc(temp_target, target)
12.1381 - self._endCallFunc(temp_target, temp_context)
12.1382 -
12.1383 - def _visitPrint(self, node, function_name):
12.1384 - self._startCallFunc()
12.1385 - self.load_builtin(function_name, node)
12.1386 -
12.1387 - args = [node.dest or compiler.ast.Name("None")] + node.nodes
12.1388 -
12.1389 - temp_target, target, temp_context = self._generateCallFunc(args, node)
12.1390 - self._doCallFunc(temp_target, target)
12.1391 - self._endCallFunc(temp_target, temp_context)
12.1392 -
12.1393 - def _visitImport(self, node):
12.1394 -
12.1395 - """
12.1396 - Although imported code already resides in any generated image, the
12.1397 - module code must be executed. Module code uses its own frame for any
12.1398 - temporary storage and thus behaves like a function.
12.1399 - """
12.1400 -
12.1401 - modules = self.importer.importers.get(node)
12.1402 - if modules:
12.1403 - for module in modules:
12.1404 - self.new_op(MakeFrame(0))
12.1405 - self.new_op(LoadConst(module))
12.1406 - self.new_op(LoadCallable())
12.1407 - self.new_op(JumpWithFrame())
12.1408 - self.new_op(DropFrame())
12.1409 -
12.1410 - def _importName(self, module, name, alias, node):
12.1411 -
12.1412 - # Get the source of the name.
12.1413 -
12.1414 - attr = module[name]
12.1415 - self.new_op(LoadAddress(attr))
12.1416 -
12.1417 - # Record the object in the current namespace.
12.1418 -
12.1419 - self.record_value()
12.1420 -
12.1421 - self.start_target()
12.1422 - self._generateName(alias or name, self.name_store_instructions, node) # AssName equivalent
12.1423 - self.assign_value()
12.1424 - self.discard_value()
12.1425 -
12.1426 -# vim: tabstop=4 expandtab shiftwidth=4
13.1 --- a/rsvp.py Fri Jun 28 21:17:02 2013 +0200
13.2 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000
13.3 @@ -1,915 +0,0 @@
13.4 -#!/usr/bin/env python
13.5 -
13.6 -"""
13.7 -A really simple virtual processor employing a simple set of instructions which
13.8 -ignore low-level operations and merely concentrate on variable access, structure
13.9 -access, structure allocation and function invocations.
13.10 -
13.11 -Copyright (C) 2007, 2008, 2009, 2010, 2011 Paul Boddie <paul@boddie.org.uk>
13.12 -
13.13 -This program is free software; you can redistribute it and/or modify it under
13.14 -the terms of the GNU General Public License as published by the Free Software
13.15 -Foundation; either version 3 of the License, or (at your option) any later
13.16 -version.
13.17 -
13.18 -This program is distributed in the hope that it will be useful, but WITHOUT
13.19 -ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
13.20 -FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
13.21 -details.
13.22 -
13.23 -You should have received a copy of the GNU General Public License along with
13.24 -this program. If not, see <http://www.gnu.org/licenses/>.
13.25 -
13.26 ---------
13.27 -
13.28 -The execution model of the virtual processor involves the following things:
13.29 -
13.30 - * Memory contains constants, global variable
13.31 - references and program code
13.32 -
13.33 - * PC (program counter) stack contains the return address associated
13.34 - with each function invocation
13.35 -
13.36 - * Frame stack contains invocation frames in use and in
13.37 - preparation plus temporary storage
13.38 -
13.39 - * Local frame pointer stack refers to the frames in the frame stack
13.40 -
13.41 - * Invocation frame pointer stack
13.42 -
13.43 - * Exception handler stack
13.44 -
13.45 - * Exception handler locals stack refers to the state of the local frame
13.46 - pointer stack
13.47 -
13.48 - * Exception handler PC stack refers to the state of the PC stack
13.49 -
13.50 - * Registers: working context/value,
13.51 - assignment source context/value,
13.52 - current exception value,
13.53 - boolean status value,
13.54 - object list start (constant),
13.55 - parameter list start (constant)
13.56 -"""
13.57 -
13.58 -from micropython.program import DataValue, ReplaceableContext, PlaceholderContext, FragmentObject
13.59 -from rsvplib import Library
13.60 -
13.61 -class IllegalInstruction(Exception):
13.62 - pass
13.63 -
13.64 -class IllegalAddress(Exception):
13.65 - def __init__(self, address):
13.66 - self.address = address
13.67 - def __repr__(self):
13.68 - return "IllegalAddress(%r)" % self.address
13.69 - def __str__(self):
13.70 - return repr(self)
13.71 -
13.72 -class EmptyPCStack(Exception):
13.73 - pass
13.74 -
13.75 -class EmptyFrameStack(Exception):
13.76 - pass
13.77 -
13.78 -class BreakpointReached(Exception):
13.79 - pass
13.80 -
13.81 -class RSVPMachine:
13.82 -
13.83 - "A really simple virtual processor."
13.84 -
13.85 - def __init__(self, memory, objlist, paramlist, pc=None, debug=0, abort_upon_exception=0):
13.86 -
13.87 - """
13.88 - Initialise the processor with a 'memory' (a list of values containing
13.89 - instructions and data), the object and parameter lists 'objlist' and
13.90 - 'paramlist', and the optional program counter 'pc'.
13.91 - """
13.92 -
13.93 - self.memory = memory
13.94 - self._objlist = objlist
13.95 - self._paramlist = paramlist
13.96 - end_of_code = len(self.memory)
13.97 -
13.98 - # Add the object list.
13.99 -
13.100 - objlist_start = len(self.memory)
13.101 - self.memory += objlist.as_raw()
13.102 -
13.103 - # Add the parameter list.
13.104 -
13.105 - paramlist_start = len(self.memory)
13.106 - self.memory += paramlist.as_raw()
13.107 -
13.108 - # A reference to the native library.
13.109 -
13.110 - self.library = None
13.111 -
13.112 - # Program counter and machine configuration.
13.113 -
13.114 - self.pc = pc or 0
13.115 - self.debug = debug
13.116 - self.abort_upon_exception = abort_upon_exception
13.117 -
13.118 - # Profiling.
13.119 -
13.120 - self.coverage = [0] * end_of_code
13.121 - self.counter = 0
13.122 - self.cost = 0
13.123 -
13.124 - # Stacks.
13.125 -
13.126 - self.pc_stack = []
13.127 - self.frame_stack = []
13.128 - self.local_sp_stack = [0]
13.129 - self.invocation_sp_stack = []
13.130 -
13.131 - # Exception handler stacks are used to reset the state of the main
13.132 - # stacks.
13.133 -
13.134 - self.handler_stack = [end_of_code - 1] # final handler is the end of the code
13.135 - self.handler_local_sp_stack = []
13.136 - self.handler_invocation_sp_stack = []
13.137 - self.handler_pc_stack = []
13.138 -
13.139 - # Registers.
13.140 -
13.141 - self.register_names = (
13.142 - "working",
13.143 - "working_context",
13.144 - "source",
13.145 - "source_context",
13.146 - "exception",
13.147 - "status",
13.148 - "objlist",
13.149 - "paramlist"
13.150 - )
13.151 - self.registers = {}
13.152 -
13.153 - for name in self.register_names:
13.154 - self.registers[name] = None
13.155 -
13.156 - self.registers["objlist"] = objlist_start
13.157 - self.registers["paramlist"] = paramlist_start
13.158 -
13.159 - self.instruction = None
13.160 -
13.161 - # Constants.
13.162 - # NOTE: These should eventually be removed once the code using them has
13.163 - # NOTE: been migrated to the native code library.
13.164 -
13.165 - cls = self._get_class("__builtins__", "AttributeError")
13.166 - self.attr_error = cls.location
13.167 - self.attr_error_instance = cls.instance_template_location
13.168 - cls = self._get_class("__builtins__", "TypeError")
13.169 - self.type_error = cls.location
13.170 - self.type_error_instance = cls.instance_template_location
13.171 - cls = self._get_class("__builtins__", "tuple")
13.172 - self.tuple_class = cls.location
13.173 - self.tuple_instance = cls.instance_template_location
13.174 -
13.175 - # Debugging attributes.
13.176 -
13.177 - self.breakpoints = set()
13.178 -
13.179 - def get_program_size(self):
13.180 - return self.registers["objlist"]
13.181 -
13.182 - def _get_class(self, module, name):
13.183 - attr = self._objlist.access(module, name)
13.184 - if attr is not None:
13.185 - return attr.get_value()
13.186 - else:
13.187 - return None
13.188 -
13.189 - # Debugging methods.
13.190 -
13.191 - def dump(self):
13.192 - print "PC", self.pc, "->", self.load(self.pc)
13.193 - print "PC stack", self.pc_stack
13.194 - print "Frame stack:"
13.195 - if self.local_sp_stack:
13.196 - start = self.local_sp_stack[0]
13.197 - for end in self.local_sp_stack[1:]:
13.198 - print " %2d" % start, self.frame_stack[start:end]
13.199 - start = end
13.200 - else:
13.201 - print " %2d" % start, self.frame_stack[start:]
13.202 - print
13.203 - print "Local stack pointers", self.local_sp_stack
13.204 - print "Invocation stack pointers", self.invocation_sp_stack
13.205 - print "Handler stack", self.handler_stack
13.206 - print "Handler frame stack", self.handler_local_sp_stack
13.207 - print "Handler PC stack", self.handler_pc_stack
13.208 - print
13.209 - print "Registers:"
13.210 - print
13.211 - for name in self.register_names:
13.212 - print "%s: %s" % (name, self.registers[name])
13.213 - print
13.214 - print "Instruction", self.instruction
13.215 -
13.216 - def show(self, start=None, end=None):
13.217 - self.show_memory(self.memory[start:end], self.coverage[start:end], start or 0)
13.218 -
13.219 - def show_pc(self, run_in=10):
13.220 - start = max(0, self.pc - run_in)
13.221 - end = self.pc + run_in
13.222 - memory = self.memory[start:end]
13.223 - coverage = self.coverage[start:end]
13.224 - self.show_memory(memory, coverage, start)
13.225 -
13.226 - def show_object(self, start):
13.227 - obj = self.memory[start]
13.228 - end = start + obj.size
13.229 - self.show_memory(self.memory[start:end], self.coverage[start:end], start)
13.230 -
13.231 - def show_memory(self, memory, coverage, start):
13.232 - for i, (c, x) in enumerate(map(None, coverage, memory)):
13.233 - location = start + i
13.234 - if location == self.pc:
13.235 - print "->",
13.236 - elif location in self.pc_stack:
13.237 - print "..",
13.238 - else:
13.239 - print " ",
13.240 - print "%-5s %5d %r" % (c or "", location, x)
13.241 -
13.242 - def step(self, dump=0):
13.243 - self.execute()
13.244 - self.show_pc()
13.245 - if dump:
13.246 - self.dump()
13.247 -
13.248 - def set_break(self, location):
13.249 - self.breakpoints.add(location)
13.250 -
13.251 - def up(self):
13.252 - retaddr = self.pc_stack[-1]
13.253 - self.set_break(retaddr)
13.254 - self.run()
13.255 -
13.256 - # Internal operations.
13.257 -
13.258 - def load(self, address):
13.259 -
13.260 - "Return the value at the given 'address'."
13.261 -
13.262 - try:
13.263 - return self.memory[address]
13.264 - except IndexError:
13.265 - raise IllegalAddress(address)
13.266 - except TypeError:
13.267 - raise IllegalAddress(address)
13.268 -
13.269 - def save(self, address, value):
13.270 -
13.271 - "Save to the given 'address' the specified 'value'."
13.272 -
13.273 - try:
13.274 - self.memory[address] = value
13.275 - except IndexError:
13.276 - raise IllegalAddress(address)
13.277 - except TypeError:
13.278 - raise IllegalAddress(address)
13.279 -
13.280 - def new(self, size):
13.281 -
13.282 - """
13.283 - Allocate space of the given 'size', returning the address of the space.
13.284 - """
13.285 -
13.286 - addr = len(self.memory)
13.287 - for i in range(0, size):
13.288 - self.memory.append(None)
13.289 - return addr
13.290 -
13.291 - def push_pc(self, data):
13.292 -
13.293 - "Push 'data' onto the PC stack."
13.294 -
13.295 - self.pc_stack.append(data)
13.296 -
13.297 - def pull_pc(self):
13.298 -
13.299 - "Pull a value from the PC stack and return it."
13.300 -
13.301 - try:
13.302 - return self.pc_stack.pop()
13.303 - except IndexError:
13.304 - raise EmptyPCStack
13.305 -
13.306 - def run(self):
13.307 -
13.308 - "Execute code in the memory, starting from the current PC address."
13.309 -
13.310 - breakpoint = 0
13.311 -
13.312 - try:
13.313 - while 1:
13.314 - self.execute()
13.315 - except EmptyPCStack:
13.316 - pass
13.317 - except BreakpointReached:
13.318 - breakpoint = 1
13.319 -
13.320 - print "Execution terminated",
13.321 - if breakpoint:
13.322 - print "with breakpoint."
13.323 - print "At address", self.pc
13.324 - elif self.registers["exception"] is not None:
13.325 - ref = self.registers["exception"]
13.326 - addr = self.load(ref + Library.instance_data_offset)
13.327 - print "with exception:", self.load(ref)
13.328 - print "At address %d: %r" % (addr, self.load(addr))
13.329 - else:
13.330 - print "successfully."
13.331 - print "After", self.counter, "instructions at cost", self.cost, "units."
13.332 -
13.333 - def test(self, module):
13.334 -
13.335 - """
13.336 - Test the code in the memory by running the code and investigating the
13.337 - contents of variables. Use 'module' to identify result variables.
13.338 - """
13.339 -
13.340 - self.run()
13.341 - success = 1
13.342 -
13.343 - if self.registers["exception"] is None:
13.344 - for name in module.keys():
13.345 - if name.startswith("result"):
13.346 - label, expected = name.split("_")
13.347 - attr = module[name]
13.348 -
13.349 - # Need to skip the header to get at the members.
13.350 -
13.351 - attr_location = module.location + Library.instance_data_offset + attr.position
13.352 - value = self.load(attr_location)
13.353 -
13.354 - if value is not None:
13.355 - content = self.load(value.ref + Library.instance_data_offset)
13.356 - print label, expected, content
13.357 - success = success and (int(expected) == content)
13.358 - else:
13.359 - print label, expected, "missing"
13.360 - success = 0
13.361 -
13.362 - return success
13.363 - else:
13.364 - return 0
13.365 -
13.366 - def execute(self):
13.367 -
13.368 - "Execute code in the memory at the current PC address."
13.369 -
13.370 - if self.pc in self.breakpoints:
13.371 - self.breakpoints.remove(self.pc)
13.372 - raise BreakpointReached
13.373 -
13.374 - self.instruction = self.load(self.pc)
13.375 -
13.376 - # Perform the instruction itself.
13.377 -
13.378 - next_pc = self.perform(self.instruction)
13.379 -
13.380 - # Update the coverage.
13.381 -
13.382 - self.coverage[self.pc] += 1
13.383 -
13.384 - # Update the program counter.
13.385 -
13.386 - if next_pc is None:
13.387 - self.pc += 1
13.388 - else:
13.389 - self.pc = next_pc
13.390 -
13.391 - def get_method(self, instruction):
13.392 -
13.393 - "Return the handler method for the given 'instruction'."
13.394 -
13.395 - instruction_name = instruction.__class__.__name__
13.396 - if self.debug:
13.397 - print "%8d %s" % (self.pc, instruction_name)
13.398 - method = getattr(self, instruction_name, None)
13.399 - if method is None:
13.400 - raise IllegalInstruction, (self.pc, instruction_name)
13.401 - return method
13.402 -
13.403 - def perform(self, instruction):
13.404 -
13.405 - "Perform the 'instruction', returning the next PC value or None."
13.406 -
13.407 - self.counter += 1
13.408 - self.cost += instruction.cost
13.409 - operand = instruction.get_operand()
13.410 - method = self.get_method(instruction)
13.411 - return method(operand, instruction)
13.412 -
13.413 - def jump(self, addr, next):
13.414 -
13.415 - """
13.416 - Jump to the subroutine at (or identified by) 'addr'. If 'addr'
13.417 - identifies a library function then invoke the library function and set
13.418 - PC to 'next' afterwards; otherwise, set PC to 'addr'.
13.419 - """
13.420 -
13.421 - # Trap library functions introduced through the use of strings instead
13.422 - # of proper locations.
13.423 -
13.424 - if isinstance(addr, str):
13.425 - handler = self.library and self.library.native_functions[addr](self.library)
13.426 - if handler is None:
13.427 - return next
13.428 - else:
13.429 - return handler
13.430 - else:
13.431 - self.push_pc(self.pc + 1)
13.432 - return addr
13.433 -
13.434 - # Helper methods.
13.435 -
13.436 - def context_of(self, register):
13.437 - return "%s_context" % register
13.438 -
13.439 - def load_from_frame(self, operand):
13.440 - frame = self.local_sp_stack[-1]
13.441 - return self.frame_stack[frame + operand]
13.442 -
13.443 - # Low-level instructions.
13.444 -
13.445 - def LoadImmediate(self, operand, target):
13.446 - self.registers[target] = operand
13.447 -
13.448 - def LoadMemory(self, operand, target, source):
13.449 - self.registers[target] = self.load(
13.450 - self.registers[source] + (operand is not None and operand or 0)
13.451 - )
13.452 -
13.453 - # Instructions.
13.454 -
13.455 - def Transfer(self, operand, instruction):
13.456 - self.registers[instruction.target] = self.registers[instruction.source]
13.457 -
13.458 - def LoadConst(self, operand, instruction):
13.459 - self.LoadImmediate(operand, self.context_of(instruction.target))
13.460 - self.LoadImmediate(operand, instruction.target)
13.461 -
13.462 - def LoadClass(self, operand, instruction):
13.463 - self.LoadImmediate(PlaceholderContext, self.context_of(instruction.target))
13.464 - self.LoadImmediate(operand, instruction.target)
13.465 -
13.466 - def LoadFunction(self, operand, instruction):
13.467 - self.LoadImmediate(ReplaceableContext, self.context_of(instruction.target))
13.468 - self.LoadImmediate(operand, instruction.target)
13.469 -
13.470 - def LoadName(self, operand, instruction):
13.471 - data = self.load_from_frame(operand)
13.472 - self.LoadImmediate(data.context, self.context_of(instruction.target))
13.473 - self.LoadImmediate(data.ref, instruction.target)
13.474 -
13.475 - def StoreName(self, operand, instruction):
13.476 - frame = self.local_sp_stack[-1]
13.477 - self.frame_stack[frame + operand] = DataValue(
13.478 - self.registers[self.context_of(instruction.source)],
13.479 - self.registers[instruction.source])
13.480 -
13.481 - LoadTemp = LoadName
13.482 -
13.483 - def StoreTemp(self, operand, instruction):
13.484 - frame = self.local_sp_stack[-1]
13.485 - self.frame_stack[frame + operand] = DataValue(
13.486 - self.registers[self.context_of(instruction.working)],
13.487 - self.registers[instruction.working])
13.488 -
13.489 - def LoadAddress(self, operand, instruction):
13.490 - # Preserve context (potentially null).
13.491 - data = self.load(operand)
13.492 - self.LoadImmediate(data.context, self.context_of(instruction.target))
13.493 - self.LoadImmediate(data.ref, instruction.target)
13.494 -
13.495 - def LoadAddressContext(self, operand, instruction):
13.496 - # Value becomes context.
13.497 - data = self.load(operand)
13.498 - self.LoadImmediate(self.registers[instruction.working], self.context_of(instruction.target))
13.499 - self.LoadImmediate(data.ref, instruction.target)
13.500 -
13.501 - def LoadAddressContextCond(self, operand, instruction):
13.502 - data = self.load(operand)
13.503 - data = self._LoadAddressContextCond(data.context, data.ref, self.registers[instruction.working])
13.504 - self.LoadImmediate(data.context, self.context_of(instruction.target))
13.505 - self.LoadImmediate(data.ref, instruction.target)
13.506 -
13.507 - def StoreAddress(self, operand, instruction):
13.508 - # Preserve context.
13.509 - self.save(operand, DataValue(
13.510 - self.registers[self.context_of(instruction.source)],
13.511 - self.registers[instruction.source]))
13.512 -
13.513 - def StoreAddressContext(self, operand, instruction):
13.514 - # Overwrite context if null.
13.515 - self._StoreAddressContext(operand,
13.516 - self.registers[self.context_of(instruction.working)],
13.517 - self.registers[instruction.working],
13.518 - self.registers[self.context_of(instruction.source)],
13.519 - self.registers[instruction.source])
13.520 -
13.521 - def MakeInstance(self, size, instruction):
13.522 - # NOTE: Referencing the instance template.
13.523 - addr = self._MakeObject(size, self.registers[instruction.working] - Library.instance_template_size)
13.524 - # Introduce object as context for the new object.
13.525 - self.LoadImmediate(addr, self.context_of(instruction.target))
13.526 - self.LoadImmediate(addr, instruction.target)
13.527 -
13.528 - def MakeFragment(self, size, instruction):
13.529 - # Reserve twice the amount of space.
13.530 - addr = self._MakeFragment(size, size * 2)
13.531 - # NOTE: Context is not relevant for fragments.
13.532 - self.LoadImmediate(None, self.context_of(instruction.target))
13.533 - self.LoadImmediate(addr, instruction.target)
13.534 -
13.535 - def LoadAttr(self, pos, instruction):
13.536 - # Retrieved context should already be appropriate for the instance.
13.537 - # Skip any header.
13.538 - data = self.load(self.registers[instruction.working] + Library.instance_data_offset + pos)
13.539 - self.LoadImmediate(data.context, self.context_of(instruction.target))
13.540 - self.LoadImmediate(data.ref, instruction.target)
13.541 -
13.542 - def StoreAttr(self, pos, instruction):
13.543 - # Target should already be an instance.
13.544 - # Skip any header.
13.545 - self.save(self.registers[instruction.working] + Library.instance_data_offset + pos , DataValue(
13.546 - self.registers[self.context_of(instruction.source)],
13.547 - self.registers[instruction.source]))
13.548 -
13.549 - def LoadAttrIndex(self, index, instruction):
13.550 - data = self.load(self.registers[instruction.working])
13.551 - element = self.load(self.registers["objlist"] + data.classcode + index)
13.552 -
13.553 - if element is not None:
13.554 - attr_index, static_attr, offset = element
13.555 - if attr_index == index:
13.556 - if static_attr:
13.557 - data = self.load(offset) # offset is address of class/module attribute
13.558 - else:
13.559 - data = self.load(self.registers[instruction.working] + offset)
13.560 - self.LoadImmediate(data.context, self.context_of(instruction.target))
13.561 - self.LoadImmediate(data.ref, instruction.target)
13.562 - return
13.563 -
13.564 - self.registers["exception"] = self._MakeObject(Library.instance_size, self.attr_error_instance)
13.565 - return self.RaiseException()
13.566 -
13.567 - # LoadAttrIndexContext not defined.
13.568 -
13.569 - def LoadAttrIndexContextCond(self, index, instruction):
13.570 - data = self.load(self.registers[instruction.working])
13.571 - element = self.load(self.registers["objlist"] + data.classcode + index)
13.572 -
13.573 - if element is not None:
13.574 - attr_index, static_attr, offset = element
13.575 - if attr_index == index:
13.576 - if static_attr:
13.577 - loaded_data = self.load(offset) # offset is address of class/module attribute
13.578 - # Absent attrcode == class/module.
13.579 - if data.attrcode is not None:
13.580 - loaded_data = self._LoadAddressContextCond(
13.581 - loaded_data.context, loaded_data.ref,
13.582 - self.registers[instruction.working])
13.583 - else:
13.584 - loaded_data = self.load(self.registers[instruction.working] + offset)
13.585 - self.LoadImmediate(loaded_data.context, self.context_of(instruction.target))
13.586 - self.LoadImmediate(loaded_data.ref, instruction.target)
13.587 - return
13.588 -
13.589 - self.registers["exception"] = self._MakeObject(Library.instance_size, self.attr_error_instance)
13.590 - return self.RaiseException()
13.591 -
13.592 - def StoreAttrIndex(self, index, instruction):
13.593 - data = self.load(self.registers[instruction.working])
13.594 - element = self.load(self.registers["objlist"] + data.classcode + index)
13.595 -
13.596 - if element is not None:
13.597 - attr_index, static_attr, offset = element
13.598 - if attr_index == index:
13.599 - if static_attr:
13.600 - self._StoreAddressContext(offset,
13.601 - self.registers[self.context_of(instruction.working)],
13.602 - self.registers[instruction.working],
13.603 - self.registers[self.context_of(instruction.source)],
13.604 - self.registers[instruction.source])
13.605 - return
13.606 - else:
13.607 - self.save(self.registers[instruction.working] + offset, DataValue(
13.608 - self.registers[self.context_of(instruction.source)],
13.609 - self.registers[instruction.source]))
13.610 - return
13.611 -
13.612 - self.registers["exception"] = self._MakeObject(Library.instance_size, self.attr_error_instance)
13.613 - return self.RaiseException()
13.614 -
13.615 - # NOTE: LoadAttrIndexContext is a possibility if a particular attribute can always be overridden.
13.616 -
13.617 - def MakeFrame(self, size, instruction):
13.618 - self.invocation_sp_stack.append(len(self.frame_stack))
13.619 - self.frame_stack.extend([None] * size)
13.620 -
13.621 - def DropFrame(self, operand, instruction):
13.622 - self.local_sp_stack.pop()
13.623 - frame = self.invocation_sp_stack.pop()
13.624 - del self.frame_stack[frame:] # reset stack before call
13.625 -
13.626 - def StoreFrame(self, pos, instruction):
13.627 - frame = self.invocation_sp_stack[-1] # different from the current frame after MakeFrame
13.628 - self.frame_stack[frame + pos] = DataValue(
13.629 - self.registers[self.context_of(instruction.working)],
13.630 - self.registers[instruction.working])
13.631 -
13.632 - def StoreFrameIndex(self, index, instruction):
13.633 - frame = self.invocation_sp_stack[-1] # different from the current frame after MakeFrame
13.634 - data = self.load(self.registers[instruction.working])
13.635 - element = self.load(self.registers["paramlist"] + data.funccode + index)
13.636 -
13.637 - if element is not None:
13.638 - # NOTE: Need to ensure correct positioning where a context has been generated.
13.639 - param_index, offset = element
13.640 - if param_index == index:
13.641 - self.frame_stack[frame + offset] = DataValue(
13.642 - self.registers[self.context_of(instruction.source)],
13.643 - self.registers[instruction.source])
13.644 - return
13.645 -
13.646 - self.registers["exception"] = self._MakeObject(Library.instance_size, self.type_error_instance)
13.647 - return self.RaiseException()
13.648 -
13.649 - def LoadCallable(self, operand, instruction):
13.650 - data = self.load(self.registers[instruction.working])
13.651 - self.registers[instruction.target] = data.codeaddr
13.652 -
13.653 - def StoreCallable(self, operand, instruction):
13.654 - # NOTE: Should improve the representation and permit direct saving.
13.655 - data = self.load(self.registers[instruction.working])
13.656 - self.save(self.registers[instruction.working], data.with_callable(self.registers[instruction.source]))
13.657 -
13.658 - def CheckContext(self, operand, instruction):
13.659 - self.registers[instruction.target] = self.registers[instruction.working] is not ReplaceableContext
13.660 -
13.661 - def CheckClass(self, operand, instruction):
13.662 - if self.registers[instruction.working] in (ReplaceableContext, PlaceholderContext):
13.663 - self.registers[instruction.target] = 0
13.664 - return
13.665 -
13.666 - data = self.load(self.registers[instruction.working])
13.667 -
13.668 - # Classes are not themselves usable as the self argument.
13.669 - # NOTE: This may change at some point.
13.670 - # However, where classes appear as the context, instance
13.671 - # compatibility is required in the first argument.
13.672 -
13.673 - self.registers[instruction.target] = data.attrcode is None # absent attrcode == class
13.674 -
13.675 - def CheckFrame(self, operand, instruction):
13.676 - (nargs, ndefaults) = operand
13.677 -
13.678 - # The frame is actually installed as the locals.
13.679 - # Retrieve the context from the first local.
13.680 -
13.681 - frame = self.local_sp_stack[-1]
13.682 - nlocals = len(self.frame_stack[frame:])
13.683 -
13.684 - if not ((nargs - ndefaults) <= nlocals):
13.685 - raise Exception, "CheckFrame %r (%r <= %r <= %r)" % (operand, nargs - ndefaults, nlocals, nargs)
13.686 - #self.registers["exception"] = self._MakeObject(Library.instance_size, self.type_error_instance)
13.687 - #return self.RaiseException()
13.688 -
13.689 - def CheckExtra(self, nargs, instruction):
13.690 -
13.691 - # The frame is actually installed as the locals.
13.692 - # Retrieve the context from the first local.
13.693 -
13.694 - frame = self.local_sp_stack[-1]
13.695 - nlocals = len(self.frame_stack[frame:])
13.696 -
13.697 - # Provide the extra star parameter if necessary.
13.698 -
13.699 - if nlocals == nargs:
13.700 - self.frame_stack.extend([None]) # ExtendFrame(1)
13.701 -
13.702 - def FillDefaults(self, operand, instruction):
13.703 - (nargs, ndefaults) = operand
13.704 -
13.705 - # The frame is actually installed as the locals.
13.706 -
13.707 - frame = self.local_sp_stack[-1]
13.708 - nlocals = len(self.frame_stack[frame:])
13.709 -
13.710 - # Support population of defaults.
13.711 - # This involves copying the "attributes" of a function into the frame.
13.712 -
13.713 - default = nlocals - (nargs - ndefaults)
13.714 - self.frame_stack.extend([None] * (nargs - nlocals))
13.715 - pos = nlocals
13.716 -
13.717 - while pos < nargs:
13.718 -
13.719 - # Skip any header.
13.720 -
13.721 - self.frame_stack[frame + pos] = self.load(self.registers[instruction.working] + Library.instance_data_offset + default)
13.722 - default += 1
13.723 - pos += 1
13.724 -
13.725 - def CopyExtra(self, start, instruction):
13.726 -
13.727 - # The frame is the source of the extra arguments.
13.728 -
13.729 - frame = self.local_sp_stack[-1]
13.730 - nlocals = len(self.frame_stack[frame:])
13.731 -
13.732 - # Make a tuple to hold the arguments.
13.733 -
13.734 - ref = self._MakeObject(nlocals - start + 1, self.tuple_instance)
13.735 -
13.736 - extra = 0
13.737 - pos = start
13.738 -
13.739 - while pos < nlocals:
13.740 -
13.741 - # Skip any header.
13.742 -
13.743 - self.save(ref + Library.instance_data_offset + extra, self.frame_stack[frame + pos])
13.744 - extra += 1
13.745 - pos += 1
13.746 -
13.747 - self.LoadImmediate(ref, self.context_of(instruction.working))
13.748 - self.LoadImmediate(ref, instruction.working)
13.749 -
13.750 - def CheckInstance(self, operand, instruction):
13.751 - # For the 'self' parameter in an invoked function, the proposed context
13.752 - # ('self') is checked against the target's context.
13.753 - self.registers[instruction.target] = self._CheckInstance(
13.754 - self.registers[instruction.working],
13.755 - self.registers[instruction.source])
13.756 -
13.757 - def JumpInFrame(self, operand, instruction):
13.758 - codeaddr = self.registers[instruction.working]
13.759 - return self.jump(codeaddr, self.pc + 1) # return to the instruction after this one
13.760 -
13.761 - def JumpInFrameDirect(self, addr, instruction):
13.762 - return self.jump(addr, self.pc + 1) # return to the instruction after this one
13.763 -
13.764 - def JumpWithFrame(self, operand, instruction):
13.765 - codeaddr = self.registers[instruction.working]
13.766 - self.local_sp_stack.append(self.invocation_sp_stack[-1]) # adopt the invocation frame
13.767 - return self.jump(codeaddr, self.pc + 1) # return to the instruction after this one
13.768 -
13.769 - def JumpWithFrameDirect(self, addr, instruction):
13.770 - self.local_sp_stack.append(self.invocation_sp_stack[-1]) # adopt the invocation frame
13.771 - return self.jump(addr, self.pc + 1) # return to the instruction after this one
13.772 -
13.773 - def ExtendFrame(self, size, instruction):
13.774 - self.frame_stack.extend([None] * size)
13.775 -
13.776 - def AdjustFrame(self, size, instruction):
13.777 - self.invocation_sp_stack[-1] += size
13.778 -
13.779 - def Return(self, operand, instruction):
13.780 - return self.pull_pc()
13.781 -
13.782 - def Jump(self, addr, instruction):
13.783 - return addr
13.784 -
13.785 - def JumpIfTrue(self, addr, instruction):
13.786 - if self.registers[instruction.working]:
13.787 - return addr
13.788 -
13.789 - def JumpIfFalse(self, addr, instruction):
13.790 - if not self.registers[instruction.working]:
13.791 - return addr
13.792 -
13.793 - def ClearException(self, operand, instruction):
13.794 - self.LoadImmediate(None, instruction.target)
13.795 -
13.796 - def RaiseException(self, operand=None, instruction=None):
13.797 - # NOTE: Adding the program counter as the first attribute after __class__.
13.798 - self.save(self.registers["exception"] + Library.instance_data_offset, self.pc)
13.799 - # Jumping to the current handler.
13.800 - if self.abort_upon_exception:
13.801 - raise Exception
13.802 - return self.handler_stack[-1]
13.803 -
13.804 - def PushHandler(self, addr, instruction):
13.805 - self.handler_stack.append(addr)
13.806 - self.handler_local_sp_stack.append(len(self.local_sp_stack))
13.807 - self.handler_invocation_sp_stack.append(len(self.invocation_sp_stack))
13.808 - self.handler_pc_stack.append(len(self.pc_stack))
13.809 -
13.810 - def PopHandler(self, nframes, instruction):
13.811 - # Get the new local frame pointer and PC stack references.
13.812 - local_sp_top = self.handler_local_sp_stack[-nframes]
13.813 - invocation_sp_top = self.handler_invocation_sp_stack[-nframes]
13.814 - pc_top = self.handler_pc_stack[-nframes]
13.815 - # Reduce the local frame pointer stack to refer to the handler's frame.
13.816 - del self.local_sp_stack[local_sp_top:]
13.817 - # Reduce the invocation frame pointer stack to refer to an outer frame.
13.818 - del self.invocation_sp_stack[invocation_sp_top:]
13.819 - # Reduce the PC stack to discard all superfluous return addresses.
13.820 - del self.pc_stack[pc_top:]
13.821 - # Remove elements from the handler stacks.
13.822 - del self.handler_pc_stack[-nframes:]
13.823 - del self.handler_local_sp_stack[-nframes:]
13.824 - del self.handler_invocation_sp_stack[-nframes:]
13.825 - del self.handler_stack[-nframes:]
13.826 -
13.827 - def CheckException(self, operand, instruction):
13.828 - self.registers[instruction.target] = self.registers["exception"] is not None and \
13.829 - self._CheckInstance(self.registers["exception"], self.registers[instruction.working])
13.830 -
13.831 - def TestIdentity(self, operand, instruction):
13.832 - self.registers[instruction.target] = self.registers[instruction.working] == self.registers[instruction.source]
13.833 -
13.834 - def TestIdentityAddress(self, addr, instruction):
13.835 - self.registers[instruction.target] = self.registers[instruction.working] == addr
13.836 -
13.837 - def InvertBoolean(self, operand, instruction):
13.838 - self.registers[instruction.target] = not self.registers[instruction.source]
13.839 -
13.840 - # Common implementation details.
13.841 -
13.842 - def _CheckInstance(self, ref, cls):
13.843 - data = self.load(ref)
13.844 - target_data = self.load(cls)
13.845 -
13.846 - # Insist on instance vs. class.
13.847 -
13.848 - if data.attrcode is None: # absent attrcode == class/module
13.849 - return 0
13.850 -
13.851 - if target_data.attrcode is not None: # present attrcode == instance
13.852 - return 0
13.853 -
13.854 - # Find the table entry for the descendant.
13.855 -
13.856 - element = self.load(self.registers["objlist"] + target_data.classcode + data.attrcode)
13.857 -
13.858 - if element is not None:
13.859 - attr_index, static_attr, offset = element
13.860 - return attr_index == data.attrcode
13.861 - else:
13.862 - return 0
13.863 -
13.864 - def _MakeObject(self, size, ref):
13.865 - # Load the template.
13.866 - data = self.load(ref)
13.867 - addr = self.new(size)
13.868 - # Save the header, overriding the size.
13.869 - self.save(addr, data.with_size(size))
13.870 - return addr
13.871 -
13.872 - def _MakeFragment(self, occupied, size):
13.873 - addr = self.new(size)
13.874 - # Save the header, overriding the size.
13.875 - self.save(addr, FragmentObject(occupied, size))
13.876 - return addr
13.877 -
13.878 - def _LoadAddressContextCond(self, context, value, inst_value):
13.879 - # Check the instance context against the target's context.
13.880 - # This provides the context overriding for methods.
13.881 - if context is ReplaceableContext or context is not PlaceholderContext and self._CheckInstance(inst_value, context):
13.882 - # Replace the context with the instance.
13.883 - return DataValue(inst_value, value)
13.884 - else:
13.885 - return DataValue(context, value)
13.886 -
13.887 - def _StoreAddressContext(self, location, context, value, source_context, source_value):
13.888 - if source_context is ReplaceableContext:
13.889 - context = value
13.890 - else:
13.891 - context = source_context
13.892 - self.save(location, DataValue(context, source_value))
13.893 -
13.894 -# Convenience functions.
13.895 -
13.896 -def machine(program, with_builtins=0, debug=0, abort_upon_exception=0):
13.897 - print "Making the image..."
13.898 - code = program.get_image(with_builtins)
13.899 - print "Getting raw structures..."
13.900 - ot = program.get_object_table()
13.901 - pt = program.get_parameter_table()
13.902 - objlist = ot.as_list()
13.903 - paramlist = pt.as_list()
13.904 - print "Getting raw image..."
13.905 - rc = program.get_raw_image()
13.906 - print "Initialising the machine..."
13.907 - importer = program.get_importer()
13.908 - constants = {}
13.909 - for x in (True, False, NotImplemented):
13.910 - constants[x] = importer.get_constant(x).location
13.911 - rm = RSVPMachine(rc, objlist, paramlist, debug=debug, abort_upon_exception=abort_upon_exception)
13.912 - library = Library(rm, constants)
13.913 - rm.library = library
13.914 - rm.pc = program.code_location
13.915 - print "Returning program occupying %d locations." % rm.get_program_size()
13.916 - return rm
13.917 -
13.918 -# vim: tabstop=4 expandtab shiftwidth=4
14.1 --- a/rsvplib.py Fri Jun 28 21:17:02 2013 +0200
14.2 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000
14.3 @@ -1,484 +0,0 @@
14.4 -#!/usr/bin/env python
14.5 -
14.6 -"""
14.7 -A native function library for a really simple virtual processor.
14.8 -NOTE: Ultimately, this should only implement only operations at the lowest
14.9 -NOTE: possible level, with generated native methods providing the functionality
14.10 -NOTE: instead.
14.11 -
14.12 -Copyright (C) 2007, 2008, 2009, 2010, 2011 Paul Boddie <paul@boddie.org.uk>
14.13 -
14.14 -This program is free software; you can redistribute it and/or modify it under
14.15 -the terms of the GNU General Public License as published by the Free Software
14.16 -Foundation; either version 3 of the License, or (at your option) any later
14.17 -version.
14.18 -
14.19 -This program is distributed in the hope that it will be useful, but WITHOUT
14.20 -ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
14.21 -FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
14.22 -details.
14.23 -
14.24 -You should have received a copy of the GNU General Public License along with
14.25 -this program. If not, see <http://www.gnu.org/licenses/>.
14.26 -"""
14.27 -
14.28 -from micropython.program import DataValue
14.29 -import operator
14.30 -
14.31 -class Library:
14.32 -
14.33 - "Native function implementations."
14.34 -
14.35 - # NOTE: These attributes need changing if the instance layout changes.
14.36 -
14.37 - instance_template_size = instance_data_offset = 1
14.38 - instance_size = instance_template_size + 1
14.39 - fragment_data_offset = 1
14.40 -
14.41 - def __init__(self, machine, constants):
14.42 -
14.43 - """
14.44 - Initialise the library with the 'machine' and the 'constants' addresses
14.45 - dictionary.
14.46 - """
14.47 -
14.48 - self.machine = machine
14.49 - self.constants = constants
14.50 -
14.51 - # Native class constants.
14.52 -
14.53 - self.int_class, self.int_instance = self._get_builtin_class_and_template("int")
14.54 - self.list_class, self.list_instance = self._get_builtin_class_and_template("list")
14.55 - self.index_error, self.index_error_instance = self._get_builtin_class_and_template("IndexError")
14.56 - self.str_class, self.str_instance = self._get_builtin_class_and_template("basestring")
14.57 - self.accessor_class, self.accessor_instance = self._get_builtin_class_and_template("_accessor")
14.58 -
14.59 - self.tuple_class = self.machine.tuple_class
14.60 - self.tuple_instance = self.machine.tuple_instance
14.61 -
14.62 - self.attr_error_instance = self.machine.attr_error_instance
14.63 - self.type_error_instance = self.machine.type_error_instance
14.64 -
14.65 - def _get_builtin_class_and_template(self, name):
14.66 - cls = self.machine._get_class("__builtins__", name)
14.67 - if cls is not None:
14.68 - return cls.location, cls.instance_template_location
14.69 - else:
14.70 - return None, None
14.71 -
14.72 - def _check_index(self, pos, nelements):
14.73 - return pos >= 0 and pos < nelements
14.74 -
14.75 - # Native functionality.
14.76 -
14.77 - def builtins_no_op(self):
14.78 - pass
14.79 -
14.80 - def native_int_arithmetic_op(self, op):
14.81 - left = self.machine.load_from_frame(0)
14.82 - left_data = left.ref + self.instance_data_offset
14.83 - right = self.machine.load_from_frame(1)
14.84 - right_data = right.ref + self.instance_data_offset
14.85 -
14.86 - # Make a new object.
14.87 -
14.88 - addr = self.machine._MakeObject(self.instance_size, self.int_instance)
14.89 -
14.90 - # Store the result.
14.91 - # NOTE: The data is considered ready to use.
14.92 -
14.93 - self.machine.save(addr + self.instance_data_offset, op(self.machine.load(left_data), self.machine.load(right_data)))
14.94 -
14.95 - # Return the new object.
14.96 - # Introduce object as context for the new object.
14.97 -
14.98 - self.machine.LoadImmediate(addr, "working_context")
14.99 - self.machine.LoadImmediate(addr, "working")
14.100 -
14.101 - def native_logical_op(self, op):
14.102 - left = self.machine.load_from_frame(0)
14.103 - left_data = left.ref + self.instance_data_offset
14.104 - right = self.machine.load_from_frame(1)
14.105 - right_data = right.ref + self.instance_data_offset
14.106 -
14.107 - # Test the data.
14.108 - # NOTE: The data is considered ready to use.
14.109 -
14.110 - if op(self.machine.load(left_data), self.machine.load(right_data)):
14.111 - self.machine.LoadImmediate(self.constants[True], "working_context")
14.112 - self.machine.LoadImmediate(self.constants[True], "working")
14.113 - else:
14.114 - self.machine.LoadImmediate(self.constants[False], "working_context")
14.115 - self.machine.LoadImmediate(self.constants[False], "working")
14.116 -
14.117 - # Operators.
14.118 - # Although this takes a short-cut by using the operator module, testing is
14.119 - # still performed on the operands to ensure that they qualify for these
14.120 - # native operations.
14.121 -
14.122 - def native_int_add(self):
14.123 - return self.native_int_arithmetic_op(operator.add)
14.124 -
14.125 - def native_int_sub(self):
14.126 - return self.native_int_arithmetic_op(operator.sub)
14.127 -
14.128 - def native_int_pow(self):
14.129 - return self.native_int_arithmetic_op(operator.pow)
14.130 -
14.131 - def native_int_and(self):
14.132 - return self.native_int_arithmetic_op(operator.and_)
14.133 -
14.134 - def native_int_or(self):
14.135 - return self.native_int_arithmetic_op(operator.or_)
14.136 -
14.137 - def native_int_lt(self):
14.138 - return self.native_logical_op(operator.lt)
14.139 -
14.140 - def native_int_gt(self):
14.141 - return self.native_logical_op(operator.gt)
14.142 -
14.143 - def native_int_eq(self):
14.144 - return self.native_logical_op(operator.eq)
14.145 -
14.146 - def native_str_lt(self):
14.147 - return self.native_logical_op(operator.lt)
14.148 -
14.149 - def native_str_gt(self):
14.150 - return self.native_logical_op(operator.gt)
14.151 -
14.152 - def native_str_eq(self):
14.153 - return self.native_logical_op(operator.eq)
14.154 -
14.155 - # Specific operator methods.
14.156 -
14.157 - def builtins_int_neg(self):
14.158 - left = self.machine.load_from_frame(0)
14.159 - left_data = left.ref + self.instance_data_offset
14.160 -
14.161 - # Make a new object.
14.162 -
14.163 - addr = self.machine._MakeObject(self.instance_size, self.int_instance)
14.164 -
14.165 - # Store the result.
14.166 - # NOTE: The data is considered ready to use.
14.167 -
14.168 - self.machine.save(addr + self.instance_data_offset, -self.machine.load(left_data))
14.169 -
14.170 - # Return the new object.
14.171 - # Introduce object as context for the new object.
14.172 -
14.173 - self.machine.LoadImmediate(addr, "working_context")
14.174 - self.machine.LoadImmediate(addr, "working")
14.175 -
14.176 - # Various built-in methods.
14.177 -
14.178 - def builtins_list_new(self):
14.179 - list_value = self.machine.load_from_frame(0)
14.180 - list_addr = list_value.ref + self.instance_data_offset
14.181 -
14.182 - # Make a new sequence.
14.183 - # NOTE: Using an arbitrary size.
14.184 -
14.185 - new_fragment = self.machine._MakeFragment(self.fragment_data_offset, 5) # include the header
14.186 -
14.187 - # Complete the list instance by saving the fragment reference.
14.188 - # NOTE: This requires an attribute in the list structure.
14.189 -
14.190 - self.machine.save(list_addr, DataValue(None, new_fragment))
14.191 -
14.192 - def builtins_list_get_single_item(self):
14.193 - obj_value = self.machine.load_from_frame(0)
14.194 - fragment_member = obj_value.ref + self.instance_data_offset
14.195 - item_value = self.machine.load_from_frame(1)
14.196 - item_pos_member = item_value.ref + self.instance_data_offset
14.197 -
14.198 - # Get the fragment address.
14.199 -
14.200 - fragment = self.machine.load(fragment_member)
14.201 -
14.202 - # Get the fragment header.
14.203 -
14.204 - header = self.machine.load(fragment.ref)
14.205 - nelements = header.occupied_size - self.fragment_data_offset
14.206 -
14.207 - # Get the item position.
14.208 -
14.209 - item_pos = self.machine.load(item_pos_member)
14.210 -
14.211 - if not self._check_index(item_pos, nelements):
14.212 - self.machine.LoadImmediate(self.machine._MakeObject(self.instance_size, self.index_error_instance), "exception")
14.213 - return self.machine.RaiseException()
14.214 -
14.215 - # Get the item itself.
14.216 -
14.217 - data = self.machine.load(fragment.ref + self.fragment_data_offset + item_pos)
14.218 - self.machine.LoadImmediate(data.context, "working_context")
14.219 - self.machine.LoadImmediate(data.ref, "working")
14.220 -
14.221 - def builtins_list_len(self):
14.222 - obj_value = self.machine.load_from_frame(0)
14.223 - fragment_member = obj_value.ref + self.instance_data_offset
14.224 -
14.225 - # Get the fragment address.
14.226 -
14.227 - fragment = self.machine.load(fragment_member)
14.228 -
14.229 - # Get the fragment header.
14.230 -
14.231 - header = self.machine.load(fragment.ref)
14.232 - nelements = header.occupied_size - self.fragment_data_offset
14.233 -
14.234 - # Make a new object.
14.235 -
14.236 - addr = self.machine._MakeObject(self.instance_size, self.int_instance)
14.237 -
14.238 - # Store the result.
14.239 - # NOTE: The data is considered ready to use.
14.240 -
14.241 - self.machine.save(addr + self.instance_data_offset, nelements)
14.242 -
14.243 - # Return the new object.
14.244 - # Introduce object as context for the new object.
14.245 -
14.246 - self.machine.LoadImmediate(addr, "working_context")
14.247 - self.machine.LoadImmediate(addr, "working")
14.248 -
14.249 - def builtins_list_append(self):
14.250 - obj_value = self.machine.load_from_frame(0)
14.251 - fragment_member = obj_value.ref + self.instance_data_offset
14.252 - arg_value = self.machine.load_from_frame(1)
14.253 -
14.254 - # Get the fragment address.
14.255 -
14.256 - fragment = self.machine.load(fragment_member)
14.257 -
14.258 - # Get the fragment header.
14.259 -
14.260 - header = self.machine.load(fragment.ref)
14.261 -
14.262 - # Attempt to add the reference.
14.263 -
14.264 - if header.occupied_size < header.allocated_size:
14.265 - self.machine.save(fragment.ref + header.occupied_size, arg_value)
14.266 - header.occupied_size += 1
14.267 - else:
14.268 -
14.269 - # Make a new fragment, maintaining more space than currently
14.270 - # occupied in order to avoid reallocation.
14.271 -
14.272 - new_fragment = self.machine._MakeFragment(header.occupied_size + 1, header.occupied_size * 2)
14.273 -
14.274 - # Copy existing elements.
14.275 -
14.276 - for i in range(self.fragment_data_offset, header.occupied_size):
14.277 - self.machine.save(new_fragment + i, self.machine.load(fragment.ref + i))
14.278 -
14.279 - self.machine.save(new_fragment + header.occupied_size, arg_value)
14.280 -
14.281 - # Set the new fragment in the object.
14.282 - # NOTE: The old fragment could be deallocated.
14.283 -
14.284 - self.machine.save(fragment_member, DataValue(None, new_fragment))
14.285 -
14.286 - def builtins_tuple_new(self):
14.287 -
14.288 - # Get the sequence address.
14.289 - # The first argument should be empty since this function acts as an
14.290 - # instantiator, and in instantiators the first argument is reserved so
14.291 - # that it can be filled in for the call to an initialiser without
14.292 - # allocating a new frame.
14.293 -
14.294 - obj_value = self.machine.load_from_frame(1)
14.295 - return self._builtins_tuple(obj_value)
14.296 -
14.297 - def builtins_tuple(self):
14.298 -
14.299 - # Get the sequence address.
14.300 -
14.301 - obj_value = self.machine.load_from_frame(0)
14.302 - return self._builtins_tuple(obj_value)
14.303 -
14.304 - def _builtins_tuple(self, obj_value):
14.305 - fragment_member = obj_value.ref + self.instance_data_offset
14.306 -
14.307 - if self.machine._CheckInstance(obj_value.ref, self.tuple_class):
14.308 - self.machine.LoadImmediate(obj_value.context, "working_context")
14.309 - self.machine.LoadImmediate(obj_value.ref, "working")
14.310 - return
14.311 -
14.312 - # Reject non-list, non-tuple types.
14.313 - # NOTE: This should probably accept any sequence.
14.314 -
14.315 - elif not self.machine._CheckInstance(obj_value.ref, self.list_class):
14.316 - self.machine.LoadImmediate(self.machine._MakeObject(self.instance_size, self.type_error_instance), "exception")
14.317 - return self.machine.RaiseException()
14.318 -
14.319 - # Get the fragment address.
14.320 -
14.321 - fragment = self.machine.load(fragment_member)
14.322 -
14.323 - # Get the fragment header.
14.324 -
14.325 - header = self.machine.load(fragment.ref)
14.326 -
14.327 - # Make a new object.
14.328 -
14.329 - addr = self.machine._MakeObject(self.instance_data_offset + header.occupied_size - self.fragment_data_offset, self.tuple_instance)
14.330 -
14.331 - # Copy the fragment contents into the tuple.
14.332 - # NOTE: This might be done by repurposing the fragment in some situations.
14.333 -
14.334 - for i in range(self.fragment_data_offset, header.occupied_size):
14.335 - self.machine.save(addr + self.instance_data_offset + i - self.fragment_data_offset, self.machine.load(fragment.ref + i))
14.336 -
14.337 - # Return the new object.
14.338 - # Introduce object as context for the new object.
14.339 -
14.340 - self.machine.LoadImmediate(addr, "working_context")
14.341 - self.machine.LoadImmediate(addr, "working")
14.342 -
14.343 - def builtins_tuple_len(self):
14.344 - obj_value = self.machine.load_from_frame(0)
14.345 -
14.346 - # Get the header.
14.347 -
14.348 - header = self.machine.load(obj_value.ref)
14.349 - nelements = header.size - self.instance_data_offset
14.350 -
14.351 - # Make a new object.
14.352 -
14.353 - addr = self.machine._MakeObject(self.instance_size, self.int_instance)
14.354 -
14.355 - # Store the result.
14.356 - # NOTE: The data is considered ready to use.
14.357 -
14.358 - self.machine.save(addr + self.instance_data_offset, nelements)
14.359 -
14.360 - # Return the new object.
14.361 - # Introduce object as context for the new object.
14.362 -
14.363 - self.machine.LoadImmediate(addr, "working_context")
14.364 - self.machine.LoadImmediate(addr, "working")
14.365 -
14.366 - def builtins_tuple_get_single_item(self):
14.367 - obj_value = self.machine.load_from_frame(0)
14.368 - fragment_member = obj_value.ref + self.instance_data_offset
14.369 - item_value = self.machine.load_from_frame(1)
14.370 - item_pos_member = item_value.ref + self.instance_data_offset
14.371 -
14.372 - # Get the header.
14.373 -
14.374 - header = self.machine.load(obj_value.ref)
14.375 - nelements = header.size - self.instance_data_offset
14.376 -
14.377 - # NOTE: Assume single location for data and header.
14.378 -
14.379 - item_pos = self.machine.load(item_pos_member)
14.380 -
14.381 - if not self._check_index(item_pos, nelements):
14.382 - self.machine.LoadImmediate(self.machine._MakeObject(self.instance_size, self.index_error_instance), "exception")
14.383 - return self.machine.RaiseException()
14.384 -
14.385 - # Get the item.
14.386 -
14.387 - data = self.machine.load(fragment_member + item_pos)
14.388 - self.machine.LoadImmediate(data.context, "working_context")
14.389 - self.machine.LoadImmediate(data.ref, "working")
14.390 -
14.391 - def builtins_getattr(self):
14.392 - obj_value = self.machine.load_from_frame(0)
14.393 - name_value = self.machine.load_from_frame(1)
14.394 - index_member = name_value.ref + self.instance_data_offset + 1
14.395 -
14.396 - if not self.machine._CheckInstance(name_value.ref, self.accessor_class):
14.397 - self.machine.LoadImmediate(self.machine._MakeObject(self.instance_size, self.attr_error_instance), "exception")
14.398 - return self.machine.RaiseException()
14.399 -
14.400 - # Get the object table index from the name. It is a bare integer, not a reference.
14.401 -
14.402 - index = self.machine.load(index_member)
14.403 -
14.404 - # NOTE: This is very much like LoadAttrIndexContextCond.
14.405 -
14.406 - data = self.machine.load(obj_value.ref)
14.407 - element = self.machine.load(self.machine.registers["objlist"] + data.classcode + index)
14.408 -
14.409 - if element is not None:
14.410 - attr_index, static_attr, offset = element
14.411 - if attr_index == index:
14.412 - if static_attr:
14.413 - loaded_data = self.machine.load(offset) # offset is address of class/module attribute
14.414 - if data.attrcode is not None: # absent attrcode == class/module
14.415 - loaded_data = self.machine._LoadAddressContextCond(loaded_data.context, loaded_data.ref, obj_value.ref)
14.416 - else:
14.417 - loaded_data = self.machine.load(obj_value.ref + offset)
14.418 - self.machine.LoadImmediate(loaded_data.context, "working_context")
14.419 - self.machine.LoadImmediate(loaded_data.ref, "working")
14.420 - return
14.421 -
14.422 - self.machine.LoadImmediate(self.machine._MakeObject(self.instance_size, self.attr_error_instance), "exception")
14.423 - return self.machine.RaiseException()
14.424 -
14.425 - def builtins_isinstance(self):
14.426 - obj_value = self.machine.load_from_frame(0)
14.427 - cls_value = self.machine.load_from_frame(1)
14.428 -
14.429 - if self.machine._CheckInstance(obj_value.ref, cls_value.ref):
14.430 - self.machine.LoadImmediate(self.constants[True], "working_context")
14.431 - self.machine.LoadImmediate(self.constants[True], "working")
14.432 - else:
14.433 - self.machine.LoadImmediate(self.constants[False], "working_context")
14.434 - self.machine.LoadImmediate(self.constants[False], "working")
14.435 -
14.436 - def builtins_print(self):
14.437 - # NOTE: Do nothing for now.
14.438 - pass
14.439 -
14.440 - def builtins_printnl(self):
14.441 - # NOTE: Do nothing for now.
14.442 - pass
14.443 -
14.444 - native_functions = {
14.445 -
14.446 - # Native method implementations:
14.447 -
14.448 - "native._int_add" : native_int_add,
14.449 - "native._int_sub" : native_int_sub,
14.450 - "native._int_pow" : native_int_pow,
14.451 - "native._int_and" : native_int_and,
14.452 - "native._int_or" : native_int_or,
14.453 - "native._int_lt" : native_int_lt,
14.454 - "native._int_gt" : native_int_gt,
14.455 - "native._int_eq" : native_int_eq,
14.456 - "native._str_lt" : native_str_lt,
14.457 - "native._str_gt" : native_str_gt,
14.458 - "native._str_eq" : native_str_eq,
14.459 - "__builtins__.int.__neg__" : builtins_int_neg,
14.460 - "__builtins__.list.__get_single_item__" : builtins_list_get_single_item,
14.461 - "__builtins__.list.__len__" : builtins_list_len,
14.462 - "__builtins__.list.append" : builtins_list_append,
14.463 - "__builtins__.tuple" : builtins_tuple_new,
14.464 - "__builtins__.tuple.__len__" : builtins_tuple_len,
14.465 - "__builtins__.tuple.__get_single_item__" : builtins_tuple_get_single_item,
14.466 -
14.467 - # Native initialisers:
14.468 -
14.469 - "__builtins__.BaseException.__init__" : builtins_no_op, # NOTE: To be made distinct, potentially in the builtins module.
14.470 -
14.471 - # Native functions:
14.472 -
14.473 - "__builtins__._getattr" : builtins_getattr,
14.474 -
14.475 - # Native instantiator helpers:
14.476 -
14.477 - "__builtins__.list.__new__" : builtins_list_new,
14.478 -
14.479 - # Native helper functions:
14.480 -
14.481 - "__builtins__._isinstance" : builtins_isinstance,
14.482 - "__builtins__._print" : builtins_print,
14.483 - "__builtins__._printnl" : builtins_printnl,
14.484 - "__builtins__._tuple" : builtins_tuple,
14.485 - }
14.486 -
14.487 -# vim: tabstop=4 expandtab shiftwidth=4
15.1 --- a/test.py Fri Jun 28 21:17:02 2013 +0200
15.2 +++ b/test.py Sat Jun 29 01:28:12 2013 +0200
15.3 @@ -5,7 +5,6 @@
15.4 import micropython.deduce
15.5 import micropython.report
15.6 import micropython.syspython
15.7 -import rsvp
15.8 import sys
15.9 import os
15.10
15.11 @@ -14,16 +13,6 @@
15.12 "/usr/share/micropython/lib"
15.13 ]
15.14
15.15 -def show_code(code):
15.16 - for i, x in enumerate(code):
15.17 - print i, x
15.18 -
15.19 -def show_table_usage(raw_table, slice_size=100):
15.20 - for x in xrange(0, len(raw_table), slice_size):
15.21 - table_slice = raw_table[x:x+slice_size]
15.22 - print "%6d" % (len(table_slice) - table_slice.count(None)), \
15.23 - "".join(entry and "#" or "_" for entry in table_slice)
15.24 -
15.25 def show_warnings(attribute_usage_failures):
15.26 failures = list(attribute_usage_failures)
15.27 failures.sort()
15.28 @@ -33,25 +22,12 @@
15.29 print >>sys.stderr, "%s: Name %r with %s attributes %r" % (
15.30 unit_name, name, all_attributes and "all" or "any", ", ".join(attrnames))
15.31
15.32 -def attrs(obj):
15.33 - for name, attr in obj.items():
15.34 - print name, attr
15.35 -
15.36 -def reset():
15.37 - global rm
15.38 - rm = rsvp.machine(p)
15.39 -
15.40 # Main program.
15.41
15.42 if __name__ == "__main__":
15.43 args = sys.argv[2:]
15.44 path = libdirs + sys.path[:]
15.45
15.46 - if "--help" in sys.argv:
15.47 - print "Optimisations:"
15.48 - print micropython.cmd.show_optimisations()
15.49 - sys.exit(1)
15.50 -
15.51 if len(sys.argv) > 1 and sys.argv[1] != "-":
15.52 filename = os.path.abspath(sys.argv[1])
15.53 path.append(os.path.split(filename)[0])
15.54 @@ -124,17 +100,6 @@
15.55 finally:
15.56 f.close()
15.57
15.58 - # Build the program.
15.59 -
15.60 - if "-m" in args or "-t" in args:
15.61 - rm = rsvp.machine(p, debug=("-g" in args), abort_upon_exception=("-x" in args))
15.62 -
15.63 - if "-t" in args:
15.64 - success = rm.test(m)
15.65 - print "Test successful?", success
15.66 -
15.67 - print "RSVP machine: rm = %r" % rm
15.68 -
15.69 ot = p.get_object_table()
15.70 pt = p.get_parameter_table()
15.71