/** * @param StreamInterface $stream * @param string|null $parentPass * * @return Stream */ public function parseStream(StreamInterface $stream, $parentPass = null) { $result = array(); while ($token = $stream->next()) { $result[] = $token; } // Looking for `$` pattern if ($result[count($result) - 1] instanceof TokenInterface && $result[count($result) - 1]->is('T_DOLLAR') && count($result) > 1) { $result[count($result) - 2] = new EndNode($this->parser->parseStream(new Stream(array($result[count($result) - 2])))->input()); array_pop($result); } unset($stream); return new Stream($result); }
/** * @param StreamInterface $stream * @param string|null $parentPass * * @throws ParserException * * @return Stream */ public function parseStream(StreamInterface $stream, $parentPass = null) { $blocksFound = 0; $stack = array(); $result = array(); while ($token = $stream->next()) { if (!$token instanceof TokenInterface) { if ($blocksFound === 0) { $result[] = $token; } else { $stack[] = $token; } continue; } // Looking for `[` pattern if ($token->is('T_LEFT_BRACKET')) { ++$blocksFound; if ($blocksFound > 1) { // We matched a nested parenthesis so we ignore it $stack[] = $token; } } elseif ($blocksFound > 0 && $token->is('T_RIGHT_BRACKET')) { if ($blocksFound === 1) { $result[] = new BlockNode($this->parser->parseStream(new Stream($stack), 'BracketBlockParserPass', array('BracketBlockParserPass'))->input()); $stack = array(); } else { $stack[] = $token; } --$blocksFound; } elseif ($blocksFound > 0) { $stack[] = $token; } elseif ($blocksFound === 0 && $token->is('T_RIGHT_BRACKET')) { throw new ParserException('Bracket block not opened'); } else { $result[] = $token; } } if ($blocksFound > 0) { throw new ParserException('Bracket block not closed'); } unset($stream); return new Stream($result); }
/** * @param StreamInterface $stream * @param string|null $parentPass * * @throws ParserException * * @return Stream */ public function parseStream(StreamInterface $stream, $parentPass = null) { $commentFound = false; $stack = array(); $result = array(); while ($token = $stream->next()) { if ($stream->cursor() < 2 || !$token instanceof TokenInterface) { $result[] = $token; continue; } // Looking for `(?#` pattern if ($token->is('T_POUND') && $stream->readAt(-1)->is('T_QUESTION') && $stream->readAt(-2)->is('T_LEFT_PARENTHESIS') && !$commentFound) { $commentFound = true; // We remove (? from result array_pop($result); array_pop($result); } elseif ($commentFound && $token->is('T_RIGHT_PARENTHESIS')) { // $stack contains our comment but we don't keep it $commentFound = false; $stack = array(); } elseif ($commentFound) { $stack[] = $token; } else { $result[] = $token; } } if ($commentFound) { throw new ParserException('Comment not closed'); } unset($stream); return new Stream($result); }
/** * @param StreamInterface $stream * @param string|null $parentPass * * @throws ParserException * * @return Stream */ public function parseStream(StreamInterface $stream, $parentPass = null) { $result = array(); while ($token = $stream->next()) { if (!$token instanceof TokenInterface) { $result[] = $token; continue; } // Looking for `*-*` pattern if ($token->is('T_PIPE')) { if ($stream->cursor() < 1 || !$stream->hasNext()) { throw new ParserException('Alternative must have a previous and a next token'); } if ($result[count($result) - 1] instanceof AlternativeNode) { if ($stream->readAt(1) instanceof TokenInterface) { $result[count($result) - 1]->appendChild(new TokenNode($stream->next())); } else { $result[count($result) - 1]->appendChild($stream->next()); } continue; } // Remove previous array_pop($result); $previous = $stream->readAt(-1); if ($previous instanceof TokenInterface) { $previous = new TokenNode($previous); } $next = $stream->next(); if ($next instanceof TokenInterface) { $next = new TokenNode($next); } $result[] = new AlternativeNode(array($previous, $next)); } else { $result[] = $token; } } unset($stream); return new Stream($result); }
/** * @param StreamInterface $stream * @param string|null $parentPass * * @return Stream */ public function parseStream(StreamInterface $stream, $parentPass = null) { $result = array(); while ($token = $stream->next()) { if (!$token instanceof TokenInterface) { $result[] = $token; continue; } // Looking for `^` pattern if ($token->is('T_HAT') && $stream->cursor() === 0) { if ($parentPass === 'BracketBlockParserPass') { $childNodes = $stream->input(); array_shift($childNodes); // Remove ^ return new Stream(array(new ExclusionNode($this->parser->parseStream(new Stream($childNodes), 'BracketBlockParserPass', array('BracketBlockParserPass'))->input()))); } $result[] = new BeginNode($this->parser->parseStream(new Stream(array($stream->next())))->input()); } else { $result[] = $token; } } unset($stream); return new Stream($result); }
/** * @param StreamInterface $stream * @param string|null $parentPass * * @throws ParserException * * @return Stream */ public function parseStream(StreamInterface $stream, $parentPass = null) { $blockFound = false; $stack = array(0 => array(), 1 => array()); $step = 0; $result = array(); while ($token = $stream->next()) { if (!$token instanceof TokenInterface) { $result[] = $token; continue; } // Looking for `*` pattern if ($token->is('T_MULTIPLY')) { if ($stream->cursor() < 1) { throw new ParserException('A repetition pattern must follow a token'); } // We remove the last token array_pop($result); $child = $stream->readAt(-1); if ($child instanceof TokenInterface) { $child = new TokenNode($child); } $result[] = new RepetitionNode(0, null, array($child)); // We reinject the current node into the stream to handle case like +? and so on... $stream->replace($stream->cursor(), $result[count($result) - 1]); } elseif ($token->is('T_PLUS')) { // Looking for `+` pattern if ($stream->cursor() < 1) { throw new ParserException('A repetition pattern must follow a token'); } // We remove the last token array_pop($result); $child = $stream->readAt(-1); if ($child instanceof TokenInterface) { $child = new TokenNode($child); } $result[] = new RepetitionNode(1, null, array($child)); // We reinject the current node into the stream to handle case like +? and so on... $stream->replace($stream->cursor(), $result[count($result) - 1]); } elseif ($token->is('T_QUESTION')) { // Looking for `?` pattern if ($stream->cursor() < 1) { throw new ParserException('A repetition pattern must follow a token'); } // We remove the last token array_pop($result); $child = $stream->readAt(-1); if ($child instanceof TokenInterface) { $child = new TokenNode($child); } $result[] = new RepetitionNode(0, 1, array($child)); // We reinject the current node into the stream to handle case like +? and so on... $stream->replace($stream->cursor(), $result[count($result) - 1]); } elseif ($token->is('T_LEFT_BRACE')) { if ($stream->cursor() < 1) { throw new ParserException('A repetition pattern must follow a token'); } $blockFound = true; } elseif ($blockFound && $token->is('T_INTEGER')) { $stack[$step][] = $token; } elseif ($blockFound && $step === 0 && $token->is('T_COMMA')) { ++$step; } elseif ($blockFound && $token->is('T_RIGHT_BRACE')) { $blockFound = false; array_pop($result); $min = (int) implode('', array_map(function ($t) { return $t->getValue(); }, $stack[0])); if (count($stack[1]) > 0) { $max = (int) implode('', array_map(function ($t) { return $t->getValue(); }, $stack[1])); if ($max !== null && $min >= $max) { throw new ParserException('Min must be greater than max in a repetition pattern'); } $offset = 3; // +3 because of {,} } else { $max = $min; $offset = 2; // +3 because of {} } $child = $stream->readAt(-(count($stack[0]) + count($stack[1]) + $offset)); if ($child instanceof TokenInterface) { $child = new TokenNode($child); } $result[] = new RepetitionNode($min, $max, array($child)); $stack = array(0 => array(), 1 => array()); $step = 0; // We reinject the current node into the stream to handle case like +? and so on... $stream->replace($stream->cursor(), $result[count($result) - 1]); } elseif ($blockFound) { throw new ParserException('Invalid token in repetition pattern'); } else { $result[] = $token; } } unset($stream); return new Stream($result); }
/** * @param StreamInterface $stream * @param string|null $parentPass * * @return Stream */ public function parseStream(StreamInterface $stream, $parentPass = null) { $result = array(); $used = array(); while ($token = $stream->next()) { if ($stream->cursor() < 1 || !$token instanceof TokenInterface) { $result[] = $token; continue; } // Looking for `*-*` pattern if ($token->is('T_MINUS') && $stream->readAt(-1) instanceof TokenInterface && $stream->readAt(1) instanceof TokenInterface && !in_array($stream->cursor() - 1, $used) && $this->isPreviousNextTokenValid($stream->readAt(-1), $stream->readAt(1), $parentPass)) { // Remove * array_pop($result); $used[] = $stream->cursor(); $used[] = $stream->cursor() - 1; $used[] = $stream->cursor() + 1; $result[] = new CharacterClassNode(new TokenNode($stream->readAt(-1)), new TokenNode($stream->readAt(1))); $stream->next(); } else { $result[] = $token; } } unset($stream); return new Stream($result); }