From 8dffdb095a1a2369544299a66a6b7a8ccc1d010b Mon Sep 17 00:00:00 2001 From: Sidhant Aggarwal <10743214+sidhant92@users.noreply.github.com> Date: Sat, 16 Mar 2024 19:52:35 +0530 Subject: [PATCH 1/2] support for arithmetic expressions --- .../ArithmeticExpressionEvaluator.java | 97 ++++ .../BooleanExpressionEvaluator.java | 16 +- .../boolparser/constant/NodeType.java | 5 +- .../boolparser/constant/Operator.java | 23 +- .../domain/arithmetic/ArithmeticLeafNode.java | 28 + .../domain/arithmetic/ArithmeticNode.java | 30 + .../arithmetic/ArithmeticUnaryNode.java | 25 + .../exception/UnsupportedToken.java | 16 + .../boolparser/operator/OperatorFactory.java | 64 ++- .../boolparser/operator/OperatorService.java | 36 +- .../operator/arithmetic/AbstractOperator.java | 23 + .../operator/arithmetic/AddOperator.java | 55 ++ .../operator/arithmetic/DivideOperator.java | 45 ++ .../operator/arithmetic/ExponentOperator.java | 47 ++ .../operator/arithmetic/ModulusOperator.java | 47 ++ .../operator/arithmetic/MultiplyOperator.java | 50 ++ .../operator/arithmetic/SubtractOperator.java | 50 ++ .../operator/arithmetic/UnaryOperator.java | 46 ++ .../{ => logical}/AbstractOperator.java | 2 +- .../{ => logical}/ContainsAllOperator.java | 2 +- .../{ => logical}/ContainsAnyOperator.java | 2 +- .../{ => logical}/EqualsOperator.java | 2 +- .../GreaterThanEqualOperator.java | 2 +- .../{ => logical}/GreaterThanOperator.java | 2 +- .../operator/{ => logical}/InOperator.java | 2 +- .../{ => logical}/LessThanEqualOperator.java | 2 +- .../{ => logical}/LessThanOperator.java | 2 +- .../{ => logical}/NotEqualsOperator.java | 2 +- .../antlr/BooleanExpressionBaseListener.java | 36 ++ .../parser/antlr/BooleanExpressionLexer.java | 344 ++++++------ .../antlr/BooleanExpressionListener.java | 34 ++ .../parser/antlr/BooleanExpressionParser.java | 531 ++++++++++++------ .../parser/antlr/BooleanFilterListener.java | 70 ++- .../sidhant92/boolparser/util/ValueUtils.java | 16 + src/main/java/resources/BooleanExpression.g4 | 22 + .../ArithmeticExpressionEvaluatorTest.java | 180 ++++++ .../antlr/BooleanFilterBoolParserTest.java | 50 ++ 37 files changed, 1640 insertions(+), 366 deletions(-) create mode 100644 src/main/java/com/github/sidhant92/boolparser/application/ArithmeticExpressionEvaluator.java create mode 100644 src/main/java/com/github/sidhant92/boolparser/domain/arithmetic/ArithmeticLeafNode.java create mode 100644 src/main/java/com/github/sidhant92/boolparser/domain/arithmetic/ArithmeticNode.java create mode 100644 src/main/java/com/github/sidhant92/boolparser/domain/arithmetic/ArithmeticUnaryNode.java create mode 100644 src/main/java/com/github/sidhant92/boolparser/exception/UnsupportedToken.java create mode 100644 src/main/java/com/github/sidhant92/boolparser/operator/arithmetic/AbstractOperator.java create mode 100644 src/main/java/com/github/sidhant92/boolparser/operator/arithmetic/AddOperator.java create mode 100644 src/main/java/com/github/sidhant92/boolparser/operator/arithmetic/DivideOperator.java create mode 100644 src/main/java/com/github/sidhant92/boolparser/operator/arithmetic/ExponentOperator.java create mode 100644 src/main/java/com/github/sidhant92/boolparser/operator/arithmetic/ModulusOperator.java create mode 100644 src/main/java/com/github/sidhant92/boolparser/operator/arithmetic/MultiplyOperator.java create mode 100644 src/main/java/com/github/sidhant92/boolparser/operator/arithmetic/SubtractOperator.java create mode 100644 src/main/java/com/github/sidhant92/boolparser/operator/arithmetic/UnaryOperator.java rename src/main/java/com/github/sidhant92/boolparser/operator/{ => logical}/AbstractOperator.java (93%) rename src/main/java/com/github/sidhant92/boolparser/operator/{ => logical}/ContainsAllOperator.java (96%) rename src/main/java/com/github/sidhant92/boolparser/operator/{ => logical}/ContainsAnyOperator.java (96%) rename src/main/java/com/github/sidhant92/boolparser/operator/{ => logical}/EqualsOperator.java (96%) rename src/main/java/com/github/sidhant92/boolparser/operator/{ => logical}/GreaterThanEqualOperator.java (96%) rename src/main/java/com/github/sidhant92/boolparser/operator/{ => logical}/GreaterThanOperator.java (96%) rename src/main/java/com/github/sidhant92/boolparser/operator/{ => logical}/InOperator.java (95%) rename src/main/java/com/github/sidhant92/boolparser/operator/{ => logical}/LessThanEqualOperator.java (96%) rename src/main/java/com/github/sidhant92/boolparser/operator/{ => logical}/LessThanOperator.java (96%) rename src/main/java/com/github/sidhant92/boolparser/operator/{ => logical}/NotEqualsOperator.java (96%) create mode 100644 src/test/java/com/github/sidhant92/boolparser/application/ArithmeticExpressionEvaluatorTest.java diff --git a/src/main/java/com/github/sidhant92/boolparser/application/ArithmeticExpressionEvaluator.java b/src/main/java/com/github/sidhant92/boolparser/application/ArithmeticExpressionEvaluator.java new file mode 100644 index 0000000..41906d6 --- /dev/null +++ b/src/main/java/com/github/sidhant92/boolparser/application/ArithmeticExpressionEvaluator.java @@ -0,0 +1,97 @@ +package com.github.sidhant92.boolparser.application; + +import java.util.Map; +import java.util.Optional; +import org.apache.commons.lang3.tuple.Pair; +import com.github.sidhant92.boolparser.constant.ContainerDataType; +import com.github.sidhant92.boolparser.constant.DataType; +import com.github.sidhant92.boolparser.constant.Operator; +import com.github.sidhant92.boolparser.domain.arithmetic.ArithmeticLeafNode; +import com.github.sidhant92.boolparser.domain.arithmetic.ArithmeticNode; +import com.github.sidhant92.boolparser.domain.arithmetic.ArithmeticUnaryNode; +import com.github.sidhant92.boolparser.domain.Node; +import com.github.sidhant92.boolparser.exception.UnsupportedToken; +import com.github.sidhant92.boolparser.operator.OperatorService; +import com.github.sidhant92.boolparser.parser.BoolExpressionParser; +import com.github.sidhant92.boolparser.util.ValueUtils; +import io.vavr.control.Try; +import lombok.extern.slf4j.Slf4j; + +/** + * @author sidhant.aggarwal + * @since 15/03/2024 + */ +@Slf4j +public class ArithmeticExpressionEvaluator { + private final BoolExpressionParser boolExpressionParser; + + private final OperatorService operatorService; + + public ArithmeticExpressionEvaluator(final BoolExpressionParser boolExpressionParser) { + this.boolExpressionParser = boolExpressionParser; + operatorService = new OperatorService(); + } + + public Try evaluate(final String expression, final Map data) { + final Try tokenOptional = boolExpressionParser.parseExpression(expression, null); + return tokenOptional.map(node -> evaluateToken(node, data)); + } + + private Object evaluateToken(final Node node, final Map data) { + switch (node.getTokenType()) { + case ARITHMETIC: + return evaluateArithmeticToken((ArithmeticNode) node, data); + case ARITHMETIC_LEAF: + return evaluateArithmeticLeafToken((ArithmeticLeafNode) node, data); + case ARITHMETIC_UNARY: + return evaluateUnaryArithmeticToken((ArithmeticUnaryNode) node, data); + default: + log.error("unsupported token {}", node.getTokenType()); + throw new UnsupportedToken(); + } + } + + private Pair evaluateArithmeticLeafToken(final ArithmeticLeafNode arithmeticLeafNode, final Map data) { + final Optional fetchedValue = ValueUtils.getValueFromMap(arithmeticLeafNode.getOperand().toString(), data); + return fetchedValue + .map(o -> Pair.of(o, ValueUtils.getDataType(o))) + .orElseGet(() -> Pair.of(arithmeticLeafNode.getOperand(), arithmeticLeafNode.getDataType())); + } + + private Object evaluateUnaryArithmeticToken(final ArithmeticUnaryNode arithmeticUnaryNode, final Map data) { + final Object resolvedValue = evaluateToken(arithmeticUnaryNode.getOperand(), data); + if (resolvedValue instanceof Pair) { + final Pair pair = (Pair) resolvedValue; + return operatorService.evaluateArithmeticOperator(pair.getLeft(), pair.getRight(), null, null, Operator.UNARY, + ContainerDataType.PRIMITIVE); + } + final DataType dataType = ValueUtils.getDataType(resolvedValue); + return operatorService.evaluateArithmeticOperator(resolvedValue, dataType, null, null, Operator.UNARY, ContainerDataType.PRIMITIVE); + } + + private Object evaluateArithmeticToken(final ArithmeticNode arithmeticNode, final Map data) { + final Object leftValue = evaluateToken(arithmeticNode.getLeft(), data); + final Object rightValue = evaluateToken(arithmeticNode.getRight(), data); + if (leftValue instanceof Pair && rightValue instanceof Pair) { + final Pair leftPair = (Pair) leftValue; + final Pair rightPair = (Pair) rightValue; + return operatorService.evaluateArithmeticOperator(leftPair.getLeft(), leftPair.getRight(), rightPair.getLeft(), rightPair.getRight(), + arithmeticNode.getOperator(), ContainerDataType.PRIMITIVE); + } else if (leftValue instanceof Pair) { + final Pair leftPair = (Pair) leftValue; + final DataType rightDataType = ValueUtils.getDataType(rightValue); + return operatorService.evaluateArithmeticOperator(leftPair.getLeft(), leftPair.getRight(), rightValue, rightDataType, + arithmeticNode.getOperator(), ContainerDataType.PRIMITIVE); + } else if (rightValue instanceof Pair) { + final Pair rightPair = (Pair) rightValue; + final DataType leftDataType = ValueUtils.getDataType(leftValue); + return operatorService.evaluateArithmeticOperator(leftValue, leftDataType, rightPair.getLeft(), rightPair.getRight(), + arithmeticNode.getOperator(), ContainerDataType.PRIMITIVE); + } else { + final DataType leftDataType = ValueUtils.getDataType(leftValue); + final DataType rightDataType = ValueUtils.getDataType(rightValue); + return operatorService.evaluateArithmeticOperator(leftValue, leftDataType, rightValue, rightDataType, arithmeticNode.getOperator(), + ContainerDataType.PRIMITIVE); + } + } +} diff --git a/src/main/java/com/github/sidhant92/boolparser/application/BooleanExpressionEvaluator.java b/src/main/java/com/github/sidhant92/boolparser/application/BooleanExpressionEvaluator.java index ce6105d..cc36546 100644 --- a/src/main/java/com/github/sidhant92/boolparser/application/BooleanExpressionEvaluator.java +++ b/src/main/java/com/github/sidhant92/boolparser/application/BooleanExpressionEvaluator.java @@ -66,17 +66,15 @@ private boolean evaluateToken(final Node node, final Map data) { private boolean evaluateComparisonToken(final ComparisonNode comparisonToken, final Map data) { final Object fieldData = ValueUtils.getValueFromMap(comparisonToken.getField(), data).orElseThrow(DataNotFoundException::new); - return operatorService.evaluate(comparisonToken.getOperator(), ContainerDataType.PRIMITIVE, comparisonToken.getDataType(), fieldData, - comparisonToken.getValue()); + return operatorService.evaluateLogicalOperator(comparisonToken.getOperator(), ContainerDataType.PRIMITIVE, comparisonToken.getDataType(), + fieldData, comparisonToken.getValue()); } private boolean evaluateNumericRangeToken(final NumericRangeNode numericRangeToken, final Map data) { final Object fieldData = ValueUtils.getValueFromMap(numericRangeToken.getField(), data).orElseThrow(DataNotFoundException::new); - return operatorService.evaluate(Operator.GREATER_THAN_EQUAL, ContainerDataType.PRIMITIVE, numericRangeToken.getFromDataType(), fieldData, - numericRangeToken.getFromValue()) && operatorService.evaluate(Operator.LESS_THAN_EQUAL, - ContainerDataType.PRIMITIVE, - numericRangeToken.getToDataType(), fieldData, - numericRangeToken.getToValue()); + return operatorService.evaluateLogicalOperator(Operator.GREATER_THAN_EQUAL, ContainerDataType.PRIMITIVE, numericRangeToken.getFromDataType(), + fieldData, numericRangeToken.getFromValue()) && operatorService.evaluateLogicalOperator( + Operator.LESS_THAN_EQUAL, ContainerDataType.PRIMITIVE, numericRangeToken.getToDataType(), fieldData, numericRangeToken.getToValue()); } private boolean evaluateInToken(final InNode inToken, final Map data) { @@ -85,7 +83,7 @@ private boolean evaluateInToken(final InNode inToken, final Map final Object[] values = inToken.getItems() .stream() .map(Pair::getRight).toArray(); - return operatorService.evaluate(Operator.IN, ContainerDataType.PRIMITIVE, dataType, fieldData, values); + return operatorService.evaluateLogicalOperator(Operator.IN, ContainerDataType.PRIMITIVE, dataType, fieldData, values); } private boolean evaluateArrayToken(final ArrayNode arrayNode, final Map data) { @@ -99,7 +97,7 @@ private boolean evaluateArrayToken(final ArrayNode arrayNode, final Map data) { diff --git a/src/main/java/com/github/sidhant92/boolparser/constant/NodeType.java b/src/main/java/com/github/sidhant92/boolparser/constant/NodeType.java index 7625f19..38a0026 100644 --- a/src/main/java/com/github/sidhant92/boolparser/constant/NodeType.java +++ b/src/main/java/com/github/sidhant92/boolparser/constant/NodeType.java @@ -10,5 +10,8 @@ public enum NodeType { NUMERIC_RANGE, IN, ARRAY, - UNARY + UNARY, + ARITHMETIC, + ARITHMETIC_LEAF, + ARITHMETIC_UNARY } diff --git a/src/main/java/com/github/sidhant92/boolparser/constant/Operator.java b/src/main/java/com/github/sidhant92/boolparser/constant/Operator.java index 170e7d7..649199b 100644 --- a/src/main/java/com/github/sidhant92/boolparser/constant/Operator.java +++ b/src/main/java/com/github/sidhant92/boolparser/constant/Operator.java @@ -1,7 +1,7 @@ package com.github.sidhant92.boolparser.constant; import java.util.Optional; -import com.github.sidhant92.boolparser.operator.AbstractOperator; +import com.github.sidhant92.boolparser.operator.logical.AbstractOperator; import com.github.sidhant92.boolparser.operator.OperatorFactory; import lombok.AccessLevel; import lombok.AllArgsConstructor; @@ -21,15 +21,32 @@ public enum Operator { LESS_THAN_EQUAL, NOT_EQUAL, IN, + + ADD, + SUBTRACT, + MULTIPLY, + DIVIDE, + MODULUS, + EXPONENT, + UNARY, + CONTAINS_ALL, CONTAINS_ANY; public static Optional getOperatorFromSymbol(final String symbol) { final String symbolLowerCase = symbol.toLowerCase(); - return OperatorFactory.getAllOperators() + final Optional operator = OperatorFactory.getAllLogicalOperators() .stream() - .filter(operator -> operator.getSymbol().toLowerCase().equals(symbolLowerCase)) + .filter(op -> op.getSymbol().toLowerCase().equals(symbolLowerCase)) .map(AbstractOperator::getOperator) .findFirst(); + if (operator.isPresent()) { + return operator; + } + return OperatorFactory.getAllArithmeticOperators() + .stream() + .filter(op -> op.getSymbol().toLowerCase().equals(symbolLowerCase)) + .map(com.github.sidhant92.boolparser.operator.arithmetic.AbstractOperator::getOperator) + .findFirst(); } } diff --git a/src/main/java/com/github/sidhant92/boolparser/domain/arithmetic/ArithmeticLeafNode.java b/src/main/java/com/github/sidhant92/boolparser/domain/arithmetic/ArithmeticLeafNode.java new file mode 100644 index 0000000..6df653f --- /dev/null +++ b/src/main/java/com/github/sidhant92/boolparser/domain/arithmetic/ArithmeticLeafNode.java @@ -0,0 +1,28 @@ +package com.github.sidhant92.boolparser.domain.arithmetic; + +import com.github.sidhant92.boolparser.constant.DataType; +import com.github.sidhant92.boolparser.constant.NodeType; +import com.github.sidhant92.boolparser.domain.Node; +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Getter; +import lombok.Setter; + +/** + * @author sidhant.aggarwal + * @since 15/03/2024 + */ +@AllArgsConstructor +@Getter +@Setter +@Builder +public class ArithmeticLeafNode extends Node { + private Object operand; + + private DataType dataType; + + @Override + public NodeType getTokenType() { + return NodeType.ARITHMETIC_LEAF; + } +} diff --git a/src/main/java/com/github/sidhant92/boolparser/domain/arithmetic/ArithmeticNode.java b/src/main/java/com/github/sidhant92/boolparser/domain/arithmetic/ArithmeticNode.java new file mode 100644 index 0000000..b1e5468 --- /dev/null +++ b/src/main/java/com/github/sidhant92/boolparser/domain/arithmetic/ArithmeticNode.java @@ -0,0 +1,30 @@ +package com.github.sidhant92.boolparser.domain.arithmetic; + +import com.github.sidhant92.boolparser.constant.NodeType; +import com.github.sidhant92.boolparser.constant.Operator; +import com.github.sidhant92.boolparser.domain.Node; +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Getter; +import lombok.Setter; + +/** + * @author sidhant.aggarwal + * @since 15/03/2024 + */ +@AllArgsConstructor +@Getter +@Setter +@Builder +public class ArithmeticNode extends Node { + private Node left; + + private Node right; + + private final Operator operator; + + @Override + public NodeType getTokenType() { + return NodeType.ARITHMETIC; + } +} diff --git a/src/main/java/com/github/sidhant92/boolparser/domain/arithmetic/ArithmeticUnaryNode.java b/src/main/java/com/github/sidhant92/boolparser/domain/arithmetic/ArithmeticUnaryNode.java new file mode 100644 index 0000000..7adda3d --- /dev/null +++ b/src/main/java/com/github/sidhant92/boolparser/domain/arithmetic/ArithmeticUnaryNode.java @@ -0,0 +1,25 @@ +package com.github.sidhant92.boolparser.domain.arithmetic; + +import com.github.sidhant92.boolparser.constant.NodeType; +import com.github.sidhant92.boolparser.domain.Node; +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Getter; +import lombok.Setter; + +/** + * @author sidhant.aggarwal + * @since 15/03/2024 + */ +@AllArgsConstructor +@Getter +@Setter +@Builder +public class ArithmeticUnaryNode extends Node { + private Node operand; + + @Override + public NodeType getTokenType() { + return NodeType.ARITHMETIC_UNARY; + } +} diff --git a/src/main/java/com/github/sidhant92/boolparser/exception/UnsupportedToken.java b/src/main/java/com/github/sidhant92/boolparser/exception/UnsupportedToken.java new file mode 100644 index 0000000..69a29bc --- /dev/null +++ b/src/main/java/com/github/sidhant92/boolparser/exception/UnsupportedToken.java @@ -0,0 +1,16 @@ +package com.github.sidhant92.boolparser.exception; + +public class UnsupportedToken extends RuntimeException { + public UnsupportedToken(final String message) { + super(message); + } + + public UnsupportedToken() { + super(); + } + + @Override + public String getMessage() { + return "Unsupported Token"; + } +} diff --git a/src/main/java/com/github/sidhant92/boolparser/operator/OperatorFactory.java b/src/main/java/com/github/sidhant92/boolparser/operator/OperatorFactory.java index cdf7833..6ec24ac 100644 --- a/src/main/java/com/github/sidhant92/boolparser/operator/OperatorFactory.java +++ b/src/main/java/com/github/sidhant92/boolparser/operator/OperatorFactory.java @@ -5,13 +5,33 @@ import java.util.List; import java.util.Map; import com.github.sidhant92.boolparser.constant.Operator; +import com.github.sidhant92.boolparser.operator.arithmetic.AddOperator; +import com.github.sidhant92.boolparser.operator.arithmetic.DivideOperator; +import com.github.sidhant92.boolparser.operator.arithmetic.ExponentOperator; +import com.github.sidhant92.boolparser.operator.arithmetic.ModulusOperator; +import com.github.sidhant92.boolparser.operator.arithmetic.MultiplyOperator; +import com.github.sidhant92.boolparser.operator.arithmetic.SubtractOperator; +import com.github.sidhant92.boolparser.operator.arithmetic.UnaryOperator; +import com.github.sidhant92.boolparser.operator.logical.AbstractOperator; +import com.github.sidhant92.boolparser.operator.logical.ContainsAllOperator; +import com.github.sidhant92.boolparser.operator.logical.ContainsAnyOperator; +import com.github.sidhant92.boolparser.operator.logical.EqualsOperator; +import com.github.sidhant92.boolparser.operator.logical.GreaterThanEqualOperator; +import com.github.sidhant92.boolparser.operator.logical.GreaterThanOperator; +import com.github.sidhant92.boolparser.operator.logical.InOperator; +import com.github.sidhant92.boolparser.operator.logical.LessThanEqualOperator; +import com.github.sidhant92.boolparser.operator.logical.LessThanOperator; +import com.github.sidhant92.boolparser.operator.logical.NotEqualsOperator; /** * @author sidhant.aggarwal * @since 05/03/2023 */ public class OperatorFactory { - private static final Map operatorMap = new EnumMap<>(Operator.class); + private static final Map logicalOperatorMap = new EnumMap<>(Operator.class); + + private static final Map arithmeticOperatorMap = new EnumMap<>( + Operator.class); private OperatorFactory() { super(); @@ -20,26 +40,38 @@ private OperatorFactory() { public static void initialize() { final EqualsOperator equalsOperator = new EqualsOperator(); final InOperator inOperator = new InOperator(equalsOperator); - operatorMap.put(Operator.EQUALS, equalsOperator); - operatorMap.put(Operator.GREATER_THAN, new GreaterThanOperator()); - operatorMap.put(Operator.GREATER_THAN_EQUAL, new GreaterThanEqualOperator()); - operatorMap.put(Operator.LESS_THAN, new LessThanOperator()); - operatorMap.put(Operator.LESS_THAN_EQUAL, new LessThanEqualOperator()); - operatorMap.put(Operator.NOT_EQUAL, new NotEqualsOperator()); - operatorMap.put(Operator.IN, new InOperator(equalsOperator)); - operatorMap.put(Operator.CONTAINS_ALL, new ContainsAllOperator(inOperator)); - operatorMap.put(Operator.CONTAINS_ANY, new ContainsAnyOperator(inOperator)); + logicalOperatorMap.put(Operator.EQUALS, equalsOperator); + logicalOperatorMap.put(Operator.GREATER_THAN, new GreaterThanOperator()); + logicalOperatorMap.put(Operator.GREATER_THAN_EQUAL, new GreaterThanEqualOperator()); + logicalOperatorMap.put(Operator.LESS_THAN, new LessThanOperator()); + logicalOperatorMap.put(Operator.LESS_THAN_EQUAL, new LessThanEqualOperator()); + logicalOperatorMap.put(Operator.NOT_EQUAL, new NotEqualsOperator()); + logicalOperatorMap.put(Operator.IN, new InOperator(equalsOperator)); + logicalOperatorMap.put(Operator.CONTAINS_ALL, new ContainsAllOperator(inOperator)); + logicalOperatorMap.put(Operator.CONTAINS_ANY, new ContainsAnyOperator(inOperator)); + + arithmeticOperatorMap.put(Operator.ADD, new AddOperator()); + arithmeticOperatorMap.put(Operator.SUBTRACT, new SubtractOperator()); + arithmeticOperatorMap.put(Operator.DIVIDE, new DivideOperator()); + arithmeticOperatorMap.put(Operator.MULTIPLY, new MultiplyOperator()); + arithmeticOperatorMap.put(Operator.EXPONENT, new ExponentOperator()); + arithmeticOperatorMap.put(Operator.MODULUS, new ModulusOperator()); + arithmeticOperatorMap.put(Operator.UNARY, new UnaryOperator()); + } + + public static AbstractOperator getLogicalOperator(final Operator operator) { + return logicalOperatorMap.get(operator); } - public static AbstractOperator getOperator(final Operator operator) { - return operatorMap.get(operator); + public static com.github.sidhant92.boolparser.operator.arithmetic.AbstractOperator getArithmeticOperator(final Operator operator) { + return arithmeticOperatorMap.get(operator); } - public static List getAllOperators() { - return new ArrayList<>(operatorMap.values()); + public static List getAllLogicalOperators() { + return new ArrayList<>(logicalOperatorMap.values()); } - public static void register(final AbstractOperator abstractOperator) { - operatorMap.put(abstractOperator.getOperator(), abstractOperator); + public static List getAllArithmeticOperators() { + return new ArrayList<>(arithmeticOperatorMap.values()); } } diff --git a/src/main/java/com/github/sidhant92/boolparser/operator/OperatorService.java b/src/main/java/com/github/sidhant92/boolparser/operator/OperatorService.java index bd31dd5..57d5853 100644 --- a/src/main/java/com/github/sidhant92/boolparser/operator/OperatorService.java +++ b/src/main/java/com/github/sidhant92/boolparser/operator/OperatorService.java @@ -1,11 +1,13 @@ package com.github.sidhant92.boolparser.operator; +import java.util.Objects; import com.github.sidhant92.boolparser.constant.ContainerDataType; import com.github.sidhant92.boolparser.constant.DataType; import com.github.sidhant92.boolparser.constant.Operator; import com.github.sidhant92.boolparser.datatype.DataTypeFactory; import com.github.sidhant92.boolparser.exception.InvalidContainerTypeException; import com.github.sidhant92.boolparser.exception.InvalidDataType; +import com.github.sidhant92.boolparser.operator.logical.AbstractOperator; import lombok.extern.slf4j.Slf4j; /** @@ -19,9 +21,9 @@ public OperatorService() { OperatorFactory.initialize(); } - public boolean evaluate(final Operator operator, final ContainerDataType containerDataType, final DataType dataType, final Object leftOperand, - final Object... rightOperands) { - final AbstractOperator abstractOperator = OperatorFactory.getOperator(operator); + public boolean evaluateLogicalOperator(final Operator operator, final ContainerDataType containerDataType, final DataType dataType, + final Object leftOperand, final Object... rightOperands) { + final AbstractOperator abstractOperator = OperatorFactory.getLogicalOperator(operator); if (!abstractOperator.getAllowedContainerTypes().contains(containerDataType)) { log.error("Invalid left container type {} for operator {}", containerDataType, operator); throw new InvalidContainerTypeException(); @@ -34,6 +36,32 @@ public boolean evaluate(final Operator operator, final ContainerDataType contain log.error("Validation failed for the operator {} for the operand {}", operator, leftOperand); throw new InvalidDataType(); } - return OperatorFactory.getOperator(operator).evaluate(containerDataType, dataType, leftOperand, rightOperands); + return OperatorFactory.getLogicalOperator(operator).evaluate(containerDataType, dataType, leftOperand, rightOperands); + } + + public Object evaluateArithmeticOperator(final Object leftOperand, final DataType leftDataType, final Object rightOperand, + final DataType rightDataType, final Operator operator, final ContainerDataType containerDataType) { + final com.github.sidhant92.boolparser.operator.arithmetic.AbstractOperator abstractOperator = OperatorFactory.getArithmeticOperator(operator); + if (!abstractOperator.getAllowedContainerTypes().contains(containerDataType)) { + log.error("Invalid left container type {} for operator {}", containerDataType, operator); + throw new InvalidContainerTypeException(); + } + if (!abstractOperator.getAllowedDataTypes().contains(leftDataType)) { + log.error("Invalid left operand data type {} for operator {}", leftDataType, operator); + throw new InvalidDataType(); + } + if (!containerDataType.isValid(leftDataType, leftOperand)) { + log.error("Validation failed for the operator {} for the operand {}", operator, leftOperand); + throw new InvalidDataType(); + } + if (Objects.nonNull(rightDataType) && !abstractOperator.getAllowedDataTypes().contains(rightDataType)) { + log.error("Invalid left operand data type {} for operator {}", rightDataType, operator); + throw new InvalidDataType(); + } + if (Objects.nonNull(rightOperand) && !containerDataType.isValid(rightDataType, rightOperand)) { + log.error("Validation failed for the operator {} for the operand {}", operator, rightDataType); + throw new InvalidDataType(); + } + return OperatorFactory.getArithmeticOperator(operator).evaluate(leftOperand, leftDataType, rightOperand, rightDataType); } } diff --git a/src/main/java/com/github/sidhant92/boolparser/operator/arithmetic/AbstractOperator.java b/src/main/java/com/github/sidhant92/boolparser/operator/arithmetic/AbstractOperator.java new file mode 100644 index 0000000..eda9c82 --- /dev/null +++ b/src/main/java/com/github/sidhant92/boolparser/operator/arithmetic/AbstractOperator.java @@ -0,0 +1,23 @@ +package com.github.sidhant92.boolparser.operator.arithmetic; + +import java.util.List; +import com.github.sidhant92.boolparser.constant.ContainerDataType; +import com.github.sidhant92.boolparser.constant.DataType; +import com.github.sidhant92.boolparser.constant.Operator; + +/** + * @author sidhant.aggarwal + * @since 15/03/2024 + */ +public abstract class AbstractOperator { + public abstract Object evaluate(final Object leftOperand, final DataType leftOperandDataType, final Object rightOperand, + final DataType rightOperandDataType); + + public abstract Operator getOperator(); + + public abstract String getSymbol(); + + public abstract List getAllowedContainerTypes(); + + public abstract List getAllowedDataTypes(); +} diff --git a/src/main/java/com/github/sidhant92/boolparser/operator/arithmetic/AddOperator.java b/src/main/java/com/github/sidhant92/boolparser/operator/arithmetic/AddOperator.java new file mode 100644 index 0000000..80dd2d4 --- /dev/null +++ b/src/main/java/com/github/sidhant92/boolparser/operator/arithmetic/AddOperator.java @@ -0,0 +1,55 @@ +package com.github.sidhant92.boolparser.operator.arithmetic; + +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Collections; +import java.util.List; +import com.github.sidhant92.boolparser.constant.ContainerDataType; +import com.github.sidhant92.boolparser.constant.DataType; +import com.github.sidhant92.boolparser.constant.Operator; +import com.github.sidhant92.boolparser.exception.InvalidDataType; + +/** + * @author sidhant.aggarwal + * @since 15/03/2024 + */ +public class AddOperator extends AbstractOperator { + @Override + public Object evaluate(final Object leftOperand, final DataType leftOperandDataType, final Object rightOperand, + final DataType rightOperandDataType) { + final List stringTypes = Arrays.asList(DataType.STRING, DataType.VERSION, DataType.BOOLEAN); + if (stringTypes.contains(leftOperandDataType) || stringTypes.contains(rightOperandDataType)) { + return leftOperand + String.valueOf(rightOperand); + } + if (leftOperandDataType.equals(DataType.DECIMAL) || rightOperandDataType.equals(DataType.DECIMAL)) { + return Double.parseDouble(leftOperand.toString()) + Double.parseDouble(rightOperand.toString()); + } + if (leftOperandDataType.equals(DataType.LONG) || rightOperandDataType.equals(DataType.LONG)) { + return Long.parseLong(leftOperand.toString()) + Long.parseLong(rightOperand.toString()); + } + if (leftOperandDataType.equals(DataType.INTEGER) || rightOperandDataType.equals(DataType.INTEGER)) { + return Integer.parseInt(leftOperand.toString()) + Integer.parseInt(rightOperand.toString()); + } + return leftOperand + String.valueOf(rightOperand); + } + + @Override + public Operator getOperator() { + return Operator.ADD; + } + + @Override + public String getSymbol() { + return "+"; + } + + @Override + public List getAllowedContainerTypes() { + return Collections.singletonList(ContainerDataType.PRIMITIVE); + } + + @Override + public List getAllowedDataTypes() { + return Arrays.asList(DataType.INTEGER, DataType.LONG, DataType.DECIMAL, DataType.STRING, DataType.BOOLEAN, DataType.VERSION); + } +} diff --git a/src/main/java/com/github/sidhant92/boolparser/operator/arithmetic/DivideOperator.java b/src/main/java/com/github/sidhant92/boolparser/operator/arithmetic/DivideOperator.java new file mode 100644 index 0000000..781d58d --- /dev/null +++ b/src/main/java/com/github/sidhant92/boolparser/operator/arithmetic/DivideOperator.java @@ -0,0 +1,45 @@ +package com.github.sidhant92.boolparser.operator.arithmetic; + +import java.util.Arrays; +import java.util.Collections; +import java.util.List; +import com.github.sidhant92.boolparser.constant.ContainerDataType; +import com.github.sidhant92.boolparser.constant.DataType; +import com.github.sidhant92.boolparser.constant.Operator; +import com.github.sidhant92.boolparser.exception.InvalidDataType; + +/** + * @author sidhant.aggarwal + * @since 15/03/2024 + */ +public class DivideOperator extends AbstractOperator { + @Override + public Object evaluate(final Object leftOperand, final DataType leftOperandDataType, final Object rightOperand, + final DataType rightOperandDataType) { + final double res = Double.parseDouble(leftOperand.toString()) / Double.parseDouble(rightOperand.toString()); + if ((int) res == res) { + return (int) res; + } + return res; + } + + @Override + public Operator getOperator() { + return Operator.DIVIDE; + } + + @Override + public String getSymbol() { + return "/"; + } + + @Override + public List getAllowedContainerTypes() { + return Collections.singletonList(ContainerDataType.PRIMITIVE); + } + + @Override + public List getAllowedDataTypes() { + return Arrays.asList(DataType.INTEGER, DataType.LONG, DataType.DECIMAL); + } +} diff --git a/src/main/java/com/github/sidhant92/boolparser/operator/arithmetic/ExponentOperator.java b/src/main/java/com/github/sidhant92/boolparser/operator/arithmetic/ExponentOperator.java new file mode 100644 index 0000000..db4640b --- /dev/null +++ b/src/main/java/com/github/sidhant92/boolparser/operator/arithmetic/ExponentOperator.java @@ -0,0 +1,47 @@ +package com.github.sidhant92.boolparser.operator.arithmetic; + +import java.util.Arrays; +import java.util.Collections; +import java.util.List; +import com.github.sidhant92.boolparser.constant.ContainerDataType; +import com.github.sidhant92.boolparser.constant.DataType; +import com.github.sidhant92.boolparser.constant.Operator; +import com.github.sidhant92.boolparser.exception.InvalidDataType; + +/** + * @author sidhant.aggarwal + * @since 15/03/2024 + */ +public class ExponentOperator extends AbstractOperator { + @Override + public Object evaluate(final Object leftOperand, final DataType leftOperandDataType, final Object rightOperand, + final DataType rightOperandDataType) { + if (leftOperandDataType.equals(DataType.LONG) || rightOperandDataType.equals(DataType.LONG)) { + return (long) Math.pow(Long.parseLong(leftOperand.toString()), Long.parseLong(rightOperand.toString())); + } + if (leftOperandDataType.equals(DataType.INTEGER) || rightOperandDataType.equals(DataType.INTEGER)) { + return (int) Math.pow(Long.parseLong(leftOperand.toString()), Long.parseLong(rightOperand.toString())); + } + throw new InvalidDataType(); + } + + @Override + public Operator getOperator() { + return Operator.EXPONENT; + } + + @Override + public String getSymbol() { + return "^"; + } + + @Override + public List getAllowedContainerTypes() { + return Collections.singletonList(ContainerDataType.PRIMITIVE); + } + + @Override + public List getAllowedDataTypes() { + return Arrays.asList(DataType.INTEGER, DataType.LONG); + } +} diff --git a/src/main/java/com/github/sidhant92/boolparser/operator/arithmetic/ModulusOperator.java b/src/main/java/com/github/sidhant92/boolparser/operator/arithmetic/ModulusOperator.java new file mode 100644 index 0000000..26c3d37 --- /dev/null +++ b/src/main/java/com/github/sidhant92/boolparser/operator/arithmetic/ModulusOperator.java @@ -0,0 +1,47 @@ +package com.github.sidhant92.boolparser.operator.arithmetic; + +import java.util.Arrays; +import java.util.Collections; +import java.util.List; +import com.github.sidhant92.boolparser.constant.ContainerDataType; +import com.github.sidhant92.boolparser.constant.DataType; +import com.github.sidhant92.boolparser.constant.Operator; +import com.github.sidhant92.boolparser.exception.InvalidDataType; + +/** + * @author sidhant.aggarwal + * @since 15/03/2024 + */ +public class ModulusOperator extends AbstractOperator { + @Override + public Object evaluate(final Object leftOperand, final DataType leftOperandDataType, final Object rightOperand, + final DataType rightOperandDataType) { + if (leftOperandDataType.equals(DataType.LONG) || rightOperandDataType.equals(DataType.LONG)) { + return Long.parseLong(leftOperand.toString()) % Long.parseLong(rightOperand.toString()); + } + if (leftOperandDataType.equals(DataType.INTEGER) || rightOperandDataType.equals(DataType.INTEGER)) { + return Integer.parseInt(leftOperand.toString()) % Integer.parseInt(rightOperand.toString()); + } + throw new InvalidDataType(); + } + + @Override + public Operator getOperator() { + return Operator.MODULUS; + } + + @Override + public String getSymbol() { + return "%"; + } + + @Override + public List getAllowedContainerTypes() { + return Collections.singletonList(ContainerDataType.PRIMITIVE); + } + + @Override + public List getAllowedDataTypes() { + return Arrays.asList(DataType.INTEGER, DataType.LONG); + } +} diff --git a/src/main/java/com/github/sidhant92/boolparser/operator/arithmetic/MultiplyOperator.java b/src/main/java/com/github/sidhant92/boolparser/operator/arithmetic/MultiplyOperator.java new file mode 100644 index 0000000..9cfa41d --- /dev/null +++ b/src/main/java/com/github/sidhant92/boolparser/operator/arithmetic/MultiplyOperator.java @@ -0,0 +1,50 @@ +package com.github.sidhant92.boolparser.operator.arithmetic; + +import java.util.Arrays; +import java.util.Collections; +import java.util.List; +import com.github.sidhant92.boolparser.constant.ContainerDataType; +import com.github.sidhant92.boolparser.constant.DataType; +import com.github.sidhant92.boolparser.constant.Operator; +import com.github.sidhant92.boolparser.exception.InvalidDataType; + +/** + * @author sidhant.aggarwal + * @since 15/03/2024 + */ +public class MultiplyOperator extends AbstractOperator { + @Override + public Object evaluate(final Object leftOperand, final DataType leftOperandDataType, final Object rightOperand, + final DataType rightOperandDataType) { + if (leftOperandDataType.equals(DataType.DECIMAL) || rightOperandDataType.equals(DataType.DECIMAL)) { + return Double.parseDouble(leftOperand.toString()) * Double.parseDouble(rightOperand.toString()); + } + if (leftOperandDataType.equals(DataType.LONG) || rightOperandDataType.equals(DataType.LONG)) { + return Long.parseLong(leftOperand.toString()) * Long.parseLong(rightOperand.toString()); + } + if (leftOperandDataType.equals(DataType.INTEGER) || rightOperandDataType.equals(DataType.INTEGER)) { + return Integer.parseInt(leftOperand.toString()) * Integer.parseInt(rightOperand.toString()); + } + throw new InvalidDataType(); + } + + @Override + public Operator getOperator() { + return Operator.MULTIPLY; + } + + @Override + public String getSymbol() { + return "*"; + } + + @Override + public List getAllowedContainerTypes() { + return Collections.singletonList(ContainerDataType.PRIMITIVE); + } + + @Override + public List getAllowedDataTypes() { + return Arrays.asList(DataType.INTEGER, DataType.LONG, DataType.DECIMAL); + } +} diff --git a/src/main/java/com/github/sidhant92/boolparser/operator/arithmetic/SubtractOperator.java b/src/main/java/com/github/sidhant92/boolparser/operator/arithmetic/SubtractOperator.java new file mode 100644 index 0000000..dab87b7 --- /dev/null +++ b/src/main/java/com/github/sidhant92/boolparser/operator/arithmetic/SubtractOperator.java @@ -0,0 +1,50 @@ +package com.github.sidhant92.boolparser.operator.arithmetic; + +import java.util.Arrays; +import java.util.Collections; +import java.util.List; +import com.github.sidhant92.boolparser.constant.ContainerDataType; +import com.github.sidhant92.boolparser.constant.DataType; +import com.github.sidhant92.boolparser.constant.Operator; +import com.github.sidhant92.boolparser.exception.InvalidDataType; + +/** + * @author sidhant.aggarwal + * @since 15/03/2024 + */ +public class SubtractOperator extends AbstractOperator { + @Override + public Object evaluate(final Object leftOperand, final DataType leftOperandDataType, final Object rightOperand, + final DataType rightOperandDataType) { + if (leftOperandDataType.equals(DataType.DECIMAL) || rightOperandDataType.equals(DataType.DECIMAL)) { + return Double.parseDouble(leftOperand.toString()) - Double.parseDouble(rightOperand.toString()); + } + if (leftOperandDataType.equals(DataType.LONG) || rightOperandDataType.equals(DataType.LONG)) { + return Long.parseLong(leftOperand.toString()) - Long.parseLong(rightOperand.toString()); + } + if (leftOperandDataType.equals(DataType.INTEGER) || rightOperandDataType.equals(DataType.INTEGER)) { + return Integer.parseInt(leftOperand.toString()) - Integer.parseInt(rightOperand.toString()); + } + throw new InvalidDataType(); + } + + @Override + public Operator getOperator() { + return Operator.SUBTRACT; + } + + @Override + public String getSymbol() { + return "-"; + } + + @Override + public List getAllowedContainerTypes() { + return Collections.singletonList(ContainerDataType.PRIMITIVE); + } + + @Override + public List getAllowedDataTypes() { + return Arrays.asList(DataType.INTEGER, DataType.LONG, DataType.DECIMAL); + } +} diff --git a/src/main/java/com/github/sidhant92/boolparser/operator/arithmetic/UnaryOperator.java b/src/main/java/com/github/sidhant92/boolparser/operator/arithmetic/UnaryOperator.java new file mode 100644 index 0000000..a6f2e6d --- /dev/null +++ b/src/main/java/com/github/sidhant92/boolparser/operator/arithmetic/UnaryOperator.java @@ -0,0 +1,46 @@ +package com.github.sidhant92.boolparser.operator.arithmetic; + +import java.util.Arrays; +import java.util.Collections; +import java.util.List; +import com.github.sidhant92.boolparser.constant.ContainerDataType; +import com.github.sidhant92.boolparser.constant.DataType; +import com.github.sidhant92.boolparser.constant.Operator; + +/** + * @author sidhant.aggarwal + * @since 15/03/2024 + */ +public class UnaryOperator extends AbstractOperator { + @Override + public Object evaluate(final Object leftOperand, final DataType leftOperandDataType, final Object rightOperand, + final DataType rightOperandDataType) { + if (leftOperandDataType.equals(DataType.DECIMAL)) { + return -(double) leftOperand; + } + if (leftOperandDataType.equals(DataType.LONG)) { + return -(long) leftOperand; + } + return -(int) leftOperand; + } + + @Override + public Operator getOperator() { + return Operator.UNARY; + } + + @Override + public String getSymbol() { + return "UNARY"; + } + + @Override + public List getAllowedContainerTypes() { + return Collections.singletonList(ContainerDataType.PRIMITIVE); + } + + @Override + public List getAllowedDataTypes() { + return Arrays.asList(DataType.INTEGER, DataType.LONG, DataType.DECIMAL); + } +} diff --git a/src/main/java/com/github/sidhant92/boolparser/operator/AbstractOperator.java b/src/main/java/com/github/sidhant92/boolparser/operator/logical/AbstractOperator.java similarity index 93% rename from src/main/java/com/github/sidhant92/boolparser/operator/AbstractOperator.java rename to src/main/java/com/github/sidhant92/boolparser/operator/logical/AbstractOperator.java index 2c95380..eaa00cb 100644 --- a/src/main/java/com/github/sidhant92/boolparser/operator/AbstractOperator.java +++ b/src/main/java/com/github/sidhant92/boolparser/operator/logical/AbstractOperator.java @@ -1,4 +1,4 @@ -package com.github.sidhant92.boolparser.operator; +package com.github.sidhant92.boolparser.operator.logical; import java.util.List; import com.github.sidhant92.boolparser.constant.ContainerDataType; diff --git a/src/main/java/com/github/sidhant92/boolparser/operator/ContainsAllOperator.java b/src/main/java/com/github/sidhant92/boolparser/operator/logical/ContainsAllOperator.java similarity index 96% rename from src/main/java/com/github/sidhant92/boolparser/operator/ContainsAllOperator.java rename to src/main/java/com/github/sidhant92/boolparser/operator/logical/ContainsAllOperator.java index a7add0d..337bb19 100644 --- a/src/main/java/com/github/sidhant92/boolparser/operator/ContainsAllOperator.java +++ b/src/main/java/com/github/sidhant92/boolparser/operator/logical/ContainsAllOperator.java @@ -1,4 +1,4 @@ -package com.github.sidhant92.boolparser.operator; +package com.github.sidhant92.boolparser.operator.logical; import java.util.Arrays; import java.util.Collections; diff --git a/src/main/java/com/github/sidhant92/boolparser/operator/ContainsAnyOperator.java b/src/main/java/com/github/sidhant92/boolparser/operator/logical/ContainsAnyOperator.java similarity index 96% rename from src/main/java/com/github/sidhant92/boolparser/operator/ContainsAnyOperator.java rename to src/main/java/com/github/sidhant92/boolparser/operator/logical/ContainsAnyOperator.java index 4cb81c9..81bf8d9 100644 --- a/src/main/java/com/github/sidhant92/boolparser/operator/ContainsAnyOperator.java +++ b/src/main/java/com/github/sidhant92/boolparser/operator/logical/ContainsAnyOperator.java @@ -1,4 +1,4 @@ -package com.github.sidhant92.boolparser.operator; +package com.github.sidhant92.boolparser.operator.logical; import java.util.Arrays; import java.util.Collections; diff --git a/src/main/java/com/github/sidhant92/boolparser/operator/EqualsOperator.java b/src/main/java/com/github/sidhant92/boolparser/operator/logical/EqualsOperator.java similarity index 96% rename from src/main/java/com/github/sidhant92/boolparser/operator/EqualsOperator.java rename to src/main/java/com/github/sidhant92/boolparser/operator/logical/EqualsOperator.java index 5bc1044..92dfa97 100644 --- a/src/main/java/com/github/sidhant92/boolparser/operator/EqualsOperator.java +++ b/src/main/java/com/github/sidhant92/boolparser/operator/logical/EqualsOperator.java @@ -1,4 +1,4 @@ -package com.github.sidhant92.boolparser.operator; +package com.github.sidhant92.boolparser.operator.logical; import java.util.Arrays; import java.util.Collections; diff --git a/src/main/java/com/github/sidhant92/boolparser/operator/GreaterThanEqualOperator.java b/src/main/java/com/github/sidhant92/boolparser/operator/logical/GreaterThanEqualOperator.java similarity index 96% rename from src/main/java/com/github/sidhant92/boolparser/operator/GreaterThanEqualOperator.java rename to src/main/java/com/github/sidhant92/boolparser/operator/logical/GreaterThanEqualOperator.java index d26ae8d..8268430 100644 --- a/src/main/java/com/github/sidhant92/boolparser/operator/GreaterThanEqualOperator.java +++ b/src/main/java/com/github/sidhant92/boolparser/operator/logical/GreaterThanEqualOperator.java @@ -1,4 +1,4 @@ -package com.github.sidhant92.boolparser.operator; +package com.github.sidhant92.boolparser.operator.logical; import java.util.Arrays; import java.util.Collections; diff --git a/src/main/java/com/github/sidhant92/boolparser/operator/GreaterThanOperator.java b/src/main/java/com/github/sidhant92/boolparser/operator/logical/GreaterThanOperator.java similarity index 96% rename from src/main/java/com/github/sidhant92/boolparser/operator/GreaterThanOperator.java rename to src/main/java/com/github/sidhant92/boolparser/operator/logical/GreaterThanOperator.java index 720df54..c26f279 100644 --- a/src/main/java/com/github/sidhant92/boolparser/operator/GreaterThanOperator.java +++ b/src/main/java/com/github/sidhant92/boolparser/operator/logical/GreaterThanOperator.java @@ -1,4 +1,4 @@ -package com.github.sidhant92.boolparser.operator; +package com.github.sidhant92.boolparser.operator.logical; import java.util.Arrays; import java.util.Collections; diff --git a/src/main/java/com/github/sidhant92/boolparser/operator/InOperator.java b/src/main/java/com/github/sidhant92/boolparser/operator/logical/InOperator.java similarity index 95% rename from src/main/java/com/github/sidhant92/boolparser/operator/InOperator.java rename to src/main/java/com/github/sidhant92/boolparser/operator/logical/InOperator.java index ef801ea..d605923 100644 --- a/src/main/java/com/github/sidhant92/boolparser/operator/InOperator.java +++ b/src/main/java/com/github/sidhant92/boolparser/operator/logical/InOperator.java @@ -1,4 +1,4 @@ -package com.github.sidhant92.boolparser.operator; +package com.github.sidhant92.boolparser.operator.logical; import java.util.Arrays; import java.util.Collections; diff --git a/src/main/java/com/github/sidhant92/boolparser/operator/LessThanEqualOperator.java b/src/main/java/com/github/sidhant92/boolparser/operator/logical/LessThanEqualOperator.java similarity index 96% rename from src/main/java/com/github/sidhant92/boolparser/operator/LessThanEqualOperator.java rename to src/main/java/com/github/sidhant92/boolparser/operator/logical/LessThanEqualOperator.java index 93307af..1e802d9 100644 --- a/src/main/java/com/github/sidhant92/boolparser/operator/LessThanEqualOperator.java +++ b/src/main/java/com/github/sidhant92/boolparser/operator/logical/LessThanEqualOperator.java @@ -1,4 +1,4 @@ -package com.github.sidhant92.boolparser.operator; +package com.github.sidhant92.boolparser.operator.logical; import java.util.Arrays; import java.util.Collections; diff --git a/src/main/java/com/github/sidhant92/boolparser/operator/LessThanOperator.java b/src/main/java/com/github/sidhant92/boolparser/operator/logical/LessThanOperator.java similarity index 96% rename from src/main/java/com/github/sidhant92/boolparser/operator/LessThanOperator.java rename to src/main/java/com/github/sidhant92/boolparser/operator/logical/LessThanOperator.java index 1c43281..8ce9578 100644 --- a/src/main/java/com/github/sidhant92/boolparser/operator/LessThanOperator.java +++ b/src/main/java/com/github/sidhant92/boolparser/operator/logical/LessThanOperator.java @@ -1,4 +1,4 @@ -package com.github.sidhant92.boolparser.operator; +package com.github.sidhant92.boolparser.operator.logical; import java.util.Arrays; import java.util.Collections; diff --git a/src/main/java/com/github/sidhant92/boolparser/operator/NotEqualsOperator.java b/src/main/java/com/github/sidhant92/boolparser/operator/logical/NotEqualsOperator.java similarity index 96% rename from src/main/java/com/github/sidhant92/boolparser/operator/NotEqualsOperator.java rename to src/main/java/com/github/sidhant92/boolparser/operator/logical/NotEqualsOperator.java index 42904e2..6283153 100644 --- a/src/main/java/com/github/sidhant92/boolparser/operator/NotEqualsOperator.java +++ b/src/main/java/com/github/sidhant92/boolparser/operator/logical/NotEqualsOperator.java @@ -1,4 +1,4 @@ -package com.github.sidhant92.boolparser.operator; +package com.github.sidhant92.boolparser.operator.logical; import java.util.Arrays; import java.util.Collections; diff --git a/src/main/java/com/github/sidhant92/boolparser/parser/antlr/BooleanExpressionBaseListener.java b/src/main/java/com/github/sidhant92/boolparser/parser/antlr/BooleanExpressionBaseListener.java index 4fafed6..17548d4 100644 --- a/src/main/java/com/github/sidhant92/boolparser/parser/antlr/BooleanExpressionBaseListener.java +++ b/src/main/java/com/github/sidhant92/boolparser/parser/antlr/BooleanExpressionBaseListener.java @@ -23,6 +23,18 @@ public class BooleanExpressionBaseListener implements BooleanExpressionListener *

The default implementation does nothing.

*/ @Override public void exitParse(BooleanExpressionParser.ParseContext ctx) { } + /** + * {@inheritDoc} + * + *

The default implementation does nothing.

+ */ + @Override public void enterUnaryArithmeticExpression(BooleanExpressionParser.UnaryArithmeticExpressionContext ctx) { } + /** + * {@inheritDoc} + * + *

The default implementation does nothing.

+ */ + @Override public void exitUnaryArithmeticExpression(BooleanExpressionParser.UnaryArithmeticExpressionContext ctx) { } /** * {@inheritDoc} * @@ -95,6 +107,18 @@ public class BooleanExpressionBaseListener implements BooleanExpressionListener *

The default implementation does nothing.

*/ @Override public void exitNotExpression(BooleanExpressionParser.NotExpressionContext ctx) { } + /** + * {@inheritDoc} + * + *

The default implementation does nothing.

+ */ + @Override public void enterArithmeticExpression(BooleanExpressionParser.ArithmeticExpressionContext ctx) { } + /** + * {@inheritDoc} + * + *

The default implementation does nothing.

+ */ + @Override public void exitArithmeticExpression(BooleanExpressionParser.ArithmeticExpressionContext ctx) { } /** * {@inheritDoc} * @@ -131,6 +155,18 @@ public class BooleanExpressionBaseListener implements BooleanExpressionListener *

The default implementation does nothing.

*/ @Override public void exitComparator(BooleanExpressionParser.ComparatorContext ctx) { } + /** + * {@inheritDoc} + * + *

The default implementation does nothing.

+ */ + @Override public void enterArithmeticOperator(BooleanExpressionParser.ArithmeticOperatorContext ctx) { } + /** + * {@inheritDoc} + * + *

The default implementation does nothing.

+ */ + @Override public void exitArithmeticOperator(BooleanExpressionParser.ArithmeticOperatorContext ctx) { } /** * {@inheritDoc} * diff --git a/src/main/java/com/github/sidhant92/boolparser/parser/antlr/BooleanExpressionLexer.java b/src/main/java/com/github/sidhant92/boolparser/parser/antlr/BooleanExpressionLexer.java index 559e5c4..cbc3ebd 100644 --- a/src/main/java/com/github/sidhant92/boolparser/parser/antlr/BooleanExpressionLexer.java +++ b/src/main/java/com/github/sidhant92/boolparser/parser/antlr/BooleanExpressionLexer.java @@ -17,9 +17,10 @@ public class BooleanExpressionLexer extends Lexer { new PredictionContextCache(); public static final int T__0=1, IN=2, TO=3, AND=4, OR=5, NOT=6, TRUE=7, FALSE=8, CONTAINS_ALL=9, - CONTAINS_ANY=10, NE=11, GT=12, GE=13, LT=14, LE=15, EQ=16, LPAREN=17, - RPAREN=18, DECIMAL=19, APP_VERSION=20, INTEGER=21, WS=22, WORD=23, ALPHANUMERIC=24, - SQ=25, DQ=26; + CONTAINS_ANY=10, ADD=11, SUBTRACT=12, MULTIPLY=13, DIVIDE=14, MODULUS=15, + EXPONENT=16, NE=17, GT=18, GE=19, LT=20, LE=21, EQ=22, LPAREN=23, RPAREN=24, + DECIMAL=25, APP_VERSION=26, INTEGER=27, WS=28, WORD=29, ALPHANUMERIC=30, + SQ=31, DQ=32; public static String[] channelNames = { "DEFAULT_TOKEN_CHANNEL", "HIDDEN" }; @@ -31,26 +32,27 @@ public class BooleanExpressionLexer extends Lexer { private static String[] makeRuleNames() { return new String[] { "T__0", "IN", "TO", "AND", "OR", "NOT", "TRUE", "FALSE", "CONTAINS_ALL", - "CONTAINS_ANY", "NE", "GT", "GE", "LT", "LE", "EQ", "LPAREN", "RPAREN", - "DECIMAL", "APP_VERSION", "INTEGER", "WS", "WORD", "ALPHANUMERIC", "SQ", - "DQ" + "CONTAINS_ANY", "ADD", "SUBTRACT", "MULTIPLY", "DIVIDE", "MODULUS", "EXPONENT", + "NE", "GT", "GE", "LT", "LE", "EQ", "LPAREN", "RPAREN", "DECIMAL", "APP_VERSION", + "INTEGER", "WS", "WORD", "ALPHANUMERIC", "SQ", "DQ" }; } public static final String[] ruleNames = makeRuleNames(); private static String[] makeLiteralNames() { return new String[] { - null, "','", null, null, null, null, null, null, null, null, null, "'!='", - "'>'", "'>='", "'<'", "'<='", "'='", "'('", "')'" + null, "','", null, null, null, null, null, null, null, null, null, "'+'", + "'-'", "'*'", "'/'", "'%'", "'^'", "'!='", "'>'", "'>='", "'<'", "'<='", + "'='", "'('", "')'" }; } private static final String[] _LITERAL_NAMES = makeLiteralNames(); private static String[] makeSymbolicNames() { return new String[] { null, null, "IN", "TO", "AND", "OR", "NOT", "TRUE", "FALSE", "CONTAINS_ALL", - "CONTAINS_ANY", "NE", "GT", "GE", "LT", "LE", "EQ", "LPAREN", "RPAREN", - "DECIMAL", "APP_VERSION", "INTEGER", "WS", "WORD", "ALPHANUMERIC", "SQ", - "DQ" + "CONTAINS_ANY", "ADD", "SUBTRACT", "MULTIPLY", "DIVIDE", "MODULUS", "EXPONENT", + "NE", "GT", "GE", "LT", "LE", "EQ", "LPAREN", "RPAREN", "DECIMAL", "APP_VERSION", + "INTEGER", "WS", "WORD", "ALPHANUMERIC", "SQ", "DQ" }; } private static final String[] _SYMBOLIC_NAMES = makeSymbolicNames(); @@ -112,161 +114,177 @@ public BooleanExpressionLexer(CharStream input) { public ATN getATN() { return _ATN; } public static final String _serializedATN = - "\u0004\u0000\u001a\u00f4\u0006\uffff\uffff\u0002\u0000\u0007\u0000\u0002"+ - "\u0001\u0007\u0001\u0002\u0002\u0007\u0002\u0002\u0003\u0007\u0003\u0002"+ - "\u0004\u0007\u0004\u0002\u0005\u0007\u0005\u0002\u0006\u0007\u0006\u0002"+ - "\u0007\u0007\u0007\u0002\b\u0007\b\u0002\t\u0007\t\u0002\n\u0007\n\u0002"+ - "\u000b\u0007\u000b\u0002\f\u0007\f\u0002\r\u0007\r\u0002\u000e\u0007\u000e"+ - "\u0002\u000f\u0007\u000f\u0002\u0010\u0007\u0010\u0002\u0011\u0007\u0011"+ - "\u0002\u0012\u0007\u0012\u0002\u0013\u0007\u0013\u0002\u0014\u0007\u0014"+ - "\u0002\u0015\u0007\u0015\u0002\u0016\u0007\u0016\u0002\u0017\u0007\u0017"+ - "\u0002\u0018\u0007\u0018\u0002\u0019\u0007\u0019\u0001\u0000\u0001\u0000"+ - "\u0001\u0001\u0001\u0001\u0001\u0001\u0001\u0001\u0003\u0001<\b\u0001"+ - "\u0001\u0002\u0001\u0002\u0001\u0002\u0001\u0002\u0003\u0002B\b\u0002"+ - "\u0001\u0003\u0001\u0003\u0001\u0003\u0001\u0003\u0001\u0003\u0001\u0003"+ - "\u0001\u0003\u0001\u0003\u0003\u0003L\b\u0003\u0001\u0004\u0001\u0004"+ - "\u0001\u0004\u0001\u0004\u0001\u0004\u0001\u0004\u0003\u0004T\b\u0004"+ - "\u0001\u0005\u0001\u0005\u0001\u0005\u0001\u0005\u0001\u0005\u0001\u0005"+ - "\u0003\u0005\\\b\u0005\u0001\u0006\u0001\u0006\u0001\u0006\u0001\u0006"+ - "\u0001\u0006\u0001\u0006\u0001\u0006\u0001\u0006\u0003\u0006f\b\u0006"+ - "\u0001\u0007\u0001\u0007\u0001\u0007\u0001\u0007\u0001\u0007\u0001\u0007"+ - "\u0001\u0007\u0001\u0007\u0001\u0007\u0001\u0007\u0003\u0007r\b\u0007"+ - "\u0001\b\u0001\b\u0001\b\u0001\b\u0001\b\u0001\b\u0001\b\u0001\b\u0001"+ + "\u0004\u0000 \u010c\u0006\uffff\uffff\u0002\u0000\u0007\u0000\u0002\u0001"+ + "\u0007\u0001\u0002\u0002\u0007\u0002\u0002\u0003\u0007\u0003\u0002\u0004"+ + "\u0007\u0004\u0002\u0005\u0007\u0005\u0002\u0006\u0007\u0006\u0002\u0007"+ + "\u0007\u0007\u0002\b\u0007\b\u0002\t\u0007\t\u0002\n\u0007\n\u0002\u000b"+ + "\u0007\u000b\u0002\f\u0007\f\u0002\r\u0007\r\u0002\u000e\u0007\u000e\u0002"+ + "\u000f\u0007\u000f\u0002\u0010\u0007\u0010\u0002\u0011\u0007\u0011\u0002"+ + "\u0012\u0007\u0012\u0002\u0013\u0007\u0013\u0002\u0014\u0007\u0014\u0002"+ + "\u0015\u0007\u0015\u0002\u0016\u0007\u0016\u0002\u0017\u0007\u0017\u0002"+ + "\u0018\u0007\u0018\u0002\u0019\u0007\u0019\u0002\u001a\u0007\u001a\u0002"+ + "\u001b\u0007\u001b\u0002\u001c\u0007\u001c\u0002\u001d\u0007\u001d\u0002"+ + "\u001e\u0007\u001e\u0002\u001f\u0007\u001f\u0001\u0000\u0001\u0000\u0001"+ + "\u0001\u0001\u0001\u0001\u0001\u0001\u0001\u0003\u0001H\b\u0001\u0001"+ + "\u0002\u0001\u0002\u0001\u0002\u0001\u0002\u0003\u0002N\b\u0002\u0001"+ + "\u0003\u0001\u0003\u0001\u0003\u0001\u0003\u0001\u0003\u0001\u0003\u0001"+ + "\u0003\u0001\u0003\u0003\u0003X\b\u0003\u0001\u0004\u0001\u0004\u0001"+ + "\u0004\u0001\u0004\u0001\u0004\u0001\u0004\u0003\u0004`\b\u0004\u0001"+ + "\u0005\u0001\u0005\u0001\u0005\u0001\u0005\u0001\u0005\u0001\u0005\u0003"+ + "\u0005h\b\u0005\u0001\u0006\u0001\u0006\u0001\u0006\u0001\u0006\u0001"+ + "\u0006\u0001\u0006\u0001\u0006\u0001\u0006\u0003\u0006r\b\u0006\u0001"+ + "\u0007\u0001\u0007\u0001\u0007\u0001\u0007\u0001\u0007\u0001\u0007\u0001"+ + "\u0007\u0001\u0007\u0001\u0007\u0001\u0007\u0003\u0007~\b\u0007\u0001"+ "\b\u0001\b\u0001\b\u0001\b\u0001\b\u0001\b\u0001\b\u0001\b\u0001\b\u0001"+ - "\b\u0001\b\u0001\b\u0001\b\u0001\b\u0001\b\u0001\b\u0003\b\u008c\b\b\u0001"+ + "\b\u0001\b\u0001\b\u0001\b\u0001\b\u0001\b\u0001\b\u0001\b\u0001\b\u0001"+ + "\b\u0001\b\u0001\b\u0001\b\u0001\b\u0001\b\u0003\b\u0098\b\b\u0001\t\u0001"+ "\t\u0001\t\u0001\t\u0001\t\u0001\t\u0001\t\u0001\t\u0001\t\u0001\t\u0001"+ "\t\u0001\t\u0001\t\u0001\t\u0001\t\u0001\t\u0001\t\u0001\t\u0001\t\u0001"+ - "\t\u0001\t\u0001\t\u0001\t\u0001\t\u0001\t\u0003\t\u00a6\b\t\u0001\n\u0001"+ - "\n\u0001\n\u0001\u000b\u0001\u000b\u0001\f\u0001\f\u0001\f\u0001\r\u0001"+ - "\r\u0001\u000e\u0001\u000e\u0001\u000e\u0001\u000f\u0001\u000f\u0001\u0010"+ - "\u0001\u0010\u0001\u0011\u0001\u0011\u0001\u0012\u0004\u0012\u00bc\b\u0012"+ - "\u000b\u0012\f\u0012\u00bd\u0001\u0012\u0001\u0012\u0004\u0012\u00c2\b"+ - "\u0012\u000b\u0012\f\u0012\u00c3\u0001\u0013\u0001\u0013\u0001\u0013\u0004"+ - "\u0013\u00c9\b\u0013\u000b\u0013\f\u0013\u00ca\u0001\u0014\u0004\u0014"+ - "\u00ce\b\u0014\u000b\u0014\f\u0014\u00cf\u0001\u0015\u0004\u0015\u00d3"+ - "\b\u0015\u000b\u0015\f\u0015\u00d4\u0001\u0015\u0001\u0015\u0001\u0016"+ - "\u0001\u0016\u0001\u0016\u0001\u0016\u0004\u0016\u00dd\b\u0016\u000b\u0016"+ - "\f\u0016\u00de\u0001\u0017\u0001\u0017\u0001\u0018\u0001\u0018\u0005\u0018"+ - "\u00e5\b\u0018\n\u0018\f\u0018\u00e8\t\u0018\u0001\u0018\u0001\u0018\u0001"+ - "\u0019\u0001\u0019\u0005\u0019\u00ee\b\u0019\n\u0019\f\u0019\u00f1\t\u0019"+ - "\u0001\u0019\u0001\u0019\u0002\u00e6\u00ef\u0000\u001a\u0001\u0001\u0003"+ - "\u0002\u0005\u0003\u0007\u0004\t\u0005\u000b\u0006\r\u0007\u000f\b\u0011"+ - "\t\u0013\n\u0015\u000b\u0017\f\u0019\r\u001b\u000e\u001d\u000f\u001f\u0010"+ - "!\u0011#\u0012%\u0013\'\u0014)\u0015+\u0016-\u0017/\u00181\u00193\u001a"+ - "\u0001\u0000\u0004\u0001\u000009\u0003\u0000\t\n\f\r \u0002\u0000-._"+ - "_\u0003\u000009AZaz\u0109\u0000\u0001\u0001\u0000\u0000\u0000\u0000\u0003"+ - "\u0001\u0000\u0000\u0000\u0000\u0005\u0001\u0000\u0000\u0000\u0000\u0007"+ - "\u0001\u0000\u0000\u0000\u0000\t\u0001\u0000\u0000\u0000\u0000\u000b\u0001"+ - "\u0000\u0000\u0000\u0000\r\u0001\u0000\u0000\u0000\u0000\u000f\u0001\u0000"+ - "\u0000\u0000\u0000\u0011\u0001\u0000\u0000\u0000\u0000\u0013\u0001\u0000"+ - "\u0000\u0000\u0000\u0015\u0001\u0000\u0000\u0000\u0000\u0017\u0001\u0000"+ - "\u0000\u0000\u0000\u0019\u0001\u0000\u0000\u0000\u0000\u001b\u0001\u0000"+ - "\u0000\u0000\u0000\u001d\u0001\u0000\u0000\u0000\u0000\u001f\u0001\u0000"+ - "\u0000\u0000\u0000!\u0001\u0000\u0000\u0000\u0000#\u0001\u0000\u0000\u0000"+ - "\u0000%\u0001\u0000\u0000\u0000\u0000\'\u0001\u0000\u0000\u0000\u0000"+ - ")\u0001\u0000\u0000\u0000\u0000+\u0001\u0000\u0000\u0000\u0000-\u0001"+ - "\u0000\u0000\u0000\u0000/\u0001\u0000\u0000\u0000\u00001\u0001\u0000\u0000"+ - "\u0000\u00003\u0001\u0000\u0000\u0000\u00015\u0001\u0000\u0000\u0000\u0003"+ - ";\u0001\u0000\u0000\u0000\u0005A\u0001\u0000\u0000\u0000\u0007K\u0001"+ - "\u0000\u0000\u0000\tS\u0001\u0000\u0000\u0000\u000b[\u0001\u0000\u0000"+ - "\u0000\re\u0001\u0000\u0000\u0000\u000fq\u0001\u0000\u0000\u0000\u0011"+ - "\u008b\u0001\u0000\u0000\u0000\u0013\u00a5\u0001\u0000\u0000\u0000\u0015"+ - "\u00a7\u0001\u0000\u0000\u0000\u0017\u00aa\u0001\u0000\u0000\u0000\u0019"+ - "\u00ac\u0001\u0000\u0000\u0000\u001b\u00af\u0001\u0000\u0000\u0000\u001d"+ - "\u00b1\u0001\u0000\u0000\u0000\u001f\u00b4\u0001\u0000\u0000\u0000!\u00b6"+ - "\u0001\u0000\u0000\u0000#\u00b8\u0001\u0000\u0000\u0000%\u00bb\u0001\u0000"+ - "\u0000\u0000\'\u00c5\u0001\u0000\u0000\u0000)\u00cd\u0001\u0000\u0000"+ - "\u0000+\u00d2\u0001\u0000\u0000\u0000-\u00dc\u0001\u0000\u0000\u0000/"+ - "\u00e0\u0001\u0000\u0000\u00001\u00e2\u0001\u0000\u0000\u00003\u00eb\u0001"+ - "\u0000\u0000\u000056\u0005,\u0000\u00006\u0002\u0001\u0000\u0000\u0000"+ - "78\u0005I\u0000\u00008<\u0005N\u0000\u00009:\u0005i\u0000\u0000:<\u0005"+ - "n\u0000\u0000;7\u0001\u0000\u0000\u0000;9\u0001\u0000\u0000\u0000<\u0004"+ - "\u0001\u0000\u0000\u0000=>\u0005T\u0000\u0000>B\u0005O\u0000\u0000?@\u0005"+ - "t\u0000\u0000@B\u0005o\u0000\u0000A=\u0001\u0000\u0000\u0000A?\u0001\u0000"+ - "\u0000\u0000B\u0006\u0001\u0000\u0000\u0000CD\u0005A\u0000\u0000DE\u0005"+ - "N\u0000\u0000EL\u0005D\u0000\u0000FG\u0005a\u0000\u0000GH\u0005n\u0000"+ - "\u0000HL\u0005d\u0000\u0000IJ\u0005&\u0000\u0000JL\u0005&\u0000\u0000"+ - "KC\u0001\u0000\u0000\u0000KF\u0001\u0000\u0000\u0000KI\u0001\u0000\u0000"+ - "\u0000L\b\u0001\u0000\u0000\u0000MN\u0005O\u0000\u0000NT\u0005R\u0000"+ - "\u0000OP\u0005o\u0000\u0000PT\u0005r\u0000\u0000QR\u0005|\u0000\u0000"+ - "RT\u0005|\u0000\u0000SM\u0001\u0000\u0000\u0000SO\u0001\u0000\u0000\u0000"+ - "SQ\u0001\u0000\u0000\u0000T\n\u0001\u0000\u0000\u0000UV\u0005N\u0000\u0000"+ - "VW\u0005O\u0000\u0000W\\\u0005T\u0000\u0000XY\u0005n\u0000\u0000YZ\u0005"+ - "o\u0000\u0000Z\\\u0005t\u0000\u0000[U\u0001\u0000\u0000\u0000[X\u0001"+ - "\u0000\u0000\u0000\\\f\u0001\u0000\u0000\u0000]^\u0005T\u0000\u0000^_"+ - "\u0005R\u0000\u0000_`\u0005U\u0000\u0000`f\u0005E\u0000\u0000ab\u0005"+ - "t\u0000\u0000bc\u0005r\u0000\u0000cd\u0005u\u0000\u0000df\u0005e\u0000"+ - "\u0000e]\u0001\u0000\u0000\u0000ea\u0001\u0000\u0000\u0000f\u000e\u0001"+ - "\u0000\u0000\u0000gh\u0005F\u0000\u0000hi\u0005A\u0000\u0000ij\u0005L"+ - "\u0000\u0000jk\u0005S\u0000\u0000kr\u0005E\u0000\u0000lm\u0005f\u0000"+ - "\u0000mn\u0005a\u0000\u0000no\u0005l\u0000\u0000op\u0005s\u0000\u0000"+ - "pr\u0005e\u0000\u0000qg\u0001\u0000\u0000\u0000ql\u0001\u0000\u0000\u0000"+ - "r\u0010\u0001\u0000\u0000\u0000st\u0005C\u0000\u0000tu\u0005O\u0000\u0000"+ - "uv\u0005N\u0000\u0000vw\u0005T\u0000\u0000wx\u0005A\u0000\u0000xy\u0005"+ - "I\u0000\u0000yz\u0005N\u0000\u0000z{\u0005S\u0000\u0000{|\u0005_\u0000"+ - "\u0000|}\u0005A\u0000\u0000}~\u0005L\u0000\u0000~\u008c\u0005L\u0000\u0000"+ - "\u007f\u0080\u0005c\u0000\u0000\u0080\u0081\u0005o\u0000\u0000\u0081\u0082"+ - "\u0005n\u0000\u0000\u0082\u0083\u0005t\u0000\u0000\u0083\u0084\u0005a"+ - "\u0000\u0000\u0084\u0085\u0005i\u0000\u0000\u0085\u0086\u0005n\u0000\u0000"+ - "\u0086\u0087\u0005s\u0000\u0000\u0087\u0088\u0005_\u0000\u0000\u0088\u0089"+ - "\u0005a\u0000\u0000\u0089\u008a\u0005l\u0000\u0000\u008a\u008c\u0005l"+ - "\u0000\u0000\u008bs\u0001\u0000\u0000\u0000\u008b\u007f\u0001\u0000\u0000"+ - "\u0000\u008c\u0012\u0001\u0000\u0000\u0000\u008d\u008e\u0005C\u0000\u0000"+ - "\u008e\u008f\u0005O\u0000\u0000\u008f\u0090\u0005N\u0000\u0000\u0090\u0091"+ - "\u0005T\u0000\u0000\u0091\u0092\u0005A\u0000\u0000\u0092\u0093\u0005I"+ - "\u0000\u0000\u0093\u0094\u0005N\u0000\u0000\u0094\u0095\u0005S\u0000\u0000"+ - "\u0095\u0096\u0005_\u0000\u0000\u0096\u0097\u0005A\u0000\u0000\u0097\u0098"+ - "\u0005N\u0000\u0000\u0098\u00a6\u0005Y\u0000\u0000\u0099\u009a\u0005c"+ - "\u0000\u0000\u009a\u009b\u0005o\u0000\u0000\u009b\u009c\u0005n\u0000\u0000"+ - "\u009c\u009d\u0005t\u0000\u0000\u009d\u009e\u0005a\u0000\u0000\u009e\u009f"+ - "\u0005i\u0000\u0000\u009f\u00a0\u0005n\u0000\u0000\u00a0\u00a1\u0005s"+ - "\u0000\u0000\u00a1\u00a2\u0005_\u0000\u0000\u00a2\u00a3\u0005a\u0000\u0000"+ - "\u00a3\u00a4\u0005n\u0000\u0000\u00a4\u00a6\u0005y\u0000\u0000\u00a5\u008d"+ - "\u0001\u0000\u0000\u0000\u00a5\u0099\u0001\u0000\u0000\u0000\u00a6\u0014"+ - "\u0001\u0000\u0000\u0000\u00a7\u00a8\u0005!\u0000\u0000\u00a8\u00a9\u0005"+ - "=\u0000\u0000\u00a9\u0016\u0001\u0000\u0000\u0000\u00aa\u00ab\u0005>\u0000"+ - "\u0000\u00ab\u0018\u0001\u0000\u0000\u0000\u00ac\u00ad\u0005>\u0000\u0000"+ - "\u00ad\u00ae\u0005=\u0000\u0000\u00ae\u001a\u0001\u0000\u0000\u0000\u00af"+ - "\u00b0\u0005<\u0000\u0000\u00b0\u001c\u0001\u0000\u0000\u0000\u00b1\u00b2"+ - "\u0005<\u0000\u0000\u00b2\u00b3\u0005=\u0000\u0000\u00b3\u001e\u0001\u0000"+ - "\u0000\u0000\u00b4\u00b5\u0005=\u0000\u0000\u00b5 \u0001\u0000\u0000\u0000"+ - "\u00b6\u00b7\u0005(\u0000\u0000\u00b7\"\u0001\u0000\u0000\u0000\u00b8"+ - "\u00b9\u0005)\u0000\u0000\u00b9$\u0001\u0000\u0000\u0000\u00ba\u00bc\u0007"+ - "\u0000\u0000\u0000\u00bb\u00ba\u0001\u0000\u0000\u0000\u00bc\u00bd\u0001"+ - "\u0000\u0000\u0000\u00bd\u00bb\u0001\u0000\u0000\u0000\u00bd\u00be\u0001"+ - "\u0000\u0000\u0000\u00be\u00bf\u0001\u0000\u0000\u0000\u00bf\u00c1\u0005"+ - ".\u0000\u0000\u00c0\u00c2\u0007\u0000\u0000\u0000\u00c1\u00c0\u0001\u0000"+ - "\u0000\u0000\u00c2\u00c3\u0001\u0000\u0000\u0000\u00c3\u00c1\u0001\u0000"+ - "\u0000\u0000\u00c3\u00c4\u0001\u0000\u0000\u0000\u00c4&\u0001\u0000\u0000"+ - "\u0000\u00c5\u00c8\u0007\u0000\u0000\u0000\u00c6\u00c7\u0005.\u0000\u0000"+ - "\u00c7\u00c9\u0003)\u0014\u0000\u00c8\u00c6\u0001\u0000\u0000\u0000\u00c9"+ - "\u00ca\u0001\u0000\u0000\u0000\u00ca\u00c8\u0001\u0000\u0000\u0000\u00ca"+ - "\u00cb\u0001\u0000\u0000\u0000\u00cb(\u0001\u0000\u0000\u0000\u00cc\u00ce"+ - "\u0007\u0000\u0000\u0000\u00cd\u00cc\u0001\u0000\u0000\u0000\u00ce\u00cf"+ - "\u0001\u0000\u0000\u0000\u00cf\u00cd\u0001\u0000\u0000\u0000\u00cf\u00d0"+ - "\u0001\u0000\u0000\u0000\u00d0*\u0001\u0000\u0000\u0000\u00d1\u00d3\u0007"+ - "\u0001\u0000\u0000\u00d2\u00d1\u0001\u0000\u0000\u0000\u00d3\u00d4\u0001"+ - "\u0000\u0000\u0000\u00d4\u00d2\u0001\u0000\u0000\u0000\u00d4\u00d5\u0001"+ - "\u0000\u0000\u0000\u00d5\u00d6\u0001\u0000\u0000\u0000\u00d6\u00d7\u0006"+ - "\u0015\u0000\u0000\u00d7,\u0001\u0000\u0000\u0000\u00d8\u00dd\u0003/\u0017"+ - "\u0000\u00d9\u00dd\u0007\u0002\u0000\u0000\u00da\u00dd\u00031\u0018\u0000"+ - "\u00db\u00dd\u00033\u0019\u0000\u00dc\u00d8\u0001\u0000\u0000\u0000\u00dc"+ - "\u00d9\u0001\u0000\u0000\u0000\u00dc\u00da\u0001\u0000\u0000\u0000\u00dc"+ - "\u00db\u0001\u0000\u0000\u0000\u00dd\u00de\u0001\u0000\u0000\u0000\u00de"+ - "\u00dc\u0001\u0000\u0000\u0000\u00de\u00df\u0001\u0000\u0000\u0000\u00df"+ - ".\u0001\u0000\u0000\u0000\u00e0\u00e1\u0007\u0003\u0000\u0000\u00e10\u0001"+ - "\u0000\u0000\u0000\u00e2\u00e6\u0005\'\u0000\u0000\u00e3\u00e5\t\u0000"+ - "\u0000\u0000\u00e4\u00e3\u0001\u0000\u0000\u0000\u00e5\u00e8\u0001\u0000"+ - "\u0000\u0000\u00e6\u00e7\u0001\u0000\u0000\u0000\u00e6\u00e4\u0001\u0000"+ - "\u0000\u0000\u00e7\u00e9\u0001\u0000\u0000\u0000\u00e8\u00e6\u0001\u0000"+ - "\u0000\u0000\u00e9\u00ea\u0005\'\u0000\u0000\u00ea2\u0001\u0000\u0000"+ - "\u0000\u00eb\u00ef\u0005\"\u0000\u0000\u00ec\u00ee\t\u0000\u0000\u0000"+ - "\u00ed\u00ec\u0001\u0000\u0000\u0000\u00ee\u00f1\u0001\u0000\u0000\u0000"+ - "\u00ef\u00f0\u0001\u0000\u0000\u0000\u00ef\u00ed\u0001\u0000\u0000\u0000"+ - "\u00f0\u00f2\u0001\u0000\u0000\u0000\u00f1\u00ef\u0001\u0000\u0000\u0000"+ - "\u00f2\u00f3\u0005\"\u0000\u0000\u00f34\u0001\u0000\u0000\u0000\u0013"+ - "\u0000;AKS[eq\u008b\u00a5\u00bd\u00c3\u00ca\u00cf\u00d4\u00dc\u00de\u00e6"+ - "\u00ef\u0001\u0006\u0000\u0000"; + "\t\u0001\t\u0001\t\u0001\t\u0001\t\u0003\t\u00b2\b\t\u0001\n\u0001\n\u0001"+ + "\u000b\u0001\u000b\u0001\f\u0001\f\u0001\r\u0001\r\u0001\u000e\u0001\u000e"+ + "\u0001\u000f\u0001\u000f\u0001\u0010\u0001\u0010\u0001\u0010\u0001\u0011"+ + "\u0001\u0011\u0001\u0012\u0001\u0012\u0001\u0012\u0001\u0013\u0001\u0013"+ + "\u0001\u0014\u0001\u0014\u0001\u0014\u0001\u0015\u0001\u0015\u0001\u0016"+ + "\u0001\u0016\u0001\u0017\u0001\u0017\u0001\u0018\u0004\u0018\u00d4\b\u0018"+ + "\u000b\u0018\f\u0018\u00d5\u0001\u0018\u0001\u0018\u0004\u0018\u00da\b"+ + "\u0018\u000b\u0018\f\u0018\u00db\u0001\u0019\u0001\u0019\u0001\u0019\u0004"+ + "\u0019\u00e1\b\u0019\u000b\u0019\f\u0019\u00e2\u0001\u001a\u0004\u001a"+ + "\u00e6\b\u001a\u000b\u001a\f\u001a\u00e7\u0001\u001b\u0004\u001b\u00eb"+ + "\b\u001b\u000b\u001b\f\u001b\u00ec\u0001\u001b\u0001\u001b\u0001\u001c"+ + "\u0001\u001c\u0001\u001c\u0001\u001c\u0004\u001c\u00f5\b\u001c\u000b\u001c"+ + "\f\u001c\u00f6\u0001\u001d\u0001\u001d\u0001\u001e\u0001\u001e\u0005\u001e"+ + "\u00fd\b\u001e\n\u001e\f\u001e\u0100\t\u001e\u0001\u001e\u0001\u001e\u0001"+ + "\u001f\u0001\u001f\u0005\u001f\u0106\b\u001f\n\u001f\f\u001f\u0109\t\u001f"+ + "\u0001\u001f\u0001\u001f\u0002\u00fe\u0107\u0000 \u0001\u0001\u0003\u0002"+ + "\u0005\u0003\u0007\u0004\t\u0005\u000b\u0006\r\u0007\u000f\b\u0011\t\u0013"+ + "\n\u0015\u000b\u0017\f\u0019\r\u001b\u000e\u001d\u000f\u001f\u0010!\u0011"+ + "#\u0012%\u0013\'\u0014)\u0015+\u0016-\u0017/\u00181\u00193\u001a5\u001b"+ + "7\u001c9\u001d;\u001e=\u001f? \u0001\u0000\u0004\u0001\u000009\u0003\u0000"+ + "\t\n\f\r \u0002\u0000-.__\u0003\u000009AZaz\u0121\u0000\u0001\u0001\u0000"+ + "\u0000\u0000\u0000\u0003\u0001\u0000\u0000\u0000\u0000\u0005\u0001\u0000"+ + "\u0000\u0000\u0000\u0007\u0001\u0000\u0000\u0000\u0000\t\u0001\u0000\u0000"+ + "\u0000\u0000\u000b\u0001\u0000\u0000\u0000\u0000\r\u0001\u0000\u0000\u0000"+ + "\u0000\u000f\u0001\u0000\u0000\u0000\u0000\u0011\u0001\u0000\u0000\u0000"+ + "\u0000\u0013\u0001\u0000\u0000\u0000\u0000\u0015\u0001\u0000\u0000\u0000"+ + "\u0000\u0017\u0001\u0000\u0000\u0000\u0000\u0019\u0001\u0000\u0000\u0000"+ + "\u0000\u001b\u0001\u0000\u0000\u0000\u0000\u001d\u0001\u0000\u0000\u0000"+ + "\u0000\u001f\u0001\u0000\u0000\u0000\u0000!\u0001\u0000\u0000\u0000\u0000"+ + "#\u0001\u0000\u0000\u0000\u0000%\u0001\u0000\u0000\u0000\u0000\'\u0001"+ + "\u0000\u0000\u0000\u0000)\u0001\u0000\u0000\u0000\u0000+\u0001\u0000\u0000"+ + "\u0000\u0000-\u0001\u0000\u0000\u0000\u0000/\u0001\u0000\u0000\u0000\u0000"+ + "1\u0001\u0000\u0000\u0000\u00003\u0001\u0000\u0000\u0000\u00005\u0001"+ + "\u0000\u0000\u0000\u00007\u0001\u0000\u0000\u0000\u00009\u0001\u0000\u0000"+ + "\u0000\u0000;\u0001\u0000\u0000\u0000\u0000=\u0001\u0000\u0000\u0000\u0000"+ + "?\u0001\u0000\u0000\u0000\u0001A\u0001\u0000\u0000\u0000\u0003G\u0001"+ + "\u0000\u0000\u0000\u0005M\u0001\u0000\u0000\u0000\u0007W\u0001\u0000\u0000"+ + "\u0000\t_\u0001\u0000\u0000\u0000\u000bg\u0001\u0000\u0000\u0000\rq\u0001"+ + "\u0000\u0000\u0000\u000f}\u0001\u0000\u0000\u0000\u0011\u0097\u0001\u0000"+ + "\u0000\u0000\u0013\u00b1\u0001\u0000\u0000\u0000\u0015\u00b3\u0001\u0000"+ + "\u0000\u0000\u0017\u00b5\u0001\u0000\u0000\u0000\u0019\u00b7\u0001\u0000"+ + "\u0000\u0000\u001b\u00b9\u0001\u0000\u0000\u0000\u001d\u00bb\u0001\u0000"+ + "\u0000\u0000\u001f\u00bd\u0001\u0000\u0000\u0000!\u00bf\u0001\u0000\u0000"+ + "\u0000#\u00c2\u0001\u0000\u0000\u0000%\u00c4\u0001\u0000\u0000\u0000\'"+ + "\u00c7\u0001\u0000\u0000\u0000)\u00c9\u0001\u0000\u0000\u0000+\u00cc\u0001"+ + "\u0000\u0000\u0000-\u00ce\u0001\u0000\u0000\u0000/\u00d0\u0001\u0000\u0000"+ + "\u00001\u00d3\u0001\u0000\u0000\u00003\u00dd\u0001\u0000\u0000\u00005"+ + "\u00e5\u0001\u0000\u0000\u00007\u00ea\u0001\u0000\u0000\u00009\u00f4\u0001"+ + "\u0000\u0000\u0000;\u00f8\u0001\u0000\u0000\u0000=\u00fa\u0001\u0000\u0000"+ + "\u0000?\u0103\u0001\u0000\u0000\u0000AB\u0005,\u0000\u0000B\u0002\u0001"+ + "\u0000\u0000\u0000CD\u0005I\u0000\u0000DH\u0005N\u0000\u0000EF\u0005i"+ + "\u0000\u0000FH\u0005n\u0000\u0000GC\u0001\u0000\u0000\u0000GE\u0001\u0000"+ + "\u0000\u0000H\u0004\u0001\u0000\u0000\u0000IJ\u0005T\u0000\u0000JN\u0005"+ + "O\u0000\u0000KL\u0005t\u0000\u0000LN\u0005o\u0000\u0000MI\u0001\u0000"+ + "\u0000\u0000MK\u0001\u0000\u0000\u0000N\u0006\u0001\u0000\u0000\u0000"+ + "OP\u0005A\u0000\u0000PQ\u0005N\u0000\u0000QX\u0005D\u0000\u0000RS\u0005"+ + "a\u0000\u0000ST\u0005n\u0000\u0000TX\u0005d\u0000\u0000UV\u0005&\u0000"+ + "\u0000VX\u0005&\u0000\u0000WO\u0001\u0000\u0000\u0000WR\u0001\u0000\u0000"+ + "\u0000WU\u0001\u0000\u0000\u0000X\b\u0001\u0000\u0000\u0000YZ\u0005O\u0000"+ + "\u0000Z`\u0005R\u0000\u0000[\\\u0005o\u0000\u0000\\`\u0005r\u0000\u0000"+ + "]^\u0005|\u0000\u0000^`\u0005|\u0000\u0000_Y\u0001\u0000\u0000\u0000_"+ + "[\u0001\u0000\u0000\u0000_]\u0001\u0000\u0000\u0000`\n\u0001\u0000\u0000"+ + "\u0000ab\u0005N\u0000\u0000bc\u0005O\u0000\u0000ch\u0005T\u0000\u0000"+ + "de\u0005n\u0000\u0000ef\u0005o\u0000\u0000fh\u0005t\u0000\u0000ga\u0001"+ + "\u0000\u0000\u0000gd\u0001\u0000\u0000\u0000h\f\u0001\u0000\u0000\u0000"+ + "ij\u0005T\u0000\u0000jk\u0005R\u0000\u0000kl\u0005U\u0000\u0000lr\u0005"+ + "E\u0000\u0000mn\u0005t\u0000\u0000no\u0005r\u0000\u0000op\u0005u\u0000"+ + "\u0000pr\u0005e\u0000\u0000qi\u0001\u0000\u0000\u0000qm\u0001\u0000\u0000"+ + "\u0000r\u000e\u0001\u0000\u0000\u0000st\u0005F\u0000\u0000tu\u0005A\u0000"+ + "\u0000uv\u0005L\u0000\u0000vw\u0005S\u0000\u0000w~\u0005E\u0000\u0000"+ + "xy\u0005f\u0000\u0000yz\u0005a\u0000\u0000z{\u0005l\u0000\u0000{|\u0005"+ + "s\u0000\u0000|~\u0005e\u0000\u0000}s\u0001\u0000\u0000\u0000}x\u0001\u0000"+ + "\u0000\u0000~\u0010\u0001\u0000\u0000\u0000\u007f\u0080\u0005C\u0000\u0000"+ + "\u0080\u0081\u0005O\u0000\u0000\u0081\u0082\u0005N\u0000\u0000\u0082\u0083"+ + "\u0005T\u0000\u0000\u0083\u0084\u0005A\u0000\u0000\u0084\u0085\u0005I"+ + "\u0000\u0000\u0085\u0086\u0005N\u0000\u0000\u0086\u0087\u0005S\u0000\u0000"+ + "\u0087\u0088\u0005_\u0000\u0000\u0088\u0089\u0005A\u0000\u0000\u0089\u008a"+ + "\u0005L\u0000\u0000\u008a\u0098\u0005L\u0000\u0000\u008b\u008c\u0005c"+ + "\u0000\u0000\u008c\u008d\u0005o\u0000\u0000\u008d\u008e\u0005n\u0000\u0000"+ + "\u008e\u008f\u0005t\u0000\u0000\u008f\u0090\u0005a\u0000\u0000\u0090\u0091"+ + "\u0005i\u0000\u0000\u0091\u0092\u0005n\u0000\u0000\u0092\u0093\u0005s"+ + "\u0000\u0000\u0093\u0094\u0005_\u0000\u0000\u0094\u0095\u0005a\u0000\u0000"+ + "\u0095\u0096\u0005l\u0000\u0000\u0096\u0098\u0005l\u0000\u0000\u0097\u007f"+ + "\u0001\u0000\u0000\u0000\u0097\u008b\u0001\u0000\u0000\u0000\u0098\u0012"+ + "\u0001\u0000\u0000\u0000\u0099\u009a\u0005C\u0000\u0000\u009a\u009b\u0005"+ + "O\u0000\u0000\u009b\u009c\u0005N\u0000\u0000\u009c\u009d\u0005T\u0000"+ + "\u0000\u009d\u009e\u0005A\u0000\u0000\u009e\u009f\u0005I\u0000\u0000\u009f"+ + "\u00a0\u0005N\u0000\u0000\u00a0\u00a1\u0005S\u0000\u0000\u00a1\u00a2\u0005"+ + "_\u0000\u0000\u00a2\u00a3\u0005A\u0000\u0000\u00a3\u00a4\u0005N\u0000"+ + "\u0000\u00a4\u00b2\u0005Y\u0000\u0000\u00a5\u00a6\u0005c\u0000\u0000\u00a6"+ + "\u00a7\u0005o\u0000\u0000\u00a7\u00a8\u0005n\u0000\u0000\u00a8\u00a9\u0005"+ + "t\u0000\u0000\u00a9\u00aa\u0005a\u0000\u0000\u00aa\u00ab\u0005i\u0000"+ + "\u0000\u00ab\u00ac\u0005n\u0000\u0000\u00ac\u00ad\u0005s\u0000\u0000\u00ad"+ + "\u00ae\u0005_\u0000\u0000\u00ae\u00af\u0005a\u0000\u0000\u00af\u00b0\u0005"+ + "n\u0000\u0000\u00b0\u00b2\u0005y\u0000\u0000\u00b1\u0099\u0001\u0000\u0000"+ + "\u0000\u00b1\u00a5\u0001\u0000\u0000\u0000\u00b2\u0014\u0001\u0000\u0000"+ + "\u0000\u00b3\u00b4\u0005+\u0000\u0000\u00b4\u0016\u0001\u0000\u0000\u0000"+ + "\u00b5\u00b6\u0005-\u0000\u0000\u00b6\u0018\u0001\u0000\u0000\u0000\u00b7"+ + "\u00b8\u0005*\u0000\u0000\u00b8\u001a\u0001\u0000\u0000\u0000\u00b9\u00ba"+ + "\u0005/\u0000\u0000\u00ba\u001c\u0001\u0000\u0000\u0000\u00bb\u00bc\u0005"+ + "%\u0000\u0000\u00bc\u001e\u0001\u0000\u0000\u0000\u00bd\u00be\u0005^\u0000"+ + "\u0000\u00be \u0001\u0000\u0000\u0000\u00bf\u00c0\u0005!\u0000\u0000\u00c0"+ + "\u00c1\u0005=\u0000\u0000\u00c1\"\u0001\u0000\u0000\u0000\u00c2\u00c3"+ + "\u0005>\u0000\u0000\u00c3$\u0001\u0000\u0000\u0000\u00c4\u00c5\u0005>"+ + "\u0000\u0000\u00c5\u00c6\u0005=\u0000\u0000\u00c6&\u0001\u0000\u0000\u0000"+ + "\u00c7\u00c8\u0005<\u0000\u0000\u00c8(\u0001\u0000\u0000\u0000\u00c9\u00ca"+ + "\u0005<\u0000\u0000\u00ca\u00cb\u0005=\u0000\u0000\u00cb*\u0001\u0000"+ + "\u0000\u0000\u00cc\u00cd\u0005=\u0000\u0000\u00cd,\u0001\u0000\u0000\u0000"+ + "\u00ce\u00cf\u0005(\u0000\u0000\u00cf.\u0001\u0000\u0000\u0000\u00d0\u00d1"+ + "\u0005)\u0000\u0000\u00d10\u0001\u0000\u0000\u0000\u00d2\u00d4\u0007\u0000"+ + "\u0000\u0000\u00d3\u00d2\u0001\u0000\u0000\u0000\u00d4\u00d5\u0001\u0000"+ + "\u0000\u0000\u00d5\u00d3\u0001\u0000\u0000\u0000\u00d5\u00d6\u0001\u0000"+ + "\u0000\u0000\u00d6\u00d7\u0001\u0000\u0000\u0000\u00d7\u00d9\u0005.\u0000"+ + "\u0000\u00d8\u00da\u0007\u0000\u0000\u0000\u00d9\u00d8\u0001\u0000\u0000"+ + "\u0000\u00da\u00db\u0001\u0000\u0000\u0000\u00db\u00d9\u0001\u0000\u0000"+ + "\u0000\u00db\u00dc\u0001\u0000\u0000\u0000\u00dc2\u0001\u0000\u0000\u0000"+ + "\u00dd\u00e0\u0007\u0000\u0000\u0000\u00de\u00df\u0005.\u0000\u0000\u00df"+ + "\u00e1\u00035\u001a\u0000\u00e0\u00de\u0001\u0000\u0000\u0000\u00e1\u00e2"+ + "\u0001\u0000\u0000\u0000\u00e2\u00e0\u0001\u0000\u0000\u0000\u00e2\u00e3"+ + "\u0001\u0000\u0000\u0000\u00e34\u0001\u0000\u0000\u0000\u00e4\u00e6\u0007"+ + "\u0000\u0000\u0000\u00e5\u00e4\u0001\u0000\u0000\u0000\u00e6\u00e7\u0001"+ + "\u0000\u0000\u0000\u00e7\u00e5\u0001\u0000\u0000\u0000\u00e7\u00e8\u0001"+ + "\u0000\u0000\u0000\u00e86\u0001\u0000\u0000\u0000\u00e9\u00eb\u0007\u0001"+ + "\u0000\u0000\u00ea\u00e9\u0001\u0000\u0000\u0000\u00eb\u00ec\u0001\u0000"+ + "\u0000\u0000\u00ec\u00ea\u0001\u0000\u0000\u0000\u00ec\u00ed\u0001\u0000"+ + "\u0000\u0000\u00ed\u00ee\u0001\u0000\u0000\u0000\u00ee\u00ef\u0006\u001b"+ + "\u0000\u0000\u00ef8\u0001\u0000\u0000\u0000\u00f0\u00f5\u0003;\u001d\u0000"+ + "\u00f1\u00f5\u0007\u0002\u0000\u0000\u00f2\u00f5\u0003=\u001e\u0000\u00f3"+ + "\u00f5\u0003?\u001f\u0000\u00f4\u00f0\u0001\u0000\u0000\u0000\u00f4\u00f1"+ + "\u0001\u0000\u0000\u0000\u00f4\u00f2\u0001\u0000\u0000\u0000\u00f4\u00f3"+ + "\u0001\u0000\u0000\u0000\u00f5\u00f6\u0001\u0000\u0000\u0000\u00f6\u00f4"+ + "\u0001\u0000\u0000\u0000\u00f6\u00f7\u0001\u0000\u0000\u0000\u00f7:\u0001"+ + "\u0000\u0000\u0000\u00f8\u00f9\u0007\u0003\u0000\u0000\u00f9<\u0001\u0000"+ + "\u0000\u0000\u00fa\u00fe\u0005\'\u0000\u0000\u00fb\u00fd\t\u0000\u0000"+ + "\u0000\u00fc\u00fb\u0001\u0000\u0000\u0000\u00fd\u0100\u0001\u0000\u0000"+ + "\u0000\u00fe\u00ff\u0001\u0000\u0000\u0000\u00fe\u00fc\u0001\u0000\u0000"+ + "\u0000\u00ff\u0101\u0001\u0000\u0000\u0000\u0100\u00fe\u0001\u0000\u0000"+ + "\u0000\u0101\u0102\u0005\'\u0000\u0000\u0102>\u0001\u0000\u0000\u0000"+ + "\u0103\u0107\u0005\"\u0000\u0000\u0104\u0106\t\u0000\u0000\u0000\u0105"+ + "\u0104\u0001\u0000\u0000\u0000\u0106\u0109\u0001\u0000\u0000\u0000\u0107"+ + "\u0108\u0001\u0000\u0000\u0000\u0107\u0105\u0001\u0000\u0000\u0000\u0108"+ + "\u010a\u0001\u0000\u0000\u0000\u0109\u0107\u0001\u0000\u0000\u0000\u010a"+ + "\u010b\u0005\"\u0000\u0000\u010b@\u0001\u0000\u0000\u0000\u0013\u0000"+ + "GMW_gq}\u0097\u00b1\u00d5\u00db\u00e2\u00e7\u00ec\u00f4\u00f6\u00fe\u0107"+ + "\u0001\u0006\u0000\u0000"; public static final ATN _ATN = new ATNDeserializer().deserialize(_serializedATN.toCharArray()); static { diff --git a/src/main/java/com/github/sidhant92/boolparser/parser/antlr/BooleanExpressionListener.java b/src/main/java/com/github/sidhant92/boolparser/parser/antlr/BooleanExpressionListener.java index c66abe2..0cf661c 100644 --- a/src/main/java/com/github/sidhant92/boolparser/parser/antlr/BooleanExpressionListener.java +++ b/src/main/java/com/github/sidhant92/boolparser/parser/antlr/BooleanExpressionListener.java @@ -16,6 +16,18 @@ public interface BooleanExpressionListener extends ParseTreeListener { * @param ctx the parse tree */ void exitParse(BooleanExpressionParser.ParseContext ctx); + /** + * Enter a parse tree produced by the {@code unaryArithmeticExpression} + * labeled alternative in {@link BooleanExpressionParser#expression}. + * @param ctx the parse tree + */ + void enterUnaryArithmeticExpression(BooleanExpressionParser.UnaryArithmeticExpressionContext ctx); + /** + * Exit a parse tree produced by the {@code unaryArithmeticExpression} + * labeled alternative in {@link BooleanExpressionParser#expression}. + * @param ctx the parse tree + */ + void exitUnaryArithmeticExpression(BooleanExpressionParser.UnaryArithmeticExpressionContext ctx); /** * Enter a parse tree produced by the {@code binaryExpression} * labeled alternative in {@link BooleanExpressionParser#expression}. @@ -88,6 +100,18 @@ public interface BooleanExpressionListener extends ParseTreeListener { * @param ctx the parse tree */ void exitNotExpression(BooleanExpressionParser.NotExpressionContext ctx); + /** + * Enter a parse tree produced by the {@code arithmeticExpression} + * labeled alternative in {@link BooleanExpressionParser#expression}. + * @param ctx the parse tree + */ + void enterArithmeticExpression(BooleanExpressionParser.ArithmeticExpressionContext ctx); + /** + * Exit a parse tree produced by the {@code arithmeticExpression} + * labeled alternative in {@link BooleanExpressionParser#expression}. + * @param ctx the parse tree + */ + void exitArithmeticExpression(BooleanExpressionParser.ArithmeticExpressionContext ctx); /** * Enter a parse tree produced by the {@code comparatorExpression} * labeled alternative in {@link BooleanExpressionParser#expression}. @@ -122,6 +146,16 @@ public interface BooleanExpressionListener extends ParseTreeListener { * @param ctx the parse tree */ void exitComparator(BooleanExpressionParser.ComparatorContext ctx); + /** + * Enter a parse tree produced by {@link BooleanExpressionParser#arithmeticOperator}. + * @param ctx the parse tree + */ + void enterArithmeticOperator(BooleanExpressionParser.ArithmeticOperatorContext ctx); + /** + * Exit a parse tree produced by {@link BooleanExpressionParser#arithmeticOperator}. + * @param ctx the parse tree + */ + void exitArithmeticOperator(BooleanExpressionParser.ArithmeticOperatorContext ctx); /** * Enter a parse tree produced by {@link BooleanExpressionParser#wordlist}. * @param ctx the parse tree diff --git a/src/main/java/com/github/sidhant92/boolparser/parser/antlr/BooleanExpressionParser.java b/src/main/java/com/github/sidhant92/boolparser/parser/antlr/BooleanExpressionParser.java index 21438de..e32b2b8 100644 --- a/src/main/java/com/github/sidhant92/boolparser/parser/antlr/BooleanExpressionParser.java +++ b/src/main/java/com/github/sidhant92/boolparser/parser/antlr/BooleanExpressionParser.java @@ -17,34 +17,36 @@ public class BooleanExpressionParser extends Parser { new PredictionContextCache(); public static final int T__0=1, IN=2, TO=3, AND=4, OR=5, NOT=6, TRUE=7, FALSE=8, CONTAINS_ALL=9, - CONTAINS_ANY=10, NE=11, GT=12, GE=13, LT=14, LE=15, EQ=16, LPAREN=17, - RPAREN=18, DECIMAL=19, APP_VERSION=20, INTEGER=21, WS=22, WORD=23, ALPHANUMERIC=24, - SQ=25, DQ=26; + CONTAINS_ANY=10, ADD=11, SUBTRACT=12, MULTIPLY=13, DIVIDE=14, MODULUS=15, + EXPONENT=16, NE=17, GT=18, GE=19, LT=20, LE=21, EQ=22, LPAREN=23, RPAREN=24, + DECIMAL=25, APP_VERSION=26, INTEGER=27, WS=28, WORD=29, ALPHANUMERIC=30, + SQ=31, DQ=32; public static final int - RULE_parse = 0, RULE_expression = 1, RULE_comparator = 2, RULE_wordlist = 3, - RULE_arrayOperators = 4, RULE_numericTypes = 5, RULE_types = 6, RULE_binary = 7, - RULE_bool = 8; + RULE_parse = 0, RULE_expression = 1, RULE_comparator = 2, RULE_arithmeticOperator = 3, + RULE_wordlist = 4, RULE_arrayOperators = 5, RULE_numericTypes = 6, RULE_types = 7, + RULE_binary = 8, RULE_bool = 9; private static String[] makeRuleNames() { return new String[] { - "parse", "expression", "comparator", "wordlist", "arrayOperators", "numericTypes", - "types", "binary", "bool" + "parse", "expression", "comparator", "arithmeticOperator", "wordlist", + "arrayOperators", "numericTypes", "types", "binary", "bool" }; } public static final String[] ruleNames = makeRuleNames(); private static String[] makeLiteralNames() { return new String[] { - null, "','", null, null, null, null, null, null, null, null, null, "'!='", - "'>'", "'>='", "'<'", "'<='", "'='", "'('", "')'" + null, "','", null, null, null, null, null, null, null, null, null, "'+'", + "'-'", "'*'", "'/'", "'%'", "'^'", "'!='", "'>'", "'>='", "'<'", "'<='", + "'='", "'('", "')'" }; } private static final String[] _LITERAL_NAMES = makeLiteralNames(); private static String[] makeSymbolicNames() { return new String[] { null, null, "IN", "TO", "AND", "OR", "NOT", "TRUE", "FALSE", "CONTAINS_ALL", - "CONTAINS_ANY", "NE", "GT", "GE", "LT", "LE", "EQ", "LPAREN", "RPAREN", - "DECIMAL", "APP_VERSION", "INTEGER", "WS", "WORD", "ALPHANUMERIC", "SQ", - "DQ" + "CONTAINS_ANY", "ADD", "SUBTRACT", "MULTIPLY", "DIVIDE", "MODULUS", "EXPONENT", + "NE", "GT", "GE", "LT", "LE", "EQ", "LPAREN", "RPAREN", "DECIMAL", "APP_VERSION", + "INTEGER", "WS", "WORD", "ALPHANUMERIC", "SQ", "DQ" }; } private static final String[] _SYMBOLIC_NAMES = makeSymbolicNames(); @@ -124,9 +126,9 @@ public final ParseContext parse() throws RecognitionException { try { enterOuterAlt(_localctx, 1); { - setState(18); + setState(20); expression(0); - setState(19); + setState(21); match(EOF); } } @@ -154,6 +156,24 @@ public void copyFrom(ExpressionContext ctx) { } } @SuppressWarnings("CheckReturnValue") + public static class UnaryArithmeticExpressionContext extends ExpressionContext { + public Token op; + public ExpressionContext exp; + public TerminalNode SUBTRACT() { return getToken(BooleanExpressionParser.SUBTRACT, 0); } + public ExpressionContext expression() { + return getRuleContext(ExpressionContext.class,0); + } + public UnaryArithmeticExpressionContext(ExpressionContext ctx) { copyFrom(ctx); } + @Override + public void enterRule(ParseTreeListener listener) { + if ( listener instanceof BooleanExpressionListener ) ((BooleanExpressionListener)listener).enterUnaryArithmeticExpression(this); + } + @Override + public void exitRule(ParseTreeListener listener) { + if ( listener instanceof BooleanExpressionListener ) ((BooleanExpressionListener)listener).exitUnaryArithmeticExpression(this); + } + } + @SuppressWarnings("CheckReturnValue") public static class BinaryExpressionContext extends ExpressionContext { public ExpressionContext left; public BinaryContext op; @@ -275,6 +295,33 @@ public void exitRule(ParseTreeListener listener) { } } @SuppressWarnings("CheckReturnValue") + public static class ArithmeticExpressionContext extends ExpressionContext { + public ExpressionContext left; + public Token op; + public ExpressionContext right; + public List expression() { + return getRuleContexts(ExpressionContext.class); + } + public ExpressionContext expression(int i) { + return getRuleContext(ExpressionContext.class,i); + } + public TerminalNode EXPONENT() { return getToken(BooleanExpressionParser.EXPONENT, 0); } + public TerminalNode DIVIDE() { return getToken(BooleanExpressionParser.DIVIDE, 0); } + public TerminalNode MULTIPLY() { return getToken(BooleanExpressionParser.MULTIPLY, 0); } + public TerminalNode MODULUS() { return getToken(BooleanExpressionParser.MODULUS, 0); } + public TerminalNode ADD() { return getToken(BooleanExpressionParser.ADD, 0); } + public TerminalNode SUBTRACT() { return getToken(BooleanExpressionParser.SUBTRACT, 0); } + public ArithmeticExpressionContext(ExpressionContext ctx) { copyFrom(ctx); } + @Override + public void enterRule(ParseTreeListener listener) { + if ( listener instanceof BooleanExpressionListener ) ((BooleanExpressionListener)listener).enterArithmeticExpression(this); + } + @Override + public void exitRule(ParseTreeListener listener) { + if ( listener instanceof BooleanExpressionListener ) ((BooleanExpressionListener)listener).exitArithmeticExpression(this); + } + } + @SuppressWarnings("CheckReturnValue") public static class ComparatorExpressionContext extends ExpressionContext { public ExpressionContext left; public ComparatorContext op; @@ -332,7 +379,7 @@ private ExpressionContext expression(int _p) throws RecognitionException { int _alt; enterOuterAlt(_localctx, 1); { - setState(50); + setState(54); _errHandler.sync(this); switch ( getInterpreter().adaptivePredict(_input,4,_ctx) ) { case 1: @@ -341,11 +388,11 @@ private ExpressionContext expression(int _p) throws RecognitionException { _ctx = _localctx; _prevctx = _localctx; - setState(22); + setState(24); match(LPAREN); - setState(23); + setState(25); expression(0); - setState(24); + setState(26); match(RPAREN); } break; @@ -354,99 +401,110 @@ private ExpressionContext expression(int _p) throws RecognitionException { _localctx = new NotExpressionContext(_localctx); _ctx = _localctx; _prevctx = _localctx; - setState(26); + setState(28); match(NOT); - setState(27); - expression(7); + setState(29); + expression(14); } break; case 3: + { + _localctx = new UnaryArithmeticExpressionContext(_localctx); + _ctx = _localctx; + _prevctx = _localctx; + setState(30); + ((UnaryArithmeticExpressionContext)_localctx).op = match(SUBTRACT); + setState(31); + ((UnaryArithmeticExpressionContext)_localctx).exp = expression(12); + } + break; + case 4: { _localctx = new TypesExpressionContext(_localctx); _ctx = _localctx; _prevctx = _localctx; - setState(28); + setState(32); types(); } break; - case 4: + case 5: { _localctx = new ToExpressionContext(_localctx); _ctx = _localctx; _prevctx = _localctx; - setState(30); + setState(34); _errHandler.sync(this); _la = _input.LA(1); if (_la==WORD) { { - setState(29); + setState(33); ((ToExpressionContext)_localctx).field = match(WORD); } } - setState(32); + setState(36); ((ToExpressionContext)_localctx).lower = numericTypes(); - setState(33); + setState(37); match(TO); - setState(34); + setState(38); ((ToExpressionContext)_localctx).upper = numericTypes(); } break; - case 5: + case 6: { _localctx = new InExpressionContext(_localctx); _ctx = _localctx; _prevctx = _localctx; - setState(37); + setState(41); _errHandler.sync(this); _la = _input.LA(1); if (_la==WORD) { { - setState(36); + setState(40); ((InExpressionContext)_localctx).field = match(WORD); } } - setState(40); + setState(44); _errHandler.sync(this); _la = _input.LA(1); if (_la==NOT) { { - setState(39); + setState(43); ((InExpressionContext)_localctx).not = match(NOT); } } - setState(42); + setState(46); match(IN); - setState(43); + setState(47); ((InExpressionContext)_localctx).data = wordlist(); } break; - case 6: + case 7: { _localctx = new ArrayExpressionContext(_localctx); _ctx = _localctx; _prevctx = _localctx; - setState(45); + setState(49); _errHandler.sync(this); _la = _input.LA(1); if (_la==WORD) { { - setState(44); + setState(48); ((ArrayExpressionContext)_localctx).field = match(WORD); } } - setState(47); + setState(51); ((ArrayExpressionContext)_localctx).op = arrayOperators(); - setState(48); + setState(52); ((ArrayExpressionContext)_localctx).data = wordlist(); } break; } _ctx.stop = _input.LT(-1); - setState(62); + setState(84); _errHandler.sync(this); _alt = getInterpreter().adaptivePredict(_input,6,_ctx); while ( _alt!=2 && _alt!= ATN.INVALID_ALT_NUMBER ) { @@ -454,7 +512,7 @@ private ExpressionContext expression(int _p) throws RecognitionException { if ( _parseListeners!=null ) triggerExitRuleEvent(); _prevctx = _localctx; { - setState(60); + setState(82); _errHandler.sync(this); switch ( getInterpreter().adaptivePredict(_input,5,_ctx) ) { case 1: @@ -462,31 +520,109 @@ private ExpressionContext expression(int _p) throws RecognitionException { _localctx = new ComparatorExpressionContext(new ExpressionContext(_parentctx, _parentState)); ((ComparatorExpressionContext)_localctx).left = _prevctx; pushNewRecursionContext(_localctx, _startState, RULE_expression); - setState(52); - if (!(precpred(_ctx, 6))) throw new FailedPredicateException(this, "precpred(_ctx, 6)"); - setState(53); + setState(56); + if (!(precpred(_ctx, 13))) throw new FailedPredicateException(this, "precpred(_ctx, 13)"); + setState(57); ((ComparatorExpressionContext)_localctx).op = comparator(); - setState(54); - ((ComparatorExpressionContext)_localctx).right = expression(7); + setState(58); + ((ComparatorExpressionContext)_localctx).right = expression(14); } break; case 2: + { + _localctx = new ArithmeticExpressionContext(new ExpressionContext(_parentctx, _parentState)); + ((ArithmeticExpressionContext)_localctx).left = _prevctx; + pushNewRecursionContext(_localctx, _startState, RULE_expression); + setState(60); + if (!(precpred(_ctx, 11))) throw new FailedPredicateException(this, "precpred(_ctx, 11)"); + setState(61); + ((ArithmeticExpressionContext)_localctx).op = match(EXPONENT); + setState(62); + ((ArithmeticExpressionContext)_localctx).right = expression(12); + } + break; + case 3: + { + _localctx = new ArithmeticExpressionContext(new ExpressionContext(_parentctx, _parentState)); + ((ArithmeticExpressionContext)_localctx).left = _prevctx; + pushNewRecursionContext(_localctx, _startState, RULE_expression); + setState(63); + if (!(precpred(_ctx, 10))) throw new FailedPredicateException(this, "precpred(_ctx, 10)"); + setState(64); + ((ArithmeticExpressionContext)_localctx).op = match(DIVIDE); + setState(65); + ((ArithmeticExpressionContext)_localctx).right = expression(11); + } + break; + case 4: + { + _localctx = new ArithmeticExpressionContext(new ExpressionContext(_parentctx, _parentState)); + ((ArithmeticExpressionContext)_localctx).left = _prevctx; + pushNewRecursionContext(_localctx, _startState, RULE_expression); + setState(66); + if (!(precpred(_ctx, 9))) throw new FailedPredicateException(this, "precpred(_ctx, 9)"); + setState(67); + ((ArithmeticExpressionContext)_localctx).op = match(MULTIPLY); + setState(68); + ((ArithmeticExpressionContext)_localctx).right = expression(10); + } + break; + case 5: + { + _localctx = new ArithmeticExpressionContext(new ExpressionContext(_parentctx, _parentState)); + ((ArithmeticExpressionContext)_localctx).left = _prevctx; + pushNewRecursionContext(_localctx, _startState, RULE_expression); + setState(69); + if (!(precpred(_ctx, 8))) throw new FailedPredicateException(this, "precpred(_ctx, 8)"); + setState(70); + ((ArithmeticExpressionContext)_localctx).op = match(MODULUS); + setState(71); + ((ArithmeticExpressionContext)_localctx).right = expression(9); + } + break; + case 6: + { + _localctx = new ArithmeticExpressionContext(new ExpressionContext(_parentctx, _parentState)); + ((ArithmeticExpressionContext)_localctx).left = _prevctx; + pushNewRecursionContext(_localctx, _startState, RULE_expression); + setState(72); + if (!(precpred(_ctx, 7))) throw new FailedPredicateException(this, "precpred(_ctx, 7)"); + setState(73); + ((ArithmeticExpressionContext)_localctx).op = match(ADD); + setState(74); + ((ArithmeticExpressionContext)_localctx).right = expression(8); + } + break; + case 7: + { + _localctx = new ArithmeticExpressionContext(new ExpressionContext(_parentctx, _parentState)); + ((ArithmeticExpressionContext)_localctx).left = _prevctx; + pushNewRecursionContext(_localctx, _startState, RULE_expression); + setState(75); + if (!(precpred(_ctx, 6))) throw new FailedPredicateException(this, "precpred(_ctx, 6)"); + setState(76); + ((ArithmeticExpressionContext)_localctx).op = match(SUBTRACT); + setState(77); + ((ArithmeticExpressionContext)_localctx).right = expression(7); + } + break; + case 8: { _localctx = new BinaryExpressionContext(new ExpressionContext(_parentctx, _parentState)); ((BinaryExpressionContext)_localctx).left = _prevctx; pushNewRecursionContext(_localctx, _startState, RULE_expression); - setState(56); + setState(78); if (!(precpred(_ctx, 5))) throw new FailedPredicateException(this, "precpred(_ctx, 5)"); - setState(57); + setState(79); ((BinaryExpressionContext)_localctx).op = binary(); - setState(58); + setState(80); ((BinaryExpressionContext)_localctx).right = expression(6); } break; } } } - setState(64); + setState(86); _errHandler.sync(this); _alt = getInterpreter().adaptivePredict(_input,6,_ctx); } @@ -532,7 +668,59 @@ public final ComparatorContext comparator() throws RecognitionException { try { enterOuterAlt(_localctx, 1); { - setState(65); + setState(87); + _la = _input.LA(1); + if ( !((((_la) & ~0x3f) == 0 && ((1L << _la) & 8257536L) != 0)) ) { + _errHandler.recoverInline(this); + } + else { + if ( _input.LA(1)==Token.EOF ) matchedEOF = true; + _errHandler.reportMatch(this); + consume(); + } + } + } + catch (RecognitionException re) { + _localctx.exception = re; + _errHandler.reportError(this, re); + _errHandler.recover(this, re); + } + finally { + exitRule(); + } + return _localctx; + } + + @SuppressWarnings("CheckReturnValue") + public static class ArithmeticOperatorContext extends ParserRuleContext { + public TerminalNode MULTIPLY() { return getToken(BooleanExpressionParser.MULTIPLY, 0); } + public TerminalNode DIVIDE() { return getToken(BooleanExpressionParser.DIVIDE, 0); } + public TerminalNode ADD() { return getToken(BooleanExpressionParser.ADD, 0); } + public TerminalNode SUBTRACT() { return getToken(BooleanExpressionParser.SUBTRACT, 0); } + public TerminalNode MODULUS() { return getToken(BooleanExpressionParser.MODULUS, 0); } + public TerminalNode EXPONENT() { return getToken(BooleanExpressionParser.EXPONENT, 0); } + public ArithmeticOperatorContext(ParserRuleContext parent, int invokingState) { + super(parent, invokingState); + } + @Override public int getRuleIndex() { return RULE_arithmeticOperator; } + @Override + public void enterRule(ParseTreeListener listener) { + if ( listener instanceof BooleanExpressionListener ) ((BooleanExpressionListener)listener).enterArithmeticOperator(this); + } + @Override + public void exitRule(ParseTreeListener listener) { + if ( listener instanceof BooleanExpressionListener ) ((BooleanExpressionListener)listener).exitArithmeticOperator(this); + } + } + + public final ArithmeticOperatorContext arithmeticOperator() throws RecognitionException { + ArithmeticOperatorContext _localctx = new ArithmeticOperatorContext(_ctx, getState()); + enterRule(_localctx, 6, RULE_arithmeticOperator); + int _la; + try { + enterOuterAlt(_localctx, 1); + { + setState(89); _la = _input.LA(1); if ( !((((_la) & ~0x3f) == 0 && ((1L << _la) & 129024L) != 0)) ) { _errHandler.recoverInline(this); @@ -587,93 +775,93 @@ public void exitRule(ParseTreeListener listener) { public final WordlistContext wordlist() throws RecognitionException { WordlistContext _localctx = new WordlistContext(_ctx, getState()); - enterRule(_localctx, 6, RULE_wordlist); + enterRule(_localctx, 8, RULE_wordlist); int _la; try { int _alt; enterOuterAlt(_localctx, 1); { - setState(67); + setState(91); match(LPAREN); - setState(71); + setState(95); _errHandler.sync(this); _alt = getInterpreter().adaptivePredict(_input,7,_ctx); while ( _alt!=2 && _alt!= ATN.INVALID_ALT_NUMBER ) { if ( _alt==1 ) { { { - setState(68); + setState(92); match(WS); } } } - setState(73); + setState(97); _errHandler.sync(this); _alt = getInterpreter().adaptivePredict(_input,7,_ctx); } - setState(74); + setState(98); ((WordlistContext)_localctx).first = types(); - setState(78); + setState(102); _errHandler.sync(this); _la = _input.LA(1); while (_la==WS) { { { - setState(75); + setState(99); match(WS); } } - setState(80); + setState(104); _errHandler.sync(this); _la = _input.LA(1); } - setState(97); + setState(121); _errHandler.sync(this); _la = _input.LA(1); while (_la==T__0) { { { - setState(81); + setState(105); match(T__0); - setState(85); + setState(109); _errHandler.sync(this); _alt = getInterpreter().adaptivePredict(_input,9,_ctx); while ( _alt!=2 && _alt!= ATN.INVALID_ALT_NUMBER ) { if ( _alt==1 ) { { { - setState(82); + setState(106); match(WS); } } } - setState(87); + setState(111); _errHandler.sync(this); _alt = getInterpreter().adaptivePredict(_input,9,_ctx); } - setState(88); + setState(112); ((WordlistContext)_localctx).rest = types(); - setState(92); + setState(116); _errHandler.sync(this); _la = _input.LA(1); while (_la==WS) { { { - setState(89); + setState(113); match(WS); } } - setState(94); + setState(118); _errHandler.sync(this); _la = _input.LA(1); } } } - setState(99); + setState(123); _errHandler.sync(this); _la = _input.LA(1); } - setState(100); + setState(124); match(RPAREN); } } @@ -708,12 +896,12 @@ public void exitRule(ParseTreeListener listener) { public final ArrayOperatorsContext arrayOperators() throws RecognitionException { ArrayOperatorsContext _localctx = new ArrayOperatorsContext(_ctx, getState()); - enterRule(_localctx, 8, RULE_arrayOperators); + enterRule(_localctx, 10, RULE_arrayOperators); int _la; try { enterOuterAlt(_localctx, 1); { - setState(102); + setState(126); _la = _input.LA(1); if ( !(_la==CONTAINS_ALL || _la==CONTAINS_ANY) ) { _errHandler.recoverInline(this); @@ -756,12 +944,12 @@ public void exitRule(ParseTreeListener listener) { public final NumericTypesContext numericTypes() throws RecognitionException { NumericTypesContext _localctx = new NumericTypesContext(_ctx, getState()); - enterRule(_localctx, 10, RULE_numericTypes); + enterRule(_localctx, 12, RULE_numericTypes); int _la; try { enterOuterAlt(_localctx, 1); { - setState(104); + setState(128); _la = _input.LA(1); if ( !(_la==DECIMAL || _la==INTEGER) ) { _errHandler.recoverInline(this); @@ -809,43 +997,43 @@ public void exitRule(ParseTreeListener listener) { public final TypesContext types() throws RecognitionException { TypesContext _localctx = new TypesContext(_ctx, getState()); - enterRule(_localctx, 12, RULE_types); + enterRule(_localctx, 14, RULE_types); try { - setState(112); + setState(136); _errHandler.sync(this); switch ( getInterpreter().adaptivePredict(_input,12,_ctx) ) { case 1: enterOuterAlt(_localctx, 1); { - setState(106); + setState(130); match(INTEGER); } break; case 2: enterOuterAlt(_localctx, 2); { - setState(107); + setState(131); match(DECIMAL); } break; case 3: enterOuterAlt(_localctx, 3); { - setState(108); + setState(132); match(APP_VERSION); } break; case 4: enterOuterAlt(_localctx, 4); { - setState(109); + setState(133); bool(); } break; case 5: enterOuterAlt(_localctx, 5); { - setState(110); + setState(134); match(WORD); } break; @@ -887,12 +1075,12 @@ public void exitRule(ParseTreeListener listener) { public final BinaryContext binary() throws RecognitionException { BinaryContext _localctx = new BinaryContext(_ctx, getState()); - enterRule(_localctx, 14, RULE_binary); + enterRule(_localctx, 16, RULE_binary); int _la; try { enterOuterAlt(_localctx, 1); { - setState(114); + setState(138); _la = _input.LA(1); if ( !(_la==AND || _la==OR) ) { _errHandler.recoverInline(this); @@ -935,12 +1123,12 @@ public void exitRule(ParseTreeListener listener) { public final BoolContext bool() throws RecognitionException { BoolContext _localctx = new BoolContext(_ctx, getState()); - enterRule(_localctx, 16, RULE_bool); + enterRule(_localctx, 18, RULE_bool); int _la; try { enterOuterAlt(_localctx, 1); { - setState(116); + setState(140); _la = _input.LA(1); if ( !(_la==TRUE || _la==FALSE) ) { _errHandler.recoverInline(this); @@ -973,86 +1161,115 @@ public boolean sempred(RuleContext _localctx, int ruleIndex, int predIndex) { private boolean expression_sempred(ExpressionContext _localctx, int predIndex) { switch (predIndex) { case 0: - return precpred(_ctx, 6); + return precpred(_ctx, 13); case 1: + return precpred(_ctx, 11); + case 2: + return precpred(_ctx, 10); + case 3: + return precpred(_ctx, 9); + case 4: + return precpred(_ctx, 8); + case 5: + return precpred(_ctx, 7); + case 6: + return precpred(_ctx, 6); + case 7: return precpred(_ctx, 5); } return true; } public static final String _serializedATN = - "\u0004\u0001\u001aw\u0002\u0000\u0007\u0000\u0002\u0001\u0007\u0001\u0002"+ + "\u0004\u0001 \u008f\u0002\u0000\u0007\u0000\u0002\u0001\u0007\u0001\u0002"+ "\u0002\u0007\u0002\u0002\u0003\u0007\u0003\u0002\u0004\u0007\u0004\u0002"+ "\u0005\u0007\u0005\u0002\u0006\u0007\u0006\u0002\u0007\u0007\u0007\u0002"+ - "\b\u0007\b\u0001\u0000\u0001\u0000\u0001\u0000\u0001\u0001\u0001\u0001"+ + "\b\u0007\b\u0002\t\u0007\t\u0001\u0000\u0001\u0000\u0001\u0000\u0001\u0001"+ + "\u0001\u0001\u0001\u0001\u0001\u0001\u0001\u0001\u0001\u0001\u0001\u0001"+ + "\u0001\u0001\u0001\u0001\u0001\u0001\u0001\u0001\u0003\u0001#\b\u0001"+ + "\u0001\u0001\u0001\u0001\u0001\u0001\u0001\u0001\u0001\u0001\u0003\u0001"+ + "*\b\u0001\u0001\u0001\u0003\u0001-\b\u0001\u0001\u0001\u0001\u0001\u0001"+ + "\u0001\u0003\u00012\b\u0001\u0001\u0001\u0001\u0001\u0001\u0001\u0003"+ + "\u00017\b\u0001\u0001\u0001\u0001\u0001\u0001\u0001\u0001\u0001\u0001"+ + "\u0001\u0001\u0001\u0001\u0001\u0001\u0001\u0001\u0001\u0001\u0001\u0001"+ "\u0001\u0001\u0001\u0001\u0001\u0001\u0001\u0001\u0001\u0001\u0001\u0001"+ - "\u0001\u0001\u0003\u0001\u001f\b\u0001\u0001\u0001\u0001\u0001\u0001\u0001"+ - "\u0001\u0001\u0001\u0001\u0003\u0001&\b\u0001\u0001\u0001\u0003\u0001"+ - ")\b\u0001\u0001\u0001\u0001\u0001\u0001\u0001\u0003\u0001.\b\u0001\u0001"+ - "\u0001\u0001\u0001\u0001\u0001\u0003\u00013\b\u0001\u0001\u0001\u0001"+ "\u0001\u0001\u0001\u0001\u0001\u0001\u0001\u0001\u0001\u0001\u0001\u0001"+ - "\u0001\u0005\u0001=\b\u0001\n\u0001\f\u0001@\t\u0001\u0001\u0002\u0001"+ - "\u0002\u0001\u0003\u0001\u0003\u0005\u0003F\b\u0003\n\u0003\f\u0003I\t"+ - "\u0003\u0001\u0003\u0001\u0003\u0005\u0003M\b\u0003\n\u0003\f\u0003P\t"+ - "\u0003\u0001\u0003\u0001\u0003\u0005\u0003T\b\u0003\n\u0003\f\u0003W\t"+ - "\u0003\u0001\u0003\u0001\u0003\u0005\u0003[\b\u0003\n\u0003\f\u0003^\t"+ - "\u0003\u0005\u0003`\b\u0003\n\u0003\f\u0003c\t\u0003\u0001\u0003\u0001"+ - "\u0003\u0001\u0004\u0001\u0004\u0001\u0005\u0001\u0005\u0001\u0006\u0001"+ - "\u0006\u0001\u0006\u0001\u0006\u0001\u0006\u0001\u0006\u0003\u0006q\b"+ - "\u0006\u0001\u0007\u0001\u0007\u0001\b\u0001\b\u0001\b\u0000\u0001\u0002"+ - "\t\u0000\u0002\u0004\u0006\b\n\f\u000e\u0010\u0000\u0005\u0001\u0000\u000b"+ - "\u0010\u0001\u0000\t\n\u0002\u0000\u0013\u0013\u0015\u0015\u0001\u0000"+ - "\u0004\u0005\u0001\u0000\u0007\b\u0082\u0000\u0012\u0001\u0000\u0000\u0000"+ - "\u00022\u0001\u0000\u0000\u0000\u0004A\u0001\u0000\u0000\u0000\u0006C"+ - "\u0001\u0000\u0000\u0000\bf\u0001\u0000\u0000\u0000\nh\u0001\u0000\u0000"+ - "\u0000\fp\u0001\u0000\u0000\u0000\u000er\u0001\u0000\u0000\u0000\u0010"+ - "t\u0001\u0000\u0000\u0000\u0012\u0013\u0003\u0002\u0001\u0000\u0013\u0014"+ - "\u0005\u0000\u0000\u0001\u0014\u0001\u0001\u0000\u0000\u0000\u0015\u0016"+ - "\u0006\u0001\uffff\uffff\u0000\u0016\u0017\u0005\u0011\u0000\u0000\u0017"+ - "\u0018\u0003\u0002\u0001\u0000\u0018\u0019\u0005\u0012\u0000\u0000\u0019"+ - "3\u0001\u0000\u0000\u0000\u001a\u001b\u0005\u0006\u0000\u0000\u001b3\u0003"+ - "\u0002\u0001\u0007\u001c3\u0003\f\u0006\u0000\u001d\u001f\u0005\u0017"+ - "\u0000\u0000\u001e\u001d\u0001\u0000\u0000\u0000\u001e\u001f\u0001\u0000"+ - "\u0000\u0000\u001f \u0001\u0000\u0000\u0000 !\u0003\n\u0005\u0000!\"\u0005"+ - "\u0003\u0000\u0000\"#\u0003\n\u0005\u0000#3\u0001\u0000\u0000\u0000$&"+ - "\u0005\u0017\u0000\u0000%$\u0001\u0000\u0000\u0000%&\u0001\u0000\u0000"+ - "\u0000&(\u0001\u0000\u0000\u0000\')\u0005\u0006\u0000\u0000(\'\u0001\u0000"+ - "\u0000\u0000()\u0001\u0000\u0000\u0000)*\u0001\u0000\u0000\u0000*+\u0005"+ - "\u0002\u0000\u0000+3\u0003\u0006\u0003\u0000,.\u0005\u0017\u0000\u0000"+ - "-,\u0001\u0000\u0000\u0000-.\u0001\u0000\u0000\u0000./\u0001\u0000\u0000"+ - "\u0000/0\u0003\b\u0004\u000001\u0003\u0006\u0003\u000013\u0001\u0000\u0000"+ - "\u00002\u0015\u0001\u0000\u0000\u00002\u001a\u0001\u0000\u0000\u00002"+ - "\u001c\u0001\u0000\u0000\u00002\u001e\u0001\u0000\u0000\u00002%\u0001"+ - "\u0000\u0000\u00002-\u0001\u0000\u0000\u00003>\u0001\u0000\u0000\u0000"+ - "45\n\u0006\u0000\u000056\u0003\u0004\u0002\u000067\u0003\u0002\u0001\u0007"+ - "7=\u0001\u0000\u0000\u000089\n\u0005\u0000\u00009:\u0003\u000e\u0007\u0000"+ - ":;\u0003\u0002\u0001\u0006;=\u0001\u0000\u0000\u0000<4\u0001\u0000\u0000"+ - "\u0000<8\u0001\u0000\u0000\u0000=@\u0001\u0000\u0000\u0000><\u0001\u0000"+ - "\u0000\u0000>?\u0001\u0000\u0000\u0000?\u0003\u0001\u0000\u0000\u0000"+ - "@>\u0001\u0000\u0000\u0000AB\u0007\u0000\u0000\u0000B\u0005\u0001\u0000"+ - "\u0000\u0000CG\u0005\u0011\u0000\u0000DF\u0005\u0016\u0000\u0000ED\u0001"+ - "\u0000\u0000\u0000FI\u0001\u0000\u0000\u0000GE\u0001\u0000\u0000\u0000"+ - "GH\u0001\u0000\u0000\u0000HJ\u0001\u0000\u0000\u0000IG\u0001\u0000\u0000"+ - "\u0000JN\u0003\f\u0006\u0000KM\u0005\u0016\u0000\u0000LK\u0001\u0000\u0000"+ - "\u0000MP\u0001\u0000\u0000\u0000NL\u0001\u0000\u0000\u0000NO\u0001\u0000"+ - "\u0000\u0000Oa\u0001\u0000\u0000\u0000PN\u0001\u0000\u0000\u0000QU\u0005"+ - "\u0001\u0000\u0000RT\u0005\u0016\u0000\u0000SR\u0001\u0000\u0000\u0000"+ - "TW\u0001\u0000\u0000\u0000US\u0001\u0000\u0000\u0000UV\u0001\u0000\u0000"+ - "\u0000VX\u0001\u0000\u0000\u0000WU\u0001\u0000\u0000\u0000X\\\u0003\f"+ - "\u0006\u0000Y[\u0005\u0016\u0000\u0000ZY\u0001\u0000\u0000\u0000[^\u0001"+ - "\u0000\u0000\u0000\\Z\u0001\u0000\u0000\u0000\\]\u0001\u0000\u0000\u0000"+ - "]`\u0001\u0000\u0000\u0000^\\\u0001\u0000\u0000\u0000_Q\u0001\u0000\u0000"+ - "\u0000`c\u0001\u0000\u0000\u0000a_\u0001\u0000\u0000\u0000ab\u0001\u0000"+ - "\u0000\u0000bd\u0001\u0000\u0000\u0000ca\u0001\u0000\u0000\u0000de\u0005"+ - "\u0012\u0000\u0000e\u0007\u0001\u0000\u0000\u0000fg\u0007\u0001\u0000"+ - "\u0000g\t\u0001\u0000\u0000\u0000hi\u0007\u0002\u0000\u0000i\u000b\u0001"+ - "\u0000\u0000\u0000jq\u0005\u0015\u0000\u0000kq\u0005\u0013\u0000\u0000"+ - "lq\u0005\u0014\u0000\u0000mq\u0003\u0010\b\u0000nq\u0005\u0017\u0000\u0000"+ - "oq\u0001\u0000\u0000\u0000pj\u0001\u0000\u0000\u0000pk\u0001\u0000\u0000"+ - "\u0000pl\u0001\u0000\u0000\u0000pm\u0001\u0000\u0000\u0000pn\u0001\u0000"+ - "\u0000\u0000po\u0001\u0000\u0000\u0000q\r\u0001\u0000\u0000\u0000rs\u0007"+ - "\u0003\u0000\u0000s\u000f\u0001\u0000\u0000\u0000tu\u0007\u0004\u0000"+ - "\u0000u\u0011\u0001\u0000\u0000\u0000\r\u001e%(-2<>GNU\\ap"; + "\u0001\u0001\u0001\u0001\u0001\u0001\u0001\u0005\u0001S\b\u0001\n\u0001"+ + "\f\u0001V\t\u0001\u0001\u0002\u0001\u0002\u0001\u0003\u0001\u0003\u0001"+ + "\u0004\u0001\u0004\u0005\u0004^\b\u0004\n\u0004\f\u0004a\t\u0004\u0001"+ + "\u0004\u0001\u0004\u0005\u0004e\b\u0004\n\u0004\f\u0004h\t\u0004\u0001"+ + "\u0004\u0001\u0004\u0005\u0004l\b\u0004\n\u0004\f\u0004o\t\u0004\u0001"+ + "\u0004\u0001\u0004\u0005\u0004s\b\u0004\n\u0004\f\u0004v\t\u0004\u0005"+ + "\u0004x\b\u0004\n\u0004\f\u0004{\t\u0004\u0001\u0004\u0001\u0004\u0001"+ + "\u0005\u0001\u0005\u0001\u0006\u0001\u0006\u0001\u0007\u0001\u0007\u0001"+ + "\u0007\u0001\u0007\u0001\u0007\u0001\u0007\u0003\u0007\u0089\b\u0007\u0001"+ + "\b\u0001\b\u0001\t\u0001\t\u0001\t\u0000\u0001\u0002\n\u0000\u0002\u0004"+ + "\u0006\b\n\f\u000e\u0010\u0012\u0000\u0006\u0001\u0000\u0011\u0016\u0001"+ + "\u0000\u000b\u0010\u0001\u0000\t\n\u0002\u0000\u0019\u0019\u001b\u001b"+ + "\u0001\u0000\u0004\u0005\u0001\u0000\u0007\b\u00a0\u0000\u0014\u0001\u0000"+ + "\u0000\u0000\u00026\u0001\u0000\u0000\u0000\u0004W\u0001\u0000\u0000\u0000"+ + "\u0006Y\u0001\u0000\u0000\u0000\b[\u0001\u0000\u0000\u0000\n~\u0001\u0000"+ + "\u0000\u0000\f\u0080\u0001\u0000\u0000\u0000\u000e\u0088\u0001\u0000\u0000"+ + "\u0000\u0010\u008a\u0001\u0000\u0000\u0000\u0012\u008c\u0001\u0000\u0000"+ + "\u0000\u0014\u0015\u0003\u0002\u0001\u0000\u0015\u0016\u0005\u0000\u0000"+ + "\u0001\u0016\u0001\u0001\u0000\u0000\u0000\u0017\u0018\u0006\u0001\uffff"+ + "\uffff\u0000\u0018\u0019\u0005\u0017\u0000\u0000\u0019\u001a\u0003\u0002"+ + "\u0001\u0000\u001a\u001b\u0005\u0018\u0000\u0000\u001b7\u0001\u0000\u0000"+ + "\u0000\u001c\u001d\u0005\u0006\u0000\u0000\u001d7\u0003\u0002\u0001\u000e"+ + "\u001e\u001f\u0005\f\u0000\u0000\u001f7\u0003\u0002\u0001\f 7\u0003\u000e"+ + "\u0007\u0000!#\u0005\u001d\u0000\u0000\"!\u0001\u0000\u0000\u0000\"#\u0001"+ + "\u0000\u0000\u0000#$\u0001\u0000\u0000\u0000$%\u0003\f\u0006\u0000%&\u0005"+ + "\u0003\u0000\u0000&\'\u0003\f\u0006\u0000\'7\u0001\u0000\u0000\u0000("+ + "*\u0005\u001d\u0000\u0000)(\u0001\u0000\u0000\u0000)*\u0001\u0000\u0000"+ + "\u0000*,\u0001\u0000\u0000\u0000+-\u0005\u0006\u0000\u0000,+\u0001\u0000"+ + "\u0000\u0000,-\u0001\u0000\u0000\u0000-.\u0001\u0000\u0000\u0000./\u0005"+ + "\u0002\u0000\u0000/7\u0003\b\u0004\u000002\u0005\u001d\u0000\u000010\u0001"+ + "\u0000\u0000\u000012\u0001\u0000\u0000\u000023\u0001\u0000\u0000\u0000"+ + "34\u0003\n\u0005\u000045\u0003\b\u0004\u000057\u0001\u0000\u0000\u0000"+ + "6\u0017\u0001\u0000\u0000\u00006\u001c\u0001\u0000\u0000\u00006\u001e"+ + "\u0001\u0000\u0000\u00006 \u0001\u0000\u0000\u00006\"\u0001\u0000\u0000"+ + "\u00006)\u0001\u0000\u0000\u000061\u0001\u0000\u0000\u00007T\u0001\u0000"+ + "\u0000\u000089\n\r\u0000\u00009:\u0003\u0004\u0002\u0000:;\u0003\u0002"+ + "\u0001\u000e;S\u0001\u0000\u0000\u0000<=\n\u000b\u0000\u0000=>\u0005\u0010"+ + "\u0000\u0000>S\u0003\u0002\u0001\f?@\n\n\u0000\u0000@A\u0005\u000e\u0000"+ + "\u0000AS\u0003\u0002\u0001\u000bBC\n\t\u0000\u0000CD\u0005\r\u0000\u0000"+ + "DS\u0003\u0002\u0001\nEF\n\b\u0000\u0000FG\u0005\u000f\u0000\u0000GS\u0003"+ + "\u0002\u0001\tHI\n\u0007\u0000\u0000IJ\u0005\u000b\u0000\u0000JS\u0003"+ + "\u0002\u0001\bKL\n\u0006\u0000\u0000LM\u0005\f\u0000\u0000MS\u0003\u0002"+ + "\u0001\u0007NO\n\u0005\u0000\u0000OP\u0003\u0010\b\u0000PQ\u0003\u0002"+ + "\u0001\u0006QS\u0001\u0000\u0000\u0000R8\u0001\u0000\u0000\u0000R<\u0001"+ + "\u0000\u0000\u0000R?\u0001\u0000\u0000\u0000RB\u0001\u0000\u0000\u0000"+ + "RE\u0001\u0000\u0000\u0000RH\u0001\u0000\u0000\u0000RK\u0001\u0000\u0000"+ + "\u0000RN\u0001\u0000\u0000\u0000SV\u0001\u0000\u0000\u0000TR\u0001\u0000"+ + "\u0000\u0000TU\u0001\u0000\u0000\u0000U\u0003\u0001\u0000\u0000\u0000"+ + "VT\u0001\u0000\u0000\u0000WX\u0007\u0000\u0000\u0000X\u0005\u0001\u0000"+ + "\u0000\u0000YZ\u0007\u0001\u0000\u0000Z\u0007\u0001\u0000\u0000\u0000"+ + "[_\u0005\u0017\u0000\u0000\\^\u0005\u001c\u0000\u0000]\\\u0001\u0000\u0000"+ + "\u0000^a\u0001\u0000\u0000\u0000_]\u0001\u0000\u0000\u0000_`\u0001\u0000"+ + "\u0000\u0000`b\u0001\u0000\u0000\u0000a_\u0001\u0000\u0000\u0000bf\u0003"+ + "\u000e\u0007\u0000ce\u0005\u001c\u0000\u0000dc\u0001\u0000\u0000\u0000"+ + "eh\u0001\u0000\u0000\u0000fd\u0001\u0000\u0000\u0000fg\u0001\u0000\u0000"+ + "\u0000gy\u0001\u0000\u0000\u0000hf\u0001\u0000\u0000\u0000im\u0005\u0001"+ + "\u0000\u0000jl\u0005\u001c\u0000\u0000kj\u0001\u0000\u0000\u0000lo\u0001"+ + "\u0000\u0000\u0000mk\u0001\u0000\u0000\u0000mn\u0001\u0000\u0000\u0000"+ + "np\u0001\u0000\u0000\u0000om\u0001\u0000\u0000\u0000pt\u0003\u000e\u0007"+ + "\u0000qs\u0005\u001c\u0000\u0000rq\u0001\u0000\u0000\u0000sv\u0001\u0000"+ + "\u0000\u0000tr\u0001\u0000\u0000\u0000tu\u0001\u0000\u0000\u0000ux\u0001"+ + "\u0000\u0000\u0000vt\u0001\u0000\u0000\u0000wi\u0001\u0000\u0000\u0000"+ + "x{\u0001\u0000\u0000\u0000yw\u0001\u0000\u0000\u0000yz\u0001\u0000\u0000"+ + "\u0000z|\u0001\u0000\u0000\u0000{y\u0001\u0000\u0000\u0000|}\u0005\u0018"+ + "\u0000\u0000}\t\u0001\u0000\u0000\u0000~\u007f\u0007\u0002\u0000\u0000"+ + "\u007f\u000b\u0001\u0000\u0000\u0000\u0080\u0081\u0007\u0003\u0000\u0000"+ + "\u0081\r\u0001\u0000\u0000\u0000\u0082\u0089\u0005\u001b\u0000\u0000\u0083"+ + "\u0089\u0005\u0019\u0000\u0000\u0084\u0089\u0005\u001a\u0000\u0000\u0085"+ + "\u0089\u0003\u0012\t\u0000\u0086\u0089\u0005\u001d\u0000\u0000\u0087\u0089"+ + "\u0001\u0000\u0000\u0000\u0088\u0082\u0001\u0000\u0000\u0000\u0088\u0083"+ + "\u0001\u0000\u0000\u0000\u0088\u0084\u0001\u0000\u0000\u0000\u0088\u0085"+ + "\u0001\u0000\u0000\u0000\u0088\u0086\u0001\u0000\u0000\u0000\u0088\u0087"+ + "\u0001\u0000\u0000\u0000\u0089\u000f\u0001\u0000\u0000\u0000\u008a\u008b"+ + "\u0007\u0004\u0000\u0000\u008b\u0011\u0001\u0000\u0000\u0000\u008c\u008d"+ + "\u0007\u0005\u0000\u0000\u008d\u0013\u0001\u0000\u0000\u0000\r\"),16R"+ + "T_fmty\u0088"; public static final ATN _ATN = new ATNDeserializer().deserialize(_serializedATN.toCharArray()); static { diff --git a/src/main/java/com/github/sidhant92/boolparser/parser/antlr/BooleanFilterListener.java b/src/main/java/com/github/sidhant92/boolparser/parser/antlr/BooleanFilterListener.java index 4e7f7d0..86f6fbf 100644 --- a/src/main/java/com/github/sidhant92/boolparser/parser/antlr/BooleanFilterListener.java +++ b/src/main/java/com/github/sidhant92/boolparser/parser/antlr/BooleanFilterListener.java @@ -11,6 +11,9 @@ import com.github.sidhant92.boolparser.constant.DataType; import com.github.sidhant92.boolparser.constant.LogicalOperationType; import com.github.sidhant92.boolparser.constant.Operator; +import com.github.sidhant92.boolparser.domain.arithmetic.ArithmeticLeafNode; +import com.github.sidhant92.boolparser.domain.arithmetic.ArithmeticNode; +import com.github.sidhant92.boolparser.domain.arithmetic.ArithmeticUnaryNode; import com.github.sidhant92.boolparser.domain.ArrayNode; import com.github.sidhant92.boolparser.domain.BooleanNode; import com.github.sidhant92.boolparser.domain.InNode; @@ -46,12 +49,63 @@ public Node getNode() { @Override public void exitComparatorExpression(BooleanExpressionParser.ComparatorExpressionContext ctx) { final String variableName = getField(ctx.left.getText()); - final DataType dataType = getDataType(ctx.right.getStart()); final Operator operator = Operator.getOperatorFromSymbol(ctx.op.getText()).orElse(Operator.EQUALS); - currentNodes.add(new ComparisonNode(variableName, ValueUtils.convertValue(ctx.right.getText(), dataType), operator, dataType)); + if (ctx.right instanceof BooleanExpressionParser.ParentExpressionContext && !currentNodes.isEmpty()) { + final Node value = currentNodes.pop(); + currentNodes.add(new ComparisonNode(variableName, value, operator, DataType.INTEGER)); + } else { + final DataType dataType = getDataType(ctx.right.getStart()); + currentNodes.add(new ComparisonNode(variableName, ValueUtils.convertValue(ctx.right.getText(), dataType), operator, dataType)); + } super.enterComparatorExpression(ctx); } + private ArithmeticLeafNode getArithmeticLeafNode(final BooleanExpressionParser.TypesExpressionContext ctx) { + final DataType dataType = getDataType(ctx.getStart()); + final Object operand = ValueUtils.convertValue(ctx.getText(), dataType); + return ArithmeticLeafNode.builder().operand(operand).dataType(dataType).build(); + } + + @Override + public void exitArithmeticExpression(BooleanExpressionParser.ArithmeticExpressionContext ctx) { + final Operator operator = Operator.getOperatorFromSymbol(ctx.op.getText()).orElse(Operator.EQUALS); + if (ctx.left instanceof BooleanExpressionParser.TypesExpressionContext && ctx.right instanceof BooleanExpressionParser.TypesExpressionContext) { + final ArithmeticLeafNode left = getArithmeticLeafNode((BooleanExpressionParser.TypesExpressionContext) ctx.left); + final ArithmeticLeafNode right = getArithmeticLeafNode((BooleanExpressionParser.TypesExpressionContext) ctx.right); + final ArithmeticNode node = ArithmeticNode.builder().left(left).right(right).operator(operator).build(); + currentNodes.add(node); + } else if (ctx.left instanceof BooleanExpressionParser.TypesExpressionContext) { + final ArithmeticLeafNode left = getArithmeticLeafNode((BooleanExpressionParser.TypesExpressionContext) ctx.left); + final Node right = currentNodes.pop(); + final ArithmeticNode node = ArithmeticNode.builder().left(left).right(right).operator(operator).build(); + currentNodes.add(node); + } else if (ctx.right instanceof BooleanExpressionParser.TypesExpressionContext) { + final ArithmeticLeafNode right = getArithmeticLeafNode((BooleanExpressionParser.TypesExpressionContext) ctx.right); + final Node left = currentNodes.pop(); + final ArithmeticNode node = ArithmeticNode.builder().left(left).right(right).operator(operator).build(); + currentNodes.add(node); + } else { + if (currentNodes.size() < 2) { + log.error("Error parsing expression for the string {}", ctx.getText()); + throw new InvalidExpressionException(); + } + final Node right = currentNodes.pop(); + final Node left = currentNodes.pop(); + final ArithmeticNode node = ArithmeticNode.builder().left(left).right(right).operator(operator).build(); + currentNodes.add(node); + } + super.exitArithmeticExpression(ctx); + } + + @Override + public void exitUnaryArithmeticExpression(BooleanExpressionParser.UnaryArithmeticExpressionContext ctx) { + final DataType dataType = getDataType(ctx.exp.getStart()); + final Object operand = ValueUtils.convertValue(ctx.exp.getText(), dataType); + final ArithmeticLeafNode leafNode = ArithmeticLeafNode.builder().operand(operand).dataType(dataType).build(); + currentNodes.add(ArithmeticUnaryNode.builder().operand(leafNode).build()); + super.enterUnaryArithmeticExpression(ctx); + } + @Override public void exitToExpression(BooleanExpressionParser.ToExpressionContext ctx) { validateField(ctx.field, ctx.getText()); @@ -143,7 +197,17 @@ private LogicalOperationType getLogicalOperator(final org.antlr.v4.runtime.Token public void exitParse(BooleanExpressionParser.ParseContext ctx) { if (this.node == null && this.currentNodes.size() == 1) { this.node = currentNodes.pop(); - } else { + } else if (this.node == null && this.currentNodes.size() == 2) { + final Node firstNode = currentNodes.pop(); + final Node secondNode = currentNodes.pop(); + if (firstNode instanceof ArithmeticNode && secondNode instanceof ArithmeticUnaryNode) { + this.node = ArithmeticUnaryNode.builder().operand(firstNode).build(); + } + if (secondNode instanceof ArithmeticNode && firstNode instanceof ArithmeticUnaryNode) { + this.node = ArithmeticUnaryNode.builder().operand(secondNode).build(); + } + } + if (this.node == null) { log.error("Error parsing expression for the string {}", ctx.getText()); throw new InvalidExpressionException(); } diff --git a/src/main/java/com/github/sidhant92/boolparser/util/ValueUtils.java b/src/main/java/com/github/sidhant92/boolparser/util/ValueUtils.java index 15232e0..a82e586 100644 --- a/src/main/java/com/github/sidhant92/boolparser/util/ValueUtils.java +++ b/src/main/java/com/github/sidhant92/boolparser/util/ValueUtils.java @@ -66,4 +66,20 @@ public static Optional parseInteger(final String number) { return Optional.empty(); } } + + public static DataType getDataType(final Object value) { + if (value instanceof Boolean) { + return DataType.BOOLEAN; + } + if (value instanceof Float || value instanceof Double) { + return DataType.DECIMAL; + } + if (value instanceof Integer) { + return DataType.INTEGER; + } + if (value instanceof Long) { + return DataType.LONG; + } + return DataType.STRING; + } } diff --git a/src/main/java/resources/BooleanExpression.g4 b/src/main/java/resources/BooleanExpression.g4 index 3c2bbba..d500a21 100644 --- a/src/main/java/resources/BooleanExpression.g4 +++ b/src/main/java/resources/BooleanExpression.g4 @@ -8,6 +8,13 @@ expression : LPAREN expression RPAREN #parentExpression | NOT expression #notExpression | left=expression op=comparator right=expression #comparatorExpression + | op=SUBTRACT exp=expression #unaryArithmeticExpression + | left=expression op= EXPONENT right=expression #arithmeticExpression + | left=expression op= DIVIDE right=expression #arithmeticExpression + | left=expression op= MULTIPLY right=expression #arithmeticExpression + | left=expression op= MODULUS right=expression #arithmeticExpression + | left=expression op= ADD right=expression #arithmeticExpression + | left=expression op= SUBTRACT right=expression #arithmeticExpression | left=expression op=binary right=expression #binaryExpression | types #typesExpression | (field=WORD)? lower=numericTypes TO upper=numericTypes #toExpression @@ -19,6 +26,15 @@ comparator : GT | GE | LT | LE | EQ | NE ; +arithmeticOperator + : MULTIPLY + | DIVIDE + | ADD + | SUBTRACT + | MODULUS + | EXPONENT + ; + wordlist : LPAREN WS* first=types WS* (',' WS* rest=types WS*)* RPAREN @@ -56,6 +72,12 @@ TRUE : 'TRUE' | 'true'; FALSE : 'FALSE' | 'false'; CONTAINS_ALL : 'CONTAINS_ALL' | 'contains_all'; CONTAINS_ANY : 'CONTAINS_ANY' | 'contains_any'; +ADD : '+'; +SUBTRACT : '-' ; +MULTIPLY : '*' ; +DIVIDE : '/' ; +MODULUS : '%' ; +EXPONENT : '^' ; NE : '!='; GT : '>' ; GE : '>=' ; diff --git a/src/test/java/com/github/sidhant92/boolparser/application/ArithmeticExpressionEvaluatorTest.java b/src/test/java/com/github/sidhant92/boolparser/application/ArithmeticExpressionEvaluatorTest.java new file mode 100644 index 0000000..ab6d203 --- /dev/null +++ b/src/test/java/com/github/sidhant92/boolparser/application/ArithmeticExpressionEvaluatorTest.java @@ -0,0 +1,180 @@ +package com.github.sidhant92.boolparser.application; + +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertFalse; +import static org.junit.jupiter.api.Assertions.assertTrue; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import org.junit.jupiter.api.Test; +import com.github.sidhant92.boolparser.exception.DataNotFoundException; +import com.github.sidhant92.boolparser.exception.InvalidDataType; +import com.github.sidhant92.boolparser.exception.InvalidExpressionException; +import com.github.sidhant92.boolparser.exception.InvalidUnaryOperand; +import com.github.sidhant92.boolparser.exception.UnsupportedToken; +import com.github.sidhant92.boolparser.parser.antlr.BoolParser; +import io.vavr.control.Try; + +/** + * @author sidhant.aggarwal + * @since 07/02/2023 + */ +public class ArithmeticExpressionEvaluatorTest { + private final ArithmeticExpressionEvaluator arithmeticExpressionEvaluator = new ArithmeticExpressionEvaluator(new BoolParser()); + + @Test + public void testSimpleAddOperationWithoutVariable() { + final Map data = new HashMap<>(); + final Try resultOptional = arithmeticExpressionEvaluator.evaluate("5 + 5", data); + assertTrue(resultOptional.isSuccess()); + assertEquals(resultOptional.get(), 10); + } + + @Test + public void testSimpleSubtractOperationWithoutVariable() { + final Map data = new HashMap<>(); + final Try resultOptional = arithmeticExpressionEvaluator.evaluate("5 - 4", data); + assertTrue(resultOptional.isSuccess()); + assertEquals(resultOptional.get(), 1); + } + + @Test + public void testSimpleMultiplyOperationWithoutVariable() { + final Map data = new HashMap<>(); + final Try resultOptional = arithmeticExpressionEvaluator.evaluate("5 * 5", data); + assertTrue(resultOptional.isSuccess()); + assertEquals(resultOptional.get(), 25); + } + + @Test + public void testSimpleDivideOperationWithoutVariable() { + final Map data = new HashMap<>(); + final Try resultOptional = arithmeticExpressionEvaluator.evaluate("5 / 5", data); + assertTrue(resultOptional.isSuccess()); + assertEquals(resultOptional.get(), 1); + } + + @Test + public void testSimpleDivideOperationWithoutVariable1() { + final Map data = new HashMap<>(); + final Try resultOptional = arithmeticExpressionEvaluator.evaluate("5 / 4", data); + assertTrue(resultOptional.isSuccess()); + assertEquals(resultOptional.get(), 1.25); + } + + @Test + public void testSimpleModulusOperationWithoutVariable() { + final Map data = new HashMap<>(); + final Try resultOptional = arithmeticExpressionEvaluator.evaluate("10 % 4", data); + assertTrue(resultOptional.isSuccess()); + assertEquals(resultOptional.get(), 2); + } + + @Test + public void testSimpleExponentOperationWithoutVariable() { + final Map data = new HashMap<>(); + final Try resultOptional = arithmeticExpressionEvaluator.evaluate("2 ^ 4", data); + assertTrue(resultOptional.isSuccess()); + assertEquals(resultOptional.get(), 16); + } + + @Test + public void testSimpleAddOperationWithVariable() { + final Map data = new HashMap<>(); + data.put("a", 10); + final Try resultOptional = arithmeticExpressionEvaluator.evaluate("a + 5", data); + assertTrue(resultOptional.isSuccess()); + assertEquals(resultOptional.get(), 15); + } + + @Test + public void testSimpleSubtractOperationWithVariable() { + final Map data = new HashMap<>(); + data.put("a", 10); + final Try resultOptional = arithmeticExpressionEvaluator.evaluate("a - 5", data); + assertTrue(resultOptional.isSuccess()); + assertEquals(resultOptional.get(), 5); + } + + @Test + public void testSimpleMultiplyOperationWithVariable() { + final Map data = new HashMap<>(); + data.put("a", 10); + final Try resultOptional = arithmeticExpressionEvaluator.evaluate("a * 5", data); + assertTrue(resultOptional.isSuccess()); + assertEquals(resultOptional.get(), 50); + } + + @Test + public void testSimpleDivideOperationWithVariable() { + final Map data = new HashMap<>(); + data.put("a", 10); + final Try resultOptional = arithmeticExpressionEvaluator.evaluate("a / 5", data); + assertTrue(resultOptional.isSuccess()); + assertEquals(resultOptional.get(), 2); + } + + @Test + public void testSimpleModulusOperationWithVariable() { + final Map data = new HashMap<>(); + data.put("a", 10); + final Try resultOptional = arithmeticExpressionEvaluator.evaluate("a % 5", data); + assertTrue(resultOptional.isSuccess()); + assertEquals(resultOptional.get(), 0); + } + + @Test + public void testSimpleExponentOperationWithVariable() { + final Map data = new HashMap<>(); + data.put("a", 10); + final Try resultOptional = arithmeticExpressionEvaluator.evaluate("a ^ 5", data); + assertTrue(resultOptional.isSuccess()); + assertEquals(resultOptional.get(), 100000); + } + + @Test + public void testExpressionWithParenthesisNoVariable() { + final Map data = new HashMap<>(); + data.put("a", 10); + final Try resultOptional = arithmeticExpressionEvaluator.evaluate("((5 * 2) + 10) * 2 + (1 + 3 * (10 / 2))", data); + assertTrue(resultOptional.isSuccess()); + assertEquals(resultOptional.get(), 56); + } + + @Test + public void testExpressionWithParenthesisWithVariable() { + final Map data = new HashMap<>(); + data.put("a", 10); + final Try resultOptional = arithmeticExpressionEvaluator.evaluate("((5 * 2) + a) * 2 + (1 + 3 * (a / 2))", data); + assertTrue(resultOptional.isSuccess()); + assertEquals(resultOptional.get(), 56); + } + + @Test + public void testExpressionWithComparison() { + final Map data = new HashMap<>(); + data.put("a", 10); + final Try resultOptional = arithmeticExpressionEvaluator.evaluate("(a > (4 + 1))", data); + assertTrue(resultOptional.isFailure()); + assertTrue(resultOptional.getCause() instanceof UnsupportedToken); + } + + @Test + public void testExpressionWithUnaryNode() { + final Map data = new HashMap<>(); + data.put("a", 10); + final Try resultOptional = arithmeticExpressionEvaluator.evaluate("- a", data); + assertTrue(resultOptional.isSuccess()); + assertEquals(resultOptional.get(), -10); + } + + @Test + public void testExpressionWithNestedUnaryNode() { + final Map data = new HashMap<>(); + data.put("a", 10); + final Try resultOptional = arithmeticExpressionEvaluator.evaluate("- (a + 5)", data); + assertTrue(resultOptional.isSuccess()); + assertEquals(resultOptional.get(), -15); + } +} diff --git a/src/test/java/com/github/sidhant92/boolparser/parser/antlr/BooleanFilterBoolParserTest.java b/src/test/java/com/github/sidhant92/boolparser/parser/antlr/BooleanFilterBoolParserTest.java index e16eda7..61a385b 100644 --- a/src/test/java/com/github/sidhant92/boolparser/parser/antlr/BooleanFilterBoolParserTest.java +++ b/src/test/java/com/github/sidhant92/boolparser/parser/antlr/BooleanFilterBoolParserTest.java @@ -9,6 +9,8 @@ import com.github.sidhant92.boolparser.constant.LogicalOperationType; import com.github.sidhant92.boolparser.constant.NodeType; import com.github.sidhant92.boolparser.constant.Operator; +import com.github.sidhant92.boolparser.domain.arithmetic.ArithmeticLeafNode; +import com.github.sidhant92.boolparser.domain.arithmetic.ArithmeticNode; import com.github.sidhant92.boolparser.domain.ArrayNode; import com.github.sidhant92.boolparser.domain.BooleanNode; import com.github.sidhant92.boolparser.domain.InNode; @@ -355,6 +357,54 @@ public void testContainsAll() { assertEquals(((ArrayNode) nodeOptional.get()).getItems().size(), 2); } + @Test + public void testAddOperatorString() { + final Try nodeOptional = boolExpressionBoolParser.parseExpression("a + b"); + assertTrue(nodeOptional.isSuccess()); + assertEquals(nodeOptional.get().getTokenType(), NodeType.ARITHMETIC); + assertEquals(((ArithmeticLeafNode)((ArithmeticNode) nodeOptional.get()).getLeft()).getOperand(), "a"); + assertEquals(((ArithmeticLeafNode)((ArithmeticNode) nodeOptional.get()).getLeft()).getDataType(), DataType.STRING); + assertEquals(((ArithmeticLeafNode)((ArithmeticNode) nodeOptional.get()).getRight()).getOperand(), "b"); + assertEquals(((ArithmeticLeafNode)((ArithmeticNode) nodeOptional.get()).getRight()).getDataType(), DataType.STRING); + assertEquals(((ArithmeticNode) nodeOptional.get()).getOperator(), Operator.ADD); + } + + @Test + public void testAddOperatorInt() { + final Try nodeOptional = boolExpressionBoolParser.parseExpression("20 + 5"); + assertTrue(nodeOptional.isSuccess()); + assertEquals(nodeOptional.get().getTokenType(), NodeType.ARITHMETIC); + assertEquals(((ArithmeticLeafNode)((ArithmeticNode) nodeOptional.get()).getLeft()).getOperand(), 20); + assertEquals(((ArithmeticLeafNode)((ArithmeticNode) nodeOptional.get()).getLeft()).getDataType(), DataType.INTEGER); + assertEquals(((ArithmeticLeafNode)((ArithmeticNode) nodeOptional.get()).getRight()).getOperand(), 5); + assertEquals(((ArithmeticLeafNode)((ArithmeticNode) nodeOptional.get()).getRight()).getDataType(), DataType.INTEGER); + assertEquals(((ArithmeticNode) nodeOptional.get()).getOperator(), Operator.ADD); + } + + @Test + public void testAddOperatorDecimal() { + final Try nodeOptional = boolExpressionBoolParser.parseExpression("20.5 + 5"); + assertTrue(nodeOptional.isSuccess()); + assertEquals(nodeOptional.get().getTokenType(), NodeType.ARITHMETIC); + assertEquals(((ArithmeticLeafNode)((ArithmeticNode) nodeOptional.get()).getLeft()).getOperand(), 20.5); + assertEquals(((ArithmeticLeafNode)((ArithmeticNode) nodeOptional.get()).getLeft()).getDataType(), DataType.DECIMAL); + assertEquals(((ArithmeticLeafNode)((ArithmeticNode) nodeOptional.get()).getRight()).getOperand(), 5); + assertEquals(((ArithmeticLeafNode)((ArithmeticNode) nodeOptional.get()).getRight()).getDataType(), DataType.INTEGER); + assertEquals(((ArithmeticNode) nodeOptional.get()).getOperator(), Operator.ADD); + } + + @Test + public void testAddOperatorBool() { + final Try nodeOptional = boolExpressionBoolParser.parseExpression("false + 5"); + assertTrue(nodeOptional.isSuccess()); + assertEquals(nodeOptional.get().getTokenType(), NodeType.ARITHMETIC); + assertEquals(((ArithmeticLeafNode)((ArithmeticNode) nodeOptional.get()).getLeft()).getOperand(), false); + assertEquals(((ArithmeticLeafNode)((ArithmeticNode) nodeOptional.get()).getLeft()).getDataType(), DataType.BOOLEAN); + assertEquals(((ArithmeticLeafNode)((ArithmeticNode) nodeOptional.get()).getRight()).getOperand(), 5); + assertEquals(((ArithmeticLeafNode)((ArithmeticNode) nodeOptional.get()).getRight()).getDataType(), DataType.INTEGER); + assertEquals(((ArithmeticNode) nodeOptional.get()).getOperator(), Operator.ADD); + } + private void verifyStringToken(final ComparisonNode stringToken, final String field, final String value) { assertEquals(stringToken.getTokenType().name(), NodeType.COMPARISON.name()); assertEquals(stringToken.getField(), field); From 797980ab84cc7cdb1c23c10dd442bfc92d144b83 Mon Sep 17 00:00:00 2001 From: Sidhant Aggarwal <10743214+sidhant92@users.noreply.github.com> Date: Sat, 16 Mar 2024 22:26:27 +0530 Subject: [PATCH 2/2] support arithmetic in logical and substitute node --- .../ArithmeticExpressionEvaluator.java | 11 ++++++++ .../BooleanExpressionEvaluator.java | 8 +++++- .../boolparser/constant/NodeType.java | 3 +- .../boolparser/domain/StringNode.java | 24 ++++++++++++++++ .../domain/arithmetic/ArithmeticBaseNode.java | 9 ++++++ .../domain/arithmetic/ArithmeticLeafNode.java | 2 +- .../domain/arithmetic/ArithmeticNode.java | 2 +- .../arithmetic/ArithmeticUnaryNode.java | 2 +- .../parser/antlr/BooleanFilterListener.java | 8 ++++++ .../ArithmeticExpressionEvaluatorTest.java | 19 +++++++++++++ .../BooleanExpressionEvaluatorTest.java | 28 +++++++++++++++++++ .../antlr/BooleanFilterBoolParserTest.java | 21 ++++++++++++-- 12 files changed, 129 insertions(+), 8 deletions(-) create mode 100644 src/main/java/com/github/sidhant92/boolparser/domain/StringNode.java create mode 100644 src/main/java/com/github/sidhant92/boolparser/domain/arithmetic/ArithmeticBaseNode.java diff --git a/src/main/java/com/github/sidhant92/boolparser/application/ArithmeticExpressionEvaluator.java b/src/main/java/com/github/sidhant92/boolparser/application/ArithmeticExpressionEvaluator.java index 41906d6..a8bfa39 100644 --- a/src/main/java/com/github/sidhant92/boolparser/application/ArithmeticExpressionEvaluator.java +++ b/src/main/java/com/github/sidhant92/boolparser/application/ArithmeticExpressionEvaluator.java @@ -6,6 +6,7 @@ import com.github.sidhant92.boolparser.constant.ContainerDataType; import com.github.sidhant92.boolparser.constant.DataType; import com.github.sidhant92.boolparser.constant.Operator; +import com.github.sidhant92.boolparser.domain.StringNode; import com.github.sidhant92.boolparser.domain.arithmetic.ArithmeticLeafNode; import com.github.sidhant92.boolparser.domain.arithmetic.ArithmeticNode; import com.github.sidhant92.boolparser.domain.arithmetic.ArithmeticUnaryNode; @@ -37,6 +38,10 @@ public Try evaluate(final String expression, final Map d return tokenOptional.map(node -> evaluateToken(node, data)); } + protected Object evaluate(final Node node, final Map data) { + return evaluateToken(node, data); + } + private Object evaluateToken(final Node node, final Map data) { switch (node.getTokenType()) { case ARITHMETIC: @@ -45,12 +50,18 @@ private Object evaluateToken(final Node node, final Map data) { return evaluateArithmeticLeafToken((ArithmeticLeafNode) node, data); case ARITHMETIC_UNARY: return evaluateUnaryArithmeticToken((ArithmeticUnaryNode) node, data); + case STRING: + return evaluateStringToken((StringNode) node, data); default: log.error("unsupported token {}", node.getTokenType()); throw new UnsupportedToken(); } } + private Object evaluateStringToken(final StringNode stringNode, final Map data) { + return ValueUtils.getValueFromMap(stringNode.getField(), data).orElse(stringNode.getField()); + } + private Pair evaluateArithmeticLeafToken(final ArithmeticLeafNode arithmeticLeafNode, final Map data) { final Optional fetchedValue = ValueUtils.getValueFromMap(arithmeticLeafNode.getOperand().toString(), data); return fetchedValue diff --git a/src/main/java/com/github/sidhant92/boolparser/application/BooleanExpressionEvaluator.java b/src/main/java/com/github/sidhant92/boolparser/application/BooleanExpressionEvaluator.java index cc36546..fc95eb4 100644 --- a/src/main/java/com/github/sidhant92/boolparser/application/BooleanExpressionEvaluator.java +++ b/src/main/java/com/github/sidhant92/boolparser/application/BooleanExpressionEvaluator.java @@ -12,6 +12,7 @@ import com.github.sidhant92.boolparser.domain.ComparisonNode; import com.github.sidhant92.boolparser.domain.Node; import com.github.sidhant92.boolparser.domain.UnaryNode; +import com.github.sidhant92.boolparser.domain.arithmetic.ArithmeticBaseNode; import com.github.sidhant92.boolparser.exception.DataNotFoundException; import com.github.sidhant92.boolparser.exception.HeterogeneousArrayException; import com.github.sidhant92.boolparser.exception.InvalidUnaryOperand; @@ -31,9 +32,12 @@ public class BooleanExpressionEvaluator { private final OperatorService operatorService; + private final ArithmeticExpressionEvaluator arithmeticExpressionEvaluator; + public BooleanExpressionEvaluator(final BoolExpressionParser boolExpressionParser) { this.boolExpressionParser = boolExpressionParser; operatorService = new OperatorService(); + arithmeticExpressionEvaluator = new ArithmeticExpressionEvaluator(boolExpressionParser); } public Try evaluate(final String expression, final Map data, final String defaultField) { @@ -66,8 +70,10 @@ private boolean evaluateToken(final Node node, final Map data) { private boolean evaluateComparisonToken(final ComparisonNode comparisonToken, final Map data) { final Object fieldData = ValueUtils.getValueFromMap(comparisonToken.getField(), data).orElseThrow(DataNotFoundException::new); + final Object value = comparisonToken.getValue() instanceof ArithmeticBaseNode ? arithmeticExpressionEvaluator.evaluate( + (Node) comparisonToken.getValue(), data) : comparisonToken.getValue(); return operatorService.evaluateLogicalOperator(comparisonToken.getOperator(), ContainerDataType.PRIMITIVE, comparisonToken.getDataType(), - fieldData, comparisonToken.getValue()); + fieldData, value); } private boolean evaluateNumericRangeToken(final NumericRangeNode numericRangeToken, final Map data) { diff --git a/src/main/java/com/github/sidhant92/boolparser/constant/NodeType.java b/src/main/java/com/github/sidhant92/boolparser/constant/NodeType.java index 38a0026..53b98f7 100644 --- a/src/main/java/com/github/sidhant92/boolparser/constant/NodeType.java +++ b/src/main/java/com/github/sidhant92/boolparser/constant/NodeType.java @@ -13,5 +13,6 @@ public enum NodeType { UNARY, ARITHMETIC, ARITHMETIC_LEAF, - ARITHMETIC_UNARY + ARITHMETIC_UNARY, + STRING } diff --git a/src/main/java/com/github/sidhant92/boolparser/domain/StringNode.java b/src/main/java/com/github/sidhant92/boolparser/domain/StringNode.java new file mode 100644 index 0000000..43a8fd3 --- /dev/null +++ b/src/main/java/com/github/sidhant92/boolparser/domain/StringNode.java @@ -0,0 +1,24 @@ +package com.github.sidhant92.boolparser.domain; + +import com.github.sidhant92.boolparser.constant.NodeType; +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Getter; +import lombok.Setter; + +/** + * @author sidhant.aggarwal + * @since 16/03/2024 + */ +@AllArgsConstructor +@Getter +@Setter +@Builder +public class StringNode extends Node { + private final String field; + + @Override + public NodeType getTokenType() { + return NodeType.STRING; + } +} diff --git a/src/main/java/com/github/sidhant92/boolparser/domain/arithmetic/ArithmeticBaseNode.java b/src/main/java/com/github/sidhant92/boolparser/domain/arithmetic/ArithmeticBaseNode.java new file mode 100644 index 0000000..76f66a7 --- /dev/null +++ b/src/main/java/com/github/sidhant92/boolparser/domain/arithmetic/ArithmeticBaseNode.java @@ -0,0 +1,9 @@ +package com.github.sidhant92.boolparser.domain.arithmetic; + +import com.github.sidhant92.boolparser.domain.Node; + +/** + * @author sidhant.aggarwal + * @since 16/03/2024 + */ +public abstract class ArithmeticBaseNode extends Node {} diff --git a/src/main/java/com/github/sidhant92/boolparser/domain/arithmetic/ArithmeticLeafNode.java b/src/main/java/com/github/sidhant92/boolparser/domain/arithmetic/ArithmeticLeafNode.java index 6df653f..56f08f6 100644 --- a/src/main/java/com/github/sidhant92/boolparser/domain/arithmetic/ArithmeticLeafNode.java +++ b/src/main/java/com/github/sidhant92/boolparser/domain/arithmetic/ArithmeticLeafNode.java @@ -16,7 +16,7 @@ @Getter @Setter @Builder -public class ArithmeticLeafNode extends Node { +public class ArithmeticLeafNode extends ArithmeticBaseNode { private Object operand; private DataType dataType; diff --git a/src/main/java/com/github/sidhant92/boolparser/domain/arithmetic/ArithmeticNode.java b/src/main/java/com/github/sidhant92/boolparser/domain/arithmetic/ArithmeticNode.java index b1e5468..a00f065 100644 --- a/src/main/java/com/github/sidhant92/boolparser/domain/arithmetic/ArithmeticNode.java +++ b/src/main/java/com/github/sidhant92/boolparser/domain/arithmetic/ArithmeticNode.java @@ -16,7 +16,7 @@ @Getter @Setter @Builder -public class ArithmeticNode extends Node { +public class ArithmeticNode extends ArithmeticBaseNode { private Node left; private Node right; diff --git a/src/main/java/com/github/sidhant92/boolparser/domain/arithmetic/ArithmeticUnaryNode.java b/src/main/java/com/github/sidhant92/boolparser/domain/arithmetic/ArithmeticUnaryNode.java index 7adda3d..57e649e 100644 --- a/src/main/java/com/github/sidhant92/boolparser/domain/arithmetic/ArithmeticUnaryNode.java +++ b/src/main/java/com/github/sidhant92/boolparser/domain/arithmetic/ArithmeticUnaryNode.java @@ -15,7 +15,7 @@ @Getter @Setter @Builder -public class ArithmeticUnaryNode extends Node { +public class ArithmeticUnaryNode extends ArithmeticBaseNode { private Node operand; @Override diff --git a/src/main/java/com/github/sidhant92/boolparser/parser/antlr/BooleanFilterListener.java b/src/main/java/com/github/sidhant92/boolparser/parser/antlr/BooleanFilterListener.java index 86f6fbf..4f06e0a 100644 --- a/src/main/java/com/github/sidhant92/boolparser/parser/antlr/BooleanFilterListener.java +++ b/src/main/java/com/github/sidhant92/boolparser/parser/antlr/BooleanFilterListener.java @@ -4,6 +4,7 @@ import java.util.Objects; import java.util.Stack; import java.util.stream.Collectors; +import org.antlr.v4.runtime.CommonToken; import org.antlr.v4.runtime.Token; import org.antlr.v4.runtime.tree.ParseTree; import org.apache.commons.lang3.StringUtils; @@ -11,6 +12,7 @@ import com.github.sidhant92.boolparser.constant.DataType; import com.github.sidhant92.boolparser.constant.LogicalOperationType; import com.github.sidhant92.boolparser.constant.Operator; +import com.github.sidhant92.boolparser.domain.StringNode; import com.github.sidhant92.boolparser.domain.arithmetic.ArithmeticLeafNode; import com.github.sidhant92.boolparser.domain.arithmetic.ArithmeticNode; import com.github.sidhant92.boolparser.domain.arithmetic.ArithmeticUnaryNode; @@ -33,6 +35,8 @@ public class BooleanFilterListener extends BooleanExpressionBaseListener { private org.antlr.v4.runtime.Token lastToken; + private int tokenCount; + private String defaultField; public BooleanFilterListener(final String defaultField) { @@ -207,6 +211,9 @@ public void exitParse(BooleanExpressionParser.ParseContext ctx) { this.node = ArithmeticUnaryNode.builder().operand(secondNode).build(); } } + if (this.node == null && tokenCount == 1 && lastToken instanceof CommonToken) { + this.node = StringNode.builder().field((lastToken.getText())).build(); + } if (this.node == null) { log.error("Error parsing expression for the string {}", ctx.getText()); throw new InvalidExpressionException(); @@ -232,6 +239,7 @@ public void exitNotExpression(BooleanExpressionParser.NotExpressionContext ctx) @Override public void exitTypesExpression(BooleanExpressionParser.TypesExpressionContext ctx) { + tokenCount++; this.lastToken = ctx.start; } diff --git a/src/test/java/com/github/sidhant92/boolparser/application/ArithmeticExpressionEvaluatorTest.java b/src/test/java/com/github/sidhant92/boolparser/application/ArithmeticExpressionEvaluatorTest.java index ab6d203..5a67421 100644 --- a/src/test/java/com/github/sidhant92/boolparser/application/ArithmeticExpressionEvaluatorTest.java +++ b/src/test/java/com/github/sidhant92/boolparser/application/ArithmeticExpressionEvaluatorTest.java @@ -133,6 +133,16 @@ public void testSimpleExponentOperationWithVariable() { assertEquals(resultOptional.get(), 100000); } + @Test + public void testStringConcatenation() { + final Map data = new HashMap<>(); + data.put("a", "first"); + data.put("b", "second"); + final Try resultOptional = arithmeticExpressionEvaluator.evaluate("a + \" \" + b", data); + assertTrue(resultOptional.isSuccess()); + assertEquals(resultOptional.get(), "first second"); + } + @Test public void testExpressionWithParenthesisNoVariable() { final Map data = new HashMap<>(); @@ -177,4 +187,13 @@ public void testExpressionWithNestedUnaryNode() { assertTrue(resultOptional.isSuccess()); assertEquals(resultOptional.get(), -15); } + + @Test + public void testExpressionWithNestedUnaryNode1() { + final Map data = new HashMap<>(); + data.put("a", "test"); + final Try resultOptional = arithmeticExpressionEvaluator.evaluate("a", data); + assertTrue(resultOptional.isSuccess()); + assertEquals(resultOptional.get(), "test"); + } } diff --git a/src/test/java/com/github/sidhant92/boolparser/application/BooleanExpressionEvaluatorTest.java b/src/test/java/com/github/sidhant92/boolparser/application/BooleanExpressionEvaluatorTest.java index ca99377..3058f28 100644 --- a/src/test/java/com/github/sidhant92/boolparser/application/BooleanExpressionEvaluatorTest.java +++ b/src/test/java/com/github/sidhant92/boolparser/application/BooleanExpressionEvaluatorTest.java @@ -514,4 +514,32 @@ public void testContainsAllFalseCondition() { assertTrue(booleanOptional.isSuccess()); assertFalse(booleanOptional.get()); } + + @Test + public void testComparisonWithArithmeticTrueCondition() { + final Map data = new HashMap<>(); + data.put("age", "20"); + final Try booleanOptional = booleanExpressionEvaluator.evaluate("age > (5 + 10)", data); + assertTrue(booleanOptional.isSuccess()); + assertTrue(booleanOptional.get()); + } + + @Test + public void testComparisonWithArithmeticFalseCondition() { + final Map data = new HashMap<>(); + data.put("age", "20"); + final Try booleanOptional = booleanExpressionEvaluator.evaluate("age > (5 + 20)", data); + assertTrue(booleanOptional.isSuccess()); + assertFalse(booleanOptional.get()); + } + + @Test + public void testComparisonWithArithmeticFalseCondition1() { + final Map data = new HashMap<>(); + data.put("age", "20"); + data.put("a", 20); + final Try booleanOptional = booleanExpressionEvaluator.evaluate("age > (5 + a)", data); + assertTrue(booleanOptional.isSuccess()); + assertFalse(booleanOptional.get()); + } } diff --git a/src/test/java/com/github/sidhant92/boolparser/parser/antlr/BooleanFilterBoolParserTest.java b/src/test/java/com/github/sidhant92/boolparser/parser/antlr/BooleanFilterBoolParserTest.java index 61a385b..c1044da 100644 --- a/src/test/java/com/github/sidhant92/boolparser/parser/antlr/BooleanFilterBoolParserTest.java +++ b/src/test/java/com/github/sidhant92/boolparser/parser/antlr/BooleanFilterBoolParserTest.java @@ -9,6 +9,7 @@ import com.github.sidhant92.boolparser.constant.LogicalOperationType; import com.github.sidhant92.boolparser.constant.NodeType; import com.github.sidhant92.boolparser.constant.Operator; +import com.github.sidhant92.boolparser.domain.StringNode; import com.github.sidhant92.boolparser.domain.arithmetic.ArithmeticLeafNode; import com.github.sidhant92.boolparser.domain.arithmetic.ArithmeticNode; import com.github.sidhant92.boolparser.domain.ArrayNode; @@ -324,10 +325,10 @@ public void testStringList2() { } @Test - public void testInvalidExpression() { + public void testSingleToken() { final Try nodeOptional = boolExpressionBoolParser.parseExpression("a"); - assertTrue(nodeOptional.isFailure()); - assertTrue(nodeOptional.getCause() instanceof InvalidExpressionException); + assertTrue(nodeOptional.isSuccess()); + assertTrue(nodeOptional.get() instanceof StringNode); } @Test @@ -405,6 +406,20 @@ public void testAddOperatorBool() { assertEquals(((ArithmeticNode) nodeOptional.get()).getOperator(), Operator.ADD); } + @Test + public void testComparisonWithArithmetic() { + final Try nodeOptional = boolExpressionBoolParser.parseExpression("a > (10 + 20)"); + assertTrue(nodeOptional.isSuccess()); + assertEquals(nodeOptional.get().getTokenType(), NodeType.COMPARISON); + assertEquals((((ComparisonNode) nodeOptional.get()).getField()), "a"); + final ArithmeticNode arithmeticNode = (ArithmeticNode) ((ComparisonNode) nodeOptional.get()).getValue(); + assertEquals(((ArithmeticLeafNode)(arithmeticNode.getLeft())).getOperand(), 10); + assertEquals(((ArithmeticLeafNode)(arithmeticNode.getLeft())).getDataType(), DataType.INTEGER); + assertEquals(((ArithmeticLeafNode)(arithmeticNode.getRight())).getOperand(), 20); + assertEquals(((ArithmeticLeafNode)(arithmeticNode.getRight())).getDataType(), DataType.INTEGER); + assertEquals(arithmeticNode.getOperator(), Operator.ADD); + } + private void verifyStringToken(final ComparisonNode stringToken, final String field, final String value) { assertEquals(stringToken.getTokenType().name(), NodeType.COMPARISON.name()); assertEquals(stringToken.getField(), field);