Cache.php

<?php

namespace Tlf\LexerTrait;

/**
 * Handles caching of asts & grammar lists
 */
trait Cache {

    /**
     * Copy of .cache/map.json
     */
    protected $cacheMap = null;

    public function getCachedAst($filePath){
        if ($this->useCache===false)return false;
        $cacheDir = dirname(__DIR__, 2).'/.cache/';
        if (!is_file($cacheDir.'/map.json'))return false;
        $map = $this->cacheMap ?? json_decode(file_get_contents($cacheDir.'/map.json'),true);
        $this->cacheMap = $map;
        if (!isset($map['files'][$filePath]))return false;
        $file = $map['files'][$filePath];

        if (sha1_file($filePath)!=$file['sha1'])return false;
        
        $grammarList = $this->getGrammarListForCache();
        if ($grammarList != $file['grammarList']) return false;

        $astTree = include($file['cachedAstPath']);
        if (!is_array($astTree))return false;

        $ast = new \Tlf\Lexer\Ast('file');
        $ast->setTree($astTree);
        
        return $ast;
    }

    public function cacheFileAst($filePath, $ast){
        if ($this->useCache===false)return;
        $tree = $ast->getTree();

        $cacheDir = dirname(__DIR__, 2).'/.cache/';
        if (!is_dir($cacheDir))mkdir($cacheDir);
        if (!is_dir($cacheDir.'/fileast/'))mkdir($cacheDir.'/fileast/');
        if (!is_file($cacheDir.'/map.json'))file_put_contents($cacheDir.'/map.json',json_encode([]));
        $map = $this->cacheMap ?? json_decode(file_get_contents($cacheDir.'/map.json'),true);

        if (isset($map['files'][$filePath]['cachedAstPath'])){
            if (is_file($cachedPath = $map['files'][$filePath]['cachedAstPath'])){
                unlink($cachedPath);
            }
        }

        $map['files'][$filePath]['sha1'] = sha1_file($filePath);
        $map['files'][$filePath]['grammarList'] = $this->getGrammarListForCache();
        if (!is_dir($cacheDir.'/fileast'))mkdir($cacheDir.'/fileast');
        $cachedAstPath = $cacheDir.'/fileast/'.uniqid().'.php';
        $map['files'][$filePath]['cachedAstPath'] = $cachedAstPath;

        file_put_contents($cachedAstPath,
            '<?php return '
                . var_export($tree,true)
            .';'
        );
        
        $this->cacheMap = $map;
        file_put_contents($cacheDir.'/map.json', json_encode($map, JSON_PRETTY_PRINT));
    }

    public function getGrammarListForCache(){
        if ($this->grammarListForCache!=null)return $this->grammarListForCache;
        $grammarList = [];
        foreach ($this->grammars as $g){
            $grammarList[get_class($g)] = filemtime((new \ReflectionClass($g))->getFileName());
        }
        ksort($grammarList);

        $this->grammarListForCache = $grammarList;
        return $grammarList;
    }
}