summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--Lib/compiler/pyassem.py258
-rw-r--r--Lib/compiler/pycodegen.py395
-rw-r--r--Lib/compiler/visitor.py44
-rw-r--r--Tools/compiler/compiler/pyassem.py258
-rw-r--r--Tools/compiler/compiler/pycodegen.py395
-rw-r--r--Tools/compiler/compiler/visitor.py44
6 files changed, 698 insertions, 696 deletions
diff --git a/Lib/compiler/pyassem.py b/Lib/compiler/pyassem.py
index 6e07987..c8d9e90 100644
--- a/Lib/compiler/pyassem.py
+++ b/Lib/compiler/pyassem.py
@@ -9,71 +9,71 @@ from compiler import misc
class FlowGraph:
def __init__(self):
- self.current = self.entry = Block()
- self.exit = Block("exit")
- self.blocks = misc.Set()
- self.blocks.add(self.entry)
- self.blocks.add(self.exit)
+ self.current = self.entry = Block()
+ self.exit = Block("exit")
+ self.blocks = misc.Set()
+ self.blocks.add(self.entry)
+ self.blocks.add(self.exit)
def startBlock(self, block):
- self.current = block
+ self.current = block
def nextBlock(self, block=None):
- if block is None:
- block = self.newBlock()
- # XXX think we need to specify when there is implicit transfer
- # from one block to the next
- #
- # I think this strategy works: each block has a child
- # designated as "next" which is returned as the last of the
- # children. because the nodes in a graph are emitted in
- # reverse post order, the "next" block will always be emitted
- # immediately after its parent.
- # Worry: maintaining this invariant could be tricky
- self.current.addNext(block)
- self.startBlock(block)
+ if block is None:
+ block = self.newBlock()
+ # XXX think we need to specify when there is implicit transfer
+ # from one block to the next
+ #
+ # I think this strategy works: each block has a child
+ # designated as "next" which is returned as the last of the
+ # children. because the nodes in a graph are emitted in
+ # reverse post order, the "next" block will always be emitted
+ # immediately after its parent.
+ # Worry: maintaining this invariant could be tricky
+ self.current.addNext(block)
+ self.startBlock(block)
def newBlock(self):
- b = Block()
- self.blocks.add(b)
- return b
+ b = Block()
+ self.blocks.add(b)
+ return b
def startExitBlock(self):
- self.startBlock(self.exit)
+ self.startBlock(self.exit)
def emit(self, *inst):
- # XXX should jump instructions implicitly call nextBlock?
- if inst[0] == 'RETURN_VALUE':
- self.current.addOutEdge(self.exit)
- self.current.emit(inst)
+ # XXX should jump instructions implicitly call nextBlock?
+ if inst[0] == 'RETURN_VALUE':
+ self.current.addOutEdge(self.exit)
+ self.current.emit(inst)
def getBlocks(self):
- """Return the blocks in reverse postorder
-
- i.e. each node appears before all of its successors
- """
- # XXX make sure every node that doesn't have an explicit next
- # is set so that next points to exit
- for b in self.blocks.elements():
- if b is self.exit:
- continue
- if not b.next:
- b.addNext(self.exit)
- order = dfs_postorder(self.entry, {})
- order.reverse()
- # hack alert
- if not self.exit in order:
- order.append(self.exit)
- return order
+ """Return the blocks in reverse postorder
+
+ i.e. each node appears before all of its successors
+ """
+ # XXX make sure every node that doesn't have an explicit next
+ # is set so that next points to exit
+ for b in self.blocks.elements():
+ if b is self.exit:
+ continue
+ if not b.next:
+ b.addNext(self.exit)
+ order = dfs_postorder(self.entry, {})
+ order.reverse()
+ # hack alert
+ if not self.exit in order:
+ order.append(self.exit)
+ return order
def dfs_postorder(b, seen):
"""Depth-first search of tree rooted at b, return in postorder"""
order = []
seen[b] = b
for c in b.children():
- if seen.has_key(c):
- continue
- order = order + dfs_postorder(c, seen)
+ if seen.has_key(c):
+ continue
+ order = order + dfs_postorder(c, seen)
order.append(b)
return order
@@ -81,47 +81,47 @@ class Block:
_count = 0
def __init__(self, label=''):
- self.insts = []
- self.inEdges = misc.Set()
- self.outEdges = misc.Set()
- self.label = label
- self.bid = Block._count
- self.next = []
- Block._count = Block._count + 1
+ self.insts = []
+ self.inEdges = misc.Set()
+ self.outEdges = misc.Set()
+ self.label = label
+ self.bid = Block._count
+ self.next = []
+ Block._count = Block._count + 1
def __repr__(self):
- if self.label:
- return "<block %s id=%d len=%d>" % (self.label, self.bid,
- len(self.insts))
- else:
- return "<block id=%d len=%d>" % (self.bid, len(self.insts))
+ if self.label:
+ return "<block %s id=%d len=%d>" % (self.label, self.bid,
+ len(self.insts))
+ else:
+ return "<block id=%d len=%d>" % (self.bid, len(self.insts))
def __str__(self):
- insts = map(str, self.insts)
- return "<block %s %d:\n%s>" % (self.label, self.bid,
- string.join(insts, '\n'))
+ insts = map(str, self.insts)
+ return "<block %s %d:\n%s>" % (self.label, self.bid,
+ string.join(insts, '\n'))
def emit(self, inst):
- op = inst[0]
- if op[:4] == 'JUMP':
- self.outEdges.add(inst[1])
- self.insts.append(inst)
+ op = inst[0]
+ if op[:4] == 'JUMP':
+ self.outEdges.add(inst[1])
+ self.insts.append(inst)
def getInstructions(self):
- return self.insts
+ return self.insts
def addInEdge(self, block):
- self.inEdges.add(block)
+ self.inEdges.add(block)
def addOutEdge(self, block):
- self.outEdges.add(block)
+ self.outEdges.add(block)
def addNext(self, block):
- self.next.append(block)
- assert len(self.next) == 1, map(str, self.next)
+ self.next.append(block)
+ assert len(self.next) == 1, map(str, self.next)
def children(self):
- return self.outEdges.elements() + self.next
+ return self.outEdges.elements() + self.next
# flags for code objects
CO_OPTIMIZED = 0x0001
@@ -139,18 +139,18 @@ class PyFlowGraph(FlowGraph):
super_init = FlowGraph.__init__
def __init__(self, name, filename, args=(), optimized=0):
- self.super_init()
- self.name = name
- self.filename = filename
- self.docstring = None
- self.args = args # XXX
- self.argcount = getArgCount(args)
- if optimized:
- self.flags = CO_OPTIMIZED | CO_NEWLOCALS
- else:
- self.flags = 0
- self.consts = []
- self.names = []
+ self.super_init()
+ self.name = name
+ self.filename = filename
+ self.docstring = None
+ self.args = args # XXX
+ self.argcount = getArgCount(args)
+ if optimized:
+ self.flags = CO_OPTIMIZED | CO_NEWLOCALS
+ else:
+ self.flags = 0
+ self.consts = []
+ self.names = []
self.varnames = list(args) or []
for i in range(len(self.varnames)):
var = self.varnames[i]
@@ -163,13 +163,13 @@ class PyFlowGraph(FlowGraph):
self.consts.insert(0, doc)
def setFlag(self, flag):
- self.flags = self.flags | flag
- if flag == CO_VARARGS:
- self.argcount = self.argcount - 1
+ self.flags = self.flags | flag
+ if flag == CO_VARARGS:
+ self.argcount = self.argcount - 1
def getCode(self):
- """Get a Python code object"""
- if self.stage == RAW:
+ """Get a Python code object"""
+ if self.stage == RAW:
self.flattenGraph()
if self.stage == FLAT:
self.convertArgs()
@@ -198,38 +198,38 @@ class PyFlowGraph(FlowGraph):
sys.stdout = save
def flattenGraph(self):
- """Arrange the blocks in order and resolve jumps"""
- assert self.stage == RAW
- self.insts = insts = []
- pc = 0
- begin = {}
- end = {}
- for b in self.getBlocks():
- begin[b] = pc
- for inst in b.getInstructions():
- insts.append(inst)
- if len(inst) == 1:
- pc = pc + 1
- else:
- # arg takes 2 bytes
- pc = pc + 3
- end[b] = pc
- pc = 0
- for i in range(len(insts)):
- inst = insts[i]
- if len(inst) == 1:
+ """Arrange the blocks in order and resolve jumps"""
+ assert self.stage == RAW
+ self.insts = insts = []
+ pc = 0
+ begin = {}
+ end = {}
+ for b in self.getBlocks():
+ begin[b] = pc
+ for inst in b.getInstructions():
+ insts.append(inst)
+ if len(inst) == 1:
+ pc = pc + 1
+ else:
+ # arg takes 2 bytes
+ pc = pc + 3
+ end[b] = pc
+ pc = 0
+ for i in range(len(insts)):
+ inst = insts[i]
+ if len(inst) == 1:
pc = pc + 1
else:
pc = pc + 3
- opname = inst[0]
- if self.hasjrel.has_elt(opname):
+ opname = inst[0]
+ if self.hasjrel.has_elt(opname):
oparg = inst[1]
offset = begin[oparg] - pc
insts[i] = opname, offset
elif self.hasjabs.has_elt(opname):
insts[i] = opname, begin[inst[1]]
- self.stacksize = findDepth(self.insts)
- self.stage = FLAT
+ self.stacksize = findDepth(self.insts)
+ self.stage = FLAT
hasjrel = misc.Set()
for i in dis.hasjrel:
@@ -292,7 +292,7 @@ class PyFlowGraph(FlowGraph):
_cmp = list(dis.cmp_op)
def _convert_COMPARE_OP(self, arg):
- return self._cmp.index(arg)
+ return self._cmp.index(arg)
# similarly for other opcodes...
@@ -314,12 +314,12 @@ class PyFlowGraph(FlowGraph):
if opname == "SET_LINENO":
lnotab.nextLine(oparg)
hi, lo = twobyte(oparg)
- try:
- lnotab.addCode(self.opnum[opname], lo, hi)
- except ValueError:
- print opname, oparg
- print self.opnum[opname], lo, hi
- raise
+ try:
+ lnotab.addCode(self.opnum[opname], lo, hi)
+ except ValueError:
+ print opname, oparg
+ print self.opnum[opname], lo, hi
+ raise
self.stage = DONE
opnum = {}
@@ -354,10 +354,10 @@ class PyFlowGraph(FlowGraph):
elt = elt.getCode()
l.append(elt)
return tuple(l)
-
+
def isJump(opname):
if opname[:4] == 'JUMP':
- return 1
+ return 1
class TupleArg:
"""Helper for marking func defs with nested tuples in arglist"""
@@ -372,10 +372,10 @@ class TupleArg:
def getArgCount(args):
argcount = len(args)
if args:
- for arg in args:
- if isinstance(arg, TupleArg):
- numNames = len(misc.flatten(arg.names))
- argcount = argcount - numNames
+ for arg in args:
+ if isinstance(arg, TupleArg):
+ numNames = len(misc.flatten(arg.names))
+ argcount = argcount - numNames
return argcount
def twobyte(val):
@@ -513,11 +513,9 @@ class StackDepthTracker:
]
# special cases:
- # UNPACK_TUPLE, UNPACK_LIST, BUILD_TUPLE,
+ # UNPACK_SEQUENCE, BUILD_TUPLE,
# BUILD_LIST, CALL_FUNCTION, MAKE_FUNCTION, BUILD_SLICE
- def UNPACK_TUPLE(self, count):
- return count
- def UNPACK_LIST(self, count):
+ def UNPACK_SEQUENCE(self, count):
return count
def BUILD_TUPLE(self, count):
return -count
diff --git a/Lib/compiler/pycodegen.py b/Lib/compiler/pycodegen.py
index b3223c1..9d9b982 100644
--- a/Lib/compiler/pycodegen.py
+++ b/Lib/compiler/pycodegen.py
@@ -7,7 +7,7 @@ from cStringIO import StringIO
from compiler import ast, parse, walk
from compiler import pyassem, misc
-from compiler.pyassem import CO_VARARGS, CO_VARKEYWORDS, TupleArg
+from compiler.pyassem import CO_VARARGS, CO_VARKEYWORDS, CO_NEWLOCALS, TupleArg
callfunc_opcode_info = {
# (Have *args, Have **args) : opcode
@@ -29,32 +29,32 @@ def compile(filename):
class Module:
def __init__(self, source, filename):
- self.filename = filename
- self.source = source
- self.code = None
+ self.filename = filename
+ self.source = source
+ self.code = None
def compile(self):
- ast = parse(self.source)
+ ast = parse(self.source)
root, filename = os.path.split(self.filename)
- gen = ModuleCodeGenerator(filename)
- walk(ast, gen, 1)
- self.code = gen.getCode()
+ gen = ModuleCodeGenerator(filename)
+ walk(ast, gen, 1)
+ self.code = gen.getCode()
def dump(self, f):
- f.write(self.getPycHeader())
- marshal.dump(self.code, f)
+ f.write(self.getPycHeader())
+ marshal.dump(self.code, f)
- MAGIC = (20121 | (ord('\r')<<16) | (ord('\n')<<24))
+ MAGIC = (50811 | (ord('\r')<<16) | (ord('\n')<<24))
def getPycHeader(self):
- # 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.
- magic = marshal.dumps(self.MAGIC)[1:]
- mtime = os.stat(self.filename)[stat.ST_MTIME]
- mtime = struct.pack('i', mtime)
- return magic + mtime
+ # 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.
+ magic = marshal.dumps(self.MAGIC)[1:]
+ mtime = os.stat(self.filename)[stat.ST_MTIME]
+ mtime = struct.pack('i', mtime)
+ return magic + mtime
class CodeGenerator:
@@ -63,24 +63,24 @@ class CodeGenerator:
def __init__(self, filename):
## Subclasses must define a constructor that intializes self.graph
## before calling this init function
-## self.graph = pyassem.PyFlowGraph()
- self.filename = filename
- self.locals = misc.Stack()
- self.loops = misc.Stack()
- self.curStack = 0
- self.maxStack = 0
- self._setupGraphDelegation()
+## self.graph = pyassem.PyFlowGraph()
+ self.filename = filename
+ self.locals = misc.Stack()
+ self.loops = misc.Stack()
+ self.curStack = 0
+ self.maxStack = 0
+ self._setupGraphDelegation()
def _setupGraphDelegation(self):
- 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
+ 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
def getCode(self):
- """Return a code object"""
- return self.graph.getCode()
+ """Return a code object"""
+ return self.graph.getCode()
# Next five methods handle name access
@@ -97,11 +97,11 @@ class CodeGenerator:
self._nameOp('DELETE', name)
def _nameOp(self, prefix, name):
- if not self.optimized:
- self.emit(prefix + '_NAME', name)
- return
+ if not self.optimized:
+ self.emit(prefix + '_NAME', name)
+ return
if self.isLocalName(name):
- self.emit(prefix + '_FAST', name)
+ self.emit(prefix + '_FAST', name)
else:
self.emit(prefix + '_GLOBAL', name)
@@ -125,25 +125,25 @@ class CodeGenerator:
# code objects
def visitModule(self, node):
- lnf = walk(node.node, LocalNameFinder(), 0)
- self.locals.push(lnf.getLocals())
- self.setDocstring(node.doc)
- self.visit(node.node)
- self.emit('LOAD_CONST', None)
- self.emit('RETURN_VALUE')
+ lnf = walk(node.node, LocalNameFinder(), 0)
+ self.locals.push(lnf.getLocals())
+ self.setDocstring(node.doc)
+ self.visit(node.node)
+ self.emit('LOAD_CONST', None)
+ self.emit('RETURN_VALUE')
def visitFunction(self, node):
- self._visitFuncOrLambda(node, isLambda=0)
- self.storeName(node.name)
+ self._visitFuncOrLambda(node, isLambda=0)
+ self.storeName(node.name)
def visitLambda(self, node):
- self._visitFuncOrLambda(node, isLambda=1)
-## self.storeName("<lambda>")
+ self._visitFuncOrLambda(node, isLambda=1)
+## self.storeName("<lambda>")
def _visitFuncOrLambda(self, node, isLambda):
- gen = FunctionCodeGenerator(node, self.filename, isLambda)
- walk(node.code, gen)
- gen.finish()
+ gen = FunctionCodeGenerator(node, self.filename, isLambda)
+ walk(node.code, gen)
+ gen.finish()
self.set_lineno(node)
for default in node.defaults:
self.visit(default)
@@ -170,158 +170,158 @@ class CodeGenerator:
# The next few implement control-flow statements
def visitIf(self, node):
- end = self.newBlock()
- numtests = len(node.tests)
- for i in range(numtests):
- test, suite = node.tests[i]
+ end = self.newBlock()
+ numtests = len(node.tests)
+ for i in range(numtests):
+ test, suite = node.tests[i]
self.set_lineno(test)
- self.visit(test)
-## if i == numtests - 1 and not node.else_:
-## nextTest = end
-## else:
-## nextTest = self.newBlock()
- nextTest = self.newBlock()
- self.emit('JUMP_IF_FALSE', nextTest)
- self.nextBlock()
- self.emit('POP_TOP')
- self.visit(suite)
- self.emit('JUMP_FORWARD', end)
- self.nextBlock(nextTest)
- self.emit('POP_TOP')
- if node.else_:
- self.visit(node.else_)
- self.nextBlock(end)
+ self.visit(test)
+## if i == numtests - 1 and not node.else_:
+## nextTest = end
+## else:
+## nextTest = self.newBlock()
+ nextTest = self.newBlock()
+ self.emit('JUMP_IF_FALSE', nextTest)
+ self.nextBlock()
+ self.emit('POP_TOP')
+ self.visit(suite)
+ self.emit('JUMP_FORWARD', end)
+ self.nextBlock(nextTest)
+ self.emit('POP_TOP')
+ if node.else_:
+ self.visit(node.else_)
+ self.nextBlock(end)
def visitWhile(self, node):
self.set_lineno(node)
- loop = self.newBlock()
- else_ = self.newBlock()
+ loop = self.newBlock()
+ else_ = self.newBlock()
- after = self.newBlock()
- self.emit('SETUP_LOOP', after)
+ after = self.newBlock()
+ self.emit('SETUP_LOOP', after)
- self.nextBlock(loop)
- self.loops.push(loop)
+ self.nextBlock(loop)
+ self.loops.push(loop)
self.set_lineno(node)
- 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')
- if node.else_:
- self.visit(node.else_)
- self.loops.pop()
- self.nextBlock(after)
+ 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')
+ if node.else_:
+ self.visit(node.else_)
+ self.loops.pop()
+ self.nextBlock(after)
def visitFor(self, node):
- start = self.newBlock()
+ start = self.newBlock()
anchor = self.newBlock()
- after = self.newBlock()
+ after = self.newBlock()
self.loops.push(start)
self.set_lineno(node)
- self.emit('SETUP_LOOP', after)
+ self.emit('SETUP_LOOP', after)
self.visit(node.list)
self.visit(ast.Const(0))
- self.nextBlock(start)
+ self.nextBlock(start)
self.set_lineno(node)
self.emit('FOR_LOOP', anchor)
self.visit(node.assign)
self.visit(node.body)
self.emit('JUMP_ABSOLUTE', start)
- self.nextBlock(anchor)
+ self.nextBlock(anchor)
self.emit('POP_BLOCK')
if node.else_:
self.visit(node.else_)
- self.loops.pop()
- self.nextBlock(after)
+ self.loops.pop()
+ self.nextBlock(after)
def visitBreak(self, node):
- if not self.loops:
- raise SyntaxError, "'break' outside loop (%s, %d)" % \
- (self.filename, node.lineno)
+ if not self.loops:
+ raise SyntaxError, "'break' outside loop (%s, %d)" % \
+ (self.filename, node.lineno)
self.set_lineno(node)
- self.emit('BREAK_LOOP')
+ self.emit('BREAK_LOOP')
def visitContinue(self, node):
if not self.loops:
raise SyntaxError, "'continue' outside loop (%s, %d)" % \
- (self.filename, node.lineno)
+ (self.filename, node.lineno)
l = self.loops.top()
self.set_lineno(node)
self.emit('JUMP_ABSOLUTE', l)
- self.nextBlock()
+ self.nextBlock()
def visitTest(self, node, jump):
- end = self.newBlock()
+ end = self.newBlock()
for child in node.nodes[:-1]:
self.visit(child)
self.emit(jump, end)
- self.nextBlock()
+ self.nextBlock()
self.emit('POP_TOP')
self.visit(node.nodes[-1])
- self.nextBlock(end)
+ self.nextBlock(end)
def visitAnd(self, node):
- self.visitTest(node, 'JUMP_IF_FALSE')
+ self.visitTest(node, 'JUMP_IF_FALSE')
def visitOr(self, node):
- self.visitTest(node, 'JUMP_IF_TRUE')
+ self.visitTest(node, 'JUMP_IF_TRUE')
def visitCompare(self, node):
- 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)
- self.nextBlock(cleanup)
- self.emit('ROT_TWO')
- self.emit('POP_TOP')
- self.nextBlock(end)
+ 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)
+ self.nextBlock(cleanup)
+ self.emit('ROT_TWO')
+ self.emit('POP_TOP')
+ self.nextBlock(end)
# exception related
def visitAssert(self, node):
- # XXX would be interesting to implement this via a
- # transformation of the AST before this stage
- end = self.newBlock()
+ # XXX would be interesting to implement this via a
+ # transformation of the AST before this stage
+ end = self.newBlock()
self.set_lineno(node)
# XXX __debug__ and AssertionError appear to be special cases
# -- they are always loaded as globals even if there are local
# names. I guess this is a sort of renaming op.
- self.emit('LOAD_GLOBAL', '__debug__')
- self.emit('JUMP_IF_FALSE', end)
- self.nextBlock()
- self.emit('POP_TOP')
- self.visit(node.test)
- self.emit('JUMP_IF_TRUE', end)
- self.nextBlock()
- self.emit('LOAD_GLOBAL', 'AssertionError')
- self.visit(node.fail)
- self.emit('RAISE_VARARGS', 2)
- self.nextBlock(end)
- self.emit('POP_TOP')
+ self.emit('LOAD_GLOBAL', '__debug__')
+ self.emit('JUMP_IF_FALSE', end)
+ self.nextBlock()
+ self.emit('POP_TOP')
+ self.visit(node.test)
+ self.emit('JUMP_IF_TRUE', end)
+ self.nextBlock()
+ self.emit('LOAD_GLOBAL', 'AssertionError')
+ self.visit(node.fail)
+ self.emit('RAISE_VARARGS', 2)
+ self.nextBlock(end)
+ self.emit('POP_TOP')
def visitRaise(self, node):
self.set_lineno(node)
@@ -349,7 +349,7 @@ class CodeGenerator:
self.visit(node.body)
self.emit('POP_BLOCK')
self.emit('JUMP_FORWARD', lElse)
- self.nextBlock(handlers)
+ self.nextBlock(handlers)
last = len(node.handlers) - 1
for i in range(len(node.handlers)):
@@ -361,7 +361,7 @@ class CodeGenerator:
self.emit('COMPARE_OP', 'exception match')
next = self.newBlock()
self.emit('JUMP_IF_FALSE', next)
- self.nextBlock()
+ self.nextBlock()
self.emit('POP_TOP')
self.emit('POP_TOP')
if target:
@@ -372,13 +372,13 @@ class CodeGenerator:
self.visit(body)
self.emit('JUMP_FORWARD', end)
if expr:
- self.nextBlock(next)
+ self.nextBlock(next)
self.emit('POP_TOP')
self.emit('END_FINALLY')
if node.else_:
- self.nextBlock(lElse)
+ self.nextBlock(lElse)
self.visit(node.else_)
- self.nextBlock(end)
+ self.nextBlock(end)
def visitTryFinally(self, node):
final = self.newBlock()
@@ -387,15 +387,15 @@ class CodeGenerator:
self.visit(node.body)
self.emit('POP_BLOCK')
self.emit('LOAD_CONST', None)
- self.nextBlock(final)
+ self.nextBlock(final)
self.visit(node.final)
self.emit('END_FINALLY')
# misc
## def visitStmt(self, node):
-## # nothing to do except walk the children
-## pass
+## # nothing to do except walk the children
+## pass
def visitDiscard(self, node):
self.visit(node.expr)
@@ -405,12 +405,12 @@ class CodeGenerator:
self.emit('LOAD_CONST', node.value)
def visitKeyword(self, node):
- self.emit('LOAD_CONST', node.name)
- self.visit(node.expr)
+ self.emit('LOAD_CONST', node.name)
+ self.visit(node.expr)
def visitGlobal(self, node):
# no code to generate
- pass
+ pass
def visitName(self, node):
self.loadName(node.name)
@@ -470,7 +470,7 @@ class CodeGenerator:
def visitAssTuple(self, node):
if findOp(node) != 'OP_DELETE':
- self.emit('UNPACK_TUPLE', len(node.nodes))
+ self.emit('UNPACK_SEQUENCE', len(node.nodes))
for child in node.nodes:
self.visit(child)
@@ -655,10 +655,10 @@ class CodeGenerator:
set.emit('SET_LINENO', lineno)
self.emit('BUILD_MAP', 0)
for k, v in node.items:
- lineno2 = getattr(node, 'lineno', None)
+ lineno2 = getattr(node, 'lineno', None)
if lineno2 is not None and lineno != lineno2:
- self.emit('SET_LINENO', lineno2)
- lineno = lineno2
+ self.emit('SET_LINENO', lineno2)
+ lineno = lineno2
self.emit('DUP_TOP')
self.visit(v)
self.emit('ROT_TWO')
@@ -669,9 +669,9 @@ class ModuleCodeGenerator(CodeGenerator):
super_init = CodeGenerator.__init__
def __init__(self, filename):
- # XXX <module> is ? in compile.c
- self.graph = pyassem.PyFlowGraph("<module>", filename)
- self.super_init(filename)
+ # XXX <module> is ? in compile.c
+ self.graph = pyassem.PyFlowGraph("<module>", filename)
+ self.super_init(filename)
class FunctionCodeGenerator(CodeGenerator):
super_init = CodeGenerator.__init__
@@ -686,27 +686,27 @@ class FunctionCodeGenerator(CodeGenerator):
klass.lambdaCount = klass.lambdaCount + 1
else:
name = func.name
- args, hasTupleArg = generateArgList(func.argnames)
- self.graph = pyassem.PyFlowGraph(name, filename, args,
- optimized=1)
- self.isLambda = isLambda
- self.super_init(filename)
+ args, hasTupleArg = generateArgList(func.argnames)
+ self.graph = pyassem.PyFlowGraph(name, filename, args,
+ optimized=1)
+ self.isLambda = isLambda
+ self.super_init(filename)
lnf = walk(func.code, LocalNameFinder(args), 0)
self.locals.push(lnf.getLocals())
- if func.varargs:
- self.graph.setFlag(CO_VARARGS)
- if func.kwargs:
- self.graph.setFlag(CO_VARKEYWORDS)
+ if func.varargs:
+ self.graph.setFlag(CO_VARARGS)
+ if func.kwargs:
+ self.graph.setFlag(CO_VARKEYWORDS)
self.set_lineno(func)
if hasTupleArg:
self.generateArgUnpack(func.argnames)
def finish(self):
- self.graph.startExitBlock()
- if not self.isLambda:
- self.emit('LOAD_CONST', None)
- self.emit('RETURN_VALUE')
+ self.graph.startExitBlock()
+ if not self.isLambda:
+ self.emit('LOAD_CONST', None)
+ self.emit('RETURN_VALUE')
def generateArgUnpack(self, args):
count = 0
@@ -714,30 +714,33 @@ class FunctionCodeGenerator(CodeGenerator):
if type(arg) == types.TupleType:
self.emit('LOAD_FAST', '.nested%d' % count)
count = count + 1
- self.unpackTuple(arg)
+ self.unpackSequence(arg)
- def unpackTuple(self, tup):
- self.emit('UNPACK_TUPLE', len(tup))
+ def unpackSequence(self, tup):
+ self.emit('UNPACK_SEQUENCE', len(tup))
for elt in tup:
if type(elt) == types.TupleType:
- self.unpackTuple(elt)
+ self.unpackSequence(elt)
else:
self.emit('STORE_FAST', elt)
+ unpackTuple = unpackSequence
+
class ClassCodeGenerator(CodeGenerator):
super_init = CodeGenerator.__init__
def __init__(self, klass, filename):
- self.graph = pyassem.PyFlowGraph(klass.name, filename,
- optimized=0)
+ self.graph = pyassem.PyFlowGraph(klass.name, filename,
+ optimized=0)
self.super_init(filename)
lnf = walk(klass.code, LocalNameFinder(), 0)
self.locals.push(lnf.getLocals())
+ self.graph.setFlag(CO_NEWLOCALS)
def finish(self):
- self.graph.startExitBlock()
+ self.graph.startExitBlock()
self.emit('LOAD_LOCALS')
- self.emit('RETURN_VALUE')
+ self.emit('RETURN_VALUE')
def generateArgList(arglist):
@@ -746,14 +749,14 @@ def generateArgList(arglist):
extra = []
count = 0
for elt in arglist:
- if type(elt) == types.StringType:
- args.append(elt)
- elif type(elt) == types.TupleType:
- args.append(TupleArg(count, elt))
- count = count + 1
- extra.extend(misc.flatten(elt))
- else:
- raise ValueError, "unexpect argument type:", elt
+ if type(elt) == types.StringType:
+ args.append(elt)
+ elif type(elt) == types.TupleType:
+ args.append(TupleArg(count, elt))
+ count = count + 1
+ extra.extend(misc.flatten(elt))
+ else:
+ raise ValueError, "unexpect argument type:", elt
return args + extra, count
class LocalNameFinder:
@@ -771,7 +774,7 @@ class LocalNameFinder:
return self.names
def visitDict(self, node):
- pass
+ pass
def visitGlobal(self, node):
for name in node.names:
@@ -781,7 +784,7 @@ class LocalNameFinder:
self.names.add(node.name)
def visitLambda(self, node):
- pass
+ pass
def visitImport(self, node):
for name in node.names:
@@ -816,4 +819,4 @@ if __name__ == "__main__":
import sys
for file in sys.argv[1:]:
- compile(file)
+ compile(file)
diff --git a/Lib/compiler/visitor.py b/Lib/compiler/visitor.py
index d0e5223..32e72e1 100644
--- a/Lib/compiler/visitor.py
+++ b/Lib/compiler/visitor.py
@@ -38,7 +38,7 @@ class ASTVisitor:
def __init__(self):
self.node = None
- self._cache = {}
+ self._cache = {}
def preorder(self, tree, visitor):
"""Do preorder walk of tree using visitor"""
@@ -47,7 +47,7 @@ class ASTVisitor:
self._preorder(tree)
def _preorder(self, node, *args):
- return apply(self.dispatch, (node,) + args)
+ return apply(self.dispatch, (node,) + args)
def default(self, node, *args):
for child in node.getChildren():
@@ -56,18 +56,18 @@ class ASTVisitor:
def dispatch(self, node, *args):
self.node = node
- meth = self._cache.get(node.__class__, None)
- className = node.__class__.__name__
- if meth is None:
- meth = getattr(self.visitor, 'visit' + className, self.default)
- self._cache[node.__class__] = meth
+ meth = self._cache.get(node.__class__, None)
+ className = node.__class__.__name__
+ if meth is None:
+ meth = getattr(self.visitor, 'visit' + className, self.default)
+ self._cache[node.__class__] = meth
if self.VERBOSE > 0:
if self.VERBOSE == 1:
if meth == 0:
print "dispatch", className
else:
print "dispatch", className, (meth and meth.__name__ or '')
- return apply(meth, (node,) + args)
+ return apply(meth, (node,) + args)
class ExampleASTVisitor(ASTVisitor):
"""Prints examples of the nodes that aren't visited
@@ -80,11 +80,11 @@ class ExampleASTVisitor(ASTVisitor):
def dispatch(self, node, *args):
self.node = node
- meth = self._cache.get(node.__class__, None)
- className = node.__class__.__name__
- if meth is None:
- meth = getattr(self.visitor, 'visit' + className, 0)
- self._cache[node.__class__] = meth
+ meth = self._cache.get(node.__class__, None)
+ className = node.__class__.__name__
+ if meth is None:
+ meth = getattr(self.visitor, 'visit' + className, 0)
+ self._cache[node.__class__] = meth
if self.VERBOSE > 1:
print "dispatch", className, (meth and meth.__name__ or '')
if meth:
@@ -92,15 +92,15 @@ class ExampleASTVisitor(ASTVisitor):
elif self.VERBOSE > 0:
klass = node.__class__
if not self.examples.has_key(klass):
- self.examples[klass] = klass
- print
- print self.visitor
- print klass
- for attr in dir(node):
- if attr[0] != '_':
- print "\t", "%-12.12s" % attr, getattr(node, attr)
- print
- return apply(self.default, (node,) + args)
+ self.examples[klass] = klass
+ print
+ print self.visitor
+ print klass
+ for attr in dir(node):
+ if attr[0] != '_':
+ print "\t", "%-12.12s" % attr, getattr(node, attr)
+ print
+ return apply(self.default, (node,) + args)
_walker = ASTVisitor
def walk(tree, visitor, verbose=None):
diff --git a/Tools/compiler/compiler/pyassem.py b/Tools/compiler/compiler/pyassem.py
index 6e07987..c8d9e90 100644
--- a/Tools/compiler/compiler/pyassem.py
+++ b/Tools/compiler/compiler/pyassem.py
@@ -9,71 +9,71 @@ from compiler import misc
class FlowGraph:
def __init__(self):
- self.current = self.entry = Block()
- self.exit = Block("exit")
- self.blocks = misc.Set()
- self.blocks.add(self.entry)
- self.blocks.add(self.exit)
+ self.current = self.entry = Block()
+ self.exit = Block("exit")
+ self.blocks = misc.Set()
+ self.blocks.add(self.entry)
+ self.blocks.add(self.exit)
def startBlock(self, block):
- self.current = block
+ self.current = block
def nextBlock(self, block=None):
- if block is None:
- block = self.newBlock()
- # XXX think we need to specify when there is implicit transfer
- # from one block to the next
- #
- # I think this strategy works: each block has a child
- # designated as "next" which is returned as the last of the
- # children. because the nodes in a graph are emitted in
- # reverse post order, the "next" block will always be emitted
- # immediately after its parent.
- # Worry: maintaining this invariant could be tricky
- self.current.addNext(block)
- self.startBlock(block)
+ if block is None:
+ block = self.newBlock()
+ # XXX think we need to specify when there is implicit transfer
+ # from one block to the next
+ #
+ # I think this strategy works: each block has a child
+ # designated as "next" which is returned as the last of the
+ # children. because the nodes in a graph are emitted in
+ # reverse post order, the "next" block will always be emitted
+ # immediately after its parent.
+ # Worry: maintaining this invariant could be tricky
+ self.current.addNext(block)
+ self.startBlock(block)
def newBlock(self):
- b = Block()
- self.blocks.add(b)
- return b
+ b = Block()
+ self.blocks.add(b)
+ return b
def startExitBlock(self):
- self.startBlock(self.exit)
+ self.startBlock(self.exit)
def emit(self, *inst):
- # XXX should jump instructions implicitly call nextBlock?
- if inst[0] == 'RETURN_VALUE':
- self.current.addOutEdge(self.exit)
- self.current.emit(inst)
+ # XXX should jump instructions implicitly call nextBlock?
+ if inst[0] == 'RETURN_VALUE':
+ self.current.addOutEdge(self.exit)
+ self.current.emit(inst)
def getBlocks(self):
- """Return the blocks in reverse postorder
-
- i.e. each node appears before all of its successors
- """
- # XXX make sure every node that doesn't have an explicit next
- # is set so that next points to exit
- for b in self.blocks.elements():
- if b is self.exit:
- continue
- if not b.next:
- b.addNext(self.exit)
- order = dfs_postorder(self.entry, {})
- order.reverse()
- # hack alert
- if not self.exit in order:
- order.append(self.exit)
- return order
+ """Return the blocks in reverse postorder
+
+ i.e. each node appears before all of its successors
+ """
+ # XXX make sure every node that doesn't have an explicit next
+ # is set so that next points to exit
+ for b in self.blocks.elements():
+ if b is self.exit:
+ continue
+ if not b.next:
+ b.addNext(self.exit)
+ order = dfs_postorder(self.entry, {})
+ order.reverse()
+ # hack alert
+ if not self.exit in order:
+ order.append(self.exit)
+ return order
def dfs_postorder(b, seen):
"""Depth-first search of tree rooted at b, return in postorder"""
order = []
seen[b] = b
for c in b.children():
- if seen.has_key(c):
- continue
- order = order + dfs_postorder(c, seen)
+ if seen.has_key(c):
+ continue
+ order = order + dfs_postorder(c, seen)
order.append(b)
return order
@@ -81,47 +81,47 @@ class Block:
_count = 0
def __init__(self, label=''):
- self.insts = []
- self.inEdges = misc.Set()
- self.outEdges = misc.Set()
- self.label = label
- self.bid = Block._count
- self.next = []
- Block._count = Block._count + 1
+ self.insts = []
+ self.inEdges = misc.Set()
+ self.outEdges = misc.Set()
+ self.label = label
+ self.bid = Block._count
+ self.next = []
+ Block._count = Block._count + 1
def __repr__(self):
- if self.label:
- return "<block %s id=%d len=%d>" % (self.label, self.bid,
- len(self.insts))
- else:
- return "<block id=%d len=%d>" % (self.bid, len(self.insts))
+ if self.label:
+ return "<block %s id=%d len=%d>" % (self.label, self.bid,
+ len(self.insts))
+ else:
+ return "<block id=%d len=%d>" % (self.bid, len(self.insts))
def __str__(self):
- insts = map(str, self.insts)
- return "<block %s %d:\n%s>" % (self.label, self.bid,
- string.join(insts, '\n'))
+ insts = map(str, self.insts)
+ return "<block %s %d:\n%s>" % (self.label, self.bid,
+ string.join(insts, '\n'))
def emit(self, inst):
- op = inst[0]
- if op[:4] == 'JUMP':
- self.outEdges.add(inst[1])
- self.insts.append(inst)
+ op = inst[0]
+ if op[:4] == 'JUMP':
+ self.outEdges.add(inst[1])
+ self.insts.append(inst)
def getInstructions(self):
- return self.insts
+ return self.insts
def addInEdge(self, block):
- self.inEdges.add(block)
+ self.inEdges.add(block)
def addOutEdge(self, block):
- self.outEdges.add(block)
+ self.outEdges.add(block)
def addNext(self, block):
- self.next.append(block)
- assert len(self.next) == 1, map(str, self.next)
+ self.next.append(block)
+ assert len(self.next) == 1, map(str, self.next)
def children(self):
- return self.outEdges.elements() + self.next
+ return self.outEdges.elements() + self.next
# flags for code objects
CO_OPTIMIZED = 0x0001
@@ -139,18 +139,18 @@ class PyFlowGraph(FlowGraph):
super_init = FlowGraph.__init__
def __init__(self, name, filename, args=(), optimized=0):
- self.super_init()
- self.name = name
- self.filename = filename
- self.docstring = None
- self.args = args # XXX
- self.argcount = getArgCount(args)
- if optimized:
- self.flags = CO_OPTIMIZED | CO_NEWLOCALS
- else:
- self.flags = 0
- self.consts = []
- self.names = []
+ self.super_init()
+ self.name = name
+ self.filename = filename
+ self.docstring = None
+ self.args = args # XXX
+ self.argcount = getArgCount(args)
+ if optimized:
+ self.flags = CO_OPTIMIZED | CO_NEWLOCALS
+ else:
+ self.flags = 0
+ self.consts = []
+ self.names = []
self.varnames = list(args) or []
for i in range(len(self.varnames)):
var = self.varnames[i]
@@ -163,13 +163,13 @@ class PyFlowGraph(FlowGraph):
self.consts.insert(0, doc)
def setFlag(self, flag):
- self.flags = self.flags | flag
- if flag == CO_VARARGS:
- self.argcount = self.argcount - 1
+ self.flags = self.flags | flag
+ if flag == CO_VARARGS:
+ self.argcount = self.argcount - 1
def getCode(self):
- """Get a Python code object"""
- if self.stage == RAW:
+ """Get a Python code object"""
+ if self.stage == RAW:
self.flattenGraph()
if self.stage == FLAT:
self.convertArgs()
@@ -198,38 +198,38 @@ class PyFlowGraph(FlowGraph):
sys.stdout = save
def flattenGraph(self):
- """Arrange the blocks in order and resolve jumps"""
- assert self.stage == RAW
- self.insts = insts = []
- pc = 0
- begin = {}
- end = {}
- for b in self.getBlocks():
- begin[b] = pc
- for inst in b.getInstructions():
- insts.append(inst)
- if len(inst) == 1:
- pc = pc + 1
- else:
- # arg takes 2 bytes
- pc = pc + 3
- end[b] = pc
- pc = 0
- for i in range(len(insts)):
- inst = insts[i]
- if len(inst) == 1:
+ """Arrange the blocks in order and resolve jumps"""
+ assert self.stage == RAW
+ self.insts = insts = []
+ pc = 0
+ begin = {}
+ end = {}
+ for b in self.getBlocks():
+ begin[b] = pc
+ for inst in b.getInstructions():
+ insts.append(inst)
+ if len(inst) == 1:
+ pc = pc + 1
+ else:
+ # arg takes 2 bytes
+ pc = pc + 3
+ end[b] = pc
+ pc = 0
+ for i in range(len(insts)):
+ inst = insts[i]
+ if len(inst) == 1:
pc = pc + 1
else:
pc = pc + 3
- opname = inst[0]
- if self.hasjrel.has_elt(opname):
+ opname = inst[0]
+ if self.hasjrel.has_elt(opname):
oparg = inst[1]
offset = begin[oparg] - pc
insts[i] = opname, offset
elif self.hasjabs.has_elt(opname):
insts[i] = opname, begin[inst[1]]
- self.stacksize = findDepth(self.insts)
- self.stage = FLAT
+ self.stacksize = findDepth(self.insts)
+ self.stage = FLAT
hasjrel = misc.Set()
for i in dis.hasjrel:
@@ -292,7 +292,7 @@ class PyFlowGraph(FlowGraph):
_cmp = list(dis.cmp_op)
def _convert_COMPARE_OP(self, arg):
- return self._cmp.index(arg)
+ return self._cmp.index(arg)
# similarly for other opcodes...
@@ -314,12 +314,12 @@ class PyFlowGraph(FlowGraph):
if opname == "SET_LINENO":
lnotab.nextLine(oparg)
hi, lo = twobyte(oparg)
- try:
- lnotab.addCode(self.opnum[opname], lo, hi)
- except ValueError:
- print opname, oparg
- print self.opnum[opname], lo, hi
- raise
+ try:
+ lnotab.addCode(self.opnum[opname], lo, hi)
+ except ValueError:
+ print opname, oparg
+ print self.opnum[opname], lo, hi
+ raise
self.stage = DONE
opnum = {}
@@ -354,10 +354,10 @@ class PyFlowGraph(FlowGraph):
elt = elt.getCode()
l.append(elt)
return tuple(l)
-
+
def isJump(opname):
if opname[:4] == 'JUMP':
- return 1
+ return 1
class TupleArg:
"""Helper for marking func defs with nested tuples in arglist"""
@@ -372,10 +372,10 @@ class TupleArg:
def getArgCount(args):
argcount = len(args)
if args:
- for arg in args:
- if isinstance(arg, TupleArg):
- numNames = len(misc.flatten(arg.names))
- argcount = argcount - numNames
+ for arg in args:
+ if isinstance(arg, TupleArg):
+ numNames = len(misc.flatten(arg.names))
+ argcount = argcount - numNames
return argcount
def twobyte(val):
@@ -513,11 +513,9 @@ class StackDepthTracker:
]
# special cases:
- # UNPACK_TUPLE, UNPACK_LIST, BUILD_TUPLE,
+ # UNPACK_SEQUENCE, BUILD_TUPLE,
# BUILD_LIST, CALL_FUNCTION, MAKE_FUNCTION, BUILD_SLICE
- def UNPACK_TUPLE(self, count):
- return count
- def UNPACK_LIST(self, count):
+ def UNPACK_SEQUENCE(self, count):
return count
def BUILD_TUPLE(self, count):
return -count
diff --git a/Tools/compiler/compiler/pycodegen.py b/Tools/compiler/compiler/pycodegen.py
index b3223c1..9d9b982 100644
--- a/Tools/compiler/compiler/pycodegen.py
+++ b/Tools/compiler/compiler/pycodegen.py
@@ -7,7 +7,7 @@ from cStringIO import StringIO
from compiler import ast, parse, walk
from compiler import pyassem, misc
-from compiler.pyassem import CO_VARARGS, CO_VARKEYWORDS, TupleArg
+from compiler.pyassem import CO_VARARGS, CO_VARKEYWORDS, CO_NEWLOCALS, TupleArg
callfunc_opcode_info = {
# (Have *args, Have **args) : opcode
@@ -29,32 +29,32 @@ def compile(filename):
class Module:
def __init__(self, source, filename):
- self.filename = filename
- self.source = source
- self.code = None
+ self.filename = filename
+ self.source = source
+ self.code = None
def compile(self):
- ast = parse(self.source)
+ ast = parse(self.source)
root, filename = os.path.split(self.filename)
- gen = ModuleCodeGenerator(filename)
- walk(ast, gen, 1)
- self.code = gen.getCode()
+ gen = ModuleCodeGenerator(filename)
+ walk(ast, gen, 1)
+ self.code = gen.getCode()
def dump(self, f):
- f.write(self.getPycHeader())
- marshal.dump(self.code, f)
+ f.write(self.getPycHeader())
+ marshal.dump(self.code, f)
- MAGIC = (20121 | (ord('\r')<<16) | (ord('\n')<<24))
+ MAGIC = (50811 | (ord('\r')<<16) | (ord('\n')<<24))
def getPycHeader(self):
- # 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.
- magic = marshal.dumps(self.MAGIC)[1:]
- mtime = os.stat(self.filename)[stat.ST_MTIME]
- mtime = struct.pack('i', mtime)
- return magic + mtime
+ # 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.
+ magic = marshal.dumps(self.MAGIC)[1:]
+ mtime = os.stat(self.filename)[stat.ST_MTIME]
+ mtime = struct.pack('i', mtime)
+ return magic + mtime
class CodeGenerator:
@@ -63,24 +63,24 @@ class CodeGenerator:
def __init__(self, filename):
## Subclasses must define a constructor that intializes self.graph
## before calling this init function
-## self.graph = pyassem.PyFlowGraph()
- self.filename = filename
- self.locals = misc.Stack()
- self.loops = misc.Stack()
- self.curStack = 0
- self.maxStack = 0
- self._setupGraphDelegation()
+## self.graph = pyassem.PyFlowGraph()
+ self.filename = filename
+ self.locals = misc.Stack()
+ self.loops = misc.Stack()
+ self.curStack = 0
+ self.maxStack = 0
+ self._setupGraphDelegation()
def _setupGraphDelegation(self):
- 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
+ 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
def getCode(self):
- """Return a code object"""
- return self.graph.getCode()
+ """Return a code object"""
+ return self.graph.getCode()
# Next five methods handle name access
@@ -97,11 +97,11 @@ class CodeGenerator:
self._nameOp('DELETE', name)
def _nameOp(self, prefix, name):
- if not self.optimized:
- self.emit(prefix + '_NAME', name)
- return
+ if not self.optimized:
+ self.emit(prefix + '_NAME', name)
+ return
if self.isLocalName(name):
- self.emit(prefix + '_FAST', name)
+ self.emit(prefix + '_FAST', name)
else:
self.emit(prefix + '_GLOBAL', name)
@@ -125,25 +125,25 @@ class CodeGenerator:
# code objects
def visitModule(self, node):
- lnf = walk(node.node, LocalNameFinder(), 0)
- self.locals.push(lnf.getLocals())
- self.setDocstring(node.doc)
- self.visit(node.node)
- self.emit('LOAD_CONST', None)
- self.emit('RETURN_VALUE')
+ lnf = walk(node.node, LocalNameFinder(), 0)
+ self.locals.push(lnf.getLocals())
+ self.setDocstring(node.doc)
+ self.visit(node.node)
+ self.emit('LOAD_CONST', None)
+ self.emit('RETURN_VALUE')
def visitFunction(self, node):
- self._visitFuncOrLambda(node, isLambda=0)
- self.storeName(node.name)
+ self._visitFuncOrLambda(node, isLambda=0)
+ self.storeName(node.name)
def visitLambda(self, node):
- self._visitFuncOrLambda(node, isLambda=1)
-## self.storeName("<lambda>")
+ self._visitFuncOrLambda(node, isLambda=1)
+## self.storeName("<lambda>")
def _visitFuncOrLambda(self, node, isLambda):
- gen = FunctionCodeGenerator(node, self.filename, isLambda)
- walk(node.code, gen)
- gen.finish()
+ gen = FunctionCodeGenerator(node, self.filename, isLambda)
+ walk(node.code, gen)
+ gen.finish()
self.set_lineno(node)
for default in node.defaults:
self.visit(default)
@@ -170,158 +170,158 @@ class CodeGenerator:
# The next few implement control-flow statements
def visitIf(self, node):
- end = self.newBlock()
- numtests = len(node.tests)
- for i in range(numtests):
- test, suite = node.tests[i]
+ end = self.newBlock()
+ numtests = len(node.tests)
+ for i in range(numtests):
+ test, suite = node.tests[i]
self.set_lineno(test)
- self.visit(test)
-## if i == numtests - 1 and not node.else_:
-## nextTest = end
-## else:
-## nextTest = self.newBlock()
- nextTest = self.newBlock()
- self.emit('JUMP_IF_FALSE', nextTest)
- self.nextBlock()
- self.emit('POP_TOP')
- self.visit(suite)
- self.emit('JUMP_FORWARD', end)
- self.nextBlock(nextTest)
- self.emit('POP_TOP')
- if node.else_:
- self.visit(node.else_)
- self.nextBlock(end)
+ self.visit(test)
+## if i == numtests - 1 and not node.else_:
+## nextTest = end
+## else:
+## nextTest = self.newBlock()
+ nextTest = self.newBlock()
+ self.emit('JUMP_IF_FALSE', nextTest)
+ self.nextBlock()
+ self.emit('POP_TOP')
+ self.visit(suite)
+ self.emit('JUMP_FORWARD', end)
+ self.nextBlock(nextTest)
+ self.emit('POP_TOP')
+ if node.else_:
+ self.visit(node.else_)
+ self.nextBlock(end)
def visitWhile(self, node):
self.set_lineno(node)
- loop = self.newBlock()
- else_ = self.newBlock()
+ loop = self.newBlock()
+ else_ = self.newBlock()
- after = self.newBlock()
- self.emit('SETUP_LOOP', after)
+ after = self.newBlock()
+ self.emit('SETUP_LOOP', after)
- self.nextBlock(loop)
- self.loops.push(loop)
+ self.nextBlock(loop)
+ self.loops.push(loop)
self.set_lineno(node)
- 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')
- if node.else_:
- self.visit(node.else_)
- self.loops.pop()
- self.nextBlock(after)
+ 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')
+ if node.else_:
+ self.visit(node.else_)
+ self.loops.pop()
+ self.nextBlock(after)
def visitFor(self, node):
- start = self.newBlock()
+ start = self.newBlock()
anchor = self.newBlock()
- after = self.newBlock()
+ after = self.newBlock()
self.loops.push(start)
self.set_lineno(node)
- self.emit('SETUP_LOOP', after)
+ self.emit('SETUP_LOOP', after)
self.visit(node.list)
self.visit(ast.Const(0))
- self.nextBlock(start)
+ self.nextBlock(start)
self.set_lineno(node)
self.emit('FOR_LOOP', anchor)
self.visit(node.assign)
self.visit(node.body)
self.emit('JUMP_ABSOLUTE', start)
- self.nextBlock(anchor)
+ self.nextBlock(anchor)
self.emit('POP_BLOCK')
if node.else_:
self.visit(node.else_)
- self.loops.pop()
- self.nextBlock(after)
+ self.loops.pop()
+ self.nextBlock(after)
def visitBreak(self, node):
- if not self.loops:
- raise SyntaxError, "'break' outside loop (%s, %d)" % \
- (self.filename, node.lineno)
+ if not self.loops:
+ raise SyntaxError, "'break' outside loop (%s, %d)" % \
+ (self.filename, node.lineno)
self.set_lineno(node)
- self.emit('BREAK_LOOP')
+ self.emit('BREAK_LOOP')
def visitContinue(self, node):
if not self.loops:
raise SyntaxError, "'continue' outside loop (%s, %d)" % \
- (self.filename, node.lineno)
+ (self.filename, node.lineno)
l = self.loops.top()
self.set_lineno(node)
self.emit('JUMP_ABSOLUTE', l)
- self.nextBlock()
+ self.nextBlock()
def visitTest(self, node, jump):
- end = self.newBlock()
+ end = self.newBlock()
for child in node.nodes[:-1]:
self.visit(child)
self.emit(jump, end)
- self.nextBlock()
+ self.nextBlock()
self.emit('POP_TOP')
self.visit(node.nodes[-1])
- self.nextBlock(end)
+ self.nextBlock(end)
def visitAnd(self, node):
- self.visitTest(node, 'JUMP_IF_FALSE')
+ self.visitTest(node, 'JUMP_IF_FALSE')
def visitOr(self, node):
- self.visitTest(node, 'JUMP_IF_TRUE')
+ self.visitTest(node, 'JUMP_IF_TRUE')
def visitCompare(self, node):
- 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)
- self.nextBlock(cleanup)
- self.emit('ROT_TWO')
- self.emit('POP_TOP')
- self.nextBlock(end)
+ 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)
+ self.nextBlock(cleanup)
+ self.emit('ROT_TWO')
+ self.emit('POP_TOP')
+ self.nextBlock(end)
# exception related
def visitAssert(self, node):
- # XXX would be interesting to implement this via a
- # transformation of the AST before this stage
- end = self.newBlock()
+ # XXX would be interesting to implement this via a
+ # transformation of the AST before this stage
+ end = self.newBlock()
self.set_lineno(node)
# XXX __debug__ and AssertionError appear to be special cases
# -- they are always loaded as globals even if there are local
# names. I guess this is a sort of renaming op.
- self.emit('LOAD_GLOBAL', '__debug__')
- self.emit('JUMP_IF_FALSE', end)
- self.nextBlock()
- self.emit('POP_TOP')
- self.visit(node.test)
- self.emit('JUMP_IF_TRUE', end)
- self.nextBlock()
- self.emit('LOAD_GLOBAL', 'AssertionError')
- self.visit(node.fail)
- self.emit('RAISE_VARARGS', 2)
- self.nextBlock(end)
- self.emit('POP_TOP')
+ self.emit('LOAD_GLOBAL', '__debug__')
+ self.emit('JUMP_IF_FALSE', end)
+ self.nextBlock()
+ self.emit('POP_TOP')
+ self.visit(node.test)
+ self.emit('JUMP_IF_TRUE', end)
+ self.nextBlock()
+ self.emit('LOAD_GLOBAL', 'AssertionError')
+ self.visit(node.fail)
+ self.emit('RAISE_VARARGS', 2)
+ self.nextBlock(end)
+ self.emit('POP_TOP')
def visitRaise(self, node):
self.set_lineno(node)
@@ -349,7 +349,7 @@ class CodeGenerator:
self.visit(node.body)
self.emit('POP_BLOCK')
self.emit('JUMP_FORWARD', lElse)
- self.nextBlock(handlers)
+ self.nextBlock(handlers)
last = len(node.handlers) - 1
for i in range(len(node.handlers)):
@@ -361,7 +361,7 @@ class CodeGenerator:
self.emit('COMPARE_OP', 'exception match')
next = self.newBlock()
self.emit('JUMP_IF_FALSE', next)
- self.nextBlock()
+ self.nextBlock()
self.emit('POP_TOP')
self.emit('POP_TOP')
if target:
@@ -372,13 +372,13 @@ class CodeGenerator:
self.visit(body)
self.emit('JUMP_FORWARD', end)
if expr:
- self.nextBlock(next)
+ self.nextBlock(next)
self.emit('POP_TOP')
self.emit('END_FINALLY')
if node.else_:
- self.nextBlock(lElse)
+ self.nextBlock(lElse)
self.visit(node.else_)
- self.nextBlock(end)
+ self.nextBlock(end)
def visitTryFinally(self, node):
final = self.newBlock()
@@ -387,15 +387,15 @@ class CodeGenerator:
self.visit(node.body)
self.emit('POP_BLOCK')
self.emit('LOAD_CONST', None)
- self.nextBlock(final)
+ self.nextBlock(final)
self.visit(node.final)
self.emit('END_FINALLY')
# misc
## def visitStmt(self, node):
-## # nothing to do except walk the children
-## pass
+## # nothing to do except walk the children
+## pass
def visitDiscard(self, node):
self.visit(node.expr)
@@ -405,12 +405,12 @@ class CodeGenerator:
self.emit('LOAD_CONST', node.value)
def visitKeyword(self, node):
- self.emit('LOAD_CONST', node.name)
- self.visit(node.expr)
+ self.emit('LOAD_CONST', node.name)
+ self.visit(node.expr)
def visitGlobal(self, node):
# no code to generate
- pass
+ pass
def visitName(self, node):
self.loadName(node.name)
@@ -470,7 +470,7 @@ class CodeGenerator:
def visitAssTuple(self, node):
if findOp(node) != 'OP_DELETE':
- self.emit('UNPACK_TUPLE', len(node.nodes))
+ self.emit('UNPACK_SEQUENCE', len(node.nodes))
for child in node.nodes:
self.visit(child)
@@ -655,10 +655,10 @@ class CodeGenerator:
set.emit('SET_LINENO', lineno)
self.emit('BUILD_MAP', 0)
for k, v in node.items:
- lineno2 = getattr(node, 'lineno', None)
+ lineno2 = getattr(node, 'lineno', None)
if lineno2 is not None and lineno != lineno2:
- self.emit('SET_LINENO', lineno2)
- lineno = lineno2
+ self.emit('SET_LINENO', lineno2)
+ lineno = lineno2
self.emit('DUP_TOP')
self.visit(v)
self.emit('ROT_TWO')
@@ -669,9 +669,9 @@ class ModuleCodeGenerator(CodeGenerator):
super_init = CodeGenerator.__init__
def __init__(self, filename):
- # XXX <module> is ? in compile.c
- self.graph = pyassem.PyFlowGraph("<module>", filename)
- self.super_init(filename)
+ # XXX <module> is ? in compile.c
+ self.graph = pyassem.PyFlowGraph("<module>", filename)
+ self.super_init(filename)
class FunctionCodeGenerator(CodeGenerator):
super_init = CodeGenerator.__init__
@@ -686,27 +686,27 @@ class FunctionCodeGenerator(CodeGenerator):
klass.lambdaCount = klass.lambdaCount + 1
else:
name = func.name
- args, hasTupleArg = generateArgList(func.argnames)
- self.graph = pyassem.PyFlowGraph(name, filename, args,
- optimized=1)
- self.isLambda = isLambda
- self.super_init(filename)
+ args, hasTupleArg = generateArgList(func.argnames)
+ self.graph = pyassem.PyFlowGraph(name, filename, args,
+ optimized=1)
+ self.isLambda = isLambda
+ self.super_init(filename)
lnf = walk(func.code, LocalNameFinder(args), 0)
self.locals.push(lnf.getLocals())
- if func.varargs:
- self.graph.setFlag(CO_VARARGS)
- if func.kwargs:
- self.graph.setFlag(CO_VARKEYWORDS)
+ if func.varargs:
+ self.graph.setFlag(CO_VARARGS)
+ if func.kwargs:
+ self.graph.setFlag(CO_VARKEYWORDS)
self.set_lineno(func)
if hasTupleArg:
self.generateArgUnpack(func.argnames)
def finish(self):
- self.graph.startExitBlock()
- if not self.isLambda:
- self.emit('LOAD_CONST', None)
- self.emit('RETURN_VALUE')
+ self.graph.startExitBlock()
+ if not self.isLambda:
+ self.emit('LOAD_CONST', None)
+ self.emit('RETURN_VALUE')
def generateArgUnpack(self, args):
count = 0
@@ -714,30 +714,33 @@ class FunctionCodeGenerator(CodeGenerator):
if type(arg) == types.TupleType:
self.emit('LOAD_FAST', '.nested%d' % count)
count = count + 1
- self.unpackTuple(arg)
+ self.unpackSequence(arg)
- def unpackTuple(self, tup):
- self.emit('UNPACK_TUPLE', len(tup))
+ def unpackSequence(self, tup):
+ self.emit('UNPACK_SEQUENCE', len(tup))
for elt in tup:
if type(elt) == types.TupleType:
- self.unpackTuple(elt)
+ self.unpackSequence(elt)
else:
self.emit('STORE_FAST', elt)
+ unpackTuple = unpackSequence
+
class ClassCodeGenerator(CodeGenerator):
super_init = CodeGenerator.__init__
def __init__(self, klass, filename):
- self.graph = pyassem.PyFlowGraph(klass.name, filename,
- optimized=0)
+ self.graph = pyassem.PyFlowGraph(klass.name, filename,
+ optimized=0)
self.super_init(filename)
lnf = walk(klass.code, LocalNameFinder(), 0)
self.locals.push(lnf.getLocals())
+ self.graph.setFlag(CO_NEWLOCALS)
def finish(self):
- self.graph.startExitBlock()
+ self.graph.startExitBlock()
self.emit('LOAD_LOCALS')
- self.emit('RETURN_VALUE')
+ self.emit('RETURN_VALUE')
def generateArgList(arglist):
@@ -746,14 +749,14 @@ def generateArgList(arglist):
extra = []
count = 0
for elt in arglist:
- if type(elt) == types.StringType:
- args.append(elt)
- elif type(elt) == types.TupleType:
- args.append(TupleArg(count, elt))
- count = count + 1
- extra.extend(misc.flatten(elt))
- else:
- raise ValueError, "unexpect argument type:", elt
+ if type(elt) == types.StringType:
+ args.append(elt)
+ elif type(elt) == types.TupleType:
+ args.append(TupleArg(count, elt))
+ count = count + 1
+ extra.extend(misc.flatten(elt))
+ else:
+ raise ValueError, "unexpect argument type:", elt
return args + extra, count
class LocalNameFinder:
@@ -771,7 +774,7 @@ class LocalNameFinder:
return self.names
def visitDict(self, node):
- pass
+ pass
def visitGlobal(self, node):
for name in node.names:
@@ -781,7 +784,7 @@ class LocalNameFinder:
self.names.add(node.name)
def visitLambda(self, node):
- pass
+ pass
def visitImport(self, node):
for name in node.names:
@@ -816,4 +819,4 @@ if __name__ == "__main__":
import sys
for file in sys.argv[1:]:
- compile(file)
+ compile(file)
diff --git a/Tools/compiler/compiler/visitor.py b/Tools/compiler/compiler/visitor.py
index d0e5223..32e72e1 100644
--- a/Tools/compiler/compiler/visitor.py
+++ b/Tools/compiler/compiler/visitor.py
@@ -38,7 +38,7 @@ class ASTVisitor:
def __init__(self):
self.node = None
- self._cache = {}
+ self._cache = {}
def preorder(self, tree, visitor):
"""Do preorder walk of tree using visitor"""
@@ -47,7 +47,7 @@ class ASTVisitor:
self._preorder(tree)
def _preorder(self, node, *args):
- return apply(self.dispatch, (node,) + args)
+ return apply(self.dispatch, (node,) + args)
def default(self, node, *args):
for child in node.getChildren():
@@ -56,18 +56,18 @@ class ASTVisitor:
def dispatch(self, node, *args):
self.node = node
- meth = self._cache.get(node.__class__, None)
- className = node.__class__.__name__
- if meth is None:
- meth = getattr(self.visitor, 'visit' + className, self.default)
- self._cache[node.__class__] = meth
+ meth = self._cache.get(node.__class__, None)
+ className = node.__class__.__name__
+ if meth is None:
+ meth = getattr(self.visitor, 'visit' + className, self.default)
+ self._cache[node.__class__] = meth
if self.VERBOSE > 0:
if self.VERBOSE == 1:
if meth == 0:
print "dispatch", className
else:
print "dispatch", className, (meth and meth.__name__ or '')
- return apply(meth, (node,) + args)
+ return apply(meth, (node,) + args)
class ExampleASTVisitor(ASTVisitor):
"""Prints examples of the nodes that aren't visited
@@ -80,11 +80,11 @@ class ExampleASTVisitor(ASTVisitor):
def dispatch(self, node, *args):
self.node = node
- meth = self._cache.get(node.__class__, None)
- className = node.__class__.__name__
- if meth is None:
- meth = getattr(self.visitor, 'visit' + className, 0)
- self._cache[node.__class__] = meth
+ meth = self._cache.get(node.__class__, None)
+ className = node.__class__.__name__
+ if meth is None:
+ meth = getattr(self.visitor, 'visit' + className, 0)
+ self._cache[node.__class__] = meth
if self.VERBOSE > 1:
print "dispatch", className, (meth and meth.__name__ or '')
if meth:
@@ -92,15 +92,15 @@ class ExampleASTVisitor(ASTVisitor):
elif self.VERBOSE > 0:
klass = node.__class__
if not self.examples.has_key(klass):
- self.examples[klass] = klass
- print
- print self.visitor
- print klass
- for attr in dir(node):
- if attr[0] != '_':
- print "\t", "%-12.12s" % attr, getattr(node, attr)
- print
- return apply(self.default, (node,) + args)
+ self.examples[klass] = klass
+ print
+ print self.visitor
+ print klass
+ for attr in dir(node):
+ if attr[0] != '_':
+ print "\t", "%-12.12s" % attr, getattr(node, attr)
+ print
+ return apply(self.default, (node,) + args)
_walker = ASTVisitor
def walk(tree, visitor, verbose=None):