/** * @param \Carrooi\Tokenizer\Parsing\Lexer $lexer * @return int */ function match(Lexer $lexer) { $tokens = []; foreach ($this->tokens as $token) { if ($token instanceof AbstractModifier || $token instanceof Matcher) { $token = $this->builder->_matchToken($lexer, $token); if (is_array($token) && Helpers::isListOfValidTokens($token)) { return $token; } elseif ($token !== false) { $tokens[] = $token; } } else { $tokens[] = $token; } } if (!$lexer->isNextToken($tokens)) { return false; } $result = []; while (true) { $peek = $lexer->peek(); if (!$peek) { break; } if (Helpers::isTokenA($peek['type'], $tokens)) { $result[] = $peek; } else { $lexer->resetPeek(); break; } } return count($result) ? $result : false; }
/** * @param \Carrooi\Tokenizer\Parsing\Lexer $lexer * @return array|bool */ function match(Lexer $lexer) { $startToken = $this->startToken instanceof AbstractModifier ? $this->builder->_matchToken($lexer, $this->startToken) : $this->startToken; $endToken = $this->endToken instanceof AbstractModifier ? $this->builder->_matchToken($lexer, $this->endToken) : $this->endToken; if (!$lexer->isNextToken($startToken)) { return false; } $openings = 0; $result = []; while (true) { $peek = $lexer->peek(); if (!$peek) { break; } if (Helpers::isTokenA($peek['type'], $startToken)) { $openings++; if ($openings > 1 && $this->recursive) { $subTokens = array_slice($lexer->tokens, $lexer->position + $lexer->peekPosition - 1); $subLexer = new Lexer($subTokens); $parenthesis = $this->match($subLexer); if (!$parenthesis) { return false; } $moveTo = $subLexer->peekPosition - 1; for ($i = 0; $i < $moveTo; $i++) { $lexer->peek(); } $openings--; $result[] = $parenthesis; } else { $result[] = $peek; } } else { $result[] = $peek; if (Helpers::isTokenA($peek['type'], $endToken) && --$openings < 1) { break; } } } return count($result) ? $result : false; }
/** * @param int|array $type * @param int|array|null $stopAt * @return bool */ public function skipUntil($type, $stopAt = null) { $type = is_array($type) ? $type : [$type]; $stopAt = is_array($stopAt) ? $stopAt : ($stopAt ? [$stopAt] : []); while ($this->lookahead !== null && !Helpers::isTokenA($this->lookahead['type'], $type) && (empty($stopAt) || !Helpers::isTokenA($this->token['type'], $stopAt))) { $this->moveNext(); } return $this->lookahead && Helpers::isTokenA($this->lookahead['type'], $type); }
/** * @param array $result * @param array $match * @return array */ private function mergeMatchToResult(array $result, $match) { if (is_array($match) && Helpers::isValidToken($match)) { $result[] = $match; } elseif (is_array($match)) { $result = array_merge($result, $match); } return $result; }
/** * @return \Carrooi\Tokenizer\Matching\Matcher */ public function classDeclaration() { $typeMatcher = new Matcher(); $typeMatcher->select($typeMatcher->expr()->anyOf(Lexer::T_FINAL, Lexer::T_ABSTRACT), Lexer::T_WHITESPACE); $extendsMatcher = new Matcher(); $extendsMatcher->select(Lexer::T_WHITESPACE, Lexer::T_EXTENDS, Lexer::T_WHITESPACE, $this->className()); $implementsDelimiterMatcher = new Matcher(); $implementsDelimiterMatcher->select($implementsDelimiterMatcher->expr()->notRequired(Lexer::T_WHITESPACE), Lexer::T_COMMA, $implementsDelimiterMatcher->expr()->notRequired(Lexer::T_WHITESPACE)); $implementsMatcher = new Matcher(); $implementsMatcher->select(Lexer::T_WHITESPACE, Lexer::T_IMPLEMENTS, Lexer::T_WHITESPACE, $implementsMatcher->expr()->listOf($implementsDelimiterMatcher, $this->className())); $matcher = new Matcher(); $matcher->select($matcher->expr()->notRequired($typeMatcher), Lexer::T_CLASS, Lexer::T_WHITESPACE, Lexer::T_STRING, $matcher->expr()->notRequired($extendsMatcher), $matcher->expr()->notRequired($implementsMatcher)); $matcher->map(new ResultMapping(function (array $tokens) { $class = new ClassDeclaration(Helpers::flattenTokens($tokens), $tokens[3]['value']); if ($tokens[0]) { if ($tokens[0][0]['type'] === Lexer::T_FINAL) { $class->final = true; } if ($tokens[0][0]['type'] === Lexer::T_ABSTRACT) { $class->abstract = true; } } if ($tokens[4] && $tokens[4][3]) { $class->extends = $tokens[4][3]; } if ($tokens[5]) { $implements = array_slice($tokens[5], 3); $implements = array_filter($implements, function ($token) { return $token instanceof ClassNameExpression; }); $class->implements = array_values($implements); } return $class; })); return $matcher; }
/** * @param \Carrooi\Tokenizer\Parsing\Lexer $lexer * @param mixed $select * @return bool|array|null */ public function _matchToken(Lexer $lexer, $select) { $match = false; if (is_int($select)) { $match = $lexer->isNextToken($select); } elseif ($select instanceof Matcher) { $tokens = array_slice($lexer->tokens, $lexer->position); $match = [$select->match($tokens)]; } elseif ($select instanceof AbstractModifier) { $match = $select->match($lexer); $lexer->resetPeek(); } if ($match === true) { $match = $lexer->lookahead; $lexer->moveNext(); } elseif ($match) { $lastToken = Helpers::getLastToken($match); if ($lastToken) { Helpers::moveLexerToToken($lexer, $lastToken); } } return $match; }