add support for Lambda nodes
change resolution of local name ops (LOAD_FAST). i think it makes sense now. if it is an argument or a local var name that it used, it must be in varnames. if it is a local var name that is used, it must also be in names
This commit is contained in:
parent
5de8cee73f
commit
76d01b820c
|
@ -167,8 +167,7 @@ class CodeGenerator:
|
||||||
self.curStack = 0
|
self.curStack = 0
|
||||||
self.maxStack = 0
|
self.maxStack = 0
|
||||||
|
|
||||||
def generateFunctionCode(self, func, filename='<?>'):
|
def _generateFunctionOrLambdaCode(self, func, filename):
|
||||||
"""Generate code for a function body"""
|
|
||||||
self.name = func.name
|
self.name = func.name
|
||||||
self.filename = filename
|
self.filename = filename
|
||||||
args = func.argnames
|
args = func.argnames
|
||||||
|
@ -183,9 +182,17 @@ class CodeGenerator:
|
||||||
self.locals.push(lnf.getLocals())
|
self.locals.push(lnf.getLocals())
|
||||||
self.code.setLineNo(func.lineno)
|
self.code.setLineNo(func.lineno)
|
||||||
walk(func.code, self)
|
walk(func.code, self)
|
||||||
|
|
||||||
|
def generateFunctionCode(self, func, filename='<?>'):
|
||||||
|
"""Generate code for a function body"""
|
||||||
|
self._generateFunctionOrLambdaCode(func, filename)
|
||||||
self.code.emit('LOAD_CONST', None)
|
self.code.emit('LOAD_CONST', None)
|
||||||
self.code.emit('RETURN_VALUE')
|
self.code.emit('RETURN_VALUE')
|
||||||
|
|
||||||
|
def generateLambdaCode(self, func, filename='<?>'):
|
||||||
|
self._generateFunctionOrLambdaCode(func, filename)
|
||||||
|
self.code.emit('RETURN_VALUE')
|
||||||
|
|
||||||
def emit(self):
|
def emit(self):
|
||||||
"""Create a Python code object
|
"""Create a Python code object
|
||||||
|
|
||||||
|
@ -267,17 +274,28 @@ class CodeGenerator:
|
||||||
self.code.emit('IMPORT_FROM', name)
|
self.code.emit('IMPORT_FROM', name)
|
||||||
self.code.emit('POP_TOP')
|
self.code.emit('POP_TOP')
|
||||||
|
|
||||||
def visitFunction(self, node):
|
def _visitFuncOrLambda(self, node, kind):
|
||||||
|
"""Code common to Function and Lambda nodes"""
|
||||||
codeBody = CodeGenerator()
|
codeBody = CodeGenerator()
|
||||||
codeBody.generateFunctionCode(node, filename=self.filename)
|
meth = getattr(codeBody, 'generate%sCode' % kind)
|
||||||
|
meth(node, filename=self.filename)
|
||||||
self.code.setLineNo(node.lineno)
|
self.code.setLineNo(node.lineno)
|
||||||
for default in node.defaults:
|
for default in node.defaults:
|
||||||
self.visit(default)
|
self.visit(default)
|
||||||
self.code.emit('LOAD_CONST', codeBody)
|
self.code.emit('LOAD_CONST', codeBody)
|
||||||
self.code.emit('MAKE_FUNCTION', len(node.defaults))
|
self.code.emit('MAKE_FUNCTION', len(node.defaults))
|
||||||
|
|
||||||
|
def visitFunction(self, node):
|
||||||
|
self._visitFuncOrLambda(node, 'Function')
|
||||||
self.storeName(node.name)
|
self.storeName(node.name)
|
||||||
return 1
|
return 1
|
||||||
|
|
||||||
|
def visitLambda(self, node):
|
||||||
|
node.name = '<lambda>'
|
||||||
|
node.varargs = node.kwargs = None
|
||||||
|
self._visitFuncOrLambda(node, 'Lambda')
|
||||||
|
return 1
|
||||||
|
|
||||||
def visitCallFunc(self, node):
|
def visitCallFunc(self, node):
|
||||||
if hasattr(node, 'lineno'):
|
if hasattr(node, 'lineno'):
|
||||||
self.code.emit('SET_LINENO', node.lineno)
|
self.code.emit('SET_LINENO', node.lineno)
|
||||||
|
@ -649,6 +667,9 @@ class LocalNameFinder:
|
||||||
self.names.add(node.name)
|
self.names.add(node.name)
|
||||||
return 1
|
return 1
|
||||||
|
|
||||||
|
def visitLambda(self, node):
|
||||||
|
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)
|
||||||
|
@ -878,10 +899,9 @@ class PythonVMCode:
|
||||||
if op == 'LOAD_CONST':
|
if op == 'LOAD_CONST':
|
||||||
return self._lookupName(arg, self.consts)
|
return self._lookupName(arg, self.consts)
|
||||||
if op in self.localOps:
|
if op in self.localOps:
|
||||||
if arg in self.names:
|
# make sure it's in self.names, but use the bytecode offset
|
||||||
return self._lookupName(arg, self.varnames)
|
self._lookupName(arg, self.names)
|
||||||
else:
|
return self._lookupName(arg, self.varnames)
|
||||||
return self._lookupName(arg, self.varnames, self.names)
|
|
||||||
if op in self.globalOps:
|
if op in self.globalOps:
|
||||||
return self._lookupName(arg, self.names)
|
return self._lookupName(arg, self.names)
|
||||||
if op in self.nameOps:
|
if op in self.nameOps:
|
||||||
|
|
|
@ -167,8 +167,7 @@ class CodeGenerator:
|
||||||
self.curStack = 0
|
self.curStack = 0
|
||||||
self.maxStack = 0
|
self.maxStack = 0
|
||||||
|
|
||||||
def generateFunctionCode(self, func, filename='<?>'):
|
def _generateFunctionOrLambdaCode(self, func, filename):
|
||||||
"""Generate code for a function body"""
|
|
||||||
self.name = func.name
|
self.name = func.name
|
||||||
self.filename = filename
|
self.filename = filename
|
||||||
args = func.argnames
|
args = func.argnames
|
||||||
|
@ -183,9 +182,17 @@ class CodeGenerator:
|
||||||
self.locals.push(lnf.getLocals())
|
self.locals.push(lnf.getLocals())
|
||||||
self.code.setLineNo(func.lineno)
|
self.code.setLineNo(func.lineno)
|
||||||
walk(func.code, self)
|
walk(func.code, self)
|
||||||
|
|
||||||
|
def generateFunctionCode(self, func, filename='<?>'):
|
||||||
|
"""Generate code for a function body"""
|
||||||
|
self._generateFunctionOrLambdaCode(func, filename)
|
||||||
self.code.emit('LOAD_CONST', None)
|
self.code.emit('LOAD_CONST', None)
|
||||||
self.code.emit('RETURN_VALUE')
|
self.code.emit('RETURN_VALUE')
|
||||||
|
|
||||||
|
def generateLambdaCode(self, func, filename='<?>'):
|
||||||
|
self._generateFunctionOrLambdaCode(func, filename)
|
||||||
|
self.code.emit('RETURN_VALUE')
|
||||||
|
|
||||||
def emit(self):
|
def emit(self):
|
||||||
"""Create a Python code object
|
"""Create a Python code object
|
||||||
|
|
||||||
|
@ -267,17 +274,28 @@ class CodeGenerator:
|
||||||
self.code.emit('IMPORT_FROM', name)
|
self.code.emit('IMPORT_FROM', name)
|
||||||
self.code.emit('POP_TOP')
|
self.code.emit('POP_TOP')
|
||||||
|
|
||||||
def visitFunction(self, node):
|
def _visitFuncOrLambda(self, node, kind):
|
||||||
|
"""Code common to Function and Lambda nodes"""
|
||||||
codeBody = CodeGenerator()
|
codeBody = CodeGenerator()
|
||||||
codeBody.generateFunctionCode(node, filename=self.filename)
|
meth = getattr(codeBody, 'generate%sCode' % kind)
|
||||||
|
meth(node, filename=self.filename)
|
||||||
self.code.setLineNo(node.lineno)
|
self.code.setLineNo(node.lineno)
|
||||||
for default in node.defaults:
|
for default in node.defaults:
|
||||||
self.visit(default)
|
self.visit(default)
|
||||||
self.code.emit('LOAD_CONST', codeBody)
|
self.code.emit('LOAD_CONST', codeBody)
|
||||||
self.code.emit('MAKE_FUNCTION', len(node.defaults))
|
self.code.emit('MAKE_FUNCTION', len(node.defaults))
|
||||||
|
|
||||||
|
def visitFunction(self, node):
|
||||||
|
self._visitFuncOrLambda(node, 'Function')
|
||||||
self.storeName(node.name)
|
self.storeName(node.name)
|
||||||
return 1
|
return 1
|
||||||
|
|
||||||
|
def visitLambda(self, node):
|
||||||
|
node.name = '<lambda>'
|
||||||
|
node.varargs = node.kwargs = None
|
||||||
|
self._visitFuncOrLambda(node, 'Lambda')
|
||||||
|
return 1
|
||||||
|
|
||||||
def visitCallFunc(self, node):
|
def visitCallFunc(self, node):
|
||||||
if hasattr(node, 'lineno'):
|
if hasattr(node, 'lineno'):
|
||||||
self.code.emit('SET_LINENO', node.lineno)
|
self.code.emit('SET_LINENO', node.lineno)
|
||||||
|
@ -649,6 +667,9 @@ class LocalNameFinder:
|
||||||
self.names.add(node.name)
|
self.names.add(node.name)
|
||||||
return 1
|
return 1
|
||||||
|
|
||||||
|
def visitLambda(self, node):
|
||||||
|
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)
|
||||||
|
@ -878,10 +899,9 @@ class PythonVMCode:
|
||||||
if op == 'LOAD_CONST':
|
if op == 'LOAD_CONST':
|
||||||
return self._lookupName(arg, self.consts)
|
return self._lookupName(arg, self.consts)
|
||||||
if op in self.localOps:
|
if op in self.localOps:
|
||||||
if arg in self.names:
|
# make sure it's in self.names, but use the bytecode offset
|
||||||
return self._lookupName(arg, self.varnames)
|
self._lookupName(arg, self.names)
|
||||||
else:
|
return self._lookupName(arg, self.varnames)
|
||||||
return self._lookupName(arg, self.varnames, self.names)
|
|
||||||
if op in self.globalOps:
|
if op in self.globalOps:
|
||||||
return self._lookupName(arg, self.names)
|
return self._lookupName(arg, self.names)
|
||||||
if op in self.nameOps:
|
if op in self.nameOps:
|
||||||
|
|
Loading…
Reference in New Issue