1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
1.2 +++ b/compiler/__init__.py Fri May 18 23:26:30 2012 +0200
1.3 @@ -0,0 +1,31 @@
1.4 +"""Package for parsing and compiling Python source code
1.5 +
1.6 +There are several functions defined at the top level that are imported
1.7 +from modules contained in the package.
1.8 +
1.9 +parse(buf, mode="exec") -> AST
1.10 + Converts a string containing Python source code to an abstract
1.11 + syntax tree (AST). The AST is defined in compiler.ast.
1.12 +
1.13 +parseFile(path) -> AST
1.14 + The same as parse(open(path))
1.15 +
1.16 +walk(ast, visitor, verbose=None)
1.17 + Does a pre-order walk over the ast using the visitor instance.
1.18 + See compiler.visitor for details.
1.19 +
1.20 +compile(source, filename, mode, flags=None, dont_inherit=None)
1.21 + Returns a code object. A replacement for the builtin compile() function.
1.22 +
1.23 +compileFile(filename)
1.24 + Generates a .pyc file by compiling filename.
1.25 +"""
1.26 +
1.27 +import warnings
1.28 +
1.29 +warnings.warn("The compiler package is deprecated and removed in Python 3.x.",
1.30 + DeprecationWarning, stacklevel=2)
1.31 +
1.32 +from compiler.transformer import parse, parseFile
1.33 +from compiler.visitor import walk
1.34 +from compiler.pycodegen import compile, compileFile
2.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
2.2 +++ b/compiler/ast.py Fri May 18 23:26:30 2012 +0200
2.3 @@ -0,0 +1,1419 @@
2.4 +"""Python abstract syntax node definitions
2.5 +
2.6 +This file is automatically generated by Tools/compiler/astgen.py
2.7 +"""
2.8 +from compiler.consts import CO_VARARGS, CO_VARKEYWORDS
2.9 +
2.10 +def flatten(seq):
2.11 + l = []
2.12 + for elt in seq:
2.13 + t = type(elt)
2.14 + if t is tuple or t is list:
2.15 + for elt2 in flatten(elt):
2.16 + l.append(elt2)
2.17 + else:
2.18 + l.append(elt)
2.19 + return l
2.20 +
2.21 +def flatten_nodes(seq):
2.22 + return [n for n in flatten(seq) if isinstance(n, Node)]
2.23 +
2.24 +nodes = {}
2.25 +
2.26 +class Node:
2.27 + """Abstract base class for ast nodes."""
2.28 + def getChildren(self):
2.29 + pass # implemented by subclasses
2.30 + def __iter__(self):
2.31 + for n in self.getChildren():
2.32 + yield n
2.33 + def asList(self): # for backwards compatibility
2.34 + return self.getChildren()
2.35 + def getChildNodes(self):
2.36 + pass # implemented by subclasses
2.37 +
2.38 +class EmptyNode(Node):
2.39 + pass
2.40 +
2.41 +class Expression(Node):
2.42 + # Expression is an artificial node class to support "eval"
2.43 + nodes["expression"] = "Expression"
2.44 + def __init__(self, node):
2.45 + self.node = node
2.46 +
2.47 + def getChildren(self):
2.48 + return self.node,
2.49 +
2.50 + def getChildNodes(self):
2.51 + return self.node,
2.52 +
2.53 + def __repr__(self):
2.54 + return "Expression(%s)" % (repr(self.node))
2.55 +
2.56 +class Add(Node):
2.57 + def __init__(self, leftright, lineno=None):
2.58 + self.left = leftright[0]
2.59 + self.right = leftright[1]
2.60 + self.lineno = lineno
2.61 +
2.62 + def getChildren(self):
2.63 + return self.left, self.right
2.64 +
2.65 + def getChildNodes(self):
2.66 + return self.left, self.right
2.67 +
2.68 + def __repr__(self):
2.69 + return "Add((%s, %s))" % (repr(self.left), repr(self.right))
2.70 +
2.71 +class And(Node):
2.72 + def __init__(self, nodes, lineno=None):
2.73 + self.nodes = nodes
2.74 + self.lineno = lineno
2.75 +
2.76 + def getChildren(self):
2.77 + return tuple(flatten(self.nodes))
2.78 +
2.79 + def getChildNodes(self):
2.80 + nodelist = []
2.81 + nodelist.extend(flatten_nodes(self.nodes))
2.82 + return tuple(nodelist)
2.83 +
2.84 + def __repr__(self):
2.85 + return "And(%s)" % (repr(self.nodes),)
2.86 +
2.87 +class AssAttr(Node):
2.88 + def __init__(self, expr, attrname, flags, lineno=None):
2.89 + self.expr = expr
2.90 + self.attrname = attrname
2.91 + self.flags = flags
2.92 + self.lineno = lineno
2.93 +
2.94 + def getChildren(self):
2.95 + return self.expr, self.attrname, self.flags
2.96 +
2.97 + def getChildNodes(self):
2.98 + return self.expr,
2.99 +
2.100 + def __repr__(self):
2.101 + return "AssAttr(%s, %s, %s)" % (repr(self.expr), repr(self.attrname), repr(self.flags))
2.102 +
2.103 +class AssList(Node):
2.104 + def __init__(self, nodes, lineno=None):
2.105 + self.nodes = nodes
2.106 + self.lineno = lineno
2.107 +
2.108 + def getChildren(self):
2.109 + return tuple(flatten(self.nodes))
2.110 +
2.111 + def getChildNodes(self):
2.112 + nodelist = []
2.113 + nodelist.extend(flatten_nodes(self.nodes))
2.114 + return tuple(nodelist)
2.115 +
2.116 + def __repr__(self):
2.117 + return "AssList(%s)" % (repr(self.nodes),)
2.118 +
2.119 +class AssName(Node):
2.120 + def __init__(self, name, flags, lineno=None):
2.121 + self.name = name
2.122 + self.flags = flags
2.123 + self.lineno = lineno
2.124 +
2.125 + def getChildren(self):
2.126 + return self.name, self.flags
2.127 +
2.128 + def getChildNodes(self):
2.129 + return ()
2.130 +
2.131 + def __repr__(self):
2.132 + return "AssName(%s, %s)" % (repr(self.name), repr(self.flags))
2.133 +
2.134 +class AssTuple(Node):
2.135 + def __init__(self, nodes, lineno=None):
2.136 + self.nodes = nodes
2.137 + self.lineno = lineno
2.138 +
2.139 + def getChildren(self):
2.140 + return tuple(flatten(self.nodes))
2.141 +
2.142 + def getChildNodes(self):
2.143 + nodelist = []
2.144 + nodelist.extend(flatten_nodes(self.nodes))
2.145 + return tuple(nodelist)
2.146 +
2.147 + def __repr__(self):
2.148 + return "AssTuple(%s)" % (repr(self.nodes),)
2.149 +
2.150 +class Assert(Node):
2.151 + def __init__(self, test, fail, lineno=None):
2.152 + self.test = test
2.153 + self.fail = fail
2.154 + self.lineno = lineno
2.155 +
2.156 + def getChildren(self):
2.157 + children = []
2.158 + children.append(self.test)
2.159 + children.append(self.fail)
2.160 + return tuple(children)
2.161 +
2.162 + def getChildNodes(self):
2.163 + nodelist = []
2.164 + nodelist.append(self.test)
2.165 + if self.fail is not None:
2.166 + nodelist.append(self.fail)
2.167 + return tuple(nodelist)
2.168 +
2.169 + def __repr__(self):
2.170 + return "Assert(%s, %s)" % (repr(self.test), repr(self.fail))
2.171 +
2.172 +class Assign(Node):
2.173 + def __init__(self, nodes, expr, lineno=None):
2.174 + self.nodes = nodes
2.175 + self.expr = expr
2.176 + self.lineno = lineno
2.177 +
2.178 + def getChildren(self):
2.179 + children = []
2.180 + children.extend(flatten(self.nodes))
2.181 + children.append(self.expr)
2.182 + return tuple(children)
2.183 +
2.184 + def getChildNodes(self):
2.185 + nodelist = []
2.186 + nodelist.extend(flatten_nodes(self.nodes))
2.187 + nodelist.append(self.expr)
2.188 + return tuple(nodelist)
2.189 +
2.190 + def __repr__(self):
2.191 + return "Assign(%s, %s)" % (repr(self.nodes), repr(self.expr))
2.192 +
2.193 +class AugAssign(Node):
2.194 + def __init__(self, node, op, expr, lineno=None):
2.195 + self.node = node
2.196 + self.op = op
2.197 + self.expr = expr
2.198 + self.lineno = lineno
2.199 +
2.200 + def getChildren(self):
2.201 + return self.node, self.op, self.expr
2.202 +
2.203 + def getChildNodes(self):
2.204 + return self.node, self.expr
2.205 +
2.206 + def __repr__(self):
2.207 + return "AugAssign(%s, %s, %s)" % (repr(self.node), repr(self.op), repr(self.expr))
2.208 +
2.209 +class Backquote(Node):
2.210 + def __init__(self, expr, lineno=None):
2.211 + self.expr = expr
2.212 + self.lineno = lineno
2.213 +
2.214 + def getChildren(self):
2.215 + return self.expr,
2.216 +
2.217 + def getChildNodes(self):
2.218 + return self.expr,
2.219 +
2.220 + def __repr__(self):
2.221 + return "Backquote(%s)" % (repr(self.expr),)
2.222 +
2.223 +class Bitand(Node):
2.224 + def __init__(self, nodes, lineno=None):
2.225 + self.nodes = nodes
2.226 + self.lineno = lineno
2.227 +
2.228 + def getChildren(self):
2.229 + return tuple(flatten(self.nodes))
2.230 +
2.231 + def getChildNodes(self):
2.232 + nodelist = []
2.233 + nodelist.extend(flatten_nodes(self.nodes))
2.234 + return tuple(nodelist)
2.235 +
2.236 + def __repr__(self):
2.237 + return "Bitand(%s)" % (repr(self.nodes),)
2.238 +
2.239 +class Bitor(Node):
2.240 + def __init__(self, nodes, lineno=None):
2.241 + self.nodes = nodes
2.242 + self.lineno = lineno
2.243 +
2.244 + def getChildren(self):
2.245 + return tuple(flatten(self.nodes))
2.246 +
2.247 + def getChildNodes(self):
2.248 + nodelist = []
2.249 + nodelist.extend(flatten_nodes(self.nodes))
2.250 + return tuple(nodelist)
2.251 +
2.252 + def __repr__(self):
2.253 + return "Bitor(%s)" % (repr(self.nodes),)
2.254 +
2.255 +class Bitxor(Node):
2.256 + def __init__(self, nodes, lineno=None):
2.257 + self.nodes = nodes
2.258 + self.lineno = lineno
2.259 +
2.260 + def getChildren(self):
2.261 + return tuple(flatten(self.nodes))
2.262 +
2.263 + def getChildNodes(self):
2.264 + nodelist = []
2.265 + nodelist.extend(flatten_nodes(self.nodes))
2.266 + return tuple(nodelist)
2.267 +
2.268 + def __repr__(self):
2.269 + return "Bitxor(%s)" % (repr(self.nodes),)
2.270 +
2.271 +class Break(Node):
2.272 + def __init__(self, lineno=None):
2.273 + self.lineno = lineno
2.274 +
2.275 + def getChildren(self):
2.276 + return ()
2.277 +
2.278 + def getChildNodes(self):
2.279 + return ()
2.280 +
2.281 + def __repr__(self):
2.282 + return "Break()"
2.283 +
2.284 +class CallFunc(Node):
2.285 + def __init__(self, node, args, star_args = None, dstar_args = None, lineno=None):
2.286 + self.node = node
2.287 + self.args = args
2.288 + self.star_args = star_args
2.289 + self.dstar_args = dstar_args
2.290 + self.lineno = lineno
2.291 +
2.292 + def getChildren(self):
2.293 + children = []
2.294 + children.append(self.node)
2.295 + children.extend(flatten(self.args))
2.296 + children.append(self.star_args)
2.297 + children.append(self.dstar_args)
2.298 + return tuple(children)
2.299 +
2.300 + def getChildNodes(self):
2.301 + nodelist = []
2.302 + nodelist.append(self.node)
2.303 + nodelist.extend(flatten_nodes(self.args))
2.304 + if self.star_args is not None:
2.305 + nodelist.append(self.star_args)
2.306 + if self.dstar_args is not None:
2.307 + nodelist.append(self.dstar_args)
2.308 + return tuple(nodelist)
2.309 +
2.310 + def __repr__(self):
2.311 + return "CallFunc(%s, %s, %s, %s)" % (repr(self.node), repr(self.args), repr(self.star_args), repr(self.dstar_args))
2.312 +
2.313 +class Class(Node):
2.314 + def __init__(self, name, bases, doc, code, decorators = None, lineno=None):
2.315 + self.name = name
2.316 + self.bases = bases
2.317 + self.doc = doc
2.318 + self.code = code
2.319 + self.decorators = decorators
2.320 + self.lineno = lineno
2.321 +
2.322 + def getChildren(self):
2.323 + children = []
2.324 + children.append(self.name)
2.325 + children.extend(flatten(self.bases))
2.326 + children.append(self.doc)
2.327 + children.append(self.code)
2.328 + children.append(self.decorators)
2.329 + return tuple(children)
2.330 +
2.331 + def getChildNodes(self):
2.332 + nodelist = []
2.333 + nodelist.extend(flatten_nodes(self.bases))
2.334 + nodelist.append(self.code)
2.335 + if self.decorators is not None:
2.336 + nodelist.append(self.decorators)
2.337 + return tuple(nodelist)
2.338 +
2.339 + def __repr__(self):
2.340 + return "Class(%s, %s, %s, %s, %s)" % (repr(self.name), repr(self.bases), repr(self.doc), repr(self.code), repr(self.decorators))
2.341 +
2.342 +class Compare(Node):
2.343 + def __init__(self, expr, ops, lineno=None):
2.344 + self.expr = expr
2.345 + self.ops = ops
2.346 + self.lineno = lineno
2.347 +
2.348 + def getChildren(self):
2.349 + children = []
2.350 + children.append(self.expr)
2.351 + children.extend(flatten(self.ops))
2.352 + return tuple(children)
2.353 +
2.354 + def getChildNodes(self):
2.355 + nodelist = []
2.356 + nodelist.append(self.expr)
2.357 + nodelist.extend(flatten_nodes(self.ops))
2.358 + return tuple(nodelist)
2.359 +
2.360 + def __repr__(self):
2.361 + return "Compare(%s, %s)" % (repr(self.expr), repr(self.ops))
2.362 +
2.363 +class Const(Node):
2.364 + def __init__(self, value, lineno=None):
2.365 + self.value = value
2.366 + self.lineno = lineno
2.367 +
2.368 + def getChildren(self):
2.369 + return self.value,
2.370 +
2.371 + def getChildNodes(self):
2.372 + return ()
2.373 +
2.374 + def __repr__(self):
2.375 + return "Const(%s)" % (repr(self.value),)
2.376 +
2.377 +class Continue(Node):
2.378 + def __init__(self, lineno=None):
2.379 + self.lineno = lineno
2.380 +
2.381 + def getChildren(self):
2.382 + return ()
2.383 +
2.384 + def getChildNodes(self):
2.385 + return ()
2.386 +
2.387 + def __repr__(self):
2.388 + return "Continue()"
2.389 +
2.390 +class Decorators(Node):
2.391 + def __init__(self, nodes, lineno=None):
2.392 + self.nodes = nodes
2.393 + self.lineno = lineno
2.394 +
2.395 + def getChildren(self):
2.396 + return tuple(flatten(self.nodes))
2.397 +
2.398 + def getChildNodes(self):
2.399 + nodelist = []
2.400 + nodelist.extend(flatten_nodes(self.nodes))
2.401 + return tuple(nodelist)
2.402 +
2.403 + def __repr__(self):
2.404 + return "Decorators(%s)" % (repr(self.nodes),)
2.405 +
2.406 +class Dict(Node):
2.407 + def __init__(self, items, lineno=None):
2.408 + self.items = items
2.409 + self.lineno = lineno
2.410 +
2.411 + def getChildren(self):
2.412 + return tuple(flatten(self.items))
2.413 +
2.414 + def getChildNodes(self):
2.415 + nodelist = []
2.416 + nodelist.extend(flatten_nodes(self.items))
2.417 + return tuple(nodelist)
2.418 +
2.419 + def __repr__(self):
2.420 + return "Dict(%s)" % (repr(self.items),)
2.421 +
2.422 +class Discard(Node):
2.423 + def __init__(self, expr, lineno=None):
2.424 + self.expr = expr
2.425 + self.lineno = lineno
2.426 +
2.427 + def getChildren(self):
2.428 + return self.expr,
2.429 +
2.430 + def getChildNodes(self):
2.431 + return self.expr,
2.432 +
2.433 + def __repr__(self):
2.434 + return "Discard(%s)" % (repr(self.expr),)
2.435 +
2.436 +class Div(Node):
2.437 + def __init__(self, leftright, lineno=None):
2.438 + self.left = leftright[0]
2.439 + self.right = leftright[1]
2.440 + self.lineno = lineno
2.441 +
2.442 + def getChildren(self):
2.443 + return self.left, self.right
2.444 +
2.445 + def getChildNodes(self):
2.446 + return self.left, self.right
2.447 +
2.448 + def __repr__(self):
2.449 + return "Div((%s, %s))" % (repr(self.left), repr(self.right))
2.450 +
2.451 +class Ellipsis(Node):
2.452 + def __init__(self, lineno=None):
2.453 + self.lineno = lineno
2.454 +
2.455 + def getChildren(self):
2.456 + return ()
2.457 +
2.458 + def getChildNodes(self):
2.459 + return ()
2.460 +
2.461 + def __repr__(self):
2.462 + return "Ellipsis()"
2.463 +
2.464 +class Exec(Node):
2.465 + def __init__(self, expr, locals, globals, lineno=None):
2.466 + self.expr = expr
2.467 + self.locals = locals
2.468 + self.globals = globals
2.469 + self.lineno = lineno
2.470 +
2.471 + def getChildren(self):
2.472 + children = []
2.473 + children.append(self.expr)
2.474 + children.append(self.locals)
2.475 + children.append(self.globals)
2.476 + return tuple(children)
2.477 +
2.478 + def getChildNodes(self):
2.479 + nodelist = []
2.480 + nodelist.append(self.expr)
2.481 + if self.locals is not None:
2.482 + nodelist.append(self.locals)
2.483 + if self.globals is not None:
2.484 + nodelist.append(self.globals)
2.485 + return tuple(nodelist)
2.486 +
2.487 + def __repr__(self):
2.488 + return "Exec(%s, %s, %s)" % (repr(self.expr), repr(self.locals), repr(self.globals))
2.489 +
2.490 +class FloorDiv(Node):
2.491 + def __init__(self, leftright, lineno=None):
2.492 + self.left = leftright[0]
2.493 + self.right = leftright[1]
2.494 + self.lineno = lineno
2.495 +
2.496 + def getChildren(self):
2.497 + return self.left, self.right
2.498 +
2.499 + def getChildNodes(self):
2.500 + return self.left, self.right
2.501 +
2.502 + def __repr__(self):
2.503 + return "FloorDiv((%s, %s))" % (repr(self.left), repr(self.right))
2.504 +
2.505 +class For(Node):
2.506 + def __init__(self, assign, list, body, else_, lineno=None):
2.507 + self.assign = assign
2.508 + self.list = list
2.509 + self.body = body
2.510 + self.else_ = else_
2.511 + self.lineno = lineno
2.512 +
2.513 + def getChildren(self):
2.514 + children = []
2.515 + children.append(self.assign)
2.516 + children.append(self.list)
2.517 + children.append(self.body)
2.518 + children.append(self.else_)
2.519 + return tuple(children)
2.520 +
2.521 + def getChildNodes(self):
2.522 + nodelist = []
2.523 + nodelist.append(self.assign)
2.524 + nodelist.append(self.list)
2.525 + nodelist.append(self.body)
2.526 + if self.else_ is not None:
2.527 + nodelist.append(self.else_)
2.528 + return tuple(nodelist)
2.529 +
2.530 + def __repr__(self):
2.531 + return "For(%s, %s, %s, %s)" % (repr(self.assign), repr(self.list), repr(self.body), repr(self.else_))
2.532 +
2.533 +class From(Node):
2.534 + def __init__(self, modname, names, level, lineno=None):
2.535 + self.modname = modname
2.536 + self.names = names
2.537 + self.level = level
2.538 + self.lineno = lineno
2.539 +
2.540 + def getChildren(self):
2.541 + return self.modname, self.names, self.level
2.542 +
2.543 + def getChildNodes(self):
2.544 + return ()
2.545 +
2.546 + def __repr__(self):
2.547 + return "From(%s, %s, %s)" % (repr(self.modname), repr(self.names), repr(self.level))
2.548 +
2.549 +class Function(Node):
2.550 + def __init__(self, decorators, name, argnames, defaults, flags, doc, code, lineno=None):
2.551 + self.decorators = decorators
2.552 + self.name = name
2.553 + self.argnames = argnames
2.554 + self.defaults = defaults
2.555 + self.flags = flags
2.556 + self.doc = doc
2.557 + self.code = code
2.558 + self.lineno = lineno
2.559 + self.varargs = self.kwargs = None
2.560 + if flags & CO_VARARGS:
2.561 + self.varargs = 1
2.562 + if flags & CO_VARKEYWORDS:
2.563 + self.kwargs = 1
2.564 +
2.565 +
2.566 + def getChildren(self):
2.567 + children = []
2.568 + children.append(self.decorators)
2.569 + children.append(self.name)
2.570 + children.append(self.argnames)
2.571 + children.extend(flatten(self.defaults))
2.572 + children.append(self.flags)
2.573 + children.append(self.doc)
2.574 + children.append(self.code)
2.575 + return tuple(children)
2.576 +
2.577 + def getChildNodes(self):
2.578 + nodelist = []
2.579 + if self.decorators is not None:
2.580 + nodelist.append(self.decorators)
2.581 + nodelist.extend(flatten_nodes(self.defaults))
2.582 + nodelist.append(self.code)
2.583 + return tuple(nodelist)
2.584 +
2.585 + def __repr__(self):
2.586 + return "Function(%s, %s, %s, %s, %s, %s, %s)" % (repr(self.decorators), repr(self.name), repr(self.argnames), repr(self.defaults), repr(self.flags), repr(self.doc), repr(self.code))
2.587 +
2.588 +class GenExpr(Node):
2.589 + def __init__(self, code, lineno=None):
2.590 + self.code = code
2.591 + self.lineno = lineno
2.592 + self.argnames = ['.0']
2.593 + self.varargs = self.kwargs = None
2.594 +
2.595 +
2.596 + def getChildren(self):
2.597 + return self.code,
2.598 +
2.599 + def getChildNodes(self):
2.600 + return self.code,
2.601 +
2.602 + def __repr__(self):
2.603 + return "GenExpr(%s)" % (repr(self.code),)
2.604 +
2.605 +class GenExprFor(Node):
2.606 + def __init__(self, assign, iter, ifs, lineno=None):
2.607 + self.assign = assign
2.608 + self.iter = iter
2.609 + self.ifs = ifs
2.610 + self.lineno = lineno
2.611 + self.is_outmost = False
2.612 +
2.613 + def getChildren(self):
2.614 + children = []
2.615 + children.append(self.assign)
2.616 + children.append(self.iter)
2.617 + children.extend(flatten(self.ifs))
2.618 + return tuple(children)
2.619 +
2.620 + def getChildNodes(self):
2.621 + nodelist = []
2.622 + nodelist.append(self.assign)
2.623 + nodelist.append(self.iter)
2.624 + nodelist.extend(flatten_nodes(self.ifs))
2.625 + return tuple(nodelist)
2.626 +
2.627 + def __repr__(self):
2.628 + return "GenExprFor(%s, %s, %s)" % (repr(self.assign), repr(self.iter), repr(self.ifs))
2.629 +
2.630 +class GenExprIf(Node):
2.631 + def __init__(self, test, lineno=None):
2.632 + self.test = test
2.633 + self.lineno = lineno
2.634 +
2.635 + def getChildren(self):
2.636 + return self.test,
2.637 +
2.638 + def getChildNodes(self):
2.639 + return self.test,
2.640 +
2.641 + def __repr__(self):
2.642 + return "GenExprIf(%s)" % (repr(self.test),)
2.643 +
2.644 +class GenExprInner(Node):
2.645 + def __init__(self, expr, quals, lineno=None):
2.646 + self.expr = expr
2.647 + self.quals = quals
2.648 + self.lineno = lineno
2.649 +
2.650 + def getChildren(self):
2.651 + children = []
2.652 + children.append(self.expr)
2.653 + children.extend(flatten(self.quals))
2.654 + return tuple(children)
2.655 +
2.656 + def getChildNodes(self):
2.657 + nodelist = []
2.658 + nodelist.append(self.expr)
2.659 + nodelist.extend(flatten_nodes(self.quals))
2.660 + return tuple(nodelist)
2.661 +
2.662 + def __repr__(self):
2.663 + return "GenExprInner(%s, %s)" % (repr(self.expr), repr(self.quals))
2.664 +
2.665 +class Getattr(Node):
2.666 + def __init__(self, expr, attrname, lineno=None):
2.667 + self.expr = expr
2.668 + self.attrname = attrname
2.669 + self.lineno = lineno
2.670 +
2.671 + def getChildren(self):
2.672 + return self.expr, self.attrname
2.673 +
2.674 + def getChildNodes(self):
2.675 + return self.expr,
2.676 +
2.677 + def __repr__(self):
2.678 + return "Getattr(%s, %s)" % (repr(self.expr), repr(self.attrname))
2.679 +
2.680 +class Global(Node):
2.681 + def __init__(self, names, lineno=None):
2.682 + self.names = names
2.683 + self.lineno = lineno
2.684 +
2.685 + def getChildren(self):
2.686 + return self.names,
2.687 +
2.688 + def getChildNodes(self):
2.689 + return ()
2.690 +
2.691 + def __repr__(self):
2.692 + return "Global(%s)" % (repr(self.names),)
2.693 +
2.694 +class If(Node):
2.695 + def __init__(self, tests, else_, lineno=None):
2.696 + self.tests = tests
2.697 + self.else_ = else_
2.698 + self.lineno = lineno
2.699 +
2.700 + def getChildren(self):
2.701 + children = []
2.702 + children.extend(flatten(self.tests))
2.703 + children.append(self.else_)
2.704 + return tuple(children)
2.705 +
2.706 + def getChildNodes(self):
2.707 + nodelist = []
2.708 + nodelist.extend(flatten_nodes(self.tests))
2.709 + if self.else_ is not None:
2.710 + nodelist.append(self.else_)
2.711 + return tuple(nodelist)
2.712 +
2.713 + def __repr__(self):
2.714 + return "If(%s, %s)" % (repr(self.tests), repr(self.else_))
2.715 +
2.716 +class IfExp(Node):
2.717 + def __init__(self, test, then, else_, lineno=None):
2.718 + self.test = test
2.719 + self.then = then
2.720 + self.else_ = else_
2.721 + self.lineno = lineno
2.722 +
2.723 + def getChildren(self):
2.724 + return self.test, self.then, self.else_
2.725 +
2.726 + def getChildNodes(self):
2.727 + return self.test, self.then, self.else_
2.728 +
2.729 + def __repr__(self):
2.730 + return "IfExp(%s, %s, %s)" % (repr(self.test), repr(self.then), repr(self.else_))
2.731 +
2.732 +class Import(Node):
2.733 + def __init__(self, names, lineno=None):
2.734 + self.names = names
2.735 + self.lineno = lineno
2.736 +
2.737 + def getChildren(self):
2.738 + return self.names,
2.739 +
2.740 + def getChildNodes(self):
2.741 + return ()
2.742 +
2.743 + def __repr__(self):
2.744 + return "Import(%s)" % (repr(self.names),)
2.745 +
2.746 +class Invert(Node):
2.747 + def __init__(self, expr, lineno=None):
2.748 + self.expr = expr
2.749 + self.lineno = lineno
2.750 +
2.751 + def getChildren(self):
2.752 + return self.expr,
2.753 +
2.754 + def getChildNodes(self):
2.755 + return self.expr,
2.756 +
2.757 + def __repr__(self):
2.758 + return "Invert(%s)" % (repr(self.expr),)
2.759 +
2.760 +class Keyword(Node):
2.761 + def __init__(self, name, expr, lineno=None):
2.762 + self.name = name
2.763 + self.expr = expr
2.764 + self.lineno = lineno
2.765 +
2.766 + def getChildren(self):
2.767 + return self.name, self.expr
2.768 +
2.769 + def getChildNodes(self):
2.770 + return self.expr,
2.771 +
2.772 + def __repr__(self):
2.773 + return "Keyword(%s, %s)" % (repr(self.name), repr(self.expr))
2.774 +
2.775 +class Lambda(Node):
2.776 + def __init__(self, argnames, defaults, flags, code, lineno=None):
2.777 + self.argnames = argnames
2.778 + self.defaults = defaults
2.779 + self.flags = flags
2.780 + self.code = code
2.781 + self.lineno = lineno
2.782 + self.varargs = self.kwargs = None
2.783 + if flags & CO_VARARGS:
2.784 + self.varargs = 1
2.785 + if flags & CO_VARKEYWORDS:
2.786 + self.kwargs = 1
2.787 +
2.788 +
2.789 + def getChildren(self):
2.790 + children = []
2.791 + children.append(self.argnames)
2.792 + children.extend(flatten(self.defaults))
2.793 + children.append(self.flags)
2.794 + children.append(self.code)
2.795 + return tuple(children)
2.796 +
2.797 + def getChildNodes(self):
2.798 + nodelist = []
2.799 + nodelist.extend(flatten_nodes(self.defaults))
2.800 + nodelist.append(self.code)
2.801 + return tuple(nodelist)
2.802 +
2.803 + def __repr__(self):
2.804 + return "Lambda(%s, %s, %s, %s)" % (repr(self.argnames), repr(self.defaults), repr(self.flags), repr(self.code))
2.805 +
2.806 +class LeftShift(Node):
2.807 + def __init__(self, leftright, lineno=None):
2.808 + self.left = leftright[0]
2.809 + self.right = leftright[1]
2.810 + self.lineno = lineno
2.811 +
2.812 + def getChildren(self):
2.813 + return self.left, self.right
2.814 +
2.815 + def getChildNodes(self):
2.816 + return self.left, self.right
2.817 +
2.818 + def __repr__(self):
2.819 + return "LeftShift((%s, %s))" % (repr(self.left), repr(self.right))
2.820 +
2.821 +class List(Node):
2.822 + def __init__(self, nodes, lineno=None):
2.823 + self.nodes = nodes
2.824 + self.lineno = lineno
2.825 +
2.826 + def getChildren(self):
2.827 + return tuple(flatten(self.nodes))
2.828 +
2.829 + def getChildNodes(self):
2.830 + nodelist = []
2.831 + nodelist.extend(flatten_nodes(self.nodes))
2.832 + return tuple(nodelist)
2.833 +
2.834 + def __repr__(self):
2.835 + return "List(%s)" % (repr(self.nodes),)
2.836 +
2.837 +class ListComp(Node):
2.838 + def __init__(self, expr, quals, lineno=None):
2.839 + self.expr = expr
2.840 + self.quals = quals
2.841 + self.lineno = lineno
2.842 +
2.843 + def getChildren(self):
2.844 + children = []
2.845 + children.append(self.expr)
2.846 + children.extend(flatten(self.quals))
2.847 + return tuple(children)
2.848 +
2.849 + def getChildNodes(self):
2.850 + nodelist = []
2.851 + nodelist.append(self.expr)
2.852 + nodelist.extend(flatten_nodes(self.quals))
2.853 + return tuple(nodelist)
2.854 +
2.855 + def __repr__(self):
2.856 + return "ListComp(%s, %s)" % (repr(self.expr), repr(self.quals))
2.857 +
2.858 +class ListCompFor(Node):
2.859 + def __init__(self, assign, list, ifs, lineno=None):
2.860 + self.assign = assign
2.861 + self.list = list
2.862 + self.ifs = ifs
2.863 + self.lineno = lineno
2.864 +
2.865 + def getChildren(self):
2.866 + children = []
2.867 + children.append(self.assign)
2.868 + children.append(self.list)
2.869 + children.extend(flatten(self.ifs))
2.870 + return tuple(children)
2.871 +
2.872 + def getChildNodes(self):
2.873 + nodelist = []
2.874 + nodelist.append(self.assign)
2.875 + nodelist.append(self.list)
2.876 + nodelist.extend(flatten_nodes(self.ifs))
2.877 + return tuple(nodelist)
2.878 +
2.879 + def __repr__(self):
2.880 + return "ListCompFor(%s, %s, %s)" % (repr(self.assign), repr(self.list), repr(self.ifs))
2.881 +
2.882 +class ListCompIf(Node):
2.883 + def __init__(self, test, lineno=None):
2.884 + self.test = test
2.885 + self.lineno = lineno
2.886 +
2.887 + def getChildren(self):
2.888 + return self.test,
2.889 +
2.890 + def getChildNodes(self):
2.891 + return self.test,
2.892 +
2.893 + def __repr__(self):
2.894 + return "ListCompIf(%s)" % (repr(self.test),)
2.895 +
2.896 +class SetComp(Node):
2.897 + def __init__(self, expr, quals, lineno=None):
2.898 + self.expr = expr
2.899 + self.quals = quals
2.900 + self.lineno = lineno
2.901 +
2.902 + def getChildren(self):
2.903 + children = []
2.904 + children.append(self.expr)
2.905 + children.extend(flatten(self.quals))
2.906 + return tuple(children)
2.907 +
2.908 + def getChildNodes(self):
2.909 + nodelist = []
2.910 + nodelist.append(self.expr)
2.911 + nodelist.extend(flatten_nodes(self.quals))
2.912 + return tuple(nodelist)
2.913 +
2.914 + def __repr__(self):
2.915 + return "SetComp(%s, %s)" % (repr(self.expr), repr(self.quals))
2.916 +
2.917 +class DictComp(Node):
2.918 + def __init__(self, key, value, quals, lineno=None):
2.919 + self.key = key
2.920 + self.value = value
2.921 + self.quals = quals
2.922 + self.lineno = lineno
2.923 +
2.924 + def getChildren(self):
2.925 + children = []
2.926 + children.append(self.key)
2.927 + children.append(self.value)
2.928 + children.extend(flatten(self.quals))
2.929 + return tuple(children)
2.930 +
2.931 + def getChildNodes(self):
2.932 + nodelist = []
2.933 + nodelist.append(self.key)
2.934 + nodelist.append(self.value)
2.935 + nodelist.extend(flatten_nodes(self.quals))
2.936 + return tuple(nodelist)
2.937 +
2.938 + def __repr__(self):
2.939 + return "DictComp(%s, %s, %s)" % (repr(self.key), repr(self.value), repr(self.quals))
2.940 +
2.941 +class Mod(Node):
2.942 + def __init__(self, leftright, lineno=None):
2.943 + self.left = leftright[0]
2.944 + self.right = leftright[1]
2.945 + self.lineno = lineno
2.946 +
2.947 + def getChildren(self):
2.948 + return self.left, self.right
2.949 +
2.950 + def getChildNodes(self):
2.951 + return self.left, self.right
2.952 +
2.953 + def __repr__(self):
2.954 + return "Mod((%s, %s))" % (repr(self.left), repr(self.right))
2.955 +
2.956 +class Module(Node):
2.957 + def __init__(self, doc, node, lineno=None):
2.958 + self.doc = doc
2.959 + self.node = node
2.960 + self.lineno = lineno
2.961 +
2.962 + def getChildren(self):
2.963 + return self.doc, self.node
2.964 +
2.965 + def getChildNodes(self):
2.966 + return self.node,
2.967 +
2.968 + def __repr__(self):
2.969 + return "Module(%s, %s)" % (repr(self.doc), repr(self.node))
2.970 +
2.971 +class Mul(Node):
2.972 + def __init__(self, leftright, lineno=None):
2.973 + self.left = leftright[0]
2.974 + self.right = leftright[1]
2.975 + self.lineno = lineno
2.976 +
2.977 + def getChildren(self):
2.978 + return self.left, self.right
2.979 +
2.980 + def getChildNodes(self):
2.981 + return self.left, self.right
2.982 +
2.983 + def __repr__(self):
2.984 + return "Mul((%s, %s))" % (repr(self.left), repr(self.right))
2.985 +
2.986 +class Name(Node):
2.987 + def __init__(self, name, lineno=None):
2.988 + self.name = name
2.989 + self.lineno = lineno
2.990 +
2.991 + def getChildren(self):
2.992 + return self.name,
2.993 +
2.994 + def getChildNodes(self):
2.995 + return ()
2.996 +
2.997 + def __repr__(self):
2.998 + return "Name(%s)" % (repr(self.name),)
2.999 +
2.1000 +class Not(Node):
2.1001 + def __init__(self, expr, lineno=None):
2.1002 + self.expr = expr
2.1003 + self.lineno = lineno
2.1004 +
2.1005 + def getChildren(self):
2.1006 + return self.expr,
2.1007 +
2.1008 + def getChildNodes(self):
2.1009 + return self.expr,
2.1010 +
2.1011 + def __repr__(self):
2.1012 + return "Not(%s)" % (repr(self.expr),)
2.1013 +
2.1014 +class Or(Node):
2.1015 + def __init__(self, nodes, lineno=None):
2.1016 + self.nodes = nodes
2.1017 + self.lineno = lineno
2.1018 +
2.1019 + def getChildren(self):
2.1020 + return tuple(flatten(self.nodes))
2.1021 +
2.1022 + def getChildNodes(self):
2.1023 + nodelist = []
2.1024 + nodelist.extend(flatten_nodes(self.nodes))
2.1025 + return tuple(nodelist)
2.1026 +
2.1027 + def __repr__(self):
2.1028 + return "Or(%s)" % (repr(self.nodes),)
2.1029 +
2.1030 +class Pass(Node):
2.1031 + def __init__(self, lineno=None):
2.1032 + self.lineno = lineno
2.1033 +
2.1034 + def getChildren(self):
2.1035 + return ()
2.1036 +
2.1037 + def getChildNodes(self):
2.1038 + return ()
2.1039 +
2.1040 + def __repr__(self):
2.1041 + return "Pass()"
2.1042 +
2.1043 +class Power(Node):
2.1044 + def __init__(self, leftright, lineno=None):
2.1045 + self.left = leftright[0]
2.1046 + self.right = leftright[1]
2.1047 + self.lineno = lineno
2.1048 +
2.1049 + def getChildren(self):
2.1050 + return self.left, self.right
2.1051 +
2.1052 + def getChildNodes(self):
2.1053 + return self.left, self.right
2.1054 +
2.1055 + def __repr__(self):
2.1056 + return "Power((%s, %s))" % (repr(self.left), repr(self.right))
2.1057 +
2.1058 +class Print(Node):
2.1059 + def __init__(self, nodes, dest, lineno=None):
2.1060 + self.nodes = nodes
2.1061 + self.dest = dest
2.1062 + self.lineno = lineno
2.1063 +
2.1064 + def getChildren(self):
2.1065 + children = []
2.1066 + children.extend(flatten(self.nodes))
2.1067 + children.append(self.dest)
2.1068 + return tuple(children)
2.1069 +
2.1070 + def getChildNodes(self):
2.1071 + nodelist = []
2.1072 + nodelist.extend(flatten_nodes(self.nodes))
2.1073 + if self.dest is not None:
2.1074 + nodelist.append(self.dest)
2.1075 + return tuple(nodelist)
2.1076 +
2.1077 + def __repr__(self):
2.1078 + return "Print(%s, %s)" % (repr(self.nodes), repr(self.dest))
2.1079 +
2.1080 +class Printnl(Node):
2.1081 + def __init__(self, nodes, dest, lineno=None):
2.1082 + self.nodes = nodes
2.1083 + self.dest = dest
2.1084 + self.lineno = lineno
2.1085 +
2.1086 + def getChildren(self):
2.1087 + children = []
2.1088 + children.extend(flatten(self.nodes))
2.1089 + children.append(self.dest)
2.1090 + return tuple(children)
2.1091 +
2.1092 + def getChildNodes(self):
2.1093 + nodelist = []
2.1094 + nodelist.extend(flatten_nodes(self.nodes))
2.1095 + if self.dest is not None:
2.1096 + nodelist.append(self.dest)
2.1097 + return tuple(nodelist)
2.1098 +
2.1099 + def __repr__(self):
2.1100 + return "Printnl(%s, %s)" % (repr(self.nodes), repr(self.dest))
2.1101 +
2.1102 +class Raise(Node):
2.1103 + def __init__(self, expr1, expr2, expr3, lineno=None):
2.1104 + self.expr1 = expr1
2.1105 + self.expr2 = expr2
2.1106 + self.expr3 = expr3
2.1107 + self.lineno = lineno
2.1108 +
2.1109 + def getChildren(self):
2.1110 + children = []
2.1111 + children.append(self.expr1)
2.1112 + children.append(self.expr2)
2.1113 + children.append(self.expr3)
2.1114 + return tuple(children)
2.1115 +
2.1116 + def getChildNodes(self):
2.1117 + nodelist = []
2.1118 + if self.expr1 is not None:
2.1119 + nodelist.append(self.expr1)
2.1120 + if self.expr2 is not None:
2.1121 + nodelist.append(self.expr2)
2.1122 + if self.expr3 is not None:
2.1123 + nodelist.append(self.expr3)
2.1124 + return tuple(nodelist)
2.1125 +
2.1126 + def __repr__(self):
2.1127 + return "Raise(%s, %s, %s)" % (repr(self.expr1), repr(self.expr2), repr(self.expr3))
2.1128 +
2.1129 +class Return(Node):
2.1130 + def __init__(self, value, lineno=None):
2.1131 + self.value = value
2.1132 + self.lineno = lineno
2.1133 +
2.1134 + def getChildren(self):
2.1135 + return self.value,
2.1136 +
2.1137 + def getChildNodes(self):
2.1138 + return self.value,
2.1139 +
2.1140 + def __repr__(self):
2.1141 + return "Return(%s)" % (repr(self.value),)
2.1142 +
2.1143 +class RightShift(Node):
2.1144 + def __init__(self, leftright, lineno=None):
2.1145 + self.left = leftright[0]
2.1146 + self.right = leftright[1]
2.1147 + self.lineno = lineno
2.1148 +
2.1149 + def getChildren(self):
2.1150 + return self.left, self.right
2.1151 +
2.1152 + def getChildNodes(self):
2.1153 + return self.left, self.right
2.1154 +
2.1155 + def __repr__(self):
2.1156 + return "RightShift((%s, %s))" % (repr(self.left), repr(self.right))
2.1157 +
2.1158 +class Set(Node):
2.1159 + def __init__(self, nodes, lineno=None):
2.1160 + self.nodes = nodes
2.1161 + self.lineno = lineno
2.1162 +
2.1163 + def getChildren(self):
2.1164 + return tuple(flatten(self.nodes))
2.1165 +
2.1166 + def getChildNodes(self):
2.1167 + nodelist = []
2.1168 + nodelist.extend(flatten_nodes(self.nodes))
2.1169 + return tuple(nodelist)
2.1170 +
2.1171 + def __repr__(self):
2.1172 + return "Set(%s)" % (repr(self.nodes),)
2.1173 +
2.1174 +class Slice(Node):
2.1175 + def __init__(self, expr, flags, lower, upper, lineno=None):
2.1176 + self.expr = expr
2.1177 + self.flags = flags
2.1178 + self.lower = lower
2.1179 + self.upper = upper
2.1180 + self.lineno = lineno
2.1181 +
2.1182 + def getChildren(self):
2.1183 + children = []
2.1184 + children.append(self.expr)
2.1185 + children.append(self.flags)
2.1186 + children.append(self.lower)
2.1187 + children.append(self.upper)
2.1188 + return tuple(children)
2.1189 +
2.1190 + def getChildNodes(self):
2.1191 + nodelist = []
2.1192 + nodelist.append(self.expr)
2.1193 + if self.lower is not None:
2.1194 + nodelist.append(self.lower)
2.1195 + if self.upper is not None:
2.1196 + nodelist.append(self.upper)
2.1197 + return tuple(nodelist)
2.1198 +
2.1199 + def __repr__(self):
2.1200 + return "Slice(%s, %s, %s, %s)" % (repr(self.expr), repr(self.flags), repr(self.lower), repr(self.upper))
2.1201 +
2.1202 +class Sliceobj(Node):
2.1203 + def __init__(self, nodes, lineno=None):
2.1204 + self.nodes = nodes
2.1205 + self.lineno = lineno
2.1206 +
2.1207 + def getChildren(self):
2.1208 + return tuple(flatten(self.nodes))
2.1209 +
2.1210 + def getChildNodes(self):
2.1211 + nodelist = []
2.1212 + nodelist.extend(flatten_nodes(self.nodes))
2.1213 + return tuple(nodelist)
2.1214 +
2.1215 + def __repr__(self):
2.1216 + return "Sliceobj(%s)" % (repr(self.nodes),)
2.1217 +
2.1218 +class Stmt(Node):
2.1219 + def __init__(self, nodes, lineno=None):
2.1220 + self.nodes = nodes
2.1221 + self.lineno = lineno
2.1222 +
2.1223 + def getChildren(self):
2.1224 + return tuple(flatten(self.nodes))
2.1225 +
2.1226 + def getChildNodes(self):
2.1227 + nodelist = []
2.1228 + nodelist.extend(flatten_nodes(self.nodes))
2.1229 + return tuple(nodelist)
2.1230 +
2.1231 + def __repr__(self):
2.1232 + return "Stmt(%s)" % (repr(self.nodes),)
2.1233 +
2.1234 +class Sub(Node):
2.1235 + def __init__(self, leftright, lineno=None):
2.1236 + self.left = leftright[0]
2.1237 + self.right = leftright[1]
2.1238 + self.lineno = lineno
2.1239 +
2.1240 + def getChildren(self):
2.1241 + return self.left, self.right
2.1242 +
2.1243 + def getChildNodes(self):
2.1244 + return self.left, self.right
2.1245 +
2.1246 + def __repr__(self):
2.1247 + return "Sub((%s, %s))" % (repr(self.left), repr(self.right))
2.1248 +
2.1249 +class Subscript(Node):
2.1250 + def __init__(self, expr, flags, subs, lineno=None):
2.1251 + self.expr = expr
2.1252 + self.flags = flags
2.1253 + self.subs = subs
2.1254 + self.lineno = lineno
2.1255 +
2.1256 + def getChildren(self):
2.1257 + children = []
2.1258 + children.append(self.expr)
2.1259 + children.append(self.flags)
2.1260 + children.extend(flatten(self.subs))
2.1261 + return tuple(children)
2.1262 +
2.1263 + def getChildNodes(self):
2.1264 + nodelist = []
2.1265 + nodelist.append(self.expr)
2.1266 + nodelist.extend(flatten_nodes(self.subs))
2.1267 + return tuple(nodelist)
2.1268 +
2.1269 + def __repr__(self):
2.1270 + return "Subscript(%s, %s, %s)" % (repr(self.expr), repr(self.flags), repr(self.subs))
2.1271 +
2.1272 +class TryExcept(Node):
2.1273 + def __init__(self, body, handlers, else_, lineno=None):
2.1274 + self.body = body
2.1275 + self.handlers = handlers
2.1276 + self.else_ = else_
2.1277 + self.lineno = lineno
2.1278 +
2.1279 + def getChildren(self):
2.1280 + children = []
2.1281 + children.append(self.body)
2.1282 + children.extend(flatten(self.handlers))
2.1283 + children.append(self.else_)
2.1284 + return tuple(children)
2.1285 +
2.1286 + def getChildNodes(self):
2.1287 + nodelist = []
2.1288 + nodelist.append(self.body)
2.1289 + nodelist.extend(flatten_nodes(self.handlers))
2.1290 + if self.else_ is not None:
2.1291 + nodelist.append(self.else_)
2.1292 + return tuple(nodelist)
2.1293 +
2.1294 + def __repr__(self):
2.1295 + return "TryExcept(%s, %s, %s)" % (repr(self.body), repr(self.handlers), repr(self.else_))
2.1296 +
2.1297 +class TryFinally(Node):
2.1298 + def __init__(self, body, final, lineno=None):
2.1299 + self.body = body
2.1300 + self.final = final
2.1301 + self.lineno = lineno
2.1302 +
2.1303 + def getChildren(self):
2.1304 + return self.body, self.final
2.1305 +
2.1306 + def getChildNodes(self):
2.1307 + return self.body, self.final
2.1308 +
2.1309 + def __repr__(self):
2.1310 + return "TryFinally(%s, %s)" % (repr(self.body), repr(self.final))
2.1311 +
2.1312 +class Tuple(Node):
2.1313 + def __init__(self, nodes, lineno=None):
2.1314 + self.nodes = nodes
2.1315 + self.lineno = lineno
2.1316 +
2.1317 + def getChildren(self):
2.1318 + return tuple(flatten(self.nodes))
2.1319 +
2.1320 + def getChildNodes(self):
2.1321 + nodelist = []
2.1322 + nodelist.extend(flatten_nodes(self.nodes))
2.1323 + return tuple(nodelist)
2.1324 +
2.1325 + def __repr__(self):
2.1326 + return "Tuple(%s)" % (repr(self.nodes),)
2.1327 +
2.1328 +class UnaryAdd(Node):
2.1329 + def __init__(self, expr, lineno=None):
2.1330 + self.expr = expr
2.1331 + self.lineno = lineno
2.1332 +
2.1333 + def getChildren(self):
2.1334 + return self.expr,
2.1335 +
2.1336 + def getChildNodes(self):
2.1337 + return self.expr,
2.1338 +
2.1339 + def __repr__(self):
2.1340 + return "UnaryAdd(%s)" % (repr(self.expr),)
2.1341 +
2.1342 +class UnarySub(Node):
2.1343 + def __init__(self, expr, lineno=None):
2.1344 + self.expr = expr
2.1345 + self.lineno = lineno
2.1346 +
2.1347 + def getChildren(self):
2.1348 + return self.expr,
2.1349 +
2.1350 + def getChildNodes(self):
2.1351 + return self.expr,
2.1352 +
2.1353 + def __repr__(self):
2.1354 + return "UnarySub(%s)" % (repr(self.expr),)
2.1355 +
2.1356 +class While(Node):
2.1357 + def __init__(self, test, body, else_, lineno=None):
2.1358 + self.test = test
2.1359 + self.body = body
2.1360 + self.else_ = else_
2.1361 + self.lineno = lineno
2.1362 +
2.1363 + def getChildren(self):
2.1364 + children = []
2.1365 + children.append(self.test)
2.1366 + children.append(self.body)
2.1367 + children.append(self.else_)
2.1368 + return tuple(children)
2.1369 +
2.1370 + def getChildNodes(self):
2.1371 + nodelist = []
2.1372 + nodelist.append(self.test)
2.1373 + nodelist.append(self.body)
2.1374 + if self.else_ is not None:
2.1375 + nodelist.append(self.else_)
2.1376 + return tuple(nodelist)
2.1377 +
2.1378 + def __repr__(self):
2.1379 + return "While(%s, %s, %s)" % (repr(self.test), repr(self.body), repr(self.else_))
2.1380 +
2.1381 +class With(Node):
2.1382 + def __init__(self, expr, vars, body, lineno=None):
2.1383 + self.expr = expr
2.1384 + self.vars = vars
2.1385 + self.body = body
2.1386 + self.lineno = lineno
2.1387 +
2.1388 + def getChildren(self):
2.1389 + children = []
2.1390 + children.append(self.expr)
2.1391 + children.append(self.vars)
2.1392 + children.append(self.body)
2.1393 + return tuple(children)
2.1394 +
2.1395 + def getChildNodes(self):
2.1396 + nodelist = []
2.1397 + nodelist.append(self.expr)
2.1398 + if self.vars is not None:
2.1399 + nodelist.append(self.vars)
2.1400 + nodelist.append(self.body)
2.1401 + return tuple(nodelist)
2.1402 +
2.1403 + def __repr__(self):
2.1404 + return "With(%s, %s, %s)" % (repr(self.expr), repr(self.vars), repr(self.body))
2.1405 +
2.1406 +class Yield(Node):
2.1407 + def __init__(self, value, lineno=None):
2.1408 + self.value = value
2.1409 + self.lineno = lineno
2.1410 +
2.1411 + def getChildren(self):
2.1412 + return self.value,
2.1413 +
2.1414 + def getChildNodes(self):
2.1415 + return self.value,
2.1416 +
2.1417 + def __repr__(self):
2.1418 + return "Yield(%s)" % (repr(self.value),)
2.1419 +
2.1420 +for name, obj in globals().items():
2.1421 + if isinstance(obj, type) and issubclass(obj, Node):
2.1422 + nodes[name.lower()] = obj
3.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
3.2 +++ b/compiler/consts.py Fri May 18 23:26:30 2012 +0200
3.3 @@ -0,0 +1,23 @@
3.4 +# operation flags
3.5 +OP_ASSIGN = 'OP_ASSIGN'
3.6 +OP_DELETE = 'OP_DELETE'
3.7 +OP_APPLY = 'OP_APPLY'
3.8 +
3.9 +SC_LOCAL = 1
3.10 +SC_GLOBAL_IMPLICIT = 2
3.11 +SC_GLOBAL_EXPLICT = 3
3.12 +SC_FREE = 4
3.13 +SC_CELL = 5
3.14 +SC_UNKNOWN = 6
3.15 +
3.16 +CO_OPTIMIZED = 0x0001
3.17 +CO_NEWLOCALS = 0x0002
3.18 +CO_VARARGS = 0x0004
3.19 +CO_VARKEYWORDS = 0x0008
3.20 +CO_NESTED = 0x0010
3.21 +CO_GENERATOR = 0x0020
3.22 +CO_GENERATOR_ALLOWED = 0
3.23 +CO_FUTURE_DIVISION = 0x2000
3.24 +CO_FUTURE_ABSIMPORT = 0x4000
3.25 +CO_FUTURE_WITH_STATEMENT = 0x8000
3.26 +CO_FUTURE_PRINT_FUNCTION = 0x10000
4.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
4.2 +++ b/compiler/future.py Fri May 18 23:26:30 2012 +0200
4.3 @@ -0,0 +1,74 @@
4.4 +"""Parser for future statements
4.5 +
4.6 +"""
4.7 +
4.8 +from compiler import ast, walk
4.9 +
4.10 +def is_future(stmt):
4.11 + """Return true if statement is a well-formed future statement"""
4.12 + if not isinstance(stmt, ast.From):
4.13 + return 0
4.14 + if stmt.modname == "__future__":
4.15 + return 1
4.16 + else:
4.17 + return 0
4.18 +
4.19 +class FutureParser:
4.20 +
4.21 + features = ("nested_scopes", "generators", "division",
4.22 + "absolute_import", "with_statement", "print_function",
4.23 + "unicode_literals")
4.24 +
4.25 + def __init__(self):
4.26 + self.found = {} # set
4.27 +
4.28 + def visitModule(self, node):
4.29 + stmt = node.node
4.30 + for s in stmt.nodes:
4.31 + if not self.check_stmt(s):
4.32 + break
4.33 +
4.34 + def check_stmt(self, stmt):
4.35 + if is_future(stmt):
4.36 + for name, asname in stmt.names:
4.37 + if name in self.features:
4.38 + self.found[name] = 1
4.39 + else:
4.40 + raise SyntaxError, \
4.41 + "future feature %s is not defined" % name
4.42 + stmt.valid_future = 1
4.43 + return 1
4.44 + return 0
4.45 +
4.46 + def get_features(self):
4.47 + """Return list of features enabled by future statements"""
4.48 + return self.found.keys()
4.49 +
4.50 +class BadFutureParser:
4.51 + """Check for invalid future statements"""
4.52 +
4.53 + def visitFrom(self, node):
4.54 + if hasattr(node, 'valid_future'):
4.55 + return
4.56 + if node.modname != "__future__":
4.57 + return
4.58 + raise SyntaxError, "invalid future statement " + repr(node)
4.59 +
4.60 +def find_futures(node):
4.61 + p1 = FutureParser()
4.62 + p2 = BadFutureParser()
4.63 + walk(node, p1)
4.64 + walk(node, p2)
4.65 + return p1.get_features()
4.66 +
4.67 +if __name__ == "__main__":
4.68 + import sys
4.69 + from compiler import parseFile, walk
4.70 +
4.71 + for file in sys.argv[1:]:
4.72 + print file
4.73 + tree = parseFile(file)
4.74 + v = FutureParser()
4.75 + walk(tree, v)
4.76 + print v.found
4.77 + print
5.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
5.2 +++ b/compiler/misc.py Fri May 18 23:26:30 2012 +0200
5.3 @@ -0,0 +1,73 @@
5.4 +
5.5 +def flatten(tup):
5.6 + elts = []
5.7 + for elt in tup:
5.8 + if isinstance(elt, tuple):
5.9 + elts = elts + flatten(elt)
5.10 + else:
5.11 + elts.append(elt)
5.12 + return elts
5.13 +
5.14 +class Set:
5.15 + def __init__(self):
5.16 + self.elts = {}
5.17 + def __len__(self):
5.18 + return len(self.elts)
5.19 + def __contains__(self, elt):
5.20 + return elt in self.elts
5.21 + def add(self, elt):
5.22 + self.elts[elt] = elt
5.23 + def elements(self):
5.24 + return self.elts.keys()
5.25 + def has_elt(self, elt):
5.26 + return elt in self.elts
5.27 + def remove(self, elt):
5.28 + del self.elts[elt]
5.29 + def copy(self):
5.30 + c = Set()
5.31 + c.elts.update(self.elts)
5.32 + return c
5.33 +
5.34 +class Stack:
5.35 + def __init__(self):
5.36 + self.stack = []
5.37 + self.pop = self.stack.pop
5.38 + def __len__(self):
5.39 + return len(self.stack)
5.40 + def push(self, elt):
5.41 + self.stack.append(elt)
5.42 + def top(self):
5.43 + return self.stack[-1]
5.44 + def __getitem__(self, index): # needed by visitContinue()
5.45 + return self.stack[index]
5.46 +
5.47 +MANGLE_LEN = 256 # magic constant from compile.c
5.48 +
5.49 +def mangle(name, klass):
5.50 + if not name.startswith('__'):
5.51 + return name
5.52 + if len(name) + 2 >= MANGLE_LEN:
5.53 + return name
5.54 + if name.endswith('__'):
5.55 + return name
5.56 + try:
5.57 + i = 0
5.58 + while klass[i] == '_':
5.59 + i = i + 1
5.60 + except IndexError:
5.61 + return name
5.62 + klass = klass[i:]
5.63 +
5.64 + tlen = len(klass) + len(name)
5.65 + if tlen > MANGLE_LEN:
5.66 + klass = klass[:MANGLE_LEN-tlen]
5.67 +
5.68 + return "_%s%s" % (klass, name)
5.69 +
5.70 +def set_filename(filename, tree):
5.71 + """Set the filename attribute to filename on every node in tree"""
5.72 + worklist = [tree]
5.73 + while worklist:
5.74 + node = worklist.pop(0)
5.75 + node.filename = filename
5.76 + worklist.extend(node.getChildNodes())
6.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
6.2 +++ b/compiler/pyassem.py Fri May 18 23:26:30 2012 +0200
6.3 @@ -0,0 +1,763 @@
6.4 +"""A flow graph representation for Python bytecode"""
6.5 +
6.6 +import dis
6.7 +import types
6.8 +import sys
6.9 +
6.10 +from compiler import misc
6.11 +from compiler.consts \
6.12 + import CO_OPTIMIZED, CO_NEWLOCALS, CO_VARARGS, CO_VARKEYWORDS
6.13 +
6.14 +class FlowGraph:
6.15 + def __init__(self):
6.16 + self.current = self.entry = Block()
6.17 + self.exit = Block("exit")
6.18 + self.blocks = misc.Set()
6.19 + self.blocks.add(self.entry)
6.20 + self.blocks.add(self.exit)
6.21 +
6.22 + def startBlock(self, block):
6.23 + if self._debug:
6.24 + if self.current:
6.25 + print "end", repr(self.current)
6.26 + print " next", self.current.next
6.27 + print " prev", self.current.prev
6.28 + print " ", self.current.get_children()
6.29 + print repr(block)
6.30 + self.current = block
6.31 +
6.32 + def nextBlock(self, block=None):
6.33 + # XXX think we need to specify when there is implicit transfer
6.34 + # from one block to the next. might be better to represent this
6.35 + # with explicit JUMP_ABSOLUTE instructions that are optimized
6.36 + # out when they are unnecessary.
6.37 + #
6.38 + # I think this strategy works: each block has a child
6.39 + # designated as "next" which is returned as the last of the
6.40 + # children. because the nodes in a graph are emitted in
6.41 + # reverse post order, the "next" block will always be emitted
6.42 + # immediately after its parent.
6.43 + # Worry: maintaining this invariant could be tricky
6.44 + if block is None:
6.45 + block = self.newBlock()
6.46 +
6.47 + # Note: If the current block ends with an unconditional control
6.48 + # transfer, then it is techically incorrect to add an implicit
6.49 + # transfer to the block graph. Doing so results in code generation
6.50 + # for unreachable blocks. That doesn't appear to be very common
6.51 + # with Python code and since the built-in compiler doesn't optimize
6.52 + # it out we don't either.
6.53 + self.current.addNext(block)
6.54 + self.startBlock(block)
6.55 +
6.56 + def newBlock(self):
6.57 + b = Block()
6.58 + self.blocks.add(b)
6.59 + return b
6.60 +
6.61 + def startExitBlock(self):
6.62 + self.startBlock(self.exit)
6.63 +
6.64 + _debug = 0
6.65 +
6.66 + def _enable_debug(self):
6.67 + self._debug = 1
6.68 +
6.69 + def _disable_debug(self):
6.70 + self._debug = 0
6.71 +
6.72 + def emit(self, *inst):
6.73 + if self._debug:
6.74 + print "\t", inst
6.75 + if len(inst) == 2 and isinstance(inst[1], Block):
6.76 + self.current.addOutEdge(inst[1])
6.77 + self.current.emit(inst)
6.78 +
6.79 + def getBlocksInOrder(self):
6.80 + """Return the blocks in reverse postorder
6.81 +
6.82 + i.e. each node appears before all of its successors
6.83 + """
6.84 + order = order_blocks(self.entry, self.exit)
6.85 + return order
6.86 +
6.87 + def getBlocks(self):
6.88 + return self.blocks.elements()
6.89 +
6.90 + def getRoot(self):
6.91 + """Return nodes appropriate for use with dominator"""
6.92 + return self.entry
6.93 +
6.94 + def getContainedGraphs(self):
6.95 + l = []
6.96 + for b in self.getBlocks():
6.97 + l.extend(b.getContainedGraphs())
6.98 + return l
6.99 +
6.100 +
6.101 +def order_blocks(start_block, exit_block):
6.102 + """Order blocks so that they are emitted in the right order"""
6.103 + # Rules:
6.104 + # - when a block has a next block, the next block must be emitted just after
6.105 + # - when a block has followers (relative jumps), it must be emitted before
6.106 + # them
6.107 + # - all reachable blocks must be emitted
6.108 + order = []
6.109 +
6.110 + # Find all the blocks to be emitted.
6.111 + remaining = set()
6.112 + todo = [start_block]
6.113 + while todo:
6.114 + b = todo.pop()
6.115 + if b in remaining:
6.116 + continue
6.117 + remaining.add(b)
6.118 + for c in b.get_children():
6.119 + if c not in remaining:
6.120 + todo.append(c)
6.121 +
6.122 + # A block is dominated by another block if that block must be emitted
6.123 + # before it.
6.124 + dominators = {}
6.125 + for b in remaining:
6.126 + if __debug__ and b.next:
6.127 + assert b is b.next[0].prev[0], (b, b.next)
6.128 + # Make sure every block appears in dominators, even if no
6.129 + # other block must precede it.
6.130 + dominators.setdefault(b, set())
6.131 + # preceeding blocks dominate following blocks
6.132 + for c in b.get_followers():
6.133 + while 1:
6.134 + dominators.setdefault(c, set()).add(b)
6.135 + # Any block that has a next pointer leading to c is also
6.136 + # dominated because the whole chain will be emitted at once.
6.137 + # Walk backwards and add them all.
6.138 + if c.prev and c.prev[0] is not b:
6.139 + c = c.prev[0]
6.140 + else:
6.141 + break
6.142 +
6.143 + def find_next():
6.144 + # Find a block that can be emitted next.
6.145 + for b in remaining:
6.146 + for c in dominators[b]:
6.147 + if c in remaining:
6.148 + break # can't emit yet, dominated by a remaining block
6.149 + else:
6.150 + return b
6.151 + assert 0, 'circular dependency, cannot find next block'
6.152 +
6.153 + b = start_block
6.154 + while 1:
6.155 + order.append(b)
6.156 + remaining.discard(b)
6.157 + if b.next:
6.158 + b = b.next[0]
6.159 + continue
6.160 + elif b is not exit_block and not b.has_unconditional_transfer():
6.161 + order.append(exit_block)
6.162 + if not remaining:
6.163 + break
6.164 + b = find_next()
6.165 + return order
6.166 +
6.167 +
6.168 +class Block:
6.169 + _count = 0
6.170 +
6.171 + def __init__(self, label=''):
6.172 + self.insts = []
6.173 + self.outEdges = set()
6.174 + self.label = label
6.175 + self.bid = Block._count
6.176 + self.next = []
6.177 + self.prev = []
6.178 + Block._count = Block._count + 1
6.179 +
6.180 + def __repr__(self):
6.181 + if self.label:
6.182 + return "<block %s id=%d>" % (self.label, self.bid)
6.183 + else:
6.184 + return "<block id=%d>" % (self.bid)
6.185 +
6.186 + def __str__(self):
6.187 + insts = map(str, self.insts)
6.188 + return "<block %s %d:\n%s>" % (self.label, self.bid,
6.189 + '\n'.join(insts))
6.190 +
6.191 + def emit(self, inst):
6.192 + op = inst[0]
6.193 + self.insts.append(inst)
6.194 +
6.195 + def getInstructions(self):
6.196 + return self.insts
6.197 +
6.198 + def addOutEdge(self, block):
6.199 + self.outEdges.add(block)
6.200 +
6.201 + def addNext(self, block):
6.202 + self.next.append(block)
6.203 + assert len(self.next) == 1, map(str, self.next)
6.204 + block.prev.append(self)
6.205 + assert len(block.prev) == 1, map(str, block.prev)
6.206 +
6.207 + _uncond_transfer = ('RETURN_VALUE', 'RAISE_VARARGS',
6.208 + 'JUMP_ABSOLUTE', 'JUMP_FORWARD', 'CONTINUE_LOOP',
6.209 + )
6.210 +
6.211 + def has_unconditional_transfer(self):
6.212 + """Returns True if there is an unconditional transfer to an other block
6.213 + at the end of this block. This means there is no risk for the bytecode
6.214 + executer to go past this block's bytecode."""
6.215 + try:
6.216 + op, arg = self.insts[-1]
6.217 + except (IndexError, ValueError):
6.218 + return
6.219 + return op in self._uncond_transfer
6.220 +
6.221 + def get_children(self):
6.222 + return list(self.outEdges) + self.next
6.223 +
6.224 + def get_followers(self):
6.225 + """Get the whole list of followers, including the next block."""
6.226 + followers = set(self.next)
6.227 + # Blocks that must be emitted *after* this one, because of
6.228 + # bytecode offsets (e.g. relative jumps) pointing to them.
6.229 + for inst in self.insts:
6.230 + if inst[0] in PyFlowGraph.hasjrel:
6.231 + followers.add(inst[1])
6.232 + return followers
6.233 +
6.234 + def getContainedGraphs(self):
6.235 + """Return all graphs contained within this block.
6.236 +
6.237 + For example, a MAKE_FUNCTION block will contain a reference to
6.238 + the graph for the function body.
6.239 + """
6.240 + contained = []
6.241 + for inst in self.insts:
6.242 + if len(inst) == 1:
6.243 + continue
6.244 + op = inst[1]
6.245 + if hasattr(op, 'graph'):
6.246 + contained.append(op.graph)
6.247 + return contained
6.248 +
6.249 +# flags for code objects
6.250 +
6.251 +# the FlowGraph is transformed in place; it exists in one of these states
6.252 +RAW = "RAW"
6.253 +FLAT = "FLAT"
6.254 +CONV = "CONV"
6.255 +DONE = "DONE"
6.256 +
6.257 +class PyFlowGraph(FlowGraph):
6.258 + super_init = FlowGraph.__init__
6.259 +
6.260 + def __init__(self, name, filename, args=(), optimized=0, klass=None):
6.261 + self.super_init()
6.262 + self.name = name
6.263 + self.filename = filename
6.264 + self.docstring = None
6.265 + self.args = args # XXX
6.266 + self.argcount = getArgCount(args)
6.267 + self.klass = klass
6.268 + if optimized:
6.269 + self.flags = CO_OPTIMIZED | CO_NEWLOCALS
6.270 + else:
6.271 + self.flags = 0
6.272 + self.consts = []
6.273 + self.names = []
6.274 + # Free variables found by the symbol table scan, including
6.275 + # variables used only in nested scopes, are included here.
6.276 + self.freevars = []
6.277 + self.cellvars = []
6.278 + # The closure list is used to track the order of cell
6.279 + # variables and free variables in the resulting code object.
6.280 + # The offsets used by LOAD_CLOSURE/LOAD_DEREF refer to both
6.281 + # kinds of variables.
6.282 + self.closure = []
6.283 + self.varnames = list(args) or []
6.284 + for i in range(len(self.varnames)):
6.285 + var = self.varnames[i]
6.286 + if isinstance(var, TupleArg):
6.287 + self.varnames[i] = var.getName()
6.288 + self.stage = RAW
6.289 +
6.290 + def setDocstring(self, doc):
6.291 + self.docstring = doc
6.292 +
6.293 + def setFlag(self, flag):
6.294 + self.flags = self.flags | flag
6.295 + if flag == CO_VARARGS:
6.296 + self.argcount = self.argcount - 1
6.297 +
6.298 + def checkFlag(self, flag):
6.299 + if self.flags & flag:
6.300 + return 1
6.301 +
6.302 + def setFreeVars(self, names):
6.303 + self.freevars = list(names)
6.304 +
6.305 + def setCellVars(self, names):
6.306 + self.cellvars = names
6.307 +
6.308 + def getCode(self):
6.309 + """Get a Python code object"""
6.310 + assert self.stage == RAW
6.311 + self.computeStackDepth()
6.312 + self.flattenGraph()
6.313 + assert self.stage == FLAT
6.314 + self.convertArgs()
6.315 + assert self.stage == CONV
6.316 + self.makeByteCode()
6.317 + assert self.stage == DONE
6.318 + return self.newCodeObject()
6.319 +
6.320 + def dump(self, io=None):
6.321 + if io:
6.322 + save = sys.stdout
6.323 + sys.stdout = io
6.324 + pc = 0
6.325 + for t in self.insts:
6.326 + opname = t[0]
6.327 + if opname == "SET_LINENO":
6.328 + print
6.329 + if len(t) == 1:
6.330 + print "\t", "%3d" % pc, opname
6.331 + pc = pc + 1
6.332 + else:
6.333 + print "\t", "%3d" % pc, opname, t[1]
6.334 + pc = pc + 3
6.335 + if io:
6.336 + sys.stdout = save
6.337 +
6.338 + def computeStackDepth(self):
6.339 + """Compute the max stack depth.
6.340 +
6.341 + Approach is to compute the stack effect of each basic block.
6.342 + Then find the path through the code with the largest total
6.343 + effect.
6.344 + """
6.345 + depth = {}
6.346 + exit = None
6.347 + for b in self.getBlocks():
6.348 + depth[b] = findDepth(b.getInstructions())
6.349 +
6.350 + seen = {}
6.351 +
6.352 + def max_depth(b, d):
6.353 + if b in seen:
6.354 + return d
6.355 + seen[b] = 1
6.356 + d = d + depth[b]
6.357 + children = b.get_children()
6.358 + if children:
6.359 + return max([max_depth(c, d) for c in children])
6.360 + else:
6.361 + if not b.label == "exit":
6.362 + return max_depth(self.exit, d)
6.363 + else:
6.364 + return d
6.365 +
6.366 + self.stacksize = max_depth(self.entry, 0)
6.367 +
6.368 + def flattenGraph(self):
6.369 + """Arrange the blocks in order and resolve jumps"""
6.370 + assert self.stage == RAW
6.371 + self.insts = insts = []
6.372 + pc = 0
6.373 + begin = {}
6.374 + end = {}
6.375 + for b in self.getBlocksInOrder():
6.376 + begin[b] = pc
6.377 + for inst in b.getInstructions():
6.378 + insts.append(inst)
6.379 + if len(inst) == 1:
6.380 + pc = pc + 1
6.381 + elif inst[0] != "SET_LINENO":
6.382 + # arg takes 2 bytes
6.383 + pc = pc + 3
6.384 + end[b] = pc
6.385 + pc = 0
6.386 + for i in range(len(insts)):
6.387 + inst = insts[i]
6.388 + if len(inst) == 1:
6.389 + pc = pc + 1
6.390 + elif inst[0] != "SET_LINENO":
6.391 + pc = pc + 3
6.392 + opname = inst[0]
6.393 + if opname in self.hasjrel:
6.394 + oparg = inst[1]
6.395 + offset = begin[oparg] - pc
6.396 + insts[i] = opname, offset
6.397 + elif opname in self.hasjabs:
6.398 + insts[i] = opname, begin[inst[1]]
6.399 + self.stage = FLAT
6.400 +
6.401 + hasjrel = set()
6.402 + for i in dis.hasjrel:
6.403 + hasjrel.add(dis.opname[i])
6.404 + hasjabs = set()
6.405 + for i in dis.hasjabs:
6.406 + hasjabs.add(dis.opname[i])
6.407 +
6.408 + def convertArgs(self):
6.409 + """Convert arguments from symbolic to concrete form"""
6.410 + assert self.stage == FLAT
6.411 + self.consts.insert(0, self.docstring)
6.412 + self.sort_cellvars()
6.413 + for i in range(len(self.insts)):
6.414 + t = self.insts[i]
6.415 + if len(t) == 2:
6.416 + opname, oparg = t
6.417 + conv = self._converters.get(opname, None)
6.418 + if conv:
6.419 + self.insts[i] = opname, conv(self, oparg)
6.420 + self.stage = CONV
6.421 +
6.422 + def sort_cellvars(self):
6.423 + """Sort cellvars in the order of varnames and prune from freevars.
6.424 + """
6.425 + cells = {}
6.426 + for name in self.cellvars:
6.427 + cells[name] = 1
6.428 + self.cellvars = [name for name in self.varnames
6.429 + if name in cells]
6.430 + for name in self.cellvars:
6.431 + del cells[name]
6.432 + self.cellvars = self.cellvars + cells.keys()
6.433 + self.closure = self.cellvars + self.freevars
6.434 +
6.435 + def _lookupName(self, name, list):
6.436 + """Return index of name in list, appending if necessary
6.437 +
6.438 + This routine uses a list instead of a dictionary, because a
6.439 + dictionary can't store two different keys if the keys have the
6.440 + same value but different types, e.g. 2 and 2L. The compiler
6.441 + must treat these two separately, so it does an explicit type
6.442 + comparison before comparing the values.
6.443 + """
6.444 + t = type(name)
6.445 + for i in range(len(list)):
6.446 + if t == type(list[i]) and list[i] == name:
6.447 + return i
6.448 + end = len(list)
6.449 + list.append(name)
6.450 + return end
6.451 +
6.452 + _converters = {}
6.453 + def _convert_LOAD_CONST(self, arg):
6.454 + if hasattr(arg, 'getCode'):
6.455 + arg = arg.getCode()
6.456 + return self._lookupName(arg, self.consts)
6.457 +
6.458 + def _convert_LOAD_FAST(self, arg):
6.459 + self._lookupName(arg, self.names)
6.460 + return self._lookupName(arg, self.varnames)
6.461 + _convert_STORE_FAST = _convert_LOAD_FAST
6.462 + _convert_DELETE_FAST = _convert_LOAD_FAST
6.463 +
6.464 + def _convert_LOAD_NAME(self, arg):
6.465 + if self.klass is None:
6.466 + self._lookupName(arg, self.varnames)
6.467 + return self._lookupName(arg, self.names)
6.468 +
6.469 + def _convert_NAME(self, arg):
6.470 + if self.klass is None:
6.471 + self._lookupName(arg, self.varnames)
6.472 + return self._lookupName(arg, self.names)
6.473 + _convert_STORE_NAME = _convert_NAME
6.474 + _convert_DELETE_NAME = _convert_NAME
6.475 + _convert_IMPORT_NAME = _convert_NAME
6.476 + _convert_IMPORT_FROM = _convert_NAME
6.477 + _convert_STORE_ATTR = _convert_NAME
6.478 + _convert_LOAD_ATTR = _convert_NAME
6.479 + _convert_DELETE_ATTR = _convert_NAME
6.480 + _convert_LOAD_GLOBAL = _convert_NAME
6.481 + _convert_STORE_GLOBAL = _convert_NAME
6.482 + _convert_DELETE_GLOBAL = _convert_NAME
6.483 +
6.484 + def _convert_DEREF(self, arg):
6.485 + self._lookupName(arg, self.names)
6.486 + self._lookupName(arg, self.varnames)
6.487 + return self._lookupName(arg, self.closure)
6.488 + _convert_LOAD_DEREF = _convert_DEREF
6.489 + _convert_STORE_DEREF = _convert_DEREF
6.490 +
6.491 + def _convert_LOAD_CLOSURE(self, arg):
6.492 + self._lookupName(arg, self.varnames)
6.493 + return self._lookupName(arg, self.closure)
6.494 +
6.495 + _cmp = list(dis.cmp_op)
6.496 + def _convert_COMPARE_OP(self, arg):
6.497 + return self._cmp.index(arg)
6.498 +
6.499 + # similarly for other opcodes...
6.500 +
6.501 + for name, obj in locals().items():
6.502 + if name[:9] == "_convert_":
6.503 + opname = name[9:]
6.504 + _converters[opname] = obj
6.505 + del name, obj, opname
6.506 +
6.507 + def makeByteCode(self):
6.508 + assert self.stage == CONV
6.509 + self.lnotab = lnotab = LineAddrTable()
6.510 + for t in self.insts:
6.511 + opname = t[0]
6.512 + if len(t) == 1:
6.513 + lnotab.addCode(self.opnum[opname])
6.514 + else:
6.515 + oparg = t[1]
6.516 + if opname == "SET_LINENO":
6.517 + lnotab.nextLine(oparg)
6.518 + continue
6.519 + hi, lo = twobyte(oparg)
6.520 + try:
6.521 + lnotab.addCode(self.opnum[opname], lo, hi)
6.522 + except ValueError:
6.523 + print opname, oparg
6.524 + print self.opnum[opname], lo, hi
6.525 + raise
6.526 + self.stage = DONE
6.527 +
6.528 + opnum = {}
6.529 + for num in range(len(dis.opname)):
6.530 + opnum[dis.opname[num]] = num
6.531 + del num
6.532 +
6.533 + def newCodeObject(self):
6.534 + assert self.stage == DONE
6.535 + if (self.flags & CO_NEWLOCALS) == 0:
6.536 + nlocals = 0
6.537 + else:
6.538 + nlocals = len(self.varnames)
6.539 + argcount = self.argcount
6.540 + if self.flags & CO_VARKEYWORDS:
6.541 + argcount = argcount - 1
6.542 + return types.CodeType(argcount, nlocals, self.stacksize, self.flags,
6.543 + self.lnotab.getCode(), self.getConsts(),
6.544 + tuple(self.names), tuple(self.varnames),
6.545 + self.filename, self.name, self.lnotab.firstline,
6.546 + self.lnotab.getTable(), tuple(self.freevars),
6.547 + tuple(self.cellvars))
6.548 +
6.549 + def getConsts(self):
6.550 + """Return a tuple for the const slot of the code object
6.551 +
6.552 + Must convert references to code (MAKE_FUNCTION) to code
6.553 + objects recursively.
6.554 + """
6.555 + l = []
6.556 + for elt in self.consts:
6.557 + if isinstance(elt, PyFlowGraph):
6.558 + elt = elt.getCode()
6.559 + l.append(elt)
6.560 + return tuple(l)
6.561 +
6.562 +def isJump(opname):
6.563 + if opname[:4] == 'JUMP':
6.564 + return 1
6.565 +
6.566 +class TupleArg:
6.567 + """Helper for marking func defs with nested tuples in arglist"""
6.568 + def __init__(self, count, names):
6.569 + self.count = count
6.570 + self.names = names
6.571 + def __repr__(self):
6.572 + return "TupleArg(%s, %s)" % (self.count, self.names)
6.573 + def getName(self):
6.574 + return ".%d" % self.count
6.575 +
6.576 +def getArgCount(args):
6.577 + argcount = len(args)
6.578 + if args:
6.579 + for arg in args:
6.580 + if isinstance(arg, TupleArg):
6.581 + numNames = len(misc.flatten(arg.names))
6.582 + argcount = argcount - numNames
6.583 + return argcount
6.584 +
6.585 +def twobyte(val):
6.586 + """Convert an int argument into high and low bytes"""
6.587 + assert isinstance(val, int)
6.588 + return divmod(val, 256)
6.589 +
6.590 +class LineAddrTable:
6.591 + """lnotab
6.592 +
6.593 + This class builds the lnotab, which is documented in compile.c.
6.594 + Here's a brief recap:
6.595 +
6.596 + For each SET_LINENO instruction after the first one, two bytes are
6.597 + added to lnotab. (In some cases, multiple two-byte entries are
6.598 + added.) The first byte is the distance in bytes between the
6.599 + instruction for the last SET_LINENO and the current SET_LINENO.
6.600 + The second byte is offset in line numbers. If either offset is
6.601 + greater than 255, multiple two-byte entries are added -- see
6.602 + compile.c for the delicate details.
6.603 + """
6.604 +
6.605 + def __init__(self):
6.606 + self.code = []
6.607 + self.codeOffset = 0
6.608 + self.firstline = 0
6.609 + self.lastline = 0
6.610 + self.lastoff = 0
6.611 + self.lnotab = []
6.612 +
6.613 + def addCode(self, *args):
6.614 + for arg in args:
6.615 + self.code.append(chr(arg))
6.616 + self.codeOffset = self.codeOffset + len(args)
6.617 +
6.618 + def nextLine(self, lineno):
6.619 + if self.firstline == 0:
6.620 + self.firstline = lineno
6.621 + self.lastline = lineno
6.622 + else:
6.623 + # compute deltas
6.624 + addr = self.codeOffset - self.lastoff
6.625 + line = lineno - self.lastline
6.626 + # Python assumes that lineno always increases with
6.627 + # increasing bytecode address (lnotab is unsigned char).
6.628 + # Depending on when SET_LINENO instructions are emitted
6.629 + # this is not always true. Consider the code:
6.630 + # a = (1,
6.631 + # b)
6.632 + # In the bytecode stream, the assignment to "a" occurs
6.633 + # after the loading of "b". This works with the C Python
6.634 + # compiler because it only generates a SET_LINENO instruction
6.635 + # for the assignment.
6.636 + if line >= 0:
6.637 + push = self.lnotab.append
6.638 + while addr > 255:
6.639 + push(255); push(0)
6.640 + addr -= 255
6.641 + while line > 255:
6.642 + push(addr); push(255)
6.643 + line -= 255
6.644 + addr = 0
6.645 + if addr > 0 or line > 0:
6.646 + push(addr); push(line)
6.647 + self.lastline = lineno
6.648 + self.lastoff = self.codeOffset
6.649 +
6.650 + def getCode(self):
6.651 + return ''.join(self.code)
6.652 +
6.653 + def getTable(self):
6.654 + return ''.join(map(chr, self.lnotab))
6.655 +
6.656 +class StackDepthTracker:
6.657 + # XXX 1. need to keep track of stack depth on jumps
6.658 + # XXX 2. at least partly as a result, this code is broken
6.659 +
6.660 + def findDepth(self, insts, debug=0):
6.661 + depth = 0
6.662 + maxDepth = 0
6.663 + for i in insts:
6.664 + opname = i[0]
6.665 + if debug:
6.666 + print i,
6.667 + delta = self.effect.get(opname, None)
6.668 + if delta is not None:
6.669 + depth = depth + delta
6.670 + else:
6.671 + # now check patterns
6.672 + for pat, pat_delta in self.patterns:
6.673 + if opname[:len(pat)] == pat:
6.674 + delta = pat_delta
6.675 + depth = depth + delta
6.676 + break
6.677 + # if we still haven't found a match
6.678 + if delta is None:
6.679 + meth = getattr(self, opname, None)
6.680 + if meth is not None:
6.681 + depth = depth + meth(i[1])
6.682 + if depth > maxDepth:
6.683 + maxDepth = depth
6.684 + if debug:
6.685 + print depth, maxDepth
6.686 + return maxDepth
6.687 +
6.688 + effect = {
6.689 + 'POP_TOP': -1,
6.690 + 'DUP_TOP': 1,
6.691 + 'LIST_APPEND': -1,
6.692 + 'SET_ADD': -1,
6.693 + 'MAP_ADD': -2,
6.694 + 'SLICE+1': -1,
6.695 + 'SLICE+2': -1,
6.696 + 'SLICE+3': -2,
6.697 + 'STORE_SLICE+0': -1,
6.698 + 'STORE_SLICE+1': -2,
6.699 + 'STORE_SLICE+2': -2,
6.700 + 'STORE_SLICE+3': -3,
6.701 + 'DELETE_SLICE+0': -1,
6.702 + 'DELETE_SLICE+1': -2,
6.703 + 'DELETE_SLICE+2': -2,
6.704 + 'DELETE_SLICE+3': -3,
6.705 + 'STORE_SUBSCR': -3,
6.706 + 'DELETE_SUBSCR': -2,
6.707 + # PRINT_EXPR?
6.708 + 'PRINT_ITEM': -1,
6.709 + 'RETURN_VALUE': -1,
6.710 + 'YIELD_VALUE': -1,
6.711 + 'EXEC_STMT': -3,
6.712 + 'BUILD_CLASS': -2,
6.713 + 'STORE_NAME': -1,
6.714 + 'STORE_ATTR': -2,
6.715 + 'DELETE_ATTR': -1,
6.716 + 'STORE_GLOBAL': -1,
6.717 + 'BUILD_MAP': 1,
6.718 + 'COMPARE_OP': -1,
6.719 + 'STORE_FAST': -1,
6.720 + 'IMPORT_STAR': -1,
6.721 + 'IMPORT_NAME': -1,
6.722 + 'IMPORT_FROM': 1,
6.723 + 'LOAD_ATTR': 0, # unlike other loads
6.724 + # close enough...
6.725 + 'SETUP_EXCEPT': 3,
6.726 + 'SETUP_FINALLY': 3,
6.727 + 'FOR_ITER': 1,
6.728 + 'WITH_CLEANUP': -1,
6.729 + }
6.730 + # use pattern match
6.731 + patterns = [
6.732 + ('BINARY_', -1),
6.733 + ('LOAD_', 1),
6.734 + ]
6.735 +
6.736 + def UNPACK_SEQUENCE(self, count):
6.737 + return count-1
6.738 + def BUILD_TUPLE(self, count):
6.739 + return -count+1
6.740 + def BUILD_LIST(self, count):
6.741 + return -count+1
6.742 + def BUILD_SET(self, count):
6.743 + return -count+1
6.744 + def CALL_FUNCTION(self, argc):
6.745 + hi, lo = divmod(argc, 256)
6.746 + return -(lo + hi * 2)
6.747 + def CALL_FUNCTION_VAR(self, argc):
6.748 + return self.CALL_FUNCTION(argc)-1
6.749 + def CALL_FUNCTION_KW(self, argc):
6.750 + return self.CALL_FUNCTION(argc)-1
6.751 + def CALL_FUNCTION_VAR_KW(self, argc):
6.752 + return self.CALL_FUNCTION(argc)-2
6.753 + def MAKE_FUNCTION(self, argc):
6.754 + return -argc
6.755 + def MAKE_CLOSURE(self, argc):
6.756 + # XXX need to account for free variables too!
6.757 + return -argc
6.758 + def BUILD_SLICE(self, argc):
6.759 + if argc == 2:
6.760 + return -1
6.761 + elif argc == 3:
6.762 + return -2
6.763 + def DUP_TOPX(self, argc):
6.764 + return argc
6.765 +
6.766 +findDepth = StackDepthTracker().findDepth
7.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
7.2 +++ b/compiler/pycodegen.py Fri May 18 23:26:30 2012 +0200
7.3 @@ -0,0 +1,1555 @@
7.4 +import imp
7.5 +import os
7.6 +import marshal
7.7 +import struct
7.8 +import sys
7.9 +from cStringIO import StringIO
7.10 +
7.11 +from compiler import ast, parse, walk, syntax
7.12 +from compiler import pyassem, misc, future, symbols
7.13 +from compiler.consts import SC_LOCAL, SC_GLOBAL_IMPLICIT, SC_GLOBAL_EXPLICT, \
7.14 + SC_FREE, SC_CELL
7.15 +from compiler.consts import (CO_VARARGS, CO_VARKEYWORDS, CO_NEWLOCALS,
7.16 + CO_NESTED, CO_GENERATOR, CO_FUTURE_DIVISION,
7.17 + CO_FUTURE_ABSIMPORT, CO_FUTURE_WITH_STATEMENT, CO_FUTURE_PRINT_FUNCTION)
7.18 +from compiler.pyassem import TupleArg
7.19 +
7.20 +# XXX The version-specific code can go, since this code only works with 2.x.
7.21 +# Do we have Python 1.x or Python 2.x?
7.22 +try:
7.23 + VERSION = sys.version_info[0]
7.24 +except AttributeError:
7.25 + VERSION = 1
7.26 +
7.27 +callfunc_opcode_info = {
7.28 + # (Have *args, Have **args) : opcode
7.29 + (0,0) : "CALL_FUNCTION",
7.30 + (1,0) : "CALL_FUNCTION_VAR",
7.31 + (0,1) : "CALL_FUNCTION_KW",
7.32 + (1,1) : "CALL_FUNCTION_VAR_KW",
7.33 +}
7.34 +
7.35 +LOOP = 1
7.36 +EXCEPT = 2
7.37 +TRY_FINALLY = 3
7.38 +END_FINALLY = 4
7.39 +
7.40 +def compileFile(filename, display=0):
7.41 + f = open(filename, 'U')
7.42 + buf = f.read()
7.43 + f.close()
7.44 + mod = Module(buf, filename)
7.45 + try:
7.46 + mod.compile(display)
7.47 + except SyntaxError:
7.48 + raise
7.49 + else:
7.50 + f = open(filename + "c", "wb")
7.51 + mod.dump(f)
7.52 + f.close()
7.53 +
7.54 +def compile(source, filename, mode, flags=None, dont_inherit=None):
7.55 + """Replacement for builtin compile() function"""
7.56 + if flags is not None or dont_inherit is not None:
7.57 + raise RuntimeError, "not implemented yet"
7.58 +
7.59 + if mode == "single":
7.60 + gen = Interactive(source, filename)
7.61 + elif mode == "exec":
7.62 + gen = Module(source, filename)
7.63 + elif mode == "eval":
7.64 + gen = Expression(source, filename)
7.65 + else:
7.66 + raise ValueError("compile() 3rd arg must be 'exec' or "
7.67 + "'eval' or 'single'")
7.68 + gen.compile()
7.69 + return gen.code
7.70 +
7.71 +class AbstractCompileMode:
7.72 +
7.73 + mode = None # defined by subclass
7.74 +
7.75 + def __init__(self, source, filename):
7.76 + self.source = source
7.77 + self.filename = filename
7.78 + self.code = None
7.79 +
7.80 + def _get_tree(self):
7.81 + tree = parse(self.source, self.mode)
7.82 + misc.set_filename(self.filename, tree)
7.83 + syntax.check(tree)
7.84 + return tree
7.85 +
7.86 + def compile(self):
7.87 + pass # implemented by subclass
7.88 +
7.89 + def getCode(self):
7.90 + return self.code
7.91 +
7.92 +class Expression(AbstractCompileMode):
7.93 +
7.94 + mode = "eval"
7.95 +
7.96 + def compile(self):
7.97 + tree = self._get_tree()
7.98 + gen = ExpressionCodeGenerator(tree)
7.99 + self.code = gen.getCode()
7.100 +
7.101 +class Interactive(AbstractCompileMode):
7.102 +
7.103 + mode = "single"
7.104 +
7.105 + def compile(self):
7.106 + tree = self._get_tree()
7.107 + gen = InteractiveCodeGenerator(tree)
7.108 + self.code = gen.getCode()
7.109 +
7.110 +class Module(AbstractCompileMode):
7.111 +
7.112 + mode = "exec"
7.113 +
7.114 + def compile(self, display=0):
7.115 + tree = self._get_tree()
7.116 + gen = ModuleCodeGenerator(tree)
7.117 + if display:
7.118 + import pprint
7.119 + print pprint.pprint(tree)
7.120 + self.code = gen.getCode()
7.121 +
7.122 + def dump(self, f):
7.123 + f.write(self.getPycHeader())
7.124 + marshal.dump(self.code, f)
7.125 +
7.126 + MAGIC = imp.get_magic()
7.127 +
7.128 + def getPycHeader(self):
7.129 + # compile.c uses marshal to write a long directly, with
7.130 + # calling the interface that would also generate a 1-byte code
7.131 + # to indicate the type of the value. simplest way to get the
7.132 + # same effect is to call marshal and then skip the code.
7.133 + mtime = os.path.getmtime(self.filename)
7.134 + mtime = struct.pack('<i', mtime)
7.135 + return self.MAGIC + mtime
7.136 +
7.137 +class LocalNameFinder:
7.138 + """Find local names in scope"""
7.139 + def __init__(self, names=()):
7.140 + self.names = misc.Set()
7.141 + self.globals = misc.Set()
7.142 + for name in names:
7.143 + self.names.add(name)
7.144 +
7.145 + # XXX list comprehensions and for loops
7.146 +
7.147 + def getLocals(self):
7.148 + for elt in self.globals.elements():
7.149 + if self.names.has_elt(elt):
7.150 + self.names.remove(elt)
7.151 + return self.names
7.152 +
7.153 + def visitDict(self, node):
7.154 + pass
7.155 +
7.156 + def visitGlobal(self, node):
7.157 + for name in node.names:
7.158 + self.globals.add(name)
7.159 +
7.160 + def visitFunction(self, node):
7.161 + self.names.add(node.name)
7.162 +
7.163 + def visitLambda(self, node):
7.164 + pass
7.165 +
7.166 + def visitImport(self, node):
7.167 + for name, alias in node.names:
7.168 + self.names.add(alias or name)
7.169 +
7.170 + def visitFrom(self, node):
7.171 + for name, alias in node.names:
7.172 + self.names.add(alias or name)
7.173 +
7.174 + def visitClass(self, node):
7.175 + self.names.add(node.name)
7.176 +
7.177 + def visitAssName(self, node):
7.178 + self.names.add(node.name)
7.179 +
7.180 +def is_constant_false(node):
7.181 + if isinstance(node, ast.Const):
7.182 + if not node.value:
7.183 + return 1
7.184 + return 0
7.185 +
7.186 +class CodeGenerator:
7.187 + """Defines basic code generator for Python bytecode
7.188 +
7.189 + This class is an abstract base class. Concrete subclasses must
7.190 + define an __init__() that defines self.graph and then calls the
7.191 + __init__() defined in this class.
7.192 +
7.193 + The concrete class must also define the class attributes
7.194 + NameFinder, FunctionGen, and ClassGen. These attributes can be
7.195 + defined in the initClass() method, which is a hook for
7.196 + initializing these methods after all the classes have been
7.197 + defined.
7.198 + """
7.199 +
7.200 + optimized = 0 # is namespace access optimized?
7.201 + __initialized = None
7.202 + class_name = None # provide default for instance variable
7.203 +
7.204 + def __init__(self):
7.205 + if self.__initialized is None:
7.206 + self.initClass()
7.207 + self.__class__.__initialized = 1
7.208 + self.checkClass()
7.209 + self.locals = misc.Stack()
7.210 + self.setups = misc.Stack()
7.211 + self.last_lineno = None
7.212 + self._setupGraphDelegation()
7.213 + self._div_op = "BINARY_DIVIDE"
7.214 +
7.215 + # XXX set flags based on future features
7.216 + futures = self.get_module().futures
7.217 + for feature in futures:
7.218 + if feature == "division":
7.219 + self.graph.setFlag(CO_FUTURE_DIVISION)
7.220 + self._div_op = "BINARY_TRUE_DIVIDE"
7.221 + elif feature == "absolute_import":
7.222 + self.graph.setFlag(CO_FUTURE_ABSIMPORT)
7.223 + elif feature == "with_statement":
7.224 + self.graph.setFlag(CO_FUTURE_WITH_STATEMENT)
7.225 + elif feature == "print_function":
7.226 + self.graph.setFlag(CO_FUTURE_PRINT_FUNCTION)
7.227 +
7.228 + def initClass(self):
7.229 + """This method is called once for each class"""
7.230 +
7.231 + def checkClass(self):
7.232 + """Verify that class is constructed correctly"""
7.233 + try:
7.234 + assert hasattr(self, 'graph')
7.235 + assert getattr(self, 'NameFinder')
7.236 + assert getattr(self, 'FunctionGen')
7.237 + assert getattr(self, 'ClassGen')
7.238 + except AssertionError, msg:
7.239 + intro = "Bad class construction for %s" % self.__class__.__name__
7.240 + raise AssertionError, intro
7.241 +
7.242 + def _setupGraphDelegation(self):
7.243 + self.emit = self.graph.emit
7.244 + self.newBlock = self.graph.newBlock
7.245 + self.startBlock = self.graph.startBlock
7.246 + self.nextBlock = self.graph.nextBlock
7.247 + self.setDocstring = self.graph.setDocstring
7.248 +
7.249 + def getCode(self):
7.250 + """Return a code object"""
7.251 + return self.graph.getCode()
7.252 +
7.253 + def mangle(self, name):
7.254 + if self.class_name is not None:
7.255 + return misc.mangle(name, self.class_name)
7.256 + else:
7.257 + return name
7.258 +
7.259 + def parseSymbols(self, tree):
7.260 + s = symbols.SymbolVisitor()
7.261 + walk(tree, s)
7.262 + return s.scopes
7.263 +
7.264 + def get_module(self):
7.265 + raise RuntimeError, "should be implemented by subclasses"
7.266 +
7.267 + # Next five methods handle name access
7.268 +
7.269 + def isLocalName(self, name):
7.270 + return self.locals.top().has_elt(name)
7.271 +
7.272 + def storeName(self, name):
7.273 + self._nameOp('STORE', name)
7.274 +
7.275 + def loadName(self, name):
7.276 + self._nameOp('LOAD', name)
7.277 +
7.278 + def delName(self, name):
7.279 + self._nameOp('DELETE', name)
7.280 +
7.281 + def _nameOp(self, prefix, name):
7.282 + name = self.mangle(name)
7.283 + scope = self.scope.check_name(name)
7.284 + if scope == SC_LOCAL:
7.285 + if not self.optimized:
7.286 + self.emit(prefix + '_NAME', name)
7.287 + else:
7.288 + self.emit(prefix + '_FAST', name)
7.289 + elif scope == SC_GLOBAL_EXPLICT:
7.290 + self.emit(prefix + '_GLOBAL', name)
7.291 + elif scope == SC_GLOBAL_IMPLICIT:
7.292 + if not self.optimized:
7.293 + self.emit(prefix + '_NAME', name)
7.294 + else:
7.295 + self.emit(prefix + '_GLOBAL', name)
7.296 + elif scope == SC_FREE or scope == SC_CELL:
7.297 + self.emit(prefix + '_DEREF', name)
7.298 + else:
7.299 + raise RuntimeError, "unsupported scope for var %s: %d" % \
7.300 + (name, scope)
7.301 +
7.302 + def _implicitNameOp(self, prefix, name):
7.303 + """Emit name ops for names generated implicitly by for loops
7.304 +
7.305 + The interpreter generates names that start with a period or
7.306 + dollar sign. The symbol table ignores these names because
7.307 + they aren't present in the program text.
7.308 + """
7.309 + if self.optimized:
7.310 + self.emit(prefix + '_FAST', name)
7.311 + else:
7.312 + self.emit(prefix + '_NAME', name)
7.313 +
7.314 + # The set_lineno() function and the explicit emit() calls for
7.315 + # SET_LINENO below are only used to generate the line number table.
7.316 + # As of Python 2.3, the interpreter does not have a SET_LINENO
7.317 + # instruction. pyassem treats SET_LINENO opcodes as a special case.
7.318 +
7.319 + def set_lineno(self, node, force=False):
7.320 + """Emit SET_LINENO if necessary.
7.321 +
7.322 + The instruction is considered necessary if the node has a
7.323 + lineno attribute and it is different than the last lineno
7.324 + emitted.
7.325 +
7.326 + Returns true if SET_LINENO was emitted.
7.327 +
7.328 + There are no rules for when an AST node should have a lineno
7.329 + attribute. The transformer and AST code need to be reviewed
7.330 + and a consistent policy implemented and documented. Until
7.331 + then, this method works around missing line numbers.
7.332 + """
7.333 + lineno = getattr(node, 'lineno', None)
7.334 + if lineno is not None and (lineno != self.last_lineno
7.335 + or force):
7.336 + self.emit('SET_LINENO', lineno)
7.337 + self.last_lineno = lineno
7.338 + return True
7.339 + return False
7.340 +
7.341 + # The first few visitor methods handle nodes that generator new
7.342 + # code objects. They use class attributes to determine what
7.343 + # specialized code generators to use.
7.344 +
7.345 + NameFinder = LocalNameFinder
7.346 + FunctionGen = None
7.347 + ClassGen = None
7.348 +
7.349 + def visitModule(self, node):
7.350 + self.scopes = self.parseSymbols(node)
7.351 + self.scope = self.scopes[node]
7.352 + self.emit('SET_LINENO', 0)
7.353 + if node.doc:
7.354 + self.emit('LOAD_CONST', node.doc)
7.355 + self.storeName('__doc__')
7.356 + lnf = walk(node.node, self.NameFinder(), verbose=0)
7.357 + self.locals.push(lnf.getLocals())
7.358 + self.visit(node.node)
7.359 + self.emit('LOAD_CONST', None)
7.360 + self.emit('RETURN_VALUE')
7.361 +
7.362 + def visitExpression(self, node):
7.363 + self.set_lineno(node)
7.364 + self.scopes = self.parseSymbols(node)
7.365 + self.scope = self.scopes[node]
7.366 + self.visit(node.node)
7.367 + self.emit('RETURN_VALUE')
7.368 +
7.369 + def visitFunction(self, node):
7.370 + self._visitFuncOrLambda(node, isLambda=0)
7.371 + if node.doc:
7.372 + self.setDocstring(node.doc)
7.373 + self.storeName(node.name)
7.374 +
7.375 + def visitLambda(self, node):
7.376 + self._visitFuncOrLambda(node, isLambda=1)
7.377 +
7.378 + def _visitFuncOrLambda(self, node, isLambda=0):
7.379 + if not isLambda and node.decorators:
7.380 + for decorator in node.decorators.nodes:
7.381 + self.visit(decorator)
7.382 + ndecorators = len(node.decorators.nodes)
7.383 + else:
7.384 + ndecorators = 0
7.385 +
7.386 + gen = self.FunctionGen(node, self.scopes, isLambda,
7.387 + self.class_name, self.get_module())
7.388 + walk(node.code, gen)
7.389 + gen.finish()
7.390 + self.set_lineno(node)
7.391 + for default in node.defaults:
7.392 + self.visit(default)
7.393 + self._makeClosure(gen, len(node.defaults))
7.394 + for i in range(ndecorators):
7.395 + self.emit('CALL_FUNCTION', 1)
7.396 +
7.397 + def visitClass(self, node):
7.398 + gen = self.ClassGen(node, self.scopes,
7.399 + self.get_module())
7.400 + walk(node.code, gen)
7.401 + gen.finish()
7.402 + self.set_lineno(node)
7.403 + self.emit('LOAD_CONST', node.name)
7.404 + for base in node.bases:
7.405 + self.visit(base)
7.406 + self.emit('BUILD_TUPLE', len(node.bases))
7.407 + self._makeClosure(gen, 0)
7.408 + self.emit('CALL_FUNCTION', 0)
7.409 + self.emit('BUILD_CLASS')
7.410 + self.storeName(node.name)
7.411 +
7.412 + # The rest are standard visitor methods
7.413 +
7.414 + # The next few implement control-flow statements
7.415 +
7.416 + def visitIf(self, node):
7.417 + end = self.newBlock()
7.418 + numtests = len(node.tests)
7.419 + for i in range(numtests):
7.420 + test, suite = node.tests[i]
7.421 + if is_constant_false(test):
7.422 + # XXX will need to check generator stuff here
7.423 + continue
7.424 + self.set_lineno(test)
7.425 + self.visit(test)
7.426 + nextTest = self.newBlock()
7.427 + self.emit('POP_JUMP_IF_FALSE', nextTest)
7.428 + self.nextBlock()
7.429 + self.visit(suite)
7.430 + self.emit('JUMP_FORWARD', end)
7.431 + self.startBlock(nextTest)
7.432 + if node.else_:
7.433 + self.visit(node.else_)
7.434 + self.nextBlock(end)
7.435 +
7.436 + def visitWhile(self, node):
7.437 + self.set_lineno(node)
7.438 +
7.439 + loop = self.newBlock()
7.440 + else_ = self.newBlock()
7.441 +
7.442 + after = self.newBlock()
7.443 + self.emit('SETUP_LOOP', after)
7.444 +
7.445 + self.nextBlock(loop)
7.446 + self.setups.push((LOOP, loop))
7.447 +
7.448 + self.set_lineno(node, force=True)
7.449 + self.visit(node.test)
7.450 + self.emit('POP_JUMP_IF_FALSE', else_ or after)
7.451 +
7.452 + self.nextBlock()
7.453 + self.visit(node.body)
7.454 + self.emit('JUMP_ABSOLUTE', loop)
7.455 +
7.456 + self.startBlock(else_) # or just the POPs if not else clause
7.457 + self.emit('POP_BLOCK')
7.458 + self.setups.pop()
7.459 + if node.else_:
7.460 + self.visit(node.else_)
7.461 + self.nextBlock(after)
7.462 +
7.463 + def visitFor(self, node):
7.464 + start = self.newBlock()
7.465 + anchor = self.newBlock()
7.466 + after = self.newBlock()
7.467 + self.setups.push((LOOP, start))
7.468 +
7.469 + self.set_lineno(node)
7.470 + self.emit('SETUP_LOOP', after)
7.471 + self.visit(node.list)
7.472 + self.emit('GET_ITER')
7.473 +
7.474 + self.nextBlock(start)
7.475 + self.set_lineno(node, force=1)
7.476 + self.emit('FOR_ITER', anchor)
7.477 + self.visit(node.assign)
7.478 + self.visit(node.body)
7.479 + self.emit('JUMP_ABSOLUTE', start)
7.480 + self.nextBlock(anchor)
7.481 + self.emit('POP_BLOCK')
7.482 + self.setups.pop()
7.483 + if node.else_:
7.484 + self.visit(node.else_)
7.485 + self.nextBlock(after)
7.486 +
7.487 + def visitBreak(self, node):
7.488 + if not self.setups:
7.489 + raise SyntaxError, "'break' outside loop (%s, %d)" % \
7.490 + (node.filename, node.lineno)
7.491 + self.set_lineno(node)
7.492 + self.emit('BREAK_LOOP')
7.493 +
7.494 + def visitContinue(self, node):
7.495 + if not self.setups:
7.496 + raise SyntaxError, "'continue' outside loop (%s, %d)" % \
7.497 + (node.filename, node.lineno)
7.498 + kind, block = self.setups.top()
7.499 + if kind == LOOP:
7.500 + self.set_lineno(node)
7.501 + self.emit('JUMP_ABSOLUTE', block)
7.502 + self.nextBlock()
7.503 + elif kind == EXCEPT or kind == TRY_FINALLY:
7.504 + self.set_lineno(node)
7.505 + # find the block that starts the loop
7.506 + top = len(self.setups)
7.507 + while top > 0:
7.508 + top = top - 1
7.509 + kind, loop_block = self.setups[top]
7.510 + if kind == LOOP:
7.511 + break
7.512 + if kind != LOOP:
7.513 + raise SyntaxError, "'continue' outside loop (%s, %d)" % \
7.514 + (node.filename, node.lineno)
7.515 + self.emit('CONTINUE_LOOP', loop_block)
7.516 + self.nextBlock()
7.517 + elif kind == END_FINALLY:
7.518 + msg = "'continue' not allowed inside 'finally' clause (%s, %d)"
7.519 + raise SyntaxError, msg % (node.filename, node.lineno)
7.520 +
7.521 + def visitTest(self, node, jump):
7.522 + end = self.newBlock()
7.523 + for child in node.nodes[:-1]:
7.524 + self.visit(child)
7.525 + self.emit(jump, end)
7.526 + self.nextBlock()
7.527 + self.visit(node.nodes[-1])
7.528 + self.nextBlock(end)
7.529 +
7.530 + def visitAnd(self, node):
7.531 + self.visitTest(node, 'JUMP_IF_FALSE_OR_POP')
7.532 +
7.533 + def visitOr(self, node):
7.534 + self.visitTest(node, 'JUMP_IF_TRUE_OR_POP')
7.535 +
7.536 + def visitIfExp(self, node):
7.537 + endblock = self.newBlock()
7.538 + elseblock = self.newBlock()
7.539 + self.visit(node.test)
7.540 + self.emit('POP_JUMP_IF_FALSE', elseblock)
7.541 + self.visit(node.then)
7.542 + self.emit('JUMP_FORWARD', endblock)
7.543 + self.nextBlock(elseblock)
7.544 + self.visit(node.else_)
7.545 + self.nextBlock(endblock)
7.546 +
7.547 + def visitCompare(self, node):
7.548 + self.visit(node.expr)
7.549 + cleanup = self.newBlock()
7.550 + for op, code in node.ops[:-1]:
7.551 + self.visit(code)
7.552 + self.emit('DUP_TOP')
7.553 + self.emit('ROT_THREE')
7.554 + self.emit('COMPARE_OP', op)
7.555 + self.emit('JUMP_IF_FALSE_OR_POP', cleanup)
7.556 + self.nextBlock()
7.557 + # now do the last comparison
7.558 + if node.ops:
7.559 + op, code = node.ops[-1]
7.560 + self.visit(code)
7.561 + self.emit('COMPARE_OP', op)
7.562 + if len(node.ops) > 1:
7.563 + end = self.newBlock()
7.564 + self.emit('JUMP_FORWARD', end)
7.565 + self.startBlock(cleanup)
7.566 + self.emit('ROT_TWO')
7.567 + self.emit('POP_TOP')
7.568 + self.nextBlock(end)
7.569 +
7.570 + # list comprehensions
7.571 + def visitListComp(self, node):
7.572 + self.set_lineno(node)
7.573 + # setup list
7.574 + self.emit('BUILD_LIST', 0)
7.575 +
7.576 + stack = []
7.577 + for i, for_ in zip(range(len(node.quals)), node.quals):
7.578 + start, anchor = self.visit(for_)
7.579 + cont = None
7.580 + for if_ in for_.ifs:
7.581 + if cont is None:
7.582 + cont = self.newBlock()
7.583 + self.visit(if_, cont)
7.584 + stack.insert(0, (start, cont, anchor))
7.585 +
7.586 + self.visit(node.expr)
7.587 + self.emit('LIST_APPEND', len(node.quals) + 1)
7.588 +
7.589 + for start, cont, anchor in stack:
7.590 + if cont:
7.591 + self.nextBlock(cont)
7.592 + self.emit('JUMP_ABSOLUTE', start)
7.593 + self.startBlock(anchor)
7.594 +
7.595 + def visitSetComp(self, node):
7.596 + self.set_lineno(node)
7.597 + # setup list
7.598 + self.emit('BUILD_SET', 0)
7.599 +
7.600 + stack = []
7.601 + for i, for_ in zip(range(len(node.quals)), node.quals):
7.602 + start, anchor = self.visit(for_)
7.603 + cont = None
7.604 + for if_ in for_.ifs:
7.605 + if cont is None:
7.606 + cont = self.newBlock()
7.607 + self.visit(if_, cont)
7.608 + stack.insert(0, (start, cont, anchor))
7.609 +
7.610 + self.visit(node.expr)
7.611 + self.emit('SET_ADD', len(node.quals) + 1)
7.612 +
7.613 + for start, cont, anchor in stack:
7.614 + if cont:
7.615 + self.nextBlock(cont)
7.616 + self.emit('JUMP_ABSOLUTE', start)
7.617 + self.startBlock(anchor)
7.618 +
7.619 + def visitDictComp(self, node):
7.620 + self.set_lineno(node)
7.621 + # setup list
7.622 + self.emit('BUILD_MAP', 0)
7.623 +
7.624 + stack = []
7.625 + for i, for_ in zip(range(len(node.quals)), node.quals):
7.626 + start, anchor = self.visit(for_)
7.627 + cont = None
7.628 + for if_ in for_.ifs:
7.629 + if cont is None:
7.630 + cont = self.newBlock()
7.631 + self.visit(if_, cont)
7.632 + stack.insert(0, (start, cont, anchor))
7.633 +
7.634 + self.visit(node.value)
7.635 + self.visit(node.key)
7.636 + self.emit('MAP_ADD', len(node.quals) + 1)
7.637 +
7.638 + for start, cont, anchor in stack:
7.639 + if cont:
7.640 + self.nextBlock(cont)
7.641 + self.emit('JUMP_ABSOLUTE', start)
7.642 + self.startBlock(anchor)
7.643 +
7.644 + def visitListCompFor(self, node):
7.645 + start = self.newBlock()
7.646 + anchor = self.newBlock()
7.647 +
7.648 + self.visit(node.list)
7.649 + self.emit('GET_ITER')
7.650 + self.nextBlock(start)
7.651 + self.set_lineno(node, force=True)
7.652 + self.emit('FOR_ITER', anchor)
7.653 + self.nextBlock()
7.654 + self.visit(node.assign)
7.655 + return start, anchor
7.656 +
7.657 + def visitListCompIf(self, node, branch):
7.658 + self.set_lineno(node, force=True)
7.659 + self.visit(node.test)
7.660 + self.emit('POP_JUMP_IF_FALSE', branch)
7.661 + self.newBlock()
7.662 +
7.663 + def _makeClosure(self, gen, args):
7.664 + frees = gen.scope.get_free_vars()
7.665 + if frees:
7.666 + for name in frees:
7.667 + self.emit('LOAD_CLOSURE', name)
7.668 + self.emit('BUILD_TUPLE', len(frees))
7.669 + self.emit('LOAD_CONST', gen)
7.670 + self.emit('MAKE_CLOSURE', args)
7.671 + else:
7.672 + self.emit('LOAD_CONST', gen)
7.673 + self.emit('MAKE_FUNCTION', args)
7.674 +
7.675 + def visitGenExpr(self, node):
7.676 + gen = GenExprCodeGenerator(node, self.scopes, self.class_name,
7.677 + self.get_module())
7.678 + walk(node.code, gen)
7.679 + gen.finish()
7.680 + self.set_lineno(node)
7.681 + self._makeClosure(gen, 0)
7.682 + # precomputation of outmost iterable
7.683 + self.visit(node.code.quals[0].iter)
7.684 + self.emit('GET_ITER')
7.685 + self.emit('CALL_FUNCTION', 1)
7.686 +
7.687 + def visitGenExprInner(self, node):
7.688 + self.set_lineno(node)
7.689 + # setup list
7.690 +
7.691 + stack = []
7.692 + for i, for_ in zip(range(len(node.quals)), node.quals):
7.693 + start, anchor, end = self.visit(for_)
7.694 + cont = None
7.695 + for if_ in for_.ifs:
7.696 + if cont is None:
7.697 + cont = self.newBlock()
7.698 + self.visit(if_, cont)
7.699 + stack.insert(0, (start, cont, anchor, end))
7.700 +
7.701 + self.visit(node.expr)
7.702 + self.emit('YIELD_VALUE')
7.703 + self.emit('POP_TOP')
7.704 +
7.705 + for start, cont, anchor, end in stack:
7.706 + if cont:
7.707 + self.nextBlock(cont)
7.708 + self.emit('JUMP_ABSOLUTE', start)
7.709 + self.startBlock(anchor)
7.710 + self.emit('POP_BLOCK')
7.711 + self.setups.pop()
7.712 + self.nextBlock(end)
7.713 +
7.714 + self.emit('LOAD_CONST', None)
7.715 +
7.716 + def visitGenExprFor(self, node):
7.717 + start = self.newBlock()
7.718 + anchor = self.newBlock()
7.719 + end = self.newBlock()
7.720 +
7.721 + self.setups.push((LOOP, start))
7.722 + self.emit('SETUP_LOOP', end)
7.723 +
7.724 + if node.is_outmost:
7.725 + self.loadName('.0')
7.726 + else:
7.727 + self.visit(node.iter)
7.728 + self.emit('GET_ITER')
7.729 +
7.730 + self.nextBlock(start)
7.731 + self.set_lineno(node, force=True)
7.732 + self.emit('FOR_ITER', anchor)
7.733 + self.nextBlock()
7.734 + self.visit(node.assign)
7.735 + return start, anchor, end
7.736 +
7.737 + def visitGenExprIf(self, node, branch):
7.738 + self.set_lineno(node, force=True)
7.739 + self.visit(node.test)
7.740 + self.emit('POP_JUMP_IF_FALSE', branch)
7.741 + self.newBlock()
7.742 +
7.743 + # exception related
7.744 +
7.745 + def visitAssert(self, node):
7.746 + # XXX would be interesting to implement this via a
7.747 + # transformation of the AST before this stage
7.748 + if __debug__:
7.749 + end = self.newBlock()
7.750 + self.set_lineno(node)
7.751 + # XXX AssertionError appears to be special case -- it is always
7.752 + # loaded as a global even if there is a local name. I guess this
7.753 + # is a sort of renaming op.
7.754 + self.nextBlock()
7.755 + self.visit(node.test)
7.756 + self.emit('POP_JUMP_IF_TRUE', end)
7.757 + self.nextBlock()
7.758 + self.emit('LOAD_GLOBAL', 'AssertionError')
7.759 + if node.fail:
7.760 + self.visit(node.fail)
7.761 + self.emit('RAISE_VARARGS', 2)
7.762 + else:
7.763 + self.emit('RAISE_VARARGS', 1)
7.764 + self.nextBlock(end)
7.765 +
7.766 + def visitRaise(self, node):
7.767 + self.set_lineno(node)
7.768 + n = 0
7.769 + if node.expr1:
7.770 + self.visit(node.expr1)
7.771 + n = n + 1
7.772 + if node.expr2:
7.773 + self.visit(node.expr2)
7.774 + n = n + 1
7.775 + if node.expr3:
7.776 + self.visit(node.expr3)
7.777 + n = n + 1
7.778 + self.emit('RAISE_VARARGS', n)
7.779 +
7.780 + def visitTryExcept(self, node):
7.781 + body = self.newBlock()
7.782 + handlers = self.newBlock()
7.783 + end = self.newBlock()
7.784 + if node.else_:
7.785 + lElse = self.newBlock()
7.786 + else:
7.787 + lElse = end
7.788 + self.set_lineno(node)
7.789 + self.emit('SETUP_EXCEPT', handlers)
7.790 + self.nextBlock(body)
7.791 + self.setups.push((EXCEPT, body))
7.792 + self.visit(node.body)
7.793 + self.emit('POP_BLOCK')
7.794 + self.setups.pop()
7.795 + self.emit('JUMP_FORWARD', lElse)
7.796 + self.startBlock(handlers)
7.797 +
7.798 + last = len(node.handlers) - 1
7.799 + for i in range(len(node.handlers)):
7.800 + expr, target, body = node.handlers[i]
7.801 + self.set_lineno(expr)
7.802 + if expr:
7.803 + self.emit('DUP_TOP')
7.804 + self.visit(expr)
7.805 + self.emit('COMPARE_OP', 'exception match')
7.806 + next = self.newBlock()
7.807 + self.emit('POP_JUMP_IF_FALSE', next)
7.808 + self.nextBlock()
7.809 + self.emit('POP_TOP')
7.810 + if target:
7.811 + self.visit(target)
7.812 + else:
7.813 + self.emit('POP_TOP')
7.814 + self.emit('POP_TOP')
7.815 + self.visit(body)
7.816 + self.emit('JUMP_FORWARD', end)
7.817 + if expr:
7.818 + self.nextBlock(next)
7.819 + else:
7.820 + self.nextBlock()
7.821 + self.emit('END_FINALLY')
7.822 + if node.else_:
7.823 + self.nextBlock(lElse)
7.824 + self.visit(node.else_)
7.825 + self.nextBlock(end)
7.826 +
7.827 + def visitTryFinally(self, node):
7.828 + body = self.newBlock()
7.829 + final = self.newBlock()
7.830 + self.set_lineno(node)
7.831 + self.emit('SETUP_FINALLY', final)
7.832 + self.nextBlock(body)
7.833 + self.setups.push((TRY_FINALLY, body))
7.834 + self.visit(node.body)
7.835 + self.emit('POP_BLOCK')
7.836 + self.setups.pop()
7.837 + self.emit('LOAD_CONST', None)
7.838 + self.nextBlock(final)
7.839 + self.setups.push((END_FINALLY, final))
7.840 + self.visit(node.final)
7.841 + self.emit('END_FINALLY')
7.842 + self.setups.pop()
7.843 +
7.844 + __with_count = 0
7.845 +
7.846 + def visitWith(self, node):
7.847 + body = self.newBlock()
7.848 + final = self.newBlock()
7.849 + self.__with_count += 1
7.850 + valuevar = "_[%d]" % self.__with_count
7.851 + self.set_lineno(node)
7.852 + self.visit(node.expr)
7.853 + self.emit('DUP_TOP')
7.854 + self.emit('LOAD_ATTR', '__exit__')
7.855 + self.emit('ROT_TWO')
7.856 + self.emit('LOAD_ATTR', '__enter__')
7.857 + self.emit('CALL_FUNCTION', 0)
7.858 + if node.vars is None:
7.859 + self.emit('POP_TOP')
7.860 + else:
7.861 + self._implicitNameOp('STORE', valuevar)
7.862 + self.emit('SETUP_FINALLY', final)
7.863 + self.nextBlock(body)
7.864 + self.setups.push((TRY_FINALLY, body))
7.865 + if node.vars is not None:
7.866 + self._implicitNameOp('LOAD', valuevar)
7.867 + self._implicitNameOp('DELETE', valuevar)
7.868 + self.visit(node.vars)
7.869 + self.visit(node.body)
7.870 + self.emit('POP_BLOCK')
7.871 + self.setups.pop()
7.872 + self.emit('LOAD_CONST', None)
7.873 + self.nextBlock(final)
7.874 + self.setups.push((END_FINALLY, final))
7.875 + self.emit('WITH_CLEANUP')
7.876 + self.emit('END_FINALLY')
7.877 + self.setups.pop()
7.878 + self.__with_count -= 1
7.879 +
7.880 + # misc
7.881 +
7.882 + def visitDiscard(self, node):
7.883 + self.set_lineno(node)
7.884 + self.visit(node.expr)
7.885 + self.emit('POP_TOP')
7.886 +
7.887 + def visitConst(self, node):
7.888 + self.emit('LOAD_CONST', node.value)
7.889 +
7.890 + def visitKeyword(self, node):
7.891 + self.emit('LOAD_CONST', node.name)
7.892 + self.visit(node.expr)
7.893 +
7.894 + def visitGlobal(self, node):
7.895 + # no code to generate
7.896 + pass
7.897 +
7.898 + def visitName(self, node):
7.899 + self.set_lineno(node)
7.900 + self.loadName(node.name)
7.901 +
7.902 + def visitPass(self, node):
7.903 + self.set_lineno(node)
7.904 +
7.905 + def visitImport(self, node):
7.906 + self.set_lineno(node)
7.907 + level = 0 if self.graph.checkFlag(CO_FUTURE_ABSIMPORT) else -1
7.908 + for name, alias in node.names:
7.909 + if VERSION > 1:
7.910 + self.emit('LOAD_CONST', level)
7.911 + self.emit('LOAD_CONST', None)
7.912 + self.emit('IMPORT_NAME', name)
7.913 + mod = name.split(".")[0]
7.914 + if alias:
7.915 + self._resolveDots(name)
7.916 + self.storeName(alias)
7.917 + else:
7.918 + self.storeName(mod)
7.919 +
7.920 + def visitFrom(self, node):
7.921 + self.set_lineno(node)
7.922 + level = node.level
7.923 + if level == 0 and not self.graph.checkFlag(CO_FUTURE_ABSIMPORT):
7.924 + level = -1
7.925 + fromlist = tuple(name for (name, alias) in node.names)
7.926 + if VERSION > 1:
7.927 + self.emit('LOAD_CONST', level)
7.928 + self.emit('LOAD_CONST', fromlist)
7.929 + self.emit('IMPORT_NAME', node.modname)
7.930 + for name, alias in node.names:
7.931 + if VERSION > 1:
7.932 + if name == '*':
7.933 + self.namespace = 0
7.934 + self.emit('IMPORT_STAR')
7.935 + # There can only be one name w/ from ... import *
7.936 + assert len(node.names) == 1
7.937 + return
7.938 + else:
7.939 + self.emit('IMPORT_FROM', name)
7.940 + self._resolveDots(name)
7.941 + self.storeName(alias or name)
7.942 + else:
7.943 + self.emit('IMPORT_FROM', name)
7.944 + self.emit('POP_TOP')
7.945 +
7.946 + def _resolveDots(self, name):
7.947 + elts = name.split(".")
7.948 + if len(elts) == 1:
7.949 + return
7.950 + for elt in elts[1:]:
7.951 + self.emit('LOAD_ATTR', elt)
7.952 +
7.953 + def visitGetattr(self, node):
7.954 + self.visit(node.expr)
7.955 + self.emit('LOAD_ATTR', self.mangle(node.attrname))
7.956 +
7.957 + # next five implement assignments
7.958 +
7.959 + def visitAssign(self, node):
7.960 + self.set_lineno(node)
7.961 + self.visit(node.expr)
7.962 + dups = len(node.nodes) - 1
7.963 + for i in range(len(node.nodes)):
7.964 + elt = node.nodes[i]
7.965 + if i < dups:
7.966 + self.emit('DUP_TOP')
7.967 + if isinstance(elt, ast.Node):
7.968 + self.visit(elt)
7.969 +
7.970 + def visitAssName(self, node):
7.971 + if node.flags == 'OP_ASSIGN':
7.972 + self.storeName(node.name)
7.973 + elif node.flags == 'OP_DELETE':
7.974 + self.set_lineno(node)
7.975 + self.delName(node.name)
7.976 + else:
7.977 + print "oops", node.flags
7.978 +
7.979 + def visitAssAttr(self, node):
7.980 + self.visit(node.expr)
7.981 + if node.flags == 'OP_ASSIGN':
7.982 + self.emit('STORE_ATTR', self.mangle(node.attrname))
7.983 + elif node.flags == 'OP_DELETE':
7.984 + self.emit('DELETE_ATTR', self.mangle(node.attrname))
7.985 + else:
7.986 + print "warning: unexpected flags:", node.flags
7.987 + print node
7.988 +
7.989 + def _visitAssSequence(self, node, op='UNPACK_SEQUENCE'):
7.990 + if findOp(node) != 'OP_DELETE':
7.991 + self.emit(op, len(node.nodes))
7.992 + for child in node.nodes:
7.993 + self.visit(child)
7.994 +
7.995 + if VERSION > 1:
7.996 + visitAssTuple = _visitAssSequence
7.997 + visitAssList = _visitAssSequence
7.998 + else:
7.999 + def visitAssTuple(self, node):
7.1000 + self._visitAssSequence(node, 'UNPACK_TUPLE')
7.1001 +
7.1002 + def visitAssList(self, node):
7.1003 + self._visitAssSequence(node, 'UNPACK_LIST')
7.1004 +
7.1005 + # augmented assignment
7.1006 +
7.1007 + def visitAugAssign(self, node):
7.1008 + self.set_lineno(node)
7.1009 + aug_node = wrap_aug(node.node)
7.1010 + self.visit(aug_node, "load")
7.1011 + self.visit(node.expr)
7.1012 + self.emit(self._augmented_opcode[node.op])
7.1013 + self.visit(aug_node, "store")
7.1014 +
7.1015 + _augmented_opcode = {
7.1016 + '+=' : 'INPLACE_ADD',
7.1017 + '-=' : 'INPLACE_SUBTRACT',
7.1018 + '*=' : 'INPLACE_MULTIPLY',
7.1019 + '/=' : 'INPLACE_DIVIDE',
7.1020 + '//=': 'INPLACE_FLOOR_DIVIDE',
7.1021 + '%=' : 'INPLACE_MODULO',
7.1022 + '**=': 'INPLACE_POWER',
7.1023 + '>>=': 'INPLACE_RSHIFT',
7.1024 + '<<=': 'INPLACE_LSHIFT',
7.1025 + '&=' : 'INPLACE_AND',
7.1026 + '^=' : 'INPLACE_XOR',
7.1027 + '|=' : 'INPLACE_OR',
7.1028 + }
7.1029 +
7.1030 + def visitAugName(self, node, mode):
7.1031 + if mode == "load":
7.1032 + self.loadName(node.name)
7.1033 + elif mode == "store":
7.1034 + self.storeName(node.name)
7.1035 +
7.1036 + def visitAugGetattr(self, node, mode):
7.1037 + if mode == "load":
7.1038 + self.visit(node.expr)
7.1039 + self.emit('DUP_TOP')
7.1040 + self.emit('LOAD_ATTR', self.mangle(node.attrname))
7.1041 + elif mode == "store":
7.1042 + self.emit('ROT_TWO')
7.1043 + self.emit('STORE_ATTR', self.mangle(node.attrname))
7.1044 +
7.1045 + def visitAugSlice(self, node, mode):
7.1046 + if mode == "load":
7.1047 + self.visitSlice(node, 1)
7.1048 + elif mode == "store":
7.1049 + slice = 0
7.1050 + if node.lower:
7.1051 + slice = slice | 1
7.1052 + if node.upper:
7.1053 + slice = slice | 2
7.1054 + if slice == 0:
7.1055 + self.emit('ROT_TWO')
7.1056 + elif slice == 3:
7.1057 + self.emit('ROT_FOUR')
7.1058 + else:
7.1059 + self.emit('ROT_THREE')
7.1060 + self.emit('STORE_SLICE+%d' % slice)
7.1061 +
7.1062 + def visitAugSubscript(self, node, mode):
7.1063 + if mode == "load":
7.1064 + self.visitSubscript(node, 1)
7.1065 + elif mode == "store":
7.1066 + self.emit('ROT_THREE')
7.1067 + self.emit('STORE_SUBSCR')
7.1068 +
7.1069 + def visitExec(self, node):
7.1070 + self.visit(node.expr)
7.1071 + if node.locals is None:
7.1072 + self.emit('LOAD_CONST', None)
7.1073 + else:
7.1074 + self.visit(node.locals)
7.1075 + if node.globals is None:
7.1076 + self.emit('DUP_TOP')
7.1077 + else:
7.1078 + self.visit(node.globals)
7.1079 + self.emit('EXEC_STMT')
7.1080 +
7.1081 + def visitCallFunc(self, node):
7.1082 + pos = 0
7.1083 + kw = 0
7.1084 + self.set_lineno(node)
7.1085 + self.visit(node.node)
7.1086 + for arg in node.args:
7.1087 + self.visit(arg)
7.1088 + if isinstance(arg, ast.Keyword):
7.1089 + kw = kw + 1
7.1090 + else:
7.1091 + pos = pos + 1
7.1092 + if node.star_args is not None:
7.1093 + self.visit(node.star_args)
7.1094 + if node.dstar_args is not None:
7.1095 + self.visit(node.dstar_args)
7.1096 + have_star = node.star_args is not None
7.1097 + have_dstar = node.dstar_args is not None
7.1098 + opcode = callfunc_opcode_info[have_star, have_dstar]
7.1099 + self.emit(opcode, kw << 8 | pos)
7.1100 +
7.1101 + def visitPrint(self, node, newline=0):
7.1102 + self.set_lineno(node)
7.1103 + if node.dest:
7.1104 + self.visit(node.dest)
7.1105 + for child in node.nodes:
7.1106 + if node.dest:
7.1107 + self.emit('DUP_TOP')
7.1108 + self.visit(child)
7.1109 + if node.dest:
7.1110 + self.emit('ROT_TWO')
7.1111 + self.emit('PRINT_ITEM_TO')
7.1112 + else:
7.1113 + self.emit('PRINT_ITEM')
7.1114 + if node.dest and not newline:
7.1115 + self.emit('POP_TOP')
7.1116 +
7.1117 + def visitPrintnl(self, node):
7.1118 + self.visitPrint(node, newline=1)
7.1119 + if node.dest:
7.1120 + self.emit('PRINT_NEWLINE_TO')
7.1121 + else:
7.1122 + self.emit('PRINT_NEWLINE')
7.1123 +
7.1124 + def visitReturn(self, node):
7.1125 + self.set_lineno(node)
7.1126 + self.visit(node.value)
7.1127 + self.emit('RETURN_VALUE')
7.1128 +
7.1129 + def visitYield(self, node):
7.1130 + self.set_lineno(node)
7.1131 + self.visit(node.value)
7.1132 + self.emit('YIELD_VALUE')
7.1133 +
7.1134 + # slice and subscript stuff
7.1135 +
7.1136 + def visitSlice(self, node, aug_flag=None):
7.1137 + # aug_flag is used by visitAugSlice
7.1138 + self.visit(node.expr)
7.1139 + slice = 0
7.1140 + if node.lower:
7.1141 + self.visit(node.lower)
7.1142 + slice = slice | 1
7.1143 + if node.upper:
7.1144 + self.visit(node.upper)
7.1145 + slice = slice | 2
7.1146 + if aug_flag:
7.1147 + if slice == 0:
7.1148 + self.emit('DUP_TOP')
7.1149 + elif slice == 3:
7.1150 + self.emit('DUP_TOPX', 3)
7.1151 + else:
7.1152 + self.emit('DUP_TOPX', 2)
7.1153 + if node.flags == 'OP_APPLY':
7.1154 + self.emit('SLICE+%d' % slice)
7.1155 + elif node.flags == 'OP_ASSIGN':
7.1156 + self.emit('STORE_SLICE+%d' % slice)
7.1157 + elif node.flags == 'OP_DELETE':
7.1158 + self.emit('DELETE_SLICE+%d' % slice)
7.1159 + else:
7.1160 + print "weird slice", node.flags
7.1161 + raise
7.1162 +
7.1163 + def visitSubscript(self, node, aug_flag=None):
7.1164 + self.visit(node.expr)
7.1165 + for sub in node.subs:
7.1166 + self.visit(sub)
7.1167 + if len(node.subs) > 1:
7.1168 + self.emit('BUILD_TUPLE', len(node.subs))
7.1169 + if aug_flag:
7.1170 + self.emit('DUP_TOPX', 2)
7.1171 + if node.flags == 'OP_APPLY':
7.1172 + self.emit('BINARY_SUBSCR')
7.1173 + elif node.flags == 'OP_ASSIGN':
7.1174 + self.emit('STORE_SUBSCR')
7.1175 + elif node.flags == 'OP_DELETE':
7.1176 + self.emit('DELETE_SUBSCR')
7.1177 +
7.1178 + # binary ops
7.1179 +
7.1180 + def binaryOp(self, node, op):
7.1181 + self.visit(node.left)
7.1182 + self.visit(node.right)
7.1183 + self.emit(op)
7.1184 +
7.1185 + def visitAdd(self, node):
7.1186 + return self.binaryOp(node, 'BINARY_ADD')
7.1187 +
7.1188 + def visitSub(self, node):
7.1189 + return self.binaryOp(node, 'BINARY_SUBTRACT')
7.1190 +
7.1191 + def visitMul(self, node):
7.1192 + return self.binaryOp(node, 'BINARY_MULTIPLY')
7.1193 +
7.1194 + def visitDiv(self, node):
7.1195 + return self.binaryOp(node, self._div_op)
7.1196 +
7.1197 + def visitFloorDiv(self, node):
7.1198 + return self.binaryOp(node, 'BINARY_FLOOR_DIVIDE')
7.1199 +
7.1200 + def visitMod(self, node):
7.1201 + return self.binaryOp(node, 'BINARY_MODULO')
7.1202 +
7.1203 + def visitPower(self, node):
7.1204 + return self.binaryOp(node, 'BINARY_POWER')
7.1205 +
7.1206 + def visitLeftShift(self, node):
7.1207 + return self.binaryOp(node, 'BINARY_LSHIFT')
7.1208 +
7.1209 + def visitRightShift(self, node):
7.1210 + return self.binaryOp(node, 'BINARY_RSHIFT')
7.1211 +
7.1212 + # unary ops
7.1213 +
7.1214 + def unaryOp(self, node, op):
7.1215 + self.visit(node.expr)
7.1216 + self.emit(op)
7.1217 +
7.1218 + def visitInvert(self, node):
7.1219 + return self.unaryOp(node, 'UNARY_INVERT')
7.1220 +
7.1221 + def visitUnarySub(self, node):
7.1222 + return self.unaryOp(node, 'UNARY_NEGATIVE')
7.1223 +
7.1224 + def visitUnaryAdd(self, node):
7.1225 + return self.unaryOp(node, 'UNARY_POSITIVE')
7.1226 +
7.1227 + def visitUnaryInvert(self, node):
7.1228 + return self.unaryOp(node, 'UNARY_INVERT')
7.1229 +
7.1230 + def visitNot(self, node):
7.1231 + return self.unaryOp(node, 'UNARY_NOT')
7.1232 +
7.1233 + def visitBackquote(self, node):
7.1234 + return self.unaryOp(node, 'UNARY_CONVERT')
7.1235 +
7.1236 + # bit ops
7.1237 +
7.1238 + def bitOp(self, nodes, op):
7.1239 + self.visit(nodes[0])
7.1240 + for node in nodes[1:]:
7.1241 + self.visit(node)
7.1242 + self.emit(op)
7.1243 +
7.1244 + def visitBitand(self, node):
7.1245 + return self.bitOp(node.nodes, 'BINARY_AND')
7.1246 +
7.1247 + def visitBitor(self, node):
7.1248 + return self.bitOp(node.nodes, 'BINARY_OR')
7.1249 +
7.1250 + def visitBitxor(self, node):
7.1251 + return self.bitOp(node.nodes, 'BINARY_XOR')
7.1252 +
7.1253 + # object constructors
7.1254 +
7.1255 + def visitEllipsis(self, node):
7.1256 + self.emit('LOAD_CONST', Ellipsis)
7.1257 +
7.1258 + def visitTuple(self, node):
7.1259 + self.set_lineno(node)
7.1260 + for elt in node.nodes:
7.1261 + self.visit(elt)
7.1262 + self.emit('BUILD_TUPLE', len(node.nodes))
7.1263 +
7.1264 + def visitList(self, node):
7.1265 + self.set_lineno(node)
7.1266 + for elt in node.nodes:
7.1267 + self.visit(elt)
7.1268 + self.emit('BUILD_LIST', len(node.nodes))
7.1269 +
7.1270 + def visitSet(self, node):
7.1271 + self.set_lineno(node)
7.1272 + for elt in node.nodes:
7.1273 + self.visit(elt)
7.1274 + self.emit('BUILD_SET', len(node.nodes))
7.1275 +
7.1276 + def visitSliceobj(self, node):
7.1277 + for child in node.nodes:
7.1278 + self.visit(child)
7.1279 + self.emit('BUILD_SLICE', len(node.nodes))
7.1280 +
7.1281 + def visitDict(self, node):
7.1282 + self.set_lineno(node)
7.1283 + self.emit('BUILD_MAP', 0)
7.1284 + for k, v in node.items:
7.1285 + self.emit('DUP_TOP')
7.1286 + self.visit(k)
7.1287 + self.visit(v)
7.1288 + self.emit('ROT_THREE')
7.1289 + self.emit('STORE_SUBSCR')
7.1290 +
7.1291 +class NestedScopeMixin:
7.1292 + """Defines initClass() for nested scoping (Python 2.2-compatible)"""
7.1293 + def initClass(self):
7.1294 + self.__class__.NameFinder = LocalNameFinder
7.1295 + self.__class__.FunctionGen = FunctionCodeGenerator
7.1296 + self.__class__.ClassGen = ClassCodeGenerator
7.1297 +
7.1298 +class ModuleCodeGenerator(NestedScopeMixin, CodeGenerator):
7.1299 + __super_init = CodeGenerator.__init__
7.1300 +
7.1301 + scopes = None
7.1302 +
7.1303 + def __init__(self, tree):
7.1304 + self.graph = pyassem.PyFlowGraph("<module>", tree.filename)
7.1305 + self.futures = future.find_futures(tree)
7.1306 + self.__super_init()
7.1307 + walk(tree, self)
7.1308 +
7.1309 + def get_module(self):
7.1310 + return self
7.1311 +
7.1312 +class ExpressionCodeGenerator(NestedScopeMixin, CodeGenerator):
7.1313 + __super_init = CodeGenerator.__init__
7.1314 +
7.1315 + scopes = None
7.1316 + futures = ()
7.1317 +
7.1318 + def __init__(self, tree):
7.1319 + self.graph = pyassem.PyFlowGraph("<expression>", tree.filename)
7.1320 + self.__super_init()
7.1321 + walk(tree, self)
7.1322 +
7.1323 + def get_module(self):
7.1324 + return self
7.1325 +
7.1326 +class InteractiveCodeGenerator(NestedScopeMixin, CodeGenerator):
7.1327 +
7.1328 + __super_init = CodeGenerator.__init__
7.1329 +
7.1330 + scopes = None
7.1331 + futures = ()
7.1332 +
7.1333 + def __init__(self, tree):
7.1334 + self.graph = pyassem.PyFlowGraph("<interactive>", tree.filename)
7.1335 + self.__super_init()
7.1336 + self.set_lineno(tree)
7.1337 + walk(tree, self)
7.1338 + self.emit('RETURN_VALUE')
7.1339 +
7.1340 + def get_module(self):
7.1341 + return self
7.1342 +
7.1343 + def visitDiscard(self, node):
7.1344 + # XXX Discard means it's an expression. Perhaps this is a bad
7.1345 + # name.
7.1346 + self.visit(node.expr)
7.1347 + self.emit('PRINT_EXPR')
7.1348 +
7.1349 +class AbstractFunctionCode:
7.1350 + optimized = 1
7.1351 + lambdaCount = 0
7.1352 +
7.1353 + def __init__(self, func, scopes, isLambda, class_name, mod):
7.1354 + self.class_name = class_name
7.1355 + self.module = mod
7.1356 + if isLambda:
7.1357 + klass = FunctionCodeGenerator
7.1358 + name = "<lambda.%d>" % klass.lambdaCount
7.1359 + klass.lambdaCount = klass.lambdaCount + 1
7.1360 + else:
7.1361 + name = func.name
7.1362 +
7.1363 + args, hasTupleArg = generateArgList(func.argnames)
7.1364 + self.graph = pyassem.PyFlowGraph(name, func.filename, args,
7.1365 + optimized=1)
7.1366 + self.isLambda = isLambda
7.1367 + self.super_init()
7.1368 +
7.1369 + if not isLambda and func.doc:
7.1370 + self.setDocstring(func.doc)
7.1371 +
7.1372 + lnf = walk(func.code, self.NameFinder(args), verbose=0)
7.1373 + self.locals.push(lnf.getLocals())
7.1374 + if func.varargs:
7.1375 + self.graph.setFlag(CO_VARARGS)
7.1376 + if func.kwargs:
7.1377 + self.graph.setFlag(CO_VARKEYWORDS)
7.1378 + self.set_lineno(func)
7.1379 + if hasTupleArg:
7.1380 + self.generateArgUnpack(func.argnames)
7.1381 +
7.1382 + def get_module(self):
7.1383 + return self.module
7.1384 +
7.1385 + def finish(self):
7.1386 + self.graph.startExitBlock()
7.1387 + if not self.isLambda:
7.1388 + self.emit('LOAD_CONST', None)
7.1389 + self.emit('RETURN_VALUE')
7.1390 +
7.1391 + def generateArgUnpack(self, args):
7.1392 + for i in range(len(args)):
7.1393 + arg = args[i]
7.1394 + if isinstance(arg, tuple):
7.1395 + self.emit('LOAD_FAST', '.%d' % (i * 2))
7.1396 + self.unpackSequence(arg)
7.1397 +
7.1398 + def unpackSequence(self, tup):
7.1399 + if VERSION > 1:
7.1400 + self.emit('UNPACK_SEQUENCE', len(tup))
7.1401 + else:
7.1402 + self.emit('UNPACK_TUPLE', len(tup))
7.1403 + for elt in tup:
7.1404 + if isinstance(elt, tuple):
7.1405 + self.unpackSequence(elt)
7.1406 + else:
7.1407 + self._nameOp('STORE', elt)
7.1408 +
7.1409 + unpackTuple = unpackSequence
7.1410 +
7.1411 +class FunctionCodeGenerator(NestedScopeMixin, AbstractFunctionCode,
7.1412 + CodeGenerator):
7.1413 + super_init = CodeGenerator.__init__ # call be other init
7.1414 + scopes = None
7.1415 +
7.1416 + __super_init = AbstractFunctionCode.__init__
7.1417 +
7.1418 + def __init__(self, func, scopes, isLambda, class_name, mod):
7.1419 + self.scopes = scopes
7.1420 + self.scope = scopes[func]
7.1421 + self.__super_init(func, scopes, isLambda, class_name, mod)
7.1422 + self.graph.setFreeVars(self.scope.get_free_vars())
7.1423 + self.graph.setCellVars(self.scope.get_cell_vars())
7.1424 + if self.scope.generator is not None:
7.1425 + self.graph.setFlag(CO_GENERATOR)
7.1426 +
7.1427 +class GenExprCodeGenerator(NestedScopeMixin, AbstractFunctionCode,
7.1428 + CodeGenerator):
7.1429 + super_init = CodeGenerator.__init__ # call be other init
7.1430 + scopes = None
7.1431 +
7.1432 + __super_init = AbstractFunctionCode.__init__
7.1433 +
7.1434 + def __init__(self, gexp, scopes, class_name, mod):
7.1435 + self.scopes = scopes
7.1436 + self.scope = scopes[gexp]
7.1437 + self.__super_init(gexp, scopes, 1, class_name, mod)
7.1438 + self.graph.setFreeVars(self.scope.get_free_vars())
7.1439 + self.graph.setCellVars(self.scope.get_cell_vars())
7.1440 + self.graph.setFlag(CO_GENERATOR)
7.1441 +
7.1442 +class AbstractClassCode:
7.1443 +
7.1444 + def __init__(self, klass, scopes, module):
7.1445 + self.class_name = klass.name
7.1446 + self.module = module
7.1447 + self.graph = pyassem.PyFlowGraph(klass.name, klass.filename,
7.1448 + optimized=0, klass=1)
7.1449 + self.super_init()
7.1450 + lnf = walk(klass.code, self.NameFinder(), verbose=0)
7.1451 + self.locals.push(lnf.getLocals())
7.1452 + self.graph.setFlag(CO_NEWLOCALS)
7.1453 + if klass.doc:
7.1454 + self.setDocstring(klass.doc)
7.1455 +
7.1456 + def get_module(self):
7.1457 + return self.module
7.1458 +
7.1459 + def finish(self):
7.1460 + self.graph.startExitBlock()
7.1461 + self.emit('LOAD_LOCALS')
7.1462 + self.emit('RETURN_VALUE')
7.1463 +
7.1464 +class ClassCodeGenerator(NestedScopeMixin, AbstractClassCode, CodeGenerator):
7.1465 + super_init = CodeGenerator.__init__
7.1466 + scopes = None
7.1467 +
7.1468 + __super_init = AbstractClassCode.__init__
7.1469 +
7.1470 + def __init__(self, klass, scopes, module):
7.1471 + self.scopes = scopes
7.1472 + self.scope = scopes[klass]
7.1473 + self.__super_init(klass, scopes, module)
7.1474 + self.graph.setFreeVars(self.scope.get_free_vars())
7.1475 + self.graph.setCellVars(self.scope.get_cell_vars())
7.1476 + self.set_lineno(klass)
7.1477 + self.emit("LOAD_GLOBAL", "__name__")
7.1478 + self.storeName("__module__")
7.1479 + if klass.doc:
7.1480 + self.emit("LOAD_CONST", klass.doc)
7.1481 + self.storeName('__doc__')
7.1482 +
7.1483 +def generateArgList(arglist):
7.1484 + """Generate an arg list marking TupleArgs"""
7.1485 + args = []
7.1486 + extra = []
7.1487 + count = 0
7.1488 + for i in range(len(arglist)):
7.1489 + elt = arglist[i]
7.1490 + if isinstance(elt, str):
7.1491 + args.append(elt)
7.1492 + elif isinstance(elt, tuple):
7.1493 + args.append(TupleArg(i * 2, elt))
7.1494 + extra.extend(misc.flatten(elt))
7.1495 + count = count + 1
7.1496 + else:
7.1497 + raise ValueError, "unexpect argument type:", elt
7.1498 + return args + extra, count
7.1499 +
7.1500 +def findOp(node):
7.1501 + """Find the op (DELETE, LOAD, STORE) in an AssTuple tree"""
7.1502 + v = OpFinder()
7.1503 + walk(node, v, verbose=0)
7.1504 + return v.op
7.1505 +
7.1506 +class OpFinder:
7.1507 + def __init__(self):
7.1508 + self.op = None
7.1509 + def visitAssName(self, node):
7.1510 + if self.op is None:
7.1511 + self.op = node.flags
7.1512 + elif self.op != node.flags:
7.1513 + raise ValueError, "mixed ops in stmt"
7.1514 + visitAssAttr = visitAssName
7.1515 + visitSubscript = visitAssName
7.1516 +
7.1517 +class Delegator:
7.1518 + """Base class to support delegation for augmented assignment nodes
7.1519 +
7.1520 + To generator code for augmented assignments, we use the following
7.1521 + wrapper classes. In visitAugAssign, the left-hand expression node
7.1522 + is visited twice. The first time the visit uses the normal method
7.1523 + for that node . The second time the visit uses a different method
7.1524 + that generates the appropriate code to perform the assignment.
7.1525 + These delegator classes wrap the original AST nodes in order to
7.1526 + support the variant visit methods.
7.1527 + """
7.1528 + def __init__(self, obj):
7.1529 + self.obj = obj
7.1530 +
7.1531 + def __getattr__(self, attr):
7.1532 + return getattr(self.obj, attr)
7.1533 +
7.1534 +class AugGetattr(Delegator):
7.1535 + pass
7.1536 +
7.1537 +class AugName(Delegator):
7.1538 + pass
7.1539 +
7.1540 +class AugSlice(Delegator):
7.1541 + pass
7.1542 +
7.1543 +class AugSubscript(Delegator):
7.1544 + pass
7.1545 +
7.1546 +wrapper = {
7.1547 + ast.Getattr: AugGetattr,
7.1548 + ast.Name: AugName,
7.1549 + ast.Slice: AugSlice,
7.1550 + ast.Subscript: AugSubscript,
7.1551 + }
7.1552 +
7.1553 +def wrap_aug(node):
7.1554 + return wrapper[node.__class__](node)
7.1555 +
7.1556 +if __name__ == "__main__":
7.1557 + for file in sys.argv[1:]:
7.1558 + compileFile(file)
8.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
8.2 +++ b/compiler/symbols.py Fri May 18 23:26:30 2012 +0200
8.3 @@ -0,0 +1,462 @@
8.4 +"""Module symbol-table generator"""
8.5 +
8.6 +from compiler import ast
8.7 +from compiler.consts import SC_LOCAL, SC_GLOBAL_IMPLICIT, SC_GLOBAL_EXPLICT, \
8.8 + SC_FREE, SC_CELL, SC_UNKNOWN
8.9 +from compiler.misc import mangle
8.10 +import types
8.11 +
8.12 +
8.13 +import sys
8.14 +
8.15 +MANGLE_LEN = 256
8.16 +
8.17 +class Scope:
8.18 + # XXX how much information do I need about each name?
8.19 + def __init__(self, name, module, klass=None):
8.20 + self.name = name
8.21 + self.module = module
8.22 + self.defs = {}
8.23 + self.uses = {}
8.24 + self.globals = {}
8.25 + self.params = {}
8.26 + self.frees = {}
8.27 + self.cells = {}
8.28 + self.children = []
8.29 + # nested is true if the class could contain free variables,
8.30 + # i.e. if it is nested within another function.
8.31 + self.nested = None
8.32 + self.generator = None
8.33 + self.klass = None
8.34 + if klass is not None:
8.35 + for i in range(len(klass)):
8.36 + if klass[i] != '_':
8.37 + self.klass = klass[i:]
8.38 + break
8.39 +
8.40 + def __repr__(self):
8.41 + return "<%s: %s>" % (self.__class__.__name__, self.name)
8.42 +
8.43 + def mangle(self, name):
8.44 + if self.klass is None:
8.45 + return name
8.46 + return mangle(name, self.klass)
8.47 +
8.48 + def add_def(self, name):
8.49 + self.defs[self.mangle(name)] = 1
8.50 +
8.51 + def add_use(self, name):
8.52 + self.uses[self.mangle(name)] = 1
8.53 +
8.54 + def add_global(self, name):
8.55 + name = self.mangle(name)
8.56 + if name in self.uses or name in self.defs:
8.57 + pass # XXX warn about global following def/use
8.58 + if name in self.params:
8.59 + raise SyntaxError, "%s in %s is global and parameter" % \
8.60 + (name, self.name)
8.61 + self.globals[name] = 1
8.62 + self.module.add_def(name)
8.63 +
8.64 + def add_param(self, name):
8.65 + name = self.mangle(name)
8.66 + self.defs[name] = 1
8.67 + self.params[name] = 1
8.68 +
8.69 + def get_names(self):
8.70 + d = {}
8.71 + d.update(self.defs)
8.72 + d.update(self.uses)
8.73 + d.update(self.globals)
8.74 + return d.keys()
8.75 +
8.76 + def add_child(self, child):
8.77 + self.children.append(child)
8.78 +
8.79 + def get_children(self):
8.80 + return self.children
8.81 +
8.82 + def DEBUG(self):
8.83 + print >> sys.stderr, self.name, self.nested and "nested" or ""
8.84 + print >> sys.stderr, "\tglobals: ", self.globals
8.85 + print >> sys.stderr, "\tcells: ", self.cells
8.86 + print >> sys.stderr, "\tdefs: ", self.defs
8.87 + print >> sys.stderr, "\tuses: ", self.uses
8.88 + print >> sys.stderr, "\tfrees:", self.frees
8.89 +
8.90 + def check_name(self, name):
8.91 + """Return scope of name.
8.92 +
8.93 + The scope of a name could be LOCAL, GLOBAL, FREE, or CELL.
8.94 + """
8.95 + if name in self.globals:
8.96 + return SC_GLOBAL_EXPLICT
8.97 + if name in self.cells:
8.98 + return SC_CELL
8.99 + if name in self.defs:
8.100 + return SC_LOCAL
8.101 + if self.nested and (name in self.frees or name in self.uses):
8.102 + return SC_FREE
8.103 + if self.nested:
8.104 + return SC_UNKNOWN
8.105 + else:
8.106 + return SC_GLOBAL_IMPLICIT
8.107 +
8.108 + def get_free_vars(self):
8.109 + if not self.nested:
8.110 + return ()
8.111 + free = {}
8.112 + free.update(self.frees)
8.113 + for name in self.uses.keys():
8.114 + if name not in self.defs and name not in self.globals:
8.115 + free[name] = 1
8.116 + return free.keys()
8.117 +
8.118 + def handle_children(self):
8.119 + for child in self.children:
8.120 + frees = child.get_free_vars()
8.121 + globals = self.add_frees(frees)
8.122 + for name in globals:
8.123 + child.force_global(name)
8.124 +
8.125 + def force_global(self, name):
8.126 + """Force name to be global in scope.
8.127 +
8.128 + Some child of the current node had a free reference to name.
8.129 + When the child was processed, it was labelled a free
8.130 + variable. Now that all its enclosing scope have been
8.131 + processed, the name is known to be a global or builtin. So
8.132 + walk back down the child chain and set the name to be global
8.133 + rather than free.
8.134 +
8.135 + Be careful to stop if a child does not think the name is
8.136 + free.
8.137 + """
8.138 + self.globals[name] = 1
8.139 + if name in self.frees:
8.140 + del self.frees[name]
8.141 + for child in self.children:
8.142 + if child.check_name(name) == SC_FREE:
8.143 + child.force_global(name)
8.144 +
8.145 + def add_frees(self, names):
8.146 + """Process list of free vars from nested scope.
8.147 +
8.148 + Returns a list of names that are either 1) declared global in the
8.149 + parent or 2) undefined in a top-level parent. In either case,
8.150 + the nested scope should treat them as globals.
8.151 + """
8.152 + child_globals = []
8.153 + for name in names:
8.154 + sc = self.check_name(name)
8.155 + if self.nested:
8.156 + if sc == SC_UNKNOWN or sc == SC_FREE \
8.157 + or isinstance(self, ClassScope):
8.158 + self.frees[name] = 1
8.159 + elif sc == SC_GLOBAL_IMPLICIT:
8.160 + child_globals.append(name)
8.161 + elif isinstance(self, FunctionScope) and sc == SC_LOCAL:
8.162 + self.cells[name] = 1
8.163 + elif sc != SC_CELL:
8.164 + child_globals.append(name)
8.165 + else:
8.166 + if sc == SC_LOCAL:
8.167 + self.cells[name] = 1
8.168 + elif sc != SC_CELL:
8.169 + child_globals.append(name)
8.170 + return child_globals
8.171 +
8.172 + def get_cell_vars(self):
8.173 + return self.cells.keys()
8.174 +
8.175 +class ModuleScope(Scope):
8.176 + __super_init = Scope.__init__
8.177 +
8.178 + def __init__(self):
8.179 + self.__super_init("global", self)
8.180 +
8.181 +class FunctionScope(Scope):
8.182 + pass
8.183 +
8.184 +class GenExprScope(Scope):
8.185 + __super_init = Scope.__init__
8.186 +
8.187 + __counter = 1
8.188 +
8.189 + def __init__(self, module, klass=None):
8.190 + i = self.__counter
8.191 + self.__counter += 1
8.192 + self.__super_init("generator expression<%d>"%i, module, klass)
8.193 + self.add_param('.0')
8.194 +
8.195 + def get_names(self):
8.196 + keys = Scope.get_names(self)
8.197 + return keys
8.198 +
8.199 +class LambdaScope(FunctionScope):
8.200 + __super_init = Scope.__init__
8.201 +
8.202 + __counter = 1
8.203 +
8.204 + def __init__(self, module, klass=None):
8.205 + i = self.__counter
8.206 + self.__counter += 1
8.207 + self.__super_init("lambda.%d" % i, module, klass)
8.208 +
8.209 +class ClassScope(Scope):
8.210 + __super_init = Scope.__init__
8.211 +
8.212 + def __init__(self, name, module):
8.213 + self.__super_init(name, module, name)
8.214 +
8.215 +class SymbolVisitor:
8.216 + def __init__(self):
8.217 + self.scopes = {}
8.218 + self.klass = None
8.219 +
8.220 + # node that define new scopes
8.221 +
8.222 + def visitModule(self, node):
8.223 + scope = self.module = self.scopes[node] = ModuleScope()
8.224 + self.visit(node.node, scope)
8.225 +
8.226 + visitExpression = visitModule
8.227 +
8.228 + def visitFunction(self, node, parent):
8.229 + if node.decorators:
8.230 + self.visit(node.decorators, parent)
8.231 + parent.add_def(node.name)
8.232 + for n in node.defaults:
8.233 + self.visit(n, parent)
8.234 + scope = FunctionScope(node.name, self.module, self.klass)
8.235 + if parent.nested or isinstance(parent, FunctionScope):
8.236 + scope.nested = 1
8.237 + self.scopes[node] = scope
8.238 + self._do_args(scope, node.argnames)
8.239 + self.visit(node.code, scope)
8.240 + self.handle_free_vars(scope, parent)
8.241 +
8.242 + def visitGenExpr(self, node, parent):
8.243 + scope = GenExprScope(self.module, self.klass);
8.244 + if parent.nested or isinstance(parent, FunctionScope) \
8.245 + or isinstance(parent, GenExprScope):
8.246 + scope.nested = 1
8.247 +
8.248 + self.scopes[node] = scope
8.249 + self.visit(node.code, scope)
8.250 +
8.251 + self.handle_free_vars(scope, parent)
8.252 +
8.253 + def visitGenExprInner(self, node, scope):
8.254 + for genfor in node.quals:
8.255 + self.visit(genfor, scope)
8.256 +
8.257 + self.visit(node.expr, scope)
8.258 +
8.259 + def visitGenExprFor(self, node, scope):
8.260 + self.visit(node.assign, scope, 1)
8.261 + self.visit(node.iter, scope)
8.262 + for if_ in node.ifs:
8.263 + self.visit(if_, scope)
8.264 +
8.265 + def visitGenExprIf(self, node, scope):
8.266 + self.visit(node.test, scope)
8.267 +
8.268 + def visitLambda(self, node, parent, assign=0):
8.269 + # Lambda is an expression, so it could appear in an expression
8.270 + # context where assign is passed. The transformer should catch
8.271 + # any code that has a lambda on the left-hand side.
8.272 + assert not assign
8.273 +
8.274 + for n in node.defaults:
8.275 + self.visit(n, parent)
8.276 + scope = LambdaScope(self.module, self.klass)
8.277 + if parent.nested or isinstance(parent, FunctionScope):
8.278 + scope.nested = 1
8.279 + self.scopes[node] = scope
8.280 + self._do_args(scope, node.argnames)
8.281 + self.visit(node.code, scope)
8.282 + self.handle_free_vars(scope, parent)
8.283 +
8.284 + def _do_args(self, scope, args):
8.285 + for name in args:
8.286 + if type(name) == types.TupleType:
8.287 + self._do_args(scope, name)
8.288 + else:
8.289 + scope.add_param(name)
8.290 +
8.291 + def handle_free_vars(self, scope, parent):
8.292 + parent.add_child(scope)
8.293 + scope.handle_children()
8.294 +
8.295 + def visitClass(self, node, parent):
8.296 + parent.add_def(node.name)
8.297 + for n in node.bases:
8.298 + self.visit(n, parent)
8.299 + scope = ClassScope(node.name, self.module)
8.300 + if parent.nested or isinstance(parent, FunctionScope):
8.301 + scope.nested = 1
8.302 + if node.doc is not None:
8.303 + scope.add_def('__doc__')
8.304 + scope.add_def('__module__')
8.305 + self.scopes[node] = scope
8.306 + prev = self.klass
8.307 + self.klass = node.name
8.308 + self.visit(node.code, scope)
8.309 + self.klass = prev
8.310 + self.handle_free_vars(scope, parent)
8.311 +
8.312 + # name can be a def or a use
8.313 +
8.314 + # XXX a few calls and nodes expect a third "assign" arg that is
8.315 + # true if the name is being used as an assignment. only
8.316 + # expressions contained within statements may have the assign arg.
8.317 +
8.318 + def visitName(self, node, scope, assign=0):
8.319 + if assign:
8.320 + scope.add_def(node.name)
8.321 + else:
8.322 + scope.add_use(node.name)
8.323 +
8.324 + # operations that bind new names
8.325 +
8.326 + def visitFor(self, node, scope):
8.327 + self.visit(node.assign, scope, 1)
8.328 + self.visit(node.list, scope)
8.329 + self.visit(node.body, scope)
8.330 + if node.else_:
8.331 + self.visit(node.else_, scope)
8.332 +
8.333 + def visitFrom(self, node, scope):
8.334 + for name, asname in node.names:
8.335 + if name == "*":
8.336 + continue
8.337 + scope.add_def(asname or name)
8.338 +
8.339 + def visitImport(self, node, scope):
8.340 + for name, asname in node.names:
8.341 + i = name.find(".")
8.342 + if i > -1:
8.343 + name = name[:i]
8.344 + scope.add_def(asname or name)
8.345 +
8.346 + def visitGlobal(self, node, scope):
8.347 + for name in node.names:
8.348 + scope.add_global(name)
8.349 +
8.350 + def visitAssign(self, node, scope):
8.351 + """Propagate assignment flag down to child nodes.
8.352 +
8.353 + The Assign node doesn't itself contains the variables being
8.354 + assigned to. Instead, the children in node.nodes are visited
8.355 + with the assign flag set to true. When the names occur in
8.356 + those nodes, they are marked as defs.
8.357 +
8.358 + Some names that occur in an assignment target are not bound by
8.359 + the assignment, e.g. a name occurring inside a slice. The
8.360 + visitor handles these nodes specially; they do not propagate
8.361 + the assign flag to their children.
8.362 + """
8.363 + for n in node.nodes:
8.364 + self.visit(n, scope, 1)
8.365 + self.visit(node.expr, scope)
8.366 +
8.367 + def visitAssName(self, node, scope, assign=1):
8.368 + scope.add_def(node.name)
8.369 +
8.370 + def visitAssAttr(self, node, scope, assign=0):
8.371 + self.visit(node.expr, scope, 0)
8.372 +
8.373 + def visitSubscript(self, node, scope, assign=0):
8.374 + self.visit(node.expr, scope, 0)
8.375 + for n in node.subs:
8.376 + self.visit(n, scope, 0)
8.377 +
8.378 + def visitSlice(self, node, scope, assign=0):
8.379 + self.visit(node.expr, scope, 0)
8.380 + if node.lower:
8.381 + self.visit(node.lower, scope, 0)
8.382 + if node.upper:
8.383 + self.visit(node.upper, scope, 0)
8.384 +
8.385 + def visitAugAssign(self, node, scope):
8.386 + # If the LHS is a name, then this counts as assignment.
8.387 + # Otherwise, it's just use.
8.388 + self.visit(node.node, scope)
8.389 + if isinstance(node.node, ast.Name):
8.390 + self.visit(node.node, scope, 1) # XXX worry about this
8.391 + self.visit(node.expr, scope)
8.392 +
8.393 + # prune if statements if tests are false
8.394 +
8.395 + _const_types = types.StringType, types.IntType, types.FloatType
8.396 +
8.397 + def visitIf(self, node, scope):
8.398 + for test, body in node.tests:
8.399 + if isinstance(test, ast.Const):
8.400 + if type(test.value) in self._const_types:
8.401 + if not test.value:
8.402 + continue
8.403 + self.visit(test, scope)
8.404 + self.visit(body, scope)
8.405 + if node.else_:
8.406 + self.visit(node.else_, scope)
8.407 +
8.408 + # a yield statement signals a generator
8.409 +
8.410 + def visitYield(self, node, scope):
8.411 + scope.generator = 1
8.412 + self.visit(node.value, scope)
8.413 +
8.414 +def list_eq(l1, l2):
8.415 + return sorted(l1) == sorted(l2)
8.416 +
8.417 +if __name__ == "__main__":
8.418 + import sys
8.419 + from compiler import parseFile, walk
8.420 + import symtable
8.421 +
8.422 + def get_names(syms):
8.423 + return [s for s in [s.get_name() for s in syms.get_symbols()]
8.424 + if not (s.startswith('_[') or s.startswith('.'))]
8.425 +
8.426 + for file in sys.argv[1:]:
8.427 + print file
8.428 + f = open(file)
8.429 + buf = f.read()
8.430 + f.close()
8.431 + syms = symtable.symtable(buf, file, "exec")
8.432 + mod_names = get_names(syms)
8.433 + tree = parseFile(file)
8.434 + s = SymbolVisitor()
8.435 + walk(tree, s)
8.436 +
8.437 + # compare module-level symbols
8.438 + names2 = s.scopes[tree].get_names()
8.439 +
8.440 + if not list_eq(mod_names, names2):
8.441 + print
8.442 + print "oops", file
8.443 + print sorted(mod_names)
8.444 + print sorted(names2)
8.445 + sys.exit(-1)
8.446 +
8.447 + d = {}
8.448 + d.update(s.scopes)
8.449 + del d[tree]
8.450 + scopes = d.values()
8.451 + del d
8.452 +
8.453 + for s in syms.get_symbols():
8.454 + if s.is_namespace():
8.455 + l = [sc for sc in scopes
8.456 + if sc.name == s.get_name()]
8.457 + if len(l) > 1:
8.458 + print "skipping", s.get_name()
8.459 + else:
8.460 + if not list_eq(get_names(s.get_namespace()),
8.461 + l[0].get_names()):
8.462 + print s.get_name()
8.463 + print sorted(get_names(s.get_namespace()))
8.464 + print sorted(l[0].get_names())
8.465 + sys.exit(-1)
9.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
9.2 +++ b/compiler/syntax.py Fri May 18 23:26:30 2012 +0200
9.3 @@ -0,0 +1,46 @@
9.4 +"""Check for errs in the AST.
9.5 +
9.6 +The Python parser does not catch all syntax errors. Others, like
9.7 +assignments with invalid targets, are caught in the code generation
9.8 +phase.
9.9 +
9.10 +The compiler package catches some errors in the transformer module.
9.11 +But it seems clearer to write checkers that use the AST to detect
9.12 +errors.
9.13 +"""
9.14 +
9.15 +from compiler import ast, walk
9.16 +
9.17 +def check(tree, multi=None):
9.18 + v = SyntaxErrorChecker(multi)
9.19 + walk(tree, v)
9.20 + return v.errors
9.21 +
9.22 +class SyntaxErrorChecker:
9.23 + """A visitor to find syntax errors in the AST."""
9.24 +
9.25 + def __init__(self, multi=None):
9.26 + """Create new visitor object.
9.27 +
9.28 + If optional argument multi is not None, then print messages
9.29 + for each error rather than raising a SyntaxError for the
9.30 + first.
9.31 + """
9.32 + self.multi = multi
9.33 + self.errors = 0
9.34 +
9.35 + def error(self, node, msg):
9.36 + self.errors = self.errors + 1
9.37 + if self.multi is not None:
9.38 + print "%s:%s: %s" % (node.filename, node.lineno, msg)
9.39 + else:
9.40 + raise SyntaxError, "%s (%s:%s)" % (msg, node.filename, node.lineno)
9.41 +
9.42 + def visitAssign(self, node):
9.43 + # the transformer module handles many of these
9.44 + pass
9.45 +## for target in node.nodes:
9.46 +## if isinstance(target, ast.AssList):
9.47 +## if target.lineno is None:
9.48 +## target.lineno = node.lineno
9.49 +## self.error(target, "can't assign to list comprehension")
10.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
10.2 +++ b/compiler/transformer.py Fri May 18 23:26:30 2012 +0200
10.3 @@ -0,0 +1,1535 @@
10.4 +"""Parse tree transformation module.
10.5 +
10.6 +Transforms Python source code into an abstract syntax tree (AST)
10.7 +defined in the ast module.
10.8 +
10.9 +The simplest ways to invoke this module are via parse and parseFile.
10.10 +parse(buf) -> AST
10.11 +parseFile(path) -> AST
10.12 +"""
10.13 +
10.14 +# Original version written by Greg Stein (gstein@lyra.org)
10.15 +# and Bill Tutt (rassilon@lima.mudlib.org)
10.16 +# February 1997.
10.17 +#
10.18 +# Modifications and improvements for Python 2.0 by Jeremy Hylton and
10.19 +# Mark Hammond
10.20 +#
10.21 +# Some fixes to try to have correct line number on almost all nodes
10.22 +# (except Module, Discard and Stmt) added by Sylvain Thenault
10.23 +#
10.24 +# Portions of this file are:
10.25 +# Copyright (C) 1997-1998 Greg Stein. All Rights Reserved.
10.26 +#
10.27 +# This module is provided under a BSD-ish license. See
10.28 +# http://www.opensource.org/licenses/bsd-license.html
10.29 +# and replace OWNER, ORGANIZATION, and YEAR as appropriate.
10.30 +
10.31 +from compiler.ast import *
10.32 +import parser
10.33 +import symbol
10.34 +import token
10.35 +
10.36 +class WalkerError(StandardError):
10.37 + pass
10.38 +
10.39 +from compiler.consts import CO_VARARGS, CO_VARKEYWORDS
10.40 +from compiler.consts import OP_ASSIGN, OP_DELETE, OP_APPLY
10.41 +
10.42 +def parseFile(path):
10.43 + f = open(path, "U")
10.44 + # XXX The parser API tolerates files without a trailing newline,
10.45 + # but not strings without a trailing newline. Always add an extra
10.46 + # newline to the file contents, since we're going through the string
10.47 + # version of the API.
10.48 + src = f.read() + "\n"
10.49 + f.close()
10.50 + return parse(src)
10.51 +
10.52 +def parse(buf, mode="exec"):
10.53 + if mode == "exec" or mode == "single":
10.54 + return Transformer().parsesuite(buf)
10.55 + elif mode == "eval":
10.56 + return Transformer().parseexpr(buf)
10.57 + else:
10.58 + raise ValueError("compile() arg 3 must be"
10.59 + " 'exec' or 'eval' or 'single'")
10.60 +
10.61 +def asList(nodes):
10.62 + l = []
10.63 + for item in nodes:
10.64 + if hasattr(item, "asList"):
10.65 + l.append(item.asList())
10.66 + else:
10.67 + if type(item) is type( (None, None) ):
10.68 + l.append(tuple(asList(item)))
10.69 + elif type(item) is type( [] ):
10.70 + l.append(asList(item))
10.71 + else:
10.72 + l.append(item)
10.73 + return l
10.74 +
10.75 +def extractLineNo(ast):
10.76 + if not isinstance(ast[1], tuple):
10.77 + # get a terminal node
10.78 + return ast[2]
10.79 + for child in ast[1:]:
10.80 + if isinstance(child, tuple):
10.81 + lineno = extractLineNo(child)
10.82 + if lineno is not None:
10.83 + return lineno
10.84 +
10.85 +def Node(*args):
10.86 + kind = args[0]
10.87 + if kind in nodes:
10.88 + try:
10.89 + return nodes[kind](*args[1:])
10.90 + except TypeError:
10.91 + print nodes[kind], len(args), args
10.92 + raise
10.93 + else:
10.94 + raise WalkerError, "Can't find appropriate Node type: %s" % str(args)
10.95 + #return apply(ast.Node, args)
10.96 +
10.97 +class Transformer:
10.98 + """Utility object for transforming Python parse trees.
10.99 +
10.100 + Exposes the following methods:
10.101 + tree = transform(ast_tree)
10.102 + tree = parsesuite(text)
10.103 + tree = parseexpr(text)
10.104 + tree = parsefile(fileob | filename)
10.105 + """
10.106 +
10.107 + def __init__(self):
10.108 + self._dispatch = {}
10.109 + for value, name in symbol.sym_name.items():
10.110 + if hasattr(self, name):
10.111 + self._dispatch[value] = getattr(self, name)
10.112 + self._dispatch[token.NEWLINE] = self.com_NEWLINE
10.113 + self._atom_dispatch = {token.LPAR: self.atom_lpar,
10.114 + token.LSQB: self.atom_lsqb,
10.115 + token.LBRACE: self.atom_lbrace,
10.116 + token.BACKQUOTE: self.atom_backquote,
10.117 + token.NUMBER: self.atom_number,
10.118 + token.STRING: self.atom_string,
10.119 + token.NAME: self.atom_name,
10.120 + }
10.121 + self.encoding = None
10.122 +
10.123 + def transform(self, tree):
10.124 + """Transform an AST into a modified parse tree."""
10.125 + if not (isinstance(tree, tuple) or isinstance(tree, list)):
10.126 + tree = parser.st2tuple(tree, line_info=1)
10.127 + return self.compile_node(tree)
10.128 +
10.129 + def parsesuite(self, text):
10.130 + """Return a modified parse tree for the given suite text."""
10.131 + return self.transform(parser.suite(text))
10.132 +
10.133 + def parseexpr(self, text):
10.134 + """Return a modified parse tree for the given expression text."""
10.135 + return self.transform(parser.expr(text))
10.136 +
10.137 + def parsefile(self, file):
10.138 + """Return a modified parse tree for the contents of the given file."""
10.139 + if type(file) == type(''):
10.140 + file = open(file)
10.141 + return self.parsesuite(file.read())
10.142 +
10.143 + # --------------------------------------------------------------
10.144 + #
10.145 + # PRIVATE METHODS
10.146 + #
10.147 +
10.148 + def compile_node(self, node):
10.149 + ### emit a line-number node?
10.150 + n = node[0]
10.151 +
10.152 + if n == symbol.encoding_decl:
10.153 + self.encoding = node[2]
10.154 + node = node[1]
10.155 + n = node[0]
10.156 +
10.157 + if n == symbol.single_input:
10.158 + return self.single_input(node[1:])
10.159 + if n == symbol.file_input:
10.160 + return self.file_input(node[1:])
10.161 + if n == symbol.eval_input:
10.162 + return self.eval_input(node[1:])
10.163 + if n == symbol.lambdef:
10.164 + return self.lambdef(node[1:])
10.165 + if n == symbol.funcdef:
10.166 + return self.funcdef(node[1:])
10.167 + if n == symbol.classdef:
10.168 + return self.classdef(node[1:])
10.169 +
10.170 + raise WalkerError, ('unexpected node type', n)
10.171 +
10.172 + def single_input(self, node):
10.173 + ### do we want to do anything about being "interactive" ?
10.174 +
10.175 + # NEWLINE | simple_stmt | compound_stmt NEWLINE
10.176 + n = node[0][0]
10.177 + if n != token.NEWLINE:
10.178 + return self.com_stmt(node[0])
10.179 +
10.180 + return Pass()
10.181 +
10.182 + def file_input(self, nodelist):
10.183 + doc = self.get_docstring(nodelist, symbol.file_input)
10.184 + if doc is not None:
10.185 + i = 1
10.186 + else:
10.187 + i = 0
10.188 + stmts = []
10.189 + for node in nodelist[i:]:
10.190 + if node[0] != token.ENDMARKER and node[0] != token.NEWLINE:
10.191 + self.com_append_stmt(stmts, node)
10.192 + return Module(doc, Stmt(stmts))
10.193 +
10.194 + def eval_input(self, nodelist):
10.195 + # from the built-in function input()
10.196 + ### is this sufficient?
10.197 + return Expression(self.com_node(nodelist[0]))
10.198 +
10.199 + def decorator_name(self, nodelist):
10.200 + listlen = len(nodelist)
10.201 + assert listlen >= 1 and listlen % 2 == 1
10.202 +
10.203 + item = self.atom_name(nodelist)
10.204 + i = 1
10.205 + while i < listlen:
10.206 + assert nodelist[i][0] == token.DOT
10.207 + assert nodelist[i + 1][0] == token.NAME
10.208 + item = Getattr(item, nodelist[i + 1][1])
10.209 + i += 2
10.210 +
10.211 + return item
10.212 +
10.213 + def decorator(self, nodelist):
10.214 + # '@' dotted_name [ '(' [arglist] ')' ]
10.215 + assert len(nodelist) in (3, 5, 6)
10.216 + assert nodelist[0][0] == token.AT
10.217 + assert nodelist[-1][0] == token.NEWLINE
10.218 +
10.219 + assert nodelist[1][0] == symbol.dotted_name
10.220 + funcname = self.decorator_name(nodelist[1][1:])
10.221 +
10.222 + if len(nodelist) > 3:
10.223 + assert nodelist[2][0] == token.LPAR
10.224 + expr = self.com_call_function(funcname, nodelist[3])
10.225 + else:
10.226 + expr = funcname
10.227 +
10.228 + return expr
10.229 +
10.230 + def decorators(self, nodelist):
10.231 + # decorators: decorator ([NEWLINE] decorator)* NEWLINE
10.232 + items = []
10.233 + for dec_nodelist in nodelist:
10.234 + assert dec_nodelist[0] == symbol.decorator
10.235 + items.append(self.decorator(dec_nodelist[1:]))
10.236 + return Decorators(items)
10.237 +
10.238 + def decorated(self, nodelist):
10.239 + assert nodelist[0][0] == symbol.decorators
10.240 + if nodelist[1][0] == symbol.funcdef:
10.241 + n = [nodelist[0]] + list(nodelist[1][1:])
10.242 + return self.funcdef(n)
10.243 + elif nodelist[1][0] == symbol.classdef:
10.244 + decorators = self.decorators(nodelist[0][1:])
10.245 + cls = self.classdef(nodelist[1][1:])
10.246 + cls.decorators = decorators
10.247 + return cls
10.248 + raise WalkerError()
10.249 +
10.250 + def funcdef(self, nodelist):
10.251 + # -6 -5 -4 -3 -2 -1
10.252 + # funcdef: [decorators] 'def' NAME parameters ':' suite
10.253 + # parameters: '(' [varargslist] ')'
10.254 +
10.255 + if len(nodelist) == 6:
10.256 + assert nodelist[0][0] == symbol.decorators
10.257 + decorators = self.decorators(nodelist[0][1:])
10.258 + else:
10.259 + assert len(nodelist) == 5
10.260 + decorators = None
10.261 +
10.262 + lineno = nodelist[-4][2]
10.263 + name = nodelist[-4][1]
10.264 + args = nodelist[-3][2]
10.265 +
10.266 + if args[0] == symbol.varargslist:
10.267 + names, defaults, flags = self.com_arglist(args[1:])
10.268 + else:
10.269 + names = defaults = ()
10.270 + flags = 0
10.271 + doc = self.get_docstring(nodelist[-1])
10.272 +
10.273 + # code for function
10.274 + code = self.com_node(nodelist[-1])
10.275 +
10.276 + if doc is not None:
10.277 + assert isinstance(code, Stmt)
10.278 + assert isinstance(code.nodes[0], Discard)
10.279 + del code.nodes[0]
10.280 + return Function(decorators, name, names, defaults, flags, doc, code,
10.281 + lineno=lineno)
10.282 +
10.283 + def lambdef(self, nodelist):
10.284 + # lambdef: 'lambda' [varargslist] ':' test
10.285 + if nodelist[2][0] == symbol.varargslist:
10.286 + names, defaults, flags = self.com_arglist(nodelist[2][1:])
10.287 + else:
10.288 + names = defaults = ()
10.289 + flags = 0
10.290 +
10.291 + # code for lambda
10.292 + code = self.com_node(nodelist[-1])
10.293 +
10.294 + return Lambda(names, defaults, flags, code, lineno=nodelist[1][2])
10.295 + old_lambdef = lambdef
10.296 +
10.297 + def classdef(self, nodelist):
10.298 + # classdef: 'class' NAME ['(' [testlist] ')'] ':' suite
10.299 +
10.300 + name = nodelist[1][1]
10.301 + doc = self.get_docstring(nodelist[-1])
10.302 + if nodelist[2][0] == token.COLON:
10.303 + bases = []
10.304 + elif nodelist[3][0] == token.RPAR:
10.305 + bases = []
10.306 + else:
10.307 + bases = self.com_bases(nodelist[3])
10.308 +
10.309 + # code for class
10.310 + code = self.com_node(nodelist[-1])
10.311 +
10.312 + if doc is not None:
10.313 + assert isinstance(code, Stmt)
10.314 + assert isinstance(code.nodes[0], Discard)
10.315 + del code.nodes[0]
10.316 +
10.317 + return Class(name, bases, doc, code, lineno=nodelist[1][2])
10.318 +
10.319 + def stmt(self, nodelist):
10.320 + return self.com_stmt(nodelist[0])
10.321 +
10.322 + small_stmt = stmt
10.323 + flow_stmt = stmt
10.324 + compound_stmt = stmt
10.325 +
10.326 + def simple_stmt(self, nodelist):
10.327 + # small_stmt (';' small_stmt)* [';'] NEWLINE
10.328 + stmts = []
10.329 + for i in range(0, len(nodelist), 2):
10.330 + self.com_append_stmt(stmts, nodelist[i])
10.331 + return Stmt(stmts)
10.332 +
10.333 + def parameters(self, nodelist):
10.334 + raise WalkerError
10.335 +
10.336 + def varargslist(self, nodelist):
10.337 + raise WalkerError
10.338 +
10.339 + def fpdef(self, nodelist):
10.340 + raise WalkerError
10.341 +
10.342 + def fplist(self, nodelist):
10.343 + raise WalkerError
10.344 +
10.345 + def dotted_name(self, nodelist):
10.346 + raise WalkerError
10.347 +
10.348 + def comp_op(self, nodelist):
10.349 + raise WalkerError
10.350 +
10.351 + def trailer(self, nodelist):
10.352 + raise WalkerError
10.353 +
10.354 + def sliceop(self, nodelist):
10.355 + raise WalkerError
10.356 +
10.357 + def argument(self, nodelist):
10.358 + raise WalkerError
10.359 +
10.360 + # --------------------------------------------------------------
10.361 + #
10.362 + # STATEMENT NODES (invoked by com_node())
10.363 + #
10.364 +
10.365 + def expr_stmt(self, nodelist):
10.366 + # augassign testlist | testlist ('=' testlist)*
10.367 + en = nodelist[-1]
10.368 + exprNode = self.lookup_node(en)(en[1:])
10.369 + if len(nodelist) == 1:
10.370 + return Discard(exprNode, lineno=exprNode.lineno)
10.371 + if nodelist[1][0] == token.EQUAL:
10.372 + nodesl = []
10.373 + for i in range(0, len(nodelist) - 2, 2):
10.374 + nodesl.append(self.com_assign(nodelist[i], OP_ASSIGN))
10.375 + return Assign(nodesl, exprNode, lineno=nodelist[1][2])
10.376 + else:
10.377 + lval = self.com_augassign(nodelist[0])
10.378 + op = self.com_augassign_op(nodelist[1])
10.379 + return AugAssign(lval, op[1], exprNode, lineno=op[2])
10.380 + raise WalkerError, "can't get here"
10.381 +
10.382 + def print_stmt(self, nodelist):
10.383 + # print ([ test (',' test)* [','] ] | '>>' test [ (',' test)+ [','] ])
10.384 + items = []
10.385 + if len(nodelist) == 1:
10.386 + start = 1
10.387 + dest = None
10.388 + elif nodelist[1][0] == token.RIGHTSHIFT:
10.389 + assert len(nodelist) == 3 \
10.390 + or nodelist[3][0] == token.COMMA
10.391 + dest = self.com_node(nodelist[2])
10.392 + start = 4
10.393 + else:
10.394 + dest = None
10.395 + start = 1
10.396 + for i in range(start, len(nodelist), 2):
10.397 + items.append(self.com_node(nodelist[i]))
10.398 + if nodelist[-1][0] == token.COMMA:
10.399 + return Print(items, dest, lineno=nodelist[0][2])
10.400 + return Printnl(items, dest, lineno=nodelist[0][2])
10.401 +
10.402 + def del_stmt(self, nodelist):
10.403 + return self.com_assign(nodelist[1], OP_DELETE)
10.404 +
10.405 + def pass_stmt(self, nodelist):
10.406 + return Pass(lineno=nodelist[0][2])
10.407 +
10.408 + def break_stmt(self, nodelist):
10.409 + return Break(lineno=nodelist[0][2])
10.410 +
10.411 + def continue_stmt(self, nodelist):
10.412 + return Continue(lineno=nodelist[0][2])
10.413 +
10.414 + def return_stmt(self, nodelist):
10.415 + # return: [testlist]
10.416 + if len(nodelist) < 2:
10.417 + return Return(Const(None), lineno=nodelist[0][2])
10.418 + return Return(self.com_node(nodelist[1]), lineno=nodelist[0][2])
10.419 +
10.420 + def yield_stmt(self, nodelist):
10.421 + expr = self.com_node(nodelist[0])
10.422 + return Discard(expr, lineno=expr.lineno)
10.423 +
10.424 + def yield_expr(self, nodelist):
10.425 + if len(nodelist) > 1:
10.426 + value = self.com_node(nodelist[1])
10.427 + else:
10.428 + value = Const(None)
10.429 + return Yield(value, lineno=nodelist[0][2])
10.430 +
10.431 + def raise_stmt(self, nodelist):
10.432 + # raise: [test [',' test [',' test]]]
10.433 + if len(nodelist) > 5:
10.434 + expr3 = self.com_node(nodelist[5])
10.435 + else:
10.436 + expr3 = None
10.437 + if len(nodelist) > 3:
10.438 + expr2 = self.com_node(nodelist[3])
10.439 + else:
10.440 + expr2 = None
10.441 + if len(nodelist) > 1:
10.442 + expr1 = self.com_node(nodelist[1])
10.443 + else:
10.444 + expr1 = None
10.445 + return Raise(expr1, expr2, expr3, lineno=nodelist[0][2])
10.446 +
10.447 + def import_stmt(self, nodelist):
10.448 + # import_stmt: import_name | import_from
10.449 + assert len(nodelist) == 1
10.450 + return self.com_node(nodelist[0])
10.451 +
10.452 + def import_name(self, nodelist):
10.453 + # import_name: 'import' dotted_as_names
10.454 + return Import(self.com_dotted_as_names(nodelist[1]),
10.455 + lineno=nodelist[0][2])
10.456 +
10.457 + def import_from(self, nodelist):
10.458 + # import_from: 'from' ('.'* dotted_name | '.') 'import' ('*' |
10.459 + # '(' import_as_names ')' | import_as_names)
10.460 + assert nodelist[0][1] == 'from'
10.461 + idx = 1
10.462 + while nodelist[idx][1] == '.':
10.463 + idx += 1
10.464 + level = idx - 1
10.465 + if nodelist[idx][0] == symbol.dotted_name:
10.466 + fromname = self.com_dotted_name(nodelist[idx])
10.467 + idx += 1
10.468 + else:
10.469 + fromname = ""
10.470 + assert nodelist[idx][1] == 'import'
10.471 + if nodelist[idx + 1][0] == token.STAR:
10.472 + return From(fromname, [('*', None)], level,
10.473 + lineno=nodelist[0][2])
10.474 + else:
10.475 + node = nodelist[idx + 1 + (nodelist[idx + 1][0] == token.LPAR)]
10.476 + return From(fromname, self.com_import_as_names(node), level,
10.477 + lineno=nodelist[0][2])
10.478 +
10.479 + def global_stmt(self, nodelist):
10.480 + # global: NAME (',' NAME)*
10.481 + names = []
10.482 + for i in range(1, len(nodelist), 2):
10.483 + names.append(nodelist[i][1])
10.484 + return Global(names, lineno=nodelist[0][2])
10.485 +
10.486 + def exec_stmt(self, nodelist):
10.487 + # exec_stmt: 'exec' expr ['in' expr [',' expr]]
10.488 + expr1 = self.com_node(nodelist[1])
10.489 + if len(nodelist) >= 4:
10.490 + expr2 = self.com_node(nodelist[3])
10.491 + if len(nodelist) >= 6:
10.492 + expr3 = self.com_node(nodelist[5])
10.493 + else:
10.494 + expr3 = None
10.495 + else:
10.496 + expr2 = expr3 = None
10.497 +
10.498 + return Exec(expr1, expr2, expr3, lineno=nodelist[0][2])
10.499 +
10.500 + def assert_stmt(self, nodelist):
10.501 + # 'assert': test, [',' test]
10.502 + expr1 = self.com_node(nodelist[1])
10.503 + if (len(nodelist) == 4):
10.504 + expr2 = self.com_node(nodelist[3])
10.505 + else:
10.506 + expr2 = None
10.507 + return Assert(expr1, expr2, lineno=nodelist[0][2])
10.508 +
10.509 + def if_stmt(self, nodelist):
10.510 + # if: test ':' suite ('elif' test ':' suite)* ['else' ':' suite]
10.511 + tests = []
10.512 + for i in range(0, len(nodelist) - 3, 4):
10.513 + testNode = self.com_node(nodelist[i + 1])
10.514 + suiteNode = self.com_node(nodelist[i + 3])
10.515 + tests.append((testNode, suiteNode))
10.516 +
10.517 + if len(nodelist) % 4 == 3:
10.518 + elseNode = self.com_node(nodelist[-1])
10.519 +## elseNode.lineno = nodelist[-1][1][2]
10.520 + else:
10.521 + elseNode = None
10.522 + return If(tests, elseNode, lineno=nodelist[0][2])
10.523 +
10.524 + def while_stmt(self, nodelist):
10.525 + # 'while' test ':' suite ['else' ':' suite]
10.526 +
10.527 + testNode = self.com_node(nodelist[1])
10.528 + bodyNode = self.com_node(nodelist[3])
10.529 +
10.530 + if len(nodelist) > 4:
10.531 + elseNode = self.com_node(nodelist[6])
10.532 + else:
10.533 + elseNode = None
10.534 +
10.535 + return While(testNode, bodyNode, elseNode, lineno=nodelist[0][2])
10.536 +
10.537 + def for_stmt(self, nodelist):
10.538 + # 'for' exprlist 'in' exprlist ':' suite ['else' ':' suite]
10.539 +
10.540 + assignNode = self.com_assign(nodelist[1], OP_ASSIGN)
10.541 + listNode = self.com_node(nodelist[3])
10.542 + bodyNode = self.com_node(nodelist[5])
10.543 +
10.544 + if len(nodelist) > 8:
10.545 + elseNode = self.com_node(nodelist[8])
10.546 + else:
10.547 + elseNode = None
10.548 +
10.549 + return For(assignNode, listNode, bodyNode, elseNode,
10.550 + lineno=nodelist[0][2])
10.551 +
10.552 + def try_stmt(self, nodelist):
10.553 + return self.com_try_except_finally(nodelist)
10.554 +
10.555 + def with_stmt(self, nodelist):
10.556 + return self.com_with(nodelist)
10.557 +
10.558 + def with_var(self, nodelist):
10.559 + return self.com_with_var(nodelist)
10.560 +
10.561 + def suite(self, nodelist):
10.562 + # simple_stmt | NEWLINE INDENT NEWLINE* (stmt NEWLINE*)+ DEDENT
10.563 + if len(nodelist) == 1:
10.564 + return self.com_stmt(nodelist[0])
10.565 +
10.566 + stmts = []
10.567 + for node in nodelist:
10.568 + if node[0] == symbol.stmt:
10.569 + self.com_append_stmt(stmts, node)
10.570 + return Stmt(stmts)
10.571 +
10.572 + # --------------------------------------------------------------
10.573 + #
10.574 + # EXPRESSION NODES (invoked by com_node())
10.575 + #
10.576 +
10.577 + def testlist(self, nodelist):
10.578 + # testlist: expr (',' expr)* [',']
10.579 + # testlist_safe: test [(',' test)+ [',']]
10.580 + # exprlist: expr (',' expr)* [',']
10.581 + return self.com_binary(Tuple, nodelist)
10.582 +
10.583 + testlist_safe = testlist # XXX
10.584 + testlist1 = testlist
10.585 + exprlist = testlist
10.586 +
10.587 + def testlist_comp(self, nodelist):
10.588 + # test ( comp_for | (',' test)* [','] )
10.589 + assert nodelist[0][0] == symbol.test
10.590 + if len(nodelist) == 2 and nodelist[1][0] == symbol.comp_for:
10.591 + test = self.com_node(nodelist[0])
10.592 + return self.com_generator_expression(test, nodelist[1])
10.593 + return self.testlist(nodelist)
10.594 +
10.595 + def test(self, nodelist):
10.596 + # or_test ['if' or_test 'else' test] | lambdef
10.597 + if len(nodelist) == 1 and nodelist[0][0] == symbol.lambdef:
10.598 + return self.lambdef(nodelist[0])
10.599 + then = self.com_node(nodelist[0])
10.600 + if len(nodelist) > 1:
10.601 + assert len(nodelist) == 5
10.602 + assert nodelist[1][1] == 'if'
10.603 + assert nodelist[3][1] == 'else'
10.604 + test = self.com_node(nodelist[2])
10.605 + else_ = self.com_node(nodelist[4])
10.606 + return IfExp(test, then, else_, lineno=nodelist[1][2])
10.607 + return then
10.608 +
10.609 + def or_test(self, nodelist):
10.610 + # and_test ('or' and_test)* | lambdef
10.611 + if len(nodelist) == 1 and nodelist[0][0] == symbol.lambdef:
10.612 + return self.lambdef(nodelist[0])
10.613 + return self.com_binary(Or, nodelist)
10.614 + old_test = or_test
10.615 +
10.616 + def and_test(self, nodelist):
10.617 + # not_test ('and' not_test)*
10.618 + return self.com_binary(And, nodelist)
10.619 +
10.620 + def not_test(self, nodelist):
10.621 + # 'not' not_test | comparison
10.622 + result = self.com_node(nodelist[-1])
10.623 + if len(nodelist) == 2:
10.624 + return Not(result, lineno=nodelist[0][2])
10.625 + return result
10.626 +
10.627 + def comparison(self, nodelist):
10.628 + # comparison: expr (comp_op expr)*
10.629 + node = self.com_node(nodelist[0])
10.630 + if len(nodelist) == 1:
10.631 + return node
10.632 +
10.633 + results = []
10.634 + for i in range(2, len(nodelist), 2):
10.635 + nl = nodelist[i-1]
10.636 +
10.637 + # comp_op: '<' | '>' | '=' | '>=' | '<=' | '<>' | '!=' | '=='
10.638 + # | 'in' | 'not' 'in' | 'is' | 'is' 'not'
10.639 + n = nl[1]
10.640 + if n[0] == token.NAME:
10.641 + type = n[1]
10.642 + if len(nl) == 3:
10.643 + if type == 'not':
10.644 + type = 'not in'
10.645 + else:
10.646 + type = 'is not'
10.647 + else:
10.648 + type = _cmp_types[n[0]]
10.649 +
10.650 + lineno = nl[1][2]
10.651 + results.append((type, self.com_node(nodelist[i])))
10.652 +
10.653 + # we need a special "compare" node so that we can distinguish
10.654 + # 3 < x < 5 from (3 < x) < 5
10.655 + # the two have very different semantics and results (note that the
10.656 + # latter form is always true)
10.657 +
10.658 + return Compare(node, results, lineno=lineno)
10.659 +
10.660 + def expr(self, nodelist):
10.661 + # xor_expr ('|' xor_expr)*
10.662 + return self.com_binary(Bitor, nodelist)
10.663 +
10.664 + def xor_expr(self, nodelist):
10.665 + # xor_expr ('^' xor_expr)*
10.666 + return self.com_binary(Bitxor, nodelist)
10.667 +
10.668 + def and_expr(self, nodelist):
10.669 + # xor_expr ('&' xor_expr)*
10.670 + return self.com_binary(Bitand, nodelist)
10.671 +
10.672 + def shift_expr(self, nodelist):
10.673 + # shift_expr ('<<'|'>>' shift_expr)*
10.674 + node = self.com_node(nodelist[0])
10.675 + for i in range(2, len(nodelist), 2):
10.676 + right = self.com_node(nodelist[i])
10.677 + if nodelist[i-1][0] == token.LEFTSHIFT:
10.678 + node = LeftShift([node, right], lineno=nodelist[1][2])
10.679 + elif nodelist[i-1][0] == token.RIGHTSHIFT:
10.680 + node = RightShift([node, right], lineno=nodelist[1][2])
10.681 + else:
10.682 + raise ValueError, "unexpected token: %s" % nodelist[i-1][0]
10.683 + return node
10.684 +
10.685 + def arith_expr(self, nodelist):
10.686 + node = self.com_node(nodelist[0])
10.687 + for i in range(2, len(nodelist), 2):
10.688 + right = self.com_node(nodelist[i])
10.689 + if nodelist[i-1][0] == token.PLUS:
10.690 + node = Add([node, right], lineno=nodelist[1][2])
10.691 + elif nodelist[i-1][0] == token.MINUS:
10.692 + node = Sub([node, right], lineno=nodelist[1][2])
10.693 + else:
10.694 + raise ValueError, "unexpected token: %s" % nodelist[i-1][0]
10.695 + return node
10.696 +
10.697 + def term(self, nodelist):
10.698 + node = self.com_node(nodelist[0])
10.699 + for i in range(2, len(nodelist), 2):
10.700 + right = self.com_node(nodelist[i])
10.701 + t = nodelist[i-1][0]
10.702 + if t == token.STAR:
10.703 + node = Mul([node, right])
10.704 + elif t == token.SLASH:
10.705 + node = Div([node, right])
10.706 + elif t == token.PERCENT:
10.707 + node = Mod([node, right])
10.708 + elif t == token.DOUBLESLASH:
10.709 + node = FloorDiv([node, right])
10.710 + else:
10.711 + raise ValueError, "unexpected token: %s" % t
10.712 + node.lineno = nodelist[1][2]
10.713 + return node
10.714 +
10.715 + def factor(self, nodelist):
10.716 + elt = nodelist[0]
10.717 + t = elt[0]
10.718 + node = self.lookup_node(nodelist[-1])(nodelist[-1][1:])
10.719 + # need to handle (unary op)constant here...
10.720 + if t == token.PLUS:
10.721 + return UnaryAdd(node, lineno=elt[2])
10.722 + elif t == token.MINUS:
10.723 + return UnarySub(node, lineno=elt[2])
10.724 + elif t == token.TILDE:
10.725 + node = Invert(node, lineno=elt[2])
10.726 + return node
10.727 +
10.728 + def power(self, nodelist):
10.729 + # power: atom trailer* ('**' factor)*
10.730 + node = self.com_node(nodelist[0])
10.731 + for i in range(1, len(nodelist)):
10.732 + elt = nodelist[i]
10.733 + if elt[0] == token.DOUBLESTAR:
10.734 + return Power([node, self.com_node(nodelist[i+1])],
10.735 + lineno=elt[2])
10.736 +
10.737 + node = self.com_apply_trailer(node, elt)
10.738 +
10.739 + return node
10.740 +
10.741 + def atom(self, nodelist):
10.742 + return self._atom_dispatch[nodelist[0][0]](nodelist)
10.743 +
10.744 + def atom_lpar(self, nodelist):
10.745 + if nodelist[1][0] == token.RPAR:
10.746 + return Tuple((), lineno=nodelist[0][2])
10.747 + return self.com_node(nodelist[1])
10.748 +
10.749 + def atom_lsqb(self, nodelist):
10.750 + if nodelist[1][0] == token.RSQB:
10.751 + return List((), lineno=nodelist[0][2])
10.752 + return self.com_list_constructor(nodelist[1])
10.753 +
10.754 + def atom_lbrace(self, nodelist):
10.755 + if nodelist[1][0] == token.RBRACE:
10.756 + return Dict((), lineno=nodelist[0][2])
10.757 + return self.com_dictorsetmaker(nodelist[1])
10.758 +
10.759 + def atom_backquote(self, nodelist):
10.760 + return Backquote(self.com_node(nodelist[1]))
10.761 +
10.762 + def atom_number(self, nodelist):
10.763 + ### need to verify this matches compile.c
10.764 + k = eval(nodelist[0][1])
10.765 + return Const(k, lineno=nodelist[0][2])
10.766 +
10.767 + def decode_literal(self, lit):
10.768 + if self.encoding:
10.769 + # this is particularly fragile & a bit of a
10.770 + # hack... changes in compile.c:parsestr and
10.771 + # tokenizer.c must be reflected here.
10.772 + if self.encoding not in ['utf-8', 'iso-8859-1']:
10.773 + lit = unicode(lit, 'utf-8').encode(self.encoding)
10.774 + return eval("# coding: %s\n%s" % (self.encoding, lit))
10.775 + else:
10.776 + return eval(lit)
10.777 +
10.778 + def atom_string(self, nodelist):
10.779 + k = ''
10.780 + for node in nodelist:
10.781 + k += self.decode_literal(node[1])
10.782 + return Const(k, lineno=nodelist[0][2])
10.783 +
10.784 + def atom_name(self, nodelist):
10.785 + return Name(nodelist[0][1], lineno=nodelist[0][2])
10.786 +
10.787 + # --------------------------------------------------------------
10.788 + #
10.789 + # INTERNAL PARSING UTILITIES
10.790 + #
10.791 +
10.792 + # The use of com_node() introduces a lot of extra stack frames,
10.793 + # enough to cause a stack overflow compiling test.test_parser with
10.794 + # the standard interpreter recursionlimit. The com_node() is a
10.795 + # convenience function that hides the dispatch details, but comes
10.796 + # at a very high cost. It is more efficient to dispatch directly
10.797 + # in the callers. In these cases, use lookup_node() and call the
10.798 + # dispatched node directly.
10.799 +
10.800 + def lookup_node(self, node):
10.801 + return self._dispatch[node[0]]
10.802 +
10.803 + def com_node(self, node):
10.804 + # Note: compile.c has handling in com_node for del_stmt, pass_stmt,
10.805 + # break_stmt, stmt, small_stmt, flow_stmt, simple_stmt,
10.806 + # and compound_stmt.
10.807 + # We'll just dispatch them.
10.808 + return self._dispatch[node[0]](node[1:])
10.809 +
10.810 + def com_NEWLINE(self, *args):
10.811 + # A ';' at the end of a line can make a NEWLINE token appear
10.812 + # here, Render it harmless. (genc discards ('discard',
10.813 + # ('const', xxxx)) Nodes)
10.814 + return Discard(Const(None))
10.815 +
10.816 + def com_arglist(self, nodelist):
10.817 + # varargslist:
10.818 + # (fpdef ['=' test] ',')* ('*' NAME [',' '**' NAME] | '**' NAME)
10.819 + # | fpdef ['=' test] (',' fpdef ['=' test])* [',']
10.820 + # fpdef: NAME | '(' fplist ')'
10.821 + # fplist: fpdef (',' fpdef)* [',']
10.822 + names = []
10.823 + defaults = []
10.824 + flags = 0
10.825 +
10.826 + i = 0
10.827 + while i < len(nodelist):
10.828 + node = nodelist[i]
10.829 + if node[0] == token.STAR or node[0] == token.DOUBLESTAR:
10.830 + if node[0] == token.STAR:
10.831 + node = nodelist[i+1]
10.832 + if node[0] == token.NAME:
10.833 + names.append(node[1])
10.834 + flags = flags | CO_VARARGS
10.835 + i = i + 3
10.836 +
10.837 + if i < len(nodelist):
10.838 + # should be DOUBLESTAR
10.839 + t = nodelist[i][0]
10.840 + if t == token.DOUBLESTAR:
10.841 + node = nodelist[i+1]
10.842 + else:
10.843 + raise ValueError, "unexpected token: %s" % t
10.844 + names.append(node[1])
10.845 + flags = flags | CO_VARKEYWORDS
10.846 +
10.847 + break
10.848 +
10.849 + # fpdef: NAME | '(' fplist ')'
10.850 + names.append(self.com_fpdef(node))
10.851 +
10.852 + i = i + 1
10.853 + if i < len(nodelist) and nodelist[i][0] == token.EQUAL:
10.854 + defaults.append(self.com_node(nodelist[i + 1]))
10.855 + i = i + 2
10.856 + elif len(defaults):
10.857 + # we have already seen an argument with default, but here
10.858 + # came one without
10.859 + raise SyntaxError, "non-default argument follows default argument"
10.860 +
10.861 + # skip the comma
10.862 + i = i + 1
10.863 +
10.864 + return names, defaults, flags
10.865 +
10.866 + def com_fpdef(self, node):
10.867 + # fpdef: NAME | '(' fplist ')'
10.868 + if node[1][0] == token.LPAR:
10.869 + return self.com_fplist(node[2])
10.870 + return node[1][1]
10.871 +
10.872 + def com_fplist(self, node):
10.873 + # fplist: fpdef (',' fpdef)* [',']
10.874 + if len(node) == 2:
10.875 + return self.com_fpdef(node[1])
10.876 + list = []
10.877 + for i in range(1, len(node), 2):
10.878 + list.append(self.com_fpdef(node[i]))
10.879 + return tuple(list)
10.880 +
10.881 + def com_dotted_name(self, node):
10.882 + # String together the dotted names and return the string
10.883 + name = ""
10.884 + for n in node:
10.885 + if type(n) == type(()) and n[0] == 1:
10.886 + name = name + n[1] + '.'
10.887 + return name[:-1]
10.888 +
10.889 + def com_dotted_as_name(self, node):
10.890 + assert node[0] == symbol.dotted_as_name
10.891 + node = node[1:]
10.892 + dot = self.com_dotted_name(node[0][1:])
10.893 + if len(node) == 1:
10.894 + return dot, None
10.895 + assert node[1][1] == 'as'
10.896 + assert node[2][0] == token.NAME
10.897 + return dot, node[2][1]
10.898 +
10.899 + def com_dotted_as_names(self, node):
10.900 + assert node[0] == symbol.dotted_as_names
10.901 + node = node[1:]
10.902 + names = [self.com_dotted_as_name(node[0])]
10.903 + for i in range(2, len(node), 2):
10.904 + names.append(self.com_dotted_as_name(node[i]))
10.905 + return names
10.906 +
10.907 + def com_import_as_name(self, node):
10.908 + assert node[0] == symbol.import_as_name
10.909 + node = node[1:]
10.910 + assert node[0][0] == token.NAME
10.911 + if len(node) == 1:
10.912 + return node[0][1], None
10.913 + assert node[1][1] == 'as', node
10.914 + assert node[2][0] == token.NAME
10.915 + return node[0][1], node[2][1]
10.916 +
10.917 + def com_import_as_names(self, node):
10.918 + assert node[0] == symbol.import_as_names
10.919 + node = node[1:]
10.920 + names = [self.com_import_as_name(node[0])]
10.921 + for i in range(2, len(node), 2):
10.922 + names.append(self.com_import_as_name(node[i]))
10.923 + return names
10.924 +
10.925 + def com_bases(self, node):
10.926 + bases = []
10.927 + for i in range(1, len(node), 2):
10.928 + bases.append(self.com_node(node[i]))
10.929 + return bases
10.930 +
10.931 + def com_try_except_finally(self, nodelist):
10.932 + # ('try' ':' suite
10.933 + # ((except_clause ':' suite)+ ['else' ':' suite] ['finally' ':' suite]
10.934 + # | 'finally' ':' suite))
10.935 +
10.936 + if nodelist[3][0] == token.NAME:
10.937 + # first clause is a finally clause: only try-finally
10.938 + return TryFinally(self.com_node(nodelist[2]),
10.939 + self.com_node(nodelist[5]),
10.940 + lineno=nodelist[0][2])
10.941 +
10.942 + #tryexcept: [TryNode, [except_clauses], elseNode)]
10.943 + clauses = []
10.944 + elseNode = None
10.945 + finallyNode = None
10.946 + for i in range(3, len(nodelist), 3):
10.947 + node = nodelist[i]
10.948 + if node[0] == symbol.except_clause:
10.949 + # except_clause: 'except' [expr [(',' | 'as') expr]] */
10.950 + if len(node) > 2:
10.951 + expr1 = self.com_node(node[2])
10.952 + if len(node) > 4:
10.953 + expr2 = self.com_assign(node[4], OP_ASSIGN)
10.954 + else:
10.955 + expr2 = None
10.956 + else:
10.957 + expr1 = expr2 = None
10.958 + clauses.append((expr1, expr2, self.com_node(nodelist[i+2])))
10.959 +
10.960 + if node[0] == token.NAME:
10.961 + if node[1] == 'else':
10.962 + elseNode = self.com_node(nodelist[i+2])
10.963 + elif node[1] == 'finally':
10.964 + finallyNode = self.com_node(nodelist[i+2])
10.965 + try_except = TryExcept(self.com_node(nodelist[2]), clauses, elseNode,
10.966 + lineno=nodelist[0][2])
10.967 + if finallyNode:
10.968 + return TryFinally(try_except, finallyNode, lineno=nodelist[0][2])
10.969 + else:
10.970 + return try_except
10.971 +
10.972 + def com_with(self, nodelist):
10.973 + # with_stmt: 'with' with_item (',' with_item)* ':' suite
10.974 + body = self.com_node(nodelist[-1])
10.975 + for i in range(len(nodelist) - 3, 0, -2):
10.976 + ret = self.com_with_item(nodelist[i], body, nodelist[0][2])
10.977 + if i == 1:
10.978 + return ret
10.979 + body = ret
10.980 +
10.981 + def com_with_item(self, nodelist, body, lineno):
10.982 + # with_item: test ['as' expr]
10.983 + if len(nodelist) == 4:
10.984 + var = self.com_assign(nodelist[3], OP_ASSIGN)
10.985 + else:
10.986 + var = None
10.987 + expr = self.com_node(nodelist[1])
10.988 + return With(expr, var, body, lineno=lineno)
10.989 +
10.990 + def com_augassign_op(self, node):
10.991 + assert node[0] == symbol.augassign
10.992 + return node[1]
10.993 +
10.994 + def com_augassign(self, node):
10.995 + """Return node suitable for lvalue of augmented assignment
10.996 +
10.997 + Names, slices, and attributes are the only allowable nodes.
10.998 + """
10.999 + l = self.com_node(node)
10.1000 + if l.__class__ in (Name, Slice, Subscript, Getattr):
10.1001 + return l
10.1002 + raise SyntaxError, "can't assign to %s" % l.__class__.__name__
10.1003 +
10.1004 + def com_assign(self, node, assigning):
10.1005 + # return a node suitable for use as an "lvalue"
10.1006 + # loop to avoid trivial recursion
10.1007 + while 1:
10.1008 + t = node[0]
10.1009 + if t in (symbol.exprlist, symbol.testlist, symbol.testlist_safe, symbol.testlist_comp):
10.1010 + if len(node) > 2:
10.1011 + return self.com_assign_tuple(node, assigning)
10.1012 + node = node[1]
10.1013 + elif t in _assign_types:
10.1014 + if len(node) > 2:
10.1015 + raise SyntaxError, "can't assign to operator"
10.1016 + node = node[1]
10.1017 + elif t == symbol.power:
10.1018 + if node[1][0] != symbol.atom:
10.1019 + raise SyntaxError, "can't assign to operator"
10.1020 + if len(node) > 2:
10.1021 + primary = self.com_node(node[1])
10.1022 + for i in range(2, len(node)-1):
10.1023 + ch = node[i]
10.1024 + if ch[0] == token.DOUBLESTAR:
10.1025 + raise SyntaxError, "can't assign to operator"
10.1026 + primary = self.com_apply_trailer(primary, ch)
10.1027 + return self.com_assign_trailer(primary, node[-1],
10.1028 + assigning)
10.1029 + node = node[1]
10.1030 + elif t == symbol.atom:
10.1031 + t = node[1][0]
10.1032 + if t == token.LPAR:
10.1033 + node = node[2]
10.1034 + if node[0] == token.RPAR:
10.1035 + raise SyntaxError, "can't assign to ()"
10.1036 + elif t == token.LSQB:
10.1037 + node = node[2]
10.1038 + if node[0] == token.RSQB:
10.1039 + raise SyntaxError, "can't assign to []"
10.1040 + return self.com_assign_list(node, assigning)
10.1041 + elif t == token.NAME:
10.1042 + return self.com_assign_name(node[1], assigning)
10.1043 + else:
10.1044 + raise SyntaxError, "can't assign to literal"
10.1045 + else:
10.1046 + raise SyntaxError, "bad assignment (%s)" % t
10.1047 +
10.1048 + def com_assign_tuple(self, node, assigning):
10.1049 + assigns = []
10.1050 + for i in range(1, len(node), 2):
10.1051 + assigns.append(self.com_assign(node[i], assigning))
10.1052 + return AssTuple(assigns, lineno=extractLineNo(node))
10.1053 +
10.1054 + def com_assign_list(self, node, assigning):
10.1055 + assigns = []
10.1056 + for i in range(1, len(node), 2):
10.1057 + if i + 1 < len(node):
10.1058 + if node[i + 1][0] == symbol.list_for:
10.1059 + raise SyntaxError, "can't assign to list comprehension"
10.1060 + assert node[i + 1][0] == token.COMMA, node[i + 1]
10.1061 + assigns.append(self.com_assign(node[i], assigning))
10.1062 + return AssList(assigns, lineno=extractLineNo(node))
10.1063 +
10.1064 + def com_assign_name(self, node, assigning):
10.1065 + return AssName(node[1], assigning, lineno=node[2])
10.1066 +
10.1067 + def com_assign_trailer(self, primary, node, assigning):
10.1068 + t = node[1][0]
10.1069 + if t == token.DOT:
10.1070 + return self.com_assign_attr(primary, node[2], assigning)
10.1071 + if t == token.LSQB:
10.1072 + return self.com_subscriptlist(primary, node[2], assigning)
10.1073 + if t == token.LPAR:
10.1074 + raise SyntaxError, "can't assign to function call"
10.1075 + raise SyntaxError, "unknown trailer type: %s" % t
10.1076 +
10.1077 + def com_assign_attr(self, primary, node, assigning):
10.1078 + return AssAttr(primary, node[1], assigning, lineno=node[-1])
10.1079 +
10.1080 + def com_binary(self, constructor, nodelist):
10.1081 + "Compile 'NODE (OP NODE)*' into (type, [ node1, ..., nodeN ])."
10.1082 + l = len(nodelist)
10.1083 + if l == 1:
10.1084 + n = nodelist[0]
10.1085 + return self.lookup_node(n)(n[1:])
10.1086 + items = []
10.1087 + for i in range(0, l, 2):
10.1088 + n = nodelist[i]
10.1089 + items.append(self.lookup_node(n)(n[1:]))
10.1090 + return constructor(items, lineno=extractLineNo(nodelist))
10.1091 +
10.1092 + def com_stmt(self, node):
10.1093 + result = self.lookup_node(node)(node[1:])
10.1094 + assert result is not None
10.1095 + if isinstance(result, Stmt):
10.1096 + return result
10.1097 + return Stmt([result])
10.1098 +
10.1099 + def com_append_stmt(self, stmts, node):
10.1100 + result = self.lookup_node(node)(node[1:])
10.1101 + assert result is not None
10.1102 + if isinstance(result, Stmt):
10.1103 + stmts.extend(result.nodes)
10.1104 + else:
10.1105 + stmts.append(result)
10.1106 +
10.1107 + def com_list_constructor(self, nodelist):
10.1108 + # listmaker: test ( list_for | (',' test)* [','] )
10.1109 + values = []
10.1110 + for i in range(1, len(nodelist)):
10.1111 + if nodelist[i][0] == symbol.list_for:
10.1112 + assert len(nodelist[i:]) == 1
10.1113 + return self.com_list_comprehension(values[0],
10.1114 + nodelist[i])
10.1115 + elif nodelist[i][0] == token.COMMA:
10.1116 + continue
10.1117 + values.append(self.com_node(nodelist[i]))
10.1118 + return List(values, lineno=values[0].lineno)
10.1119 +
10.1120 + def com_list_comprehension(self, expr, node):
10.1121 + return self.com_comprehension(expr, None, node, 'list')
10.1122 +
10.1123 + def com_comprehension(self, expr1, expr2, node, type):
10.1124 + # list_iter: list_for | list_if
10.1125 + # list_for: 'for' exprlist 'in' testlist [list_iter]
10.1126 + # list_if: 'if' test [list_iter]
10.1127 +
10.1128 + # XXX should raise SyntaxError for assignment
10.1129 + # XXX(avassalotti) Set and dict comprehensions should have generator
10.1130 + # semantics. In other words, they shouldn't leak
10.1131 + # variables outside of the comprehension's scope.
10.1132 +
10.1133 + lineno = node[1][2]
10.1134 + fors = []
10.1135 + while node:
10.1136 + t = node[1][1]
10.1137 + if t == 'for':
10.1138 + assignNode = self.com_assign(node[2], OP_ASSIGN)
10.1139 + compNode = self.com_node(node[4])
10.1140 + newfor = ListCompFor(assignNode, compNode, [])
10.1141 + newfor.lineno = node[1][2]
10.1142 + fors.append(newfor)
10.1143 + if len(node) == 5:
10.1144 + node = None
10.1145 + elif type == 'list':
10.1146 + node = self.com_list_iter(node[5])
10.1147 + else:
10.1148 + node = self.com_comp_iter(node[5])
10.1149 + elif t == 'if':
10.1150 + test = self.com_node(node[2])
10.1151 + newif = ListCompIf(test, lineno=node[1][2])
10.1152 + newfor.ifs.append(newif)
10.1153 + if len(node) == 3:
10.1154 + node = None
10.1155 + elif type == 'list':
10.1156 + node = self.com_list_iter(node[3])
10.1157 + else:
10.1158 + node = self.com_comp_iter(node[3])
10.1159 + else:
10.1160 + raise SyntaxError, \
10.1161 + ("unexpected comprehension element: %s %d"
10.1162 + % (node, lineno))
10.1163 + if type == 'list':
10.1164 + return ListComp(expr1, fors, lineno=lineno)
10.1165 + elif type == 'set':
10.1166 + return SetComp(expr1, fors, lineno=lineno)
10.1167 + elif type == 'dict':
10.1168 + return DictComp(expr1, expr2, fors, lineno=lineno)
10.1169 + else:
10.1170 + raise ValueError("unexpected comprehension type: " + repr(type))
10.1171 +
10.1172 + def com_list_iter(self, node):
10.1173 + assert node[0] == symbol.list_iter
10.1174 + return node[1]
10.1175 +
10.1176 + def com_comp_iter(self, node):
10.1177 + assert node[0] == symbol.comp_iter
10.1178 + return node[1]
10.1179 +
10.1180 + def com_generator_expression(self, expr, node):
10.1181 + # comp_iter: comp_for | comp_if
10.1182 + # comp_for: 'for' exprlist 'in' test [comp_iter]
10.1183 + # comp_if: 'if' test [comp_iter]
10.1184 +
10.1185 + lineno = node[1][2]
10.1186 + fors = []
10.1187 + while node:
10.1188 + t = node[1][1]
10.1189 + if t == 'for':
10.1190 + assignNode = self.com_assign(node[2], OP_ASSIGN)
10.1191 + genNode = self.com_node(node[4])
10.1192 + newfor = GenExprFor(assignNode, genNode, [],
10.1193 + lineno=node[1][2])
10.1194 + fors.append(newfor)
10.1195 + if (len(node)) == 5:
10.1196 + node = None
10.1197 + else:
10.1198 + node = self.com_comp_iter(node[5])
10.1199 + elif t == 'if':
10.1200 + test = self.com_node(node[2])
10.1201 + newif = GenExprIf(test, lineno=node[1][2])
10.1202 + newfor.ifs.append(newif)
10.1203 + if len(node) == 3:
10.1204 + node = None
10.1205 + else:
10.1206 + node = self.com_comp_iter(node[3])
10.1207 + else:
10.1208 + raise SyntaxError, \
10.1209 + ("unexpected generator expression element: %s %d"
10.1210 + % (node, lineno))
10.1211 + fors[0].is_outmost = True
10.1212 + return GenExpr(GenExprInner(expr, fors), lineno=lineno)
10.1213 +
10.1214 + def com_dictorsetmaker(self, nodelist):
10.1215 + # dictorsetmaker: ( (test ':' test (comp_for | (',' test ':' test)* [','])) |
10.1216 + # (test (comp_for | (',' test)* [','])) )
10.1217 + assert nodelist[0] == symbol.dictorsetmaker
10.1218 + nodelist = nodelist[1:]
10.1219 + if len(nodelist) == 1 or nodelist[1][0] == token.COMMA:
10.1220 + # set literal
10.1221 + items = []
10.1222 + for i in range(0, len(nodelist), 2):
10.1223 + items.append(self.com_node(nodelist[i]))
10.1224 + return Set(items, lineno=items[0].lineno)
10.1225 + elif nodelist[1][0] == symbol.comp_for:
10.1226 + # set comprehension
10.1227 + expr = self.com_node(nodelist[0])
10.1228 + return self.com_comprehension(expr, None, nodelist[1], 'set')
10.1229 + elif len(nodelist) > 3 and nodelist[3][0] == symbol.comp_for:
10.1230 + # dict comprehension
10.1231 + assert nodelist[1][0] == token.COLON
10.1232 + key = self.com_node(nodelist[0])
10.1233 + value = self.com_node(nodelist[2])
10.1234 + return self.com_comprehension(key, value, nodelist[3], 'dict')
10.1235 + else:
10.1236 + # dict literal
10.1237 + items = []
10.1238 + for i in range(0, len(nodelist), 4):
10.1239 + items.append((self.com_node(nodelist[i]),
10.1240 + self.com_node(nodelist[i+2])))
10.1241 + return Dict(items, lineno=items[0][0].lineno)
10.1242 +
10.1243 + def com_apply_trailer(self, primaryNode, nodelist):
10.1244 + t = nodelist[1][0]
10.1245 + if t == token.LPAR:
10.1246 + return self.com_call_function(primaryNode, nodelist[2])
10.1247 + if t == token.DOT:
10.1248 + return self.com_select_member(primaryNode, nodelist[2])
10.1249 + if t == token.LSQB:
10.1250 + return self.com_subscriptlist(primaryNode, nodelist[2], OP_APPLY)
10.1251 +
10.1252 + raise SyntaxError, 'unknown node type: %s' % t
10.1253 +
10.1254 + def com_select_member(self, primaryNode, nodelist):
10.1255 + if nodelist[0] != token.NAME:
10.1256 + raise SyntaxError, "member must be a name"
10.1257 + return Getattr(primaryNode, nodelist[1], lineno=nodelist[2])
10.1258 +
10.1259 + def com_call_function(self, primaryNode, nodelist):
10.1260 + if nodelist[0] == token.RPAR:
10.1261 + return CallFunc(primaryNode, [], lineno=extractLineNo(nodelist))
10.1262 + args = []
10.1263 + kw = 0
10.1264 + star_node = dstar_node = None
10.1265 + len_nodelist = len(nodelist)
10.1266 + i = 1
10.1267 + while i < len_nodelist:
10.1268 + node = nodelist[i]
10.1269 +
10.1270 + if node[0]==token.STAR:
10.1271 + if star_node is not None:
10.1272 + raise SyntaxError, 'already have the varargs indentifier'
10.1273 + star_node = self.com_node(nodelist[i+1])
10.1274 + i = i + 3
10.1275 + continue
10.1276 + elif node[0]==token.DOUBLESTAR:
10.1277 + if dstar_node is not None:
10.1278 + raise SyntaxError, 'already have the kwargs indentifier'
10.1279 + dstar_node = self.com_node(nodelist[i+1])
10.1280 + i = i + 3
10.1281 + continue
10.1282 +
10.1283 + # positional or named parameters
10.1284 + kw, result = self.com_argument(node, kw, star_node)
10.1285 +
10.1286 + if len_nodelist != 2 and isinstance(result, GenExpr) \
10.1287 + and len(node) == 3 and node[2][0] == symbol.comp_for:
10.1288 + # allow f(x for x in y), but reject f(x for x in y, 1)
10.1289 + # should use f((x for x in y), 1) instead of f(x for x in y, 1)
10.1290 + raise SyntaxError, 'generator expression needs parenthesis'
10.1291 +
10.1292 + args.append(result)
10.1293 + i = i + 2
10.1294 +
10.1295 + return CallFunc(primaryNode, args, star_node, dstar_node,
10.1296 + lineno=extractLineNo(nodelist))
10.1297 +
10.1298 + def com_argument(self, nodelist, kw, star_node):
10.1299 + if len(nodelist) == 3 and nodelist[2][0] == symbol.comp_for:
10.1300 + test = self.com_node(nodelist[1])
10.1301 + return 0, self.com_generator_expression(test, nodelist[2])
10.1302 + if len(nodelist) == 2:
10.1303 + if kw:
10.1304 + raise SyntaxError, "non-keyword arg after keyword arg"
10.1305 + if star_node:
10.1306 + raise SyntaxError, "only named arguments may follow *expression"
10.1307 + return 0, self.com_node(nodelist[1])
10.1308 + result = self.com_node(nodelist[3])
10.1309 + n = nodelist[1]
10.1310 + while len(n) == 2 and n[0] != token.NAME:
10.1311 + n = n[1]
10.1312 + if n[0] != token.NAME:
10.1313 + raise SyntaxError, "keyword can't be an expression (%s)"%n[0]
10.1314 + node = Keyword(n[1], result, lineno=n[2])
10.1315 + return 1, node
10.1316 +
10.1317 + def com_subscriptlist(self, primary, nodelist, assigning):
10.1318 + # slicing: simple_slicing | extended_slicing
10.1319 + # simple_slicing: primary "[" short_slice "]"
10.1320 + # extended_slicing: primary "[" slice_list "]"
10.1321 + # slice_list: slice_item ("," slice_item)* [","]
10.1322 +
10.1323 + # backwards compat slice for '[i:j]'
10.1324 + if len(nodelist) == 2:
10.1325 + sub = nodelist[1]
10.1326 + if (sub[1][0] == token.COLON or \
10.1327 + (len(sub) > 2 and sub[2][0] == token.COLON)) and \
10.1328 + sub[-1][0] != symbol.sliceop:
10.1329 + return self.com_slice(primary, sub, assigning)
10.1330 +
10.1331 + subscripts = []
10.1332 + for i in range(1, len(nodelist), 2):
10.1333 + subscripts.append(self.com_subscript(nodelist[i]))
10.1334 + return Subscript(primary, assigning, subscripts,
10.1335 + lineno=extractLineNo(nodelist))
10.1336 +
10.1337 + def com_subscript(self, node):
10.1338 + # slice_item: expression | proper_slice | ellipsis
10.1339 + ch = node[1]
10.1340 + t = ch[0]
10.1341 + if t == token.DOT and node[2][0] == token.DOT:
10.1342 + return Ellipsis()
10.1343 + if t == token.COLON or len(node) > 2:
10.1344 + return self.com_sliceobj(node)
10.1345 + return self.com_node(ch)
10.1346 +
10.1347 + def com_sliceobj(self, node):
10.1348 + # proper_slice: short_slice | long_slice
10.1349 + # short_slice: [lower_bound] ":" [upper_bound]
10.1350 + # long_slice: short_slice ":" [stride]
10.1351 + # lower_bound: expression
10.1352 + # upper_bound: expression
10.1353 + # stride: expression
10.1354 + #
10.1355 + # Note: a stride may be further slicing...
10.1356 +
10.1357 + items = []
10.1358 +
10.1359 + if node[1][0] == token.COLON:
10.1360 + items.append(Const(None))
10.1361 + i = 2
10.1362 + else:
10.1363 + items.append(self.com_node(node[1]))
10.1364 + # i == 2 is a COLON
10.1365 + i = 3
10.1366 +
10.1367 + if i < len(node) and node[i][0] == symbol.test:
10.1368 + items.append(self.com_node(node[i]))
10.1369 + i = i + 1
10.1370 + else:
10.1371 + items.append(Const(None))
10.1372 +
10.1373 + # a short_slice has been built. look for long_slice now by looking
10.1374 + # for strides...
10.1375 + for j in range(i, len(node)):
10.1376 + ch = node[j]
10.1377 + if len(ch) == 2:
10.1378 + items.append(Const(None))
10.1379 + else:
10.1380 + items.append(self.com_node(ch[2]))
10.1381 + return Sliceobj(items, lineno=extractLineNo(node))
10.1382 +
10.1383 + def com_slice(self, primary, node, assigning):
10.1384 + # short_slice: [lower_bound] ":" [upper_bound]
10.1385 + lower = upper = None
10.1386 + if len(node) == 3:
10.1387 + if node[1][0] == token.COLON:
10.1388 + upper = self.com_node(node[2])
10.1389 + else:
10.1390 + lower = self.com_node(node[1])
10.1391 + elif len(node) == 4:
10.1392 + lower = self.com_node(node[1])
10.1393 + upper = self.com_node(node[3])
10.1394 + return Slice(primary, assigning, lower, upper,
10.1395 + lineno=extractLineNo(node))
10.1396 +
10.1397 + def get_docstring(self, node, n=None):
10.1398 + if n is None:
10.1399 + n = node[0]
10.1400 + node = node[1:]
10.1401 + if n == symbol.suite:
10.1402 + if len(node) == 1:
10.1403 + return self.get_docstring(node[0])
10.1404 + for sub in node:
10.1405 + if sub[0] == symbol.stmt:
10.1406 + return self.get_docstring(sub)
10.1407 + return None
10.1408 + if n == symbol.file_input:
10.1409 + for sub in node:
10.1410 + if sub[0] == symbol.stmt:
10.1411 + return self.get_docstring(sub)
10.1412 + return None
10.1413 + if n == symbol.atom:
10.1414 + if node[0][0] == token.STRING:
10.1415 + s = ''
10.1416 + for t in node:
10.1417 + s = s + eval(t[1])
10.1418 + return s
10.1419 + return None
10.1420 + if n == symbol.stmt or n == symbol.simple_stmt \
10.1421 + or n == symbol.small_stmt:
10.1422 + return self.get_docstring(node[0])
10.1423 + if n in _doc_nodes and len(node) == 1:
10.1424 + return self.get_docstring(node[0])
10.1425 + return None
10.1426 +
10.1427 +
10.1428 +_doc_nodes = [
10.1429 + symbol.expr_stmt,
10.1430 + symbol.testlist,
10.1431 + symbol.testlist_safe,
10.1432 + symbol.test,
10.1433 + symbol.or_test,
10.1434 + symbol.and_test,
10.1435 + symbol.not_test,
10.1436 + symbol.comparison,
10.1437 + symbol.expr,
10.1438 + symbol.xor_expr,
10.1439 + symbol.and_expr,
10.1440 + symbol.shift_expr,
10.1441 + symbol.arith_expr,
10.1442 + symbol.term,
10.1443 + symbol.factor,
10.1444 + symbol.power,
10.1445 + ]
10.1446 +
10.1447 +# comp_op: '<' | '>' | '=' | '>=' | '<=' | '<>' | '!=' | '=='
10.1448 +# | 'in' | 'not' 'in' | 'is' | 'is' 'not'
10.1449 +_cmp_types = {
10.1450 + token.LESS : '<',
10.1451 + token.GREATER : '>',
10.1452 + token.EQEQUAL : '==',
10.1453 + token.EQUAL : '==',
10.1454 + token.LESSEQUAL : '<=',
10.1455 + token.GREATEREQUAL : '>=',
10.1456 + token.NOTEQUAL : '!=',
10.1457 + }
10.1458 +
10.1459 +_legal_node_types = [
10.1460 + symbol.funcdef,
10.1461 + symbol.classdef,
10.1462 + symbol.stmt,
10.1463 + symbol.small_stmt,
10.1464 + symbol.flow_stmt,
10.1465 + symbol.simple_stmt,
10.1466 + symbol.compound_stmt,
10.1467 + symbol.expr_stmt,
10.1468 + symbol.print_stmt,
10.1469 + symbol.del_stmt,
10.1470 + symbol.pass_stmt,
10.1471 + symbol.break_stmt,
10.1472 + symbol.continue_stmt,
10.1473 + symbol.return_stmt,
10.1474 + symbol.raise_stmt,
10.1475 + symbol.import_stmt,
10.1476 + symbol.global_stmt,
10.1477 + symbol.exec_stmt,
10.1478 + symbol.assert_stmt,
10.1479 + symbol.if_stmt,
10.1480 + symbol.while_stmt,
10.1481 + symbol.for_stmt,
10.1482 + symbol.try_stmt,
10.1483 + symbol.with_stmt,
10.1484 + symbol.suite,
10.1485 + symbol.testlist,
10.1486 + symbol.testlist_safe,
10.1487 + symbol.test,
10.1488 + symbol.and_test,
10.1489 + symbol.not_test,
10.1490 + symbol.comparison,
10.1491 + symbol.exprlist,
10.1492 + symbol.expr,
10.1493 + symbol.xor_expr,
10.1494 + symbol.and_expr,
10.1495 + symbol.shift_expr,
10.1496 + symbol.arith_expr,
10.1497 + symbol.term,
10.1498 + symbol.factor,
10.1499 + symbol.power,
10.1500 + symbol.atom,
10.1501 + ]
10.1502 +
10.1503 +if hasattr(symbol, 'yield_stmt'):
10.1504 + _legal_node_types.append(symbol.yield_stmt)
10.1505 +if hasattr(symbol, 'yield_expr'):
10.1506 + _legal_node_types.append(symbol.yield_expr)
10.1507 +
10.1508 +_assign_types = [
10.1509 + symbol.test,
10.1510 + symbol.or_test,
10.1511 + symbol.and_test,
10.1512 + symbol.not_test,
10.1513 + symbol.comparison,
10.1514 + symbol.expr,
10.1515 + symbol.xor_expr,
10.1516 + symbol.and_expr,
10.1517 + symbol.shift_expr,
10.1518 + symbol.arith_expr,
10.1519 + symbol.term,
10.1520 + symbol.factor,
10.1521 + ]
10.1522 +
10.1523 +_names = {}
10.1524 +for k, v in symbol.sym_name.items():
10.1525 + _names[k] = v
10.1526 +for k, v in token.tok_name.items():
10.1527 + _names[k] = v
10.1528 +
10.1529 +def debug_tree(tree):
10.1530 + l = []
10.1531 + for elt in tree:
10.1532 + if isinstance(elt, int):
10.1533 + l.append(_names.get(elt, elt))
10.1534 + elif isinstance(elt, str):
10.1535 + l.append(elt)
10.1536 + else:
10.1537 + l.append(debug_tree(elt))
10.1538 + return l
11.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
11.2 +++ b/compiler/visitor.py Fri May 18 23:26:30 2012 +0200
11.3 @@ -0,0 +1,113 @@
11.4 +from compiler import ast
11.5 +
11.6 +# XXX should probably rename ASTVisitor to ASTWalker
11.7 +# XXX can it be made even more generic?
11.8 +
11.9 +class ASTVisitor:
11.10 + """Performs a depth-first walk of the AST
11.11 +
11.12 + The ASTVisitor will walk the AST, performing either a preorder or
11.13 + postorder traversal depending on which method is called.
11.14 +
11.15 + methods:
11.16 + preorder(tree, visitor)
11.17 + postorder(tree, visitor)
11.18 + tree: an instance of ast.Node
11.19 + visitor: an instance with visitXXX methods
11.20 +
11.21 + The ASTVisitor is responsible for walking over the tree in the
11.22 + correct order. For each node, it checks the visitor argument for
11.23 + a method named 'visitNodeType' where NodeType is the name of the
11.24 + node's class, e.g. Class. If the method exists, it is called
11.25 + with the node as its sole argument.
11.26 +
11.27 + The visitor method for a particular node type can control how
11.28 + child nodes are visited during a preorder walk. (It can't control
11.29 + the order during a postorder walk, because it is called _after_
11.30 + the walk has occurred.) The ASTVisitor modifies the visitor
11.31 + argument by adding a visit method to the visitor; this method can
11.32 + be used to visit a child node of arbitrary type.
11.33 + """
11.34 +
11.35 + VERBOSE = 0
11.36 +
11.37 + def __init__(self):
11.38 + self.node = None
11.39 + self._cache = {}
11.40 +
11.41 + def default(self, node, *args):
11.42 + for child in node.getChildNodes():
11.43 + self.dispatch(child, *args)
11.44 +
11.45 + def dispatch(self, node, *args):
11.46 + self.node = node
11.47 + klass = node.__class__
11.48 + meth = self._cache.get(klass, None)
11.49 + if meth is None:
11.50 + className = klass.__name__
11.51 + meth = getattr(self.visitor, 'visit' + className, self.default)
11.52 + self._cache[klass] = meth
11.53 +## if self.VERBOSE > 0:
11.54 +## className = klass.__name__
11.55 +## if self.VERBOSE == 1:
11.56 +## if meth == 0:
11.57 +## print "dispatch", className
11.58 +## else:
11.59 +## print "dispatch", className, (meth and meth.__name__ or '')
11.60 + return meth(node, *args)
11.61 +
11.62 + def preorder(self, tree, visitor, *args):
11.63 + """Do preorder walk of tree using visitor"""
11.64 + self.visitor = visitor
11.65 + visitor.visit = self.dispatch
11.66 + self.dispatch(tree, *args) # XXX *args make sense?
11.67 +
11.68 +class ExampleASTVisitor(ASTVisitor):
11.69 + """Prints examples of the nodes that aren't visited
11.70 +
11.71 + This visitor-driver is only useful for development, when it's
11.72 + helpful to develop a visitor incrementally, and get feedback on what
11.73 + you still have to do.
11.74 + """
11.75 + examples = {}
11.76 +
11.77 + def dispatch(self, node, *args):
11.78 + self.node = node
11.79 + meth = self._cache.get(node.__class__, None)
11.80 + className = node.__class__.__name__
11.81 + if meth is None:
11.82 + meth = getattr(self.visitor, 'visit' + className, 0)
11.83 + self._cache[node.__class__] = meth
11.84 + if self.VERBOSE > 1:
11.85 + print "dispatch", className, (meth and meth.__name__ or '')
11.86 + if meth:
11.87 + meth(node, *args)
11.88 + elif self.VERBOSE > 0:
11.89 + klass = node.__class__
11.90 + if klass not in self.examples:
11.91 + self.examples[klass] = klass
11.92 + print
11.93 + print self.visitor
11.94 + print klass
11.95 + for attr in dir(node):
11.96 + if attr[0] != '_':
11.97 + print "\t", "%-12.12s" % attr, getattr(node, attr)
11.98 + print
11.99 + return self.default(node, *args)
11.100 +
11.101 +# XXX this is an API change
11.102 +
11.103 +_walker = ASTVisitor
11.104 +def walk(tree, visitor, walker=None, verbose=None):
11.105 + if walker is None:
11.106 + walker = _walker()
11.107 + if verbose is not None:
11.108 + walker.VERBOSE = verbose
11.109 + walker.preorder(tree, visitor)
11.110 + return walker.visitor
11.111 +
11.112 +def dumpNode(node):
11.113 + print node.__class__
11.114 + for attr in dir(node):
11.115 + if attr[0] != '_':
11.116 + print "\t", "%-10.10s" % attr, getattr(node, attr)
12.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
12.2 +++ b/docs/COPYRIGHT Fri May 18 23:26:30 2012 +0200
12.3 @@ -0,0 +1,22 @@
12.4 +Copyright information from Python 2.7.3
12.5 +---------------------------------------
12.6 +
12.7 +Copyright (c) 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010, 2011,
12.8 +2012 Python Software Foundation. All rights reserved.
12.9 +
12.10 +Copyright (c) 2000 BeOpen.com.
12.11 +All rights reserved.
12.12 +
12.13 +Copyright (c) 1995-2001 Corporation for National Research Initiatives.
12.14 +All rights reserved.
12.15 +
12.16 +Copyright (c) 1991-1995 Stichting Mathematisch Centrum.
12.17 +All rights reserved.
12.18 +
12.19 +
12.20 +License information
12.21 +-------------------
12.22 +
12.23 +See the file "LICENSE" for information on the history of this
12.24 +software, terms & conditions for usage, and a DISCLAIMER OF ALL
12.25 +WARRANTIES.
13.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
13.2 +++ b/docs/LICENSE Fri May 18 23:26:30 2012 +0200
13.3 @@ -0,0 +1,279 @@
13.4 +A. HISTORY OF THE SOFTWARE
13.5 +==========================
13.6 +
13.7 +Python was created in the early 1990s by Guido van Rossum at Stichting
13.8 +Mathematisch Centrum (CWI, see http://www.cwi.nl) in the Netherlands
13.9 +as a successor of a language called ABC. Guido remains Python's
13.10 +principal author, although it includes many contributions from others.
13.11 +
13.12 +In 1995, Guido continued his work on Python at the Corporation for
13.13 +National Research Initiatives (CNRI, see http://www.cnri.reston.va.us)
13.14 +in Reston, Virginia where he released several versions of the
13.15 +software.
13.16 +
13.17 +In May 2000, Guido and the Python core development team moved to
13.18 +BeOpen.com to form the BeOpen PythonLabs team. In October of the same
13.19 +year, the PythonLabs team moved to Digital Creations (now Zope
13.20 +Corporation, see http://www.zope.com). In 2001, the Python Software
13.21 +Foundation (PSF, see http://www.python.org/psf/) was formed, a
13.22 +non-profit organization created specifically to own Python-related
13.23 +Intellectual Property. Zope Corporation is a sponsoring member of
13.24 +the PSF.
13.25 +
13.26 +All Python releases are Open Source (see http://www.opensource.org for
13.27 +the Open Source Definition). Historically, most, but not all, Python
13.28 +releases have also been GPL-compatible; the table below summarizes
13.29 +the various releases.
13.30 +
13.31 + Release Derived Year Owner GPL-
13.32 + from compatible? (1)
13.33 +
13.34 + 0.9.0 thru 1.2 1991-1995 CWI yes
13.35 + 1.3 thru 1.5.2 1.2 1995-1999 CNRI yes
13.36 + 1.6 1.5.2 2000 CNRI no
13.37 + 2.0 1.6 2000 BeOpen.com no
13.38 + 1.6.1 1.6 2001 CNRI yes (2)
13.39 + 2.1 2.0+1.6.1 2001 PSF no
13.40 + 2.0.1 2.0+1.6.1 2001 PSF yes
13.41 + 2.1.1 2.1+2.0.1 2001 PSF yes
13.42 + 2.2 2.1.1 2001 PSF yes
13.43 + 2.1.2 2.1.1 2002 PSF yes
13.44 + 2.1.3 2.1.2 2002 PSF yes
13.45 + 2.2.1 2.2 2002 PSF yes
13.46 + 2.2.2 2.2.1 2002 PSF yes
13.47 + 2.2.3 2.2.2 2003 PSF yes
13.48 + 2.3 2.2.2 2002-2003 PSF yes
13.49 + 2.3.1 2.3 2002-2003 PSF yes
13.50 + 2.3.2 2.3.1 2002-2003 PSF yes
13.51 + 2.3.3 2.3.2 2002-2003 PSF yes
13.52 + 2.3.4 2.3.3 2004 PSF yes
13.53 + 2.3.5 2.3.4 2005 PSF yes
13.54 + 2.4 2.3 2004 PSF yes
13.55 + 2.4.1 2.4 2005 PSF yes
13.56 + 2.4.2 2.4.1 2005 PSF yes
13.57 + 2.4.3 2.4.2 2006 PSF yes
13.58 + 2.4.4 2.4.3 2006 PSF yes
13.59 + 2.5 2.4 2006 PSF yes
13.60 + 2.5.1 2.5 2007 PSF yes
13.61 + 2.5.2 2.5.1 2008 PSF yes
13.62 + 2.5.3 2.5.2 2008 PSF yes
13.63 + 2.6 2.5 2008 PSF yes
13.64 + 2.6.1 2.6 2008 PSF yes
13.65 + 2.6.2 2.6.1 2009 PSF yes
13.66 + 2.6.3 2.6.2 2009 PSF yes
13.67 + 2.6.4 2.6.3 2009 PSF yes
13.68 + 2.6.5 2.6.4 2010 PSF yes
13.69 + 2.7 2.6 2010 PSF yes
13.70 +
13.71 +Footnotes:
13.72 +
13.73 +(1) GPL-compatible doesn't mean that we're distributing Python under
13.74 + the GPL. All Python licenses, unlike the GPL, let you distribute
13.75 + a modified version without making your changes open source. The
13.76 + GPL-compatible licenses make it possible to combine Python with
13.77 + other software that is released under the GPL; the others don't.
13.78 +
13.79 +(2) According to Richard Stallman, 1.6.1 is not GPL-compatible,
13.80 + because its license has a choice of law clause. According to
13.81 + CNRI, however, Stallman's lawyer has told CNRI's lawyer that 1.6.1
13.82 + is "not incompatible" with the GPL.
13.83 +
13.84 +Thanks to the many outside volunteers who have worked under Guido's
13.85 +direction to make these releases possible.
13.86 +
13.87 +
13.88 +B. TERMS AND CONDITIONS FOR ACCESSING OR OTHERWISE USING PYTHON
13.89 +===============================================================
13.90 +
13.91 +PYTHON SOFTWARE FOUNDATION LICENSE VERSION 2
13.92 +--------------------------------------------
13.93 +
13.94 +1. This LICENSE AGREEMENT is between the Python Software Foundation
13.95 +("PSF"), and the Individual or Organization ("Licensee") accessing and
13.96 +otherwise using this software ("Python") in source or binary form and
13.97 +its associated documentation.
13.98 +
13.99 +2. Subject to the terms and conditions of this License Agreement, PSF hereby
13.100 +grants Licensee a nonexclusive, royalty-free, world-wide license to reproduce,
13.101 +analyze, test, perform and/or display publicly, prepare derivative works,
13.102 +distribute, and otherwise use Python alone or in any derivative version,
13.103 +provided, however, that PSF's License Agreement and PSF's notice of copyright,
13.104 +i.e., "Copyright (c) 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010,
13.105 +2011, 2012 Python Software Foundation; All Rights Reserved" are retained in Python
13.106 +alone or in any derivative version prepared by Licensee.
13.107 +
13.108 +3. In the event Licensee prepares a derivative work that is based on
13.109 +or incorporates Python or any part thereof, and wants to make
13.110 +the derivative work available to others as provided herein, then
13.111 +Licensee hereby agrees to include in any such work a brief summary of
13.112 +the changes made to Python.
13.113 +
13.114 +4. PSF is making Python available to Licensee on an "AS IS"
13.115 +basis. PSF MAKES NO REPRESENTATIONS OR WARRANTIES, EXPRESS OR
13.116 +IMPLIED. BY WAY OF EXAMPLE, BUT NOT LIMITATION, PSF MAKES NO AND
13.117 +DISCLAIMS ANY REPRESENTATION OR WARRANTY OF MERCHANTABILITY OR FITNESS
13.118 +FOR ANY PARTICULAR PURPOSE OR THAT THE USE OF PYTHON WILL NOT
13.119 +INFRINGE ANY THIRD PARTY RIGHTS.
13.120 +
13.121 +5. PSF SHALL NOT BE LIABLE TO LICENSEE OR ANY OTHER USERS OF PYTHON
13.122 +FOR ANY INCIDENTAL, SPECIAL, OR CONSEQUENTIAL DAMAGES OR LOSS AS
13.123 +A RESULT OF MODIFYING, DISTRIBUTING, OR OTHERWISE USING PYTHON,
13.124 +OR ANY DERIVATIVE THEREOF, EVEN IF ADVISED OF THE POSSIBILITY THEREOF.
13.125 +
13.126 +6. This License Agreement will automatically terminate upon a material
13.127 +breach of its terms and conditions.
13.128 +
13.129 +7. Nothing in this License Agreement shall be deemed to create any
13.130 +relationship of agency, partnership, or joint venture between PSF and
13.131 +Licensee. This License Agreement does not grant permission to use PSF
13.132 +trademarks or trade name in a trademark sense to endorse or promote
13.133 +products or services of Licensee, or any third party.
13.134 +
13.135 +8. By copying, installing or otherwise using Python, Licensee
13.136 +agrees to be bound by the terms and conditions of this License
13.137 +Agreement.
13.138 +
13.139 +
13.140 +BEOPEN.COM LICENSE AGREEMENT FOR PYTHON 2.0
13.141 +-------------------------------------------
13.142 +
13.143 +BEOPEN PYTHON OPEN SOURCE LICENSE AGREEMENT VERSION 1
13.144 +
13.145 +1. This LICENSE AGREEMENT is between BeOpen.com ("BeOpen"), having an
13.146 +office at 160 Saratoga Avenue, Santa Clara, CA 95051, and the
13.147 +Individual or Organization ("Licensee") accessing and otherwise using
13.148 +this software in source or binary form and its associated
13.149 +documentation ("the Software").
13.150 +
13.151 +2. Subject to the terms and conditions of this BeOpen Python License
13.152 +Agreement, BeOpen hereby grants Licensee a non-exclusive,
13.153 +royalty-free, world-wide license to reproduce, analyze, test, perform
13.154 +and/or display publicly, prepare derivative works, distribute, and
13.155 +otherwise use the Software alone or in any derivative version,
13.156 +provided, however, that the BeOpen Python License is retained in the
13.157 +Software, alone or in any derivative version prepared by Licensee.
13.158 +
13.159 +3. BeOpen is making the Software available to Licensee on an "AS IS"
13.160 +basis. BEOPEN MAKES NO REPRESENTATIONS OR WARRANTIES, EXPRESS OR
13.161 +IMPLIED. BY WAY OF EXAMPLE, BUT NOT LIMITATION, BEOPEN MAKES NO AND
13.162 +DISCLAIMS ANY REPRESENTATION OR WARRANTY OF MERCHANTABILITY OR FITNESS
13.163 +FOR ANY PARTICULAR PURPOSE OR THAT THE USE OF THE SOFTWARE WILL NOT
13.164 +INFRINGE ANY THIRD PARTY RIGHTS.
13.165 +
13.166 +4. BEOPEN SHALL NOT BE LIABLE TO LICENSEE OR ANY OTHER USERS OF THE
13.167 +SOFTWARE FOR ANY INCIDENTAL, SPECIAL, OR CONSEQUENTIAL DAMAGES OR LOSS
13.168 +AS A RESULT OF USING, MODIFYING OR DISTRIBUTING THE SOFTWARE, OR ANY
13.169 +DERIVATIVE THEREOF, EVEN IF ADVISED OF THE POSSIBILITY THEREOF.
13.170 +
13.171 +5. This License Agreement will automatically terminate upon a material
13.172 +breach of its terms and conditions.
13.173 +
13.174 +6. This License Agreement shall be governed by and interpreted in all
13.175 +respects by the law of the State of California, excluding conflict of
13.176 +law provisions. Nothing in this License Agreement shall be deemed to
13.177 +create any relationship of agency, partnership, or joint venture
13.178 +between BeOpen and Licensee. This License Agreement does not grant
13.179 +permission to use BeOpen trademarks or trade names in a trademark
13.180 +sense to endorse or promote products or services of Licensee, or any
13.181 +third party. As an exception, the "BeOpen Python" logos available at
13.182 +http://www.pythonlabs.com/logos.html may be used according to the
13.183 +permissions granted on that web page.
13.184 +
13.185 +7. By copying, installing or otherwise using the software, Licensee
13.186 +agrees to be bound by the terms and conditions of this License
13.187 +Agreement.
13.188 +
13.189 +
13.190 +CNRI LICENSE AGREEMENT FOR PYTHON 1.6.1
13.191 +---------------------------------------
13.192 +
13.193 +1. This LICENSE AGREEMENT is between the Corporation for National
13.194 +Research Initiatives, having an office at 1895 Preston White Drive,
13.195 +Reston, VA 20191 ("CNRI"), and the Individual or Organization
13.196 +("Licensee") accessing and otherwise using Python 1.6.1 software in
13.197 +source or binary form and its associated documentation.
13.198 +
13.199 +2. Subject to the terms and conditions of this License Agreement, CNRI
13.200 +hereby grants Licensee a nonexclusive, royalty-free, world-wide
13.201 +license to reproduce, analyze, test, perform and/or display publicly,
13.202 +prepare derivative works, distribute, and otherwise use Python 1.6.1
13.203 +alone or in any derivative version, provided, however, that CNRI's
13.204 +License Agreement and CNRI's notice of copyright, i.e., "Copyright (c)
13.205 +1995-2001 Corporation for National Research Initiatives; All Rights
13.206 +Reserved" are retained in Python 1.6.1 alone or in any derivative
13.207 +version prepared by Licensee. Alternately, in lieu of CNRI's License
13.208 +Agreement, Licensee may substitute the following text (omitting the
13.209 +quotes): "Python 1.6.1 is made available subject to the terms and
13.210 +conditions in CNRI's License Agreement. This Agreement together with
13.211 +Python 1.6.1 may be located on the Internet using the following
13.212 +unique, persistent identifier (known as a handle): 1895.22/1013. This
13.213 +Agreement may also be obtained from a proxy server on the Internet
13.214 +using the following URL: http://hdl.handle.net/1895.22/1013".
13.215 +
13.216 +3. In the event Licensee prepares a derivative work that is based on
13.217 +or incorporates Python 1.6.1 or any part thereof, and wants to make
13.218 +the derivative work available to others as provided herein, then
13.219 +Licensee hereby agrees to include in any such work a brief summary of
13.220 +the changes made to Python 1.6.1.
13.221 +
13.222 +4. CNRI is making Python 1.6.1 available to Licensee on an "AS IS"
13.223 +basis. CNRI MAKES NO REPRESENTATIONS OR WARRANTIES, EXPRESS OR
13.224 +IMPLIED. BY WAY OF EXAMPLE, BUT NOT LIMITATION, CNRI MAKES NO AND
13.225 +DISCLAIMS ANY REPRESENTATION OR WARRANTY OF MERCHANTABILITY OR FITNESS
13.226 +FOR ANY PARTICULAR PURPOSE OR THAT THE USE OF PYTHON 1.6.1 WILL NOT
13.227 +INFRINGE ANY THIRD PARTY RIGHTS.
13.228 +
13.229 +5. CNRI SHALL NOT BE LIABLE TO LICENSEE OR ANY OTHER USERS OF PYTHON
13.230 +1.6.1 FOR ANY INCIDENTAL, SPECIAL, OR CONSEQUENTIAL DAMAGES OR LOSS AS
13.231 +A RESULT OF MODIFYING, DISTRIBUTING, OR OTHERWISE USING PYTHON 1.6.1,
13.232 +OR ANY DERIVATIVE THEREOF, EVEN IF ADVISED OF THE POSSIBILITY THEREOF.
13.233 +
13.234 +6. This License Agreement will automatically terminate upon a material
13.235 +breach of its terms and conditions.
13.236 +
13.237 +7. This License Agreement shall be governed by the federal
13.238 +intellectual property law of the United States, including without
13.239 +limitation the federal copyright law, and, to the extent such
13.240 +U.S. federal law does not apply, by the law of the Commonwealth of
13.241 +Virginia, excluding Virginia's conflict of law provisions.
13.242 +Notwithstanding the foregoing, with regard to derivative works based
13.243 +on Python 1.6.1 that incorporate non-separable material that was
13.244 +previously distributed under the GNU General Public License (GPL), the
13.245 +law of the Commonwealth of Virginia shall govern this License
13.246 +Agreement only as to issues arising under or with respect to
13.247 +Paragraphs 4, 5, and 7 of this License Agreement. Nothing in this
13.248 +License Agreement shall be deemed to create any relationship of
13.249 +agency, partnership, or joint venture between CNRI and Licensee. This
13.250 +License Agreement does not grant permission to use CNRI trademarks or
13.251 +trade name in a trademark sense to endorse or promote products or
13.252 +services of Licensee, or any third party.
13.253 +
13.254 +8. By clicking on the "ACCEPT" button where indicated, or by copying,
13.255 +installing or otherwise using Python 1.6.1, Licensee agrees to be
13.256 +bound by the terms and conditions of this License Agreement.
13.257 +
13.258 + ACCEPT
13.259 +
13.260 +
13.261 +CWI LICENSE AGREEMENT FOR PYTHON 0.9.0 THROUGH 1.2
13.262 +--------------------------------------------------
13.263 +
13.264 +Copyright (c) 1991 - 1995, Stichting Mathematisch Centrum Amsterdam,
13.265 +The Netherlands. All rights reserved.
13.266 +
13.267 +Permission to use, copy, modify, and distribute this software and its
13.268 +documentation for any purpose and without fee is hereby granted,
13.269 +provided that the above copyright notice appear in all copies and that
13.270 +both that copyright notice and this permission notice appear in
13.271 +supporting documentation, and that the name of Stichting Mathematisch
13.272 +Centrum or CWI not be used in advertising or publicity pertaining to
13.273 +distribution of the software without specific, written prior
13.274 +permission.
13.275 +
13.276 +STICHTING MATHEMATISCH CENTRUM DISCLAIMS ALL WARRANTIES WITH REGARD TO
13.277 +THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND
13.278 +FITNESS, IN NO EVENT SHALL STICHTING MATHEMATISCH CENTRUM BE LIABLE
13.279 +FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
13.280 +WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
13.281 +ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT
13.282 +OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.