mirror of
				https://github.com/python/cpython.git
				synced 2025-10-31 13:41:24 +00:00 
			
		
		
		
	replace most calls to emit 'SET_LINENO' will call to method set_lineno
based on bug report by Neil Schemenauer
This commit is contained in:
		
							parent
							
								
									8612f1c152
								
							
						
					
					
						commit
						7daf04d9e0
					
				
					 2 changed files with 84 additions and 62 deletions
				
			
		|  | @ -105,6 +105,22 @@ def _nameOp(self, prefix, name): | |||
|         else: | ||||
|             self.emit(prefix + '_GLOBAL', name) | ||||
| 
 | ||||
|     def set_lineno(self, node): | ||||
|         """Emit SET_LINENO if node has lineno attribute | ||||
| 
 | ||||
|         Returns true if SET_LINENO was emitted. | ||||
| 
 | ||||
|         There are no rules for when an AST node should have a lineno | ||||
|         attribute.  The transformer and AST code need to be reviewed | ||||
|         and a consistent policy implemented and documented.  Until | ||||
|         then, this method works around missing line numbers. | ||||
|         """ | ||||
|         lineno = getattr(node, 'lineno', None) | ||||
|         if lineno is not None: | ||||
|             self.emit('SET_LINENO', lineno) | ||||
|             return 1 | ||||
|         return 0 | ||||
| 
 | ||||
|     # The first few visitor methods handle nodes that generator new | ||||
|     # code objects  | ||||
| 
 | ||||
|  | @ -128,7 +144,7 @@ def _visitFuncOrLambda(self, node, isLambda): | |||
| 	gen = FunctionCodeGenerator(node, self.filename, isLambda) | ||||
| 	walk(node.code, gen) | ||||
| 	gen.finish() | ||||
| 	self.emit('SET_LINENO', node.lineno) | ||||
|         self.set_lineno(node) | ||||
|         for default in node.defaults: | ||||
|             self.visit(default) | ||||
|         self.emit('LOAD_CONST', gen.getCode()) | ||||
|  | @ -138,7 +154,7 @@ def visitClass(self, node): | |||
|         gen = ClassCodeGenerator(node, self.filename) | ||||
|         walk(node.code, gen) | ||||
|         gen.finish() | ||||
|         self.emit('SET_LINENO', node.lineno) | ||||
|         self.set_lineno(node) | ||||
|         self.emit('LOAD_CONST', node.name) | ||||
|         for base in node.bases: | ||||
|             self.visit(base) | ||||
|  | @ -158,8 +174,7 @@ def visitIf(self, node): | |||
| 	numtests = len(node.tests) | ||||
| 	for i in range(numtests): | ||||
| 	    test, suite = node.tests[i] | ||||
| 	    if hasattr(test, 'lineno'): | ||||
| 		self.emit('SET_LINENO', test.lineno) | ||||
|             self.set_lineno(test) | ||||
| 	    self.visit(test) | ||||
| ## 	    if i == numtests - 1 and not node.else_: | ||||
| ## 		nextTest = end | ||||
|  | @ -178,7 +193,7 @@ def visitIf(self, node): | |||
| 	self.nextBlock(end) | ||||
| 
 | ||||
|     def visitWhile(self, node): | ||||
| 	self.emit('SET_LINENO', node.lineno) | ||||
|         self.set_lineno(node) | ||||
| 
 | ||||
| 	loop = self.newBlock() | ||||
| 	else_ = self.newBlock() | ||||
|  | @ -189,7 +204,7 @@ def visitWhile(self, node): | |||
| 	self.nextBlock(loop) | ||||
| 	self.loops.push(loop) | ||||
| 
 | ||||
| 	self.emit('SET_LINENO', node.lineno) | ||||
|         self.set_lineno(node) | ||||
| 	self.visit(node.test) | ||||
| 	self.emit('JUMP_IF_FALSE', else_ or after) | ||||
| 
 | ||||
|  | @ -212,12 +227,12 @@ def visitFor(self, node): | |||
| 	after = self.newBlock() | ||||
|         self.loops.push(start) | ||||
| 
 | ||||
|         self.emit('SET_LINENO', node.lineno) | ||||
|         self.set_lineno(node) | ||||
| 	self.emit('SETUP_LOOP', after) | ||||
|         self.visit(node.list) | ||||
|         self.visit(ast.Const(0)) | ||||
| 	self.nextBlock(start) | ||||
|         self.emit('SET_LINENO', node.lineno) | ||||
|         self.set_lineno(node) | ||||
|         self.emit('FOR_LOOP', anchor) | ||||
|         self.visit(node.assign) | ||||
|         self.visit(node.body) | ||||
|  | @ -233,7 +248,7 @@ def visitBreak(self, node): | |||
| 	if not self.loops: | ||||
| 	    raise SyntaxError, "'break' outside loop (%s, %d)" % \ | ||||
| 		  (self.filename, node.lineno) | ||||
| 	self.emit('SET_LINENO', node.lineno) | ||||
|         self.set_lineno(node) | ||||
| 	self.emit('BREAK_LOOP') | ||||
| 
 | ||||
|     def visitContinue(self, node): | ||||
|  | @ -241,7 +256,7 @@ def visitContinue(self, node): | |||
|             raise SyntaxError, "'continue' outside loop (%s, %d)" % \ | ||||
| 		  (self.filename, node.lineno) | ||||
|         l = self.loops.top() | ||||
|         self.emit('SET_LINENO', node.lineno) | ||||
|         self.set_lineno(node) | ||||
|         self.emit('JUMP_ABSOLUTE', l) | ||||
| 	self.nextBlock() | ||||
| 
 | ||||
|  | @ -291,7 +306,7 @@ def visitAssert(self, node): | |||
| 	# XXX would be interesting to implement this via a | ||||
| 	# transformation of the AST before this stage | ||||
| 	end = self.newBlock() | ||||
| 	self.emit('SET_LINENO', node.lineno) | ||||
|         self.set_lineno(node) | ||||
|         # XXX __debug__ and AssertionError appear to be special cases | ||||
|         # -- they are always loaded as globals even if there are local | ||||
|         # names.  I guess this is a sort of renaming op. | ||||
|  | @ -309,7 +324,7 @@ def visitAssert(self, node): | |||
| 	self.emit('POP_TOP') | ||||
| 
 | ||||
|     def visitRaise(self, node): | ||||
|         self.emit('SET_LINENO', node.lineno) | ||||
|         self.set_lineno(node) | ||||
|         n = 0 | ||||
|         if node.expr1: | ||||
|             self.visit(node.expr1) | ||||
|  | @ -329,7 +344,7 @@ def visitTryExcept(self, node): | |||
|             lElse = self.newBlock() | ||||
|         else: | ||||
|             lElse = end | ||||
|         self.emit('SET_LINENO', node.lineno) | ||||
|         self.set_lineno(node) | ||||
|         self.emit('SETUP_EXCEPT', handlers) | ||||
|         self.visit(node.body) | ||||
|         self.emit('POP_BLOCK') | ||||
|  | @ -339,8 +354,7 @@ def visitTryExcept(self, node): | |||
|         last = len(node.handlers) - 1 | ||||
|         for i in range(len(node.handlers)): | ||||
|             expr, target, body = node.handlers[i] | ||||
|             if hasattr(expr, 'lineno'): | ||||
|                 self.emit('SET_LINENO', expr.lineno) | ||||
|             self.set_lineno(expr) | ||||
|             if expr: | ||||
|                 self.emit('DUP_TOP') | ||||
|                 self.visit(expr) | ||||
|  | @ -368,7 +382,7 @@ def visitTryExcept(self, node): | |||
|      | ||||
|     def visitTryFinally(self, node): | ||||
|         final = self.newBlock() | ||||
|         self.emit('SET_LINENO', node.lineno) | ||||
|         self.set_lineno(node) | ||||
|         self.emit('SETUP_FINALLY', final) | ||||
|         self.visit(node.body) | ||||
|         self.emit('POP_BLOCK') | ||||
|  | @ -402,16 +416,16 @@ def visitName(self, node): | |||
|         self.loadName(node.name) | ||||
|          | ||||
|     def visitPass(self, node): | ||||
|         self.emit('SET_LINENO', node.lineno) | ||||
|         self.set_lineno(node) | ||||
| 
 | ||||
|     def visitImport(self, node): | ||||
|         self.emit('SET_LINENO', node.lineno) | ||||
|         self.set_lineno(node) | ||||
|         for name in node.names: | ||||
|             self.emit('IMPORT_NAME', name) | ||||
|             self.storeName(name) | ||||
| 
 | ||||
|     def visitFrom(self, node): | ||||
|         self.emit('SET_LINENO', node.lineno) | ||||
|         self.set_lineno(node) | ||||
|         self.emit('IMPORT_NAME', node.modname) | ||||
|         for name in node.names: | ||||
|             if name == '*': | ||||
|  | @ -426,7 +440,7 @@ def visitGetattr(self, node): | |||
|     # next five implement assignments | ||||
| 
 | ||||
|     def visitAssign(self, node): | ||||
|         self.emit('SET_LINENO', node.lineno) | ||||
|         self.set_lineno(node) | ||||
|         self.visit(node.expr) | ||||
|         dups = len(node.nodes) - 1 | ||||
|         for i in range(len(node.nodes)): | ||||
|  | @ -477,8 +491,7 @@ def visitExec(self, node): | |||
|     def visitCallFunc(self, node): | ||||
|         pos = 0 | ||||
|         kw = 0 | ||||
|         if hasattr(node, 'lineno'): | ||||
|             self.emit('SET_LINENO', node.lineno) | ||||
|         self.set_lineno(node) | ||||
|         self.visit(node.node) | ||||
|         for arg in node.args: | ||||
|             self.visit(arg) | ||||
|  | @ -496,7 +509,7 @@ def visitCallFunc(self, node): | |||
|         self.emit(opcode, kw << 8 | pos) | ||||
| 
 | ||||
|     def visitPrint(self, node): | ||||
|         self.emit('SET_LINENO', node.lineno) | ||||
|         self.set_lineno(node) | ||||
|         for child in node.nodes: | ||||
|             self.visit(child) | ||||
|             self.emit('PRINT_ITEM') | ||||
|  | @ -506,7 +519,7 @@ def visitPrintnl(self, node): | |||
|         self.emit('PRINT_NEWLINE') | ||||
| 
 | ||||
|     def visitReturn(self, node): | ||||
|         self.emit('SET_LINENO', node.lineno) | ||||
|         self.set_lineno(node) | ||||
|         self.visit(node.value) | ||||
|         self.emit('RETURN_VALUE') | ||||
| 
 | ||||
|  | @ -637,15 +650,13 @@ def visitSliceobj(self, node): | |||
|         self.emit('BUILD_SLICE', len(node.nodes)) | ||||
| 
 | ||||
|     def visitDict(self, node): | ||||
| 	# XXX is this a good general strategy?  could it be done  | ||||
| 	# separately from the general visitor | ||||
| 	lineno = getattr(node, 'lineno', None) | ||||
| 	if lineno: | ||||
| 	    self.emit('SET_LINENO', lineno) | ||||
|         lineno = getattr(node, 'lineno', None) | ||||
|         if lineno: | ||||
|             set.emit('SET_LINENO', lineno) | ||||
|         self.emit('BUILD_MAP', 0) | ||||
|         for k, v in node.items: | ||||
| 	    lineno2 = getattr(node, 'lineno', None) | ||||
| 	    if lineno != lineno2: | ||||
|             if lineno2 is not None and lineno != lineno2: | ||||
| 		self.emit('SET_LINENO', lineno2) | ||||
| 		lineno = lineno2 | ||||
|             self.emit('DUP_TOP') | ||||
|  | @ -687,7 +698,7 @@ def __init__(self, func, filename, isLambda=0): | |||
| 	    self.graph.setFlag(CO_VARARGS) | ||||
| 	if func.kwargs: | ||||
| 	    self.graph.setFlag(CO_VARKEYWORDS) | ||||
|         self.emit('SET_LINENO', func.lineno) | ||||
|         self.set_lineno(func) | ||||
|         if hasTupleArg: | ||||
|             self.generateArgUnpack(func.argnames) | ||||
| 
 | ||||
|  |  | |||
|  | @ -105,6 +105,22 @@ def _nameOp(self, prefix, name): | |||
|         else: | ||||
|             self.emit(prefix + '_GLOBAL', name) | ||||
| 
 | ||||
|     def set_lineno(self, node): | ||||
|         """Emit SET_LINENO if node has lineno attribute | ||||
| 
 | ||||
|         Returns true if SET_LINENO was emitted. | ||||
| 
 | ||||
|         There are no rules for when an AST node should have a lineno | ||||
|         attribute.  The transformer and AST code need to be reviewed | ||||
|         and a consistent policy implemented and documented.  Until | ||||
|         then, this method works around missing line numbers. | ||||
|         """ | ||||
|         lineno = getattr(node, 'lineno', None) | ||||
|         if lineno is not None: | ||||
|             self.emit('SET_LINENO', lineno) | ||||
|             return 1 | ||||
|         return 0 | ||||
| 
 | ||||
|     # The first few visitor methods handle nodes that generator new | ||||
|     # code objects  | ||||
| 
 | ||||
|  | @ -128,7 +144,7 @@ def _visitFuncOrLambda(self, node, isLambda): | |||
| 	gen = FunctionCodeGenerator(node, self.filename, isLambda) | ||||
| 	walk(node.code, gen) | ||||
| 	gen.finish() | ||||
| 	self.emit('SET_LINENO', node.lineno) | ||||
|         self.set_lineno(node) | ||||
|         for default in node.defaults: | ||||
|             self.visit(default) | ||||
|         self.emit('LOAD_CONST', gen.getCode()) | ||||
|  | @ -138,7 +154,7 @@ def visitClass(self, node): | |||
|         gen = ClassCodeGenerator(node, self.filename) | ||||
|         walk(node.code, gen) | ||||
|         gen.finish() | ||||
|         self.emit('SET_LINENO', node.lineno) | ||||
|         self.set_lineno(node) | ||||
|         self.emit('LOAD_CONST', node.name) | ||||
|         for base in node.bases: | ||||
|             self.visit(base) | ||||
|  | @ -158,8 +174,7 @@ def visitIf(self, node): | |||
| 	numtests = len(node.tests) | ||||
| 	for i in range(numtests): | ||||
| 	    test, suite = node.tests[i] | ||||
| 	    if hasattr(test, 'lineno'): | ||||
| 		self.emit('SET_LINENO', test.lineno) | ||||
|             self.set_lineno(test) | ||||
| 	    self.visit(test) | ||||
| ## 	    if i == numtests - 1 and not node.else_: | ||||
| ## 		nextTest = end | ||||
|  | @ -178,7 +193,7 @@ def visitIf(self, node): | |||
| 	self.nextBlock(end) | ||||
| 
 | ||||
|     def visitWhile(self, node): | ||||
| 	self.emit('SET_LINENO', node.lineno) | ||||
|         self.set_lineno(node) | ||||
| 
 | ||||
| 	loop = self.newBlock() | ||||
| 	else_ = self.newBlock() | ||||
|  | @ -189,7 +204,7 @@ def visitWhile(self, node): | |||
| 	self.nextBlock(loop) | ||||
| 	self.loops.push(loop) | ||||
| 
 | ||||
| 	self.emit('SET_LINENO', node.lineno) | ||||
|         self.set_lineno(node) | ||||
| 	self.visit(node.test) | ||||
| 	self.emit('JUMP_IF_FALSE', else_ or after) | ||||
| 
 | ||||
|  | @ -212,12 +227,12 @@ def visitFor(self, node): | |||
| 	after = self.newBlock() | ||||
|         self.loops.push(start) | ||||
| 
 | ||||
|         self.emit('SET_LINENO', node.lineno) | ||||
|         self.set_lineno(node) | ||||
| 	self.emit('SETUP_LOOP', after) | ||||
|         self.visit(node.list) | ||||
|         self.visit(ast.Const(0)) | ||||
| 	self.nextBlock(start) | ||||
|         self.emit('SET_LINENO', node.lineno) | ||||
|         self.set_lineno(node) | ||||
|         self.emit('FOR_LOOP', anchor) | ||||
|         self.visit(node.assign) | ||||
|         self.visit(node.body) | ||||
|  | @ -233,7 +248,7 @@ def visitBreak(self, node): | |||
| 	if not self.loops: | ||||
| 	    raise SyntaxError, "'break' outside loop (%s, %d)" % \ | ||||
| 		  (self.filename, node.lineno) | ||||
| 	self.emit('SET_LINENO', node.lineno) | ||||
|         self.set_lineno(node) | ||||
| 	self.emit('BREAK_LOOP') | ||||
| 
 | ||||
|     def visitContinue(self, node): | ||||
|  | @ -241,7 +256,7 @@ def visitContinue(self, node): | |||
|             raise SyntaxError, "'continue' outside loop (%s, %d)" % \ | ||||
| 		  (self.filename, node.lineno) | ||||
|         l = self.loops.top() | ||||
|         self.emit('SET_LINENO', node.lineno) | ||||
|         self.set_lineno(node) | ||||
|         self.emit('JUMP_ABSOLUTE', l) | ||||
| 	self.nextBlock() | ||||
| 
 | ||||
|  | @ -291,7 +306,7 @@ def visitAssert(self, node): | |||
| 	# XXX would be interesting to implement this via a | ||||
| 	# transformation of the AST before this stage | ||||
| 	end = self.newBlock() | ||||
| 	self.emit('SET_LINENO', node.lineno) | ||||
|         self.set_lineno(node) | ||||
|         # XXX __debug__ and AssertionError appear to be special cases | ||||
|         # -- they are always loaded as globals even if there are local | ||||
|         # names.  I guess this is a sort of renaming op. | ||||
|  | @ -309,7 +324,7 @@ def visitAssert(self, node): | |||
| 	self.emit('POP_TOP') | ||||
| 
 | ||||
|     def visitRaise(self, node): | ||||
|         self.emit('SET_LINENO', node.lineno) | ||||
|         self.set_lineno(node) | ||||
|         n = 0 | ||||
|         if node.expr1: | ||||
|             self.visit(node.expr1) | ||||
|  | @ -329,7 +344,7 @@ def visitTryExcept(self, node): | |||
|             lElse = self.newBlock() | ||||
|         else: | ||||
|             lElse = end | ||||
|         self.emit('SET_LINENO', node.lineno) | ||||
|         self.set_lineno(node) | ||||
|         self.emit('SETUP_EXCEPT', handlers) | ||||
|         self.visit(node.body) | ||||
|         self.emit('POP_BLOCK') | ||||
|  | @ -339,8 +354,7 @@ def visitTryExcept(self, node): | |||
|         last = len(node.handlers) - 1 | ||||
|         for i in range(len(node.handlers)): | ||||
|             expr, target, body = node.handlers[i] | ||||
|             if hasattr(expr, 'lineno'): | ||||
|                 self.emit('SET_LINENO', expr.lineno) | ||||
|             self.set_lineno(expr) | ||||
|             if expr: | ||||
|                 self.emit('DUP_TOP') | ||||
|                 self.visit(expr) | ||||
|  | @ -368,7 +382,7 @@ def visitTryExcept(self, node): | |||
|      | ||||
|     def visitTryFinally(self, node): | ||||
|         final = self.newBlock() | ||||
|         self.emit('SET_LINENO', node.lineno) | ||||
|         self.set_lineno(node) | ||||
|         self.emit('SETUP_FINALLY', final) | ||||
|         self.visit(node.body) | ||||
|         self.emit('POP_BLOCK') | ||||
|  | @ -402,16 +416,16 @@ def visitName(self, node): | |||
|         self.loadName(node.name) | ||||
|          | ||||
|     def visitPass(self, node): | ||||
|         self.emit('SET_LINENO', node.lineno) | ||||
|         self.set_lineno(node) | ||||
| 
 | ||||
|     def visitImport(self, node): | ||||
|         self.emit('SET_LINENO', node.lineno) | ||||
|         self.set_lineno(node) | ||||
|         for name in node.names: | ||||
|             self.emit('IMPORT_NAME', name) | ||||
|             self.storeName(name) | ||||
| 
 | ||||
|     def visitFrom(self, node): | ||||
|         self.emit('SET_LINENO', node.lineno) | ||||
|         self.set_lineno(node) | ||||
|         self.emit('IMPORT_NAME', node.modname) | ||||
|         for name in node.names: | ||||
|             if name == '*': | ||||
|  | @ -426,7 +440,7 @@ def visitGetattr(self, node): | |||
|     # next five implement assignments | ||||
| 
 | ||||
|     def visitAssign(self, node): | ||||
|         self.emit('SET_LINENO', node.lineno) | ||||
|         self.set_lineno(node) | ||||
|         self.visit(node.expr) | ||||
|         dups = len(node.nodes) - 1 | ||||
|         for i in range(len(node.nodes)): | ||||
|  | @ -477,8 +491,7 @@ def visitExec(self, node): | |||
|     def visitCallFunc(self, node): | ||||
|         pos = 0 | ||||
|         kw = 0 | ||||
|         if hasattr(node, 'lineno'): | ||||
|             self.emit('SET_LINENO', node.lineno) | ||||
|         self.set_lineno(node) | ||||
|         self.visit(node.node) | ||||
|         for arg in node.args: | ||||
|             self.visit(arg) | ||||
|  | @ -496,7 +509,7 @@ def visitCallFunc(self, node): | |||
|         self.emit(opcode, kw << 8 | pos) | ||||
| 
 | ||||
|     def visitPrint(self, node): | ||||
|         self.emit('SET_LINENO', node.lineno) | ||||
|         self.set_lineno(node) | ||||
|         for child in node.nodes: | ||||
|             self.visit(child) | ||||
|             self.emit('PRINT_ITEM') | ||||
|  | @ -506,7 +519,7 @@ def visitPrintnl(self, node): | |||
|         self.emit('PRINT_NEWLINE') | ||||
| 
 | ||||
|     def visitReturn(self, node): | ||||
|         self.emit('SET_LINENO', node.lineno) | ||||
|         self.set_lineno(node) | ||||
|         self.visit(node.value) | ||||
|         self.emit('RETURN_VALUE') | ||||
| 
 | ||||
|  | @ -637,15 +650,13 @@ def visitSliceobj(self, node): | |||
|         self.emit('BUILD_SLICE', len(node.nodes)) | ||||
| 
 | ||||
|     def visitDict(self, node): | ||||
| 	# XXX is this a good general strategy?  could it be done  | ||||
| 	# separately from the general visitor | ||||
| 	lineno = getattr(node, 'lineno', None) | ||||
| 	if lineno: | ||||
| 	    self.emit('SET_LINENO', lineno) | ||||
|         lineno = getattr(node, 'lineno', None) | ||||
|         if lineno: | ||||
|             set.emit('SET_LINENO', lineno) | ||||
|         self.emit('BUILD_MAP', 0) | ||||
|         for k, v in node.items: | ||||
| 	    lineno2 = getattr(node, 'lineno', None) | ||||
| 	    if lineno != lineno2: | ||||
|             if lineno2 is not None and lineno != lineno2: | ||||
| 		self.emit('SET_LINENO', lineno2) | ||||
| 		lineno = lineno2 | ||||
|             self.emit('DUP_TOP') | ||||
|  | @ -687,7 +698,7 @@ def __init__(self, func, filename, isLambda=0): | |||
| 	    self.graph.setFlag(CO_VARARGS) | ||||
| 	if func.kwargs: | ||||
| 	    self.graph.setFlag(CO_VARKEYWORDS) | ||||
|         self.emit('SET_LINENO', func.lineno) | ||||
|         self.set_lineno(func) | ||||
|         if hasTupleArg: | ||||
|             self.generateArgUnpack(func.argnames) | ||||
| 
 | ||||
|  |  | |||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue
	
	 Jeremy Hylton
						Jeremy Hylton