aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorldore <laurent.dore@gmail.com>2017-11-21 05:55:47 +0100
committerEli Bendersky <eliben@users.noreply.github.com>2017-11-20 20:55:47 -0800
commit5da662c5dc5474b724b0a22d5424d6066bd30d91 (patch)
treedd737392386f6a26f25d625eb81d16dd8a1330c8
parent7547e850a05d84fbe598e6bd1bd03f09bf524ac6 (diff)
downloadpycparser-5da662c5dc5474b724b0a22d5424d6066bd30d91.tar.gz
Improve NodeVisitor performance, add iterator on Node children (Issue #219). (#220)
Improve NodeVisitor performance, add iterator on Node children.
-rw-r--r--pycparser/_ast_gen.py48
-rw-r--r--pycparser/c_ast.py256
2 files changed, 296 insertions, 8 deletions
diff --git a/pycparser/_ast_gen.py b/pycparser/_ast_gen.py
index 669c303..aacc700 100644
--- a/pycparser/_ast_gen.py
+++ b/pycparser/_ast_gen.py
@@ -84,6 +84,7 @@ class NodeCfg(object):
def generate_source(self):
src = self._gen_init()
src += '\n' + self._gen_children()
+ src += '\n' + self._gen_iter()
src += '\n' + self._gen_attr_names()
return src
@@ -131,6 +132,35 @@ class NodeCfg(object):
return src
+ def _gen_iter(self):
+ src = ' def __iter__(self):\n'
+
+ if self.all_entries:
+ for child in self.child:
+ src += (
+ ' if self.%(child)s is not None:\n' +
+ ' yield self.%(child)s\n') % (dict(child=child))
+
+ for seq_child in self.seq_child:
+ src += (
+ ' for child in (self.%(child)s or []):\n'
+ ' yield child\n') % (dict(child=seq_child))
+
+ if not (self.child or self.seq_child):
+ # Empty generator
+ src += (
+ ' return\n' +
+ ' yield\n'
+ )
+ else:
+ # Empty generator
+ src += (
+ ' return\n' +
+ ' yield\n'
+ )
+
+ return src
+
def _gen_attr_names(self):
src = " attr_names = (" + ''.join("%r, " % nm for nm in self.attr) + ')'
return src
@@ -253,21 +283,31 @@ class NodeVisitor(object):
* Modeled after Python's own AST visiting facilities
(the ast module of Python 3.0)
"""
+
+ _method_cache = None
+
def visit(self, node):
""" Visit a node.
"""
- method = 'visit_' + node.__class__.__name__
- visitor = getattr(self, method, self.generic_visit)
+
+ if self._method_cache is None:
+ self._method_cache = {}
+
+ visitor = self._method_cache.get(node.__class__.__name__, None)
+ if visitor is None:
+ method = 'visit_' + node.__class__.__name__
+ visitor = getattr(self, method, self.generic_visit)
+ self._method_cache[node.__class__.__name__] = visitor
+
return visitor(node)
def generic_visit(self, node):
""" Called if no explicit visitor function exists for a
node. Implements preorder visiting of the node.
"""
- for c_name, c in node.children():
+ for c in node:
self.visit(c)
-
'''
diff --git a/pycparser/c_ast.py b/pycparser/c_ast.py
index 5e81648..99cd6a4 100644
--- a/pycparser/c_ast.py
+++ b/pycparser/c_ast.py
@@ -112,21 +112,31 @@ class NodeVisitor(object):
* Modeled after Python's own AST visiting facilities
(the ast module of Python 3.0)
"""
+
+ _method_cache = None
+
def visit(self, node):
""" Visit a node.
"""
- method = 'visit_' + node.__class__.__name__
- visitor = getattr(self, method, self.generic_visit)
+
+ if self._method_cache is None:
+ self._method_cache = {}
+
+ visitor = self._method_cache.get(node.__class__.__name__, None)
+ if visitor is None:
+ method = 'visit_' + node.__class__.__name__
+ visitor = getattr(self, method, self.generic_visit)
+ self._method_cache[node.__class__.__name__] = visitor
+
return visitor(node)
def generic_visit(self, node):
""" Called if no explicit visitor function exists for a
node. Implements preorder visiting of the node.
"""
- for c_name, c in node.children():
+ for c in node:
self.visit(c)
-
class ArrayDecl(Node):
__slots__ = ('type', 'dim', 'dim_quals', 'coord', '__weakref__')
def __init__(self, type, dim, dim_quals, coord=None):
@@ -141,6 +151,12 @@ class ArrayDecl(Node):
if self.dim is not None: nodelist.append(("dim", self.dim))
return tuple(nodelist)
+ def __iter__(self):
+ if self.type is not None:
+ yield self.type
+ if self.dim is not None:
+ yield self.dim
+
attr_names = ('dim_quals', )
class ArrayRef(Node):
@@ -156,6 +172,12 @@ class ArrayRef(Node):
if self.subscript is not None: nodelist.append(("subscript", self.subscript))
return tuple(nodelist)
+ def __iter__(self):
+ if self.name is not None:
+ yield self.name
+ if self.subscript is not None:
+ yield self.subscript
+
attr_names = ()
class Assignment(Node):
@@ -172,6 +194,12 @@ class Assignment(Node):
if self.rvalue is not None: nodelist.append(("rvalue", self.rvalue))
return tuple(nodelist)
+ def __iter__(self):
+ if self.lvalue is not None:
+ yield self.lvalue
+ if self.rvalue is not None:
+ yield self.rvalue
+
attr_names = ('op', )
class BinaryOp(Node):
@@ -188,6 +216,12 @@ class BinaryOp(Node):
if self.right is not None: nodelist.append(("right", self.right))
return tuple(nodelist)
+ def __iter__(self):
+ if self.left is not None:
+ yield self.left
+ if self.right is not None:
+ yield self.right
+
attr_names = ('op', )
class Break(Node):
@@ -198,6 +232,10 @@ class Break(Node):
def children(self):
return ()
+ def __iter__(self):
+ return
+ yield
+
attr_names = ()
class Case(Node):
@@ -214,6 +252,12 @@ class Case(Node):
nodelist.append(("stmts[%d]" % i, child))
return tuple(nodelist)
+ def __iter__(self):
+ if self.expr is not None:
+ yield self.expr
+ for child in (self.stmts or []):
+ yield child
+
attr_names = ()
class Cast(Node):
@@ -229,6 +273,12 @@ class Cast(Node):
if self.expr is not None: nodelist.append(("expr", self.expr))
return tuple(nodelist)
+ def __iter__(self):
+ if self.to_type is not None:
+ yield self.to_type
+ if self.expr is not None:
+ yield self.expr
+
attr_names = ()
class Compound(Node):
@@ -243,6 +293,10 @@ class Compound(Node):
nodelist.append(("block_items[%d]" % i, child))
return tuple(nodelist)
+ def __iter__(self):
+ for child in (self.block_items or []):
+ yield child
+
attr_names = ()
class CompoundLiteral(Node):
@@ -258,6 +312,12 @@ class CompoundLiteral(Node):
if self.init is not None: nodelist.append(("init", self.init))
return tuple(nodelist)
+ def __iter__(self):
+ if self.type is not None:
+ yield self.type
+ if self.init is not None:
+ yield self.init
+
attr_names = ()
class Constant(Node):
@@ -271,6 +331,10 @@ class Constant(Node):
nodelist = []
return tuple(nodelist)
+ def __iter__(self):
+ return
+ yield
+
attr_names = ('type', 'value', )
class Continue(Node):
@@ -281,6 +345,10 @@ class Continue(Node):
def children(self):
return ()
+ def __iter__(self):
+ return
+ yield
+
attr_names = ()
class Decl(Node):
@@ -302,6 +370,14 @@ class Decl(Node):
if self.bitsize is not None: nodelist.append(("bitsize", self.bitsize))
return tuple(nodelist)
+ def __iter__(self):
+ if self.type is not None:
+ yield self.type
+ if self.init is not None:
+ yield self.init
+ if self.bitsize is not None:
+ yield self.bitsize
+
attr_names = ('name', 'quals', 'storage', 'funcspec', )
class DeclList(Node):
@@ -316,6 +392,10 @@ class DeclList(Node):
nodelist.append(("decls[%d]" % i, child))
return tuple(nodelist)
+ def __iter__(self):
+ for child in (self.decls or []):
+ yield child
+
attr_names = ()
class Default(Node):
@@ -330,6 +410,10 @@ class Default(Node):
nodelist.append(("stmts[%d]" % i, child))
return tuple(nodelist)
+ def __iter__(self):
+ for child in (self.stmts or []):
+ yield child
+
attr_names = ()
class DoWhile(Node):
@@ -345,6 +429,12 @@ class DoWhile(Node):
if self.stmt is not None: nodelist.append(("stmt", self.stmt))
return tuple(nodelist)
+ def __iter__(self):
+ if self.cond is not None:
+ yield self.cond
+ if self.stmt is not None:
+ yield self.stmt
+
attr_names = ()
class EllipsisParam(Node):
@@ -355,6 +445,10 @@ class EllipsisParam(Node):
def children(self):
return ()
+ def __iter__(self):
+ return
+ yield
+
attr_names = ()
class EmptyStatement(Node):
@@ -365,6 +459,10 @@ class EmptyStatement(Node):
def children(self):
return ()
+ def __iter__(self):
+ return
+ yield
+
attr_names = ()
class Enum(Node):
@@ -379,6 +477,10 @@ class Enum(Node):
if self.values is not None: nodelist.append(("values", self.values))
return tuple(nodelist)
+ def __iter__(self):
+ if self.values is not None:
+ yield self.values
+
attr_names = ('name', )
class Enumerator(Node):
@@ -393,6 +495,10 @@ class Enumerator(Node):
if self.value is not None: nodelist.append(("value", self.value))
return tuple(nodelist)
+ def __iter__(self):
+ if self.value is not None:
+ yield self.value
+
attr_names = ('name', )
class EnumeratorList(Node):
@@ -407,6 +513,10 @@ class EnumeratorList(Node):
nodelist.append(("enumerators[%d]" % i, child))
return tuple(nodelist)
+ def __iter__(self):
+ for child in (self.enumerators or []):
+ yield child
+
attr_names = ()
class ExprList(Node):
@@ -421,6 +531,10 @@ class ExprList(Node):
nodelist.append(("exprs[%d]" % i, child))
return tuple(nodelist)
+ def __iter__(self):
+ for child in (self.exprs or []):
+ yield child
+
attr_names = ()
class FileAST(Node):
@@ -435,6 +549,10 @@ class FileAST(Node):
nodelist.append(("ext[%d]" % i, child))
return tuple(nodelist)
+ def __iter__(self):
+ for child in (self.ext or []):
+ yield child
+
attr_names = ()
class For(Node):
@@ -454,6 +572,16 @@ class For(Node):
if self.stmt is not None: nodelist.append(("stmt", self.stmt))
return tuple(nodelist)
+ def __iter__(self):
+ if self.init is not None:
+ yield self.init
+ if self.cond is not None:
+ yield self.cond
+ if self.next is not None:
+ yield self.next
+ if self.stmt is not None:
+ yield self.stmt
+
attr_names = ()
class FuncCall(Node):
@@ -469,6 +597,12 @@ class FuncCall(Node):
if self.args is not None: nodelist.append(("args", self.args))
return tuple(nodelist)
+ def __iter__(self):
+ if self.name is not None:
+ yield self.name
+ if self.args is not None:
+ yield self.args
+
attr_names = ()
class FuncDecl(Node):
@@ -484,6 +618,12 @@ class FuncDecl(Node):
if self.type is not None: nodelist.append(("type", self.type))
return tuple(nodelist)
+ def __iter__(self):
+ if self.args is not None:
+ yield self.args
+ if self.type is not None:
+ yield self.type
+
attr_names = ()
class FuncDef(Node):
@@ -502,6 +642,14 @@ class FuncDef(Node):
nodelist.append(("param_decls[%d]" % i, child))
return tuple(nodelist)
+ def __iter__(self):
+ if self.decl is not None:
+ yield self.decl
+ if self.body is not None:
+ yield self.body
+ for child in (self.param_decls or []):
+ yield child
+
attr_names = ()
class Goto(Node):
@@ -514,6 +662,10 @@ class Goto(Node):
nodelist = []
return tuple(nodelist)
+ def __iter__(self):
+ return
+ yield
+
attr_names = ('name', )
class ID(Node):
@@ -526,6 +678,10 @@ class ID(Node):
nodelist = []
return tuple(nodelist)
+ def __iter__(self):
+ return
+ yield
+
attr_names = ('name', )
class IdentifierType(Node):
@@ -538,6 +694,10 @@ class IdentifierType(Node):
nodelist = []
return tuple(nodelist)
+ def __iter__(self):
+ return
+ yield
+
attr_names = ('names', )
class If(Node):
@@ -555,6 +715,14 @@ class If(Node):
if self.iffalse is not None: nodelist.append(("iffalse", self.iffalse))
return tuple(nodelist)
+ def __iter__(self):
+ if self.cond is not None:
+ yield self.cond
+ if self.iftrue is not None:
+ yield self.iftrue
+ if self.iffalse is not None:
+ yield self.iffalse
+
attr_names = ()
class InitList(Node):
@@ -569,6 +737,10 @@ class InitList(Node):
nodelist.append(("exprs[%d]" % i, child))
return tuple(nodelist)
+ def __iter__(self):
+ for child in (self.exprs or []):
+ yield child
+
attr_names = ()
class Label(Node):
@@ -583,6 +755,10 @@ class Label(Node):
if self.stmt is not None: nodelist.append(("stmt", self.stmt))
return tuple(nodelist)
+ def __iter__(self):
+ if self.stmt is not None:
+ yield self.stmt
+
attr_names = ('name', )
class NamedInitializer(Node):
@@ -599,6 +775,12 @@ class NamedInitializer(Node):
nodelist.append(("name[%d]" % i, child))
return tuple(nodelist)
+ def __iter__(self):
+ if self.expr is not None:
+ yield self.expr
+ for child in (self.name or []):
+ yield child
+
attr_names = ()
class ParamList(Node):
@@ -613,6 +795,10 @@ class ParamList(Node):
nodelist.append(("params[%d]" % i, child))
return tuple(nodelist)
+ def __iter__(self):
+ for child in (self.params or []):
+ yield child
+
attr_names = ()
class PtrDecl(Node):
@@ -627,6 +813,10 @@ class PtrDecl(Node):
if self.type is not None: nodelist.append(("type", self.type))
return tuple(nodelist)
+ def __iter__(self):
+ if self.type is not None:
+ yield self.type
+
attr_names = ('quals', )
class Return(Node):
@@ -640,6 +830,10 @@ class Return(Node):
if self.expr is not None: nodelist.append(("expr", self.expr))
return tuple(nodelist)
+ def __iter__(self):
+ if self.expr is not None:
+ yield self.expr
+
attr_names = ()
class Struct(Node):
@@ -655,6 +849,10 @@ class Struct(Node):
nodelist.append(("decls[%d]" % i, child))
return tuple(nodelist)
+ def __iter__(self):
+ for child in (self.decls or []):
+ yield child
+
attr_names = ('name', )
class StructRef(Node):
@@ -671,6 +869,12 @@ class StructRef(Node):
if self.field is not None: nodelist.append(("field", self.field))
return tuple(nodelist)
+ def __iter__(self):
+ if self.name is not None:
+ yield self.name
+ if self.field is not None:
+ yield self.field
+
attr_names = ('type', )
class Switch(Node):
@@ -686,6 +890,12 @@ class Switch(Node):
if self.stmt is not None: nodelist.append(("stmt", self.stmt))
return tuple(nodelist)
+ def __iter__(self):
+ if self.cond is not None:
+ yield self.cond
+ if self.stmt is not None:
+ yield self.stmt
+
attr_names = ()
class TernaryOp(Node):
@@ -703,6 +913,14 @@ class TernaryOp(Node):
if self.iffalse is not None: nodelist.append(("iffalse", self.iffalse))
return tuple(nodelist)
+ def __iter__(self):
+ if self.cond is not None:
+ yield self.cond
+ if self.iftrue is not None:
+ yield self.iftrue
+ if self.iffalse is not None:
+ yield self.iffalse
+
attr_names = ()
class TypeDecl(Node):
@@ -718,6 +936,10 @@ class TypeDecl(Node):
if self.type is not None: nodelist.append(("type", self.type))
return tuple(nodelist)
+ def __iter__(self):
+ if self.type is not None:
+ yield self.type
+
attr_names = ('declname', 'quals', )
class Typedef(Node):
@@ -734,6 +956,10 @@ class Typedef(Node):
if self.type is not None: nodelist.append(("type", self.type))
return tuple(nodelist)
+ def __iter__(self):
+ if self.type is not None:
+ yield self.type
+
attr_names = ('name', 'quals', 'storage', )
class Typename(Node):
@@ -749,6 +975,10 @@ class Typename(Node):
if self.type is not None: nodelist.append(("type", self.type))
return tuple(nodelist)
+ def __iter__(self):
+ if self.type is not None:
+ yield self.type
+
attr_names = ('name', 'quals', )
class UnaryOp(Node):
@@ -763,6 +993,10 @@ class UnaryOp(Node):
if self.expr is not None: nodelist.append(("expr", self.expr))
return tuple(nodelist)
+ def __iter__(self):
+ if self.expr is not None:
+ yield self.expr
+
attr_names = ('op', )
class Union(Node):
@@ -778,6 +1012,10 @@ class Union(Node):
nodelist.append(("decls[%d]" % i, child))
return tuple(nodelist)
+ def __iter__(self):
+ for child in (self.decls or []):
+ yield child
+
attr_names = ('name', )
class While(Node):
@@ -793,6 +1031,12 @@ class While(Node):
if self.stmt is not None: nodelist.append(("stmt", self.stmt))
return tuple(nodelist)
+ def __iter__(self):
+ if self.cond is not None:
+ yield self.cond
+ if self.stmt is not None:
+ yield self.stmt
+
attr_names = ()
class Pragma(Node):
@@ -805,5 +1049,9 @@ class Pragma(Node):
nodelist = []
return tuple(nodelist)
+ def __iter__(self):
+ return
+ yield
+
attr_names = ('string', )