Buffer.php

<?php

namespace Tlf\Lexer2\StdLib;

/**
 * An interface for programs to interact with the AST on the top of the ast stack.
 */
class Buffer {

    public \Tlf\Lexer2\Buffer $stored_buffer;

    public function __construct(
        protected \Tlf\Lexer2\Program $program,
        protected \Tlf\Lexer2\Buffer $buffer,
    ){

    }

    /**
     * Stop execution if the current buffer does not end with $text
     */
    public function ends_with(string $text): bool {
        if ($this->buffer->ends_with($text))return true;

        $this->program->execute_commands = false;
        return false;
    }

    /**
     * Clears the buffer. Does not change any other state.
     */
    public function clear() {
        $this->buffer->clearBuffer();
    }


    /**
     * Prepend one or more spaces to the left side of the current buffer
     */
    public function padLeft(int $num_spaces = 1) { 
        $this->buffer->prepend(str_repeat(" ", $num_spaces));
    }

    /**
     * Remove characters from the left of the buffer
     */
    public function removeLeft(int $num_chars_to_remove = 1){
        $this->buffer->removeLeft($num_chars_to_remove);
    }

    /**
     * If the current buffer does not match the $string_or_pattern, stop execution of the current instruction set.
     * Sets local variables from each match
     *
     * @param $string_or_pattern a string or regex pattern. Any string starting and ending with `/` will be treated as regex.
     *
     * @return bool whether the current buffer matches or not
     */
    public function match(string $string_or_pattern): bool {
        //echo "\nbuffer.match $string_or_pattern";
        //echo "\n  CurBuffer: '".$this->buffer->buffer()."'";

        if ($string_or_pattern[0] == '/' 
            && $string_or_pattern[-1] == '/'){
            $does_match = preg_match($string_or_pattern, $this->buffer->buffer(), $matches);
        } else {
            $does_match = $this->buffer->buffer() == $string_or_pattern;

            if ($does_match) $matches = [$string_or_pattern];
        }

        if (!$does_match){
            $this->program->execute_commands = false;
            return false;
        }

        foreach ($matches as $index=>$match){
            $this->program->set_local_var($index, $match);
        }

        return true;
    }


    /**
     * Move the buffer forward by $num_chars
     *
     */
    public function next(int $num_chars = 1){
        $this->buffer->forward($num_chars);
    }

    /**
     * Remove characters from the right-most end of the Buffer.
     *
     */
    public function rewind(int $num_chars = 1){
        $this->buffer->rewind($num_chars);
    }


    /**
     * Store the buffer's current state. The next call to reset() will restore that state.
     * State is automatically stored before running each instruction set.
     */
    public function store_state(){
        $this->stored_buffer = clone $this->buffer;
    }
    /**
     * Reset the buffer to the stored state.
     * State is automatically stored before each instruction set is run.
     * State can be manually stored by calling buffer.store_state
     */
    public function reset(){
        $this->buffer = $this->stored_buffer;
        $this->program->objects['lexer']->buffer = $this->buffer;
        //$this->program->setObject('buffer', $this->buffer);
    }
}