mirror of
https://github.com/nikic/PHP-Parser.git
synced 2025-02-06 08:58:27 +01:00
4b497045e0
The Lexer now only provides the tokens to the parser, while the parser is responsible for determining which attributes are placed on notes. This only needs to be done when the attributes are actually needed, rather than for all tokens. This removes the usedAttributes lexer option (and lexer options entirely). The attributes are now enabled unconditionally. They have less overhead now, and the need to explicitly enable them for some use cases (e.g. formatting-preserving printing) doesn't seem like a good tradeoff anymore. There are some additional changes to the Lexer interface that should be done after this, and the docs / upgrading guide haven't been adjusted yet.
207 lines
6.4 KiB
PHP
Executable File
207 lines
6.4 KiB
PHP
Executable File
#!/usr/bin/env php
|
|
<?php
|
|
|
|
foreach ([__DIR__ . '/../../../autoload.php', __DIR__ . '/../vendor/autoload.php'] as $file) {
|
|
if (file_exists($file)) {
|
|
require $file;
|
|
break;
|
|
}
|
|
}
|
|
|
|
ini_set('xdebug.max_nesting_level', 3000);
|
|
|
|
// Disable Xdebug var_dump() output truncation
|
|
ini_set('xdebug.var_display_max_children', -1);
|
|
ini_set('xdebug.var_display_max_data', -1);
|
|
ini_set('xdebug.var_display_max_depth', -1);
|
|
|
|
list($operations, $files, $attributes) = parseArgs($argv);
|
|
|
|
/* Dump nodes by default */
|
|
if (empty($operations)) {
|
|
$operations[] = 'dump';
|
|
}
|
|
|
|
if (empty($files)) {
|
|
showHelp("Must specify at least one file.");
|
|
}
|
|
|
|
$parser = (new PhpParser\ParserFactory())->createForVersion($attributes['version']);
|
|
$dumper = new PhpParser\NodeDumper([
|
|
'dumpComments' => true,
|
|
'dumpPositions' => $attributes['with-positions'],
|
|
]);
|
|
$prettyPrinter = new PhpParser\PrettyPrinter\Standard;
|
|
|
|
$traverser = new PhpParser\NodeTraverser();
|
|
$traverser->addVisitor(new PhpParser\NodeVisitor\NameResolver);
|
|
|
|
foreach ($files as $file) {
|
|
if ($file === '-') {
|
|
$code = file_get_contents('php://stdin');
|
|
fwrite(STDERR, "====> Stdin:\n");
|
|
} else if (strpos($file, '<?php') === 0) {
|
|
$code = $file;
|
|
fwrite(STDERR, "====> Code $code\n");
|
|
} else {
|
|
if (!file_exists($file)) {
|
|
fwrite(STDERR, "File $file does not exist.\n");
|
|
exit(1);
|
|
}
|
|
|
|
$code = file_get_contents($file);
|
|
fwrite(STDERR, "====> File $file:\n");
|
|
}
|
|
|
|
if ($attributes['with-recovery']) {
|
|
$errorHandler = new PhpParser\ErrorHandler\Collecting;
|
|
$stmts = $parser->parse($code, $errorHandler);
|
|
foreach ($errorHandler->getErrors() as $error) {
|
|
$message = formatErrorMessage($error, $code, $attributes['with-column-info']);
|
|
fwrite(STDERR, $message . "\n");
|
|
}
|
|
if (null === $stmts) {
|
|
continue;
|
|
}
|
|
} else {
|
|
try {
|
|
$stmts = $parser->parse($code);
|
|
} catch (PhpParser\Error $error) {
|
|
$message = formatErrorMessage($error, $code, $attributes['with-column-info']);
|
|
fwrite(STDERR, $message . "\n");
|
|
exit(1);
|
|
}
|
|
}
|
|
|
|
foreach ($operations as $operation) {
|
|
if ('dump' === $operation) {
|
|
fwrite(STDERR, "==> Node dump:\n");
|
|
echo $dumper->dump($stmts, $code), "\n";
|
|
} elseif ('pretty-print' === $operation) {
|
|
fwrite(STDERR, "==> Pretty print:\n");
|
|
echo $prettyPrinter->prettyPrintFile($stmts), "\n";
|
|
} elseif ('json-dump' === $operation) {
|
|
fwrite(STDERR, "==> JSON dump:\n");
|
|
echo json_encode($stmts, JSON_PRETTY_PRINT), "\n";
|
|
} elseif ('var-dump' === $operation) {
|
|
fwrite(STDERR, "==> var_dump():\n");
|
|
var_dump($stmts);
|
|
} elseif ('resolve-names' === $operation) {
|
|
fwrite(STDERR, "==> Resolved names.\n");
|
|
$stmts = $traverser->traverse($stmts);
|
|
}
|
|
}
|
|
}
|
|
|
|
function formatErrorMessage(PhpParser\Error $e, $code, $withColumnInfo) {
|
|
if ($withColumnInfo && $e->hasColumnInfo()) {
|
|
return $e->getMessageWithColumnInfo($code);
|
|
} else {
|
|
return $e->getMessage();
|
|
}
|
|
}
|
|
|
|
function showHelp($error = '') {
|
|
if ($error) {
|
|
fwrite(STDERR, $error . "\n\n");
|
|
}
|
|
fwrite($error ? STDERR : STDOUT, <<<'OUTPUT'
|
|
Usage: php-parse [operations] file1.php [file2.php ...]
|
|
or: php-parse [operations] "<?php code"
|
|
Turn PHP source code into an abstract syntax tree.
|
|
|
|
Operations is a list of the following options (--dump by default):
|
|
|
|
-d, --dump Dump nodes using NodeDumper
|
|
-p, --pretty-print Pretty print file using PrettyPrinter\Standard
|
|
-j, --json-dump Print json_encode() result
|
|
--var-dump var_dump() nodes (for exact structure)
|
|
-N, --resolve-names Resolve names using NodeVisitor\NameResolver
|
|
-c, --with-column-info Show column-numbers for errors (if available)
|
|
-P, --with-positions Show positions in node dumps
|
|
-r, --with-recovery Use parsing with error recovery
|
|
--version=VERSION Target specific PHP version (default: newest)
|
|
-h, --help Display this page
|
|
|
|
Example:
|
|
php-parse -d -p -N -d file.php
|
|
|
|
Dumps nodes, pretty prints them, then resolves names and dumps them again.
|
|
|
|
|
|
OUTPUT
|
|
);
|
|
exit($error ? 1 : 0);
|
|
}
|
|
|
|
function parseArgs($args) {
|
|
$operations = [];
|
|
$files = [];
|
|
$attributes = [
|
|
'with-column-info' => false,
|
|
'with-positions' => false,
|
|
'with-recovery' => false,
|
|
'version' => PhpParser\PhpVersion::getNewestSupported(),
|
|
];
|
|
|
|
array_shift($args);
|
|
$parseOptions = true;
|
|
foreach ($args as $arg) {
|
|
if (!$parseOptions) {
|
|
$files[] = $arg;
|
|
continue;
|
|
}
|
|
|
|
switch ($arg) {
|
|
case '--dump':
|
|
case '-d':
|
|
$operations[] = 'dump';
|
|
break;
|
|
case '--pretty-print':
|
|
case '-p':
|
|
$operations[] = 'pretty-print';
|
|
break;
|
|
case '--json-dump':
|
|
case '-j':
|
|
$operations[] = 'json-dump';
|
|
break;
|
|
case '--var-dump':
|
|
$operations[] = 'var-dump';
|
|
break;
|
|
case '--resolve-names':
|
|
case '-N';
|
|
$operations[] = 'resolve-names';
|
|
break;
|
|
case '--with-column-info':
|
|
case '-c';
|
|
$attributes['with-column-info'] = true;
|
|
break;
|
|
case '--with-positions':
|
|
case '-P':
|
|
$attributes['with-positions'] = true;
|
|
break;
|
|
case '--with-recovery':
|
|
case '-r':
|
|
$attributes['with-recovery'] = true;
|
|
break;
|
|
case '--help':
|
|
case '-h';
|
|
showHelp();
|
|
break;
|
|
case '--':
|
|
$parseOptions = false;
|
|
break;
|
|
default:
|
|
if (preg_match('/^--version=(.*)$/', $arg, $matches)) {
|
|
$attributes['version'] = PhpParser\PhpVersion::fromString($matches[1]);
|
|
} elseif ($arg[0] === '-' && \strlen($arg[0]) > 1) {
|
|
showHelp("Invalid operation $arg.");
|
|
} else {
|
|
$files[] = $arg;
|
|
}
|
|
}
|
|
}
|
|
|
|
return [$operations, $files, $attributes];
|
|
}
|