PhpGrammarTest.php

<?php

namespace Tlf\Lexer\Test;


class PhpGrammarOld extends Tester {

    protected $thingies = [


        'Property.IntType'=>[
            'expect_failure'=>true,
            'start'=>['class_modifier', 'whitespace'],
            'input'=>' public int $blm = "an important movement.";',
            'expect'=>[
                'properties'=>[
                    0=>[
                        'type'=>'property',
                        'modifiers'=>'public ',
                        'docblock'=> '',
                        'name'=>'blm',
                        'declaration'=>'public int $blm = "an important movement.";',
                    ],
                ],
            ],
        ],

        'Property.NoType'=>[
            'start'=>['class_modifier', 'whitespace'],
            'input'=>' public $blm = "an important movement.";',
            'expect'=>[
                'properties'=>[
                    0=>[
                        'type'=>'property',
                        'modifiers'=>'public ',
                        'docblock'=> '',
                        'name'=>'blm',
                        'declaration'=>'public $blm = "an important movement.";',
                    ],
                ],
            ],
        ],

        'String.Nowdoc'=>[
            'start'=>'strings',
            'input'=>"<<<'PHP'\nyep yep\nPHP;",
            'expect.previous'=>[
                'string'=>"<<<'PHP'\nyep yep\nPHP",
            ]
        ],
        'String.Heredoc'=>[
            'start'=>'strings',
            'input'=>"<<<PHP\nyep yep\nPHP;",
            'expect.previous'=>[
                'string'=>"<<<PHP\nyep yep\nPHP",
            ]
        ],

        'String.EndsWithBackslash'=>[
            'start'=>'strings',
            'input'=>"'a\\\\'",
            'expect.previous'=>[
                'string'=>"'a\\\\'",
            ],
        ],
        'String.HasABackslash'=>[
            'start'=>'strings',
            'input'=>"'\\a'",
            'expect.previous'=>[
                'string'=>"'\\a'",
            ],
        ],
        'String.EscapedSingleQuote'=>[
            'start'=>'strings',
            'input'=>"'abc \\'quote start '",
            'expect.previous'=>[
                'string'=>"'abc \\'quote start '",
            ],
        ],
        'String.SingleQuotesInside'=>[
            'start'=>'strings',
            'input'=>'"abc \'quoted\' 123"',
            'expect.previous'=>[
                'string'=>'"abc \'quoted\' 123"',
            ],
        ],
        'String.DoubleQuotesInside'=>[
            'start'=>'strings',
            'input'=>"'abc \"quoted\" 123'",
            'expect.previous'=>[
                'string'=>"'abc \"quoted\" 123'",
            ],
        ],
        'String.Simple'=>[
            'start'=>'strings',
            'input'=>"'abc def 123'",
            'expect.previous'=>[
                'string'=>"'abc def 123'",
            ],
        ],

        'Method.ContainsNestedBlock'=>[
            'start'=>'class_modifier',
            'input'=>
                <<<PHP
                public function nest(){
                    if (true){
                        while(false){
                            echo "okay";
                        }
                    }
                }
                PHP,
            'expect'=>[
                'methods'=>[
                    0=>[
                        'type'=>'method',
                        'modifiers'=>'public function ',
                        'docblock'=>'',
                        'name'=>'nest',
                        'definition'=>'public function nest()',
                        'arglist'=>'',
                    ]
                ],
            ],
        ],

        'Php.Open.Docblock.Namespace'=>[
            'start'=>'php_open',
            'input'=>"<?php \n /** This is a namespace */ namespace abc;",
            'expect'=>[
                'namespace.docblock'=>[
                    'type'=>'docblock',
                    'description'=>'This is a namespace',
                ],
                'namespace'=>'abc',
            ],
        ],
        'Php.Open.Convoluted'=>[
            'start'=>'php_open',
            'input'=>"/*asdflku<\\?php<?php namespace abc;",
            'expect'=>[
                'namespace'=>'abc',
                'namespace.docblock'=>'',
            ],
        ],
        'Php.Open.Simple'=>[
            'start'=>'php_open',
            'input'=>"<?php namespace abc;",
            'expect'=>[
                'namespace'=>'abc',
                'namespace.docblock'=>'',
            ],
        ],

        'Class.Extends.IntoAst'=>[
            'expect_failure'=>true,
            'start'=>['class'],
            'input'=>'class Abc extends Def {',
            'expect'=>[
                'class'=>[[
                    'type'=>'class', 'docblock'=>null, 'namespace'=>'', 'name'=>'Abc', 'extends'=>'Def', 'declaration'=>'class Abc extends Def '
                ]],
            ]
        ],
        'Class.Extends.IntoDeclaration'=>[
            // 'expect_failure'=>true,
            'start'=>['class'],
            'input'=>'class Abc extends Def {',
            'expect'=>[
                'class'=>[[
                    'type'=>'class', 'docblock'=>null, 'namespace'=>'', 'name'=>'Abc', 'declaration'=>'class Abc extends Def '
                ]],
            ]
        ],
        
        'Class.Abstract'=>[
            'expect_failure'=>true,
            'start'=>['class'],
            'input'=>'abstract class Def {',
            'expect'=>[
                'class'=>[[
                    'type'=>'class', 'docblock'=>null, 'namespace'=>'', 'name'=>'Abc', 'declaration'=>'class Abc '
                ]],
            ],
        ],
        'Class.ExtendsWithNoSpaceAfterExtendedClass'=>[
            'start'=>['php_open'],
            'input'=>'<?php class Abc extends Alphabet{}',
            'expect'=>[
                'class'=>[[
                    'type'=>'class', 'docblock'=>null, 'namespace'=>'', 'name'=>'Abc', 'declaration'=>'class Abc extends Alphabet'
                ]],
            ],
        ],

        'Class.MinimalMinusASpace'=>[
            'start'=>['class'],
            'input'=>'class Abc{}',
            'expect'=>[
                'class'=>[[
                    'type'=>'class', 'docblock'=>null, 'namespace'=>'', 'name'=>'Abc', 'declaration'=>'class Abc'
                ]],
            ],
        ],
        'Class.Minimal'=>[
            'start'=>['class'],
            'input'=>'class Abc {',
            'expect'=>[
                'class'=>[[
                    'type'=>'class', 'docblock'=>null, 'namespace'=>'', 'name'=>'Abc', 'declaration'=>'class Abc '
                ]],
            ],
        ],
        'Namespace.WithDocblockAfterNs'=>[
            'expect_failure'=>true,
            'start'=>['namespace'],
            'input'=>"namespace/**docblock*/Abc\Def;",
            'expect'=>[
                "namespace"=> 'Abc\\Def',        
                'namespace.docblock'=>'docblock',
            ],
        ],
        'Namespace.WithNewLines'=>[
            'start'=>['namespace'],
            'input'=>"namespace \nAbc\n\\\\\nDef_09;",
            'expect'=>[
                "namespace"=> 'Abc\\Def_09',           
                'namespace.docblock'=>'',
            ],
        ],
        'Namespace.WithDocblocksAtTheEnd'=>[
            'start'=>['namespace'],
            'input'=>"namespace Abc\\/**docblock**/Def_09/**more docblock*/;",
            'expect'=>[
                'namespace.docblock'=>[
                    'type'=>'docblock',
                    'description'=>'more docblock',
                ],
                "namespace"=> 'Abc\\Def_09',          
            ],
        ],
        'Namespace.WithDocblocksInTheMiddle'=>[
            'start'=>['namespace'],
            'input'=>"namespace Abc\\/**docblock**/Def_09;",
            'expect'=>[
                'namespace.docblock'=>[
                    'type'=>'docblock',
                    'description'=>'docblock*',
                ],
                "namespace"=> 'Abc\\Def_09',
            ],
        ],
        'Namespace.SeparatedName'=>[
            'start'=>['namespace'],
            'input'=>"namespace Abc\\Def\_09;",
            'expect'=>[
                "namespace"=> 'Abc\\Def\\_09',
                'namespace.docblock'=>'',
            ],
        ],
        'Namespace.Simple'=>[
            'start'=>['namespace'],
            'input'=>"namespace AbcDef_09;",
            'expect'=>[
                "namespace"=> 'AbcDef_09',
                'namespace.docblock'=>'',
            ],
        ],
    ];

    public function testPhpDirectives(){
        $phpGram = new \Tlf\Lexer\PhpGrammar();
        $grammars = [
            $phpGram,
        ];
        $phpGram->buildDirectives();

        $this->runDirectiveTests($grammars, $this->thingies);
    }



    public function testPhpPhpGrammar16Jul21(){
        $dir = dirname(__DIR__).'/php/';
        $file = $dir.'PhpGrammar.16jul21.php';
        $targetTree = include($dir.'PhpGrammar.16jul21.tree.php');

        $lexer = new \Tlf\Lexer();
        $lexer->debug = true;

        // This is for devving v0.6:
        // $lexer->stop_loop = 2900;
        // $lexer->stop_loop = 4675;
        // $lexer->stop_loop = 4700; //just before 4700, problems start. There is a block closer thats being caught as a comment
//
        // $lexer->stop_loop = 5450; //between 5450 & 5500, we're getting stuck & execution just is not completing
        //5483 is where it gets stuck, due to a bug in docblock which has since been fixed

        if (isset($this->options['stop_loop'])){
            $lexer->stop_loop = (int)$this->options['stop_loop'];
        }

        
        // $lexer->stop_loop = 9999999;
        $lexer->useCache = false; // useCache only matters when lexing a file
        $lexer->addGrammar($phpGrammar = new \Tlf\Lexer\PhpGrammar());

        $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.'PhpGrammar.16jul21.tree2.php',var_export($tree,true));
        echo "\n----\n\n\n";
        $this->compare(
            $targetTree, 
            $tree
        );
    }
    public function testPhpStarterGrammar16Jul21(){
        $dir = dirname(__DIR__).'/php/';
        $file = $dir.'StarterGrammar.16jul21.php';
        $targetTree = include($dir.'StarterGrammar.16jul21.tree.php');

        $lexer = new \Tlf\Lexer();
        $lexer->debug = true;

        // This is for devving v0.6:
        // $lexer->stop_loop = 1400;
        // $lexer->stop_loop = 1415; // 1396 introduces a nested block in `onLexerStart()` method. Its an if block.
        // $lexer->stop_loop = 1450; //1446 is the nested block end
        // $lexer->stop_loop = 1466; //during the nested if block?
        // $lexer->stop_loop = 1475; //class declaration is messed up between 1450 & 1475
        // $lexer->stop_loop = 1500; // already has extra whitespace
        // $lexer->stop_loop = 1600; // We're already parsing trimBuffer() method & class declaration is messed up

        
        // $lexer->stop_loop = 9999999;
        $lexer->useCache = false; // useCache only matters when lexing a file
        $lexer->addGrammar($phpGrammar = new \Tlf\Lexer\PhpGrammar());

        $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.'StarterGrammar.16jul21.tree2.php',var_export($tree,true));
        echo "\n----\n\n\n";
        $this->compare(
            $targetTree, 
            $tree
        );
    }

    public function testPhpSampleClass(){
        $dir = dirname(__DIR__).'/php/';
        $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\PhpGrammar());

        $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
        );
    }

}