Grammar Commands
These commands are available for your directives to execute. See an example at doc/GrammarExample.md. See instructions for writing a grammar at doc/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":
$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.");
}