assert types != null && types.length > 0;
assert types.length == 1 || !CollectionUtils.contains(types, Object.class);
final boolean isObject = types.length == 1 && types[0] == Object.class;
final ParseLogHandler log = SkriptLogger.startParseLogHandler();
try {
final Expression<? extends T> r = parseSingleExpr(false, null, types);
if (r != null) {
log.printLog();
return r;
}
log.clear();
final List<Expression<? extends T>> ts = new ArrayList<Expression<? extends T>>();
Kleenean and = Kleenean.UNKNOWN;
boolean isLiteralList = true;
final List<int[]> pieces = new ArrayList<int[]>();
{
final Matcher m = listSplitPattern.matcher(expr);
int i = 0, j = 0;
for (; i >= 0 && i <= expr.length(); i = next(expr, i, context)) {
if (i == expr.length() || m.region(i, expr.length()).lookingAt()) {
pieces.add(new int[] {j, i});
if (i == expr.length())
break;
j = i = m.end();
}
}
if (i != expr.length()) {
assert i == -1 && context != ParseContext.COMMAND : i + "; " + expr;
log.printError("Invalid brackets/variables/text in '" + expr + "'", ErrorQuality.NOT_AN_EXPRESSION);
return null;
}
}
if (pieces.size() == 1) { // not a list of expressions, and a single one has failed to parse above
if (expr.startsWith("(") && expr.endsWith(")") && next(expr, 0, context) == expr.length()) {
log.clear();
log.printLog();
return new SkriptParser(this, "" + expr.substring(1, expr.length() - 1)).parseExpression(types);
}
if (isObject && (flags & PARSE_LITERALS) != 0) { // single expression - can return an UnparsedLiteral now
log.clear();
log.printLog();
return (Expression<? extends T>) new UnparsedLiteral(expr, log.getError());
}
// results in useless errors most of the time
// log.printError("'" + expr + "' " + Language.get("is") + " " + notOfType(types), ErrorQuality.NOT_AN_EXPRESSION);
log.printError();
return null;
}
outer: for (int b = 0; b < pieces.size();) {
for (int a = pieces.size() - b; a >= 1; a--) {
if (b == 0 && a == pieces.size()) // i.e. the whole expression - already tried to parse above
continue;
final int x = pieces.get(b)[0], y = pieces.get(b + a - 1)[1];
final String subExpr = "" + expr.substring(x, y).trim();
assert subExpr.length() < expr.length() : subExpr;
final Expression<? extends T> t;
if (subExpr.startsWith("(") && subExpr.endsWith(")") && next(subExpr, 0, context) == subExpr.length())
t = new SkriptParser(this, subExpr).parseExpression(types); // only parse as possible expression list if its surrounded by brackets
else
t = new SkriptParser(this, subExpr).parseSingleExpr(a == 1, log.getError(), types); // otherwise parse as a single expression only
if (t != null) {
isLiteralList &= t instanceof Literal;
ts.add(t);
if (b != 0) {
final String d = expr.substring(pieces.get(b - 1)[1], x).trim();
if (!d.equals(",")) {
if (and.isUnknown()) {
and = Kleenean.get(!d.equalsIgnoreCase("or")); // nor is and
} else {
if (and != Kleenean.get(!d.equalsIgnoreCase("or"))) {
Skript.warning(MULTIPLE_AND_OR + " List: " + expr);
and = Kleenean.TRUE;
}
}
}
}
b += a;
continue outer;
}
}
log.printError();
return null;
}
// String lastExpr = expr;
// int end = expr.length();
// int expectedEnd = -1;
// boolean last = false;
// while (m.find() || (last = !last)) {
// if (expectedEnd == -1) {
// if (last)
// break;
// expectedEnd = m.start();
// }
// final int start = last ? 0 : m.end();
// final Expression<? extends T> t;
// if (context != ParseContext.COMMAND && (start < expr.length() && expr.charAt(start) == '(' || end - 1 > 0 && expr.charAt(end - 1) == ')')) {
// if (start < expr.length() && expr.charAt(start) == '(' && end - 1 > 0 && expr.charAt(end - 1) == ')' && next(expr, start, context) == end)
// t = new SkriptParser(lastExpr = "" + expr.substring(start + 1, end - 1), flags, context).parseExpression(types);
// else
// t = null;
// } else {
// t = new SkriptParser(lastExpr = "" + expr.substring(start, end), flags, context).parseSingleExpr(types);
// }
// if (t != null) {
// isLiteralList &= t instanceof Literal;
// if (!last && m.group(1) != null) {
// if (and.isUnknown()) {
// and = Kleenean.get(!m.group(1).equalsIgnoreCase("or")); // nor is and
// } else {
// if (and != Kleenean.get(!m.group(1).equalsIgnoreCase("or"))) {
// Skript.warning(MULTIPLE_AND_OR);
// and = Kleenean.TRUE;
// }
// }
// }
// ts.addFirst(t);
// if (last)
// break;
// end = m.start();
// m.region(0, end);
// } else {
// log.clear();
// if (last)
// end = -2; // fails the test below
// }
// }
// if (end != expectedEnd) {
// log.printError("'" + lastExpr + "' " + Language.get("is") + " " + notOfType(types), ErrorQuality.NOT_AN_EXPRESSION);
// return null;
// }
log.printLog();
if (ts.size() == 1)
return ts.get(0);
if (and.isUnknown())
Skript.warning(MISSING_AND_OR + ": " + expr);
final Class<? extends T>[] exprRetTypes = new Class[ts.size()];
for (int i = 0; i < ts.size(); i++)
exprRetTypes[i] = ts.get(i).getReturnType();
if (isLiteralList) {
final Literal<T>[] ls = ts.toArray(new Literal[ts.size()]);
assert ls != null;
return new LiteralList<T>(ls, (Class<T>) Utils.getSuperType(exprRetTypes), !and.isFalse());
} else {
final Expression<T>[] es = ts.toArray(new Expression[ts.size()]);
assert es != null;
return new ExpressionList<T>(es, (Class<T>) Utils.getSuperType(exprRetTypes), !and.isFalse());
}
} finally {
log.stop();
}
}