1: <?php declare(strict_types=1);
2:
3: namespace PhpParser\Parser;
4:
5: use PhpParser\Error;
6: use PhpParser\ErrorHandler;
7: use PhpParser\Parser;
8:
9: class Multiple implements Parser
10: {
11: /** @var Parser[] List of parsers to try, in order of preference */
12: private $parsers;
13:
14: /**
15: * Create a parser which will try multiple parsers in an order of preference.
16: *
17: * Parsers will be invoked in the order they're provided to the constructor. If one of the
18: * parsers runs without throwing, it's output is returned. Otherwise the exception that the
19: * first parser generated is thrown.
20: *
21: * @param Parser[] $parsers
22: */
23: public function __construct(array $parsers) {
24: $this->parsers = $parsers;
25: }
26:
27: public function parse(string $code, ErrorHandler $errorHandler = null) {
28: if (null === $errorHandler) {
29: $errorHandler = new ErrorHandler\Throwing;
30: }
31:
32: list($firstStmts, $firstError) = $this->tryParse($this->parsers[0], $errorHandler, $code);
33: if ($firstError === null) {
34: return $firstStmts;
35: }
36:
37: for ($i = 1, $c = count($this->parsers); $i < $c; ++$i) {
38: list($stmts, $error) = $this->tryParse($this->parsers[$i], $errorHandler, $code);
39: if ($error === null) {
40: return $stmts;
41: }
42: }
43:
44: throw $firstError;
45: }
46:
47: private function tryParse(Parser $parser, ErrorHandler $errorHandler, $code) {
48: $stmts = null;
49: $error = null;
50: try {
51: $stmts = $parser->parse($code, $errorHandler);
52: } catch (Error $error) {}
53: return [$stmts, $error];
54: }
55: }
56: