loopDepth = 0; } /** * @throws FatalErrorException if the node is a break or continue in a non-loop or switch context * @throws FatalErrorException if the node is trying to break out of more nested structures than exist * @throws FatalErrorException if the node is a break or continue and has a non-numeric argument * @throws FatalErrorException if the node is a break or continue and has an argument less than 1 * * @param Node $node */ public function enterNode(Node $node) { switch (true) { case $node instanceof Do_: case $node instanceof For_: case $node instanceof Foreach_: case $node instanceof Switch_: case $node instanceof While_: $this->loopDepth++; break; case $node instanceof Break_: case $node instanceof Continue_: $operator = $node instanceof Break_ ? 'break' : 'continue'; if ($this->loopDepth === 0) { $msg = \sprintf("'%s' not in the 'loop' or 'switch' context", $operator); throw new FatalErrorException($msg, 0, E_ERROR, null, $node->getLine()); } if ($node->num instanceof LNumber || $node->num instanceof DNumber) { $num = $node->num->value; if ($node->num instanceof DNumber || $num < 1) { $msg = \sprintf("'%s' operator accepts only positive numbers", $operator); throw new FatalErrorException($msg, 0, E_ERROR, null, $node->getLine()); } if ($num > $this->loopDepth) { $msg = \sprintf("Cannot '%s' %d levels", $operator, $num); throw new FatalErrorException($msg, 0, E_ERROR, null, $node->getLine()); } } elseif ($node->num) { $msg = \sprintf("'%s' operator with non-constant operand is no longer supported", $operator); throw new FatalErrorException($msg, 0, E_ERROR, null, $node->getLine()); } break; } } /** * @param Node $node */ public function leaveNode(Node $node) { switch (true) { case $node instanceof Do_: case $node instanceof For_: case $node instanceof Foreach_: case $node instanceof Switch_: case $node instanceof While_: $this->loopDepth--; break; } } }