mirror of https://github.com/python/cpython.git
Many changes -- bug fixes and sundry improvements
Make nested scopes enabled by default Add is_constant_false() helper so that compiled code and symbols are consistent with builtin compiler's handling of "if 0:" Fix doc string handling to be consistent with recent change that eliminates the doc string from the Module's node attribute. Add fix to print handling from Evan & Shane. Track change to visitor api by making "verbose" explicit. Comment out setting CO_NESTED flag (it's unnecessary in 2.2).
This commit is contained in:
parent
9f448150c8
commit
2afff324ea
|
@ -40,18 +40,14 @@ def compile(filename, display=0):
|
|||
|
||||
class Module:
|
||||
def __init__(self, source, filename):
|
||||
self.filename = filename
|
||||
self.filename = os.path.abspath(filename)
|
||||
self.source = source
|
||||
self.code = None
|
||||
|
||||
def compile(self, display=0):
|
||||
tree = parse(self.source)
|
||||
root, filename = os.path.split(self.filename)
|
||||
if "nested_scopes" in future.find_futures(tree):
|
||||
gen = NestedScopeModuleCodeGenerator(filename)
|
||||
else:
|
||||
gen = ModuleCodeGenerator(filename)
|
||||
walk(tree, gen, 1)
|
||||
gen = NestedScopeModuleCodeGenerator(self.filename)
|
||||
walk(tree, gen, verbose=1)
|
||||
if display:
|
||||
import pprint
|
||||
print pprint.pprint(tree)
|
||||
|
@ -115,6 +111,12 @@ def visitClass(self, node):
|
|||
def visitAssName(self, node):
|
||||
self.names.add(node.name)
|
||||
|
||||
def is_constant_false(node):
|
||||
if isinstance(node, ast.Const):
|
||||
if not node.value:
|
||||
return 1
|
||||
return 0
|
||||
|
||||
class CodeGenerator:
|
||||
"""Defines basic code generator for Python bytecode
|
||||
|
||||
|
@ -234,10 +236,11 @@ def set_lineno(self, node, force=0):
|
|||
|
||||
def visitModule(self, node):
|
||||
self.emit('SET_LINENO', 0)
|
||||
lnf = walk(node.node, self.NameFinder(), 0)
|
||||
self.locals.push(lnf.getLocals())
|
||||
if node.doc:
|
||||
self.fixDocstring(node.node)
|
||||
self.emit('LOAD_CONST', node.doc)
|
||||
self.storeName('__doc__')
|
||||
lnf = walk(node.node, self.NameFinder(), verbose=0)
|
||||
self.locals.push(lnf.getLocals())
|
||||
self.visit(node.node)
|
||||
self.emit('LOAD_CONST', None)
|
||||
self.emit('RETURN_VALUE')
|
||||
|
@ -264,7 +267,8 @@ def _visitFuncOrLambda(self, node, isLambda=0):
|
|||
def visitClass(self, node):
|
||||
gen = self.ClassGen(node, self.filename, self.scopes)
|
||||
if node.doc:
|
||||
self.fixDocstring(node.code)
|
||||
self.emit('LOAD_CONST', node.doc)
|
||||
self.storeName('__doc__')
|
||||
walk(node.code, gen)
|
||||
gen.finish()
|
||||
self.set_lineno(node)
|
||||
|
@ -278,19 +282,6 @@ def visitClass(self, node):
|
|||
self.emit('BUILD_CLASS')
|
||||
self.storeName(node.name)
|
||||
|
||||
def fixDocstring(self, node):
|
||||
"""Rewrite the ast for a class with a docstring.
|
||||
|
||||
The AST includes a Discard(Const(docstring)) node. Replace
|
||||
this with an Assign([AssName('__doc__', ...])
|
||||
"""
|
||||
assert isinstance(node, ast.Stmt)
|
||||
stmts = node.nodes
|
||||
discard = stmts[0]
|
||||
assert isinstance(discard, ast.Discard)
|
||||
stmts[0] = ast.Assign([ast.AssName('__doc__', 'OP_ASSIGN')],
|
||||
discard.expr)
|
||||
stmts[0].lineno = discard.lineno
|
||||
# The rest are standard visitor methods
|
||||
|
||||
# The next few implement control-flow statements
|
||||
|
@ -300,6 +291,9 @@ def visitIf(self, node):
|
|||
numtests = len(node.tests)
|
||||
for i in range(numtests):
|
||||
test, suite = node.tests[i]
|
||||
if is_constant_false(test):
|
||||
# XXX will need to check generator stuff here
|
||||
continue
|
||||
self.set_lineno(test)
|
||||
self.visit(test)
|
||||
nextTest = self.newBlock()
|
||||
|
@ -793,7 +787,7 @@ def visitCallFunc(self, node):
|
|||
opcode = callfunc_opcode_info[have_star, have_dstar]
|
||||
self.emit(opcode, kw << 8 | pos)
|
||||
|
||||
def visitPrint(self, node):
|
||||
def visitPrint(self, node, newline=0):
|
||||
self.set_lineno(node)
|
||||
if node.dest:
|
||||
self.visit(node.dest)
|
||||
|
@ -806,9 +800,11 @@ def visitPrint(self, node):
|
|||
self.emit('PRINT_ITEM_TO')
|
||||
else:
|
||||
self.emit('PRINT_ITEM')
|
||||
if node.dest and not newline:
|
||||
self.emit('POP_TOP')
|
||||
|
||||
def visitPrintnl(self, node):
|
||||
self.visitPrint(node)
|
||||
self.visitPrint(node, newline=1)
|
||||
if node.dest:
|
||||
self.emit('PRINT_NEWLINE_TO')
|
||||
else:
|
||||
|
@ -1021,7 +1017,8 @@ def _visitFuncOrLambda(self, node, isLambda=0):
|
|||
def visitClass(self, node):
|
||||
gen = self.ClassGen(node, self.filename, self.scopes)
|
||||
if node.doc:
|
||||
self.fixDocstring(node.code)
|
||||
self.emit('LOAD_CONST', node.doc)
|
||||
self.storeName('__doc__')
|
||||
walk(node.code, gen)
|
||||
gen.finish()
|
||||
self.set_lineno(node)
|
||||
|
@ -1072,7 +1069,7 @@ class NestedScopeModuleCodeGenerator(NestedScopeMixin,
|
|||
def __init__(self, filename):
|
||||
self.graph = pyassem.PyFlowGraph("<module>", filename)
|
||||
self.__super_init(filename)
|
||||
self.graph.setFlag(CO_NESTED)
|
||||
## self.graph.setFlag(CO_NESTED)
|
||||
|
||||
class AbstractFunctionCode:
|
||||
optimized = 1
|
||||
|
@ -1094,7 +1091,7 @@ def __init__(self, func, filename, scopes, isLambda):
|
|||
if not isLambda and func.doc:
|
||||
self.setDocstring(func.doc)
|
||||
|
||||
lnf = walk(func.code, self.NameFinder(args), 0)
|
||||
lnf = walk(func.code, self.NameFinder(args), verbose=0)
|
||||
self.locals.push(lnf.getLocals())
|
||||
if func.varargs:
|
||||
self.graph.setFlag(CO_VARARGS)
|
||||
|
@ -1147,7 +1144,7 @@ def __init__(self, func, filename, scopes, isLambda):
|
|||
self.__super_init(func, filename, scopes, isLambda)
|
||||
self.graph.setFreeVars(self.scope.get_free_vars())
|
||||
self.graph.setCellVars(self.scope.get_cell_vars())
|
||||
self.graph.setFlag(CO_NESTED)
|
||||
## self.graph.setFlag(CO_NESTED)
|
||||
|
||||
class AbstractClassCode:
|
||||
|
||||
|
@ -1155,7 +1152,7 @@ def __init__(self, klass, filename, scopes):
|
|||
self.graph = pyassem.PyFlowGraph(klass.name, filename,
|
||||
optimized=0)
|
||||
self.super_init(filename)
|
||||
lnf = walk(klass.code, self.NameFinder(), 0)
|
||||
lnf = walk(klass.code, self.NameFinder(), verbose=0)
|
||||
self.locals.push(lnf.getLocals())
|
||||
self.graph.setFlag(CO_NEWLOCALS)
|
||||
if klass.doc:
|
||||
|
@ -1186,7 +1183,7 @@ def __init__(self, klass, filename, scopes):
|
|||
self.__super_init(klass, filename, scopes)
|
||||
self.graph.setFreeVars(self.scope.get_free_vars())
|
||||
self.graph.setCellVars(self.scope.get_cell_vars())
|
||||
self.graph.setFlag(CO_NESTED)
|
||||
## self.graph.setFlag(CO_NESTED)
|
||||
|
||||
def generateArgList(arglist):
|
||||
"""Generate an arg list marking TupleArgs"""
|
||||
|
@ -1208,7 +1205,7 @@ def generateArgList(arglist):
|
|||
def findOp(node):
|
||||
"""Find the op (DELETE, LOAD, STORE) in an AssTuple tree"""
|
||||
v = OpFinder()
|
||||
walk(node, v, 0)
|
||||
walk(node, v, verbose=0)
|
||||
return v.op
|
||||
|
||||
class OpFinder:
|
||||
|
|
|
@ -40,18 +40,14 @@ def compile(filename, display=0):
|
|||
|
||||
class Module:
|
||||
def __init__(self, source, filename):
|
||||
self.filename = filename
|
||||
self.filename = os.path.abspath(filename)
|
||||
self.source = source
|
||||
self.code = None
|
||||
|
||||
def compile(self, display=0):
|
||||
tree = parse(self.source)
|
||||
root, filename = os.path.split(self.filename)
|
||||
if "nested_scopes" in future.find_futures(tree):
|
||||
gen = NestedScopeModuleCodeGenerator(filename)
|
||||
else:
|
||||
gen = ModuleCodeGenerator(filename)
|
||||
walk(tree, gen, 1)
|
||||
gen = NestedScopeModuleCodeGenerator(self.filename)
|
||||
walk(tree, gen, verbose=1)
|
||||
if display:
|
||||
import pprint
|
||||
print pprint.pprint(tree)
|
||||
|
@ -115,6 +111,12 @@ def visitClass(self, node):
|
|||
def visitAssName(self, node):
|
||||
self.names.add(node.name)
|
||||
|
||||
def is_constant_false(node):
|
||||
if isinstance(node, ast.Const):
|
||||
if not node.value:
|
||||
return 1
|
||||
return 0
|
||||
|
||||
class CodeGenerator:
|
||||
"""Defines basic code generator for Python bytecode
|
||||
|
||||
|
@ -234,10 +236,11 @@ def set_lineno(self, node, force=0):
|
|||
|
||||
def visitModule(self, node):
|
||||
self.emit('SET_LINENO', 0)
|
||||
lnf = walk(node.node, self.NameFinder(), 0)
|
||||
self.locals.push(lnf.getLocals())
|
||||
if node.doc:
|
||||
self.fixDocstring(node.node)
|
||||
self.emit('LOAD_CONST', node.doc)
|
||||
self.storeName('__doc__')
|
||||
lnf = walk(node.node, self.NameFinder(), verbose=0)
|
||||
self.locals.push(lnf.getLocals())
|
||||
self.visit(node.node)
|
||||
self.emit('LOAD_CONST', None)
|
||||
self.emit('RETURN_VALUE')
|
||||
|
@ -264,7 +267,8 @@ def _visitFuncOrLambda(self, node, isLambda=0):
|
|||
def visitClass(self, node):
|
||||
gen = self.ClassGen(node, self.filename, self.scopes)
|
||||
if node.doc:
|
||||
self.fixDocstring(node.code)
|
||||
self.emit('LOAD_CONST', node.doc)
|
||||
self.storeName('__doc__')
|
||||
walk(node.code, gen)
|
||||
gen.finish()
|
||||
self.set_lineno(node)
|
||||
|
@ -278,19 +282,6 @@ def visitClass(self, node):
|
|||
self.emit('BUILD_CLASS')
|
||||
self.storeName(node.name)
|
||||
|
||||
def fixDocstring(self, node):
|
||||
"""Rewrite the ast for a class with a docstring.
|
||||
|
||||
The AST includes a Discard(Const(docstring)) node. Replace
|
||||
this with an Assign([AssName('__doc__', ...])
|
||||
"""
|
||||
assert isinstance(node, ast.Stmt)
|
||||
stmts = node.nodes
|
||||
discard = stmts[0]
|
||||
assert isinstance(discard, ast.Discard)
|
||||
stmts[0] = ast.Assign([ast.AssName('__doc__', 'OP_ASSIGN')],
|
||||
discard.expr)
|
||||
stmts[0].lineno = discard.lineno
|
||||
# The rest are standard visitor methods
|
||||
|
||||
# The next few implement control-flow statements
|
||||
|
@ -300,6 +291,9 @@ def visitIf(self, node):
|
|||
numtests = len(node.tests)
|
||||
for i in range(numtests):
|
||||
test, suite = node.tests[i]
|
||||
if is_constant_false(test):
|
||||
# XXX will need to check generator stuff here
|
||||
continue
|
||||
self.set_lineno(test)
|
||||
self.visit(test)
|
||||
nextTest = self.newBlock()
|
||||
|
@ -793,7 +787,7 @@ def visitCallFunc(self, node):
|
|||
opcode = callfunc_opcode_info[have_star, have_dstar]
|
||||
self.emit(opcode, kw << 8 | pos)
|
||||
|
||||
def visitPrint(self, node):
|
||||
def visitPrint(self, node, newline=0):
|
||||
self.set_lineno(node)
|
||||
if node.dest:
|
||||
self.visit(node.dest)
|
||||
|
@ -806,9 +800,11 @@ def visitPrint(self, node):
|
|||
self.emit('PRINT_ITEM_TO')
|
||||
else:
|
||||
self.emit('PRINT_ITEM')
|
||||
if node.dest and not newline:
|
||||
self.emit('POP_TOP')
|
||||
|
||||
def visitPrintnl(self, node):
|
||||
self.visitPrint(node)
|
||||
self.visitPrint(node, newline=1)
|
||||
if node.dest:
|
||||
self.emit('PRINT_NEWLINE_TO')
|
||||
else:
|
||||
|
@ -1021,7 +1017,8 @@ def _visitFuncOrLambda(self, node, isLambda=0):
|
|||
def visitClass(self, node):
|
||||
gen = self.ClassGen(node, self.filename, self.scopes)
|
||||
if node.doc:
|
||||
self.fixDocstring(node.code)
|
||||
self.emit('LOAD_CONST', node.doc)
|
||||
self.storeName('__doc__')
|
||||
walk(node.code, gen)
|
||||
gen.finish()
|
||||
self.set_lineno(node)
|
||||
|
@ -1072,7 +1069,7 @@ class NestedScopeModuleCodeGenerator(NestedScopeMixin,
|
|||
def __init__(self, filename):
|
||||
self.graph = pyassem.PyFlowGraph("<module>", filename)
|
||||
self.__super_init(filename)
|
||||
self.graph.setFlag(CO_NESTED)
|
||||
## self.graph.setFlag(CO_NESTED)
|
||||
|
||||
class AbstractFunctionCode:
|
||||
optimized = 1
|
||||
|
@ -1094,7 +1091,7 @@ def __init__(self, func, filename, scopes, isLambda):
|
|||
if not isLambda and func.doc:
|
||||
self.setDocstring(func.doc)
|
||||
|
||||
lnf = walk(func.code, self.NameFinder(args), 0)
|
||||
lnf = walk(func.code, self.NameFinder(args), verbose=0)
|
||||
self.locals.push(lnf.getLocals())
|
||||
if func.varargs:
|
||||
self.graph.setFlag(CO_VARARGS)
|
||||
|
@ -1147,7 +1144,7 @@ def __init__(self, func, filename, scopes, isLambda):
|
|||
self.__super_init(func, filename, scopes, isLambda)
|
||||
self.graph.setFreeVars(self.scope.get_free_vars())
|
||||
self.graph.setCellVars(self.scope.get_cell_vars())
|
||||
self.graph.setFlag(CO_NESTED)
|
||||
## self.graph.setFlag(CO_NESTED)
|
||||
|
||||
class AbstractClassCode:
|
||||
|
||||
|
@ -1155,7 +1152,7 @@ def __init__(self, klass, filename, scopes):
|
|||
self.graph = pyassem.PyFlowGraph(klass.name, filename,
|
||||
optimized=0)
|
||||
self.super_init(filename)
|
||||
lnf = walk(klass.code, self.NameFinder(), 0)
|
||||
lnf = walk(klass.code, self.NameFinder(), verbose=0)
|
||||
self.locals.push(lnf.getLocals())
|
||||
self.graph.setFlag(CO_NEWLOCALS)
|
||||
if klass.doc:
|
||||
|
@ -1186,7 +1183,7 @@ def __init__(self, klass, filename, scopes):
|
|||
self.__super_init(klass, filename, scopes)
|
||||
self.graph.setFreeVars(self.scope.get_free_vars())
|
||||
self.graph.setCellVars(self.scope.get_cell_vars())
|
||||
self.graph.setFlag(CO_NESTED)
|
||||
## self.graph.setFlag(CO_NESTED)
|
||||
|
||||
def generateArgList(arglist):
|
||||
"""Generate an arg list marking TupleArgs"""
|
||||
|
@ -1208,7 +1205,7 @@ def generateArgList(arglist):
|
|||
def findOp(node):
|
||||
"""Find the op (DELETE, LOAD, STORE) in an AssTuple tree"""
|
||||
v = OpFinder()
|
||||
walk(node, v, 0)
|
||||
walk(node, v, verbose=0)
|
||||
return v.op
|
||||
|
||||
class OpFinder:
|
||||
|
|
Loading…
Reference in New Issue