ParseCommand.php 3.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121
  1. <?php
  2. /*
  3. * This file is part of Psy Shell.
  4. *
  5. * (c) 2012-2023 Justin Hileman
  6. *
  7. * For the full copyright and license information, please view the LICENSE
  8. * file that was distributed with this source code.
  9. */
  10. namespace Psy\Command;
  11. use PhpParser\Node;
  12. use PhpParser\Parser;
  13. use Psy\Context;
  14. use Psy\ContextAware;
  15. use Psy\Input\CodeArgument;
  16. use Psy\ParserFactory;
  17. use Psy\VarDumper\Presenter;
  18. use Psy\VarDumper\PresenterAware;
  19. use Symfony\Component\Console\Input\InputInterface;
  20. use Symfony\Component\Console\Input\InputOption;
  21. use Symfony\Component\Console\Output\OutputInterface;
  22. use Symfony\Component\VarDumper\Caster\Caster;
  23. /**
  24. * Parse PHP code and show the abstract syntax tree.
  25. */
  26. class ParseCommand extends Command implements ContextAware, PresenterAware
  27. {
  28. protected Context $context;
  29. private Presenter $presenter;
  30. private Parser $parser;
  31. /**
  32. * {@inheritdoc}
  33. */
  34. public function __construct($name = null)
  35. {
  36. $this->parser = (new ParserFactory())->createParser();
  37. parent::__construct($name);
  38. }
  39. /**
  40. * ContextAware interface.
  41. *
  42. * @param Context $context
  43. */
  44. public function setContext(Context $context)
  45. {
  46. $this->context = $context;
  47. }
  48. /**
  49. * PresenterAware interface.
  50. *
  51. * @param Presenter $presenter
  52. */
  53. public function setPresenter(Presenter $presenter)
  54. {
  55. $this->presenter = clone $presenter;
  56. $this->presenter->addCasters([
  57. Node::class => function (Node $node, array $a) {
  58. $a = [
  59. Caster::PREFIX_VIRTUAL.'type' => $node->getType(),
  60. Caster::PREFIX_VIRTUAL.'attributes' => $node->getAttributes(),
  61. ];
  62. foreach ($node->getSubNodeNames() as $name) {
  63. $a[Caster::PREFIX_VIRTUAL.$name] = $node->$name;
  64. }
  65. return $a;
  66. },
  67. ]);
  68. }
  69. /**
  70. * {@inheritdoc}
  71. */
  72. protected function configure()
  73. {
  74. $this
  75. ->setName('parse')
  76. ->setDefinition([
  77. new CodeArgument('code', CodeArgument::REQUIRED, 'PHP code to parse.'),
  78. new InputOption('depth', '', InputOption::VALUE_REQUIRED, 'Depth to parse.', 10),
  79. ])
  80. ->setDescription('Parse PHP code and show the abstract syntax tree.')
  81. ->setHelp(
  82. <<<'HELP'
  83. Parse PHP code and show the abstract syntax tree.
  84. This command is used in the development of PsySH. Given a string of PHP code,
  85. it pretty-prints the PHP Parser parse tree.
  86. See https://github.com/nikic/PHP-Parser
  87. It prolly won't be super useful for most of you, but it's here if you want to play.
  88. HELP
  89. );
  90. }
  91. /**
  92. * {@inheritdoc}
  93. */
  94. protected function execute(InputInterface $input, OutputInterface $output): int
  95. {
  96. $code = $input->getArgument('code');
  97. $depth = $input->getOption('depth');
  98. $nodes = $this->parser->parse($code);
  99. $output->page($this->presenter->present($nodes, $depth));
  100. $this->context->setReturnValue($nodes);
  101. return 0;
  102. }
  103. }