From 63adb465105a19e2ecddf5eac084b4e98428ed63 Mon Sep 17 00:00:00 2001 From: Sidhant Aggarwal <10743214+sidhant92@users.noreply.github.com> Date: Mon, 6 Nov 2023 19:00:13 +0530 Subject: [PATCH 1/4] array support and not in support --- build.gradle | 12 +- .../BooleanExpressionEvaluator.java | 26 +- .../constant/ContainerDataType.java | 40 +- .../boolparser/constant/NodeType.java | 1 + .../boolparser/constant/Operator.java | 12 +- .../boolparser/domain/ArrayNode.java | 27 ++ .../HeterogeneousArrayException.java | 8 + .../InvalidContainerTypeException.java | 16 + .../boolparser/operator/AbstractOperator.java | 9 +- .../operator/ContainsAllOperator.java | 49 ++ .../operator/ContainsAnyOperator.java | 49 ++ .../boolparser/operator/EqualsOperator.java | 13 + .../operator/GreaterThanEqualOperator.java | 13 + .../operator/GreaterThanOperator.java | 13 + .../boolparser/operator/InOperator.java | 14 +- .../operator/LessThanEqualOperator.java | 13 + .../boolparser/operator/LessThanOperator.java | 13 + .../operator/NotEqualsOperator.java | 13 + .../boolparser/operator/OperatorFactory.java | 3 + .../boolparser/operator/OperatorService.java | 19 +- .../antlr/BooleanExpressionBaseListener.java | 26 +- .../parser/antlr/BooleanExpressionLexer.java | 292 +++++++----- .../antlr/BooleanExpressionListener.java | 24 +- .../parser/antlr/BooleanExpressionParser.java | 437 ++++++++++++------ .../parser/antlr/BooleanFilterListener.java | 41 +- src/main/java/resources/BooleanExpression.g4 | 11 +- .../BooleanExpressionEvaluatorTest.java | 64 +++ .../antlr/BooleanFilterBoolParserTest.java | 41 +- 28 files changed, 989 insertions(+), 310 deletions(-) create mode 100644 src/main/java/com/github/sidhant92/boolparser/domain/ArrayNode.java create mode 100644 src/main/java/com/github/sidhant92/boolparser/exception/HeterogeneousArrayException.java create mode 100644 src/main/java/com/github/sidhant92/boolparser/exception/InvalidContainerTypeException.java create mode 100644 src/main/java/com/github/sidhant92/boolparser/operator/ContainsAllOperator.java create mode 100644 src/main/java/com/github/sidhant92/boolparser/operator/ContainsAnyOperator.java diff --git a/build.gradle b/build.gradle index 9292a51..b7f7ccc 100644 --- a/build.gradle +++ b/build.gradle @@ -22,7 +22,7 @@ sourceCompatibility = 1.8 targetCompatibility = 1.8 group 'com.github.sidhant92' -version = "1.1.1" +version = "1.2.0" apply plugin: "com.dipien.semantic-version" @@ -36,7 +36,7 @@ dependencies { implementation 'ch.qos.logback.contrib:logback-jackson:0.1.5' implementation 'net.logstash.logback:logstash-logback-encoder:5.2' implementation 'org.apache.maven:maven-artifact:3.5.2' - implementation 'org.antlr:antlr4-runtime:4.11.1' + implementation 'org.antlr:antlr4-runtime:4.13.1' implementation 'io.vavr:vavr:0.10.4' implementation 'com.github.ben-manes.caffeine:caffeine:2.9.3' implementation 'org.projectlombok:lombok:1.18.26' @@ -91,7 +91,7 @@ publishing { pom { name = 'bool-parser' description = 'Java parser for boolean expressions' - url = 'https://github.com/sidhant92/bool-parser' + url = 'https://github.com/sidhant92/bool-parser-java' licenses { license { name = 'The Apache License, Version 2.0' @@ -105,9 +105,9 @@ publishing { } } scm { - url = 'https://github.com/sidhant92/bool-parser' - connection = 'scm:git://github.com/sidhant92/bool-parser.git' - developerConnection = 'scm:git://github.com/sidhant92/bool-parser.git' + url = 'https://github.com/sidhant92/bool-parser-java' + connection = 'scm:git://github.com/sidhant92/bool-parser-java.git' + developerConnection = 'scm:git://github.com/sidhant92/bool-parser-java.git' } } } 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 c76e4d2..ce6105d 100644 --- a/src/main/java/com/github/sidhant92/boolparser/application/BooleanExpressionEvaluator.java +++ b/src/main/java/com/github/sidhant92/boolparser/application/BooleanExpressionEvaluator.java @@ -5,6 +5,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.ArrayNode; import com.github.sidhant92.boolparser.domain.BooleanNode; import com.github.sidhant92.boolparser.domain.InNode; import com.github.sidhant92.boolparser.domain.NumericRangeNode; @@ -12,6 +13,7 @@ import com.github.sidhant92.boolparser.domain.Node; import com.github.sidhant92.boolparser.domain.UnaryNode; import com.github.sidhant92.boolparser.exception.DataNotFoundException; +import com.github.sidhant92.boolparser.exception.HeterogeneousArrayException; import com.github.sidhant92.boolparser.exception.InvalidUnaryOperand; import com.github.sidhant92.boolparser.operator.OperatorService; import com.github.sidhant92.boolparser.parser.BoolExpressionParser; @@ -51,6 +53,8 @@ private boolean evaluateToken(final Node node, final Map data) { return evaluateNumericRangeToken((NumericRangeNode) node, data); case IN: return evaluateInToken((InNode) node, data); + case ARRAY: + return evaluateArrayToken((ArrayNode) node, data); case UNARY: return evaluateUnaryToken((UnaryNode) node, data); case BOOLEAN: @@ -62,15 +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, + return operatorService.evaluate(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, + return operatorService.evaluate(Operator.GREATER_THAN_EQUAL, ContainerDataType.PRIMITIVE, numericRangeToken.getFromDataType(), fieldData, numericRangeToken.getFromValue()) && operatorService.evaluate(Operator.LESS_THAN_EQUAL, - ContainerDataType.primitive, + ContainerDataType.PRIMITIVE, numericRangeToken.getToDataType(), fieldData, numericRangeToken.getToValue()); } @@ -81,7 +85,21 @@ 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.evaluate(Operator.IN, ContainerDataType.PRIMITIVE, dataType, fieldData, values); + } + + private boolean evaluateArrayToken(final ArrayNode arrayNode, final Map data) { + final Object fieldData = ValueUtils.getValueFromMap(arrayNode.getField(), data).orElseThrow(DataNotFoundException::new); + if (arrayNode.getItems() + .stream() + .map(Pair::getLeft).distinct().count() > 1) { + throw new HeterogeneousArrayException(); + } + final DataType dataType = arrayNode.getItems().get(0).getLeft(); + final Object[] values = arrayNode.getItems() + .stream() + .map(Pair::getRight).toArray(); + return operatorService.evaluate(arrayNode.getOperator(), ContainerDataType.LIST, dataType, fieldData, values); } private boolean evaluateUnaryToken(final UnaryNode unaryToken, final Map data) { diff --git a/src/main/java/com/github/sidhant92/boolparser/constant/ContainerDataType.java b/src/main/java/com/github/sidhant92/boolparser/constant/ContainerDataType.java index 1f3240f..98c4e09 100644 --- a/src/main/java/com/github/sidhant92/boolparser/constant/ContainerDataType.java +++ b/src/main/java/com/github/sidhant92/boolparser/constant/ContainerDataType.java @@ -1,6 +1,11 @@ package com.github.sidhant92.boolparser.constant; +import java.util.Collection; +import java.util.List; +import java.util.Objects; import java.util.Optional; +import java.util.stream.Collectors; +import java.util.stream.Stream; import com.github.sidhant92.boolparser.datatype.DataTypeFactory; import com.github.sidhant92.boolparser.exception.InvalidDataType; import lombok.AllArgsConstructor; @@ -15,7 +20,7 @@ @AllArgsConstructor @Slf4j public enum ContainerDataType { - primitive() { + PRIMITIVE() { @Override public Optional getValue(final DataType dataType, final Object value) { final Optional result = DataTypeFactory.getDataType(dataType).getValue(value); @@ -30,6 +35,39 @@ public Optional getValue(final DataType dataType, final Object value) { public boolean isValid(final DataType dataType, final Object value) { return DataTypeFactory.getDataType(dataType).isValid(value); } + }, + LIST() { + @Override + public Optional> getValue(final DataType dataType, final Object value) { + if (Objects.isNull(value) || !(value instanceof Collection || value instanceof Object[])) { + return Optional.empty(); + } + if (value instanceof Object[]) { + return Optional.of(Stream.of((Object[]) value) + .map(v -> DataTypeFactory.getDataType(dataType).getValue(v)) + .filter(Optional::isPresent) + .map(Optional::get) + .collect(Collectors.toList())); + } + return Optional.of(((Collection) value) + .stream() + .map(v -> DataTypeFactory.getDataType(dataType).getValue(v)) + .filter(Optional::isPresent) + .map(Optional::get) + .collect(Collectors.toList())); + } + + @Override + public boolean isValid(final DataType dataType, final Object value) { + if (Objects.isNull(value) || !(value instanceof Collection || value instanceof Object[])) { + return false; + } + if (value instanceof Object[]) { + return Stream.of((Object[]) value).allMatch(v -> DataTypeFactory.getDataType(dataType).isValid(v)); + } + return ((Collection) value) + .stream().allMatch(v -> DataTypeFactory.getDataType(dataType).isValid(v)); + } }; public abstract Optional getValue(final DataType dataType, final Object value); 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 4ab582a..7625f19 100644 --- a/src/main/java/com/github/sidhant92/boolparser/constant/NodeType.java +++ b/src/main/java/com/github/sidhant92/boolparser/constant/NodeType.java @@ -9,5 +9,6 @@ public enum NodeType { COMPARISON, NUMERIC_RANGE, IN, + ARRAY, 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 4fd76f7..170e7d7 100644 --- a/src/main/java/com/github/sidhant92/boolparser/constant/Operator.java +++ b/src/main/java/com/github/sidhant92/boolparser/constant/Operator.java @@ -20,10 +20,16 @@ public enum Operator { LESS_THAN, LESS_THAN_EQUAL, NOT_EQUAL, - IN; + IN, + CONTAINS_ALL, + CONTAINS_ANY; public static Optional getOperatorFromSymbol(final String symbol) { - return OperatorFactory.getAllOperators().stream().filter(operator -> operator.getSymbol().equals(symbol)).map(AbstractOperator::getOperator) - .findFirst(); + final String symbolLowerCase = symbol.toLowerCase(); + return OperatorFactory.getAllOperators() + .stream() + .filter(operator -> operator.getSymbol().toLowerCase().equals(symbolLowerCase)) + .map(AbstractOperator::getOperator) + .findFirst(); } } diff --git a/src/main/java/com/github/sidhant92/boolparser/domain/ArrayNode.java b/src/main/java/com/github/sidhant92/boolparser/domain/ArrayNode.java new file mode 100644 index 0000000..06fd7f7 --- /dev/null +++ b/src/main/java/com/github/sidhant92/boolparser/domain/ArrayNode.java @@ -0,0 +1,27 @@ +package com.github.sidhant92.boolparser.domain; + +import java.util.List; +import org.apache.commons.lang3.tuple.Pair; +import com.github.sidhant92.boolparser.constant.DataType; +import com.github.sidhant92.boolparser.constant.NodeType; +import com.github.sidhant92.boolparser.constant.Operator; +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Getter; +import lombok.Setter; + +@AllArgsConstructor +@Getter +@Setter +@Builder +public class ArrayNode extends Node { + private final String field; + + private final Operator operator; + + private final List> items; + @Override + public NodeType getTokenType() { + return NodeType.ARRAY; + } +} diff --git a/src/main/java/com/github/sidhant92/boolparser/exception/HeterogeneousArrayException.java b/src/main/java/com/github/sidhant92/boolparser/exception/HeterogeneousArrayException.java new file mode 100644 index 0000000..a13c354 --- /dev/null +++ b/src/main/java/com/github/sidhant92/boolparser/exception/HeterogeneousArrayException.java @@ -0,0 +1,8 @@ +package com.github.sidhant92.boolparser.exception; + +public class HeterogeneousArrayException extends RuntimeException{ + @Override + public String getMessage() { + return "Heterogeneous input of array not allowed"; + } +} diff --git a/src/main/java/com/github/sidhant92/boolparser/exception/InvalidContainerTypeException.java b/src/main/java/com/github/sidhant92/boolparser/exception/InvalidContainerTypeException.java new file mode 100644 index 0000000..4e1b292 --- /dev/null +++ b/src/main/java/com/github/sidhant92/boolparser/exception/InvalidContainerTypeException.java @@ -0,0 +1,16 @@ +package com.github.sidhant92.boolparser.exception; + +public class InvalidContainerTypeException extends RuntimeException { + public InvalidContainerTypeException(final String message) { + super(message); + } + + public InvalidContainerTypeException() { + super(); + } + + @Override + public String getMessage() { + return "Invalid Container Type"; + } +} diff --git a/src/main/java/com/github/sidhant92/boolparser/operator/AbstractOperator.java b/src/main/java/com/github/sidhant92/boolparser/operator/AbstractOperator.java index 197a4f9..2c95380 100644 --- a/src/main/java/com/github/sidhant92/boolparser/operator/AbstractOperator.java +++ b/src/main/java/com/github/sidhant92/boolparser/operator/AbstractOperator.java @@ -1,5 +1,6 @@ package com.github.sidhant92.boolparser.operator; +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; @@ -9,10 +10,14 @@ * @since 05/03/2023 */ public abstract class AbstractOperator { - public abstract > boolean evaluate(final ContainerDataType containerDataType, final DataType dataType, final Object leftOperand, - final Object... rightOperands); + public abstract > boolean evaluate(final ContainerDataType containerDataType, final DataType dataType, + final Object leftOperand, final Object... rightOperands); 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/ContainsAllOperator.java b/src/main/java/com/github/sidhant92/boolparser/operator/ContainsAllOperator.java new file mode 100644 index 0000000..a7add0d --- /dev/null +++ b/src/main/java/com/github/sidhant92/boolparser/operator/ContainsAllOperator.java @@ -0,0 +1,49 @@ +package com.github.sidhant92.boolparser.operator; + +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 lombok.AllArgsConstructor; +import lombok.extern.slf4j.Slf4j; + +@AllArgsConstructor +@Slf4j +public class ContainsAllOperator extends AbstractOperator { + private final InOperator inOperator; + + @Override + public > boolean evaluate(final ContainerDataType containerDataType, final DataType dataType, + final Object leftOperand, final Object... rightOperands) { + if (!containerDataType.isValid(dataType, leftOperand)) { + log.error("Validation failed for any operator for the operand {}", leftOperand); + return false; + } + final Object[] leftOperandArray = ((List) leftOperand).toArray(); + return Arrays + .stream(rightOperands) + .allMatch(rightOperand -> inOperator.evaluate(ContainerDataType.PRIMITIVE, dataType, rightOperand, leftOperandArray)); + } + + @Override + public Operator getOperator() { + return Operator.CONTAINS_ALL; + } + + @Override + public String getSymbol() { + return "CONTAINS_ALL"; + } + + @Override + public List getAllowedContainerTypes() { + return Collections.singletonList(ContainerDataType.LIST); + } + + @Override + public List getAllowedDataTypes() { + return Arrays.asList(DataType.values()); + } +} diff --git a/src/main/java/com/github/sidhant92/boolparser/operator/ContainsAnyOperator.java b/src/main/java/com/github/sidhant92/boolparser/operator/ContainsAnyOperator.java new file mode 100644 index 0000000..4cb81c9 --- /dev/null +++ b/src/main/java/com/github/sidhant92/boolparser/operator/ContainsAnyOperator.java @@ -0,0 +1,49 @@ +package com.github.sidhant92.boolparser.operator; + +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 lombok.AllArgsConstructor; +import lombok.extern.slf4j.Slf4j; + +@AllArgsConstructor +@Slf4j +public class ContainsAnyOperator extends AbstractOperator { + private final InOperator inOperator; + + @Override + public > boolean evaluate(final ContainerDataType containerDataType, final DataType dataType, + final Object leftOperand, final Object... rightOperands) { + if (!containerDataType.isValid(dataType, leftOperand)) { + log.error("Validation failed for any operator for the operand {}", leftOperand); + return false; + } + final Object[] leftOperandArray = ((List) leftOperand).toArray(); + return Arrays + .stream(rightOperands) + .anyMatch(rightOperand -> inOperator.evaluate(ContainerDataType.PRIMITIVE, dataType, rightOperand, leftOperandArray)); + } + + @Override + public Operator getOperator() { + return Operator.CONTAINS_ANY; + } + + @Override + public String getSymbol() { + return "CONTAINS_ANY"; + } + + @Override + public List getAllowedContainerTypes() { + return Collections.singletonList(ContainerDataType.LIST); + } + + @Override + public List getAllowedDataTypes() { + return Arrays.asList(DataType.values()); + } +} diff --git a/src/main/java/com/github/sidhant92/boolparser/operator/EqualsOperator.java b/src/main/java/com/github/sidhant92/boolparser/operator/EqualsOperator.java index 6e839cb..5bc1044 100644 --- a/src/main/java/com/github/sidhant92/boolparser/operator/EqualsOperator.java +++ b/src/main/java/com/github/sidhant92/boolparser/operator/EqualsOperator.java @@ -1,5 +1,8 @@ package com.github.sidhant92.boolparser.operator; +import java.util.Arrays; +import java.util.Collections; +import java.util.List; import java.util.Optional; import com.github.sidhant92.boolparser.constant.ContainerDataType; import com.github.sidhant92.boolparser.constant.DataType; @@ -27,4 +30,14 @@ public Operator getOperator() { public String getSymbol() { return "="; } + + @Override + public List getAllowedContainerTypes() { + return Collections.singletonList(ContainerDataType.PRIMITIVE); + } + + @Override + public List getAllowedDataTypes() { + return Arrays.asList(DataType.values()); + } } diff --git a/src/main/java/com/github/sidhant92/boolparser/operator/GreaterThanEqualOperator.java b/src/main/java/com/github/sidhant92/boolparser/operator/GreaterThanEqualOperator.java index 80b66ae..d26ae8d 100644 --- a/src/main/java/com/github/sidhant92/boolparser/operator/GreaterThanEqualOperator.java +++ b/src/main/java/com/github/sidhant92/boolparser/operator/GreaterThanEqualOperator.java @@ -1,5 +1,8 @@ package com.github.sidhant92.boolparser.operator; +import java.util.Arrays; +import java.util.Collections; +import java.util.List; import java.util.Optional; import com.github.sidhant92.boolparser.constant.ContainerDataType; import com.github.sidhant92.boolparser.constant.DataType; @@ -27,4 +30,14 @@ public Operator getOperator() { 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.VERSION); + } } diff --git a/src/main/java/com/github/sidhant92/boolparser/operator/GreaterThanOperator.java b/src/main/java/com/github/sidhant92/boolparser/operator/GreaterThanOperator.java index 9843f1f..720df54 100644 --- a/src/main/java/com/github/sidhant92/boolparser/operator/GreaterThanOperator.java +++ b/src/main/java/com/github/sidhant92/boolparser/operator/GreaterThanOperator.java @@ -1,5 +1,8 @@ package com.github.sidhant92.boolparser.operator; +import java.util.Arrays; +import java.util.Collections; +import java.util.List; import java.util.Optional; import com.github.sidhant92.boolparser.constant.ContainerDataType; import com.github.sidhant92.boolparser.constant.DataType; @@ -27,4 +30,14 @@ public Operator getOperator() { 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.VERSION); + } } diff --git a/src/main/java/com/github/sidhant92/boolparser/operator/InOperator.java b/src/main/java/com/github/sidhant92/boolparser/operator/InOperator.java index 5c4b9b1..ef801ea 100644 --- a/src/main/java/com/github/sidhant92/boolparser/operator/InOperator.java +++ b/src/main/java/com/github/sidhant92/boolparser/operator/InOperator.java @@ -1,6 +1,8 @@ package com.github.sidhant92.boolparser.operator; 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; @@ -18,7 +20,7 @@ public class InOperator extends AbstractOperator { public > boolean evaluate(final ContainerDataType containerDataType, final DataType dataType, final Object leftOperand, final Object... rightOperands) { return Arrays - .stream(rightOperands).anyMatch(a -> equalsOperator.evaluate(ContainerDataType.primitive, dataType, leftOperand, a)); + .stream(rightOperands).anyMatch(a -> equalsOperator.evaluate(containerDataType, dataType, leftOperand, a)); } @Override @@ -30,4 +32,14 @@ public Operator getOperator() { public String getSymbol() { return "IN"; } + + @Override + public List getAllowedContainerTypes() { + return Collections.singletonList(ContainerDataType.PRIMITIVE); + } + + @Override + public List getAllowedDataTypes() { + return Arrays.asList(DataType.values()); + } } diff --git a/src/main/java/com/github/sidhant92/boolparser/operator/LessThanEqualOperator.java b/src/main/java/com/github/sidhant92/boolparser/operator/LessThanEqualOperator.java index 5ebf4b4..93307af 100644 --- a/src/main/java/com/github/sidhant92/boolparser/operator/LessThanEqualOperator.java +++ b/src/main/java/com/github/sidhant92/boolparser/operator/LessThanEqualOperator.java @@ -1,5 +1,8 @@ package com.github.sidhant92.boolparser.operator; +import java.util.Arrays; +import java.util.Collections; +import java.util.List; import java.util.Optional; import com.github.sidhant92.boolparser.constant.ContainerDataType; import com.github.sidhant92.boolparser.constant.DataType; @@ -27,4 +30,14 @@ public Operator getOperator() { 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.VERSION); + } } diff --git a/src/main/java/com/github/sidhant92/boolparser/operator/LessThanOperator.java b/src/main/java/com/github/sidhant92/boolparser/operator/LessThanOperator.java index fcb4dda..1c43281 100644 --- a/src/main/java/com/github/sidhant92/boolparser/operator/LessThanOperator.java +++ b/src/main/java/com/github/sidhant92/boolparser/operator/LessThanOperator.java @@ -1,5 +1,8 @@ package com.github.sidhant92.boolparser.operator; +import java.util.Arrays; +import java.util.Collections; +import java.util.List; import java.util.Optional; import com.github.sidhant92.boolparser.constant.ContainerDataType; import com.github.sidhant92.boolparser.constant.DataType; @@ -27,4 +30,14 @@ public Operator getOperator() { 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.VERSION); + } } diff --git a/src/main/java/com/github/sidhant92/boolparser/operator/NotEqualsOperator.java b/src/main/java/com/github/sidhant92/boolparser/operator/NotEqualsOperator.java index 5994a8b..42904e2 100644 --- a/src/main/java/com/github/sidhant92/boolparser/operator/NotEqualsOperator.java +++ b/src/main/java/com/github/sidhant92/boolparser/operator/NotEqualsOperator.java @@ -1,5 +1,8 @@ package com.github.sidhant92.boolparser.operator; +import java.util.Arrays; +import java.util.Collections; +import java.util.List; import java.util.Optional; import com.github.sidhant92.boolparser.constant.ContainerDataType; import com.github.sidhant92.boolparser.constant.DataType; @@ -27,4 +30,14 @@ public Operator getOperator() { public String getSymbol() { return "!="; } + + @Override + public List getAllowedContainerTypes() { + return Collections.singletonList(ContainerDataType.PRIMITIVE); + } + + @Override + public List getAllowedDataTypes() { + return Arrays.asList(DataType.values()); + } } 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 d75536e..cdf7833 100644 --- a/src/main/java/com/github/sidhant92/boolparser/operator/OperatorFactory.java +++ b/src/main/java/com/github/sidhant92/boolparser/operator/OperatorFactory.java @@ -19,6 +19,7 @@ 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()); @@ -26,6 +27,8 @@ public static void initialize() { 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)); } public static AbstractOperator getOperator(final Operator operator) { 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 ef4bb07..bd31dd5 100644 --- a/src/main/java/com/github/sidhant92/boolparser/operator/OperatorService.java +++ b/src/main/java/com/github/sidhant92/boolparser/operator/OperatorService.java @@ -4,11 +4,15 @@ 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 lombok.extern.slf4j.Slf4j; /** * @author sidhant.aggarwal * @since 05/03/2023 */ +@Slf4j public class OperatorService { public OperatorService() { DataTypeFactory.initialize(); @@ -16,7 +20,20 @@ public OperatorService() { } public boolean evaluate(final Operator operator, final ContainerDataType containerDataType, final DataType dataType, final Object leftOperand, - final Object... rightOperands) { + final Object... rightOperands) { + final AbstractOperator abstractOperator = OperatorFactory.getOperator(operator); + if (!abstractOperator.getAllowedContainerTypes().contains(containerDataType)) { + log.error("Invalid left container type {} for operator {}", containerDataType, operator); + throw new InvalidContainerTypeException(); + } + if (!abstractOperator.getAllowedDataTypes().contains(dataType)) { + log.error("Invalid left operand data type {} for operator {}", dataType, operator); + throw new InvalidDataType(); + } + if (!containerDataType.isValid(dataType, leftOperand)) { + log.error("Validation failed for the operator {} for the operand {}", operator, leftOperand); + throw new InvalidDataType(); + } return OperatorFactory.getOperator(operator).evaluate(containerDataType, dataType, leftOperand, rightOperands); } } 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 01a8e27..4fafed6 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 @@ -1,4 +1,4 @@ -package com.github.sidhant92.boolparser.parser.antlr;// Generated from java-escape by ANTLR 4.11.1 +package com.github.sidhant92.boolparser.parser.antlr;// Generated from /Users/sid/Desktop/filter1/BooleanExpression.g4 by ANTLR 4.13.1 import org.antlr.v4.runtime.ParserRuleContext; import org.antlr.v4.runtime.tree.ErrorNode; @@ -59,6 +59,18 @@ public class BooleanExpressionBaseListener implements BooleanExpressionListener *

The default implementation does nothing.

*/ @Override public void exitInExpression(BooleanExpressionParser.InExpressionContext ctx) { } + /** + * {@inheritDoc} + * + *

The default implementation does nothing.

+ */ + @Override public void enterArrayExpression(BooleanExpressionParser.ArrayExpressionContext ctx) { } + /** + * {@inheritDoc} + * + *

The default implementation does nothing.

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

The default implementation does nothing.

*/ @Override public void exitWordlist(BooleanExpressionParser.WordlistContext ctx) { } + /** + * {@inheritDoc} + * + *

The default implementation does nothing.

+ */ + @Override public void enterArrayOperators(BooleanExpressionParser.ArrayOperatorsContext ctx) { } + /** + * {@inheritDoc} + * + *

The default implementation does nothing.

+ */ + @Override public void exitArrayOperators(BooleanExpressionParser.ArrayOperatorsContext 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 180c6ed..559e5c4 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 @@ -1,4 +1,4 @@ -package com.github.sidhant92.boolparser.parser.antlr;// Generated from java-escape by ANTLR 4.11.1 +package com.github.sidhant92.boolparser.parser.antlr;// Generated from /Users/sid/Desktop/filter1/BooleanExpression.g4 by ANTLR 4.13.1 import org.antlr.v4.runtime.Lexer; import org.antlr.v4.runtime.CharStream; import org.antlr.v4.runtime.Token; @@ -8,17 +8,18 @@ import org.antlr.v4.runtime.dfa.DFA; import org.antlr.v4.runtime.misc.*; -@SuppressWarnings({"all", "warnings", "unchecked", "unused", "cast", "CheckReturnValue"}) +@SuppressWarnings({"all", "warnings", "unchecked", "unused", "cast", "CheckReturnValue", "this-escape"}) public class BooleanExpressionLexer extends Lexer { - static { RuntimeMetaData.checkVersion("4.11.1", RuntimeMetaData.VERSION); } + static { RuntimeMetaData.checkVersion("4.13.1", RuntimeMetaData.VERSION); } protected static final DFA[] _decisionToDFA; protected static final PredictionContextCache _sharedContextCache = new PredictionContextCache(); public static final int - T__0=1, IN=2, TO=3, AND=4, OR=5, NOT=6, TRUE=7, FALSE=8, NE=9, GT=10, - GE=11, LT=12, LE=13, EQ=14, LPAREN=15, RPAREN=16, DECIMAL=17, APP_VERSION=18, - INTEGER=19, WS=20, WORD=21, ALPHANUMERIC=22, SQ=23, DQ=24; + 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; public static String[] channelNames = { "DEFAULT_TOKEN_CHANNEL", "HIDDEN" }; @@ -29,25 +30,27 @@ public class BooleanExpressionLexer extends Lexer { private static String[] makeRuleNames() { return new String[] { - "T__0", "IN", "TO", "AND", "OR", "NOT", "TRUE", "FALSE", "NE", "GT", - "GE", "LT", "LE", "EQ", "LPAREN", "RPAREN", "DECIMAL", "APP_VERSION", - "INTEGER", "WS", "WORD", "ALPHANUMERIC", "SQ", "DQ" + "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" }; } 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, "'!='", + "'>'", "'>='", "'<'", "'<='", "'='", "'('", "')'" }; } private static final String[] _LITERAL_NAMES = makeLiteralNames(); private static String[] makeSymbolicNames() { return new String[] { - null, null, "IN", "TO", "AND", "OR", "NOT", "TRUE", "FALSE", "NE", "GT", - "GE", "LT", "LE", "EQ", "LPAREN", "RPAREN", "DECIMAL", "APP_VERSION", - "INTEGER", "WS", "WORD", "ALPHANUMERIC", "SQ", "DQ" + 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" }; } private static final String[] _SYMBOLIC_NAMES = makeSymbolicNames(); @@ -109,7 +112,7 @@ public BooleanExpressionLexer(CharStream input) { public ATN getATN() { return _ATN; } public static final String _serializedATN = - "\u0004\u0000\u0018\u00bc\u0006\uffff\uffff\u0002\u0000\u0007\u0000\u0002"+ + "\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"+ @@ -117,120 +120,153 @@ public BooleanExpressionLexer(CharStream input) { "\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"+ - "\u0001\u0000\u0001\u0000\u0001\u0001\u0001\u0001\u0001\u0001\u0001\u0001"+ - "\u0003\u00018\b\u0001\u0001\u0002\u0001\u0002\u0001\u0002\u0001\u0002"+ - "\u0003\u0002>\b\u0002\u0001\u0003\u0001\u0003\u0001\u0003\u0001\u0003"+ - "\u0001\u0003\u0001\u0003\u0001\u0003\u0001\u0003\u0003\u0003H\b\u0003"+ - "\u0001\u0004\u0001\u0004\u0001\u0004\u0001\u0004\u0001\u0004\u0001\u0004"+ - "\u0003\u0004P\b\u0004\u0001\u0005\u0001\u0005\u0001\u0005\u0001\u0005"+ - "\u0001\u0005\u0001\u0005\u0003\u0005X\b\u0005\u0001\u0006\u0001\u0006"+ - "\u0001\u0006\u0001\u0006\u0001\u0006\u0001\u0006\u0001\u0006\u0001\u0006"+ - "\u0003\u0006b\b\u0006\u0001\u0007\u0001\u0007\u0001\u0007\u0001\u0007"+ + "\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"+ - "\u0003\u0007n\b\u0007\u0001\b\u0001\b\u0001\b\u0001\t\u0001\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\u000f\u0001\u000f\u0001\u0010"+ - "\u0004\u0010\u0084\b\u0010\u000b\u0010\f\u0010\u0085\u0001\u0010\u0001"+ - "\u0010\u0004\u0010\u008a\b\u0010\u000b\u0010\f\u0010\u008b\u0001\u0011"+ - "\u0001\u0011\u0001\u0011\u0004\u0011\u0091\b\u0011\u000b\u0011\f\u0011"+ - "\u0092\u0001\u0012\u0004\u0012\u0096\b\u0012\u000b\u0012\f\u0012\u0097"+ - "\u0001\u0013\u0004\u0013\u009b\b\u0013\u000b\u0013\f\u0013\u009c\u0001"+ - "\u0013\u0001\u0013\u0001\u0014\u0001\u0014\u0001\u0014\u0001\u0014\u0004"+ - "\u0014\u00a5\b\u0014\u000b\u0014\f\u0014\u00a6\u0001\u0015\u0001\u0015"+ - "\u0001\u0016\u0001\u0016\u0005\u0016\u00ad\b\u0016\n\u0016\f\u0016\u00b0"+ - "\t\u0016\u0001\u0016\u0001\u0016\u0001\u0017\u0001\u0017\u0005\u0017\u00b6"+ - "\b\u0017\n\u0017\f\u0017\u00b9\t\u0017\u0001\u0017\u0001\u0017\u0002\u00ae"+ - "\u00b7\u0000\u0018\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/\u0018\u0001\u0000\u0004\u0001\u000009\u0003\u0000\t\n"+ - "\f\r \u0002\u0000-.__\u0003\u000009AZaz\u00cf\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\u0001"+ - "1\u0001\u0000\u0000\u0000\u00037\u0001\u0000\u0000\u0000\u0005=\u0001"+ - "\u0000\u0000\u0000\u0007G\u0001\u0000\u0000\u0000\tO\u0001\u0000\u0000"+ - "\u0000\u000bW\u0001\u0000\u0000\u0000\ra\u0001\u0000\u0000\u0000\u000f"+ - "m\u0001\u0000\u0000\u0000\u0011o\u0001\u0000\u0000\u0000\u0013r\u0001"+ - "\u0000\u0000\u0000\u0015t\u0001\u0000\u0000\u0000\u0017w\u0001\u0000\u0000"+ - "\u0000\u0019y\u0001\u0000\u0000\u0000\u001b|\u0001\u0000\u0000\u0000\u001d"+ - "~\u0001\u0000\u0000\u0000\u001f\u0080\u0001\u0000\u0000\u0000!\u0083\u0001"+ - "\u0000\u0000\u0000#\u008d\u0001\u0000\u0000\u0000%\u0095\u0001\u0000\u0000"+ - "\u0000\'\u009a\u0001\u0000\u0000\u0000)\u00a4\u0001\u0000\u0000\u0000"+ - "+\u00a8\u0001\u0000\u0000\u0000-\u00aa\u0001\u0000\u0000\u0000/\u00b3"+ - "\u0001\u0000\u0000\u000012\u0005,\u0000\u00002\u0002\u0001\u0000\u0000"+ - "\u000034\u0005I\u0000\u000048\u0005N\u0000\u000056\u0005i\u0000\u0000"+ - "68\u0005n\u0000\u000073\u0001\u0000\u0000\u000075\u0001\u0000\u0000\u0000"+ - "8\u0004\u0001\u0000\u0000\u00009:\u0005T\u0000\u0000:>\u0005O\u0000\u0000"+ - ";<\u0005t\u0000\u0000<>\u0005o\u0000\u0000=9\u0001\u0000\u0000\u0000="+ - ";\u0001\u0000\u0000\u0000>\u0006\u0001\u0000\u0000\u0000?@\u0005A\u0000"+ - "\u0000@A\u0005N\u0000\u0000AH\u0005D\u0000\u0000BC\u0005a\u0000\u0000"+ - "CD\u0005n\u0000\u0000DH\u0005d\u0000\u0000EF\u0005&\u0000\u0000FH\u0005"+ - "&\u0000\u0000G?\u0001\u0000\u0000\u0000GB\u0001\u0000\u0000\u0000GE\u0001"+ - "\u0000\u0000\u0000H\b\u0001\u0000\u0000\u0000IJ\u0005O\u0000\u0000JP\u0005"+ - "R\u0000\u0000KL\u0005o\u0000\u0000LP\u0005r\u0000\u0000MN\u0005|\u0000"+ - "\u0000NP\u0005|\u0000\u0000OI\u0001\u0000\u0000\u0000OK\u0001\u0000\u0000"+ - "\u0000OM\u0001\u0000\u0000\u0000P\n\u0001\u0000\u0000\u0000QR\u0005N\u0000"+ - "\u0000RS\u0005O\u0000\u0000SX\u0005T\u0000\u0000TU\u0005n\u0000\u0000"+ - "UV\u0005o\u0000\u0000VX\u0005t\u0000\u0000WQ\u0001\u0000\u0000\u0000W"+ - "T\u0001\u0000\u0000\u0000X\f\u0001\u0000\u0000\u0000YZ\u0005T\u0000\u0000"+ - "Z[\u0005R\u0000\u0000[\\\u0005U\u0000\u0000\\b\u0005E\u0000\u0000]^\u0005"+ - "t\u0000\u0000^_\u0005r\u0000\u0000_`\u0005u\u0000\u0000`b\u0005e\u0000"+ - "\u0000aY\u0001\u0000\u0000\u0000a]\u0001\u0000\u0000\u0000b\u000e\u0001"+ - "\u0000\u0000\u0000cd\u0005F\u0000\u0000de\u0005A\u0000\u0000ef\u0005L"+ - "\u0000\u0000fg\u0005S\u0000\u0000gn\u0005E\u0000\u0000hi\u0005f\u0000"+ - "\u0000ij\u0005a\u0000\u0000jk\u0005l\u0000\u0000kl\u0005s\u0000\u0000"+ - "ln\u0005e\u0000\u0000mc\u0001\u0000\u0000\u0000mh\u0001\u0000\u0000\u0000"+ - "n\u0010\u0001\u0000\u0000\u0000op\u0005!\u0000\u0000pq\u0005=\u0000\u0000"+ - "q\u0012\u0001\u0000\u0000\u0000rs\u0005>\u0000\u0000s\u0014\u0001\u0000"+ - "\u0000\u0000tu\u0005>\u0000\u0000uv\u0005=\u0000\u0000v\u0016\u0001\u0000"+ - "\u0000\u0000wx\u0005<\u0000\u0000x\u0018\u0001\u0000\u0000\u0000yz\u0005"+ - "<\u0000\u0000z{\u0005=\u0000\u0000{\u001a\u0001\u0000\u0000\u0000|}\u0005"+ - "=\u0000\u0000}\u001c\u0001\u0000\u0000\u0000~\u007f\u0005(\u0000\u0000"+ - "\u007f\u001e\u0001\u0000\u0000\u0000\u0080\u0081\u0005)\u0000\u0000\u0081"+ - " \u0001\u0000\u0000\u0000\u0082\u0084\u0007\u0000\u0000\u0000\u0083\u0082"+ - "\u0001\u0000\u0000\u0000\u0084\u0085\u0001\u0000\u0000\u0000\u0085\u0083"+ - "\u0001\u0000\u0000\u0000\u0085\u0086\u0001\u0000\u0000\u0000\u0086\u0087"+ - "\u0001\u0000\u0000\u0000\u0087\u0089\u0005.\u0000\u0000\u0088\u008a\u0007"+ - "\u0000\u0000\u0000\u0089\u0088\u0001\u0000\u0000\u0000\u008a\u008b\u0001"+ - "\u0000\u0000\u0000\u008b\u0089\u0001\u0000\u0000\u0000\u008b\u008c\u0001"+ - "\u0000\u0000\u0000\u008c\"\u0001\u0000\u0000\u0000\u008d\u0090\u0007\u0000"+ - "\u0000\u0000\u008e\u008f\u0005.\u0000\u0000\u008f\u0091\u0003%\u0012\u0000"+ - "\u0090\u008e\u0001\u0000\u0000\u0000\u0091\u0092\u0001\u0000\u0000\u0000"+ - "\u0092\u0090\u0001\u0000\u0000\u0000\u0092\u0093\u0001\u0000\u0000\u0000"+ - "\u0093$\u0001\u0000\u0000\u0000\u0094\u0096\u0007\u0000\u0000\u0000\u0095"+ - "\u0094\u0001\u0000\u0000\u0000\u0096\u0097\u0001\u0000\u0000\u0000\u0097"+ - "\u0095\u0001\u0000\u0000\u0000\u0097\u0098\u0001\u0000\u0000\u0000\u0098"+ - "&\u0001\u0000\u0000\u0000\u0099\u009b\u0007\u0001\u0000\u0000\u009a\u0099"+ - "\u0001\u0000\u0000\u0000\u009b\u009c\u0001\u0000\u0000\u0000\u009c\u009a"+ - "\u0001\u0000\u0000\u0000\u009c\u009d\u0001\u0000\u0000\u0000\u009d\u009e"+ - "\u0001\u0000\u0000\u0000\u009e\u009f\u0006\u0013\u0000\u0000\u009f(\u0001"+ - "\u0000\u0000\u0000\u00a0\u00a5\u0003+\u0015\u0000\u00a1\u00a5\u0007\u0002"+ - "\u0000\u0000\u00a2\u00a5\u0003-\u0016\u0000\u00a3\u00a5\u0003/\u0017\u0000"+ - "\u00a4\u00a0\u0001\u0000\u0000\u0000\u00a4\u00a1\u0001\u0000\u0000\u0000"+ - "\u00a4\u00a2\u0001\u0000\u0000\u0000\u00a4\u00a3\u0001\u0000\u0000\u0000"+ - "\u00a5\u00a6\u0001\u0000\u0000\u0000\u00a6\u00a4\u0001\u0000\u0000\u0000"+ - "\u00a6\u00a7\u0001\u0000\u0000\u0000\u00a7*\u0001\u0000\u0000\u0000\u00a8"+ - "\u00a9\u0007\u0003\u0000\u0000\u00a9,\u0001\u0000\u0000\u0000\u00aa\u00ae"+ - "\u0005\'\u0000\u0000\u00ab\u00ad\t\u0000\u0000\u0000\u00ac\u00ab\u0001"+ - "\u0000\u0000\u0000\u00ad\u00b0\u0001\u0000\u0000\u0000\u00ae\u00af\u0001"+ - "\u0000\u0000\u0000\u00ae\u00ac\u0001\u0000\u0000\u0000\u00af\u00b1\u0001"+ - "\u0000\u0000\u0000\u00b0\u00ae\u0001\u0000\u0000\u0000\u00b1\u00b2\u0005"+ - "\'\u0000\u0000\u00b2.\u0001\u0000\u0000\u0000\u00b3\u00b7\u0005\"\u0000"+ - "\u0000\u00b4\u00b6\t\u0000\u0000\u0000\u00b5\u00b4\u0001\u0000\u0000\u0000"+ - "\u00b6\u00b9\u0001\u0000\u0000\u0000\u00b7\u00b8\u0001\u0000\u0000\u0000"+ - "\u00b7\u00b5\u0001\u0000\u0000\u0000\u00b8\u00ba\u0001\u0000\u0000\u0000"+ - "\u00b9\u00b7\u0001\u0000\u0000\u0000\u00ba\u00bb\u0005\"\u0000\u0000\u00bb"+ - "0\u0001\u0000\u0000\u0000\u0011\u00007=GOWam\u0085\u008b\u0092\u0097\u009c"+ - "\u00a4\u00a6\u00ae\u00b7\u0001\u0006\u0000\u0000"; + "\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"+ + "\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"+ + "\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"; 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 fc3de7c..c66abe2 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 @@ -1,4 +1,4 @@ -package com.github.sidhant92.boolparser.parser.antlr;// Generated from java-escape by ANTLR 4.11.1 +package com.github.sidhant92.boolparser.parser.antlr;// Generated from /Users/sid/Desktop/filter1/BooleanExpression.g4 by ANTLR 4.13.1 import org.antlr.v4.runtime.tree.ParseTreeListener; /** @@ -52,6 +52,18 @@ public interface BooleanExpressionListener extends ParseTreeListener { * @param ctx the parse tree */ void exitInExpression(BooleanExpressionParser.InExpressionContext ctx); + /** + * Enter a parse tree produced by the {@code arrayExpression} + * labeled alternative in {@link BooleanExpressionParser#expression}. + * @param ctx the parse tree + */ + void enterArrayExpression(BooleanExpressionParser.ArrayExpressionContext ctx); + /** + * Exit a parse tree produced by the {@code arrayExpression} + * labeled alternative in {@link BooleanExpressionParser#expression}. + * @param ctx the parse tree + */ + void exitArrayExpression(BooleanExpressionParser.ArrayExpressionContext ctx); /** * Enter a parse tree produced by the {@code toExpression} * labeled alternative in {@link BooleanExpressionParser#expression}. @@ -120,6 +132,16 @@ public interface BooleanExpressionListener extends ParseTreeListener { * @param ctx the parse tree */ void exitWordlist(BooleanExpressionParser.WordlistContext ctx); + /** + * Enter a parse tree produced by {@link BooleanExpressionParser#arrayOperators}. + * @param ctx the parse tree + */ + void enterArrayOperators(BooleanExpressionParser.ArrayOperatorsContext ctx); + /** + * Exit a parse tree produced by {@link BooleanExpressionParser#arrayOperators}. + * @param ctx the parse tree + */ + void exitArrayOperators(BooleanExpressionParser.ArrayOperatorsContext ctx); /** * Enter a parse tree produced by {@link BooleanExpressionParser#numericTypes}. * @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 b7e0129..21438de 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 @@ -1,4 +1,4 @@ -package com.github.sidhant92.boolparser.parser.antlr;// Generated from java-escape by ANTLR 4.11.1 +package com.github.sidhant92.boolparser.parser.antlr;// Generated from /Users/sid/Desktop/filter1/BooleanExpression.g4 by ANTLR 4.13.1 import org.antlr.v4.runtime.atn.*; import org.antlr.v4.runtime.dfa.DFA; import org.antlr.v4.runtime.*; @@ -10,38 +10,41 @@ @SuppressWarnings({"all", "warnings", "unchecked", "unused", "cast", "CheckReturnValue"}) public class BooleanExpressionParser extends Parser { - static { RuntimeMetaData.checkVersion("4.11.1", RuntimeMetaData.VERSION); } + static { RuntimeMetaData.checkVersion("4.13.1", RuntimeMetaData.VERSION); } protected static final DFA[] _decisionToDFA; protected static final PredictionContextCache _sharedContextCache = new PredictionContextCache(); public static final int - T__0=1, IN=2, TO=3, AND=4, OR=5, NOT=6, TRUE=7, FALSE=8, NE=9, GT=10, - GE=11, LT=12, LE=13, EQ=14, LPAREN=15, RPAREN=16, DECIMAL=17, APP_VERSION=18, - INTEGER=19, WS=20, WORD=21, ALPHANUMERIC=22, SQ=23, DQ=24; + 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; public static final int RULE_parse = 0, RULE_expression = 1, RULE_comparator = 2, RULE_wordlist = 3, - RULE_numericTypes = 4, RULE_types = 5, RULE_binary = 6, RULE_bool = 7; + RULE_arrayOperators = 4, RULE_numericTypes = 5, RULE_types = 6, RULE_binary = 7, + RULE_bool = 8; private static String[] makeRuleNames() { return new String[] { - "parse", "expression", "comparator", "wordlist", "numericTypes", "types", - "binary", "bool" + "parse", "expression", "comparator", "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, "'!='", + "'>'", "'>='", "'<'", "'<='", "'='", "'('", "')'" }; } private static final String[] _LITERAL_NAMES = makeLiteralNames(); private static String[] makeSymbolicNames() { return new String[] { - null, null, "IN", "TO", "AND", "OR", "NOT", "TRUE", "FALSE", "NE", "GT", - "GE", "LT", "LE", "EQ", "LPAREN", "RPAREN", "DECIMAL", "APP_VERSION", - "INTEGER", "WS", "WORD", "ALPHANUMERIC", "SQ", "DQ" + 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" }; } private static final String[] _SYMBOLIC_NAMES = makeSymbolicNames(); @@ -79,7 +82,7 @@ public Vocabulary getVocabulary() { } @Override - public String getGrammarFileName() { return "java-escape"; } + public String getGrammarFileName() { return "BooleanExpression.g4"; } @Override public String[] getRuleNames() { return ruleNames; } @@ -121,9 +124,9 @@ public final ParseContext parse() throws RecognitionException { try { enterOuterAlt(_localctx, 1); { - setState(16); + setState(18); expression(0); - setState(17); + setState(19); match(EOF); } } @@ -192,12 +195,14 @@ public void exitRule(ParseTreeListener listener) { @SuppressWarnings("CheckReturnValue") public static class InExpressionContext extends ExpressionContext { public Token field; + public Token not; public WordlistContext data; public TerminalNode IN() { return getToken(BooleanExpressionParser.IN, 0); } - public TerminalNode WORD() { return getToken(BooleanExpressionParser.WORD, 0); } public WordlistContext wordlist() { return getRuleContext(WordlistContext.class,0); } + public TerminalNode WORD() { return getToken(BooleanExpressionParser.WORD, 0); } + public TerminalNode NOT() { return getToken(BooleanExpressionParser.NOT, 0); } public InExpressionContext(ExpressionContext ctx) { copyFrom(ctx); } @Override public void enterRule(ParseTreeListener listener) { @@ -209,18 +214,40 @@ public void exitRule(ParseTreeListener listener) { } } @SuppressWarnings("CheckReturnValue") + public static class ArrayExpressionContext extends ExpressionContext { + public Token field; + public ArrayOperatorsContext op; + public WordlistContext data; + public ArrayOperatorsContext arrayOperators() { + return getRuleContext(ArrayOperatorsContext.class,0); + } + public WordlistContext wordlist() { + return getRuleContext(WordlistContext.class,0); + } + public TerminalNode WORD() { return getToken(BooleanExpressionParser.WORD, 0); } + public ArrayExpressionContext(ExpressionContext ctx) { copyFrom(ctx); } + @Override + public void enterRule(ParseTreeListener listener) { + if ( listener instanceof BooleanExpressionListener ) ((BooleanExpressionListener)listener).enterArrayExpression(this); + } + @Override + public void exitRule(ParseTreeListener listener) { + if ( listener instanceof BooleanExpressionListener ) ((BooleanExpressionListener)listener).exitArrayExpression(this); + } + } + @SuppressWarnings("CheckReturnValue") public static class ToExpressionContext extends ExpressionContext { public Token field; public NumericTypesContext lower; public NumericTypesContext upper; public TerminalNode TO() { return getToken(BooleanExpressionParser.TO, 0); } - public TerminalNode WORD() { return getToken(BooleanExpressionParser.WORD, 0); } public List numericTypes() { return getRuleContexts(NumericTypesContext.class); } public NumericTypesContext numericTypes(int i) { return getRuleContext(NumericTypesContext.class,i); } + public TerminalNode WORD() { return getToken(BooleanExpressionParser.WORD, 0); } public ToExpressionContext(ExpressionContext ctx) { copyFrom(ctx); } @Override public void enterRule(ParseTreeListener listener) { @@ -300,24 +327,25 @@ private ExpressionContext expression(int _p) throws RecognitionException { ExpressionContext _prevctx = _localctx; int _startState = 2; enterRecursionRule(_localctx, 2, RULE_expression, _p); + int _la; try { int _alt; enterOuterAlt(_localctx, 1); { - setState(35); + setState(50); _errHandler.sync(this); - switch ( getInterpreter().adaptivePredict(_input,0,_ctx) ) { + switch ( getInterpreter().adaptivePredict(_input,4,_ctx) ) { case 1: { _localctx = new ParentExpressionContext(_localctx); _ctx = _localctx; _prevctx = _localctx; - setState(20); + setState(22); match(LPAREN); - setState(21); + setState(23); expression(0); - setState(22); + setState(24); match(RPAREN); } break; @@ -326,10 +354,10 @@ private ExpressionContext expression(int _p) throws RecognitionException { _localctx = new NotExpressionContext(_localctx); _ctx = _localctx; _prevctx = _localctx; - setState(24); + setState(26); match(NOT); - setState(25); - expression(6); + setState(27); + expression(7); } break; case 3: @@ -337,7 +365,7 @@ private ExpressionContext expression(int _p) throws RecognitionException { _localctx = new TypesExpressionContext(_localctx); _ctx = _localctx; _prevctx = _localctx; - setState(26); + setState(28); types(); } break; @@ -346,13 +374,21 @@ private ExpressionContext expression(int _p) throws RecognitionException { _localctx = new ToExpressionContext(_localctx); _ctx = _localctx; _prevctx = _localctx; - setState(27); - ((ToExpressionContext)_localctx).field = match(WORD); - setState(28); + setState(30); + _errHandler.sync(this); + _la = _input.LA(1); + if (_la==WORD) { + { + setState(29); + ((ToExpressionContext)_localctx).field = match(WORD); + } + } + + setState(32); ((ToExpressionContext)_localctx).lower = numericTypes(); - setState(29); + setState(33); match(TO); - setState(30); + setState(34); ((ToExpressionContext)_localctx).upper = numericTypes(); } break; @@ -361,38 +397,77 @@ private ExpressionContext expression(int _p) throws RecognitionException { _localctx = new InExpressionContext(_localctx); _ctx = _localctx; _prevctx = _localctx; - setState(32); - ((InExpressionContext)_localctx).field = match(WORD); - setState(33); + setState(37); + _errHandler.sync(this); + _la = _input.LA(1); + if (_la==WORD) { + { + setState(36); + ((InExpressionContext)_localctx).field = match(WORD); + } + } + + setState(40); + _errHandler.sync(this); + _la = _input.LA(1); + if (_la==NOT) { + { + setState(39); + ((InExpressionContext)_localctx).not = match(NOT); + } + } + + setState(42); match(IN); - setState(34); + setState(43); ((InExpressionContext)_localctx).data = wordlist(); } break; + case 6: + { + _localctx = new ArrayExpressionContext(_localctx); + _ctx = _localctx; + _prevctx = _localctx; + setState(45); + _errHandler.sync(this); + _la = _input.LA(1); + if (_la==WORD) { + { + setState(44); + ((ArrayExpressionContext)_localctx).field = match(WORD); + } + } + + setState(47); + ((ArrayExpressionContext)_localctx).op = arrayOperators(); + setState(48); + ((ArrayExpressionContext)_localctx).data = wordlist(); + } + break; } _ctx.stop = _input.LT(-1); - setState(47); + setState(62); _errHandler.sync(this); - _alt = getInterpreter().adaptivePredict(_input,2,_ctx); + _alt = getInterpreter().adaptivePredict(_input,6,_ctx); while ( _alt!=2 && _alt!= ATN.INVALID_ALT_NUMBER ) { if ( _alt==1 ) { if ( _parseListeners!=null ) triggerExitRuleEvent(); _prevctx = _localctx; { - setState(45); + setState(60); _errHandler.sync(this); - switch ( getInterpreter().adaptivePredict(_input,1,_ctx) ) { + switch ( getInterpreter().adaptivePredict(_input,5,_ctx) ) { case 1: { _localctx = new ComparatorExpressionContext(new ExpressionContext(_parentctx, _parentState)); ((ComparatorExpressionContext)_localctx).left = _prevctx; pushNewRecursionContext(_localctx, _startState, RULE_expression); - setState(37); - if (!(precpred(_ctx, 5))) throw new FailedPredicateException(this, "precpred(_ctx, 5)"); - setState(38); + setState(52); + if (!(precpred(_ctx, 6))) throw new FailedPredicateException(this, "precpred(_ctx, 6)"); + setState(53); ((ComparatorExpressionContext)_localctx).op = comparator(); - setState(39); - ((ComparatorExpressionContext)_localctx).right = expression(6); + setState(54); + ((ComparatorExpressionContext)_localctx).right = expression(7); } break; case 2: @@ -400,20 +475,20 @@ private ExpressionContext expression(int _p) throws RecognitionException { _localctx = new BinaryExpressionContext(new ExpressionContext(_parentctx, _parentState)); ((BinaryExpressionContext)_localctx).left = _prevctx; pushNewRecursionContext(_localctx, _startState, RULE_expression); - setState(41); - if (!(precpred(_ctx, 4))) throw new FailedPredicateException(this, "precpred(_ctx, 4)"); - setState(42); + setState(56); + if (!(precpred(_ctx, 5))) throw new FailedPredicateException(this, "precpred(_ctx, 5)"); + setState(57); ((BinaryExpressionContext)_localctx).op = binary(); - setState(43); - ((BinaryExpressionContext)_localctx).right = expression(5); + setState(58); + ((BinaryExpressionContext)_localctx).right = expression(6); } break; } } } - setState(49); + setState(64); _errHandler.sync(this); - _alt = getInterpreter().adaptivePredict(_input,2,_ctx); + _alt = getInterpreter().adaptivePredict(_input,6,_ctx); } } } @@ -457,9 +532,9 @@ public final ComparatorContext comparator() throws RecognitionException { try { enterOuterAlt(_localctx, 1); { - setState(50); + setState(65); _la = _input.LA(1); - if ( !(((_la) & ~0x3f) == 0 && ((1L << _la) & 32256L) != 0) ) { + if ( !((((_la) & ~0x3f) == 0 && ((1L << _la) & 129024L) != 0)) ) { _errHandler.recoverInline(this); } else { @@ -518,87 +593,87 @@ public final WordlistContext wordlist() throws RecognitionException { int _alt; enterOuterAlt(_localctx, 1); { - setState(52); + setState(67); match(LPAREN); - setState(56); + setState(71); _errHandler.sync(this); - _alt = getInterpreter().adaptivePredict(_input,3,_ctx); + _alt = getInterpreter().adaptivePredict(_input,7,_ctx); while ( _alt!=2 && _alt!= ATN.INVALID_ALT_NUMBER ) { if ( _alt==1 ) { { { - setState(53); + setState(68); match(WS); } } } - setState(58); + setState(73); _errHandler.sync(this); - _alt = getInterpreter().adaptivePredict(_input,3,_ctx); + _alt = getInterpreter().adaptivePredict(_input,7,_ctx); } - setState(59); + setState(74); ((WordlistContext)_localctx).first = types(); - setState(63); + setState(78); _errHandler.sync(this); _la = _input.LA(1); while (_la==WS) { { { - setState(60); + setState(75); match(WS); } } - setState(65); + setState(80); _errHandler.sync(this); _la = _input.LA(1); } - setState(82); + setState(97); _errHandler.sync(this); _la = _input.LA(1); while (_la==T__0) { { { - setState(66); + setState(81); match(T__0); - setState(70); + setState(85); _errHandler.sync(this); - _alt = getInterpreter().adaptivePredict(_input,5,_ctx); + _alt = getInterpreter().adaptivePredict(_input,9,_ctx); while ( _alt!=2 && _alt!= ATN.INVALID_ALT_NUMBER ) { if ( _alt==1 ) { { { - setState(67); + setState(82); match(WS); } } } - setState(72); + setState(87); _errHandler.sync(this); - _alt = getInterpreter().adaptivePredict(_input,5,_ctx); + _alt = getInterpreter().adaptivePredict(_input,9,_ctx); } - setState(73); + setState(88); ((WordlistContext)_localctx).rest = types(); - setState(77); + setState(92); _errHandler.sync(this); _la = _input.LA(1); while (_la==WS) { { { - setState(74); + setState(89); match(WS); } } - setState(79); + setState(94); _errHandler.sync(this); _la = _input.LA(1); } } } - setState(84); + setState(99); _errHandler.sync(this); _la = _input.LA(1); } - setState(85); + setState(100); match(RPAREN); } } @@ -613,6 +688,54 @@ public final WordlistContext wordlist() throws RecognitionException { return _localctx; } + @SuppressWarnings("CheckReturnValue") + public static class ArrayOperatorsContext extends ParserRuleContext { + public TerminalNode CONTAINS_ANY() { return getToken(BooleanExpressionParser.CONTAINS_ANY, 0); } + public TerminalNode CONTAINS_ALL() { return getToken(BooleanExpressionParser.CONTAINS_ALL, 0); } + public ArrayOperatorsContext(ParserRuleContext parent, int invokingState) { + super(parent, invokingState); + } + @Override public int getRuleIndex() { return RULE_arrayOperators; } + @Override + public void enterRule(ParseTreeListener listener) { + if ( listener instanceof BooleanExpressionListener ) ((BooleanExpressionListener)listener).enterArrayOperators(this); + } + @Override + public void exitRule(ParseTreeListener listener) { + if ( listener instanceof BooleanExpressionListener ) ((BooleanExpressionListener)listener).exitArrayOperators(this); + } + } + + public final ArrayOperatorsContext arrayOperators() throws RecognitionException { + ArrayOperatorsContext _localctx = new ArrayOperatorsContext(_ctx, getState()); + enterRule(_localctx, 8, RULE_arrayOperators); + int _la; + try { + enterOuterAlt(_localctx, 1); + { + setState(102); + _la = _input.LA(1); + if ( !(_la==CONTAINS_ALL || _la==CONTAINS_ANY) ) { + _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 NumericTypesContext extends ParserRuleContext { public TerminalNode INTEGER() { return getToken(BooleanExpressionParser.INTEGER, 0); } @@ -633,12 +756,12 @@ public void exitRule(ParseTreeListener listener) { public final NumericTypesContext numericTypes() throws RecognitionException { NumericTypesContext _localctx = new NumericTypesContext(_ctx, getState()); - enterRule(_localctx, 8, RULE_numericTypes); + enterRule(_localctx, 10, RULE_numericTypes); int _la; try { enterOuterAlt(_localctx, 1); { - setState(87); + setState(104); _la = _input.LA(1); if ( !(_la==DECIMAL || _la==INTEGER) ) { _errHandler.recoverInline(this); @@ -686,43 +809,43 @@ public void exitRule(ParseTreeListener listener) { public final TypesContext types() throws RecognitionException { TypesContext _localctx = new TypesContext(_ctx, getState()); - enterRule(_localctx, 10, RULE_types); + enterRule(_localctx, 12, RULE_types); try { - setState(95); + setState(112); _errHandler.sync(this); - switch ( getInterpreter().adaptivePredict(_input,8,_ctx) ) { + switch ( getInterpreter().adaptivePredict(_input,12,_ctx) ) { case 1: enterOuterAlt(_localctx, 1); { - setState(89); + setState(106); match(INTEGER); } break; case 2: enterOuterAlt(_localctx, 2); { - setState(90); + setState(107); match(DECIMAL); } break; case 3: enterOuterAlt(_localctx, 3); { - setState(91); + setState(108); match(APP_VERSION); } break; case 4: enterOuterAlt(_localctx, 4); { - setState(92); + setState(109); bool(); } break; case 5: enterOuterAlt(_localctx, 5); { - setState(93); + setState(110); match(WORD); } break; @@ -764,12 +887,12 @@ public void exitRule(ParseTreeListener listener) { public final BinaryContext binary() throws RecognitionException { BinaryContext _localctx = new BinaryContext(_ctx, getState()); - enterRule(_localctx, 12, RULE_binary); + enterRule(_localctx, 14, RULE_binary); int _la; try { enterOuterAlt(_localctx, 1); { - setState(97); + setState(114); _la = _input.LA(1); if ( !(_la==AND || _la==OR) ) { _errHandler.recoverInline(this); @@ -812,12 +935,12 @@ public void exitRule(ParseTreeListener listener) { public final BoolContext bool() throws RecognitionException { BoolContext _localctx = new BoolContext(_ctx, getState()); - enterRule(_localctx, 14, RULE_bool); + enterRule(_localctx, 16, RULE_bool); int _la; try { enterOuterAlt(_localctx, 1); { - setState(99); + setState(116); _la = _input.LA(1); if ( !(_la==TRUE || _la==FALSE) ) { _errHandler.recoverInline(this); @@ -850,76 +973,86 @@ public boolean sempred(RuleContext _localctx, int ruleIndex, int predIndex) { private boolean expression_sempred(ExpressionContext _localctx, int predIndex) { switch (predIndex) { case 0: - return precpred(_ctx, 5); + return precpred(_ctx, 6); case 1: - return precpred(_ctx, 4); + return precpred(_ctx, 5); } return true; } public static final String _serializedATN = - "\u0004\u0001\u0018f\u0002\u0000\u0007\u0000\u0002\u0001\u0007\u0001\u0002"+ + "\u0004\u0001\u001aw\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\u0001"+ - "\u0000\u0001\u0000\u0001\u0000\u0001\u0001\u0001\u0001\u0001\u0001\u0001"+ + "\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"+ "\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\u0003\u0001$\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\u00011\t\u0001\u0001\u0002\u0001\u0002\u0001\u0003\u0001"+ - "\u0003\u0005\u00037\b\u0003\n\u0003\f\u0003:\t\u0003\u0001\u0003\u0001"+ - "\u0003\u0005\u0003>\b\u0003\n\u0003\f\u0003A\t\u0003\u0001\u0003\u0001"+ - "\u0003\u0005\u0003E\b\u0003\n\u0003\f\u0003H\t\u0003\u0001\u0003\u0001"+ - "\u0003\u0005\u0003L\b\u0003\n\u0003\f\u0003O\t\u0003\u0005\u0003Q\b\u0003"+ - "\n\u0003\f\u0003T\t\u0003\u0001\u0003\u0001\u0003\u0001\u0004\u0001\u0004"+ - "\u0001\u0005\u0001\u0005\u0001\u0005\u0001\u0005\u0001\u0005\u0001\u0005"+ - "\u0003\u0005`\b\u0005\u0001\u0006\u0001\u0006\u0001\u0007\u0001\u0007"+ - "\u0001\u0007\u0000\u0001\u0002\b\u0000\u0002\u0004\u0006\b\n\f\u000e\u0000"+ - "\u0004\u0001\u0000\t\u000e\u0002\u0000\u0011\u0011\u0013\u0013\u0001\u0000"+ - "\u0004\u0005\u0001\u0000\u0007\bm\u0000\u0010\u0001\u0000\u0000\u0000"+ - "\u0002#\u0001\u0000\u0000\u0000\u00042\u0001\u0000\u0000\u0000\u00064"+ - "\u0001\u0000\u0000\u0000\bW\u0001\u0000\u0000\u0000\n_\u0001\u0000\u0000"+ - "\u0000\fa\u0001\u0000\u0000\u0000\u000ec\u0001\u0000\u0000\u0000\u0010"+ - "\u0011\u0003\u0002\u0001\u0000\u0011\u0012\u0005\u0000\u0000\u0001\u0012"+ - "\u0001\u0001\u0000\u0000\u0000\u0013\u0014\u0006\u0001\uffff\uffff\u0000"+ - "\u0014\u0015\u0005\u000f\u0000\u0000\u0015\u0016\u0003\u0002\u0001\u0000"+ - "\u0016\u0017\u0005\u0010\u0000\u0000\u0017$\u0001\u0000\u0000\u0000\u0018"+ - "\u0019\u0005\u0006\u0000\u0000\u0019$\u0003\u0002\u0001\u0006\u001a$\u0003"+ - "\n\u0005\u0000\u001b\u001c\u0005\u0015\u0000\u0000\u001c\u001d\u0003\b"+ - "\u0004\u0000\u001d\u001e\u0005\u0003\u0000\u0000\u001e\u001f\u0003\b\u0004"+ - "\u0000\u001f$\u0001\u0000\u0000\u0000 !\u0005\u0015\u0000\u0000!\"\u0005"+ - "\u0002\u0000\u0000\"$\u0003\u0006\u0003\u0000#\u0013\u0001\u0000\u0000"+ - "\u0000#\u0018\u0001\u0000\u0000\u0000#\u001a\u0001\u0000\u0000\u0000#"+ - "\u001b\u0001\u0000\u0000\u0000# \u0001\u0000\u0000\u0000$/\u0001\u0000"+ - "\u0000\u0000%&\n\u0005\u0000\u0000&\'\u0003\u0004\u0002\u0000\'(\u0003"+ - "\u0002\u0001\u0006(.\u0001\u0000\u0000\u0000)*\n\u0004\u0000\u0000*+\u0003"+ - "\f\u0006\u0000+,\u0003\u0002\u0001\u0005,.\u0001\u0000\u0000\u0000-%\u0001"+ - "\u0000\u0000\u0000-)\u0001\u0000\u0000\u0000.1\u0001\u0000\u0000\u0000"+ - "/-\u0001\u0000\u0000\u0000/0\u0001\u0000\u0000\u00000\u0003\u0001\u0000"+ - "\u0000\u00001/\u0001\u0000\u0000\u000023\u0007\u0000\u0000\u00003\u0005"+ - "\u0001\u0000\u0000\u000048\u0005\u000f\u0000\u000057\u0005\u0014\u0000"+ - "\u000065\u0001\u0000\u0000\u00007:\u0001\u0000\u0000\u000086\u0001\u0000"+ - "\u0000\u000089\u0001\u0000\u0000\u00009;\u0001\u0000\u0000\u0000:8\u0001"+ - "\u0000\u0000\u0000;?\u0003\n\u0005\u0000<>\u0005\u0014\u0000\u0000=<\u0001"+ - "\u0000\u0000\u0000>A\u0001\u0000\u0000\u0000?=\u0001\u0000\u0000\u0000"+ - "?@\u0001\u0000\u0000\u0000@R\u0001\u0000\u0000\u0000A?\u0001\u0000\u0000"+ - "\u0000BF\u0005\u0001\u0000\u0000CE\u0005\u0014\u0000\u0000DC\u0001\u0000"+ - "\u0000\u0000EH\u0001\u0000\u0000\u0000FD\u0001\u0000\u0000\u0000FG\u0001"+ - "\u0000\u0000\u0000GI\u0001\u0000\u0000\u0000HF\u0001\u0000\u0000\u0000"+ - "IM\u0003\n\u0005\u0000JL\u0005\u0014\u0000\u0000KJ\u0001\u0000\u0000\u0000"+ - "LO\u0001\u0000\u0000\u0000MK\u0001\u0000\u0000\u0000MN\u0001\u0000\u0000"+ - "\u0000NQ\u0001\u0000\u0000\u0000OM\u0001\u0000\u0000\u0000PB\u0001\u0000"+ - "\u0000\u0000QT\u0001\u0000\u0000\u0000RP\u0001\u0000\u0000\u0000RS\u0001"+ - "\u0000\u0000\u0000SU\u0001\u0000\u0000\u0000TR\u0001\u0000\u0000\u0000"+ - "UV\u0005\u0010\u0000\u0000V\u0007\u0001\u0000\u0000\u0000WX\u0007\u0001"+ - "\u0000\u0000X\t\u0001\u0000\u0000\u0000Y`\u0005\u0013\u0000\u0000Z`\u0005"+ - "\u0011\u0000\u0000[`\u0005\u0012\u0000\u0000\\`\u0003\u000e\u0007\u0000"+ - "]`\u0005\u0015\u0000\u0000^`\u0001\u0000\u0000\u0000_Y\u0001\u0000\u0000"+ - "\u0000_Z\u0001\u0000\u0000\u0000_[\u0001\u0000\u0000\u0000_\\\u0001\u0000"+ - "\u0000\u0000_]\u0001\u0000\u0000\u0000_^\u0001\u0000\u0000\u0000`\u000b"+ - "\u0001\u0000\u0000\u0000ab\u0007\u0002\u0000\u0000b\r\u0001\u0000\u0000"+ - "\u0000cd\u0007\u0003\u0000\u0000d\u000f\u0001\u0000\u0000\u0000\t#-/8"+ - "?FMR_"; + "\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"; 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 f887946..4e7f7d0 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,11 +4,14 @@ import java.util.Objects; import java.util.Stack; import java.util.stream.Collectors; +import org.antlr.v4.runtime.Token; +import org.antlr.v4.runtime.tree.ParseTree; import org.apache.commons.lang3.StringUtils; import org.apache.commons.lang3.tuple.Pair; 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.ArrayNode; import com.github.sidhant92.boolparser.domain.BooleanNode; import com.github.sidhant92.boolparser.domain.InNode; import com.github.sidhant92.boolparser.domain.Node; @@ -51,6 +54,7 @@ public void exitComparatorExpression(BooleanExpressionParser.ComparatorExpressio @Override public void exitToExpression(BooleanExpressionParser.ToExpressionContext ctx) { + validateField(ctx.field, ctx.getText()); final String field = getField(ctx.field.getText()); final DataType lowerDataType = getDataType(ctx.lower.start); final Object lowerValue = ValueUtils.convertValue(ctx.lower.start.getText(), lowerDataType); @@ -60,10 +64,33 @@ public void exitToExpression(BooleanExpressionParser.ToExpressionContext ctx) { super.exitToExpression(ctx); } + @Override + public void exitArrayExpression(BooleanExpressionParser.ArrayExpressionContext ctx) { + validateField(ctx.field, ctx.getText()); + final String field = getField(ctx.field.getText()); + final List> items = getArrayElements(ctx.data.children); + final Operator operator = Operator.getOperatorFromSymbol(ctx.op.getText()).orElse(Operator.EQUALS); + currentNodes.add(new ArrayNode(field, operator, items)); + super.exitArrayExpression(ctx); + } + @Override public void exitInExpression(BooleanExpressionParser.InExpressionContext ctx) { + validateField(ctx.field, ctx.getText()); final String field = getField(ctx.field.getText()); - final List> items = ctx.data.children + final List> items = getArrayElements(ctx.data.children); + final InNode inNode = new InNode(field, items); + if (Objects.isNull(ctx.not)) { + currentNodes.add(inNode); + } else { + final BooleanNode booleanNode = new BooleanNode(inNode, null, LogicalOperationType.NOT); + currentNodes.add(booleanNode); + } + super.exitInExpression(ctx); + } + + private List> getArrayElements(final List trees) { + return trees .stream() .filter(child -> child instanceof BooleanExpressionParser.TypesContext) .map(child -> { @@ -72,14 +99,16 @@ public void exitInExpression(BooleanExpressionParser.InExpressionContext ctx) { return Pair.of(dataType, value); }) .collect(Collectors.toList()); - currentNodes.add(new InNode(field, items)); - super.exitInExpression(ctx); } - private String getField(final String field) { - if (Objects.isNull(defaultField)) { - return field; + private void validateField(final Token token, final String text) { + if (Objects.isNull(token) || (StringUtils.isBlank(token.getText()) && StringUtils.isBlank(this.defaultField))) { + log.error("Error parsing expression (missing field) for the string {}", text); + throw new InvalidExpressionException(); } + } + + private String getField(final String field) { return StringUtils.isBlank(field) ? defaultField : field; } diff --git a/src/main/java/resources/BooleanExpression.g4 b/src/main/java/resources/BooleanExpression.g4 index ebebc95..3c2bbba 100644 --- a/src/main/java/resources/BooleanExpression.g4 +++ b/src/main/java/resources/BooleanExpression.g4 @@ -10,8 +10,9 @@ expression | left=expression op=comparator right=expression #comparatorExpression | left=expression op=binary right=expression #binaryExpression | types #typesExpression - | field=WORD lower=numericTypes TO upper=numericTypes #toExpression - | field=WORD IN data=wordlist #inExpression + | (field=WORD)? lower=numericTypes TO upper=numericTypes #toExpression + | (field=WORD)? (not=NOT)? IN data=wordlist #inExpression + | (field=WORD)? op=arrayOperators data=wordlist #arrayExpression ; comparator @@ -23,6 +24,10 @@ comparator : LPAREN WS* first=types WS* (',' WS* rest=types WS*)* RPAREN ; + arrayOperators + : CONTAINS_ANY | CONTAINS_ALL + ; + numericTypes : INTEGER | DECIMAL @@ -49,6 +54,8 @@ OR : 'OR' | 'or' | '||'; NOT : 'NOT' | 'not'; TRUE : 'TRUE' | 'true'; FALSE : 'FALSE' | 'false'; +CONTAINS_ALL : 'CONTAINS_ALL' | 'contains_all'; +CONTAINS_ANY : 'CONTAINS_ANY' | 'contains_any'; NE : '!='; GT : '>' ; GE : '>=' ; 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 d140aef..afef8c2 100644 --- a/src/test/java/com/github/sidhant92/boolparser/application/BooleanExpressionEvaluatorTest.java +++ b/src/test/java/com/github/sidhant92/boolparser/application/BooleanExpressionEvaluatorTest.java @@ -1,8 +1,11 @@ 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; @@ -272,6 +275,15 @@ public void testNegativeInClauseForIntegers() { assertFalse(booleanOptional.get()); } + @Test + public void testNotInClauseForIntegers() { + final Map data = new HashMap<>(); + data.put("age", 30); + final Try booleanOptional = booleanExpressionEvaluator.evaluate("age not in (26,56,34)", data); + assertTrue(booleanOptional.isSuccess()); + assertTrue(booleanOptional.get()); + } + @Test public void testPositiveInClauseForIntegers() { final Map data = new HashMap<>(); @@ -437,4 +449,56 @@ public void testDefaultFieldFalse() { assertTrue(booleanOptional.isSuccess()); assertFalse(booleanOptional.get()); } + + @Test + public void testContainsAnyTrueCondition() { + final Map data = new HashMap<>(); + final List ages = new ArrayList<>(); + ages.add(1); + ages.add(2); + ages.add(3); + data.put("age", ages); + final Try booleanOptional = booleanExpressionEvaluator.evaluate("age contains_any (2)", data); + assertTrue(booleanOptional.isSuccess()); + assertTrue(booleanOptional.get()); + } + + @Test + public void testContainsAnyFalseCondition() { + final Map data = new HashMap<>(); + final List ages = new ArrayList<>(); + ages.add(1); + ages.add(2); + ages.add(3); + data.put("age", ages); + final Try booleanOptional = booleanExpressionEvaluator.evaluate("age contains_any (12)", data); + assertTrue(booleanOptional.isSuccess()); + assertFalse(booleanOptional.get()); + } + + @Test + public void testContainsAllTrueCondition() { + final Map data = new HashMap<>(); + final List ages = new ArrayList<>(); + ages.add(1); + ages.add(2); + ages.add(3); + data.put("age", ages); + final Try booleanOptional = booleanExpressionEvaluator.evaluate("age contains_all (1,2)", data); + assertTrue(booleanOptional.isSuccess()); + assertTrue(booleanOptional.get()); + } + + @Test + public void testContainsAllFalseCondition() { + final Map data = new HashMap<>(); + final List ages = new ArrayList<>(); + ages.add(1); + ages.add(2); + ages.add(3); + data.put("age", ages); + final Try booleanOptional = booleanExpressionEvaluator.evaluate("age contains_all (2,5)", 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 e1003ce..e16eda7 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.ArrayNode; import com.github.sidhant92.boolparser.domain.BooleanNode; import com.github.sidhant92.boolparser.domain.InNode; import com.github.sidhant92.boolparser.domain.Node; @@ -255,6 +256,23 @@ public void testIntegerList() { assertEquals(inToken.getItems().get(1).getValue(), 45); } + @Test + public void testNotIntegerList() { + final Try nodeOptional = boolExpressionBoolParser.parseExpression("age not IN (12,45)"); + assertTrue(nodeOptional.isSuccess()); + assertEquals(nodeOptional.get().getTokenType().name(), NodeType.BOOLEAN.name()); + assertNotNull(((BooleanNode)nodeOptional.get()).getLeft()); + assertNull(((BooleanNode)nodeOptional.get()).getRight()); + assertEquals(((BooleanNode)nodeOptional.get()).getOperator(), LogicalOperationType.NOT); + final InNode inToken = (InNode) ((BooleanNode)nodeOptional.get()).getLeft(); + assertEquals(inToken.getItems().size(), 2); + assertEquals(inToken.getField(), "age"); + assertEquals(inToken.getItems().get(0).getKey(), DataType.INTEGER); + assertEquals(inToken.getItems().get(1).getKey(), DataType.INTEGER); + assertEquals(inToken.getItems().get(0).getValue(), 12); + assertEquals(inToken.getItems().get(1).getValue(), 45); + } + @Test public void testStringList() { final Try nodeOptional = boolExpressionBoolParser.parseExpression("name IN (abc, def, 'abc def')"); @@ -317,6 +335,26 @@ public void testInvalidNotExpression() { assertTrue(nodeOptional.getCause() instanceof InvalidExpressionException); } + @Test + public void testContainsAny() { + final Try nodeOptional = boolExpressionBoolParser.parseExpression("a contains_any (1,2,3)"); + assertTrue(nodeOptional.isSuccess()); + assertEquals(nodeOptional.get().getTokenType(), NodeType.ARRAY); + assertEquals(((ArrayNode) nodeOptional.get()).getField(), "a"); + assertEquals(((ArrayNode) nodeOptional.get()).getOperator(), Operator.CONTAINS_ANY); + assertEquals(((ArrayNode) nodeOptional.get()).getItems().size(), 3); + } + + @Test + public void testContainsAll() { + final Try nodeOptional = boolExpressionBoolParser.parseExpression("a contains_all (\"a\", \"b\""); + assertTrue(nodeOptional.isSuccess()); + assertEquals(nodeOptional.get().getTokenType(), NodeType.ARRAY); + assertEquals(((ArrayNode) nodeOptional.get()).getField(), "a"); + assertEquals(((ArrayNode) nodeOptional.get()).getOperator(), Operator.CONTAINS_ALL); + assertEquals(((ArrayNode) nodeOptional.get()).getItems().size(), 2); + } + private void verifyStringToken(final ComparisonNode stringToken, final String field, final String value) { assertEquals(stringToken.getTokenType().name(), NodeType.COMPARISON.name()); assertEquals(stringToken.getField(), field); @@ -330,8 +368,7 @@ private void verifyNumericToken(final ComparisonNode comparisonToken, final Stri assertEquals(comparisonToken.getOperator().name(), operator.name()); } - private void verifyNumericRangeToken(final NumericRangeNode numericRangeToken, final String field, final Object fromValue, - final Object toValue) { + private void verifyNumericRangeToken(final NumericRangeNode numericRangeToken, final String field, final Object fromValue, final Object toValue) { assertEquals(numericRangeToken.getTokenType().name(), NodeType.NUMERIC_RANGE.name()); assertEquals(numericRangeToken.getField(), field); assertEquals(numericRangeToken.getFromValue(), fromValue); From d9fa239287062d9032797335bac1f0c246efa285 Mon Sep 17 00:00:00 2001 From: Sidhant Aggarwal <10743214+sidhant92@users.noreply.github.com> Date: Thu, 23 Nov 2023 23:04:50 +0530 Subject: [PATCH 2/4] support for strict data type checking --- .../sidhant92/boolparser/datatype/AbstractDataType.java | 9 +++++++++ .../sidhant92/boolparser/datatype/BooleanDataType.java | 5 +++++ .../sidhant92/boolparser/datatype/DecimalDataType.java | 7 ++++++- .../sidhant92/boolparser/datatype/IntegerDataType.java | 5 +++++ .../sidhant92/boolparser/datatype/LongDataType.java | 5 +++++ .../sidhant92/boolparser/datatype/StringDataType.java | 5 +++++ .../sidhant92/boolparser/datatype/VersionDataType.java | 5 +++++ 7 files changed, 40 insertions(+), 1 deletion(-) diff --git a/src/main/java/com/github/sidhant92/boolparser/datatype/AbstractDataType.java b/src/main/java/com/github/sidhant92/boolparser/datatype/AbstractDataType.java index dfb715b..6d0aab1 100644 --- a/src/main/java/com/github/sidhant92/boolparser/datatype/AbstractDataType.java +++ b/src/main/java/com/github/sidhant92/boolparser/datatype/AbstractDataType.java @@ -18,10 +18,17 @@ public AbstractDataType(final Class clazz) { } public boolean defaultIsValid(final Object value, final ObjectMapper objectMapper) { + return defaultIsValid(value, objectMapper, false); + } + + public boolean defaultIsValid(final Object value, final ObjectMapper objectMapper, final boolean useStrictValidation) { try { if (clazz.isInstance(value)) { return true; } + if (useStrictValidation) { + return false; + } return objectMapper.convertValue(value, clazz) != null; } catch (final Exception ex) { log.error("Unable to convert value = {} to type = {}", value, clazz); @@ -45,5 +52,7 @@ public Optional defaultGetValue(final Object value, final ObjectMapper object public abstract boolean isValid(final Object value); + public abstract boolean isValid(final Object value, final boolean useStrictValidation); + public abstract Optional getValue(final Object value); } diff --git a/src/main/java/com/github/sidhant92/boolparser/datatype/BooleanDataType.java b/src/main/java/com/github/sidhant92/boolparser/datatype/BooleanDataType.java index 67de6cc..28ce325 100644 --- a/src/main/java/com/github/sidhant92/boolparser/datatype/BooleanDataType.java +++ b/src/main/java/com/github/sidhant92/boolparser/datatype/BooleanDataType.java @@ -26,6 +26,11 @@ public boolean isValid(final Object value) { return super.defaultIsValid(value, objectMapper); } + @Override + public boolean isValid(final Object value, final boolean useStrictValidation) { + return super.defaultIsValid(value, objectMapper, useStrictValidation); + } + @Override public Optional getValue(Object value) { return defaultGetValue(value, objectMapper); diff --git a/src/main/java/com/github/sidhant92/boolparser/datatype/DecimalDataType.java b/src/main/java/com/github/sidhant92/boolparser/datatype/DecimalDataType.java index f2063cf..0b11cb5 100644 --- a/src/main/java/com/github/sidhant92/boolparser/datatype/DecimalDataType.java +++ b/src/main/java/com/github/sidhant92/boolparser/datatype/DecimalDataType.java @@ -18,7 +18,7 @@ public DecimalDataType(final ObjectMapper objectMapper) { @Override public DataType getDataType() { - return DataType.STRING; + return DataType.DECIMAL; } @Override @@ -26,6 +26,11 @@ public boolean isValid(final Object value) { return super.defaultIsValid(value, objectMapper); } + @Override + public boolean isValid(final Object value, final boolean useStrictValidation) { + return super.defaultIsValid(value, objectMapper, useStrictValidation); + } + @Override public Optional getValue(Object value) { return defaultGetValue(value, objectMapper); diff --git a/src/main/java/com/github/sidhant92/boolparser/datatype/IntegerDataType.java b/src/main/java/com/github/sidhant92/boolparser/datatype/IntegerDataType.java index f4eb9b9..3195abe 100644 --- a/src/main/java/com/github/sidhant92/boolparser/datatype/IntegerDataType.java +++ b/src/main/java/com/github/sidhant92/boolparser/datatype/IntegerDataType.java @@ -26,6 +26,11 @@ public boolean isValid(final Object value) { return super.defaultIsValid(value, objectMapper); } + @Override + public boolean isValid(final Object value, final boolean useStrictValidation) { + return super.defaultIsValid(value, objectMapper, useStrictValidation); + } + @Override public Optional getValue(Object value) { return defaultGetValue(value, objectMapper); diff --git a/src/main/java/com/github/sidhant92/boolparser/datatype/LongDataType.java b/src/main/java/com/github/sidhant92/boolparser/datatype/LongDataType.java index b726a9c..7623dec 100644 --- a/src/main/java/com/github/sidhant92/boolparser/datatype/LongDataType.java +++ b/src/main/java/com/github/sidhant92/boolparser/datatype/LongDataType.java @@ -26,6 +26,11 @@ public boolean isValid(final Object value) { return super.defaultIsValid(value, objectMapper); } + @Override + public boolean isValid(final Object value, final boolean useStrictValidation) { + return super.defaultIsValid(value, objectMapper, useStrictValidation); + } + @Override public Optional getValue(Object value) { return defaultGetValue(value, objectMapper); diff --git a/src/main/java/com/github/sidhant92/boolparser/datatype/StringDataType.java b/src/main/java/com/github/sidhant92/boolparser/datatype/StringDataType.java index 795f87e..195c991 100644 --- a/src/main/java/com/github/sidhant92/boolparser/datatype/StringDataType.java +++ b/src/main/java/com/github/sidhant92/boolparser/datatype/StringDataType.java @@ -26,6 +26,11 @@ public boolean isValid(final Object value) { return super.defaultIsValid(value, objectMapper); } + @Override + public boolean isValid(final Object value, final boolean useStrictValidation) { + return super.defaultIsValid(value, objectMapper, useStrictValidation); + } + @Override public Optional getValue(Object value) { return defaultGetValue(value, objectMapper); diff --git a/src/main/java/com/github/sidhant92/boolparser/datatype/VersionDataType.java b/src/main/java/com/github/sidhant92/boolparser/datatype/VersionDataType.java index 383f153..4069148 100644 --- a/src/main/java/com/github/sidhant92/boolparser/datatype/VersionDataType.java +++ b/src/main/java/com/github/sidhant92/boolparser/datatype/VersionDataType.java @@ -27,6 +27,11 @@ public boolean isValid(final Object value) { return super.defaultIsValid(value, objectMapper); } + @Override + public boolean isValid(final Object value, final boolean useStrictValidation) { + return super.defaultIsValid(value, objectMapper, useStrictValidation); + } + @Override public Optional getValue(Object value) { return defaultGetValue(value, objectMapper); From ddd9c01da8746444eb2a931779bca71fdfdf6016 Mon Sep 17 00:00:00 2001 From: Sidhant Aggarwal <10743214+sidhant92@users.noreply.github.com> Date: Thu, 23 Nov 2023 23:10:58 +0530 Subject: [PATCH 3/4] change methods to protected --- .../sidhant92/boolparser/datatype/AbstractDataType.java | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/main/java/com/github/sidhant92/boolparser/datatype/AbstractDataType.java b/src/main/java/com/github/sidhant92/boolparser/datatype/AbstractDataType.java index 6d0aab1..0a3c22d 100644 --- a/src/main/java/com/github/sidhant92/boolparser/datatype/AbstractDataType.java +++ b/src/main/java/com/github/sidhant92/boolparser/datatype/AbstractDataType.java @@ -17,11 +17,11 @@ public AbstractDataType(final Class clazz) { this.clazz = clazz; } - public boolean defaultIsValid(final Object value, final ObjectMapper objectMapper) { + protected boolean defaultIsValid(final Object value, final ObjectMapper objectMapper) { return defaultIsValid(value, objectMapper, false); } - public boolean defaultIsValid(final Object value, final ObjectMapper objectMapper, final boolean useStrictValidation) { + protected boolean defaultIsValid(final Object value, final ObjectMapper objectMapper, final boolean useStrictValidation) { try { if (clazz.isInstance(value)) { return true; @@ -36,7 +36,7 @@ public boolean defaultIsValid(final Object value, final ObjectMapper objectMappe return false; } - public Optional defaultGetValue(final Object value, final ObjectMapper objectMapper) { + protected Optional defaultGetValue(final Object value, final ObjectMapper objectMapper) { try { if (clazz.isInstance(value)) { return Optional.of(clazz.cast(value)); From fa505b99d57bda9bfc43583d799eea21e322ffca Mon Sep 17 00:00:00 2001 From: Sidhant Aggarwal <10743214+sidhant92@users.noreply.github.com> Date: Fri, 15 Dec 2023 15:48:19 +0530 Subject: [PATCH 4/4] Support nesting upto n Levels --- .../sidhant92/boolparser/util/ValueUtils.java | 11 ++++++++--- .../application/BooleanExpressionEvaluatorTest.java | 13 +++++++++++++ 2 files changed, 21 insertions(+), 3 deletions(-) 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 1fd5306..15232e0 100644 --- a/src/main/java/com/github/sidhant92/boolparser/util/ValueUtils.java +++ b/src/main/java/com/github/sidhant92/boolparser/util/ValueUtils.java @@ -1,7 +1,9 @@ package com.github.sidhant92.boolparser.util; +import java.util.Arrays; import java.util.Map; import java.util.Optional; +import java.util.stream.Collectors; import org.apache.maven.artifact.versioning.ComparableVersion; import com.github.sidhant92.boolparser.constant.DataType; import lombok.extern.slf4j.Slf4j; @@ -17,7 +19,10 @@ public static Optional getValueFromMap(final String key, final Map) fieldData.get()); + final String newKey = Arrays + .stream(keys).skip(1) + .collect(Collectors.joining(".")); + return getValueFromMap(newKey, (Map) fieldData.get()); } catch (ClassCastException ex) { return Optional.empty(); } @@ -40,10 +45,10 @@ public static Object convertValue(final String value, final DataType dataType) { new ComparableVersion(value); default: if (value.startsWith("'") && value.endsWith("'")) { - return value.substring(1, value.length() -1); + return value.substring(1, value.length() - 1); } if (value.startsWith("\"") && value.endsWith("\"")) { - return value.substring(1, value.length() -1); + return value.substring(1, value.length() - 1); } return value; } 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 afef8c2..ca99377 100644 --- a/src/test/java/com/github/sidhant92/boolparser/application/BooleanExpressionEvaluatorTest.java +++ b/src/test/java/com/github/sidhant92/boolparser/application/BooleanExpressionEvaluatorTest.java @@ -123,6 +123,19 @@ public void testNestedField() { assertTrue(booleanOptional.get()); } + @Test + public void testTwoNestedField() { + final Map data = new HashMap<>(); + final Map person = new HashMap<>(); + final Map details = new HashMap<>(); + details.put("age", 24); + person.put("details", details); + data.put("person", person); + final Try booleanOptional = booleanExpressionEvaluator.evaluate("person.details.age > 20", data); + assertTrue(booleanOptional.isSuccess()); + assertTrue(booleanOptional.get()); + } + @Test public void testMissingNestedField() { final Map data = new HashMap<>();