<SYSTEM_TASK:>
Solve the following problem using Python, implementing the functions described below, one line at a time
<END_TASK>
<USER_TASK:>
Description:
 def format_action(nonterminal: str, right_hand_side: str, is_string: bool = False, is_number: bool = False, keywords_to_uppercase: List[str] = None) -> str: """ This function formats an action as it appears in models. It splits productions based on the special `ws` and `wsp` rules, which are used in grammars to denote whitespace, and then rejoins these tokens a formatted, comma separated list. Importantly, note that it `does not` split on spaces in the grammar string, because these might not correspond to spaces in the language the grammar recognises. Parameters nonterminal : ``str``, required. The nonterminal in the action. right_hand_side : ``str``, required. The right hand side of the action (i.e the thing which is produced). is_string : ``bool``, optional (default = False). Whether the production produces a string. If it does, it is formatted as ``nonterminal -> ['string']`` is_number : ``bool``, optional, (default = False). Whether the production produces a string. If it does, it is formatted as ``nonterminal -> ['number']`` keywords_to_uppercase: ``List[str]``, optional, (default = None) Keywords in the grammar to uppercase. In the case of sql, this might be SELECT, MAX etc. """

    keywords_to_uppercase = keywords_to_uppercase or []
    if right_hand_side.upper() in keywords_to_uppercase:
        right_hand_side = right_hand_side.upper()

    if is_string:
        return f'{nonterminal} -> ["\'{right_hand_side}\'"]'

    elif is_number:
        return f'{nonterminal} -> ["{right_hand_side}"]'

    else:
        right_hand_side = right_hand_side.lstrip("(").rstrip(")")
        child_strings = [token for token in WHITESPACE_REGEX.split(right_hand_side) if token]
        child_strings = [tok.upper() if tok.upper() in keywords_to_uppercase else tok for tok in child_strings]
        return f"{nonterminal} -> [{', '.join(child_strings)}]"