public function processRequest() { $request = $this->getRequest(); $user = $request->getUser(); if ($request->isFormPost()) { $source = $request->getStr('source'); $future = xhpast_get_parser_future($source); $resolved = $future->resolve(); // This is just to let it throw exceptions if stuff is broken. $parse_tree = XHPASTTree::newFromDataAndResolvedExecFuture($source, $resolved); list($err, $stdout, $stderr) = $resolved; $storage_tree = new PhabricatorXHPASTViewParseTree(); $storage_tree->setInput($source); $storage_tree->setStdout($stdout); $storage_tree->setAuthorPHID($user->getPHID()); $storage_tree->save(); return id(new AphrontRedirectResponse())->setURI('/xhpast/view/' . $storage_tree->getID() . '/'); } $form = id(new AphrontFormView())->setUser($user)->appendChild(id(new AphrontFormTextAreaControl())->setLabel('Source')->setName('source')->setHeight(AphrontFormTextAreaControl::HEIGHT_VERY_TALL))->appendChild(id(new AphrontFormSubmitControl())->setValue('Parse')); $panel = new AphrontPanelView(); $panel->setHeader('Generate XHP AST'); $panel->setWidth(AphrontPanelView::WIDTH_WIDE); $panel->appendChild($form); return $this->buildStandardPageResponse($panel, array('title' => 'XHPAST View')); }
protected function execute(ConduitAPIRequest $request) { $source = $request->getValue('code'); $future = xhpast_get_parser_future($source); list($stdout) = $future->resolvex(); return json_decode($stdout, true); }
public function willLintPaths(array $paths) { $futures = array(); foreach ($paths as $path) { if (array_key_exists($path, $this->trees)) { continue; } $futures[$path] = xhpast_get_parser_future($this->getData($path)); } foreach (Futures($futures)->limit(8) as $path => $future) { $this->willLintPath($path); $this->trees[$path] = null; try { $this->trees[$path] = XHPASTTree::newFromDataAndResolvedExecFuture($this->getData($path), $future->resolve()); $root = $this->trees[$path]->getRootNode(); $root->buildSelectCache(); $root->buildTokenCache(); } catch (XHPASTSyntaxErrorException $ex) { $this->raiseLintAtLine($ex->getErrorLine(), 1, self::LINT_PHP_SYNTAX_ERROR, 'This file contains a syntax error: ' . $ex->getMessage()); $this->stopAllLinters(); return; } catch (Exception $ex) { $this->raiseLintAtPath(self::LINT_UNABLE_TO_PARSE, 'XHPAST could not parse this file, probably because the AST is too ' . 'deep. Some lint issues may not have been detected. You may safely ' . 'ignore this warning.'); return; } } }
public function getHighlightFuture($source) { $scrub = false; if (strpos($source, '<?') === false) { $source = "<?php\n" . $source . "\n"; $scrub = true; } return new PhutilXHPASTSyntaxHighlighterFuture(xhpast_get_parser_future($source), $source, $scrub); }
protected function buildFutures(array $paths) { foreach ($paths as $path) { if (!isset($this->futures[$path])) { $this->futures[$path] = xhpast_get_parser_future($this->getData($path)); } } return array_select_keys($this->futures, $paths); }
*/ $root = dirname(dirname(dirname(__FILE__))); require_once $root . '/scripts/__init_script__.php'; if ($argc !== 1 || posix_isatty(STDIN)) { echo phutil_console_format("usage: find . -type f -name '*.php' | ./generate_php_symbols.php\n"); exit(1); } $input = file_get_contents('php://stdin'); $input = trim($input); $input = explode("\n", $input); $data = array(); $futures = array(); foreach ($input as $file) { $file = Filesystem::readablePath($file); $data[$file] = Filesystem::readFile($file); $futures[$file] = xhpast_get_parser_future($data[$file]); } foreach (Futures($futures)->limit(8) as $file => $future) { $tree = XHPASTTree::newFromDataAndResolvedExecFuture($data[$file], $future->resolve()); $root = $tree->getRootNode(); $scopes = array(); $functions = $root->selectDescendantsOfType('n_FUNCTION_DECLARATION'); foreach ($functions as $function) { $name = $function->getChildByIndex(2); print_symbol($file, 'function', $name); } $classes = $root->selectDescendantsOfType('n_CLASS_DECLARATION'); foreach ($classes as $class) { $class_name = $class->getChildByIndex(1); print_symbol($file, 'class', $class_name); $scopes[] = array($class, $class_name);
private function executeParserTest($name, $data) { $data = explode("\n", $data, 2); if (count($data) !== 2) { throw new Exception(pht('Expected multiple lines in parser test file "%s".', $name)); } $head = head($data); $body = last($data); if (!preg_match('/^#/', $head)) { throw new Exception(pht('Expected first line of parser test file "%s" to begin with "#" ' . 'and specify test options.', $name)); } $head = preg_replace('/^#\\s*/', '', $head); $options_parser = new PhutilSimpleOptions(); $options = $options_parser->parse($head); $type = null; foreach ($options as $key => $value) { switch ($key) { case 'pass': case 'fail-syntax': case 'fail-parse': if ($type !== null) { throw new Exception(pht('Test file "%s" unexpectedly specifies multiple expected ', 'test outcomes.', $name)); } $type = $key; break; case 'comment': // Human readable comment providing test case information. break; case 'rtrim': // Allows construction of tests which rely on EOF without newlines. $body = rtrim($body); break; default: throw new Exception(pht('Test file "%s" has unknown option "%s" in its options ' . 'string.', $name, $key)); } } if ($type === null) { throw new Exception(pht('Test file "%s" does not specify a test result (like "pass") in ' . 'its options string.', $name)); } $future = xhpast_get_parser_future($body); list($err, $stdout, $stderr) = $future->resolve(); switch ($type) { case 'pass': case 'fail-parse': $this->assertEqual(0, $err, pht('Exit code for "%s".', $name)); $expect_name = preg_replace('/\\.test$/', '.expect', $name); $dir = dirname(__FILE__) . '/data/'; $expect = Filesystem::readFile($dir . $expect_name); $expect = json_decode($expect, true); if (!is_array($expect)) { throw new Exception(pht('Test ".expect" file "%s" for test "%s" is not valid JSON.', $expect_name, $name)); } $stdout = json_decode($stdout, true); if (!is_array($stdout)) { throw new Exception(pht('Output for test file "%s" is not valid JSON.', $name)); } $json = new PhutilJSON(); $expect_nice = $json->encodeFormatted($expect); $stdout_nice = $json->encodeFormatted($stdout); if ($type == 'pass') { $this->assertEqual($expect_nice, $stdout_nice, pht('Parser output for "%s".', $name)); } else { $this->assertFalse($expect_nice == $stdout_nice, pht('Expected parser to parse "%s" incorrectly.', $name)); } break; case 'fail-syntax': $this->assertEqual(1, $err, pht('Exit code for "%s".', $name)); $this->assertTrue((bool) preg_match('/syntax error/', $stderr), pht('Expect "syntax error" in stderr or "%s".', $name)); break; } }
public static function newFromData($php_source) { $future = xhpast_get_parser_future($php_source); return self::newFromDataAndResolvedExecFuture($php_source, $future->resolve()); }
protected function executeAtomize($file_name, $file_data) { $future = xhpast_get_parser_future($file_data); $tree = XHPASTTree::newFromDataAndResolvedExecFuture($file_data, $future->resolve()); $atoms = array(); $root = $tree->getRootNode(); $func_decl = $root->selectDescendantsOfType('n_FUNCTION_DECLARATION'); foreach ($func_decl as $func) { $name = $func->getChildByIndex(2); // Don't atomize closures if ($name->getTypeName() === 'n_EMPTY') { continue; } $atom = $this->newAtom(DivinerAtom::TYPE_FUNCTION)->setName($name->getConcreteString())->setLine($func->getLineNumber())->setFile($file_name); $this->findAtomDocblock($atom, $func); $this->parseParams($atom, $func); $this->parseReturnType($atom, $func); $atoms[] = $atom; } $class_types = array(DivinerAtom::TYPE_CLASS => 'n_CLASS_DECLARATION', DivinerAtom::TYPE_INTERFACE => 'n_INTERFACE_DECLARATION'); foreach ($class_types as $atom_type => $node_type) { $class_decls = $root->selectDescendantsOfType($node_type); foreach ($class_decls as $class) { $name = $class->getChildByIndex(1, 'n_CLASS_NAME'); $atom = $this->newAtom($atom_type)->setName($name->getConcreteString())->setFile($file_name)->setLine($class->getLineNumber()); // This parses "final" and "abstract". $attributes = $class->getChildByIndex(0, 'n_CLASS_ATTRIBUTES'); foreach ($attributes->selectDescendantsOfType('n_STRING') as $attr) { $atom->setProperty($attr->getConcreteString(), true); } // If this exists, it is n_EXTENDS_LIST. $extends = $class->getChildByIndex(2); $extends_class = $extends->selectDescendantsOfType('n_CLASS_NAME'); foreach ($extends_class as $parent_class) { $atom->addExtends($this->newRef(DivinerAtom::TYPE_CLASS, $parent_class->getConcreteString())); } // If this exists, it is n_IMPLEMENTS_LIST. $implements = $class->getChildByIndex(3); $iface_names = $implements->selectDescendantsOfType('n_CLASS_NAME'); foreach ($iface_names as $iface_name) { $atom->addExtends($this->newRef(DivinerAtom::TYPE_INTERFACE, $iface_name->getConcreteString())); } $this->findAtomDocblock($atom, $class); $methods = $class->selectDescendantsOfType('n_METHOD_DECLARATION'); foreach ($methods as $method) { $matom = $this->newAtom(DivinerAtom::TYPE_METHOD); $this->findAtomDocblock($matom, $method); $attribute_list = $method->getChildByIndex(0); $attributes = $attribute_list->selectDescendantsOfType('n_STRING'); if ($attributes) { foreach ($attributes as $attribute) { $attr = strtolower($attribute->getConcreteString()); switch ($attr) { case 'final': case 'abstract': case 'static': $matom->setProperty($attr, true); break; case 'public': case 'protected': case 'private': $matom->setProperty('access', $attr); break; } } } else { $matom->setProperty('access', 'public'); } $this->parseParams($matom, $method); $matom->setName($method->getChildByIndex(2)->getConcreteString()); $matom->setLine($method->getLineNumber()); $matom->setFile($file_name); $this->parseReturnType($matom, $method); $atom->addChild($matom); $atoms[] = $matom; } $atoms[] = $atom; } } return $atoms; }