DocblockGrammar.php

<?php

namespace Tlf\Lexer;

class DocblockGrammar extends Grammar {

    //public $directives = [

        //'/*'=>[
            //'start'=>[
                //'match'=>'/\\/\*/',
                //'buffer.clear',
            //],
            //'stop'=>[
                //'match'=>'*/',
                //// 'directive.pop 1',
                //'rewind 2',
                //'this:processDocblock',
                //'forward 2',
                //'buffer.clear',
            //]
        //],
    //];

    public function __construct(){
        $this->directives = require(__DIR__.'/directives.php');
    }

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

    public function onGrammarAdded($lexer){
        //return; // @todo continue developing directive-driven grammar
        //$lexer->addDirective($this->getDirectives(':php_open')['php_open']);
    }
    public function onLexerStart($lexer, $ast, $token){
    }
    public function onLexerEnd($lexer, $ast, $token){
        $prev = $lexer->previous('docblock');
        if ($prev!==null){
            $ast->add('docblock', $prev);
        }
    }

    public function processDocblock($lexer, $ast, $token, $directive){
// echo "\n\n\n-----------\n\n";
        // echo 'are we here?';
// echo "\n\n\n-----------\n\n";
// exit;
        // if ($lexer->loop_count==5483){
            // var_dump($lexer->loop_count);
            // var_dump("k");
            // echo "\n\n\n";
            // var_dump($token->buffer());
            // exit;
        // }
        // if (false){
        //     var_dump($lexer->loop_count);
        //     var_dump("k");
        //     echo "\n\n\n";
        //     var_dump($token->buffer());
        //     // exit;
        // }
        $body = $token->buffer();
        $lines = $this->cleanIndentation($body);


        $ast = $this->buildAstWithAttributes($lines);

        $lexer->setPrevious('docblock',$ast);
        if ($lexer->getHead()->_type=='expression'){
            $lexer->getHead()->set('docblock', $ast);
        }
    }

    public function buildAstWithAttributes($lines){
        // echo "\n\n\n++\n";
        $docblock = new Ast('docblock');
        $docblock->set('description', '');
        $curAttr = false;

        $head = $docblock;
        $key = 'description';
        $newLine = false;
        foreach ($lines as $index=>$line){
            if ($index>0)$newLine = true;
            if (preg_match('/^\s*\@([a-zA-Z\_0-9]+)[^a-zA-Z\_0-9]/',$line, $match)){
    
                if ($head->type=='attribute'){
                    $desc = $head->get('description');
                    $descLines = explode("\n", $desc);
                    // var_dump($descLines);
                    // exit;
                    while (count($descLines)>0&&trim($lastLine = array_pop($descLines)) == ''){
                        // var_dump($lastLine);
                    }
                    if (trim($lastLine)!=false){
                        $descLines[] = $lastLine;
                    }
                    $head->set('description', implode("\n", $descLines));
                }

                $line = substr($line, strlen($match[0])-1);
                $line = trim($line);
                $head = $match[1];
                $isAttr = true;
                $attr = new Ast('attribute');
                $attr->set('name', $match[1]);
                $attr->set('description', '');
                $head = $attr;
                $docblock->add('attribute', $attr);
                $newLine = false;
            }

            if ($newLine)$line = "\n$line";
            $head->append('description', $line);
        }

        // echo "\n\n\n++\n";
        return $docblock;
    }
    /**
     * Remove indentation and * from docblock body 
     */
    public function cleanIndentation($body){
        if (substr($body,0)=='*')$body = substr($body,1);
        // remove * from lines that only have whitespace and *
        $body = preg_replace("/^(\s*)\*(\s*)$/m", '\1 \2', $body);
        // remove * from all lines
        $body = preg_replace("/^(\s*)\*(\s*)/m", '\1 \2', $body);

        $body = \Tlf\Lexer\Utility::trim_indents($body);

        return explode("\n", $body);
    }
}