/
home
/
assocoweys
/
khata
/
plugins
/
system
/
nrframework
/
NRFramework
/
Parser
/
Upload File
HOME
<?php /** * @author Tassos.gr <info@tassos.gr> * @link https://www.tassos.gr * @copyright Copyright © 2024 Tassos All Rights Reserved * @license GNU GPLv3 <http://www.gnu.org/licenses/gpl.html> or later */ namespace NRFramework\Parser; defined('_JEXEC') or die; use NRFramework\Parser\Lexer; /** * ShortcodeLexer * * Tokenizes a string using the following grammar. * Acts as the input "stream" for NRFramework\Parser\ShortcodeParser * * Tokens: * ------- * sc_open : shortcode tag opening character(s), default: { * sc_close : shortcode tag closing character(s), default: } * if_keyword : if keyword, default: 'if' * endif_keyword : endif keyword, default: '/if' * text : any character sequence * text_preserved : any character sequence with quoted values preserved * whitespace : ' ' | '\r' | '\n' | '\t' */ class ShortcodeLexer extends Lexer { /** * Shortcode opening character(s) (default: {) * * @var string */ protected $sc_open_char; /** * Shortcode closing character(s) (default: }) * * @var string */ protected $sc_close_char; /** * if keyword (default: 'if') * * @var string */ protected $if_keyword; /** * endif keyword (default: '/if') * * @var string */ protected $endif_keyword; /** * ShortcodeLexer constructor * * @param string $input * @param object $options */ public function __construct($input, $options = null) { parent::__construct($input); $this->tokens->addType('sc_open'); $this->tokens->addType('sc_close'); $this->tokens->addType('if_keyword'); $this->tokens->addType('endif_keyword'); $this->tokens->addType('char'); $this->sc_open_char = $options->tag_open_char ?? '{'; $this->sc_close_char = $options->tag_close_char ?? '}'; $this->if_keyword = $options->if_keyword ?? 'if'; $this->endif_keyword = '/' . $this->if_keyword; } /** * Returns the next token from the input string * * @return RestrictContent\Parser\Token */ public function nextToken() { static $if_flag = false; while ($this->cur !== Lexer::EOF) { if ($this->state->skip_whitespace && preg_match('/\s+/', $this->cur)) { $this->whitespace(); continue; } if ($this->predictScOpen()) { $this->setTokenizeContentState(false); $this->setSkipWhitespaceState(true); return $this->sc_open(); } else if ($this->predictScClose()) { $this->setTokenizeContentState(true); $this->setSkipWhitespaceState(false); return $this->sc_close(); } // check for if/endif else if ($this->predictIf(false)) { return $this->_if(); } else if ($this->predictEndif(false)) { return $this->_endif(); } // check for text else { $preserve_quoted_values = !$this->getTokenizeContentState(); $token = $this->text($preserve_quoted_values); return $token; } } // return EOF token at the end of stream return $this->tokens->create('EOF', '<EOF>', -1); } /** * Predicts an upcoming 'if' keyword from the input stream * * @param bool $reset Reset to the marked position when the keyword is found * @return bool */ protected function predictIf($reset = true) { $this->mark(); $tmp = $this->consume(2); if ($tmp === $this->if_keyword) { if ($reset) { $this->reset(); } return true; } $this->reset(); return false; } /** * Predicts an upcoming 'endif' keyword from the input stream * * @param bool $reset Reset to the marked position when the keyword is found * @return bool */ protected function predictEndif($reset = true) { $this->mark(); $tmp = $this->consume(3); if ($tmp === $this->endif_keyword) { if ($reset) { $this->reset(); } return true; } $this->reset(); return false; } /** * Predicts any upcoming keyword * * @return bool */ protected function predictKeywords() { return $this->predictIf() || $this->predictEndif(); } /** * Predicts any upcoming special character * * @return bool */ protected function predictSpecialChars() { return $this->predictScOpen() || $this->predictScClose(); } /** * Predicts upcoming shortcode opening character(s), default: { * * @return bool */ protected function predictScOpen() { $sc_length = \strlen($this->sc_open_char); $res = false; $this->mark(); $tmp = $this->consume($sc_length); if ($tmp === $this->sc_open_char) { $res = true; } $this->reset(); return $res; } /** * Predicts upcoming shortcode closing character(s), default: { * * @return bool */ protected function predictScClose() { $sc_length = \strlen($this->sc_close_char); $res = false; $this->mark(); $tmp = $this->consume($sc_length); if ($tmp === $this->sc_close_char) { $res = true; } $this->reset(); return $res; } /** * sc_open : shortcode tag opening character, default: { * * @return Token */ protected function sc_open() { $pos = $this->index; $length = \strlen($this->sc_open_char); $this->consume($length); return $this->tokens->create('sc_open', $this->sc_open_char, $pos); } /** * sc_close : shortcode tag closeing character, default: } * * @return Token */ protected function sc_close() { $pos = $this->index; $length = \strlen($this->sc_close_char); $this->consume($length); return $this->tokens->create('sc_close', $this->sc_close_char, $pos); } /** * if_keyword, default: 'if' * * @return Token */ protected function _if() { return $this->tokens->create('if_keyword', $this->if_keyword, $this->index - \strlen($this->if_keyword)); } /** * endif_keyword, default: '/if' * * @return Token */ protected function _endif() { return $this->tokens->create('endif_keyword', $this->endif_keyword, $this->index - \strlen($this->endif_keyword)); } /** * text : any character sequence * * @param bool $preserve Preserve keywords and special characters inside quotes * @return Token */ protected function text($preserve) { if ($preserve) { return $this->text_preserved(); } $pos = $this->index; $buf = ''; while ($this->cur !== Lexer::EOF) { if ($this->predictKeywords() || $this->predictSpecialChars()) { return $this->tokens->create('text', $buf, $pos); } $buf .= $this->cur; $this->consume(); } return $this->tokens->create('EOF', '<EOF>', -1); } /** * text_preserved : any character sequence with quoted values preserved * * @return Token */ protected function text_preserved() { $quote_queue = []; $buf = ''; $pos = $this->index; while ($this->cur !== Lexer::EOF) { // manage quote parsing if ($this->cur == '"' || $this->cur == "'") { if ($this->cur == end($quote_queue)) { // remove last added quote array_pop($quote_queue); } else { // add quote to the queue array_push($quote_queue, $this->cur); } } // End parsing when any keyword or special character is found // handles quoted values if ($this->predictKeywords() || $this->predictSpecialChars()) { // return the expression's text if no quotes are open if (empty($quote_queue)) { return $this->tokens->create('text_preserved', trim($buf), $pos); } } // add current character to buffer $buf .= $this->cur; $this->consume(); } return $this->tokens->create('EOF', '<EOF>', -1); } }