1. 构建 VariateType 类
public enum VariateType {
/**
* Variate type, include STRING , NUMERIC ,
* ARRAY , BOOLEAN , FUNCTION ,
* SYMBOL , SYMBOL and ORIGINAL .
*/
STRING, NUMERIC, FUNCTION, SYMBOL, BOOLEAN, ORIGINAL, ARRAY, ERROR, STREAM,
}
2. 构建 Variate 类
import com.google.gson.JsonArray;
import com.google.gson.JsonElement;
import com.google.gson.JsonParser;
import com.google.gson.JsonPrimitive;
import com.neusoft.rsapm.brain.common.exception.CompilerException;
import com.neusoft.rsapm.brain.common.util.Util;
import lombok.Getter;
import lombok.ToString;
import org.apache.commons.lang.StringUtils;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.Objects;
import java.util.stream.Collectors;
import static com.neusoft.rsapm.compile.VariateType.*;
/**
* @author Muxin Sun
* @date 2019/05/20
*/
@Getter
@ToString
public class Variate {
/**
* @date 2019/05/20
* Supported operators, sort operational character by priority level. ' is max level,
* Note: = is not mutator method.
*/
public static final String LEFT_PARENTHESIS = "(";
public static final String RIGHT_PARENTHESIS = ")";
public static final String GREATER_THAN = ">";
public static final String LESS_THAN = "<";
public static final String EQUAL = "=";
public static final String PLUS = "+";
public static final String MINUS = "-";
public static final String COMMA = ",";
public static final String TIMES = "*";
public static final String DIVISION = "/";
public static final String DOT = ".";
public static final String QUERY = "#";
public static final String GREATER_EQUAL = ">=";
public static final String LESS_EQUAL = "<=";
public static final String OR = " or ";
public static final String AND = " and ";
public static final Variate LEFT_PARENTHESIS_VARIATE = build(SYMBOL, LEFT_PARENTHESIS);
public static final Variate RIGHT_PARENTHESIS_VARIATE = build(SYMBOL, RIGHT_PARENTHESIS);
public static final Variate GREATER_THAN_VARIATE = build(SYMBOL, GREATER_THAN);
public static final Variate LESS_THAN_VARIATE = build(SYMBOL, LESS_THAN);
public static final Variate EQUAL_VARIATE = build(SYMBOL, EQUAL);
public static final Variate PLUS_VARIATE = build(SYMBOL, PLUS);
public static final Variate MINUS_VARIATE = build(SYMBOL, MINUS);
public static final Variate COMMA_VARIATE = build(SYMBOL, COMMA);
public static final Variate TIMES_VARIATE = build(SYMBOL, TIMES);
public static final Variate DIVISION_VARIATE = build(SYMBOL, DIVISION);
public static final Variate QUERY_VARIATE = build(SYMBOL, QUERY);
public static final Variate GREATER_EQUAL_VARIATE = build(SYMBOL, GREATER_EQUAL);
public static final Variate LESS_EQUAL_VARIATE = build(SYMBOL, LESS_EQUAL);
public static final Variate OR_VARIATE = build(SYMBOL, OR);
public static final Variate AND_VARIATE = build(SYMBOL, AND);
public static final String[] OPERATORS = {LEFT_PARENTHESIS, RIGHT_PARENTHESIS, QUERY,
GREATER_THAN, GREATER_EQUAL, LESS_THAN, LESS_EQUAL, EQUAL, PLUS, MINUS, COMMA, TIMES,
DIVISION, OR, AND};
/**
* check {@code op} is OPERATOR?
*
* @return ture if {@code op} is in {@code OPERATORS}, else false
* @see #OPERATORS
*/
public static boolean isOperator(String op) {
return Arrays.asList(OPERATORS).contains(op);
}
public static List spliteExpr(String expr) throws CompilerException {
return spliteExpr(expr, new BaseQuery());
}
public static List spliteExpr(final String expr, final BaseQuery baseQuery) throws CompilerException {
List words = new ArrayList<>();
StringBuffer sb = new StringBuffer();
for (int i = 0; i < expr.length();) {
if (expr.substring(i).startsWith(OR)) {
words.add(sb.toString().trim());
words.add(OR);
sb = new StringBuffer();
i += OR.length();
} else if (expr.substring(i).startsWith(AND)) {
words.add(sb.toString().trim());
words.add(AND);
sb = new StringBuffer();
i += AND.length();
} else if (expr.substring(i).startsWith(LESS_EQUAL)) {
words.add(sb.toString().trim());
words.add(LESS_EQUAL);
sb = new StringBuffer();
i += LESS_EQUAL.length();
} else if (expr.substring(i).startsWith(GREATER_EQUAL)) {
words.add(sb.toString().trim());
words.add(GREATER_EQUAL);
sb = new StringBuffer();
i += GREATER_EQUAL.length();
} else if (expr.substring(i).startsWith(QUERY)) {
words.add(sb.toString().trim());
words.add(QUERY);
sb = new StringBuffer();
i += QUERY.length();
if (expr.substring(i).contains(QUERY)) {
final String query = expr.substring(i).substring(0, expr.substring(i).indexOf(QUERY));
baseQuery.addQuery(query);
words.add(query);
i += query.length();
words.add(QUERY);
i += QUERY.length();
} else {
throw new CompilerException("expr query no match.");
}
} else if (expr.substring(i).startsWith(DIVISION)) {
words.add(sb.toString().trim());
words.add(DIVISION);
sb = new StringBuffer();
i += DIVISION.length();
} else if (expr.substring(i).startsWith(TIMES)) {
words.add(sb.toString().trim());
words.add(TIMES);
sb = new StringBuffer();
i += TIMES.length();
} else if (expr.substring(i).startsWith(COMMA)) {
words.add(sb.toString().trim());
words.add(COMMA);
sb = new StringBuffer();
i += COMMA.length();
} else if (expr.substring(i).startsWith(MINUS)) {
words.add(sb.toString().trim());
words.add(MINUS);
sb = new StringBuffer();
i += MINUS.length();
} else if (expr.substring(i).startsWith(PLUS)) {
words.add(sb.toString().trim());
words.add(PLUS);
sb = new StringBuffer();
i += PLUS.length();
} else if (expr.substring(i).startsWith(EQUAL)) {
words.add(sb.toString().trim());
words.add(EQUAL);
sb = new StringBuffer();
i += EQUAL.length();
} else if (expr.substring(i).startsWith(LESS_THAN)) {
words.add(sb.toString().trim());
words.add(LESS_THAN);
sb = new StringBuffer();
i += LESS_THAN.length();
} else if (expr.substring(i).startsWith(GREATER_THAN)) {
words.add(sb.toString().trim());
words.add(GREATER_THAN);
sb = new StringBuffer();
i += GREATER_THAN.length();
} else if (expr.substring(i).startsWith(RIGHT_PARENTHESIS)) {
words.add(sb.toString().trim());
words.add(RIGHT_PARENTHESIS);
sb = new StringBuffer();
i += RIGHT_PARENTHESIS.length();
} else if (expr.substring(i).startsWith(LEFT_PARENTHESIS)) {
words.add(sb.toString().trim());
words.add(LEFT_PARENTHESIS);
sb = new StringBuffer();
i += LEFT_PARENTHESIS.length();
} else if (expr.substring(i).startsWith(DOT) && StringUtils.isAlpha(expr.substring(i+1,i+2))) {
words.add(sb.toString().trim());
words.add(DOT);
sb = new StringBuffer();
i += DOT.length();
StringBuffer func_name = new StringBuffer();
while((!LEFT_PARENTHESIS.equals(String.valueOf(expr.charAt(i)))) && i 0 && i 0) {
func_body.append(expr.charAt(i));
}
}
words.add(func_body.toString().trim());
words.add(RIGHT_PARENTHESIS);
i++;
} else {
sb.append(expr.charAt(i));
i += 1;
}
}
if (sb.length() > 0) {
words.add(sb.toString().trim());
}
return words.stream().filter(StringUtils::isNotEmpty).collect(Collectors.toList());
}
/**
* Lexical compiler triple: type
is variate type,
* name
is variate name, value
is variate value.
*
* @date 2019/05/21
*/
private VariateType type;
private JsonElement value;
private StringBuffer sb;
/**
* Variate Constructor.
*
* @param type variate type.
* @param value variate value.
*/
private Variate(VariateType type, JsonPrimitive value, StringBuffer sb) {
this.type = type;
this.value = value;
this.sb = sb;
}
/**
* Variate Constructor.
*
* @param type variate type.
* @param value variate value.
*/
private Variate(VariateType type, JsonArray value, StringBuffer sb) {
this.type = type;
this.value = value;
this.sb = sb;
}
/**
* build type
variate
*
* @param obj variate value.
* @return Variate
Variate type is type
, name is null, value is empty
*/
public static Variate build(Object obj) {
if (obj instanceof JsonArray) {
return new Variate(ARRAY, (JsonArray) obj, new StringBuffer());
}
return build(ORIGINAL, obj);
}
/**
* build type
variate
*
* @param type datum type.
* @param obj variate value.
* @return Variate
Variate type is type
, name is null, value is empty
*/
public static Variate build(VariateType type, Object obj) {
if (type.equals(ARRAY) || type.equals(STREAM)) {
if (obj instanceof JsonArray) {
return new Variate(type, (JsonArray) obj, new StringBuffer());
}
}
if (type == ORIGINAL) {
return new Variate(ORIGINAL, new JsonPrimitive(""), new StringBuffer(obj.toString()));
}
if (obj instanceof Integer) {
return new Variate(type, new JsonPrimitive((int) obj), new StringBuffer());
} else if (obj instanceof Long) {
return new Variate(type, new JsonPrimitive((long) obj), new StringBuffer());
} else if (obj instanceof Short) {
return new Variate(type, new JsonPrimitive((short) obj), new StringBuffer());
} else if (obj instanceof Float) {
return new Variate(type, new JsonPrimitive((float) obj), new StringBuffer());
} else if (obj instanceof Double) {
return new Variate(type, new JsonPrimitive((double) obj), new StringBuffer());
} else if (obj instanceof Byte) {
return new Variate(type, new JsonPrimitive((byte) obj), new StringBuffer());
} else if (obj instanceof Boolean) {
return new Variate(type, new JsonPrimitive((boolean) obj), new StringBuffer());
} else if (obj instanceof Character) {
return new Variate(type, new JsonPrimitive((char) obj), new StringBuffer());
} else if (obj instanceof Number) {
return new Variate(type, new JsonPrimitive((Number) obj), new StringBuffer());
}
return new Variate(type, new JsonPrimitive(obj.toString()), new StringBuffer());
}
/**
* check {@code value} is empty?
*
* @return ture if {@code value} is null or the size of {@code value} is 0, else false
* @see #value
*/
boolean isEmpty() {
return (Objects.isNull(this.value) || StringUtils.isEmpty(this.value.getAsString()))
&& Objects.deepEquals(this.sb.length(), 0);
}
/**
* expand value
*
* @param ch the next of variate ch
*/
void expand(String ch) throws CompilerException {
if (this.type.equals(ORIGINAL)) {
this.sb.append(ch);
return;
}
throw new CompilerException("expand error: type is not ORIGINAL. ");
}
/**
* check {@code value} is empty?
*
* @return true ior false
* @see #isEmpty()
*/
private boolean isValid() {
if (this.type.equals(ORIGINAL)) {
return true;
} else if (this.type.equals(FUNCTION)) {
return StringUtils.isAlpha(getValue().getAsString()) && Objects.deepEquals(isEmpty(), false);
} else if (this.type.equals(NUMERIC)) {
return Util.isNumeric(value.getAsNumber());
} else if (this.type.equals(STRING)) {
return true;
} else if (this.type.equals(SYMBOL)) {
return isOperator(getValue().getAsString());
} else if (this.type.equals(BOOLEAN)) {
getValue().getAsBoolean();
return true;
} else if (this.type.equals(ARRAY)) {
return getValue().isJsonArray();
} else if (this.type.equals(STREAM)) {
return getValue().isJsonArray();
}
return false;
}
/**
* transform {@code type}
*
* @return void
* @throws CompilerException type and value do not match
* @throws CompilerException type is not {@code original} and @{code this.type.equals(type)}
*/
private void transformType(VariateType type) throws CompilerException {
if (this.type.equals(type)) {
return ;
}
if (isORIGINAL()) {
this.type = type;
switch (type) {
case BOOLEAN:
value = new JsonPrimitive(Boolean.valueOf(sb.toString()));
break;
case NUMERIC:
value = new JsonPrimitive(Double.valueOf(sb.toString()));
break;
case ORIGINAL:
case ERROR:
break;
case ARRAY:
value = new JsonParser().parse(sb.toString());
break;
case STRING:
case SYMBOL:
case FUNCTION:
value = new JsonPrimitive(sb.toString());
break;
}
if (!isValid()) {
this.type = ORIGINAL;
throw new CompilerException("transform error: type and value do not match. ");
}
sb = new StringBuffer();
} else {
throw new CompilerException("transform error: original type is not {@code original}. ");
}
}
/**
* transform {@code FUNCTION} type
*
* @return void
* @throws CompilerException type and value do not match
* @throws CompilerException original type is not {@code original}
*
* @see #transformType(VariateType)
*/
void toFUNCTION() throws CompilerException {
transformType(FUNCTION);
}
/**
* transform {@code STRING} type
*
* @return void
* @throws CompilerException type and value do not match
* @throws CompilerException original type is not {@code original}
*
* @see #transformType(VariateType)
*/
void toSTRING() throws CompilerException {
transformType(STRING);
}
/**
* transform {@code FUNCTION} type
*
* @return void
* @throws CompilerException type and value do not match
* @throws CompilerException original type is not {@code original}
*
* @see #transformType(VariateType)
*/
void toSYMBOL() throws CompilerException {
transformType(SYMBOL);
}
/**
* transform {@code NUMERIC} type
*
* @return void
* @throws CompilerException type and value do not match
* @throws CompilerException original type is not {@code original}
*
* @see #transformType(VariateType)
*/
void toNUMERIC() throws CompilerException {
transformType(NUMERIC);
}
/**
* transform {@code BOOLEAN} type
*
* @return void
*
* @see #transformType(VariateType)
*/
void toBOOLEAN() {
type = BOOLEAN;
}
/**
* transform {@code STREAM} type
*
* @return void
*
* @see #transformType(VariateType)
*/
void toSTREAM() {
type = STREAM;
}
/**
* transform {@code ARRAY} type
*
* @return void
*
* @see #transformType(VariateType)
*/
void toARRAY() {
type = ARRAY;
}
/**
* transform {@code NUMERIC} type
*
* @return void
*
* @see #transformType(VariateType)
*/
void toERROR() {
type = ERROR;
}
/**
* check variate {@code type}
*
* @return true if {@code type} is {@code STRING}, else false
*/
public boolean isSTRING() {
return this.type.equals(STRING) && this.isValid();
}
/**
* check variate {@code type}
*
* @return true if {@code type} is {@code NUMERIC}, else false
*/
public boolean isNUMERIC() {
return this.type.equals(NUMERIC) && this.isValid();
}
/**
* check variate {@code type}
*
* @return true if {@code type} is {@code FUNCTION}, else false
*/
public boolean isFUNCTION() {
return this.type.equals(FUNCTION) && this.isValid();
}
/**
* check variate {@code type}
*
* @return true if {@code type} is {@code SYMBOL}, else false
*/
public boolean isSYMBOL() {
return this.type.equals(SYMBOL) && this.isValid();
}
/**
* check variate {@code type}
*
* @return true if {@code type} is {@code STREAM}, else false
*/
public boolean isSTREAM() {
return this.type.equals(STREAM) && this.isValid();
}
/**
* check variate {@code type}
*
* @return true if {@code type} is {@code ARRAY}, else false
*/
public boolean isARRAY() {
return this.type.equals(ARRAY) && this.isValid();
}
/**
* check variate {@code type}
*
* @return true if {@code type} is {@code BOOLEAN}, else false
*/
public boolean isBOOLEAN() {
return this.type.equals(BOOLEAN) && this.isValid();
}
/**
* check variate {@code type}
*
* @return true if {@code type} is {@code ORIGINAL}, else false
*/
public boolean isORIGINAL() {
return this.type.equals(ORIGINAL) && this.isValid();
}
/**
* check variate {@code type}
*
* @return true if {@code type} is {@code ERROR}, else false
*/
public boolean isERROR() {
return this.type.equals(ERROR) && this.isValid();
}
/**
* check variate {@code value}
*
* @param value string value
* @return true if {@code value} is value, else false
*/
public boolean equals(String value) {
return getValue().getAsString().equals(value);
}
/**
* check variate {@code value}
*
* @param v Variate
* @return true if {@code value} is value, else false
*/
public boolean equals(Variate v) {
return v.type.equals(this.type) && v.value.getAsString().equals(this.value.getAsString());
}
}
3. 构建 Lexical 类
import com.neusoft.rsapm.brain.common.exception.CompilerException;
import com.neusoft.rsapm.brain.common.exception.MessageException;
import com.neusoft.rsapm.brain.common.util.Util;
import org.apache.commons.lang.StringUtils;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.stream.Collectors;
import java.util.stream.Stream;
import static com.neusoft.rsapm.compile.VariateType.*;
/**
* Lexocal for metric cal
*
* @author Muxin Sun
* @date 2018/12/20
*/
public interface Lexical {
/**
* function name
*/
String MIN_FUNCTION = "min";
String MAX_FUNCTION = "max";
String SUM_FUNCTION = "sum";
String AVG_FUNCTION = "avg";
String COUNT_FUNCTION = "count";
String NAME_PREFIX = "v";
AtomicInteger SEQUENCE = new AtomicInteger(0);
/**
* variate to values
*/
Map NAME_VARIATE = new HashMap<>();
/**
* gt sign
*
* @param valueA valueA is numeric
* @param valueB valueB is numeric
* @return 1 if valueA grant than valueB, else 0
* @throws CompilerException Non-numeric type cannot be multiplied.
*/
default Variate gt(Variate valueA, Variate valueB) throws CompilerException {
if (valueA.isNUMERIC() && valueB.isNUMERIC()) {
return Variate.build(NUMERIC, valueA.getValue().getAsDouble()>valueB.getValue().getAsDouble()?1:0);
} else if (valueA.isSTRING() && valueB.isSTRING()) {
return Variate.build(NUMERIC, valueA.getValue().getAsString().compareTo(valueB.getValue().getAsString())>0?1:0);
}
throw new CompilerException("Operator type cannot be compared.");
}
/**
* lt sign
*
* @param valueA valueA is numeric
* @param valueB valueB is numeric
* @return 1 if valueA less than valueB, else 0
* @throws CompilerException Non-numeric type cannot be multiplied.
*/
default Variate lt(Variate valueA, Variate valueB) throws CompilerException {
if (valueA.isNUMERIC() && valueB.isNUMERIC()) {
return Variate.build(NUMERIC, valueA.getValue().getAsDouble()eq sign
*
* @param valueA valueA is numeric
* @param valueB valueB is numeric
* @return 1 if valueA less than valueB, else 0
* @throws CompilerException Non-numeric type cannot be multiplied.
*/
default Variate eq(Variate valueA, Variate valueB) throws CompilerException {
if (valueA.isNUMERIC() && valueB.isNUMERIC()) {
return Variate.build(NUMERIC, valueA.getValue().getAsDouble()==valueB.getValue().getAsDouble()?1:0);
} else if (valueA.isSTRING() && valueB.isSTRING()) {
return Variate.build(NUMERIC, valueA.getValue().getAsString().compareTo(valueB.getValue().getAsString())==0?1:0);
}
throw new CompilerException("Operator type cannot be compared.");
}
/**
* eq sign
*
* @param valueA valueA is numeric
* @param valueB valueB is numeric
* @return 1 if valueA less than valueB, else 0
* @throws CompilerException Non-numeric type cannot be multiplied.
*/
default Variate ge(Variate valueA, Variate valueB) throws CompilerException {
if (valueA.isNUMERIC() && valueB.isNUMERIC()) {
return Variate.build(NUMERIC, valueA.getValue().getAsDouble()>=valueB.getValue().getAsDouble()?1:0);
} else if (valueA.isSTRING() && valueB.isSTRING()) {
return Variate.build(NUMERIC, valueA.getValue().getAsString().compareTo(valueB.getValue().getAsString())>=0?1:0);
}
throw new CompilerException("Operator type cannot be compared.");
}
/**
* eq sign
*
* @param valueA valueA is numeric
* @param valueB valueB is numeric
* @return 1 if valueA less than or equal valueB, else 0
* @throws CompilerException Non-numeric type cannot be multiplied.
*/
default Variate le(Variate valueA, Variate valueB) throws CompilerException {
if (valueA.isNUMERIC() && valueB.isNUMERIC()) {
return Variate.build(NUMERIC, valueA.getValue().getAsDouble()<=valueB.getValue().getAsDouble()?1:0);
} else if (valueA.isSTRING() && valueB.isSTRING()) {
return Variate.build(NUMERIC, valueA.getValue().getAsString().compareTo(valueB.getValue().getAsString())<=0?1:0);
}
throw new CompilerException("Operator type cannot be compared.");
}
/**
* plus sign
*
* @param valueA valueA is numeric
* @param valueB valueB is numeric
* @return valueA+valueB
* @throws CompilerException Non-numeric types cannot be added.
*/
default Variate plus(Variate valueA, Variate valueB) throws CompilerException {
if (valueA.isNUMERIC() && valueB.isNUMERIC()) {
return Variate.build(NUMERIC, valueA.getValue().getAsDouble() + valueB.getValue().getAsDouble());
}
throw new CompilerException("Non-numeric types cannot be added.");
}
/**
* minus sign
*
* @param valueA valueA is numeric
* @param valueB valueB is numeric
* @return valueA-valueB
* @throws CompilerException Non-numeric type cannot be subtracted.
*/
default Variate minus(Variate valueA, Variate valueB) throws CompilerException {
if (valueA.isNUMERIC() && valueB.isNUMERIC()) {
return Variate.build(NUMERIC, valueA.getValue().getAsDouble() - valueB.getValue().getAsDouble());
}
throw new CompilerException("Non-numeric type cannot be subtracted.");
}
/**
* times sign
*
* @param valueA valueA is numeric
* @param valueB valueB is numeric
* @return valueA*valueB
* @throws CompilerException Non-numeric type cannot be multiplied.
*/
default Variate times(Variate valueA, Variate valueB) throws CompilerException {
if (valueA.isNUMERIC() && valueB.isNUMERIC()) {
return Variate.build(NUMERIC, valueA.getValue().getAsDouble() * valueB.getValue().getAsDouble());
}
throw new CompilerException("Non-numeric type cannot be multiplied.");
}
/**
* divide sign
*
* @param valueA valueA is numeric
* @param valueB valueB is numeric
* @return valueA/valueB
valueB is no-null
* @throws CompilerException Non-numeric type cannot be divided.
*/
default Variate division(Variate valueA, Variate valueB) throws CompilerException {
if (valueA.isNUMERIC() && valueB.isNUMERIC()) {
return Variate.build(NUMERIC, valueA.getValue().getAsDouble() / valueB.getValue().getAsDouble());
}
throw new CompilerException("Non-numeric type cannot be divided.");
}
/**
* execute function and
*
* @param function function name
* @param parameters parameters is variate_stream
* @return execute result
* @throws CompilerException if function is not def.
*/
default Variate execute(String function, List parameters) throws CompilerException {
if (MIN_FUNCTION.equals(function)) {
if (parameters.stream().allMatch(Variate::isNUMERIC)) {
return Variate.build(NUMERIC, parameters.stream().map(Variate::getValue).mapToDouble(Util::getNumeric).min().orElse(Double.NaN));
}
throw new CompilerException("min function do not accept non-numeric parameters.");
}
if (MAX_FUNCTION.equals(function)) {
if (parameters.stream().allMatch(Variate::isNUMERIC)) {
return Variate.build(NUMERIC, parameters.stream().map(Variate::getValue).mapToDouble(Util::getNumeric).max().orElse(Double.NaN));
}
throw new CompilerException("max function do not accept non-numeric parameters.");
}
if (SUM_FUNCTION.equals(function)) {
if (parameters.stream().allMatch(Variate::isNUMERIC)) {
return Variate.build(NUMERIC, parameters.stream().map(Variate::getValue).mapToDouble(Util::getNumeric).sum());
}
throw new CompilerException("sum function do not accept non-numeric parameters.");
}
if (AVG_FUNCTION.equals(function)) {
if (parameters.stream().allMatch(Variate::isNUMERIC)) {
return Variate.build(NUMERIC, parameters.stream().map(Variate::getValue).mapToDouble(Util::getNumeric).average().orElse(Double.NaN));
}
throw new CompilerException("avg function do not accept non-numeric parameters.");
}
if (COUNT_FUNCTION.equals(function)) {
return Variate.build(NUMERIC, parameters.stream().count());
}
throw new CompilerException("function is not def.");
}
/**
* execute function, and args is array
*
* @param function function name
* @param parameters function parameters
* @return execute result
*/
default Variate execute(String function, Variate... parameters) throws CompilerException, MessageException {
return execute(function, Stream.of(parameters).collect(Collectors.toList()));
}
/**
* check operator is a function?
*
* isFunction(null) = false
* isFunction("") = true
* isFunction(" ") = false
* isFunction("abc") = true
* isFunction("ab2c") = false
* isFunction("ab-c") = false
*
* @param operator operator name
* @return true
if only contains letters, and is non-null
*/
default boolean isFunction(String operator) {
return StringUtils.isAlpha(operator);
}
/**
* store variate value function, return random variate
*
* @param variate {@link #NAME_VARIATE}
* @return variate name
, name is auto-created
*/
default String putVariate(final Variate variate) {
NAME_VARIATE.put(String.format("%s-%d", NAME_PREFIX, SEQUENCE.incrementAndGet()), variate);
return String.valueOf(String.format("%s-%d", NAME_PREFIX, SEQUENCE.get()));
}
/**
* get variate value, by name
*
* @param name variate name
* @return variate
* @throws CompilerException if variate
is not exist
*/
default boolean isVariate(String name) throws CompilerException {
return NAME_VARIATE.containsKey(name);
}
/**
* get variate value, by name
*
* @param name variate name
* @return variate
* @throws CompilerException if variate
is not exist
*/
default Variate getVariate(String name) throws CompilerException {
if (NAME_VARIATE.containsKey(name)) {
return NAME_VARIATE.get(name);
}
throw new CompilerException("variate {"+name+"} is not exist");
}
}
4. 构建 Syntactic 类
import com.neusoft.rsapm.brain.common.exception.CompilerException;
import com.neusoft.rsapm.brain.common.util.Util;
import java.util.ArrayList;
import java.util.List;
import java.util.Objects;
import java.util.Stack;
import static com.neusoft.rsapm.compile.Variate.*;
import static com.neusoft.rsapm.compile.Variate.COMMA_VARIATE;
import static com.neusoft.rsapm.compile.VariateType.*;
/**
* @author Muxin Sun
* @date 2018/12/20
*/
public class Syntactic {
private static Variate transform(final Lexical lexical, final Variate variate) throws CompilerException {
if (variate.isORIGINAL() && Util.isNumeric(variate.getSb().toString())) {
variate.toNUMERIC();
return variate;
} else if (variate.isORIGINAL() && lexical.isVariate(variate.getSb().toString())) {
return lexical.getVariate(variate.getSb().toString());
} else if (variate.isORIGINAL()) {
throw new CompilerException("no variate.");
}
return variate;
}
/**
* calculate expr value
*
* @param lexical lexical
* @param expr expr
* @return Variate
*/
public static Variate getExprValue(final Lexical lexical, final String expr) throws CompilerException {
final BaseQuery baseQuery = new BaseQuery();
List words = Variate.spliteExpr(expr, baseQuery);
baseQuery.exeQuery();
return getExprValue(lexical, baseQuery, words);
}
/**
* calculate expr value
*
* @param lexical lexical
* @param baseQuery baseQuery
* @param words words
* @return Variate
*/
public static Variate getExprValue(final Lexical lexical, final BaseQuery baseQuery,
final List words) throws CompilerException {
boolean isQuery = false;
Stack operators = new Stack<>();
Stack numbers = new Stack<>();
Variate variate = Variate.build("");
for (String word : words) {
switch (word) {
case LEFT_PARENTHESIS:
if (Objects.deepEquals(variate.isEmpty(), false)) {
variate.toFUNCTION();
operators.push(variate);
}
operators.push(LEFT_PARENTHESIS_VARIATE);
variate = Variate.build("");
break;
case RIGHT_PARENTHESIS:
List variates = new ArrayList<>();
variate = transform(lexical, variate);
while (!operators.isEmpty()) {
if (operators.peek().equals(LEFT_PARENTHESIS_VARIATE)) {
operators.pop();
variates.add(variate);
if (!operators.isEmpty() && operators.peek().isFUNCTION()) {
variate = lexical.execute(operators.pop().getValue().getAsString(), variates);
}
break;
} else if (operators.peek().equals(COMMA_VARIATE)) {
operators.pop();
variates.add(numbers.pop());
} else if (operators.peek().equals(GREATER_THAN_VARIATE)) {
operators.pop();
variate = lexical.gt(numbers.pop(), variate);
} else if (operators.peek().equals(LESS_THAN_VARIATE)) {
operators.pop();
variate = lexical.lt(numbers.pop(), variate);
} else if (operators.peek().equals(EQUAL_VARIATE)) {
operators.pop();
variate = lexical.eq(numbers.pop(), variate);
} else if (operators.peek().equals(GREATER_EQUAL_VARIATE)) {
operators.pop();
variate = lexical.ge(numbers.pop(), variate);
} else if (operators.peek().equals(LESS_EQUAL_VARIATE)) {
operators.pop();
variate = lexical.le(numbers.pop(), variate);
} else if (operators.peek().equals(PLUS_VARIATE)) {
operators.pop();
variate = lexical.plus(numbers.pop(), variate);
} else if (operators.peek().equals(MINUS_VARIATE)) {
operators.pop();
variate = lexical.minus(numbers.pop(), variate);
} else if (operators.peek().equals(TIMES_VARIATE)) {
operators.pop();
variate = lexical.times(numbers.pop(), variate);
} else if (operators.peek().equals(DIVISION_VARIATE)) {
operators.pop();
variate = lexical.division(numbers.pop(), variate);
} else {
throw new CompilerException(
"operators error : " + operators.peek());
}
}
break;
case COMMA:
variate = transform(lexical, variate);
while (!operators.isEmpty()) {
if (operators.peek().equals(LEFT_PARENTHESIS_VARIATE) || operators.peek().equals(COMMA_VARIATE)) {
break;
} else if (operators.peek().equals(GREATER_THAN_VARIATE)) {
operators.pop();
variate = lexical.gt(numbers.pop(), variate);
} else if (operators.peek().equals(LESS_THAN_VARIATE)) {
operators.pop();
variate = lexical.lt(numbers.pop(), variate);
} else if (operators.peek().equals(EQUAL_VARIATE)) {
operators.pop();
variate = lexical.eq(numbers.pop(), variate);
} else if (operators.peek().equals(GREATER_EQUAL_VARIATE)) {
operators.pop();
variate = lexical.ge(numbers.pop(), variate);
} else if (operators.peek().equals(LESS_EQUAL_VARIATE)) {
operators.pop();
variate = lexical.le(numbers.pop(), variate);
} else if (operators.peek().equals(PLUS_VARIATE)) {
operators.pop();
variate = lexical.plus(numbers.pop(), variate);
} else if (operators.peek().equals(MINUS_VARIATE)) {
operators.pop();
variate = lexical.minus(numbers.pop(), variate);
} else if (operators.peek().equals(TIMES_VARIATE)) {
operators.pop();
variate = lexical.times(numbers.pop(), variate);
} else if (operators.peek().equals(DIVISION_VARIATE)) {
operators.pop();
variate = lexical.division(numbers.pop(), variate);
} else {
throw new CompilerException(
"operators error : " + operators.peek());
}
}
numbers.push(variate);
operators.push(COMMA_VARIATE);
variate = Variate.build("");
break;
case GREATER_THAN:
variate = transform(lexical, variate);
while (!operators.isEmpty()) {
if (operators.peek().equals(LEFT_PARENTHESIS_VARIATE) || operators.peek().equals(COMMA_VARIATE)) {
break;
} else if (operators.peek().equals(GREATER_THAN_VARIATE)) {
operators.pop();
variate = lexical.gt(numbers.pop(), variate);
} else if (operators.peek().equals(GREATER_EQUAL_VARIATE)) {
operators.pop();
variate = lexical.ge(numbers.pop(), variate);
} else if (operators.peek().equals(LESS_THAN)) {
operators.pop();
variate = lexical.lt(numbers.pop(), variate);
} else if (operators.peek().equals(LESS_EQUAL_VARIATE)) {
operators.pop();
variate = lexical.le(numbers.pop(), variate);
} else if (operators.peek().equals(EQUAL)) {
operators.pop();
variate = lexical.eq(numbers.pop(), variate);
} else if (operators.peek().equals(PLUS)) {
operators.pop();
variate = lexical.plus(numbers.pop(), variate);
} else if (operators.peek().equals(MINUS)) {
operators.pop();
variate = lexical.minus(numbers.pop(), variate);
} else if (operators.peek().equals(TIMES)) {
operators.pop();
variate = lexical.times(numbers.pop(), variate);
} else if (operators.peek().equals(DIVISION)) {
operators.pop();
variate = lexical.division(numbers.pop(), variate);
} else {
throw new CompilerException(
"operators error : " + operators.peek());
}
}
numbers.push(variate);
operators.push(GREATER_THAN_VARIATE);
variate = Variate.build("");
break;
case GREATER_EQUAL:
variate = transform(lexical, variate);
while (!operators.isEmpty()) {
if (operators.peek().equals(LEFT_PARENTHESIS_VARIATE) || operators.peek().equals(COMMA_VARIATE)) {
break;
} else if (operators.peek().equals(GREATER_THAN_VARIATE)) {
operators.pop();
variate = lexical.gt(numbers.pop(), variate);
} else if (operators.peek().equals(GREATER_EQUAL_VARIATE)) {
operators.pop();
variate = lexical.ge(numbers.pop(), variate);
} else if (operators.peek().equals(LESS_THAN)) {
operators.pop();
variate = lexical.lt(numbers.pop(), variate);
} else if (operators.peek().equals(LESS_EQUAL_VARIATE)) {
operators.pop();
variate = lexical.le(numbers.pop(), variate);
} else if (operators.peek().equals(EQUAL)) {
operators.pop();
variate = lexical.eq(numbers.pop(), variate);
} else if (operators.peek().equals(PLUS)) {
operators.pop();
variate = lexical.plus(numbers.pop(), variate);
} else if (operators.peek().equals(MINUS)) {
operators.pop();
variate = lexical.minus(numbers.pop(), variate);
} else if (operators.peek().equals(TIMES)) {
operators.pop();
variate = lexical.times(numbers.pop(), variate);
} else if (operators.peek().equals(DIVISION)) {
operators.pop();
variate = lexical.division(numbers.pop(), variate);
} else {
throw new CompilerException(
"operators error : " + operators.peek());
}
}
numbers.push(variate);
operators.push(GREATER_EQUAL_VARIATE);
variate = Variate.build("");
break;
case LESS_THAN:
variate = transform(lexical, variate);
while (!operators.isEmpty()) {
if (operators.peek().equals(LEFT_PARENTHESIS_VARIATE) || operators.peek().equals(COMMA_VARIATE)) {
break;
} else if (operators.peek().equals(GREATER_THAN_VARIATE)) {
operators.pop();
variate = lexical.gt(numbers.pop(), variate);
} else if (operators.peek().equals(GREATER_EQUAL_VARIATE)) {
operators.pop();
variate = lexical.ge(numbers.pop(), variate);
} else if (operators.peek().equals(LESS_THAN)) {
operators.pop();
variate = lexical.lt(numbers.pop(), variate);
} else if (operators.peek().equals(LESS_EQUAL_VARIATE)) {
operators.pop();
variate = lexical.le(numbers.pop(), variate);
} else if (operators.peek().equals(EQUAL)) {
operators.pop();
variate = lexical.eq(numbers.pop(), variate);
} else if (operators.peek().equals(PLUS)) {
operators.pop();
variate = lexical.plus(numbers.pop(), variate);
} else if (operators.peek().equals(MINUS)) {
operators.pop();
variate = lexical.minus(numbers.pop(), variate);
} else if (operators.peek().equals(TIMES)) {
operators.pop();
variate = lexical.times(numbers.pop(), variate);
} else if (operators.peek().equals(DIVISION)) {
operators.pop();
variate = lexical.division(numbers.pop(), variate);
} else {
throw new CompilerException(
"operators error : " + operators.peek());
}
}
numbers.push(variate);
operators.push(LESS_THAN_VARIATE);
variate = Variate.build("");
break;
case LESS_EQUAL:
variate = transform(lexical, variate);
while (!operators.isEmpty()) {
if (operators.peek().equals(LEFT_PARENTHESIS_VARIATE) || operators.peek().equals(COMMA_VARIATE)) {
break;
} else if (operators.peek().equals(GREATER_THAN_VARIATE)) {
operators.pop();
variate = lexical.gt(numbers.pop(), variate);
} else if (operators.peek().equals(GREATER_EQUAL_VARIATE)) {
operators.pop();
variate = lexical.ge(numbers.pop(), variate);
} else if (operators.peek().equals(LESS_THAN)) {
operators.pop();
variate = lexical.lt(numbers.pop(), variate);
} else if (operators.peek().equals(LESS_EQUAL_VARIATE)) {
operators.pop();
variate = lexical.le(numbers.pop(), variate);
} else if (operators.peek().equals(EQUAL)) {
operators.pop();
variate = lexical.eq(numbers.pop(), variate);
} else if (operators.peek().equals(PLUS)) {
operators.pop();
variate = lexical.plus(numbers.pop(), variate);
} else if (operators.peek().equals(MINUS)) {
operators.pop();
variate = lexical.minus(numbers.pop(), variate);
} else if (operators.peek().equals(TIMES)) {
operators.pop();
variate = lexical.times(numbers.pop(), variate);
} else if (operators.peek().equals(DIVISION)) {
operators.pop();
variate = lexical.division(numbers.pop(), variate);
} else {
throw new CompilerException(
"operators error : " + operators.peek());
}
}
numbers.push(variate);
operators.push(LESS_EQUAL_VARIATE);
variate = Variate.build("");
break;
case EQUAL:
variate = transform(lexical, variate);
while (!operators.isEmpty()) {
if (operators.peek().equals(LEFT_PARENTHESIS_VARIATE) || operators.peek().equals(COMMA_VARIATE)) {
break;
} else if (operators.peek().equals(GREATER_THAN_VARIATE)) {
operators.pop();
variate = lexical.gt(numbers.pop(), variate);
} else if (operators.peek().equals(GREATER_EQUAL_VARIATE)) {
operators.pop();
variate = lexical.ge(numbers.pop(), variate);
} else if (operators.peek().equals(LESS_THAN)) {
operators.pop();
variate = lexical.lt(numbers.pop(), variate);
} else if (operators.peek().equals(LESS_EQUAL_VARIATE)) {
operators.pop();
variate = lexical.le(numbers.pop(), variate);
} else if (operators.peek().equals(EQUAL)) {
operators.pop();
variate = lexical.eq(numbers.pop(), variate);
} else if (operators.peek().equals(PLUS)) {
operators.pop();
variate = lexical.plus(numbers.pop(), variate);
} else if (operators.peek().equals(MINUS)) {
operators.pop();
variate = lexical.minus(numbers.pop(), variate);
} else if (operators.peek().equals(TIMES)) {
operators.pop();
variate = lexical.times(numbers.pop(), variate);
} else if (operators.peek().equals(DIVISION)) {
operators.pop();
variate = lexical.division(numbers.pop(), variate);
} else {
throw new CompilerException(
"operators error : " + operators.peek());
}
}
numbers.push(variate);
operators.push(EQUAL_VARIATE);
variate = Variate.build("");
break;
case PLUS:
variate = transform(lexical, variate);
while (!operators.isEmpty()) {
if (operators.peek().equals(LEFT_PARENTHESIS_VARIATE) || operators.peek().equals(COMMA_VARIATE) ||
operators.peek().equals(GREATER_THAN_VARIATE) || operators.peek().equals(GREATER_EQUAL_VARIATE) ||
operators.peek().equals(LESS_THAN_VARIATE) || operators.peek().equals(LESS_EQUAL_VARIATE) ||
operators.peek().equals(EQUAL_VARIATE)) {
break;
} else if (operators.peek().equals(PLUS_VARIATE)) {
operators.pop();
variate = lexical.plus(numbers.pop(), variate);
} else if (operators.peek().equals(MINUS_VARIATE)) {
operators.pop();
variate = lexical.minus(numbers.pop(), variate);
} else if (operators.peek().equals(TIMES_VARIATE)) {
operators.pop();
variate = lexical.times(numbers.pop(), variate);
} else if (operators.peek().equals(DIVISION_VARIATE)) {
operators.pop();
variate = lexical.division(numbers.pop(), variate);
} else {
throw new CompilerException(
"operators error : " + operators.peek().getValue());
}
}
numbers.push(variate);
operators.push(PLUS_VARIATE);
variate = Variate.build("");
break;
case MINUS:
variate = transform(lexical, variate);
while (!operators.isEmpty()) {
if (operators.peek().equals(LEFT_PARENTHESIS_VARIATE) || operators.peek().equals(COMMA_VARIATE) ||
operators.peek().equals(GREATER_THAN_VARIATE) || operators.peek().equals(GREATER_EQUAL_VARIATE) ||
operators.peek().equals(LESS_THAN_VARIATE) || operators.peek().equals(LESS_EQUAL_VARIATE) ||
operators.peek().equals(EQUAL_VARIATE)) {
break;
} else if (operators.peek().equals(PLUS_VARIATE)) {
operators.pop();
variate = lexical.plus(numbers.pop(), variate);
} else if (operators.peek().equals(MINUS_VARIATE)) {
operators.pop();
variate = lexical.minus(numbers.pop(), variate);
} else if (operators.peek().equals(TIMES_VARIATE)) {
operators.pop();
variate = lexical.times(numbers.pop(), variate);
} else if (operators.peek().equals(DIVISION_VARIATE)) {
operators.pop();
variate = lexical.division(numbers.pop(), variate);
} else {
throw new CompilerException(
"operators error : " + operators.peek().getValue());
}
}
numbers.push(variate);
operators.push(MINUS_VARIATE);
variate = Variate.build("");
break;
case TIMES:
variate = transform(lexical, variate);
while (!operators.isEmpty()) {
if (operators.peek().equals(LEFT_PARENTHESIS_VARIATE) || operators.peek().equals(COMMA_VARIATE) ||
operators.peek().equals(GREATER_THAN_VARIATE) || operators.peek().equals(GREATER_EQUAL_VARIATE) ||
operators.peek().equals(LESS_THAN_VARIATE) || operators.peek().equals(LESS_EQUAL_VARIATE) ||
operators.peek().equals(EQUAL_VARIATE) || operators.peek().equals(PLUS_VARIATE) ||
operators.peek().equals(MINUS_VARIATE)) {
break;
} else if (operators.peek().equals(TIMES_VARIATE)) {
operators.pop();
variate = lexical.times(numbers.pop(), variate);
} else if (operators.peek().equals(DIVISION_VARIATE)) {
operators.pop();
variate = lexical.division(numbers.pop(), variate);
} else {
throw new CompilerException(
"operators error : " + operators.peek().getValue());
}
}
numbers.push(variate);
operators.push(TIMES_VARIATE);
variate = Variate.build("");
break;
case DIVISION:
variate = transform(lexical, variate);
while (!operators.isEmpty()) {
if (operators.peek().equals(LEFT_PARENTHESIS_VARIATE) || operators.peek().equals(COMMA_VARIATE) ||
operators.peek().equals(GREATER_THAN_VARIATE) || operators.peek().equals(GREATER_EQUAL_VARIATE) ||
operators.peek().equals(LESS_THAN_VARIATE) || operators.peek().equals(LESS_EQUAL_VARIATE) ||
operators.peek().equals(EQUAL_VARIATE) || operators.peek().equals(PLUS_VARIATE) ||
operators.peek().equals(MINUS_VARIATE)) {
break;
} else if (operators.peek().equals(TIMES_VARIATE)) {
operators.pop();
variate = lexical.times(numbers.pop(), variate);
} else if (operators.peek().equals(DIVISION_VARIATE)) {
operators.pop();
variate = lexical.division(numbers.pop(), variate);
} else {
throw new CompilerException(
"operators error : " + operators.peek().getValue());
}
}
numbers.push(variate);
operators.push(DIVISION_VARIATE);
variate = Variate.build("");
break;
case QUERY:
isQuery = !isQuery;
break;
default:
if (isQuery) {
if (variate.isEmpty()) {
variate = Variate.build(ARRAY, baseQuery.getResponse(word));
} else {
throw new CompilerException("operators error.");
}
} else {
variate.expand(word);
}
}
}
variate = transform(lexical, variate);
while ( !operators.isEmpty() ) {
if (operators.peek().equals(COMMA_VARIATE)) {
operators.pop();
} else if (operators.peek().equals(GREATER_THAN_VARIATE)) {
operators.pop();
variate = lexical.gt(numbers.pop(), variate);
} else if (operators.peek().equals(GREATER_EQUAL_VARIATE)) {
operators.pop();
variate = lexical.ge(numbers.pop(), variate);
} else if (operators.peek().equals(LESS_THAN_VARIATE)) {
operators.pop();
variate = lexical.lt(numbers.pop(), variate);
} else if (operators.peek().equals(LESS_EQUAL_VARIATE)) {
operators.pop();
variate = lexical.lt(numbers.pop(), variate);
} else if (operators.peek().equals(EQUAL_VARIATE)) {
operators.pop();
variate = lexical.eq(numbers.pop(), variate);
} else if (operators.peek().equals(PLUS_VARIATE)) {
operators.pop();
variate = lexical.plus(numbers.pop(), variate);
} else if (operators.peek().equals(MINUS_VARIATE)) {
operators.pop();
variate = lexical.minus(numbers.pop(), variate);
} else if (operators.peek().equals(TIMES_VARIATE)) {
operators.pop();
variate = lexical.times(numbers.pop(), variate);
} else if (operators.peek().equals(DIVISION_VARIATE)) {
operators.pop();
variate = lexical.division(numbers.pop(), variate);
} else {
throw new CompilerException(
"operators error : " + operators.peek().getValue());
}
}
if (numbers.empty()) {
return variate;
}
throw new CompilerException(
"expr error : " + words);
}
}