diff --git a/.travis.yml b/.travis.yml index 99de817..d88c6f0 100644 --- a/.travis.yml +++ b/.travis.yml @@ -5,17 +5,27 @@ sudo: false matrix: include: - php: 5.2 + dist: precise - php: 5.3 + dist: precise - php: 5.4 + dist: trusty - php: 5.5 + dist: trusty - php: 5.6 - php: 7.0 - php: 7.1 + - php: 7.2 + - php: 7.3 + - php: 7.4snapshot - php: hhvm dist: trusty + allow_failures: + - php: hhvm + - php: 7.4snapshot script: - - '[[ "$TRAVIS_PHP_VERSION" = 5.2* ]] && phpunit || vendor/bin/phpunit --verbose' + - '[[ "$TRAVIS_PHP_VERSION" = 5.2* ]] && phpunit || vendor/bin/phpunit --verbose' install: - - '[[ "$TRAVIS_PHP_VERSION" = 5.2* ]] || composer install' + - '[[ "$TRAVIS_PHP_VERSION" = 5.2* ]] || composer install' diff --git a/src/Mustache/Engine.php b/src/Mustache/Engine.php index 9110977..fe99799 100644 --- a/src/Mustache/Engine.php +++ b/src/Mustache/Engine.php @@ -23,7 +23,7 @@ */ class Mustache_Engine { - const VERSION = '2.12.0'; + const VERSION = '2.13.0'; const SPEC_VERSION = '1.1.2'; const PRAGMA_FILTERS = 'FILTERS'; diff --git a/src/Mustache/Parser.php b/src/Mustache/Parser.php index c36a84a..0ec4192 100644 --- a/src/Mustache/Parser.php +++ b/src/Mustache/Parser.php @@ -149,7 +149,7 @@ class Mustache_Parser case Mustache_Tokenizer::T_BLOCK_VAR: if ($this->pragmaBlocks) { // BLOCKS pragma is enabled, let's do this! - if ($parent[Mustache_Tokenizer::TYPE] === Mustache_Tokenizer::T_PARENT) { + if (isset($parent) && $parent[Mustache_Tokenizer::TYPE] === Mustache_Tokenizer::T_PARENT) { $token[Mustache_Tokenizer::TYPE] = Mustache_Tokenizer::T_BLOCK_ARG; } $this->clearStandaloneLines($nodes, $tokens); @@ -275,7 +275,7 @@ class Mustache_Parser */ private function checkIfTokenIsAllowedInParent($parent, array $token) { - if ($parent[Mustache_Tokenizer::TYPE] === Mustache_Tokenizer::T_PARENT) { + if (isset($parent) && $parent[Mustache_Tokenizer::TYPE] === Mustache_Tokenizer::T_PARENT) { throw new Mustache_Exception_SyntaxException('Illegal content in < parent tag', $token); } } diff --git a/src/Mustache/Tokenizer.php b/src/Mustache/Tokenizer.php index b1f3d73..6dbe0cd 100644 --- a/src/Mustache/Tokenizer.php +++ b/src/Mustache/Tokenizer.php @@ -72,15 +72,20 @@ class Mustache_Tokenizer private $tokens; private $seenTag; private $line; + private $otag; - private $ctag; + private $otagChar; private $otagLen; + + private $ctag; + private $ctagChar; private $ctagLen; /** * Scan and tokenize template source. * * @throws Mustache_Exception_SyntaxException when mismatched section tags are encountered + * @throws Mustache_Exception_InvalidArgumentException when $delimiters string is invalid * * @param string $text Mustache template source to tokenize * @param string $delimiters Optionally, pass initial opening and closing delimiters (default: null) @@ -110,12 +115,13 @@ class Mustache_Tokenizer for ($i = 0; $i < $len; $i++) { switch ($this->state) { case self::IN_TEXT: - if ($this->tagChange($this->otag, $this->otagLen, $text, $i)) { + $char = $text[$i]; + // Test whether it's time to change tags. + if ($char === $this->otagChar && substr($text, $i, $this->otagLen) === $this->otag) { $i--; $this->flushBuffer(); $this->state = self::IN_TAG_TYPE; } else { - $char = $text[$i]; $this->buffer .= $char; if ($char === "\n") { $this->flushBuffer(); @@ -151,7 +157,9 @@ class Mustache_Tokenizer break; default: - if ($this->tagChange($this->ctag, $this->ctagLen, $text, $i)) { + $char = $text[$i]; + // Test whether it's time to change tags. + if ($char === $this->ctagChar && substr($text, $i, $this->ctagLen) === $this->ctag) { $token = array( self::TYPE => $this->tagType, self::NAME => trim($this->buffer), @@ -196,7 +204,7 @@ class Mustache_Tokenizer $this->state = self::IN_TEXT; $this->tokens[] = $token; } else { - $this->buffer .= $text[$i]; + $this->buffer .= $char; } break; } @@ -219,16 +227,20 @@ class Mustache_Tokenizer */ private function reset() { - $this->state = self::IN_TEXT; - $this->tagType = null; - $this->buffer = ''; - $this->tokens = array(); - $this->seenTag = false; - $this->line = 0; - $this->otag = '{{'; - $this->ctag = '}}'; - $this->otagLen = 2; - $this->ctagLen = 2; + $this->state = self::IN_TEXT; + $this->tagType = null; + $this->buffer = ''; + $this->tokens = array(); + $this->seenTag = false; + $this->line = 0; + + $this->otag = '{{'; + $this->otagChar = '{'; + $this->otagLen = 2; + + $this->ctag = '}}'; + $this->ctagChar = '}'; + $this->ctagLen = 2; } /** @@ -249,6 +261,8 @@ class Mustache_Tokenizer /** * Change the current Mustache delimiters. Set new `otag` and `ctag` values. * + * @throws Mustache_Exception_SyntaxException when delimiter string is invalid + * * @param string $text Mustache template source * @param int $index Current tokenizer index * @@ -260,28 +274,44 @@ class Mustache_Tokenizer $close = '=' . $this->ctag; $closeIndex = strpos($text, $close, $index); - $this->setDelimiters(trim(substr($text, $startIndex, $closeIndex - $startIndex))); - - $this->tokens[] = array( + $token = array( self::TYPE => self::T_DELIM_CHANGE, self::LINE => $this->line, ); + try { + $this->setDelimiters(trim(substr($text, $startIndex, $closeIndex - $startIndex))); + } catch (Mustache_Exception_InvalidArgumentException $e) { + throw new Mustache_Exception_SyntaxException($e->getMessage(), $token); + } + + $this->tokens[] = $token; + return $closeIndex + strlen($close) - 1; } /** * Set the current Mustache `otag` and `ctag` delimiters. * + * @throws Mustache_Exception_InvalidArgumentException when delimiter string is invalid + * * @param string $delimiters */ private function setDelimiters($delimiters) { - list($otag, $ctag) = explode(' ', $delimiters); - $this->otag = $otag; - $this->ctag = $ctag; - $this->otagLen = strlen($otag); - $this->ctagLen = strlen($ctag); + if (!preg_match('/^\s*(\S+)\s+(\S+)\s*$/', $delimiters, $matches)) { + throw new Mustache_Exception_InvalidArgumentException(sprintf('Invalid delimiters: %s', $delimiters)); + } + + list($_, $otag, $ctag) = $matches; + + $this->otag = $otag; + $this->otagChar = $otag[0]; + $this->otagLen = strlen($otag); + + $this->ctag = $ctag; + $this->ctagChar = $ctag[0]; + $this->ctagLen = strlen($ctag); } /** @@ -309,19 +339,4 @@ class Mustache_Tokenizer return $end + $this->ctagLen - 1; } - - /** - * Test whether it's time to change tags. - * - * @param string $tag Current tag name - * @param int $tagLen Current tag name length - * @param string $text Mustache template source - * @param int $index Current tokenizer index - * - * @return bool True if this is a closing section tag - */ - private function tagChange($tag, $tagLen, $text, $index) - { - return substr($text, $index, $tagLen) === $tag; - } }