/** * Handles a repetition token * * @param Token $token Token * * @return void */ protected function _handleRepetition(Token $token) { //If there is no current item, throw exception if ($this->_currentItem === null) { throw new Exception\InvalidRepetition("Nothing to repeat"); } //Repetitions are allowed only after certain tokens, so check the last //emitted token $lastToken = $this->_tokensStack->top(); switch ($lastToken->getType()) { //Handle lazy repetition case Token::TYPE_REPETITION: $prevLastToken = $this->_tokensStack->offsetGet(1); //if this token is "?" and follows a repetition token that //does not come after another repetition token set the lazy flag if ($token->getIdentifier() === "?" && $prevLastToken->getType() !== Token::TYPE_REPETITION) { //Check if last repetition supports the lazy flag $lastRepetition = $this->_currentItem->getRepetition(); if ($lastRepetition->supportsLazy()) { $lastRepetition->setLazy(true); } return; } else { throw new Exception\InvalidRepetition("Nothing to repeat"); } break; //Tokens that can handle the repetition //Tokens that can handle the repetition case Token::TYPE_NON_PRINTING_CHAR: case Token::TYPE_GENERIC_CHAR_TYPE: case Token::TYPE_CONTROL_CHAR: case Token::TYPE_EXT_UNICODE_SEQUENCE: case Token::TYPE_UNICODE_CHAR_CLASS: case Token::TYPE_HEX_CHAR: case Token::TYPE_DOT: case Token::TYPE_BYTE: case Token::TYPE_SUBPATTERN_END: case Token::TYPE_COMMENT: case Token::TYPE_OCTAL_CHAR: case Token::TYPE_BACK_REFERENCE: case Token::TYPE_CHAR_CLASS_END: case Token::TYPE_RECURSIVE_PATTERN: break; //When simple characters are grouped, repetition is valid only //for the last one, so it needs to be splitted so that the last //character belongs to a different object //When simple characters are grouped, repetition is valid only //for the last one, so it needs to be splitted so that the last //character belongs to a different object case Token::TYPE_CHAR: $chars = $this->_currentItem->getChar(); if (strlen($chars) > 1) { $this->_currentItem->setChar(substr($chars, 0, -1)); $this->_currentItem = new Pattern\Char($chars[strlen($chars) - 1]); $this->_containersStack->top()->addChild($this->_currentItem); } break; default: throw new Exception\InvalidRepetition("Repetition cannot be inserted at this point"); break; } //Get the right repetition class switch ($token->getIdentifier()) { case "*": $repetition = new Pattern\Repetition\ZeroOrMore(); break; case "+": $repetition = new Pattern\Repetition\OneOrMore(); break; case "?": $repetition = new Pattern\Repetition\Optional(); break; case "{": //Check if {} if (strpos($token->getSubject(), ",") === false) { $repetition = new Pattern\Repetition\Number($token->getSubject()); } else { $limits = explode(",", $token->getSubject()); $repetition = new Pattern\Repetition\Range($limits[0], $limits[1] === "" ? null : $limits[1]); } break; } //Set the repetition on the current item $this->_currentItem->setRepetition($repetition); }