PhpGrammar.php
<?php
namespace Tlf\Lexer\Test;
class PhpGrammar extends Tester {
use Directives\Props;
use Directives\Args;
use Directives\Methods;
use Directives\Classes;
use Directives\ClassIntegration;
use Directives\Traits;
use Directives\Namespaces;
use Directives\UseTrait;
use Directives\PhpOpenTags;
use Directives\Consts;
use Directives\Values;
protected $directive_tests;
public function prepare(){
$this->directive_tests = array_merge(
$this->_prop_tests,
$this->_arg_tests,
$this->_namespace_tests,
$this->_method_tests,
$this->_class_tests,
$this->_class_integration_tests,
$this->_trait_tests,
$this->_php_open_tags_tests,
$this->_const_tests,
$this->_use_trait_tests,
$this->_values_tests,
);
}
public function testMethodBodyIsString(){
$this->disable();
// this involves the test/input/php/lex/code-scrawl/IntegrationTest.php file
// which keeps showing ast objects in the output
// where there should be a body string
$lexer = new \Tlf\Lexer();
$abs_path = $this->file('test/input/php/lex/code-scrawl/IntegrationTest.php');
$phpGram = new \Tlf\Lexer\PhpGrammarNew();
$lexer = new \Tlf\Lexer();
$lexer->useCache = false;
$lexer->debug = false;
$lexer->addGrammar($phpGram);
// the first directive we're listening for
$lexer->addDirective($phpGram->getDirectives(':php_open')['php_open']);
// ob_start();
// runs the lexer with $ast as the head
$ast = $lexer->lexFile($abs_path);
// ob_end_clean();
// echo 'oh';
// exit;
print_r($ast->getTree());
// exit;
}
public function testRunFile(){
$file = $this->options['file'] ?? '';
$dir = $this->file('test/input/php/lex/');
if (is_file($dir.$file)){
// echo 'zeep';
// exit;
$this->run_parse_file(substr($file,0,-4), false);
} else {
foreach (scandir($dir.$file) as $sub_file){
if (substr($sub_file,-4)!='.php')continue;
$this->run_parse_file(substr($file.'/'.$sub_file));
}
}
return;
if (isset($this->options['file'])){
$file = $this->options['file'];
var_dump($file);
exit;
}
}
public function testLilDb(){
// $this->run_parse_file('MethodParseErrors',true);
$this->run_parse_file('lildb/LilDb',true,-1);
}
public function testPhad(){
$this->run_parse_file('phad/FormsTest',true,);
}
public function testScrawl(){
$this->run_parse_file('code-scrawl/functionListTemplate',true,);
}
public function testPhtml(){
// $this->run_parse_file('MethodParseErrors',true);
// return;
// $this->run_parse_file('phtml/Compiler',false);
// // return;
// $this->run_parse_file('SampleClass', false);
//
//
//
// $this->run_parse_file('phtml/TextNode',false);
// //fails
// $this->run_parse_file('phtml/Phtml',false);
// return;
// $this->run_parse_file('phtml/PHPParser',false);
// return;
// $this->run_parse_file('phtml/Node',false);
// return;
// $this->run_parse_file('phtml/Compiler',false);
// below, i want to test for docblock count ... use array_walk_recursive()?
}
public function run_parse_file($file, bool $debug=true, int $stop_loop = -1){
// if (!$debug)ob_start();
echo "\nParse $file\n";
$in = $this->file('test/input/php/lex/');
$out = $this->file('test/input/php/tree/');
$input = file_get_contents($in.$file.'.php');
$phpGram = new \Tlf\Lexer\PhpGrammarNew();
$phpGram->directives = array_merge(
$phpGram->_string_directives,
$phpGram->_core_directives,
);
$lexer = new \Tlf\Lexer();
$lexer->stop_loop = $stop_loop;
$lexer->debug = $debug;
$lexer->addGrammar($phpGram, null, false);
$lexer->addDirective($phpGram->getDirectives(':php_open')['php_open']);
$ast = new \Tlf\Lexer\Ast('file');
$ast = $lexer->lex($input, $ast);
$tree = $ast->getTree();
$json = json_encode($tree, JSON_PRETTY_PRINT);
$tree_print = print_r($tree,true);
// i like the highlighting better when i make it .js
file_put_contents($out.$file.'.printr.js', $tree_print);
file_put_contents($out.$file.'.js', $json);
// file_put_contents($out.'phtml/TextNode.php', $tree);
// file_put_contents($out.'phtml/TextNode.json', $json);
$expect_file = $in.$file.'.expect.js';
if (!file_exists($expect_file))return;
$expect = json_decode(file_get_contents($expect_file),true);
// print_r($expect);
// exit;
$counts = $expect['class_counts'];
$counts = array_merge(['properties'=>0,'methods'=>0,'comments'=>0,'consts'=>0], $counts);
// print_r($tree);
$class = $tree['namespace']['class'][0] ?? $tree['class'][0];
foreach ($counts as $key=>$count){
$this->test($key.' count');
$this->compare($count, count($class[$key]??[]));
}
$tree_counts = $expect['tree_counts'];
unset($tree_counts['docblocks']);
// $tree_counts = array_merge(['classes'=>0,'functions'=>0,''])
foreach ($tree_counts as $key=>$c){
if ($key=='class'&&!isset($tree[$key])){
$count = count($tree['namespace']['class']);
} else $count = count($tree[$key]);
$this->test($key.' tree count');
$this->compare($c, $count);
}
return;
$this->test('method count');
$this->compare($counts['methods'], count($class['methods']??[]));
$this->test('property count');
$this->compare($counts['properties'], count($class['properties']??[]));
$this->test('comments count');
$this->compare($counts['properties'], count($class['comments']??[]));
return;
echo "\n\n\n-----------\n\n";
print_r($tree);
$expect =
[
'type'=>'class_body',
'const'=>[
0=>[
'type'=>'const',
'name'=>'blm',
'value'=>'"yes"',
'declaration'=>'const blm = "yes";',
],
]
];
$this->compare($expect,
$tree
);
}
public function testShowMePhpFeatures(){
ob_start();
$phpGram = new \Tlf\Lexer\PhpGrammarNew();
$docblockGram = new \Tlf\Lexer\DocblockGrammar();
$grammars = [
$phpGram,
$docblockGram,
];
$phpGram->buildDirectives();
$test_results = $this->runDirectiveTests($grammars, $this->directive_tests);
ob_end_clean();
$fh = fopen($this->file('test/output/PhpFeatures.md'),'w');
foreach ($this->directive_tests as $name=>$test){
$status = 'fail';
$s = '-';
if ($test_results[$name]){
$s = '+';
$status = 'pass';
}
$str = "\n$s$name: ".$test['input'];
echo $str;
$str = "\n- $s$name($status): `".$test['input'].'`';
fwrite($fh, $str);
}
fclose($fh);
$this->disable();
}
public function testPhpGrammarNew(){
$phpGram = new \Tlf\Lexer\PhpGrammarNew();
$docblockGram = new \Tlf\Lexer\DocblockGrammar();
$grammars = [
$phpGram,
$docblockGram,
];
$phpGram->buildDirectives();
$this->runDirectiveTests($grammars, $this->directive_tests);
}
/* convert a tree into json to see if i like the output better */
public function testMakeJson(){
$file = $this->file('test/input/php/');
$tree = require($file.'tree/SampleClass.tree.php');
$json = json_encode($tree, JSON_PRETTY_PRINT);
file_put_contents($file.'tree/SampleClass.tree.json', $json);
}
public function testPhpGrammarNew_SampleClass(){
// $dir = dirname(__DIR__).'/php-new/';
// $dir = dirname()
$dir = $this->file('test/input/php/lex/');
$file = $dir.'SampleClass.php';
$targetTree = include($dir.'SampleClass.tree.php');
$lexer = new \Tlf\Lexer();
$lexer->debug = true;
//the string rewrite
// $lexer->stop_loop = 305; // on loop 293, we start listening for strings. string_double STOPS on loop 299
//on loop 300,
// This is for devving v0.6:
// $lexer->stop_loop = 18;
// $lexer->stop_loop = 33;
// $lexer->stop_loop = 21;
// $lexer->stop_loop = 31;
// $lexer->stop_loop = 41;
// $lexer->stop_loop = 51;
// $lexer->stop_loop = 111; // catching 'class'
// $lexer->stop_loop = 120;
// $lexer->stop_loop = 135; // block starts at 132
// $lexer->stop_loop = 150; // use trait is about 150
// $lexer->stop_loop = 185; // 181 is new line for first comment
// $lexer->stop_loop = 206; // process # second comment at 203
// $lexer->stop_loop = 261; // Process first property's docblock
// $lexer->stop_loop = 280; // 277 'modifier' starts
// $lexer->stop_loop = 300; // first property processed on 299
// $lexer->stop_loop = 335; // second property is complete
// $lexer->stop_loop = 395; // static public property is finished by loop 385
// $lexer->stop_loop = 445; // method docblock finishes on 441
// $lexer->stop_loop = 460; // `public ` is captured on 454, starting method modifier
// $lexer->stop_loop = 492; // method block (opening curly brace) starts on 473
// $lexer->stop_loop = 525; // closing method curly brace is loop 516
// $lexer->stop_loop = 553; // issues around `=` around 550
// $lexer->stop_loop = 585; // see 542 for `const `. `=` is loop 551. string closes on 578
// $lexer->stop_loop = 800;
// $lexer->stop_loop = 1200;
// $lexer->stop_loop = 9999999;
$lexer->useCache = false; // useCache only matters when lexing a file
$lexer->addGrammar($phpGrammar = new \Tlf\Lexer\PhpGrammarNew());
$ast = $lexer->lexFile($file);
$tree = $ast->getTree(); // not what we normally want with json
echo "\n\n\n --- file AST ---\n\n";
print_r($tree);
//
// write the current tree to a file
//
file_put_contents($dir.'SampleClass.tree2.php',var_export($tree,true));
echo "\n----\n\n\n";
$this->compare(
$targetTree,
$tree
);
}
}