protected static void parseStep(char[] chars, int charIdx, List<String> terms, StringBuilder token, int parenDepth) throws ParseException {
        if (charIdx == chars.length) {
            if (token.length() > 0) {
                terms.add(token.toString());
            }
            return;
        }
        char c = chars[charIdx];
        if (c == '(') {
            parseStep(chars, charIdx + 1, terms, token.append(c), parenDepth + 1);
        } else if (c == ')') {
            if (parenDepth < 1) {
                throw new ParseException("too many closing parentheses", charIdx);
            } else if (parenDepth == 1) {
                terms.add(token.append(c).toString());
                parseStep(chars, charIdx + 1, terms, new StringBuilder(), 0);
            } else {
                parseStep(chars, charIdx + 1, terms, token.append(c), parenDepth - 1);
            }
        } else if (c == ',') {
            if (parenDepth == 0) {
                if (token.length() > 0) {
                    terms.add(token.toString());
                }
                parseStep(chars, charIdx + 1, terms, new StringBuilder(), parenDepth);
            } else {
                parseStep(chars, charIdx + 1, terms, token.append(c), parenDepth);
            }
        } else {
            parseStep(chars, charIdx + 1, terms, token.append(c), parenDepth);
        }
    }