Ast.php

<?php

namespace Tlf\Lexer;

class Ast {

    protected $_path;
    protected $_name;
    protected $_ext;


    public $_source;
    protected $_tree = [];
    public $_type;

    public function __construct($type, $startingTree=[]){
        $this->_type = $type;
        $this->_tree = $startingTree ?? [];
        $this->set('type',$type);
    }

    /**
     * Removes an ast if it is setto/addedto this ast. If $key points to an empty array, then $key is unset from this ast
     *
     * @param $key The key $ast was setto/addedto
     * @param $ast The ast to remove
     */
    public function removeAst($key, $ast){
        $value = $this->_tree[$key];
        if (is_array($value)){
            foreach ($value as $i=>$target){
                if ($target===$ast)unset($this->tree[$key][$i]);
            }
        if ($this->tree[$key]===[])unset($this->tree[$key]);
        } else if ($value===$ast){
            unset($this->tree[$key]);
        }

    }

    /**
     * Set $value to $key, overwriting any previously set value
     */
    public function set($key,$value){
        $this->_tree[$key] = $value;
    }

    public function append($key, $value){
        $this->_tree[$key] = $this->_tree[$key] . $value;
    }

    /**
     * @param $keyValues a `key=>value` array to call `$this->set($key, $value)` on each entry
     */
    public function setAll(array $keyValues){
        foreach ($keyValues as $key=>$value){
            $this->set($key,$value);
        }
    }

    /**
     * Add $value to an array
     * @param $key the key that we'll be pushing $value onto
     * @param $value the value to append
     * @param $subKey a subkey for an assoc array
     */
    public function add($key,$value, $subKey=false){
        // if (!isset($this->_tree[$key]))$this->_tree[$key] = [];
        if ($subKey===false)
            $this->_tree[$key][] = $value;
        else 
            $this->_tree[$key][$subKey] = $value;
    }
    /**
     * Alias for add 
     */
    public function push($key, $value, $subKey=false){
        $this->add($key, $value, $subKey);
    }

    public function get($key){
        return $this->_tree[$key] ?? null;
    }

    /**
     * Get the current tree as-is (asts are still asts)
     */
    public function getAll(){
        return $this->_tree;
    }

    protected $passthrough = [];
    public function addPassthrough($ast){
        $this->passthrough[] = $ast;
    }
    /**
     * Get the tree as a pure array
     */
    public function getTree($sourceTree=null){
        static $a = 0;
        $srcTreeIsNull = is_null($sourceTree);
        $sourceTree = $sourceTree ?? $this->_tree;
        $tree = [];
        foreach ($sourceTree as $key=>$value){
            if (is_array($value)){
                $tree[$key] =  $this->getTree($value);
                // $tree[$key] = 'array';
                // $tree[$key] = json_encode($value);
            } else if ($value instanceof Ast){
                $tree[$key] = $value->getTree();
            } else {
                $tree[$key] = $value;

            }
        }
        if ($srcTreeIsNull){
            foreach ($this->passthrough as $pt){
                $ptTree = $pt->getTree();
                unset($ptTree['type']);
                foreach ($ptTree as $k=>$v){
                    // if ($k=='methods'){
                        // $a++;
                        // echo "\n\n\n\n\n-----";
                        // var_dump($this);
                        // echo "\n\n\n\n\n-----";
                        // var_dump($ptTree);
                        // echo "\n\n\n\n\n-----";
                        // if ($a==2)exit;
                    // }
                    if (is_object($v))$v = $v->getTree();
                    // $tree[$k] = '--'.$this->type.':'.$k.'--'.$a++;
                    $tree[$k] = $v;
                }
            }
        }
        return $tree;
    }

    public function setTree($astTree){
        $this->_tree = $astTree;
    }

    public function __get($prop){
        return $this->get($prop);
    }
    public function __set($prop, $value){
        $this->set($prop, $value);
    }
    public function __isset($prop){
        return isset($this->_tree[$prop]);
    }

    static public function __set_state($array){
        return $array;
    }
}