11cb0ef41Sopenharmony_ci# -*- coding: utf-8 -*- 21cb0ef41Sopenharmony_ci""" 31cb0ef41Sopenharmony_ci jinja2.visitor 41cb0ef41Sopenharmony_ci ~~~~~~~~~~~~~~ 51cb0ef41Sopenharmony_ci 61cb0ef41Sopenharmony_ci This module implements a visitor for the nodes. 71cb0ef41Sopenharmony_ci 81cb0ef41Sopenharmony_ci :copyright: (c) 2017 by the Jinja Team. 91cb0ef41Sopenharmony_ci :license: BSD. 101cb0ef41Sopenharmony_ci""" 111cb0ef41Sopenharmony_cifrom jinja2.nodes import Node 121cb0ef41Sopenharmony_ci 131cb0ef41Sopenharmony_ci 141cb0ef41Sopenharmony_ciclass NodeVisitor(object): 151cb0ef41Sopenharmony_ci """Walks the abstract syntax tree and call visitor functions for every 161cb0ef41Sopenharmony_ci node found. The visitor functions may return values which will be 171cb0ef41Sopenharmony_ci forwarded by the `visit` method. 181cb0ef41Sopenharmony_ci 191cb0ef41Sopenharmony_ci Per default the visitor functions for the nodes are ``'visit_'`` + 201cb0ef41Sopenharmony_ci class name of the node. So a `TryFinally` node visit function would 211cb0ef41Sopenharmony_ci be `visit_TryFinally`. This behavior can be changed by overriding 221cb0ef41Sopenharmony_ci the `get_visitor` function. If no visitor function exists for a node 231cb0ef41Sopenharmony_ci (return value `None`) the `generic_visit` visitor is used instead. 241cb0ef41Sopenharmony_ci """ 251cb0ef41Sopenharmony_ci 261cb0ef41Sopenharmony_ci def get_visitor(self, node): 271cb0ef41Sopenharmony_ci """Return the visitor function for this node or `None` if no visitor 281cb0ef41Sopenharmony_ci exists for this node. In that case the generic visit function is 291cb0ef41Sopenharmony_ci used instead. 301cb0ef41Sopenharmony_ci """ 311cb0ef41Sopenharmony_ci method = 'visit_' + node.__class__.__name__ 321cb0ef41Sopenharmony_ci return getattr(self, method, None) 331cb0ef41Sopenharmony_ci 341cb0ef41Sopenharmony_ci def visit(self, node, *args, **kwargs): 351cb0ef41Sopenharmony_ci """Visit a node.""" 361cb0ef41Sopenharmony_ci f = self.get_visitor(node) 371cb0ef41Sopenharmony_ci if f is not None: 381cb0ef41Sopenharmony_ci return f(node, *args, **kwargs) 391cb0ef41Sopenharmony_ci return self.generic_visit(node, *args, **kwargs) 401cb0ef41Sopenharmony_ci 411cb0ef41Sopenharmony_ci def generic_visit(self, node, *args, **kwargs): 421cb0ef41Sopenharmony_ci """Called if no explicit visitor function exists for a node.""" 431cb0ef41Sopenharmony_ci for node in node.iter_child_nodes(): 441cb0ef41Sopenharmony_ci self.visit(node, *args, **kwargs) 451cb0ef41Sopenharmony_ci 461cb0ef41Sopenharmony_ci 471cb0ef41Sopenharmony_ciclass NodeTransformer(NodeVisitor): 481cb0ef41Sopenharmony_ci """Walks the abstract syntax tree and allows modifications of nodes. 491cb0ef41Sopenharmony_ci 501cb0ef41Sopenharmony_ci The `NodeTransformer` will walk the AST and use the return value of the 511cb0ef41Sopenharmony_ci visitor functions to replace or remove the old node. If the return 521cb0ef41Sopenharmony_ci value of the visitor function is `None` the node will be removed 531cb0ef41Sopenharmony_ci from the previous location otherwise it's replaced with the return 541cb0ef41Sopenharmony_ci value. The return value may be the original node in which case no 551cb0ef41Sopenharmony_ci replacement takes place. 561cb0ef41Sopenharmony_ci """ 571cb0ef41Sopenharmony_ci 581cb0ef41Sopenharmony_ci def generic_visit(self, node, *args, **kwargs): 591cb0ef41Sopenharmony_ci for field, old_value in node.iter_fields(): 601cb0ef41Sopenharmony_ci if isinstance(old_value, list): 611cb0ef41Sopenharmony_ci new_values = [] 621cb0ef41Sopenharmony_ci for value in old_value: 631cb0ef41Sopenharmony_ci if isinstance(value, Node): 641cb0ef41Sopenharmony_ci value = self.visit(value, *args, **kwargs) 651cb0ef41Sopenharmony_ci if value is None: 661cb0ef41Sopenharmony_ci continue 671cb0ef41Sopenharmony_ci elif not isinstance(value, Node): 681cb0ef41Sopenharmony_ci new_values.extend(value) 691cb0ef41Sopenharmony_ci continue 701cb0ef41Sopenharmony_ci new_values.append(value) 711cb0ef41Sopenharmony_ci old_value[:] = new_values 721cb0ef41Sopenharmony_ci elif isinstance(old_value, Node): 731cb0ef41Sopenharmony_ci new_node = self.visit(old_value, *args, **kwargs) 741cb0ef41Sopenharmony_ci if new_node is None: 751cb0ef41Sopenharmony_ci delattr(node, field) 761cb0ef41Sopenharmony_ci else: 771cb0ef41Sopenharmony_ci setattr(node, field, new_node) 781cb0ef41Sopenharmony_ci return node 791cb0ef41Sopenharmony_ci 801cb0ef41Sopenharmony_ci def visit_list(self, node, *args, **kwargs): 811cb0ef41Sopenharmony_ci """As transformers may return lists in some places this method 821cb0ef41Sopenharmony_ci can be used to enforce a list as return value. 831cb0ef41Sopenharmony_ci """ 841cb0ef41Sopenharmony_ci rv = self.visit(node, *args, **kwargs) 851cb0ef41Sopenharmony_ci if not isinstance(rv, list): 861cb0ef41Sopenharmony_ci rv = [rv] 871cb0ef41Sopenharmony_ci return rv 88