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:
Jeremy Hylton 2000-02-16 00:55:44 +00:00
parent 3d9f5e4de2
commit ad9a86fb1c
2 changed files with 122 additions and 30 deletions

View File

@ -16,6 +16,7 @@
import os
import stat
import struct
import types
def parse(path):
f = open(path)
@ -177,7 +178,10 @@ def emit(self, *args):
def _generateFunctionOrLambdaCode(self, func):
self.name = func.name
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,
filename=filename)
self.namespace = self.OPTIMIZED
@ -188,8 +192,41 @@ def _generateFunctionOrLambdaCode(self, func):
lnf = walk(func.code, LocalNameFinder(args), 0)
self.locals.push(lnf.getLocals())
self.emit('SET_LINENO', func.lineno)
if hasTupleArg:
self.generateArgUnpack(func.argnames)
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):
"""Generate code for a function body"""
self._generateFunctionOrLambdaCode(func)
@ -391,7 +428,8 @@ def visitWhile(self, node):
else:
lElse = l.breakAnchor
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.emit('JUMP_IF_FALSE', lElse)
self.emit('POP_TOP')
@ -455,7 +493,8 @@ def visitTryExcept(self, node):
self.emit('POP_TOP')
self.visit(body)
self.emit('JUMP_FORWARD', end)
next.bind(self.code.getCurInst())
if expr:
next.bind(self.code.getCurInst())
self.emit('POP_TOP')
self.emit('END_FINALLY')
if node.else_:
@ -553,7 +592,6 @@ def visitSubscript(self, node):
self.emit('STORE_SUBSCR')
elif node.flags == 'OP_DELETE':
self.emit('DELETE_SUBSCR')
print
return 1
def visitSlice(self, node):
@ -596,16 +634,20 @@ def visitAssign(self, node):
return 1
def visitAssName(self, node):
# XXX handle OP_DELETE
if node.flags != 'OP_ASSIGN':
print "oops", node.flags
self.storeName(node.name)
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 node
self.visit(node.expr)
self.emit('STORE_ATTR', node.attrname)
return 1
def visitAssTuple(self, node):
@ -865,7 +907,7 @@ def compile(self):
t = transformer.Transformer()
self.ast = t.parsesuite(self.source)
cg = CodeGenerator(self.filename)
walk(self.ast, cg, walker=ExampleASTVisitor)
walk(self.ast, cg)
self.code = cg.asConst()
def dump(self, path):
@ -888,18 +930,22 @@ def _pyc_header(self):
if __name__ == "__main__":
import getopt
VERBOSE = 0
opts, args = getopt.getopt(sys.argv[1:], 'vq')
for k, v in opts:
if k == '-v':
VERBOSE = 1
ASTVisitor.VERBOSE = ASTVisitor.VERBOSE + 1
if k == '-q':
f = open('/dev/null', 'wb')
sys.stdout = f
if args:
filename = args[0]
if not args:
print "no files to compile"
else:
filename = 'test.py'
buf = open(filename).read()
mod = CompiledModule(buf, filename)
mod.compile()
mod.dump(filename + 'c')
for filename in args:
if VERBOSE:
print filename
buf = open(filename).read()
mod = CompiledModule(buf, filename)
mod.compile()
mod.dump(filename + 'c')

View File

@ -16,6 +16,7 @@
import os
import stat
import struct
import types
def parse(path):
f = open(path)
@ -177,7 +178,10 @@ def emit(self, *args):
def _generateFunctionOrLambdaCode(self, func):
self.name = func.name
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,
filename=filename)
self.namespace = self.OPTIMIZED
@ -188,8 +192,41 @@ def _generateFunctionOrLambdaCode(self, func):
lnf = walk(func.code, LocalNameFinder(args), 0)
self.locals.push(lnf.getLocals())
self.emit('SET_LINENO', func.lineno)
if hasTupleArg:
self.generateArgUnpack(func.argnames)
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):
"""Generate code for a function body"""
self._generateFunctionOrLambdaCode(func)
@ -391,7 +428,8 @@ def visitWhile(self, node):
else:
lElse = l.breakAnchor
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.emit('JUMP_IF_FALSE', lElse)
self.emit('POP_TOP')
@ -455,7 +493,8 @@ def visitTryExcept(self, node):
self.emit('POP_TOP')
self.visit(body)
self.emit('JUMP_FORWARD', end)
next.bind(self.code.getCurInst())
if expr:
next.bind(self.code.getCurInst())
self.emit('POP_TOP')
self.emit('END_FINALLY')
if node.else_:
@ -553,7 +592,6 @@ def visitSubscript(self, node):
self.emit('STORE_SUBSCR')
elif node.flags == 'OP_DELETE':
self.emit('DELETE_SUBSCR')
print
return 1
def visitSlice(self, node):
@ -596,16 +634,20 @@ def visitAssign(self, node):
return 1
def visitAssName(self, node):
# XXX handle OP_DELETE
if node.flags != 'OP_ASSIGN':
print "oops", node.flags
self.storeName(node.name)
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 node
self.visit(node.expr)
self.emit('STORE_ATTR', node.attrname)
return 1
def visitAssTuple(self, node):
@ -865,7 +907,7 @@ def compile(self):
t = transformer.Transformer()
self.ast = t.parsesuite(self.source)
cg = CodeGenerator(self.filename)
walk(self.ast, cg, walker=ExampleASTVisitor)
walk(self.ast, cg)
self.code = cg.asConst()
def dump(self, path):
@ -888,18 +930,22 @@ def _pyc_header(self):
if __name__ == "__main__":
import getopt
VERBOSE = 0
opts, args = getopt.getopt(sys.argv[1:], 'vq')
for k, v in opts:
if k == '-v':
VERBOSE = 1
ASTVisitor.VERBOSE = ASTVisitor.VERBOSE + 1
if k == '-q':
f = open('/dev/null', 'wb')
sys.stdout = f
if args:
filename = args[0]
if not args:
print "no files to compile"
else:
filename = 'test.py'
buf = open(filename).read()
mod = CompiledModule(buf, filename)
mod.compile()
mod.dump(filename + 'c')
for filename in args:
if VERBOSE:
print filename
buf = open(filename).read()
mod = CompiledModule(buf, filename)
mod.compile()
mod.dump(filename + 'c')