pycodegen.py 45.7 KB
Newer Older
1
import imp
2
import os
Jeremy Hylton's avatar
Jeremy Hylton committed
3
import marshal
4
import struct
5
import sys
Jeremy Hylton's avatar
Jeremy Hylton committed
6
from cStringIO import StringIO
7

8
from compiler import ast, parse, walk, syntax
9 10
from compiler import pyassem, misc, future, symbols
from compiler.consts import SC_LOCAL, SC_GLOBAL, SC_FREE, SC_CELL
11
from compiler.consts import (CO_VARARGS, CO_VARKEYWORDS, CO_NEWLOCALS,
12
     CO_NESTED, CO_GENERATOR, CO_FUTURE_DIVISION,
13
     CO_FUTURE_ABSIMPORT, CO_FUTURE_WITH_STATEMENT, CO_FUTURE_PRINT_FUNCTION)
14
from compiler.pyassem import TupleArg
15

16
# XXX The version-specific code can go, since this code only works with 2.x.
17 18 19 20 21 22
# Do we have Python 1.x or Python 2.x?
try:
    VERSION = sys.version_info[0]
except AttributeError:
    VERSION = 1

23 24 25 26 27 28 29 30
callfunc_opcode_info = {
    # (Have *args, Have **args) : opcode
    (0,0) : "CALL_FUNCTION",
    (1,0) : "CALL_FUNCTION_VAR",
    (0,1) : "CALL_FUNCTION_KW",
    (1,1) : "CALL_FUNCTION_VAR_KW",
}

31 32 33 34 35
LOOP = 1
EXCEPT = 2
TRY_FINALLY = 3
END_FINALLY = 4

Jeremy Hylton's avatar
Jeremy Hylton committed
36
def compileFile(filename, display=0):
37
    f = open(filename, 'U')
Jeremy Hylton's avatar
Jeremy Hylton committed
38 39 40
    buf = f.read()
    f.close()
    mod = Module(buf, filename)
41 42
    try:
        mod.compile(display)
43
    except SyntaxError:
44
        raise
45 46 47 48
    else:
        f = open(filename + "c", "wb")
        mod.dump(f)
        f.close()
49

Jeremy Hylton's avatar
Jeremy Hylton committed
50 51 52 53
def compile(source, filename, mode, flags=None, dont_inherit=None):
    """Replacement for builtin compile() function"""
    if flags is not None or dont_inherit is not None:
        raise RuntimeError, "not implemented yet"
Tim Peters's avatar
Tim Peters committed
54

Jeremy Hylton's avatar
Jeremy Hylton committed
55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70
    if mode == "single":
        gen = Interactive(source, filename)
    elif mode == "exec":
        gen = Module(source, filename)
    elif mode == "eval":
        gen = Expression(source, filename)
    else:
        raise ValueError("compile() 3rd arg must be 'exec' or "
                         "'eval' or 'single'")
    gen.compile()
    return gen.code

class AbstractCompileMode:

    mode = None # defined by subclass

Jeremy Hylton's avatar
Jeremy Hylton committed
71
    def __init__(self, source, filename):
72
        self.source = source
Jeremy Hylton's avatar
Jeremy Hylton committed
73
        self.filename = filename
74
        self.code = None
75

Jeremy Hylton's avatar
Jeremy Hylton committed
76 77
    def _get_tree(self):
        tree = parse(self.source, self.mode)
78 79
        misc.set_filename(self.filename, tree)
        syntax.check(tree)
Jeremy Hylton's avatar
Jeremy Hylton committed
80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111
        return tree

    def compile(self):
        pass # implemented by subclass

    def getCode(self):
        return self.code

class Expression(AbstractCompileMode):

    mode = "eval"

    def compile(self):
        tree = self._get_tree()
        gen = ExpressionCodeGenerator(tree)
        self.code = gen.getCode()

class Interactive(AbstractCompileMode):

    mode = "single"

    def compile(self):
        tree = self._get_tree()
        gen = InteractiveCodeGenerator(tree)
        self.code = gen.getCode()

class Module(AbstractCompileMode):

    mode = "exec"

    def compile(self, display=0):
        tree = self._get_tree()
112
        gen = ModuleCodeGenerator(tree)
113 114
        if display:
            import pprint
115
            print pprint.pprint(tree)
116
        self.code = gen.getCode()
Jeremy Hylton's avatar
Jeremy Hylton committed
117

Jeremy Hylton's avatar
Jeremy Hylton committed
118
    def dump(self, f):
119 120
        f.write(self.getPycHeader())
        marshal.dump(self.code, f)
121

122
    MAGIC = imp.get_magic()
Jeremy Hylton's avatar
Jeremy Hylton committed
123 124

    def getPycHeader(self):
125 126 127 128
        # compile.c uses marshal to write a long directly, with
        # calling the interface that would also generate a 1-byte code
        # to indicate the type of the value.  simplest way to get the
        # same effect is to call marshal and then skip the code.
129
        mtime = os.path.getmtime(self.filename)
130
        mtime = struct.pack('<i', mtime)
131
        return self.MAGIC + mtime
Jeremy Hylton's avatar
Jeremy Hylton committed
132

133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175
class LocalNameFinder:
    """Find local names in scope"""
    def __init__(self, names=()):
        self.names = misc.Set()
        self.globals = misc.Set()
        for name in names:
            self.names.add(name)

    # XXX list comprehensions and for loops

    def getLocals(self):
        for elt in self.globals.elements():
            if self.names.has_elt(elt):
                self.names.remove(elt)
        return self.names

    def visitDict(self, node):
        pass

    def visitGlobal(self, node):
        for name in node.names:
            self.globals.add(name)

    def visitFunction(self, node):
        self.names.add(node.name)

    def visitLambda(self, node):
        pass

    def visitImport(self, node):
        for name, alias in node.names:
            self.names.add(alias or name)

    def visitFrom(self, node):
        for name, alias in node.names:
            self.names.add(alias or name)

    def visitClass(self, node):
        self.names.add(node.name)

    def visitAssName(self, node):
        self.names.add(node.name)

176 177 178 179 180 181
def is_constant_false(node):
    if isinstance(node, ast.Const):
        if not node.value:
            return 1
    return 0

Jeremy Hylton's avatar
Jeremy Hylton committed
182
class CodeGenerator:
183 184 185 186 187 188 189 190 191 192
    """Defines basic code generator for Python bytecode

    This class is an abstract base class.  Concrete subclasses must
    define an __init__() that defines self.graph and then calls the
    __init__() defined in this class.

    The concrete class must also define the class attributes
    NameFinder, FunctionGen, and ClassGen.  These attributes can be
    defined in the initClass() method, which is a hook for
    initializing these methods after all the classes have been
Tim Peters's avatar
Tim Peters committed
193
    defined.
194
    """
Jeremy Hylton's avatar
Jeremy Hylton committed
195 196

    optimized = 0 # is namespace access optimized?
197
    __initialized = None
Jeremy Hylton's avatar
Jeremy Hylton committed
198
    class_name = None # provide default for instance variable
Jeremy Hylton's avatar
Jeremy Hylton committed
199

200
    def __init__(self):
201 202 203 204
        if self.__initialized is None:
            self.initClass()
            self.__class__.__initialized = 1
        self.checkClass()
205
        self.locals = misc.Stack()
206
        self.setups = misc.Stack()
207
        self.last_lineno = None
208
        self._setupGraphDelegation()
Jeremy Hylton's avatar
Jeremy Hylton committed
209
        self._div_op = "BINARY_DIVIDE"
Jeremy Hylton's avatar
Jeremy Hylton committed
210

211 212 213 214 215
        # XXX set flags based on future features
        futures = self.get_module().futures
        for feature in futures:
            if feature == "division":
                self.graph.setFlag(CO_FUTURE_DIVISION)
Jeremy Hylton's avatar
Jeremy Hylton committed
216
                self._div_op = "BINARY_TRUE_DIVIDE"
217 218 219 220
            elif feature == "absolute_import":
                self.graph.setFlag(CO_FUTURE_ABSIMPORT)
            elif feature == "with_statement":
                self.graph.setFlag(CO_FUTURE_WITH_STATEMENT)
221 222
            elif feature == "print_function":
                self.graph.setFlag(CO_FUTURE_PRINT_FUNCTION)
223

224 225 226 227 228 229 230 231 232 233 234 235 236 237
    def initClass(self):
        """This method is called once for each class"""

    def checkClass(self):
        """Verify that class is constructed correctly"""
        try:
            assert hasattr(self, 'graph')
            assert getattr(self, 'NameFinder')
            assert getattr(self, 'FunctionGen')
            assert getattr(self, 'ClassGen')
        except AssertionError, msg:
            intro = "Bad class construction for %s" % self.__class__.__name__
            raise AssertionError, intro

Jeremy Hylton's avatar
Jeremy Hylton committed
238
    def _setupGraphDelegation(self):
239 240 241 242 243
        self.emit = self.graph.emit
        self.newBlock = self.graph.newBlock
        self.startBlock = self.graph.startBlock
        self.nextBlock = self.graph.nextBlock
        self.setDocstring = self.graph.setDocstring
244

Jeremy Hylton's avatar
Jeremy Hylton committed
245
    def getCode(self):
246 247
        """Return a code object"""
        return self.graph.getCode()
Jeremy Hylton's avatar
Jeremy Hylton committed
248

Jeremy Hylton's avatar
Jeremy Hylton committed
249 250 251 252 253 254
    def mangle(self, name):
        if self.class_name is not None:
            return misc.mangle(name, self.class_name)
        else:
            return name

255 256 257 258 259 260 261 262
    def parseSymbols(self, tree):
        s = symbols.SymbolVisitor()
        walk(tree, s)
        return s.scopes

    def get_module(self):
        raise RuntimeError, "should be implemented by subclasses"

Jeremy Hylton's avatar
Jeremy Hylton committed
263
    # Next five methods handle name access
264

265
    def isLocalName(self, name):
Jeremy Hylton's avatar
Jeremy Hylton committed
266
        return self.locals.top().has_elt(name)
267

268 269 270 271 272 273 274 275 276
    def storeName(self, name):
        self._nameOp('STORE', name)

    def loadName(self, name):
        self._nameOp('LOAD', name)

    def delName(self, name):
        self._nameOp('DELETE', name)

Jeremy Hylton's avatar
Jeremy Hylton committed
277
    def _nameOp(self, prefix, name):
Jeremy Hylton's avatar
Jeremy Hylton committed
278
        name = self.mangle(name)
279 280 281 282 283 284 285 286 287 288 289 290 291
        scope = self.scope.check_name(name)
        if scope == SC_LOCAL:
            if not self.optimized:
                self.emit(prefix + '_NAME', name)
            else:
                self.emit(prefix + '_FAST', name)
        elif scope == SC_GLOBAL:
            if not self.optimized:
                self.emit(prefix + '_NAME', name)
            else:
                self.emit(prefix + '_GLOBAL', name)
        elif scope == SC_FREE or scope == SC_CELL:
            self.emit(prefix + '_DEREF', name)
Jeremy Hylton's avatar
Jeremy Hylton committed
292
        else:
293 294
            raise RuntimeError, "unsupported scope for var %s: %d" % \
                  (name, scope)
295

296 297 298 299 300 301 302 303 304 305 306 307
    def _implicitNameOp(self, prefix, name):
        """Emit name ops for names generated implicitly by for loops

        The interpreter generates names that start with a period or
        dollar sign.  The symbol table ignores these names because
        they aren't present in the program text.
        """
        if self.optimized:
            self.emit(prefix + '_FAST', name)
        else:
            self.emit(prefix + '_NAME', name)

308 309 310 311 312 313 314 315 316 317 318
    # The set_lineno() function and the explicit emit() calls for
    # SET_LINENO below are only used to generate the line number table.
    # As of Python 2.3, the interpreter does not have a SET_LINENO
    # instruction.  pyassem treats SET_LINENO opcodes as a special case.

    def set_lineno(self, node, force=False):
        """Emit SET_LINENO if necessary.

        The instruction is considered necessary if the node has a
        lineno attribute and it is different than the last lineno
        emitted.
319 320 321 322 323 324 325 326 327

        Returns true if SET_LINENO was emitted.

        There are no rules for when an AST node should have a lineno
        attribute.  The transformer and AST code need to be reviewed
        and a consistent policy implemented and documented.  Until
        then, this method works around missing line numbers.
        """
        lineno = getattr(node, 'lineno', None)
Jeremy Hylton's avatar
Jeremy Hylton committed
328 329
        if lineno is not None and (lineno != self.last_lineno
                                   or force):
330
            self.emit('SET_LINENO', lineno)
331
            self.last_lineno = lineno
332 333
            return True
        return False
334

Jeremy Hylton's avatar
Jeremy Hylton committed
335
    # The first few visitor methods handle nodes that generator new
336 337 338 339 340 341
    # code objects.  They use class attributes to determine what
    # specialized code generators to use.

    NameFinder = LocalNameFinder
    FunctionGen = None
    ClassGen = None
Jeremy Hylton's avatar
Jeremy Hylton committed
342

343
    def visitModule(self, node):
344 345
        self.scopes = self.parseSymbols(node)
        self.scope = self.scopes[node]
346
        self.emit('SET_LINENO', 0)
Jeremy Hylton's avatar
Jeremy Hylton committed
347
        if node.doc:
348 349 350 351
            self.emit('LOAD_CONST', node.doc)
            self.storeName('__doc__')
        lnf = walk(node.node, self.NameFinder(), verbose=0)
        self.locals.push(lnf.getLocals())
352 353 354
        self.visit(node.node)
        self.emit('LOAD_CONST', None)
        self.emit('RETURN_VALUE')
355

356 357 358 359 360 361 362
    def visitExpression(self, node):
        self.set_lineno(node)
        self.scopes = self.parseSymbols(node)
        self.scope = self.scopes[node]
        self.visit(node.node)
        self.emit('RETURN_VALUE')

Jeremy Hylton's avatar
Jeremy Hylton committed
363
    def visitFunction(self, node):
364
        self._visitFuncOrLambda(node, isLambda=0)
Jeremy Hylton's avatar
Jeremy Hylton committed
365 366
        if node.doc:
            self.setDocstring(node.doc)
367
        self.storeName(node.name)
Jeremy Hylton's avatar
Jeremy Hylton committed
368

Jeremy Hylton's avatar
Jeremy Hylton committed
369
    def visitLambda(self, node):
370
        self._visitFuncOrLambda(node, isLambda=1)
Jeremy Hylton's avatar
Jeremy Hylton committed
371

372
    def _visitFuncOrLambda(self, node, isLambda=0):
373
        if not isLambda and node.decorators:
374
            for decorator in node.decorators.nodes:
375 376 377 378
                self.visit(decorator)
            ndecorators = len(node.decorators.nodes)
        else:
            ndecorators = 0
Tim Peters's avatar
Tim Peters committed
379

380
        gen = self.FunctionGen(node, self.scopes, isLambda,
381
                               self.class_name, self.get_module())
382 383
        walk(node.code, gen)
        gen.finish()
384
        self.set_lineno(node)
Jeremy Hylton's avatar
Jeremy Hylton committed
385 386
        for default in node.defaults:
            self.visit(default)
387
        self._makeClosure(gen, len(node.defaults))
388 389
        for i in range(ndecorators):
            self.emit('CALL_FUNCTION', 1)
Jeremy Hylton's avatar
Jeremy Hylton committed
390

391
    def visitClass(self, node):
392
        gen = self.ClassGen(node, self.scopes,
393
                            self.get_module())
Jeremy Hylton's avatar
Jeremy Hylton committed
394 395
        walk(node.code, gen)
        gen.finish()
396
        self.set_lineno(node)
397
        self.emit('LOAD_CONST', node.name)
398 399
        for base in node.bases:
            self.visit(base)
400
        self.emit('BUILD_TUPLE', len(node.bases))
401
        self._makeClosure(gen, 0)
402 403
        self.emit('CALL_FUNCTION', 0)
        self.emit('BUILD_CLASS')
404 405
        self.storeName(node.name)

Jeremy Hylton's avatar
Jeremy Hylton committed
406
    # The rest are standard visitor methods
407

Jeremy Hylton's avatar
Jeremy Hylton committed
408
    # The next few implement control-flow statements
409

Jeremy Hylton's avatar
Jeremy Hylton committed
410
    def visitIf(self, node):
411 412 413 414
        end = self.newBlock()
        numtests = len(node.tests)
        for i in range(numtests):
            test, suite = node.tests[i]
415 416 417
            if is_constant_false(test):
                # XXX will need to check generator stuff here
                continue
418
            self.set_lineno(test)
419 420 421 422 423 424 425
            self.visit(test)
            nextTest = self.newBlock()
            self.emit('JUMP_IF_FALSE', nextTest)
            self.nextBlock()
            self.emit('POP_TOP')
            self.visit(suite)
            self.emit('JUMP_FORWARD', end)
426
            self.startBlock(nextTest)
427 428 429 430
            self.emit('POP_TOP')
        if node.else_:
            self.visit(node.else_)
        self.nextBlock(end)
431

Jeremy Hylton's avatar
Jeremy Hylton committed
432
    def visitWhile(self, node):
433
        self.set_lineno(node)
434

435 436
        loop = self.newBlock()
        else_ = self.newBlock()
437

438 439
        after = self.newBlock()
        self.emit('SETUP_LOOP', after)
Jeremy Hylton's avatar
Jeremy Hylton committed
440

441
        self.nextBlock(loop)
442
        self.setups.push((LOOP, loop))
Jeremy Hylton's avatar
Jeremy Hylton committed
443

444
        self.set_lineno(node, force=True)
445 446 447 448 449 450 451 452 453 454 455
        self.visit(node.test)
        self.emit('JUMP_IF_FALSE', else_ or after)

        self.nextBlock()
        self.emit('POP_TOP')
        self.visit(node.body)
        self.emit('JUMP_ABSOLUTE', loop)

        self.startBlock(else_) # or just the POPs if not else clause
        self.emit('POP_TOP')
        self.emit('POP_BLOCK')
456
        self.setups.pop()
457 458 459
        if node.else_:
            self.visit(node.else_)
        self.nextBlock(after)
Jeremy Hylton's avatar
Jeremy Hylton committed
460

461
    def visitFor(self, node):
462
        start = self.newBlock()
Jeremy Hylton's avatar
Jeremy Hylton committed
463
        anchor = self.newBlock()
464
        after = self.newBlock()
465
        self.setups.push((LOOP, start))
466

467
        self.set_lineno(node)
468
        self.emit('SETUP_LOOP', after)
469
        self.visit(node.list)
470 471
        self.emit('GET_ITER')

472
        self.nextBlock(start)
473
        self.set_lineno(node, force=1)
474
        self.emit('FOR_ITER', anchor)
475 476
        self.visit(node.assign)
        self.visit(node.body)
Jeremy Hylton's avatar
Jeremy Hylton committed
477
        self.emit('JUMP_ABSOLUTE', start)
478
        self.nextBlock(anchor)
479
        self.emit('POP_BLOCK')
480
        self.setups.pop()
481 482
        if node.else_:
            self.visit(node.else_)
483
        self.nextBlock(after)
Jeremy Hylton's avatar
Jeremy Hylton committed
484 485

    def visitBreak(self, node):
486
        if not self.setups:
487
            raise SyntaxError, "'break' outside loop (%s, %d)" % \
488
                  (node.filename, node.lineno)
489
        self.set_lineno(node)
490
        self.emit('BREAK_LOOP')
Jeremy Hylton's avatar
Jeremy Hylton committed
491 492

    def visitContinue(self, node):
493
        if not self.setups:
Jeremy Hylton's avatar
Jeremy Hylton committed
494
            raise SyntaxError, "'continue' outside loop (%s, %d)" % \
495
                  (node.filename, node.lineno)
496 497 498 499 500 501 502 503 504 505 506 507 508 509 510 511
        kind, block = self.setups.top()
        if kind == LOOP:
            self.set_lineno(node)
            self.emit('JUMP_ABSOLUTE', block)
            self.nextBlock()
        elif kind == EXCEPT or kind == TRY_FINALLY:
            self.set_lineno(node)
            # find the block that starts the loop
            top = len(self.setups)
            while top > 0:
                top = top - 1
                kind, loop_block = self.setups[top]
                if kind == LOOP:
                    break
            if kind != LOOP:
                raise SyntaxError, "'continue' outside loop (%s, %d)" % \
512
                      (node.filename, node.lineno)
513 514 515
            self.emit('CONTINUE_LOOP', loop_block)
            self.nextBlock()
        elif kind == END_FINALLY:
Tim Peters's avatar
Tim Peters committed
516
            msg = "'continue' not allowed inside 'finally' clause (%s, %d)"
517
            raise SyntaxError, msg % (node.filename, node.lineno)
Jeremy Hylton's avatar
Jeremy Hylton committed
518 519

    def visitTest(self, node, jump):
520
        end = self.newBlock()
Jeremy Hylton's avatar
Jeremy Hylton committed
521 522 523
        for child in node.nodes[:-1]:
            self.visit(child)
            self.emit(jump, end)
524
            self.nextBlock()
Jeremy Hylton's avatar
Jeremy Hylton committed
525 526
            self.emit('POP_TOP')
        self.visit(node.nodes[-1])
527
        self.nextBlock(end)
Jeremy Hylton's avatar
Jeremy Hylton committed
528 529

    def visitAnd(self, node):
530
        self.visitTest(node, 'JUMP_IF_FALSE')
Jeremy Hylton's avatar
Jeremy Hylton committed
531 532

    def visitOr(self, node):
533
        self.visitTest(node, 'JUMP_IF_TRUE')
Jeremy Hylton's avatar
Jeremy Hylton committed
534

535 536 537 538 539 540 541 542 543 544 545 546 547
    def visitIfExp(self, node):
        endblock = self.newBlock()
        elseblock = self.newBlock()
        self.visit(node.test)
        self.emit('JUMP_IF_FALSE', elseblock)
        self.emit('POP_TOP')
        self.visit(node.then)
        self.emit('JUMP_FORWARD', endblock)
        self.nextBlock(elseblock)
        self.emit('POP_TOP')
        self.visit(node.else_)
        self.nextBlock(endblock)

Jeremy Hylton's avatar
Jeremy Hylton committed
548
    def visitCompare(self, node):
549 550 551 552 553 554 555 556 557 558 559 560 561 562 563 564 565 566
        self.visit(node.expr)
        cleanup = self.newBlock()
        for op, code in node.ops[:-1]:
            self.visit(code)
            self.emit('DUP_TOP')
            self.emit('ROT_THREE')
            self.emit('COMPARE_OP', op)
            self.emit('JUMP_IF_FALSE', cleanup)
            self.nextBlock()
            self.emit('POP_TOP')
        # now do the last comparison
        if node.ops:
            op, code = node.ops[-1]
            self.visit(code)
            self.emit('COMPARE_OP', op)
        if len(node.ops) > 1:
            end = self.newBlock()
            self.emit('JUMP_FORWARD', end)
567
            self.startBlock(cleanup)
568 569 570
            self.emit('ROT_TWO')
            self.emit('POP_TOP')
            self.nextBlock(end)
Jeremy Hylton's avatar
Jeremy Hylton committed
571

572 573 574 575 576
    # list comprehensions
    def visitListComp(self, node):
        self.set_lineno(node)
        # setup list
        self.emit('BUILD_LIST', 0)
Tim Peters's avatar
Tim Peters committed
577

578
        stack = []
Jeremy Hylton's avatar
Jeremy Hylton committed
579
        for i, for_ in zip(range(len(node.quals)), node.quals):
580 581 582 583 584 585 586
            start, anchor = self.visit(for_)
            cont = None
            for if_ in for_.ifs:
                if cont is None:
                    cont = self.newBlock()
                self.visit(if_, cont)
            stack.insert(0, (start, cont, anchor))
Jeremy Hylton's avatar
Jeremy Hylton committed
587

588
        self.visit(node.expr)
589
        self.emit('LIST_APPEND', len(node.quals) + 1)
Tim Peters's avatar
Tim Peters committed
590

591 592 593 594
        for start, cont, anchor in stack:
            if cont:
                skip_one = self.newBlock()
                self.emit('JUMP_FORWARD', skip_one)
595
                self.startBlock(cont)
596 597 598
                self.emit('POP_TOP')
                self.nextBlock(skip_one)
            self.emit('JUMP_ABSOLUTE', start)
599
            self.startBlock(anchor)
600 601 602 603 604 605

    def visitListCompFor(self, node):
        start = self.newBlock()
        anchor = self.newBlock()

        self.visit(node.list)
606
        self.emit('GET_ITER')
607
        self.nextBlock(start)
608
        self.set_lineno(node, force=True)
609
        self.emit('FOR_ITER', anchor)
610
        self.nextBlock()
611 612 613 614
        self.visit(node.assign)
        return start, anchor

    def visitListCompIf(self, node, branch):
615
        self.set_lineno(node, force=True)
616 617 618 619 620
        self.visit(node.test)
        self.emit('JUMP_IF_FALSE', branch)
        self.newBlock()
        self.emit('POP_TOP')

621
    def _makeClosure(self, gen, args):
622 623 624 625
        frees = gen.scope.get_free_vars()
        if frees:
            for name in frees:
                self.emit('LOAD_CLOSURE', name)
626
            self.emit('BUILD_TUPLE', len(frees))
627
            self.emit('LOAD_CONST', gen)
628
            self.emit('MAKE_CLOSURE', args)
629 630
        else:
            self.emit('LOAD_CONST', gen)
631
            self.emit('MAKE_FUNCTION', args)
632

633 634 635 636 637 638 639
    def visitGenExpr(self, node):
        gen = GenExprCodeGenerator(node, self.scopes, self.class_name,
                                   self.get_module())
        walk(node.code, gen)
        gen.finish()
        self.set_lineno(node)
        self._makeClosure(gen, 0)
640 641 642 643 644 645 646 647 648 649 650
        # precomputation of outmost iterable
        self.visit(node.code.quals[0].iter)
        self.emit('GET_ITER')
        self.emit('CALL_FUNCTION', 1)

    def visitGenExprInner(self, node):
        self.set_lineno(node)
        # setup list

        stack = []
        for i, for_ in zip(range(len(node.quals)), node.quals):
651
            start, anchor, end = self.visit(for_)
652 653 654 655 656
            cont = None
            for if_ in for_.ifs:
                if cont is None:
                    cont = self.newBlock()
                self.visit(if_, cont)
657
            stack.insert(0, (start, cont, anchor, end))
658 659 660

        self.visit(node.expr)
        self.emit('YIELD_VALUE')
661
        self.emit('POP_TOP')
662

663
        for start, cont, anchor, end in stack:
664 665 666 667 668 669 670 671
            if cont:
                skip_one = self.newBlock()
                self.emit('JUMP_FORWARD', skip_one)
                self.startBlock(cont)
                self.emit('POP_TOP')
                self.nextBlock(skip_one)
            self.emit('JUMP_ABSOLUTE', start)
            self.startBlock(anchor)
672 673 674 675
            self.emit('POP_BLOCK')
            self.setups.pop()
            self.startBlock(end)

676 677 678 679 680
        self.emit('LOAD_CONST', None)

    def visitGenExprFor(self, node):
        start = self.newBlock()
        anchor = self.newBlock()
681 682 683 684
        end = self.newBlock()

        self.setups.push((LOOP, start))
        self.emit('SETUP_LOOP', end)
Tim Peters's avatar
Tim Peters committed
685

686
        if node.is_outmost:
687
            self.loadName('.0')
688 689 690 691 692 693 694 695 696
        else:
            self.visit(node.iter)
            self.emit('GET_ITER')

        self.nextBlock(start)
        self.set_lineno(node, force=True)
        self.emit('FOR_ITER', anchor)
        self.nextBlock()
        self.visit(node.assign)
697
        return start, anchor, end
698 699 700 701 702 703 704 705

    def visitGenExprIf(self, node, branch):
        self.set_lineno(node, force=True)
        self.visit(node.test)
        self.emit('JUMP_IF_FALSE', branch)
        self.newBlock()
        self.emit('POP_TOP')

Jeremy Hylton's avatar
Jeremy Hylton committed
706 707 708
    # exception related

    def visitAssert(self, node):
709 710
        # XXX would be interesting to implement this via a
        # transformation of the AST before this stage
Jeremy Hylton's avatar
Jeremy Hylton committed
711 712 713 714 715 716 717 718 719 720 721 722 723 724 725 726 727 728 729
        if __debug__:
            end = self.newBlock()
            self.set_lineno(node)
            # XXX AssertionError appears to be special case -- it is always
            # loaded as a global even if there is a local name.  I guess this
            # is a sort of renaming op.
            self.nextBlock()
            self.visit(node.test)
            self.emit('JUMP_IF_TRUE', end)
            self.nextBlock()
            self.emit('POP_TOP')
            self.emit('LOAD_GLOBAL', 'AssertionError')
            if node.fail:
                self.visit(node.fail)
                self.emit('RAISE_VARARGS', 2)
            else:
                self.emit('RAISE_VARARGS', 1)
            self.nextBlock(end)
            self.emit('POP_TOP')
Jeremy Hylton's avatar
Jeremy Hylton committed
730 731

    def visitRaise(self, node):
732
        self.set_lineno(node)
Jeremy Hylton's avatar
Jeremy Hylton committed
733 734 735 736 737 738 739 740 741 742 743
        n = 0
        if node.expr1:
            self.visit(node.expr1)
            n = n + 1
        if node.expr2:
            self.visit(node.expr2)
            n = n + 1
        if node.expr3:
            self.visit(node.expr3)
            n = n + 1
        self.emit('RAISE_VARARGS', n)
Jeremy Hylton's avatar
Jeremy Hylton committed
744

745
    def visitTryExcept(self, node):
746
        body = self.newBlock()
Jeremy Hylton's avatar
Jeremy Hylton committed
747 748
        handlers = self.newBlock()
        end = self.newBlock()
749
        if node.else_:
Jeremy Hylton's avatar
Jeremy Hylton committed
750
            lElse = self.newBlock()
751 752
        else:
            lElse = end
753
        self.set_lineno(node)
754
        self.emit('SETUP_EXCEPT', handlers)
755 756
        self.nextBlock(body)
        self.setups.push((EXCEPT, body))
757 758
        self.visit(node.body)
        self.emit('POP_BLOCK')
759
        self.setups.pop()
760
        self.emit('JUMP_FORWARD', lElse)
761
        self.startBlock(handlers)
Tim Peters's avatar
Tim Peters committed
762

763 764 765
        last = len(node.handlers) - 1
        for i in range(len(node.handlers)):
            expr, target, body = node.handlers[i]
766
            self.set_lineno(expr)
767 768 769
            if expr:
                self.emit('DUP_TOP')
                self.visit(expr)
Jeremy Hylton's avatar
Jeremy Hylton committed
770 771
                self.emit('COMPARE_OP', 'exception match')
                next = self.newBlock()
772
                self.emit('JUMP_IF_FALSE', next)
773
                self.nextBlock()
774 775 776 777 778 779 780 781 782
                self.emit('POP_TOP')
            self.emit('POP_TOP')
            if target:
                self.visit(target)
            else:
                self.emit('POP_TOP')
            self.emit('POP_TOP')
            self.visit(body)
            self.emit('JUMP_FORWARD', end)
783
            if expr:
784
                self.nextBlock(next)
785 786
            else:
                self.nextBlock()
787 788
            if expr: # XXX
                self.emit('POP_TOP')
789 790
        self.emit('END_FINALLY')
        if node.else_:
791
            self.nextBlock(lElse)
792
            self.visit(node.else_)
793
        self.nextBlock(end)
Tim Peters's avatar
Tim Peters committed
794

795
    def visitTryFinally(self, node):
796
        body = self.newBlock()
Jeremy Hylton's avatar
Jeremy Hylton committed
797
        final = self.newBlock()
798
        self.set_lineno(node)
799
        self.emit('SETUP_FINALLY', final)
800 801
        self.nextBlock(body)
        self.setups.push((TRY_FINALLY, body))
802 803
        self.visit(node.body)
        self.emit('POP_BLOCK')
804
        self.setups.pop()
805
        self.emit('LOAD_CONST', None)
806
        self.nextBlock(final)
807
        self.setups.push((END_FINALLY, final))
808 809
        self.visit(node.final)
        self.emit('END_FINALLY')
810
        self.setups.pop()
811

812 813 814 815 816 817 818 819 820 821 822
    __with_count = 0

    def visitWith(self, node):
        body = self.newBlock()
        final = self.newBlock()
        valuevar = "$value%d" % self.__with_count
        self.__with_count += 1
        self.set_lineno(node)
        self.visit(node.expr)
        self.emit('DUP_TOP')
        self.emit('LOAD_ATTR', '__exit__')
823
        self.emit('ROT_TWO')
824 825 826 827 828 829 830 831 832 833 834 835 836 837 838 839 840 841 842 843 844 845 846 847
        self.emit('LOAD_ATTR', '__enter__')
        self.emit('CALL_FUNCTION', 0)
        if node.vars is None:
            self.emit('POP_TOP')
        else:
            self._implicitNameOp('STORE', valuevar)
        self.emit('SETUP_FINALLY', final)
        self.nextBlock(body)
        self.setups.push((TRY_FINALLY, body))
        if node.vars is not None:
            self._implicitNameOp('LOAD', valuevar)
            self._implicitNameOp('DELETE', valuevar)
            self.visit(node.vars)
        self.visit(node.body)
        self.emit('POP_BLOCK')
        self.setups.pop()
        self.emit('LOAD_CONST', None)
        self.nextBlock(final)
        self.setups.push((END_FINALLY, final))
        self.emit('WITH_CLEANUP')
        self.emit('END_FINALLY')
        self.setups.pop()
        self.__with_count -= 1

Jeremy Hylton's avatar
Jeremy Hylton committed
848
    # misc
849

Jeremy Hylton's avatar
Jeremy Hylton committed
850
    def visitDiscard(self, node):
851
        self.set_lineno(node)
Jeremy Hylton's avatar
Jeremy Hylton committed
852
        self.visit(node.expr)
Jeremy Hylton's avatar
Jeremy Hylton committed
853
        self.emit('POP_TOP')
Jeremy Hylton's avatar
Jeremy Hylton committed
854

Jeremy Hylton's avatar
Jeremy Hylton committed
855 856 857 858
    def visitConst(self, node):
        self.emit('LOAD_CONST', node.value)

    def visitKeyword(self, node):
859 860
        self.emit('LOAD_CONST', node.name)
        self.visit(node.expr)
Jeremy Hylton's avatar
Jeremy Hylton committed
861 862 863

    def visitGlobal(self, node):
        # no code to generate
864
        pass
Jeremy Hylton's avatar
Jeremy Hylton committed
865 866

    def visitName(self, node):
867
        self.set_lineno(node)
Jeremy Hylton's avatar
Jeremy Hylton committed
868
        self.loadName(node.name)
Tim Peters's avatar
Tim Peters committed
869

Jeremy Hylton's avatar
Jeremy Hylton committed
870
    def visitPass(self, node):
871
        self.set_lineno(node)
Jeremy Hylton's avatar
Jeremy Hylton committed
872 873

    def visitImport(self, node):
874
        self.set_lineno(node)
875
        level = 0 if self.graph.checkFlag(CO_FUTURE_ABSIMPORT) else -1
Jeremy Hylton's avatar
Jeremy Hylton committed
876
        for name, alias in node.names:
877
            if VERSION > 1:
878
                self.emit('LOAD_CONST', level)
879
                self.emit('LOAD_CONST', None)
Jeremy Hylton's avatar
Jeremy Hylton committed
880
            self.emit('IMPORT_NAME', name)
881
            mod = name.split(".")[0]
882 883 884 885 886
            if alias:
                self._resolveDots(name)
                self.storeName(alias)
            else:
                self.storeName(mod)
Jeremy Hylton's avatar
Jeremy Hylton committed
887 888

    def visitFrom(self, node):
889
        self.set_lineno(node)
890
        level = node.level
891
        if level == 0 and not self.graph.checkFlag(CO_FUTURE_ABSIMPORT):
892
            level = -1
Jeremy Hylton's avatar
Jeremy Hylton committed
893
        fromlist = map(lambda (name, alias): name, node.names)
894
        if VERSION > 1:
895
            self.emit('LOAD_CONST', level)
896
            self.emit('LOAD_CONST', tuple(fromlist))
Jeremy Hylton's avatar
Jeremy Hylton committed
897
        self.emit('IMPORT_NAME', node.modname)
Jeremy Hylton's avatar
Jeremy Hylton committed
898
        for name, alias in node.names:
899 900 901 902 903 904 905 906 907 908 909
            if VERSION > 1:
                if name == '*':
                    self.namespace = 0
                    self.emit('IMPORT_STAR')
                    # There can only be one name w/ from ... import *
                    assert len(node.names) == 1
                    return
                else:
                    self.emit('IMPORT_FROM', name)
                    self._resolveDots(name)
                    self.storeName(alias or name)
910 911
            else:
                self.emit('IMPORT_FROM', name)
Jeremy Hylton's avatar
Jeremy Hylton committed
912 913
        self.emit('POP_TOP')

Jeremy Hylton's avatar
Jeremy Hylton committed
914
    def _resolveDots(self, name):
915
        elts = name.split(".")
Jeremy Hylton's avatar
Jeremy Hylton committed
916 917 918 919 920
        if len(elts) == 1:
            return
        for elt in elts[1:]:
            self.emit('LOAD_ATTR', elt)

Jeremy Hylton's avatar
Jeremy Hylton committed
921
    def visitGetattr(self, node):
Jeremy Hylton's avatar
Jeremy Hylton committed
922
        self.visit(node.expr)
Jeremy Hylton's avatar
Jeremy Hylton committed
923
        self.emit('LOAD_ATTR', self.mangle(node.attrname))
Jeremy Hylton's avatar
Jeremy Hylton committed
924

Jeremy Hylton's avatar
Jeremy Hylton committed
925
    # next five implement assignments
926

927
    def visitAssign(self, node):
928
        self.set_lineno(node)
929
        self.visit(node.expr)
Jeremy Hylton's avatar
Jeremy Hylton committed
930
        dups = len(node.nodes) - 1
931
        for i in range(len(node.nodes)):
Jeremy Hylton's avatar
Jeremy Hylton committed
932 933 934
            elt = node.nodes[i]
            if i < dups:
                self.emit('DUP_TOP')
935 936 937 938
            if isinstance(elt, ast.Node):
                self.visit(elt)

    def visitAssName(self, node):
939 940 941
        if node.flags == 'OP_ASSIGN':
            self.storeName(node.name)
        elif node.flags == 'OP_DELETE':
Jeremy Hylton's avatar
Jeremy Hylton committed
942
            self.set_lineno(node)
943 944
            self.delName(node.name)
        else:
945 946
            print "oops", node.flags

Jeremy Hylton's avatar
Jeremy Hylton committed
947
    def visitAssAttr(self, node):
948 949
        self.visit(node.expr)
        if node.flags == 'OP_ASSIGN':
Jeremy Hylton's avatar
Jeremy Hylton committed
950
            self.emit('STORE_ATTR', self.mangle(node.attrname))
951
        elif node.flags == 'OP_DELETE':
Jeremy Hylton's avatar
Jeremy Hylton committed
952
            self.emit('DELETE_ATTR', self.mangle(node.attrname))
953
        else:
Jeremy Hylton's avatar
Jeremy Hylton committed
954 955 956
            print "warning: unexpected flags:", node.flags
            print node

957
    def _visitAssSequence(self, node, op='UNPACK_SEQUENCE'):
958
        if findOp(node) != 'OP_DELETE':
959
            self.emit(op, len(node.nodes))
Jeremy Hylton's avatar
Jeremy Hylton committed
960 961 962
        for child in node.nodes:
            self.visit(child)

963 964 965 966 967 968 969 970 971 972 973 974 975
    if VERSION > 1:
        visitAssTuple = _visitAssSequence
        visitAssList = _visitAssSequence
    else:
        def visitAssTuple(self, node):
            self._visitAssSequence(node, 'UNPACK_TUPLE')

        def visitAssList(self, node):
            self._visitAssSequence(node, 'UNPACK_LIST')

    # augmented assignment

    def visitAugAssign(self, node):
976
        self.set_lineno(node)
977 978 979 980 981 982 983 984 985 986 987
        aug_node = wrap_aug(node.node)
        self.visit(aug_node, "load")
        self.visit(node.expr)
        self.emit(self._augmented_opcode[node.op])
        self.visit(aug_node, "store")

    _augmented_opcode = {
        '+=' : 'INPLACE_ADD',
        '-=' : 'INPLACE_SUBTRACT',
        '*=' : 'INPLACE_MULTIPLY',
        '/=' : 'INPLACE_DIVIDE',
Jeremy Hylton's avatar
Jeremy Hylton committed
988
        '//=': 'INPLACE_FLOOR_DIVIDE',
989 990 991 992 993 994 995 996 997 998 999 1000 1001 1002 1003 1004 1005 1006 1007
        '%=' : 'INPLACE_MODULO',
        '**=': 'INPLACE_POWER',
        '>>=': 'INPLACE_RSHIFT',
        '<<=': 'INPLACE_LSHIFT',
        '&=' : 'INPLACE_AND',
        '^=' : 'INPLACE_XOR',
        '|=' : 'INPLACE_OR',
        }

    def visitAugName(self, node, mode):
        if mode == "load":
            self.loadName(node.name)
        elif mode == "store":
            self.storeName(node.name)

    def visitAugGetattr(self, node, mode):
        if mode == "load":
            self.visit(node.expr)
            self.emit('DUP_TOP')
Jeremy Hylton's avatar
Jeremy Hylton committed
1008
            self.emit('LOAD_ATTR', self.mangle(node.attrname))
1009 1010
        elif mode == "store":
            self.emit('ROT_TWO')
Jeremy Hylton's avatar
Jeremy Hylton committed
1011
            self.emit('STORE_ATTR', self.mangle(node.attrname))
1012 1013 1014

    def visitAugSlice(self, node, mode):
        if mode == "load":
Jeremy Hylton's avatar
Jeremy Hylton committed
1015
            self.visitSlice(node, 1)
1016 1017 1018 1019 1020 1021 1022 1023 1024 1025 1026 1027 1028 1029 1030 1031 1032 1033 1034 1035
        elif mode == "store":
            slice = 0
            if node.lower:
                slice = slice | 1
            if node.upper:
                slice = slice | 2
            if slice == 0:
                self.emit('ROT_TWO')
            elif slice == 3:
                self.emit('ROT_FOUR')
            else:
                self.emit('ROT_THREE')
            self.emit('STORE_SLICE+%d' % slice)

    def visitAugSubscript(self, node, mode):
        if mode == "load":
            self.visitSubscript(node, 1)
        elif mode == "store":
            self.emit('ROT_THREE')
            self.emit('STORE_SUBSCR')
Jeremy Hylton's avatar
Jeremy Hylton committed
1036

Jeremy Hylton's avatar
Jeremy Hylton committed
1037 1038 1039 1040 1041 1042 1043 1044 1045 1046 1047 1048 1049 1050 1051
    def visitExec(self, node):
        self.visit(node.expr)
        if node.locals is None:
            self.emit('LOAD_CONST', None)
        else:
            self.visit(node.locals)
        if node.globals is None:
            self.emit('DUP_TOP')
        else:
            self.visit(node.globals)
        self.emit('EXEC_STMT')

    def visitCallFunc(self, node):
        pos = 0
        kw = 0
1052
        self.set_lineno(node)
Jeremy Hylton's avatar
Jeremy Hylton committed
1053 1054 1055 1056 1057 1058 1059
        self.visit(node.node)
        for arg in node.args:
            self.visit(arg)
            if isinstance(arg, ast.Keyword):
                kw = kw + 1
            else:
                pos = pos + 1
1060 1061 1062 1063 1064 1065 1066 1067
        if node.star_args is not None:
            self.visit(node.star_args)
        if node.dstar_args is not None:
            self.visit(node.dstar_args)
        have_star = node.star_args is not None
        have_dstar = node.dstar_args is not None
        opcode = callfunc_opcode_info[have_star, have_dstar]
        self.emit(opcode, kw << 8 | pos)
Jeremy Hylton's avatar
Jeremy Hylton committed
1068

1069
    def visitPrint(self, node, newline=0):
1070
        self.set_lineno(node)
1071 1072
        if node.dest:
            self.visit(node.dest)
Jeremy Hylton's avatar
Jeremy Hylton committed
1073
        for child in node.nodes:
1074 1075
            if node.dest:
                self.emit('DUP_TOP')
Jeremy Hylton's avatar
Jeremy Hylton committed
1076
            self.visit(child)
1077 1078 1079 1080 1081
            if node.dest:
                self.emit('ROT_TWO')
                self.emit('PRINT_ITEM_TO')
            else:
                self.emit('PRINT_ITEM')
1082 1083
        if node.dest and not newline:
            self.emit('POP_TOP')
Jeremy Hylton's avatar
Jeremy Hylton committed
1084 1085

    def visitPrintnl(self, node):
1086
        self.visitPrint(node, newline=1)
1087 1088 1089 1090
        if node.dest:
            self.emit('PRINT_NEWLINE_TO')
        else:
            self.emit('PRINT_NEWLINE')
Jeremy Hylton's avatar
Jeremy Hylton committed
1091 1092

    def visitReturn(self, node):
1093
        self.set_lineno(node)
Jeremy Hylton's avatar
Jeremy Hylton committed
1094 1095 1096
        self.visit(node.value)
        self.emit('RETURN_VALUE')

1097 1098 1099
    def visitYield(self, node):
        self.set_lineno(node)
        self.visit(node.value)
1100
        self.emit('YIELD_VALUE')
1101

Jeremy Hylton's avatar
Jeremy Hylton committed
1102 1103
    # slice and subscript stuff

1104 1105
    def visitSlice(self, node, aug_flag=None):
        # aug_flag is used by visitAugSlice
Jeremy Hylton's avatar
Jeremy Hylton committed
1106 1107 1108 1109 1110 1111 1112 1113
        self.visit(node.expr)
        slice = 0
        if node.lower:
            self.visit(node.lower)
            slice = slice | 1
        if node.upper:
            self.visit(node.upper)
            slice = slice | 2
1114 1115 1116 1117 1118 1119 1120
        if aug_flag:
            if slice == 0:
                self.emit('DUP_TOP')
            elif slice == 3:
                self.emit('DUP_TOPX', 3)
            else:
                self.emit('DUP_TOPX', 2)
Jeremy Hylton's avatar
Jeremy Hylton committed
1121 1122 1123 1124 1125 1126 1127 1128 1129 1130
        if node.flags == 'OP_APPLY':
            self.emit('SLICE+%d' % slice)
        elif node.flags == 'OP_ASSIGN':
            self.emit('STORE_SLICE+%d' % slice)
        elif node.flags == 'OP_DELETE':
            self.emit('DELETE_SLICE+%d' % slice)
        else:
            print "weird slice", node.flags
            raise

1131
    def visitSubscript(self, node, aug_flag=None):
Jeremy Hylton's avatar
Jeremy Hylton committed
1132 1133 1134 1135 1136
        self.visit(node.expr)
        for sub in node.subs:
            self.visit(sub)
        if len(node.subs) > 1:
            self.emit('BUILD_TUPLE', len(node.subs))
1137 1138
        if aug_flag:
            self.emit('DUP_TOPX', 2)
Jeremy Hylton's avatar
Jeremy Hylton committed
1139 1140 1141 1142 1143 1144 1145
        if node.flags == 'OP_APPLY':
            self.emit('BINARY_SUBSCR')
        elif node.flags == 'OP_ASSIGN':
            self.emit('STORE_SUBSCR')
        elif node.flags == 'OP_DELETE':
            self.emit('DELETE_SUBSCR')

1146 1147
    # binary ops

1148
    def binaryOp(self, node, op):
Jeremy Hylton's avatar
Jeremy Hylton committed
1149 1150 1151
        self.visit(node.left)
        self.visit(node.right)
        self.emit(op)
1152 1153

    def visitAdd(self, node):
Jeremy Hylton's avatar
Jeremy Hylton committed
1154
        return self.binaryOp(node, 'BINARY_ADD')
1155 1156

    def visitSub(self, node):
Jeremy Hylton's avatar
Jeremy Hylton committed
1157
        return self.binaryOp(node, 'BINARY_SUBTRACT')
1158 1159

    def visitMul(self, node):
Jeremy Hylton's avatar
Jeremy Hylton committed
1160
        return self.binaryOp(node, 'BINARY_MULTIPLY')
1161 1162

    def visitDiv(self, node):
Jeremy Hylton's avatar
Jeremy Hylton committed
1163
        return self.binaryOp(node, self._div_op)
1164

Jeremy Hylton's avatar
Jeremy Hylton committed
1165 1166 1167
    def visitFloorDiv(self, node):
        return self.binaryOp(node, 'BINARY_FLOOR_DIVIDE')

Jeremy Hylton's avatar
Jeremy Hylton committed
1168
    def visitMod(self, node):
Jeremy Hylton's avatar
Jeremy Hylton committed
1169
        return self.binaryOp(node, 'BINARY_MODULO')
Jeremy Hylton's avatar
Jeremy Hylton committed
1170

1171
    def visitPower(self, node):
Jeremy Hylton's avatar
Jeremy Hylton committed
1172
        return self.binaryOp(node, 'BINARY_POWER')
1173 1174

    def visitLeftShift(self, node):
Jeremy Hylton's avatar
Jeremy Hylton committed
1175
        return self.binaryOp(node, 'BINARY_LSHIFT')
1176 1177

    def visitRightShift(self, node):
Jeremy Hylton's avatar
Jeremy Hylton committed
1178
        return self.binaryOp(node, 'BINARY_RSHIFT')
1179

1180 1181 1182 1183 1184 1185
    # unary ops

    def unaryOp(self, node, op):
        self.visit(node.expr)
        self.emit(op)

1186 1187 1188
    def visitInvert(self, node):
        return self.unaryOp(node, 'UNARY_INVERT')

1189 1190 1191 1192 1193 1194 1195 1196 1197
    def visitUnarySub(self, node):
        return self.unaryOp(node, 'UNARY_NEGATIVE')

    def visitUnaryAdd(self, node):
        return self.unaryOp(node, 'UNARY_POSITIVE')

    def visitUnaryInvert(self, node):
        return self.unaryOp(node, 'UNARY_INVERT')

Jeremy Hylton's avatar
Jeremy Hylton committed
1198 1199 1200
    def visitNot(self, node):
        return self.unaryOp(node, 'UNARY_NOT')

1201 1202 1203
    def visitBackquote(self, node):
        return self.unaryOp(node, 'UNARY_CONVERT')

1204 1205
    # bit ops

1206
    def bitOp(self, nodes, op):
Jeremy Hylton's avatar
Jeremy Hylton committed
1207 1208 1209 1210
        self.visit(nodes[0])
        for node in nodes[1:]:
            self.visit(node)
            self.emit(op)
1211 1212

    def visitBitand(self, node):
Jeremy Hylton's avatar
Jeremy Hylton committed
1213
        return self.bitOp(node.nodes, 'BINARY_AND')
1214 1215

    def visitBitor(self, node):
Jeremy Hylton's avatar
Jeremy Hylton committed
1216
        return self.bitOp(node.nodes, 'BINARY_OR')
1217 1218

    def visitBitxor(self, node):
Jeremy Hylton's avatar
Jeremy Hylton committed
1219
        return self.bitOp(node.nodes, 'BINARY_XOR')
1220

Jeremy Hylton's avatar
Jeremy Hylton committed
1221
    # object constructors
1222

1223
    def visitEllipsis(self, node):
Jeremy Hylton's avatar
Jeremy Hylton committed
1224
        self.emit('LOAD_CONST', Ellipsis)
1225

1226
    def visitTuple(self, node):
1227
        self.set_lineno(node)
1228 1229
        for elt in node.nodes:
            self.visit(elt)
1230
        self.emit('BUILD_TUPLE', len(node.nodes))
1231

Jeremy Hylton's avatar
Jeremy Hylton committed
1232
    def visitList(self, node):
1233
        self.set_lineno(node)
Jeremy Hylton's avatar
Jeremy Hylton committed
1234 1235
        for elt in node.nodes:
            self.visit(elt)
1236
        self.emit('BUILD_LIST', len(node.nodes))
Jeremy Hylton's avatar
Jeremy Hylton committed
1237 1238 1239 1240 1241

    def visitSliceobj(self, node):
        for child in node.nodes:
            self.visit(child)
        self.emit('BUILD_SLICE', len(node.nodes))
Jeremy Hylton's avatar
Jeremy Hylton committed
1242

1243
    def visitDict(self, node):
1244
        self.set_lineno(node)
Jeremy Hylton's avatar
Jeremy Hylton committed
1245 1246 1247 1248
        self.emit('BUILD_MAP', 0)
        for k, v in node.items:
            self.emit('DUP_TOP')
            self.visit(k)
Gustavo Niemeyer's avatar
Gustavo Niemeyer committed
1249 1250
            self.visit(v)
            self.emit('ROT_THREE')
Jeremy Hylton's avatar
Jeremy Hylton committed
1251
            self.emit('STORE_SUBSCR')
1252

1253 1254 1255 1256
class NestedScopeMixin:
    """Defines initClass() for nested scoping (Python 2.2-compatible)"""
    def initClass(self):
        self.__class__.NameFinder = LocalNameFinder
1257 1258
        self.__class__.FunctionGen = FunctionCodeGenerator
        self.__class__.ClassGen = ClassCodeGenerator
1259

1260
class ModuleCodeGenerator(NestedScopeMixin, CodeGenerator):
1261 1262 1263
    __super_init = CodeGenerator.__init__

    scopes = None
Tim Peters's avatar
Tim Peters committed
1264

1265 1266
    def __init__(self, tree):
        self.graph = pyassem.PyFlowGraph("<module>", tree.filename)
1267
        self.futures = future.find_futures(tree)
1268
        self.__super_init()
1269
        walk(tree, self)
1270

1271 1272
    def get_module(self):
        return self
Jeremy Hylton's avatar
Jeremy Hylton committed
1273

Jeremy Hylton's avatar
Jeremy Hylton committed
1274 1275 1276 1277 1278
class ExpressionCodeGenerator(NestedScopeMixin, CodeGenerator):
    __super_init = CodeGenerator.__init__

    scopes = None
    futures = ()
Tim Peters's avatar
Tim Peters committed
1279

Jeremy Hylton's avatar
Jeremy Hylton committed
1280 1281 1282 1283 1284 1285 1286 1287 1288 1289 1290 1291 1292 1293
    def __init__(self, tree):
        self.graph = pyassem.PyFlowGraph("<expression>", tree.filename)
        self.__super_init()
        walk(tree, self)

    def get_module(self):
        return self

class InteractiveCodeGenerator(NestedScopeMixin, CodeGenerator):

    __super_init = CodeGenerator.__init__

    scopes = None
    futures = ()
Tim Peters's avatar
Tim Peters committed
1294

Jeremy Hylton's avatar
Jeremy Hylton committed
1295 1296 1297 1298 1299 1300 1301 1302 1303
    def __init__(self, tree):
        self.graph = pyassem.PyFlowGraph("<interactive>", tree.filename)
        self.__super_init()
        self.set_lineno(tree)
        walk(tree, self)
        self.emit('RETURN_VALUE')

    def get_module(self):
        return self
Tim Peters's avatar
Tim Peters committed
1304

Jeremy Hylton's avatar
Jeremy Hylton committed
1305 1306 1307 1308 1309 1310
    def visitDiscard(self, node):
        # XXX Discard means it's an expression.  Perhaps this is a bad
        # name.
        self.visit(node.expr)
        self.emit('PRINT_EXPR')

1311
class AbstractFunctionCode:
Jeremy Hylton's avatar
Jeremy Hylton committed
1312 1313 1314
    optimized = 1
    lambdaCount = 0

1315
    def __init__(self, func, scopes, isLambda, class_name, mod):
Jeremy Hylton's avatar
Jeremy Hylton committed
1316
        self.class_name = class_name
1317
        self.module = mod
Jeremy Hylton's avatar
Jeremy Hylton committed
1318 1319 1320 1321 1322 1323
        if isLambda:
            klass = FunctionCodeGenerator
            name = "<lambda.%d>" % klass.lambdaCount
            klass.lambdaCount = klass.lambdaCount + 1
        else:
            name = func.name
1324

1325
        args, hasTupleArg = generateArgList(func.argnames)
Tim Peters's avatar
Tim Peters committed
1326 1327
        self.graph = pyassem.PyFlowGraph(name, func.filename, args,
                                         optimized=1)
1328
        self.isLambda = isLambda
1329
        self.super_init()
1330

Jeremy Hylton's avatar
Jeremy Hylton committed
1331 1332 1333
        if not isLambda and func.doc:
            self.setDocstring(func.doc)

1334
        lnf = walk(func.code, self.NameFinder(args), verbose=0)
Jeremy Hylton's avatar
Jeremy Hylton committed
1335
        self.locals.push(lnf.getLocals())
1336 1337 1338 1339
        if func.varargs:
            self.graph.setFlag(CO_VARARGS)
        if func.kwargs:
            self.graph.setFlag(CO_VARKEYWORDS)
1340
        self.set_lineno(func)
Jeremy Hylton's avatar
Jeremy Hylton committed
1341 1342
        if hasTupleArg:
            self.generateArgUnpack(func.argnames)
1343

1344 1345 1346
    def get_module(self):
        return self.module

Jeremy Hylton's avatar
Jeremy Hylton committed
1347
    def finish(self):
1348 1349 1350 1351
        self.graph.startExitBlock()
        if not self.isLambda:
            self.emit('LOAD_CONST', None)
        self.emit('RETURN_VALUE')
1352

Jeremy Hylton's avatar
Jeremy Hylton committed
1353
    def generateArgUnpack(self, args):
1354 1355
        for i in range(len(args)):
            arg = args[i]
1356
            if isinstance(arg, tuple):
1357
                self.emit('LOAD_FAST', '.%d' % (i * 2))
1358
                self.unpackSequence(arg)
Tim Peters's avatar
Tim Peters committed
1359

1360
    def unpackSequence(self, tup):
1361 1362 1363 1364
        if VERSION > 1:
            self.emit('UNPACK_SEQUENCE', len(tup))
        else:
            self.emit('UNPACK_TUPLE', len(tup))
Jeremy Hylton's avatar
Jeremy Hylton committed
1365
        for elt in tup:
1366
            if isinstance(elt, tuple):
1367
                self.unpackSequence(elt)
Jeremy Hylton's avatar
Jeremy Hylton committed
1368
            else:
1369
                self._nameOp('STORE', elt)
1370

1371 1372
    unpackTuple = unpackSequence

1373
class FunctionCodeGenerator(NestedScopeMixin, AbstractFunctionCode,
Tim Peters's avatar
Tim Peters committed
1374
                            CodeGenerator):
1375 1376 1377 1378 1379
    super_init = CodeGenerator.__init__ # call be other init
    scopes = None

    __super_init = AbstractFunctionCode.__init__

1380
    def __init__(self, func, scopes, isLambda, class_name, mod):
1381 1382
        self.scopes = scopes
        self.scope = scopes[func]
1383
        self.__super_init(func, scopes, isLambda, class_name, mod)
1384 1385
        self.graph.setFreeVars(self.scope.get_free_vars())
        self.graph.setCellVars(self.scope.get_cell_vars())
1386 1387
        if self.scope.generator is not None:
            self.graph.setFlag(CO_GENERATOR)
1388

1389 1390 1391 1392 1393 1394 1395 1396 1397 1398 1399 1400 1401 1402 1403
class GenExprCodeGenerator(NestedScopeMixin, AbstractFunctionCode,
                           CodeGenerator):
    super_init = CodeGenerator.__init__ # call be other init
    scopes = None

    __super_init = AbstractFunctionCode.__init__

    def __init__(self, gexp, scopes, class_name, mod):
        self.scopes = scopes
        self.scope = scopes[gexp]
        self.__super_init(gexp, scopes, 1, class_name, mod)
        self.graph.setFreeVars(self.scope.get_free_vars())
        self.graph.setCellVars(self.scope.get_cell_vars())
        self.graph.setFlag(CO_GENERATOR)

1404
class AbstractClassCode:
Jeremy Hylton's avatar
Jeremy Hylton committed
1405

1406
    def __init__(self, klass, scopes, module):
Jeremy Hylton's avatar
Jeremy Hylton committed
1407
        self.class_name = klass.name
1408
        self.module = module
1409
        self.graph = pyassem.PyFlowGraph(klass.name, klass.filename,
Jeremy Hylton's avatar
Jeremy Hylton committed
1410
                                           optimized=0, klass=1)
1411
        self.super_init()
1412
        lnf = walk(klass.code, self.NameFinder(), verbose=0)
Jeremy Hylton's avatar
Jeremy Hylton committed
1413
        self.locals.push(lnf.getLocals())
1414
        self.graph.setFlag(CO_NEWLOCALS)
Jeremy Hylton's avatar
Jeremy Hylton committed
1415 1416
        if klass.doc:
            self.setDocstring(klass.doc)
Jeremy Hylton's avatar
Jeremy Hylton committed
1417

1418 1419
    def get_module(self):
        return self.module
1420

Jeremy Hylton's avatar
Jeremy Hylton committed
1421
    def finish(self):
1422
        self.graph.startExitBlock()
Jeremy Hylton's avatar
Jeremy Hylton committed
1423
        self.emit('LOAD_LOCALS')
1424
        self.emit('RETURN_VALUE')
Jeremy Hylton's avatar
Jeremy Hylton committed
1425

1426
class ClassCodeGenerator(NestedScopeMixin, AbstractClassCode, CodeGenerator):
1427 1428 1429 1430 1431
    super_init = CodeGenerator.__init__
    scopes = None

    __super_init = AbstractClassCode.__init__

1432
    def __init__(self, klass, scopes, module):
1433 1434
        self.scopes = scopes
        self.scope = scopes[klass]
1435
        self.__super_init(klass, scopes, module)
1436 1437
        self.graph.setFreeVars(self.scope.get_free_vars())
        self.graph.setCellVars(self.scope.get_cell_vars())
1438 1439 1440 1441 1442 1443
        self.set_lineno(klass)
        self.emit("LOAD_GLOBAL", "__name__")
        self.storeName("__module__")
        if klass.doc:
            self.emit("LOAD_CONST", klass.doc)
            self.storeName('__doc__')
1444

Jeremy Hylton's avatar
Jeremy Hylton committed
1445 1446 1447 1448 1449
def generateArgList(arglist):
    """Generate an arg list marking TupleArgs"""
    args = []
    extra = []
    count = 0
1450 1451
    for i in range(len(arglist)):
        elt = arglist[i]
1452
        if isinstance(elt, str):
1453
            args.append(elt)
1454
        elif isinstance(elt, tuple):
1455
            args.append(TupleArg(i * 2, elt))
1456
            extra.extend(misc.flatten(elt))
1457
            count = count + 1
1458 1459
        else:
            raise ValueError, "unexpect argument type:", elt
Jeremy Hylton's avatar
Jeremy Hylton committed
1460
    return args + extra, count
1461

Jeremy Hylton's avatar
Jeremy Hylton committed
1462 1463 1464
def findOp(node):
    """Find the op (DELETE, LOAD, STORE) in an AssTuple tree"""
    v = OpFinder()
1465
    walk(node, v, verbose=0)
Jeremy Hylton's avatar
Jeremy Hylton committed
1466 1467
    return v.op

1468 1469 1470 1471 1472 1473 1474 1475
class OpFinder:
    def __init__(self):
        self.op = None
    def visitAssName(self, node):
        if self.op is None:
            self.op = node.flags
        elif self.op != node.flags:
            raise ValueError, "mixed ops in stmt"
1476
    visitAssAttr = visitAssName
1477
    visitSubscript = visitAssName
1478

1479 1480 1481 1482 1483 1484 1485 1486 1487 1488 1489 1490 1491 1492 1493 1494 1495 1496 1497 1498 1499 1500 1501 1502 1503 1504 1505 1506 1507 1508 1509 1510 1511 1512 1513 1514 1515 1516 1517
class Delegator:
    """Base class to support delegation for augmented assignment nodes

    To generator code for augmented assignments, we use the following
    wrapper classes.  In visitAugAssign, the left-hand expression node
    is visited twice.  The first time the visit uses the normal method
    for that node .  The second time the visit uses a different method
    that generates the appropriate code to perform the assignment.
    These delegator classes wrap the original AST nodes in order to
    support the variant visit methods.
    """
    def __init__(self, obj):
        self.obj = obj

    def __getattr__(self, attr):
        return getattr(self.obj, attr)

class AugGetattr(Delegator):
    pass

class AugName(Delegator):
    pass

class AugSlice(Delegator):
    pass

class AugSubscript(Delegator):
    pass

wrapper = {
    ast.Getattr: AugGetattr,
    ast.Name: AugName,
    ast.Slice: AugSlice,
    ast.Subscript: AugSubscript,
    }

def wrap_aug(node):
    return wrapper[node.__class__](node)

Jeremy Hylton's avatar
Jeremy Hylton committed
1518 1519
if __name__ == "__main__":
    for file in sys.argv[1:]:
1520
        compileFile(file)