Skip to content

Commit

Permalink
Forward-compatible PHP Parser factory support.
Browse files Browse the repository at this point in the history
This drops support for "parser kind". This means the `parse` command no longer accepts a `--kind` argument, but I'm not convinced anyone ever used that anyway :)
  • Loading branch information
bobthecow committed Nov 13, 2023
1 parent 7e0785b commit 72b65ee
Show file tree
Hide file tree
Showing 5 changed files with 13 additions and 96 deletions.
7 changes: 1 addition & 6 deletions src/CodeCleaner.php
Original file line number Diff line number Diff line change
Expand Up @@ -70,12 +70,7 @@ public function __construct(Parser $parser = null, Printer $printer = null, Node
$this->yolo = $yolo;
$this->strictTypes = $strictTypes;

if ($parser === null) {
$parserFactory = new ParserFactory();
$parser = $parserFactory->createParser();
}

$this->parser = $parser;
$this->parser = $parser ?? (new ParserFactory())->createParser();
$this->printer = $printer ?: new Printer();
$this->traverser = $traverser ?: new NodeTraverser();

Expand Down
28 changes: 3 additions & 25 deletions src/Command/ParseCommand.php
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,6 @@
namespace Psy\Command;

use PhpParser\Node;
use PhpParser\Parser;
use Psy\Context;
use Psy\ContextAware;
use Psy\Input\CodeArgument;
Expand All @@ -37,16 +36,14 @@ class ParseCommand extends Command implements ContextAware, PresenterAware
protected $context;

private $presenter;
private $parserFactory;
private $parsers;
private $parser;

/**
* {@inheritdoc}
*/
public function __construct($name = null)
{
$this->parserFactory = new ParserFactory();
$this->parsers = [];
$this->parser = (new ParserFactory())->createParser();

parent::__construct($name);
}
Expand Down Expand Up @@ -90,16 +87,11 @@ public function setPresenter(Presenter $presenter)
*/
protected function configure()
{
$kindMsg = 'One of PhpParser\\ParserFactory constants: '
.\implode(', ', ParserFactory::getPossibleKinds())
." (default is based on current interpreter's version).";

$this
->setName('parse')
->setDefinition([
new CodeArgument('code', CodeArgument::REQUIRED, 'PHP code to parse.'),
new InputOption('depth', '', InputOption::VALUE_REQUIRED, 'Depth to parse.', 10),
new InputOption('kind', '', InputOption::VALUE_REQUIRED, $kindMsg, $this->parserFactory->getDefaultKind()),
])
->setDescription('Parse PHP code and show the abstract syntax tree.')
->setHelp(
Expand All @@ -125,25 +117,11 @@ protected function execute(InputInterface $input, OutputInterface $output): int
$parserKind = $input->getOption('kind');
$depth = $input->getOption('depth');

$nodes = $this->getParser($parserKind)->parse($code);
$nodes = $this->parser->parse($code);
$output->page($this->presenter->present($nodes, $depth));

$this->context->setReturnValue($nodes);

return 0;
}

/**
* Get (or create) the Parser instance.
*
* @param string|null $kind One of Psy\ParserFactory constants (only for PHP parser 2.0 and above)
*/
private function getParser(string $kind = null): CodeArgumentParser
{
if (!\array_key_exists($kind, $this->parsers)) {
$this->parsers[$kind] = new CodeArgumentParser($this->parserFactory->createParser($kind));
}

return $this->parsers[$kind];
}
}
3 changes: 1 addition & 2 deletions src/ExecutionLoop/RunkitReloader.php
Original file line number Diff line number Diff line change
Expand Up @@ -41,8 +41,7 @@ public static function isSupported(): bool
*/
public function __construct()
{
$parserFactory = new ParserFactory();
$this->parser = $parserFactory->createParser();
$this->parser = (new ParserFactory())->createParser();
}

/**
Expand Down
45 changes: 7 additions & 38 deletions src/ParserFactory.php
Original file line number Diff line number Diff line change
Expand Up @@ -15,52 +15,21 @@
use PhpParser\ParserFactory as OriginalParserFactory;

/**
* Parser factory to abstract over PHP parser library versions.
* Parser factory to abstract over PHP Parser library versions.
*/
class ParserFactory
{
const ONLY_PHP5 = 'ONLY_PHP5';
const ONLY_PHP7 = 'ONLY_PHP7';
const PREFER_PHP5 = 'PREFER_PHP5';
const PREFER_PHP7 = 'PREFER_PHP7';

/**
* Possible kinds of parsers for the factory, from PHP parser library.
*
* @return string[]
* New parser instance.
*/
public static function getPossibleKinds(): array
public function createParser(): Parser
{
return ['ONLY_PHP5', 'ONLY_PHP7', 'PREFER_PHP5', 'PREFER_PHP7'];
}

/**
* Default kind (if supported, based on current interpreter's version).
*
* @return string|null
*/
public function getDefaultKind()
{
return static::ONLY_PHP7;
}
$factory = new OriginalParserFactory();

/**
* New parser instance with given kind.
*
* @param string|null $kind One of class constants (only for PHP parser 2.0 and above)
*/
public function createParser($kind = null): Parser
{
$originalFactory = new OriginalParserFactory();

$kind = $kind ?: $this->getDefaultKind();

if (!\in_array($kind, static::getPossibleKinds())) {
throw new \InvalidArgumentException('Unknown parser kind');
if (!\method_exists($factory, 'createForHostVersion')) {
return $factory->create(OriginalParserFactory::PREFER_PHP7);
}

$parser = $originalFactory->create(\constant(OriginalParserFactory::class.'::'.$kind));

return $parser;
return $factory->createForHostVersion();
}
}
26 changes: 1 addition & 25 deletions test/ParserFactoryTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -11,41 +11,17 @@

namespace Psy\Test;

use PhpParser\ParserFactory as OriginalParserFactory;
use Psy\ParserFactory;

/**
* @group isolation-fail
*/
class ParserFactoryTest extends \PHPUnit\Framework\TestCase
{
public function testGetPossibleKinds()
{
$kinds = ParserFactory::getPossibleKinds();
$this->assertContains(ParserFactory::PREFER_PHP7, $kinds);
foreach ($kinds as $kind) {
$this->assertTrue(\defined("Psy\\ParserFactory::$kind"));
}
}

public function testGetDefaultKind()
{
$factory = new ParserFactory();

if (!\class_exists(OriginalParserFactory::class)) {
$this->assertNull($factory->getDefaultKind());

return;
}

$this->assertSame(ParserFactory::ONLY_PHP7, $factory->getDefaultKind());
}

public function testCreateParser()
{
$factory = new ParserFactory();

$parser = $factory->createParser();
$this->assertInstanceOf(\PhpParser\Parser\Php7::class, $parser);
$this->assertInstanceOf(\PhpParser\Parser::class, $parser);
}
}

0 comments on commit 72b65ee

Please sign in to comment.