in spectator-reg-atlas/src/main/java/com/netflix/spectator/atlas/impl/Parser.java [63:225]
private static Object parse(String expr) {
DataExpr.AggregateFunction af;
Query q, q1, q2;
String k, v;
int depth = 0;
List<String> tmp;
List<String> vs = null;
String[] parts = expr.split(",");
Deque<Object> stack = new ArrayDeque<>(parts.length);
for (String p : parts) {
String token = unescape(p.trim());
if (token.isEmpty()) {
continue;
}
if (vs != null && (depth > 0 || !")".equals(token))) {
if ("(".equals(token)) {
++depth;
} else if (")".equals(token)) {
--depth;
}
vs.add(token);
continue;
}
switch (token) {
case "(":
vs = new ArrayList<>();
break;
case ")":
if (vs == null) {
throw new IllegalArgumentException("unmatched closing paren: " + expr);
}
stack.push(vs);
vs = null;
depth = 0;
break;
case ":true":
stack.push(Query.TRUE);
break;
case ":false":
stack.push(Query.FALSE);
break;
case ":and":
q2 = (Query) stack.pop();
q1 = (Query) stack.pop();
stack.push(q1.and(q2));
break;
case ":or":
q2 = (Query) stack.pop();
q1 = (Query) stack.pop();
stack.push(q1.or(q2));
break;
case ":not":
q = (Query) stack.pop();
stack.push(q.not());
break;
case ":has":
k = (String) stack.pop();
stack.push(new Query.Has(k));
break;
case ":eq":
v = (String) stack.pop();
k = (String) stack.pop();
stack.push(new Query.Equal(k, v));
break;
case ":in":
tmp = (List<String>) stack.pop();
k = (String) stack.pop();
pushIn(stack, k, tmp);
break;
case ":lt":
v = (String) stack.pop();
k = (String) stack.pop();
stack.push(new Query.LessThan(k, v));
break;
case ":le":
v = (String) stack.pop();
k = (String) stack.pop();
stack.push(new Query.LessThanEqual(k, v));
break;
case ":gt":
v = (String) stack.pop();
k = (String) stack.pop();
stack.push(new Query.GreaterThan(k, v));
break;
case ":ge":
v = (String) stack.pop();
k = (String) stack.pop();
stack.push(new Query.GreaterThanEqual(k, v));
break;
case ":re":
v = (String) stack.pop();
k = (String) stack.pop();
pushRegex(stack, new Query.Regex(k, v));
break;
case ":reic":
v = (String) stack.pop();
k = (String) stack.pop();
pushRegex(stack, new Query.Regex(k, v, true, ":reic"));
break;
case ":contains":
v = (String) stack.pop();
k = (String) stack.pop();
pushRegex(stack, new Query.Regex(k, ".*" + PatternUtils.escape(v)));
break;
case ":starts":
v = (String) stack.pop();
k = (String) stack.pop();
pushRegex(stack, new Query.Regex(k, PatternUtils.escape(v)));
break;
case ":ends":
v = (String) stack.pop();
k = (String) stack.pop();
pushRegex(stack, new Query.Regex(k, ".*" + PatternUtils.escape(v) + "$"));
break;
case ":all":
q = (Query) stack.pop();
stack.push(new DataExpr.All(q));
break;
case ":sum":
q = (Query) stack.pop();
stack.push(new DataExpr.Sum(q));
break;
case ":min":
q = (Query) stack.pop();
stack.push(new DataExpr.Min(q));
break;
case ":max":
q = (Query) stack.pop();
stack.push(new DataExpr.Max(q));
break;
case ":count":
q = (Query) stack.pop();
stack.push(new DataExpr.Count(q));
break;
case ":by":
tmp = (List<String>) stack.pop();
af = (DataExpr.AggregateFunction) stack.pop();
stack.push(new DataExpr.GroupBy(af, new LinkedHashSet<>(tmp)));
break;
case ":rollup-drop":
tmp = (List<String>) stack.pop();
af = (DataExpr.AggregateFunction) stack.pop();
stack.push(new DataExpr.DropRollup(af, tmp));
break;
case ":rollup-keep":
tmp = (List<String>) stack.pop();
af = (DataExpr.AggregateFunction) stack.pop();
stack.push(new DataExpr.KeepRollup(af, tmp));
break;
default:
if (token.startsWith(":")) {
throw new IllegalArgumentException("unknown word '" + token + "'");
}
stack.push(token);
break;
}
}
Object obj = stack.pop();
if (!stack.isEmpty()) {
throw new IllegalArgumentException("too many items remaining on stack: " + stack);
}
return obj;
}