From 5da662c5dc5474b724b0a22d5424d6066bd30d91 Mon Sep 17 00:00:00 2001 From: ldore Date: Tue, 21 Nov 2017 05:55:47 +0100 Subject: [PATCH] Improve NodeVisitor performance, add iterator on Node children (Issue #219). (#220) Improve NodeVisitor performance, add iterator on Node children. --- pycparser/_ast_gen.py | 48 +++++++- pycparser/c_ast.py | 256 +++++++++++++++++++++++++++++++++++++++++- 2 files changed, 296 insertions(+), 8 deletions(-) diff --git a/pycparser/_ast_gen.py b/pycparser/_ast_gen.py index 669c303e..aacc7005 100644 --- a/pycparser/_ast_gen.py +++ b/pycparser/_ast_gen.py @@ -84,6 +84,7 @@ def __init__(self, name, contents): 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 @@ def _gen_children(self): 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 @@ def visit_Constant(self, node): * 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 5e81648d..99cd6a46 100644 --- a/pycparser/c_ast.py +++ b/pycparser/c_ast.py @@ -112,21 +112,31 @@ def visit_Constant(self, node): * 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 @@ def children(self): 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 @@ def children(self): 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 @@ def children(self): 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 @@ def children(self): 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 @@ def __init__(self, coord=None): def children(self): return () + def __iter__(self): + return + yield + attr_names = () class Case(Node): @@ -214,6 +252,12 @@ def children(self): 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 @@ def children(self): 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 @@ def children(self): 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 @@ def children(self): 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 @@ def children(self): nodelist = [] return tuple(nodelist) + def __iter__(self): + return + yield + attr_names = ('type', 'value', ) class Continue(Node): @@ -281,6 +345,10 @@ def __init__(self, coord=None): def children(self): return () + def __iter__(self): + return + yield + attr_names = () class Decl(Node): @@ -302,6 +370,14 @@ def children(self): 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 @@ def children(self): 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 @@ def children(self): 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 @@ def children(self): 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 @@ def __init__(self, coord=None): def children(self): return () + def __iter__(self): + return + yield + attr_names = () class EmptyStatement(Node): @@ -365,6 +459,10 @@ def __init__(self, coord=None): def children(self): return () + def __iter__(self): + return + yield + attr_names = () class Enum(Node): @@ -379,6 +477,10 @@ def children(self): 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 @@ def children(self): 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 @@ def children(self): 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 @@ def children(self): 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 @@ def children(self): 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 @@ def children(self): 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 @@ def children(self): 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 @@ def children(self): 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 @@ def children(self): 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 @@ def children(self): nodelist = [] return tuple(nodelist) + def __iter__(self): + return + yield + attr_names = ('name', ) class ID(Node): @@ -526,6 +678,10 @@ def children(self): nodelist = [] return tuple(nodelist) + def __iter__(self): + return + yield + attr_names = ('name', ) class IdentifierType(Node): @@ -538,6 +694,10 @@ def children(self): nodelist = [] return tuple(nodelist) + def __iter__(self): + return + yield + attr_names = ('names', ) class If(Node): @@ -555,6 +715,14 @@ def children(self): 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 @@ def children(self): 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 @@ def children(self): 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 @@ def children(self): 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 @@ def children(self): 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 @@ def children(self): 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 @@ def children(self): 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 @@ def children(self): 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 @@ def children(self): 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 @@ def children(self): 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 @@ def children(self): 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 @@ def children(self): 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 @@ def children(self): 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 @@ def children(self): 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 @@ def children(self): 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 @@ def children(self): 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 @@ def children(self): 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 @@ def children(self): nodelist = [] return tuple(nodelist) + def __iter__(self): + return + yield + attr_names = ('string', )