Grammar Commands

These commands are available for your directives to execute. See an example at docs/GrammarExample.md. See instructions for writing a grammar at docs/GrammarWriting.md

In the internals, there are two types of commands.

  • switch/case commands, which generally have a simple or small implementation.
  • mapped commands, which point a command to a method (rather than the switch-case)

Mapped commands

The key points to a method on the $lexer instance, but they're written in the MappedMethods trait. See code/Lexer/MappedMethods.php

[  
    'directive.then'=>'cmdThen',  
    'then'=>'cmdThen',  
    'then.pop'=>'cmdThenPop',  
  
    'match'=>'cmdMatch',  
    'buffer.match'=>'cmdMatch',  
  
    'buffer.notin'=>'cmdBuffer_notin',  
  
    'ast.new'=>'cmdAst_new',  
];  

switch/case commands

These are the exact implementations of the commands from code/Lexer/Instructions.php

switch ($command){  
    ///  
    // comands for debugging  
    ///  
    case "debug.die":  
    case "die":  
        var_dump($args);  
        exit;  
        break;  
    case "debug.print":  
    case "print":  
        var_dump($args);  
        break;  
    /**  
     * Run commands of another directive. Does not run 'match' by default  
     *  
     * @arg :directive.isn  
     * @arg literal string 'match' to keep the match command from the inherited directive  
     *  
     * @example directive.inherit :varchars.start  
     */  
    case "directive.inherit":  
    case "inherit":  
        $arg2 = $args[1]??'';  
        $parts = explode('.', $arg1);  
        $name = $parts[0];  
        $isn = $parts[1];  
        $directives = $directive->_grammar->getDirectives($name);  
        foreach ($directives as $d){  
            if ($arg2!=='match'){  
                unset($d->$isn['match']);  
            }  
            // print_r($d  
            $this->processInstructions($d, $isn, $directiveList);  
            if ($arg2==='match'&&isset($d->$isn['_matches'])){  
                $directive->$isn['_matches'] = $d->$isn['_matches'];  
            }  
        }  
        echo "\n\033[0;32mContinue ".$directive->_name."\033[0m";  
        break;  
    //  
    // commands with non-namespaced shorthands  
    //  
    case "directive.start":  
    case "start":  
        $this->directiveStarted($directive);  
        break;  
    case "directive.stop":  
    case "stop":  
        $this->directiveStopped($directive);  
        break;  
    case "token.rewind":  
    case "rewind":  
        $token->rewind($arg1);  
        break;  
    case "token.forward":  
    case "forward":  
        $token->forward($arg1);  
        break;  
    /**  
     * Halt execution of current directive (don't run its following instructions). Useful for preventing overrides from being executed  
     */  
    case "directive.halt":  
    case "halt":  
        $this->haltInstructions();  
        break;  
    case "halt.all":  
        // @TODO maybe I should also haltInstruction, but ... I shouldn't break things.  
        $this->haltAll();  
        break;  
    //  
    // namespaced commands  
    //  
    case "previous.append":  
        if (!is_array($arg1))$arg1 = [$arg1];  
        foreach ($arg1 as $index=>$keyForPrevious){  
            $this->appendToPrevious($keyForPrevious, $token->buffer());  
        }  
        break;  
    case "previous.set":  
        $value = $args[1] ?? $token->buffer();  
        if ($value ===true)$value = $token->buffer();  
        $this->setPrevious($arg1, $value);  
        break;  
    case "directive.stop_others":  
        foreach ($directiveList['started'] as $started){  
            if ($started!=$directive){  
                $this->directiveStopped($started, $list);  
            }  
        }  
        break;  
    case "directive.pop":  
        $arg1 = (int)$arg1;  
        if ($arg1===0)echo "\n    --no directives popped.";  
        while ($arg1-- > 0){  
            $this->popDirectivesLayer();  
        }  
        break;  
  
    //  
    // buffer commands  
    //  
    case "buffer.clear":  
        $token->clearBuffer();  
        break;  
    case "buffer.clearNext":  
        $amount = (int)$arg1;  
        $remove = 0;  
        while ($amount-->0){  
            if ($token->next())$remove++;  
        }  
        $token->setBuffer(substr($token->buffer(),0,-$remove));  
        break;  
    case "buffer.appendChar":  
        $token->setBuffer($token->buffer() . $arg1);  
        break;  
    //  
    // ast commands  
    //  
    case "ast.pop":  
        $this->popHead();  
        break;  
    case "ast.set":  
        if (isset($args[1])){  
            $value = $this->executeMethodString($args[1]);  
        } else $value = $token->buffer();  
        $this->getHead()->set($arg1, $value);  
        break;  
    /**  
     * Save the currrent buffer to the given key  
     * @arg key to push to  
     */  
    case "ast.push":  
        $key = $arg1;  
        $toPush = $token->buffer();  
        $ast = $this->getHead();  
        $ast->add($key,$toPush);  
        break;  
    case "ast.append":  
        $key = $arg1;  
        if (isset($args[1])&&is_string($args[1])){  
            var_dump($args[1]);  
            $value = $this->executeMethodString($args[1]);  
        } else $value = $token->buffer();  
        $ast = $this->getHead();  
        $src = $ast->get($key);  
        $new = $src . $value;  
        $ast->set($key, $new);  
        break;  
  
    default:  
        throw new \Exception("\nAction '$command' not handled yet. Maybe it needs to be a callable. Prepend `this:` to call a method on your grammar.");  
}