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
2.1 --- a/simplify/annotate.py Sun May 27 18:30:34 2007 +0200
2.2 +++ b/simplify/annotate.py Sun May 27 19:45:48 2007 +0200
2.3 @@ -55,7 +55,7 @@
2.4 """
2.5
2.6 from simplify.simplified import *
2.7 -import simplify, simplify.fixnames # for the load function
2.8 +import simplify.ast, simplify.fixnames # for the load function
2.9 import compiler
2.10 import os
2.11
2.12 @@ -1766,7 +1766,7 @@
2.13 optional 'importer' to provide a means of finding and loading modules.
2.14 """
2.15
2.16 - module = simplify.simplify(name, builtins is None, module_name)
2.17 + module = simplify.ast.simplify(name, builtins is None, module_name)
2.18 simplify.fixnames.fix(module, builtins)
2.19 if not no_annotate:
2.20 annotate(module, builtins, importer)
3.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
3.2 +++ b/simplify/ast.py Sun May 27 19:45:48 2007 +0200
3.3 @@ -0,0 +1,1941 @@
3.4 +#!/usr/bin/env python
3.5 +
3.6 +"""
3.7 +Simplify AST structures for easier type propagation and analysis. The code in
3.8 +this module processes AST trees originating from the compiler module and
3.9 +produces a result tree consisting of instruction-oriented program nodes.
3.10 +
3.11 +Copyright (C) 2006, 2007 Paul Boddie <paul@boddie.org.uk>
3.12 +
3.13 +This software is free software; you can redistribute it and/or
3.14 +modify it under the terms of the GNU General Public License as
3.15 +published by the Free Software Foundation; either version 2 of
3.16 +the License, or (at your option) any later version.
3.17 +
3.18 +This software is distributed in the hope that it will be useful,
3.19 +but WITHOUT ANY WARRANTY; without even the implied warranty of
3.20 +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
3.21 +GNU General Public License for more details.
3.22 +
3.23 +You should have received a copy of the GNU General Public
3.24 +License along with this library; see the file LICENCE.txt
3.25 +If not, write to the Free Software Foundation, Inc.,
3.26 +51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
3.27 +
3.28 +--------
3.29 +
3.30 +To use this module, the easiest approach is to use the simplify function:
3.31 +
3.32 +simplify(filename)
3.33 +
3.34 +The more complicated approach involves first instantiating a Simplifier object:
3.35 +
3.36 +simplifier = Simplifier()
3.37 +
3.38 +Then, applying the simplifier to an AST tree:
3.39 +
3.40 +module = compiler.parseFile(filename)
3.41 +simplifier.process(module)
3.42 +"""
3.43 +
3.44 +from simplify.simplified import *
3.45 +import compiler.ast
3.46 +import os
3.47 +
3.48 +class Simplifier(Visitor):
3.49 +
3.50 + """
3.51 + A simplifying visitor for AST nodes.
3.52 +
3.53 + Covered: Add, And, Assert, AssAttr, AssList, AssName, AssTuple, Assign,
3.54 + AugAssign, Bitand, Break, CallFunc, Class, Compare, Const,
3.55 + Continue, Dict, Discard, Div, FloorDiv, For, From, Function,
3.56 + Getattr, Global, If, Import, Invert, Keyword, Lambda, List,
3.57 + ListComp, ListCompFor, ListCompIf, Mod, Module, Mul, Name, Not, Or,
3.58 + Pass, Power, Print, Printnl, Raise, Return, Slice, Sliceobj, Stmt,
3.59 + Sub, Subscript, TryExcept, TryFinally, Tuple, While, UnaryAdd,
3.60 + UnarySub.
3.61 +
3.62 + Missing: Backquote, Bitor, Bitxor, Decorators, Ellipsis, Exec, LeftShift,
3.63 + RightShift, Yield.
3.64 + """
3.65 +
3.66 + def __init__(self, builtins=0):
3.67 +
3.68 + """
3.69 + Initialise the simplifier with the optional 'builtins' parameter
3.70 + indicating whether the module contains the built-in classes and
3.71 + functions.
3.72 + """
3.73 +
3.74 + Visitor.__init__(self)
3.75 + self.subprograms = [] # Subprograms outside the tree.
3.76 + self.structures = [] # Structures/classes.
3.77 + self.constants = {} # Constants.
3.78 + self.current_subprograms = [] # Current subprograms being processed.
3.79 + self.current_structures = [] # Current structures being processed.
3.80 + self.within_class = 0 # Whether a class is being defined.
3.81 + self.builtins = builtins # Whether the builtins are being processed.
3.82 +
3.83 + # Convenience attributes.
3.84 +
3.85 + self.subnames = {}
3.86 +
3.87 + # For compiler package mechanisms.
3.88 +
3.89 + self.visitor = self
3.90 +
3.91 + def process(self, node, name):
3.92 + result = self.dispatch(node, name)
3.93 + result.simplifier = self
3.94 + return result
3.95 +
3.96 + def dispatch_or_none(self, node, *args):
3.97 + if node is not None:
3.98 + return self.dispatch(node, *args)
3.99 + else:
3.100 + return LoadName(node, name="None")
3.101 +
3.102 + # Top-level transformation.
3.103 +
3.104 + def visitModule(self, module, name=None):
3.105 +
3.106 + """
3.107 + Process the given 'module', producing a Module object which contains the
3.108 + resulting program nodes. If the optional 'name' is provided, the 'name'
3.109 + attribute is set on the Module object using a value other than None.
3.110 + """
3.111 +
3.112 + result = self.module = Module(module, 1, name=name)
3.113 + result.code = self.dispatch(module.node)
3.114 + return result
3.115 +
3.116 + # Node transformations.
3.117 +
3.118 + def visitAdd(self, add):
3.119 + return self._visitBinary(add, "__add__", "__radd__")
3.120 +
3.121 + def visitAnd(self, and_):
3.122 +
3.123 + """
3.124 + Make a subprogram for the 'and_' node and record its contents inside the
3.125 + subprogram. Convert...
3.126 +
3.127 + And (test)
3.128 + (test)
3.129 + ...
3.130 +
3.131 + ...to:
3.132 +
3.133 + Subprogram -> Conditional (test) -> ReturnFromBlock ...
3.134 + (else) -> Conditional (test) -> ReturnFromBlock ...
3.135 + (else) -> ...
3.136 + """
3.137 +
3.138 + subprogram = Subprogram(name=None, module=self.module, internal=1, returns_value=1, params=[], star=None, dstar=None)
3.139 + self.current_subprograms.append(subprogram)
3.140 +
3.141 + # In the subprogram, make instructions which store each operand, test
3.142 + # for each operand's truth status, and if appropriate return from the
3.143 + # subprogram with the value of the operand.
3.144 +
3.145 + last = and_.nodes[-1]
3.146 + results = nodes = []
3.147 +
3.148 + for node in and_.nodes:
3.149 + expr = self.dispatch(node)
3.150 +
3.151 + # Return from the subprogram where the test is not satisfied.
3.152 +
3.153 + if node is not last:
3.154 + nodes += [
3.155 + StoreTemp(expr=expr),
3.156 + Conditional(
3.157 + test=self._visitNot(LoadTemp()),
3.158 + body=[
3.159 + ReturnFromBlock(
3.160 + expr=LoadTemp()
3.161 + )
3.162 + ],
3.163 + else_=[
3.164 + ReleaseTemp()
3.165 + # Subsequent operations go here!
3.166 + ]
3.167 + )
3.168 + ]
3.169 +
3.170 + # Put subsequent operations in the else section of this conditional.
3.171 +
3.172 + nodes = nodes[-1].else_
3.173 +
3.174 + # For the last operation, return the result.
3.175 +
3.176 + else:
3.177 + nodes.append(ReturnFromBlock(expr=expr))
3.178 +
3.179 + # Finish the subprogram definition.
3.180 +
3.181 + subprogram.code = results
3.182 +
3.183 + self.current_subprograms.pop()
3.184 + self.subprograms.append(subprogram); self.subnames[subprogram.full_name()] = subprogram
3.185 +
3.186 + # Make an invocation of the subprogram.
3.187 +
3.188 + result = InvokeRef(and_, 1, produces_result=1, ref=subprogram)
3.189 + return result
3.190 +
3.191 + def visitAssert(self, assert_):
3.192 + if assert_.fail:
3.193 + fail_args = [self.dispatch(assert_.fail)]
3.194 + else:
3.195 + fail_args = []
3.196 +
3.197 + result = Conditional(assert_, 1,
3.198 + test=self.dispatch(assert_.test),
3.199 + body=[],
3.200 + else_=[
3.201 + Raise(assert_,
3.202 + expr=InvokeFunction(assert_,
3.203 + expr=LoadName(name="AssertionError"),
3.204 + args=fail_args,
3.205 + star=None,
3.206 + dstar=None
3.207 + )
3.208 + )
3.209 + ]
3.210 + )
3.211 +
3.212 + # Make nice annotations for the viewer.
3.213 +
3.214 + assert_._raises = result.else_[0].expr
3.215 + return result
3.216 +
3.217 + # Assignments.
3.218 +
3.219 + def visitAssAttr(self, assattr, in_sequence=0):
3.220 + expr = self._visitAssNameOrAttr(assattr, in_sequence)
3.221 + lvalue = self.dispatch(assattr.expr)
3.222 + result = StoreAttr(assattr, 1, name=assattr.attrname, lvalue=lvalue, expr=expr)
3.223 + return result
3.224 +
3.225 + def visitAssign(self, assign):
3.226 + result = Assign(assign, 1)
3.227 + store = StoreTemp(expr=self.dispatch(assign.expr))
3.228 + release = ReleaseTemp()
3.229 + result.code = [store] + self.dispatches(assign.nodes, 0) + [release]
3.230 + return result
3.231 +
3.232 + def visitAssList(self, asslist, in_sequence=0):
3.233 + if not in_sequence:
3.234 + expr = LoadTemp()
3.235 + else:
3.236 + expr = InvokeFunction(asslist, expr=LoadAttr(expr=LoadTemp(), name="next"))
3.237 + result = Assign(asslist, 1)
3.238 + store = StoreTemp(expr=InvokeFunction(asslist, expr=LoadAttr(name="__iter__", expr=expr)))
3.239 + release = ReleaseTemp()
3.240 + result.code = [store] + self.dispatches(asslist.nodes, 1) + [release]
3.241 + return result
3.242 +
3.243 + visitAssTuple = visitAssList
3.244 +
3.245 + def _visitAssNameOrAttr(self, node, in_sequence):
3.246 + if not in_sequence:
3.247 + return LoadTemp()
3.248 + else:
3.249 + return InvokeFunction(node, expr=LoadAttr(expr=LoadTemp(), name="next"))
3.250 +
3.251 + def visitAssName(self, assname, in_sequence=0):
3.252 + expr = self._visitAssNameOrAttr(assname, in_sequence)
3.253 + result = StoreName(assname, 1, name=assname.name, expr=expr)
3.254 + return result
3.255 +
3.256 + augassign_methods = {
3.257 + "+=" : "__iadd__", "-=" : "__isub__", "*=" : "__imul__", "/=" : "__idiv__",
3.258 + "%=" : "__imod__", "**=" : "__ipow__", "<<=" : "__ilshift__", ">>=" : "__irshift__",
3.259 + "&=" : "__iand__", "^=" : "__ixor__", "|=" : "__ior__"
3.260 + }
3.261 +
3.262 + def visitAugAssign(self, augassign):
3.263 +
3.264 + """
3.265 + Convert the augmented assignment...
3.266 +
3.267 + AugAssign (node) -> Name | Getattr | Slice | Subscript
3.268 + (op)
3.269 + (expr)
3.270 +
3.271 + ...to:
3.272 +
3.273 + Assign (code) -> StoreTemp (expr) -> InvokeFunction (expr) -> LoadAttr (expr) -> <name>
3.274 + (name) -> <op>
3.275 + StoreName (name) -> <name>
3.276 + (expr) -> LoadTemp
3.277 + ReleaseTemp
3.278 + """
3.279 +
3.280 + result = Assign(augassign, 1)
3.281 + expr = self.dispatch(augassign.expr)
3.282 +
3.283 + # Simple augmented assignment: name += expr
3.284 +
3.285 + if isinstance(augassign.node, compiler.ast.Name):
3.286 + result.code = [
3.287 + StoreTemp(
3.288 + expr=InvokeFunction( # referenced below
3.289 + augassign,
3.290 + args=[expr],
3.291 + star=None,
3.292 + dstar=None,
3.293 + expr=LoadAttr(
3.294 + expr=self.dispatch(augassign.node),
3.295 + name=self.augassign_methods[augassign.op]
3.296 + )
3.297 + )
3.298 + ),
3.299 + StoreName(
3.300 + expr=LoadTemp(),
3.301 + name=augassign.node.name),
3.302 + ReleaseTemp()
3.303 + ]
3.304 +
3.305 + # Make nice annotations for the viewer.
3.306 +
3.307 + augassign._op_call = result.code[0].expr
3.308 +
3.309 + # Complicated augmented assignment: lvalue.attr += expr
3.310 +
3.311 + elif isinstance(augassign.node, compiler.ast.Getattr):
3.312 +
3.313 + # <lvalue> -> setattr(<lvalue>, getattr(<lvalue>, "attr").__xxx__(expr))
3.314 +
3.315 + result.code = [
3.316 + StoreTemp(
3.317 + index="expr",
3.318 + expr=self.dispatch(augassign.node.expr)
3.319 + ),
3.320 + StoreTemp(
3.321 + expr=InvokeFunction( # referenced below
3.322 + augassign,
3.323 + args=[expr], star=None, dstar=None,
3.324 + expr=LoadAttr(
3.325 + expr=LoadAttr(augassign.node, 1,
3.326 + expr=LoadTemp(index="expr"),
3.327 + name=augassign.node.attrname
3.328 + ),
3.329 + name=self.augassign_methods[augassign.op]
3.330 + )
3.331 + )
3.332 + ),
3.333 + StoreAttr(
3.334 + expr=LoadTemp(),
3.335 + lvalue=LoadTemp(index="expr"),
3.336 + name=augassign.node.attrname
3.337 + ),
3.338 + ReleaseTemp(index="expr"),
3.339 + ReleaseTemp()
3.340 + ]
3.341 +
3.342 + # Make nice annotations for the viewer.
3.343 +
3.344 + augassign._op_call = result.code[1].expr
3.345 +
3.346 + # Complicated augassign using slices: lvalue[lower:upper] += expr
3.347 +
3.348 + elif isinstance(augassign.node, compiler.ast.Slice):
3.349 +
3.350 + # <lvalue>, <lower>, <upper> -> <lvalue>.__setslice__(<lower>, <upper>, <lvalue>.__getslice__(<lower>, <upper>).__xxx__(expr))
3.351 +
3.352 + result.code = [
3.353 + StoreTemp(
3.354 + index="expr",
3.355 + expr=self.dispatch(augassign.node.expr)
3.356 + ),
3.357 + StoreTemp(
3.358 + index="lower",
3.359 + expr=self.dispatch_or_none(augassign.node.lower)
3.360 + ),
3.361 + StoreTemp(
3.362 + index="upper",
3.363 + expr=self.dispatch_or_none(augassign.node.upper)
3.364 + ),
3.365 + StoreTemp(
3.366 + expr=InvokeFunction( # referenced below
3.367 + augassign,
3.368 + args=[expr], star=None, dstar=None,
3.369 + expr=LoadAttr(
3.370 + expr=self._visitSlice(
3.371 + augassign.node,
3.372 + LoadTemp(index="expr"),
3.373 + LoadTemp(index="lower"),
3.374 + LoadTemp(index="upper"),
3.375 + "OP_APPLY"),
3.376 + name=self.augassign_methods[augassign.op]
3.377 + )
3.378 + )
3.379 + ),
3.380 + self._visitSlice(
3.381 + augassign.node,
3.382 + LoadTemp(index="expr"),
3.383 + LoadTemp(index="lower"),
3.384 + LoadTemp(index="upper"),
3.385 + "OP_ASSIGN",
3.386 + LoadTemp()
3.387 + ),
3.388 + ReleaseTemp(index="expr"),
3.389 + ReleaseTemp(index="lower"),
3.390 + ReleaseTemp(index="upper"),
3.391 + ReleaseTemp()
3.392 + ]
3.393 +
3.394 + # Make nice annotations for the viewer.
3.395 +
3.396 + augassign._op_call = result.code[3].expr
3.397 +
3.398 + # Complicated augassign using subscripts: lvalue[subs] += expr
3.399 +
3.400 + elif isinstance(augassign.node, compiler.ast.Subscript):
3.401 +
3.402 + # <lvalue>, <subs> -> <lvalue>.__setitem__(<subs>, <lvalue>.__getitem__(<subs>).__xxx__(expr))
3.403 +
3.404 + result.code = [
3.405 + StoreTemp(index="expr", expr=self.dispatch(augassign.node.expr)),
3.406 + StoreTemp(index="subs", expr=self._visitSubscriptSubs(augassign.node, augassign.node.subs)),
3.407 + StoreTemp(
3.408 + expr=InvokeFunction( # referenced below
3.409 + augassign,
3.410 + args=[expr], star=None, dstar=None,
3.411 + expr=LoadAttr(
3.412 + expr=self._visitSubscript(
3.413 + augassign.node,
3.414 + LoadTemp(index="expr"),
3.415 + LoadTemp(index="subs"),
3.416 + "OP_APPLY"
3.417 + ),
3.418 + name=self.augassign_methods[augassign.op]
3.419 + )
3.420 + )
3.421 + ),
3.422 + self._visitSubscript(
3.423 + augassign.node,
3.424 + LoadTemp(index="expr"),
3.425 + LoadTemp(index="subs"),
3.426 + "OP_ASSIGN",
3.427 + LoadTemp()
3.428 + ),
3.429 + ReleaseTemp(index="expr"),
3.430 + ReleaseTemp(index="subs"),
3.431 + ReleaseTemp()
3.432 + ]
3.433 +
3.434 + # Make nice annotations for the viewer.
3.435 +
3.436 + augassign._op_call = result.code[2].expr
3.437 +
3.438 + else:
3.439 + raise NotImplementedError, augassign.node.__class__
3.440 +
3.441 + return result
3.442 +
3.443 + def visitBitand(self, bitand):
3.444 +
3.445 + """
3.446 + Make a subprogram for the 'bitand' node and record its contents inside the
3.447 + subprogram. Convert...
3.448 +
3.449 + Bitand (node)
3.450 + (node)
3.451 + ...
3.452 +
3.453 + ...to:
3.454 +
3.455 + Subprogram -> Conditional (test) -> ReturnFromBlock ...
3.456 + (else) -> Conditional (test) -> ReturnFromBlock ...
3.457 + (else) -> ...
3.458 + """
3.459 +
3.460 + subprogram = Subprogram(name=None, module=self.module, internal=1, returns_value=1, params=[], star=None, dstar=None)
3.461 + self.current_subprograms.append(subprogram)
3.462 +
3.463 + # In the subprogram, make instructions which store each operand, test
3.464 + # for each operand's truth status, and if appropriate return from the
3.465 + # subprogram with the value of the operand.
3.466 +
3.467 + last = bitand.nodes[-1]
3.468 + results = nodes = []
3.469 +
3.470 + # Start by storing the first operand.
3.471 +
3.472 + nodes += [
3.473 + StoreTemp(expr=self.dispatch(bitand.nodes[0]))
3.474 + ]
3.475 +
3.476 + # For viewing purposes, record invocations on the AST node.
3.477 +
3.478 + bitand._ops = []
3.479 +
3.480 + for node in bitand.nodes[1:]:
3.481 +
3.482 + # Make a new AST-style node to wrap the operation program nodes.
3.483 +
3.484 + new_op = Op("&", node)
3.485 + bitand._ops.append(new_op)
3.486 +
3.487 + # Generate the operation involving the previous result and the
3.488 + # current operand.
3.489 +
3.490 + expr = self._visitBinaryOp(new_op, LoadTemp(), self.dispatch(node), "__and__", "__rand__")
3.491 +
3.492 + # Return from the subprogram where the test is not satisfied.
3.493 +
3.494 + if node is not last:
3.495 + nodes += [
3.496 + StoreTemp(expr=expr),
3.497 + Conditional(
3.498 + test=self._visitNot(LoadTemp()),
3.499 + body=[
3.500 + ReturnFromBlock(
3.501 + expr=LoadTemp()
3.502 + )
3.503 + ],
3.504 + else_=[
3.505 + # Subsequent operations go here!
3.506 + ]
3.507 + )
3.508 + ]
3.509 +
3.510 + # Put subsequent operations in the else section of this conditional.
3.511 +
3.512 + nodes = nodes[-1].else_
3.513 +
3.514 + # For the last operation, return the result.
3.515 +
3.516 + else:
3.517 + nodes.append(ReturnFromBlock(expr=expr))
3.518 +
3.519 + # Finish the subprogram definition.
3.520 +
3.521 + subprogram.code = results
3.522 +
3.523 + self.current_subprograms.pop()
3.524 + self.subprograms.append(subprogram); self.subnames[subprogram.full_name()] = subprogram
3.525 +
3.526 + # Make an invocation of the subprogram.
3.527 +
3.528 + result = InvokeRef(bitand, 1, produces_result=1, ref=subprogram)
3.529 + return result
3.530 +
3.531 + def visitBreak(self, break_):
3.532 + result = ReturnFromBlock(break_, 1)
3.533 + return result
3.534 +
3.535 + def visitCallFunc(self, callfunc):
3.536 + result = InvokeFunction(callfunc, 1, star=None, dstar=None, args=self.dispatches(callfunc.args))
3.537 + if callfunc.star_args is not None:
3.538 + result.star = self.dispatch(callfunc.star_args)
3.539 + if callfunc.dstar_args is not None:
3.540 + result.dstar = self.dispatch(callfunc.dstar_args)
3.541 + result.expr = self.dispatch(callfunc.node)
3.542 + return result
3.543 +
3.544 + def visitClass(self, class_):
3.545 +
3.546 + # Add "object" if the class is not "object" and has an empty bases list.
3.547 +
3.548 + if class_.name != "object" and not class_.bases:
3.549 + bases = [compiler.ast.Name("object")]
3.550 + else:
3.551 + bases = class_.bases
3.552 +
3.553 + structure = Class(name=class_.name, module=self.module, bases=self.dispatches(bases))
3.554 + self.structures.append(structure)
3.555 + within_class = self.within_class
3.556 + self.within_class = 1
3.557 +
3.558 + # Make a subprogram which initialises the class structure.
3.559 +
3.560 + subprogram = Subprogram(name=None, module=self.module, structure=structure, params=[], star=None, dstar=None)
3.561 + self.current_subprograms.append(subprogram)
3.562 + self.current_structures.append(structure) # mostly for name construction
3.563 +
3.564 + # The class is initialised using the code found inside.
3.565 +
3.566 + subprogram.code = self.dispatch(class_.code) + [ReturnFromBlock()]
3.567 +
3.568 + self.within_class = within_class
3.569 + self.current_structures.pop()
3.570 + self.current_subprograms.pop()
3.571 + self.subprograms.append(subprogram); self.subnames[subprogram.full_name()] = subprogram
3.572 +
3.573 + # Make a definition of the class associating it with a name.
3.574 +
3.575 + result = Assign(
3.576 + code=[
3.577 + StoreName(class_, 1, # defines the class
3.578 + name=class_.name,
3.579 + expr=LoadRef(ref=structure)
3.580 + ),
3.581 + InvokeRef(
3.582 + class_,
3.583 + share_locals=0, # override the local sharing usually in InvokeRef
3.584 + ref=subprogram
3.585 + )
3.586 + ]
3.587 + )
3.588 + return result
3.589 +
3.590 + comparison_methods = {
3.591 + "==" : ("__eq__", "__ne__"),
3.592 + "!=" : ("__ne__", "__eq__"),
3.593 + "<" : ("__lt__", "__gt__"),
3.594 + "<=" : ("__le__", "__ge__"),
3.595 + ">=" : ("__ge__", "__le__"),
3.596 + ">" : ("__gt__", "__lt__"),
3.597 + "is" : None,
3.598 + "is not" : None,
3.599 + "in" : None,
3.600 + "not in" : None
3.601 + }
3.602 +
3.603 + def visitCompare(self, compare):
3.604 +
3.605 + """
3.606 + Make a subprogram for the 'compare' node and record its contents inside
3.607 + the subprogram. Convert...
3.608 +
3.609 + Compare (expr)
3.610 + (name/node)
3.611 + ...
3.612 +
3.613 + ...to:
3.614 +
3.615 + InvokeRef -> Subprogram -> Conditional (test) -> (body)
3.616 + (else) -> Conditional (test) -> (body)
3.617 + (else) -> ...
3.618 + """
3.619 +
3.620 + subprogram = Subprogram(name=None, module=self.module, internal=1, returns_value=1, params=[], star=None, dstar=None)
3.621 + self.current_subprograms.append(subprogram)
3.622 +
3.623 + # In the subprogram, make instructions which invoke a method on the
3.624 + # first operand of each operand pair and, if appropriate, return with
3.625 + # the value from that method.
3.626 +
3.627 + last = compare.ops[-1]
3.628 + previous = self.dispatch(compare.expr)
3.629 + results = nodes = []
3.630 +
3.631 + # For viewing purposes, record invocations on the AST node.
3.632 +
3.633 + compare._ops = []
3.634 +
3.635 + for op in compare.ops:
3.636 + op_name, node = op
3.637 +
3.638 + # Make a new AST-style node to wrap the operation program nodes.
3.639 +
3.640 + new_op = Op(op_name, node)
3.641 + compare._ops.append(new_op)
3.642 +
3.643 + expr = self.dispatch(node)
3.644 +
3.645 + # Identify the operation and produce the appropriate method call.
3.646 +
3.647 + method_names = self.comparison_methods[op_name]
3.648 + if method_names:
3.649 + first_name, alternative_name = method_names
3.650 + invocation = self._visitBinaryCompareOp(new_op, previous, expr, first_name, alternative_name)
3.651 +
3.652 + elif op_name == "is":
3.653 + invocation = InvokeFunction(
3.654 + new_op, 1,
3.655 + expr=LoadName(name="__is__"),
3.656 + args=[previous, expr],
3.657 + star=None,
3.658 + dstar=None)
3.659 +
3.660 + elif op_name == "is not":
3.661 + invocation = Not(
3.662 + new_op, 1,
3.663 + expr=InvokeFunction(
3.664 + new_op,
3.665 + expr=LoadName(name="__is__"),
3.666 + args=[previous, expr],
3.667 + star=None,
3.668 + dstar=None)
3.669 + )
3.670 +
3.671 + elif op_name == "in":
3.672 + invocation = InvokeFunction(
3.673 + new_op, 1,
3.674 + expr=LoadAttr(
3.675 + expr=previous,
3.676 + name="__contains__"
3.677 + ),
3.678 + args=[expr],
3.679 + star=None,
3.680 + dstar=None)
3.681 +
3.682 + elif op_name == "not in":
3.683 + invocation = Not(
3.684 + new_op, 1,
3.685 + expr=InvokeFunction(
3.686 + new_op,
3.687 + expr=LoadAttr(
3.688 + expr=previous,
3.689 + name="__contains__"
3.690 + ),
3.691 + args=[expr],
3.692 + star=None,
3.693 + dstar=None)
3.694 + )
3.695 +
3.696 + else:
3.697 + raise NotImplementedError, op_name
3.698 +
3.699 + nodes.append(StoreTemp(expr=invocation))
3.700 +
3.701 + # Return from the subprogram where the test is not satisfied.
3.702 +
3.703 + if op is not last:
3.704 + nodes.append(
3.705 + Conditional(
3.706 + test=self._visitNot(LoadTemp()),
3.707 + body=[
3.708 + ReturnFromBlock(expr=LoadTemp())
3.709 + ],
3.710 + else_=[
3.711 + ReleaseTemp()
3.712 + # Subsequent operations go here!
3.713 + ]
3.714 + )
3.715 + )
3.716 +
3.717 + # Put subsequent operations in the else section of this conditional.
3.718 +
3.719 + nodes = nodes[-1].else_
3.720 +
3.721 + # For the last operation, return the result.
3.722 +
3.723 + else:
3.724 + nodes.append(
3.725 + ReturnFromBlock(expr=LoadTemp(release=1))
3.726 + )
3.727 +
3.728 + previous = expr
3.729 +
3.730 + # Finish the subprogram definition.
3.731 +
3.732 + subprogram.code = results
3.733 +
3.734 + self.current_subprograms.pop()
3.735 + self.subprograms.append(subprogram); self.subnames[subprogram.full_name()] = subprogram
3.736 +
3.737 + # Make an invocation of the subprogram.
3.738 +
3.739 + result = InvokeRef(compare, 1, produces_result=1, ref=subprogram)
3.740 + return result
3.741 +
3.742 + def visitConst(self, const):
3.743 + key = "%s-%s" % (const.value.__class__.__name__, const.value)
3.744 + if not self.constants.has_key(key):
3.745 + self.constants[key] = Constant(name=repr(const.value), value=const.value)
3.746 + result = InvokeFunction(const, 1, expr=LoadName(name=self.constants[key].typename))
3.747 + return result
3.748 +
3.749 + def visitContinue(self, continue_):
3.750 + result = InvokeRef(continue_, 1, ref=self.current_subprograms[-1])
3.751 + return result
3.752 +
3.753 + def visitDict(self, dict):
3.754 + result = InvokeFunction(dict, 1, expr=LoadName(name="dict"))
3.755 + args = []
3.756 + for key, value in dict.items:
3.757 + tuple = InvokeFunction(dict, expr=LoadName(name="tuple"))
3.758 + tuple.set_args([self.dispatch(key), self.dispatch(value)])
3.759 + args.append(tuple)
3.760 + result.set_args(args)
3.761 + return result
3.762 +
3.763 + def visitDiscard(self, discard):
3.764 + return self.dispatch(discard.expr)
3.765 +
3.766 + def visitDiv(self, div):
3.767 + return self._visitBinary(div, "__div__", "__rdiv__")
3.768 +
3.769 + def visitFloorDiv(self, floordiv):
3.770 + return self._visitBinary(floordiv, "__floordiv__", "__rfloordiv__")
3.771 +
3.772 + def visitFor(self, for_):
3.773 +
3.774 + """
3.775 + Make a subprogram for the 'for_' node and record its contents inside the
3.776 + subprogram. Convert...
3.777 +
3.778 + For (assign)
3.779 + (body)
3.780 + (else)
3.781 +
3.782 + ...to:
3.783 +
3.784 + Assign (assign #1)
3.785 + Invoke -> Subprogram -> Try (body) -> (assign #2)
3.786 + (body)
3.787 + Invoke subprogram
3.788 + (handler) -> ...
3.789 + (else) -> ...
3.790 + """
3.791 +
3.792 + return self._visitFor(for_, self.dispatches(for_.body), for_.else_)
3.793 +
3.794 + def _visitFor(self, node, body_stmt, else_=None):
3.795 +
3.796 + subprogram = Subprogram(name=None, module=self.module, internal=1, returns_value=0, params=[])
3.797 + self.current_subprograms.append(subprogram)
3.798 +
3.799 + # Always return from conditional sections/subprograms.
3.800 +
3.801 + if else_ is not None:
3.802 + else_stmt = self.dispatch(else_) + [ReturnFromBlock()]
3.803 + else:
3.804 + else_stmt = [ReturnFromBlock()]
3.805 +
3.806 + # Wrap the assignment in a try...except statement.
3.807 + # Inside the body, add a recursive invocation to the subprogram.
3.808 +
3.809 + subprogram.code = [
3.810 + Try(
3.811 + body=[
3.812 + Assign(
3.813 + code=[
3.814 + StoreTemp(
3.815 + expr=InvokeFunction(node,
3.816 + expr=LoadAttr(
3.817 + expr=LoadTemp(),
3.818 + name="next"
3.819 + )
3.820 + )
3.821 + ),
3.822 + self.dispatch(node.assign),
3.823 + ReleaseTemp()
3.824 + ])
3.825 + ] + body_stmt + [
3.826 + InvokeRef(
3.827 + node,
3.828 + ref=subprogram
3.829 + )
3.830 + ],
3.831 + handler=[
3.832 + Conditional(
3.833 + test=InvokeFunction(
3.834 + node,
3.835 + expr=LoadName(name="isinstance"),
3.836 + args=[LoadExc(), LoadName(name="StopIteration")],
3.837 + star=None,
3.838 + dstar=None),
3.839 + body=else_stmt,
3.840 + else_=[
3.841 + Raise(
3.842 + expr=LoadExc()
3.843 + )
3.844 + ]
3.845 + )
3.846 + ],
3.847 + else_=[],
3.848 + finally_=[]
3.849 + ),
3.850 + ReturnFromBlock()
3.851 + ]
3.852 +
3.853 + # Finish the subprogram definition.
3.854 +
3.855 + self.current_subprograms.pop()
3.856 + self.subprograms.append(subprogram); self.subnames[subprogram.full_name()] = subprogram
3.857 +
3.858 + # Obtain an iterator for the sequence involved.
3.859 + # Then, make an invocation of the subprogram.
3.860 +
3.861 + result = Assign(node, 1,
3.862 + code=[
3.863 + StoreTemp(
3.864 + expr=InvokeFunction(
3.865 + node,
3.866 + expr=LoadAttr(
3.867 + name="__iter__",
3.868 + expr=self.dispatch(node.list)
3.869 + )
3.870 + )
3.871 + ),
3.872 + InvokeRef(node, ref=subprogram),
3.873 + ReleaseTemp()
3.874 + ]
3.875 + )
3.876 +
3.877 + # Make nice annotations for the viewer.
3.878 +
3.879 + node._iter_call = result.code[0].expr
3.880 + node._next_call = subprogram.code[0].body[0].code[0].expr
3.881 +
3.882 + return result
3.883 +
3.884 + def visitFrom(self, from_):
3.885 + result = Assign(from_, 1)
3.886 + code = []
3.887 + _names = []
3.888 + code.append(
3.889 + StoreTemp(
3.890 + expr=Import(name=from_.modname, alias=1)
3.891 + )
3.892 + )
3.893 + from_._modname = code[-1].expr
3.894 + for name, alias in from_.names:
3.895 + code.append(
3.896 + StoreName(
3.897 + expr=LoadAttr(
3.898 + expr=LoadTemp(),
3.899 + name=name),
3.900 + name=(alias or name)
3.901 + )
3.902 + )
3.903 + _names.append(code[-1].expr)
3.904 + code.append(ReleaseTemp())
3.905 + result.code = code
3.906 + from_._names = _names
3.907 + return result
3.908 +
3.909 + def _visitFunction(self, function, subprogram):
3.910 +
3.911 + """
3.912 + A common function generator which transforms the given 'function' node
3.913 + and initialises the given 'subprogram' appropriately.
3.914 + """
3.915 +
3.916 + # Discover star and dstar parameters.
3.917 +
3.918 + if function.flags & 4 != 0:
3.919 + has_star = 1
3.920 + else:
3.921 + has_star = 0
3.922 + if function.flags & 8 != 0:
3.923 + has_dstar = 1
3.924 + else:
3.925 + has_dstar = 0
3.926 +
3.927 + # Discover the number of defaults and positional parameters.
3.928 +
3.929 + ndefaults = len(function.defaults)
3.930 + npositional = len(function.argnames) - has_star - has_dstar
3.931 +
3.932 + # Produce star and dstar parameters with appropriate defaults.
3.933 +
3.934 + if has_star:
3.935 + star = (
3.936 + function.argnames[npositional],
3.937 + self.dispatch(compiler.ast.List([]))
3.938 + )
3.939 + else:
3.940 + star = None
3.941 + if has_dstar:
3.942 + dstar = (
3.943 + function.argnames[npositional + has_star],
3.944 + self.dispatch(compiler.ast.Dict([]))
3.945 + )
3.946 + else:
3.947 + dstar = None
3.948 +
3.949 + params = []
3.950 + for i in range(0, npositional - ndefaults):
3.951 + params.append((function.argnames[i], None))
3.952 +
3.953 + # Process defaults.
3.954 +
3.955 + for i in range(0, ndefaults):
3.956 + default = function.defaults[i]
3.957 + if default is not None:
3.958 + params.append((function.argnames[npositional - ndefaults + i], self.dispatch(default)))
3.959 + else:
3.960 + params.append((function.argnames[npositional - ndefaults + i], None))
3.961 +
3.962 + subprogram.params = params
3.963 + subprogram.star = star
3.964 + subprogram.dstar = dstar
3.965 + self.subprograms.append(subprogram); self.subnames[subprogram.full_name()] = subprogram
3.966 +
3.967 + def visitFunction(self, function):
3.968 +
3.969 + """
3.970 + Make a subprogram for the 'function' and record it outside the main
3.971 + tree. Produce something like the following:
3.972 +
3.973 + StoreName (name)
3.974 + (expr) -> LoadRef (ref) -> Subprogram (params)
3.975 + (star)
3.976 + (dstar)
3.977 + """
3.978 +
3.979 + subprogram = Subprogram(function, name=function.name, module=self.module, structures=self.current_structures[:],
3.980 + internal=0, returns_value=1, star=None, dstar=None, is_method=self.within_class, original_def=function)
3.981 +
3.982 + # Make nice annotations for the viewer.
3.983 +
3.984 + function._subprogram = subprogram
3.985 +
3.986 + self.current_subprograms.append(subprogram)
3.987 + within_class = self.within_class
3.988 + self.within_class = 0
3.989 +
3.990 + subprogram.code = self.dispatch(function.code) + [ReturnFromFunction()]
3.991 +
3.992 + self.within_class = within_class
3.993 + self.current_subprograms.pop()
3.994 + self._visitFunction(function, subprogram)
3.995 +
3.996 + # Make a definition of the function associating it with a name.
3.997 +
3.998 + result = StoreName(function, 1, name=function.name, expr=LoadRef(ref=subprogram))
3.999 + return result
3.1000 +
3.1001 + def visitGetattr(self, getattr):
3.1002 + result = LoadAttr(getattr, 1,
3.1003 + name=getattr.attrname,
3.1004 + expr=self.dispatch(getattr.expr)
3.1005 + )
3.1006 + return result
3.1007 +
3.1008 + def visitGlobal(self, global_):
3.1009 + result = Global(global_, 1,
3.1010 + names=global_.names
3.1011 + )
3.1012 + return result
3.1013 +
3.1014 + def visitIf(self, if_):
3.1015 +
3.1016 + """
3.1017 + Make conditionals for each test from an 'if_' AST node, adding the body
3.1018 + and putting each subsequent test as part of the conditional's else
3.1019 + section.
3.1020 +
3.1021 + Convert...
3.1022 +
3.1023 + If (test/body)
3.1024 + (test/body)
3.1025 + ...
3.1026 + (else/body)
3.1027 +
3.1028 + ...to:
3.1029 +
3.1030 + Conditional (test) -> (body)
3.1031 + (else) -> Conditional (test) -> (body)
3.1032 + (else) -> ...
3.1033 + """
3.1034 +
3.1035 +
3.1036 + results = nodes = []
3.1037 +
3.1038 + # Produce something like...
3.1039 + # expr.__bool__() ? body
3.1040 +
3.1041 + first = 1
3.1042 + for compare, stmt in if_.tests:
3.1043 +
3.1044 + # Set the first as the defining node.
3.1045 +
3.1046 + test = Conditional(if_, first,
3.1047 + test=InvokeFunction(
3.1048 + if_,
3.1049 + expr=LoadAttr(
3.1050 + expr=self.dispatch(compare),
3.1051 + name="__bool__"
3.1052 + ),
3.1053 + )
3.1054 + )
3.1055 + test.body = self.dispatch(stmt)
3.1056 + nodes.append(test)
3.1057 + nodes = test.else_ = []
3.1058 + first = 0
3.1059 +
3.1060 + # Add the compound statement from any else clause to the end.
3.1061 +
3.1062 + if if_.else_ is not None:
3.1063 + nodes += self.dispatch(if_.else_)
3.1064 +
3.1065 + result = results[0]
3.1066 + return result
3.1067 +
3.1068 + def visitImport(self, import_):
3.1069 + result = Assign(import_, 1)
3.1070 + code = []
3.1071 + _names = []
3.1072 + for path, alias in import_.names:
3.1073 + importer = Import(name=path, alias=alias)
3.1074 + top = alias or path.split(".")[0]
3.1075 + code.append(StoreName(expr=importer, name=top))
3.1076 + _names.append(code[-1].expr)
3.1077 + result.code = code
3.1078 + import_._names = _names
3.1079 + return result
3.1080 +
3.1081 + def visitInvert(self, invert):
3.1082 + return self._visitUnary(invert, "__invert__")
3.1083 +
3.1084 + def visitKeyword(self, keyword):
3.1085 + result = Keyword(keyword, 1,
3.1086 + name=keyword.name,
3.1087 + expr=self.dispatch(keyword.expr)
3.1088 + )
3.1089 + return result
3.1090 +
3.1091 + def visitLambda(self, lambda_):
3.1092 +
3.1093 + # Make a subprogram for the function and record it outside the main
3.1094 + # tree.
3.1095 +
3.1096 + subprogram = Subprogram(lambda_, name=None, module=self.module, internal=0, returns_value=1, star=None, dstar=None, original_def=lambda_)
3.1097 +
3.1098 + # Make nice annotations for the viewer.
3.1099 +
3.1100 + lambda_._subprogram = subprogram
3.1101 +
3.1102 + # Process the lambda contents.
3.1103 +
3.1104 + self.current_subprograms.append(subprogram)
3.1105 + subprogram.code = [ReturnFromFunction(expr=self.dispatch(lambda_.code))]
3.1106 + self.current_subprograms.pop()
3.1107 + self._visitFunction(lambda_, subprogram)
3.1108 +
3.1109 + # Get the subprogram reference to the lambda.
3.1110 +
3.1111 + return LoadRef(lambda_, 1, ref=subprogram)
3.1112 +
3.1113 + def visitList(self, list):
3.1114 +
3.1115 + # Make a subprogram for the list construction and record it outside the
3.1116 + # main tree.
3.1117 +
3.1118 + subprogram = Subprogram(list, name=None, module=self.module, internal=0, returns_value=1, star=None, dstar=None, original_def=list)
3.1119 + self.current_subprograms.append(subprogram)
3.1120 +
3.1121 + # Make nice annotations for the viewer.
3.1122 +
3.1123 + list._subprogram = subprogram
3.1124 +
3.1125 + subprogram.code=[
3.1126 + StoreTemp(
3.1127 + expr=InvokeFunction(
3.1128 + list,
3.1129 + expr=LoadName(
3.1130 + name="list"
3.1131 + ),
3.1132 + args=[],
3.1133 + star=None,
3.1134 + dstar=None
3.1135 + )
3.1136 + )
3.1137 + ]
3.1138 +
3.1139 + for node in list.nodes:
3.1140 + subprogram.code.append(
3.1141 + InvokeFunction(
3.1142 + list,
3.1143 + expr=LoadAttr(
3.1144 + expr=LoadTemp(),
3.1145 + name="append"
3.1146 + ),
3.1147 + args=[self.dispatch(node)],
3.1148 + star=None,
3.1149 + dstar=None
3.1150 + )
3.1151 + )
3.1152 +
3.1153 + subprogram.code.append(
3.1154 + ReturnFromBlock(
3.1155 + expr=LoadTemp(release=1)
3.1156 + )
3.1157 + )
3.1158 +
3.1159 + self.current_subprograms.pop()
3.1160 + self.subprograms.append(subprogram); self.subnames[subprogram.full_name()] = subprogram
3.1161 +
3.1162 + # Make an invocation of the subprogram.
3.1163 +
3.1164 + result = InvokeRef(list, 1,
3.1165 + produces_result=1,
3.1166 + ref=subprogram
3.1167 + )
3.1168 + return result
3.1169 +
3.1170 + def visitListComp(self, listcomp):
3.1171 +
3.1172 + # Make a subprogram for the list comprehension and record it outside the
3.1173 + # main tree.
3.1174 +
3.1175 + subprogram = Subprogram(listcomp, name=None, module=self.module, internal=0, returns_value=1, star=None, dstar=None, original_def=listcomp)
3.1176 + self.current_subprograms.append(subprogram)
3.1177 +
3.1178 + # Make nice annotations for the viewer.
3.1179 +
3.1180 + listcomp._subprogram = subprogram
3.1181 +
3.1182 + # Add a temporary variable.
3.1183 + # Produce for loops within the subprogram.
3.1184 + # Return the result.
3.1185 +
3.1186 + subprogram.code = [
3.1187 + StoreTemp(
3.1188 + index="listcomp",
3.1189 + expr=InvokeFunction(
3.1190 + expr=LoadName(name="list"),
3.1191 + args=[],
3.1192 + star=None,
3.1193 + dstar=None
3.1194 + )
3.1195 + )
3.1196 + ] + self._visitListCompFor(listcomp, listcomp.quals) + [
3.1197 + ReturnFromBlock(
3.1198 + expr=LoadTemp(
3.1199 + index="listcomp",
3.1200 + release=1
3.1201 + )
3.1202 + )
3.1203 + ]
3.1204 +
3.1205 + self.current_subprograms.pop()
3.1206 + self.subprograms.append(subprogram); self.subnames[subprogram.full_name()] = subprogram
3.1207 +
3.1208 + # Make an invocation of the subprogram.
3.1209 +
3.1210 + result = InvokeRef(listcomp, 1,
3.1211 + produces_result=1,
3.1212 + ref=subprogram
3.1213 + )
3.1214 + return result
3.1215 +
3.1216 + def _visitListCompFor(self, node, quals):
3.1217 + qual = quals[0]
3.1218 + if len(quals) > 1:
3.1219 + body = self._visitListCompFor(node, quals[1:])
3.1220 + if qual.ifs:
3.1221 + body = self._visitListCompIf(node, qual.ifs, body)
3.1222 + elif qual.ifs:
3.1223 + body = self._visitListCompIf(node, qual.ifs)
3.1224 + else:
3.1225 + body = self._visitListCompBody(node)
3.1226 + return [self._visitFor(qual, body)]
3.1227 +
3.1228 + def _visitListCompIf(self, node, ifs, expr=None):
3.1229 + if_ = ifs[0]
3.1230 + if len(ifs) > 1:
3.1231 + body = self._visitListCompIf(node, ifs[1:], expr)
3.1232 + elif expr is None:
3.1233 + body = self._visitListCompBody(node)
3.1234 + else:
3.1235 + body = expr
3.1236 + return [
3.1237 + Conditional(if_, 1,
3.1238 + test=InvokeFunction(
3.1239 + if_,
3.1240 + expr=LoadAttr(
3.1241 + expr=self.dispatch(if_.test),
3.1242 + name="__bool__"
3.1243 + ),
3.1244 + ),
3.1245 + body=body,
3.1246 + else_=[]
3.1247 + )
3.1248 + ]
3.1249 +
3.1250 + def _visitListCompBody(self, node):
3.1251 + return [
3.1252 + InvokeFunction(
3.1253 + expr=LoadAttr(
3.1254 + expr=LoadTemp(index="listcomp"),
3.1255 + name="append"
3.1256 + ),
3.1257 + args=[self.dispatch(node.expr)],
3.1258 + star=None,
3.1259 + dstar=None
3.1260 + )
3.1261 + ]
3.1262 +
3.1263 + def visitMod(self, mod):
3.1264 + return self._visitBinary(mod, "__mod__", "__rmod__")
3.1265 +
3.1266 + def visitMul(self, mul):
3.1267 + return self._visitBinary(mul, "__mul__", "__rmul__")
3.1268 +
3.1269 + def visitName(self, name):
3.1270 + result = LoadName(name, 1, name=name.name)
3.1271 + return result
3.1272 +
3.1273 + def _visitNot(self, expr, not_=None):
3.1274 + invocation = InvokeFunction(
3.1275 + not_, # NOTE: May need a real original node.
3.1276 + expr=LoadAttr(
3.1277 + expr=expr,
3.1278 + name="__bool__"
3.1279 + ),
3.1280 + )
3.1281 + if not_ is not None:
3.1282 + result = Not(not_, 1, expr=invocation)
3.1283 + else:
3.1284 + result = Not(expr=invocation)
3.1285 + return result
3.1286 +
3.1287 + def visitNot(self, not_):
3.1288 + return self._visitNot(self.dispatch(not_.expr), not_)
3.1289 +
3.1290 + def visitOr(self, or_):
3.1291 +
3.1292 + """
3.1293 + Make a subprogram for the 'or_' node and record its contents inside the
3.1294 + subprogram. Convert...
3.1295 +
3.1296 + Or (test)
3.1297 + (test)
3.1298 + ...
3.1299 +
3.1300 + ...to:
3.1301 +
3.1302 + Subprogram -> Conditional (test) -> ReturnFromBlock ...
3.1303 + (else) -> Conditional (test) -> ReturnFromBlock ...
3.1304 + (else) -> ...
3.1305 + """
3.1306 +
3.1307 + subprogram = Subprogram(name=None, module=self.module, internal=1, returns_value=1, params=[], star=None, dstar=None)
3.1308 + self.current_subprograms.append(subprogram)
3.1309 +
3.1310 + # In the subprogram, make instructions which store each operand, test
3.1311 + # for each operand's truth status, and if appropriate return from the
3.1312 + # subprogram with the value of the operand.
3.1313 +
3.1314 + last = or_.nodes[-1]
3.1315 + results = nodes = []
3.1316 +
3.1317 + for node in or_.nodes:
3.1318 + expr = self.dispatch(node)
3.1319 +
3.1320 + # Return from the subprogram where the test is satisfied.
3.1321 +
3.1322 + if node is not last:
3.1323 + nodes.append(StoreTemp(expr=expr))
3.1324 + invocation = InvokeFunction(or_, expr=LoadAttr(expr=LoadTemp(), name="__bool__"))
3.1325 + test = Conditional(test=invocation, body=[ReturnFromBlock(expr=LoadTemp())])
3.1326 + nodes.append(test)
3.1327 +
3.1328 + # Put subsequent operations in the else section of this conditional.
3.1329 +
3.1330 + nodes = test.else_ = [ReleaseTemp()]
3.1331 +
3.1332 + # For the last operation, return the result.
3.1333 +
3.1334 + else:
3.1335 + nodes.append(
3.1336 + ReturnFromBlock(expr=expr)
3.1337 + )
3.1338 +
3.1339 + # Finish the subprogram definition.
3.1340 +
3.1341 + subprogram.code = results
3.1342 +
3.1343 + self.current_subprograms.pop()
3.1344 + self.subprograms.append(subprogram); self.subnames[subprogram.full_name()] = subprogram
3.1345 +
3.1346 + # Make an invocation of the subprogram.
3.1347 +
3.1348 + result = InvokeRef(or_, 1,
3.1349 + produces_result=1,
3.1350 + ref=subprogram
3.1351 + )
3.1352 + return result
3.1353 +
3.1354 + def visitPass(self, pass_):
3.1355 + return Pass(pass_, 1)
3.1356 +
3.1357 + def visitPower(self, power):
3.1358 + return self._visitBinary(power, "__pow__", "__rpow__")
3.1359 +
3.1360 + def visitPrint(self, print_):
3.1361 +
3.1362 + """
3.1363 + Convert...
3.1364 +
3.1365 + Print (dest) ->
3.1366 + (nodes)
3.1367 +
3.1368 + ...to:
3.1369 +
3.1370 + StoreTemp (index) -> "print"
3.1371 + (expr) -> LoadAttr (expr) -> (dest)
3.1372 + (name) -> "write"
3.1373 + InvokeFunction (expr) -> LoadTemp (index) -> "print"
3.1374 + (args) -> [(node)]
3.1375 + ReleaseTemp (index) -> "print"
3.1376 + """
3.1377 +
3.1378 + if print_.dest is not None:
3.1379 + dest = self.dispatch(print_.dest)
3.1380 + else:
3.1381 + dest = self.dispatch(compiler.ast.Name("stdout"))
3.1382 +
3.1383 + result = Assign(print_, 1,
3.1384 + code=[
3.1385 + StoreTemp(
3.1386 + index="print",
3.1387 + expr=LoadAttr(
3.1388 + expr=dest,
3.1389 + name="write"
3.1390 + )
3.1391 + )
3.1392 + ]
3.1393 + )
3.1394 +
3.1395 + for node in print_.nodes:
3.1396 + result.code.append(
3.1397 + InvokeFunction(
3.1398 + print_,
3.1399 + expr=LoadTemp(index="print"),
3.1400 + args=[self.dispatch(node)],
3.1401 + star=None,
3.1402 + dstar=None
3.1403 + )
3.1404 + )
3.1405 +
3.1406 + result.code.append(
3.1407 + ReleaseTemp(index="print")
3.1408 + )
3.1409 +
3.1410 + return result
3.1411 +
3.1412 + def visitPrintnl(self, printnl):
3.1413 + result = self.visitPrint(printnl)
3.1414 + result.code.insert(
3.1415 + len(result.code) - 1,
3.1416 + InvokeFunction(
3.1417 + printnl,
3.1418 + expr=LoadTemp(index="print"),
3.1419 + args=[self.dispatch(compiler.ast.Const("\n"))],
3.1420 + star=None,
3.1421 + dstar=None
3.1422 + )
3.1423 + )
3.1424 + return result
3.1425 +
3.1426 + def visitRaise(self, raise_):
3.1427 + result = Raise(raise_, 1)
3.1428 + if raise_.expr2 is None:
3.1429 + result.expr = self.dispatch(raise_.expr1)
3.1430 + else:
3.1431 + result.expr = InvokeFunction(
3.1432 + raise_,
3.1433 + expr=self.dispatch(raise_.expr1),
3.1434 + args=[self.dispatch(raise_.expr2)],
3.1435 + star=None,
3.1436 + dstar=None
3.1437 + )
3.1438 + if raise_.expr3 is not None:
3.1439 + result.traceback = self.dispatch(raise_.expr3)
3.1440 + else:
3.1441 + result.traceback = None
3.1442 + return result
3.1443 +
3.1444 + def visitReturn(self, return_):
3.1445 + result = ReturnFromFunction(return_, 1,
3.1446 + expr=self.dispatch(return_.value)
3.1447 + )
3.1448 + return result
3.1449 +
3.1450 + def _visitSlice(self, slice, expr, lower, upper, flags, value=None):
3.1451 + if flags == "OP_ASSIGN":
3.1452 + result = InvokeFunction(slice, 1,
3.1453 + expr=LoadAttr(
3.1454 + expr=expr,
3.1455 + name="__setslice__"
3.1456 + ),
3.1457 + star=None,
3.1458 + dstar=None,
3.1459 + args=[lower, upper, value]
3.1460 + )
3.1461 + elif flags == "OP_APPLY":
3.1462 + args = []
3.1463 + result = InvokeFunction(slice, 1,
3.1464 + expr=LoadAttr(
3.1465 + expr=expr,
3.1466 + name="__getslice__"
3.1467 + ),
3.1468 + star=None,
3.1469 + dstar=None,
3.1470 + args=[lower, upper]
3.1471 + )
3.1472 + elif flags == "OP_DELETE":
3.1473 + args = []
3.1474 + result = InvokeFunction(slice, 1,
3.1475 + expr=LoadAttr(
3.1476 + expr=expr,
3.1477 + name="__delslice__"
3.1478 + ),
3.1479 + star=None,
3.1480 + dstar=None,
3.1481 + args=[lower, upper]
3.1482 + )
3.1483 + else:
3.1484 + raise NotImplementedError, flags
3.1485 +
3.1486 + return result
3.1487 +
3.1488 + def visitSlice(self, slice, in_sequence=0):
3.1489 + return self._visitSlice(slice, self.dispatch(slice.expr), self.dispatch_or_none(slice.lower),
3.1490 + self.dispatch_or_none(slice.upper), slice.flags, self._visitAssNameOrAttr(slice, in_sequence))
3.1491 +
3.1492 + def visitSliceobj(self, sliceobj):
3.1493 + return InvokeFunction(sliceobj, 1,
3.1494 + expr=LoadName(name="slice"),
3.1495 + args=self.dispatches(sliceobj.nodes),
3.1496 + star=None,
3.1497 + dstar=None
3.1498 + )
3.1499 +
3.1500 + def visitStmt(self, stmt):
3.1501 + return self.dispatches(stmt.nodes)
3.1502 +
3.1503 + def visitSub(self, sub):
3.1504 + return self._visitBinary(sub, "__sub__", "__rsub__")
3.1505 +
3.1506 + def _visitSubscript(self, subscript, expr, subs, flags, value=None):
3.1507 + if flags == "OP_ASSIGN":
3.1508 + result = InvokeFunction(subscript, 1,
3.1509 + expr=LoadAttr(
3.1510 + expr=expr,
3.1511 + name="__setitem__"
3.1512 + ),
3.1513 + star=None,
3.1514 + dstar=None,
3.1515 + args=[subs, value]
3.1516 + )
3.1517 + elif flags == "OP_APPLY":
3.1518 + args = []
3.1519 + result = InvokeFunction(subscript, 1,
3.1520 + expr=LoadAttr(
3.1521 + expr=expr,
3.1522 + name="__getitem__"
3.1523 + ),
3.1524 + star=None,
3.1525 + dstar=None,
3.1526 + args=[subs]
3.1527 + )
3.1528 + elif flags == "OP_DELETE":
3.1529 + args = []
3.1530 + result = InvokeFunction(subscript, 1,
3.1531 + expr=LoadAttr(
3.1532 + expr=expr,
3.1533 + name="__delitem__"
3.1534 + ),
3.1535 + star=None,
3.1536 + dstar=None,
3.1537 + args=[subs]
3.1538 + )
3.1539 + else:
3.1540 + raise NotImplementedError, flags
3.1541 +
3.1542 + return result
3.1543 +
3.1544 + def _visitSubscriptSubs(self, node, subs):
3.1545 + if len(subs) == 1:
3.1546 + return self.dispatch(subs[0])
3.1547 + else:
3.1548 + return InvokeFunction(node, 1,
3.1549 + expr=LoadName(name="tuple"),
3.1550 + args=self.dispatches(subs),
3.1551 + star=None,
3.1552 + dstar=None
3.1553 + )
3.1554 +
3.1555 + def visitSubscript(self, subscript, in_sequence=0):
3.1556 + return self._visitSubscript(
3.1557 + subscript, self.dispatch(subscript.expr), self._visitSubscriptSubs(subscript, subscript.subs), subscript.flags,
3.1558 + self._visitAssNameOrAttr(subscript, in_sequence)
3.1559 + )
3.1560 +
3.1561 + def visitTryExcept(self, tryexcept):
3.1562 +
3.1563 + """
3.1564 + Make conditionals for each handler associated with a 'tryexcept' node.
3.1565 +
3.1566 + Convert...
3.1567 +
3.1568 + TryExcept (body)
3.1569 + (else)
3.1570 + (spec/assign/stmt)
3.1571 + ...
3.1572 +
3.1573 + ...to:
3.1574 +
3.1575 + Try (body)
3.1576 + (else)
3.1577 + (handler) -> Conditional (test) -> (stmt)
3.1578 + (body) -> ResetExc ...
3.1579 + (else) -> Conditional (test) -> (stmt)
3.1580 + (body) -> ResetExc ...
3.1581 + (else) -> ...
3.1582 + """
3.1583 +
3.1584 + result = Try(tryexcept, 1, body=[], else_=[], finally_=[])
3.1585 +
3.1586 + if tryexcept.body is not None:
3.1587 + result.body = self.dispatch(tryexcept.body)
3.1588 + if tryexcept.else_ is not None:
3.1589 + result.else_ = self.dispatch(tryexcept.else_)
3.1590 +
3.1591 + results = nodes = []
3.1592 + catch_all = 0
3.1593 +
3.1594 + for spec, assign, stmt in tryexcept.handlers:
3.1595 +
3.1596 + # If no specification exists, produce an unconditional block.
3.1597 +
3.1598 + if spec is None:
3.1599 + nodes += self.dispatch(stmt)
3.1600 + catch_all = 1
3.1601 +
3.1602 + # Produce an exception value check.
3.1603 +
3.1604 + else:
3.1605 + test = Conditional(
3.1606 + isolate_test=1,
3.1607 + test=CheckType(expr=LoadExc(), choices=self._visitTryExcept(spec))
3.1608 + )
3.1609 + test.body = []
3.1610 +
3.1611 + if assign is not None:
3.1612 + test.body.append(
3.1613 + Assign(
3.1614 + code=[
3.1615 + StoreTemp(expr=LoadExc()),
3.1616 + self.dispatch(assign),
3.1617 + ReleaseTemp()
3.1618 + ]
3.1619 + )
3.1620 + )
3.1621 +
3.1622 + test.body += [ResetExc()] + self.dispatch(stmt)
3.1623 + nodes.append(test)
3.1624 + nodes = test.else_ = []
3.1625 +
3.1626 + # Add a raise operation to deal with unhandled exceptions.
3.1627 +
3.1628 + if not catch_all:
3.1629 + nodes.append(
3.1630 + Raise(
3.1631 + expr=LoadExc())
3.1632 + )
3.1633 +
3.1634 + result.handler = results
3.1635 + return result
3.1636 +
3.1637 + def _visitTryExcept(self, spec):
3.1638 +
3.1639 + "Return a list of nodes for the given exception type 'spec'."
3.1640 +
3.1641 + if isinstance(spec, compiler.ast.Tuple):
3.1642 + nodes = []
3.1643 + for node in spec.nodes:
3.1644 + nodes += self._visitTryExcept(node)
3.1645 + else:
3.1646 + nodes = [self.dispatch(spec)]
3.1647 + return nodes
3.1648 +
3.1649 + def visitTryFinally(self, tryfinally):
3.1650 + result = Try(tryfinally, 1, body=[], else_=[], finally_=[])
3.1651 + if tryfinally.body is not None:
3.1652 + result.body = self.dispatch(tryfinally.body)
3.1653 + if tryfinally.final is not None:
3.1654 + result.finally_ = self.dispatch(tryfinally.final)
3.1655 + return result
3.1656 +
3.1657 + def visitTuple(self, tuple):
3.1658 +
3.1659 + "Make a MakeTuple node containing the original 'tuple' contents."
3.1660 +
3.1661 + result = MakeTuple(tuple, 1,
3.1662 + nodes=self.dispatches(tuple.nodes)
3.1663 + )
3.1664 + return result
3.1665 +
3.1666 + def visitUnaryAdd(self, unaryadd):
3.1667 + return self._visitUnary(unaryadd, "__pos__")
3.1668 +
3.1669 + def visitUnarySub(self, unarysub):
3.1670 + return self._visitUnary(unarysub, "__neg__")
3.1671 +
3.1672 + def visitWhile(self, while_):
3.1673 +
3.1674 + """
3.1675 + Make a subprogram for the 'while' node and record its contents inside the
3.1676 + subprogram. Convert...
3.1677 +
3.1678 + While (test) -> (body)
3.1679 + (else)
3.1680 +
3.1681 + ...to:
3.1682 +
3.1683 + Subprogram -> Conditional (test) -> (body) -> Invoke subprogram
3.1684 + (else) -> Conditional (test) -> ReturnFromBlock ...
3.1685 + (else) -> ...
3.1686 + """
3.1687 +
3.1688 + subprogram = Subprogram(name=None, module=self.module, internal=1, returns_value=0, params=[], star=None, dstar=None)
3.1689 + self.current_subprograms.append(subprogram)
3.1690 +
3.1691 + # Include a conditional statement in the subprogram.
3.1692 + # Inside the conditional, add a recursive invocation to the subprogram
3.1693 + # if the test condition was satisfied.
3.1694 + # Return within the main section of the loop.
3.1695 +
3.1696 + test = Conditional(
3.1697 + test=InvokeFunction(
3.1698 + while_,
3.1699 + expr=LoadAttr(
3.1700 + expr=self.dispatch(while_.test),
3.1701 + name="__bool__"),
3.1702 + ),
3.1703 + body=self.dispatch(while_.body) + [
3.1704 + InvokeRef(
3.1705 + while_,
3.1706 + ref=subprogram
3.1707 + ),
3.1708 + ReturnFromBlock()
3.1709 + ],
3.1710 + else_=[]
3.1711 + )
3.1712 +
3.1713 + # Provide the else section, if present, along with an explicit return.
3.1714 +
3.1715 + if while_.else_ is not None:
3.1716 + test.else_ = self.dispatch(while_.else_) + [ReturnFromBlock()]
3.1717 +
3.1718 + # Finish the subprogram definition.
3.1719 +
3.1720 + subprogram.code = [test]
3.1721 +
3.1722 + self.current_subprograms.pop()
3.1723 + self.subprograms.append(subprogram); self.subnames[subprogram.full_name()] = subprogram
3.1724 +
3.1725 + # Make an invocation of the subprogram.
3.1726 +
3.1727 + result = InvokeRef(while_, 1, ref=subprogram)
3.1728 +
3.1729 + # Make nice annotations for the viewer.
3.1730 +
3.1731 + while_._test_call = subprogram.code[0].test
3.1732 +
3.1733 + return result
3.1734 +
3.1735 + # NOTE: Not actually supported.
3.1736 + # NOTE: Virtually the same as visitReturn...
3.1737 +
3.1738 + def visitYield(self, yield_):
3.1739 + result = Yield(yield_, 1,
3.1740 + expr=self.dispatch(yield_.value)
3.1741 + )
3.1742 + return result
3.1743 +
3.1744 + # Convenience methods.
3.1745 +
3.1746 + def _visitBinary(self, binary, left_name, right_name):
3.1747 + return self._visitBinaryOp(binary, self.dispatch(binary.left), self.dispatch(binary.right), left_name, right_name)
3.1748 +
3.1749 + def _visitBinaryCompareOp(self, binary, left, right, left_name, right_name):
3.1750 +
3.1751 + """
3.1752 + Emulate the current mechanisms by producing nodes as follows:
3.1753 +
3.1754 + InvokeRef -> Subprogram -> StoreTemp (expr) -> x.__lt__(y)
3.1755 + Conditional (test) -> __is__(LoadTemp, NotImplemented)
3.1756 + (body) -> ReleaseTemp
3.1757 + StoreTemp (expr) -> y.__gt__(x)
3.1758 + Conditional (test) -> __is__(LoadTemp, NotImplemented)
3.1759 + (body) -> ReturnFromBlock (expr) -> False
3.1760 + (else) -> ReturnFromBlock (expr) -> LoadTemp
3.1761 + (else) -> ReturnFromBlock (expr) -> LoadTemp
3.1762 + """
3.1763 +
3.1764 + subprogram = Subprogram(name=None, module=self.module, internal=1, returns_value=1, params=[], star=None, dstar=None)
3.1765 + self.current_subprograms.append(subprogram)
3.1766 +
3.1767 + subprogram.code = [
3.1768 + StoreTemp(
3.1769 + expr=InvokeFunction(
3.1770 + binary,
3.1771 + expr=LoadAttr(expr=left, name=left_name),
3.1772 + args=[right],
3.1773 + star=None,
3.1774 + dstar=None)
3.1775 + ),
3.1776 + Conditional(
3.1777 + isolate_test=1,
3.1778 + test=CheckType(
3.1779 + expr=LoadTemp(), choices=[LoadName(name="NotImplementedType")]
3.1780 + ),
3.1781 + body=[
3.1782 + ReleaseTemp(),
3.1783 + StoreTemp(
3.1784 + expr=InvokeFunction(
3.1785 + binary,
3.1786 + expr=LoadAttr(expr=right, name=right_name),
3.1787 + args=[left],
3.1788 + star=None,
3.1789 + dstar=None)
3.1790 + ),
3.1791 + Conditional(
3.1792 + isolate_test=1,
3.1793 + test=CheckType(
3.1794 + expr=LoadTemp(), choices=[LoadName(name="NotImplementedType")]
3.1795 + ),
3.1796 + body=[
3.1797 + ReturnFromBlock(
3.1798 + expr=LoadName(name="False")
3.1799 + )
3.1800 + ],
3.1801 + else_=[
3.1802 + CheckType(
3.1803 + inverted=1, expr=LoadTemp(), choices=[LoadName(name="NotImplementedType")]
3.1804 + ),
3.1805 + ReturnFromBlock(
3.1806 + expr=LoadTemp()
3.1807 + )
3.1808 + ]
3.1809 + )
3.1810 + ],
3.1811 + else_=[
3.1812 + CheckType(
3.1813 + inverted=1, expr=LoadTemp(), choices=[LoadName(name="NotImplementedType")]
3.1814 + ),
3.1815 + ReturnFromBlock(
3.1816 + expr=LoadTemp()
3.1817 + )
3.1818 + ]
3.1819 + )
3.1820 + ]
3.1821 +
3.1822 + self.current_subprograms.pop()
3.1823 + self.subprograms.append(subprogram); self.subnames[subprogram.full_name()] = subprogram
3.1824 +
3.1825 + result = InvokeRef(
3.1826 + binary,
3.1827 + produces_result=1,
3.1828 + ref=subprogram
3.1829 + )
3.1830 +
3.1831 + # Make nice annotations for the viewer.
3.1832 +
3.1833 + binary._left_call = subprogram.code[0].expr
3.1834 + binary._right_call = subprogram.code[1].body[1].expr
3.1835 +
3.1836 + return result
3.1837 +
3.1838 + def _visitBinaryOp(self, binary, left, right, left_name, right_name):
3.1839 +
3.1840 + """
3.1841 + Emulate the current mechanisms by producing nodes as follows:
3.1842 +
3.1843 + InvokeRef -> Subprogram -> Try (body) -> ReturnFromBlock (expr) -> x.__add__(y)
3.1844 + (else)
3.1845 + (handler) -> Conditional (test) -> CheckType (expr) -> LoadExc
3.1846 + (choices) -> LoadName TypeError
3.1847 + (body) -> ReturnFromBlock (expr) -> y.__radd__(x)
3.1848 + (else)
3.1849 + """
3.1850 +
3.1851 + subprogram = Subprogram(name=None, module=self.module, internal=1, returns_value=1, params=[], star=None, dstar=None)
3.1852 + self.current_subprograms.append(subprogram)
3.1853 +
3.1854 + subprogram.code = [
3.1855 + Try(binary, 1,
3.1856 + body=[
3.1857 + ReturnFromBlock(
3.1858 + expr=InvokeFunction(
3.1859 + binary,
3.1860 + expr=LoadAttr(expr=left, name=left_name),
3.1861 + args=[right],
3.1862 + star=None,
3.1863 + dstar=None)
3.1864 + )
3.1865 + ],
3.1866 + else_=[],
3.1867 + finally_=[],
3.1868 + handler=[
3.1869 + Conditional(
3.1870 + test=CheckType(expr=LoadExc(), choices=[LoadName(name="TypeError")]),
3.1871 + body=[
3.1872 + ReturnFromBlock(
3.1873 + expr=InvokeFunction(
3.1874 + binary,
3.1875 + expr=LoadAttr(expr=right, name=right_name),
3.1876 + args=[left],
3.1877 + star=None,
3.1878 + dstar=None)
3.1879 + )
3.1880 + ],
3.1881 + else_=[]
3.1882 + )
3.1883 + ]
3.1884 + )
3.1885 + ]
3.1886 +
3.1887 + self.current_subprograms.pop()
3.1888 + self.subprograms.append(subprogram); self.subnames[subprogram.full_name()] = subprogram
3.1889 +
3.1890 + result = InvokeRef(
3.1891 + binary,
3.1892 + produces_result=1,
3.1893 + ref=subprogram
3.1894 + )
3.1895 +
3.1896 + # Make nice annotations for the viewer.
3.1897 +
3.1898 + binary._left_call = subprogram.code[0].body[0].expr
3.1899 + binary._right_call = subprogram.code[0].handler[0].body[0].expr
3.1900 +
3.1901 + return result
3.1902 +
3.1903 + def _visitBuiltin(self, builtin, name):
3.1904 + result = InvokeFunction(builtin, 1, expr=LoadName(name=name), args=self.dispatches(builtin.nodes))
3.1905 + return result
3.1906 +
3.1907 + def _visitUnary(self, unary, name):
3.1908 + result = InvokeFunction(unary, 1,
3.1909 + expr=LoadAttr(
3.1910 + expr=self.dispatch(unary.expr),
3.1911 + name=name
3.1912 + )
3.1913 + )
3.1914 +
3.1915 + # Make nice annotations for the viewer.
3.1916 +
3.1917 + unary._unary_call = result
3.1918 +
3.1919 + return result
3.1920 +
3.1921 +# Convenience functions.
3.1922 +
3.1923 +def simplify(filename, builtins=0, module_name=None):
3.1924 +
3.1925 + """
3.1926 + Simplify the module stored in the file with the given 'filename'.
3.1927 +
3.1928 + If the optional 'builtins' parameter is set to a true value (the default
3.1929 + being a false value), then the module is considered as the builtins module.
3.1930 + """
3.1931 +
3.1932 + simplifier = Simplifier(builtins)
3.1933 + module = compiler.parseFile(filename)
3.1934 + compiler.misc.set_filename(filename, module)
3.1935 + if builtins:
3.1936 + name = module_name or "__builtins__"
3.1937 + else:
3.1938 + path, ext = os.path.splitext(filename)
3.1939 + path, name = os.path.split(path)
3.1940 + name = module_name or name
3.1941 + simplified = simplifier.process(module, name)
3.1942 + return simplified
3.1943 +
3.1944 +# vim: tabstop=4 expandtab shiftwidth=4
4.1 --- a/simplify/simplified/__init__.py Sun May 27 18:30:34 2007 +0200
4.2 +++ b/simplify/simplified/__init__.py Sun May 27 19:45:48 2007 +0200
4.3 @@ -34,4 +34,25 @@
4.4
4.5 libdir = os.path.join(os.path.split(os.path.split(__file__)[0])[0], "lib")
4.6
4.7 +# Configuration setting.
4.8 +
4.9 +Class = SingleInstanceClass
4.10 +#Class = MultipleInstanceClass
4.11 +
4.12 +def set_single_instance_mode():
4.13 + global Class
4.14 + Class = SingleInstanceClass
4.15 +
4.16 +def set_multiple_instance_mode():
4.17 + global Class
4.18 + Class = MultipleInstanceClass
4.19 +
4.20 +def set_selective_multiple_instance_mode():
4.21 + global Class
4.22 + Class = SelectiveMultipleInstanceClass
4.23 +
4.24 +def set_prolific_multiple_instance_mode():
4.25 + global Class
4.26 + Class = ProlificMultipleInstanceClass
4.27 +
4.28 # vim: tabstop=4 expandtab shiftwidth=4
5.1 --- a/simplify/simplified/data.py Sun May 27 18:30:34 2007 +0200
5.2 +++ b/simplify/simplified/data.py Sun May 27 19:45:48 2007 +0200
5.3 @@ -22,6 +22,7 @@
5.4 """
5.5
5.6 from simplify.simplified.utils import Structure, WithName, name
5.7 +from simplify.simplified.program import Subprogram
5.8
5.9 # Special non-program nodes.
5.10
5.11 @@ -213,25 +214,4 @@
5.12 def __hash__(self):
5.13 return id(self.type)
5.14
5.15 -# Configuration setting.
5.16 -
5.17 -Class = SingleInstanceClass
5.18 -#Class = MultipleInstanceClass
5.19 -
5.20 -def set_single_instance_mode():
5.21 - global Class
5.22 - Class = SingleInstanceClass
5.23 -
5.24 -def set_multiple_instance_mode():
5.25 - global Class
5.26 - Class = MultipleInstanceClass
5.27 -
5.28 -def set_selective_multiple_instance_mode():
5.29 - global Class
5.30 - Class = SelectiveMultipleInstanceClass
5.31 -
5.32 -def set_prolific_multiple_instance_mode():
5.33 - global Class
5.34 - Class = ProlificMultipleInstanceClass
5.35 -
5.36 # vim: tabstop=4 expandtab shiftwidth=4
6.1 --- a/simplify/viewer.py Sun May 27 18:30:34 2007 +0200
6.2 +++ b/simplify/viewer.py Sun May 27 19:45:48 2007 +0200
6.3 @@ -125,9 +125,39 @@
6.4 </html>
6.5 """
6.6
6.7 +# Utility classes.
6.8 +
6.9 +class Writer:
6.10 +
6.11 + "A utility class providing useful HTML output methods."
6.12 +
6.13 + def _text(self, text):
6.14 + return text.replace("&", "&").replace("<", "<").replace(">", ">")
6.15 +
6.16 + def _attr(self, attr):
6.17 + return self._text(attr).replace("'", "'").replace('"', """)
6.18 +
6.19 + def _url(self, url):
6.20 + return self._attr(url).replace("#", "%23").replace("-", "%2d")
6.21 +
6.22 +# Summary classes.
6.23 +
6.24 +class Summariser(Writer):
6.25 +
6.26 + def __init__(self, stream):
6.27 + self.stream = stream
6.28 +
6.29 + def process(self, module):
6.30 + self.stream.write(html_header)
6.31 + self._write_classes(module)
6.32 + self.stream.write(html_footer)
6.33 +
6.34 + def _write_classes(self, module):
6.35 + pass
6.36 +
6.37 # Browser classes.
6.38
6.39 -class Browser(ASTVisitor):
6.40 +class Browser(ASTVisitor, Writer):
6.41
6.42 """
6.43 A browsing visitor for AST nodes.
6.44 @@ -872,15 +902,6 @@
6.45
6.46 # Output preparation methods.
6.47
6.48 - def _text(self, text):
6.49 - return text.replace("&", "&").replace("<", "<").replace(">", ">")
6.50 -
6.51 - def _attr(self, attr):
6.52 - return self._text(attr).replace("'", "'").replace('"', """)
6.53 -
6.54 - def _url(self, url):
6.55 - return self._attr(url).replace("#", "%23").replace("-", "%2d")
6.56 -
6.57 def _comment(self, comment):
6.58 self.stream.write("<span class='comment'># %s</span>\n" % comment)
6.59
7.1 --- a/tests/class.py Sun May 27 18:30:34 2007 +0200
7.2 +++ b/tests/class.py Sun May 27 19:45:48 2007 +0200
7.3 @@ -1,6 +1,6 @@
7.4 class A:
7.5 "A class with attribute and method."
7.6 - x = 123
7.7 + x = 123.456
7.8 def m(self, x):
7.9 self.x = x
7.10 def n(self, y=x):