@@ -105,6 +105,22 @@ def _nameOp(self, prefix, name):
105105 else :
106106 self .emit (prefix + '_GLOBAL' , name )
107107
108+ def set_lineno (self , node ):
109+ """Emit SET_LINENO if node has lineno attribute
110+
111+ Returns true if SET_LINENO was emitted.
112+
113+ There are no rules for when an AST node should have a lineno
114+ attribute. The transformer and AST code need to be reviewed
115+ and a consistent policy implemented and documented. Until
116+ then, this method works around missing line numbers.
117+ """
118+ lineno = getattr (node , 'lineno' , None )
119+ if lineno is not None :
120+ self .emit ('SET_LINENO' , lineno )
121+ return 1
122+ return 0
123+
108124 # The first few visitor methods handle nodes that generator new
109125 # code objects
110126
@@ -128,7 +144,7 @@ def _visitFuncOrLambda(self, node, isLambda):
128144 gen = FunctionCodeGenerator (node , self .filename , isLambda )
129145 walk (node .code , gen )
130146 gen .finish ()
131- self .emit ( 'SET_LINENO' , node . lineno )
147+ self .set_lineno ( node )
132148 for default in node .defaults :
133149 self .visit (default )
134150 self .emit ('LOAD_CONST' , gen .getCode ())
@@ -138,7 +154,7 @@ def visitClass(self, node):
138154 gen = ClassCodeGenerator (node , self .filename )
139155 walk (node .code , gen )
140156 gen .finish ()
141- self .emit ( 'SET_LINENO' , node . lineno )
157+ self .set_lineno ( node )
142158 self .emit ('LOAD_CONST' , node .name )
143159 for base in node .bases :
144160 self .visit (base )
@@ -158,8 +174,7 @@ def visitIf(self, node):
158174 numtests = len (node .tests )
159175 for i in range (numtests ):
160176 test , suite = node .tests [i ]
161- if hasattr (test , 'lineno' ):
162- self .emit ('SET_LINENO' , test .lineno )
177+ self .set_lineno (test )
163178 self .visit (test )
164179## if i == numtests - 1 and not node.else_:
165180## nextTest = end
@@ -178,7 +193,7 @@ def visitIf(self, node):
178193 self .nextBlock (end )
179194
180195 def visitWhile (self , node ):
181- self .emit ( 'SET_LINENO' , node . lineno )
196+ self .set_lineno ( node )
182197
183198 loop = self .newBlock ()
184199 else_ = self .newBlock ()
@@ -189,7 +204,7 @@ def visitWhile(self, node):
189204 self .nextBlock (loop )
190205 self .loops .push (loop )
191206
192- self .emit ( 'SET_LINENO' , node . lineno )
207+ self .set_lineno ( node )
193208 self .visit (node .test )
194209 self .emit ('JUMP_IF_FALSE' , else_ or after )
195210
@@ -212,12 +227,12 @@ def visitFor(self, node):
212227 after = self .newBlock ()
213228 self .loops .push (start )
214229
215- self .emit ( 'SET_LINENO' , node . lineno )
230+ self .set_lineno ( node )
216231 self .emit ('SETUP_LOOP' , after )
217232 self .visit (node .list )
218233 self .visit (ast .Const (0 ))
219234 self .nextBlock (start )
220- self .emit ( 'SET_LINENO' , node . lineno )
235+ self .set_lineno ( node )
221236 self .emit ('FOR_LOOP' , anchor )
222237 self .visit (node .assign )
223238 self .visit (node .body )
@@ -233,15 +248,15 @@ def visitBreak(self, node):
233248 if not self .loops :
234249 raise SyntaxError , "'break' outside loop (%s, %d)" % \
235250 (self .filename , node .lineno )
236- self .emit ( 'SET_LINENO' , node . lineno )
251+ self .set_lineno ( node )
237252 self .emit ('BREAK_LOOP' )
238253
239254 def visitContinue (self , node ):
240255 if not self .loops :
241256 raise SyntaxError , "'continue' outside loop (%s, %d)" % \
242257 (self .filename , node .lineno )
243258 l = self .loops .top ()
244- self .emit ( 'SET_LINENO' , node . lineno )
259+ self .set_lineno ( node )
245260 self .emit ('JUMP_ABSOLUTE' , l )
246261 self .nextBlock ()
247262
@@ -291,7 +306,7 @@ def visitAssert(self, node):
291306 # XXX would be interesting to implement this via a
292307 # transformation of the AST before this stage
293308 end = self .newBlock ()
294- self .emit ( 'SET_LINENO' , node . lineno )
309+ self .set_lineno ( node )
295310 # XXX __debug__ and AssertionError appear to be special cases
296311 # -- they are always loaded as globals even if there are local
297312 # names. I guess this is a sort of renaming op.
@@ -309,7 +324,7 @@ def visitAssert(self, node):
309324 self .emit ('POP_TOP' )
310325
311326 def visitRaise (self , node ):
312- self .emit ( 'SET_LINENO' , node . lineno )
327+ self .set_lineno ( node )
313328 n = 0
314329 if node .expr1 :
315330 self .visit (node .expr1 )
@@ -329,7 +344,7 @@ def visitTryExcept(self, node):
329344 lElse = self .newBlock ()
330345 else :
331346 lElse = end
332- self .emit ( 'SET_LINENO' , node . lineno )
347+ self .set_lineno ( node )
333348 self .emit ('SETUP_EXCEPT' , handlers )
334349 self .visit (node .body )
335350 self .emit ('POP_BLOCK' )
@@ -339,8 +354,7 @@ def visitTryExcept(self, node):
339354 last = len (node .handlers ) - 1
340355 for i in range (len (node .handlers )):
341356 expr , target , body = node .handlers [i ]
342- if hasattr (expr , 'lineno' ):
343- self .emit ('SET_LINENO' , expr .lineno )
357+ self .set_lineno (expr )
344358 if expr :
345359 self .emit ('DUP_TOP' )
346360 self .visit (expr )
@@ -368,7 +382,7 @@ def visitTryExcept(self, node):
368382
369383 def visitTryFinally (self , node ):
370384 final = self .newBlock ()
371- self .emit ( 'SET_LINENO' , node . lineno )
385+ self .set_lineno ( node )
372386 self .emit ('SETUP_FINALLY' , final )
373387 self .visit (node .body )
374388 self .emit ('POP_BLOCK' )
@@ -402,16 +416,16 @@ def visitName(self, node):
402416 self .loadName (node .name )
403417
404418 def visitPass (self , node ):
405- self .emit ( 'SET_LINENO' , node . lineno )
419+ self .set_lineno ( node )
406420
407421 def visitImport (self , node ):
408- self .emit ( 'SET_LINENO' , node . lineno )
422+ self .set_lineno ( node )
409423 for name in node .names :
410424 self .emit ('IMPORT_NAME' , name )
411425 self .storeName (name )
412426
413427 def visitFrom (self , node ):
414- self .emit ( 'SET_LINENO' , node . lineno )
428+ self .set_lineno ( node )
415429 self .emit ('IMPORT_NAME' , node .modname )
416430 for name in node .names :
417431 if name == '*' :
@@ -426,7 +440,7 @@ def visitGetattr(self, node):
426440 # next five implement assignments
427441
428442 def visitAssign (self , node ):
429- self .emit ( 'SET_LINENO' , node . lineno )
443+ self .set_lineno ( node )
430444 self .visit (node .expr )
431445 dups = len (node .nodes ) - 1
432446 for i in range (len (node .nodes )):
@@ -477,8 +491,7 @@ def visitExec(self, node):
477491 def visitCallFunc (self , node ):
478492 pos = 0
479493 kw = 0
480- if hasattr (node , 'lineno' ):
481- self .emit ('SET_LINENO' , node .lineno )
494+ self .set_lineno (node )
482495 self .visit (node .node )
483496 for arg in node .args :
484497 self .visit (arg )
@@ -496,7 +509,7 @@ def visitCallFunc(self, node):
496509 self .emit (opcode , kw << 8 | pos )
497510
498511 def visitPrint (self , node ):
499- self .emit ( 'SET_LINENO' , node . lineno )
512+ self .set_lineno ( node )
500513 for child in node .nodes :
501514 self .visit (child )
502515 self .emit ('PRINT_ITEM' )
@@ -506,7 +519,7 @@ def visitPrintnl(self, node):
506519 self .emit ('PRINT_NEWLINE' )
507520
508521 def visitReturn (self , node ):
509- self .emit ( 'SET_LINENO' , node . lineno )
522+ self .set_lineno ( node )
510523 self .visit (node .value )
511524 self .emit ('RETURN_VALUE' )
512525
@@ -637,15 +650,13 @@ def visitSliceobj(self, node):
637650 self .emit ('BUILD_SLICE' , len (node .nodes ))
638651
639652 def visitDict (self , node ):
640- # XXX is this a good general strategy? could it be done
641- # separately from the general visitor
642- lineno = getattr (node , 'lineno' , None )
643- if lineno :
644- self .emit ('SET_LINENO' , lineno )
653+ lineno = getattr (node , 'lineno' , None )
654+ if lineno :
655+ set .emit ('SET_LINENO' , lineno )
645656 self .emit ('BUILD_MAP' , 0 )
646657 for k , v in node .items :
647658 lineno2 = getattr (node , 'lineno' , None )
648- if lineno != lineno2 :
659+ if lineno2 is not None and lineno != lineno2 :
649660 self .emit ('SET_LINENO' , lineno2 )
650661 lineno = lineno2
651662 self .emit ('DUP_TOP' )
@@ -687,7 +698,7 @@ def __init__(self, func, filename, isLambda=0):
687698 self .graph .setFlag (CO_VARARGS )
688699 if func .kwargs :
689700 self .graph .setFlag (CO_VARKEYWORDS )
690- self .emit ( 'SET_LINENO' , func . lineno )
701+ self .set_lineno ( func )
691702 if hasTupleArg :
692703 self .generateArgUnpack (func .argnames )
693704
0 commit comments