xarxaprod-wp-theme/vendor/mck89/peast/doc/tree-traversing.md

120 lines
4.5 KiB
Markdown
Raw Permalink Normal View History

2024-01-09 16:13:20 +01:00
Tree Traversing
==========
**_From version 1.1_**
To traverse an AST generated by Peast you can use the **Traverser** class:
```php
//Generate the AST
$ast = Peast\Peast::latest($source, $options)->parse();
//Set up the Traverser
$traverser = new Peast\Traverser;
$traverser->addFunction(function ($node) {
//Do something with the current node
});
//Start traversing
$traverser->traverse($ast);
```
You can add one or more functions to the Traverser using the `addFunction` method. These functions receive the current traversed node while the Traverser runs on the tree.
The `traverse` method runs the traversing starting from the given node.
Options
-------------
**_From version 1.12_**
The Traverser class constructor takes an optional associative array of options.
Available options are:
* "skipStartingNode": by default the traversing begins with the starting node passed to the `traverse` method. If this option is set to true the starting node will be ignored.
* "passParentNode": by default the functions added to the Traverser receive the traversed node as the only argument. if this option is set to true the node's parent node will be passed as second argument to all the functions. Note that the parent node is calculated during traversing, so for the starting node it will always be null.
Tree manipulation
-------------
Functions added to the Traverser instance can alter the tree during the traversing by modifying, replacing or removing the node they receive and they can also control the behaviour of the Traverser to make it stop or skip the node's children.
Traverser class provides some constants to perform these operations:
* `Traverser::REMOVE_NODE`: removes the node
* `Traverser::DONT_TRAVERSE_CHILD_NODES`: skips the node's children
* `Traverser::STOP_TRAVERSING`: stops the traversing
The action that will be executed depends on the value returned by the functions.
If you want to remove a node the function must return the `Traverser::REMOVE_NODE` constant:
```php
$traverser->addFunction(function ($node) {
//Remove all literal nodes
if ($node->getType() === "Literal") {
return Peast\Traverser::REMOVE_NODE;
}
});
```
If you want to control the traversing you can return `Traverser::DONT_TRAVERSE_CHILD_NODES` or `Traverser::STOP_TRAVERSING` constants:
```php
$traverser->addFunction(function ($node) {
//Skip nodes inside array expressions
if ($node->getType() === "ArrayExpression") {
return Peast\Traverser::DONT_TRAVERSE_CHILD_NODES;
}
//Stop the traversing when an identifier named "stop" is found
elseif ($node->getType() === "Identifier" && $node->getName() === "stop") {
return Peast\Traverser::STOP_TRAVERSING;
}
});
```
You can also return a combination of these constants:
```php
$traverser->addFunction(function ($node) {
//Remove the string "test" and then stop the traversing
if ($node->getType() === "Literal" && $node->getValue() === "test") {
return Peast\Traverser::REMOVE_NODE | Peast\Traverser::STOP_TRAVERSING;
}
});
```
To replace a node you must return the replacement node:
```php
$traverser->addFunction(function ($node) {
//Replace the number 2 with 1
if ($node->getType() === "Literal" && $node->getValue() === 2) {
$literal = new \Peast\Syntax\Node\NumericLiteral();
return $literal->setValue(1);
}
});
```
You can also control the traversing and replace a node in the same function:
```php
$traverser->addFunction(function ($node) {
//Replace an array expression with an object expression without traversing its children
if ($node->getType() === "ArrayExpression") {
$obj = new \Peast\Syntax\Node\ObjectExpression();
return array($obj, Peast\Traverser::DONT_TRAVERSE_CHILD_NODES);
}
});
```
If the function returns any other value or nothing, no action will be executed and you can modify nodes without altering the tree structure:
```php
use Peast\Syntax\Node\StringLiteral;
$traverser->addFunction(function ($node) {
//Make all the strings uppercase
if ($node->getType() === "Literal" && $node instanceof StringLiteral) {
$node->setValue(strtoupper($node->getValue()));
}
});
```
Shortcut method
-------------
Every node implements a `traverse` method as a shortcut to initialize a traverser on itself:
```php
$traversingFn = function ($node) { /* ... */ };
//Traverse $ast node
$ast->traverse($traversingFn, $options);
//Equivalent to
$traverser = new Peast\Traverser;
$traverser->addFunction($traversingFn)->traverse($ast);
```