Returns the first match with the list of terminals

@return array An array with the following keys:
[0] (string): name of the token
[1] (array): matches of the regular expression

@throws SyntaxErrorException If the line does not contain any token
481039
protected function match(string $line, int $lineNumber, int $offset) : array
    {
        $restLine = substr($line, $offset);

        foreach ($this->terminals as $pattern => $name) {
            if (preg_match($pattern, $restLine, $matches)) {
                return [
                    $name,
                    $matches,
                ];
            }
        }

        throw new SyntaxErrorException(sprintf('Lexer error: unable to parse "%s" at line %s.', $line, $lineNumber));
    }
93075
private function parseConnectionError(): array
    {
        $return = ['sql_state' => null, 'code' => null, 'message' => 'Unknown error.'];
        if ($error = error_get_last()) {
            $errorMessage = preg_replace('~mysqli::real_connect\(\): +\(.+\): +~', '', $error['message']);
            preg_match('~\((?<sql_state>[0-9A-Z]+)/(?<code>\d+)\)~', $error['message'], $match);
            if (isset($match['sql_state'], $match['code'])) {
                $return['sql_state'] = $match['sql_state'];
                switch ($match['code']) {
                    case '2002':
                        $return['message'] = sprintf('Unable to connect to MySQL server at "%s", '.
                            'could not translate host name "%s" to address.', $this->config['host'], $this->config['host']);
                        $return['sql_state'] = SqlState::OPPA_HOST_ERROR;
                        break;
                    case '1044':
                        $return['message'] = sprintf('Unable to connect to MySQL server at "%s", '.
                            'database "%s" does not exist.', $this->config['host'], $this->config['name']);
                        $return['sql_state'] = SqlState::OPPA_DATABASE_ERROR;
                        break;
                    case '1045':
                        $return['message'] = sprintf('Unable to connect to MySQL server at "%s", '.
                            'password authentication failed for user "%s".', $this->config['host'], $this->config['username']);
                        $return['sql_state'] = SqlState::OPPA_AUTHENTICATION_ERROR;
                        break;
                    default:
                        $return['message'] = $errorMessage .'.';
                }
            } else {
                $return['message'] = $errorMessage .'.';
                $return['sql_state'] = SqlState::OPPA_CONNECTION_ERROR;
            }
        }

        return $return;
    }
1142029
private function doParseTokens()
    {
        $tokens = array();

        while ($this->valid()) {
            while (ctype_space($this->current)) {
                // Skip spaces
                $this->next();
            }

            if ($this->valid()) {
                $tokens[] = $this->parseToken();
            }
        }

        return $tokens;
    }
919627
protected function consumeMatch()
    {

        //Make sure we don't consume matched newlines (We match for them sometimes)
        //We need the newLine tokens and don't want them consumed here.
        $match = $this->lastMatches[0] !== "\n" ? rtrim($this->lastMatches[0], "\n") : $this->lastMatches[0];

        return $this->consume($this->strlen($match));
    }
1202631
private function match($token)
    {
        if (!$this->lexer->isNextToken($token)) {
            throw SyntaxException::expectedToken(
                $this->lexer->getLiteral($token),
                null,
                $this->lexer
            );
        }

        return $this->lexer->moveNext();
    }
851450
public function tokens() {
		if ($this->success()) {
			// Get tokens of contained matcher
			if ($this->matched instanceof MatcherInterface) {
				return $this->matched->tokens();
			}
			
			// Allow children to store arrays of matches here
			elseif(\is_array($this->matched)) {
				return $this->matched;
			}
			
			// Default behaviour on success
			elseif ($this->matched instanceof Token) {
				return [ $this->matched ];
			}
		}
		
		// Fallback
		return [];
	}
322278
protected function getMatchTypes()
    {
        return array(self::EXACT_MATCH_TYPE, self::EXISTS_MATCH_TYPE, self::GREATER_THAN_MATCH_TYPE,
         self::LESS_THAN_MATCH_TYPE, self::SUBSTRING_MATCH_TYPE);
    }
1130998
public function getRegex()
    {
        if (null === $this->constraint) {
            $delim = $this->next instanceof Delimiter ? (string)$this->next : '';
            $this->constraint = sprintf('[^%s%s]++', preg_quote($this->default, ParserInterface::EXP_DELIM), $delim);
        }

        return $this->regex = sprintf('(?P<%s>%s)', $this->value, $this->constraint);
    }
966852
public function getNext()
    {
        if ($this->peeking) {
            $this->peeking = false;
            $this->used[] = $this->peeked;

            return $this->peeked;
        }

        if (!isset($this->tokens[$this->cursor])) {
            throw new InternalErrorException('Unexpected token stream end.');
        }

        return $this->tokens[$this->cursor++];
    }
363029
protected function getRegexes()
    {
        if (empty($this->regexList)) {
            $cacheKey = 'DeviceDetector-'.DeviceDetector::VERSION.'regexes-'.$this->getName();
            $cacheKey = preg_replace('/([^a-z0-9_-]+)/i', '', $cacheKey);
            $this->regexList = $this->getCache()->fetch($cacheKey);
            if (empty($this->regexList)) {
                $this->regexList = $this->getYamlParser()->parseFile(
                    $this->getRegexesDirectory().DIRECTORY_SEPARATOR.$this->fixtureFile
                );
                $this->getCache()->save($cacheKey, $this->regexList);
            }
        }
        return $this->regexList;
    }
1263524
protected function createInitialDefinition()
    {
        return [
            /*
             * Match against non-special characters. To explain the components of this:
             *
             * [^\\\\*\[?]+(?:\\\\.[^\\\\*\[?]*)*
             *  - This matches non-special (\*[?) characters. If it matches one, it'll permit it to be an escape
             *    (i.e. \) if a character exists after it (which may be "special"). This then returns to the previous
             *    matching pattern, repeating the same rules until a non-escaped "special" character is hit.
             *
             * (?:\\\\.[^\\\\*\[?]*)+
             *  - This immediately looks for escape characters, as the previous component of this regex requires for the
             *    initial character to be non-special. This then returns to the standard rules the previous regex.
             */
            '[^\\\\*\[?]+(?:\\\\.[^\\\\*\[?]*)*|(?:\\\\.[^\\\\*\[?]*)+' => self::T_WORD,
            // Simple match of "*"
            '\*' => self::T_WILDCARD_MULTI,
            // Simple match of "?"
            '\?' => self::T_WILDCARD_SINGLE,
            /*
             * Matches against [. This also optionally matches "!" or "^" as the first character to provide negation
             * context. The positive lookahead provides a means to check for "]" as the first character. This is a
             * slightly nasty hack to deal with a rule that "]" can be permitted as a standard character in a character,
             * grouping so long as it's the first character. Once we move into the IN_GROUP state we have no such
             * context, so it must be checked at this level. To achieve this we lookahead for the character, and ensure
             * it's captured by adding a capturing group inside (regex lookarounds do not capture).
             */
            '\[([!^]?)(?=(\])?)' => function (Stateful $lexer, $matches) {
                // Determine the state to enter (depending on whether the lookahead succeeded, i.e. "]" is the first
                // character of the grouping)
                $state = isset($matches[2])
                    ? 'IN_GROUP_SPECIAL_FIRST'
                    : 'IN_GROUP';

                $lexer->pushState($state);

                // Negated grouping if the first character is "!"
                return $matches[1] !== ''
                    ? self::T_GROUP_BEGIN_NEGATED
                    : self::T_GROUP_BEGIN;
            }
        ];
    }
595403
public function getLineIndentation()
    {
        $first = $this->getFirstTokenOnLine();
        if ( ! $first->matches(T_WHITESPACE)) {
            return '';
        }

        return $first->getContentUntil($first->findNextToken('NO_WHITESPACE')->get());
    }
376637
protected function getRegex()
    {

        if( !self::$regexDefault ) {
            self::$regexDefault = implode(
                '|',
                array_map(
                    function($value){
                        return "(?<=[a-z0-9]){$value}(?=[A-Z])";
                    },
                    array_flip( self::$operations )
                )
            );
            self::$regexDefault = "/".self::$regexDefault."/";
        }

        return self::$regexDefault;

    }
1307422
private Token[] match(Token.Kind... kinds) {
		Token[] result = new Token[kinds.length];
		for (int i = 0; i != result.length; ++i) {
			checkNotEof();
			Token token = tokens.get(index++);
			if (token.kind == kinds[i]) {
				result[i] = token;
			} else {
				syntaxError("Expected \"" + kinds[i] + "\" here", token);
			}
		}
		return result;
	}
365611
protected function getInlineCodeMarkers()
	{
		$pos = $this->text->indexOf('`');
		if ($pos === false)
		{
			return [];
		}

		preg_match_all(
			'/(`+)(\\s*)[^\\x17`]*/',
			str_replace("\x1BB", '\\`', $this->text),
			$matches,
			PREG_OFFSET_CAPTURE | PREG_SET_ORDER,
			$pos
		);
		$trimNext = 0;
		$markers  = [];
		foreach ($matches as $m)
		{
			$markers[] = [
				'pos'        => $m[0][1],
				'len'        => strlen($m[1][0]),
				'trimBefore' => $trimNext,
				'trimAfter'  => strlen($m[2][0]),
				'next'       => $m[0][1] + strlen($m[0][0])
			];
			$trimNext = strlen($m[0][0]) - strlen(rtrim($m[0][0]));
		}

		return $markers;
	}
233750
public function getCodeLines() {
    // Add a terminal ';' to the last of the fluent method calls.
    $this->lines[count($this->lines) - 1] .= ';';

    $this->lines = $this->indentCodeLines($this->lines);

    return $this->lines;
  }
26068
private function build_first_sets(){
		$firsts = array();
		do {
			$changes = 0;
			foreach( $this->rules as $rule ){
				list( $nt, $rhs ) = $rule;
				$s = reset( $rhs );
				// get any special rule processing for this non-terminal
				//$excludela = isset($this->excludela[$nt]) ? $this->excludela[$nt] : null;
				do {
					// add terminal to first set of $nt
					if( $this->is_terminal( $s ) ){
						if( ! isset($firsts[$nt][$s]) ){
							$firsts[$nt][$s] = $s;
							$changes++;
						}
						continue 2;
					}
					// else inherit from first set of this non-terminal
					if( ! isset($firsts[$s]) ){
						// throw new Exception( sprintf("FIRST(%s) not defined", $s) );
						$changes++;
						continue 2;
					}
					// collect all terminal symbols in this non-terminal's set
					// except the empty string which we do not inherit.
					$derives_e = isset( $firsts[$s][P_EPSILON] );
					foreach( $firsts[$s] as $t ){
						// Omit any lookahead symbols denied by special rule
						//if( $excludela && in_array( $t, $excludela,true ) ){
						//	// ignored
						//}
						//else 
						if( $t !== P_EPSILON && ! isset( $firsts[$nt][$t] ) ){
							$firsts[$nt][$t] = $t;
							$changes++;
						}
					}
					// we move to next in sequence if non-terminal can derive empty 
				}
				while( $derives_e && $s = next($rhs) );
			}
		}
		while( $changes > 0 );
		return $firsts;
	}