summaryrefslogtreecommitdiff
path: root/doc/_extensions/autojsdoc/parser/visitor.py
diff options
context:
space:
mode:
authorChristophe Simonis <chs@odoo.com>2017-09-19 13:05:04 +0200
committerChristophe Simonis <chs@odoo.com>2017-09-19 13:05:04 +0200
commit08db385d02dd67f82937e4325179dda1a82519b7 (patch)
tree9d1be20b01650218fefa38ec3ecae9a708fa0cf3 /doc/_extensions/autojsdoc/parser/visitor.py
parent071b46c22786d9b0b7d1ef46387907cbfeb8980b (diff)
parentd15a31ae6d944cf04f9da8752b069b221cac0d9a (diff)
[MERGE] forward port branch saas-18 up to d15a31ae6d9
Diffstat (limited to 'doc/_extensions/autojsdoc/parser/visitor.py')
-rw-r--r--doc/_extensions/autojsdoc/parser/visitor.py126
1 files changed, 126 insertions, 0 deletions
diff --git a/doc/_extensions/autojsdoc/parser/visitor.py b/doc/_extensions/autojsdoc/parser/visitor.py
new file mode 100644
index 00000000000..e5529d511dc
--- /dev/null
+++ b/doc/_extensions/autojsdoc/parser/visitor.py
@@ -0,0 +1,126 @@
+from pyjsparser.pyjsparserdata import Syntax
+
+_binary = lambda n: [n['left'], n['right']]
+_function = lambda n: n['params'] + n['defaults'] + [n['body']]
+# yields children in visitation order
+_children = {
+ Syntax.ArrayExpression: lambda n: n['elements'],
+ Syntax.ArrayPattern: lambda n: n['elements'],
+ Syntax.ArrowFunctionExpression: _function,
+ Syntax.AssignmentExpression: _binary,
+ Syntax.AssignmentPattern: _binary,
+ Syntax.BinaryExpression: _binary,
+ Syntax.BlockStatement: lambda n: n['body'],
+ Syntax.BreakStatement: lambda n: [],
+ Syntax.CallExpression: lambda n: [n['callee']] + n['arguments'],
+ Syntax.CatchClause: lambda n: [n['param'], n['body']],
+ Syntax.ClassBody: lambda n: [n['body']],
+ Syntax.ClassDeclaration: lambda n: [n['superClass'], n['body']],
+ Syntax.ClassExpression: lambda n: [n['superClass'], n['body']],
+ Syntax.ConditionalExpression: lambda n: [n['test'], n['consequent'], n['alternate']],
+ Syntax.ContinueStatement: lambda n: [],
+ Syntax.DebuggerStatement: lambda n: [],
+ Syntax.DoWhileStatement: lambda n: [n['body'], n['test']],
+ Syntax.EmptyStatement: lambda n: [],
+ Syntax.ExportAllDeclaration: lambda n: [n['source']],
+ Syntax.ExportDefaultDeclaration: lambda n: [n['declaration']],
+ Syntax.ExportNamedDeclaration: lambda n: ([n['declaration']] if n['declaration'] else n['specifiers']) + [n['source']],
+ Syntax.ExportSpecifier: lambda n: [n['local'], n['exported']],
+ Syntax.ExpressionStatement: lambda n: [n['expression']],
+ Syntax.ForStatement: lambda n: [n['init'], n['test'], n['update'], n['body']],
+ Syntax.ForInStatement: lambda n: [n['left'], n['right'], n['body']],
+ Syntax.FunctionDeclaration: _function,
+ Syntax.FunctionExpression: _function,
+ Syntax.Identifier: lambda n: [],
+ Syntax.IfStatement: lambda n: [n['test'], n['consequent'], n['alternate']],
+ Syntax.ImportDeclaration: lambda n: n['specifiers'] + [n['source']],
+ Syntax.ImportDefaultSpecifier: lambda n: [n['local']],
+ Syntax.ImportNamespaceSpecifier: lambda n: [n['local']],
+ Syntax.ImportSpecifier: lambda n: [n['local'], n['imported']],
+ Syntax.LabeledStatement: lambda n: [n['body']],
+ Syntax.Literal: lambda n: [],
+ Syntax.LogicalExpression: _binary,
+ Syntax.MemberExpression: lambda n: [n['object'], n['property']],
+ #Syntax.MethodDefinition: lambda n: [],
+ Syntax.NewExpression: lambda n: [n['callee']] + n['arguments'],
+ Syntax.ObjectExpression: lambda n: n['properties'],
+ Syntax.ObjectPattern: lambda n: n['properties'],
+ Syntax.Program: lambda n: n['body'],
+ Syntax.Property: lambda n: [n['key'], n['value']],
+ Syntax.RestElement: lambda n: [n['argument']],
+ Syntax.ReturnStatement: lambda n: [n['argument']],
+ Syntax.SequenceExpression: lambda n: n['expressions'],
+ Syntax.SpreadElement: lambda n: [n['argument']],
+ Syntax.Super: lambda n: [],
+ Syntax.SwitchCase: lambda n: [n['test'], n['consequent']],
+ Syntax.SwitchStatement: lambda n: [n['discriminant']] + n['cases'],
+ Syntax.TaggedTemplateExpression: lambda n: [n['tag'], n['quasi']],
+ Syntax.TemplateElement: lambda n: [],
+ Syntax.TemplateLiteral: lambda n: n['quasis'] + n['expressions'],
+ Syntax.ThisExpression: lambda n: [],
+ Syntax.ThrowStatement: lambda n: [n['argument']],
+ Syntax.TryStatement: lambda n: [n['block'], n['handler'], n['finalizer']],
+ Syntax.UnaryExpression: lambda n: [n['argument']],
+ Syntax.UpdateExpression: lambda n: [n['argument']],
+ Syntax.VariableDeclaration: lambda n: n['declarations'],
+ Syntax.VariableDeclarator: lambda n: [n['id'], n['init']],
+ Syntax.WhileStatement: lambda n: [n['test'], n['body']],
+ Syntax.WithStatement: lambda n: [n['object'], n['body']],
+}
+
+SKIP = object()
+class Visitor(object):
+ """
+ Generic visitor for the pyjsparser AST.
+
+ Visitation is driven by the ``visit`` method, which iterates the tree in
+ depth-first pre-order.
+
+ For each node, calls ``enter_$NODETYPE``, visits the children then calls
+ ``exit_$NODETYPE``. If the enter or exit methods are not present on the
+ visitor, falls back on ``enter_generic`` and ``exit_generic``.
+
+ Any ``enter_`` method can return ``SKIP`` to suppress both the traversal
+ of the subtree *and* the call to the corresponding ``exit_`` method
+ (whether generic or specific).
+
+ For convenience, ``visit`` will return whatever is set as the visitor's
+ ``result`` attribute, ``None`` by default.
+
+ ``visit`` can be given multiple root nodes, and it can be called multiple
+ times. The ``result`` attribute is cleared at each call but not between
+ two roots of the same ``visit`` call.
+ """
+ def __init__(self):
+ super(Visitor, self).__init__()
+ self.result = None
+
+ def enter_generic(self, node): pass
+ def exit_generic(self, node): pass
+
+ def visit(self, nodes):
+ if isinstance(nodes, dict):
+ nodes = [nodes]
+ # if multiple nodes are passed in, we need to reverse the order in
+ # order to traverse front-to-back rather than the other way around
+ nodes = list(reversed(nodes))
+
+ while nodes:
+ node = nodes.pop()
+ # should probably filter None descendants in _children...
+ if node is None:
+ continue
+ node_type = node['type']
+ if node_type == '_exit':
+ node = node['node']
+ getattr(self, 'exit_' + node['type'], self.exit_generic)(node)
+ continue
+
+ if getattr(self, 'enter_' + node_type, self.enter_generic)(node) is SKIP:
+ continue
+
+ nodes.append({'type': '_exit', 'node': node})
+ nodes.extend(reversed(_children[node_type](node)))
+
+ return self.result
+