def extractArgumentsFromCallStr(callStr):
    """
    Parse the argument string via an AST instead of the overly simple
    callStr.split(','). The latter incorrectly splits any string parameters
    that contain commas therein, like ic(1, 'a,b', 2).
    """
    def isTuple(ele):
        return classname(ele) == 'Tuple'

    paramsStr = callStr.split('(', 1)[-1].rsplit(')', 1)[0].strip()

    root = ast.parse(paramsStr).body[0].value
    eles = root.elts if isTuple(root) else [root]

    # The ast module parses 'a, b' and '(a, b)' identically. Thus, ast.parse()
    # alone can't tell the difference between
    #
    #   ic(a, b)
    #
    # and
    #
    #   ic((a, b))
    #
    # Detect this situation and preserve whole tuples, e.g. '(a, b)', passed to
    # ic() by creating a new, temporary tuple around the original tuple and
    # parsing that.
    if paramsStr[0] == '(' and paramsStr[-1] == ')' and len(eles) > 1:
        newTupleStr = '(' + paramsStr + ", 'ignored')"
        argStrs = extractArgumentsFromCallStr(newTupleStr)[:-1]
        return argStrs

    indices = [
        max(0, e.col_offset - 1) if isTuple(e) else e.col_offset for e in eles]
    argStrs = [s.strip(' ,') for s in splitStringAtIndices(paramsStr, indices)]

    return argStrs
Parse the argument string via an AST instead of the overly simple
    callStr.split(','). The latter incorrectly splits any string parameters
    that contain commas therein, like ic(1, 'a,b', 2).