コード例 #1
0
ファイル: XHPASTNodeList.php プロジェクト: rmoorman/libphutil
 public static function newFromTree(XHPASTTree $tree)
 {
     $obj = new XHPASTNodeList();
     $obj->tree = $tree;
     $obj->list = array(0 => $tree->getRootNode());
     $obj->ids = array(0 => 0);
     return $obj;
 }
コード例 #2
0
 /**
  * The actual testing method
  */
 public function run()
 {
     /** @var XHPASTNode $root_node */
     $root_node = $this->input->getRootNode();
     /** @var AASTNodeList $classes */
     $classes = $root_node->selectDescendantsOfType('n_CLASS_DECLARATION');
     $class_symbols = array();
     foreach ($classes as $class_node) {
         /** @var XHPASTNode $class_node */
         $class_symbols[] = $class_node->getStringLiteralValue();
     }
     $this->result = $class_symbols;
     $this->success = count($this->result) < 2;
 }
コード例 #3
0
 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'));
 }
コード例 #4
0
 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;
         }
     }
 }
コード例 #5
0
 /**
  * The actual testing method
  */
 public function run()
 {
     /** @var XHPASTNode $root_node */
     $root_node = $this->input->getRootNode();
     /** @var AASTNodeList $node */
     $nodes = $root_node->selectDescendantsOfType('n_STATEMENT');
     if ($nodes->count()) {
         $nodes->rewind();
         /** @var XHPASTNode $node */
         $node = $nodes->current();
         $node_string = $node->getConcreteString();
         if (strtolower(substr($node_string, 0, 5)) !== 'defin') {
             $this->result = $node_string;
             $this->success = false;
         }
         $this->result = $node_string;
     }
 }
コード例 #6
0
 public function processRequest()
 {
     $storage = $this->getStorageTree();
     $input = $storage->getInput();
     $stdout = $storage->getStdout();
     $tree = XHPASTTree::newFromDataAndResolvedExecFuture($input, array(0, $stdout, ''));
     $tree = phutil_tag('ul', array(), $this->buildTree($tree->getRootNode()));
     return $this->buildXHPASTViewPanelResponse($tree);
 }
コード例 #7
0
 /**
  * Reads and parses test data from a specified file.
  *
  * This method reads and parses test data from a file. The file is expected
  * to have the following structure
  *
  * ```
  * <?php
  * // PHP code goes here.
  * ~~~~~~~~~~
  * {
  *   // JSON dictionary containing expected results from testing method.
  * }
  * ```
  *
  * @param  string                 The path to the test file.
  * @return pair<XHPASTTree, map>  The first element of the pair is the
  *                                `XHPASTTree` contained within the test file.
  *                                The second element of the pair is the
  *                                "expect" data.
  */
 private function readTestData($file)
 {
     $contents = Filesystem::readFile($file);
     $contents = preg_split('/^~{10}$/m', $contents);
     if (count($contents) < 2) {
         throw new Exception(pht("Expected '%s' separating test case and results.", '~~~~~~~~~~'));
     }
     list($data, $expect) = $contents;
     $tree = XHPASTTree::newFromData($data);
     $expect = phutil_json_decode($expect);
     return array($tree, $expect);
 }
コード例 #8
0
ファイル: XHPASTTree.php プロジェクト: rwray/libphutil
 public static function evalStaticString($string)
 {
     $string = '<?php ' . rtrim($string, ';') . ';';
     $tree = XHPASTTree::newFromData($string);
     $statements = $tree->getRootNode()->selectDescendantsOfType('n_STATEMENT');
     if (count($statements) != 1) {
         throw new Exception("String does not parse into exactly one statement!");
     }
     // Return the first one, trying to use reset() with iterators ends in tears.
     foreach ($statements as $statement) {
         return $statement->evalStatic();
     }
 }
 public function handleRequest(AphrontRequest $request)
 {
     $storage = $this->getStorageTree();
     $input = $storage->getInput();
     $stdout = $storage->getStdout();
     $tree = XHPASTTree::newFromDataAndResolvedExecFuture($input, array(0, $stdout, ''));
     $tokens = array();
     foreach ($tree->getRawTokenStream() as $id => $token) {
         $seq = $id;
         $name = $token->getTypeName();
         $title = pht('Token %s: %s', $seq, $name);
         $tokens[] = phutil_tag('span', array('title' => $title, 'class' => 'token'), $token->getValue());
     }
     return $this->buildXHPASTViewPanelResponse(phutil_implode_html('', $tokens));
 }
 public function processRequest()
 {
     $storage = $this->getStorageTree();
     $input = $storage->getInput();
     $stdout = $storage->getStdout();
     $tree = XHPASTTree::newFromDataAndResolvedExecFuture($input, array(0, $stdout, ''));
     $tokens = array();
     foreach ($tree->getRawTokenStream() as $id => $token) {
         $seq = $id;
         $name = $token->getTypeName();
         $title = "Token {$seq}: {$name}";
         $tokens[] = phutil_render_tag('span', array('title' => $title, 'class' => 'token'), phutil_escape_html($token->getValue()));
     }
     return $this->buildXHPASTViewPanelResponse(implode('', $tokens));
 }
コード例 #11
0
 public function handleRequest(AphrontRequest $request)
 {
     $storage = $this->getStorageTree();
     $input = $storage->getInput();
     $err = $storage->getReturnCode();
     $stdout = $storage->getStdout();
     $stderr = $storage->getStderr();
     try {
         $tree = XHPASTTree::newFromDataAndResolvedExecFuture($input, array($err, $stdout, $stderr));
     } catch (XHPASTSyntaxErrorException $ex) {
         return $this->buildXHPASTViewPanelResponse($ex->getMessage());
     }
     $tree = phutil_tag('ul', array(), $this->buildTree($tree->getRootNode()));
     return $this->buildXHPASTViewPanelResponse($tree);
 }
コード例 #12
0
 public function getXHPASTTreeForPath($path)
 {
     if (!array_key_exists($path, $this->trees)) {
         $this->trees[$path] = null;
         try {
             $this->trees[$path] = XHPASTTree::newFromDataAndResolvedExecFuture($this->getData($path), $this->futures[$path]->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());
         } catch (Exception $ex) {
             $this->raiseLintAtPath(self::LINT_UNABLE_TO_PARSE, $ex->getMessage());
         }
     }
     return $this->trees[$path];
 }
コード例 #13
0
 public function handleRequest(AphrontRequest $request)
 {
     $viewer = $this->getViewer();
     if ($request->isFormPost()) {
         $source = $request->getStr('source');
         $future = PhutilXHPASTBinary::getParserFuture($source);
         $resolved = $future->resolve();
         // This is just to let it throw exceptions if stuff is broken.
         try {
             XHPASTTree::newFromDataAndResolvedExecFuture($source, $resolved);
         } catch (XHPASTSyntaxErrorException $ex) {
             // This is possibly expected.
         }
         list($err, $stdout, $stderr) = $resolved;
         $storage_tree = id(new PhabricatorXHPASTParseTree())->setInput($source)->setReturnCode($err)->setStdout($stdout)->setStderr($stderr)->setAuthorPHID($viewer->getPHID())->save();
         return id(new AphrontRedirectResponse())->setURI('/xhpast/view/' . $storage_tree->getID() . '/');
     }
     $form = id(new AphrontFormView())->setUser($viewer)->appendChild(id(new AphrontFormTextAreaControl())->setLabel(pht('Source'))->setName('source')->setValue("<?php\n\n")->setHeight(AphrontFormTextAreaControl::HEIGHT_VERY_TALL))->appendChild(id(new AphrontFormSubmitControl())->setValue(pht('Parse')));
     $form_box = id(new PHUIObjectBoxView())->setHeaderText(pht('Generate XHP AST'))->setForm($form);
     return $this->buildApplicationPage($form_box, array('title' => pht('XHPAST View')));
 }
 private function extractFiles($root_path, array $files)
 {
     $hashes = array();
     $futures = array();
     foreach ($files as $file => $hash) {
         $full_path = $root_path . DIRECTORY_SEPARATOR . $file;
         $data = Filesystem::readFile($full_path);
         $futures[$full_path] = PhutilXHPASTBinary::getParserFuture($data);
         $hashes[$full_path] = $hash;
     }
     $bar = id(new PhutilConsoleProgressBar())->setTotal(count($futures));
     $messages = array();
     $results = array();
     $futures = id(new FutureIterator($futures))->limit(8);
     foreach ($futures as $full_path => $future) {
         $bar->update(1);
         $hash = $hashes[$full_path];
         try {
             $tree = XHPASTTree::newFromDataAndResolvedExecFuture(Filesystem::readFile($full_path), $future->resolve());
         } catch (Exception $ex) {
             $messages[] = pht('WARNING: Failed to extract strings from file "%s": %s', $full_path, $ex->getMessage());
             continue;
         }
         $root = $tree->getRootNode();
         $calls = $root->selectDescendantsOfType('n_FUNCTION_CALL');
         foreach ($calls as $call) {
             $name = $call->getChildByIndex(0)->getConcreteString();
             if ($name != 'pht') {
                 continue;
             }
             $params = $call->getChildByIndex(1, 'n_CALL_PARAMETER_LIST');
             $string_node = $params->getChildByIndex(0);
             $string_line = $string_node->getLineNumber();
             try {
                 $string_value = $string_node->evalStatic();
                 $results[$hash][] = array('string' => $string_value, 'file' => Filesystem::readablePath($full_path, $root_path), 'line' => $string_line);
             } catch (Exception $ex) {
                 $messages[] = pht('WARNING: Failed to evaluate pht() call on line %d in "%s": %s', $call->getLineNumber(), $full_path, $ex->getMessage());
             }
         }
         $tree->dispose();
     }
     $bar->done();
     foreach ($messages as $message) {
         echo tsprintf("**<bg:yellow> %s </bg>** %s\n", pht('WARNING'), $message);
     }
     return $results;
 }
コード例 #15
0
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);
    }
    $interfaces = $root->selectDescendantsOfType('n_INTERFACE_DECLARATION');
    foreach ($interfaces as $interface) {
コード例 #16
0
 /**
  * Get a path's tree from the responsible linter.
  *
  * @param   string           Path to retrieve tree for.
  * @return  XHPASTTree|null  Tree, or null if unparseable.
  * @task sharing
  */
 protected final function getXHPASTTreeForPath($path)
 {
     // If we aren't the linter responsible for actually building the parse
     // trees, go get the tree from that linter.
     if ($this->getXHPASTLinter() !== $this) {
         return $this->getXHPASTLinter()->getXHPASTTreeForPath($path);
     }
     if (!array_key_exists($path, $this->trees)) {
         if (!array_key_exists($path, $this->futures)) {
             return;
         }
         $this->trees[$path] = null;
         try {
             $this->trees[$path] = XHPASTTree::newFromDataAndResolvedExecFuture($this->getData($path), $this->futures[$path]->resolve());
             $root = $this->trees[$path]->getRootNode();
             $root->buildSelectCache();
             $root->buildTokenCache();
         } catch (Exception $ex) {
             $this->exceptions[$path] = $ex;
         }
     }
     return $this->trees[$path];
 }
コード例 #17
0
 private function assertEval($value, $string)
 {
     $this->assertEqual($value, XHPASTTree::newStatementFromString($string)->evalStatic(), $string);
 }
コード例 #18
0
 private function assertStringVariables($expected, $string)
 {
     $statement = XHPASTTree::newStatementFromString($string);
     $this->assertEqual($expected, $statement->getChildByIndex(0)->getStringVariables(), $string);
 }
コード例 #19
0
 private function assertEval($value, $string)
 {
     $this->assertEqual($value, XHPASTTree::evalStaticString($string), $string);
 }
コード例 #20
0
 private function applyXHPHighlight($source)
 {
     // We perform two passes here: one using the AST to find symbols we care
     // about -- particularly, class names and function names. These are used
     // in the crossreference stuff to link into Diffusion. After we've done our
     // AST pass, we do a followup pass on the token stream to catch all the
     // simple stuff like strings and comments.
     $scrub = false;
     if (strpos($source, '<?') === false) {
         $source = "<?php\n" . $source . "\n";
         $scrub = true;
     }
     $tree = XHPASTTree::newFromData($source);
     $root = $tree->getRootNode();
     $tokens = $root->getTokens();
     $interesting_symbols = $this->findInterestingSymbols($root);
     $out = array();
     foreach ($tokens as $key => $token) {
         $value = phutil_escape_html($token->getValue());
         $class = null;
         $multi = false;
         $attrs = '';
         if (isset($interesting_symbols[$key])) {
             $sym = $interesting_symbols[$key];
             $class = $sym[0];
             if (isset($sym['context'])) {
                 $attrs = $attrs . ' data-symbol-context="' . $sym['context'] . '"';
             }
             if (isset($sym['symbol'])) {
                 $attrs = $attrs . ' data-symbol-name="' . $sym['symbol'] . '"';
             }
         } else {
             switch ($token->getTypeName()) {
                 case 'T_WHITESPACE':
                     break;
                 case 'T_DOC_COMMENT':
                     $class = 'dc';
                     $multi = true;
                     break;
                 case 'T_COMMENT':
                     $class = 'c';
                     $multi = true;
                     break;
                 case 'T_CONSTANT_ENCAPSED_STRING':
                 case 'T_ENCAPSED_AND_WHITESPACE':
                 case 'T_INLINE_HTML':
                     $class = 's';
                     $multi = true;
                     break;
                 case 'T_VARIABLE':
                     $class = 'nv';
                     break;
                 case 'T_OPEN_TAG':
                 case 'T_OPEN_TAG_WITH_ECHO':
                 case 'T_CLOSE_TAG':
                     $class = 'o';
                     break;
                 case 'T_LNUMBER':
                 case 'T_DNUMBER':
                     $class = 'm';
                     break;
                 case 'T_STRING':
                     static $magic = array('true' => true, 'false' => true, 'null' => true);
                     if (isset($magic[$value])) {
                         $class = 'k';
                         break;
                     }
                     $class = 'nx';
                     break;
                 default:
                     $class = 'k';
                     break;
             }
         }
         if ($class) {
             $l = '<span class="' . $class . '"' . $attrs . '>';
             $r = '</span>';
             $value = $l . $value . $r;
             if ($multi) {
                 // If the token may have multiple lines in it, make sure each
                 // <span> crosses no more than one line so the lines can be put
                 // in a table, etc., later.
                 $value = str_replace("\n", $r . "\n" . $l, $value);
             }
             $out[] = $value;
         } else {
             $out[] = $value;
         }
     }
     if ($scrub) {
         array_shift($out);
     }
     return rtrim(implode('', $out));
 }
コード例 #21
0
 private function applyXHPHighlight($result)
 {
     // We perform two passes here: one using the AST to find symbols we care
     // about -- particularly, class names and function names. These are used
     // in the crossreference stuff to link into Diffusion. After we've done our
     // AST pass, we do a followup pass on the token stream to catch all the
     // simple stuff like strings and comments.
     $tree = XHPASTTree::newFromDataAndResolvedExecFuture($this->source, $result);
     $root = $tree->getRootNode();
     $tokens = $root->getTokens();
     $interesting_symbols = $this->findInterestingSymbols($root);
     $out = array();
     foreach ($tokens as $key => $token) {
         $value = $token->getValue();
         $class = null;
         $multi = false;
         $attrs = array();
         if (isset($interesting_symbols[$key])) {
             $sym = $interesting_symbols[$key];
             $class = $sym[0];
             $attrs['data-symbol-context'] = idx($sym, 'context');
             $attrs['data-symbol-name'] = idx($sym, 'symbol');
         } else {
             switch ($token->getTypeName()) {
                 case 'T_WHITESPACE':
                     break;
                 case 'T_DOC_COMMENT':
                     $class = 'dc';
                     $multi = true;
                     break;
                 case 'T_COMMENT':
                     $class = 'c';
                     $multi = true;
                     break;
                 case 'T_CONSTANT_ENCAPSED_STRING':
                 case 'T_ENCAPSED_AND_WHITESPACE':
                 case 'T_INLINE_HTML':
                     $class = 's';
                     $multi = true;
                     break;
                 case 'T_VARIABLE':
                     $class = 'nv';
                     break;
                 case 'T_OPEN_TAG':
                 case 'T_OPEN_TAG_WITH_ECHO':
                 case 'T_CLOSE_TAG':
                     $class = 'o';
                     break;
                 case 'T_LNUMBER':
                 case 'T_DNUMBER':
                     $class = 'm';
                     break;
                 case 'T_STRING':
                     static $magic = array('true' => true, 'false' => true, 'null' => true);
                     if (isset($magic[strtolower($value)])) {
                         $class = 'k';
                         break;
                     }
                     $class = 'nx';
                     break;
                 default:
                     $class = 'k';
                     break;
             }
         }
         if ($class) {
             $attrs['class'] = $class;
             if ($multi) {
                 // If the token may have multiple lines in it, make sure each
                 // <span> crosses no more than one line so the lines can be put
                 // in a table, etc., later.
                 $value = phutil_split_lines($value, $retain_endings = true);
             } else {
                 $value = array($value);
             }
             foreach ($value as $val) {
                 $out[] = phutil_tag('span', $attrs, $val);
             }
         } else {
             $out[] = $value;
         }
     }
     if ($this->scrub) {
         array_shift($out);
     }
     return phutil_implode_html('', $out);
 }
コード例 #22
0
 protected function executeAtomize($file_name, $file_data)
 {
     $future = PhutilXHPASTBinary::getParserFuture($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;
 }
コード例 #23
0
ファイル: phutil_symbols.php プロジェクト: endlessm/libphutil
        as it's relatively stable and performance is currently awful
        (500ms+ for moderately large files).

EOHELP
);
$args->parseStandardArguments();
$args->parse(array(array('name' => 'all', 'help' => pht('Report all symbols, including built-ins and declared externals.')), array('name' => 'ugly', 'help' => pht('Do not prettify JSON output.')), array('name' => 'path', 'wildcard' => true, 'help' => pht('PHP Source file to analyze.'))));
$paths = $args->getArg('path');
if (count($paths) !== 1) {
    throw new Exception(pht('Specify exactly one path!'));
}
$path = Filesystem::resolvePath(head($paths));
$show_all = $args->getArg('all');
$source_code = Filesystem::readFile($path);
try {
    $tree = XHPASTTree::newFromData($source_code);
} catch (XHPASTSyntaxErrorException $ex) {
    $result = array('error' => $ex->getMessage(), 'line' => $ex->getErrorLine(), 'file' => $path);
    $json = new PhutilJSON();
    echo $json->encodeFormatted($result);
    exit(0);
}
$root = $tree->getRootNode();
$root->buildSelectCache();
// -(  Unsupported Constructs  )------------------------------------------------
$namespaces = $root->selectDescendantsOfType('n_NAMESPACE');
foreach ($namespaces as $namespace) {
    phutil_fail_on_unsupported_feature($namespace, $path, pht('namespaces'));
}
$uses = $root->selectDescendantsOfType('n_USE');
foreach ($namespaces as $namespace) {
コード例 #24
0
 private function applyXHPHighlight($result)
 {
     // We perform two passes here: one using the AST to find symbols we care
     // about -- particularly, class names and function names. These are used
     // in the crossreference stuff to link into Diffusion. After we've done our
     // AST pass, we do a followup pass on the token stream to catch all the
     // simple stuff like strings and comments.
     $tree = XHPASTTree::newFromDataAndResolvedExecFuture($this->source, $result);
     $root = $tree->getRootNode();
     $tokens = $root->getTokens();
     $interesting_symbols = $this->findInterestingSymbols($root);
     if ($this->scrub) {
         // If we're scrubbing, we prepended "<?php\n" to the text to force the
         // highlighter to treat it as PHP source. Now, we need to remove that.
         $ok = false;
         if (count($tokens) >= 2) {
             if ($tokens[0]->getTypeName() === 'T_OPEN_TAG') {
                 if ($tokens[1]->getTypeName() === 'T_WHITESPACE') {
                     $ok = true;
                 }
             }
         }
         if (!$ok) {
             throw new Exception(pht('Expected T_OPEN_TAG, T_WHITESPACE tokens at head of results ' . 'for highlighting parse of PHP snippet.'));
         }
         // Remove the "<?php".
         unset($tokens[0]);
         $value = $tokens[1]->getValue();
         if (strlen($value) < 1 || $value[0] != "\n") {
             throw new Exception(pht('Expected "\\n" at beginning of T_WHITESPACE token at head of ' . 'tokens for highlighting parse of PHP snippet.'));
         }
         $value = substr($value, 1);
         $tokens[1]->overwriteValue($value);
     }
     $out = array();
     foreach ($tokens as $key => $token) {
         $value = $token->getValue();
         $class = null;
         $multi = false;
         $attrs = array();
         if (isset($interesting_symbols[$key])) {
             $sym = $interesting_symbols[$key];
             $class = $sym[0];
             $attrs['data-symbol-context'] = idx($sym, 'context');
             $attrs['data-symbol-name'] = idx($sym, 'symbol');
         } else {
             switch ($token->getTypeName()) {
                 case 'T_WHITESPACE':
                     break;
                 case 'T_DOC_COMMENT':
                     $class = 'dc';
                     $multi = true;
                     break;
                 case 'T_COMMENT':
                     $class = 'c';
                     $multi = true;
                     break;
                 case 'T_CONSTANT_ENCAPSED_STRING':
                 case 'T_ENCAPSED_AND_WHITESPACE':
                 case 'T_INLINE_HTML':
                     $class = 's';
                     $multi = true;
                     break;
                 case 'T_VARIABLE':
                     $class = 'nv';
                     break;
                 case 'T_OPEN_TAG':
                 case 'T_OPEN_TAG_WITH_ECHO':
                 case 'T_CLOSE_TAG':
                     $class = 'o';
                     break;
                 case 'T_LNUMBER':
                 case 'T_DNUMBER':
                     $class = 'm';
                     break;
                 case 'T_STRING':
                     static $magic = array('true' => true, 'false' => true, 'null' => true);
                     if (isset($magic[strtolower($value)])) {
                         $class = 'k';
                         break;
                     }
                     $class = 'nx';
                     break;
                 default:
                     $class = 'k';
                     break;
             }
         }
         if ($class) {
             $attrs['class'] = $class;
             if ($multi) {
                 // If the token may have multiple lines in it, make sure each
                 // <span> crosses no more than one line so the lines can be put
                 // in a table, etc., later.
                 $value = phutil_split_lines($value, $retain_endings = true);
             } else {
                 $value = array($value);
             }
             foreach ($value as $val) {
                 $out[] = phutil_tag('span', $attrs, $val);
             }
         } else {
             $out[] = $value;
         }
     }
     return phutil_implode_html('', $out);
 }