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