/** * @param array $tokens * @param null $stack * @param null $exitToken * @return bool * @throws LexerException * @internal param bool $allowBlocks */ protected function tokenizeByTokens(array $tokens, &$stack = null, $exitToken = null) { // If any tokens found $any = false; // Stack for opened parenthesis,closures and brackets if (!$stack) { $stack = []; } $n = 0; do { // Check for exit if ($exitToken && empty($stack) && $this->reader->strippedMatch($exitToken) !== false) { break; } // Strip white spaces $this->stripSpaces(); // Found flag $found = false; foreach ($tokens as $tokenType => $regexp) { $mustComeAfter = null; if (is_array($regexp)) { list($regexp, $mustComeAfter) = $regexp; } if ($mustComeAfter && !in_array($this->tokens->last()->getType(), $mustComeAfter)) { continue; } if (empty($regexp)) { $this->throwException('Regex for token "%s" is empty', $this->getTokenName($tokenType)); } if (($name = $this->reader->matchAndGo($regexp)) !== false) { // Empty token if (strlen($name) == 0) { $this->throwException('Invalid language token `%s`', $regexp); } // Open context token if ($this->isOpenToken($tokenType)) { $stack[] = $this->getCloseToken($tokenType); } elseif (end($stack) == $tokenType) { array_pop($stack); } elseif ($this->isCloseToken($tokenType) && end($stack) != $tokenType) { $this->throwException('Unexpected close token `%s`, `%s` expected', $name, end($stack)); } // Add token to tokens collections $this->addToken($name, $tokenType); // Set found flag $any = $found = true; break; } } # Check infinite loop if ($n++ > 50) { $this->throwException('Infinite loop %d', $found); } } while (!$this->reader->isEnd() && $found); # Stack $this->checkStack($stack); return $any; }
/** * @DataMapper\Object() * @return Token */ public function getLastToken() { return $this->tokens->last(); }
/** * @param Token $token */ public function removeToken(Token $token) { $this->tokens->removeElement($token); }