A more powerful version of generic_visit for statement blocks. An example of a block is the body of an if statement. This function allows specifying a postprocessing callback (the after_visit argument) argument which can be used to move nodes to a new destination. This is done by a
(self, nodes, before_visit=None, after_visit=None)
| 311 | return templates.replace(template, target=target, expression=expression) |
| 312 | |
| 313 | def visit_block(self, nodes, before_visit=None, after_visit=None): |
| 314 | """A more powerful version of generic_visit for statement blocks. |
| 315 | |
| 316 | An example of a block is the body of an if statement. |
| 317 | |
| 318 | This function allows specifying a postprocessing callback (the |
| 319 | after_visit argument) argument which can be used to move nodes to a new |
| 320 | destination. This is done by after_visit by returning a non-null |
| 321 | second return value, e.g. return new_node, new_destination. |
| 322 | |
| 323 | For example, a transformer could perform the following move: |
| 324 | |
| 325 | foo() |
| 326 | bar() |
| 327 | baz() |
| 328 | |
| 329 | foo() |
| 330 | if cond: |
| 331 | bar() |
| 332 | baz() |
| 333 | |
| 334 | The above could be done with a postprocessor of this kind: |
| 335 | |
| 336 | def after_visit(node): |
| 337 | if node_is_function_call(bar): |
| 338 | new_container_node = build_cond() |
| 339 | new_container_node.body.append(node) |
| 340 | return new_container_node, new_container_node.body |
| 341 | else: |
| 342 | # Once we set a new destination, all subsequent items will be |
| 343 | # moved to it, so we don't need to explicitly handle baz. |
| 344 | return node, None |
| 345 | |
| 346 | Args: |
| 347 | nodes: enumerable of AST node objects. If None, the function returns None. |
| 348 | before_visit: optional callable that is called before visiting each item |
| 349 | in nodes |
| 350 | after_visit: optional callable that takes in an AST node and returns a |
| 351 | tuple (new_node, new_destination). It is called after visiting each item |
| 352 | in nodes. Is used in the same was as the |
| 353 | visit_* methods: new_node will replace the node; if not None, |
| 354 | new_destination must be a list, and subsequent nodes will be placed |
| 355 | in this list instead of the list returned by visit_block. |
| 356 | |
| 357 | Returns: |
| 358 | A list of AST node objects containing the transformed items fron nodes, |
| 359 | except those nodes that have been relocated using after_visit. |
| 360 | """ |
| 361 | if nodes is None: |
| 362 | return None |
| 363 | |
| 364 | results = [] |
| 365 | node_destination = results |
| 366 | for node in nodes: |
| 367 | if before_visit: |
| 368 | # TODO(mdan): We can modify node here too, if ever needed. |
| 369 | before_visit() |
| 370 |