[Python-checkins] CVS: python/dist/src/Tools/compiler/compiler pyassem.py,1.9,1.10 pycodegen.py,1.21,1.22 visitor.py,1.3,1.4
Thomas Wouters
python-dev@python.org
Sat, 12 Aug 2000 13:32:49 -0700
Update of /cvsroot/python/python/dist/src/Tools/compiler/compiler
In directory slayer.i.sourceforge.net:/tmp/cvs-serv6567/compiler
Modified Files:
pyassem.py pycodegen.py visitor.py
Log Message:
Bring Tools/compiler almost up to date. Specifically:
- fix tab space issues (SF patch #101167 by Neil Schemenauer)
- fix co_flags for classes to include CO_NEWLOCALS (SF patch #101145 by Neil)
- fix for merger of UNPACK_LIST and UNPACK_TUPLE into UNPACK_SEQUENCE,
(SF patch #101168 by, well, Neil :)
- Adjust bytecode MAGIC to current bytecode.
TODO: teach compile.py about list comprehensions.
Index: pyassem.py
===================================================================
RCS file: /cvsroot/python/python/dist/src/Tools/compiler/compiler/pyassem.py,v
retrieving revision 1.9
retrieving revision 1.10
diff -C2 -r1.9 -r1.10
*** pyassem.py 2000/05/02 22:32:59 1.9
--- pyassem.py 2000/08/12 20:32:46 1.10
***************
*** 10,69 ****
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)
def startBlock(self, 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)
def newBlock(self):
! b = Block()
! self.blocks.add(b)
! return b
def startExitBlock(self):
! 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)
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
def dfs_postorder(b, seen):
--- 10,69 ----
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)
def startBlock(self, 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)
def newBlock(self):
! b = Block()
! self.blocks.add(b)
! return b
def startExitBlock(self):
! 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)
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
def dfs_postorder(b, seen):
***************
*** 72,78 ****
seen[b] = b
for c in b.children():
! if seen.has_key(c):
! continue
! order = order + dfs_postorder(c, seen)
order.append(b)
return order
--- 72,78 ----
seen[b] = b
for c in b.children():
! if seen.has_key(c):
! continue
! order = order + dfs_postorder(c, seen)
order.append(b)
return order
***************
*** 82,126 ****
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
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))
def __str__(self):
! 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)
def getInstructions(self):
! return self.insts
def addInEdge(self, block):
! self.inEdges.add(block)
def addOutEdge(self, block):
! self.outEdges.add(block)
def addNext(self, block):
! self.next.append(block)
! assert len(self.next) == 1, map(str, self.next)
def children(self):
! return self.outEdges.elements() + self.next
# flags for code objects
--- 82,126 ----
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
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))
def __str__(self):
! 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)
def getInstructions(self):
! return self.insts
def addInEdge(self, block):
! self.inEdges.add(block)
def addOutEdge(self, block):
! self.outEdges.add(block)
def addNext(self, block):
! self.next.append(block)
! assert len(self.next) == 1, map(str, self.next)
def children(self):
! return self.outEdges.elements() + self.next
# flags for code objects
***************
*** 140,155 ****
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.varnames = list(args) or []
for i in range(len(self.varnames)):
--- 140,155 ----
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.varnames = list(args) or []
for i in range(len(self.varnames)):
***************
*** 164,174 ****
def setFlag(self, flag):
! 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:
self.flattenGraph()
if self.stage == FLAT:
--- 164,174 ----
def setFlag(self, flag):
! 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:
self.flattenGraph()
if self.stage == FLAT:
***************
*** 199,227 ****
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:
pc = pc + 1
else:
pc = pc + 3
! opname = inst[0]
! if self.hasjrel.has_elt(opname):
oparg = inst[1]
offset = begin[oparg] - pc
--- 199,227 ----
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:
pc = pc + 1
else:
pc = pc + 3
! opname = inst[0]
! if self.hasjrel.has_elt(opname):
oparg = inst[1]
offset = begin[oparg] - pc
***************
*** 229,234 ****
elif self.hasjabs.has_elt(opname):
insts[i] = opname, begin[inst[1]]
! self.stacksize = findDepth(self.insts)
! self.stage = FLAT
hasjrel = misc.Set()
--- 229,234 ----
elif self.hasjabs.has_elt(opname):
insts[i] = opname, begin[inst[1]]
! self.stacksize = findDepth(self.insts)
! self.stage = FLAT
hasjrel = misc.Set()
***************
*** 293,297 ****
_cmp = list(dis.cmp_op)
def _convert_COMPARE_OP(self, arg):
! return self._cmp.index(arg)
# similarly for other opcodes...
--- 293,297 ----
_cmp = list(dis.cmp_op)
def _convert_COMPARE_OP(self, arg):
! return self._cmp.index(arg)
# similarly for other opcodes...
***************
*** 315,324 ****
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
self.stage = DONE
--- 315,324 ----
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
self.stage = DONE
***************
*** 355,362 ****
l.append(elt)
return tuple(l)
!
def isJump(opname):
if opname[:4] == 'JUMP':
! return 1
class TupleArg:
--- 355,362 ----
l.append(elt)
return tuple(l)
!
def isJump(opname):
if opname[:4] == 'JUMP':
! return 1
class TupleArg:
***************
*** 373,380 ****
argcount = len(args)
if args:
! for arg in args:
! if isinstance(arg, TupleArg):
! numNames = len(misc.flatten(arg.names))
! argcount = argcount - numNames
return argcount
--- 373,380 ----
argcount = len(args)
if args:
! for arg in args:
! if isinstance(arg, TupleArg):
! numNames = len(misc.flatten(arg.names))
! argcount = argcount - numNames
return argcount
***************
*** 514,522 ****
# special cases:
! # UNPACK_TUPLE, UNPACK_LIST, BUILD_TUPLE,
# BUILD_LIST, CALL_FUNCTION, MAKE_FUNCTION, BUILD_SLICE
! def UNPACK_TUPLE(self, count):
! return count
! def UNPACK_LIST(self, count):
return count
def BUILD_TUPLE(self, count):
--- 514,520 ----
# special cases:
! # UNPACK_SEQUENCE, BUILD_TUPLE,
# BUILD_LIST, CALL_FUNCTION, MAKE_FUNCTION, BUILD_SLICE
! def UNPACK_SEQUENCE(self, count):
return count
def BUILD_TUPLE(self, count):
Index: pycodegen.py
===================================================================
RCS file: /cvsroot/python/python/dist/src/Tools/compiler/compiler/pycodegen.py,v
retrieving revision 1.21
retrieving revision 1.22
diff -C2 -r1.21 -r1.22
*** pycodegen.py 2000/08/04 16:56:51 1.21
--- pycodegen.py 2000/08/12 20:32:46 1.22
***************
*** 8,12 ****
from compiler import ast, parse, walk
from compiler import pyassem, misc
! from compiler.pyassem import CO_VARARGS, CO_VARKEYWORDS, TupleArg
callfunc_opcode_info = {
--- 8,12 ----
from compiler import ast, parse, walk
from compiler import pyassem, misc
! from compiler.pyassem import CO_VARARGS, CO_VARKEYWORDS, CO_NEWLOCALS, TupleArg
callfunc_opcode_info = {
***************
*** 30,59 ****
class Module:
def __init__(self, source, filename):
! self.filename = filename
! self.source = source
! self.code = None
def compile(self):
! ast = parse(self.source)
root, filename = os.path.split(self.filename)
! gen = ModuleCodeGenerator(filename)
! walk(ast, gen, 1)
! self.code = gen.getCode()
def dump(self, f):
! f.write(self.getPycHeader())
! marshal.dump(self.code, f)
! MAGIC = (20121 | (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
class CodeGenerator:
--- 30,59 ----
class Module:
def __init__(self, source, filename):
! self.filename = filename
! self.source = source
! self.code = None
def compile(self):
! ast = parse(self.source)
root, filename = os.path.split(self.filename)
! gen = ModuleCodeGenerator(filename)
! walk(ast, gen, 1)
! self.code = gen.getCode()
def dump(self, f):
! f.write(self.getPycHeader())
! marshal.dump(self.code, f)
! 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
class CodeGenerator:
***************
*** 64,85 ****
## 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()
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
def getCode(self):
! """Return a code object"""
! return self.graph.getCode()
# Next five methods handle name access
--- 64,85 ----
## 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()
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
def getCode(self):
! """Return a code object"""
! return self.graph.getCode()
# Next five methods handle name access
***************
*** 98,106 ****
def _nameOp(self, prefix, name):
! if not self.optimized:
! self.emit(prefix + '_NAME', name)
! return
if self.isLocalName(name):
! self.emit(prefix + '_FAST', name)
else:
self.emit(prefix + '_GLOBAL', name)
--- 98,106 ----
def _nameOp(self, prefix, name):
! if not self.optimized:
! self.emit(prefix + '_NAME', name)
! return
if self.isLocalName(name):
! self.emit(prefix + '_FAST', name)
else:
self.emit(prefix + '_GLOBAL', name)
***************
*** 126,148 ****
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')
def visitFunction(self, node):
! self._visitFuncOrLambda(node, isLambda=0)
! self.storeName(node.name)
def visitLambda(self, node):
! 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()
self.set_lineno(node)
for default in node.defaults:
--- 126,148 ----
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')
def visitFunction(self, node):
! self._visitFuncOrLambda(node, isLambda=0)
! self.storeName(node.name)
def visitLambda(self, node):
! 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()
self.set_lineno(node)
for default in node.defaults:
***************
*** 171,236 ****
def visitIf(self, node):
! 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)
def visitWhile(self, node):
self.set_lineno(node)
! loop = self.newBlock()
! else_ = self.newBlock()
! after = self.newBlock()
! self.emit('SETUP_LOOP', after)
! 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)
def visitFor(self, node):
! start = self.newBlock()
anchor = self.newBlock()
! after = self.newBlock()
self.loops.push(start)
self.set_lineno(node)
! self.emit('SETUP_LOOP', after)
self.visit(node.list)
self.visit(ast.Const(0))
! self.nextBlock(start)
self.set_lineno(node)
self.emit('FOR_LOOP', anchor)
--- 171,236 ----
def visitIf(self, node):
! 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)
def visitWhile(self, node):
self.set_lineno(node)
! loop = self.newBlock()
! else_ = self.newBlock()
! after = self.newBlock()
! self.emit('SETUP_LOOP', after)
! 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)
def visitFor(self, node):
! start = self.newBlock()
anchor = self.newBlock()
! after = self.newBlock()
self.loops.push(start)
self.set_lineno(node)
! self.emit('SETUP_LOOP', after)
self.visit(node.list)
self.visit(ast.Const(0))
! self.nextBlock(start)
self.set_lineno(node)
self.emit('FOR_LOOP', anchor)
***************
*** 238,326 ****
self.visit(node.body)
self.emit('JUMP_ABSOLUTE', start)
! self.nextBlock(anchor)
self.emit('POP_BLOCK')
if node.else_:
self.visit(node.else_)
! 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)
self.set_lineno(node)
! self.emit('BREAK_LOOP')
def visitContinue(self, node):
if not self.loops:
raise SyntaxError, "'continue' outside loop (%s, %d)" % \
! (self.filename, node.lineno)
l = self.loops.top()
self.set_lineno(node)
self.emit('JUMP_ABSOLUTE', l)
! self.nextBlock()
def visitTest(self, node, jump):
! end = self.newBlock()
for child in node.nodes[:-1]:
self.visit(child)
self.emit(jump, end)
! self.nextBlock()
self.emit('POP_TOP')
self.visit(node.nodes[-1])
! self.nextBlock(end)
def visitAnd(self, node):
! self.visitTest(node, 'JUMP_IF_FALSE')
def visitOr(self, node):
! 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)
# 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()
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')
def visitRaise(self, node):
--- 238,326 ----
self.visit(node.body)
self.emit('JUMP_ABSOLUTE', start)
! self.nextBlock(anchor)
self.emit('POP_BLOCK')
if node.else_:
self.visit(node.else_)
! 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)
self.set_lineno(node)
! self.emit('BREAK_LOOP')
def visitContinue(self, node):
if not self.loops:
raise SyntaxError, "'continue' outside loop (%s, %d)" % \
! (self.filename, node.lineno)
l = self.loops.top()
self.set_lineno(node)
self.emit('JUMP_ABSOLUTE', l)
! self.nextBlock()
def visitTest(self, node, jump):
! end = self.newBlock()
for child in node.nodes[:-1]:
self.visit(child)
self.emit(jump, end)
! self.nextBlock()
self.emit('POP_TOP')
self.visit(node.nodes[-1])
! self.nextBlock(end)
def visitAnd(self, node):
! self.visitTest(node, 'JUMP_IF_FALSE')
def visitOr(self, node):
! 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)
# 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()
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')
def visitRaise(self, node):
***************
*** 350,354 ****
self.emit('POP_BLOCK')
self.emit('JUMP_FORWARD', lElse)
! self.nextBlock(handlers)
last = len(node.handlers) - 1
--- 350,354 ----
self.emit('POP_BLOCK')
self.emit('JUMP_FORWARD', lElse)
! self.nextBlock(handlers)
last = len(node.handlers) - 1
***************
*** 362,366 ****
next = self.newBlock()
self.emit('JUMP_IF_FALSE', next)
! self.nextBlock()
self.emit('POP_TOP')
self.emit('POP_TOP')
--- 362,366 ----
next = self.newBlock()
self.emit('JUMP_IF_FALSE', next)
! self.nextBlock()
self.emit('POP_TOP')
self.emit('POP_TOP')
***************
*** 373,383 ****
self.emit('JUMP_FORWARD', end)
if expr:
! self.nextBlock(next)
self.emit('POP_TOP')
self.emit('END_FINALLY')
if node.else_:
! self.nextBlock(lElse)
self.visit(node.else_)
! self.nextBlock(end)
def visitTryFinally(self, node):
--- 373,383 ----
self.emit('JUMP_FORWARD', end)
if expr:
! self.nextBlock(next)
self.emit('POP_TOP')
self.emit('END_FINALLY')
if node.else_:
! self.nextBlock(lElse)
self.visit(node.else_)
! self.nextBlock(end)
def visitTryFinally(self, node):
***************
*** 388,392 ****
self.emit('POP_BLOCK')
self.emit('LOAD_CONST', None)
! self.nextBlock(final)
self.visit(node.final)
self.emit('END_FINALLY')
--- 388,392 ----
self.emit('POP_BLOCK')
self.emit('LOAD_CONST', None)
! self.nextBlock(final)
self.visit(node.final)
self.emit('END_FINALLY')
***************
*** 395,400 ****
## def visitStmt(self, node):
! ## # nothing to do except walk the children
! ## pass
def visitDiscard(self, node):
--- 395,400 ----
## def visitStmt(self, node):
! ## # nothing to do except walk the children
! ## pass
def visitDiscard(self, node):
***************
*** 406,415 ****
def visitKeyword(self, node):
! self.emit('LOAD_CONST', node.name)
! self.visit(node.expr)
def visitGlobal(self, node):
# no code to generate
! pass
def visitName(self, node):
--- 406,415 ----
def visitKeyword(self, node):
! self.emit('LOAD_CONST', node.name)
! self.visit(node.expr)
def visitGlobal(self, node):
# no code to generate
! pass
def visitName(self, node):
***************
*** 471,475 ****
def visitAssTuple(self, node):
if findOp(node) != 'OP_DELETE':
! self.emit('UNPACK_TUPLE', len(node.nodes))
for child in node.nodes:
self.visit(child)
--- 471,475 ----
def visitAssTuple(self, node):
if findOp(node) != 'OP_DELETE':
! self.emit('UNPACK_SEQUENCE', len(node.nodes))
for child in node.nodes:
self.visit(child)
***************
*** 656,663 ****
self.emit('BUILD_MAP', 0)
for k, v in node.items:
! lineno2 = getattr(node, 'lineno', None)
if lineno2 is not None and lineno != lineno2:
! self.emit('SET_LINENO', lineno2)
! lineno = lineno2
self.emit('DUP_TOP')
self.visit(v)
--- 656,663 ----
self.emit('BUILD_MAP', 0)
for k, v in node.items:
! lineno2 = getattr(node, 'lineno', None)
if lineno2 is not None and lineno != lineno2:
! self.emit('SET_LINENO', lineno2)
! lineno = lineno2
self.emit('DUP_TOP')
self.visit(v)
***************
*** 670,676 ****
def __init__(self, filename):
! # XXX <module> is ? in compile.c
! self.graph = pyassem.PyFlowGraph("<module>", filename)
! self.super_init(filename)
class FunctionCodeGenerator(CodeGenerator):
--- 670,676 ----
def __init__(self, filename):
! # XXX <module> is ? in compile.c
! self.graph = pyassem.PyFlowGraph("<module>", filename)
! self.super_init(filename)
class FunctionCodeGenerator(CodeGenerator):
***************
*** 687,702 ****
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)
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)
self.set_lineno(func)
if hasTupleArg:
--- 687,702 ----
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)
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)
self.set_lineno(func)
if hasTupleArg:
***************
*** 704,711 ****
def finish(self):
! self.graph.startExitBlock()
! if not self.isLambda:
! self.emit('LOAD_CONST', None)
! self.emit('RETURN_VALUE')
def generateArgUnpack(self, args):
--- 704,711 ----
def finish(self):
! self.graph.startExitBlock()
! if not self.isLambda:
! self.emit('LOAD_CONST', None)
! self.emit('RETURN_VALUE')
def generateArgUnpack(self, args):
***************
*** 715,742 ****
self.emit('LOAD_FAST', '.nested%d' % count)
count = count + 1
! self.unpackTuple(arg)
! def unpackTuple(self, tup):
! self.emit('UNPACK_TUPLE', len(tup))
for elt in tup:
if type(elt) == types.TupleType:
! self.unpackTuple(elt)
else:
self.emit('STORE_FAST', elt)
class ClassCodeGenerator(CodeGenerator):
super_init = CodeGenerator.__init__
def __init__(self, klass, filename):
! self.graph = pyassem.PyFlowGraph(klass.name, filename,
! optimized=0)
self.super_init(filename)
lnf = walk(klass.code, LocalNameFinder(), 0)
self.locals.push(lnf.getLocals())
def finish(self):
! self.graph.startExitBlock()
self.emit('LOAD_LOCALS')
! self.emit('RETURN_VALUE')
--- 715,745 ----
self.emit('LOAD_FAST', '.nested%d' % count)
count = count + 1
! self.unpackSequence(arg)
! def unpackSequence(self, tup):
! self.emit('UNPACK_SEQUENCE', len(tup))
for elt in tup:
if type(elt) == types.TupleType:
! 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.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.emit('LOAD_LOCALS')
! self.emit('RETURN_VALUE')
***************
*** 747,758 ****
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
return args + extra, count
--- 750,761 ----
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
return args + extra, count
***************
*** 772,776 ****
def visitDict(self, node):
! pass
def visitGlobal(self, node):
--- 775,779 ----
def visitDict(self, node):
! pass
def visitGlobal(self, node):
***************
*** 782,786 ****
def visitLambda(self, node):
! pass
def visitImport(self, node):
--- 785,789 ----
def visitLambda(self, node):
! pass
def visitImport(self, node):
***************
*** 817,819 ****
for file in sys.argv[1:]:
! compile(file)
--- 820,822 ----
for file in sys.argv[1:]:
! compile(file)
Index: visitor.py
===================================================================
RCS file: /cvsroot/python/python/dist/src/Tools/compiler/compiler/visitor.py,v
retrieving revision 1.3
retrieving revision 1.4
diff -C2 -r1.3 -r1.4
*** visitor.py 2000/03/16 20:04:16 1.3
--- visitor.py 2000/08/12 20:32:46 1.4
***************
*** 39,43 ****
def __init__(self):
self.node = None
! self._cache = {}
def preorder(self, tree, visitor):
--- 39,43 ----
def __init__(self):
self.node = None
! self._cache = {}
def preorder(self, tree, visitor):
***************
*** 48,52 ****
def _preorder(self, node, *args):
! return apply(self.dispatch, (node,) + args)
def default(self, node, *args):
--- 48,52 ----
def _preorder(self, node, *args):
! return apply(self.dispatch, (node,) + args)
def default(self, node, *args):
***************
*** 57,65 ****
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
if self.VERBOSE > 0:
if self.VERBOSE == 1:
--- 57,65 ----
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
if self.VERBOSE > 0:
if self.VERBOSE == 1:
***************
*** 68,72 ****
else:
print "dispatch", className, (meth and meth.__name__ or '')
! return apply(meth, (node,) + args)
class ExampleASTVisitor(ASTVisitor):
--- 68,72 ----
else:
print "dispatch", className, (meth and meth.__name__ or '')
! return apply(meth, (node,) + args)
class ExampleASTVisitor(ASTVisitor):
***************
*** 81,89 ****
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
if self.VERBOSE > 1:
print "dispatch", className, (meth and meth.__name__ or '')
--- 81,89 ----
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
if self.VERBOSE > 1:
print "dispatch", className, (meth and meth.__name__ or '')
***************
*** 93,105 ****
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)
_walker = ASTVisitor
--- 93,105 ----
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)
_walker = ASTVisitor