1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
1.2 +++ b/compiler/pycodegen.py Fri May 18 23:26:30 2012 +0200
1.3 @@ -0,0 +1,1555 @@
1.4 +import imp
1.5 +import os
1.6 +import marshal
1.7 +import struct
1.8 +import sys
1.9 +from cStringIO import StringIO
1.10 +
1.11 +from compiler import ast, parse, walk, syntax
1.12 +from compiler import pyassem, misc, future, symbols
1.13 +from compiler.consts import SC_LOCAL, SC_GLOBAL_IMPLICIT, SC_GLOBAL_EXPLICT, \
1.14 + SC_FREE, SC_CELL
1.15 +from compiler.consts import (CO_VARARGS, CO_VARKEYWORDS, CO_NEWLOCALS,
1.16 + CO_NESTED, CO_GENERATOR, CO_FUTURE_DIVISION,
1.17 + CO_FUTURE_ABSIMPORT, CO_FUTURE_WITH_STATEMENT, CO_FUTURE_PRINT_FUNCTION)
1.18 +from compiler.pyassem import TupleArg
1.19 +
1.20 +# XXX The version-specific code can go, since this code only works with 2.x.
1.21 +# Do we have Python 1.x or Python 2.x?
1.22 +try:
1.23 + VERSION = sys.version_info[0]
1.24 +except AttributeError:
1.25 + VERSION = 1
1.26 +
1.27 +callfunc_opcode_info = {
1.28 + # (Have *args, Have **args) : opcode
1.29 + (0,0) : "CALL_FUNCTION",
1.30 + (1,0) : "CALL_FUNCTION_VAR",
1.31 + (0,1) : "CALL_FUNCTION_KW",
1.32 + (1,1) : "CALL_FUNCTION_VAR_KW",
1.33 +}
1.34 +
1.35 +LOOP = 1
1.36 +EXCEPT = 2
1.37 +TRY_FINALLY = 3
1.38 +END_FINALLY = 4
1.39 +
1.40 +def compileFile(filename, display=0):
1.41 + f = open(filename, 'U')
1.42 + buf = f.read()
1.43 + f.close()
1.44 + mod = Module(buf, filename)
1.45 + try:
1.46 + mod.compile(display)
1.47 + except SyntaxError:
1.48 + raise
1.49 + else:
1.50 + f = open(filename + "c", "wb")
1.51 + mod.dump(f)
1.52 + f.close()
1.53 +
1.54 +def compile(source, filename, mode, flags=None, dont_inherit=None):
1.55 + """Replacement for builtin compile() function"""
1.56 + if flags is not None or dont_inherit is not None:
1.57 + raise RuntimeError, "not implemented yet"
1.58 +
1.59 + if mode == "single":
1.60 + gen = Interactive(source, filename)
1.61 + elif mode == "exec":
1.62 + gen = Module(source, filename)
1.63 + elif mode == "eval":
1.64 + gen = Expression(source, filename)
1.65 + else:
1.66 + raise ValueError("compile() 3rd arg must be 'exec' or "
1.67 + "'eval' or 'single'")
1.68 + gen.compile()
1.69 + return gen.code
1.70 +
1.71 +class AbstractCompileMode:
1.72 +
1.73 + mode = None # defined by subclass
1.74 +
1.75 + def __init__(self, source, filename):
1.76 + self.source = source
1.77 + self.filename = filename
1.78 + self.code = None
1.79 +
1.80 + def _get_tree(self):
1.81 + tree = parse(self.source, self.mode)
1.82 + misc.set_filename(self.filename, tree)
1.83 + syntax.check(tree)
1.84 + return tree
1.85 +
1.86 + def compile(self):
1.87 + pass # implemented by subclass
1.88 +
1.89 + def getCode(self):
1.90 + return self.code
1.91 +
1.92 +class Expression(AbstractCompileMode):
1.93 +
1.94 + mode = "eval"
1.95 +
1.96 + def compile(self):
1.97 + tree = self._get_tree()
1.98 + gen = ExpressionCodeGenerator(tree)
1.99 + self.code = gen.getCode()
1.100 +
1.101 +class Interactive(AbstractCompileMode):
1.102 +
1.103 + mode = "single"
1.104 +
1.105 + def compile(self):
1.106 + tree = self._get_tree()
1.107 + gen = InteractiveCodeGenerator(tree)
1.108 + self.code = gen.getCode()
1.109 +
1.110 +class Module(AbstractCompileMode):
1.111 +
1.112 + mode = "exec"
1.113 +
1.114 + def compile(self, display=0):
1.115 + tree = self._get_tree()
1.116 + gen = ModuleCodeGenerator(tree)
1.117 + if display:
1.118 + import pprint
1.119 + print pprint.pprint(tree)
1.120 + self.code = gen.getCode()
1.121 +
1.122 + def dump(self, f):
1.123 + f.write(self.getPycHeader())
1.124 + marshal.dump(self.code, f)
1.125 +
1.126 + MAGIC = imp.get_magic()
1.127 +
1.128 + def getPycHeader(self):
1.129 + # compile.c uses marshal to write a long directly, with
1.130 + # calling the interface that would also generate a 1-byte code
1.131 + # to indicate the type of the value. simplest way to get the
1.132 + # same effect is to call marshal and then skip the code.
1.133 + mtime = os.path.getmtime(self.filename)
1.134 + mtime = struct.pack('<i', mtime)
1.135 + return self.MAGIC + mtime
1.136 +
1.137 +class LocalNameFinder:
1.138 + """Find local names in scope"""
1.139 + def __init__(self, names=()):
1.140 + self.names = misc.Set()
1.141 + self.globals = misc.Set()
1.142 + for name in names:
1.143 + self.names.add(name)
1.144 +
1.145 + # XXX list comprehensions and for loops
1.146 +
1.147 + def getLocals(self):
1.148 + for elt in self.globals.elements():
1.149 + if self.names.has_elt(elt):
1.150 + self.names.remove(elt)
1.151 + return self.names
1.152 +
1.153 + def visitDict(self, node):
1.154 + pass
1.155 +
1.156 + def visitGlobal(self, node):
1.157 + for name in node.names:
1.158 + self.globals.add(name)
1.159 +
1.160 + def visitFunction(self, node):
1.161 + self.names.add(node.name)
1.162 +
1.163 + def visitLambda(self, node):
1.164 + pass
1.165 +
1.166 + def visitImport(self, node):
1.167 + for name, alias in node.names:
1.168 + self.names.add(alias or name)
1.169 +
1.170 + def visitFrom(self, node):
1.171 + for name, alias in node.names:
1.172 + self.names.add(alias or name)
1.173 +
1.174 + def visitClass(self, node):
1.175 + self.names.add(node.name)
1.176 +
1.177 + def visitAssName(self, node):
1.178 + self.names.add(node.name)
1.179 +
1.180 +def is_constant_false(node):
1.181 + if isinstance(node, ast.Const):
1.182 + if not node.value:
1.183 + return 1
1.184 + return 0
1.185 +
1.186 +class CodeGenerator:
1.187 + """Defines basic code generator for Python bytecode
1.188 +
1.189 + This class is an abstract base class. Concrete subclasses must
1.190 + define an __init__() that defines self.graph and then calls the
1.191 + __init__() defined in this class.
1.192 +
1.193 + The concrete class must also define the class attributes
1.194 + NameFinder, FunctionGen, and ClassGen. These attributes can be
1.195 + defined in the initClass() method, which is a hook for
1.196 + initializing these methods after all the classes have been
1.197 + defined.
1.198 + """
1.199 +
1.200 + optimized = 0 # is namespace access optimized?
1.201 + __initialized = None
1.202 + class_name = None # provide default for instance variable
1.203 +
1.204 + def __init__(self):
1.205 + if self.__initialized is None:
1.206 + self.initClass()
1.207 + self.__class__.__initialized = 1
1.208 + self.checkClass()
1.209 + self.locals = misc.Stack()
1.210 + self.setups = misc.Stack()
1.211 + self.last_lineno = None
1.212 + self._setupGraphDelegation()
1.213 + self._div_op = "BINARY_DIVIDE"
1.214 +
1.215 + # XXX set flags based on future features
1.216 + futures = self.get_module().futures
1.217 + for feature in futures:
1.218 + if feature == "division":
1.219 + self.graph.setFlag(CO_FUTURE_DIVISION)
1.220 + self._div_op = "BINARY_TRUE_DIVIDE"
1.221 + elif feature == "absolute_import":
1.222 + self.graph.setFlag(CO_FUTURE_ABSIMPORT)
1.223 + elif feature == "with_statement":
1.224 + self.graph.setFlag(CO_FUTURE_WITH_STATEMENT)
1.225 + elif feature == "print_function":
1.226 + self.graph.setFlag(CO_FUTURE_PRINT_FUNCTION)
1.227 +
1.228 + def initClass(self):
1.229 + """This method is called once for each class"""
1.230 +
1.231 + def checkClass(self):
1.232 + """Verify that class is constructed correctly"""
1.233 + try:
1.234 + assert hasattr(self, 'graph')
1.235 + assert getattr(self, 'NameFinder')
1.236 + assert getattr(self, 'FunctionGen')
1.237 + assert getattr(self, 'ClassGen')
1.238 + except AssertionError, msg:
1.239 + intro = "Bad class construction for %s" % self.__class__.__name__
1.240 + raise AssertionError, intro
1.241 +
1.242 + def _setupGraphDelegation(self):
1.243 + self.emit = self.graph.emit
1.244 + self.newBlock = self.graph.newBlock
1.245 + self.startBlock = self.graph.startBlock
1.246 + self.nextBlock = self.graph.nextBlock
1.247 + self.setDocstring = self.graph.setDocstring
1.248 +
1.249 + def getCode(self):
1.250 + """Return a code object"""
1.251 + return self.graph.getCode()
1.252 +
1.253 + def mangle(self, name):
1.254 + if self.class_name is not None:
1.255 + return misc.mangle(name, self.class_name)
1.256 + else:
1.257 + return name
1.258 +
1.259 + def parseSymbols(self, tree):
1.260 + s = symbols.SymbolVisitor()
1.261 + walk(tree, s)
1.262 + return s.scopes
1.263 +
1.264 + def get_module(self):
1.265 + raise RuntimeError, "should be implemented by subclasses"
1.266 +
1.267 + # Next five methods handle name access
1.268 +
1.269 + def isLocalName(self, name):
1.270 + return self.locals.top().has_elt(name)
1.271 +
1.272 + def storeName(self, name):
1.273 + self._nameOp('STORE', name)
1.274 +
1.275 + def loadName(self, name):
1.276 + self._nameOp('LOAD', name)
1.277 +
1.278 + def delName(self, name):
1.279 + self._nameOp('DELETE', name)
1.280 +
1.281 + def _nameOp(self, prefix, name):
1.282 + name = self.mangle(name)
1.283 + scope = self.scope.check_name(name)
1.284 + if scope == SC_LOCAL:
1.285 + if not self.optimized:
1.286 + self.emit(prefix + '_NAME', name)
1.287 + else:
1.288 + self.emit(prefix + '_FAST', name)
1.289 + elif scope == SC_GLOBAL_EXPLICT:
1.290 + self.emit(prefix + '_GLOBAL', name)
1.291 + elif scope == SC_GLOBAL_IMPLICIT:
1.292 + if not self.optimized:
1.293 + self.emit(prefix + '_NAME', name)
1.294 + else:
1.295 + self.emit(prefix + '_GLOBAL', name)
1.296 + elif scope == SC_FREE or scope == SC_CELL:
1.297 + self.emit(prefix + '_DEREF', name)
1.298 + else:
1.299 + raise RuntimeError, "unsupported scope for var %s: %d" % \
1.300 + (name, scope)
1.301 +
1.302 + def _implicitNameOp(self, prefix, name):
1.303 + """Emit name ops for names generated implicitly by for loops
1.304 +
1.305 + The interpreter generates names that start with a period or
1.306 + dollar sign. The symbol table ignores these names because
1.307 + they aren't present in the program text.
1.308 + """
1.309 + if self.optimized:
1.310 + self.emit(prefix + '_FAST', name)
1.311 + else:
1.312 + self.emit(prefix + '_NAME', name)
1.313 +
1.314 + # The set_lineno() function and the explicit emit() calls for
1.315 + # SET_LINENO below are only used to generate the line number table.
1.316 + # As of Python 2.3, the interpreter does not have a SET_LINENO
1.317 + # instruction. pyassem treats SET_LINENO opcodes as a special case.
1.318 +
1.319 + def set_lineno(self, node, force=False):
1.320 + """Emit SET_LINENO if necessary.
1.321 +
1.322 + The instruction is considered necessary if the node has a
1.323 + lineno attribute and it is different than the last lineno
1.324 + emitted.
1.325 +
1.326 + Returns true if SET_LINENO was emitted.
1.327 +
1.328 + There are no rules for when an AST node should have a lineno
1.329 + attribute. The transformer and AST code need to be reviewed
1.330 + and a consistent policy implemented and documented. Until
1.331 + then, this method works around missing line numbers.
1.332 + """
1.333 + lineno = getattr(node, 'lineno', None)
1.334 + if lineno is not None and (lineno != self.last_lineno
1.335 + or force):
1.336 + self.emit('SET_LINENO', lineno)
1.337 + self.last_lineno = lineno
1.338 + return True
1.339 + return False
1.340 +
1.341 + # The first few visitor methods handle nodes that generator new
1.342 + # code objects. They use class attributes to determine what
1.343 + # specialized code generators to use.
1.344 +
1.345 + NameFinder = LocalNameFinder
1.346 + FunctionGen = None
1.347 + ClassGen = None
1.348 +
1.349 + def visitModule(self, node):
1.350 + self.scopes = self.parseSymbols(node)
1.351 + self.scope = self.scopes[node]
1.352 + self.emit('SET_LINENO', 0)
1.353 + if node.doc:
1.354 + self.emit('LOAD_CONST', node.doc)
1.355 + self.storeName('__doc__')
1.356 + lnf = walk(node.node, self.NameFinder(), verbose=0)
1.357 + self.locals.push(lnf.getLocals())
1.358 + self.visit(node.node)
1.359 + self.emit('LOAD_CONST', None)
1.360 + self.emit('RETURN_VALUE')
1.361 +
1.362 + def visitExpression(self, node):
1.363 + self.set_lineno(node)
1.364 + self.scopes = self.parseSymbols(node)
1.365 + self.scope = self.scopes[node]
1.366 + self.visit(node.node)
1.367 + self.emit('RETURN_VALUE')
1.368 +
1.369 + def visitFunction(self, node):
1.370 + self._visitFuncOrLambda(node, isLambda=0)
1.371 + if node.doc:
1.372 + self.setDocstring(node.doc)
1.373 + self.storeName(node.name)
1.374 +
1.375 + def visitLambda(self, node):
1.376 + self._visitFuncOrLambda(node, isLambda=1)
1.377 +
1.378 + def _visitFuncOrLambda(self, node, isLambda=0):
1.379 + if not isLambda and node.decorators:
1.380 + for decorator in node.decorators.nodes:
1.381 + self.visit(decorator)
1.382 + ndecorators = len(node.decorators.nodes)
1.383 + else:
1.384 + ndecorators = 0
1.385 +
1.386 + gen = self.FunctionGen(node, self.scopes, isLambda,
1.387 + self.class_name, self.get_module())
1.388 + walk(node.code, gen)
1.389 + gen.finish()
1.390 + self.set_lineno(node)
1.391 + for default in node.defaults:
1.392 + self.visit(default)
1.393 + self._makeClosure(gen, len(node.defaults))
1.394 + for i in range(ndecorators):
1.395 + self.emit('CALL_FUNCTION', 1)
1.396 +
1.397 + def visitClass(self, node):
1.398 + gen = self.ClassGen(node, self.scopes,
1.399 + self.get_module())
1.400 + walk(node.code, gen)
1.401 + gen.finish()
1.402 + self.set_lineno(node)
1.403 + self.emit('LOAD_CONST', node.name)
1.404 + for base in node.bases:
1.405 + self.visit(base)
1.406 + self.emit('BUILD_TUPLE', len(node.bases))
1.407 + self._makeClosure(gen, 0)
1.408 + self.emit('CALL_FUNCTION', 0)
1.409 + self.emit('BUILD_CLASS')
1.410 + self.storeName(node.name)
1.411 +
1.412 + # The rest are standard visitor methods
1.413 +
1.414 + # The next few implement control-flow statements
1.415 +
1.416 + def visitIf(self, node):
1.417 + end = self.newBlock()
1.418 + numtests = len(node.tests)
1.419 + for i in range(numtests):
1.420 + test, suite = node.tests[i]
1.421 + if is_constant_false(test):
1.422 + # XXX will need to check generator stuff here
1.423 + continue
1.424 + self.set_lineno(test)
1.425 + self.visit(test)
1.426 + nextTest = self.newBlock()
1.427 + self.emit('POP_JUMP_IF_FALSE', nextTest)
1.428 + self.nextBlock()
1.429 + self.visit(suite)
1.430 + self.emit('JUMP_FORWARD', end)
1.431 + self.startBlock(nextTest)
1.432 + if node.else_:
1.433 + self.visit(node.else_)
1.434 + self.nextBlock(end)
1.435 +
1.436 + def visitWhile(self, node):
1.437 + self.set_lineno(node)
1.438 +
1.439 + loop = self.newBlock()
1.440 + else_ = self.newBlock()
1.441 +
1.442 + after = self.newBlock()
1.443 + self.emit('SETUP_LOOP', after)
1.444 +
1.445 + self.nextBlock(loop)
1.446 + self.setups.push((LOOP, loop))
1.447 +
1.448 + self.set_lineno(node, force=True)
1.449 + self.visit(node.test)
1.450 + self.emit('POP_JUMP_IF_FALSE', else_ or after)
1.451 +
1.452 + self.nextBlock()
1.453 + self.visit(node.body)
1.454 + self.emit('JUMP_ABSOLUTE', loop)
1.455 +
1.456 + self.startBlock(else_) # or just the POPs if not else clause
1.457 + self.emit('POP_BLOCK')
1.458 + self.setups.pop()
1.459 + if node.else_:
1.460 + self.visit(node.else_)
1.461 + self.nextBlock(after)
1.462 +
1.463 + def visitFor(self, node):
1.464 + start = self.newBlock()
1.465 + anchor = self.newBlock()
1.466 + after = self.newBlock()
1.467 + self.setups.push((LOOP, start))
1.468 +
1.469 + self.set_lineno(node)
1.470 + self.emit('SETUP_LOOP', after)
1.471 + self.visit(node.list)
1.472 + self.emit('GET_ITER')
1.473 +
1.474 + self.nextBlock(start)
1.475 + self.set_lineno(node, force=1)
1.476 + self.emit('FOR_ITER', anchor)
1.477 + self.visit(node.assign)
1.478 + self.visit(node.body)
1.479 + self.emit('JUMP_ABSOLUTE', start)
1.480 + self.nextBlock(anchor)
1.481 + self.emit('POP_BLOCK')
1.482 + self.setups.pop()
1.483 + if node.else_:
1.484 + self.visit(node.else_)
1.485 + self.nextBlock(after)
1.486 +
1.487 + def visitBreak(self, node):
1.488 + if not self.setups:
1.489 + raise SyntaxError, "'break' outside loop (%s, %d)" % \
1.490 + (node.filename, node.lineno)
1.491 + self.set_lineno(node)
1.492 + self.emit('BREAK_LOOP')
1.493 +
1.494 + def visitContinue(self, node):
1.495 + if not self.setups:
1.496 + raise SyntaxError, "'continue' outside loop (%s, %d)" % \
1.497 + (node.filename, node.lineno)
1.498 + kind, block = self.setups.top()
1.499 + if kind == LOOP:
1.500 + self.set_lineno(node)
1.501 + self.emit('JUMP_ABSOLUTE', block)
1.502 + self.nextBlock()
1.503 + elif kind == EXCEPT or kind == TRY_FINALLY:
1.504 + self.set_lineno(node)
1.505 + # find the block that starts the loop
1.506 + top = len(self.setups)
1.507 + while top > 0:
1.508 + top = top - 1
1.509 + kind, loop_block = self.setups[top]
1.510 + if kind == LOOP:
1.511 + break
1.512 + if kind != LOOP:
1.513 + raise SyntaxError, "'continue' outside loop (%s, %d)" % \
1.514 + (node.filename, node.lineno)
1.515 + self.emit('CONTINUE_LOOP', loop_block)
1.516 + self.nextBlock()
1.517 + elif kind == END_FINALLY:
1.518 + msg = "'continue' not allowed inside 'finally' clause (%s, %d)"
1.519 + raise SyntaxError, msg % (node.filename, node.lineno)
1.520 +
1.521 + def visitTest(self, node, jump):
1.522 + end = self.newBlock()
1.523 + for child in node.nodes[:-1]:
1.524 + self.visit(child)
1.525 + self.emit(jump, end)
1.526 + self.nextBlock()
1.527 + self.visit(node.nodes[-1])
1.528 + self.nextBlock(end)
1.529 +
1.530 + def visitAnd(self, node):
1.531 + self.visitTest(node, 'JUMP_IF_FALSE_OR_POP')
1.532 +
1.533 + def visitOr(self, node):
1.534 + self.visitTest(node, 'JUMP_IF_TRUE_OR_POP')
1.535 +
1.536 + def visitIfExp(self, node):
1.537 + endblock = self.newBlock()
1.538 + elseblock = self.newBlock()
1.539 + self.visit(node.test)
1.540 + self.emit('POP_JUMP_IF_FALSE', elseblock)
1.541 + self.visit(node.then)
1.542 + self.emit('JUMP_FORWARD', endblock)
1.543 + self.nextBlock(elseblock)
1.544 + self.visit(node.else_)
1.545 + self.nextBlock(endblock)
1.546 +
1.547 + def visitCompare(self, node):
1.548 + self.visit(node.expr)
1.549 + cleanup = self.newBlock()
1.550 + for op, code in node.ops[:-1]:
1.551 + self.visit(code)
1.552 + self.emit('DUP_TOP')
1.553 + self.emit('ROT_THREE')
1.554 + self.emit('COMPARE_OP', op)
1.555 + self.emit('JUMP_IF_FALSE_OR_POP', cleanup)
1.556 + self.nextBlock()
1.557 + # now do the last comparison
1.558 + if node.ops:
1.559 + op, code = node.ops[-1]
1.560 + self.visit(code)
1.561 + self.emit('COMPARE_OP', op)
1.562 + if len(node.ops) > 1:
1.563 + end = self.newBlock()
1.564 + self.emit('JUMP_FORWARD', end)
1.565 + self.startBlock(cleanup)
1.566 + self.emit('ROT_TWO')
1.567 + self.emit('POP_TOP')
1.568 + self.nextBlock(end)
1.569 +
1.570 + # list comprehensions
1.571 + def visitListComp(self, node):
1.572 + self.set_lineno(node)
1.573 + # setup list
1.574 + self.emit('BUILD_LIST', 0)
1.575 +
1.576 + stack = []
1.577 + for i, for_ in zip(range(len(node.quals)), node.quals):
1.578 + start, anchor = self.visit(for_)
1.579 + cont = None
1.580 + for if_ in for_.ifs:
1.581 + if cont is None:
1.582 + cont = self.newBlock()
1.583 + self.visit(if_, cont)
1.584 + stack.insert(0, (start, cont, anchor))
1.585 +
1.586 + self.visit(node.expr)
1.587 + self.emit('LIST_APPEND', len(node.quals) + 1)
1.588 +
1.589 + for start, cont, anchor in stack:
1.590 + if cont:
1.591 + self.nextBlock(cont)
1.592 + self.emit('JUMP_ABSOLUTE', start)
1.593 + self.startBlock(anchor)
1.594 +
1.595 + def visitSetComp(self, node):
1.596 + self.set_lineno(node)
1.597 + # setup list
1.598 + self.emit('BUILD_SET', 0)
1.599 +
1.600 + stack = []
1.601 + for i, for_ in zip(range(len(node.quals)), node.quals):
1.602 + start, anchor = self.visit(for_)
1.603 + cont = None
1.604 + for if_ in for_.ifs:
1.605 + if cont is None:
1.606 + cont = self.newBlock()
1.607 + self.visit(if_, cont)
1.608 + stack.insert(0, (start, cont, anchor))
1.609 +
1.610 + self.visit(node.expr)
1.611 + self.emit('SET_ADD', len(node.quals) + 1)
1.612 +
1.613 + for start, cont, anchor in stack:
1.614 + if cont:
1.615 + self.nextBlock(cont)
1.616 + self.emit('JUMP_ABSOLUTE', start)
1.617 + self.startBlock(anchor)
1.618 +
1.619 + def visitDictComp(self, node):
1.620 + self.set_lineno(node)
1.621 + # setup list
1.622 + self.emit('BUILD_MAP', 0)
1.623 +
1.624 + stack = []
1.625 + for i, for_ in zip(range(len(node.quals)), node.quals):
1.626 + start, anchor = self.visit(for_)
1.627 + cont = None
1.628 + for if_ in for_.ifs:
1.629 + if cont is None:
1.630 + cont = self.newBlock()
1.631 + self.visit(if_, cont)
1.632 + stack.insert(0, (start, cont, anchor))
1.633 +
1.634 + self.visit(node.value)
1.635 + self.visit(node.key)
1.636 + self.emit('MAP_ADD', len(node.quals) + 1)
1.637 +
1.638 + for start, cont, anchor in stack:
1.639 + if cont:
1.640 + self.nextBlock(cont)
1.641 + self.emit('JUMP_ABSOLUTE', start)
1.642 + self.startBlock(anchor)
1.643 +
1.644 + def visitListCompFor(self, node):
1.645 + start = self.newBlock()
1.646 + anchor = self.newBlock()
1.647 +
1.648 + self.visit(node.list)
1.649 + self.emit('GET_ITER')
1.650 + self.nextBlock(start)
1.651 + self.set_lineno(node, force=True)
1.652 + self.emit('FOR_ITER', anchor)
1.653 + self.nextBlock()
1.654 + self.visit(node.assign)
1.655 + return start, anchor
1.656 +
1.657 + def visitListCompIf(self, node, branch):
1.658 + self.set_lineno(node, force=True)
1.659 + self.visit(node.test)
1.660 + self.emit('POP_JUMP_IF_FALSE', branch)
1.661 + self.newBlock()
1.662 +
1.663 + def _makeClosure(self, gen, args):
1.664 + frees = gen.scope.get_free_vars()
1.665 + if frees:
1.666 + for name in frees:
1.667 + self.emit('LOAD_CLOSURE', name)
1.668 + self.emit('BUILD_TUPLE', len(frees))
1.669 + self.emit('LOAD_CONST', gen)
1.670 + self.emit('MAKE_CLOSURE', args)
1.671 + else:
1.672 + self.emit('LOAD_CONST', gen)
1.673 + self.emit('MAKE_FUNCTION', args)
1.674 +
1.675 + def visitGenExpr(self, node):
1.676 + gen = GenExprCodeGenerator(node, self.scopes, self.class_name,
1.677 + self.get_module())
1.678 + walk(node.code, gen)
1.679 + gen.finish()
1.680 + self.set_lineno(node)
1.681 + self._makeClosure(gen, 0)
1.682 + # precomputation of outmost iterable
1.683 + self.visit(node.code.quals[0].iter)
1.684 + self.emit('GET_ITER')
1.685 + self.emit('CALL_FUNCTION', 1)
1.686 +
1.687 + def visitGenExprInner(self, node):
1.688 + self.set_lineno(node)
1.689 + # setup list
1.690 +
1.691 + stack = []
1.692 + for i, for_ in zip(range(len(node.quals)), node.quals):
1.693 + start, anchor, end = self.visit(for_)
1.694 + cont = None
1.695 + for if_ in for_.ifs:
1.696 + if cont is None:
1.697 + cont = self.newBlock()
1.698 + self.visit(if_, cont)
1.699 + stack.insert(0, (start, cont, anchor, end))
1.700 +
1.701 + self.visit(node.expr)
1.702 + self.emit('YIELD_VALUE')
1.703 + self.emit('POP_TOP')
1.704 +
1.705 + for start, cont, anchor, end in stack:
1.706 + if cont:
1.707 + self.nextBlock(cont)
1.708 + self.emit('JUMP_ABSOLUTE', start)
1.709 + self.startBlock(anchor)
1.710 + self.emit('POP_BLOCK')
1.711 + self.setups.pop()
1.712 + self.nextBlock(end)
1.713 +
1.714 + self.emit('LOAD_CONST', None)
1.715 +
1.716 + def visitGenExprFor(self, node):
1.717 + start = self.newBlock()
1.718 + anchor = self.newBlock()
1.719 + end = self.newBlock()
1.720 +
1.721 + self.setups.push((LOOP, start))
1.722 + self.emit('SETUP_LOOP', end)
1.723 +
1.724 + if node.is_outmost:
1.725 + self.loadName('.0')
1.726 + else:
1.727 + self.visit(node.iter)
1.728 + self.emit('GET_ITER')
1.729 +
1.730 + self.nextBlock(start)
1.731 + self.set_lineno(node, force=True)
1.732 + self.emit('FOR_ITER', anchor)
1.733 + self.nextBlock()
1.734 + self.visit(node.assign)
1.735 + return start, anchor, end
1.736 +
1.737 + def visitGenExprIf(self, node, branch):
1.738 + self.set_lineno(node, force=True)
1.739 + self.visit(node.test)
1.740 + self.emit('POP_JUMP_IF_FALSE', branch)
1.741 + self.newBlock()
1.742 +
1.743 + # exception related
1.744 +
1.745 + def visitAssert(self, node):
1.746 + # XXX would be interesting to implement this via a
1.747 + # transformation of the AST before this stage
1.748 + if __debug__:
1.749 + end = self.newBlock()
1.750 + self.set_lineno(node)
1.751 + # XXX AssertionError appears to be special case -- it is always
1.752 + # loaded as a global even if there is a local name. I guess this
1.753 + # is a sort of renaming op.
1.754 + self.nextBlock()
1.755 + self.visit(node.test)
1.756 + self.emit('POP_JUMP_IF_TRUE', end)
1.757 + self.nextBlock()
1.758 + self.emit('LOAD_GLOBAL', 'AssertionError')
1.759 + if node.fail:
1.760 + self.visit(node.fail)
1.761 + self.emit('RAISE_VARARGS', 2)
1.762 + else:
1.763 + self.emit('RAISE_VARARGS', 1)
1.764 + self.nextBlock(end)
1.765 +
1.766 + def visitRaise(self, node):
1.767 + self.set_lineno(node)
1.768 + n = 0
1.769 + if node.expr1:
1.770 + self.visit(node.expr1)
1.771 + n = n + 1
1.772 + if node.expr2:
1.773 + self.visit(node.expr2)
1.774 + n = n + 1
1.775 + if node.expr3:
1.776 + self.visit(node.expr3)
1.777 + n = n + 1
1.778 + self.emit('RAISE_VARARGS', n)
1.779 +
1.780 + def visitTryExcept(self, node):
1.781 + body = self.newBlock()
1.782 + handlers = self.newBlock()
1.783 + end = self.newBlock()
1.784 + if node.else_:
1.785 + lElse = self.newBlock()
1.786 + else:
1.787 + lElse = end
1.788 + self.set_lineno(node)
1.789 + self.emit('SETUP_EXCEPT', handlers)
1.790 + self.nextBlock(body)
1.791 + self.setups.push((EXCEPT, body))
1.792 + self.visit(node.body)
1.793 + self.emit('POP_BLOCK')
1.794 + self.setups.pop()
1.795 + self.emit('JUMP_FORWARD', lElse)
1.796 + self.startBlock(handlers)
1.797 +
1.798 + last = len(node.handlers) - 1
1.799 + for i in range(len(node.handlers)):
1.800 + expr, target, body = node.handlers[i]
1.801 + self.set_lineno(expr)
1.802 + if expr:
1.803 + self.emit('DUP_TOP')
1.804 + self.visit(expr)
1.805 + self.emit('COMPARE_OP', 'exception match')
1.806 + next = self.newBlock()
1.807 + self.emit('POP_JUMP_IF_FALSE', next)
1.808 + self.nextBlock()
1.809 + self.emit('POP_TOP')
1.810 + if target:
1.811 + self.visit(target)
1.812 + else:
1.813 + self.emit('POP_TOP')
1.814 + self.emit('POP_TOP')
1.815 + self.visit(body)
1.816 + self.emit('JUMP_FORWARD', end)
1.817 + if expr:
1.818 + self.nextBlock(next)
1.819 + else:
1.820 + self.nextBlock()
1.821 + self.emit('END_FINALLY')
1.822 + if node.else_:
1.823 + self.nextBlock(lElse)
1.824 + self.visit(node.else_)
1.825 + self.nextBlock(end)
1.826 +
1.827 + def visitTryFinally(self, node):
1.828 + body = self.newBlock()
1.829 + final = self.newBlock()
1.830 + self.set_lineno(node)
1.831 + self.emit('SETUP_FINALLY', final)
1.832 + self.nextBlock(body)
1.833 + self.setups.push((TRY_FINALLY, body))
1.834 + self.visit(node.body)
1.835 + self.emit('POP_BLOCK')
1.836 + self.setups.pop()
1.837 + self.emit('LOAD_CONST', None)
1.838 + self.nextBlock(final)
1.839 + self.setups.push((END_FINALLY, final))
1.840 + self.visit(node.final)
1.841 + self.emit('END_FINALLY')
1.842 + self.setups.pop()
1.843 +
1.844 + __with_count = 0
1.845 +
1.846 + def visitWith(self, node):
1.847 + body = self.newBlock()
1.848 + final = self.newBlock()
1.849 + self.__with_count += 1
1.850 + valuevar = "_[%d]" % self.__with_count
1.851 + self.set_lineno(node)
1.852 + self.visit(node.expr)
1.853 + self.emit('DUP_TOP')
1.854 + self.emit('LOAD_ATTR', '__exit__')
1.855 + self.emit('ROT_TWO')
1.856 + self.emit('LOAD_ATTR', '__enter__')
1.857 + self.emit('CALL_FUNCTION', 0)
1.858 + if node.vars is None:
1.859 + self.emit('POP_TOP')
1.860 + else:
1.861 + self._implicitNameOp('STORE', valuevar)
1.862 + self.emit('SETUP_FINALLY', final)
1.863 + self.nextBlock(body)
1.864 + self.setups.push((TRY_FINALLY, body))
1.865 + if node.vars is not None:
1.866 + self._implicitNameOp('LOAD', valuevar)
1.867 + self._implicitNameOp('DELETE', valuevar)
1.868 + self.visit(node.vars)
1.869 + self.visit(node.body)
1.870 + self.emit('POP_BLOCK')
1.871 + self.setups.pop()
1.872 + self.emit('LOAD_CONST', None)
1.873 + self.nextBlock(final)
1.874 + self.setups.push((END_FINALLY, final))
1.875 + self.emit('WITH_CLEANUP')
1.876 + self.emit('END_FINALLY')
1.877 + self.setups.pop()
1.878 + self.__with_count -= 1
1.879 +
1.880 + # misc
1.881 +
1.882 + def visitDiscard(self, node):
1.883 + self.set_lineno(node)
1.884 + self.visit(node.expr)
1.885 + self.emit('POP_TOP')
1.886 +
1.887 + def visitConst(self, node):
1.888 + self.emit('LOAD_CONST', node.value)
1.889 +
1.890 + def visitKeyword(self, node):
1.891 + self.emit('LOAD_CONST', node.name)
1.892 + self.visit(node.expr)
1.893 +
1.894 + def visitGlobal(self, node):
1.895 + # no code to generate
1.896 + pass
1.897 +
1.898 + def visitName(self, node):
1.899 + self.set_lineno(node)
1.900 + self.loadName(node.name)
1.901 +
1.902 + def visitPass(self, node):
1.903 + self.set_lineno(node)
1.904 +
1.905 + def visitImport(self, node):
1.906 + self.set_lineno(node)
1.907 + level = 0 if self.graph.checkFlag(CO_FUTURE_ABSIMPORT) else -1
1.908 + for name, alias in node.names:
1.909 + if VERSION > 1:
1.910 + self.emit('LOAD_CONST', level)
1.911 + self.emit('LOAD_CONST', None)
1.912 + self.emit('IMPORT_NAME', name)
1.913 + mod = name.split(".")[0]
1.914 + if alias:
1.915 + self._resolveDots(name)
1.916 + self.storeName(alias)
1.917 + else:
1.918 + self.storeName(mod)
1.919 +
1.920 + def visitFrom(self, node):
1.921 + self.set_lineno(node)
1.922 + level = node.level
1.923 + if level == 0 and not self.graph.checkFlag(CO_FUTURE_ABSIMPORT):
1.924 + level = -1
1.925 + fromlist = tuple(name for (name, alias) in node.names)
1.926 + if VERSION > 1:
1.927 + self.emit('LOAD_CONST', level)
1.928 + self.emit('LOAD_CONST', fromlist)
1.929 + self.emit('IMPORT_NAME', node.modname)
1.930 + for name, alias in node.names:
1.931 + if VERSION > 1:
1.932 + if name == '*':
1.933 + self.namespace = 0
1.934 + self.emit('IMPORT_STAR')
1.935 + # There can only be one name w/ from ... import *
1.936 + assert len(node.names) == 1
1.937 + return
1.938 + else:
1.939 + self.emit('IMPORT_FROM', name)
1.940 + self._resolveDots(name)
1.941 + self.storeName(alias or name)
1.942 + else:
1.943 + self.emit('IMPORT_FROM', name)
1.944 + self.emit('POP_TOP')
1.945 +
1.946 + def _resolveDots(self, name):
1.947 + elts = name.split(".")
1.948 + if len(elts) == 1:
1.949 + return
1.950 + for elt in elts[1:]:
1.951 + self.emit('LOAD_ATTR', elt)
1.952 +
1.953 + def visitGetattr(self, node):
1.954 + self.visit(node.expr)
1.955 + self.emit('LOAD_ATTR', self.mangle(node.attrname))
1.956 +
1.957 + # next five implement assignments
1.958 +
1.959 + def visitAssign(self, node):
1.960 + self.set_lineno(node)
1.961 + self.visit(node.expr)
1.962 + dups = len(node.nodes) - 1
1.963 + for i in range(len(node.nodes)):
1.964 + elt = node.nodes[i]
1.965 + if i < dups:
1.966 + self.emit('DUP_TOP')
1.967 + if isinstance(elt, ast.Node):
1.968 + self.visit(elt)
1.969 +
1.970 + def visitAssName(self, node):
1.971 + if node.flags == 'OP_ASSIGN':
1.972 + self.storeName(node.name)
1.973 + elif node.flags == 'OP_DELETE':
1.974 + self.set_lineno(node)
1.975 + self.delName(node.name)
1.976 + else:
1.977 + print "oops", node.flags
1.978 +
1.979 + def visitAssAttr(self, node):
1.980 + self.visit(node.expr)
1.981 + if node.flags == 'OP_ASSIGN':
1.982 + self.emit('STORE_ATTR', self.mangle(node.attrname))
1.983 + elif node.flags == 'OP_DELETE':
1.984 + self.emit('DELETE_ATTR', self.mangle(node.attrname))
1.985 + else:
1.986 + print "warning: unexpected flags:", node.flags
1.987 + print node
1.988 +
1.989 + def _visitAssSequence(self, node, op='UNPACK_SEQUENCE'):
1.990 + if findOp(node) != 'OP_DELETE':
1.991 + self.emit(op, len(node.nodes))
1.992 + for child in node.nodes:
1.993 + self.visit(child)
1.994 +
1.995 + if VERSION > 1:
1.996 + visitAssTuple = _visitAssSequence
1.997 + visitAssList = _visitAssSequence
1.998 + else:
1.999 + def visitAssTuple(self, node):
1.1000 + self._visitAssSequence(node, 'UNPACK_TUPLE')
1.1001 +
1.1002 + def visitAssList(self, node):
1.1003 + self._visitAssSequence(node, 'UNPACK_LIST')
1.1004 +
1.1005 + # augmented assignment
1.1006 +
1.1007 + def visitAugAssign(self, node):
1.1008 + self.set_lineno(node)
1.1009 + aug_node = wrap_aug(node.node)
1.1010 + self.visit(aug_node, "load")
1.1011 + self.visit(node.expr)
1.1012 + self.emit(self._augmented_opcode[node.op])
1.1013 + self.visit(aug_node, "store")
1.1014 +
1.1015 + _augmented_opcode = {
1.1016 + '+=' : 'INPLACE_ADD',
1.1017 + '-=' : 'INPLACE_SUBTRACT',
1.1018 + '*=' : 'INPLACE_MULTIPLY',
1.1019 + '/=' : 'INPLACE_DIVIDE',
1.1020 + '//=': 'INPLACE_FLOOR_DIVIDE',
1.1021 + '%=' : 'INPLACE_MODULO',
1.1022 + '**=': 'INPLACE_POWER',
1.1023 + '>>=': 'INPLACE_RSHIFT',
1.1024 + '<<=': 'INPLACE_LSHIFT',
1.1025 + '&=' : 'INPLACE_AND',
1.1026 + '^=' : 'INPLACE_XOR',
1.1027 + '|=' : 'INPLACE_OR',
1.1028 + }
1.1029 +
1.1030 + def visitAugName(self, node, mode):
1.1031 + if mode == "load":
1.1032 + self.loadName(node.name)
1.1033 + elif mode == "store":
1.1034 + self.storeName(node.name)
1.1035 +
1.1036 + def visitAugGetattr(self, node, mode):
1.1037 + if mode == "load":
1.1038 + self.visit(node.expr)
1.1039 + self.emit('DUP_TOP')
1.1040 + self.emit('LOAD_ATTR', self.mangle(node.attrname))
1.1041 + elif mode == "store":
1.1042 + self.emit('ROT_TWO')
1.1043 + self.emit('STORE_ATTR', self.mangle(node.attrname))
1.1044 +
1.1045 + def visitAugSlice(self, node, mode):
1.1046 + if mode == "load":
1.1047 + self.visitSlice(node, 1)
1.1048 + elif mode == "store":
1.1049 + slice = 0
1.1050 + if node.lower:
1.1051 + slice = slice | 1
1.1052 + if node.upper:
1.1053 + slice = slice | 2
1.1054 + if slice == 0:
1.1055 + self.emit('ROT_TWO')
1.1056 + elif slice == 3:
1.1057 + self.emit('ROT_FOUR')
1.1058 + else:
1.1059 + self.emit('ROT_THREE')
1.1060 + self.emit('STORE_SLICE+%d' % slice)
1.1061 +
1.1062 + def visitAugSubscript(self, node, mode):
1.1063 + if mode == "load":
1.1064 + self.visitSubscript(node, 1)
1.1065 + elif mode == "store":
1.1066 + self.emit('ROT_THREE')
1.1067 + self.emit('STORE_SUBSCR')
1.1068 +
1.1069 + def visitExec(self, node):
1.1070 + self.visit(node.expr)
1.1071 + if node.locals is None:
1.1072 + self.emit('LOAD_CONST', None)
1.1073 + else:
1.1074 + self.visit(node.locals)
1.1075 + if node.globals is None:
1.1076 + self.emit('DUP_TOP')
1.1077 + else:
1.1078 + self.visit(node.globals)
1.1079 + self.emit('EXEC_STMT')
1.1080 +
1.1081 + def visitCallFunc(self, node):
1.1082 + pos = 0
1.1083 + kw = 0
1.1084 + self.set_lineno(node)
1.1085 + self.visit(node.node)
1.1086 + for arg in node.args:
1.1087 + self.visit(arg)
1.1088 + if isinstance(arg, ast.Keyword):
1.1089 + kw = kw + 1
1.1090 + else:
1.1091 + pos = pos + 1
1.1092 + if node.star_args is not None:
1.1093 + self.visit(node.star_args)
1.1094 + if node.dstar_args is not None:
1.1095 + self.visit(node.dstar_args)
1.1096 + have_star = node.star_args is not None
1.1097 + have_dstar = node.dstar_args is not None
1.1098 + opcode = callfunc_opcode_info[have_star, have_dstar]
1.1099 + self.emit(opcode, kw << 8 | pos)
1.1100 +
1.1101 + def visitPrint(self, node, newline=0):
1.1102 + self.set_lineno(node)
1.1103 + if node.dest:
1.1104 + self.visit(node.dest)
1.1105 + for child in node.nodes:
1.1106 + if node.dest:
1.1107 + self.emit('DUP_TOP')
1.1108 + self.visit(child)
1.1109 + if node.dest:
1.1110 + self.emit('ROT_TWO')
1.1111 + self.emit('PRINT_ITEM_TO')
1.1112 + else:
1.1113 + self.emit('PRINT_ITEM')
1.1114 + if node.dest and not newline:
1.1115 + self.emit('POP_TOP')
1.1116 +
1.1117 + def visitPrintnl(self, node):
1.1118 + self.visitPrint(node, newline=1)
1.1119 + if node.dest:
1.1120 + self.emit('PRINT_NEWLINE_TO')
1.1121 + else:
1.1122 + self.emit('PRINT_NEWLINE')
1.1123 +
1.1124 + def visitReturn(self, node):
1.1125 + self.set_lineno(node)
1.1126 + self.visit(node.value)
1.1127 + self.emit('RETURN_VALUE')
1.1128 +
1.1129 + def visitYield(self, node):
1.1130 + self.set_lineno(node)
1.1131 + self.visit(node.value)
1.1132 + self.emit('YIELD_VALUE')
1.1133 +
1.1134 + # slice and subscript stuff
1.1135 +
1.1136 + def visitSlice(self, node, aug_flag=None):
1.1137 + # aug_flag is used by visitAugSlice
1.1138 + self.visit(node.expr)
1.1139 + slice = 0
1.1140 + if node.lower:
1.1141 + self.visit(node.lower)
1.1142 + slice = slice | 1
1.1143 + if node.upper:
1.1144 + self.visit(node.upper)
1.1145 + slice = slice | 2
1.1146 + if aug_flag:
1.1147 + if slice == 0:
1.1148 + self.emit('DUP_TOP')
1.1149 + elif slice == 3:
1.1150 + self.emit('DUP_TOPX', 3)
1.1151 + else:
1.1152 + self.emit('DUP_TOPX', 2)
1.1153 + if node.flags == 'OP_APPLY':
1.1154 + self.emit('SLICE+%d' % slice)
1.1155 + elif node.flags == 'OP_ASSIGN':
1.1156 + self.emit('STORE_SLICE+%d' % slice)
1.1157 + elif node.flags == 'OP_DELETE':
1.1158 + self.emit('DELETE_SLICE+%d' % slice)
1.1159 + else:
1.1160 + print "weird slice", node.flags
1.1161 + raise
1.1162 +
1.1163 + def visitSubscript(self, node, aug_flag=None):
1.1164 + self.visit(node.expr)
1.1165 + for sub in node.subs:
1.1166 + self.visit(sub)
1.1167 + if len(node.subs) > 1:
1.1168 + self.emit('BUILD_TUPLE', len(node.subs))
1.1169 + if aug_flag:
1.1170 + self.emit('DUP_TOPX', 2)
1.1171 + if node.flags == 'OP_APPLY':
1.1172 + self.emit('BINARY_SUBSCR')
1.1173 + elif node.flags == 'OP_ASSIGN':
1.1174 + self.emit('STORE_SUBSCR')
1.1175 + elif node.flags == 'OP_DELETE':
1.1176 + self.emit('DELETE_SUBSCR')
1.1177 +
1.1178 + # binary ops
1.1179 +
1.1180 + def binaryOp(self, node, op):
1.1181 + self.visit(node.left)
1.1182 + self.visit(node.right)
1.1183 + self.emit(op)
1.1184 +
1.1185 + def visitAdd(self, node):
1.1186 + return self.binaryOp(node, 'BINARY_ADD')
1.1187 +
1.1188 + def visitSub(self, node):
1.1189 + return self.binaryOp(node, 'BINARY_SUBTRACT')
1.1190 +
1.1191 + def visitMul(self, node):
1.1192 + return self.binaryOp(node, 'BINARY_MULTIPLY')
1.1193 +
1.1194 + def visitDiv(self, node):
1.1195 + return self.binaryOp(node, self._div_op)
1.1196 +
1.1197 + def visitFloorDiv(self, node):
1.1198 + return self.binaryOp(node, 'BINARY_FLOOR_DIVIDE')
1.1199 +
1.1200 + def visitMod(self, node):
1.1201 + return self.binaryOp(node, 'BINARY_MODULO')
1.1202 +
1.1203 + def visitPower(self, node):
1.1204 + return self.binaryOp(node, 'BINARY_POWER')
1.1205 +
1.1206 + def visitLeftShift(self, node):
1.1207 + return self.binaryOp(node, 'BINARY_LSHIFT')
1.1208 +
1.1209 + def visitRightShift(self, node):
1.1210 + return self.binaryOp(node, 'BINARY_RSHIFT')
1.1211 +
1.1212 + # unary ops
1.1213 +
1.1214 + def unaryOp(self, node, op):
1.1215 + self.visit(node.expr)
1.1216 + self.emit(op)
1.1217 +
1.1218 + def visitInvert(self, node):
1.1219 + return self.unaryOp(node, 'UNARY_INVERT')
1.1220 +
1.1221 + def visitUnarySub(self, node):
1.1222 + return self.unaryOp(node, 'UNARY_NEGATIVE')
1.1223 +
1.1224 + def visitUnaryAdd(self, node):
1.1225 + return self.unaryOp(node, 'UNARY_POSITIVE')
1.1226 +
1.1227 + def visitUnaryInvert(self, node):
1.1228 + return self.unaryOp(node, 'UNARY_INVERT')
1.1229 +
1.1230 + def visitNot(self, node):
1.1231 + return self.unaryOp(node, 'UNARY_NOT')
1.1232 +
1.1233 + def visitBackquote(self, node):
1.1234 + return self.unaryOp(node, 'UNARY_CONVERT')
1.1235 +
1.1236 + # bit ops
1.1237 +
1.1238 + def bitOp(self, nodes, op):
1.1239 + self.visit(nodes[0])
1.1240 + for node in nodes[1:]:
1.1241 + self.visit(node)
1.1242 + self.emit(op)
1.1243 +
1.1244 + def visitBitand(self, node):
1.1245 + return self.bitOp(node.nodes, 'BINARY_AND')
1.1246 +
1.1247 + def visitBitor(self, node):
1.1248 + return self.bitOp(node.nodes, 'BINARY_OR')
1.1249 +
1.1250 + def visitBitxor(self, node):
1.1251 + return self.bitOp(node.nodes, 'BINARY_XOR')
1.1252 +
1.1253 + # object constructors
1.1254 +
1.1255 + def visitEllipsis(self, node):
1.1256 + self.emit('LOAD_CONST', Ellipsis)
1.1257 +
1.1258 + def visitTuple(self, node):
1.1259 + self.set_lineno(node)
1.1260 + for elt in node.nodes:
1.1261 + self.visit(elt)
1.1262 + self.emit('BUILD_TUPLE', len(node.nodes))
1.1263 +
1.1264 + def visitList(self, node):
1.1265 + self.set_lineno(node)
1.1266 + for elt in node.nodes:
1.1267 + self.visit(elt)
1.1268 + self.emit('BUILD_LIST', len(node.nodes))
1.1269 +
1.1270 + def visitSet(self, node):
1.1271 + self.set_lineno(node)
1.1272 + for elt in node.nodes:
1.1273 + self.visit(elt)
1.1274 + self.emit('BUILD_SET', len(node.nodes))
1.1275 +
1.1276 + def visitSliceobj(self, node):
1.1277 + for child in node.nodes:
1.1278 + self.visit(child)
1.1279 + self.emit('BUILD_SLICE', len(node.nodes))
1.1280 +
1.1281 + def visitDict(self, node):
1.1282 + self.set_lineno(node)
1.1283 + self.emit('BUILD_MAP', 0)
1.1284 + for k, v in node.items:
1.1285 + self.emit('DUP_TOP')
1.1286 + self.visit(k)
1.1287 + self.visit(v)
1.1288 + self.emit('ROT_THREE')
1.1289 + self.emit('STORE_SUBSCR')
1.1290 +
1.1291 +class NestedScopeMixin:
1.1292 + """Defines initClass() for nested scoping (Python 2.2-compatible)"""
1.1293 + def initClass(self):
1.1294 + self.__class__.NameFinder = LocalNameFinder
1.1295 + self.__class__.FunctionGen = FunctionCodeGenerator
1.1296 + self.__class__.ClassGen = ClassCodeGenerator
1.1297 +
1.1298 +class ModuleCodeGenerator(NestedScopeMixin, CodeGenerator):
1.1299 + __super_init = CodeGenerator.__init__
1.1300 +
1.1301 + scopes = None
1.1302 +
1.1303 + def __init__(self, tree):
1.1304 + self.graph = pyassem.PyFlowGraph("<module>", tree.filename)
1.1305 + self.futures = future.find_futures(tree)
1.1306 + self.__super_init()
1.1307 + walk(tree, self)
1.1308 +
1.1309 + def get_module(self):
1.1310 + return self
1.1311 +
1.1312 +class ExpressionCodeGenerator(NestedScopeMixin, CodeGenerator):
1.1313 + __super_init = CodeGenerator.__init__
1.1314 +
1.1315 + scopes = None
1.1316 + futures = ()
1.1317 +
1.1318 + def __init__(self, tree):
1.1319 + self.graph = pyassem.PyFlowGraph("<expression>", tree.filename)
1.1320 + self.__super_init()
1.1321 + walk(tree, self)
1.1322 +
1.1323 + def get_module(self):
1.1324 + return self
1.1325 +
1.1326 +class InteractiveCodeGenerator(NestedScopeMixin, CodeGenerator):
1.1327 +
1.1328 + __super_init = CodeGenerator.__init__
1.1329 +
1.1330 + scopes = None
1.1331 + futures = ()
1.1332 +
1.1333 + def __init__(self, tree):
1.1334 + self.graph = pyassem.PyFlowGraph("<interactive>", tree.filename)
1.1335 + self.__super_init()
1.1336 + self.set_lineno(tree)
1.1337 + walk(tree, self)
1.1338 + self.emit('RETURN_VALUE')
1.1339 +
1.1340 + def get_module(self):
1.1341 + return self
1.1342 +
1.1343 + def visitDiscard(self, node):
1.1344 + # XXX Discard means it's an expression. Perhaps this is a bad
1.1345 + # name.
1.1346 + self.visit(node.expr)
1.1347 + self.emit('PRINT_EXPR')
1.1348 +
1.1349 +class AbstractFunctionCode:
1.1350 + optimized = 1
1.1351 + lambdaCount = 0
1.1352 +
1.1353 + def __init__(self, func, scopes, isLambda, class_name, mod):
1.1354 + self.class_name = class_name
1.1355 + self.module = mod
1.1356 + if isLambda:
1.1357 + klass = FunctionCodeGenerator
1.1358 + name = "<lambda.%d>" % klass.lambdaCount
1.1359 + klass.lambdaCount = klass.lambdaCount + 1
1.1360 + else:
1.1361 + name = func.name
1.1362 +
1.1363 + args, hasTupleArg = generateArgList(func.argnames)
1.1364 + self.graph = pyassem.PyFlowGraph(name, func.filename, args,
1.1365 + optimized=1)
1.1366 + self.isLambda = isLambda
1.1367 + self.super_init()
1.1368 +
1.1369 + if not isLambda and func.doc:
1.1370 + self.setDocstring(func.doc)
1.1371 +
1.1372 + lnf = walk(func.code, self.NameFinder(args), verbose=0)
1.1373 + self.locals.push(lnf.getLocals())
1.1374 + if func.varargs:
1.1375 + self.graph.setFlag(CO_VARARGS)
1.1376 + if func.kwargs:
1.1377 + self.graph.setFlag(CO_VARKEYWORDS)
1.1378 + self.set_lineno(func)
1.1379 + if hasTupleArg:
1.1380 + self.generateArgUnpack(func.argnames)
1.1381 +
1.1382 + def get_module(self):
1.1383 + return self.module
1.1384 +
1.1385 + def finish(self):
1.1386 + self.graph.startExitBlock()
1.1387 + if not self.isLambda:
1.1388 + self.emit('LOAD_CONST', None)
1.1389 + self.emit('RETURN_VALUE')
1.1390 +
1.1391 + def generateArgUnpack(self, args):
1.1392 + for i in range(len(args)):
1.1393 + arg = args[i]
1.1394 + if isinstance(arg, tuple):
1.1395 + self.emit('LOAD_FAST', '.%d' % (i * 2))
1.1396 + self.unpackSequence(arg)
1.1397 +
1.1398 + def unpackSequence(self, tup):
1.1399 + if VERSION > 1:
1.1400 + self.emit('UNPACK_SEQUENCE', len(tup))
1.1401 + else:
1.1402 + self.emit('UNPACK_TUPLE', len(tup))
1.1403 + for elt in tup:
1.1404 + if isinstance(elt, tuple):
1.1405 + self.unpackSequence(elt)
1.1406 + else:
1.1407 + self._nameOp('STORE', elt)
1.1408 +
1.1409 + unpackTuple = unpackSequence
1.1410 +
1.1411 +class FunctionCodeGenerator(NestedScopeMixin, AbstractFunctionCode,
1.1412 + CodeGenerator):
1.1413 + super_init = CodeGenerator.__init__ # call be other init
1.1414 + scopes = None
1.1415 +
1.1416 + __super_init = AbstractFunctionCode.__init__
1.1417 +
1.1418 + def __init__(self, func, scopes, isLambda, class_name, mod):
1.1419 + self.scopes = scopes
1.1420 + self.scope = scopes[func]
1.1421 + self.__super_init(func, scopes, isLambda, class_name, mod)
1.1422 + self.graph.setFreeVars(self.scope.get_free_vars())
1.1423 + self.graph.setCellVars(self.scope.get_cell_vars())
1.1424 + if self.scope.generator is not None:
1.1425 + self.graph.setFlag(CO_GENERATOR)
1.1426 +
1.1427 +class GenExprCodeGenerator(NestedScopeMixin, AbstractFunctionCode,
1.1428 + CodeGenerator):
1.1429 + super_init = CodeGenerator.__init__ # call be other init
1.1430 + scopes = None
1.1431 +
1.1432 + __super_init = AbstractFunctionCode.__init__
1.1433 +
1.1434 + def __init__(self, gexp, scopes, class_name, mod):
1.1435 + self.scopes = scopes
1.1436 + self.scope = scopes[gexp]
1.1437 + self.__super_init(gexp, scopes, 1, class_name, mod)
1.1438 + self.graph.setFreeVars(self.scope.get_free_vars())
1.1439 + self.graph.setCellVars(self.scope.get_cell_vars())
1.1440 + self.graph.setFlag(CO_GENERATOR)
1.1441 +
1.1442 +class AbstractClassCode:
1.1443 +
1.1444 + def __init__(self, klass, scopes, module):
1.1445 + self.class_name = klass.name
1.1446 + self.module = module
1.1447 + self.graph = pyassem.PyFlowGraph(klass.name, klass.filename,
1.1448 + optimized=0, klass=1)
1.1449 + self.super_init()
1.1450 + lnf = walk(klass.code, self.NameFinder(), verbose=0)
1.1451 + self.locals.push(lnf.getLocals())
1.1452 + self.graph.setFlag(CO_NEWLOCALS)
1.1453 + if klass.doc:
1.1454 + self.setDocstring(klass.doc)
1.1455 +
1.1456 + def get_module(self):
1.1457 + return self.module
1.1458 +
1.1459 + def finish(self):
1.1460 + self.graph.startExitBlock()
1.1461 + self.emit('LOAD_LOCALS')
1.1462 + self.emit('RETURN_VALUE')
1.1463 +
1.1464 +class ClassCodeGenerator(NestedScopeMixin, AbstractClassCode, CodeGenerator):
1.1465 + super_init = CodeGenerator.__init__
1.1466 + scopes = None
1.1467 +
1.1468 + __super_init = AbstractClassCode.__init__
1.1469 +
1.1470 + def __init__(self, klass, scopes, module):
1.1471 + self.scopes = scopes
1.1472 + self.scope = scopes[klass]
1.1473 + self.__super_init(klass, scopes, module)
1.1474 + self.graph.setFreeVars(self.scope.get_free_vars())
1.1475 + self.graph.setCellVars(self.scope.get_cell_vars())
1.1476 + self.set_lineno(klass)
1.1477 + self.emit("LOAD_GLOBAL", "__name__")
1.1478 + self.storeName("__module__")
1.1479 + if klass.doc:
1.1480 + self.emit("LOAD_CONST", klass.doc)
1.1481 + self.storeName('__doc__')
1.1482 +
1.1483 +def generateArgList(arglist):
1.1484 + """Generate an arg list marking TupleArgs"""
1.1485 + args = []
1.1486 + extra = []
1.1487 + count = 0
1.1488 + for i in range(len(arglist)):
1.1489 + elt = arglist[i]
1.1490 + if isinstance(elt, str):
1.1491 + args.append(elt)
1.1492 + elif isinstance(elt, tuple):
1.1493 + args.append(TupleArg(i * 2, elt))
1.1494 + extra.extend(misc.flatten(elt))
1.1495 + count = count + 1
1.1496 + else:
1.1497 + raise ValueError, "unexpect argument type:", elt
1.1498 + return args + extra, count
1.1499 +
1.1500 +def findOp(node):
1.1501 + """Find the op (DELETE, LOAD, STORE) in an AssTuple tree"""
1.1502 + v = OpFinder()
1.1503 + walk(node, v, verbose=0)
1.1504 + return v.op
1.1505 +
1.1506 +class OpFinder:
1.1507 + def __init__(self):
1.1508 + self.op = None
1.1509 + def visitAssName(self, node):
1.1510 + if self.op is None:
1.1511 + self.op = node.flags
1.1512 + elif self.op != node.flags:
1.1513 + raise ValueError, "mixed ops in stmt"
1.1514 + visitAssAttr = visitAssName
1.1515 + visitSubscript = visitAssName
1.1516 +
1.1517 +class Delegator:
1.1518 + """Base class to support delegation for augmented assignment nodes
1.1519 +
1.1520 + To generator code for augmented assignments, we use the following
1.1521 + wrapper classes. In visitAugAssign, the left-hand expression node
1.1522 + is visited twice. The first time the visit uses the normal method
1.1523 + for that node . The second time the visit uses a different method
1.1524 + that generates the appropriate code to perform the assignment.
1.1525 + These delegator classes wrap the original AST nodes in order to
1.1526 + support the variant visit methods.
1.1527 + """
1.1528 + def __init__(self, obj):
1.1529 + self.obj = obj
1.1530 +
1.1531 + def __getattr__(self, attr):
1.1532 + return getattr(self.obj, attr)
1.1533 +
1.1534 +class AugGetattr(Delegator):
1.1535 + pass
1.1536 +
1.1537 +class AugName(Delegator):
1.1538 + pass
1.1539 +
1.1540 +class AugSlice(Delegator):
1.1541 + pass
1.1542 +
1.1543 +class AugSubscript(Delegator):
1.1544 + pass
1.1545 +
1.1546 +wrapper = {
1.1547 + ast.Getattr: AugGetattr,
1.1548 + ast.Name: AugName,
1.1549 + ast.Slice: AugSlice,
1.1550 + ast.Subscript: AugSubscript,
1.1551 + }
1.1552 +
1.1553 +def wrap_aug(node):
1.1554 + return wrapper[node.__class__](node)
1.1555 +
1.1556 +if __name__ == "__main__":
1.1557 + for file in sys.argv[1:]:
1.1558 + compileFile(file)