/**
  * 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);
 }
Example #2
0
 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();
     }
 }
Example #3
0
        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) {
 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));
 }