mirror of https://github.com/python/cpython
support for arglists with implicit tuple unpacks
- added a number of support methods to generate code just before the body - hack protocol for communicating number of args to PyAssembler fix TryExcept generation for case where exception handler has no body fix visitAssAttr add comment about incomplete visitAssName stop using the ExampleASTVisitor change script invocation to accept a list of .py files (e.g. Lib/*.py)
This commit is contained in:
parent
3d9f5e4de2
commit
ad9a86fb1c
|
@ -16,6 +16,7 @@ import sys
|
||||||
import os
|
import os
|
||||||
import stat
|
import stat
|
||||||
import struct
|
import struct
|
||||||
|
import types
|
||||||
|
|
||||||
def parse(path):
|
def parse(path):
|
||||||
f = open(path)
|
f = open(path)
|
||||||
|
@ -177,7 +178,10 @@ class CodeGenerator:
|
||||||
def _generateFunctionOrLambdaCode(self, func):
|
def _generateFunctionOrLambdaCode(self, func):
|
||||||
self.name = func.name
|
self.name = func.name
|
||||||
self.filename = filename
|
self.filename = filename
|
||||||
args = func.argnames
|
|
||||||
|
# keep a lookout for 'def foo((x,y)):'
|
||||||
|
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=filename)
|
||||||
self.namespace = self.OPTIMIZED
|
self.namespace = self.OPTIMIZED
|
||||||
|
@ -188,8 +192,41 @@ class CodeGenerator:
|
||||||
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:
|
||||||
|
self.generateArgUnpack(func.argnames)
|
||||||
walk(func.code, self)
|
walk(func.code, self)
|
||||||
|
|
||||||
|
def generateArglist(self, arglist):
|
||||||
|
args = []
|
||||||
|
extra = []
|
||||||
|
count = 0
|
||||||
|
for elt in arglist:
|
||||||
|
if type(elt) == types.StringType:
|
||||||
|
args.append(elt)
|
||||||
|
elif type(elt) == types.TupleType:
|
||||||
|
args.append(".nested%d" % count)
|
||||||
|
count = count + 1
|
||||||
|
extra.extend(misc.flatten(elt))
|
||||||
|
else:
|
||||||
|
raise ValueError, "unexpect argument type:", elt
|
||||||
|
return args + extra, count
|
||||||
|
|
||||||
|
def generateArgUnpack(self, args):
|
||||||
|
count = 0
|
||||||
|
for arg in args:
|
||||||
|
if type(arg) == types.TupleType:
|
||||||
|
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)
|
||||||
|
|
||||||
def generateFunctionCode(self, func):
|
def generateFunctionCode(self, func):
|
||||||
"""Generate code for a function body"""
|
"""Generate code for a function body"""
|
||||||
self._generateFunctionOrLambdaCode(func)
|
self._generateFunctionOrLambdaCode(func)
|
||||||
|
@ -391,7 +428,8 @@ class CodeGenerator:
|
||||||
else:
|
else:
|
||||||
lElse = l.breakAnchor
|
lElse = l.breakAnchor
|
||||||
l.startAnchor.bind(self.code.getCurInst())
|
l.startAnchor.bind(self.code.getCurInst())
|
||||||
self.emit('SET_LINENO', node.test.lineno)
|
if hasattr(node.test, 'lineno'):
|
||||||
|
self.emit('SET_LINENO', node.test.lineno)
|
||||||
self.visit(node.test)
|
self.visit(node.test)
|
||||||
self.emit('JUMP_IF_FALSE', lElse)
|
self.emit('JUMP_IF_FALSE', lElse)
|
||||||
self.emit('POP_TOP')
|
self.emit('POP_TOP')
|
||||||
|
@ -455,7 +493,8 @@ class CodeGenerator:
|
||||||
self.emit('POP_TOP')
|
self.emit('POP_TOP')
|
||||||
self.visit(body)
|
self.visit(body)
|
||||||
self.emit('JUMP_FORWARD', end)
|
self.emit('JUMP_FORWARD', end)
|
||||||
next.bind(self.code.getCurInst())
|
if expr:
|
||||||
|
next.bind(self.code.getCurInst())
|
||||||
self.emit('POP_TOP')
|
self.emit('POP_TOP')
|
||||||
self.emit('END_FINALLY')
|
self.emit('END_FINALLY')
|
||||||
if node.else_:
|
if node.else_:
|
||||||
|
@ -553,7 +592,6 @@ class CodeGenerator:
|
||||||
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')
|
||||||
print
|
|
||||||
return 1
|
return 1
|
||||||
|
|
||||||
def visitSlice(self, node):
|
def visitSlice(self, node):
|
||||||
|
@ -596,16 +634,20 @@ class CodeGenerator:
|
||||||
return 1
|
return 1
|
||||||
|
|
||||||
def visitAssName(self, node):
|
def visitAssName(self, node):
|
||||||
|
# XXX handle OP_DELETE
|
||||||
if node.flags != 'OP_ASSIGN':
|
if node.flags != 'OP_ASSIGN':
|
||||||
print "oops", node.flags
|
print "oops", node.flags
|
||||||
self.storeName(node.name)
|
self.storeName(node.name)
|
||||||
|
|
||||||
def visitAssAttr(self, node):
|
def visitAssAttr(self, node):
|
||||||
if node.flags != 'OP_ASSIGN':
|
self.visit(node.expr)
|
||||||
|
if node.flags == 'OP_ASSIGN':
|
||||||
|
self.emit('STORE_ATTR', node.attrname)
|
||||||
|
elif node.flags == 'OP_DELETE':
|
||||||
|
self.emit('DELETE_ATTR', node.attrname)
|
||||||
|
else:
|
||||||
print "warning: unexpected flags:", node.flags
|
print "warning: unexpected flags:", node.flags
|
||||||
print node
|
print node
|
||||||
self.visit(node.expr)
|
|
||||||
self.emit('STORE_ATTR', node.attrname)
|
|
||||||
return 1
|
return 1
|
||||||
|
|
||||||
def visitAssTuple(self, node):
|
def visitAssTuple(self, node):
|
||||||
|
@ -865,7 +907,7 @@ class CompiledModule:
|
||||||
t = transformer.Transformer()
|
t = transformer.Transformer()
|
||||||
self.ast = t.parsesuite(self.source)
|
self.ast = t.parsesuite(self.source)
|
||||||
cg = CodeGenerator(self.filename)
|
cg = CodeGenerator(self.filename)
|
||||||
walk(self.ast, cg, walker=ExampleASTVisitor)
|
walk(self.ast, cg)
|
||||||
self.code = cg.asConst()
|
self.code = cg.asConst()
|
||||||
|
|
||||||
def dump(self, path):
|
def dump(self, path):
|
||||||
|
@ -888,18 +930,22 @@ class CompiledModule:
|
||||||
if __name__ == "__main__":
|
if __name__ == "__main__":
|
||||||
import getopt
|
import getopt
|
||||||
|
|
||||||
|
VERBOSE = 0
|
||||||
opts, args = getopt.getopt(sys.argv[1:], 'vq')
|
opts, args = getopt.getopt(sys.argv[1:], 'vq')
|
||||||
for k, v in opts:
|
for k, v in opts:
|
||||||
if k == '-v':
|
if k == '-v':
|
||||||
|
VERBOSE = 1
|
||||||
ASTVisitor.VERBOSE = ASTVisitor.VERBOSE + 1
|
ASTVisitor.VERBOSE = ASTVisitor.VERBOSE + 1
|
||||||
if k == '-q':
|
if k == '-q':
|
||||||
f = open('/dev/null', 'wb')
|
f = open('/dev/null', 'wb')
|
||||||
sys.stdout = f
|
sys.stdout = f
|
||||||
if args:
|
if not args:
|
||||||
filename = args[0]
|
print "no files to compile"
|
||||||
else:
|
else:
|
||||||
filename = 'test.py'
|
for filename in args:
|
||||||
buf = open(filename).read()
|
if VERBOSE:
|
||||||
mod = CompiledModule(buf, filename)
|
print filename
|
||||||
mod.compile()
|
buf = open(filename).read()
|
||||||
mod.dump(filename + 'c')
|
mod = CompiledModule(buf, filename)
|
||||||
|
mod.compile()
|
||||||
|
mod.dump(filename + 'c')
|
||||||
|
|
|
@ -16,6 +16,7 @@ import sys
|
||||||
import os
|
import os
|
||||||
import stat
|
import stat
|
||||||
import struct
|
import struct
|
||||||
|
import types
|
||||||
|
|
||||||
def parse(path):
|
def parse(path):
|
||||||
f = open(path)
|
f = open(path)
|
||||||
|
@ -177,7 +178,10 @@ class CodeGenerator:
|
||||||
def _generateFunctionOrLambdaCode(self, func):
|
def _generateFunctionOrLambdaCode(self, func):
|
||||||
self.name = func.name
|
self.name = func.name
|
||||||
self.filename = filename
|
self.filename = filename
|
||||||
args = func.argnames
|
|
||||||
|
# keep a lookout for 'def foo((x,y)):'
|
||||||
|
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=filename)
|
||||||
self.namespace = self.OPTIMIZED
|
self.namespace = self.OPTIMIZED
|
||||||
|
@ -188,8 +192,41 @@ class CodeGenerator:
|
||||||
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:
|
||||||
|
self.generateArgUnpack(func.argnames)
|
||||||
walk(func.code, self)
|
walk(func.code, self)
|
||||||
|
|
||||||
|
def generateArglist(self, arglist):
|
||||||
|
args = []
|
||||||
|
extra = []
|
||||||
|
count = 0
|
||||||
|
for elt in arglist:
|
||||||
|
if type(elt) == types.StringType:
|
||||||
|
args.append(elt)
|
||||||
|
elif type(elt) == types.TupleType:
|
||||||
|
args.append(".nested%d" % count)
|
||||||
|
count = count + 1
|
||||||
|
extra.extend(misc.flatten(elt))
|
||||||
|
else:
|
||||||
|
raise ValueError, "unexpect argument type:", elt
|
||||||
|
return args + extra, count
|
||||||
|
|
||||||
|
def generateArgUnpack(self, args):
|
||||||
|
count = 0
|
||||||
|
for arg in args:
|
||||||
|
if type(arg) == types.TupleType:
|
||||||
|
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)
|
||||||
|
|
||||||
def generateFunctionCode(self, func):
|
def generateFunctionCode(self, func):
|
||||||
"""Generate code for a function body"""
|
"""Generate code for a function body"""
|
||||||
self._generateFunctionOrLambdaCode(func)
|
self._generateFunctionOrLambdaCode(func)
|
||||||
|
@ -391,7 +428,8 @@ class CodeGenerator:
|
||||||
else:
|
else:
|
||||||
lElse = l.breakAnchor
|
lElse = l.breakAnchor
|
||||||
l.startAnchor.bind(self.code.getCurInst())
|
l.startAnchor.bind(self.code.getCurInst())
|
||||||
self.emit('SET_LINENO', node.test.lineno)
|
if hasattr(node.test, 'lineno'):
|
||||||
|
self.emit('SET_LINENO', node.test.lineno)
|
||||||
self.visit(node.test)
|
self.visit(node.test)
|
||||||
self.emit('JUMP_IF_FALSE', lElse)
|
self.emit('JUMP_IF_FALSE', lElse)
|
||||||
self.emit('POP_TOP')
|
self.emit('POP_TOP')
|
||||||
|
@ -455,7 +493,8 @@ class CodeGenerator:
|
||||||
self.emit('POP_TOP')
|
self.emit('POP_TOP')
|
||||||
self.visit(body)
|
self.visit(body)
|
||||||
self.emit('JUMP_FORWARD', end)
|
self.emit('JUMP_FORWARD', end)
|
||||||
next.bind(self.code.getCurInst())
|
if expr:
|
||||||
|
next.bind(self.code.getCurInst())
|
||||||
self.emit('POP_TOP')
|
self.emit('POP_TOP')
|
||||||
self.emit('END_FINALLY')
|
self.emit('END_FINALLY')
|
||||||
if node.else_:
|
if node.else_:
|
||||||
|
@ -553,7 +592,6 @@ class CodeGenerator:
|
||||||
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')
|
||||||
print
|
|
||||||
return 1
|
return 1
|
||||||
|
|
||||||
def visitSlice(self, node):
|
def visitSlice(self, node):
|
||||||
|
@ -596,16 +634,20 @@ class CodeGenerator:
|
||||||
return 1
|
return 1
|
||||||
|
|
||||||
def visitAssName(self, node):
|
def visitAssName(self, node):
|
||||||
|
# XXX handle OP_DELETE
|
||||||
if node.flags != 'OP_ASSIGN':
|
if node.flags != 'OP_ASSIGN':
|
||||||
print "oops", node.flags
|
print "oops", node.flags
|
||||||
self.storeName(node.name)
|
self.storeName(node.name)
|
||||||
|
|
||||||
def visitAssAttr(self, node):
|
def visitAssAttr(self, node):
|
||||||
if node.flags != 'OP_ASSIGN':
|
self.visit(node.expr)
|
||||||
|
if node.flags == 'OP_ASSIGN':
|
||||||
|
self.emit('STORE_ATTR', node.attrname)
|
||||||
|
elif node.flags == 'OP_DELETE':
|
||||||
|
self.emit('DELETE_ATTR', node.attrname)
|
||||||
|
else:
|
||||||
print "warning: unexpected flags:", node.flags
|
print "warning: unexpected flags:", node.flags
|
||||||
print node
|
print node
|
||||||
self.visit(node.expr)
|
|
||||||
self.emit('STORE_ATTR', node.attrname)
|
|
||||||
return 1
|
return 1
|
||||||
|
|
||||||
def visitAssTuple(self, node):
|
def visitAssTuple(self, node):
|
||||||
|
@ -865,7 +907,7 @@ class CompiledModule:
|
||||||
t = transformer.Transformer()
|
t = transformer.Transformer()
|
||||||
self.ast = t.parsesuite(self.source)
|
self.ast = t.parsesuite(self.source)
|
||||||
cg = CodeGenerator(self.filename)
|
cg = CodeGenerator(self.filename)
|
||||||
walk(self.ast, cg, walker=ExampleASTVisitor)
|
walk(self.ast, cg)
|
||||||
self.code = cg.asConst()
|
self.code = cg.asConst()
|
||||||
|
|
||||||
def dump(self, path):
|
def dump(self, path):
|
||||||
|
@ -888,18 +930,22 @@ class CompiledModule:
|
||||||
if __name__ == "__main__":
|
if __name__ == "__main__":
|
||||||
import getopt
|
import getopt
|
||||||
|
|
||||||
|
VERBOSE = 0
|
||||||
opts, args = getopt.getopt(sys.argv[1:], 'vq')
|
opts, args = getopt.getopt(sys.argv[1:], 'vq')
|
||||||
for k, v in opts:
|
for k, v in opts:
|
||||||
if k == '-v':
|
if k == '-v':
|
||||||
|
VERBOSE = 1
|
||||||
ASTVisitor.VERBOSE = ASTVisitor.VERBOSE + 1
|
ASTVisitor.VERBOSE = ASTVisitor.VERBOSE + 1
|
||||||
if k == '-q':
|
if k == '-q':
|
||||||
f = open('/dev/null', 'wb')
|
f = open('/dev/null', 'wb')
|
||||||
sys.stdout = f
|
sys.stdout = f
|
||||||
if args:
|
if not args:
|
||||||
filename = args[0]
|
print "no files to compile"
|
||||||
else:
|
else:
|
||||||
filename = 'test.py'
|
for filename in args:
|
||||||
buf = open(filename).read()
|
if VERBOSE:
|
||||||
mod = CompiledModule(buf, filename)
|
print filename
|
||||||
mod.compile()
|
buf = open(filename).read()
|
||||||
mod.dump(filename + 'c')
|
mod = CompiledModule(buf, filename)
|
||||||
|
mod.compile()
|
||||||
|
mod.dump(filename + 'c')
|
||||||
|
|
Loading…
Reference in New Issue