PageRenderTime 51ms CodeModel.GetById 22ms RepoModel.GetById 0ms app.codeStats 0ms

/vendor/psy/psysh/src/Psy/Command/ParseCommand.php

https://bitbucket.org/acarolinepassos/tumblr-pando
PHP | 160 lines | 118 code | 13 blank | 29 comment | 3 complexity | a37c413fbc45d482deb7ac0ae4f0096a MD5 | raw file
Possible License(s): MPL-2.0-no-copyleft-exception, BSD-3-Clause, LGPL-2.1
  1. <?php
  2. /*
  3. * This file is part of Psy Shell.
  4. *
  5. * (c) 2012-2017 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\Input\CodeArgument;
  14. use Psy\ParserFactory;
  15. use Psy\VarDumper\Presenter;
  16. use Psy\VarDumper\PresenterAware;
  17. use Symfony\Component\Console\Input\InputArgument;
  18. use Symfony\Component\Console\Input\InputInterface;
  19. use Symfony\Component\Console\Input\InputOption;
  20. use Symfony\Component\Console\Output\OutputInterface;
  21. use Symfony\Component\VarDumper\Caster\Caster;
  22. /**
  23. * Parse PHP code and show the abstract syntax tree.
  24. */
  25. class ParseCommand extends Command implements PresenterAware
  26. {
  27. private $presenter;
  28. private $parserFactory;
  29. private $parsers;
  30. /**
  31. * {@inheritdoc}
  32. */
  33. public function __construct($name = null)
  34. {
  35. $this->parserFactory = new ParserFactory();
  36. $this->parsers = array();
  37. parent::__construct($name);
  38. }
  39. /**
  40. * PresenterAware interface.
  41. *
  42. * @param Presenter $presenter
  43. */
  44. public function setPresenter(Presenter $presenter)
  45. {
  46. $this->presenter = clone $presenter;
  47. $this->presenter->addCasters(array(
  48. 'PhpParser\Node' => function (Node $node, array $a) {
  49. $a = array(
  50. Caster::PREFIX_VIRTUAL . 'type' => $node->getType(),
  51. Caster::PREFIX_VIRTUAL . 'attributes' => $node->getAttributes(),
  52. );
  53. foreach ($node->getSubNodeNames() as $name) {
  54. $a[Caster::PREFIX_VIRTUAL . $name] = $node->$name;
  55. }
  56. return $a;
  57. },
  58. ));
  59. }
  60. /**
  61. * {@inheritdoc}
  62. */
  63. protected function configure()
  64. {
  65. $definition = array(
  66. new CodeArgument('code', InputArgument::REQUIRED, 'PHP code to parse.'),
  67. new InputOption('depth', '', InputOption::VALUE_REQUIRED, 'Depth to parse', 10),
  68. );
  69. if ($this->parserFactory->hasKindsSupport()) {
  70. $msg = 'One of PhpParser\\ParserFactory constants: '
  71. . implode(', ', ParserFactory::getPossibleKinds())
  72. . " (default is based on current interpreter's version)";
  73. $defaultKind = $this->parserFactory->getDefaultKind();
  74. $definition[] = new InputOption('kind', '', InputOption::VALUE_REQUIRED, $msg, $defaultKind);
  75. }
  76. $this
  77. ->setName('parse')
  78. ->setDefinition($definition)
  79. ->setDescription('Parse PHP code and show the abstract syntax tree.')
  80. ->setHelp(
  81. <<<'HELP'
  82. Parse PHP code and show the abstract syntax tree.
  83. This command is used in the development of PsySH. Given a string of PHP code,
  84. it pretty-prints the PHP Parser parse tree.
  85. See https://github.com/nikic/PHP-Parser
  86. It prolly won't be super useful for most of you, but it's here if you want to play.
  87. HELP
  88. );
  89. }
  90. /**
  91. * {@inheritdoc}
  92. */
  93. protected function execute(InputInterface $input, OutputInterface $output)
  94. {
  95. $code = $input->getArgument('code');
  96. if (strpos('<?', $code) === false) {
  97. $code = '<?php ' . $code;
  98. }
  99. $parserKind = $this->parserFactory->hasKindsSupport() ? $input->getOption('kind') : null;
  100. $depth = $input->getOption('depth');
  101. $nodes = $this->parse($this->getParser($parserKind), $code);
  102. $output->page($this->presenter->present($nodes, $depth));
  103. }
  104. /**
  105. * Lex and parse a string of code into statements.
  106. *
  107. * @param Parser $parser
  108. * @param string $code
  109. *
  110. * @return array Statements
  111. */
  112. private function parse(Parser $parser, $code)
  113. {
  114. try {
  115. return $parser->parse($code);
  116. } catch (\PhpParser\Error $e) {
  117. if (strpos($e->getMessage(), 'unexpected EOF') === false) {
  118. throw $e;
  119. }
  120. // If we got an unexpected EOF, let's try it again with a semicolon.
  121. return $parser->parse($code . ';');
  122. }
  123. }
  124. /**
  125. * Get (or create) the Parser instance.
  126. *
  127. * @param string|null $kind One of Psy\ParserFactory constants (only for PHP parser 2.0 and above)
  128. *
  129. * @return Parser
  130. */
  131. private function getParser($kind = null)
  132. {
  133. if (!array_key_exists($kind, $this->parsers)) {
  134. $this->parsers[$kind] = $this->parserFactory->createParser($kind);
  135. }
  136. return $this->parsers[$kind];
  137. }
  138. }