Skip to content

Commit

Permalink
Some documentation updates
Browse files Browse the repository at this point in the history
  • Loading branch information
nikic committed May 27, 2023
1 parent 69993a1 commit 5b65f9f
Show file tree
Hide file tree
Showing 4 changed files with 55 additions and 23 deletions.
14 changes: 11 additions & 3 deletions README.md
Expand Up @@ -70,12 +70,17 @@ This dumps an AST looking something like this:
```
array(
0: Stmt_Function(
attrGroups: array(
)
byRef: false
name: Identifier(
name: test
)
params: array(
0: Param(
attrGroups: array(
)
flags: 0
type: null
byRef: false
variadic: false
Expand All @@ -90,12 +95,11 @@ array(
0: Stmt_Expression(
expr: Expr_FuncCall(
name: Name(
parts: array(
0: var_dump
)
name: var_dump
)
args: array(
0: Arg(
name: null
value: Expr_Variable(
name: foo
)
Expand Down Expand Up @@ -137,12 +141,16 @@ This gives us an AST where the `Function_::$stmts` are empty:
```
array(
0: Stmt_Function(
attrGroups: array(
)
byRef: false
name: Identifier(
name: test
)
params: array(
0: Param(
attrGroups: array(
)
type: null
byRef: false
variadic: false
Expand Down
27 changes: 17 additions & 10 deletions doc/2_Usage_of_basic_components.markdown
Expand Up @@ -96,12 +96,17 @@ For the sample code from the previous section, this will produce the following o
```
array(
0: Stmt_Function(
attrGroups: array(
)
byRef: false
name: Identifier(
name: printLine
)
params: array(
0: Param(
attrGroups: array(
)
flags: 0
type: null
byRef: false
variadic: false
Expand Down Expand Up @@ -129,12 +134,11 @@ array(
1: Stmt_Expression(
expr: Expr_FuncCall(
name: Name(
parts: array(
0: printLine
)
name: printLine
)
args: array(
0: Arg(
name: null
value: Scalar_String(
value: Hello World!!!
)
Expand Down Expand Up @@ -343,15 +347,18 @@ i.e. before its subnodes are traversed, the latter when it is left.
All four methods can either return the changed node or not return at all (i.e. `null`) in which
case the current node is not changed.

The `enterNode()` method can additionally return the value `NodeTraverser::DONT_TRAVERSE_CHILDREN`,
The `enterNode()` method can additionally return the value `NodeVisitor::DONT_TRAVERSE_CHILDREN`,
which instructs the traverser to skip all children of the current node. To furthermore prevent subsequent
visitors from visiting the current node, `NodeTraverser::DONT_TRAVERSE_CURRENT_AND_CHILDREN` can be used instead.
visitors from visiting the current node, `NodeVisitor::DONT_TRAVERSE_CURRENT_AND_CHILDREN` can be used instead.

Both methods can additionally return the following values:

Both methods can additionally return the value `NodeTraverser::REMOVE_NODE`, in which
case the current node will be removed from the parent array. Furthermore, it is possible to return
an array of nodes, which will be merged into the parent array at the offset of the current node.
I.e. if in `array(A, B, C)` the node `B` should be replaced with `array(X, Y, Z)` the result will
be `array(A, X, Y, Z, C)`.
* `NodeVisitor::STOP_TRAVERSAL`, in which case no further nodes will be visited.
* `NodeVisitor::REMOVE_NODE`, in which case the current node will be removed from the parent array.
* `NodeVisitor::REPLACE_WITH_NULL`, in which case the current node will be replaced with `null`.
* An array of nodes, which will be merged into the parent array at the offset of the current node.
I.e. if in `array(A, B, C)` the node `B` should be replaced with `array(X, Y, Z)` the result will
be `array(A, X, Y, Z, C)`.

Instead of manually implementing the `NodeVisitor` interface you can also extend the `NodeVisitorAbstract`
class, which will define empty default implementations for all the above methods.
Expand Down
5 changes: 3 additions & 2 deletions doc/component/Pretty_printing.markdown
Expand Up @@ -32,10 +32,11 @@ Customizing the formatting
--------------------------

The pretty printer respects a number of `kind` attributes used by some notes (e.g., whether an
integer should be printed as decimal, hexadecimal, etc). Additionally, it supports two options:
integer should be printed as decimal, hexadecimal, etc). Additionally, it supports three options:

* `phpVersion` (defaults to 7.0) allows opting into formatting that is not supported by older PHP
* `phpVersion` (defaults to 7.1) allows opting into formatting that is not supported by older PHP
versions.
* `newline` (defaults to `"\n"`) can be set to `"\r\n"` in order to produce Windows newlines.
* `shortArraySyntax` determines the used array syntax if the `kind` attribute is not set. This is
a legacy option, and `phpVersion` should be used to control this behavior instead.

Expand Down
32 changes: 24 additions & 8 deletions doc/component/Walking_the_AST.markdown
Expand Up @@ -129,13 +129,13 @@ Now `$a && $b` will be replaced by `!($a && $b)`. Then the traverser will go int
only) child of `!($a && $b)`, which is `$a && $b`. The transformation applies again and we end up
with `!!($a && $b)`. This will continue until PHP hits the memory limit.

Finally, there are two special replacement types. The first is removal of a node:
Finally, there are three special replacement types. The first is removal of a node:

```php
public function leaveNode(Node $node) {
if ($node instanceof Node\Stmt\Return_) {
// Remove all return statements
return NodeTraverser::REMOVE_NODE;
return NodeVisitor::REMOVE_NODE;
}
}
```
Expand All @@ -155,7 +155,7 @@ public function leaveNode(Node $node) {
&& $node->expr->name instanceof Node\Name
&& $node->expr->name->toString() === 'var_dump'
) {
return NodeTraverser::REMOVE_NODE;
return NodeVisitor::REMOVE_NODE;
}
}
```
Expand All @@ -164,6 +164,20 @@ This example will remove all calls to `var_dump()` which occur as expression sta
that `var_dump($a);` will be removed, but `if (var_dump($a))` will not be removed (and there is no
obvious way in which it can be removed).

Another way to remove nodes is to replace them with `null`. For example, all `else` statements could
be removed as follows:

```php
public function leaveNode(Node $node) {
if ($node instanceof Node\Stmt\Else_) {
return NodeVisitor::REPLACE_WITH_NULL;
}
}
```

This is only safe to do if the subnode the node is stored in is nullable. `Node\Stmt\Else_` only
occurs inside `Node\Stmt\If_::$else`, which is nullable, so this particular replacement is safe.

Next to removing nodes, it is also possible to replace one node with multiple nodes. This
only works if the parent structure is an array.

Expand Down Expand Up @@ -197,7 +211,7 @@ private $classes = [];
public function enterNode(Node $node) {
if ($node instanceof Node\Stmt\Class_) {
$this->classes[] = $node;
return NodeTraverser::DONT_TRAVERSE_CHILDREN;
return NodeVisitor::DONT_TRAVERSE_CHILDREN;
}
}
```
Expand All @@ -217,7 +231,7 @@ public function enterNode(Node $node) {
$node->namespacedName->toString() === 'Foo\Bar\Baz'
) {
$this->class = $node;
return NodeTraverser::STOP_TRAVERSAL;
return NodeVisitor::STOP_TRAVERSAL;
}
}
```
Expand Down Expand Up @@ -255,13 +269,14 @@ $visitorA->enterNode(Stmt_Return)
$visitorB->enterNode(Stmt_Return)
$visitorA->enterNode(Expr_Variable)
$visitorB->enterNode(Expr_Variable)
$visitorA->leaveNode(Expr_Variable)
$visitorB->leaveNode(Expr_Variable)
$visitorA->leaveNode(Stmt_Return)
$visitorA->leaveNode(Expr_Variable)
$visitorB->leaveNode(Stmt_Return)
$visitorA->leaveNode(Stmt_Return)
```

That is, when visiting a node, enterNode and leaveNode will always be called for all visitors.
That is, when visiting a node, `enterNode()` and `leaveNode()` will always be called for all
visitors, with the `leaveNode()` calls happening in the reverse order of the `enterNode()` calls.
Running multiple visitors in parallel improves performance, as the AST only has to be traversed
once. However, it is not always possible to write visitors in a way that allows interleaved
execution. In this case, you can always fall back to performing multiple traversals:
Expand All @@ -286,6 +301,7 @@ special enterNode/leaveNode return values:
* If a visitor returns a replacement node, subsequent visitors will be passed the replacement node,
not the original one.
* If a visitor returns `REMOVE_NODE`, subsequent visitors will not see this node.
* If a visitor returns `REPLACE_WITH_NULL`, subsequent visitors will not see this node.
* If a visitor returns an array of replacement nodes, subsequent visitors will see neither the node
that was replaced, nor the replacement nodes.

Expand Down

0 comments on commit 5b65f9f

Please sign in to comment.