Lexer2.php
<?php
namespace Tlf;
class Lexer2 {
public Lexer2\Program $program;
public Lexer2\Buffer $buffer;
public function __construct(){
$this->program = new \Tlf\Lexer2\Program();
$this->program->addLanguage(new \Tlf\Lexer2\Language\StdLibLanguage());
}
/**
* Add code to the Program using a generic Language with no StdLib.
* (The Lexer's StdLib is already added to the Program)
*
* @param $parser_code string parser code
* @param $namespace string the namespace of your code
*
* @return array ast of the parser_code. @see Tlf\Lexer2\Parser
*/
public function addCode(string $parser_code, string $namespace): array {
$generic_language = new \Tlf\Lexer2\Language\GenericLanguage($parser_code, $namespace);
$this->program->addLanguage($generic_language);
return $generic_language->get_directives();
}
/**
* Add a language to the Program.
*
* @param $language
*/
public function addLanguage(\Tlf\Lexer2\Language $language): array {
$this->program->addLanguage($language);
return $language->get_directives();
}
/**
* Get an AST from input text, by executing loaded code.
*/
public function parse(string $input_text): \Tlf\Lexer2\Ast {
$this->buffer = new \Tlf\Lexer2\Buffer($input_text);
$stdlib_main = new \Tlf\Lexer2\StdLib\Main($this->program);
$stdlib_buffer = new \Tlf\Lexer2\StdLib\Buffer($this->program, $this->buffer);
$stdlib_head = new \Tlf\Lexer2\StdLib\AstHead($this->program);
$this->program->setObject('head', $stdlib_head);
$this->program->setObject('buffer', $stdlib_buffer);
$this->program->setObject('StdLib', $stdlib_main);
$this->program->setObject('lexer', $this);
$languages = [];
foreach ($this->program->languages as $l_meta){
$language = $l_meta['language'];
$directives = $l_meta['initial_directives'];
$languages[] = ['language'=>get_class($language), 'initial_directives'=>$directives];
}
$root_ast = new \Tlf\Lexer2\Ast('Program',
['input'=>$input_text,
'input_type'=>'string',
'context'=>[
'git_origin_url' => shell_exec("git remote get-url origin"),
'git_hash' => shell_exec("git rev-parse --short HEAD"),
'languages'=> $languages,
]
],
);
$this->program->ast_stack[] = $root_ast;
$this->program->will_execute_command_hooks[] = [$stdlib_buffer, 'store_state'];
$this->program->initialize();
$loop_count = 0;
// terminal color codes from https://gitlab.com/taeluf/bash/cli/-/blob/v0.1/code/lib/colors.bash?ref_type=heads
while ($this->buffer->next()){
$this->print_loop_and_buffer_status($this->buffer, $loop_count++);
$this->program->execute();
}
return $this->program->ast_stack[0];
}
/** print newlines as literal `\n` so they can be read in the terminal without actually causing a newline */
protected function make_newlines_printable(string $dirty_text): string {
return str_replace(["\r","\n"], ["\\r", "\\n"], $dirty_text);
}
public function print_loop_and_buffer_status(\Tlf\Lexer2\Buffer $buffer, int $loop_count){
$color_off = "\033[0m";
$color_black = "\033[1;30m";
$bg_yellow = "\033[0;103m";
echo "\n\n\033[42m$color_black ### Loop $loop_count ### $color_off";
echo "\n \033[4;32mBUFFER INFO$color_off ";
echo "\n Add Char: $bg_yellow$color_black ".
$this->make_newlines_printable(substr($buffer->buffer(),-1)." $color_off");
echo "\n Current Buffer: $bg_yellow$color_black"
. $this->make_newlines_printable(
$buffer->buffer()
). $color_off;
echo "\n Buffer Length: ".strlen($buffer->buffer());
$next_five = $this->make_newlines_printable(
substr($buffer->remainder(),0,5)
);
if (($len = strlen($next_five)) < 5){
$next_five .= "\033[41m". str_repeat(" ", 5-$len);
}
echo "\n Next 5 Chars: \033[0;103m$color_black"
.$next_five
. "$color_off"
;
}
}