1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
1.2 +++ b/simplify/__init__.py Sun May 27 18:25:25 2007 +0200
1.3 @@ -0,0 +1,1941 @@
1.4 +#!/usr/bin/env python
1.5 +
1.6 +"""
1.7 +Simplify AST structures for easier type propagation and analysis. The code in
1.8 +this module processes AST trees originating from the compiler module and
1.9 +produces a result tree consisting of instruction-oriented program nodes.
1.10 +
1.11 +Copyright (C) 2006, 2007 Paul Boddie <paul@boddie.org.uk>
1.12 +
1.13 +This software is free software; you can redistribute it and/or
1.14 +modify it under the terms of the GNU General Public License as
1.15 +published by the Free Software Foundation; either version 2 of
1.16 +the License, or (at your option) any later version.
1.17 +
1.18 +This software is distributed in the hope that it will be useful,
1.19 +but WITHOUT ANY WARRANTY; without even the implied warranty of
1.20 +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
1.21 +GNU General Public License for more details.
1.22 +
1.23 +You should have received a copy of the GNU General Public
1.24 +License along with this library; see the file LICENCE.txt
1.25 +If not, write to the Free Software Foundation, Inc.,
1.26 +51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
1.27 +
1.28 +--------
1.29 +
1.30 +To use this module, the easiest approach is to use the simplify function:
1.31 +
1.32 +simplify(filename)
1.33 +
1.34 +The more complicated approach involves first instantiating a Simplifier object:
1.35 +
1.36 +simplifier = Simplifier()
1.37 +
1.38 +Then, applying the simplifier to an AST tree:
1.39 +
1.40 +module = compiler.parseFile(filename)
1.41 +simplifier.process(module)
1.42 +"""
1.43 +
1.44 +from simplify.simplified import *
1.45 +import compiler.ast
1.46 +import os
1.47 +
1.48 +class Simplifier(Visitor):
1.49 +
1.50 + """
1.51 + A simplifying visitor for AST nodes.
1.52 +
1.53 + Covered: Add, And, Assert, AssAttr, AssList, AssName, AssTuple, Assign,
1.54 + AugAssign, Bitand, Break, CallFunc, Class, Compare, Const,
1.55 + Continue, Dict, Discard, Div, FloorDiv, For, From, Function,
1.56 + Getattr, Global, If, Import, Invert, Keyword, Lambda, List,
1.57 + ListComp, ListCompFor, ListCompIf, Mod, Module, Mul, Name, Not, Or,
1.58 + Pass, Power, Print, Printnl, Raise, Return, Slice, Sliceobj, Stmt,
1.59 + Sub, Subscript, TryExcept, TryFinally, Tuple, While, UnaryAdd,
1.60 + UnarySub.
1.61 +
1.62 + Missing: Backquote, Bitor, Bitxor, Decorators, Ellipsis, Exec, LeftShift,
1.63 + RightShift, Yield.
1.64 + """
1.65 +
1.66 + def __init__(self, builtins=0):
1.67 +
1.68 + """
1.69 + Initialise the simplifier with the optional 'builtins' parameter
1.70 + indicating whether the module contains the built-in classes and
1.71 + functions.
1.72 + """
1.73 +
1.74 + Visitor.__init__(self)
1.75 + self.subprograms = [] # Subprograms outside the tree.
1.76 + self.structures = [] # Structures/classes.
1.77 + self.constants = {} # Constants.
1.78 + self.current_subprograms = [] # Current subprograms being processed.
1.79 + self.current_structures = [] # Current structures being processed.
1.80 + self.within_class = 0 # Whether a class is being defined.
1.81 + self.builtins = builtins # Whether the builtins are being processed.
1.82 +
1.83 + # Convenience attributes.
1.84 +
1.85 + self.subnames = {}
1.86 +
1.87 + # For compiler package mechanisms.
1.88 +
1.89 + self.visitor = self
1.90 +
1.91 + def process(self, node, name):
1.92 + result = self.dispatch(node, name)
1.93 + result.simplifier = self
1.94 + return result
1.95 +
1.96 + def dispatch_or_none(self, node, *args):
1.97 + if node is not None:
1.98 + return self.dispatch(node, *args)
1.99 + else:
1.100 + return LoadName(node, name="None")
1.101 +
1.102 + # Top-level transformation.
1.103 +
1.104 + def visitModule(self, module, name=None):
1.105 +
1.106 + """
1.107 + Process the given 'module', producing a Module object which contains the
1.108 + resulting program nodes. If the optional 'name' is provided, the 'name'
1.109 + attribute is set on the Module object using a value other than None.
1.110 + """
1.111 +
1.112 + result = self.module = Module(module, 1, name=name)
1.113 + result.code = self.dispatch(module.node)
1.114 + return result
1.115 +
1.116 + # Node transformations.
1.117 +
1.118 + def visitAdd(self, add):
1.119 + return self._visitBinary(add, "__add__", "__radd__")
1.120 +
1.121 + def visitAnd(self, and_):
1.122 +
1.123 + """
1.124 + Make a subprogram for the 'and_' node and record its contents inside the
1.125 + subprogram. Convert...
1.126 +
1.127 + And (test)
1.128 + (test)
1.129 + ...
1.130 +
1.131 + ...to:
1.132 +
1.133 + Subprogram -> Conditional (test) -> ReturnFromBlock ...
1.134 + (else) -> Conditional (test) -> ReturnFromBlock ...
1.135 + (else) -> ...
1.136 + """
1.137 +
1.138 + subprogram = Subprogram(name=None, module=self.module, internal=1, returns_value=1, params=[], star=None, dstar=None)
1.139 + self.current_subprograms.append(subprogram)
1.140 +
1.141 + # In the subprogram, make instructions which store each operand, test
1.142 + # for each operand's truth status, and if appropriate return from the
1.143 + # subprogram with the value of the operand.
1.144 +
1.145 + last = and_.nodes[-1]
1.146 + results = nodes = []
1.147 +
1.148 + for node in and_.nodes:
1.149 + expr = self.dispatch(node)
1.150 +
1.151 + # Return from the subprogram where the test is not satisfied.
1.152 +
1.153 + if node is not last:
1.154 + nodes += [
1.155 + StoreTemp(expr=expr),
1.156 + Conditional(
1.157 + test=self._visitNot(LoadTemp()),
1.158 + body=[
1.159 + ReturnFromBlock(
1.160 + expr=LoadTemp()
1.161 + )
1.162 + ],
1.163 + else_=[
1.164 + ReleaseTemp()
1.165 + # Subsequent operations go here!
1.166 + ]
1.167 + )
1.168 + ]
1.169 +
1.170 + # Put subsequent operations in the else section of this conditional.
1.171 +
1.172 + nodes = nodes[-1].else_
1.173 +
1.174 + # For the last operation, return the result.
1.175 +
1.176 + else:
1.177 + nodes.append(ReturnFromBlock(expr=expr))
1.178 +
1.179 + # Finish the subprogram definition.
1.180 +
1.181 + subprogram.code = results
1.182 +
1.183 + self.current_subprograms.pop()
1.184 + self.subprograms.append(subprogram); self.subnames[subprogram.full_name()] = subprogram
1.185 +
1.186 + # Make an invocation of the subprogram.
1.187 +
1.188 + result = InvokeRef(and_, 1, produces_result=1, ref=subprogram)
1.189 + return result
1.190 +
1.191 + def visitAssert(self, assert_):
1.192 + if assert_.fail:
1.193 + fail_args = [self.dispatch(assert_.fail)]
1.194 + else:
1.195 + fail_args = []
1.196 +
1.197 + result = Conditional(assert_, 1,
1.198 + test=self.dispatch(assert_.test),
1.199 + body=[],
1.200 + else_=[
1.201 + Raise(assert_,
1.202 + expr=InvokeFunction(assert_,
1.203 + expr=LoadName(name="AssertionError"),
1.204 + args=fail_args,
1.205 + star=None,
1.206 + dstar=None
1.207 + )
1.208 + )
1.209 + ]
1.210 + )
1.211 +
1.212 + # Make nice annotations for the viewer.
1.213 +
1.214 + assert_._raises = result.else_[0].expr
1.215 + return result
1.216 +
1.217 + # Assignments.
1.218 +
1.219 + def visitAssAttr(self, assattr, in_sequence=0):
1.220 + expr = self._visitAssNameOrAttr(assattr, in_sequence)
1.221 + lvalue = self.dispatch(assattr.expr)
1.222 + result = StoreAttr(assattr, 1, name=assattr.attrname, lvalue=lvalue, expr=expr)
1.223 + return result
1.224 +
1.225 + def visitAssign(self, assign):
1.226 + result = Assign(assign, 1)
1.227 + store = StoreTemp(expr=self.dispatch(assign.expr))
1.228 + release = ReleaseTemp()
1.229 + result.code = [store] + self.dispatches(assign.nodes, 0) + [release]
1.230 + return result
1.231 +
1.232 + def visitAssList(self, asslist, in_sequence=0):
1.233 + if not in_sequence:
1.234 + expr = LoadTemp()
1.235 + else:
1.236 + expr = InvokeFunction(asslist, expr=LoadAttr(expr=LoadTemp(), name="next"))
1.237 + result = Assign(asslist, 1)
1.238 + store = StoreTemp(expr=InvokeFunction(asslist, expr=LoadAttr(name="__iter__", expr=expr)))
1.239 + release = ReleaseTemp()
1.240 + result.code = [store] + self.dispatches(asslist.nodes, 1) + [release]
1.241 + return result
1.242 +
1.243 + visitAssTuple = visitAssList
1.244 +
1.245 + def _visitAssNameOrAttr(self, node, in_sequence):
1.246 + if not in_sequence:
1.247 + return LoadTemp()
1.248 + else:
1.249 + return InvokeFunction(node, expr=LoadAttr(expr=LoadTemp(), name="next"))
1.250 +
1.251 + def visitAssName(self, assname, in_sequence=0):
1.252 + expr = self._visitAssNameOrAttr(assname, in_sequence)
1.253 + result = StoreName(assname, 1, name=assname.name, expr=expr)
1.254 + return result
1.255 +
1.256 + augassign_methods = {
1.257 + "+=" : "__iadd__", "-=" : "__isub__", "*=" : "__imul__", "/=" : "__idiv__",
1.258 + "%=" : "__imod__", "**=" : "__ipow__", "<<=" : "__ilshift__", ">>=" : "__irshift__",
1.259 + "&=" : "__iand__", "^=" : "__ixor__", "|=" : "__ior__"
1.260 + }
1.261 +
1.262 + def visitAugAssign(self, augassign):
1.263 +
1.264 + """
1.265 + Convert the augmented assignment...
1.266 +
1.267 + AugAssign (node) -> Name | Getattr | Slice | Subscript
1.268 + (op)
1.269 + (expr)
1.270 +
1.271 + ...to:
1.272 +
1.273 + Assign (code) -> StoreTemp (expr) -> InvokeFunction (expr) -> LoadAttr (expr) -> <name>
1.274 + (name) -> <op>
1.275 + StoreName (name) -> <name>
1.276 + (expr) -> LoadTemp
1.277 + ReleaseTemp
1.278 + """
1.279 +
1.280 + result = Assign(augassign, 1)
1.281 + expr = self.dispatch(augassign.expr)
1.282 +
1.283 + # Simple augmented assignment: name += expr
1.284 +
1.285 + if isinstance(augassign.node, compiler.ast.Name):
1.286 + result.code = [
1.287 + StoreTemp(
1.288 + expr=InvokeFunction( # referenced below
1.289 + augassign,
1.290 + args=[expr],
1.291 + star=None,
1.292 + dstar=None,
1.293 + expr=LoadAttr(
1.294 + expr=self.dispatch(augassign.node),
1.295 + name=self.augassign_methods[augassign.op]
1.296 + )
1.297 + )
1.298 + ),
1.299 + StoreName(
1.300 + expr=LoadTemp(),
1.301 + name=augassign.node.name),
1.302 + ReleaseTemp()
1.303 + ]
1.304 +
1.305 + # Make nice annotations for the viewer.
1.306 +
1.307 + augassign._op_call = result.code[0].expr
1.308 +
1.309 + # Complicated augmented assignment: lvalue.attr += expr
1.310 +
1.311 + elif isinstance(augassign.node, compiler.ast.Getattr):
1.312 +
1.313 + # <lvalue> -> setattr(<lvalue>, getattr(<lvalue>, "attr").__xxx__(expr))
1.314 +
1.315 + result.code = [
1.316 + StoreTemp(
1.317 + index="expr",
1.318 + expr=self.dispatch(augassign.node.expr)
1.319 + ),
1.320 + StoreTemp(
1.321 + expr=InvokeFunction( # referenced below
1.322 + augassign,
1.323 + args=[expr], star=None, dstar=None,
1.324 + expr=LoadAttr(
1.325 + expr=LoadAttr(augassign.node, 1,
1.326 + expr=LoadTemp(index="expr"),
1.327 + name=augassign.node.attrname
1.328 + ),
1.329 + name=self.augassign_methods[augassign.op]
1.330 + )
1.331 + )
1.332 + ),
1.333 + StoreAttr(
1.334 + expr=LoadTemp(),
1.335 + lvalue=LoadTemp(index="expr"),
1.336 + name=augassign.node.attrname
1.337 + ),
1.338 + ReleaseTemp(index="expr"),
1.339 + ReleaseTemp()
1.340 + ]
1.341 +
1.342 + # Make nice annotations for the viewer.
1.343 +
1.344 + augassign._op_call = result.code[1].expr
1.345 +
1.346 + # Complicated augassign using slices: lvalue[lower:upper] += expr
1.347 +
1.348 + elif isinstance(augassign.node, compiler.ast.Slice):
1.349 +
1.350 + # <lvalue>, <lower>, <upper> -> <lvalue>.__setslice__(<lower>, <upper>, <lvalue>.__getslice__(<lower>, <upper>).__xxx__(expr))
1.351 +
1.352 + result.code = [
1.353 + StoreTemp(
1.354 + index="expr",
1.355 + expr=self.dispatch(augassign.node.expr)
1.356 + ),
1.357 + StoreTemp(
1.358 + index="lower",
1.359 + expr=self.dispatch_or_none(augassign.node.lower)
1.360 + ),
1.361 + StoreTemp(
1.362 + index="upper",
1.363 + expr=self.dispatch_or_none(augassign.node.upper)
1.364 + ),
1.365 + StoreTemp(
1.366 + expr=InvokeFunction( # referenced below
1.367 + augassign,
1.368 + args=[expr], star=None, dstar=None,
1.369 + expr=LoadAttr(
1.370 + expr=self._visitSlice(
1.371 + augassign.node,
1.372 + LoadTemp(index="expr"),
1.373 + LoadTemp(index="lower"),
1.374 + LoadTemp(index="upper"),
1.375 + "OP_APPLY"),
1.376 + name=self.augassign_methods[augassign.op]
1.377 + )
1.378 + )
1.379 + ),
1.380 + self._visitSlice(
1.381 + augassign.node,
1.382 + LoadTemp(index="expr"),
1.383 + LoadTemp(index="lower"),
1.384 + LoadTemp(index="upper"),
1.385 + "OP_ASSIGN",
1.386 + LoadTemp()
1.387 + ),
1.388 + ReleaseTemp(index="expr"),
1.389 + ReleaseTemp(index="lower"),
1.390 + ReleaseTemp(index="upper"),
1.391 + ReleaseTemp()
1.392 + ]
1.393 +
1.394 + # Make nice annotations for the viewer.
1.395 +
1.396 + augassign._op_call = result.code[3].expr
1.397 +
1.398 + # Complicated augassign using subscripts: lvalue[subs] += expr
1.399 +
1.400 + elif isinstance(augassign.node, compiler.ast.Subscript):
1.401 +
1.402 + # <lvalue>, <subs> -> <lvalue>.__setitem__(<subs>, <lvalue>.__getitem__(<subs>).__xxx__(expr))
1.403 +
1.404 + result.code = [
1.405 + StoreTemp(index="expr", expr=self.dispatch(augassign.node.expr)),
1.406 + StoreTemp(index="subs", expr=self._visitSubscriptSubs(augassign.node, augassign.node.subs)),
1.407 + StoreTemp(
1.408 + expr=InvokeFunction( # referenced below
1.409 + augassign,
1.410 + args=[expr], star=None, dstar=None,
1.411 + expr=LoadAttr(
1.412 + expr=self._visitSubscript(
1.413 + augassign.node,
1.414 + LoadTemp(index="expr"),
1.415 + LoadTemp(index="subs"),
1.416 + "OP_APPLY"
1.417 + ),
1.418 + name=self.augassign_methods[augassign.op]
1.419 + )
1.420 + )
1.421 + ),
1.422 + self._visitSubscript(
1.423 + augassign.node,
1.424 + LoadTemp(index="expr"),
1.425 + LoadTemp(index="subs"),
1.426 + "OP_ASSIGN",
1.427 + LoadTemp()
1.428 + ),
1.429 + ReleaseTemp(index="expr"),
1.430 + ReleaseTemp(index="subs"),
1.431 + ReleaseTemp()
1.432 + ]
1.433 +
1.434 + # Make nice annotations for the viewer.
1.435 +
1.436 + augassign._op_call = result.code[2].expr
1.437 +
1.438 + else:
1.439 + raise NotImplementedError, augassign.node.__class__
1.440 +
1.441 + return result
1.442 +
1.443 + def visitBitand(self, bitand):
1.444 +
1.445 + """
1.446 + Make a subprogram for the 'bitand' node and record its contents inside the
1.447 + subprogram. Convert...
1.448 +
1.449 + Bitand (node)
1.450 + (node)
1.451 + ...
1.452 +
1.453 + ...to:
1.454 +
1.455 + Subprogram -> Conditional (test) -> ReturnFromBlock ...
1.456 + (else) -> Conditional (test) -> ReturnFromBlock ...
1.457 + (else) -> ...
1.458 + """
1.459 +
1.460 + subprogram = Subprogram(name=None, module=self.module, internal=1, returns_value=1, params=[], star=None, dstar=None)
1.461 + self.current_subprograms.append(subprogram)
1.462 +
1.463 + # In the subprogram, make instructions which store each operand, test
1.464 + # for each operand's truth status, and if appropriate return from the
1.465 + # subprogram with the value of the operand.
1.466 +
1.467 + last = bitand.nodes[-1]
1.468 + results = nodes = []
1.469 +
1.470 + # Start by storing the first operand.
1.471 +
1.472 + nodes += [
1.473 + StoreTemp(expr=self.dispatch(bitand.nodes[0]))
1.474 + ]
1.475 +
1.476 + # For viewing purposes, record invocations on the AST node.
1.477 +
1.478 + bitand._ops = []
1.479 +
1.480 + for node in bitand.nodes[1:]:
1.481 +
1.482 + # Make a new AST-style node to wrap the operation program nodes.
1.483 +
1.484 + new_op = Op("&", node)
1.485 + bitand._ops.append(new_op)
1.486 +
1.487 + # Generate the operation involving the previous result and the
1.488 + # current operand.
1.489 +
1.490 + expr = self._visitBinaryOp(new_op, LoadTemp(), self.dispatch(node), "__and__", "__rand__")
1.491 +
1.492 + # Return from the subprogram where the test is not satisfied.
1.493 +
1.494 + if node is not last:
1.495 + nodes += [
1.496 + StoreTemp(expr=expr),
1.497 + Conditional(
1.498 + test=self._visitNot(LoadTemp()),
1.499 + body=[
1.500 + ReturnFromBlock(
1.501 + expr=LoadTemp()
1.502 + )
1.503 + ],
1.504 + else_=[
1.505 + # Subsequent operations go here!
1.506 + ]
1.507 + )
1.508 + ]
1.509 +
1.510 + # Put subsequent operations in the else section of this conditional.
1.511 +
1.512 + nodes = nodes[-1].else_
1.513 +
1.514 + # For the last operation, return the result.
1.515 +
1.516 + else:
1.517 + nodes.append(ReturnFromBlock(expr=expr))
1.518 +
1.519 + # Finish the subprogram definition.
1.520 +
1.521 + subprogram.code = results
1.522 +
1.523 + self.current_subprograms.pop()
1.524 + self.subprograms.append(subprogram); self.subnames[subprogram.full_name()] = subprogram
1.525 +
1.526 + # Make an invocation of the subprogram.
1.527 +
1.528 + result = InvokeRef(bitand, 1, produces_result=1, ref=subprogram)
1.529 + return result
1.530 +
1.531 + def visitBreak(self, break_):
1.532 + result = ReturnFromBlock(break_, 1)
1.533 + return result
1.534 +
1.535 + def visitCallFunc(self, callfunc):
1.536 + result = InvokeFunction(callfunc, 1, star=None, dstar=None, args=self.dispatches(callfunc.args))
1.537 + if callfunc.star_args is not None:
1.538 + result.star = self.dispatch(callfunc.star_args)
1.539 + if callfunc.dstar_args is not None:
1.540 + result.dstar = self.dispatch(callfunc.dstar_args)
1.541 + result.expr = self.dispatch(callfunc.node)
1.542 + return result
1.543 +
1.544 + def visitClass(self, class_):
1.545 +
1.546 + # Add "object" if the class is not "object" and has an empty bases list.
1.547 +
1.548 + if class_.name != "object" and not class_.bases:
1.549 + bases = [compiler.ast.Name("object")]
1.550 + else:
1.551 + bases = class_.bases
1.552 +
1.553 + structure = Class(name=class_.name, module=self.module, bases=self.dispatches(bases))
1.554 + self.structures.append(structure)
1.555 + within_class = self.within_class
1.556 + self.within_class = 1
1.557 +
1.558 + # Make a subprogram which initialises the class structure.
1.559 +
1.560 + subprogram = Subprogram(name=None, module=self.module, structure=structure, params=[], star=None, dstar=None)
1.561 + self.current_subprograms.append(subprogram)
1.562 + self.current_structures.append(structure) # mostly for name construction
1.563 +
1.564 + # The class is initialised using the code found inside.
1.565 +
1.566 + subprogram.code = self.dispatch(class_.code) + [ReturnFromBlock()]
1.567 +
1.568 + self.within_class = within_class
1.569 + self.current_structures.pop()
1.570 + self.current_subprograms.pop()
1.571 + self.subprograms.append(subprogram); self.subnames[subprogram.full_name()] = subprogram
1.572 +
1.573 + # Make a definition of the class associating it with a name.
1.574 +
1.575 + result = Assign(
1.576 + code=[
1.577 + StoreName(class_, 1, # defines the class
1.578 + name=class_.name,
1.579 + expr=LoadRef(ref=structure)
1.580 + ),
1.581 + InvokeRef(
1.582 + class_,
1.583 + share_locals=0, # override the local sharing usually in InvokeRef
1.584 + ref=subprogram
1.585 + )
1.586 + ]
1.587 + )
1.588 + return result
1.589 +
1.590 + comparison_methods = {
1.591 + "==" : ("__eq__", "__ne__"),
1.592 + "!=" : ("__ne__", "__eq__"),
1.593 + "<" : ("__lt__", "__gt__"),
1.594 + "<=" : ("__le__", "__ge__"),
1.595 + ">=" : ("__ge__", "__le__"),
1.596 + ">" : ("__gt__", "__lt__"),
1.597 + "is" : None,
1.598 + "is not" : None,
1.599 + "in" : None,
1.600 + "not in" : None
1.601 + }
1.602 +
1.603 + def visitCompare(self, compare):
1.604 +
1.605 + """
1.606 + Make a subprogram for the 'compare' node and record its contents inside
1.607 + the subprogram. Convert...
1.608 +
1.609 + Compare (expr)
1.610 + (name/node)
1.611 + ...
1.612 +
1.613 + ...to:
1.614 +
1.615 + InvokeRef -> Subprogram -> Conditional (test) -> (body)
1.616 + (else) -> Conditional (test) -> (body)
1.617 + (else) -> ...
1.618 + """
1.619 +
1.620 + subprogram = Subprogram(name=None, module=self.module, internal=1, returns_value=1, params=[], star=None, dstar=None)
1.621 + self.current_subprograms.append(subprogram)
1.622 +
1.623 + # In the subprogram, make instructions which invoke a method on the
1.624 + # first operand of each operand pair and, if appropriate, return with
1.625 + # the value from that method.
1.626 +
1.627 + last = compare.ops[-1]
1.628 + previous = self.dispatch(compare.expr)
1.629 + results = nodes = []
1.630 +
1.631 + # For viewing purposes, record invocations on the AST node.
1.632 +
1.633 + compare._ops = []
1.634 +
1.635 + for op in compare.ops:
1.636 + op_name, node = op
1.637 +
1.638 + # Make a new AST-style node to wrap the operation program nodes.
1.639 +
1.640 + new_op = Op(op_name, node)
1.641 + compare._ops.append(new_op)
1.642 +
1.643 + expr = self.dispatch(node)
1.644 +
1.645 + # Identify the operation and produce the appropriate method call.
1.646 +
1.647 + method_names = self.comparison_methods[op_name]
1.648 + if method_names:
1.649 + first_name, alternative_name = method_names
1.650 + invocation = self._visitBinaryCompareOp(new_op, previous, expr, first_name, alternative_name)
1.651 +
1.652 + elif op_name == "is":
1.653 + invocation = InvokeFunction(
1.654 + new_op, 1,
1.655 + expr=LoadName(name="__is__"),
1.656 + args=[previous, expr],
1.657 + star=None,
1.658 + dstar=None)
1.659 +
1.660 + elif op_name == "is not":
1.661 + invocation = Not(
1.662 + new_op, 1,
1.663 + expr=InvokeFunction(
1.664 + new_op,
1.665 + expr=LoadName(name="__is__"),
1.666 + args=[previous, expr],
1.667 + star=None,
1.668 + dstar=None)
1.669 + )
1.670 +
1.671 + elif op_name == "in":
1.672 + invocation = InvokeFunction(
1.673 + new_op, 1,
1.674 + expr=LoadAttr(
1.675 + expr=previous,
1.676 + name="__contains__"
1.677 + ),
1.678 + args=[expr],
1.679 + star=None,
1.680 + dstar=None)
1.681 +
1.682 + elif op_name == "not in":
1.683 + invocation = Not(
1.684 + new_op, 1,
1.685 + expr=InvokeFunction(
1.686 + new_op,
1.687 + expr=LoadAttr(
1.688 + expr=previous,
1.689 + name="__contains__"
1.690 + ),
1.691 + args=[expr],
1.692 + star=None,
1.693 + dstar=None)
1.694 + )
1.695 +
1.696 + else:
1.697 + raise NotImplementedError, op_name
1.698 +
1.699 + nodes.append(StoreTemp(expr=invocation))
1.700 +
1.701 + # Return from the subprogram where the test is not satisfied.
1.702 +
1.703 + if op is not last:
1.704 + nodes.append(
1.705 + Conditional(
1.706 + test=self._visitNot(LoadTemp()),
1.707 + body=[
1.708 + ReturnFromBlock(expr=LoadTemp())
1.709 + ],
1.710 + else_=[
1.711 + ReleaseTemp()
1.712 + # Subsequent operations go here!
1.713 + ]
1.714 + )
1.715 + )
1.716 +
1.717 + # Put subsequent operations in the else section of this conditional.
1.718 +
1.719 + nodes = nodes[-1].else_
1.720 +
1.721 + # For the last operation, return the result.
1.722 +
1.723 + else:
1.724 + nodes.append(
1.725 + ReturnFromBlock(expr=LoadTemp(release=1))
1.726 + )
1.727 +
1.728 + previous = expr
1.729 +
1.730 + # Finish the subprogram definition.
1.731 +
1.732 + subprogram.code = results
1.733 +
1.734 + self.current_subprograms.pop()
1.735 + self.subprograms.append(subprogram); self.subnames[subprogram.full_name()] = subprogram
1.736 +
1.737 + # Make an invocation of the subprogram.
1.738 +
1.739 + result = InvokeRef(compare, 1, produces_result=1, ref=subprogram)
1.740 + return result
1.741 +
1.742 + def visitConst(self, const):
1.743 + key = "%s-%s" % (const.value.__class__.__name__, const.value)
1.744 + if not self.constants.has_key(key):
1.745 + self.constants[key] = Constant(name=repr(const.value), value=const.value)
1.746 + result = InvokeFunction(const, 1, expr=LoadName(name=self.constants[key].typename))
1.747 + return result
1.748 +
1.749 + def visitContinue(self, continue_):
1.750 + result = InvokeRef(continue_, 1, ref=self.current_subprograms[-1])
1.751 + return result
1.752 +
1.753 + def visitDict(self, dict):
1.754 + result = InvokeFunction(dict, 1, expr=LoadName(name="dict"))
1.755 + args = []
1.756 + for key, value in dict.items:
1.757 + tuple = InvokeFunction(dict, expr=LoadName(name="tuple"))
1.758 + tuple.set_args([self.dispatch(key), self.dispatch(value)])
1.759 + args.append(tuple)
1.760 + result.set_args(args)
1.761 + return result
1.762 +
1.763 + def visitDiscard(self, discard):
1.764 + return self.dispatch(discard.expr)
1.765 +
1.766 + def visitDiv(self, div):
1.767 + return self._visitBinary(div, "__div__", "__rdiv__")
1.768 +
1.769 + def visitFloorDiv(self, floordiv):
1.770 + return self._visitBinary(floordiv, "__floordiv__", "__rfloordiv__")
1.771 +
1.772 + def visitFor(self, for_):
1.773 +
1.774 + """
1.775 + Make a subprogram for the 'for_' node and record its contents inside the
1.776 + subprogram. Convert...
1.777 +
1.778 + For (assign)
1.779 + (body)
1.780 + (else)
1.781 +
1.782 + ...to:
1.783 +
1.784 + Assign (assign #1)
1.785 + Invoke -> Subprogram -> Try (body) -> (assign #2)
1.786 + (body)
1.787 + Invoke subprogram
1.788 + (handler) -> ...
1.789 + (else) -> ...
1.790 + """
1.791 +
1.792 + return self._visitFor(for_, self.dispatches(for_.body), for_.else_)
1.793 +
1.794 + def _visitFor(self, node, body_stmt, else_=None):
1.795 +
1.796 + subprogram = Subprogram(name=None, module=self.module, internal=1, returns_value=0, params=[])
1.797 + self.current_subprograms.append(subprogram)
1.798 +
1.799 + # Always return from conditional sections/subprograms.
1.800 +
1.801 + if else_ is not None:
1.802 + else_stmt = self.dispatch(else_) + [ReturnFromBlock()]
1.803 + else:
1.804 + else_stmt = [ReturnFromBlock()]
1.805 +
1.806 + # Wrap the assignment in a try...except statement.
1.807 + # Inside the body, add a recursive invocation to the subprogram.
1.808 +
1.809 + subprogram.code = [
1.810 + Try(
1.811 + body=[
1.812 + Assign(
1.813 + code=[
1.814 + StoreTemp(
1.815 + expr=InvokeFunction(node,
1.816 + expr=LoadAttr(
1.817 + expr=LoadTemp(),
1.818 + name="next"
1.819 + )
1.820 + )
1.821 + ),
1.822 + self.dispatch(node.assign),
1.823 + ReleaseTemp()
1.824 + ])
1.825 + ] + body_stmt + [
1.826 + InvokeRef(
1.827 + node,
1.828 + ref=subprogram
1.829 + )
1.830 + ],
1.831 + handler=[
1.832 + Conditional(
1.833 + test=InvokeFunction(
1.834 + node,
1.835 + expr=LoadName(name="isinstance"),
1.836 + args=[LoadExc(), LoadName(name="StopIteration")],
1.837 + star=None,
1.838 + dstar=None),
1.839 + body=else_stmt,
1.840 + else_=[
1.841 + Raise(
1.842 + expr=LoadExc()
1.843 + )
1.844 + ]
1.845 + )
1.846 + ],
1.847 + else_=[],
1.848 + finally_=[]
1.849 + ),
1.850 + ReturnFromBlock()
1.851 + ]
1.852 +
1.853 + # Finish the subprogram definition.
1.854 +
1.855 + self.current_subprograms.pop()
1.856 + self.subprograms.append(subprogram); self.subnames[subprogram.full_name()] = subprogram
1.857 +
1.858 + # Obtain an iterator for the sequence involved.
1.859 + # Then, make an invocation of the subprogram.
1.860 +
1.861 + result = Assign(node, 1,
1.862 + code=[
1.863 + StoreTemp(
1.864 + expr=InvokeFunction(
1.865 + node,
1.866 + expr=LoadAttr(
1.867 + name="__iter__",
1.868 + expr=self.dispatch(node.list)
1.869 + )
1.870 + )
1.871 + ),
1.872 + InvokeRef(node, ref=subprogram),
1.873 + ReleaseTemp()
1.874 + ]
1.875 + )
1.876 +
1.877 + # Make nice annotations for the viewer.
1.878 +
1.879 + node._iter_call = result.code[0].expr
1.880 + node._next_call = subprogram.code[0].body[0].code[0].expr
1.881 +
1.882 + return result
1.883 +
1.884 + def visitFrom(self, from_):
1.885 + result = Assign(from_, 1)
1.886 + code = []
1.887 + _names = []
1.888 + code.append(
1.889 + StoreTemp(
1.890 + expr=Import(name=from_.modname, alias=1)
1.891 + )
1.892 + )
1.893 + from_._modname = code[-1].expr
1.894 + for name, alias in from_.names:
1.895 + code.append(
1.896 + StoreName(
1.897 + expr=LoadAttr(
1.898 + expr=LoadTemp(),
1.899 + name=name),
1.900 + name=(alias or name)
1.901 + )
1.902 + )
1.903 + _names.append(code[-1].expr)
1.904 + code.append(ReleaseTemp())
1.905 + result.code = code
1.906 + from_._names = _names
1.907 + return result
1.908 +
1.909 + def _visitFunction(self, function, subprogram):
1.910 +
1.911 + """
1.912 + A common function generator which transforms the given 'function' node
1.913 + and initialises the given 'subprogram' appropriately.
1.914 + """
1.915 +
1.916 + # Discover star and dstar parameters.
1.917 +
1.918 + if function.flags & 4 != 0:
1.919 + has_star = 1
1.920 + else:
1.921 + has_star = 0
1.922 + if function.flags & 8 != 0:
1.923 + has_dstar = 1
1.924 + else:
1.925 + has_dstar = 0
1.926 +
1.927 + # Discover the number of defaults and positional parameters.
1.928 +
1.929 + ndefaults = len(function.defaults)
1.930 + npositional = len(function.argnames) - has_star - has_dstar
1.931 +
1.932 + # Produce star and dstar parameters with appropriate defaults.
1.933 +
1.934 + if has_star:
1.935 + star = (
1.936 + function.argnames[npositional],
1.937 + self.dispatch(compiler.ast.List([]))
1.938 + )
1.939 + else:
1.940 + star = None
1.941 + if has_dstar:
1.942 + dstar = (
1.943 + function.argnames[npositional + has_star],
1.944 + self.dispatch(compiler.ast.Dict([]))
1.945 + )
1.946 + else:
1.947 + dstar = None
1.948 +
1.949 + params = []
1.950 + for i in range(0, npositional - ndefaults):
1.951 + params.append((function.argnames[i], None))
1.952 +
1.953 + # Process defaults.
1.954 +
1.955 + for i in range(0, ndefaults):
1.956 + default = function.defaults[i]
1.957 + if default is not None:
1.958 + params.append((function.argnames[npositional - ndefaults + i], self.dispatch(default)))
1.959 + else:
1.960 + params.append((function.argnames[npositional - ndefaults + i], None))
1.961 +
1.962 + subprogram.params = params
1.963 + subprogram.star = star
1.964 + subprogram.dstar = dstar
1.965 + self.subprograms.append(subprogram); self.subnames[subprogram.full_name()] = subprogram
1.966 +
1.967 + def visitFunction(self, function):
1.968 +
1.969 + """
1.970 + Make a subprogram for the 'function' and record it outside the main
1.971 + tree. Produce something like the following:
1.972 +
1.973 + StoreName (name)
1.974 + (expr) -> LoadRef (ref) -> Subprogram (params)
1.975 + (star)
1.976 + (dstar)
1.977 + """
1.978 +
1.979 + subprogram = Subprogram(function, name=function.name, module=self.module, structures=self.current_structures[:],
1.980 + internal=0, returns_value=1, star=None, dstar=None, is_method=self.within_class, original_def=function)
1.981 +
1.982 + # Make nice annotations for the viewer.
1.983 +
1.984 + function._subprogram = subprogram
1.985 +
1.986 + self.current_subprograms.append(subprogram)
1.987 + within_class = self.within_class
1.988 + self.within_class = 0
1.989 +
1.990 + subprogram.code = self.dispatch(function.code) + [ReturnFromFunction()]
1.991 +
1.992 + self.within_class = within_class
1.993 + self.current_subprograms.pop()
1.994 + self._visitFunction(function, subprogram)
1.995 +
1.996 + # Make a definition of the function associating it with a name.
1.997 +
1.998 + result = StoreName(function, 1, name=function.name, expr=LoadRef(ref=subprogram))
1.999 + return result
1.1000 +
1.1001 + def visitGetattr(self, getattr):
1.1002 + result = LoadAttr(getattr, 1,
1.1003 + name=getattr.attrname,
1.1004 + expr=self.dispatch(getattr.expr)
1.1005 + )
1.1006 + return result
1.1007 +
1.1008 + def visitGlobal(self, global_):
1.1009 + result = Global(global_, 1,
1.1010 + names=global_.names
1.1011 + )
1.1012 + return result
1.1013 +
1.1014 + def visitIf(self, if_):
1.1015 +
1.1016 + """
1.1017 + Make conditionals for each test from an 'if_' AST node, adding the body
1.1018 + and putting each subsequent test as part of the conditional's else
1.1019 + section.
1.1020 +
1.1021 + Convert...
1.1022 +
1.1023 + If (test/body)
1.1024 + (test/body)
1.1025 + ...
1.1026 + (else/body)
1.1027 +
1.1028 + ...to:
1.1029 +
1.1030 + Conditional (test) -> (body)
1.1031 + (else) -> Conditional (test) -> (body)
1.1032 + (else) -> ...
1.1033 + """
1.1034 +
1.1035 +
1.1036 + results = nodes = []
1.1037 +
1.1038 + # Produce something like...
1.1039 + # expr.__bool__() ? body
1.1040 +
1.1041 + first = 1
1.1042 + for compare, stmt in if_.tests:
1.1043 +
1.1044 + # Set the first as the defining node.
1.1045 +
1.1046 + test = Conditional(if_, first,
1.1047 + test=InvokeFunction(
1.1048 + if_,
1.1049 + expr=LoadAttr(
1.1050 + expr=self.dispatch(compare),
1.1051 + name="__bool__"
1.1052 + ),
1.1053 + )
1.1054 + )
1.1055 + test.body = self.dispatch(stmt)
1.1056 + nodes.append(test)
1.1057 + nodes = test.else_ = []
1.1058 + first = 0
1.1059 +
1.1060 + # Add the compound statement from any else clause to the end.
1.1061 +
1.1062 + if if_.else_ is not None:
1.1063 + nodes += self.dispatch(if_.else_)
1.1064 +
1.1065 + result = results[0]
1.1066 + return result
1.1067 +
1.1068 + def visitImport(self, import_):
1.1069 + result = Assign(import_, 1)
1.1070 + code = []
1.1071 + _names = []
1.1072 + for path, alias in import_.names:
1.1073 + importer = Import(name=path, alias=alias)
1.1074 + top = alias or path.split(".")[0]
1.1075 + code.append(StoreName(expr=importer, name=top))
1.1076 + _names.append(code[-1].expr)
1.1077 + result.code = code
1.1078 + import_._names = _names
1.1079 + return result
1.1080 +
1.1081 + def visitInvert(self, invert):
1.1082 + return self._visitUnary(invert, "__invert__")
1.1083 +
1.1084 + def visitKeyword(self, keyword):
1.1085 + result = Keyword(keyword, 1,
1.1086 + name=keyword.name,
1.1087 + expr=self.dispatch(keyword.expr)
1.1088 + )
1.1089 + return result
1.1090 +
1.1091 + def visitLambda(self, lambda_):
1.1092 +
1.1093 + # Make a subprogram for the function and record it outside the main
1.1094 + # tree.
1.1095 +
1.1096 + subprogram = Subprogram(lambda_, name=None, module=self.module, internal=0, returns_value=1, star=None, dstar=None, original_def=lambda_)
1.1097 +
1.1098 + # Make nice annotations for the viewer.
1.1099 +
1.1100 + lambda_._subprogram = subprogram
1.1101 +
1.1102 + # Process the lambda contents.
1.1103 +
1.1104 + self.current_subprograms.append(subprogram)
1.1105 + subprogram.code = [ReturnFromFunction(expr=self.dispatch(lambda_.code))]
1.1106 + self.current_subprograms.pop()
1.1107 + self._visitFunction(lambda_, subprogram)
1.1108 +
1.1109 + # Get the subprogram reference to the lambda.
1.1110 +
1.1111 + return LoadRef(lambda_, 1, ref=subprogram)
1.1112 +
1.1113 + def visitList(self, list):
1.1114 +
1.1115 + # Make a subprogram for the list construction and record it outside the
1.1116 + # main tree.
1.1117 +
1.1118 + subprogram = Subprogram(list, name=None, module=self.module, internal=0, returns_value=1, star=None, dstar=None, original_def=list)
1.1119 + self.current_subprograms.append(subprogram)
1.1120 +
1.1121 + # Make nice annotations for the viewer.
1.1122 +
1.1123 + list._subprogram = subprogram
1.1124 +
1.1125 + subprogram.code=[
1.1126 + StoreTemp(
1.1127 + expr=InvokeFunction(
1.1128 + list,
1.1129 + expr=LoadName(
1.1130 + name="list"
1.1131 + ),
1.1132 + args=[],
1.1133 + star=None,
1.1134 + dstar=None
1.1135 + )
1.1136 + )
1.1137 + ]
1.1138 +
1.1139 + for node in list.nodes:
1.1140 + subprogram.code.append(
1.1141 + InvokeFunction(
1.1142 + list,
1.1143 + expr=LoadAttr(
1.1144 + expr=LoadTemp(),
1.1145 + name="append"
1.1146 + ),
1.1147 + args=[self.dispatch(node)],
1.1148 + star=None,
1.1149 + dstar=None
1.1150 + )
1.1151 + )
1.1152 +
1.1153 + subprogram.code.append(
1.1154 + ReturnFromBlock(
1.1155 + expr=LoadTemp(release=1)
1.1156 + )
1.1157 + )
1.1158 +
1.1159 + self.current_subprograms.pop()
1.1160 + self.subprograms.append(subprogram); self.subnames[subprogram.full_name()] = subprogram
1.1161 +
1.1162 + # Make an invocation of the subprogram.
1.1163 +
1.1164 + result = InvokeRef(list, 1,
1.1165 + produces_result=1,
1.1166 + ref=subprogram
1.1167 + )
1.1168 + return result
1.1169 +
1.1170 + def visitListComp(self, listcomp):
1.1171 +
1.1172 + # Make a subprogram for the list comprehension and record it outside the
1.1173 + # main tree.
1.1174 +
1.1175 + subprogram = Subprogram(listcomp, name=None, module=self.module, internal=0, returns_value=1, star=None, dstar=None, original_def=listcomp)
1.1176 + self.current_subprograms.append(subprogram)
1.1177 +
1.1178 + # Make nice annotations for the viewer.
1.1179 +
1.1180 + listcomp._subprogram = subprogram
1.1181 +
1.1182 + # Add a temporary variable.
1.1183 + # Produce for loops within the subprogram.
1.1184 + # Return the result.
1.1185 +
1.1186 + subprogram.code = [
1.1187 + StoreTemp(
1.1188 + index="listcomp",
1.1189 + expr=InvokeFunction(
1.1190 + expr=LoadName(name="list"),
1.1191 + args=[],
1.1192 + star=None,
1.1193 + dstar=None
1.1194 + )
1.1195 + )
1.1196 + ] + self._visitListCompFor(listcomp, listcomp.quals) + [
1.1197 + ReturnFromBlock(
1.1198 + expr=LoadTemp(
1.1199 + index="listcomp",
1.1200 + release=1
1.1201 + )
1.1202 + )
1.1203 + ]
1.1204 +
1.1205 + self.current_subprograms.pop()
1.1206 + self.subprograms.append(subprogram); self.subnames[subprogram.full_name()] = subprogram
1.1207 +
1.1208 + # Make an invocation of the subprogram.
1.1209 +
1.1210 + result = InvokeRef(listcomp, 1,
1.1211 + produces_result=1,
1.1212 + ref=subprogram
1.1213 + )
1.1214 + return result
1.1215 +
1.1216 + def _visitListCompFor(self, node, quals):
1.1217 + qual = quals[0]
1.1218 + if len(quals) > 1:
1.1219 + body = self._visitListCompFor(node, quals[1:])
1.1220 + if qual.ifs:
1.1221 + body = self._visitListCompIf(node, qual.ifs, body)
1.1222 + elif qual.ifs:
1.1223 + body = self._visitListCompIf(node, qual.ifs)
1.1224 + else:
1.1225 + body = self._visitListCompBody(node)
1.1226 + return [self._visitFor(qual, body)]
1.1227 +
1.1228 + def _visitListCompIf(self, node, ifs, expr=None):
1.1229 + if_ = ifs[0]
1.1230 + if len(ifs) > 1:
1.1231 + body = self._visitListCompIf(node, ifs[1:], expr)
1.1232 + elif expr is None:
1.1233 + body = self._visitListCompBody(node)
1.1234 + else:
1.1235 + body = expr
1.1236 + return [
1.1237 + Conditional(if_, 1,
1.1238 + test=InvokeFunction(
1.1239 + if_,
1.1240 + expr=LoadAttr(
1.1241 + expr=self.dispatch(if_.test),
1.1242 + name="__bool__"
1.1243 + ),
1.1244 + ),
1.1245 + body=body,
1.1246 + else_=[]
1.1247 + )
1.1248 + ]
1.1249 +
1.1250 + def _visitListCompBody(self, node):
1.1251 + return [
1.1252 + InvokeFunction(
1.1253 + expr=LoadAttr(
1.1254 + expr=LoadTemp(index="listcomp"),
1.1255 + name="append"
1.1256 + ),
1.1257 + args=[self.dispatch(node.expr)],
1.1258 + star=None,
1.1259 + dstar=None
1.1260 + )
1.1261 + ]
1.1262 +
1.1263 + def visitMod(self, mod):
1.1264 + return self._visitBinary(mod, "__mod__", "__rmod__")
1.1265 +
1.1266 + def visitMul(self, mul):
1.1267 + return self._visitBinary(mul, "__mul__", "__rmul__")
1.1268 +
1.1269 + def visitName(self, name):
1.1270 + result = LoadName(name, 1, name=name.name)
1.1271 + return result
1.1272 +
1.1273 + def _visitNot(self, expr, not_=None):
1.1274 + invocation = InvokeFunction(
1.1275 + not_, # NOTE: May need a real original node.
1.1276 + expr=LoadAttr(
1.1277 + expr=expr,
1.1278 + name="__bool__"
1.1279 + ),
1.1280 + )
1.1281 + if not_ is not None:
1.1282 + result = Not(not_, 1, expr=invocation)
1.1283 + else:
1.1284 + result = Not(expr=invocation)
1.1285 + return result
1.1286 +
1.1287 + def visitNot(self, not_):
1.1288 + return self._visitNot(self.dispatch(not_.expr), not_)
1.1289 +
1.1290 + def visitOr(self, or_):
1.1291 +
1.1292 + """
1.1293 + Make a subprogram for the 'or_' node and record its contents inside the
1.1294 + subprogram. Convert...
1.1295 +
1.1296 + Or (test)
1.1297 + (test)
1.1298 + ...
1.1299 +
1.1300 + ...to:
1.1301 +
1.1302 + Subprogram -> Conditional (test) -> ReturnFromBlock ...
1.1303 + (else) -> Conditional (test) -> ReturnFromBlock ...
1.1304 + (else) -> ...
1.1305 + """
1.1306 +
1.1307 + subprogram = Subprogram(name=None, module=self.module, internal=1, returns_value=1, params=[], star=None, dstar=None)
1.1308 + self.current_subprograms.append(subprogram)
1.1309 +
1.1310 + # In the subprogram, make instructions which store each operand, test
1.1311 + # for each operand's truth status, and if appropriate return from the
1.1312 + # subprogram with the value of the operand.
1.1313 +
1.1314 + last = or_.nodes[-1]
1.1315 + results = nodes = []
1.1316 +
1.1317 + for node in or_.nodes:
1.1318 + expr = self.dispatch(node)
1.1319 +
1.1320 + # Return from the subprogram where the test is satisfied.
1.1321 +
1.1322 + if node is not last:
1.1323 + nodes.append(StoreTemp(expr=expr))
1.1324 + invocation = InvokeFunction(or_, expr=LoadAttr(expr=LoadTemp(), name="__bool__"))
1.1325 + test = Conditional(test=invocation, body=[ReturnFromBlock(expr=LoadTemp())])
1.1326 + nodes.append(test)
1.1327 +
1.1328 + # Put subsequent operations in the else section of this conditional.
1.1329 +
1.1330 + nodes = test.else_ = [ReleaseTemp()]
1.1331 +
1.1332 + # For the last operation, return the result.
1.1333 +
1.1334 + else:
1.1335 + nodes.append(
1.1336 + ReturnFromBlock(expr=expr)
1.1337 + )
1.1338 +
1.1339 + # Finish the subprogram definition.
1.1340 +
1.1341 + subprogram.code = results
1.1342 +
1.1343 + self.current_subprograms.pop()
1.1344 + self.subprograms.append(subprogram); self.subnames[subprogram.full_name()] = subprogram
1.1345 +
1.1346 + # Make an invocation of the subprogram.
1.1347 +
1.1348 + result = InvokeRef(or_, 1,
1.1349 + produces_result=1,
1.1350 + ref=subprogram
1.1351 + )
1.1352 + return result
1.1353 +
1.1354 + def visitPass(self, pass_):
1.1355 + return Pass(pass_, 1)
1.1356 +
1.1357 + def visitPower(self, power):
1.1358 + return self._visitBinary(power, "__pow__", "__rpow__")
1.1359 +
1.1360 + def visitPrint(self, print_):
1.1361 +
1.1362 + """
1.1363 + Convert...
1.1364 +
1.1365 + Print (dest) ->
1.1366 + (nodes)
1.1367 +
1.1368 + ...to:
1.1369 +
1.1370 + StoreTemp (index) -> "print"
1.1371 + (expr) -> LoadAttr (expr) -> (dest)
1.1372 + (name) -> "write"
1.1373 + InvokeFunction (expr) -> LoadTemp (index) -> "print"
1.1374 + (args) -> [(node)]
1.1375 + ReleaseTemp (index) -> "print"
1.1376 + """
1.1377 +
1.1378 + if print_.dest is not None:
1.1379 + dest = self.dispatch(print_.dest)
1.1380 + else:
1.1381 + dest = self.dispatch(compiler.ast.Name("stdout"))
1.1382 +
1.1383 + result = Assign(print_, 1,
1.1384 + code=[
1.1385 + StoreTemp(
1.1386 + index="print",
1.1387 + expr=LoadAttr(
1.1388 + expr=dest,
1.1389 + name="write"
1.1390 + )
1.1391 + )
1.1392 + ]
1.1393 + )
1.1394 +
1.1395 + for node in print_.nodes:
1.1396 + result.code.append(
1.1397 + InvokeFunction(
1.1398 + print_,
1.1399 + expr=LoadTemp(index="print"),
1.1400 + args=[self.dispatch(node)],
1.1401 + star=None,
1.1402 + dstar=None
1.1403 + )
1.1404 + )
1.1405 +
1.1406 + result.code.append(
1.1407 + ReleaseTemp(index="print")
1.1408 + )
1.1409 +
1.1410 + return result
1.1411 +
1.1412 + def visitPrintnl(self, printnl):
1.1413 + result = self.visitPrint(printnl)
1.1414 + result.code.insert(
1.1415 + len(result.code) - 1,
1.1416 + InvokeFunction(
1.1417 + printnl,
1.1418 + expr=LoadTemp(index="print"),
1.1419 + args=[self.dispatch(compiler.ast.Const("\n"))],
1.1420 + star=None,
1.1421 + dstar=None
1.1422 + )
1.1423 + )
1.1424 + return result
1.1425 +
1.1426 + def visitRaise(self, raise_):
1.1427 + result = Raise(raise_, 1)
1.1428 + if raise_.expr2 is None:
1.1429 + result.expr = self.dispatch(raise_.expr1)
1.1430 + else:
1.1431 + result.expr = InvokeFunction(
1.1432 + raise_,
1.1433 + expr=self.dispatch(raise_.expr1),
1.1434 + args=[self.dispatch(raise_.expr2)],
1.1435 + star=None,
1.1436 + dstar=None
1.1437 + )
1.1438 + if raise_.expr3 is not None:
1.1439 + result.traceback = self.dispatch(raise_.expr3)
1.1440 + else:
1.1441 + result.traceback = None
1.1442 + return result
1.1443 +
1.1444 + def visitReturn(self, return_):
1.1445 + result = ReturnFromFunction(return_, 1,
1.1446 + expr=self.dispatch(return_.value)
1.1447 + )
1.1448 + return result
1.1449 +
1.1450 + def _visitSlice(self, slice, expr, lower, upper, flags, value=None):
1.1451 + if flags == "OP_ASSIGN":
1.1452 + result = InvokeFunction(slice, 1,
1.1453 + expr=LoadAttr(
1.1454 + expr=expr,
1.1455 + name="__setslice__"
1.1456 + ),
1.1457 + star=None,
1.1458 + dstar=None,
1.1459 + args=[lower, upper, value]
1.1460 + )
1.1461 + elif flags == "OP_APPLY":
1.1462 + args = []
1.1463 + result = InvokeFunction(slice, 1,
1.1464 + expr=LoadAttr(
1.1465 + expr=expr,
1.1466 + name="__getslice__"
1.1467 + ),
1.1468 + star=None,
1.1469 + dstar=None,
1.1470 + args=[lower, upper]
1.1471 + )
1.1472 + elif flags == "OP_DELETE":
1.1473 + args = []
1.1474 + result = InvokeFunction(slice, 1,
1.1475 + expr=LoadAttr(
1.1476 + expr=expr,
1.1477 + name="__delslice__"
1.1478 + ),
1.1479 + star=None,
1.1480 + dstar=None,
1.1481 + args=[lower, upper]
1.1482 + )
1.1483 + else:
1.1484 + raise NotImplementedError, flags
1.1485 +
1.1486 + return result
1.1487 +
1.1488 + def visitSlice(self, slice, in_sequence=0):
1.1489 + return self._visitSlice(slice, self.dispatch(slice.expr), self.dispatch_or_none(slice.lower),
1.1490 + self.dispatch_or_none(slice.upper), slice.flags, self._visitAssNameOrAttr(slice, in_sequence))
1.1491 +
1.1492 + def visitSliceobj(self, sliceobj):
1.1493 + return InvokeFunction(sliceobj, 1,
1.1494 + expr=LoadName(name="slice"),
1.1495 + args=self.dispatches(sliceobj.nodes),
1.1496 + star=None,
1.1497 + dstar=None
1.1498 + )
1.1499 +
1.1500 + def visitStmt(self, stmt):
1.1501 + return self.dispatches(stmt.nodes)
1.1502 +
1.1503 + def visitSub(self, sub):
1.1504 + return self._visitBinary(sub, "__sub__", "__rsub__")
1.1505 +
1.1506 + def _visitSubscript(self, subscript, expr, subs, flags, value=None):
1.1507 + if flags == "OP_ASSIGN":
1.1508 + result = InvokeFunction(subscript, 1,
1.1509 + expr=LoadAttr(
1.1510 + expr=expr,
1.1511 + name="__setitem__"
1.1512 + ),
1.1513 + star=None,
1.1514 + dstar=None,
1.1515 + args=[subs, value]
1.1516 + )
1.1517 + elif flags == "OP_APPLY":
1.1518 + args = []
1.1519 + result = InvokeFunction(subscript, 1,
1.1520 + expr=LoadAttr(
1.1521 + expr=expr,
1.1522 + name="__getitem__"
1.1523 + ),
1.1524 + star=None,
1.1525 + dstar=None,
1.1526 + args=[subs]
1.1527 + )
1.1528 + elif flags == "OP_DELETE":
1.1529 + args = []
1.1530 + result = InvokeFunction(subscript, 1,
1.1531 + expr=LoadAttr(
1.1532 + expr=expr,
1.1533 + name="__delitem__"
1.1534 + ),
1.1535 + star=None,
1.1536 + dstar=None,
1.1537 + args=[subs]
1.1538 + )
1.1539 + else:
1.1540 + raise NotImplementedError, flags
1.1541 +
1.1542 + return result
1.1543 +
1.1544 + def _visitSubscriptSubs(self, node, subs):
1.1545 + if len(subs) == 1:
1.1546 + return self.dispatch(subs[0])
1.1547 + else:
1.1548 + return InvokeFunction(node, 1,
1.1549 + expr=LoadName(name="tuple"),
1.1550 + args=self.dispatches(subs),
1.1551 + star=None,
1.1552 + dstar=None
1.1553 + )
1.1554 +
1.1555 + def visitSubscript(self, subscript, in_sequence=0):
1.1556 + return self._visitSubscript(
1.1557 + subscript, self.dispatch(subscript.expr), self._visitSubscriptSubs(subscript, subscript.subs), subscript.flags,
1.1558 + self._visitAssNameOrAttr(subscript, in_sequence)
1.1559 + )
1.1560 +
1.1561 + def visitTryExcept(self, tryexcept):
1.1562 +
1.1563 + """
1.1564 + Make conditionals for each handler associated with a 'tryexcept' node.
1.1565 +
1.1566 + Convert...
1.1567 +
1.1568 + TryExcept (body)
1.1569 + (else)
1.1570 + (spec/assign/stmt)
1.1571 + ...
1.1572 +
1.1573 + ...to:
1.1574 +
1.1575 + Try (body)
1.1576 + (else)
1.1577 + (handler) -> Conditional (test) -> (stmt)
1.1578 + (body) -> ResetExc ...
1.1579 + (else) -> Conditional (test) -> (stmt)
1.1580 + (body) -> ResetExc ...
1.1581 + (else) -> ...
1.1582 + """
1.1583 +
1.1584 + result = Try(tryexcept, 1, body=[], else_=[], finally_=[])
1.1585 +
1.1586 + if tryexcept.body is not None:
1.1587 + result.body = self.dispatch(tryexcept.body)
1.1588 + if tryexcept.else_ is not None:
1.1589 + result.else_ = self.dispatch(tryexcept.else_)
1.1590 +
1.1591 + results = nodes = []
1.1592 + catch_all = 0
1.1593 +
1.1594 + for spec, assign, stmt in tryexcept.handlers:
1.1595 +
1.1596 + # If no specification exists, produce an unconditional block.
1.1597 +
1.1598 + if spec is None:
1.1599 + nodes += self.dispatch(stmt)
1.1600 + catch_all = 1
1.1601 +
1.1602 + # Produce an exception value check.
1.1603 +
1.1604 + else:
1.1605 + test = Conditional(
1.1606 + isolate_test=1,
1.1607 + test=CheckType(expr=LoadExc(), choices=self._visitTryExcept(spec))
1.1608 + )
1.1609 + test.body = []
1.1610 +
1.1611 + if assign is not None:
1.1612 + test.body.append(
1.1613 + Assign(
1.1614 + code=[
1.1615 + StoreTemp(expr=LoadExc()),
1.1616 + self.dispatch(assign),
1.1617 + ReleaseTemp()
1.1618 + ]
1.1619 + )
1.1620 + )
1.1621 +
1.1622 + test.body += [ResetExc()] + self.dispatch(stmt)
1.1623 + nodes.append(test)
1.1624 + nodes = test.else_ = []
1.1625 +
1.1626 + # Add a raise operation to deal with unhandled exceptions.
1.1627 +
1.1628 + if not catch_all:
1.1629 + nodes.append(
1.1630 + Raise(
1.1631 + expr=LoadExc())
1.1632 + )
1.1633 +
1.1634 + result.handler = results
1.1635 + return result
1.1636 +
1.1637 + def _visitTryExcept(self, spec):
1.1638 +
1.1639 + "Return a list of nodes for the given exception type 'spec'."
1.1640 +
1.1641 + if isinstance(spec, compiler.ast.Tuple):
1.1642 + nodes = []
1.1643 + for node in spec.nodes:
1.1644 + nodes += self._visitTryExcept(node)
1.1645 + else:
1.1646 + nodes = [self.dispatch(spec)]
1.1647 + return nodes
1.1648 +
1.1649 + def visitTryFinally(self, tryfinally):
1.1650 + result = Try(tryfinally, 1, body=[], else_=[], finally_=[])
1.1651 + if tryfinally.body is not None:
1.1652 + result.body = self.dispatch(tryfinally.body)
1.1653 + if tryfinally.final is not None:
1.1654 + result.finally_ = self.dispatch(tryfinally.final)
1.1655 + return result
1.1656 +
1.1657 + def visitTuple(self, tuple):
1.1658 +
1.1659 + "Make a MakeTuple node containing the original 'tuple' contents."
1.1660 +
1.1661 + result = MakeTuple(tuple, 1,
1.1662 + nodes=self.dispatches(tuple.nodes)
1.1663 + )
1.1664 + return result
1.1665 +
1.1666 + def visitUnaryAdd(self, unaryadd):
1.1667 + return self._visitUnary(unaryadd, "__pos__")
1.1668 +
1.1669 + def visitUnarySub(self, unarysub):
1.1670 + return self._visitUnary(unarysub, "__neg__")
1.1671 +
1.1672 + def visitWhile(self, while_):
1.1673 +
1.1674 + """
1.1675 + Make a subprogram for the 'while' node and record its contents inside the
1.1676 + subprogram. Convert...
1.1677 +
1.1678 + While (test) -> (body)
1.1679 + (else)
1.1680 +
1.1681 + ...to:
1.1682 +
1.1683 + Subprogram -> Conditional (test) -> (body) -> Invoke subprogram
1.1684 + (else) -> Conditional (test) -> ReturnFromBlock ...
1.1685 + (else) -> ...
1.1686 + """
1.1687 +
1.1688 + subprogram = Subprogram(name=None, module=self.module, internal=1, returns_value=0, params=[], star=None, dstar=None)
1.1689 + self.current_subprograms.append(subprogram)
1.1690 +
1.1691 + # Include a conditional statement in the subprogram.
1.1692 + # Inside the conditional, add a recursive invocation to the subprogram
1.1693 + # if the test condition was satisfied.
1.1694 + # Return within the main section of the loop.
1.1695 +
1.1696 + test = Conditional(
1.1697 + test=InvokeFunction(
1.1698 + while_,
1.1699 + expr=LoadAttr(
1.1700 + expr=self.dispatch(while_.test),
1.1701 + name="__bool__"),
1.1702 + ),
1.1703 + body=self.dispatch(while_.body) + [
1.1704 + InvokeRef(
1.1705 + while_,
1.1706 + ref=subprogram
1.1707 + ),
1.1708 + ReturnFromBlock()
1.1709 + ],
1.1710 + else_=[]
1.1711 + )
1.1712 +
1.1713 + # Provide the else section, if present, along with an explicit return.
1.1714 +
1.1715 + if while_.else_ is not None:
1.1716 + test.else_ = self.dispatch(while_.else_) + [ReturnFromBlock()]
1.1717 +
1.1718 + # Finish the subprogram definition.
1.1719 +
1.1720 + subprogram.code = [test]
1.1721 +
1.1722 + self.current_subprograms.pop()
1.1723 + self.subprograms.append(subprogram); self.subnames[subprogram.full_name()] = subprogram
1.1724 +
1.1725 + # Make an invocation of the subprogram.
1.1726 +
1.1727 + result = InvokeRef(while_, 1, ref=subprogram)
1.1728 +
1.1729 + # Make nice annotations for the viewer.
1.1730 +
1.1731 + while_._test_call = subprogram.code[0].test
1.1732 +
1.1733 + return result
1.1734 +
1.1735 + # NOTE: Not actually supported.
1.1736 + # NOTE: Virtually the same as visitReturn...
1.1737 +
1.1738 + def visitYield(self, yield_):
1.1739 + result = Yield(yield_, 1,
1.1740 + expr=self.dispatch(yield_.value)
1.1741 + )
1.1742 + return result
1.1743 +
1.1744 + # Convenience methods.
1.1745 +
1.1746 + def _visitBinary(self, binary, left_name, right_name):
1.1747 + return self._visitBinaryOp(binary, self.dispatch(binary.left), self.dispatch(binary.right), left_name, right_name)
1.1748 +
1.1749 + def _visitBinaryCompareOp(self, binary, left, right, left_name, right_name):
1.1750 +
1.1751 + """
1.1752 + Emulate the current mechanisms by producing nodes as follows:
1.1753 +
1.1754 + InvokeRef -> Subprogram -> StoreTemp (expr) -> x.__lt__(y)
1.1755 + Conditional (test) -> __is__(LoadTemp, NotImplemented)
1.1756 + (body) -> ReleaseTemp
1.1757 + StoreTemp (expr) -> y.__gt__(x)
1.1758 + Conditional (test) -> __is__(LoadTemp, NotImplemented)
1.1759 + (body) -> ReturnFromBlock (expr) -> False
1.1760 + (else) -> ReturnFromBlock (expr) -> LoadTemp
1.1761 + (else) -> ReturnFromBlock (expr) -> LoadTemp
1.1762 + """
1.1763 +
1.1764 + subprogram = Subprogram(name=None, module=self.module, internal=1, returns_value=1, params=[], star=None, dstar=None)
1.1765 + self.current_subprograms.append(subprogram)
1.1766 +
1.1767 + subprogram.code = [
1.1768 + StoreTemp(
1.1769 + expr=InvokeFunction(
1.1770 + binary,
1.1771 + expr=LoadAttr(expr=left, name=left_name),
1.1772 + args=[right],
1.1773 + star=None,
1.1774 + dstar=None)
1.1775 + ),
1.1776 + Conditional(
1.1777 + isolate_test=1,
1.1778 + test=CheckType(
1.1779 + expr=LoadTemp(), choices=[LoadName(name="NotImplementedType")]
1.1780 + ),
1.1781 + body=[
1.1782 + ReleaseTemp(),
1.1783 + StoreTemp(
1.1784 + expr=InvokeFunction(
1.1785 + binary,
1.1786 + expr=LoadAttr(expr=right, name=right_name),
1.1787 + args=[left],
1.1788 + star=None,
1.1789 + dstar=None)
1.1790 + ),
1.1791 + Conditional(
1.1792 + isolate_test=1,
1.1793 + test=CheckType(
1.1794 + expr=LoadTemp(), choices=[LoadName(name="NotImplementedType")]
1.1795 + ),
1.1796 + body=[
1.1797 + ReturnFromBlock(
1.1798 + expr=LoadName(name="False")
1.1799 + )
1.1800 + ],
1.1801 + else_=[
1.1802 + CheckType(
1.1803 + inverted=1, expr=LoadTemp(), choices=[LoadName(name="NotImplementedType")]
1.1804 + ),
1.1805 + ReturnFromBlock(
1.1806 + expr=LoadTemp()
1.1807 + )
1.1808 + ]
1.1809 + )
1.1810 + ],
1.1811 + else_=[
1.1812 + CheckType(
1.1813 + inverted=1, expr=LoadTemp(), choices=[LoadName(name="NotImplementedType")]
1.1814 + ),
1.1815 + ReturnFromBlock(
1.1816 + expr=LoadTemp()
1.1817 + )
1.1818 + ]
1.1819 + )
1.1820 + ]
1.1821 +
1.1822 + self.current_subprograms.pop()
1.1823 + self.subprograms.append(subprogram); self.subnames[subprogram.full_name()] = subprogram
1.1824 +
1.1825 + result = InvokeRef(
1.1826 + binary,
1.1827 + produces_result=1,
1.1828 + ref=subprogram
1.1829 + )
1.1830 +
1.1831 + # Make nice annotations for the viewer.
1.1832 +
1.1833 + binary._left_call = subprogram.code[0].expr
1.1834 + binary._right_call = subprogram.code[1].body[1].expr
1.1835 +
1.1836 + return result
1.1837 +
1.1838 + def _visitBinaryOp(self, binary, left, right, left_name, right_name):
1.1839 +
1.1840 + """
1.1841 + Emulate the current mechanisms by producing nodes as follows:
1.1842 +
1.1843 + InvokeRef -> Subprogram -> Try (body) -> ReturnFromBlock (expr) -> x.__add__(y)
1.1844 + (else)
1.1845 + (handler) -> Conditional (test) -> CheckType (expr) -> LoadExc
1.1846 + (choices) -> LoadName TypeError
1.1847 + (body) -> ReturnFromBlock (expr) -> y.__radd__(x)
1.1848 + (else)
1.1849 + """
1.1850 +
1.1851 + subprogram = Subprogram(name=None, module=self.module, internal=1, returns_value=1, params=[], star=None, dstar=None)
1.1852 + self.current_subprograms.append(subprogram)
1.1853 +
1.1854 + subprogram.code = [
1.1855 + Try(binary, 1,
1.1856 + body=[
1.1857 + ReturnFromBlock(
1.1858 + expr=InvokeFunction(
1.1859 + binary,
1.1860 + expr=LoadAttr(expr=left, name=left_name),
1.1861 + args=[right],
1.1862 + star=None,
1.1863 + dstar=None)
1.1864 + )
1.1865 + ],
1.1866 + else_=[],
1.1867 + finally_=[],
1.1868 + handler=[
1.1869 + Conditional(
1.1870 + test=CheckType(expr=LoadExc(), choices=[LoadName(name="TypeError")]),
1.1871 + body=[
1.1872 + ReturnFromBlock(
1.1873 + expr=InvokeFunction(
1.1874 + binary,
1.1875 + expr=LoadAttr(expr=right, name=right_name),
1.1876 + args=[left],
1.1877 + star=None,
1.1878 + dstar=None)
1.1879 + )
1.1880 + ],
1.1881 + else_=[]
1.1882 + )
1.1883 + ]
1.1884 + )
1.1885 + ]
1.1886 +
1.1887 + self.current_subprograms.pop()
1.1888 + self.subprograms.append(subprogram); self.subnames[subprogram.full_name()] = subprogram
1.1889 +
1.1890 + result = InvokeRef(
1.1891 + binary,
1.1892 + produces_result=1,
1.1893 + ref=subprogram
1.1894 + )
1.1895 +
1.1896 + # Make nice annotations for the viewer.
1.1897 +
1.1898 + binary._left_call = subprogram.code[0].body[0].expr
1.1899 + binary._right_call = subprogram.code[0].handler[0].body[0].expr
1.1900 +
1.1901 + return result
1.1902 +
1.1903 + def _visitBuiltin(self, builtin, name):
1.1904 + result = InvokeFunction(builtin, 1, expr=LoadName(name=name), args=self.dispatches(builtin.nodes))
1.1905 + return result
1.1906 +
1.1907 + def _visitUnary(self, unary, name):
1.1908 + result = InvokeFunction(unary, 1,
1.1909 + expr=LoadAttr(
1.1910 + expr=self.dispatch(unary.expr),
1.1911 + name=name
1.1912 + )
1.1913 + )
1.1914 +
1.1915 + # Make nice annotations for the viewer.
1.1916 +
1.1917 + unary._unary_call = result
1.1918 +
1.1919 + return result
1.1920 +
1.1921 +# Convenience functions.
1.1922 +
1.1923 +def simplify(filename, builtins=0, module_name=None):
1.1924 +
1.1925 + """
1.1926 + Simplify the module stored in the file with the given 'filename'.
1.1927 +
1.1928 + If the optional 'builtins' parameter is set to a true value (the default
1.1929 + being a false value), then the module is considered as the builtins module.
1.1930 + """
1.1931 +
1.1932 + simplifier = Simplifier(builtins)
1.1933 + module = compiler.parseFile(filename)
1.1934 + compiler.misc.set_filename(filename, module)
1.1935 + if builtins:
1.1936 + name = module_name or "__builtins__"
1.1937 + else:
1.1938 + path, ext = os.path.splitext(filename)
1.1939 + path, name = os.path.split(path)
1.1940 + name = module_name or name
1.1941 + simplified = simplifier.process(module, name)
1.1942 + return simplified
1.1943 +
1.1944 +# vim: tabstop=4 expandtab shiftwidth=4