paul@17 | 1 | #!/usr/bin/env python |
paul@17 | 2 | |
paul@17 | 3 | """ |
paul@17 | 4 | Translate the AST of a Python program into a more interpretable representation. |
paul@17 | 5 | |
paul@175 | 6 | Copyright (C) 2007, 2008, 2009 Paul Boddie <paul@boddie.org.uk> |
paul@17 | 7 | |
paul@17 | 8 | This program is free software; you can redistribute it and/or modify it under |
paul@17 | 9 | the terms of the GNU General Public License as published by the Free Software |
paul@17 | 10 | Foundation; either version 3 of the License, or (at your option) any later |
paul@17 | 11 | version. |
paul@17 | 12 | |
paul@17 | 13 | This program is distributed in the hope that it will be useful, but WITHOUT |
paul@17 | 14 | ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS |
paul@17 | 15 | FOR A PARTICULAR PURPOSE. See the GNU General Public License for more |
paul@17 | 16 | details. |
paul@17 | 17 | |
paul@17 | 18 | You should have received a copy of the GNU General Public License along with |
paul@17 | 19 | this program. If not, see <http://www.gnu.org/licenses/>. |
paul@17 | 20 | """ |
paul@17 | 21 | |
paul@154 | 22 | from micropython.opt import Optimiser |
paul@83 | 23 | from micropython.common import * |
paul@83 | 24 | from micropython.data import * |
paul@17 | 25 | from micropython.rsvp import * |
paul@196 | 26 | from micropython.trans import Helper |
paul@17 | 27 | import compiler.ast |
paul@17 | 28 | from compiler.visitor import ASTVisitor |
paul@17 | 29 | |
paul@17 | 30 | # Program visitors. |
paul@17 | 31 | |
paul@196 | 32 | class Translation(ASTVisitor, Helper): |
paul@17 | 33 | |
paul@17 | 34 | "A translated module." |
paul@17 | 35 | |
paul@122 | 36 | # Attribute access instructions, for use with the appropriate handlers. |
paul@122 | 37 | |
paul@194 | 38 | attribute_load_instructions = ( |
paul@194 | 39 | LoadAddress, LoadAddressContext, LoadAddressContextCond, |
paul@226 | 40 | LoadAttr, LoadAttrIndex, LoadAttrIndexContextCond |
paul@194 | 41 | ) |
paul@194 | 42 | attribute_store_instructions = ( |
paul@194 | 43 | None, None, None, |
paul@226 | 44 | StoreAttr, StoreAttrIndex, None |
paul@194 | 45 | ) |
paul@122 | 46 | |
paul@122 | 47 | # Name access instructions, for use with the appropriate handlers. |
paul@122 | 48 | |
paul@223 | 49 | name_load_instructions = (LoadName, LoadAddress, None) |
paul@223 | 50 | name_store_instructions = (StoreName, StoreAddress, StoreAddressContext) |
paul@98 | 51 | |
paul@175 | 52 | def __init__(self, module, program): |
paul@18 | 53 | |
paul@21 | 54 | """ |
paul@175 | 55 | Initialise the translation with an inspected 'module' and the 'program' |
paul@175 | 56 | container. |
paul@21 | 57 | """ |
paul@18 | 58 | |
paul@17 | 59 | ASTVisitor.__init__(self) |
paul@17 | 60 | self.visitor = self |
paul@17 | 61 | self.module = module |
paul@72 | 62 | |
paul@72 | 63 | # Global program dependencies. |
paul@72 | 64 | |
paul@175 | 65 | self.program = program |
paul@175 | 66 | self.objtable = self.program.get_object_table() |
paul@175 | 67 | self.paramtable = self.program.get_parameter_table() |
paul@175 | 68 | self.importer = self.program.get_importer() |
paul@72 | 69 | self.builtins = self.importer.modules.get("__builtins__") |
paul@61 | 70 | |
paul@140 | 71 | # Optimisation. |
paul@140 | 72 | |
paul@175 | 73 | self.optimiser = Optimiser(self, program.optimisations) |
paul@62 | 74 | |
paul@61 | 75 | # The current unit being translated. |
paul@61 | 76 | |
paul@17 | 77 | self.unit = None |
paul@17 | 78 | |
paul@103 | 79 | # The temporary storage used by the current assignment expression. |
paul@103 | 80 | |
paul@139 | 81 | self.expr_temp = [] |
paul@103 | 82 | |
paul@19 | 83 | # Wiring within the code. |
paul@19 | 84 | |
paul@19 | 85 | self.labels = {} |
paul@19 | 86 | self.label_number = 0 |
paul@163 | 87 | self.loop_blocks = [] |
paul@163 | 88 | self.exception_blocks = [] |
paul@235 | 89 | self.in_exception_handler = 0 |
paul@41 | 90 | |
paul@156 | 91 | self.reset() |
paul@19 | 92 | |
paul@95 | 93 | def __repr__(self): |
paul@95 | 94 | return "Translation(%r)" % self.module |
paul@72 | 95 | |
paul@156 | 96 | def reset(self): |
paul@156 | 97 | |
paul@156 | 98 | "Reset the state of the translator." |
paul@156 | 99 | |
paul@156 | 100 | # The code itself. This is limited to the code for a particular block |
paul@156 | 101 | # being processed. |
paul@156 | 102 | |
paul@163 | 103 | self.blocks = [] |
paul@156 | 104 | |
paul@156 | 105 | # Information about temporary values. |
paul@156 | 106 | |
paul@156 | 107 | self.temp_positions = set() |
paul@156 | 108 | self.max_temp_position = -1 |
paul@156 | 109 | |
paul@156 | 110 | # Information about instructions which construct frames. |
paul@156 | 111 | |
paul@156 | 112 | self.frame_makers = [] |
paul@156 | 113 | |
paul@156 | 114 | # Optimiser state must be reset for each unit. |
paul@156 | 115 | |
paul@156 | 116 | self.optimiser.reset() |
paul@156 | 117 | |
paul@139 | 118 | def get_module_code(self, final=0): |
paul@139 | 119 | |
paul@139 | 120 | """ |
paul@139 | 121 | Return the top-level module code including finalising code if 'final' is |
paul@139 | 122 | set to a true value. |
paul@139 | 123 | """ |
paul@17 | 124 | |
paul@17 | 125 | self.unit = self.module |
paul@156 | 126 | self.reset() |
paul@73 | 127 | |
paul@163 | 128 | block = self.new_block() |
paul@163 | 129 | self.set_block(block) |
paul@163 | 130 | |
paul@44 | 131 | if self.module.module is not None: |
paul@44 | 132 | self.dispatch(self.module.module) |
paul@73 | 133 | |
paul@139 | 134 | # Finish off the translated program if appropriate. |
paul@139 | 135 | |
paul@139 | 136 | if final: |
paul@139 | 137 | self.new_op(Return()) |
paul@139 | 138 | |
paul@116 | 139 | self.unit.temp_usage = self.max_temp_position + 1 |
paul@173 | 140 | self.unit.blocks = self.blocks |
paul@163 | 141 | return self.blocks |
paul@17 | 142 | |
paul@17 | 143 | def get_code(self, unit): |
paul@17 | 144 | |
paul@17 | 145 | "Return the code for the given 'unit'." |
paul@17 | 146 | |
paul@17 | 147 | self.unit = unit |
paul@156 | 148 | self.reset() |
paul@73 | 149 | |
paul@163 | 150 | block = self.new_block() |
paul@163 | 151 | self.set_block(block) |
paul@163 | 152 | |
paul@91 | 153 | if unit.astnode is not None: |
paul@91 | 154 | self.dispatch(unit.astnode) |
paul@73 | 155 | |
paul@208 | 156 | self.unit.temp_usage = self.max_temp_position + 2 # include space for instantiators to expand backwards |
paul@173 | 157 | self.unit.blocks = self.blocks |
paul@163 | 158 | return self.blocks |
paul@17 | 159 | |
paul@137 | 160 | def get_instantiator_code(self, cls): |
paul@137 | 161 | |
paul@137 | 162 | "Return the code for the given class 'cls'." |
paul@137 | 163 | |
paul@137 | 164 | self.unit = cls.get_instantiator() |
paul@156 | 165 | self.reset() |
paul@137 | 166 | |
paul@163 | 167 | block = self.new_block() |
paul@163 | 168 | self.set_block(block) |
paul@163 | 169 | |
paul@137 | 170 | init_method = cls.get_init_method() |
paul@137 | 171 | |
paul@230 | 172 | # Make an object and store it in the unused first slot. |
paul@137 | 173 | |
paul@233 | 174 | self.make_instance(cls, len(cls.instance_attributes())) |
paul@230 | 175 | self.new_op(StoreTemp(0)) |
paul@137 | 176 | |
paul@137 | 177 | # Invoke the appropriate initialiser. |
paul@137 | 178 | |
paul@223 | 179 | self.new_op(LoadFunction(init_method)) |
paul@137 | 180 | self.new_op(LoadCallable()) |
paul@230 | 181 | self.new_op(JumpInFrame()) |
paul@137 | 182 | |
paul@137 | 183 | # Store the object as the result. |
paul@137 | 184 | |
paul@230 | 185 | self.new_op(LoadTemp(0)) # load the context from the locals |
paul@137 | 186 | self.new_op(StoreResult()) |
paul@137 | 187 | self.new_op(Return()) |
paul@137 | 188 | |
paul@173 | 189 | self.unit.blocks = self.blocks |
paul@163 | 190 | return self.blocks |
paul@137 | 191 | |
paul@103 | 192 | # Visitor methods. |
paul@103 | 193 | |
paul@103 | 194 | def default(self, node, *args): |
paul@103 | 195 | raise TranslateError(self.module.full_name(), node, "Node class %r is not supported." % node.__class__) |
paul@103 | 196 | |
paul@103 | 197 | def dispatch(self, node, *args): |
paul@103 | 198 | return ASTVisitor.dispatch(self, node, *args) |
paul@103 | 199 | |
paul@103 | 200 | # Concrete visitor methods. |
paul@103 | 201 | |
paul@160 | 202 | # Binary operators. |
paul@160 | 203 | |
paul@196 | 204 | visitAdd = Helper._visitBinary |
paul@196 | 205 | visitBitand = Helper._visitBinary |
paul@196 | 206 | visitBitor = Helper._visitBinary |
paul@196 | 207 | visitBitxor = Helper._visitBinary |
paul@196 | 208 | visitDiv = Helper._visitBinary |
paul@196 | 209 | visitFloorDiv = Helper._visitBinary |
paul@196 | 210 | visitLeftShift = Helper._visitBinary |
paul@196 | 211 | visitMod = Helper._visitBinary |
paul@196 | 212 | visitMul = Helper._visitBinary |
paul@196 | 213 | visitPower = Helper._visitBinary |
paul@196 | 214 | visitRightShift = Helper._visitBinary |
paul@196 | 215 | visitSub = Helper._visitBinary |
paul@160 | 216 | |
paul@160 | 217 | # Unary operators. |
paul@160 | 218 | |
paul@196 | 219 | visitInvert = Helper._visitUnary |
paul@196 | 220 | visitUnaryAdd = Helper._visitUnary |
paul@196 | 221 | visitUnarySub = Helper._visitUnary |
paul@160 | 222 | |
paul@160 | 223 | # Logical operators. |
paul@160 | 224 | |
paul@101 | 225 | def visitAnd(self, node): |
paul@163 | 226 | end_block = self.new_block() |
paul@130 | 227 | temp_pos = self.reserve_temp() |
paul@130 | 228 | temp = LoadTemp(temp_pos) |
paul@101 | 229 | |
paul@101 | 230 | for n in node.nodes[:-1]: |
paul@101 | 231 | self.dispatch(n) |
paul@130 | 232 | self.new_op(StoreTemp(temp_pos)) |
paul@130 | 233 | |
paul@130 | 234 | self._generateTestBoolean(n, temp) |
paul@163 | 235 | self.new_op(JumpIfFalse(end_block)) |
paul@101 | 236 | |
paul@101 | 237 | self.dispatch(node.nodes[-1]) |
paul@130 | 238 | self.new_op(StoreTemp(temp_pos)) |
paul@130 | 239 | |
paul@163 | 240 | self.set_block(end_block) |
paul@130 | 241 | |
paul@130 | 242 | self.new_op(temp) |
paul@130 | 243 | self.discard_temp(temp) |
paul@56 | 244 | |
paul@160 | 245 | def visitNot(self, node): |
paul@160 | 246 | self.dispatch(node.expr) |
paul@160 | 247 | |
paul@160 | 248 | temp = self.optimiser.optimise_temp_storage() |
paul@160 | 249 | self._generateTestBoolean(node.expr, temp) |
paul@160 | 250 | self.discard_temp(temp) |
paul@160 | 251 | |
paul@160 | 252 | self.new_op(InvertBoolean()) |
paul@160 | 253 | self._generateLoadBoolean(node) |
paul@160 | 254 | |
paul@160 | 255 | def visitOr(self, node): |
paul@163 | 256 | end_block = self.new_block() |
paul@160 | 257 | temp_pos = self.reserve_temp() |
paul@160 | 258 | temp = LoadTemp(temp_pos) |
paul@160 | 259 | |
paul@160 | 260 | for n in node.nodes[:-1]: |
paul@160 | 261 | self.dispatch(n) |
paul@160 | 262 | self.new_op(StoreTemp(temp_pos)) |
paul@160 | 263 | |
paul@160 | 264 | self._generateTestBoolean(n, temp) |
paul@163 | 265 | self.new_op(JumpIfTrue(end_block)) |
paul@160 | 266 | |
paul@160 | 267 | self.dispatch(node.nodes[-1]) |
paul@160 | 268 | self.new_op(StoreTemp(temp_pos)) |
paul@160 | 269 | |
paul@163 | 270 | self.set_block(end_block) |
paul@160 | 271 | |
paul@160 | 272 | self.new_op(temp) |
paul@160 | 273 | self.discard_temp(temp) |
paul@160 | 274 | |
paul@160 | 275 | # Comparisons. |
paul@160 | 276 | |
paul@160 | 277 | def visitCompare(self, node): |
paul@160 | 278 | |
paul@160 | 279 | """ |
paul@160 | 280 | _t1 = node.expr |
paul@160 | 281 | _t1 op1 _t2 and _t2 op2 _t3 and ... |
paul@160 | 282 | """ |
paul@160 | 283 | |
paul@163 | 284 | end_block = self.new_block() |
paul@160 | 285 | |
paul@160 | 286 | self.dispatch(node.expr) |
paul@160 | 287 | temp2 = self.optimiser.optimise_temp_storage() |
paul@160 | 288 | |
paul@172 | 289 | # NOTE: Replicated by some code in micropython.inspect.visitCompare. |
paul@172 | 290 | |
paul@160 | 291 | last_op = node.ops[-1] |
paul@160 | 292 | |
paul@160 | 293 | for op in node.ops: |
paul@160 | 294 | op_name, next_node = op |
paul@172 | 295 | methods = comparison_methods[op_name] |
paul@160 | 296 | |
paul@161 | 297 | # Propagate the arguments as we traverse the construct. |
paul@161 | 298 | |
paul@160 | 299 | temp1 = temp2 |
paul@160 | 300 | self.dispatch(next_node) |
paul@160 | 301 | temp2 = self.optimiser.optimise_temp_storage() |
paul@160 | 302 | |
paul@160 | 303 | # Use the appropriate mechanism, setting the boolean status for the |
paul@160 | 304 | # comparison. |
paul@160 | 305 | |
paul@160 | 306 | if methods is not None: |
paul@160 | 307 | left_method, right_method = methods |
paul@160 | 308 | |
paul@160 | 309 | # Generate method call using evaluated argument and next node. |
paul@160 | 310 | |
paul@160 | 311 | temp_result = self._generateBinary(node, temp1, temp2, left_method, right_method) |
paul@160 | 312 | self.new_op(temp_result) |
paul@160 | 313 | self._generateTestBoolean(node, temp_result) |
paul@160 | 314 | self.discard_temp(temp_result) |
paul@160 | 315 | |
paul@160 | 316 | else: |
paul@160 | 317 | # Deal with the special operators. |
paul@160 | 318 | |
paul@160 | 319 | if op_name.startswith("is"): |
paul@160 | 320 | self.new_op(temp1) |
paul@160 | 321 | self.record_value() |
paul@160 | 322 | self.new_op(temp2) |
paul@160 | 323 | self.new_op(TestIdentity()) |
paul@160 | 324 | self.set_source() |
paul@160 | 325 | self.discard_value() |
paul@160 | 326 | |
paul@160 | 327 | elif op_name.endswith("in"): |
paul@160 | 328 | self.new_op(temp2) |
paul@160 | 329 | |
paul@160 | 330 | # Get method on temp2. |
paul@160 | 331 | |
paul@160 | 332 | self._generateAttr(node, "__contains__", self.attribute_load_instructions) |
paul@160 | 333 | temp_method = self.optimiser.optimise_temp_storage() |
paul@160 | 334 | |
paul@160 | 335 | # Add arguments. |
paul@160 | 336 | # NOTE: No support for defaults. |
paul@160 | 337 | |
paul@161 | 338 | self._startCallFunc() |
paul@160 | 339 | self.new_op(temp2) |
paul@160 | 340 | self.new_op(StoreFrame(0)) |
paul@160 | 341 | self.new_op(temp1) |
paul@160 | 342 | self.new_op(StoreFrame(1)) |
paul@160 | 343 | self._endCallFuncArgs(2) |
paul@160 | 344 | self._doCallFunc(temp_method) |
paul@160 | 345 | self._endCallFunc(temp_method) |
paul@160 | 346 | |
paul@160 | 347 | temp_result = self.get_temp() |
paul@160 | 348 | self._generateTestBoolean(node, temp_result) |
paul@160 | 349 | self.discard_temp(temp_result) |
paul@160 | 350 | |
paul@160 | 351 | if op_name.find("not") != -1: |
paul@160 | 352 | self.new_op(InvertBoolean()) |
paul@160 | 353 | |
paul@163 | 354 | # Test the result and jump to the end block if false. |
paul@160 | 355 | |
paul@160 | 356 | if op is not last_op: |
paul@163 | 357 | self.new_op(JumpIfFalse(end_block)) |
paul@160 | 358 | |
paul@160 | 359 | # Compilation duties... |
paul@160 | 360 | |
paul@160 | 361 | self.discard_temp(temp1) |
paul@160 | 362 | |
paul@160 | 363 | self.discard_temp(temp2) |
paul@161 | 364 | |
paul@161 | 365 | # With the status set above, produce a boolean result. |
paul@161 | 366 | |
paul@163 | 367 | self.set_block(end_block) |
paul@161 | 368 | |
paul@160 | 369 | # Yield the appropriate value. |
paul@160 | 370 | |
paul@160 | 371 | self._generateLoadBoolean(node) |
paul@160 | 372 | |
paul@160 | 373 | # Expressions. |
paul@160 | 374 | |
paul@160 | 375 | def visitBackquote(self, node): raise TranslationNotImplementedError(self.module.full_name(), node, "Backquote") |
paul@160 | 376 | |
paul@160 | 377 | def visitCallFunc(self, node): |
paul@160 | 378 | |
paul@160 | 379 | """ |
paul@160 | 380 | Evaluate positional arguments, evaluate and store keyword arguments in |
paul@160 | 381 | the correct location, then invoke the function. |
paul@160 | 382 | """ |
paul@160 | 383 | |
paul@160 | 384 | # Mark the frame, evaluate the target, generate the call. |
paul@160 | 385 | |
paul@160 | 386 | self._startCallFunc() |
paul@160 | 387 | self.dispatch(node.node) |
paul@234 | 388 | temp_target, target, temp_context = self._generateCallFunc(node.args, node) |
paul@234 | 389 | self._doCallFunc(temp_target, target) |
paul@234 | 390 | self._endCallFunc(temp_target, target, temp_context) |
paul@160 | 391 | |
paul@160 | 392 | def visitConst(self, node): |
paul@168 | 393 | const = self.importer.get_constant(node.value) |
paul@160 | 394 | self.new_op(LoadConst(const)) |
paul@160 | 395 | |
paul@160 | 396 | def visitDict(self, node): raise TranslationNotImplementedError(self.module.full_name(), node, "Dict") |
paul@160 | 397 | |
paul@160 | 398 | def visitEllipsis(self, node): raise TranslationNotImplementedError(self.module.full_name(), node, "Ellipsis") |
paul@160 | 399 | |
paul@160 | 400 | def visitExec(self, node): raise TranslationNotImplementedError(self.module.full_name(), node, "Exec") |
paul@160 | 401 | |
paul@160 | 402 | def visitExpression(self, node): raise TranslationNotImplementedError(self.module.full_name(), node, "Expression") |
paul@160 | 403 | |
paul@160 | 404 | def visitGenExpr(self, node): raise TranslationNotImplementedError(self.module.full_name(), node, "GenExpr") |
paul@160 | 405 | |
paul@160 | 406 | def visitGenExprFor(self, node): raise TranslationNotImplementedError(self.module.full_name(), node, "GenExprFor") |
paul@160 | 407 | |
paul@160 | 408 | def visitGenExprIf(self, node): raise TranslationNotImplementedError(self.module.full_name(), node, "GenExprIf") |
paul@160 | 409 | |
paul@160 | 410 | def visitGenExprInner(self, node): raise TranslationNotImplementedError(self.module.full_name(), node, "GenExprInner") |
paul@160 | 411 | |
paul@160 | 412 | def visitGetattr(self, node): |
paul@160 | 413 | self._visitAttr(node, self.attribute_load_instructions) |
paul@160 | 414 | |
paul@160 | 415 | def visitList(self, node): |
paul@160 | 416 | self._generateSequence("list", node) |
paul@160 | 417 | |
paul@160 | 418 | def visitListComp(self, node): raise TranslationNotImplementedError(self.module.full_name(), node, "ListComp") |
paul@160 | 419 | |
paul@160 | 420 | def visitListCompFor(self, node): raise TranslationNotImplementedError(self.module.full_name(), node, "ListCompFor") |
paul@160 | 421 | |
paul@160 | 422 | def visitListCompIf(self, node): raise TranslationNotImplementedError(self.module.full_name(), node, "ListCompIf") |
paul@160 | 423 | |
paul@160 | 424 | def visitName(self, node): |
paul@168 | 425 | if self.importer.predefined_constants.has_key(node.name): |
paul@168 | 426 | const = self.importer.get_predefined_constant(node.name) |
paul@160 | 427 | self.new_op(LoadConst(const)) |
paul@160 | 428 | else: |
paul@160 | 429 | self._visitName(node, self.name_load_instructions) |
paul@160 | 430 | |
paul@160 | 431 | def visitSlice(self, node): raise TranslationNotImplementedError(self.module.full_name(), node, "Slice") |
paul@160 | 432 | |
paul@216 | 433 | def visitSubscript(self, node): |
paul@216 | 434 | self.dispatch(node.expr) |
paul@216 | 435 | self._startCallFunc() |
paul@216 | 436 | self._generateAttr(node, "__getitem__", self.attribute_load_instructions) |
paul@234 | 437 | temp_target, target, temp_context = self._generateCallFunc(node.subs, node) |
paul@234 | 438 | self._doCallFunc(temp_target, target) |
paul@234 | 439 | self._endCallFunc(temp_target, target, temp_context) |
paul@160 | 440 | |
paul@160 | 441 | def visitTuple(self, node): |
paul@160 | 442 | self._generateSequence("tuple", node) |
paul@160 | 443 | |
paul@160 | 444 | # Definitions. |
paul@56 | 445 | |
paul@56 | 446 | def visitAssign(self, node): |
paul@159 | 447 | |
paul@159 | 448 | """ |
paul@159 | 449 | Evaluate the expression from the given 'node' and assign it to the |
paul@159 | 450 | associated recipients. |
paul@159 | 451 | """ |
paul@159 | 452 | |
paul@56 | 453 | self.dispatch(node.expr) |
paul@146 | 454 | |
paul@146 | 455 | # Record the value and then dispatch to the assignment targets. |
paul@146 | 456 | |
paul@159 | 457 | self.record_value(self.has_immediate_usage(node.nodes)) |
paul@101 | 458 | |
paul@56 | 459 | for n in node.nodes: |
paul@143 | 460 | self.dispatch(n) |
paul@56 | 461 | |
paul@104 | 462 | self.discard_value() |
paul@101 | 463 | |
paul@143 | 464 | def visitAssAttr(self, node): |
paul@159 | 465 | |
paul@159 | 466 | "Assign the assignment expression to the recipient 'node'." |
paul@159 | 467 | |
paul@98 | 468 | self._visitAttr(node, self.attribute_store_instructions) |
paul@104 | 469 | self.set_source() |
paul@56 | 470 | |
paul@143 | 471 | def visitAssList(self, node): |
paul@159 | 472 | |
paul@159 | 473 | """ |
paul@159 | 474 | Assign items from the assignment expression to each of the recipients |
paul@159 | 475 | found within the given 'node'. |
paul@159 | 476 | """ |
paul@159 | 477 | |
paul@139 | 478 | for i, n in enumerate(node.nodes): |
paul@139 | 479 | self._startCallFunc() |
paul@139 | 480 | self.new_op(self.expr_temp[-1]) |
paul@139 | 481 | self._generateAttr(node, "__getitem__", self.attribute_load_instructions) |
paul@234 | 482 | temp_target, target, temp_context = self._generateCallFunc([compiler.ast.Const(i)], node) |
paul@234 | 483 | self._doCallFunc(temp_target, target) |
paul@234 | 484 | self._endCallFunc(temp_target, target, temp_context) |
paul@139 | 485 | |
paul@139 | 486 | # Provide a different source value. |
paul@159 | 487 | # NOTE: Permitting immediate usage given that neither name nor |
paul@159 | 488 | # NOTE: attribute accesses should involve a function call |
paul@159 | 489 | # NOTE: overwriting the above result. |
paul@159 | 490 | |
paul@159 | 491 | self.record_value(self.is_immediate_user(n)) |
paul@143 | 492 | self.dispatch(n) |
paul@139 | 493 | self.discard_value() |
paul@139 | 494 | |
paul@143 | 495 | def visitAssName(self, node): |
paul@159 | 496 | |
paul@159 | 497 | "Assign the assignment expression to the recipient 'node'." |
paul@159 | 498 | |
paul@106 | 499 | self._visitName(node, self.name_store_instructions) |
paul@143 | 500 | self.set_source() |
paul@56 | 501 | |
paul@56 | 502 | visitAssTuple = visitAssList |
paul@56 | 503 | |
paul@151 | 504 | def visitAugAssign(self, node): |
paul@163 | 505 | use_binary_block = self.new_block() |
paul@163 | 506 | end_block = self.new_block() |
paul@151 | 507 | |
paul@151 | 508 | # Evaluate the expression. |
paul@151 | 509 | |
paul@151 | 510 | self.dispatch(node.expr) |
paul@151 | 511 | temp2 = self.optimiser.optimise_temp_storage() |
paul@151 | 512 | |
paul@151 | 513 | # Evaluate the target. |
paul@151 | 514 | |
paul@151 | 515 | self.dispatch(node.node) |
paul@151 | 516 | temp1 = self.optimiser.optimise_temp_storage() |
paul@151 | 517 | |
paul@151 | 518 | # Find the augmented assignment method and attempt to use it. |
paul@151 | 519 | |
paul@172 | 520 | aug_method, (left_method, right_method) = augassign_methods[node.op] |
paul@239 | 521 | temp_out = self._generateOpMethod(node, temp1, temp2, aug_method, use_binary_block, use_binary_block, end_block) |
paul@151 | 522 | self.discard_temp(temp_out) # NOTE: Will re-use the same storage. |
paul@151 | 523 | |
paul@151 | 524 | # Where no such method exists, use the binary operator methods. |
paul@151 | 525 | |
paul@163 | 526 | self.set_block(use_binary_block) |
paul@151 | 527 | temp_out = self._generateBinary(node, temp1, temp2, left_method, right_method) |
paul@151 | 528 | |
paul@151 | 529 | # Assign the result to the name. |
paul@151 | 530 | |
paul@163 | 531 | self.set_block(end_block) |
paul@151 | 532 | self.new_op(temp_out) |
paul@151 | 533 | self.record_value(1) |
paul@151 | 534 | |
paul@151 | 535 | if isinstance(node.node, compiler.ast.Name): |
paul@151 | 536 | self.visitAssName(node.node) |
paul@151 | 537 | elif isinstance(node.node, compiler.ast.Getattr): |
paul@151 | 538 | self.visitAssAttr(node.node) |
paul@151 | 539 | else: |
paul@151 | 540 | raise TranslationNotImplementedError(self.module.full_name(), node, "AugAssign(Slice or Subscript)") |
paul@151 | 541 | |
paul@151 | 542 | self.discard_value() |
paul@151 | 543 | |
paul@151 | 544 | # Compilation duties... |
paul@151 | 545 | |
paul@151 | 546 | self.discard_temp(temp1) |
paul@151 | 547 | self.discard_temp(temp2) |
paul@56 | 548 | |
paul@38 | 549 | def visitClass(self, node): |
paul@167 | 550 | if not node.unit.referenced: |
paul@167 | 551 | return |
paul@90 | 552 | |
paul@90 | 553 | # Store the name. |
paul@90 | 554 | |
paul@237 | 555 | self.new_op(LoadClass(node.unit)) |
paul@104 | 556 | self.record_value() |
paul@106 | 557 | self._visitName(node, self.name_store_instructions) |
paul@104 | 558 | self.set_source() |
paul@104 | 559 | self.discard_value() |
paul@90 | 560 | |
paul@90 | 561 | # Visit the code. |
paul@90 | 562 | |
paul@38 | 563 | unit = self.unit |
paul@39 | 564 | self.unit = node.unit |
paul@38 | 565 | self.dispatch(node.code) |
paul@38 | 566 | self.unit = unit |
paul@17 | 567 | |
paul@160 | 568 | def visitDecorators(self, node): raise TranslationNotImplementedError(self.module.full_name(), node, "Decorators") |
paul@160 | 569 | |
paul@160 | 570 | def visitFrom(self, node): pass |
paul@160 | 571 | |
paul@160 | 572 | def visitFunction(self, node): |
paul@171 | 573 | if not node.unit.referenced and (not node.unit.is_method() or not node.unit.parent.has_key(node.unit.name)): |
paul@167 | 574 | return |
paul@160 | 575 | |
paul@160 | 576 | # Only store the name when visiting this node from outside. |
paul@160 | 577 | |
paul@160 | 578 | if self.unit is not node.unit: |
paul@223 | 579 | self.new_op(LoadFunction(node.unit)) |
paul@222 | 580 | self.record_value() |
paul@160 | 581 | |
paul@160 | 582 | self._visitName(node, self.name_store_instructions) # AssName equivalent |
paul@160 | 583 | self.set_source() |
paul@160 | 584 | self.discard_value() |
paul@160 | 585 | |
paul@160 | 586 | self._generateFunctionDefaults(node.unit) |
paul@160 | 587 | |
paul@165 | 588 | # Visiting of the code occurs when get_code is invoked on this node. |
paul@160 | 589 | |
paul@160 | 590 | else: |
paul@215 | 591 | # Check frames using the function's details. |
paul@215 | 592 | |
paul@215 | 593 | fn = node.unit |
paul@215 | 594 | nparams = len(fn.positional_names) |
paul@215 | 595 | ndefaults = len(fn.defaults) |
paul@215 | 596 | |
paul@225 | 597 | fn.body_block = self.new_block() |
paul@222 | 598 | |
paul@222 | 599 | # Check the number of parameters and defaults. |
paul@222 | 600 | |
paul@215 | 601 | self.new_op(CheckFrame((nparams, ndefaults, fn.has_star))) |
paul@219 | 602 | if ndefaults > 0: |
paul@233 | 603 | self.new_op(LoadFunction(fn)) |
paul@233 | 604 | self.new_op(FillDefaults((nparams, ndefaults))) |
paul@215 | 605 | |
paul@215 | 606 | # Produce the body. |
paul@215 | 607 | |
paul@225 | 608 | self.set_block(fn.body_block) |
paul@215 | 609 | |
paul@160 | 610 | extend = ExtendFrame() |
paul@160 | 611 | self.new_op(extend) |
paul@160 | 612 | |
paul@160 | 613 | self.dispatch(node.code) |
paul@215 | 614 | |
paul@160 | 615 | if not isinstance(self.last_op(), Return): |
paul@160 | 616 | self.dispatch(compiler.ast.Name("None")) |
paul@160 | 617 | self.new_op(StoreResult()) |
paul@215 | 618 | self.new_op(Return()) |
paul@160 | 619 | |
paul@215 | 620 | # Make sure that enough frame space is reserved from the start. |
paul@160 | 621 | |
paul@160 | 622 | self.set_frame_usage(node, extend) |
paul@160 | 623 | |
paul@160 | 624 | def visitGlobal(self, node): pass |
paul@160 | 625 | |
paul@160 | 626 | def visitImport(self, node): pass |
paul@160 | 627 | |
paul@160 | 628 | def visitKeyword(self, node): pass |
paul@160 | 629 | |
paul@160 | 630 | def visitLambda(self, node): |
paul@21 | 631 | |
paul@21 | 632 | """ |
paul@160 | 633 | Lambda functions can be represented as globally defined functions |
paul@160 | 634 | provided they do not define any default parameter values, since these |
paul@160 | 635 | may defined in a non-global scope. |
paul@160 | 636 | |
paul@160 | 637 | Where defaults are defined, an object must be created and its content |
paul@160 | 638 | defined: the callable member of the object's structure must be set to |
paul@160 | 639 | the lambda function definition; each default must be attached to the |
paul@160 | 640 | object as an attribute, as is the case with normal functions and |
paul@160 | 641 | methods. |
paul@112 | 642 | """ |
paul@112 | 643 | |
paul@160 | 644 | # Produce the reference to this function when visiting this node from |
paul@160 | 645 | # outside. |
paul@160 | 646 | |
paul@160 | 647 | if self.unit is not node.unit: |
paul@234 | 648 | fn = node.unit |
paul@234 | 649 | ndefaults = len(fn.defaults) |
paul@234 | 650 | temp = self._generateFunctionDefaults(fn) |
paul@234 | 651 | |
paul@234 | 652 | if ndefaults > 0: |
paul@234 | 653 | self.new_op(LoadConst(fn)) |
paul@234 | 654 | else: |
paul@234 | 655 | self.new_op(LoadFunction(fn)) |
paul@160 | 656 | |
paul@160 | 657 | # Populate the new object required for the function. |
paul@160 | 658 | |
paul@160 | 659 | if temp is not None: |
paul@160 | 660 | self.new_op(LoadCallable()) |
paul@160 | 661 | self.new_op(temp) |
paul@160 | 662 | self.new_op(StoreCallable()) |
paul@160 | 663 | |
paul@160 | 664 | self.new_op(temp) |
paul@160 | 665 | #self.discard_temp(temp) |
paul@160 | 666 | |
paul@165 | 667 | # Visiting of the code occurs when get_code is invoked on this node. |
paul@160 | 668 | |
paul@160 | 669 | else: |
paul@215 | 670 | # Check frames using the function's details. |
paul@215 | 671 | |
paul@215 | 672 | fn = node.unit |
paul@215 | 673 | nparams = len(fn.positional_names) |
paul@215 | 674 | ndefaults = len(fn.defaults) |
paul@215 | 675 | |
paul@225 | 676 | fn.body_block = self.new_block() |
paul@222 | 677 | |
paul@222 | 678 | # Check the number of parameters and defaults. |
paul@222 | 679 | |
paul@215 | 680 | self.new_op(CheckFrame((nparams, ndefaults, fn.has_star))) |
paul@219 | 681 | if ndefaults > 0: |
paul@233 | 682 | self.new_op(LoadTemp(0)) # context provides storage |
paul@233 | 683 | self.new_op(FillDefaults((nparams, ndefaults))) |
paul@215 | 684 | |
paul@215 | 685 | # Produce the body. |
paul@215 | 686 | |
paul@225 | 687 | self.set_block(fn.body_block) |
paul@215 | 688 | |
paul@215 | 689 | extend = ExtendFrame() |
paul@215 | 690 | self.new_op(extend) |
paul@215 | 691 | |
paul@160 | 692 | self.dispatch(node.code) |
paul@215 | 693 | |
paul@160 | 694 | self.new_op(StoreResult()) |
paul@160 | 695 | self.new_op(Return()) |
paul@160 | 696 | |
paul@215 | 697 | # Make sure that enough frame space is reserved from the start. |
paul@215 | 698 | |
paul@215 | 699 | self.set_frame_usage(node, extend) |
paul@215 | 700 | |
paul@160 | 701 | def visitModule(self, node): |
paul@160 | 702 | extend = ExtendFrame() |
paul@160 | 703 | self.new_op(extend) |
paul@160 | 704 | self.dispatch(node.node) |
paul@160 | 705 | self.set_frame_usage(node, extend) |
paul@160 | 706 | |
paul@160 | 707 | # Statements. |
paul@160 | 708 | |
paul@160 | 709 | def visitStmt(self, node): |
paul@160 | 710 | |
paul@160 | 711 | "Process the collection of statements provided by 'node'." |
paul@160 | 712 | |
paul@160 | 713 | for n in node.nodes: |
paul@160 | 714 | |
paul@160 | 715 | # Process the statement. |
paul@160 | 716 | |
paul@160 | 717 | self.dispatch(n) |
paul@160 | 718 | |
paul@160 | 719 | # Discard temporary storage. |
paul@160 | 720 | |
paul@160 | 721 | if self.temp_positions: |
paul@160 | 722 | #print "Had temp", self.temp_positions |
paul@160 | 723 | self.temp_positions = set() |
paul@160 | 724 | |
paul@160 | 725 | # Prevent incorrect optimisation by resetting the optimiser after |
paul@160 | 726 | # each statement. |
paul@160 | 727 | |
paul@160 | 728 | self.optimiser.reset() |
paul@160 | 729 | |
paul@160 | 730 | def visitAssert(self, node): raise TranslationNotImplementedError(self.module.full_name(), node, "Assert") |
paul@160 | 731 | |
paul@160 | 732 | def visitBreak(self, node): |
paul@163 | 733 | next_block, exit_block = self.get_loop_blocks() |
paul@163 | 734 | self.new_op(Jump(exit_block)) |
paul@17 | 735 | |
paul@41 | 736 | def visitContinue(self, node): |
paul@163 | 737 | next_block, exit_block = self.get_loop_blocks() |
paul@163 | 738 | self.new_op(Jump(next_block)) |
paul@17 | 739 | |
paul@18 | 740 | def visitDiscard(self, node): |
paul@19 | 741 | self.dispatch(node.expr) |
paul@140 | 742 | self.optimiser.optimise_unused_results() |
paul@17 | 743 | |
paul@44 | 744 | def visitFor(self, node): |
paul@163 | 745 | next_handler_block = self.new_block() |
paul@163 | 746 | end_handler_block = self.new_block() |
paul@163 | 747 | exit_block = self.new_block() |
paul@163 | 748 | next_block = self.new_block() |
paul@163 | 749 | else_block = self.new_block() |
paul@44 | 750 | |
paul@44 | 751 | # Get the "list" to be iterated over, obtain its iterator. |
paul@44 | 752 | |
paul@45 | 753 | self._startCallFunc() |
paul@44 | 754 | self.dispatch(node.list) |
paul@104 | 755 | self._generateAttr(node, "__iter__", self.attribute_load_instructions) |
paul@234 | 756 | temp_target, target, temp_context = self._generateCallFunc([], node) |
paul@234 | 757 | self._doCallFunc(temp_target, target) |
paul@234 | 758 | self._endCallFunc(temp_target, target, temp_context) |
paul@57 | 759 | |
paul@240 | 760 | # Use a long-lasting temporary storage slot, since any result from the |
paul@240 | 761 | # __iter__ method will not remain around for long. |
paul@240 | 762 | |
paul@240 | 763 | temp_iterator = self.get_temp() |
paul@98 | 764 | |
paul@44 | 765 | # In the loop... |
paul@44 | 766 | |
paul@163 | 767 | self.set_block(next_block) |
paul@44 | 768 | |
paul@146 | 769 | # Handle exceptions when calling "next"... |
paul@146 | 770 | |
paul@163 | 771 | self.new_op(PushHandler(next_handler_block)) |
paul@146 | 772 | |
paul@44 | 773 | # Use the iterator to get the next value. |
paul@44 | 774 | |
paul@45 | 775 | self._startCallFunc() |
paul@102 | 776 | self.new_op(temp_iterator) |
paul@104 | 777 | self._generateAttr(node, "next", self.attribute_load_instructions) |
paul@234 | 778 | temp_target, target, temp_context = self._generateCallFunc([], node) |
paul@234 | 779 | self._doCallFunc(temp_target, target) |
paul@234 | 780 | self._endCallFunc(temp_target, target, temp_context) |
paul@44 | 781 | |
paul@139 | 782 | # Record the value to be assigned. |
paul@139 | 783 | |
paul@139 | 784 | self.record_value() |
paul@139 | 785 | |
paul@146 | 786 | # Skip the handler where the call was successful. |
paul@146 | 787 | |
paul@232 | 788 | self.new_op(PopHandler()) |
paul@163 | 789 | self.new_op(Jump(end_handler_block)) |
paul@146 | 790 | |
paul@146 | 791 | # Enter the exception handler. |
paul@146 | 792 | |
paul@163 | 793 | self.set_block(next_handler_block) |
paul@146 | 794 | self.new_op(PopHandler()) |
paul@146 | 795 | |
paul@44 | 796 | # Test for StopIteration. |
paul@44 | 797 | |
paul@101 | 798 | self.load_builtin("StopIteration", node) |
paul@57 | 799 | self.new_op(CheckException()) |
paul@44 | 800 | if node.else_ is not None: |
paul@163 | 801 | self.new_op(JumpIfTrue(else_block)) |
paul@44 | 802 | else: |
paul@163 | 803 | self.new_op(JumpIfTrue(exit_block)) |
paul@44 | 804 | |
paul@146 | 805 | # Re-raise the exception otherwise. |
paul@146 | 806 | |
paul@146 | 807 | self.new_op(RaiseException()) |
paul@146 | 808 | |
paul@232 | 809 | # After the handler, clear the exception. |
paul@146 | 810 | |
paul@163 | 811 | self.set_block(end_handler_block) |
paul@146 | 812 | |
paul@44 | 813 | # Assign to the target. |
paul@44 | 814 | |
paul@44 | 815 | self.dispatch(node.assign) |
paul@139 | 816 | self.discard_value() |
paul@44 | 817 | |
paul@44 | 818 | # Process the body with the current next and exit points. |
paul@44 | 819 | |
paul@163 | 820 | self.add_loop_blocks(next_block, exit_block) |
paul@44 | 821 | self.dispatch(node.body) |
paul@163 | 822 | self.drop_loop_blocks() |
paul@44 | 823 | |
paul@44 | 824 | # Repeat the loop. |
paul@44 | 825 | |
paul@163 | 826 | self.new_op(Jump(next_block)) |
paul@44 | 827 | |
paul@44 | 828 | # Produce the "else" section. |
paul@44 | 829 | |
paul@44 | 830 | if node.else_ is not None: |
paul@240 | 831 | self.set_block(else_block) |
paul@240 | 832 | self.new_op(ClearException()) |
paul@44 | 833 | self.dispatch(node.else_) |
paul@44 | 834 | |
paul@240 | 835 | # After the loop... |
paul@240 | 836 | |
paul@240 | 837 | self.set_block(exit_block) |
paul@44 | 838 | |
paul@240 | 839 | else: |
paul@240 | 840 | # After the loop... |
paul@240 | 841 | |
paul@240 | 842 | self.set_block(exit_block) |
paul@240 | 843 | self.new_op(ClearException()) |
paul@17 | 844 | |
paul@98 | 845 | # Compilation duties... |
paul@98 | 846 | |
paul@98 | 847 | self.discard_temp(temp_iterator) |
paul@98 | 848 | |
paul@17 | 849 | def visitIf(self, node): |
paul@19 | 850 | first = 1 |
paul@232 | 851 | next_block = None |
paul@163 | 852 | exit_block = self.new_block() |
paul@17 | 853 | |
paul@108 | 854 | clauses = node.tests + [(None, node.else_)] |
paul@108 | 855 | |
paul@108 | 856 | for clause in clauses: |
paul@108 | 857 | test, body = clause |
paul@19 | 858 | if body is None: |
paul@19 | 859 | break |
paul@232 | 860 | |
paul@19 | 861 | if not first: |
paul@232 | 862 | self.new_op(Jump(exit_block)) # finish last body |
paul@232 | 863 | self.set_block(next_block) # start next test |
paul@232 | 864 | next_block = None |
paul@232 | 865 | |
paul@19 | 866 | if test is not None: |
paul@19 | 867 | self.dispatch(test) |
paul@234 | 868 | |
paul@234 | 869 | temp = self.optimiser.optimise_temp_storage() |
paul@234 | 870 | self._generateTestBoolean(node, temp) |
paul@234 | 871 | |
paul@163 | 872 | next_block = self.new_block() |
paul@163 | 873 | self.new_op(JumpIfFalse(next_block)) |
paul@232 | 874 | |
paul@19 | 875 | self.dispatch(body) |
paul@232 | 876 | first = 0 |
paul@160 | 877 | |
paul@232 | 878 | if next_block is not None: |
paul@232 | 879 | self.set_block(next_block) |
paul@17 | 880 | |
paul@163 | 881 | self.set_block(exit_block) |
paul@17 | 882 | |
paul@19 | 883 | def visitPass(self, node): pass |
paul@17 | 884 | |
paul@100 | 885 | def visitPrint(self, node): raise TranslationNotImplementedError(self.module.full_name(), node, "Print") |
paul@17 | 886 | |
paul@100 | 887 | def visitPrintnl(self, node): raise TranslationNotImplementedError(self.module.full_name(), node, "Printnl") |
paul@17 | 888 | |
paul@97 | 889 | def visitRaise(self, node): |
paul@97 | 890 | # NOTE: expr1 only => instance provided |
paul@97 | 891 | self.dispatch(node.expr1) |
paul@97 | 892 | |
paul@97 | 893 | if node.expr2 is not None: |
paul@140 | 894 | temp = self.optimiser.optimise_temp_storage() |
paul@102 | 895 | |
paul@97 | 896 | self.dispatch(node.expr2) |
paul@140 | 897 | temp_arg = self.optimiser.optimise_temp_storage() |
paul@102 | 898 | |
paul@102 | 899 | self._startCallFunc() |
paul@102 | 900 | self.new_op(temp_arg) |
paul@102 | 901 | self.new_op(StoreFrame(0)) |
paul@129 | 902 | self._endCallFuncArgs(1) |
paul@102 | 903 | self._doCallFunc(temp) |
paul@102 | 904 | self._endCallFunc(temp) |
paul@102 | 905 | |
paul@102 | 906 | self.discard_temp(temp_arg) |
paul@97 | 907 | |
paul@105 | 908 | self.new_op(StoreException()) |
paul@97 | 909 | self.new_op(RaiseException()) |
paul@17 | 910 | |
paul@21 | 911 | def visitReturn(self, node): |
paul@21 | 912 | if node.value is not None: |
paul@21 | 913 | self.dispatch(node.value) |
paul@68 | 914 | else: |
paul@68 | 915 | self.dispatch(compiler.ast.Name("None")) |
paul@104 | 916 | |
paul@104 | 917 | self.new_op(StoreResult()) |
paul@235 | 918 | |
paul@235 | 919 | if self.in_exception_handler: |
paul@235 | 920 | self.new_op(ClearException()) |
paul@235 | 921 | |
paul@21 | 922 | self.new_op(Return()) |
paul@17 | 923 | |
paul@57 | 924 | def visitTryExcept(self, node): |
paul@163 | 925 | exit_block = self.new_block() |
paul@163 | 926 | else_block = self.new_block() |
paul@163 | 927 | handler_block = self.new_block() |
paul@163 | 928 | |
paul@163 | 929 | self.add_exception_blocks(handler_block, exit_block) |
paul@57 | 930 | |
paul@68 | 931 | # Try... |
paul@68 | 932 | # Produce the code, then jump to the exit. |
paul@68 | 933 | |
paul@163 | 934 | self.new_op(PushHandler(handler_block)) |
paul@57 | 935 | self.dispatch(node.body) |
paul@103 | 936 | self.new_op(PopHandler()) |
paul@160 | 937 | |
paul@160 | 938 | if node.else_ is not None: |
paul@163 | 939 | self.new_op(Jump(else_block)) |
paul@160 | 940 | else: |
paul@163 | 941 | self.new_op(Jump(exit_block)) |
paul@57 | 942 | |
paul@68 | 943 | # Start of handlers. |
paul@68 | 944 | |
paul@163 | 945 | self.set_block(handler_block) |
paul@103 | 946 | self.new_op(PopHandler()) |
paul@102 | 947 | |
paul@57 | 948 | for name, assignment, handler in node.handlers: |
paul@163 | 949 | next_block = self.new_block() |
paul@57 | 950 | |
paul@68 | 951 | # Test the given exception against the current exception. |
paul@68 | 952 | |
paul@57 | 953 | if name is not None: |
paul@57 | 954 | self.dispatch(name) |
paul@145 | 955 | |
paul@57 | 956 | self.new_op(CheckException()) |
paul@163 | 957 | self.new_op(JumpIfFalse(next_block)) |
paul@57 | 958 | |
paul@145 | 959 | # Handle assignment to exception variable. |
paul@145 | 960 | |
paul@145 | 961 | if assignment is not None: |
paul@145 | 962 | self.new_op(LoadException()) |
paul@145 | 963 | |
paul@145 | 964 | # Record the value to be assigned. |
paul@145 | 965 | |
paul@145 | 966 | self.record_value() |
paul@145 | 967 | self.dispatch(assignment) |
paul@145 | 968 | self.discard_value() |
paul@57 | 969 | |
paul@68 | 970 | # Produce the handler code, then jump to the exit. |
paul@68 | 971 | |
paul@235 | 972 | self.in_exception_handler = 1 |
paul@57 | 973 | self.dispatch(handler) |
paul@235 | 974 | self.in_exception_handler = 0 |
paul@235 | 975 | |
paul@163 | 976 | self.new_op(Jump(exit_block)) |
paul@163 | 977 | |
paul@163 | 978 | self.set_block(next_block) |
paul@160 | 979 | |
paul@57 | 980 | # Unhandled exceptions. |
paul@57 | 981 | |
paul@57 | 982 | self.new_op(RaiseException()) |
paul@57 | 983 | |
paul@57 | 984 | # Optional else clause. |
paul@57 | 985 | |
paul@57 | 986 | if node.else_ is not None: |
paul@163 | 987 | self.set_block(else_block) |
paul@57 | 988 | self.dispatch(node.else_) |
paul@57 | 989 | |
paul@232 | 990 | # Clear the exception. |
paul@232 | 991 | |
paul@163 | 992 | self.set_block(exit_block) |
paul@232 | 993 | self.new_op(ClearException()) |
paul@163 | 994 | self.drop_exception_blocks() |
paul@17 | 995 | |
paul@100 | 996 | def visitTryFinally(self, node): raise TranslationNotImplementedError(self.module.full_name(), node, "TryFinally") |
paul@17 | 997 | |
paul@41 | 998 | def visitWhile(self, node): |
paul@163 | 999 | exit_block = self.new_block() |
paul@163 | 1000 | next_block = self.new_block() |
paul@163 | 1001 | else_block = self.new_block() |
paul@163 | 1002 | |
paul@163 | 1003 | self.set_block(next_block) |
paul@44 | 1004 | self.dispatch(node.test) |
paul@44 | 1005 | if node.else_ is not None: |
paul@163 | 1006 | self.new_op(JumpIfFalse(else_block)) |
paul@44 | 1007 | else: |
paul@163 | 1008 | self.new_op(JumpIfFalse(exit_block)) |
paul@163 | 1009 | |
paul@163 | 1010 | self.add_loop_blocks(next_block, exit_block) |
paul@41 | 1011 | |
paul@41 | 1012 | self.dispatch(node.body) |
paul@163 | 1013 | self.new_op(Jump(next_block)) |
paul@41 | 1014 | |
paul@41 | 1015 | if node.else_ is not None: |
paul@163 | 1016 | self.set_block(else_block) |
paul@160 | 1017 | |
paul@41 | 1018 | self.dispatch(node.else_) |
paul@41 | 1019 | |
paul@163 | 1020 | self.set_block(exit_block) |
paul@163 | 1021 | |
paul@163 | 1022 | self.drop_loop_blocks() |
paul@17 | 1023 | |
paul@100 | 1024 | def visitWith(self, node): raise TranslationNotImplementedError(self.module.full_name(), node, "With") |
paul@17 | 1025 | |
paul@100 | 1026 | def visitYield(self, node): raise TranslationNotImplementedError(self.module.full_name(), node, "Yield") |
paul@17 | 1027 | |
paul@17 | 1028 | # vim: tabstop=4 expandtab shiftwidth=4 |