MappedMethods.php
<?php
namespace Tlf\LexerTrait;
trait MappedMethods {
public function getCmdMethodMap(){
return
//@export_start(Commands.MethodMap)
[
'directive.then'=>'cmdThen',
'then'=>'cmdThen',
'then.pop'=>'cmdThenPop',
'match'=>'cmdMatch',
'buffer.match'=>'cmdMatch',
'buffer.notin'=>'cmdBuffer_notin',
'ast.new'=>'cmdAst_new',
];
//@export_end(Commands.MethodMap)
}
public function cmdMatch($args, $directive, $isn, &$directiveList){
$token = $this->token;
$debug = $this->debug;
// echo "\n\n\n\n\n\n---------\n\n";
// $directive = (object)(array)$directive;
// unset($directive->_grammar);
// var_dump($directive);
// echo "\n\n\n----\n\n";
// var_dump($args);
if (is_string($args[0])){
$args[0] = [$args[0]];
}
// echo "\n\n\n";
$matches = $this->doesATargetPass($directive, $args[0], $token->buffer());
$token->setMatch($matches);
// print_r($matches);
if ($matches!==false){
// $passed[$isn][$directive->_name] = $directive;
$directive->$isn['_matches'] = $matches;
if ($isn=='start'){
$this->directiveStarted($directive, $directiveList);
} else if ($isn=='stop'){
$this->directiveStopped($directive, $directiveList);
}
} else {
$this->haltInstructions();
}
if ($debug){
if ($matches===false){
echo ' [[fail]]';
} else {
echo "\033[42m".'[[pass]]'."\033[0m";
}
}
}
/**
* Add a directive to the stack & immediately pop the directive layer when it is matched (instead of the directive's normal functioning).
*
* @example then.pop :directive_name.stop 2 //this will pop 2 directives when directive_name.stop matches.
* @experimental there's an automatic rewind component of this feature & that will likely change. Currently, I'm rewinding by the lenght of $matches[1] (the first capture group).
*/
public function cmdThenPop($args, $directive, $isn, &$directiveList){
if ($this->last_then_loop<$this->loop_count){
$this->newDirectivesLayer();
}
$this->last_then_loop = $this->loop_count;
$targetDirectiveName = $args[0];
$popAmount = $args[1];
$rewindLen = strlen($directive->start['_matches'][1]);
$overrides = [
'start'=>[
'rewind'=>$rewindLen,
'stop',
'directive.pop'=>$popAmount,
'halt',
],
];
$grammar = $directive->_grammar;
$directives = $grammar->getDirectives($targetDirectiveName, $overrides);
foreach ($directives as $d){
$this->addDirective($d);
}
}
/**
* Add a directive to the directive stack
*
* @example then :directive_name
*/
public function cmdThen($args, $directive, $isn, &$directiveList){
if ($this->last_then_loop<$this->loop_count){
$this->newDirectivesLayer();
}
$this->last_then_loop = $this->loop_count;
// echo "\n\n--";
// print_r($args);
// echo "\n\n";
// exit;
$targetDirectiveName = $args[0];
$overrides = $args[1];
// $grammar = $this->grammars[$directive->_grammar];
$grammar = $directive->_grammar;
$directives = $grammar->getDirectives($targetDirectiveName, $overrides);
foreach ($directives as $d){
$this->addDirective($d);
}
}
/**
* Checks if the current buffer matches any strings in `$grammar->notin['arg1']` and invalidates a match if the buffer matches
*
* @param $args the list of arguments
*
* @example `notin keyword` checks `$grammar->notin
* @arg the group of words to check in
*/
public function cmdBuffer_notin($args, $directive, $isn, &$directiveList){
$token = $this->token;
$type = $args[0] ?? false;
$list = $directive->_grammar->notin[$type] ?? [];
if (in_array($token->buffer(), $list)){
echo "\n - '".$token->buffer()."' is a $type, so match fails";
$this->haltInstructions();
// unset($passed[$isn][$directive->_name]);
unset($directive->$isn['_matches']);
if ($isn=='start'){
$this->directiveStopped($directive, $list);
} else if ($isn=='stop'){
$this->directiveStarted($directive, $list);
}
$token->clearBuffer();
}
}
public function cmdAst_new($args, $directive, $isn, &$list){
$info = $args[0];
$type = $info['type'] ?? $info['_type'];
$type = $this->executeMethodString($type);
if (isset($info['_class'])){
$astClass = $info['_class'];
} else {
// $ownGrammar = $this->grammars[$directive->_grammar];
$ownGrammar = $directive->_grammar;
$astClass = $ownGrammar->getAstClass($directive);
}
$ast = new $astClass($type);
if (isset($info['_setto'])){
$_setto = $this->executeMethodString($info['_setto']);
$this->getHead()->set($_setto, $ast);
unset($info['_setto']);
} else if (isset($info['_addto'])){
if ($info['_addto']!==false){
$_addto = $this->executeMethodString($info['_addto']);
$this->getHead()->add($_addto, $ast);
}
unset($info['_addto']);
} else {
$this->getHead()->add($type, $ast);
}
if (isset($info['_setPrevious']) && $info['_setPrevious'] != false){
$this->setPrevious($info['_setPrevious'], $ast);
}
foreach ($info as $key=>$value){
if (is_string($value)){
$realValue = $this->executeMethodString($value);
} else $realValue=$value;
$info[$key] = $realValue;
}
$setHead = isset($info['_setHead']) ? $info['_setHead'] : true;
unset($info['_type'], $info['_setPrevious'], $info['_setHead']);
$ast->setAll($info);
if ($setHead){
$this->setHead($ast);
}
}
}