def parse_lexical_query(text: str) -> Tuple[List[str], List[str]]:
    r"""
    Find required terms enclosed within double quotes.

    All other terms go into blob, split by whitespace. blob starts as a string then splits into
    a list by space.

    Backslash will be used to escape " or \, but if it is not followed by " or \,
    it should be IGNORED. This is to prevent hanging backslashes accidentally escaping query quotes or inserting bad
    characters into query (for example \a causes a Vespa 400).

    Syntax:
        Required strings must be enclosed by quotes. These quotes must be enclosed by spaces or the start
        or end of the text. Quotes always come in pairs.

        Bad syntax rules:
        - If 1 or both of the quotes in a pair has bad syntax (e.g. no space before opening quote or after closing
          quote), both will be treated as whitespace.
        - Incomplete quotes will be treated as whitespace.
    Notes:
        - Correct double quote can be either opening, closing, or escaped.
        - Escaped double quotes are interpreted literally.
        - Escaped backslashes are interpreted literally

    PYTHON NOTE:
    Users using python need to escape the backslash itself. (Single \ get ignored) -> q='dwayne \\"the rock\\" johnson'
    Unneeded if using CLI or raw string.

    Return:
        2-tuple of <required terms> (for "must" clause) <optional terms> (for "should" clause)
    """

    required_terms = []
    blob = ""
    opening_quote_idx = None
    current_quote_pair_is_faulty = False
    escape = False

    if not isinstance(text, str):
        raise TypeError("parse_lexical_query must have string as input")

    for i in range(len(text)):
        # Every character immediately after a \\ should be read literally
        if escape:
            escape = False
            blob += text[i]
        elif text[i] == "\\":
            escape = True
            # Stray backslashes should be ignored (not followed by special char, or is last char)
            if not (i == len(text) - 1 or text[i + 1] not in CHARACTERS_TO_BE_ESCAPED_IN_VESPA):
                blob += text[i]
        elif text[i] == '"':
            # OPENING QUOTE
            if (opening_quote_idx is None):
                opening_quote_idx = i
                blob_opening_quote_idx = len(blob) # Opening quote index in blob is different from text

                # Bad syntax opening quote: flag it, replace quote with whitespace
                if not (i == 0 or text[i - 1] == " "):
                    current_quote_pair_is_faulty = True
                    blob += " "
                else:
                    # Good syntax opening quote: add to blob
                    blob += text[i]
            # CLOSING QUOTE
            else:
                # Good syntax closing: must have space on the right (or is last character) while opening exists.
                if (i == len(text) - 1 or text[i + 1] == " ") and not current_quote_pair_is_faulty:
                    # Add this quote to the blob
                    blob += text[i]
                    # Add everything in between the quotes as a required term
                    new_required_term = text[opening_quote_idx + 1:i]
                    if new_required_term:                           # Do not add empty strings as required terms
                        required_terms.append(new_required_term)

                    # Remove this required term from the blob
                    blob = blob[:-(len(new_required_term) + 2)]

                else:
                    # Bad syntax closing: treat this and opening quote as whitespace
                    blob = blob[:blob_opening_quote_idx] + " " + \
                                     blob[blob_opening_quote_idx + 1:] + " "

                # Clean up flags
                opening_quote_idx = None
                current_quote_pair_is_faulty = False
        else:
            # If not a special character, add to blob
            blob += text[i]

    # Unpaired quote will be turned to whitespace
    if opening_quote_idx is not None:
        blob = blob[:blob_opening_quote_idx] + " " + blob[blob_opening_quote_idx + 1:]

    # Remove double/leading white spaces
    optional_terms = blob.split()

    return required_terms, optional_terms

    Find required terms enclosed within double quotes.

    All other terms go into blob, split by whitespace. blob starts as a string then splits into
    a list by space.

    Backslash will be used to escape " or \, but if it is not followed by " or \,
    it should be IGNORED. This is to prevent hanging backslashes accidentally escaping query quotes or inserting bad
    characters into query (for example \a causes a Vespa 400).

    Syntax:
        Required strings must be enclosed by quotes. These quotes must be enclosed by spaces or the start
        or end of the text. Quotes always come in pairs.

        Bad syntax rules:
        - If 1 or both of the quotes in a pair has bad syntax (e.g. no space before opening quote or after closing
          quote), both will be treated as whitespace.
        - Incomplete quotes will be treated as whitespace.
    Notes:
        - Correct double quote can be either opening, closing, or escaped.
        - Escaped double quotes are interpreted literally.
        - Escaped backslashes are interpreted literally

    PYTHON NOTE:
    Users using python need to escape the backslash itself. (Single \ get ignored) -> q='dwayne \\"the rock\\" johnson'
    Unneeded if using CLI or raw string.

    Return:
        2-tuple of <required terms> (for "must" clause) <optional terms> (for "should" clause)
    
src/marqo/tensor_search/utils.py