Operations.php
<?php
namespace Tlf\Lexer\PhpNew;
trait Operations {
// public function op_none(){return false;}
public function operation_match($lexer, $ast, $token, $directive){
$buff = $token->buffer();
$next = $token->remainder()[0] ?? ' ';
$buffNext = $buff . $next;
$buffNextNext = $buff . $next . ($token->remainder()[1] ?? ' ');
$ops = $this->get_operations();
// does $buff + next == an operation? Then we stop and match fails
// Does $buff == an operation? then we stop and match succeeds
if (isset($ops[$buffNext])
||isset($ops[$buffNextNext])
||!isset($ops[$buff])
||$ops[$buff]=='none'){
$lexer->haltInstructions();
return;
}
}
public function get_operations(){
$map = [
// (i think) 'none' disables default operation handling
// this is good if it has it's own directive
//
'/*'=>'none',
'//'=>'none',
'?>'=>'none', // without this, the `?` gets handled & php_stop never does
'<<<' => 'none', // has a directive in StringDirectives
// '&&'=>'none',
// '||'=>'none',
'&&'=>'and',
'||'=>'or',
//comparison
'!='=>'does not equal',
'!=='=>'strictly does not equal',
'=>'=>'array_keyed',
'>='=>'is_lt_equal',
'>='=>'is_gt_equal',
'=='=>'is_equal',
'>'=>'is_gt',
'<'=>'is_lt',
//math
'+'=>'math',
'-'=>'math',
'*'=>'math',
'**'=>'math',
'/'=>'math',
//other
'='=>'assign',
';'=>'terminate',
':'=>'return_type',
'$'=>'var',
','=>'comma',
'.'=>'concat',
'&'=>'reference',
'->'=>'method_call',
'::'=>'static_call',
'!'=>'not',
'|'=>'binary_thing',
'++'=>'increment',
'--'=>'decrement',
'??'=>'null coalesce',
'?'=>'nullable type',
'@'=>'suppress error',
//scope
'{'=>'block_start',
'}'=>'block_end',
'('=>'arglist_open',
')'=>'arglist_close',
'['=>'array_open',
']'=>'array_close',
];
return $map;
}
public function op_array_open($lexer, $ast, $xpn){
$array = new \Tlf\Lexer\StringAst('array');
$ast->set('value', $array);
// $array->abc = 'okay';
$xpn->push('declaration', '[');
$xpn->push('words','[');
$lexer->setHead($array);
}
public function op_array_close($lexer, $ast, $xpn){
$lexer->popHead();
$xpn->push('words',']');
$xpn->push('declaration', ']');
}
public function op_array_keyed($lexer, $ast, $xpn){
$xpn->push('words', '=>');
$xpn->push('declaration', '=>');
}
public function op_math($lexer, $ast, $xpn){
$xpn->push('words', $lexer->getToken()->buffer());
$xpn->push('declaration', $lexer->getToken()->buffer());
}
public function op_reference($lexer, $ast, $xpn){
if ($ast->type == 'method'){
$xpn->push('declaration', '&');
$xpn->push('words', '&');
$ast->return_by_reference = true;
$lexer->getToken()->clearBuffer();
}
}
public function op_var($lexer, $ast, $xpn){
$xpn->push('declaration','$');
//how do I know if it is a(n):
// - argument
// if I'm inside a method/function, its an argument
// - property
// if i'm inside a class ast, then its a property
// - variable
// If i'm anywhere else, its a variable
// - Other cases?
// like inside a use() statement for an anonymous function
$head = $lexer->getHead();
if ($head->type=='class_body'){
$prop = new \Tlf\Lexer\Ast('property');
$prop->modifiers = $xpn->words;
$this->docblock($prop);
$lexer->setHead($prop);
$head->push('properties', $prop);
$prop->name = new \Tlf\Lexer\StringAst('property_name');
$lexer->setHead($prop->name);
} else if ($head->type=='method_arglist'){
$prop = new \Tlf\Lexer\Ast('arg');
if (count($xpn->words??[])>0){
$prop->arg_types = $xpn->words;
}
$xpn->words = [];
$this->docblock($prop);
$head->push('value', $prop);
$lexer->setHead($prop);
$propName = new \Tlf\Lexer\StringAst('arg_name');
$lexer->setHead($propName);
$prop->set('name', $propName);
}
}
public function op_comma($lexer, $ast, $xpn){
$head = $lexer->getHead();
if ($head->type == 'arg'){
$this->setArgDeclaration($ast);
} else if ($head->type=='var_assign'){
$head->value = implode('',$xpn->words);
$lexer->popHead();
$this->setArgDeclaration($lexer->getHead());
$lexer->popHead();
} else if ($head->type=='array'){
$xpn->push('words', ',');
}
$xpn->push('declaration', ',');
}
public function op_concat($lexer, $ast, $xpn){
$xpn->push('words', '.');
$xpn->push('declaration', '.');
}
public function op_terminate($lexer, $ast, $xpn){
// $head->declaration = trim(implode('', $xpn->declaration).';');
$declaration = trim(implode('', $xpn->declaration??[]).';');
if ($ast->type=='var_assign'){
$ast->value = implode('',$xpn->words);
$lexer->popHead();
$lexer->getHead()->declaration = $declaration;
$lexer->popHead();
} else if ($ast->type == 'property'){
$ast->declaration = $declaration;
$lexer->popHead();
} else if ($ast->type == 'namespace' || $ast->type=='use_trait'){
$ast->set('name', implode('',$xpn->words));
$ast->declaration = $declaration;
if ($ast->type=='use_trait')$lexer->popHead();
}
// $newXpn = new \Tlf\Lexer\Ast('expression');
// $lexer->setPrevious('xpn', $newXpn);
$xpn->declaration = [];
$xpn->words = [];
}
public function op_block_start($lexer, $ast, $xpn){
// echo ("\n\n\nAST TYPE({): ".$ast->type."\n\n\n");
$ast = $lexer->getHead();
if ($ast->type == 'return_types'){
$lexer->popHead();
$ast = $lexer->getHead();
}
if ($ast->type == 'method' || $ast->type=='function'){
// $body = new \Tlf\Lexer\ArrayAst('method_body');
$body = new \Tlf\Lexer\StringAst('method_body');
$lexer->setHead($body);
$ast->set('body', $body);
$ast->declaration = trim(implode('', $xpn->declaration));
$xpn->declaration = [];
$xpn->words = [];
$lexer->setPrevious('method_start', $lexer->token->index+1);
// $index = $lexer->token->index+1;
// echo "\n\n\n-----------\n\n";
// var_dump($lexer->token->source);
// echo "\n\n\n-----------\n\n";
// var_dump($index);
// exit;
} else if ($ast->type=='class' || $ast->type=='class_implements' || $ast->type == 'trait'){
// echo 'okay, now stop';
// exit;
$body = new \Tlf\Lexer\Ast('class_body');
$lexer->setHead($body);
$ast->addPassthrough($body);
$ast->declaration = trim(implode('',$xpn->declaration));
$xpn->declaration = [];
$xpn->words = [];
} else if ($ast->type=='method_body' || $ast->type == 'block_body'){
$body = new \Tlf\Lexer\ArrayAst('block_body');
$lexer->setHead($body);
}
}
public function op_block_end($lexer, $ast, $xpn){
// echo ("\n\n\nAST TYPE(}): ".$ast->type."\n\n\n");
if ($ast->type == 'method_body'){
$start = $lexer->unsetPrevious('method_start');
$end = $lexer->token->index - $start;
$body = substr($lexer->token->source,$start,$end);
$body = \Tlf\Lexer\Utility::trim_indents($body);
$body = \Tlf\Lexer\Utility::trim_trailing_whitespace($body);
$ast->value = $body;
$lexer->popHead();
$lexer->popHead();
} else if ($ast->type=='class_body'){
$lexer->popHead();
$lexer->popHead();
} else if ($ast->type=='block_body'){
// $lexer->popHead();
$lexer->popHead();
$lexer->setPrevious('xpn', new \Tlf\Lexer\Ast('expression'));
// var_dump($xpn);
// exit;
}
// else if ($ast->type=='function'){
// $xpn->declaration = [];
// $xpn->last_word = null;
// $xpn->words = [];
// // var_dump($xpn);
// // exit;
// $lexer->popHead();
// }
// else {
// echo 'else block end';
// exit;
// }
}
public function op_assign($lexer, $ast, $xpn){
$ast = $lexer->getHead();
if ($ast->type!='arg'&&$ast->type!='property' && $ast->type!='var'
&&$ast->type!='const'
|| isset($ast->value))return;
$xpn->push('declaration', '=');
$xpn->set('words',[]);
$var_assign = new \Tlf\Lexer\StringAst('var_assign');
$lexer->setHead($var_assign);
$ast->set('value', $var_assign);
}
public function op_arglist_open($lexer, $ast, $xpn){
if ($ast->type!='method'){
$xpn->parenthesisCount = $xpn->parenthesisCount + 1;
$xpn->push('declaration', '(');
$xpn->push('words', '(');
return;
}
$arglist = new \Tlf\Lexer\ArrayAst('method_arglist');
$ast->set('args', $arglist);
$xpn->push('declaration', '(');
$xpn->words = [];
$lexer->setHead($arglist);
}
public function op_arglist_close($lexer, $ast, $xpn) {
if ($xpn->parenthesisCount > 0){
$xpn->parenthesisCount = $xpn->parenthesisCount - 1;
$xpn->push('declaration', ')');
$xpn->push('words', ')');
// if ($xpn->parenthesisCount == 0){
// var_dump($xpn->getTree());
// exit;
// }
return;
}
$head = $lexer->getHead();
if ($head->type == 'method_arglist'){
$lexer->popHead();
} else if ($head->type == 'arg'){
$this->setArgDeclaration($ast);
$lexer->popHead();
} else if ($head->type == 'var_assign'){
$head->value = implode('', $xpn->words);
$lexer->popHead();
$this->setArgDeclaration($lexer->getHead());
$lexer->popHead();
}
$xpn->push('declaration', ')');
}
public function op_return_type($lexer, $ast, $xpn){
if ($lexer->getHead()->type=='method' || $lexer->getHead()->type=='function'){
$xpn->push('declaration',':');
$ast = new \Tlf\Lexer\ArrayAst('return_types');
$lexer->getHead()->set('return_types', $ast);
$lexer->setHead($ast);
}
}
}