PhpGrammar.php

<?php

namespace Tlf\Lexer;

/**
 *
 * This is not for actual parsing yet. This is for design work. The $directives array & 'php_open' and 'namespace' are design aspects I'm interested in implementing at some point... maybe
 *
 */
class PhpGrammar extends Grammar {

    use Php\LanguageDirectives;
    use Php\ClassDirectives;
    use Php\ClassMemberDirectives;
    use Php\BodyDirectives;
    use Php\OtherDirectives;

    protected $directives;

    public $notin = [
        'keyword'=>[
            // 'match'=>'/this-regex-available on php.net keywords page/',
            '__halt_compiler', 'abstract', 'and', 'array', 'as', 'break', 'callable', 'case', 'catch', 'class', 'clone', 'const', 'continue', 'declare', 'default', 'die', 'do', 'echo', 'else', 'elseif', 'empty', 'enddeclare', 'endfor', 'endforeach', 'endif', 'endswitch', 'endwhile', 'eval', 'exit', 'extends', 'final', 'for', 'foreach', 'function', 'global', 'goto', 'if', 'implements', 'include', 'include_once', 'instanceof', 'insteadof', 'interface', 'isset', 'list', 'namespace', 'new', 'or', 'print', 'private', 'protected', 'public', 'require', 'require_once', 'return', 'static', 'switch', 'throw', 'trait', 'try', 'unset', 'use', 'var', 'while', 'xor'
        ],
    ];

    public function getNamespace(){return 'php';}

    public function buildDirectives(){
        $this->directives = array_merge(
            $this->_language_directives,
            $this->_body_directives,
            $this->_class_directives,
            $this->_class_member_directives,
            $this->_other_directives,
        );
    }

    public function onGrammarAdded($lexer){
        $this->buildDirectives();
        $lexer->addDirective($this->getDirectives(':php_open')['php_open']);
    }

    public function onLexerStart($lexer,$file,$token){
        $lexer->addGrammar(new DocblockGrammar());
        // $this->buildDirectives();
        // $lexer->addDirective($this->getDirectives(':html')[':html']);
        // $lexer->stackDirectiveList('phpgrammar:html', 'phpgrammar:php_open');
        // $lexer->setDirective([$this->getDirective('html')]);

        if ($file->type=='file'){
            $file->set('namespace', '');
        }
    }

    public function holdNamespaceName($lexer, $file, $token){
        $prev = $lexer->previous('namespace.name');
        if ($prev == null)$prev = [];
        $prev[] = $token->buffer();
        $lexer->setPrevious('namespace.name', $prev);
    }

    public function saveNamespace($lexer, $file, $token){
        $namespace = $lexer->previous('namespace.name');
        $namespace = implode('\\',$namespace);
        $file->set('namespace.docblock', $lexer->unsetPrevious('docblock'));
        $file->set('namespace', $namespace);
        $lexer->setPrevious('namespace.name', $namespace);
    }

    public function handleClassDeclaration($lexer, $class, $token){
        $class->set('declaration', $lexer->unsetPrevious('class.declaration'));
    }

    public function processDocBlock($lexer, $ast, $token){
        $lexer->setPrevious('docblock', $token->buffer());
    }
    public function captureUseTrait($lexer, $ast, $token){
        $ast->add('traits',$token->buffer());
    }
    public function processComment($lexer, $ast, $token){
        $comment = trim($token->buffer());
        $ast->add('comments', $comment);
        $lexer->previous('comment', $comment);
    }



    // public function end_docblock($lexer, $unknownAst, $token){
    //     $block = $token->buffer();
    //     $block = trim($block);
    //     $block = trim(substr($block,strlen('/**'),-1));
    //     $block = preg_replace('/^\s*\*+/m','',$block);
    //     $block = \Tlf\Scrawl\Utility::trimTextBlock($block);
    //     $block = trim($block);
    //     // if (substr($block,0,3)=='/**')$block = substr($block,3);
    //
    //         $docLex = new \Tlf\Lexer();
    //         $docLex->addGrammar(new \Tlf\Lexer\DocBlockGrammar());
    //
    //         $docAst = new \Tlf\Lexer\Ast('docblock');
    //         $docAst->set('src', $block);
    //         $docLex->setHead($docAst);
    //
    //         $docAst = $docLex->lexAst($docAst, $block);
    //
    //     $lexer->setPrevious('docblock', $docAst);
    //     $unknownAst->add('childDocblock', $docAst);
    //     $token->setBuffer($token->match(0));
    // }



    /**
     * Do nothing, apparently? I thought it was supposed to append to previous('whitespace'). Idunno
     */
    public function appendToWhitespace($lexer, $ast, $token, $directive){
        // $whitespace = $lexer->previous('whitespace') ?? '';
        // $lexer->setPrevious('whitespace', $whitespace.$directive->_matches[0]);
        // $lexer->setPrevious('whitespace', $whitespace.$token->buffer());
    }

    /**
     * Combine the stored modifier with the stored property declaration
     */
    public function setPropertyDeclaration($lexer, $ast, $token, $directive){
        $ast->set('declaration',
            $lexer->unsetPrevious('modifier')
            .$lexer->unsetPrevious('property.declaration')
        );
    }

    /**
     * 
     */
    public function storeMethodDefinition($lexer, $ast, $token, $directive){
        $ast->set('definition', 
            $lexer->unsetPrevious('modifier')
            .$lexer->unsetPrevious('method.definition')
        );
        $ast->set('arglist', $lexer->unsetPrevious('method.arglist') );
        $name = $lexer->unsetPrevious('method.name');
        $ast->set('name', $name);
        //remove the method name from the modifiers.
        $modifiers = $ast->get('modifiers');
        $ast->set('modifiers', substr($modifiers,0, -strlen($name)));
    }
}