diff --git a/.gitignore b/.gitignore index 3ba01b2..7b87329 100644 --- a/.gitignore +++ b/.gitignore @@ -30,3 +30,4 @@ out/ ` gradle.properties +src/**/*.peg \ No newline at end of file diff --git a/README.md b/README.md index b8aed6e..8bb7fe5 100644 --- a/README.md +++ b/README.md @@ -171,4 +171,16 @@ assertTrue(booleanOptional.get()); The return type is `Optional`. If its absent which means parsing has failed and any fallback can be used. -[For a complete list of examples please check out the test file](src/test/java/com/github/sidhant92/boolparser/application/BooleanExpressionEvaluatorTest.java) \ No newline at end of file +[For a complete list of examples please check out the test file](src/test/java/com/github/sidhant92/boolparser/application/BooleanExpressionEvaluatorTest.java) + +### Contribution +We use [Canopy](http://canopy.jcoglan.com/) which is a PEG parser compiler. You can make changes to the grammar and generate the code using the following steps. It will be better if you read its documentation first. +1. install canopy using `npm install -g canopy`. + 1. you might need to fix the canopy(0.3.0) file(in the node_modules) depending on the node version. try following the next steps and if it throws some error related to `mkdirp` put the write function in(or around) line 32 in the `then` part of the promise. +2. copy `canopy.peg` file to `$APP_HOME/src/main/java/com/github/sidhant92/boolparser/parser`. +3. go to dir `$APP_HOME/src/main/java` +4. run `canopy com/github/sidhant92/boolparser/parser/canopy.peg --lang java` + +#### To run tests +Make a `gradle.properties` file in `$APP_HOME` and copy the contents of `gradle.properties.sample` file there. +Change the java home location as per your OS/java-version. For rest of the fields you can put dummy data. \ No newline at end of file diff --git a/build.gradle b/build.gradle index 4c6ff9c..1b07143 100644 --- a/build.gradle +++ b/build.gradle @@ -19,6 +19,9 @@ dependencies { compile 'ch.qos.logback.contrib:logback-jackson:0.1.5' compile 'net.logstash.logback:logstash-logback-encoder:5.2' compile 'org.apache.maven:maven-artifact:3.5.2' + compile 'com.google.guava:guava:30.1-jre' + compile 'org.apache.commons:commons-collections4:4.1' + compileOnly 'org.projectlombok:lombok:1.18.12' annotationProcessor 'org.projectlombok:lombok:1.18.12' diff --git a/canopy.peg b/canopy.peg new file mode 100644 index 0000000..579f0a2 --- /dev/null +++ b/canopy.peg @@ -0,0 +1,35 @@ +grammar Filters + start <- logical_or + logical_or <- logical_and (ws+ or ws+ logical_and)* %make_logical_or + logical_and <- primary (ws+ and ws+ primary)* %make_logical_and + primary <- token / "(" logical_or ")" %make_primary + token <- "NOT"? ws* alphanumeric ws* "=" ws* decimal %make_numeric_token + / "NOT"? ws* alphanumeric ws* ">" ws* app_version %make_app_version_token + / "NOT"? ws* alphanumeric ws* ">=" ws* app_version %make_app_version_token + / "NOT"? ws* alphanumeric ws* "<" ws* app_version %make_app_version_token + / "NOT"? ws* alphanumeric ws* "<=" ws* app_version %make_app_version_token + / "NOT"? ws* alphanumeric ws* ">" ws* decimal %make_numeric_token + / "NOT"? ws* alphanumeric ws* ">=" ws* decimal %make_numeric_token + / "NOT"? ws* alphanumeric ws* "<" ws* decimal %make_numeric_token + / "NOT"? ws* alphanumeric ws* "<=" ws* decimal %make_numeric_token + / "NOT"? ws* alphanumeric ws* "!=" ws* decimal %make_numeric_token + / "NOT"? ws* alphanumeric ws* ":" ws* decimal ws* ("TO" / "to") ws* decimal %make_numeric_range_token + / "NOT"? ws* alphanumeric ws* ":" ws* alphanumeric %make_string_token + / "NOT"? ws* alphanumeric ws* in ws* "(" number_list ")" %make_decimal_list + / "NOT"? ws* alphanumeric ws* in ws* "(" string_list ")" %make_string_list + / "NOT"? ws* alphanumeric ws* rev_all ws* "(" number_list ")" %make_rev_all_decimal_list + / "NOT"? ws* alphanumeric ws* rev_all ws* "(" string_list ")" %make_rev_all_string_list + number_list <- ws* decimal ws* number_list_token* + number_list_token <- "," ws* decimal ws* + string_list <- ws* alphanumeric ws* string_list_token* + string_list_token <- "," ws* alphanumeric ws* + app_version <- [0-9]+ "." [0-9]+ app_version_token+ + app_version_token <- "." [0-9]+ + alphanumeric <- [^ \t'"<>=:(),]+ / ["]+ [^"]+ ["]+ / [']+ [^']+ [']+ + decimal <- [0-9]+ "."? [0-9]* + or <- ("OR" / "or" / "|" / "||") + and <- ("AND" / "and" / "&" / "&&") + operator <- ("=" / ">" / ">=" / "<" / "<=" / "!=") + in <- ("IN" / "in") + rev_all <- (`rev_all`) + ws <- [ \t] diff --git a/gradle.properties.sample b/gradle.properties.sample index af1e4d5..3004f0e 100644 --- a/gradle.properties.sample +++ b/gradle.properties.sample @@ -3,4 +3,4 @@ ossrhPassword= signing.keyId= signing.password=@ signing.secretKeyRingFile= -org.gradle.java.home= +org.gradle.java.home=/Library/Java/JavaVirtualMachines/jdk-17.0.1.jdk/Contents/Home 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 46ad328..5f37520 100644 --- a/src/main/java/com/github/sidhant92/boolparser/application/BooleanExpressionEvaluator.java +++ b/src/main/java/com/github/sidhant92/boolparser/application/BooleanExpressionEvaluator.java @@ -9,6 +9,7 @@ import com.github.sidhant92.boolparser.domain.Node; import com.github.sidhant92.boolparser.domain.NumericRangeToken; import com.github.sidhant92.boolparser.domain.NumericToken; +import com.github.sidhant92.boolparser.domain.ReverseAllMatchToken; import com.github.sidhant92.boolparser.domain.StringToken; import com.github.sidhant92.boolparser.operator.OperatorService; import com.github.sidhant92.boolparser.parser.BoolExpressionParser; @@ -45,6 +46,8 @@ private boolean evaluateNode(final Node node, final Map data) { return evaluateNumericRangeToken((NumericRangeToken) node, data); case BOOL_EXPRESSION: return evaluateBooleanNode((BoolExpression) node, data); + case REVERSE_ALL_MATCH_TOKEN: + return evaluateReverseAllMatchToken((ReverseAllMatchToken) node, data); default: return false; } @@ -78,6 +81,15 @@ private boolean evaluateNumericRangeToken(final NumericRangeToken numericRangeTo numericRangeToken.getToValue()); } + private boolean evaluateReverseAllMatchToken(final ReverseAllMatchToken token, final Map data) { + if (checkFieldDataMissing(token.getField(), data)) { + return false; + } + final Object fieldData = data.get(token.getField()); + return operatorService.evaluate(Operator.REVERSE_MATCH_ALL, ContainerDataType.set, token.getDataType(), fieldData, token.getValues()); + } + + private boolean evaluateBooleanNode(final BoolExpression boolExpression, final Map data) { return (boolExpression.getOrOperations().stream().anyMatch(orOperation -> evaluateNode(orOperation, data)) || boolExpression.getOrOperations() .isEmpty()) && (boolExpression 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 234e764..6093df8 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.Optional; +import java.util.Set; +import com.fasterxml.jackson.databind.ObjectMapper; +import com.fasterxml.jackson.databind.type.CollectionType; import com.github.sidhant92.boolparser.datatype.DataTypeFactory; import lombok.AllArgsConstructor; import lombok.Getter; @@ -12,7 +17,7 @@ @Getter @AllArgsConstructor public enum ContainerDataType { - primitive() { + primitive(null) { @Override public Optional getValue(final DataType dataType, final Object value) { return DataTypeFactory.getDataType(dataType).getValue(value); @@ -22,8 +27,56 @@ public Optional getValue(final DataType dataType, final Object value) { public boolean isValid(final DataType dataType, final Object value) { return DataTypeFactory.getDataType(dataType).isValid(value); } + }, + set(Set.class) { + @Override + public Optional> getValue(final DataType dataType, final Object value) { + final CollectionType collectionType = objectMapper.getTypeFactory().constructCollectionType(this.getClassType(), + DataTypeFactory.getDataType(dataType).getClassType()); + Set valueSet = objectMapper.convertValue(value, collectionType); + return Optional.ofNullable(valueSet); + } + + @Override + public boolean isValid(final DataType dataType, final Object value) { + return isValidCollectionType(dataType, value); + } + }, + list(List.class) { + @Override + public Optional> getValue(final DataType dataType, final Object value) { + final CollectionType collectionType = objectMapper.getTypeFactory().constructCollectionType(this.getClassType(), + DataTypeFactory.getDataType(dataType).getClassType()); + List valueSet = objectMapper.convertValue(value, collectionType); + return Optional.ofNullable(valueSet); + } + + @Override + public boolean isValid(final DataType dataType, final Object value) { + return isValidCollectionType(dataType, value); + } }; + private static ObjectMapper objectMapper; + + private Class classType; + + public static void init(final ObjectMapper objectMapper) { + ContainerDataType.objectMapper = objectMapper; + } + + protected boolean isValidCollectionType(final DataType dataType, final Object value) { + try { + final CollectionType collectionType = objectMapper.getTypeFactory().constructCollectionType(getClassType(), + DataTypeFactory.getDataType(dataType).getClassType()); + Collection collection = objectMapper.convertValue(value, collectionType); + return collection != null && collection.stream().allMatch(DataTypeFactory.getDataType(dataType)::isValid); + + } catch (final Exception ex) { + return false; + } + } + public abstract Optional getValue(final DataType dataType, final Object value); public abstract boolean isValid(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 74ca9f2..bade548 100644 --- a/src/main/java/com/github/sidhant92/boolparser/constant/NodeType.java +++ b/src/main/java/com/github/sidhant92/boolparser/constant/NodeType.java @@ -8,5 +8,6 @@ public enum NodeType { BOOL_EXPRESSION, STRING_TOKEN, NUMERIC_TOKEN, - NUMERIC_RANGE_TOKEN + NUMERIC_RANGE_TOKEN, + REVERSE_ALL_MATCH_TOKEN } 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 34596cc..b5267cd 100644 --- a/src/main/java/com/github/sidhant92/boolparser/constant/Operator.java +++ b/src/main/java/com/github/sidhant92/boolparser/constant/Operator.java @@ -21,10 +21,10 @@ public enum Operator { GREATER_THAN_EQUAL, LESS_THAN, LESS_THAN_EQUAL, - NOT_EQUAL; + NOT_EQUAL, + REVERSE_MATCH_ALL; public static Optional getOperatorFromSymbol(final String symbol) { - final List abc = OperatorFactory.getAllOperators(); return OperatorFactory.getAllOperators().stream().filter(operator -> operator.getSymbol().equals(symbol)).map(AbstractOperator::getOperator) .findFirst(); } 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 1d2a982..09134b6 100644 --- a/src/main/java/com/github/sidhant92/boolparser/datatype/AbstractDataType.java +++ b/src/main/java/com/github/sidhant92/boolparser/datatype/AbstractDataType.java @@ -40,4 +40,8 @@ public Optional defaultGetValue(final Object value, final ObjectMapper object public abstract boolean isValid(final Object value); public abstract Optional getValue(final Object value); + + public Class getClassType() { + return clazz; + } } diff --git a/src/main/java/com/github/sidhant92/boolparser/datatype/DataTypeFactory.java b/src/main/java/com/github/sidhant92/boolparser/datatype/DataTypeFactory.java index e56abd9..3ff0f27 100644 --- a/src/main/java/com/github/sidhant92/boolparser/datatype/DataTypeFactory.java +++ b/src/main/java/com/github/sidhant92/boolparser/datatype/DataTypeFactory.java @@ -3,6 +3,7 @@ import java.util.EnumMap; import java.util.Map; import com.fasterxml.jackson.databind.ObjectMapper; +import com.github.sidhant92.boolparser.constant.ContainerDataType; import com.github.sidhant92.boolparser.constant.DataType; /** @@ -18,6 +19,7 @@ private DataTypeFactory() { public static void initialize() { final ObjectMapper objectMapper = new ObjectMapper(); + ContainerDataType.init(objectMapper); abstractDataTypeMap.put(DataType.STRING, new StringDataType(objectMapper)); abstractDataTypeMap.put(DataType.INTEGER, new IntegerDataType(objectMapper)); abstractDataTypeMap.put(DataType.DECIMAL, new DecimalDataType(objectMapper)); diff --git a/src/main/java/com/github/sidhant92/boolparser/domain/ReverseAllMatchToken.java b/src/main/java/com/github/sidhant92/boolparser/domain/ReverseAllMatchToken.java new file mode 100644 index 0000000..8ab6527 --- /dev/null +++ b/src/main/java/com/github/sidhant92/boolparser/domain/ReverseAllMatchToken.java @@ -0,0 +1,26 @@ +package com.github.sidhant92.boolparser.domain; + +import java.util.List; +import com.github.sidhant92.boolparser.constant.DataType; +import com.github.sidhant92.boolparser.constant.NodeType; +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Getter; +import lombok.Setter; + +@AllArgsConstructor +@Getter +@Setter +@Builder +public class ReverseAllMatchToken extends Node{ + final String field; + + final List values; + + final DataType dataType; + + @Override + public NodeType getNodeType() { + return NodeType.REVERSE_ALL_MATCH_TOKEN; + } +} diff --git a/src/main/java/com/github/sidhant92/boolparser/operator/OperatorFactory.java b/src/main/java/com/github/sidhant92/boolparser/operator/OperatorFactory.java index 9a9e24d..3a0e3cb 100644 --- a/src/main/java/com/github/sidhant92/boolparser/operator/OperatorFactory.java +++ b/src/main/java/com/github/sidhant92/boolparser/operator/OperatorFactory.java @@ -24,6 +24,7 @@ public static void initialize() { operatorMap.put(Operator.LESS_THAN, new LessThanOperator()); operatorMap.put(Operator.LESS_THAN_EQUAL, new LessThanEqualOperator()); operatorMap.put(Operator.NOT_EQUAL, new NotEqualsOperator()); + operatorMap.put(Operator.REVERSE_MATCH_ALL, new ReverseMatchAllOperator()); } public static AbstractOperator getOperator(final Operator operator) { diff --git a/src/main/java/com/github/sidhant92/boolparser/operator/ReverseMatchAllOperator.java b/src/main/java/com/github/sidhant92/boolparser/operator/ReverseMatchAllOperator.java new file mode 100644 index 0000000..4e45d56 --- /dev/null +++ b/src/main/java/com/github/sidhant92/boolparser/operator/ReverseMatchAllOperator.java @@ -0,0 +1,30 @@ +package com.github.sidhant92.boolparser.operator; + +import java.util.Optional; +import java.util.Set; +import org.apache.commons.collections4.SetUtils; +import com.github.sidhant92.boolparser.constant.ContainerDataType; +import com.github.sidhant92.boolparser.constant.DataType; +import com.github.sidhant92.boolparser.constant.Operator; + +public class ReverseMatchAllOperator extends AbstractOperator { + @Override + public > boolean evaluate(final ContainerDataType containerDataType, final DataType dataType, + final Object leftOperand, final Object... rightOperands) { + assert containerDataType.getClassType() == Set.class; + final Optional> leftValueOptional = containerDataType.getValue(dataType, leftOperand); + final Optional> rightValueOptional = containerDataType.getValue(dataType, rightOperands[0]); + return leftValueOptional.flatMap(leftValue -> rightValueOptional.map(rightValue -> SetUtils.difference(leftValue, + rightValue).isEmpty())).orElse(false); + } + + @Override + public Operator getOperator() { + return Operator.REVERSE_MATCH_ALL; + } + + @Override + public String getSymbol() { + return "rev_all"; + } +} \ No newline at end of file diff --git a/src/main/java/com/github/sidhant92/boolparser/parser/canopy/Actions.java b/src/main/java/com/github/sidhant92/boolparser/parser/canopy/Actions.java index b709838..04c863f 100644 --- a/src/main/java/com/github/sidhant92/boolparser/parser/canopy/Actions.java +++ b/src/main/java/com/github/sidhant92/boolparser/parser/canopy/Actions.java @@ -12,4 +12,6 @@ public interface Actions { TreeNode make_primary(String input, int start, int end, List elements); TreeNode make_string_list(String input, int start, int end, List elements); TreeNode make_string_token(String input, int start, int end, List elements); + TreeNode make_rev_all_decimal_list(String input, int start, int end, List elements); + TreeNode make_rev_all_string_list(String input, int start, int end, List elements); } diff --git a/src/main/java/com/github/sidhant92/boolparser/parser/canopy/ActionsImpl.java b/src/main/java/com/github/sidhant92/boolparser/parser/canopy/ActionsImpl.java index 9861313..99a077c 100644 --- a/src/main/java/com/github/sidhant92/boolparser/parser/canopy/ActionsImpl.java +++ b/src/main/java/com/github/sidhant92/boolparser/parser/canopy/ActionsImpl.java @@ -10,6 +10,7 @@ import com.github.sidhant92.boolparser.parser.canopy.domain.NumericRangeNode; import com.github.sidhant92.boolparser.parser.canopy.domain.NumericNode; import com.github.sidhant92.boolparser.parser.canopy.domain.BooleanNode; +import com.github.sidhant92.boolparser.parser.canopy.domain.ReverseAllMatchNode; import com.github.sidhant92.boolparser.parser.canopy.domain.StringNode; /** @@ -75,6 +76,7 @@ public TreeNode make_numeric_range_token(String input, int start, int end, List< return checkNotExpression(elements, numericRangeNode); } + @Override public TreeNode make_primary(String input, int start, int end, List elements) { return elements.get(1); } @@ -106,6 +108,7 @@ private String getCapturedString(final String input) { } } + @Override public TreeNode make_logical_and(String input, int start, int end, List elements) { BooleanNode booleanNode = new BooleanNode(); if (elements.get(1).iterator().hasNext()) { @@ -121,6 +124,7 @@ public TreeNode make_logical_and(String input, int start, int end, List elements) { BooleanNode booleanNode = new BooleanNode(); if (elements.get(0) instanceof BooleanNode) { @@ -145,6 +149,7 @@ public TreeNode make_logical_or(String input, int start, int end, List } } + @Override public TreeNode make_decimal_list(String input, int start, int end, List elements) { final BooleanNode booleanNode = new BooleanNode(); final List list = Arrays.stream(elements.get(7).text.split(",")).map(String::trim).collect(Collectors.toList()); @@ -188,6 +193,7 @@ private Optional parseInteger(final String number) { } } + @Override public TreeNode make_string_list(String input, int start, int end, List elements) { final BooleanNode booleanNode = new BooleanNode(); final List list = getAllAlphanumericTokens(elements.get(7)); @@ -202,4 +208,20 @@ private List getAllAlphanumericTokens(final TreeNode treeNode) { treeNode.elements.forEach(node -> tokens.addAll(getAllAlphanumericTokens(node))); return tokens; } + + @Override + public TreeNode make_rev_all_decimal_list(String input, int start, int end, List elements) { + final List list = Arrays.stream(elements.get(7).text.split(",")).map(String::trim).collect(Collectors.toList()); + final DataType dataType = findNumericDataTypeForList(list); + final List data = list.stream().map(d -> getValue(d, dataType)).collect(Collectors.toList()); + final ReverseAllMatchNode node = new ReverseAllMatchNode(elements.get(2).text, data, dataType); + return checkNotExpression(elements, node); + } + + @Override + public TreeNode make_rev_all_string_list(String input, int start, int end, List elements) { + final List list = getAllAlphanumericTokens(elements.get(7)); + final ReverseAllMatchNode node = new ReverseAllMatchNode(elements.get(2).text, Arrays.asList(list.toArray()), DataType.STRING); + return checkNotExpression(elements, node); + } } diff --git a/src/main/java/com/github/sidhant92/boolparser/parser/canopy/ExpressionMapper.java b/src/main/java/com/github/sidhant92/boolparser/parser/canopy/ExpressionMapper.java index b91d7ff..04ea2ec 100644 --- a/src/main/java/com/github/sidhant92/boolparser/parser/canopy/ExpressionMapper.java +++ b/src/main/java/com/github/sidhant92/boolparser/parser/canopy/ExpressionMapper.java @@ -4,10 +4,14 @@ import com.github.sidhant92.boolparser.constant.Operator; import com.github.sidhant92.boolparser.domain.BoolExpression; import com.github.sidhant92.boolparser.domain.Node; +import com.github.sidhant92.boolparser.domain.NumericRangeToken; +import com.github.sidhant92.boolparser.domain.NumericToken; +import com.github.sidhant92.boolparser.domain.ReverseAllMatchToken; import com.github.sidhant92.boolparser.domain.StringToken; import com.github.sidhant92.boolparser.parser.canopy.domain.NumericRangeNode; import com.github.sidhant92.boolparser.parser.canopy.domain.NumericNode; import com.github.sidhant92.boolparser.parser.canopy.domain.BooleanNode; +import com.github.sidhant92.boolparser.parser.canopy.domain.ReverseAllMatchNode; import com.github.sidhant92.boolparser.parser.canopy.domain.StringNode; /** @@ -48,6 +52,9 @@ Node identifyAndMapToNode(final TreeNode treeNode) { } else if (treeNode instanceof NumericRangeNode) { final NumericRangeNode numericRangeNode = (NumericRangeNode) treeNode; return mapToNumericRangeToken(numericRangeNode); + } else if (treeNode instanceof ReverseAllMatchNode) { + final ReverseAllMatchNode reverseAllMatchNode = (ReverseAllMatchNode) treeNode; + return mapToReverseAllMatchToken(reverseAllMatchNode); } else { return processBooleanExpression((BooleanNode) treeNode); } @@ -57,18 +64,22 @@ private StringToken mapToStringToken(final StringNode stringNode) { return new StringToken(stringNode.getField(), stringNode.getValue()); } - private com.github.sidhant92.boolparser.domain.NumericToken mapToNumericToken(final NumericNode token) { - return com.github.sidhant92.boolparser.domain.NumericToken.builder().field(token.getField()).value(token.getValue()) + private NumericToken mapToNumericToken(final NumericNode token) { + return NumericToken.builder().field(token.getField()).value(token.getValue()) .dataType(token.getDataType()) .operator(Operator.getOperatorFromSymbol(token.getOperator()).orElse(null)).build(); } - private com.github.sidhant92.boolparser.domain.NumericRangeToken mapToNumericRangeToken(final NumericRangeNode token) { - return com.github.sidhant92.boolparser.domain.NumericRangeToken.builder().field(token.getField()).fromValue(token.getFromValue()) + private NumericRangeToken mapToNumericRangeToken(final NumericRangeNode token) { + return NumericRangeToken.builder().field(token.getField()).fromValue(token.getFromValue()) .fromDataType(token.getFromDataType()).toValue(token.getToValue()) .toDataType(token.getToDataType()).build(); } + private ReverseAllMatchToken mapToReverseAllMatchToken(final ReverseAllMatchNode token) { + return ReverseAllMatchToken.builder().dataType(token.getDataType()).field(token.getField()).values(token.getValues()).build(); + } + Node getFilterQuery(final BooleanNode booleanNode) { if (booleanNode.getAndQueries().size() == 1 && booleanNode.getOrQueries().isEmpty() && booleanNode.getNotQueries().isEmpty()) { return identifyAndMapToNode(booleanNode.getAndQueries().get(0)); diff --git a/src/main/java/com/github/sidhant92/boolparser/parser/canopy/Grammar.java b/src/main/java/com/github/sidhant92/boolparser/parser/canopy/Grammar.java index 570a06a..96da83f 100644 --- a/src/main/java/com/github/sidhant92/boolparser/parser/canopy/Grammar.java +++ b/src/main/java/com/github/sidhant92/boolparser/parser/canopy/Grammar.java @@ -324,7 +324,7 @@ TreeNode _read_primary() { TreeNode address1 = FAILURE; String chunk0 = null; if (offset < inputSize) { - chunk0 = input.substring(offset, Math.min(offset + 1, input.length())); + chunk0 = input.substring(offset, offset + 1); } if (chunk0 != null && chunk0.equals("(")) { address1 = new TreeNode(input.substring(offset, offset + 1), offset); @@ -348,7 +348,7 @@ TreeNode _read_primary() { TreeNode address3 = FAILURE; String chunk1 = null; if (offset < inputSize) { - chunk1 = input.substring(offset, Math.min(offset + 1, input.length())); + chunk1 = input.substring(offset, offset + 1); } if (chunk1 != null && chunk1.equals(")")) { address3 = new TreeNode(input.substring(offset, offset + 1), offset); @@ -411,7 +411,7 @@ TreeNode _read_token() { int index3 = offset; String chunk0 = null; if (offset < inputSize) { - chunk0 = input.substring(offset, Math.min(offset + 3, input.length())); + chunk0 = input.substring(offset, offset + 3); } if (chunk0 != null && chunk0.equals("NOT")) { address1 = new TreeNode(input.substring(offset, offset + 3), offset); @@ -479,7 +479,7 @@ TreeNode _read_token() { TreeNode address7 = FAILURE; String chunk1 = null; if (offset < inputSize) { - chunk1 = input.substring(offset, Math.min(offset + 1, input.length())); + chunk1 = input.substring(offset, offset + 1); } if (chunk1 != null && chunk1.equals("=")) { address7 = new TreeNode(input.substring(offset, offset + 1), offset); @@ -562,7 +562,7 @@ TreeNode _read_token() { int index8 = offset; String chunk2 = null; if (offset < inputSize) { - chunk2 = input.substring(offset, Math.min(offset + 3, input.length())); + chunk2 = input.substring(offset, offset + 3); } if (chunk2 != null && chunk2.equals("NOT")) { address11 = new TreeNode(input.substring(offset, offset + 3), offset); @@ -630,7 +630,7 @@ TreeNode _read_token() { TreeNode address17 = FAILURE; String chunk3 = null; if (offset < inputSize) { - chunk3 = input.substring(offset, Math.min(offset + 1, input.length())); + chunk3 = input.substring(offset, offset + 1); } if (chunk3 != null && chunk3.equals(">")) { address17 = new TreeNode(input.substring(offset, offset + 1), offset); @@ -713,7 +713,7 @@ TreeNode _read_token() { int index13 = offset; String chunk4 = null; if (offset < inputSize) { - chunk4 = input.substring(offset, Math.min(offset + 3, input.length())); + chunk4 = input.substring(offset, offset + 3); } if (chunk4 != null && chunk4.equals("NOT")) { address21 = new TreeNode(input.substring(offset, offset + 3), offset); @@ -781,7 +781,7 @@ TreeNode _read_token() { TreeNode address27 = FAILURE; String chunk5 = null; if (offset < inputSize) { - chunk5 = input.substring(offset, Math.min(offset + 2, input.length())); + chunk5 = input.substring(offset, offset + 2); } if (chunk5 != null && chunk5.equals(">=")) { address27 = new TreeNode(input.substring(offset, offset + 2), offset); @@ -864,7 +864,7 @@ TreeNode _read_token() { int index18 = offset; String chunk6 = null; if (offset < inputSize) { - chunk6 = input.substring(offset, Math.min(offset + 3, input.length())); + chunk6 = input.substring(offset, offset + 3); } if (chunk6 != null && chunk6.equals("NOT")) { address31 = new TreeNode(input.substring(offset, offset + 3), offset); @@ -932,7 +932,7 @@ TreeNode _read_token() { TreeNode address37 = FAILURE; String chunk7 = null; if (offset < inputSize) { - chunk7 = input.substring(offset, Math.min(offset + 1, input.length())); + chunk7 = input.substring(offset, offset + 1); } if (chunk7 != null && chunk7.equals("<")) { address37 = new TreeNode(input.substring(offset, offset + 1), offset); @@ -1015,7 +1015,7 @@ TreeNode _read_token() { int index23 = offset; String chunk8 = null; if (offset < inputSize) { - chunk8 = input.substring(offset, Math.min(offset + 3, input.length())); + chunk8 = input.substring(offset, offset + 3); } if (chunk8 != null && chunk8.equals("NOT")) { address41 = new TreeNode(input.substring(offset, offset + 3), offset); @@ -1083,7 +1083,7 @@ TreeNode _read_token() { TreeNode address47 = FAILURE; String chunk9 = null; if (offset < inputSize) { - chunk9 = input.substring(offset, Math.min(offset + 2, input.length())); + chunk9 = input.substring(offset, offset + 2); } if (chunk9 != null && chunk9.equals("<=")) { address47 = new TreeNode(input.substring(offset, offset + 2), offset); @@ -1166,7 +1166,7 @@ TreeNode _read_token() { int index28 = offset; String chunk10 = null; if (offset < inputSize) { - chunk10 = input.substring(offset, Math.min(offset + 3, input.length())); + chunk10 = input.substring(offset, offset + 3); } if (chunk10 != null && chunk10.equals("NOT")) { address51 = new TreeNode(input.substring(offset, offset + 3), offset); @@ -1234,7 +1234,7 @@ TreeNode _read_token() { TreeNode address57 = FAILURE; String chunk11 = null; if (offset < inputSize) { - chunk11 = input.substring(offset, Math.min(offset + 1, input.length())); + chunk11 = input.substring(offset, offset + 1); } if (chunk11 != null && chunk11.equals(">")) { address57 = new TreeNode(input.substring(offset, offset + 1), offset); @@ -1317,7 +1317,7 @@ TreeNode _read_token() { int index33 = offset; String chunk12 = null; if (offset < inputSize) { - chunk12 = input.substring(offset, Math.min(offset + 3, input.length())); + chunk12 = input.substring(offset, offset + 3); } if (chunk12 != null && chunk12.equals("NOT")) { address61 = new TreeNode(input.substring(offset, offset + 3), offset); @@ -1385,7 +1385,7 @@ TreeNode _read_token() { TreeNode address67 = FAILURE; String chunk13 = null; if (offset < inputSize) { - chunk13 = input.substring(offset, Math.min(offset + 2, input.length())); + chunk13 = input.substring(offset, offset + 2); } if (chunk13 != null && chunk13.equals(">=")) { address67 = new TreeNode(input.substring(offset, offset + 2), offset); @@ -1468,7 +1468,7 @@ TreeNode _read_token() { int index38 = offset; String chunk14 = null; if (offset < inputSize) { - chunk14 = input.substring(offset, Math.min(offset + 3, input.length())); + chunk14 = input.substring(offset, offset + 3); } if (chunk14 != null && chunk14.equals("NOT")) { address71 = new TreeNode(input.substring(offset, offset + 3), offset); @@ -1536,7 +1536,7 @@ TreeNode _read_token() { TreeNode address77 = FAILURE; String chunk15 = null; if (offset < inputSize) { - chunk15 = input.substring(offset, Math.min(offset + 1, input.length())); + chunk15 = input.substring(offset, offset + 1); } if (chunk15 != null && chunk15.equals("<")) { address77 = new TreeNode(input.substring(offset, offset + 1), offset); @@ -1619,7 +1619,7 @@ TreeNode _read_token() { int index43 = offset; String chunk16 = null; if (offset < inputSize) { - chunk16 = input.substring(offset, Math.min(offset + 3, input.length())); + chunk16 = input.substring(offset, offset + 3); } if (chunk16 != null && chunk16.equals("NOT")) { address81 = new TreeNode(input.substring(offset, offset + 3), offset); @@ -1687,7 +1687,7 @@ TreeNode _read_token() { TreeNode address87 = FAILURE; String chunk17 = null; if (offset < inputSize) { - chunk17 = input.substring(offset, Math.min(offset + 2, input.length())); + chunk17 = input.substring(offset, offset + 2); } if (chunk17 != null && chunk17.equals("<=")) { address87 = new TreeNode(input.substring(offset, offset + 2), offset); @@ -1770,7 +1770,7 @@ TreeNode _read_token() { int index48 = offset; String chunk18 = null; if (offset < inputSize) { - chunk18 = input.substring(offset, Math.min(offset + 3, input.length())); + chunk18 = input.substring(offset, offset + 3); } if (chunk18 != null && chunk18.equals("NOT")) { address91 = new TreeNode(input.substring(offset, offset + 3), offset); @@ -1838,7 +1838,7 @@ TreeNode _read_token() { TreeNode address97 = FAILURE; String chunk19 = null; if (offset < inputSize) { - chunk19 = input.substring(offset, Math.min(offset + 2, input.length())); + chunk19 = input.substring(offset, offset + 2); } if (chunk19 != null && chunk19.equals("!=")) { address97 = new TreeNode(input.substring(offset, offset + 2), offset); @@ -1921,7 +1921,7 @@ TreeNode _read_token() { int index53 = offset; String chunk20 = null; if (offset < inputSize) { - chunk20 = input.substring(offset, Math.min(offset + 3, input.length())); + chunk20 = input.substring(offset, offset + 3); } if (chunk20 != null && chunk20.equals("NOT")) { address101 = new TreeNode(input.substring(offset, offset + 3), offset); @@ -1989,7 +1989,7 @@ TreeNode _read_token() { TreeNode address107 = FAILURE; String chunk21 = null; if (offset < inputSize) { - chunk21 = input.substring(offset, Math.min(offset + 1, input.length())); + chunk21 = input.substring(offset, offset + 1); } if (chunk21 != null && chunk21.equals(":")) { address107 = new TreeNode(input.substring(offset, offset + 1), offset); @@ -2054,7 +2054,7 @@ TreeNode _read_token() { int index58 = offset; String chunk22 = null; if (offset < inputSize) { - chunk22 = input.substring(offset, Math.min(offset + 2, input.length())); + chunk22 = input.substring(offset, offset + 2); } if (chunk22 != null && chunk22.equals("TO")) { address113 = new TreeNode(input.substring(offset, offset + 2), offset); @@ -2073,7 +2073,7 @@ TreeNode _read_token() { offset = index58; String chunk23 = null; if (offset < inputSize) { - chunk23 = input.substring(offset, Math.min(offset + 2, input.length())); + chunk23 = input.substring(offset, offset + 2); } if (chunk23 != null && chunk23.equals("to")) { address113 = new TreeNode(input.substring(offset, offset + 2), offset); @@ -2176,7 +2176,7 @@ TreeNode _read_token() { int index61 = offset; String chunk24 = null; if (offset < inputSize) { - chunk24 = input.substring(offset, Math.min(offset + 3, input.length())); + chunk24 = input.substring(offset, offset + 3); } if (chunk24 != null && chunk24.equals("NOT")) { address117 = new TreeNode(input.substring(offset, offset + 3), offset); @@ -2244,7 +2244,7 @@ TreeNode _read_token() { TreeNode address123 = FAILURE; String chunk25 = null; if (offset < inputSize) { - chunk25 = input.substring(offset, Math.min(offset + 1, input.length())); + chunk25 = input.substring(offset, offset + 1); } if (chunk25 != null && chunk25.equals(":")) { address123 = new TreeNode(input.substring(offset, offset + 1), offset); @@ -2327,7 +2327,7 @@ TreeNode _read_token() { int index66 = offset; String chunk26 = null; if (offset < inputSize) { - chunk26 = input.substring(offset, Math.min(offset + 3, input.length())); + chunk26 = input.substring(offset, offset + 3); } if (chunk26 != null && chunk26.equals("NOT")) { address127 = new TreeNode(input.substring(offset, offset + 3), offset); @@ -2419,7 +2419,7 @@ TreeNode _read_token() { TreeNode address136 = FAILURE; String chunk27 = null; if (offset < inputSize) { - chunk27 = input.substring(offset, Math.min(offset + 1, input.length())); + chunk27 = input.substring(offset, offset + 1); } if (chunk27 != null && chunk27.equals("(")) { address136 = new TreeNode(input.substring(offset, offset + 1), offset); @@ -2443,7 +2443,7 @@ TreeNode _read_token() { TreeNode address138 = FAILURE; String chunk28 = null; if (offset < inputSize) { - chunk28 = input.substring(offset, Math.min(offset + 1, input.length())); + chunk28 = input.substring(offset, offset + 1); } if (chunk28 != null && chunk28.equals(")")) { address138 = new TreeNode(input.substring(offset, offset + 1), offset); @@ -2510,7 +2510,7 @@ TreeNode _read_token() { int index71 = offset; String chunk29 = null; if (offset < inputSize) { - chunk29 = input.substring(offset, Math.min(offset + 3, input.length())); + chunk29 = input.substring(offset, offset + 3); } if (chunk29 != null && chunk29.equals("NOT")) { address139 = new TreeNode(input.substring(offset, offset + 3), offset); @@ -2602,7 +2602,7 @@ TreeNode _read_token() { TreeNode address148 = FAILURE; String chunk30 = null; if (offset < inputSize) { - chunk30 = input.substring(offset, Math.min(offset + 1, input.length())); + chunk30 = input.substring(offset, offset + 1); } if (chunk30 != null && chunk30.equals("(")) { address148 = new TreeNode(input.substring(offset, offset + 1), offset); @@ -2626,7 +2626,7 @@ TreeNode _read_token() { TreeNode address150 = FAILURE; String chunk31 = null; if (offset < inputSize) { - chunk31 = input.substring(offset, Math.min(offset + 1, input.length())); + chunk31 = input.substring(offset, offset + 1); } if (chunk31 != null && chunk31.equals(")")) { address150 = new TreeNode(input.substring(offset, offset + 1), offset); @@ -2687,6 +2687,374 @@ TreeNode _read_token() { } if (address0 == FAILURE) { offset = index1; + int index75 = offset; + List elements58 = new ArrayList(9); + TreeNode address151 = FAILURE; + int index76 = offset; + String chunk32 = null; + if (offset < inputSize) { + chunk32 = input.substring(offset, offset + 3); + } + if (chunk32 != null && chunk32.equals("NOT")) { + address151 = new TreeNode(input.substring(offset, offset + 3), offset); + offset = offset + 3; + } else { + address151 = FAILURE; + if (offset > failure) { + failure = offset; + expected = new ArrayList(); + } + if (offset == failure) { + expected.add("\"NOT\""); + } + } + if (address151 == FAILURE) { + address151 = new TreeNode(input.substring(index76, index76), index76); + offset = index76; + } + if (address151 != FAILURE) { + elements58.add(0, address151); + TreeNode address152 = FAILURE; + int remaining44 = 0; + int index77 = offset; + List elements59 = new ArrayList(); + TreeNode address153 = new TreeNode("", -1); + while (address153 != FAILURE) { + address153 = _read_ws(); + if (address153 != FAILURE) { + elements59.add(address153); + --remaining44; + } + } + if (remaining44 <= 0) { + address152 = new TreeNode(input.substring(index77, offset), index77, elements59); + offset = offset; + } else { + address152 = FAILURE; + } + if (address152 != FAILURE) { + elements58.add(1, address152); + TreeNode address154 = FAILURE; + address154 = _read_alphanumeric(); + if (address154 != FAILURE) { + elements58.add(2, address154); + TreeNode address155 = FAILURE; + int remaining45 = 0; + int index78 = offset; + List elements60 = new ArrayList(); + TreeNode address156 = new TreeNode("", -1); + while (address156 != FAILURE) { + address156 = _read_ws(); + if (address156 != FAILURE) { + elements60.add(address156); + --remaining45; + } + } + if (remaining45 <= 0) { + address155 = new TreeNode(input.substring(index78, offset), index78, elements60); + offset = offset; + } else { + address155 = FAILURE; + } + if (address155 != FAILURE) { + elements58.add(3, address155); + TreeNode address157 = FAILURE; + address157 = _read_rev_all(); + if (address157 != FAILURE) { + elements58.add(4, address157); + TreeNode address158 = FAILURE; + int remaining46 = 0; + int index79 = offset; + List elements61 = new ArrayList(); + TreeNode address159 = new TreeNode("", -1); + while (address159 != FAILURE) { + address159 = _read_ws(); + if (address159 != FAILURE) { + elements61.add(address159); + --remaining46; + } + } + if (remaining46 <= 0) { + address158 = new TreeNode(input.substring(index79, offset), index79, elements61); + offset = offset; + } else { + address158 = FAILURE; + } + if (address158 != FAILURE) { + elements58.add(5, address158); + TreeNode address160 = FAILURE; + String chunk33 = null; + if (offset < inputSize) { + chunk33 = input.substring(offset, offset + 1); + } + if (chunk33 != null && chunk33.equals("(")) { + address160 = new TreeNode(input.substring(offset, offset + 1), offset); + offset = offset + 1; + } else { + address160 = FAILURE; + if (offset > failure) { + failure = offset; + expected = new ArrayList(); + } + if (offset == failure) { + expected.add("\"(\""); + } + } + if (address160 != FAILURE) { + elements58.add(6, address160); + TreeNode address161 = FAILURE; + address161 = _read_number_list(); + if (address161 != FAILURE) { + elements58.add(7, address161); + TreeNode address162 = FAILURE; + String chunk34 = null; + if (offset < inputSize) { + chunk34 = input.substring(offset, offset + 1); + } + if (chunk34 != null && chunk34.equals(")")) { + address162 = new TreeNode(input.substring(offset, offset + 1), offset); + offset = offset + 1; + } else { + address162 = FAILURE; + if (offset > failure) { + failure = offset; + expected = new ArrayList(); + } + if (offset == failure) { + expected.add("\")\""); + } + } + if (address162 != FAILURE) { + elements58.add(8, address162); + } else { + elements58 = null; + offset = index75; + } + } else { + elements58 = null; + offset = index75; + } + } else { + elements58 = null; + offset = index75; + } + } else { + elements58 = null; + offset = index75; + } + } else { + elements58 = null; + offset = index75; + } + } else { + elements58 = null; + offset = index75; + } + } else { + elements58 = null; + offset = index75; + } + } else { + elements58 = null; + offset = index75; + } + } else { + elements58 = null; + offset = index75; + } + if (elements58 == null) { + address0 = FAILURE; + } else { + address0 = actions.make_rev_all_decimal_list(input, index75, offset, elements58); + offset = offset; + } + if (address0 == FAILURE) { + offset = index1; + int index80 = offset; + List elements62 = new ArrayList(9); + TreeNode address163 = FAILURE; + int index81 = offset; + String chunk35 = null; + if (offset < inputSize) { + chunk35 = input.substring(offset, offset + 3); + } + if (chunk35 != null && chunk35.equals("NOT")) { + address163 = new TreeNode(input.substring(offset, offset + 3), offset); + offset = offset + 3; + } else { + address163 = FAILURE; + if (offset > failure) { + failure = offset; + expected = new ArrayList(); + } + if (offset == failure) { + expected.add("\"NOT\""); + } + } + if (address163 == FAILURE) { + address163 = new TreeNode(input.substring(index81, index81), index81); + offset = index81; + } + if (address163 != FAILURE) { + elements62.add(0, address163); + TreeNode address164 = FAILURE; + int remaining47 = 0; + int index82 = offset; + List elements63 = new ArrayList(); + TreeNode address165 = new TreeNode("", -1); + while (address165 != FAILURE) { + address165 = _read_ws(); + if (address165 != FAILURE) { + elements63.add(address165); + --remaining47; + } + } + if (remaining47 <= 0) { + address164 = new TreeNode(input.substring(index82, offset), index82, elements63); + offset = offset; + } else { + address164 = FAILURE; + } + if (address164 != FAILURE) { + elements62.add(1, address164); + TreeNode address166 = FAILURE; + address166 = _read_alphanumeric(); + if (address166 != FAILURE) { + elements62.add(2, address166); + TreeNode address167 = FAILURE; + int remaining48 = 0; + int index83 = offset; + List elements64 = new ArrayList(); + TreeNode address168 = new TreeNode("", -1); + while (address168 != FAILURE) { + address168 = _read_ws(); + if (address168 != FAILURE) { + elements64.add(address168); + --remaining48; + } + } + if (remaining48 <= 0) { + address167 = new TreeNode(input.substring(index83, offset), index83, elements64); + offset = offset; + } else { + address167 = FAILURE; + } + if (address167 != FAILURE) { + elements62.add(3, address167); + TreeNode address169 = FAILURE; + address169 = _read_rev_all(); + if (address169 != FAILURE) { + elements62.add(4, address169); + TreeNode address170 = FAILURE; + int remaining49 = 0; + int index84 = offset; + List elements65 = new ArrayList(); + TreeNode address171 = new TreeNode("", -1); + while (address171 != FAILURE) { + address171 = _read_ws(); + if (address171 != FAILURE) { + elements65.add(address171); + --remaining49; + } + } + if (remaining49 <= 0) { + address170 = new TreeNode(input.substring(index84, offset), index84, elements65); + offset = offset; + } else { + address170 = FAILURE; + } + if (address170 != FAILURE) { + elements62.add(5, address170); + TreeNode address172 = FAILURE; + String chunk36 = null; + if (offset < inputSize) { + chunk36 = input.substring(offset, offset + 1); + } + if (chunk36 != null && chunk36.equals("(")) { + address172 = new TreeNode(input.substring(offset, offset + 1), offset); + offset = offset + 1; + } else { + address172 = FAILURE; + if (offset > failure) { + failure = offset; + expected = new ArrayList(); + } + if (offset == failure) { + expected.add("\"(\""); + } + } + if (address172 != FAILURE) { + elements62.add(6, address172); + TreeNode address173 = FAILURE; + address173 = _read_string_list(); + if (address173 != FAILURE) { + elements62.add(7, address173); + TreeNode address174 = FAILURE; + String chunk37 = null; + if (offset < inputSize) { + chunk37 = input.substring(offset, offset + 1); + } + if (chunk37 != null && chunk37.equals(")")) { + address174 = new TreeNode(input.substring(offset, offset + 1), offset); + offset = offset + 1; + } else { + address174 = FAILURE; + if (offset > failure) { + failure = offset; + expected = new ArrayList(); + } + if (offset == failure) { + expected.add("\")\""); + } + } + if (address174 != FAILURE) { + elements62.add(8, address174); + } else { + elements62 = null; + offset = index80; + } + } else { + elements62 = null; + offset = index80; + } + } else { + elements62 = null; + offset = index80; + } + } else { + elements62 = null; + offset = index80; + } + } else { + elements62 = null; + offset = index80; + } + } else { + elements62 = null; + offset = index80; + } + } else { + elements62 = null; + offset = index80; + } + } else { + elements62 = null; + offset = index80; + } + } else { + elements62 = null; + offset = index80; + } + if (elements62 == null) { + address0 = FAILURE; + } else { + address0 = actions.make_rev_all_string_list(input, index80, offset, elements62); + offset = offset; + } + if (address0 == FAILURE) { + offset = index1; + } + } } } } @@ -2803,7 +3171,7 @@ TreeNode _read_number_list() { if (elements0 == null) { address0 = FAILURE; } else { - address0 = new TreeNode20(input.substring(index1, offset), index1, elements0); + address0 = new TreeNode22(input.substring(index1, offset), index1, elements0); offset = offset; } rule.put(index0, new CacheRecord(address0, offset)); @@ -2828,7 +3196,7 @@ TreeNode _read_number_list_token() { TreeNode address1 = FAILURE; String chunk0 = null; if (offset < inputSize) { - chunk0 = input.substring(offset, Math.min(offset + 1, input.length())); + chunk0 = input.substring(offset, offset + 1); } if (chunk0 != null && chunk0.equals(",")) { address1 = new TreeNode(input.substring(offset, offset + 1), offset); @@ -2908,7 +3276,7 @@ TreeNode _read_number_list_token() { if (elements0 == null) { address0 = FAILURE; } else { - address0 = new TreeNode21(input.substring(index1, offset), index1, elements0); + address0 = new TreeNode23(input.substring(index1, offset), index1, elements0); offset = offset; } rule.put(index0, new CacheRecord(address0, offset)); @@ -3013,7 +3381,7 @@ TreeNode _read_string_list() { if (elements0 == null) { address0 = FAILURE; } else { - address0 = new TreeNode22(input.substring(index1, offset), index1, elements0); + address0 = new TreeNode24(input.substring(index1, offset), index1, elements0); offset = offset; } rule.put(index0, new CacheRecord(address0, offset)); @@ -3038,7 +3406,7 @@ TreeNode _read_string_list_token() { TreeNode address1 = FAILURE; String chunk0 = null; if (offset < inputSize) { - chunk0 = input.substring(offset, Math.min(offset + 1, input.length())); + chunk0 = input.substring(offset, offset + 1); } if (chunk0 != null && chunk0.equals(",")) { address1 = new TreeNode(input.substring(offset, offset + 1), offset); @@ -3118,7 +3486,7 @@ TreeNode _read_string_list_token() { if (elements0 == null) { address0 = FAILURE; } else { - address0 = new TreeNode23(input.substring(index1, offset), index1, elements0); + address0 = new TreeNode25(input.substring(index1, offset), index1, elements0); offset = offset; } rule.put(index0, new CacheRecord(address0, offset)); @@ -3148,7 +3516,7 @@ TreeNode _read_app_version() { while (address2 != FAILURE) { String chunk0 = null; if (offset < inputSize) { - chunk0 = input.substring(offset, Math.min(offset + 1, input.length())); + chunk0 = input.substring(offset, offset + 1); } if (chunk0 != null && REGEX_1.matcher(chunk0).matches()) { address2 = new TreeNode(input.substring(offset, offset + 1), offset); @@ -3179,7 +3547,7 @@ TreeNode _read_app_version() { TreeNode address3 = FAILURE; String chunk1 = null; if (offset < inputSize) { - chunk1 = input.substring(offset, Math.min(offset + 1, input.length())); + chunk1 = input.substring(offset, offset + 1); } if (chunk1 != null && chunk1.equals(".")) { address3 = new TreeNode(input.substring(offset, offset + 1), offset); @@ -3204,7 +3572,7 @@ TreeNode _read_app_version() { while (address5 != FAILURE) { String chunk2 = null; if (offset < inputSize) { - chunk2 = input.substring(offset, Math.min(offset + 1, input.length())); + chunk2 = input.substring(offset, offset + 1); } if (chunk2 != null && REGEX_2.matcher(chunk2).matches()) { address5 = new TreeNode(input.substring(offset, offset + 1), offset); @@ -3296,7 +3664,7 @@ TreeNode _read_app_version_token() { TreeNode address1 = FAILURE; String chunk0 = null; if (offset < inputSize) { - chunk0 = input.substring(offset, Math.min(offset + 1, input.length())); + chunk0 = input.substring(offset, offset + 1); } if (chunk0 != null && chunk0.equals(".")) { address1 = new TreeNode(input.substring(offset, offset + 1), offset); @@ -3321,7 +3689,7 @@ TreeNode _read_app_version_token() { while (address3 != FAILURE) { String chunk1 = null; if (offset < inputSize) { - chunk1 = input.substring(offset, Math.min(offset + 1, input.length())); + chunk1 = input.substring(offset, offset + 1); } if (chunk1 != null && REGEX_3.matcher(chunk1).matches()) { address3 = new TreeNode(input.substring(offset, offset + 1), offset); @@ -3388,7 +3756,7 @@ TreeNode _read_alphanumeric() { while (address1 != FAILURE) { String chunk0 = null; if (offset < inputSize) { - chunk0 = input.substring(offset, Math.min(offset + 1, input.length())); + chunk0 = input.substring(offset, offset + 1); } if (chunk0 != null && REGEX_4.matcher(chunk0).matches()) { address1 = new TreeNode(input.substring(offset, offset + 1), offset); @@ -3426,7 +3794,7 @@ TreeNode _read_alphanumeric() { while (address3 != FAILURE) { String chunk1 = null; if (offset < inputSize) { - chunk1 = input.substring(offset, Math.min(offset + 1, input.length())); + chunk1 = input.substring(offset, offset + 1); } if (chunk1 != null && REGEX_5.matcher(chunk1).matches()) { address3 = new TreeNode(input.substring(offset, offset + 1), offset); @@ -3462,7 +3830,7 @@ TreeNode _read_alphanumeric() { while (address5 != FAILURE) { String chunk2 = null; if (offset < inputSize) { - chunk2 = input.substring(offset, Math.min(offset + 1, input.length())); + chunk2 = input.substring(offset, offset + 1); } if (chunk2 != null && REGEX_6.matcher(chunk2).matches()) { address5 = new TreeNode(input.substring(offset, offset + 1), offset); @@ -3498,7 +3866,7 @@ TreeNode _read_alphanumeric() { while (address7 != FAILURE) { String chunk3 = null; if (offset < inputSize) { - chunk3 = input.substring(offset, Math.min(offset + 1, input.length())); + chunk3 = input.substring(offset, offset + 1); } if (chunk3 != null && REGEX_7.matcher(chunk3).matches()) { address7 = new TreeNode(input.substring(offset, offset + 1), offset); @@ -3556,7 +3924,7 @@ TreeNode _read_alphanumeric() { while (address9 != FAILURE) { String chunk4 = null; if (offset < inputSize) { - chunk4 = input.substring(offset, Math.min(offset + 1, input.length())); + chunk4 = input.substring(offset, offset + 1); } if (chunk4 != null && REGEX_8.matcher(chunk4).matches()) { address9 = new TreeNode(input.substring(offset, offset + 1), offset); @@ -3592,7 +3960,7 @@ TreeNode _read_alphanumeric() { while (address11 != FAILURE) { String chunk5 = null; if (offset < inputSize) { - chunk5 = input.substring(offset, Math.min(offset + 1, input.length())); + chunk5 = input.substring(offset, offset + 1); } if (chunk5 != null && REGEX_9.matcher(chunk5).matches()) { address11 = new TreeNode(input.substring(offset, offset + 1), offset); @@ -3628,7 +3996,7 @@ TreeNode _read_alphanumeric() { while (address13 != FAILURE) { String chunk6 = null; if (offset < inputSize) { - chunk6 = input.substring(offset, Math.min(offset + 1, input.length())); + chunk6 = input.substring(offset, offset + 1); } if (chunk6 != null && REGEX_10.matcher(chunk6).matches()) { address13 = new TreeNode(input.substring(offset, offset + 1), offset); @@ -3706,7 +4074,7 @@ TreeNode _read_decimal() { while (address2 != FAILURE) { String chunk0 = null; if (offset < inputSize) { - chunk0 = input.substring(offset, Math.min(offset + 1, input.length())); + chunk0 = input.substring(offset, offset + 1); } if (chunk0 != null && REGEX_11.matcher(chunk0).matches()) { address2 = new TreeNode(input.substring(offset, offset + 1), offset); @@ -3738,7 +4106,7 @@ TreeNode _read_decimal() { int index3 = offset; String chunk1 = null; if (offset < inputSize) { - chunk1 = input.substring(offset, Math.min(offset + 1, input.length())); + chunk1 = input.substring(offset, offset + 1); } if (chunk1 != null && chunk1.equals(".")) { address3 = new TreeNode(input.substring(offset, offset + 1), offset); @@ -3767,7 +4135,7 @@ TreeNode _read_decimal() { while (address5 != FAILURE) { String chunk2 = null; if (offset < inputSize) { - chunk2 = input.substring(offset, Math.min(offset + 1, input.length())); + chunk2 = input.substring(offset, offset + 1); } if (chunk2 != null && REGEX_12.matcher(chunk2).matches()) { address5 = new TreeNode(input.substring(offset, offset + 1), offset); @@ -3833,7 +4201,7 @@ TreeNode _read_or() { int index1 = offset; String chunk0 = null; if (offset < inputSize) { - chunk0 = input.substring(offset, Math.min(offset + 2, input.length())); + chunk0 = input.substring(offset, offset + 2); } if (chunk0 != null && chunk0.equals("OR")) { address0 = new TreeNode(input.substring(offset, offset + 2), offset); @@ -3852,7 +4220,7 @@ TreeNode _read_or() { offset = index1; String chunk1 = null; if (offset < inputSize) { - chunk1 = input.substring(offset, Math.min(offset + 2, input.length())); + chunk1 = input.substring(offset, offset + 2); } if (chunk1 != null && chunk1.equals("or")) { address0 = new TreeNode(input.substring(offset, offset + 2), offset); @@ -3871,7 +4239,7 @@ TreeNode _read_or() { offset = index1; String chunk2 = null; if (offset < inputSize) { - chunk2 = input.substring(offset, Math.min(offset + 1, input.length())); + chunk2 = input.substring(offset, offset + 1); } if (chunk2 != null && chunk2.equals("|")) { address0 = new TreeNode(input.substring(offset, offset + 1), offset); @@ -3890,7 +4258,7 @@ TreeNode _read_or() { offset = index1; String chunk3 = null; if (offset < inputSize) { - chunk3 = input.substring(offset, Math.min(offset + 2, input.length())); + chunk3 = input.substring(offset, offset + 2); } if (chunk3 != null && chunk3.equals("||")) { address0 = new TreeNode(input.substring(offset, offset + 2), offset); @@ -3931,7 +4299,7 @@ TreeNode _read_and() { int index1 = offset; String chunk0 = null; if (offset < inputSize) { - chunk0 = input.substring(offset, Math.min(offset + 3, input.length())); + chunk0 = input.substring(offset, offset + 3); } if (chunk0 != null && chunk0.equals("AND")) { address0 = new TreeNode(input.substring(offset, offset + 3), offset); @@ -3950,7 +4318,7 @@ TreeNode _read_and() { offset = index1; String chunk1 = null; if (offset < inputSize) { - chunk1 = input.substring(offset, Math.min(offset + 3, input.length())); + chunk1 = input.substring(offset, offset + 3); } if (chunk1 != null && chunk1.equals("and")) { address0 = new TreeNode(input.substring(offset, offset + 3), offset); @@ -3969,7 +4337,7 @@ TreeNode _read_and() { offset = index1; String chunk2 = null; if (offset < inputSize) { - chunk2 = input.substring(offset, Math.min(offset + 1, input.length())); + chunk2 = input.substring(offset, offset + 1); } if (chunk2 != null && chunk2.equals("&")) { address0 = new TreeNode(input.substring(offset, offset + 1), offset); @@ -3988,7 +4356,7 @@ TreeNode _read_and() { offset = index1; String chunk3 = null; if (offset < inputSize) { - chunk3 = input.substring(offset, Math.min(offset + 2, input.length())); + chunk3 = input.substring(offset, offset + 2); } if (chunk3 != null && chunk3.equals("&&")) { address0 = new TreeNode(input.substring(offset, offset + 2), offset); @@ -4029,7 +4397,7 @@ TreeNode _read_operator() { int index1 = offset; String chunk0 = null; if (offset < inputSize) { - chunk0 = input.substring(offset, Math.min(offset + 1, input.length())); + chunk0 = input.substring(offset, offset + 1); } if (chunk0 != null && chunk0.equals("=")) { address0 = new TreeNode(input.substring(offset, offset + 1), offset); @@ -4048,7 +4416,7 @@ TreeNode _read_operator() { offset = index1; String chunk1 = null; if (offset < inputSize) { - chunk1 = input.substring(offset, Math.min(offset + 1, input.length())); + chunk1 = input.substring(offset, offset + 1); } if (chunk1 != null && chunk1.equals(">")) { address0 = new TreeNode(input.substring(offset, offset + 1), offset); @@ -4067,7 +4435,7 @@ TreeNode _read_operator() { offset = index1; String chunk2 = null; if (offset < inputSize) { - chunk2 = input.substring(offset, Math.min(offset + 2, input.length())); + chunk2 = input.substring(offset, offset + 2); } if (chunk2 != null && chunk2.equals(">=")) { address0 = new TreeNode(input.substring(offset, offset + 2), offset); @@ -4086,7 +4454,7 @@ TreeNode _read_operator() { offset = index1; String chunk3 = null; if (offset < inputSize) { - chunk3 = input.substring(offset, Math.min(offset + 1, input.length())); + chunk3 = input.substring(offset, offset + 1); } if (chunk3 != null && chunk3.equals("<")) { address0 = new TreeNode(input.substring(offset, offset + 1), offset); @@ -4105,7 +4473,7 @@ TreeNode _read_operator() { offset = index1; String chunk4 = null; if (offset < inputSize) { - chunk4 = input.substring(offset, Math.min(offset + 2, input.length())); + chunk4 = input.substring(offset, offset + 2); } if (chunk4 != null && chunk4.equals("<=")) { address0 = new TreeNode(input.substring(offset, offset + 2), offset); @@ -4124,7 +4492,7 @@ TreeNode _read_operator() { offset = index1; String chunk5 = null; if (offset < inputSize) { - chunk5 = input.substring(offset, Math.min(offset + 2, input.length())); + chunk5 = input.substring(offset, offset + 2); } if (chunk5 != null && chunk5.equals("!=")) { address0 = new TreeNode(input.substring(offset, offset + 2), offset); @@ -4167,7 +4535,7 @@ TreeNode _read_in() { int index1 = offset; String chunk0 = null; if (offset < inputSize) { - chunk0 = input.substring(offset, Math.min(offset + 2, input.length())); + chunk0 = input.substring(offset, offset + 2); } if (chunk0 != null && chunk0.equals("IN")) { address0 = new TreeNode(input.substring(offset, offset + 2), offset); @@ -4186,7 +4554,7 @@ TreeNode _read_in() { offset = index1; String chunk1 = null; if (offset < inputSize) { - chunk1 = input.substring(offset, Math.min(offset + 2, input.length())); + chunk1 = input.substring(offset, offset + 2); } if (chunk1 != null && chunk1.equals("in")) { address0 = new TreeNode(input.substring(offset, offset + 2), offset); @@ -4210,6 +4578,40 @@ TreeNode _read_in() { return address0; } + TreeNode _read_rev_all() { + TreeNode address0 = FAILURE; + int index0 = offset; + Map rule = cache.get(Label.rev_all); + if (rule == null) { + rule = new HashMap(); + cache.put(Label.rev_all, rule); + } + if (rule.containsKey(offset)) { + address0 = rule.get(offset).node; + offset = rule.get(offset).tail; + } else { + String chunk0 = null; + if (offset < inputSize) { + chunk0 = input.substring(offset, offset + 7); + } + if (chunk0 != null && chunk0.toLowerCase().equals("rev_all".toLowerCase())) { + address0 = new TreeNode(input.substring(offset, offset + 7), offset); + offset = offset + 7; + } else { + address0 = FAILURE; + if (offset > failure) { + failure = offset; + expected = new ArrayList(); + } + if (offset == failure) { + expected.add("`rev_all`"); + } + } + rule.put(index0, new CacheRecord(address0, offset)); + } + return address0; + } + TreeNode _read_ws() { TreeNode address0 = FAILURE; int index0 = offset; @@ -4224,7 +4626,7 @@ TreeNode _read_ws() { } else { String chunk0 = null; if (offset < inputSize) { - chunk0 = input.substring(offset, Math.min(offset + 1, input.length())); + chunk0 = input.substring(offset, offset + 1); } if (chunk0 != null && REGEX_13.matcher(chunk0).matches()) { address0 = new TreeNode(input.substring(offset, offset + 1), offset); diff --git a/src/main/java/com/github/sidhant92/boolparser/parser/canopy/Label.java b/src/main/java/com/github/sidhant92/boolparser/parser/canopy/Label.java index fd95ee2..5f28d99 100644 --- a/src/main/java/com/github/sidhant92/boolparser/parser/canopy/Label.java +++ b/src/main/java/com/github/sidhant92/boolparser/parser/canopy/Label.java @@ -14,6 +14,7 @@ public enum Label { operator, or, primary, + rev_all, start, string_list, string_list_token, diff --git a/src/main/java/com/github/sidhant92/boolparser/parser/canopy/TreeNode.java b/src/main/java/com/github/sidhant92/boolparser/parser/canopy/TreeNode.java index 9fe14f4..3a38ed5 100644 --- a/src/main/java/com/github/sidhant92/boolparser/parser/canopy/TreeNode.java +++ b/src/main/java/com/github/sidhant92/boolparser/parser/canopy/TreeNode.java @@ -190,26 +190,44 @@ class TreeNode19 extends TreeNode { class TreeNode20 extends TreeNode { TreeNode20(String text, int offset, List elements) { super(text, offset, elements); - labelled.put(Label.decimal, elements.get(1)); + labelled.put(Label.alphanumeric, elements.get(2)); + labelled.put(Label.rev_all, elements.get(4)); + labelled.put(Label.number_list, elements.get(7)); } } class TreeNode21 extends TreeNode { TreeNode21(String text, int offset, List elements) { super(text, offset, elements); - labelled.put(Label.decimal, elements.get(2)); + labelled.put(Label.alphanumeric, elements.get(2)); + labelled.put(Label.rev_all, elements.get(4)); + labelled.put(Label.string_list, elements.get(7)); } } class TreeNode22 extends TreeNode { TreeNode22(String text, int offset, List elements) { super(text, offset, elements); - labelled.put(Label.alphanumeric, elements.get(1)); + labelled.put(Label.decimal, elements.get(1)); } } class TreeNode23 extends TreeNode { TreeNode23(String text, int offset, List elements) { + super(text, offset, elements); + labelled.put(Label.decimal, elements.get(2)); + } +} + +class TreeNode24 extends TreeNode { + TreeNode24(String text, int offset, List elements) { + super(text, offset, elements); + labelled.put(Label.alphanumeric, elements.get(1)); + } +} + +class TreeNode25 extends TreeNode { + TreeNode25(String text, int offset, List elements) { super(text, offset, elements); labelled.put(Label.alphanumeric, elements.get(2)); } diff --git a/src/main/java/com/github/sidhant92/boolparser/parser/canopy/domain/ReverseAllMatchNode.java b/src/main/java/com/github/sidhant92/boolparser/parser/canopy/domain/ReverseAllMatchNode.java new file mode 100644 index 0000000..7c39a47 --- /dev/null +++ b/src/main/java/com/github/sidhant92/boolparser/parser/canopy/domain/ReverseAllMatchNode.java @@ -0,0 +1,17 @@ +package com.github.sidhant92.boolparser.parser.canopy.domain; + +import java.util.List; +import com.github.sidhant92.boolparser.constant.DataType; +import com.github.sidhant92.boolparser.parser.canopy.TreeNode; +import lombok.AllArgsConstructor; +import lombok.Getter; + +@AllArgsConstructor +@Getter +public class ReverseAllMatchNode extends TreeNode { + final String field; + + final List values; + + final DataType dataType; +} 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 11e0a4a..1e7307e 100644 --- a/src/test/java/com/github/sidhant92/boolparser/application/BooleanExpressionEvaluatorTest.java +++ b/src/test/java/com/github/sidhant92/boolparser/application/BooleanExpressionEvaluatorTest.java @@ -2,7 +2,9 @@ import static org.junit.jupiter.api.Assertions.assertFalse; import static org.junit.jupiter.api.Assertions.assertTrue; +import java.util.Arrays; import java.util.HashMap; +import java.util.List; import java.util.Map; import java.util.Optional; import org.junit.jupiter.api.Test; @@ -12,6 +14,26 @@ * @since 29/07/2020 */ public class BooleanExpressionEvaluatorTest { + @Test + public void testReverseAllMatchCorrectExpression() { + final BooleanExpressionEvaluator booleanExpressionEvaluator = new BooleanExpressionEvaluator(); + final Map data = new HashMap<>(); + data.put("age", List.of(1, 2)); + final Optional booleanOptional = booleanExpressionEvaluator.evaluate("age rev_all (1,2,4)", data); + assertTrue(booleanOptional.isPresent()); + assertTrue(booleanOptional.get()); + } + + @Test + public void testReverseAllMatchInCorrectExpression() { + final BooleanExpressionEvaluator booleanExpressionEvaluator = new BooleanExpressionEvaluator(); + final Map data = new HashMap<>(); + data.put("age", List.of(1, 2)); + final Optional booleanOptional = booleanExpressionEvaluator.evaluate("age rev_all (1,3,4)", data); + assertTrue(booleanOptional.isPresent()); + assertFalse(booleanOptional.get()); + } + @Test public void testSimpleTrueCorrectExpression() { final BooleanExpressionEvaluator booleanExpressionEvaluator = new BooleanExpressionEvaluator(); diff --git a/src/test/java/com/github/sidhant92/boolparser/parser/canopy/PEGBoolExpressionParserTest.java b/src/test/java/com/github/sidhant92/boolparser/parser/canopy/PEGBoolExpressionParserTest.java index f090b4c..5741e9d 100644 --- a/src/test/java/com/github/sidhant92/boolparser/parser/canopy/PEGBoolExpressionParserTest.java +++ b/src/test/java/com/github/sidhant92/boolparser/parser/canopy/PEGBoolExpressionParserTest.java @@ -2,14 +2,17 @@ import static org.junit.jupiter.api.Assertions.assertEquals; import static org.junit.jupiter.api.Assertions.assertTrue; +import java.util.List; import java.util.Optional; import org.junit.jupiter.api.Test; +import com.github.sidhant92.boolparser.constant.DataType; import com.github.sidhant92.boolparser.constant.NodeType; import com.github.sidhant92.boolparser.constant.Operator; import com.github.sidhant92.boolparser.domain.BoolExpression; import com.github.sidhant92.boolparser.domain.Node; import com.github.sidhant92.boolparser.domain.NumericRangeToken; import com.github.sidhant92.boolparser.domain.NumericToken; +import com.github.sidhant92.boolparser.domain.ReverseAllMatchToken; import com.github.sidhant92.boolparser.domain.StringToken; /** @@ -271,6 +274,22 @@ public void testStringList2() { verifyStringToken((StringToken) boolExpression.getOrOperations().get(2), "name", "ab\"c"); } + @Test + public void testReverseAllMatchIntegerList() { + final PEGBoolExpressionParser boolExpressionParser = new PEGBoolExpressionParser(); + final Optional nodeOptional = boolExpressionParser.parseExpression("age rev_all (1, 2)"); + assertTrue(nodeOptional.isPresent()); + verifyReverseAllMatchToken((ReverseAllMatchToken) nodeOptional.get(), "age", List.of(1, 2), DataType.INTEGER); + } + + @Test + public void testReverseAllMatchStringList() { + final PEGBoolExpressionParser boolExpressionParser = new PEGBoolExpressionParser(); + final Optional nodeOptional = boolExpressionParser.parseExpression("name rev_all (a, bc)"); + assertTrue(nodeOptional.isPresent()); + verifyReverseAllMatchToken((ReverseAllMatchToken) nodeOptional.get(), "name", List.of("a", "bc"), DataType.STRING); + } + private void verifyStringToken(final StringToken stringToken, final String field, final String value) { assertEquals(stringToken.getNodeType().name(), NodeType.STRING_TOKEN.name()); assertEquals(stringToken.getField(), field); @@ -291,4 +310,11 @@ private void verifyNumericRangeToken(final NumericRangeToken numericRangeToken, assertEquals(numericRangeToken.getFromValue(), fromValue); assertEquals(numericRangeToken.getToValue(), toValue); } + + private void verifyReverseAllMatchToken(final ReverseAllMatchToken reverseAllMatchToken, final String field, final List values, + final DataType dataType) { + assertEquals(reverseAllMatchToken.getField(), field); + assertEquals(reverseAllMatchToken.getDataType(), dataType); + assertEquals(reverseAllMatchToken.getValues(), values); + } }