Kaydet (Commit) 566d9347 authored tarafından Jeremy Hylton's avatar Jeremy Hylton

compiler.transformer: correct lineno attribute when possible

SF patch #1015989

The basic idea of this patch is to compute lineno attributes for all AST nodes.  The actual
implementation lead to a lot of restructing and code cleanup.

The generated AST nodes now have an optional lineno argument to constructor.  Remove the
top-level asList(), since it didn't seem to serve any purpose.  Add an __iter__ to ast nodes.
Use isinstance() instead of explicit type tests.

Change transformer to use the new lineno attribute, which replaces three lines of code with one.
Use universal newlines so that we can get rid of special-case code for line endings.  Use
lookup_node() in a few more frequently called, but simple com_xxx methods().  Change string
exception to class exception.
üst 2ad68e69
This diff is collapsed.
This diff is collapsed.
...@@ -33,6 +33,65 @@ class CompilerTest(unittest.TestCase): ...@@ -33,6 +33,65 @@ class CompilerTest(unittest.TestCase):
else: else:
compiler.compile(buf, basename, "exec") compiler.compile(buf, basename, "exec")
def testLineNo(self):
# Test that all nodes except Module have a correct lineno attribute.
filename = __file__
if filename.endswith(".pyc") or filename.endswith(".pyo"):
filename = filename[:-1]
tree = compiler.parseFile(filename)
self.check_lineno(tree)
def check_lineno(self, node):
try:
self._check_lineno(node)
except AssertionError:
print node.__class__, node.lineno
raise
def _check_lineno(self, node):
if not node.__class__ in NOLINENO:
self.assert_(isinstance(node.lineno, int),
"lineno=%s on %s" % (node.lineno, node.__class__))
self.assert_(node.lineno > 0,
"lineno=%s on %s" % (node.lineno, node.__class__))
for child in node.getChildNodes():
self.check_lineno(child)
NOLINENO = (compiler.ast.Module, compiler.ast.Stmt, compiler.ast.Discard)
###############################################################################
# code below is just used to trigger some possible errors, for the benefit of
# testLineNo
###############################################################################
class Toto:
"""docstring"""
pass
a, b = 2, 3
[c, d] = 5, 6
l = [(x, y) for x, y in zip(range(5), range(5,10))]
l[0]
l[3:4]
if l:
pass
else:
a, b = b, a
try:
print yo
except:
yo = 3
else:
yo += 3
try:
a += b
finally:
b = 0
###############################################################################
def test_main(): def test_main():
global TEST_ALL global TEST_ALL
TEST_ALL = test.test_support.is_resource_enabled("compiler") TEST_ALL = test.test_support.is_resource_enabled("compiler")
......
...@@ -29,9 +29,7 @@ class Tests(unittest.TestCase): ...@@ -29,9 +29,7 @@ class Tests(unittest.TestCase):
assert vals['b'] == 2 assert vals['b'] == 2
def test_main(): def test_main():
test_support.run_unittest( test_support.run_unittest(Tests)
Tests
)
if __name__ == "__main__": if __name__ == "__main__":
test_main() test_main()
...@@ -563,6 +563,7 @@ Michael Stone ...@@ -563,6 +563,7 @@ Michael Stone
Ken Stox Ken Stox
Daniel Stutzbach Daniel Stutzbach
Paul Swartz Paul Swartz
Thenault Sylvain
Geoff Talvola Geoff Talvola
William Tanksley William Tanksley
Christian Tanzer Christian Tanzer
......
...@@ -94,7 +94,6 @@ class NodeInfo: ...@@ -94,7 +94,6 @@ class NodeInfo:
def gen_source(self): def gen_source(self):
buf = StringIO() buf = StringIO()
print >> buf, "class %s(Node):" % self.name print >> buf, "class %s(Node):" % self.name
print >> buf, ' nodes["%s"] = "%s"' % (self.name.lower(), self.name)
self._gen_init(buf) self._gen_init(buf)
print >> buf print >> buf
self._gen_getChildren(buf) self._gen_getChildren(buf)
...@@ -106,12 +105,14 @@ class NodeInfo: ...@@ -106,12 +105,14 @@ class NodeInfo:
return buf.read() return buf.read()
def _gen_init(self, buf): def _gen_init(self, buf):
print >> buf, " def __init__(self, %s):" % self.args if self.args:
print >> buf, " def __init__(self, %s, lineno=None):" % self.args
else:
print >> buf, " def __init__(self, lineno=None):"
if self.argnames: if self.argnames:
for name in self.argnames: for name in self.argnames:
print >> buf, " self.%s = %s" % (name, name) print >> buf, " self.%s = %s" % (name, name)
else: print >> buf, " self.lineno = lineno"
print >> buf, " pass"
if self.init: if self.init:
print >> buf, "".join([" " + line for line in self.init]) print >> buf, "".join([" " + line for line in self.init])
...@@ -128,15 +129,18 @@ class NodeInfo: ...@@ -128,15 +129,18 @@ class NodeInfo:
else: else:
print >> buf, " return %s" % clist print >> buf, " return %s" % clist
else: else:
print >> buf, " children = []" if len(self.argnames) == 1:
template = " children.%s(%sself.%s%s)" print >> buf, " return tuple(flatten(self.%s))" % self.argnames[0]
for name in self.argnames: else:
if self.argprops[name] == P_NESTED: print >> buf, " children = []"
print >> buf, template % ("extend", "flatten(", template = " children.%s(%sself.%s%s)"
name, ")") for name in self.argnames:
else: if self.argprops[name] == P_NESTED:
print >> buf, template % ("append", "", name, "") print >> buf, template % ("extend", "flatten(",
print >> buf, " return tuple(children)" name, ")")
else:
print >> buf, template % ("append", "", name, "")
print >> buf, " return tuple(children)"
def _gen_getChildNodes(self, buf): def _gen_getChildNodes(self, buf):
print >> buf, " def getChildNodes(self):" print >> buf, " def getChildNodes(self):"
...@@ -158,7 +162,7 @@ class NodeInfo: ...@@ -158,7 +162,7 @@ class NodeInfo:
template = " nodelist.%s(%sself.%s%s)" template = " nodelist.%s(%sself.%s%s)"
for name in self.argnames: for name in self.argnames:
if self.argprops[name] == P_NONE: if self.argprops[name] == P_NONE:
tmp = (" if self.%s is not None:" tmp = (" if self.%s is not None:\n"
" nodelist.append(self.%s)") " nodelist.append(self.%s)")
print >> buf, tmp % (name, name) print >> buf, tmp % (name, name)
elif self.argprops[name] == P_NESTED: elif self.argprops[name] == P_NESTED:
...@@ -226,16 +230,15 @@ if __name__ == "__main__": ...@@ -226,16 +230,15 @@ if __name__ == "__main__":
### PROLOGUE ### PROLOGUE
"""Python abstract syntax node definitions """Python abstract syntax node definitions
This file is automatically generated. This file is automatically generated by Tools/compiler/astgen.py
""" """
from types import TupleType, ListType
from consts import CO_VARARGS, CO_VARKEYWORDS from consts import CO_VARARGS, CO_VARKEYWORDS
def flatten(list): def flatten(list):
l = [] l = []
for elt in list: for elt in list:
t = type(elt) t = type(elt)
if t is TupleType or t is ListType: if t is tuple or t is list:
for elt2 in flatten(elt): for elt2 in flatten(elt):
l.append(elt2) l.append(elt2)
else: else:
...@@ -245,29 +248,17 @@ def flatten(list): ...@@ -245,29 +248,17 @@ def flatten(list):
def flatten_nodes(list): def flatten_nodes(list):
return [n for n in flatten(list) if isinstance(n, Node)] return [n for n in flatten(list) if isinstance(n, Node)]
def asList(nodearg):
l = []
for item in nodearg:
if hasattr(item, "asList"):
l.append(item.asList())
else:
t = type(item)
if t is TupleType or t is ListType:
l.append(tuple(asList(item)))
else:
l.append(item)
return l
nodes = {} nodes = {}
class Node: # an abstract base class class Node:
lineno = None # provide a lineno for nodes that don't have one """Abstract base class for ast nodes."""
def getType(self):
pass # implemented by subclass
def getChildren(self): def getChildren(self):
pass # implemented by subclasses pass # implemented by subclasses
def asList(self): def __iter__(self):
return tuple(asList(self.getChildren())) for n in self.getChildren():
yield n
def asList(self): # for backwards compatibility
return self.getChildren()
def getChildNodes(self): def getChildNodes(self):
pass # implemented by subclasses pass # implemented by subclasses
...@@ -290,6 +281,6 @@ class Expression(Node): ...@@ -290,6 +281,6 @@ class Expression(Node):
return "Expression(%s)" % (repr(self.node)) return "Expression(%s)" % (repr(self.node))
### EPILOGUE ### EPILOGUE
klasses = globals() for name, obj in globals().items():
for k in nodes.keys(): if isinstance(obj, type) and issubclass(obj, Node):
nodes[k] = klasses[nodes[k]] nodes[name.lower()] = obj
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment