public function match($input)
    {
        if ($this->currentState===State::MATCH_FOUND) {
            return true;
        }
        if ($this->noMatch) {
            return false;
        }
        $advancing = true;

        while ($advancing) {
            $hasEmpty = false;
            foreach ($this->states[$this->currentState]->conditions as $condition) {
                if ($condition->isTokenEmpty()) {
                    // Move on to next state and check again
                    $this->callCallbacks($this->currentState, $condition->nextState);
                    $this->currentState = $condition->nextState;

                    $hasEmpty = true;
                    break;
                }
                if ($condition->match($input)) {
                    $this->matched[] = $condition->matched($input);
                    $this->actualMatched[] = $condition->matched($input);
                    $this->callCallbacks($this->currentState, $condition->nextState);
                    $this->currentState = $condition->nextState;
                    return true;
                }
            }
            $advancing = $hasEmpty;
        }
        // A no-match is confirmed
        $this->error = self::E_NOMATCH;
        $this->noMatch = true;
        $this->currentState = State::NO_MATCH;
        return false;
    }