mirror of
				https://github.com/python/cpython.git
				synced 2025-11-01 06:01:29 +00:00 
			
		
		
		
	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
					
				
					 2 changed files with 60 additions and 66 deletions
				
			
		|  | @ -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…
	
	Add table
		Add a link
		
	
		Reference in a new issue
	
	 Jeremy Hylton
						Jeremy Hylton