Commit 873bdc18 authored by Jeremy Hylton's avatar Jeremy Hylton

satisfy the tabnanny

fix broken references to filename var in generateXXX methods
parent 1e862e8a
...@@ -80,7 +80,7 @@ class ASTVisitor: ...@@ -80,7 +80,7 @@ class ASTVisitor:
VERBOSE = 0 VERBOSE = 0
def __init__(self): def __init__(self):
self.node = None self.node = None
def preorder(self, tree, visitor): def preorder(self, tree, visitor):
"""Do preorder walk of tree using visitor""" """Do preorder walk of tree using visitor"""
...@@ -163,27 +163,26 @@ class CodeGenerator: ...@@ -163,27 +163,26 @@ class CodeGenerator:
# XXX should clean up initialization and generateXXX funcs # XXX should clean up initialization and generateXXX funcs
def __init__(self, filename="<?>"): def __init__(self, filename="<?>"):
self.filename = filename self.filename = filename
self.code = PyAssembler() self.code = PyAssembler()
self.code.setFlags(0) self.code.setFlags(0)
self.locals = misc.Stack() self.locals = misc.Stack()
self.loops = misc.Stack() self.loops = misc.Stack()
self.namespace = 0 self.namespace = 0
self.curStack = 0 self.curStack = 0
self.maxStack = 0 self.maxStack = 0
def emit(self, *args): def emit(self, *args):
# XXX could just use self.emit = self.code.emit # XXX could just use self.emit = self.code.emit
apply(self.code.emit, args) apply(self.code.emit, args)
def _generateFunctionOrLambdaCode(self, func): def _generateFunctionOrLambdaCode(self, func):
self.name = func.name self.name = func.name
self.filename = filename
# keep a lookout for 'def foo((x,y)):' # keep a lookout for 'def foo((x,y)):'
args, hasTupleArg = self.generateArglist(func.argnames) args, hasTupleArg = self.generateArglist(func.argnames)
self.code = PyAssembler(args=args, name=func.name, self.code = PyAssembler(args=args, name=func.name,
filename=filename) filename=self.filename)
self.namespace = self.OPTIMIZED self.namespace = self.OPTIMIZED
if func.varargs: if func.varargs:
self.code.setVarArgs() self.code.setVarArgs()
...@@ -191,8 +190,8 @@ class CodeGenerator: ...@@ -191,8 +190,8 @@ class CodeGenerator:
self.code.setKWArgs() self.code.setKWArgs()
lnf = walk(func.code, LocalNameFinder(args), 0) lnf = walk(func.code, LocalNameFinder(args), 0)
self.locals.push(lnf.getLocals()) self.locals.push(lnf.getLocals())
self.emit('SET_LINENO', func.lineno) self.emit('SET_LINENO', func.lineno)
if hasTupleArg: if hasTupleArg:
self.generateArgUnpack(func.argnames) self.generateArgUnpack(func.argnames)
walk(func.code, self) walk(func.code, self)
...@@ -239,7 +238,7 @@ class CodeGenerator: ...@@ -239,7 +238,7 @@ class CodeGenerator:
def generateClassCode(self, klass): def generateClassCode(self, klass):
self.code = PyAssembler(name=klass.name, self.code = PyAssembler(name=klass.name,
filename=filename) filename=self.filename)
self.emit('SET_LINENO', klass.lineno) self.emit('SET_LINENO', klass.lineno)
lnf = walk(klass.code, LocalNameFinder(), 0) lnf = walk(klass.code, LocalNameFinder(), 0)
self.locals.push(lnf.getLocals()) self.locals.push(lnf.getLocals())
...@@ -254,7 +253,7 @@ class CodeGenerator: ...@@ -254,7 +253,7 @@ class CodeGenerator:
return self.code.makeCodeObject() return self.code.makeCodeObject()
def isLocalName(self, name): def isLocalName(self, name):
return self.locals.top().has_elt(name) return self.locals.top().has_elt(name)
def _nameOp(self, prefix, name): def _nameOp(self, prefix, name):
if self.isLocalName(name): if self.isLocalName(name):
...@@ -290,8 +289,8 @@ class CodeGenerator: ...@@ -290,8 +289,8 @@ class CodeGenerator:
self.emit('SET_LINENO', node.lineno) self.emit('SET_LINENO', node.lineno)
def visitModule(self, node): def visitModule(self, node):
lnf = walk(node.node, LocalNameFinder(), 0) lnf = walk(node.node, LocalNameFinder(), 0)
self.locals.push(lnf.getLocals()) self.locals.push(lnf.getLocals())
self.visit(node.node) self.visit(node.node)
self.emit('LOAD_CONST', None) self.emit('LOAD_CONST', None)
self.emit('RETURN_VALUE') self.emit('RETURN_VALUE')
...@@ -353,15 +352,15 @@ class CodeGenerator: ...@@ -353,15 +352,15 @@ class CodeGenerator:
kw = 0 kw = 0
if hasattr(node, 'lineno'): if hasattr(node, 'lineno'):
self.emit('SET_LINENO', node.lineno) self.emit('SET_LINENO', node.lineno)
self.visit(node.node) self.visit(node.node)
for arg in node.args: for arg in node.args:
self.visit(arg) self.visit(arg)
if isinstance(arg, ast.Keyword): if isinstance(arg, ast.Keyword):
kw = kw + 1 kw = kw + 1
else: else:
pos = pos + 1 pos = pos + 1
self.emit('CALL_FUNCTION', kw << 8 | pos) self.emit('CALL_FUNCTION', kw << 8 | pos)
return 1 return 1
def visitKeyword(self, node): def visitKeyword(self, node):
self.emit('LOAD_CONST', node.name) self.emit('LOAD_CONST', node.name)
...@@ -369,24 +368,24 @@ class CodeGenerator: ...@@ -369,24 +368,24 @@ class CodeGenerator:
return 1 return 1
def visitIf(self, node): def visitIf(self, node):
after = StackRef() after = StackRef()
for test, suite in node.tests: for test, suite in node.tests:
if hasattr(test, 'lineno'): if hasattr(test, 'lineno'):
self.emit('SET_LINENO', test.lineno) self.emit('SET_LINENO', test.lineno)
else: else:
print "warning", "no line number" print "warning", "no line number"
self.visit(test) self.visit(test)
dest = StackRef() dest = StackRef()
self.emit('JUMP_IF_FALSE', dest) self.emit('JUMP_IF_FALSE', dest)
self.emit('POP_TOP') self.emit('POP_TOP')
self.visit(suite) self.visit(suite)
self.emit('JUMP_FORWARD', after) self.emit('JUMP_FORWARD', after)
dest.bind(self.code.getCurInst()) dest.bind(self.code.getCurInst())
self.emit('POP_TOP') self.emit('POP_TOP')
if node.else_: if node.else_:
self.visit(node.else_) self.visit(node.else_)
after.bind(self.code.getCurInst()) after.bind(self.code.getCurInst())
return 1 return 1
def startLoop(self): def startLoop(self):
l = Loop() l = Loop()
...@@ -516,64 +515,64 @@ class CodeGenerator: ...@@ -516,64 +515,64 @@ class CodeGenerator:
return 1 return 1
def visitCompare(self, node): def visitCompare(self, node):
"""Comment from compile.c follows: """Comment from compile.c follows:
The following code is generated for all but the last The following code is generated for all but the last
comparison in a chain: comparison in a chain:
label: on stack: opcode: jump to: label: on stack: opcode: jump to:
a <code to load b> a <code to load b>
a, b DUP_TOP a, b DUP_TOP
a, b, b ROT_THREE a, b, b ROT_THREE
b, a, b COMPARE_OP b, a, b COMPARE_OP
b, 0-or-1 JUMP_IF_FALSE L1 b, 0-or-1 JUMP_IF_FALSE L1
b, 1 POP_TOP b, 1 POP_TOP
b b
We are now ready to repeat this sequence for the next We are now ready to repeat this sequence for the next
comparison in the chain. comparison in the chain.
For the last we generate: For the last we generate:
b <code to load c> b <code to load c>
b, c COMPARE_OP b, c COMPARE_OP
0-or-1 0-or-1
If there were any jumps to L1 (i.e., there was more than one If there were any jumps to L1 (i.e., there was more than one
comparison), we generate: comparison), we generate:
0-or-1 JUMP_FORWARD L2 0-or-1 JUMP_FORWARD L2
L1: b, 0 ROT_TWO L1: b, 0 ROT_TWO
0, b POP_TOP 0, b POP_TOP
0 0
L2: 0-or-1 L2: 0-or-1
""" """
self.visit(node.expr) self.visit(node.expr)
# if refs are never emitted, subsequent bind call has no effect # if refs are never emitted, subsequent bind call has no effect
l1 = StackRef() l1 = StackRef()
l2 = StackRef() l2 = StackRef()
for op, code in node.ops[:-1]: for op, code in node.ops[:-1]:
# emit every comparison except the last # emit every comparison except the last
self.visit(code) self.visit(code)
self.emit('DUP_TOP') self.emit('DUP_TOP')
self.emit('ROT_THREE') self.emit('ROT_THREE')
self.emit('COMPARE_OP', op) self.emit('COMPARE_OP', op)
# dupTop and compareOp cancel stack effect # dupTop and compareOp cancel stack effect
self.emit('JUMP_IF_FALSE', l1) self.emit('JUMP_IF_FALSE', l1)
self.emit('POP_TOP') self.emit('POP_TOP')
if node.ops: if node.ops:
# emit the last comparison # emit the last comparison
op, code = node.ops[-1] op, code = node.ops[-1]
self.visit(code) self.visit(code)
self.emit('COMPARE_OP', op) self.emit('COMPARE_OP', op)
if len(node.ops) > 1: if len(node.ops) > 1:
self.emit('JUMP_FORWARD', l2) self.emit('JUMP_FORWARD', l2)
l1.bind(self.code.getCurInst()) l1.bind(self.code.getCurInst())
self.emit('ROT_TWO') self.emit('ROT_TWO')
self.emit('POP_TOP') self.emit('POP_TOP')
l2.bind(self.code.getCurInst()) l2.bind(self.code.getCurInst())
return 1 return 1
def visitGetattr(self, node): def visitGetattr(self, node):
self.visit(node.expr) self.visit(node.expr)
...@@ -590,7 +589,7 @@ class CodeGenerator: ...@@ -590,7 +589,7 @@ class CodeGenerator:
self.emit('BINARY_SUBSCR') self.emit('BINARY_SUBSCR')
elif node.flags == 'OP_ASSIGN': elif node.flags == 'OP_ASSIGN':
self.emit('STORE_SUBSCR') self.emit('STORE_SUBSCR')
elif node.flags == 'OP_DELETE': elif node.flags == 'OP_DELETE':
self.emit('DELETE_SUBSCR') self.emit('DELETE_SUBSCR')
return 1 return 1
...@@ -624,11 +623,11 @@ class CodeGenerator: ...@@ -624,11 +623,11 @@ class CodeGenerator:
def visitAssign(self, node): def visitAssign(self, node):
self.emit('SET_LINENO', node.lineno) self.emit('SET_LINENO', node.lineno)
self.visit(node.expr) self.visit(node.expr)
dups = len(node.nodes) - 1 dups = len(node.nodes) - 1
for i in range(len(node.nodes)): for i in range(len(node.nodes)):
elt = node.nodes[i] elt = node.nodes[i]
if i < dups: if i < dups:
self.emit('DUP_TOP') self.emit('DUP_TOP')
if isinstance(elt, ast.Node): if isinstance(elt, ast.Node):
self.visit(elt) self.visit(elt)
return 1 return 1
...@@ -659,10 +658,10 @@ class CodeGenerator: ...@@ -659,10 +658,10 @@ class CodeGenerator:
visitAssList = visitAssTuple visitAssList = visitAssTuple
def binaryOp(self, node, op): def binaryOp(self, node, op):
self.visit(node.left) self.visit(node.left)
self.visit(node.right) self.visit(node.right)
self.emit(op) self.emit(op)
return 1 return 1
def unaryOp(self, node, op): def unaryOp(self, node, op):
self.visit(node.expr) self.visit(node.expr)
...@@ -670,28 +669,28 @@ class CodeGenerator: ...@@ -670,28 +669,28 @@ class CodeGenerator:
return 1 return 1
def visitAdd(self, node): def visitAdd(self, node):
return self.binaryOp(node, 'BINARY_ADD') return self.binaryOp(node, 'BINARY_ADD')
def visitSub(self, node): def visitSub(self, node):
return self.binaryOp(node, 'BINARY_SUBTRACT') return self.binaryOp(node, 'BINARY_SUBTRACT')
def visitMul(self, node): def visitMul(self, node):
return self.binaryOp(node, 'BINARY_MULTIPLY') return self.binaryOp(node, 'BINARY_MULTIPLY')
def visitDiv(self, node): def visitDiv(self, node):
return self.binaryOp(node, 'BINARY_DIVIDE') return self.binaryOp(node, 'BINARY_DIVIDE')
def visitMod(self, node): def visitMod(self, node):
return self.binaryOp(node, 'BINARY_MODULO') return self.binaryOp(node, 'BINARY_MODULO')
def visitPower(self, node): def visitPower(self, node):
return self.binaryOp(node, 'BINARY_POWER') return self.binaryOp(node, 'BINARY_POWER')
def visitLeftShift(self, node): def visitLeftShift(self, node):
return self.binaryOp(node, 'BINARY_LSHIFT') return self.binaryOp(node, 'BINARY_LSHIFT')
def visitRightShift(self, node): def visitRightShift(self, node):
return self.binaryOp(node, 'BINARY_RSHIFT') return self.binaryOp(node, 'BINARY_RSHIFT')
def visitInvert(self, node): def visitInvert(self, node):
return self.unaryOp(node, 'UNARY_INVERT') return self.unaryOp(node, 'UNARY_INVERT')
...@@ -712,20 +711,20 @@ class CodeGenerator: ...@@ -712,20 +711,20 @@ class CodeGenerator:
return self.unaryOp(node, 'UNARY_CONVERT') return self.unaryOp(node, 'UNARY_CONVERT')
def bitOp(self, nodes, op): def bitOp(self, nodes, op):
self.visit(nodes[0]) self.visit(nodes[0])
for node in nodes[1:]: for node in nodes[1:]:
self.visit(node) self.visit(node)
self.emit(op) self.emit(op)
return 1 return 1
def visitBitand(self, node): def visitBitand(self, node):
return self.bitOp(node.nodes, 'BINARY_AND') return self.bitOp(node.nodes, 'BINARY_AND')
def visitBitor(self, node): def visitBitor(self, node):
return self.bitOp(node.nodes, 'BINARY_OR') return self.bitOp(node.nodes, 'BINARY_OR')
def visitBitxor(self, node): def visitBitxor(self, node):
return self.bitOp(node.nodes, 'BINARY_XOR') return self.bitOp(node.nodes, 'BINARY_XOR')
def visitTest(self, node, jump): def visitTest(self, node, jump):
end = StackRef() end = StackRef()
...@@ -738,22 +737,22 @@ class CodeGenerator: ...@@ -738,22 +737,22 @@ class CodeGenerator:
return 1 return 1
def visitAssert(self, node): def visitAssert(self, node):
# XXX __debug__ and AssertionError appear to be special cases # XXX __debug__ and AssertionError appear to be special cases
# -- they are always loaded as globals even if there are local # -- they are always loaded as globals even if there are local
# names. I guess this is a sort of renaming op. # names. I guess this is a sort of renaming op.
skip = StackRef() skip = StackRef()
self.emit('SET_LINENO', node.lineno) self.emit('SET_LINENO', node.lineno)
self.emit('LOAD_GLOBAL', '__debug__') self.emit('LOAD_GLOBAL', '__debug__')
self.emit('JUMP_IF_FALSE', skip) self.emit('JUMP_IF_FALSE', skip)
self.emit('POP_TOP') self.emit('POP_TOP')
self.visit(node.test) self.visit(node.test)
self.emit('JUMP_IF_TRUE', skip) self.emit('JUMP_IF_TRUE', skip)
self.emit('LOAD_GLOBAL', 'AssertionError') self.emit('LOAD_GLOBAL', 'AssertionError')
self.visit(node.fail) self.visit(node.fail)
self.emit('RAISE_VARARGS', 2) self.emit('RAISE_VARARGS', 2)
skip.bind(self.code.getCurInst()) skip.bind(self.code.getCurInst())
self.emit('POP_TOP') self.emit('POP_TOP')
return 1 return 1
def visitAnd(self, node): def visitAnd(self, node):
return self.visitTest(node, 'JUMP_IF_FALSE') return self.visitTest(node, 'JUMP_IF_FALSE')
...@@ -765,12 +764,12 @@ class CodeGenerator: ...@@ -765,12 +764,12 @@ class CodeGenerator:
self.loadName(node.name) self.loadName(node.name)
def visitConst(self, node): def visitConst(self, node):
self.emit('LOAD_CONST', node.value) self.emit('LOAD_CONST', node.value)
return 1 return 1
def visitEllipsis(self, node): def visitEllipsis(self, node):
self.emit('LOAD_CONST', Ellipsis) self.emit('LOAD_CONST', Ellipsis)
return 1 return 1
def visitTuple(self, node): def visitTuple(self, node):
for elt in node.nodes: for elt in node.nodes:
...@@ -785,76 +784,76 @@ class CodeGenerator: ...@@ -785,76 +784,76 @@ class CodeGenerator:
return 1 return 1
def visitDict(self, node): def visitDict(self, node):
self.emit('BUILD_MAP', 0) self.emit('BUILD_MAP', 0)
for k, v in node.items: for k, v in node.items:
# XXX need to add set lineno when there aren't constants # XXX need to add set lineno when there aren't constants
self.emit('DUP_TOP') self.emit('DUP_TOP')
self.visit(v) self.visit(v)
self.emit('ROT_TWO') self.emit('ROT_TWO')
self.visit(k) self.visit(k)
self.emit('STORE_SUBSCR') self.emit('STORE_SUBSCR')
return 1 return 1
def visitReturn(self, node): def visitReturn(self, node):
self.emit('SET_LINENO', node.lineno) self.emit('SET_LINENO', node.lineno)
self.visit(node.value) self.visit(node.value)
self.emit('RETURN_VALUE') self.emit('RETURN_VALUE')
return 1 return 1
def visitRaise(self, node): def visitRaise(self, node):
self.emit('SET_LINENO', node.lineno) self.emit('SET_LINENO', node.lineno)
n = 0 n = 0
if node.expr1: if node.expr1:
self.visit(node.expr1) self.visit(node.expr1)
n = n + 1 n = n + 1
if node.expr2: if node.expr2:
self.visit(node.expr2) self.visit(node.expr2)
n = n + 1 n = n + 1
if node.expr3: if node.expr3:
self.visit(node.expr3) self.visit(node.expr3)
n = n + 1 n = n + 1
self.emit('RAISE_VARARGS', n) self.emit('RAISE_VARARGS', n)
return 1 return 1
def visitPrint(self, node): def visitPrint(self, node):
self.emit('SET_LINENO', node.lineno) self.emit('SET_LINENO', node.lineno)
for child in node.nodes: for child in node.nodes:
self.visit(child) self.visit(child)
self.emit('PRINT_ITEM') self.emit('PRINT_ITEM')
return 1 return 1
def visitPrintnl(self, node): def visitPrintnl(self, node):
self.visitPrint(node) self.visitPrint(node)
self.emit('PRINT_NEWLINE') self.emit('PRINT_NEWLINE')
return 1 return 1
def visitExec(self, node): def visitExec(self, node):
self.visit(node.expr) self.visit(node.expr)
if node.locals is None: if node.locals is None:
self.emit('LOAD_CONST', None) self.emit('LOAD_CONST', None)
else: else:
self.visit(node.locals) self.visit(node.locals)
if node.globals is None: if node.globals is None:
self.emit('DUP_TOP') self.emit('DUP_TOP')
else: else:
self.visit(node.globals) self.visit(node.globals)
self.emit('EXEC_STMT') self.emit('EXEC_STMT')
class LocalNameFinder: class LocalNameFinder:
def __init__(self, names=()): def __init__(self, names=()):
self.names = misc.Set() self.names = misc.Set()
self.globals = misc.Set() self.globals = misc.Set()
for name in names: for name in names:
self.names.add(name) self.names.add(name)
def getLocals(self): def getLocals(self):
for elt in self.globals.items(): for elt in self.globals.items():
if self.names.has_elt(elt): if self.names.has_elt(elt):
self.names.remove(elt) self.names.remove(elt)
return self.names return self.names
def visitDict(self, node): def visitDict(self, node):
return 1 return 1
def visitGlobal(self, node): def visitGlobal(self, node):
for name in node.names: for name in node.names:
...@@ -863,25 +862,25 @@ class LocalNameFinder: ...@@ -863,25 +862,25 @@ class LocalNameFinder:
def visitFunction(self, node): def visitFunction(self, node):
self.names.add(node.name) self.names.add(node.name)
return 1 return 1
def visitLambda(self, node): def visitLambda(self, node):
return 1 return 1
def visitImport(self, node): def visitImport(self, node):
for name in node.names: for name in node.names:
self.names.add(name) self.names.add(name)
def visitFrom(self, node): def visitFrom(self, node):
for name in node.names: for name in node.names:
self.names.add(name) self.names.add(name)
def visitClassdef(self, node): def visitClassdef(self, node):
self.names.add(node.name) self.names.add(node.name)
return 1 return 1
def visitAssName(self, node): def visitAssName(self, node):
self.names.add(node.name) self.names.add(node.name)
class Loop: class Loop:
def __init__(self): def __init__(self):
...@@ -926,7 +925,13 @@ class CompiledModule: ...@@ -926,7 +925,13 @@ class CompiledModule:
mtime = os.stat(self.filename)[stat.ST_MTIME] mtime = os.stat(self.filename)[stat.ST_MTIME]
mtime = struct.pack('i', mtime) mtime = struct.pack('i', mtime)
return magic + mtime return magic + mtime
def compile(filename):
buf = open(filename).read()
mod = CompiledModule(buf, filename)
mod.compile()
mod.dump(filename + 'c')
if __name__ == "__main__": if __name__ == "__main__":
import getopt import getopt
...@@ -945,7 +950,4 @@ if __name__ == "__main__": ...@@ -945,7 +950,4 @@ if __name__ == "__main__":
for filename in args: for filename in args:
if VERBOSE: if VERBOSE:
print filename print filename
buf = open(filename).read() compile(filename)
mod = CompiledModule(buf, filename)
mod.compile()
mod.dump(filename + 'c')
...@@ -80,7 +80,7 @@ class ASTVisitor: ...@@ -80,7 +80,7 @@ class ASTVisitor:
VERBOSE = 0 VERBOSE = 0
def __init__(self): def __init__(self):
self.node = None self.node = None
def preorder(self, tree, visitor): def preorder(self, tree, visitor):
"""Do preorder walk of tree using visitor""" """Do preorder walk of tree using visitor"""
...@@ -163,27 +163,26 @@ class CodeGenerator: ...@@ -163,27 +163,26 @@ class CodeGenerator:
# XXX should clean up initialization and generateXXX funcs # XXX should clean up initialization and generateXXX funcs
def __init__(self, filename="<?>"): def __init__(self, filename="<?>"):
self.filename = filename self.filename = filename
self.code = PyAssembler() self.code = PyAssembler()
self.code.setFlags(0) self.code.setFlags(0)
self.locals = misc.Stack() self.locals = misc.Stack()
self.loops = misc.Stack() self.loops = misc.Stack()
self.namespace = 0 self.namespace = 0
self.curStack = 0 self.curStack = 0
self.maxStack = 0 self.maxStack = 0
def emit(self, *args): def emit(self, *args):
# XXX could just use self.emit = self.code.emit # XXX could just use self.emit = self.code.emit
apply(self.code.emit, args) apply(self.code.emit, args)
def _generateFunctionOrLambdaCode(self, func): def _generateFunctionOrLambdaCode(self, func):
self.name = func.name self.name = func.name
self.filename = filename
# keep a lookout for 'def foo((x,y)):' # keep a lookout for 'def foo((x,y)):'
args, hasTupleArg = self.generateArglist(func.argnames) args, hasTupleArg = self.generateArglist(func.argnames)
self.code = PyAssembler(args=args, name=func.name, self.code = PyAssembler(args=args, name=func.name,
filename=filename) filename=self.filename)
self.namespace = self.OPTIMIZED self.namespace = self.OPTIMIZED
if func.varargs: if func.varargs:
self.code.setVarArgs() self.code.setVarArgs()
...@@ -191,8 +190,8 @@ class CodeGenerator: ...@@ -191,8 +190,8 @@ class CodeGenerator:
self.code.setKWArgs() self.code.setKWArgs()
lnf = walk(func.code, LocalNameFinder(args), 0) lnf = walk(func.code, LocalNameFinder(args), 0)
self.locals.push(lnf.getLocals()) self.locals.push(lnf.getLocals())
self.emit('SET_LINENO', func.lineno) self.emit('SET_LINENO', func.lineno)
if hasTupleArg: if hasTupleArg:
self.generateArgUnpack(func.argnames) self.generateArgUnpack(func.argnames)
walk(func.code, self) walk(func.code, self)
...@@ -239,7 +238,7 @@ class CodeGenerator: ...@@ -239,7 +238,7 @@ class CodeGenerator:
def generateClassCode(self, klass): def generateClassCode(self, klass):
self.code = PyAssembler(name=klass.name, self.code = PyAssembler(name=klass.name,
filename=filename) filename=self.filename)
self.emit('SET_LINENO', klass.lineno) self.emit('SET_LINENO', klass.lineno)
lnf = walk(klass.code, LocalNameFinder(), 0) lnf = walk(klass.code, LocalNameFinder(), 0)
self.locals.push(lnf.getLocals()) self.locals.push(lnf.getLocals())
...@@ -254,7 +253,7 @@ class CodeGenerator: ...@@ -254,7 +253,7 @@ class CodeGenerator:
return self.code.makeCodeObject() return self.code.makeCodeObject()
def isLocalName(self, name): def isLocalName(self, name):
return self.locals.top().has_elt(name) return self.locals.top().has_elt(name)
def _nameOp(self, prefix, name): def _nameOp(self, prefix, name):
if self.isLocalName(name): if self.isLocalName(name):
...@@ -290,8 +289,8 @@ class CodeGenerator: ...@@ -290,8 +289,8 @@ class CodeGenerator:
self.emit('SET_LINENO', node.lineno) self.emit('SET_LINENO', node.lineno)
def visitModule(self, node): def visitModule(self, node):
lnf = walk(node.node, LocalNameFinder(), 0) lnf = walk(node.node, LocalNameFinder(), 0)
self.locals.push(lnf.getLocals()) self.locals.push(lnf.getLocals())
self.visit(node.node) self.visit(node.node)
self.emit('LOAD_CONST', None) self.emit('LOAD_CONST', None)
self.emit('RETURN_VALUE') self.emit('RETURN_VALUE')
...@@ -353,15 +352,15 @@ class CodeGenerator: ...@@ -353,15 +352,15 @@ class CodeGenerator:
kw = 0 kw = 0
if hasattr(node, 'lineno'): if hasattr(node, 'lineno'):
self.emit('SET_LINENO', node.lineno) self.emit('SET_LINENO', node.lineno)
self.visit(node.node) self.visit(node.node)
for arg in node.args: for arg in node.args:
self.visit(arg) self.visit(arg)
if isinstance(arg, ast.Keyword): if isinstance(arg, ast.Keyword):
kw = kw + 1 kw = kw + 1
else: else:
pos = pos + 1 pos = pos + 1
self.emit('CALL_FUNCTION', kw << 8 | pos) self.emit('CALL_FUNCTION', kw << 8 | pos)
return 1 return 1
def visitKeyword(self, node): def visitKeyword(self, node):
self.emit('LOAD_CONST', node.name) self.emit('LOAD_CONST', node.name)
...@@ -369,24 +368,24 @@ class CodeGenerator: ...@@ -369,24 +368,24 @@ class CodeGenerator:
return 1 return 1
def visitIf(self, node): def visitIf(self, node):
after = StackRef() after = StackRef()
for test, suite in node.tests: for test, suite in node.tests:
if hasattr(test, 'lineno'): if hasattr(test, 'lineno'):
self.emit('SET_LINENO', test.lineno) self.emit('SET_LINENO', test.lineno)
else: else:
print "warning", "no line number" print "warning", "no line number"
self.visit(test) self.visit(test)
dest = StackRef() dest = StackRef()
self.emit('JUMP_IF_FALSE', dest) self.emit('JUMP_IF_FALSE', dest)
self.emit('POP_TOP') self.emit('POP_TOP')
self.visit(suite) self.visit(suite)
self.emit('JUMP_FORWARD', after) self.emit('JUMP_FORWARD', after)
dest.bind(self.code.getCurInst()) dest.bind(self.code.getCurInst())
self.emit('POP_TOP') self.emit('POP_TOP')
if node.else_: if node.else_:
self.visit(node.else_) self.visit(node.else_)
after.bind(self.code.getCurInst()) after.bind(self.code.getCurInst())
return 1 return 1
def startLoop(self): def startLoop(self):
l = Loop() l = Loop()
...@@ -516,64 +515,64 @@ class CodeGenerator: ...@@ -516,64 +515,64 @@ class CodeGenerator:
return 1 return 1
def visitCompare(self, node): def visitCompare(self, node):
"""Comment from compile.c follows: """Comment from compile.c follows:
The following code is generated for all but the last The following code is generated for all but the last
comparison in a chain: comparison in a chain:
label: on stack: opcode: jump to: label: on stack: opcode: jump to:
a <code to load b> a <code to load b>
a, b DUP_TOP a, b DUP_TOP
a, b, b ROT_THREE a, b, b ROT_THREE
b, a, b COMPARE_OP b, a, b COMPARE_OP
b, 0-or-1 JUMP_IF_FALSE L1 b, 0-or-1 JUMP_IF_FALSE L1
b, 1 POP_TOP b, 1 POP_TOP
b b
We are now ready to repeat this sequence for the next We are now ready to repeat this sequence for the next
comparison in the chain. comparison in the chain.
For the last we generate: For the last we generate:
b <code to load c> b <code to load c>
b, c COMPARE_OP b, c COMPARE_OP
0-or-1 0-or-1
If there were any jumps to L1 (i.e., there was more than one If there were any jumps to L1 (i.e., there was more than one
comparison), we generate: comparison), we generate:
0-or-1 JUMP_FORWARD L2 0-or-1 JUMP_FORWARD L2
L1: b, 0 ROT_TWO L1: b, 0 ROT_TWO
0, b POP_TOP 0, b POP_TOP
0 0
L2: 0-or-1 L2: 0-or-1
""" """
self.visit(node.expr) self.visit(node.expr)
# if refs are never emitted, subsequent bind call has no effect # if refs are never emitted, subsequent bind call has no effect
l1 = StackRef() l1 = StackRef()
l2 = StackRef() l2 = StackRef()
for op, code in node.ops[:-1]: for op, code in node.ops[:-1]:
# emit every comparison except the last # emit every comparison except the last
self.visit(code) self.visit(code)
self.emit('DUP_TOP') self.emit('DUP_TOP')
self.emit('ROT_THREE') self.emit('ROT_THREE')
self.emit('COMPARE_OP', op) self.emit('COMPARE_OP', op)
# dupTop and compareOp cancel stack effect # dupTop and compareOp cancel stack effect
self.emit('JUMP_IF_FALSE', l1) self.emit('JUMP_IF_FALSE', l1)
self.emit('POP_TOP') self.emit('POP_TOP')
if node.ops: if node.ops:
# emit the last comparison # emit the last comparison
op, code = node.ops[-1] op, code = node.ops[-1]
self.visit(code) self.visit(code)
self.emit('COMPARE_OP', op) self.emit('COMPARE_OP', op)
if len(node.ops) > 1: if len(node.ops) > 1:
self.emit('JUMP_FORWARD', l2) self.emit('JUMP_FORWARD', l2)
l1.bind(self.code.getCurInst()) l1.bind(self.code.getCurInst())
self.emit('ROT_TWO') self.emit('ROT_TWO')
self.emit('POP_TOP') self.emit('POP_TOP')
l2.bind(self.code.getCurInst()) l2.bind(self.code.getCurInst())
return 1 return 1
def visitGetattr(self, node): def visitGetattr(self, node):
self.visit(node.expr) self.visit(node.expr)
...@@ -590,7 +589,7 @@ class CodeGenerator: ...@@ -590,7 +589,7 @@ class CodeGenerator:
self.emit('BINARY_SUBSCR') self.emit('BINARY_SUBSCR')
elif node.flags == 'OP_ASSIGN': elif node.flags == 'OP_ASSIGN':
self.emit('STORE_SUBSCR') self.emit('STORE_SUBSCR')
elif node.flags == 'OP_DELETE': elif node.flags == 'OP_DELETE':
self.emit('DELETE_SUBSCR') self.emit('DELETE_SUBSCR')
return 1 return 1
...@@ -624,11 +623,11 @@ class CodeGenerator: ...@@ -624,11 +623,11 @@ class CodeGenerator:
def visitAssign(self, node): def visitAssign(self, node):
self.emit('SET_LINENO', node.lineno) self.emit('SET_LINENO', node.lineno)
self.visit(node.expr) self.visit(node.expr)
dups = len(node.nodes) - 1 dups = len(node.nodes) - 1
for i in range(len(node.nodes)): for i in range(len(node.nodes)):
elt = node.nodes[i] elt = node.nodes[i]
if i < dups: if i < dups:
self.emit('DUP_TOP') self.emit('DUP_TOP')
if isinstance(elt, ast.Node): if isinstance(elt, ast.Node):
self.visit(elt) self.visit(elt)
return 1 return 1
...@@ -659,10 +658,10 @@ class CodeGenerator: ...@@ -659,10 +658,10 @@ class CodeGenerator:
visitAssList = visitAssTuple visitAssList = visitAssTuple
def binaryOp(self, node, op): def binaryOp(self, node, op):
self.visit(node.left) self.visit(node.left)
self.visit(node.right) self.visit(node.right)
self.emit(op) self.emit(op)
return 1 return 1
def unaryOp(self, node, op): def unaryOp(self, node, op):
self.visit(node.expr) self.visit(node.expr)
...@@ -670,28 +669,28 @@ class CodeGenerator: ...@@ -670,28 +669,28 @@ class CodeGenerator:
return 1 return 1
def visitAdd(self, node): def visitAdd(self, node):
return self.binaryOp(node, 'BINARY_ADD') return self.binaryOp(node, 'BINARY_ADD')
def visitSub(self, node): def visitSub(self, node):
return self.binaryOp(node, 'BINARY_SUBTRACT') return self.binaryOp(node, 'BINARY_SUBTRACT')
def visitMul(self, node): def visitMul(self, node):
return self.binaryOp(node, 'BINARY_MULTIPLY') return self.binaryOp(node, 'BINARY_MULTIPLY')
def visitDiv(self, node): def visitDiv(self, node):
return self.binaryOp(node, 'BINARY_DIVIDE') return self.binaryOp(node, 'BINARY_DIVIDE')
def visitMod(self, node): def visitMod(self, node):
return self.binaryOp(node, 'BINARY_MODULO') return self.binaryOp(node, 'BINARY_MODULO')
def visitPower(self, node): def visitPower(self, node):
return self.binaryOp(node, 'BINARY_POWER') return self.binaryOp(node, 'BINARY_POWER')
def visitLeftShift(self, node): def visitLeftShift(self, node):
return self.binaryOp(node, 'BINARY_LSHIFT') return self.binaryOp(node, 'BINARY_LSHIFT')
def visitRightShift(self, node): def visitRightShift(self, node):
return self.binaryOp(node, 'BINARY_RSHIFT') return self.binaryOp(node, 'BINARY_RSHIFT')
def visitInvert(self, node): def visitInvert(self, node):
return self.unaryOp(node, 'UNARY_INVERT') return self.unaryOp(node, 'UNARY_INVERT')
...@@ -712,20 +711,20 @@ class CodeGenerator: ...@@ -712,20 +711,20 @@ class CodeGenerator:
return self.unaryOp(node, 'UNARY_CONVERT') return self.unaryOp(node, 'UNARY_CONVERT')
def bitOp(self, nodes, op): def bitOp(self, nodes, op):
self.visit(nodes[0]) self.visit(nodes[0])
for node in nodes[1:]: for node in nodes[1:]:
self.visit(node) self.visit(node)
self.emit(op) self.emit(op)
return 1 return 1
def visitBitand(self, node): def visitBitand(self, node):
return self.bitOp(node.nodes, 'BINARY_AND') return self.bitOp(node.nodes, 'BINARY_AND')
def visitBitor(self, node): def visitBitor(self, node):
return self.bitOp(node.nodes, 'BINARY_OR') return self.bitOp(node.nodes, 'BINARY_OR')
def visitBitxor(self, node): def visitBitxor(self, node):
return self.bitOp(node.nodes, 'BINARY_XOR') return self.bitOp(node.nodes, 'BINARY_XOR')
def visitTest(self, node, jump): def visitTest(self, node, jump):
end = StackRef() end = StackRef()
...@@ -738,22 +737,22 @@ class CodeGenerator: ...@@ -738,22 +737,22 @@ class CodeGenerator:
return 1 return 1
def visitAssert(self, node): def visitAssert(self, node):
# XXX __debug__ and AssertionError appear to be special cases # XXX __debug__ and AssertionError appear to be special cases
# -- they are always loaded as globals even if there are local # -- they are always loaded as globals even if there are local
# names. I guess this is a sort of renaming op. # names. I guess this is a sort of renaming op.
skip = StackRef() skip = StackRef()
self.emit('SET_LINENO', node.lineno) self.emit('SET_LINENO', node.lineno)
self.emit('LOAD_GLOBAL', '__debug__') self.emit('LOAD_GLOBAL', '__debug__')
self.emit('JUMP_IF_FALSE', skip) self.emit('JUMP_IF_FALSE', skip)
self.emit('POP_TOP') self.emit('POP_TOP')
self.visit(node.test) self.visit(node.test)
self.emit('JUMP_IF_TRUE', skip) self.emit('JUMP_IF_TRUE', skip)
self.emit('LOAD_GLOBAL', 'AssertionError') self.emit('LOAD_GLOBAL', 'AssertionError')
self.visit(node.fail) self.visit(node.fail)
self.emit('RAISE_VARARGS', 2) self.emit('RAISE_VARARGS', 2)
skip.bind(self.code.getCurInst()) skip.bind(self.code.getCurInst())
self.emit('POP_TOP') self.emit('POP_TOP')
return 1 return 1
def visitAnd(self, node): def visitAnd(self, node):
return self.visitTest(node, 'JUMP_IF_FALSE') return self.visitTest(node, 'JUMP_IF_FALSE')
...@@ -765,12 +764,12 @@ class CodeGenerator: ...@@ -765,12 +764,12 @@ class CodeGenerator:
self.loadName(node.name) self.loadName(node.name)
def visitConst(self, node): def visitConst(self, node):
self.emit('LOAD_CONST', node.value) self.emit('LOAD_CONST', node.value)
return 1 return 1
def visitEllipsis(self, node): def visitEllipsis(self, node):
self.emit('LOAD_CONST', Ellipsis) self.emit('LOAD_CONST', Ellipsis)
return 1 return 1
def visitTuple(self, node): def visitTuple(self, node):
for elt in node.nodes: for elt in node.nodes:
...@@ -785,76 +784,76 @@ class CodeGenerator: ...@@ -785,76 +784,76 @@ class CodeGenerator:
return 1 return 1
def visitDict(self, node): def visitDict(self, node):
self.emit('BUILD_MAP', 0) self.emit('BUILD_MAP', 0)
for k, v in node.items: for k, v in node.items:
# XXX need to add set lineno when there aren't constants # XXX need to add set lineno when there aren't constants
self.emit('DUP_TOP') self.emit('DUP_TOP')
self.visit(v) self.visit(v)
self.emit('ROT_TWO') self.emit('ROT_TWO')
self.visit(k) self.visit(k)
self.emit('STORE_SUBSCR') self.emit('STORE_SUBSCR')
return 1 return 1
def visitReturn(self, node): def visitReturn(self, node):
self.emit('SET_LINENO', node.lineno) self.emit('SET_LINENO', node.lineno)
self.visit(node.value) self.visit(node.value)
self.emit('RETURN_VALUE') self.emit('RETURN_VALUE')
return 1 return 1
def visitRaise(self, node): def visitRaise(self, node):
self.emit('SET_LINENO', node.lineno) self.emit('SET_LINENO', node.lineno)
n = 0 n = 0
if node.expr1: if node.expr1:
self.visit(node.expr1) self.visit(node.expr1)
n = n + 1 n = n + 1
if node.expr2: if node.expr2:
self.visit(node.expr2) self.visit(node.expr2)
n = n + 1 n = n + 1
if node.expr3: if node.expr3:
self.visit(node.expr3) self.visit(node.expr3)
n = n + 1 n = n + 1
self.emit('RAISE_VARARGS', n) self.emit('RAISE_VARARGS', n)
return 1 return 1
def visitPrint(self, node): def visitPrint(self, node):
self.emit('SET_LINENO', node.lineno) self.emit('SET_LINENO', node.lineno)
for child in node.nodes: for child in node.nodes:
self.visit(child) self.visit(child)
self.emit('PRINT_ITEM') self.emit('PRINT_ITEM')
return 1 return 1
def visitPrintnl(self, node): def visitPrintnl(self, node):
self.visitPrint(node) self.visitPrint(node)
self.emit('PRINT_NEWLINE') self.emit('PRINT_NEWLINE')
return 1 return 1
def visitExec(self, node): def visitExec(self, node):
self.visit(node.expr) self.visit(node.expr)
if node.locals is None: if node.locals is None:
self.emit('LOAD_CONST', None) self.emit('LOAD_CONST', None)
else: else:
self.visit(node.locals) self.visit(node.locals)
if node.globals is None: if node.globals is None:
self.emit('DUP_TOP') self.emit('DUP_TOP')
else: else:
self.visit(node.globals) self.visit(node.globals)
self.emit('EXEC_STMT') self.emit('EXEC_STMT')
class LocalNameFinder: class LocalNameFinder:
def __init__(self, names=()): def __init__(self, names=()):
self.names = misc.Set() self.names = misc.Set()
self.globals = misc.Set() self.globals = misc.Set()
for name in names: for name in names:
self.names.add(name) self.names.add(name)
def getLocals(self): def getLocals(self):
for elt in self.globals.items(): for elt in self.globals.items():
if self.names.has_elt(elt): if self.names.has_elt(elt):
self.names.remove(elt) self.names.remove(elt)
return self.names return self.names
def visitDict(self, node): def visitDict(self, node):
return 1 return 1
def visitGlobal(self, node): def visitGlobal(self, node):
for name in node.names: for name in node.names:
...@@ -863,25 +862,25 @@ class LocalNameFinder: ...@@ -863,25 +862,25 @@ class LocalNameFinder:
def visitFunction(self, node): def visitFunction(self, node):
self.names.add(node.name) self.names.add(node.name)
return 1 return 1
def visitLambda(self, node): def visitLambda(self, node):
return 1 return 1
def visitImport(self, node): def visitImport(self, node):
for name in node.names: for name in node.names:
self.names.add(name) self.names.add(name)
def visitFrom(self, node): def visitFrom(self, node):
for name in node.names: for name in node.names:
self.names.add(name) self.names.add(name)
def visitClassdef(self, node): def visitClassdef(self, node):
self.names.add(node.name) self.names.add(node.name)
return 1 return 1
def visitAssName(self, node): def visitAssName(self, node):
self.names.add(node.name) self.names.add(node.name)
class Loop: class Loop:
def __init__(self): def __init__(self):
...@@ -926,7 +925,13 @@ class CompiledModule: ...@@ -926,7 +925,13 @@ class CompiledModule:
mtime = os.stat(self.filename)[stat.ST_MTIME] mtime = os.stat(self.filename)[stat.ST_MTIME]
mtime = struct.pack('i', mtime) mtime = struct.pack('i', mtime)
return magic + mtime return magic + mtime
def compile(filename):
buf = open(filename).read()
mod = CompiledModule(buf, filename)
mod.compile()
mod.dump(filename + 'c')
if __name__ == "__main__": if __name__ == "__main__":
import getopt import getopt
...@@ -945,7 +950,4 @@ if __name__ == "__main__": ...@@ -945,7 +950,4 @@ if __name__ == "__main__":
for filename in args: for filename in args:
if VERBOSE: if VERBOSE:
print filename print filename
buf = open(filename).read() compile(filename)
mod = CompiledModule(buf, filename)
mod.compile()
mod.dump(filename + 'c')
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment