Main.php

<?php

namespace Tlf\Lexer2\StdLib;

/**
 * The standard library for a Lexer program
 */
class Main {

    public function __construct(
        protected \Tlf\Lexer2\Program $program
    ){

    }


    public function hook(string $hook_name, ...$command): void {

        switch ($hook_name){
            case "end_execute_commands":
                $parser = new \Tlf\Lexer2\Parser();
                $command = $parser->parse_command_string(implode(" ",$command),null)->toArray();
                $this->program->end_execute_commands_hooks[] = $command;
                break;

            default:
                throw new \Exception("Hook '$hook_name' does not exist");
        }
    }

    /**
     * Create a new object & return it.
     * If the new object is an AST, then set it as the head ast.
     *
     * @param $object_name string like 'Ast\Type'
     * @param $params array<string key, mixed value>
     */
    public function new(string $object_name, array $params): object {
        $parts = explode("\\", $object_name);
        if ($parts[0]!='Ast'){
            throw new \Exception("Currently, only Ast Objects are supported by the 'new' method");
        }
        $type = $parts[1];

        $tree = [];
        foreach ($params as $name=>$value){
            if ($this->program->is_command($value)){
                $real_value = $this->program->execute_command($value,4);
                //var_dump($value);
                //var_dump($real_value);
                //exit;
                $tree[$name] = $real_value;
            } else {
                $tree[$name] = $value;
            }
        }

        $ast = new \Tlf\Lexer\Ast($type, $tree);
        $this->program->ast_stack[] = $ast;

        return $ast;
    }

    /**
     * Return a local variable from the program.
     */
    public function get_arg(string $arg_name){
        //echo "\n\n\n\n\n";
        //var_dump($arg_name);
        //var_dump($this->program->local_vars);
        //echo "\n\n\n\n\n";
        //var_dump($this->program->local_vars[$arg_name]);
        //exit;
        return $this->program->local_vars[$arg_name];
    }

    public function set_arg(string $arg_name, $value){
        $this->program->local_vars[$arg_name] = $value;
    }



    /**
     * Remove the current directive from the 'unstarted' list of the current directive layer, and add it to the 'started' list
     */
    public function start(){
        $active_directive = $this->program->active_directive;
        $stack_index = count($this->program->directive_stack) - 1;
        $this->program->directive_stack[$stack_index]['started'][] = $active_directive;
        $directive_index = array_search($active_directive, $this->program->directive_stack[$stack_index]['unstarted']);
        unset($this->program->directive_stack[$stack_index]['unstarted'][$directive_index]);
        $this->program->directive_stack[$stack_index]['unstarted'] = array_values($this->program->directive_stack[$stack_index]['unstarted']);
    }

    /**
     * Remove the current directive from the 'started' list of the current directive layer, and add it to the 'unstarted' list
     */
    public function stop(){
        $active_directive = $this->program->active_directive;
        $stack_index = count($this->program->directive_stack) - 1;
        $this->program->directive_stack[$stack_index]['unstarted'][] = $active_directive;
        $directive_index = array_search($active_directive, $this->program->directive_stack[$stack_index]['started']);
        unset($this->program->directive_stack[$stack_index]['started'][$directive_index]);
        $this->program->directive_stack[$stack_index]['started'] = array_values($this->program->directive_stack[$stack_index]['started']);

    }

    public function add_directive_layer(){
        $this->program->directive_stack[] = ['unstarted'=>[], 'started'=>[]];
    }

    /**
     * array_pop() a Program array, such as ast_stack or directive_stack
     */
    public function pop(string $program_param_name){
        if (!isset($this->program->$program_param_name)){
            throw new \Exception("The Program does not have a property named $program_param_name");
        } else if (!is_array($this->program->$program_param_name)){
            throw new \Exception("The Program's property $program_param_name MUST be an array. It is a ".gettype($this->program->$program_param_name));
        }
        array_pop($this->program->$program_param_name);
    }


    //public function rewind(int $amount=1){
        //$this->program->call('buffer.
    //}

    public function activateDirective(?string $namespace, string $directive_name){

        if ($namespace == null){
            $active_directive = $this->program->active_directive;
            $namespace = $active_directive['--context--']['namespace'];
        }

        if (!isset($this->program->directives[$namespace][$directive_name])){
            $this->program->error("Directive $namespace:$directive_name is not available");
            echo "\n\n";
            exit;
        }
        $directive = $this->program->directives[$namespace][$directive_name];
        $this->program->addUnstartedDirectiveToStack($namespace.':'.$directive_name, $directive);
    }
}