mirror of https://github.com/python/cpython
add optional verbose arg to walk function. it overrides the global
VERBOSE setting for the ASTVisitor add getopt handling for one or more -v args rename ForwardRef to StackRef, because it isn't necessarily directional CodeGenerator: * add assertStackEmpty method. prints warning if stack is not empty when it should be * define methods for AssName, UNARY_*, For PythonVMCode: * fix mix up between hasjrel and hasjabs for address calculation
This commit is contained in:
parent
156a975476
commit
402456020b
|
@ -23,9 +23,13 @@ def parse(path):
|
|||
t = transformer.Transformer()
|
||||
return t.parsesuite(src)
|
||||
|
||||
def walk(tree, visitor):
|
||||
def walk(tree, visitor, verbose=None):
|
||||
print visitor, "start"
|
||||
w = ASTVisitor()
|
||||
if verbose is not None:
|
||||
w.VERBOSE = verbose
|
||||
w.preorder(tree, visitor)
|
||||
print visitor, "finish"
|
||||
return w.visitor
|
||||
|
||||
class ASTVisitor:
|
||||
|
@ -64,7 +68,7 @@ class ASTVisitor:
|
|||
XXX Perhaps I can use a postorder walk for the code generator?
|
||||
"""
|
||||
|
||||
VERBOSE = 1
|
||||
VERBOSE = 0
|
||||
|
||||
def __init__(self):
|
||||
self.node = None
|
||||
|
@ -99,8 +103,12 @@ class ASTVisitor:
|
|||
self.node = node
|
||||
className = node.__class__.__name__
|
||||
meth = getattr(self.visitor, 'visit' + className, None)
|
||||
if self.VERBOSE:
|
||||
print "dispatch", className, (meth and meth.__name__ or '')
|
||||
if self.VERBOSE > 0:
|
||||
if self.VERBOSE == 1:
|
||||
if meth is None:
|
||||
print "dispatch", className
|
||||
else:
|
||||
print "dispatch", className, (meth and meth.__name__ or '')
|
||||
if meth:
|
||||
return meth(node)
|
||||
|
||||
|
@ -123,6 +131,9 @@ class CodeGenerator:
|
|||
"""
|
||||
return self.code.makeCodeObject(self.maxStack)
|
||||
|
||||
def isLocalName(self, name):
|
||||
return self.locals.top().has_elt(name)
|
||||
|
||||
def push(self, n):
|
||||
self.curStack = self.curStack + n
|
||||
if self.curStack > self.maxStack:
|
||||
|
@ -134,11 +145,15 @@ class CodeGenerator:
|
|||
else:
|
||||
self.curStack = 0
|
||||
|
||||
def assertStackEmpty(self):
|
||||
if self.curStack != 0:
|
||||
print "warning: stack should be empty"
|
||||
|
||||
def visitDiscard(self, node):
|
||||
return 1
|
||||
|
||||
def visitModule(self, node):
|
||||
lnf = walk(node.node, LocalNameFinder())
|
||||
lnf = walk(node.node, LocalNameFinder(), 0)
|
||||
self.locals.push(lnf.getLocals())
|
||||
self.visit(node.node)
|
||||
self.code.emit('LOAD_CONST', None)
|
||||
|
@ -162,11 +177,14 @@ class CodeGenerator:
|
|||
return 1
|
||||
|
||||
def visitIf(self, node):
|
||||
after = ForwardRef()
|
||||
after = StackRef()
|
||||
for test, suite in node.tests:
|
||||
self.code.setLineNo(test.lineno)
|
||||
if hasattr(test, 'lineno'):
|
||||
self.code.setLineNo(test.lineno)
|
||||
else:
|
||||
print "warning", "no line number"
|
||||
self.visit(test)
|
||||
dest = ForwardRef()
|
||||
dest = StackRef()
|
||||
self.code.jumpIfFalse(dest)
|
||||
self.code.popTop()
|
||||
self.visit(suite)
|
||||
|
@ -178,6 +196,30 @@ class CodeGenerator:
|
|||
after.bind(self.code.getCurInst())
|
||||
return 1
|
||||
|
||||
def visitFor(self, node):
|
||||
# three refs needed
|
||||
start = StackRef()
|
||||
anchor = StackRef()
|
||||
breakAnchor = StackRef()
|
||||
|
||||
self.code.emit('SET_LINENO', node.lineno)
|
||||
self.code.emit('SETUP_LOOP', breakAnchor)
|
||||
self.visit(node.list)
|
||||
self.visit(ast.Const(0))
|
||||
start.bind(self.code.getCurInst())
|
||||
self.code.setLineNo(node.lineno)
|
||||
self.code.emit('FOR_LOOP', anchor)
|
||||
self.push(1)
|
||||
self.visit(node.assign)
|
||||
self.visit(node.body)
|
||||
self.code.emit('JUMP_ABSOLUTE', start)
|
||||
anchor.bind(self.code.getCurInst())
|
||||
self.code.emit('POP_BLOCK')
|
||||
if node.else_:
|
||||
self.visit(node.else_)
|
||||
breakAnchor.bind(self.code.getCurInst())
|
||||
return 1
|
||||
|
||||
def visitCompare(self, node):
|
||||
"""Comment from compile.c follows:
|
||||
|
||||
|
@ -214,29 +256,54 @@ class CodeGenerator:
|
|||
"""
|
||||
self.visit(node.expr)
|
||||
# if refs are never emitted, subsequent bind call has no effect
|
||||
l1 = ForwardRef()
|
||||
l2 = ForwardRef()
|
||||
l1 = StackRef()
|
||||
l2 = StackRef()
|
||||
for op, code in node.ops[:-1]:
|
||||
# emit every comparison except the last
|
||||
self.visit(code)
|
||||
self.code.dupTop()
|
||||
self.code.rotThree()
|
||||
self.code.compareOp(op)
|
||||
# dupTop and compareOp cancel stack effect
|
||||
self.code.jumpIfFalse(l1)
|
||||
self.code.popTop()
|
||||
self.pop(1)
|
||||
if node.ops:
|
||||
# emit the last comparison
|
||||
op, code = node.ops[-1]
|
||||
self.visit(code)
|
||||
self.code.compareOp(op)
|
||||
self.pop(1)
|
||||
if len(node.ops) > 1:
|
||||
self.code.jumpForward(l2)
|
||||
l1.bind(self.code.getCurInst())
|
||||
self.code.rotTwo()
|
||||
self.code.popTop()
|
||||
self.pop(1)
|
||||
l2.bind(self.code.getCurInst())
|
||||
return 1
|
||||
|
||||
def visitAssign(self, node):
|
||||
self.code.setLineNo(node.lineno)
|
||||
print "Assign"
|
||||
print node.nodes
|
||||
print node.expr
|
||||
print
|
||||
self.visit(node.expr)
|
||||
for elt in node.nodes:
|
||||
if isinstance(elt, ast.Node):
|
||||
self.visit(elt)
|
||||
return 1
|
||||
|
||||
def visitAssName(self, node):
|
||||
if node.flags != 'OP_ASSIGN':
|
||||
print "oops", node.flags
|
||||
if self.isLocalName(node.name):
|
||||
self.code.emit('STORE_FAST', node.name)
|
||||
else:
|
||||
self.code.emit('STORE_GLOBAL', node.name)
|
||||
self.pop(1)
|
||||
|
||||
def binaryOp(self, node, op):
|
||||
self.visit(node.left)
|
||||
self.visit(node.right)
|
||||
|
@ -244,6 +311,11 @@ class CodeGenerator:
|
|||
self.pop(1)
|
||||
return 1
|
||||
|
||||
def unaryOp(self, node, op):
|
||||
self.visit(node.expr)
|
||||
self.code.emit(op)
|
||||
return 1
|
||||
|
||||
def visitAdd(self, node):
|
||||
return self.binaryOp(node, 'BINARY_ADD')
|
||||
|
||||
|
@ -256,9 +328,20 @@ class CodeGenerator:
|
|||
def visitDiv(self, node):
|
||||
return self.binaryOp(node, 'BINARY_DIVIDE')
|
||||
|
||||
def visitUnarySub(self, node):
|
||||
return self.unaryOp(node, 'UNARY_NEGATIVE')
|
||||
|
||||
def visitUnaryAdd(self, node):
|
||||
return self.unaryOp(node, 'UNARY_POSITIVE')
|
||||
|
||||
def visitUnaryInvert(self, node):
|
||||
return self.unaryOp(node, 'UNARY_INVERT')
|
||||
|
||||
def visitBackquote(self, node):
|
||||
return self.unaryOp(node, 'UNARY_CONVERT')
|
||||
|
||||
def visitName(self, node):
|
||||
locals = self.locals.top()
|
||||
if locals.has_elt(node.name):
|
||||
if self.isLocalName(node.name):
|
||||
self.code.loadFast(node.name)
|
||||
else:
|
||||
self.code.loadGlobal(node.name)
|
||||
|
@ -267,11 +350,21 @@ class CodeGenerator:
|
|||
def visitConst(self, node):
|
||||
self.code.loadConst(node.value)
|
||||
self.push(1)
|
||||
return 1
|
||||
|
||||
def visitTuple(self, node):
|
||||
for elt in node.nodes:
|
||||
self.visit(elt)
|
||||
self.code.emit('BUILD_TUPLE', len(node.nodes))
|
||||
self.pop(len(node.nodes))
|
||||
return 1
|
||||
|
||||
def visitReturn(self, node):
|
||||
self.code.setLineNo(node.lineno)
|
||||
self.visit(node.value)
|
||||
self.code.returnValue()
|
||||
self.pop(1)
|
||||
self.assertStackEmpty()
|
||||
return 1
|
||||
|
||||
def visitRaise(self, node):
|
||||
|
@ -326,14 +419,14 @@ class NestedCodeGenerator(CodeGenerator):
|
|||
self.code.setVarArgs()
|
||||
if func.kwargs:
|
||||
self.code.setKWArgs()
|
||||
lnf = walk(func.code, LocalNameFinder(args))
|
||||
lnf = walk(func.code, LocalNameFinder(args), 0)
|
||||
self.locals.push(lnf.getLocals())
|
||||
|
||||
def __repr__(self):
|
||||
return "<NestedCodeGenerator: %s>" % self.name
|
||||
|
||||
def visitFunction(self, node):
|
||||
lnf = walk(node.code, LocalNameFinder(node.argnames))
|
||||
lnf = walk(node.code, LocalNameFinder(node.argnames), 0)
|
||||
self.locals.push(lnf.getLocals())
|
||||
# XXX need to handle def foo((a, b)):
|
||||
self.code.setLineNo(node.lineno)
|
||||
|
@ -376,21 +469,22 @@ class Label:
|
|||
def __repr__(self):
|
||||
return "Label(%d)" % self.num
|
||||
|
||||
class ForwardRef:
|
||||
class StackRef:
|
||||
"""Manage stack locations for jumps, loops, etc."""
|
||||
count = 0
|
||||
|
||||
def __init__(self, id=None, val=None):
|
||||
if id is None:
|
||||
id = ForwardRef.count
|
||||
ForwardRef.count = ForwardRef.count + 1
|
||||
id = StackRef.count
|
||||
StackRef.count = StackRef.count + 1
|
||||
self.id = id
|
||||
self.val = val
|
||||
|
||||
def __repr__(self):
|
||||
if self.val:
|
||||
return "ForwardRef(val=%d)" % self.val
|
||||
return "StackRef(val=%d)" % self.val
|
||||
else:
|
||||
return "ForwardRef(id=%d)" % self.id
|
||||
return "StackRef(id=%d)" % self.id
|
||||
|
||||
def bind(self, inst):
|
||||
self.val = inst
|
||||
|
@ -522,7 +616,11 @@ class PythonVMCode:
|
|||
oparg = self._convertArg(opname, t[1])
|
||||
if opname == 'SET_LINENO':
|
||||
lnotab.nextLine(oparg)
|
||||
hi, lo = divmod(oparg, 256)
|
||||
try:
|
||||
hi, lo = divmod(oparg, 256)
|
||||
except TypeError:
|
||||
print opname, oparg
|
||||
raise
|
||||
lnotab.addCode(chr(self.opnum[opname]) + chr(lo) +
|
||||
chr(hi))
|
||||
# why is a module a special case?
|
||||
|
@ -551,7 +649,7 @@ class PythonVMCode:
|
|||
return tuple(l)
|
||||
|
||||
def _findOffsets(self):
|
||||
"""Find offsets for use in resolving ForwardRefs"""
|
||||
"""Find offsets for use in resolving StackRefs"""
|
||||
self.offsets = []
|
||||
cur = 0
|
||||
for t in self.insts:
|
||||
|
@ -560,10 +658,10 @@ class PythonVMCode:
|
|||
if l == 1:
|
||||
cur = cur + 1
|
||||
elif l == 2:
|
||||
arg = t[1]
|
||||
if isinstance(arg, ForwardRef):
|
||||
arg.__offset = cur
|
||||
cur = cur + 3
|
||||
arg = t[1]
|
||||
if isinstance(arg, StackRef):
|
||||
arg.__offset = cur
|
||||
|
||||
def _convertArg(self, op, arg):
|
||||
"""Convert the string representation of an arg to a number
|
||||
|
@ -577,23 +675,26 @@ class PythonVMCode:
|
|||
return arg
|
||||
if op == 'LOAD_CONST':
|
||||
return self._lookupName(arg, self.consts)
|
||||
if op == 'LOAD_FAST':
|
||||
if op in self.localOps:
|
||||
if arg in self.names:
|
||||
return self._lookupName(arg, self.varnames)
|
||||
else:
|
||||
return self._lookupName(arg, self.varnames, self.names)
|
||||
if op == 'LOAD_GLOBAL':
|
||||
if op in self.globalOps:
|
||||
return self._lookupName(arg, self.names)
|
||||
if op == 'STORE_NAME':
|
||||
return self._lookupName(arg, self.names)
|
||||
if op == 'COMPARE_OP':
|
||||
return self.cmp_op.index(arg)
|
||||
if self.hasjrel.has_elt(op):
|
||||
return self.offsets[arg.resolve()]
|
||||
if self.hasjabs.has_elt(op):
|
||||
return self.offsets[arg.resolve()] - arg.__offset
|
||||
if self.hasjabs.has_elt(op):
|
||||
return self.offsets[arg.resolve()]
|
||||
return arg
|
||||
|
||||
localOps = ('LOAD_FAST', 'STORE_FAST')
|
||||
globalOps = ('LOAD_GLOBAL', 'STORE_GLOBAL')
|
||||
|
||||
def _lookupName(self, name, list, list2=None):
|
||||
"""Return index of name in list, appending if necessary
|
||||
|
||||
|
@ -787,8 +888,15 @@ class CompiledModule:
|
|||
return magic + mtime
|
||||
|
||||
if __name__ == "__main__":
|
||||
if len(sys.argv) > 1:
|
||||
filename = sys.argv[1]
|
||||
import getopt
|
||||
|
||||
opts, args = getopt.getopt(sys.argv[1:], 'v')
|
||||
for k, v in opts:
|
||||
if k == '-v':
|
||||
ASTVisitor.VERBOSE = ASTVisitor.VERBOSE + 1
|
||||
print k
|
||||
if args:
|
||||
filename = args[0]
|
||||
else:
|
||||
filename = 'test.py'
|
||||
buf = open(filename).read()
|
||||
|
|
|
@ -23,9 +23,13 @@ def parse(path):
|
|||
t = transformer.Transformer()
|
||||
return t.parsesuite(src)
|
||||
|
||||
def walk(tree, visitor):
|
||||
def walk(tree, visitor, verbose=None):
|
||||
print visitor, "start"
|
||||
w = ASTVisitor()
|
||||
if verbose is not None:
|
||||
w.VERBOSE = verbose
|
||||
w.preorder(tree, visitor)
|
||||
print visitor, "finish"
|
||||
return w.visitor
|
||||
|
||||
class ASTVisitor:
|
||||
|
@ -64,7 +68,7 @@ class ASTVisitor:
|
|||
XXX Perhaps I can use a postorder walk for the code generator?
|
||||
"""
|
||||
|
||||
VERBOSE = 1
|
||||
VERBOSE = 0
|
||||
|
||||
def __init__(self):
|
||||
self.node = None
|
||||
|
@ -99,8 +103,12 @@ class ASTVisitor:
|
|||
self.node = node
|
||||
className = node.__class__.__name__
|
||||
meth = getattr(self.visitor, 'visit' + className, None)
|
||||
if self.VERBOSE:
|
||||
print "dispatch", className, (meth and meth.__name__ or '')
|
||||
if self.VERBOSE > 0:
|
||||
if self.VERBOSE == 1:
|
||||
if meth is None:
|
||||
print "dispatch", className
|
||||
else:
|
||||
print "dispatch", className, (meth and meth.__name__ or '')
|
||||
if meth:
|
||||
return meth(node)
|
||||
|
||||
|
@ -123,6 +131,9 @@ class CodeGenerator:
|
|||
"""
|
||||
return self.code.makeCodeObject(self.maxStack)
|
||||
|
||||
def isLocalName(self, name):
|
||||
return self.locals.top().has_elt(name)
|
||||
|
||||
def push(self, n):
|
||||
self.curStack = self.curStack + n
|
||||
if self.curStack > self.maxStack:
|
||||
|
@ -134,11 +145,15 @@ class CodeGenerator:
|
|||
else:
|
||||
self.curStack = 0
|
||||
|
||||
def assertStackEmpty(self):
|
||||
if self.curStack != 0:
|
||||
print "warning: stack should be empty"
|
||||
|
||||
def visitDiscard(self, node):
|
||||
return 1
|
||||
|
||||
def visitModule(self, node):
|
||||
lnf = walk(node.node, LocalNameFinder())
|
||||
lnf = walk(node.node, LocalNameFinder(), 0)
|
||||
self.locals.push(lnf.getLocals())
|
||||
self.visit(node.node)
|
||||
self.code.emit('LOAD_CONST', None)
|
||||
|
@ -162,11 +177,14 @@ class CodeGenerator:
|
|||
return 1
|
||||
|
||||
def visitIf(self, node):
|
||||
after = ForwardRef()
|
||||
after = StackRef()
|
||||
for test, suite in node.tests:
|
||||
self.code.setLineNo(test.lineno)
|
||||
if hasattr(test, 'lineno'):
|
||||
self.code.setLineNo(test.lineno)
|
||||
else:
|
||||
print "warning", "no line number"
|
||||
self.visit(test)
|
||||
dest = ForwardRef()
|
||||
dest = StackRef()
|
||||
self.code.jumpIfFalse(dest)
|
||||
self.code.popTop()
|
||||
self.visit(suite)
|
||||
|
@ -178,6 +196,30 @@ class CodeGenerator:
|
|||
after.bind(self.code.getCurInst())
|
||||
return 1
|
||||
|
||||
def visitFor(self, node):
|
||||
# three refs needed
|
||||
start = StackRef()
|
||||
anchor = StackRef()
|
||||
breakAnchor = StackRef()
|
||||
|
||||
self.code.emit('SET_LINENO', node.lineno)
|
||||
self.code.emit('SETUP_LOOP', breakAnchor)
|
||||
self.visit(node.list)
|
||||
self.visit(ast.Const(0))
|
||||
start.bind(self.code.getCurInst())
|
||||
self.code.setLineNo(node.lineno)
|
||||
self.code.emit('FOR_LOOP', anchor)
|
||||
self.push(1)
|
||||
self.visit(node.assign)
|
||||
self.visit(node.body)
|
||||
self.code.emit('JUMP_ABSOLUTE', start)
|
||||
anchor.bind(self.code.getCurInst())
|
||||
self.code.emit('POP_BLOCK')
|
||||
if node.else_:
|
||||
self.visit(node.else_)
|
||||
breakAnchor.bind(self.code.getCurInst())
|
||||
return 1
|
||||
|
||||
def visitCompare(self, node):
|
||||
"""Comment from compile.c follows:
|
||||
|
||||
|
@ -214,29 +256,54 @@ class CodeGenerator:
|
|||
"""
|
||||
self.visit(node.expr)
|
||||
# if refs are never emitted, subsequent bind call has no effect
|
||||
l1 = ForwardRef()
|
||||
l2 = ForwardRef()
|
||||
l1 = StackRef()
|
||||
l2 = StackRef()
|
||||
for op, code in node.ops[:-1]:
|
||||
# emit every comparison except the last
|
||||
self.visit(code)
|
||||
self.code.dupTop()
|
||||
self.code.rotThree()
|
||||
self.code.compareOp(op)
|
||||
# dupTop and compareOp cancel stack effect
|
||||
self.code.jumpIfFalse(l1)
|
||||
self.code.popTop()
|
||||
self.pop(1)
|
||||
if node.ops:
|
||||
# emit the last comparison
|
||||
op, code = node.ops[-1]
|
||||
self.visit(code)
|
||||
self.code.compareOp(op)
|
||||
self.pop(1)
|
||||
if len(node.ops) > 1:
|
||||
self.code.jumpForward(l2)
|
||||
l1.bind(self.code.getCurInst())
|
||||
self.code.rotTwo()
|
||||
self.code.popTop()
|
||||
self.pop(1)
|
||||
l2.bind(self.code.getCurInst())
|
||||
return 1
|
||||
|
||||
def visitAssign(self, node):
|
||||
self.code.setLineNo(node.lineno)
|
||||
print "Assign"
|
||||
print node.nodes
|
||||
print node.expr
|
||||
print
|
||||
self.visit(node.expr)
|
||||
for elt in node.nodes:
|
||||
if isinstance(elt, ast.Node):
|
||||
self.visit(elt)
|
||||
return 1
|
||||
|
||||
def visitAssName(self, node):
|
||||
if node.flags != 'OP_ASSIGN':
|
||||
print "oops", node.flags
|
||||
if self.isLocalName(node.name):
|
||||
self.code.emit('STORE_FAST', node.name)
|
||||
else:
|
||||
self.code.emit('STORE_GLOBAL', node.name)
|
||||
self.pop(1)
|
||||
|
||||
def binaryOp(self, node, op):
|
||||
self.visit(node.left)
|
||||
self.visit(node.right)
|
||||
|
@ -244,6 +311,11 @@ class CodeGenerator:
|
|||
self.pop(1)
|
||||
return 1
|
||||
|
||||
def unaryOp(self, node, op):
|
||||
self.visit(node.expr)
|
||||
self.code.emit(op)
|
||||
return 1
|
||||
|
||||
def visitAdd(self, node):
|
||||
return self.binaryOp(node, 'BINARY_ADD')
|
||||
|
||||
|
@ -256,9 +328,20 @@ class CodeGenerator:
|
|||
def visitDiv(self, node):
|
||||
return self.binaryOp(node, 'BINARY_DIVIDE')
|
||||
|
||||
def visitUnarySub(self, node):
|
||||
return self.unaryOp(node, 'UNARY_NEGATIVE')
|
||||
|
||||
def visitUnaryAdd(self, node):
|
||||
return self.unaryOp(node, 'UNARY_POSITIVE')
|
||||
|
||||
def visitUnaryInvert(self, node):
|
||||
return self.unaryOp(node, 'UNARY_INVERT')
|
||||
|
||||
def visitBackquote(self, node):
|
||||
return self.unaryOp(node, 'UNARY_CONVERT')
|
||||
|
||||
def visitName(self, node):
|
||||
locals = self.locals.top()
|
||||
if locals.has_elt(node.name):
|
||||
if self.isLocalName(node.name):
|
||||
self.code.loadFast(node.name)
|
||||
else:
|
||||
self.code.loadGlobal(node.name)
|
||||
|
@ -267,11 +350,21 @@ class CodeGenerator:
|
|||
def visitConst(self, node):
|
||||
self.code.loadConst(node.value)
|
||||
self.push(1)
|
||||
return 1
|
||||
|
||||
def visitTuple(self, node):
|
||||
for elt in node.nodes:
|
||||
self.visit(elt)
|
||||
self.code.emit('BUILD_TUPLE', len(node.nodes))
|
||||
self.pop(len(node.nodes))
|
||||
return 1
|
||||
|
||||
def visitReturn(self, node):
|
||||
self.code.setLineNo(node.lineno)
|
||||
self.visit(node.value)
|
||||
self.code.returnValue()
|
||||
self.pop(1)
|
||||
self.assertStackEmpty()
|
||||
return 1
|
||||
|
||||
def visitRaise(self, node):
|
||||
|
@ -326,14 +419,14 @@ class NestedCodeGenerator(CodeGenerator):
|
|||
self.code.setVarArgs()
|
||||
if func.kwargs:
|
||||
self.code.setKWArgs()
|
||||
lnf = walk(func.code, LocalNameFinder(args))
|
||||
lnf = walk(func.code, LocalNameFinder(args), 0)
|
||||
self.locals.push(lnf.getLocals())
|
||||
|
||||
def __repr__(self):
|
||||
return "<NestedCodeGenerator: %s>" % self.name
|
||||
|
||||
def visitFunction(self, node):
|
||||
lnf = walk(node.code, LocalNameFinder(node.argnames))
|
||||
lnf = walk(node.code, LocalNameFinder(node.argnames), 0)
|
||||
self.locals.push(lnf.getLocals())
|
||||
# XXX need to handle def foo((a, b)):
|
||||
self.code.setLineNo(node.lineno)
|
||||
|
@ -376,21 +469,22 @@ class Label:
|
|||
def __repr__(self):
|
||||
return "Label(%d)" % self.num
|
||||
|
||||
class ForwardRef:
|
||||
class StackRef:
|
||||
"""Manage stack locations for jumps, loops, etc."""
|
||||
count = 0
|
||||
|
||||
def __init__(self, id=None, val=None):
|
||||
if id is None:
|
||||
id = ForwardRef.count
|
||||
ForwardRef.count = ForwardRef.count + 1
|
||||
id = StackRef.count
|
||||
StackRef.count = StackRef.count + 1
|
||||
self.id = id
|
||||
self.val = val
|
||||
|
||||
def __repr__(self):
|
||||
if self.val:
|
||||
return "ForwardRef(val=%d)" % self.val
|
||||
return "StackRef(val=%d)" % self.val
|
||||
else:
|
||||
return "ForwardRef(id=%d)" % self.id
|
||||
return "StackRef(id=%d)" % self.id
|
||||
|
||||
def bind(self, inst):
|
||||
self.val = inst
|
||||
|
@ -522,7 +616,11 @@ class PythonVMCode:
|
|||
oparg = self._convertArg(opname, t[1])
|
||||
if opname == 'SET_LINENO':
|
||||
lnotab.nextLine(oparg)
|
||||
hi, lo = divmod(oparg, 256)
|
||||
try:
|
||||
hi, lo = divmod(oparg, 256)
|
||||
except TypeError:
|
||||
print opname, oparg
|
||||
raise
|
||||
lnotab.addCode(chr(self.opnum[opname]) + chr(lo) +
|
||||
chr(hi))
|
||||
# why is a module a special case?
|
||||
|
@ -551,7 +649,7 @@ class PythonVMCode:
|
|||
return tuple(l)
|
||||
|
||||
def _findOffsets(self):
|
||||
"""Find offsets for use in resolving ForwardRefs"""
|
||||
"""Find offsets for use in resolving StackRefs"""
|
||||
self.offsets = []
|
||||
cur = 0
|
||||
for t in self.insts:
|
||||
|
@ -560,10 +658,10 @@ class PythonVMCode:
|
|||
if l == 1:
|
||||
cur = cur + 1
|
||||
elif l == 2:
|
||||
arg = t[1]
|
||||
if isinstance(arg, ForwardRef):
|
||||
arg.__offset = cur
|
||||
cur = cur + 3
|
||||
arg = t[1]
|
||||
if isinstance(arg, StackRef):
|
||||
arg.__offset = cur
|
||||
|
||||
def _convertArg(self, op, arg):
|
||||
"""Convert the string representation of an arg to a number
|
||||
|
@ -577,23 +675,26 @@ class PythonVMCode:
|
|||
return arg
|
||||
if op == 'LOAD_CONST':
|
||||
return self._lookupName(arg, self.consts)
|
||||
if op == 'LOAD_FAST':
|
||||
if op in self.localOps:
|
||||
if arg in self.names:
|
||||
return self._lookupName(arg, self.varnames)
|
||||
else:
|
||||
return self._lookupName(arg, self.varnames, self.names)
|
||||
if op == 'LOAD_GLOBAL':
|
||||
if op in self.globalOps:
|
||||
return self._lookupName(arg, self.names)
|
||||
if op == 'STORE_NAME':
|
||||
return self._lookupName(arg, self.names)
|
||||
if op == 'COMPARE_OP':
|
||||
return self.cmp_op.index(arg)
|
||||
if self.hasjrel.has_elt(op):
|
||||
return self.offsets[arg.resolve()]
|
||||
if self.hasjabs.has_elt(op):
|
||||
return self.offsets[arg.resolve()] - arg.__offset
|
||||
if self.hasjabs.has_elt(op):
|
||||
return self.offsets[arg.resolve()]
|
||||
return arg
|
||||
|
||||
localOps = ('LOAD_FAST', 'STORE_FAST')
|
||||
globalOps = ('LOAD_GLOBAL', 'STORE_GLOBAL')
|
||||
|
||||
def _lookupName(self, name, list, list2=None):
|
||||
"""Return index of name in list, appending if necessary
|
||||
|
||||
|
@ -787,8 +888,15 @@ class CompiledModule:
|
|||
return magic + mtime
|
||||
|
||||
if __name__ == "__main__":
|
||||
if len(sys.argv) > 1:
|
||||
filename = sys.argv[1]
|
||||
import getopt
|
||||
|
||||
opts, args = getopt.getopt(sys.argv[1:], 'v')
|
||||
for k, v in opts:
|
||||
if k == '-v':
|
||||
ASTVisitor.VERBOSE = ASTVisitor.VERBOSE + 1
|
||||
print k
|
||||
if args:
|
||||
filename = args[0]
|
||||
else:
|
||||
filename = 'test.py'
|
||||
buf = open(filename).read()
|
||||
|
|
Loading…
Reference in New Issue