private function match(string $input, int $pos, array $preferredTokens): ?Match
    {
        $current_regexp = $this->getRegexpForTokens($preferredTokens);

        if (false === preg_match($current_regexp, $input, $match, 0, $pos)) {
            $error_code = preg_last_error();
            throw new \RuntimeException(
                "PCRE error #" . $error_code
                . " for token at input pos $pos; REGEXP = $current_regexp",
                $error_code
            );
        }

        if (!$match) {
            return null;
        }

        $full_match = $match[0];
        if ('' === $full_match) {
            throw new DevException(
                'Tokens should not match empty string'
                . '; context: `' . substr($input, $pos, 10) . '`'
                . '; expected: ' . json_encode($preferredTokens)
                . "; REGEXP: $current_regexp"
            );
        }

        // remove null, empty "" values and integer keys but [0]
        foreach ($match as $key => $value) {
            if (
                null === $value
                || '' === $value
                || (0 !== $key && is_int($key))
            ) {
                unset($match[$key]);
            }
        }

        $named = $match;
        unset($named[0]);
        if (1 !== count($named)) {
            throw new InternalException('Match with multiple named group');
        }

        $content = reset($named);
        $type = key($named);
        $is_inline = false;
        if (isset($this->aliased[$type])) {
            $type = $this->aliased[$type];
            $is_inline = true;
        }
        $token = new Token($type, $content, $match, $pos, $is_inline);

        $result = new Match();
        $result->token = $token;
        $result->nextOffset = $pos + strlen($full_match);

        return $result;
    }
private function match(string $input, int $pos, array $preferredTokens): ?Match
    {
        $current_regexp = $this->getRegexpForTokens($preferredTokens);

        if (false === preg_match($current_regexp, $input, $match, 0, $pos)) {
            $error_code = preg_last_error();
            throw new \RuntimeException(
                "PCRE error #" . $error_code
                . " for token at input pos $pos; REGEXP = $current_regexp",
                $error_code
            );
        }

        if (!$match) {
            return null;
        }

        $full_match = $match[0];
        if ('' === $full_match) {
            throw new DevException(
                'Tokens should not match empty string'
                . '; context: `' . substr($input, $pos, 10) . '`'
                . '; expected: ' . json_encode($preferredTokens)
                . "; REGEXP: $current_regexp"
            );
        }

        // remove null, empty "" values and integer keys but [0]
        foreach ($match as $key => $value) {
            if (
                null === $value
                || '' === $value
                || (0 !== $key && is_int($key))
            ) {
                unset($match[$key]);
            }
        }

        $named = $match;
        unset($named[0]);
        if (1 !== count($named)) {
            throw new InternalException('Match with multiple named group');
        }

        $content = reset($named);
        $type = key($named);
        $is_inline = false;
        if (isset($this->aliased[$type])) {
            $type = $this->aliased[$type];
            $is_inline = true;
        }
        $token = new Token($type, $content, $match, $pos, $is_inline);

        $result = new Match();
        $result->token = $token;
        $result->nextOffset = $pos + strlen($full_match);

        return $result;
    }
private function match ( string $ input , int $ pos , array $ preferredTokens ) : ? Match { $ current_regexp = $ this -> getRegexpForTokens ( $ preferredTokens ) ; if ( false === preg_match ( $ current_regexp , $ input , $ match , 0 , $ pos ) ) { $ error_code = preg_last_error ( ) ; throw new \ RuntimeException ( "PCRE error #" . $ error_code . " for token at input pos $pos; REGEXP = $current_regexp" , $ error_code ) ; } if ( ! $ match ) { return null ; } $ full_match = $ match [ 0 ] ; if ( '' === $ full_match ) { throw new DevException ( 'Tokens should not match empty string' . '; context: `' . substr ( $ input , $ pos , 10 ) . '`' . '; expected: ' . json_encode ( $ preferredTokens ) . "; REGEXP: $current_regexp" ) ; } // remove null, empty "" values and integer keys but [0] foreach ( $ match as $ key => $ value ) { if ( null === $ value || '' === $ value || ( 0 !== $ key && is_int ( $ key ) ) ) { unset ( $ match [ $ key ] ) ; } } $ named = $ match ; unset ( $ named [ 0 ] ) ; if ( 1 !== count ( $ named ) ) { throw new InternalException ( 'Match with multiple named group' ) ; } $ content = reset ( $ named ) ; $ type = key ( $ named ) ; $ is_inline = false ; if ( isset ( $ this -> aliased [ $ type ] ) ) { $ type = $ this -> aliased [ $ type ] ; $ is_inline = true ; } $ token = new Token ( $ type , $ content , $ match , $ pos , $ is_inline ) ; $ result = new Match ( ) ; $ result -> token = $ token ; $ result -> nextOffset = $ pos + strlen ( $ full_match ) ; return $ result ; }
Search a match in input text at a position

Search is performed by `parse()` after `compile()` call. Match is searched
exactly in the given position by `\G`.
@param string $input Input text to search where
@param int $pos Position inthe text to match where
@param string[] $preferredTokens Preferred tokens types to match first
@return Match|null Match object on success match. `null` if no match found.
@throws \RuntimeException Error from PCRE
@throws DevException Error by end developer in lexer configuration
@throws InternalException Error in the package
Search a match in input text at a position