Closed pako-pl closed 9 years ago
Need some more info here. If you have the function declaration node it would be:
$functionDeclarationNode->getBody()
->children(Filter::isInstanceOf('\Pharborist\Operators\AssignNode'));
Or if you want to find all assignments for all functions:
$assignments = $tree->find(Filter::isInstanceOf('\Pharborist\Functions\FunctionDeclarationNode'))
->map(function(FunctionDeclarationNode $node) {
return $node->getBody();
})
->children(Filter::isInstanceOf('\Pharborist\Operators\AssignNode'));
For now I added a specialized version of the walk() method to ParentNode:
public function walkSkippingAnonymousFunctions(callable $callback) {
$child = $this->head;
while($child) {
$callback($child);
if($child instanceof ParentNode && !($child instanceof Functions\AnonymousFunctionNode)) {
$child->walk($callback);
}
$child = $child->next;
}
}
This way when processing a method or a function I can skip bodies of anonymous functions it contains. Anything that happens inside the body of an anonymous function (for example variable assignments) isn't visible in the parent scope, so it should be processed separately.
A more generic solution would be to either have the callback return a boolean on wether it should continue processing that node. Or take an additional callback that decides which nodes to walk down.
public function walk(callable $callback) {
$child = $this->head;
while ($child) {
if ($callback($child) && $child instanceof ParentNode) {
$child->walk($callback);
}
$child = $child->next;
}
}
Or
public function walk(callable $callback, callaback $walkTest) {
$child = $this->head;
while ($child) {
$callback($child);
if ($child instanceof ParentNode && $walkTest($child)) {
$child->walk($callback, $walkTest);
}
$child = $child->next;
}
}
A second callback would make the code a little cleaner, but it's an extra function call for every node, so there would be a small performance penalty.
I think the first option - returning a boolean from the callback - is the way to go.
Added the callback returning FALSE to not walk down that parent node.
When doing static code analisys, context of a currenly processed call is very important. Right now there is no easy way to "skip" some nodes that shouldn't be matched by find() based on the type of their parent.
Let's say I would like to find all assignments inside the example() method, except for assignments contained inside the anonymous function, which belong to a different scope. I can use find() with an isInstanceOf() filter on the example() method node, but it will also match the assignments from the anonynous function. Any suggestions as to filter those out in an efficient way? Or perhaps there should be some more specialized filter for this use case?