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