diff --git a/README.md b/README.md index 24c5863..7b19564 100644 --- a/README.md +++ b/README.md @@ -68,7 +68,9 @@ The language supports the following data types: 4. **Decimal**: Numbers with decimal points (stored as BigDecimal). Examples: `3.14`, `-2.5` 5. **Boolean**: `true` or `false` (case-insensitive) 6. **Version**: Semantic version numbers. Examples: `1.0.6`, `2.3.1.5` -7. **Null**: Represented as `null` +7. **Date**: Date values in YYYY-MM-DD format. Examples: `2023-12-25`, `2024-01-15` +8. **DateTime**: Date and time values in YYYY-MM-DD HH:MM:SS format. Examples: `2023-12-25 14:30:00`, `2024-01-15 09:15:30` +9. **Null**: Represented as `null` ### Field References @@ -174,6 +176,7 @@ permissions CONTAINS_ALL ('read', 'write') | `MODE` | Mode of values | `MODE(1, 1, 2, 3)` or `MODE(numbers)` | | `LEN` | Length of string or array | `LEN('hello')` or `LEN(items)` | | `INT` | Convert to integer | `INT(2.7)` or `INT(value)` | +| `DAYS_ELAPSED` | Number of days elapsed since a date | `DAYS_ELAPSED(2023-01-01)` or `DAYS_ELAPSED(startDate)` | Functions can be used in both boolean and arithmetic contexts: @@ -233,6 +236,24 @@ permissions CONTAINS_ALL ('read', 'write', 'delete') LEN(items) > 0 ``` +#### Working with Dates + +Date and DateTime values can be used in comparisons and with the DAYS_ELAPSED function: + +``` +// Date comparisons +startDate > 2023-01-01 +endDate <= 2024-12-31 + +// DateTime comparisons +lastLogin >= 2023-06-15 09:30:00 +createdAt < 2024-01-01 00:00:00 + +// Using DAYS_ELAPSED function +DAYS_ELAPSED(startDate) > 30 +DAYS_ELAPSED(2023-01-01) < 365 +``` + #### String Handling - Strings must be enclosed in single or double quotes diff --git a/build.gradle b/build.gradle index 78560a4..f807b30 100644 --- a/build.gradle +++ b/build.gradle @@ -32,7 +32,7 @@ repositories { dependencies { implementation 'org.apache.maven:maven-artifact:3.5.2' - implementation 'org.antlr:antlr4-runtime:4.13.1' + implementation 'org.antlr:antlr4-runtime:4.13.2' implementation 'io.vavr:vavr:0.10.4' implementation 'com.github.ben-manes.caffeine:caffeine:2.9.3' implementation 'org.projectlombok:lombok:1.18.26' diff --git a/src/main/java/com/github/sidhant92/boolparser/constant/DataType.java b/src/main/java/com/github/sidhant92/boolparser/constant/DataType.java index 03c9165..c3e44b4 100644 --- a/src/main/java/com/github/sidhant92/boolparser/constant/DataType.java +++ b/src/main/java/com/github/sidhant92/boolparser/constant/DataType.java @@ -8,12 +8,14 @@ */ @AllArgsConstructor public enum DataType { - STRING(6, false), + STRING(8, false), INTEGER(3, true), LONG(4, true), DECIMAL(5, true), VERSION(2, true), - BOOLEAN(1, false); + BOOLEAN(1, false), + DATE(6, false), + DATETIME(7, false); public final int priority; diff --git a/src/main/java/com/github/sidhant92/boolparser/constant/FunctionType.java b/src/main/java/com/github/sidhant92/boolparser/constant/FunctionType.java index cc731dd..d47ff4b 100644 --- a/src/main/java/com/github/sidhant92/boolparser/constant/FunctionType.java +++ b/src/main/java/com/github/sidhant92/boolparser/constant/FunctionType.java @@ -16,7 +16,8 @@ public enum FunctionType { MODE, MEDIAN, INT, - LEN; + LEN, + DAYS_ELAPSED; public static Optional getArrayFunctionFromSymbol(final String symbol) { final String symbolUpperCase = symbol.toUpperCase(); 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 aedeed7..db19a1f 100644 --- a/src/main/java/com/github/sidhant92/boolparser/datatype/DataTypeFactory.java +++ b/src/main/java/com/github/sidhant92/boolparser/datatype/DataTypeFactory.java @@ -22,6 +22,8 @@ public static void initialize() { abstractDataTypeMap.put(DataType.LONG, new LongDataType()); abstractDataTypeMap.put(DataType.VERSION, new VersionDataType()); abstractDataTypeMap.put(DataType.BOOLEAN, new BooleanDataType()); + abstractDataTypeMap.put(DataType.DATE, new DateDataType()); + abstractDataTypeMap.put(DataType.DATETIME, new DateTimeDataType()); } public static AbstractDataType getDataType(final DataType dataType) { diff --git a/src/main/java/com/github/sidhant92/boolparser/datatype/DateDataType.java b/src/main/java/com/github/sidhant92/boolparser/datatype/DateDataType.java new file mode 100644 index 0000000..999e616 --- /dev/null +++ b/src/main/java/com/github/sidhant92/boolparser/datatype/DateDataType.java @@ -0,0 +1,58 @@ +package com.github.sidhant92.boolparser.datatype; + +import java.time.LocalDate; +import java.time.format.DateTimeFormatter; +import java.time.format.DateTimeParseException; +import java.util.Optional; +import com.github.sidhant92.boolparser.constant.DataType; + +/** + * @author sidhant.aggarwal + * @since 05/03/2023 + */ +public class DateDataType extends AbstractDataType { + private static final DateTimeFormatter DATE_FORMATTER = DateTimeFormatter.ofPattern("yyyy-MM-dd"); + + public DateDataType() { + super(LocalDate.class); + } + + @Override + public DataType getDataType() { + return DataType.DATE; + } + + @Override + public boolean isValid(final Object value) { + boolean isValid = super.defaultIsValid(value); + if (!isValid) { + return parseDate(value.toString()).isPresent(); + } + return true; + } + + @Override + public boolean isValid(final Object value, final boolean useStrictValidation) { + if (!useStrictValidation) { + return isValid(value); + } + return super.defaultIsValid(value); + } + + @Override + public Optional getValue(Object value) { + final Optional result = defaultGetValue(value); + if (result.isPresent()) { + return result; + } + return parseDate(value.toString()); + } + + private Optional parseDate(String dateString) { + try { + return Optional.of(LocalDate.parse(dateString, DATE_FORMATTER)); + } catch (DateTimeParseException ignored) { + return Optional.empty(); + } + } +} \ No newline at end of file diff --git a/src/main/java/com/github/sidhant92/boolparser/datatype/DateTimeDataType.java b/src/main/java/com/github/sidhant92/boolparser/datatype/DateTimeDataType.java new file mode 100644 index 0000000..3418b46 --- /dev/null +++ b/src/main/java/com/github/sidhant92/boolparser/datatype/DateTimeDataType.java @@ -0,0 +1,58 @@ +package com.github.sidhant92.boolparser.datatype; + +import java.time.LocalDateTime; +import java.time.format.DateTimeFormatter; +import java.time.format.DateTimeParseException; +import java.util.Optional; +import com.github.sidhant92.boolparser.constant.DataType; + +/** + * @author sidhant.aggarwal + * @since 05/03/2023 + */ +public class DateTimeDataType extends AbstractDataType { + private static final DateTimeFormatter DATETIME_FORMATTER = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss"); + + public DateTimeDataType() { + super(LocalDateTime.class); + } + + @Override + public DataType getDataType() { + return DataType.DATETIME; + } + + @Override + public boolean isValid(final Object value) { + boolean isValid = super.defaultIsValid(value); + if (!isValid) { + return parseDateTime(value.toString()).isPresent(); + } + return true; + } + + @Override + public boolean isValid(final Object value, final boolean useStrictValidation) { + if (!useStrictValidation) { + return isValid(value); + } + return super.defaultIsValid(value); + } + + @Override + public Optional getValue(Object value) { + final Optional result = defaultGetValue(value); + if (result.isPresent()) { + return result; + } + return parseDateTime(value.toString()); + } + + private Optional parseDateTime(String dateTimeString) { + try { + return Optional.of(LocalDateTime.parse(dateTimeString, DATETIME_FORMATTER)); + } catch (DateTimeParseException ignored) { + return Optional.empty(); + } + } +} \ No newline at end of file diff --git a/src/main/java/com/github/sidhant92/boolparser/exception/InvalidFunctionArgument.java b/src/main/java/com/github/sidhant92/boolparser/exception/InvalidFunctionArgument.java new file mode 100644 index 0000000..7aafd4d --- /dev/null +++ b/src/main/java/com/github/sidhant92/boolparser/exception/InvalidFunctionArgument.java @@ -0,0 +1,11 @@ +package com.github.sidhant92.boolparser.exception; + +public class InvalidFunctionArgument extends RuntimeException { + public InvalidFunctionArgument(final String message) { + super(message); + } + + public InvalidFunctionArgument() { + super(); + } +} \ No newline at end of file diff --git a/src/main/java/com/github/sidhant92/boolparser/function/FunctionFactory.java b/src/main/java/com/github/sidhant92/boolparser/function/FunctionFactory.java index 201e337..6abfdf4 100644 --- a/src/main/java/com/github/sidhant92/boolparser/function/FunctionFactory.java +++ b/src/main/java/com/github/sidhant92/boolparser/function/FunctionFactory.java @@ -5,6 +5,7 @@ import com.github.sidhant92.boolparser.constant.FunctionType; import com.github.sidhant92.boolparser.function.arithmetic.AbstractFunction; import com.github.sidhant92.boolparser.function.arithmetic.AvgFunction; +import com.github.sidhant92.boolparser.function.arithmetic.DaysElapsedFunction; import com.github.sidhant92.boolparser.function.arithmetic.IntFunction; import com.github.sidhant92.boolparser.function.arithmetic.LenFunction; import com.github.sidhant92.boolparser.function.arithmetic.MaxFunction; @@ -35,6 +36,7 @@ public static void initialize() { arithmeticFunctionrMap.put(FunctionType.MODE, new ModeFunction()); arithmeticFunctionrMap.put(FunctionType.INT, new IntFunction()); arithmeticFunctionrMap.put(FunctionType.LEN, new LenFunction()); + arithmeticFunctionrMap.put(FunctionType.DAYS_ELAPSED, new DaysElapsedFunction()); } public static AbstractFunction getArithmeticFunction(final FunctionType functionType) { diff --git a/src/main/java/com/github/sidhant92/boolparser/function/arithmetic/DaysElapsedFunction.java b/src/main/java/com/github/sidhant92/boolparser/function/arithmetic/DaysElapsedFunction.java new file mode 100644 index 0000000..14955ed --- /dev/null +++ b/src/main/java/com/github/sidhant92/boolparser/function/arithmetic/DaysElapsedFunction.java @@ -0,0 +1,63 @@ +package com.github.sidhant92.boolparser.function.arithmetic; + +import java.time.LocalDate; +import java.time.temporal.ChronoUnit; +import java.util.Arrays; +import java.util.List; +import com.github.sidhant92.boolparser.constant.ContainerDataType; +import com.github.sidhant92.boolparser.constant.DataType; +import com.github.sidhant92.boolparser.constant.FunctionType; +import com.github.sidhant92.boolparser.domain.EvaluatedNode; +import com.github.sidhant92.boolparser.exception.InvalidFunctionArgument; + +/** + * Function to calculate the number of days elapsed since a given date. + * Returns a positive number for dates in the past, negative for dates in the future. + * + * @author sidhant.aggarwal + * @since 05/03/2023 + */ +public class DaysElapsedFunction extends AbstractFunction { + + @Override + public Object evaluate(final List items) { + if (items.size() != 1) { + throw new InvalidFunctionArgument("DAYS_ELAPSED function requires exactly one argument"); + } + + final EvaluatedNode item = items.get(0); + final Object value = item.getValue(); + + LocalDate inputDate; + if (value instanceof LocalDate) { + inputDate = (LocalDate) value; + } else if (value instanceof String) { + // Try to parse string as date if the DataType detection missed it + try { + inputDate = LocalDate.parse((String) value); + } catch (Exception e) { + throw new InvalidFunctionArgument("DAYS_ELAPSED function requires a valid date argument, got: " + value); + } + } else { + throw new InvalidFunctionArgument("DAYS_ELAPSED function requires a date argument, got: " + value.getClass().getSimpleName()); + } + + final LocalDate today = LocalDate.now(); + return ChronoUnit.DAYS.between(inputDate, today); + } + + @Override + public FunctionType getFunctionType() { + return FunctionType.DAYS_ELAPSED; + } + + @Override + public List getAllowedContainerTypes() { + return Arrays.asList(ContainerDataType.PRIMITIVE); + } + + @Override + public List getAllowedDataTypes() { + return Arrays.asList(DataType.DATE); + } +} \ No newline at end of file diff --git a/src/main/java/com/github/sidhant92/boolparser/operator/comparison/GreaterThanEqualOperator.java b/src/main/java/com/github/sidhant92/boolparser/operator/comparison/GreaterThanEqualOperator.java index 588ab10..4abde66 100644 --- a/src/main/java/com/github/sidhant92/boolparser/operator/comparison/GreaterThanEqualOperator.java +++ b/src/main/java/com/github/sidhant92/boolparser/operator/comparison/GreaterThanEqualOperator.java @@ -44,6 +44,6 @@ public List getAllowedContainerTypes() { @Override public List getAllowedDataTypes() { - return Arrays.asList(DataType.INTEGER, DataType.LONG, DataType.DECIMAL, DataType.STRING, DataType.VERSION); + return Arrays.asList(DataType.INTEGER, DataType.LONG, DataType.DECIMAL, DataType.STRING, DataType.VERSION, DataType.DATE, DataType.DATETIME); } } diff --git a/src/main/java/com/github/sidhant92/boolparser/operator/comparison/GreaterThanOperator.java b/src/main/java/com/github/sidhant92/boolparser/operator/comparison/GreaterThanOperator.java index cf1f9a8..3ee9b61 100644 --- a/src/main/java/com/github/sidhant92/boolparser/operator/comparison/GreaterThanOperator.java +++ b/src/main/java/com/github/sidhant92/boolparser/operator/comparison/GreaterThanOperator.java @@ -44,6 +44,6 @@ public List getAllowedContainerTypes() { @Override public List getAllowedDataTypes() { - return Arrays.asList(DataType.INTEGER, DataType.LONG, DataType.DECIMAL, DataType.STRING, DataType.VERSION); + return Arrays.asList(DataType.INTEGER, DataType.LONG, DataType.DECIMAL, DataType.STRING, DataType.VERSION, DataType.DATE, DataType.DATETIME); } } diff --git a/src/main/java/com/github/sidhant92/boolparser/operator/comparison/LessThanEqualOperator.java b/src/main/java/com/github/sidhant92/boolparser/operator/comparison/LessThanEqualOperator.java index 00320dc..edddb8b 100644 --- a/src/main/java/com/github/sidhant92/boolparser/operator/comparison/LessThanEqualOperator.java +++ b/src/main/java/com/github/sidhant92/boolparser/operator/comparison/LessThanEqualOperator.java @@ -44,6 +44,6 @@ public List getAllowedContainerTypes() { @Override public List getAllowedDataTypes() { - return Arrays.asList(DataType.INTEGER, DataType.LONG, DataType.DECIMAL, DataType.STRING, DataType.VERSION); + return Arrays.asList(DataType.INTEGER, DataType.LONG, DataType.DECIMAL, DataType.STRING, DataType.VERSION, DataType.DATE, DataType.DATETIME); } } diff --git a/src/main/java/com/github/sidhant92/boolparser/operator/comparison/LessThanOperator.java b/src/main/java/com/github/sidhant92/boolparser/operator/comparison/LessThanOperator.java index 684e981..f7271e1 100644 --- a/src/main/java/com/github/sidhant92/boolparser/operator/comparison/LessThanOperator.java +++ b/src/main/java/com/github/sidhant92/boolparser/operator/comparison/LessThanOperator.java @@ -44,6 +44,6 @@ public List getAllowedContainerTypes() { @Override public List getAllowedDataTypes() { - return Arrays.asList(DataType.INTEGER, DataType.LONG, DataType.DECIMAL, DataType.STRING, DataType.VERSION); + return Arrays.asList(DataType.INTEGER, DataType.LONG, DataType.DECIMAL, DataType.STRING, DataType.VERSION, DataType.DATE, DataType.DATETIME); } } 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 fd825b8..6336796 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,5 @@ -package com.github.sidhant92.boolparser.parser.antlr;// Generated from /Users/sid/Desktop/filter2/BooleanExpression.g4 by ANTLR 4.13.1 +// Generated from /Users/sidhantaggarwal/bool-parser-java/src/main/java/resources/BooleanExpression.g4 by ANTLR 4.13.2 +package com.github.sidhant92.boolparser.parser.antlr; import org.antlr.v4.runtime.ParserRuleContext; import org.antlr.v4.runtime.tree.ErrorNode; 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 fe48745..6b10f3f 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,5 @@ -package com.github.sidhant92.boolparser.parser.antlr;// Generated from /Users/sid/Desktop/filter2/BooleanExpression.g4 by ANTLR 4.13.1 +// Generated from /Users/sidhantaggarwal/bool-parser-java/src/main/java/resources/BooleanExpression.g4 by ANTLR 4.13.2 +package com.github.sidhant92.boolparser.parser.antlr; import org.antlr.v4.runtime.Lexer; import org.antlr.v4.runtime.CharStream; import org.antlr.v4.runtime.Token; @@ -10,7 +11,7 @@ @SuppressWarnings({"all", "warnings", "unchecked", "unused", "cast", "CheckReturnValue", "this-escape"}) public class BooleanExpressionLexer extends Lexer { - static { RuntimeMetaData.checkVersion("4.13.1", RuntimeMetaData.VERSION); } + static { RuntimeMetaData.checkVersion("4.13.2", RuntimeMetaData.VERSION); } protected static final DFA[] _decisionToDFA; protected static final PredictionContextCache _sharedContextCache = @@ -18,10 +19,11 @@ public class BooleanExpressionLexer extends Lexer { public static final int T__0=1, IN=2, TO=3, AND=4, OR=5, NOT=6, TRUE=7, FALSE=8, CONTAINS_ALL=9, CONTAINS_ANY=10, MIN=11, MAX=12, AVG=13, SUM=14, MEAN=15, MODE=16, MEDIAN=17, - LEN=18, INT=19, ADD=20, SUBTRACT=21, MULTIPLY=22, DIVIDE=23, MODULUS=24, - EXPONENT=25, NE=26, GT=27, GE=28, LT=29, LE=30, EQ=31, LPAREN=32, RPAREN=33, - DECIMAL=34, APP_VERSION=35, INTEGER=36, WS=37, WORD=38, SQSTR=39, DQSTR=40, - FIELD=41, ALPHANUMERIC=42, SQ=43, DQ=44; + LEN=18, INT=19, DAYS_ELAPSED=20, ADD=21, SUBTRACT=22, MULTIPLY=23, DIVIDE=24, + MODULUS=25, EXPONENT=26, NE=27, GT=28, GE=29, LT=30, LE=31, EQ=32, LPAREN=33, + RPAREN=34, DECIMAL=35, APP_VERSION=36, INTEGER=37, DATE=38, DATETIME=39, + WS=40, WORD=41, SQSTR=42, DQSTR=43, FIELD=44, ALPHANUMERIC=45, SQ=46, + DQ=47; public static String[] channelNames = { "DEFAULT_TOKEN_CHANNEL", "HIDDEN" }; @@ -34,10 +36,11 @@ private static String[] makeRuleNames() { return new String[] { "T__0", "IN", "TO", "AND", "OR", "NOT", "TRUE", "FALSE", "CONTAINS_ALL", "CONTAINS_ANY", "MIN", "MAX", "AVG", "SUM", "MEAN", "MODE", "MEDIAN", - "LEN", "INT", "ADD", "SUBTRACT", "MULTIPLY", "DIVIDE", "MODULUS", "EXPONENT", - "NE", "GT", "GE", "LT", "LE", "EQ", "LPAREN", "RPAREN", "DECIMAL", "APP_VERSION", - "INTEGER", "WS", "WORD", "SQSTR", "DQSTR", "FIELD", "ALPHANUMERIC", "SQ", - "DQ" + "LEN", "INT", "DAYS_ELAPSED", "ADD", "SUBTRACT", "MULTIPLY", "DIVIDE", + "MODULUS", "EXPONENT", "NE", "GT", "GE", "LT", "LE", "EQ", "LPAREN", + "RPAREN", "DECIMAL", "APP_VERSION", "INTEGER", "DATE", "DATETIME", "WS", + "WORD", "SQSTR", "DQSTR", "FIELD", "ALPHANUMERIC", "SQ", "DQ", "DATE_PATTERN", + "DATETIME_PATTERN" }; } public static final String[] ruleNames = makeRuleNames(); @@ -45,7 +48,7 @@ private static String[] makeRuleNames() { private static String[] makeLiteralNames() { return new String[] { null, "','", null, null, null, null, null, null, null, null, null, null, - null, null, null, null, null, null, null, null, "'+'", "'-'", "'*'", + null, null, null, null, null, null, null, null, null, "'+'", "'-'", "'*'", "'/'", "'%'", "'^'", "'!='", "'>'", "'>='", "'<'", "'<='", "'='", "'('", "')'" }; @@ -55,10 +58,10 @@ private static String[] makeSymbolicNames() { return new String[] { null, null, "IN", "TO", "AND", "OR", "NOT", "TRUE", "FALSE", "CONTAINS_ALL", "CONTAINS_ANY", "MIN", "MAX", "AVG", "SUM", "MEAN", "MODE", "MEDIAN", - "LEN", "INT", "ADD", "SUBTRACT", "MULTIPLY", "DIVIDE", "MODULUS", "EXPONENT", - "NE", "GT", "GE", "LT", "LE", "EQ", "LPAREN", "RPAREN", "DECIMAL", "APP_VERSION", - "INTEGER", "WS", "WORD", "SQSTR", "DQSTR", "FIELD", "ALPHANUMERIC", "SQ", - "DQ" + "LEN", "INT", "DAYS_ELAPSED", "ADD", "SUBTRACT", "MULTIPLY", "DIVIDE", + "MODULUS", "EXPONENT", "NE", "GT", "GE", "LT", "LE", "EQ", "LPAREN", + "RPAREN", "DECIMAL", "APP_VERSION", "INTEGER", "DATE", "DATETIME", "WS", + "WORD", "SQSTR", "DQSTR", "FIELD", "ALPHANUMERIC", "SQ", "DQ" }; } private static final String[] _SYMBOLIC_NAMES = makeSymbolicNames(); @@ -120,7 +123,7 @@ public BooleanExpressionLexer(CharStream input) { public ATN getATN() { return _ATN; } public static final String _serializedATN = - "\u0004\u0000,\u018a\u0006\uffff\uffff\u0002\u0000\u0007\u0000\u0002\u0001"+ + "\u0004\u0000/\u01d1\u0006\uffff\uffff\u0002\u0000\u0007\u0000\u0002\u0001"+ "\u0007\u0001\u0002\u0002\u0007\u0002\u0002\u0003\u0007\u0003\u0002\u0004"+ "\u0007\u0004\u0002\u0005\u0007\u0005\u0002\u0006\u0007\u0006\u0002\u0007"+ "\u0007\u0007\u0002\b\u0007\b\u0002\t\u0007\t\u0002\n\u0007\n\u0002\u000b"+ @@ -133,243 +136,285 @@ public BooleanExpressionLexer(CharStream input) { "\u001e\u0007\u001e\u0002\u001f\u0007\u001f\u0002 \u0007 \u0002!\u0007"+ "!\u0002\"\u0007\"\u0002#\u0007#\u0002$\u0007$\u0002%\u0007%\u0002&\u0007"+ "&\u0002\'\u0007\'\u0002(\u0007(\u0002)\u0007)\u0002*\u0007*\u0002+\u0007"+ - "+\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\u0002f\b\u0002\u0001\u0003\u0001\u0003\u0001\u0003\u0001\u0003"+ - "\u0001\u0003\u0001\u0003\u0001\u0003\u0001\u0003\u0003\u0003p\b\u0003"+ + "+\u0002,\u0007,\u0002-\u0007-\u0002.\u0007.\u0002/\u0007/\u00020\u0007"+ + "0\u0001\u0000\u0001\u0000\u0001\u0001\u0001\u0001\u0001\u0001\u0001\u0001"+ + "\u0003\u0001j\b\u0001\u0001\u0002\u0001\u0002\u0001\u0002\u0001\u0002"+ + "\u0003\u0002p\b\u0002\u0001\u0003\u0001\u0003\u0001\u0003\u0001\u0003"+ + "\u0001\u0003\u0001\u0003\u0001\u0003\u0001\u0003\u0003\u0003z\b\u0003"+ "\u0001\u0004\u0001\u0004\u0001\u0004\u0001\u0004\u0001\u0004\u0001\u0004"+ - "\u0003\u0004x\b\u0004\u0001\u0005\u0001\u0005\u0001\u0005\u0001\u0005"+ - "\u0001\u0005\u0001\u0005\u0003\u0005\u0080\b\u0005\u0001\u0006\u0001\u0006"+ + "\u0003\u0004\u0082\b\u0004\u0001\u0005\u0001\u0005\u0001\u0005\u0001\u0005"+ + "\u0001\u0005\u0001\u0005\u0003\u0005\u008a\b\u0005\u0001\u0006\u0001\u0006"+ "\u0001\u0006\u0001\u0006\u0001\u0006\u0001\u0006\u0001\u0006\u0001\u0006"+ - "\u0003\u0006\u008a\b\u0006\u0001\u0007\u0001\u0007\u0001\u0007\u0001\u0007"+ + "\u0003\u0006\u0094\b\u0006\u0001\u0007\u0001\u0007\u0001\u0007\u0001\u0007"+ "\u0001\u0007\u0001\u0007\u0001\u0007\u0001\u0007\u0001\u0007\u0001\u0007"+ - "\u0003\u0007\u0096\b\u0007\u0001\b\u0001\b\u0001\b\u0001\b\u0001\b\u0001"+ + "\u0003\u0007\u00a0\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\u00b0\b\b\u0001\t\u0001\t\u0001\t\u0001\t\u0001\t\u0001\t\u0001"+ + "\b\u0003\b\u00ba\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\u00ca\b\t\u0001\n\u0001\n\u0001\n\u0001\n\u0001\n\u0001\n\u0003\n\u00d2"+ + "\t\u00d4\b\t\u0001\n\u0001\n\u0001\n\u0001\n\u0001\n\u0001\n\u0003\n\u00dc"+ "\b\n\u0001\u000b\u0001\u000b\u0001\u000b\u0001\u000b\u0001\u000b\u0001"+ - "\u000b\u0003\u000b\u00da\b\u000b\u0001\f\u0001\f\u0001\f\u0001\f\u0001"+ - "\f\u0001\f\u0003\f\u00e2\b\f\u0001\r\u0001\r\u0001\r\u0001\r\u0001\r\u0001"+ - "\r\u0003\r\u00ea\b\r\u0001\u000e\u0001\u000e\u0001\u000e\u0001\u000e\u0001"+ - "\u000e\u0001\u000e\u0001\u000e\u0001\u000e\u0003\u000e\u00f4\b\u000e\u0001"+ + "\u000b\u0003\u000b\u00e4\b\u000b\u0001\f\u0001\f\u0001\f\u0001\f\u0001"+ + "\f\u0001\f\u0003\f\u00ec\b\f\u0001\r\u0001\r\u0001\r\u0001\r\u0001\r\u0001"+ + "\r\u0003\r\u00f4\b\r\u0001\u000e\u0001\u000e\u0001\u000e\u0001\u000e\u0001"+ + "\u000e\u0001\u000e\u0001\u000e\u0001\u000e\u0003\u000e\u00fe\b\u000e\u0001"+ "\u000f\u0001\u000f\u0001\u000f\u0001\u000f\u0001\u000f\u0001\u000f\u0001"+ - "\u000f\u0001\u000f\u0003\u000f\u00fe\b\u000f\u0001\u0010\u0001\u0010\u0001"+ + "\u000f\u0001\u000f\u0003\u000f\u0108\b\u000f\u0001\u0010\u0001\u0010\u0001"+ "\u0010\u0001\u0010\u0001\u0010\u0001\u0010\u0001\u0010\u0001\u0010\u0001"+ - "\u0010\u0001\u0010\u0001\u0010\u0001\u0010\u0003\u0010\u010c\b\u0010\u0001"+ + "\u0010\u0001\u0010\u0001\u0010\u0001\u0010\u0003\u0010\u0116\b\u0010\u0001"+ "\u0011\u0001\u0011\u0001\u0011\u0001\u0011\u0001\u0011\u0001\u0011\u0003"+ - "\u0011\u0114\b\u0011\u0001\u0012\u0001\u0012\u0001\u0012\u0001\u0012\u0001"+ - "\u0012\u0001\u0012\u0003\u0012\u011c\b\u0012\u0001\u0013\u0001\u0013\u0001"+ + "\u0011\u011e\b\u0011\u0001\u0012\u0001\u0012\u0001\u0012\u0001\u0012\u0001"+ + "\u0012\u0001\u0012\u0003\u0012\u0126\b\u0012\u0001\u0013\u0001\u0013\u0001"+ + "\u0013\u0001\u0013\u0001\u0013\u0001\u0013\u0001\u0013\u0001\u0013\u0001"+ + "\u0013\u0001\u0013\u0001\u0013\u0001\u0013\u0001\u0013\u0001\u0013\u0001"+ + "\u0013\u0001\u0013\u0001\u0013\u0001\u0013\u0001\u0013\u0001\u0013\u0001"+ + "\u0013\u0001\u0013\u0001\u0013\u0001\u0013\u0003\u0013\u0140\b\u0013\u0001"+ "\u0014\u0001\u0014\u0001\u0015\u0001\u0015\u0001\u0016\u0001\u0016\u0001"+ "\u0017\u0001\u0017\u0001\u0018\u0001\u0018\u0001\u0019\u0001\u0019\u0001"+ - "\u0019\u0001\u001a\u0001\u001a\u0001\u001b\u0001\u001b\u0001\u001b\u0001"+ - "\u001c\u0001\u001c\u0001\u001d\u0001\u001d\u0001\u001d\u0001\u001e\u0001"+ - "\u001e\u0001\u001f\u0001\u001f\u0001 \u0001 \u0001!\u0004!\u013e\b!\u000b"+ - "!\f!\u013f\u0001!\u0001!\u0004!\u0144\b!\u000b!\f!\u0145\u0001\"\u0001"+ - "\"\u0001\"\u0004\"\u014b\b\"\u000b\"\f\"\u014c\u0001#\u0004#\u0150\b#"+ - "\u000b#\f#\u0151\u0001$\u0004$\u0155\b$\u000b$\f$\u0156\u0001$\u0001$"+ - "\u0001%\u0001%\u0003%\u015d\b%\u0001&\u0001&\u0005&\u0161\b&\n&\f&\u0164"+ - "\t&\u0001&\u0001&\u0001\'\u0001\'\u0005\'\u016a\b\'\n\'\f\'\u016d\t\'"+ - "\u0001\'\u0001\'\u0001(\u0001(\u0004(\u0173\b(\u000b(\f(\u0174\u0001)"+ - "\u0001)\u0001*\u0001*\u0005*\u017b\b*\n*\f*\u017e\t*\u0001*\u0001*\u0001"+ - "+\u0001+\u0005+\u0184\b+\n+\f+\u0187\t+\u0001+\u0001+\u0004\u0162\u016b"+ - "\u017c\u0185\u0000,\u0001\u0001\u0003\u0002\u0005\u0003\u0007\u0004\t"+ - "\u0005\u000b\u0006\r\u0007\u000f\b\u0011\t\u0013\n\u0015\u000b\u0017\f"+ - "\u0019\r\u001b\u000e\u001d\u000f\u001f\u0010!\u0011#\u0012%\u0013\'\u0014"+ - ")\u0015+\u0016-\u0017/\u00181\u00193\u001a5\u001b7\u001c9\u001d;\u001e"+ - "=\u001f? A!C\"E#G$I%K&M\'O(Q)S*U+W,\u0001\u0000\u0004\u0001\u000009\u0003"+ - "\u0000\t\n\f\r \u0002\u0000..__\u0003\u000009AZaz\u01a9\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\u00005"+ - "\u0001\u0000\u0000\u0000\u00007\u0001\u0000\u0000\u0000\u00009\u0001\u0000"+ - "\u0000\u0000\u0000;\u0001\u0000\u0000\u0000\u0000=\u0001\u0000\u0000\u0000"+ - "\u0000?\u0001\u0000\u0000\u0000\u0000A\u0001\u0000\u0000\u0000\u0000C"+ - "\u0001\u0000\u0000\u0000\u0000E\u0001\u0000\u0000\u0000\u0000G\u0001\u0000"+ - "\u0000\u0000\u0000I\u0001\u0000\u0000\u0000\u0000K\u0001\u0000\u0000\u0000"+ - "\u0000M\u0001\u0000\u0000\u0000\u0000O\u0001\u0000\u0000\u0000\u0000Q"+ - "\u0001\u0000\u0000\u0000\u0000S\u0001\u0000\u0000\u0000\u0000U\u0001\u0000"+ - "\u0000\u0000\u0000W\u0001\u0000\u0000\u0000\u0001Y\u0001\u0000\u0000\u0000"+ - "\u0003_\u0001\u0000\u0000\u0000\u0005e\u0001\u0000\u0000\u0000\u0007o"+ - "\u0001\u0000\u0000\u0000\tw\u0001\u0000\u0000\u0000\u000b\u007f\u0001"+ - "\u0000\u0000\u0000\r\u0089\u0001\u0000\u0000\u0000\u000f\u0095\u0001\u0000"+ - "\u0000\u0000\u0011\u00af\u0001\u0000\u0000\u0000\u0013\u00c9\u0001\u0000"+ - "\u0000\u0000\u0015\u00d1\u0001\u0000\u0000\u0000\u0017\u00d9\u0001\u0000"+ - "\u0000\u0000\u0019\u00e1\u0001\u0000\u0000\u0000\u001b\u00e9\u0001\u0000"+ - "\u0000\u0000\u001d\u00f3\u0001\u0000\u0000\u0000\u001f\u00fd\u0001\u0000"+ - "\u0000\u0000!\u010b\u0001\u0000\u0000\u0000#\u0113\u0001\u0000\u0000\u0000"+ - "%\u011b\u0001\u0000\u0000\u0000\'\u011d\u0001\u0000\u0000\u0000)\u011f"+ - "\u0001\u0000\u0000\u0000+\u0121\u0001\u0000\u0000\u0000-\u0123\u0001\u0000"+ - "\u0000\u0000/\u0125\u0001\u0000\u0000\u00001\u0127\u0001\u0000\u0000\u0000"+ - "3\u0129\u0001\u0000\u0000\u00005\u012c\u0001\u0000\u0000\u00007\u012e"+ - "\u0001\u0000\u0000\u00009\u0131\u0001\u0000\u0000\u0000;\u0133\u0001\u0000"+ - "\u0000\u0000=\u0136\u0001\u0000\u0000\u0000?\u0138\u0001\u0000\u0000\u0000"+ - "A\u013a\u0001\u0000\u0000\u0000C\u013d\u0001\u0000\u0000\u0000E\u0147"+ - "\u0001\u0000\u0000\u0000G\u014f\u0001\u0000\u0000\u0000I\u0154\u0001\u0000"+ - "\u0000\u0000K\u015c\u0001\u0000\u0000\u0000M\u015e\u0001\u0000\u0000\u0000"+ - "O\u0167\u0001\u0000\u0000\u0000Q\u0172\u0001\u0000\u0000\u0000S\u0176"+ - "\u0001\u0000\u0000\u0000U\u0178\u0001\u0000\u0000\u0000W\u0181\u0001\u0000"+ - "\u0000\u0000YZ\u0005,\u0000\u0000Z\u0002\u0001\u0000\u0000\u0000[\\\u0005"+ - "I\u0000\u0000\\`\u0005N\u0000\u0000]^\u0005i\u0000\u0000^`\u0005n\u0000"+ - "\u0000_[\u0001\u0000\u0000\u0000_]\u0001\u0000\u0000\u0000`\u0004\u0001"+ - "\u0000\u0000\u0000ab\u0005T\u0000\u0000bf\u0005O\u0000\u0000cd\u0005t"+ - "\u0000\u0000df\u0005o\u0000\u0000ea\u0001\u0000\u0000\u0000ec\u0001\u0000"+ - "\u0000\u0000f\u0006\u0001\u0000\u0000\u0000gh\u0005A\u0000\u0000hi\u0005"+ - "N\u0000\u0000ip\u0005D\u0000\u0000jk\u0005a\u0000\u0000kl\u0005n\u0000"+ - "\u0000lp\u0005d\u0000\u0000mn\u0005&\u0000\u0000np\u0005&\u0000\u0000"+ - "og\u0001\u0000\u0000\u0000oj\u0001\u0000\u0000\u0000om\u0001\u0000\u0000"+ - "\u0000p\b\u0001\u0000\u0000\u0000qr\u0005O\u0000\u0000rx\u0005R\u0000"+ - "\u0000st\u0005o\u0000\u0000tx\u0005r\u0000\u0000uv\u0005|\u0000\u0000"+ - "vx\u0005|\u0000\u0000wq\u0001\u0000\u0000\u0000ws\u0001\u0000\u0000\u0000"+ - "wu\u0001\u0000\u0000\u0000x\n\u0001\u0000\u0000\u0000yz\u0005N\u0000\u0000"+ - "z{\u0005O\u0000\u0000{\u0080\u0005T\u0000\u0000|}\u0005n\u0000\u0000}"+ - "~\u0005o\u0000\u0000~\u0080\u0005t\u0000\u0000\u007fy\u0001\u0000\u0000"+ - "\u0000\u007f|\u0001\u0000\u0000\u0000\u0080\f\u0001\u0000\u0000\u0000"+ - "\u0081\u0082\u0005T\u0000\u0000\u0082\u0083\u0005R\u0000\u0000\u0083\u0084"+ - "\u0005U\u0000\u0000\u0084\u008a\u0005E\u0000\u0000\u0085\u0086\u0005t"+ - "\u0000\u0000\u0086\u0087\u0005r\u0000\u0000\u0087\u0088\u0005u\u0000\u0000"+ - "\u0088\u008a\u0005e\u0000\u0000\u0089\u0081\u0001\u0000\u0000\u0000\u0089"+ - "\u0085\u0001\u0000\u0000\u0000\u008a\u000e\u0001\u0000\u0000\u0000\u008b"+ - "\u008c\u0005F\u0000\u0000\u008c\u008d\u0005A\u0000\u0000\u008d\u008e\u0005"+ - "L\u0000\u0000\u008e\u008f\u0005S\u0000\u0000\u008f\u0096\u0005E\u0000"+ - "\u0000\u0090\u0091\u0005f\u0000\u0000\u0091\u0092\u0005a\u0000\u0000\u0092"+ - "\u0093\u0005l\u0000\u0000\u0093\u0094\u0005s\u0000\u0000\u0094\u0096\u0005"+ - "e\u0000\u0000\u0095\u008b\u0001\u0000\u0000\u0000\u0095\u0090\u0001\u0000"+ - "\u0000\u0000\u0096\u0010\u0001\u0000\u0000\u0000\u0097\u0098\u0005C\u0000"+ - "\u0000\u0098\u0099\u0005O\u0000\u0000\u0099\u009a\u0005N\u0000\u0000\u009a"+ - "\u009b\u0005T\u0000\u0000\u009b\u009c\u0005A\u0000\u0000\u009c\u009d\u0005"+ - "I\u0000\u0000\u009d\u009e\u0005N\u0000\u0000\u009e\u009f\u0005S\u0000"+ - "\u0000\u009f\u00a0\u0005_\u0000\u0000\u00a0\u00a1\u0005A\u0000\u0000\u00a1"+ - "\u00a2\u0005L\u0000\u0000\u00a2\u00b0\u0005L\u0000\u0000\u00a3\u00a4\u0005"+ - "c\u0000\u0000\u00a4\u00a5\u0005o\u0000\u0000\u00a5\u00a6\u0005n\u0000"+ - "\u0000\u00a6\u00a7\u0005t\u0000\u0000\u00a7\u00a8\u0005a\u0000\u0000\u00a8"+ - "\u00a9\u0005i\u0000\u0000\u00a9\u00aa\u0005n\u0000\u0000\u00aa\u00ab\u0005"+ - "s\u0000\u0000\u00ab\u00ac\u0005_\u0000\u0000\u00ac\u00ad\u0005a\u0000"+ - "\u0000\u00ad\u00ae\u0005l\u0000\u0000\u00ae\u00b0\u0005l\u0000\u0000\u00af"+ - "\u0097\u0001\u0000\u0000\u0000\u00af\u00a3\u0001\u0000\u0000\u0000\u00b0"+ - "\u0012\u0001\u0000\u0000\u0000\u00b1\u00b2\u0005C\u0000\u0000\u00b2\u00b3"+ - "\u0005O\u0000\u0000\u00b3\u00b4\u0005N\u0000\u0000\u00b4\u00b5\u0005T"+ - "\u0000\u0000\u00b5\u00b6\u0005A\u0000\u0000\u00b6\u00b7\u0005I\u0000\u0000"+ - "\u00b7\u00b8\u0005N\u0000\u0000\u00b8\u00b9\u0005S\u0000\u0000\u00b9\u00ba"+ - "\u0005_\u0000\u0000\u00ba\u00bb\u0005A\u0000\u0000\u00bb\u00bc\u0005N"+ - "\u0000\u0000\u00bc\u00ca\u0005Y\u0000\u0000\u00bd\u00be\u0005c\u0000\u0000"+ - "\u00be\u00bf\u0005o\u0000\u0000\u00bf\u00c0\u0005n\u0000\u0000\u00c0\u00c1"+ - "\u0005t\u0000\u0000\u00c1\u00c2\u0005a\u0000\u0000\u00c2\u00c3\u0005i"+ - "\u0000\u0000\u00c3\u00c4\u0005n\u0000\u0000\u00c4\u00c5\u0005s\u0000\u0000"+ - "\u00c5\u00c6\u0005_\u0000\u0000\u00c6\u00c7\u0005a\u0000\u0000\u00c7\u00c8"+ - "\u0005n\u0000\u0000\u00c8\u00ca\u0005y\u0000\u0000\u00c9\u00b1\u0001\u0000"+ - "\u0000\u0000\u00c9\u00bd\u0001\u0000\u0000\u0000\u00ca\u0014\u0001\u0000"+ - "\u0000\u0000\u00cb\u00cc\u0005M\u0000\u0000\u00cc\u00cd\u0005I\u0000\u0000"+ - "\u00cd\u00d2\u0005N\u0000\u0000\u00ce\u00cf\u0005m\u0000\u0000\u00cf\u00d0"+ - "\u0005i\u0000\u0000\u00d0\u00d2\u0005n\u0000\u0000\u00d1\u00cb\u0001\u0000"+ - "\u0000\u0000\u00d1\u00ce\u0001\u0000\u0000\u0000\u00d2\u0016\u0001\u0000"+ - "\u0000\u0000\u00d3\u00d4\u0005M\u0000\u0000\u00d4\u00d5\u0005A\u0000\u0000"+ - "\u00d5\u00da\u0005X\u0000\u0000\u00d6\u00d7\u0005m\u0000\u0000\u00d7\u00d8"+ - "\u0005a\u0000\u0000\u00d8\u00da\u0005x\u0000\u0000\u00d9\u00d3\u0001\u0000"+ - "\u0000\u0000\u00d9\u00d6\u0001\u0000\u0000\u0000\u00da\u0018\u0001\u0000"+ - "\u0000\u0000\u00db\u00dc\u0005A\u0000\u0000\u00dc\u00dd\u0005V\u0000\u0000"+ - "\u00dd\u00e2\u0005G\u0000\u0000\u00de\u00df\u0005a\u0000\u0000\u00df\u00e0"+ - "\u0005v\u0000\u0000\u00e0\u00e2\u0005g\u0000\u0000\u00e1\u00db\u0001\u0000"+ - "\u0000\u0000\u00e1\u00de\u0001\u0000\u0000\u0000\u00e2\u001a\u0001\u0000"+ - "\u0000\u0000\u00e3\u00e4\u0005S\u0000\u0000\u00e4\u00e5\u0005U\u0000\u0000"+ - "\u00e5\u00ea\u0005M\u0000\u0000\u00e6\u00e7\u0005s\u0000\u0000\u00e7\u00e8"+ - "\u0005u\u0000\u0000\u00e8\u00ea\u0005m\u0000\u0000\u00e9\u00e3\u0001\u0000"+ - "\u0000\u0000\u00e9\u00e6\u0001\u0000\u0000\u0000\u00ea\u001c\u0001\u0000"+ - "\u0000\u0000\u00eb\u00ec\u0005M\u0000\u0000\u00ec\u00ed\u0005E\u0000\u0000"+ - "\u00ed\u00ee\u0005A\u0000\u0000\u00ee\u00f4\u0005N\u0000\u0000\u00ef\u00f0"+ - "\u0005m\u0000\u0000\u00f0\u00f1\u0005e\u0000\u0000\u00f1\u00f2\u0005a"+ - "\u0000\u0000\u00f2\u00f4\u0005n\u0000\u0000\u00f3\u00eb\u0001\u0000\u0000"+ - "\u0000\u00f3\u00ef\u0001\u0000\u0000\u0000\u00f4\u001e\u0001\u0000\u0000"+ - "\u0000\u00f5\u00f6\u0005M\u0000\u0000\u00f6\u00f7\u0005O\u0000\u0000\u00f7"+ - "\u00f8\u0005D\u0000\u0000\u00f8\u00fe\u0005E\u0000\u0000\u00f9\u00fa\u0005"+ - "m\u0000\u0000\u00fa\u00fb\u0005o\u0000\u0000\u00fb\u00fc\u0005d\u0000"+ - "\u0000\u00fc\u00fe\u0005e\u0000\u0000\u00fd\u00f5\u0001\u0000\u0000\u0000"+ - "\u00fd\u00f9\u0001\u0000\u0000\u0000\u00fe \u0001\u0000\u0000\u0000\u00ff"+ - "\u0100\u0005M\u0000\u0000\u0100\u0101\u0005E\u0000\u0000\u0101\u0102\u0005"+ - "D\u0000\u0000\u0102\u0103\u0005I\u0000\u0000\u0103\u0104\u0005A\u0000"+ - "\u0000\u0104\u010c\u0005N\u0000\u0000\u0105\u0106\u0005m\u0000\u0000\u0106"+ - "\u0107\u0005e\u0000\u0000\u0107\u0108\u0005d\u0000\u0000\u0108\u0109\u0005"+ - "i\u0000\u0000\u0109\u010a\u0005a\u0000\u0000\u010a\u010c\u0005n\u0000"+ - "\u0000\u010b\u00ff\u0001\u0000\u0000\u0000\u010b\u0105\u0001\u0000\u0000"+ - "\u0000\u010c\"\u0001\u0000\u0000\u0000\u010d\u010e\u0005L\u0000\u0000"+ - "\u010e\u010f\u0005E\u0000\u0000\u010f\u0114\u0005N\u0000\u0000\u0110\u0111"+ - "\u0005l\u0000\u0000\u0111\u0112\u0005e\u0000\u0000\u0112\u0114\u0005n"+ - "\u0000\u0000\u0113\u010d\u0001\u0000\u0000\u0000\u0113\u0110\u0001\u0000"+ - "\u0000\u0000\u0114$\u0001\u0000\u0000\u0000\u0115\u0116\u0005I\u0000\u0000"+ - "\u0116\u0117\u0005N\u0000\u0000\u0117\u011c\u0005T\u0000\u0000\u0118\u0119"+ - "\u0005i\u0000\u0000\u0119\u011a\u0005n\u0000\u0000\u011a\u011c\u0005t"+ - "\u0000\u0000\u011b\u0115\u0001\u0000\u0000\u0000\u011b\u0118\u0001\u0000"+ - "\u0000\u0000\u011c&\u0001\u0000\u0000\u0000\u011d\u011e\u0005+\u0000\u0000"+ - "\u011e(\u0001\u0000\u0000\u0000\u011f\u0120\u0005-\u0000\u0000\u0120*"+ - "\u0001\u0000\u0000\u0000\u0121\u0122\u0005*\u0000\u0000\u0122,\u0001\u0000"+ - "\u0000\u0000\u0123\u0124\u0005/\u0000\u0000\u0124.\u0001\u0000\u0000\u0000"+ - "\u0125\u0126\u0005%\u0000\u0000\u01260\u0001\u0000\u0000\u0000\u0127\u0128"+ - "\u0005^\u0000\u0000\u01282\u0001\u0000\u0000\u0000\u0129\u012a\u0005!"+ - "\u0000\u0000\u012a\u012b\u0005=\u0000\u0000\u012b4\u0001\u0000\u0000\u0000"+ - "\u012c\u012d\u0005>\u0000\u0000\u012d6\u0001\u0000\u0000\u0000\u012e\u012f"+ - "\u0005>\u0000\u0000\u012f\u0130\u0005=\u0000\u0000\u01308\u0001\u0000"+ - "\u0000\u0000\u0131\u0132\u0005<\u0000\u0000\u0132:\u0001\u0000\u0000\u0000"+ - "\u0133\u0134\u0005<\u0000\u0000\u0134\u0135\u0005=\u0000\u0000\u0135<"+ - "\u0001\u0000\u0000\u0000\u0136\u0137\u0005=\u0000\u0000\u0137>\u0001\u0000"+ - "\u0000\u0000\u0138\u0139\u0005(\u0000\u0000\u0139@\u0001\u0000\u0000\u0000"+ - "\u013a\u013b\u0005)\u0000\u0000\u013bB\u0001\u0000\u0000\u0000\u013c\u013e"+ - "\u0007\u0000\u0000\u0000\u013d\u013c\u0001\u0000\u0000\u0000\u013e\u013f"+ - "\u0001\u0000\u0000\u0000\u013f\u013d\u0001\u0000\u0000\u0000\u013f\u0140"+ - "\u0001\u0000\u0000\u0000\u0140\u0141\u0001\u0000\u0000\u0000\u0141\u0143"+ - "\u0005.\u0000\u0000\u0142\u0144\u0007\u0000\u0000\u0000\u0143\u0142\u0001"+ - "\u0000\u0000\u0000\u0144\u0145\u0001\u0000\u0000\u0000\u0145\u0143\u0001"+ - "\u0000\u0000\u0000\u0145\u0146\u0001\u0000\u0000\u0000\u0146D\u0001\u0000"+ - "\u0000\u0000\u0147\u014a\u0007\u0000\u0000\u0000\u0148\u0149\u0005.\u0000"+ - "\u0000\u0149\u014b\u0003G#\u0000\u014a\u0148\u0001\u0000\u0000\u0000\u014b"+ - "\u014c\u0001\u0000\u0000\u0000\u014c\u014a\u0001\u0000\u0000\u0000\u014c"+ - "\u014d\u0001\u0000\u0000\u0000\u014dF\u0001\u0000\u0000\u0000\u014e\u0150"+ - "\u0007\u0000\u0000\u0000\u014f\u014e\u0001\u0000\u0000\u0000\u0150\u0151"+ - "\u0001\u0000\u0000\u0000\u0151\u014f\u0001\u0000\u0000\u0000\u0151\u0152"+ - "\u0001\u0000\u0000\u0000\u0152H\u0001\u0000\u0000\u0000\u0153\u0155\u0007"+ - "\u0001\u0000\u0000\u0154\u0153\u0001\u0000\u0000\u0000\u0155\u0156\u0001"+ - "\u0000\u0000\u0000\u0156\u0154\u0001\u0000\u0000\u0000\u0156\u0157\u0001"+ - "\u0000\u0000\u0000\u0157\u0158\u0001\u0000\u0000\u0000\u0158\u0159\u0006"+ - "$\u0000\u0000\u0159J\u0001\u0000\u0000\u0000\u015a\u015d\u0003M&\u0000"+ - "\u015b\u015d\u0003O\'\u0000\u015c\u015a\u0001\u0000\u0000\u0000\u015c"+ - "\u015b\u0001\u0000\u0000\u0000\u015dL\u0001\u0000\u0000\u0000\u015e\u0162"+ - "\u0005\'\u0000\u0000\u015f\u0161\t\u0000\u0000\u0000\u0160\u015f\u0001"+ - "\u0000\u0000\u0000\u0161\u0164\u0001\u0000\u0000\u0000\u0162\u0163\u0001"+ - "\u0000\u0000\u0000\u0162\u0160\u0001\u0000\u0000\u0000\u0163\u0165\u0001"+ - "\u0000\u0000\u0000\u0164\u0162\u0001\u0000\u0000\u0000\u0165\u0166\u0005"+ - "\'\u0000\u0000\u0166N\u0001\u0000\u0000\u0000\u0167\u016b\u0005\"\u0000"+ - "\u0000\u0168\u016a\t\u0000\u0000\u0000\u0169\u0168\u0001\u0000\u0000\u0000"+ - "\u016a\u016d\u0001\u0000\u0000\u0000\u016b\u016c\u0001\u0000\u0000\u0000"+ - "\u016b\u0169\u0001\u0000\u0000\u0000\u016c\u016e\u0001\u0000\u0000\u0000"+ - "\u016d\u016b\u0001\u0000\u0000\u0000\u016e\u016f\u0005\"\u0000\u0000\u016f"+ - "P\u0001\u0000\u0000\u0000\u0170\u0173\u0003S)\u0000\u0171\u0173\u0007"+ - "\u0002\u0000\u0000\u0172\u0170\u0001\u0000\u0000\u0000\u0172\u0171\u0001"+ - "\u0000\u0000\u0000\u0173\u0174\u0001\u0000\u0000\u0000\u0174\u0172\u0001"+ - "\u0000\u0000\u0000\u0174\u0175\u0001\u0000\u0000\u0000\u0175R\u0001\u0000"+ - "\u0000\u0000\u0176\u0177\u0007\u0003\u0000\u0000\u0177T\u0001\u0000\u0000"+ - "\u0000\u0178\u017c\u0005\'\u0000\u0000\u0179\u017b\t\u0000\u0000\u0000"+ - "\u017a\u0179\u0001\u0000\u0000\u0000\u017b\u017e\u0001\u0000\u0000\u0000"+ - "\u017c\u017d\u0001\u0000\u0000\u0000\u017c\u017a\u0001\u0000\u0000\u0000"+ - "\u017d\u017f\u0001\u0000\u0000\u0000\u017e\u017c\u0001\u0000\u0000\u0000"+ - "\u017f\u0180\u0005\'\u0000\u0000\u0180V\u0001\u0000\u0000\u0000\u0181"+ - "\u0185\u0005\"\u0000\u0000\u0182\u0184\t\u0000\u0000\u0000\u0183\u0182"+ - "\u0001\u0000\u0000\u0000\u0184\u0187\u0001\u0000\u0000\u0000\u0185\u0186"+ - "\u0001\u0000\u0000\u0000\u0185\u0183\u0001\u0000\u0000\u0000\u0186\u0188"+ - "\u0001\u0000\u0000\u0000\u0187\u0185\u0001\u0000\u0000\u0000\u0188\u0189"+ - "\u0005\"\u0000\u0000\u0189X\u0001\u0000\u0000\u0000\u001f\u0000_eow\u007f"+ - "\u0089\u0095\u00af\u00c9\u00d1\u00d9\u00e1\u00e9\u00f3\u00fd\u010b\u0113"+ - "\u011b\u013f\u0145\u014c\u0151\u0156\u015c\u0162\u016b\u0172\u0174\u017c"+ - "\u0185\u0001\u0006\u0000\u0000"; + "\u001a\u0001\u001a\u0001\u001a\u0001\u001b\u0001\u001b\u0001\u001c\u0001"+ + "\u001c\u0001\u001c\u0001\u001d\u0001\u001d\u0001\u001e\u0001\u001e\u0001"+ + "\u001e\u0001\u001f\u0001\u001f\u0001 \u0001 \u0001!\u0001!\u0001\"\u0004"+ + "\"\u0162\b\"\u000b\"\f\"\u0163\u0001\"\u0001\"\u0004\"\u0168\b\"\u000b"+ + "\"\f\"\u0169\u0001#\u0001#\u0001#\u0004#\u016f\b#\u000b#\f#\u0170\u0001"+ + "$\u0004$\u0174\b$\u000b$\f$\u0175\u0001%\u0001%\u0001&\u0001&\u0001\'"+ + "\u0004\'\u017d\b\'\u000b\'\f\'\u017e\u0001\'\u0001\'\u0001(\u0001(\u0003"+ + "(\u0185\b(\u0001)\u0001)\u0005)\u0189\b)\n)\f)\u018c\t)\u0001)\u0001)"+ + "\u0001*\u0001*\u0005*\u0192\b*\n*\f*\u0195\t*\u0001*\u0001*\u0001+\u0001"+ + "+\u0004+\u019b\b+\u000b+\f+\u019c\u0001,\u0001,\u0001-\u0001-\u0005-\u01a3"+ + "\b-\n-\f-\u01a6\t-\u0001-\u0001-\u0001.\u0001.\u0005.\u01ac\b.\n.\f.\u01af"+ + "\t.\u0001.\u0001.\u0001/\u0001/\u0001/\u0001/\u0001/\u0001/\u0001/\u0001"+ + "/\u0001/\u0001/\u0001/\u00010\u00010\u00010\u00010\u00010\u00010\u0001"+ + "0\u00010\u00010\u00010\u00010\u00010\u00010\u00010\u00010\u00010\u0001"+ + "0\u00010\u00010\u00010\u0004\u018a\u0193\u01a4\u01ad\u00001\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"+ + "1\u00193\u001a5\u001b7\u001c9\u001d;\u001e=\u001f? A!C\"E#G$I%K&M\'O("+ + "Q)S*U+W,Y-[.]/_\u0000a\u0000\u0001\u0000\u0004\u0001\u000009\u0003\u0000"+ + "\t\n\f\r \u0002\u0000..__\u0003\u000009AZaz\u01ef\u0000\u0001\u0001\u0000"+ + "\u0000\u0000\u0000\u0003\u0001\u0000\u0000\u0000\u0000\u0005\u0001\u0000"+ + "\u0000\u0000\u0000\u0007\u0001\u0000\u0000\u0000\u0000\t\u0001\u0000\u0000"+ + "\u0000\u0000\u000b\u0001\u0000\u0000\u0000\u0000\r\u0001\u0000\u0000\u0000"+ + "\u0000\u000f\u0001\u0000\u0000\u0000\u0000\u0011\u0001\u0000\u0000\u0000"+ + "\u0000\u0013\u0001\u0000\u0000\u0000\u0000\u0015\u0001\u0000\u0000\u0000"+ + "\u0000\u0017\u0001\u0000\u0000\u0000\u0000\u0019\u0001\u0000\u0000\u0000"+ + "\u0000\u001b\u0001\u0000\u0000\u0000\u0000\u001d\u0001\u0000\u0000\u0000"+ + "\u0000\u001f\u0001\u0000\u0000\u0000\u0000!\u0001\u0000\u0000\u0000\u0000"+ + "#\u0001\u0000\u0000\u0000\u0000%\u0001\u0000\u0000\u0000\u0000\'\u0001"+ + "\u0000\u0000\u0000\u0000)\u0001\u0000\u0000\u0000\u0000+\u0001\u0000\u0000"+ + "\u0000\u0000-\u0001\u0000\u0000\u0000\u0000/\u0001\u0000\u0000\u0000\u0000"+ + "1\u0001\u0000\u0000\u0000\u00003\u0001\u0000\u0000\u0000\u00005\u0001"+ + "\u0000\u0000\u0000\u00007\u0001\u0000\u0000\u0000\u00009\u0001\u0000\u0000"+ + "\u0000\u0000;\u0001\u0000\u0000\u0000\u0000=\u0001\u0000\u0000\u0000\u0000"+ + "?\u0001\u0000\u0000\u0000\u0000A\u0001\u0000\u0000\u0000\u0000C\u0001"+ + "\u0000\u0000\u0000\u0000E\u0001\u0000\u0000\u0000\u0000G\u0001\u0000\u0000"+ + "\u0000\u0000I\u0001\u0000\u0000\u0000\u0000K\u0001\u0000\u0000\u0000\u0000"+ + "M\u0001\u0000\u0000\u0000\u0000O\u0001\u0000\u0000\u0000\u0000Q\u0001"+ + "\u0000\u0000\u0000\u0000S\u0001\u0000\u0000\u0000\u0000U\u0001\u0000\u0000"+ + "\u0000\u0000W\u0001\u0000\u0000\u0000\u0000Y\u0001\u0000\u0000\u0000\u0000"+ + "[\u0001\u0000\u0000\u0000\u0000]\u0001\u0000\u0000\u0000\u0001c\u0001"+ + "\u0000\u0000\u0000\u0003i\u0001\u0000\u0000\u0000\u0005o\u0001\u0000\u0000"+ + "\u0000\u0007y\u0001\u0000\u0000\u0000\t\u0081\u0001\u0000\u0000\u0000"+ + "\u000b\u0089\u0001\u0000\u0000\u0000\r\u0093\u0001\u0000\u0000\u0000\u000f"+ + "\u009f\u0001\u0000\u0000\u0000\u0011\u00b9\u0001\u0000\u0000\u0000\u0013"+ + "\u00d3\u0001\u0000\u0000\u0000\u0015\u00db\u0001\u0000\u0000\u0000\u0017"+ + "\u00e3\u0001\u0000\u0000\u0000\u0019\u00eb\u0001\u0000\u0000\u0000\u001b"+ + "\u00f3\u0001\u0000\u0000\u0000\u001d\u00fd\u0001\u0000\u0000\u0000\u001f"+ + "\u0107\u0001\u0000\u0000\u0000!\u0115\u0001\u0000\u0000\u0000#\u011d\u0001"+ + "\u0000\u0000\u0000%\u0125\u0001\u0000\u0000\u0000\'\u013f\u0001\u0000"+ + "\u0000\u0000)\u0141\u0001\u0000\u0000\u0000+\u0143\u0001\u0000\u0000\u0000"+ + "-\u0145\u0001\u0000\u0000\u0000/\u0147\u0001\u0000\u0000\u00001\u0149"+ + "\u0001\u0000\u0000\u00003\u014b\u0001\u0000\u0000\u00005\u014d\u0001\u0000"+ + "\u0000\u00007\u0150\u0001\u0000\u0000\u00009\u0152\u0001\u0000\u0000\u0000"+ + ";\u0155\u0001\u0000\u0000\u0000=\u0157\u0001\u0000\u0000\u0000?\u015a"+ + "\u0001\u0000\u0000\u0000A\u015c\u0001\u0000\u0000\u0000C\u015e\u0001\u0000"+ + "\u0000\u0000E\u0161\u0001\u0000\u0000\u0000G\u016b\u0001\u0000\u0000\u0000"+ + "I\u0173\u0001\u0000\u0000\u0000K\u0177\u0001\u0000\u0000\u0000M\u0179"+ + "\u0001\u0000\u0000\u0000O\u017c\u0001\u0000\u0000\u0000Q\u0184\u0001\u0000"+ + "\u0000\u0000S\u0186\u0001\u0000\u0000\u0000U\u018f\u0001\u0000\u0000\u0000"+ + "W\u019a\u0001\u0000\u0000\u0000Y\u019e\u0001\u0000\u0000\u0000[\u01a0"+ + "\u0001\u0000\u0000\u0000]\u01a9\u0001\u0000\u0000\u0000_\u01b2\u0001\u0000"+ + "\u0000\u0000a\u01bd\u0001\u0000\u0000\u0000cd\u0005,\u0000\u0000d\u0002"+ + "\u0001\u0000\u0000\u0000ef\u0005I\u0000\u0000fj\u0005N\u0000\u0000gh\u0005"+ + "i\u0000\u0000hj\u0005n\u0000\u0000ie\u0001\u0000\u0000\u0000ig\u0001\u0000"+ + "\u0000\u0000j\u0004\u0001\u0000\u0000\u0000kl\u0005T\u0000\u0000lp\u0005"+ + "O\u0000\u0000mn\u0005t\u0000\u0000np\u0005o\u0000\u0000ok\u0001\u0000"+ + "\u0000\u0000om\u0001\u0000\u0000\u0000p\u0006\u0001\u0000\u0000\u0000"+ + "qr\u0005A\u0000\u0000rs\u0005N\u0000\u0000sz\u0005D\u0000\u0000tu\u0005"+ + "a\u0000\u0000uv\u0005n\u0000\u0000vz\u0005d\u0000\u0000wx\u0005&\u0000"+ + "\u0000xz\u0005&\u0000\u0000yq\u0001\u0000\u0000\u0000yt\u0001\u0000\u0000"+ + "\u0000yw\u0001\u0000\u0000\u0000z\b\u0001\u0000\u0000\u0000{|\u0005O\u0000"+ + "\u0000|\u0082\u0005R\u0000\u0000}~\u0005o\u0000\u0000~\u0082\u0005r\u0000"+ + "\u0000\u007f\u0080\u0005|\u0000\u0000\u0080\u0082\u0005|\u0000\u0000\u0081"+ + "{\u0001\u0000\u0000\u0000\u0081}\u0001\u0000\u0000\u0000\u0081\u007f\u0001"+ + "\u0000\u0000\u0000\u0082\n\u0001\u0000\u0000\u0000\u0083\u0084\u0005N"+ + "\u0000\u0000\u0084\u0085\u0005O\u0000\u0000\u0085\u008a\u0005T\u0000\u0000"+ + "\u0086\u0087\u0005n\u0000\u0000\u0087\u0088\u0005o\u0000\u0000\u0088\u008a"+ + "\u0005t\u0000\u0000\u0089\u0083\u0001\u0000\u0000\u0000\u0089\u0086\u0001"+ + "\u0000\u0000\u0000\u008a\f\u0001\u0000\u0000\u0000\u008b\u008c\u0005T"+ + "\u0000\u0000\u008c\u008d\u0005R\u0000\u0000\u008d\u008e\u0005U\u0000\u0000"+ + "\u008e\u0094\u0005E\u0000\u0000\u008f\u0090\u0005t\u0000\u0000\u0090\u0091"+ + "\u0005r\u0000\u0000\u0091\u0092\u0005u\u0000\u0000\u0092\u0094\u0005e"+ + "\u0000\u0000\u0093\u008b\u0001\u0000\u0000\u0000\u0093\u008f\u0001\u0000"+ + "\u0000\u0000\u0094\u000e\u0001\u0000\u0000\u0000\u0095\u0096\u0005F\u0000"+ + "\u0000\u0096\u0097\u0005A\u0000\u0000\u0097\u0098\u0005L\u0000\u0000\u0098"+ + "\u0099\u0005S\u0000\u0000\u0099\u00a0\u0005E\u0000\u0000\u009a\u009b\u0005"+ + "f\u0000\u0000\u009b\u009c\u0005a\u0000\u0000\u009c\u009d\u0005l\u0000"+ + "\u0000\u009d\u009e\u0005s\u0000\u0000\u009e\u00a0\u0005e\u0000\u0000\u009f"+ + "\u0095\u0001\u0000\u0000\u0000\u009f\u009a\u0001\u0000\u0000\u0000\u00a0"+ + "\u0010\u0001\u0000\u0000\u0000\u00a1\u00a2\u0005C\u0000\u0000\u00a2\u00a3"+ + "\u0005O\u0000\u0000\u00a3\u00a4\u0005N\u0000\u0000\u00a4\u00a5\u0005T"+ + "\u0000\u0000\u00a5\u00a6\u0005A\u0000\u0000\u00a6\u00a7\u0005I\u0000\u0000"+ + "\u00a7\u00a8\u0005N\u0000\u0000\u00a8\u00a9\u0005S\u0000\u0000\u00a9\u00aa"+ + "\u0005_\u0000\u0000\u00aa\u00ab\u0005A\u0000\u0000\u00ab\u00ac\u0005L"+ + "\u0000\u0000\u00ac\u00ba\u0005L\u0000\u0000\u00ad\u00ae\u0005c\u0000\u0000"+ + "\u00ae\u00af\u0005o\u0000\u0000\u00af\u00b0\u0005n\u0000\u0000\u00b0\u00b1"+ + "\u0005t\u0000\u0000\u00b1\u00b2\u0005a\u0000\u0000\u00b2\u00b3\u0005i"+ + "\u0000\u0000\u00b3\u00b4\u0005n\u0000\u0000\u00b4\u00b5\u0005s\u0000\u0000"+ + "\u00b5\u00b6\u0005_\u0000\u0000\u00b6\u00b7\u0005a\u0000\u0000\u00b7\u00b8"+ + "\u0005l\u0000\u0000\u00b8\u00ba\u0005l\u0000\u0000\u00b9\u00a1\u0001\u0000"+ + "\u0000\u0000\u00b9\u00ad\u0001\u0000\u0000\u0000\u00ba\u0012\u0001\u0000"+ + "\u0000\u0000\u00bb\u00bc\u0005C\u0000\u0000\u00bc\u00bd\u0005O\u0000\u0000"+ + "\u00bd\u00be\u0005N\u0000\u0000\u00be\u00bf\u0005T\u0000\u0000\u00bf\u00c0"+ + "\u0005A\u0000\u0000\u00c0\u00c1\u0005I\u0000\u0000\u00c1\u00c2\u0005N"+ + "\u0000\u0000\u00c2\u00c3\u0005S\u0000\u0000\u00c3\u00c4\u0005_\u0000\u0000"+ + "\u00c4\u00c5\u0005A\u0000\u0000\u00c5\u00c6\u0005N\u0000\u0000\u00c6\u00d4"+ + "\u0005Y\u0000\u0000\u00c7\u00c8\u0005c\u0000\u0000\u00c8\u00c9\u0005o"+ + "\u0000\u0000\u00c9\u00ca\u0005n\u0000\u0000\u00ca\u00cb\u0005t\u0000\u0000"+ + "\u00cb\u00cc\u0005a\u0000\u0000\u00cc\u00cd\u0005i\u0000\u0000\u00cd\u00ce"+ + "\u0005n\u0000\u0000\u00ce\u00cf\u0005s\u0000\u0000\u00cf\u00d0\u0005_"+ + "\u0000\u0000\u00d0\u00d1\u0005a\u0000\u0000\u00d1\u00d2\u0005n\u0000\u0000"+ + "\u00d2\u00d4\u0005y\u0000\u0000\u00d3\u00bb\u0001\u0000\u0000\u0000\u00d3"+ + "\u00c7\u0001\u0000\u0000\u0000\u00d4\u0014\u0001\u0000\u0000\u0000\u00d5"+ + "\u00d6\u0005M\u0000\u0000\u00d6\u00d7\u0005I\u0000\u0000\u00d7\u00dc\u0005"+ + "N\u0000\u0000\u00d8\u00d9\u0005m\u0000\u0000\u00d9\u00da\u0005i\u0000"+ + "\u0000\u00da\u00dc\u0005n\u0000\u0000\u00db\u00d5\u0001\u0000\u0000\u0000"+ + "\u00db\u00d8\u0001\u0000\u0000\u0000\u00dc\u0016\u0001\u0000\u0000\u0000"+ + "\u00dd\u00de\u0005M\u0000\u0000\u00de\u00df\u0005A\u0000\u0000\u00df\u00e4"+ + "\u0005X\u0000\u0000\u00e0\u00e1\u0005m\u0000\u0000\u00e1\u00e2\u0005a"+ + "\u0000\u0000\u00e2\u00e4\u0005x\u0000\u0000\u00e3\u00dd\u0001\u0000\u0000"+ + "\u0000\u00e3\u00e0\u0001\u0000\u0000\u0000\u00e4\u0018\u0001\u0000\u0000"+ + "\u0000\u00e5\u00e6\u0005A\u0000\u0000\u00e6\u00e7\u0005V\u0000\u0000\u00e7"+ + "\u00ec\u0005G\u0000\u0000\u00e8\u00e9\u0005a\u0000\u0000\u00e9\u00ea\u0005"+ + "v\u0000\u0000\u00ea\u00ec\u0005g\u0000\u0000\u00eb\u00e5\u0001\u0000\u0000"+ + "\u0000\u00eb\u00e8\u0001\u0000\u0000\u0000\u00ec\u001a\u0001\u0000\u0000"+ + "\u0000\u00ed\u00ee\u0005S\u0000\u0000\u00ee\u00ef\u0005U\u0000\u0000\u00ef"+ + "\u00f4\u0005M\u0000\u0000\u00f0\u00f1\u0005s\u0000\u0000\u00f1\u00f2\u0005"+ + "u\u0000\u0000\u00f2\u00f4\u0005m\u0000\u0000\u00f3\u00ed\u0001\u0000\u0000"+ + "\u0000\u00f3\u00f0\u0001\u0000\u0000\u0000\u00f4\u001c\u0001\u0000\u0000"+ + "\u0000\u00f5\u00f6\u0005M\u0000\u0000\u00f6\u00f7\u0005E\u0000\u0000\u00f7"+ + "\u00f8\u0005A\u0000\u0000\u00f8\u00fe\u0005N\u0000\u0000\u00f9\u00fa\u0005"+ + "m\u0000\u0000\u00fa\u00fb\u0005e\u0000\u0000\u00fb\u00fc\u0005a\u0000"+ + "\u0000\u00fc\u00fe\u0005n\u0000\u0000\u00fd\u00f5\u0001\u0000\u0000\u0000"+ + "\u00fd\u00f9\u0001\u0000\u0000\u0000\u00fe\u001e\u0001\u0000\u0000\u0000"+ + "\u00ff\u0100\u0005M\u0000\u0000\u0100\u0101\u0005O\u0000\u0000\u0101\u0102"+ + "\u0005D\u0000\u0000\u0102\u0108\u0005E\u0000\u0000\u0103\u0104\u0005m"+ + "\u0000\u0000\u0104\u0105\u0005o\u0000\u0000\u0105\u0106\u0005d\u0000\u0000"+ + "\u0106\u0108\u0005e\u0000\u0000\u0107\u00ff\u0001\u0000\u0000\u0000\u0107"+ + "\u0103\u0001\u0000\u0000\u0000\u0108 \u0001\u0000\u0000\u0000\u0109\u010a"+ + "\u0005M\u0000\u0000\u010a\u010b\u0005E\u0000\u0000\u010b\u010c\u0005D"+ + "\u0000\u0000\u010c\u010d\u0005I\u0000\u0000\u010d\u010e\u0005A\u0000\u0000"+ + "\u010e\u0116\u0005N\u0000\u0000\u010f\u0110\u0005m\u0000\u0000\u0110\u0111"+ + "\u0005e\u0000\u0000\u0111\u0112\u0005d\u0000\u0000\u0112\u0113\u0005i"+ + "\u0000\u0000\u0113\u0114\u0005a\u0000\u0000\u0114\u0116\u0005n\u0000\u0000"+ + "\u0115\u0109\u0001\u0000\u0000\u0000\u0115\u010f\u0001\u0000\u0000\u0000"+ + "\u0116\"\u0001\u0000\u0000\u0000\u0117\u0118\u0005L\u0000\u0000\u0118"+ + "\u0119\u0005E\u0000\u0000\u0119\u011e\u0005N\u0000\u0000\u011a\u011b\u0005"+ + "l\u0000\u0000\u011b\u011c\u0005e\u0000\u0000\u011c\u011e\u0005n\u0000"+ + "\u0000\u011d\u0117\u0001\u0000\u0000\u0000\u011d\u011a\u0001\u0000\u0000"+ + "\u0000\u011e$\u0001\u0000\u0000\u0000\u011f\u0120\u0005I\u0000\u0000\u0120"+ + "\u0121\u0005N\u0000\u0000\u0121\u0126\u0005T\u0000\u0000\u0122\u0123\u0005"+ + "i\u0000\u0000\u0123\u0124\u0005n\u0000\u0000\u0124\u0126\u0005t\u0000"+ + "\u0000\u0125\u011f\u0001\u0000\u0000\u0000\u0125\u0122\u0001\u0000\u0000"+ + "\u0000\u0126&\u0001\u0000\u0000\u0000\u0127\u0128\u0005D\u0000\u0000\u0128"+ + "\u0129\u0005A\u0000\u0000\u0129\u012a\u0005Y\u0000\u0000\u012a\u012b\u0005"+ + "S\u0000\u0000\u012b\u012c\u0005_\u0000\u0000\u012c\u012d\u0005E\u0000"+ + "\u0000\u012d\u012e\u0005L\u0000\u0000\u012e\u012f\u0005A\u0000\u0000\u012f"+ + "\u0130\u0005P\u0000\u0000\u0130\u0131\u0005S\u0000\u0000\u0131\u0132\u0005"+ + "E\u0000\u0000\u0132\u0140\u0005D\u0000\u0000\u0133\u0134\u0005d\u0000"+ + "\u0000\u0134\u0135\u0005a\u0000\u0000\u0135\u0136\u0005y\u0000\u0000\u0136"+ + "\u0137\u0005s\u0000\u0000\u0137\u0138\u0005_\u0000\u0000\u0138\u0139\u0005"+ + "e\u0000\u0000\u0139\u013a\u0005l\u0000\u0000\u013a\u013b\u0005a\u0000"+ + "\u0000\u013b\u013c\u0005p\u0000\u0000\u013c\u013d\u0005s\u0000\u0000\u013d"+ + "\u013e\u0005e\u0000\u0000\u013e\u0140\u0005d\u0000\u0000\u013f\u0127\u0001"+ + "\u0000\u0000\u0000\u013f\u0133\u0001\u0000\u0000\u0000\u0140(\u0001\u0000"+ + "\u0000\u0000\u0141\u0142\u0005+\u0000\u0000\u0142*\u0001\u0000\u0000\u0000"+ + "\u0143\u0144\u0005-\u0000\u0000\u0144,\u0001\u0000\u0000\u0000\u0145\u0146"+ + "\u0005*\u0000\u0000\u0146.\u0001\u0000\u0000\u0000\u0147\u0148\u0005/"+ + "\u0000\u0000\u01480\u0001\u0000\u0000\u0000\u0149\u014a\u0005%\u0000\u0000"+ + "\u014a2\u0001\u0000\u0000\u0000\u014b\u014c\u0005^\u0000\u0000\u014c4"+ + "\u0001\u0000\u0000\u0000\u014d\u014e\u0005!\u0000\u0000\u014e\u014f\u0005"+ + "=\u0000\u0000\u014f6\u0001\u0000\u0000\u0000\u0150\u0151\u0005>\u0000"+ + "\u0000\u01518\u0001\u0000\u0000\u0000\u0152\u0153\u0005>\u0000\u0000\u0153"+ + "\u0154\u0005=\u0000\u0000\u0154:\u0001\u0000\u0000\u0000\u0155\u0156\u0005"+ + "<\u0000\u0000\u0156<\u0001\u0000\u0000\u0000\u0157\u0158\u0005<\u0000"+ + "\u0000\u0158\u0159\u0005=\u0000\u0000\u0159>\u0001\u0000\u0000\u0000\u015a"+ + "\u015b\u0005=\u0000\u0000\u015b@\u0001\u0000\u0000\u0000\u015c\u015d\u0005"+ + "(\u0000\u0000\u015dB\u0001\u0000\u0000\u0000\u015e\u015f\u0005)\u0000"+ + "\u0000\u015fD\u0001\u0000\u0000\u0000\u0160\u0162\u0007\u0000\u0000\u0000"+ + "\u0161\u0160\u0001\u0000\u0000\u0000\u0162\u0163\u0001\u0000\u0000\u0000"+ + "\u0163\u0161\u0001\u0000\u0000\u0000\u0163\u0164\u0001\u0000\u0000\u0000"+ + "\u0164\u0165\u0001\u0000\u0000\u0000\u0165\u0167\u0005.\u0000\u0000\u0166"+ + "\u0168\u0007\u0000\u0000\u0000\u0167\u0166\u0001\u0000\u0000\u0000\u0168"+ + "\u0169\u0001\u0000\u0000\u0000\u0169\u0167\u0001\u0000\u0000\u0000\u0169"+ + "\u016a\u0001\u0000\u0000\u0000\u016aF\u0001\u0000\u0000\u0000\u016b\u016e"+ + "\u0007\u0000\u0000\u0000\u016c\u016d\u0005.\u0000\u0000\u016d\u016f\u0003"+ + "I$\u0000\u016e\u016c\u0001\u0000\u0000\u0000\u016f\u0170\u0001\u0000\u0000"+ + "\u0000\u0170\u016e\u0001\u0000\u0000\u0000\u0170\u0171\u0001\u0000\u0000"+ + "\u0000\u0171H\u0001\u0000\u0000\u0000\u0172\u0174\u0007\u0000\u0000\u0000"+ + "\u0173\u0172\u0001\u0000\u0000\u0000\u0174\u0175\u0001\u0000\u0000\u0000"+ + "\u0175\u0173\u0001\u0000\u0000\u0000\u0175\u0176\u0001\u0000\u0000\u0000"+ + "\u0176J\u0001\u0000\u0000\u0000\u0177\u0178\u0003_/\u0000\u0178L\u0001"+ + "\u0000\u0000\u0000\u0179\u017a\u0003a0\u0000\u017aN\u0001\u0000\u0000"+ + "\u0000\u017b\u017d\u0007\u0001\u0000\u0000\u017c\u017b\u0001\u0000\u0000"+ + "\u0000\u017d\u017e\u0001\u0000\u0000\u0000\u017e\u017c\u0001\u0000\u0000"+ + "\u0000\u017e\u017f\u0001\u0000\u0000\u0000\u017f\u0180\u0001\u0000\u0000"+ + "\u0000\u0180\u0181\u0006\'\u0000\u0000\u0181P\u0001\u0000\u0000\u0000"+ + "\u0182\u0185\u0003S)\u0000\u0183\u0185\u0003U*\u0000\u0184\u0182\u0001"+ + "\u0000\u0000\u0000\u0184\u0183\u0001\u0000\u0000\u0000\u0185R\u0001\u0000"+ + "\u0000\u0000\u0186\u018a\u0005\'\u0000\u0000\u0187\u0189\t\u0000\u0000"+ + "\u0000\u0188\u0187\u0001\u0000\u0000\u0000\u0189\u018c\u0001\u0000\u0000"+ + "\u0000\u018a\u018b\u0001\u0000\u0000\u0000\u018a\u0188\u0001\u0000\u0000"+ + "\u0000\u018b\u018d\u0001\u0000\u0000\u0000\u018c\u018a\u0001\u0000\u0000"+ + "\u0000\u018d\u018e\u0005\'\u0000\u0000\u018eT\u0001\u0000\u0000\u0000"+ + "\u018f\u0193\u0005\"\u0000\u0000\u0190\u0192\t\u0000\u0000\u0000\u0191"+ + "\u0190\u0001\u0000\u0000\u0000\u0192\u0195\u0001\u0000\u0000\u0000\u0193"+ + "\u0194\u0001\u0000\u0000\u0000\u0193\u0191\u0001\u0000\u0000\u0000\u0194"+ + "\u0196\u0001\u0000\u0000\u0000\u0195\u0193\u0001\u0000\u0000\u0000\u0196"+ + "\u0197\u0005\"\u0000\u0000\u0197V\u0001\u0000\u0000\u0000\u0198\u019b"+ + "\u0003Y,\u0000\u0199\u019b\u0007\u0002\u0000\u0000\u019a\u0198\u0001\u0000"+ + "\u0000\u0000\u019a\u0199\u0001\u0000\u0000\u0000\u019b\u019c\u0001\u0000"+ + "\u0000\u0000\u019c\u019a\u0001\u0000\u0000\u0000\u019c\u019d\u0001\u0000"+ + "\u0000\u0000\u019dX\u0001\u0000\u0000\u0000\u019e\u019f\u0007\u0003\u0000"+ + "\u0000\u019fZ\u0001\u0000\u0000\u0000\u01a0\u01a4\u0005\'\u0000\u0000"+ + "\u01a1\u01a3\t\u0000\u0000\u0000\u01a2\u01a1\u0001\u0000\u0000\u0000\u01a3"+ + "\u01a6\u0001\u0000\u0000\u0000\u01a4\u01a5\u0001\u0000\u0000\u0000\u01a4"+ + "\u01a2\u0001\u0000\u0000\u0000\u01a5\u01a7\u0001\u0000\u0000\u0000\u01a6"+ + "\u01a4\u0001\u0000\u0000\u0000\u01a7\u01a8\u0005\'\u0000\u0000\u01a8\\"+ + "\u0001\u0000\u0000\u0000\u01a9\u01ad\u0005\"\u0000\u0000\u01aa\u01ac\t"+ + "\u0000\u0000\u0000\u01ab\u01aa\u0001\u0000\u0000\u0000\u01ac\u01af\u0001"+ + "\u0000\u0000\u0000\u01ad\u01ae\u0001\u0000\u0000\u0000\u01ad\u01ab\u0001"+ + "\u0000\u0000\u0000\u01ae\u01b0\u0001\u0000\u0000\u0000\u01af\u01ad\u0001"+ + "\u0000\u0000\u0000\u01b0\u01b1\u0005\"\u0000\u0000\u01b1^\u0001\u0000"+ + "\u0000\u0000\u01b2\u01b3\u0007\u0000\u0000\u0000\u01b3\u01b4\u0007\u0000"+ + "\u0000\u0000\u01b4\u01b5\u0007\u0000\u0000\u0000\u01b5\u01b6\u0007\u0000"+ + "\u0000\u0000\u01b6\u01b7\u0005-\u0000\u0000\u01b7\u01b8\u0007\u0000\u0000"+ + "\u0000\u01b8\u01b9\u0007\u0000\u0000\u0000\u01b9\u01ba\u0005-\u0000\u0000"+ + "\u01ba\u01bb\u0007\u0000\u0000\u0000\u01bb\u01bc\u0007\u0000\u0000\u0000"+ + "\u01bc`\u0001\u0000\u0000\u0000\u01bd\u01be\u0007\u0000\u0000\u0000\u01be"+ + "\u01bf\u0007\u0000\u0000\u0000\u01bf\u01c0\u0007\u0000\u0000\u0000\u01c0"+ + "\u01c1\u0007\u0000\u0000\u0000\u01c1\u01c2\u0005-\u0000\u0000\u01c2\u01c3"+ + "\u0007\u0000\u0000\u0000\u01c3\u01c4\u0007\u0000\u0000\u0000\u01c4\u01c5"+ + "\u0005-\u0000\u0000\u01c5\u01c6\u0007\u0000\u0000\u0000\u01c6\u01c7\u0007"+ + "\u0000\u0000\u0000\u01c7\u01c8\u0005 \u0000\u0000\u01c8\u01c9\u0007\u0000"+ + "\u0000\u0000\u01c9\u01ca\u0007\u0000\u0000\u0000\u01ca\u01cb\u0005:\u0000"+ + "\u0000\u01cb\u01cc\u0007\u0000\u0000\u0000\u01cc\u01cd\u0007\u0000\u0000"+ + "\u0000\u01cd\u01ce\u0005:\u0000\u0000\u01ce\u01cf\u0007\u0000\u0000\u0000"+ + "\u01cf\u01d0\u0007\u0000\u0000\u0000\u01d0b\u0001\u0000\u0000\u0000 \u0000"+ + "ioy\u0081\u0089\u0093\u009f\u00b9\u00d3\u00db\u00e3\u00eb\u00f3\u00fd"+ + "\u0107\u0115\u011d\u0125\u013f\u0163\u0169\u0170\u0175\u017e\u0184\u018a"+ + "\u0193\u019a\u019c\u01a4\u01ad\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 8c2d033..9015db0 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,5 @@ -package com.github.sidhant92.boolparser.parser.antlr;// Generated from /Users/sid/Desktop/filter2/BooleanExpression.g4 by ANTLR 4.13.1 +// Generated from /Users/sidhantaggarwal/bool-parser-java/src/main/java/resources/BooleanExpression.g4 by ANTLR 4.13.2 +package com.github.sidhant92.boolparser.parser.antlr; import org.antlr.v4.runtime.tree.ParseTreeListener; /** 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 6589155..9ce4e3c 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,5 @@ -package com.github.sidhant92.boolparser.parser.antlr;// Generated from /Users/sid/Desktop/filter2/BooleanExpression.g4 by ANTLR 4.13.1 +// Generated from /Users/sidhantaggarwal/bool-parser-java/src/main/java/resources/BooleanExpression.g4 by ANTLR 4.13.2 +package com.github.sidhant92.boolparser.parser.antlr; import org.antlr.v4.runtime.atn.*; import org.antlr.v4.runtime.dfa.DFA; import org.antlr.v4.runtime.*; @@ -8,9 +9,9 @@ import java.util.Iterator; import java.util.ArrayList; -@SuppressWarnings({"all", "warnings", "unchecked", "unused", "cast", "CheckReturnValue"}) +@SuppressWarnings({"all", "warnings", "unchecked", "unused", "cast", "CheckReturnValue", "this-escape"}) public class BooleanExpressionParser extends Parser { - static { RuntimeMetaData.checkVersion("4.13.1", RuntimeMetaData.VERSION); } + static { RuntimeMetaData.checkVersion("4.13.2", RuntimeMetaData.VERSION); } protected static final DFA[] _decisionToDFA; protected static final PredictionContextCache _sharedContextCache = @@ -18,10 +19,11 @@ public class BooleanExpressionParser extends Parser { public static final int T__0=1, IN=2, TO=3, AND=4, OR=5, NOT=6, TRUE=7, FALSE=8, CONTAINS_ALL=9, CONTAINS_ANY=10, MIN=11, MAX=12, AVG=13, SUM=14, MEAN=15, MODE=16, MEDIAN=17, - LEN=18, INT=19, ADD=20, SUBTRACT=21, MULTIPLY=22, DIVIDE=23, MODULUS=24, - EXPONENT=25, NE=26, GT=27, GE=28, LT=29, LE=30, EQ=31, LPAREN=32, RPAREN=33, - DECIMAL=34, APP_VERSION=35, INTEGER=36, WS=37, WORD=38, SQSTR=39, DQSTR=40, - FIELD=41, ALPHANUMERIC=42, SQ=43, DQ=44; + LEN=18, INT=19, DAYS_ELAPSED=20, ADD=21, SUBTRACT=22, MULTIPLY=23, DIVIDE=24, + MODULUS=25, EXPONENT=26, NE=27, GT=28, GE=29, LT=30, LE=31, EQ=32, LPAREN=33, + RPAREN=34, DECIMAL=35, APP_VERSION=36, INTEGER=37, DATE=38, DATETIME=39, + WS=40, WORD=41, SQSTR=42, DQSTR=43, FIELD=44, ALPHANUMERIC=45, SQ=46, + DQ=47; public static final int RULE_parse = 0, RULE_expression = 1, RULE_comparator = 2, RULE_arithmeticOperator = 3, RULE_arithmeticFunction = 4, RULE_wordlist = 5, RULE_arrayOperators = 6, @@ -37,7 +39,7 @@ private static String[] makeRuleNames() { private static String[] makeLiteralNames() { return new String[] { null, "','", null, null, null, null, null, null, null, null, null, null, - null, null, null, null, null, null, null, null, "'+'", "'-'", "'*'", + null, null, null, null, null, null, null, null, null, "'+'", "'-'", "'*'", "'/'", "'%'", "'^'", "'!='", "'>'", "'>='", "'<'", "'<='", "'='", "'('", "')'" }; @@ -47,10 +49,10 @@ private static String[] makeSymbolicNames() { return new String[] { null, null, "IN", "TO", "AND", "OR", "NOT", "TRUE", "FALSE", "CONTAINS_ALL", "CONTAINS_ANY", "MIN", "MAX", "AVG", "SUM", "MEAN", "MODE", "MEDIAN", - "LEN", "INT", "ADD", "SUBTRACT", "MULTIPLY", "DIVIDE", "MODULUS", "EXPONENT", - "NE", "GT", "GE", "LT", "LE", "EQ", "LPAREN", "RPAREN", "DECIMAL", "APP_VERSION", - "INTEGER", "WS", "WORD", "SQSTR", "DQSTR", "FIELD", "ALPHANUMERIC", "SQ", - "DQ" + "LEN", "INT", "DAYS_ELAPSED", "ADD", "SUBTRACT", "MULTIPLY", "DIVIDE", + "MODULUS", "EXPONENT", "NE", "GT", "GE", "LT", "LE", "EQ", "LPAREN", + "RPAREN", "DECIMAL", "APP_VERSION", "INTEGER", "DATE", "DATETIME", "WS", + "WORD", "SQSTR", "DQSTR", "FIELD", "ALPHANUMERIC", "SQ", "DQ" }; } private static final String[] _SYMBOLIC_NAMES = makeSymbolicNames(); @@ -687,7 +689,7 @@ public final ComparatorContext comparator() throws RecognitionException { { setState(86); _la = _input.LA(1); - if ( !((((_la) & ~0x3f) == 0 && ((1L << _la) & 4227858432L) != 0)) ) { + if ( !((((_la) & ~0x3f) == 0 && ((1L << _la) & 8455716864L) != 0)) ) { _errHandler.recoverInline(this); } else { @@ -739,7 +741,7 @@ public final ArithmeticOperatorContext arithmeticOperator() throws RecognitionEx { setState(88); _la = _input.LA(1); - if ( !((((_la) & ~0x3f) == 0 && ((1L << _la) & 66060288L) != 0)) ) { + if ( !((((_la) & ~0x3f) == 0 && ((1L << _la) & 132120576L) != 0)) ) { _errHandler.recoverInline(this); } else { @@ -771,6 +773,7 @@ public static class ArithmeticFunctionContext extends ParserRuleContext { public TerminalNode LEN() { return getToken(BooleanExpressionParser.LEN, 0); } public TerminalNode MEDIAN() { return getToken(BooleanExpressionParser.MEDIAN, 0); } public TerminalNode INT() { return getToken(BooleanExpressionParser.INT, 0); } + public TerminalNode DAYS_ELAPSED() { return getToken(BooleanExpressionParser.DAYS_ELAPSED, 0); } public ArithmeticFunctionContext(ParserRuleContext parent, int invokingState) { super(parent, invokingState); } @@ -794,7 +797,7 @@ public final ArithmeticFunctionContext arithmeticFunction() throws RecognitionEx { setState(90); _la = _input.LA(1); - if ( !((((_la) & ~0x3f) == 0 && ((1L << _la) & 1046528L) != 0)) ) { + if ( !((((_la) & ~0x3f) == 0 && ((1L << _la) & 2095104L) != 0)) ) { _errHandler.recoverInline(this); } else { @@ -1054,6 +1057,8 @@ public BoolContext bool() { } public TerminalNode WORD() { return getToken(BooleanExpressionParser.WORD, 0); } public TerminalNode FIELD() { return getToken(BooleanExpressionParser.FIELD, 0); } + public TerminalNode DATE() { return getToken(BooleanExpressionParser.DATE, 0); } + public TerminalNode DATETIME() { return getToken(BooleanExpressionParser.DATETIME, 0); } public TypesContext(ParserRuleContext parent, int invokingState) { super(parent, invokingState); } @@ -1072,7 +1077,7 @@ public final TypesContext types() throws RecognitionException { TypesContext _localctx = new TypesContext(_ctx, getState()); enterRule(_localctx, 16, RULE_types); try { - setState(138); + setState(140); _errHandler.sync(this); switch ( getInterpreter().adaptivePredict(_input,9,_ctx) ) { case 1: @@ -1120,6 +1125,20 @@ public final TypesContext types() throws RecognitionException { case 7: enterOuterAlt(_localctx, 7); { + setState(137); + match(DATE); + } + break; + case 8: + enterOuterAlt(_localctx, 8); + { + setState(138); + match(DATETIME); + } + break; + case 9: + enterOuterAlt(_localctx, 9); + { } break; } @@ -1160,7 +1179,7 @@ public final BinaryContext binary() throws RecognitionException { try { enterOuterAlt(_localctx, 1); { - setState(140); + setState(142); _la = _input.LA(1); if ( !(_la==AND || _la==OR) ) { _errHandler.recoverInline(this); @@ -1208,7 +1227,7 @@ public final BoolContext bool() throws RecognitionException { try { enterOuterAlt(_localctx, 1); { - setState(142); + setState(144); _la = _input.LA(1); if ( !(_la==TRUE || _la==FALSE) ) { _errHandler.recoverInline(this); @@ -1261,7 +1280,7 @@ private boolean expression_sempred(ExpressionContext _localctx, int predIndex) { } public static final String _serializedATN = - "\u0004\u0001,\u0091\u0002\u0000\u0007\u0000\u0002\u0001\u0007\u0001\u0002"+ + "\u0004\u0001/\u0093\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\u0001\u0000\u0001\u0000\u0001"+ @@ -1282,73 +1301,75 @@ private boolean expression_sempred(ExpressionContext _localctx, int predIndex) { "\u0005\u0001\u0005\u0001\u0005\u0005\u0005t\b\u0005\n\u0005\f\u0005w\t"+ "\u0005\u0005\u0005y\b\u0005\n\u0005\f\u0005|\t\u0005\u0001\u0005\u0001"+ "\u0005\u0001\u0006\u0001\u0006\u0001\u0007\u0001\u0007\u0001\b\u0001\b"+ - "\u0001\b\u0001\b\u0001\b\u0001\b\u0001\b\u0003\b\u008b\b\b\u0001\t\u0001"+ - "\t\u0001\n\u0001\n\u0001\n\u0000\u0001\u0002\u000b\u0000\u0002\u0004\u0006"+ - "\b\n\f\u000e\u0010\u0012\u0014\u0000\u0007\u0001\u0000\u001a\u001f\u0001"+ - "\u0000\u0014\u0019\u0001\u0000\u000b\u0013\u0001\u0000\t\n\u0002\u0000"+ - "\"\"$$\u0001\u0000\u0004\u0005\u0001\u0000\u0007\b\u00a0\u0000\u0016\u0001"+ - "\u0000\u0000\u0000\u00025\u0001\u0000\u0000\u0000\u0004V\u0001\u0000\u0000"+ - "\u0000\u0006X\u0001\u0000\u0000\u0000\bZ\u0001\u0000\u0000\u0000\n\\\u0001"+ - "\u0000\u0000\u0000\f\u007f\u0001\u0000\u0000\u0000\u000e\u0081\u0001\u0000"+ - "\u0000\u0000\u0010\u008a\u0001\u0000\u0000\u0000\u0012\u008c\u0001\u0000"+ - "\u0000\u0000\u0014\u008e\u0001\u0000\u0000\u0000\u0016\u0017\u0003\u0002"+ - "\u0001\u0000\u0017\u0018\u0005\u0000\u0000\u0001\u0018\u0001\u0001\u0000"+ - "\u0000\u0000\u0019\u001a\u0006\u0001\uffff\uffff\u0000\u001a\u001b\u0005"+ - " \u0000\u0000\u001b\u001c\u0003\u0002\u0001\u0000\u001c\u001d\u0005!\u0000"+ - "\u0000\u001d6\u0001\u0000\u0000\u0000\u001e\u001f\u0005\u0006\u0000\u0000"+ - "\u001f6\u0003\u0002\u0001\u000f !\u0005\u0015\u0000\u0000!6\u0003\u0002"+ - "\u0001\r\"#\u0003\b\u0004\u0000#$\u0003\n\u0005\u0000$6\u0001\u0000\u0000"+ - "\u0000%6\u0003\u0010\b\u0000&\'\u0005)\u0000\u0000\'(\u0003\u000e\u0007"+ - "\u0000()\u0005\u0003\u0000\u0000)*\u0003\u000e\u0007\u0000*6\u0001\u0000"+ - "\u0000\u0000+-\u0005)\u0000\u0000,.\u0005\u0006\u0000\u0000-,\u0001\u0000"+ - "\u0000\u0000-.\u0001\u0000\u0000\u0000./\u0001\u0000\u0000\u0000/0\u0005"+ - "\u0002\u0000\u000006\u0003\n\u0005\u000012\u0005)\u0000\u000023\u0003"+ - "\f\u0006\u000034\u0003\n\u0005\u000046\u0001\u0000\u0000\u00005\u0019"+ - "\u0001\u0000\u0000\u00005\u001e\u0001\u0000\u0000\u00005 \u0001\u0000"+ - "\u0000\u00005\"\u0001\u0000\u0000\u00005%\u0001\u0000\u0000\u00005&\u0001"+ - "\u0000\u0000\u00005+\u0001\u0000\u0000\u000051\u0001\u0000\u0000\u0000"+ - "6S\u0001\u0000\u0000\u000078\n\u000e\u0000\u000089\u0003\u0004\u0002\u0000"+ - "9:\u0003\u0002\u0001\u000f:R\u0001\u0000\u0000\u0000;<\n\f\u0000\u0000"+ - "<=\u0005\u0019\u0000\u0000=R\u0003\u0002\u0001\r>?\n\u000b\u0000\u0000"+ - "?@\u0005\u0017\u0000\u0000@R\u0003\u0002\u0001\fAB\n\n\u0000\u0000BC\u0005"+ - "\u0016\u0000\u0000CR\u0003\u0002\u0001\u000bDE\n\t\u0000\u0000EF\u0005"+ - "\u0018\u0000\u0000FR\u0003\u0002\u0001\nGH\n\b\u0000\u0000HI\u0005\u0014"+ - "\u0000\u0000IR\u0003\u0002\u0001\tJK\n\u0007\u0000\u0000KL\u0005\u0015"+ - "\u0000\u0000LR\u0003\u0002\u0001\bMN\n\u0005\u0000\u0000NO\u0003\u0012"+ - "\t\u0000OP\u0003\u0002\u0001\u0006PR\u0001\u0000\u0000\u0000Q7\u0001\u0000"+ - "\u0000\u0000Q;\u0001\u0000\u0000\u0000Q>\u0001\u0000\u0000\u0000QA\u0001"+ - "\u0000\u0000\u0000QD\u0001\u0000\u0000\u0000QG\u0001\u0000\u0000\u0000"+ - "QJ\u0001\u0000\u0000\u0000QM\u0001\u0000\u0000\u0000RU\u0001\u0000\u0000"+ - "\u0000SQ\u0001\u0000\u0000\u0000ST\u0001\u0000\u0000\u0000T\u0003\u0001"+ - "\u0000\u0000\u0000US\u0001\u0000\u0000\u0000VW\u0007\u0000\u0000\u0000"+ - "W\u0005\u0001\u0000\u0000\u0000XY\u0007\u0001\u0000\u0000Y\u0007\u0001"+ - "\u0000\u0000\u0000Z[\u0007\u0002\u0000\u0000[\t\u0001\u0000\u0000\u0000"+ - "\\`\u0005 \u0000\u0000]_\u0005%\u0000\u0000^]\u0001\u0000\u0000\u0000"+ - "_b\u0001\u0000\u0000\u0000`^\u0001\u0000\u0000\u0000`a\u0001\u0000\u0000"+ - "\u0000ac\u0001\u0000\u0000\u0000b`\u0001\u0000\u0000\u0000cg\u0003\u0002"+ - "\u0001\u0000df\u0005%\u0000\u0000ed\u0001\u0000\u0000\u0000fi\u0001\u0000"+ - "\u0000\u0000ge\u0001\u0000\u0000\u0000gh\u0001\u0000\u0000\u0000hz\u0001"+ - "\u0000\u0000\u0000ig\u0001\u0000\u0000\u0000jn\u0005\u0001\u0000\u0000"+ - "km\u0005%\u0000\u0000lk\u0001\u0000\u0000\u0000mp\u0001\u0000\u0000\u0000"+ - "nl\u0001\u0000\u0000\u0000no\u0001\u0000\u0000\u0000oq\u0001\u0000\u0000"+ - "\u0000pn\u0001\u0000\u0000\u0000qu\u0003\u0002\u0001\u0000rt\u0005%\u0000"+ - "\u0000sr\u0001\u0000\u0000\u0000tw\u0001\u0000\u0000\u0000us\u0001\u0000"+ - "\u0000\u0000uv\u0001\u0000\u0000\u0000vy\u0001\u0000\u0000\u0000wu\u0001"+ - "\u0000\u0000\u0000xj\u0001\u0000\u0000\u0000y|\u0001\u0000\u0000\u0000"+ - "zx\u0001\u0000\u0000\u0000z{\u0001\u0000\u0000\u0000{}\u0001\u0000\u0000"+ - "\u0000|z\u0001\u0000\u0000\u0000}~\u0005!\u0000\u0000~\u000b\u0001\u0000"+ - "\u0000\u0000\u007f\u0080\u0007\u0003\u0000\u0000\u0080\r\u0001\u0000\u0000"+ - "\u0000\u0081\u0082\u0007\u0004\u0000\u0000\u0082\u000f\u0001\u0000\u0000"+ - "\u0000\u0083\u008b\u0005$\u0000\u0000\u0084\u008b\u0005\"\u0000\u0000"+ - "\u0085\u008b\u0005#\u0000\u0000\u0086\u008b\u0003\u0014\n\u0000\u0087"+ - "\u008b\u0005&\u0000\u0000\u0088\u008b\u0005)\u0000\u0000\u0089\u008b\u0001"+ - "\u0000\u0000\u0000\u008a\u0083\u0001\u0000\u0000\u0000\u008a\u0084\u0001"+ - "\u0000\u0000\u0000\u008a\u0085\u0001\u0000\u0000\u0000\u008a\u0086\u0001"+ - "\u0000\u0000\u0000\u008a\u0087\u0001\u0000\u0000\u0000\u008a\u0088\u0001"+ - "\u0000\u0000\u0000\u008a\u0089\u0001\u0000\u0000\u0000\u008b\u0011\u0001"+ - "\u0000\u0000\u0000\u008c\u008d\u0007\u0005\u0000\u0000\u008d\u0013\u0001"+ - "\u0000\u0000\u0000\u008e\u008f\u0007\u0006\u0000\u0000\u008f\u0015\u0001"+ - "\u0000\u0000\u0000\n-5QS`gnuz\u008a"; + "\u0001\b\u0001\b\u0001\b\u0001\b\u0001\b\u0001\b\u0001\b\u0003\b\u008d"+ + "\b\b\u0001\t\u0001\t\u0001\n\u0001\n\u0001\n\u0000\u0001\u0002\u000b\u0000"+ + "\u0002\u0004\u0006\b\n\f\u000e\u0010\u0012\u0014\u0000\u0007\u0001\u0000"+ + "\u001b \u0001\u0000\u0015\u001a\u0001\u0000\u000b\u0014\u0001\u0000\t"+ + "\n\u0002\u0000##%%\u0001\u0000\u0004\u0005\u0001\u0000\u0007\b\u00a4\u0000"+ + "\u0016\u0001\u0000\u0000\u0000\u00025\u0001\u0000\u0000\u0000\u0004V\u0001"+ + "\u0000\u0000\u0000\u0006X\u0001\u0000\u0000\u0000\bZ\u0001\u0000\u0000"+ + "\u0000\n\\\u0001\u0000\u0000\u0000\f\u007f\u0001\u0000\u0000\u0000\u000e"+ + "\u0081\u0001\u0000\u0000\u0000\u0010\u008c\u0001\u0000\u0000\u0000\u0012"+ + "\u008e\u0001\u0000\u0000\u0000\u0014\u0090\u0001\u0000\u0000\u0000\u0016"+ + "\u0017\u0003\u0002\u0001\u0000\u0017\u0018\u0005\u0000\u0000\u0001\u0018"+ + "\u0001\u0001\u0000\u0000\u0000\u0019\u001a\u0006\u0001\uffff\uffff\u0000"+ + "\u001a\u001b\u0005!\u0000\u0000\u001b\u001c\u0003\u0002\u0001\u0000\u001c"+ + "\u001d\u0005\"\u0000\u0000\u001d6\u0001\u0000\u0000\u0000\u001e\u001f"+ + "\u0005\u0006\u0000\u0000\u001f6\u0003\u0002\u0001\u000f !\u0005\u0016"+ + "\u0000\u0000!6\u0003\u0002\u0001\r\"#\u0003\b\u0004\u0000#$\u0003\n\u0005"+ + "\u0000$6\u0001\u0000\u0000\u0000%6\u0003\u0010\b\u0000&\'\u0005,\u0000"+ + "\u0000\'(\u0003\u000e\u0007\u0000()\u0005\u0003\u0000\u0000)*\u0003\u000e"+ + "\u0007\u0000*6\u0001\u0000\u0000\u0000+-\u0005,\u0000\u0000,.\u0005\u0006"+ + "\u0000\u0000-,\u0001\u0000\u0000\u0000-.\u0001\u0000\u0000\u0000./\u0001"+ + "\u0000\u0000\u0000/0\u0005\u0002\u0000\u000006\u0003\n\u0005\u000012\u0005"+ + ",\u0000\u000023\u0003\f\u0006\u000034\u0003\n\u0005\u000046\u0001\u0000"+ + "\u0000\u00005\u0019\u0001\u0000\u0000\u00005\u001e\u0001\u0000\u0000\u0000"+ + "5 \u0001\u0000\u0000\u00005\"\u0001\u0000\u0000\u00005%\u0001\u0000\u0000"+ + "\u00005&\u0001\u0000\u0000\u00005+\u0001\u0000\u0000\u000051\u0001\u0000"+ + "\u0000\u00006S\u0001\u0000\u0000\u000078\n\u000e\u0000\u000089\u0003\u0004"+ + "\u0002\u00009:\u0003\u0002\u0001\u000f:R\u0001\u0000\u0000\u0000;<\n\f"+ + "\u0000\u0000<=\u0005\u001a\u0000\u0000=R\u0003\u0002\u0001\r>?\n\u000b"+ + "\u0000\u0000?@\u0005\u0018\u0000\u0000@R\u0003\u0002\u0001\fAB\n\n\u0000"+ + "\u0000BC\u0005\u0017\u0000\u0000CR\u0003\u0002\u0001\u000bDE\n\t\u0000"+ + "\u0000EF\u0005\u0019\u0000\u0000FR\u0003\u0002\u0001\nGH\n\b\u0000\u0000"+ + "HI\u0005\u0015\u0000\u0000IR\u0003\u0002\u0001\tJK\n\u0007\u0000\u0000"+ + "KL\u0005\u0016\u0000\u0000LR\u0003\u0002\u0001\bMN\n\u0005\u0000\u0000"+ + "NO\u0003\u0012\t\u0000OP\u0003\u0002\u0001\u0006PR\u0001\u0000\u0000\u0000"+ + "Q7\u0001\u0000\u0000\u0000Q;\u0001\u0000\u0000\u0000Q>\u0001\u0000\u0000"+ + "\u0000QA\u0001\u0000\u0000\u0000QD\u0001\u0000\u0000\u0000QG\u0001\u0000"+ + "\u0000\u0000QJ\u0001\u0000\u0000\u0000QM\u0001\u0000\u0000\u0000RU\u0001"+ + "\u0000\u0000\u0000SQ\u0001\u0000\u0000\u0000ST\u0001\u0000\u0000\u0000"+ + "T\u0003\u0001\u0000\u0000\u0000US\u0001\u0000\u0000\u0000VW\u0007\u0000"+ + "\u0000\u0000W\u0005\u0001\u0000\u0000\u0000XY\u0007\u0001\u0000\u0000"+ + "Y\u0007\u0001\u0000\u0000\u0000Z[\u0007\u0002\u0000\u0000[\t\u0001\u0000"+ + "\u0000\u0000\\`\u0005!\u0000\u0000]_\u0005(\u0000\u0000^]\u0001\u0000"+ + "\u0000\u0000_b\u0001\u0000\u0000\u0000`^\u0001\u0000\u0000\u0000`a\u0001"+ + "\u0000\u0000\u0000ac\u0001\u0000\u0000\u0000b`\u0001\u0000\u0000\u0000"+ + "cg\u0003\u0002\u0001\u0000df\u0005(\u0000\u0000ed\u0001\u0000\u0000\u0000"+ + "fi\u0001\u0000\u0000\u0000ge\u0001\u0000\u0000\u0000gh\u0001\u0000\u0000"+ + "\u0000hz\u0001\u0000\u0000\u0000ig\u0001\u0000\u0000\u0000jn\u0005\u0001"+ + "\u0000\u0000km\u0005(\u0000\u0000lk\u0001\u0000\u0000\u0000mp\u0001\u0000"+ + "\u0000\u0000nl\u0001\u0000\u0000\u0000no\u0001\u0000\u0000\u0000oq\u0001"+ + "\u0000\u0000\u0000pn\u0001\u0000\u0000\u0000qu\u0003\u0002\u0001\u0000"+ + "rt\u0005(\u0000\u0000sr\u0001\u0000\u0000\u0000tw\u0001\u0000\u0000\u0000"+ + "us\u0001\u0000\u0000\u0000uv\u0001\u0000\u0000\u0000vy\u0001\u0000\u0000"+ + "\u0000wu\u0001\u0000\u0000\u0000xj\u0001\u0000\u0000\u0000y|\u0001\u0000"+ + "\u0000\u0000zx\u0001\u0000\u0000\u0000z{\u0001\u0000\u0000\u0000{}\u0001"+ + "\u0000\u0000\u0000|z\u0001\u0000\u0000\u0000}~\u0005\"\u0000\u0000~\u000b"+ + "\u0001\u0000\u0000\u0000\u007f\u0080\u0007\u0003\u0000\u0000\u0080\r\u0001"+ + "\u0000\u0000\u0000\u0081\u0082\u0007\u0004\u0000\u0000\u0082\u000f\u0001"+ + "\u0000\u0000\u0000\u0083\u008d\u0005%\u0000\u0000\u0084\u008d\u0005#\u0000"+ + "\u0000\u0085\u008d\u0005$\u0000\u0000\u0086\u008d\u0003\u0014\n\u0000"+ + "\u0087\u008d\u0005)\u0000\u0000\u0088\u008d\u0005,\u0000\u0000\u0089\u008d"+ + "\u0005&\u0000\u0000\u008a\u008d\u0005\'\u0000\u0000\u008b\u008d\u0001"+ + "\u0000\u0000\u0000\u008c\u0083\u0001\u0000\u0000\u0000\u008c\u0084\u0001"+ + "\u0000\u0000\u0000\u008c\u0085\u0001\u0000\u0000\u0000\u008c\u0086\u0001"+ + "\u0000\u0000\u0000\u008c\u0087\u0001\u0000\u0000\u0000\u008c\u0088\u0001"+ + "\u0000\u0000\u0000\u008c\u0089\u0001\u0000\u0000\u0000\u008c\u008a\u0001"+ + "\u0000\u0000\u0000\u008c\u008b\u0001\u0000\u0000\u0000\u008d\u0011\u0001"+ + "\u0000\u0000\u0000\u008e\u008f\u0007\u0005\u0000\u0000\u008f\u0013\u0001"+ + "\u0000\u0000\u0000\u0090\u0091\u0007\u0006\u0000\u0000\u0091\u0015\u0001"+ + "\u0000\u0000\u0000\n-5QS`gnuz\u008c"; 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 ff806f3..92c3423 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 @@ -240,6 +240,10 @@ private DataType getDataType(final org.antlr.v4.runtime.Token token) { case BooleanExpressionLexer.TRUE: case BooleanExpressionLexer.FALSE: return DataType.BOOLEAN; + case BooleanExpressionLexer.DATE: + return DataType.DATE; + case BooleanExpressionLexer.DATETIME: + return DataType.DATETIME; default: return DataType.STRING; } 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 6366e73..7e9e377 100644 --- a/src/main/java/com/github/sidhant92/boolparser/util/ValueUtils.java +++ b/src/main/java/com/github/sidhant92/boolparser/util/ValueUtils.java @@ -1,6 +1,10 @@ package com.github.sidhant92.boolparser.util; import java.math.BigDecimal; +import java.time.LocalDate; +import java.time.LocalDateTime; +import java.time.format.DateTimeFormatter; +import java.time.format.DateTimeParseException; import java.util.ArrayList; import java.util.Arrays; import java.util.Collection; @@ -67,6 +71,10 @@ public static Object convertValue(final String value, final DataType dataType) { return Boolean.parseBoolean(value); case VERSION: return new ComparableVersion(value); + case DATE: + return parseDate(value).orElse(null); + case DATETIME: + return parseDateTime(value).orElse(null); default: if (value.startsWith("'") && value.endsWith("'")) { return value.substring(1, value.length() - 1); @@ -128,6 +136,42 @@ public static DataType getDataType(final Object value) { if (value instanceof ComparableVersion) { return DataType.VERSION; } + if (value instanceof LocalDate) { + return DataType.DATE; + } + if (value instanceof LocalDateTime) { + return DataType.DATETIME; + } + if (value instanceof String) { + String stringValue = (String) value; + // Check if string represents a datetime first (more specific) + if (parseDateTime(stringValue).isPresent()) { + return DataType.DATETIME; + } + // Then check if it's a date + if (parseDate(stringValue).isPresent()) { + return DataType.DATE; + } + } return DataType.STRING; } + + private static final DateTimeFormatter DATE_FORMATTER = DateTimeFormatter.ofPattern("yyyy-MM-dd"); + private static final DateTimeFormatter DATETIME_FORMATTER = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss"); + + private static Optional parseDate(String dateString) { + try { + return Optional.of(LocalDate.parse(dateString, DATE_FORMATTER)); + } catch (DateTimeParseException ignored) { + return Optional.empty(); + } + } + + private static Optional parseDateTime(String dateTimeString) { + try { + return Optional.of(LocalDateTime.parse(dateTimeString, DATETIME_FORMATTER)); + } catch (DateTimeParseException ignored) { + return Optional.empty(); + } + } } diff --git a/src/main/java/resources/BooleanExpression.g4 b/src/main/java/resources/BooleanExpression.g4 index b1ec315..6b84f66 100644 --- a/src/main/java/resources/BooleanExpression.g4 +++ b/src/main/java/resources/BooleanExpression.g4 @@ -46,6 +46,7 @@ arithmeticFunction | LEN | MEDIAN | INT + | DAYS_ELAPSED ; wordlist @@ -62,7 +63,7 @@ arithmeticFunction ; types - : INTEGER | DECIMAL | APP_VERSION | bool | WORD | FIELD | + : INTEGER | DECIMAL | APP_VERSION | bool | WORD | FIELD | DATE | DATETIME | ; @@ -93,6 +94,7 @@ MODE : 'MODE' | 'mode'; MEDIAN : 'MEDIAN' | 'median'; LEN : 'LEN' | 'len'; INT : 'INT' | 'int'; +DAYS_ELAPSED : 'DAYS_ELAPSED' | 'days_elapsed'; ADD : '+'; SUBTRACT : '-' ; MULTIPLY : '*' ; @@ -110,6 +112,8 @@ RPAREN : ')' ; DECIMAL : [0-9]+ '.' [0-9]+; APP_VERSION : [0-9] ('.' INTEGER)+; INTEGER : [0-9]+; +DATE : DATE_PATTERN; +DATETIME : DATETIME_PATTERN; WS : [ \r\t\u000C\n]+ -> skip; WORD : SQSTR | DQSTR; SQSTR : '\'' .*? '\''; @@ -118,3 +122,11 @@ FIELD : (ALPHANUMERIC | '_' | '.')+; ALPHANUMERIC : [a-zA-Z0-9]; SQ : '\''.*? '\''; DQ : '"'.*? '"'; + +fragment DATE_PATTERN + : [0-9][0-9][0-9][0-9]'-'[0-9][0-9]'-'[0-9][0-9] // YYYY-MM-DD + ; + +fragment DATETIME_PATTERN + : [0-9][0-9][0-9][0-9]'-'[0-9][0-9]'-'[0-9][0-9]' '[0-9][0-9]':'[0-9][0-9]':'[0-9][0-9] // YYYY-MM-DD HH:MM:SS + ; 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 2f83944..c3c4625 100644 --- a/src/test/java/com/github/sidhant92/boolparser/application/BooleanExpressionEvaluatorTest.java +++ b/src/test/java/com/github/sidhant92/boolparser/application/BooleanExpressionEvaluatorTest.java @@ -3,6 +3,8 @@ 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.time.LocalDate; +import java.time.LocalDateTime; import java.util.ArrayList; import java.util.HashMap; import java.util.List; @@ -686,4 +688,246 @@ public void testArithmeticFunctionAndComparison() { assertTrue(resultOptional.isSuccess()); assertEquals(resultOptional.get(), true); } + + @Test + public void testDateEqualityCorrectExpression() { + final Map data = new HashMap<>(); + data.put("created_date", LocalDate.of(2023, 3, 5)); + final Try booleanOptional = booleanExpressionEvaluator.evaluate("created_date = 2023-03-05", data); + assertTrue(booleanOptional.isSuccess()); + assertTrue(booleanOptional.get()); + } + + @Test + public void testDateEqualityIncorrectExpression() { + final Map data = new HashMap<>(); + data.put("created_date", LocalDate.of(2023, 3, 5)); + final Try booleanOptional = booleanExpressionEvaluator.evaluate("created_date = 2023-03-06", data); + assertTrue(booleanOptional.isSuccess()); + assertFalse(booleanOptional.get()); + } + + @Test + public void testDateGreaterThanCorrectExpression() { + final Map data = new HashMap<>(); + data.put("event_date", LocalDate.of(2023, 6, 15)); + final Try booleanOptional = booleanExpressionEvaluator.evaluate("event_date > 2023-03-05", data); + assertTrue(booleanOptional.isSuccess()); + assertTrue(booleanOptional.get()); + } + + @Test + public void testDateLessThanCorrectExpression() { + final Map data = new HashMap<>(); + data.put("birth_date", LocalDate.of(1990, 1, 1)); + final Try booleanOptional = booleanExpressionEvaluator.evaluate("birth_date < 2000-01-01", data); + assertTrue(booleanOptional.isSuccess()); + assertTrue(booleanOptional.get()); + } + + @Test + public void testDateTimeEqualityCorrectExpression() { + final Map data = new HashMap<>(); + data.put("timestamp", LocalDateTime.of(2023, 3, 5, 14, 30, 0)); + final Try booleanOptional = booleanExpressionEvaluator.evaluate("timestamp = 2023-03-05 14:30:00", data); + assertTrue(booleanOptional.isSuccess()); + assertTrue(booleanOptional.get()); + } + + @Test + public void testDateTimeEqualityIncorrectExpression() { + final Map data = new HashMap<>(); + data.put("timestamp", LocalDateTime.of(2023, 3, 5, 14, 30, 0)); + final Try booleanOptional = booleanExpressionEvaluator.evaluate("timestamp = 2023-03-05 14:31:00", data); + assertTrue(booleanOptional.isSuccess()); + assertFalse(booleanOptional.get()); + } + + @Test + public void testDateTimeGreaterThanCorrectExpression() { + final Map data = new HashMap<>(); + data.put("last_modified", LocalDateTime.of(2023, 6, 15, 10, 30, 0)); + final Try booleanOptional = booleanExpressionEvaluator.evaluate("last_modified > 2023-03-05 14:30:00", data); + assertTrue(booleanOptional.isSuccess()); + assertTrue(booleanOptional.get()); + } + + @Test + public void testDateTimeLessThanCorrectExpression() { + final Map data = new HashMap<>(); + data.put("created_at", LocalDateTime.of(2023, 1, 1, 9, 0, 0)); + final Try booleanOptional = booleanExpressionEvaluator.evaluate("created_at < 2023-03-05 14:30:00", data); + assertTrue(booleanOptional.isSuccess()); + assertTrue(booleanOptional.get()); + } + + @Test + public void testDateInClause() { + final Map data = new HashMap<>(); + data.put("holiday", LocalDate.of(2023, 12, 25)); + final Try booleanOptional = booleanExpressionEvaluator.evaluate("holiday in (2023-12-24, 2023-12-25, 2023-12-26)", data); + assertTrue(booleanOptional.isSuccess()); + assertTrue(booleanOptional.get()); + } + + @Test + public void testDateTimeInClause() { + final Map data = new HashMap<>(); + data.put("meeting_time", LocalDateTime.of(2023, 3, 5, 14, 30, 0)); + final Try booleanOptional = booleanExpressionEvaluator.evaluate("meeting_time in (2023-03-05 13:30:00, 2023-03-05 14:30:00, 2023-03-05 15:30:00)", data); + assertTrue(booleanOptional.isSuccess()); + assertTrue(booleanOptional.get()); + } + + @Test + public void testComplexDateTimeExpression() { + final Map data = new HashMap<>(); + data.put("start_date", LocalDate.of(2023, 1, 1)); + data.put("end_date", LocalDate.of(2023, 12, 31)); + data.put("current_date", LocalDate.of(2023, 6, 15)); + final Try booleanOptional = booleanExpressionEvaluator.evaluate("current_date >= start_date AND current_date <= end_date", data); + assertTrue(booleanOptional.isSuccess()); + assertTrue(booleanOptional.get()); + } + + @Test + public void testDateEqualityWithStringData() { + final Map data = new HashMap<>(); + data.put("created_date", "2023-03-05"); + final Try booleanOptional = booleanExpressionEvaluator.evaluate("created_date = 2023-03-05", data); + assertTrue(booleanOptional.isSuccess()); + assertTrue(booleanOptional.get()); + } + + @Test + public void testDateComparisonWithStringData() { + final Map data = new HashMap<>(); + data.put("event_date", "2023-06-15"); + final Try booleanOptional = booleanExpressionEvaluator.evaluate("event_date > 2023-03-05", data); + assertTrue(booleanOptional.isSuccess()); + assertTrue(booleanOptional.get()); + } + + @Test + public void testDateTimeEqualityWithStringData() { + final Map data = new HashMap<>(); + data.put("timestamp", "2023-03-05 14:30:00"); + final Try booleanOptional = booleanExpressionEvaluator.evaluate("timestamp = 2023-03-05 14:30:00", data); + assertTrue(booleanOptional.isSuccess()); + assertTrue(booleanOptional.get()); + } + + @Test + public void testDateTimeComparisonWithStringData() { + final Map data = new HashMap<>(); + data.put("last_modified", "2023-06-15 10:30:00"); + final Try booleanOptional = booleanExpressionEvaluator.evaluate("last_modified > 2023-03-05 14:30:00", data); + assertTrue(booleanOptional.isSuccess()); + assertTrue(booleanOptional.get()); + } + + @Test + public void testMixedDateTypesComparison() { + final Map data = new HashMap<>(); + data.put("string_date", "2023-06-15"); + data.put("object_date", LocalDate.of(2023, 3, 5)); + final Try booleanOptional = booleanExpressionEvaluator.evaluate("string_date > object_date", data); + assertTrue(booleanOptional.isSuccess()); + assertTrue(booleanOptional.get()); + } + + @Test + public void testMixedDateTimeTypesComparison() { + final Map data = new HashMap<>(); + data.put("string_datetime", "2023-06-15 10:30:00"); + data.put("object_datetime", LocalDateTime.of(2023, 3, 5, 14, 30, 0)); + final Try booleanOptional = booleanExpressionEvaluator.evaluate("string_datetime > object_datetime", data); + assertTrue(booleanOptional.isSuccess()); + assertTrue(booleanOptional.get()); + } + + @Test + public void testInvalidDateStringFormat() { + final Map data = new HashMap<>(); + data.put("bad_date", "03/05/2023"); + final Try booleanOptional = booleanExpressionEvaluator.evaluate("bad_date = 2023-03-05", data); + assertTrue(booleanOptional.isSuccess()); + assertFalse(booleanOptional.get()); + } + + @Test + public void testInvalidDateTimeStringFormat() { + final Map data = new HashMap<>(); + data.put("bad_datetime", "2023-03-05T14:30:00"); + final Try booleanOptional = booleanExpressionEvaluator.evaluate("bad_datetime = 2023-03-05 14:30:00", data); + assertTrue(booleanOptional.isSuccess()); + assertFalse(booleanOptional.get()); + } + + @Test + public void testStringDateAutoDetection() { + final Map data = new HashMap<>(); + data.put("date_string", "2023-03-05"); + data.put("regular_string", "hello world"); + final Try booleanOptional = booleanExpressionEvaluator.evaluate("date_string > 2023-01-01", data); + assertTrue(booleanOptional.isSuccess()); + assertTrue(booleanOptional.get()); + } + + @Test + public void testStringDateTimeAutoDetection() { + final Map data = new HashMap<>(); + data.put("datetime_string", "2023-03-05 14:30:00"); + data.put("regular_string", "hello world"); + final Try booleanOptional = booleanExpressionEvaluator.evaluate("datetime_string > 2023-01-01 10:00:00", data); + assertTrue(booleanOptional.isSuccess()); + assertTrue(booleanOptional.get()); + } + + @Test + public void testAutoDetectionInComplexExpressions() { + final Map data = new HashMap<>(); + data.put("start_date_str", "2023-01-01"); + data.put("end_date_str", "2023-12-31"); + data.put("current_date_str", "2023-06-15"); + final Try booleanOptional = booleanExpressionEvaluator.evaluate("current_date_str >= start_date_str AND current_date_str <= end_date_str", data); + assertTrue(booleanOptional.isSuccess()); + assertTrue(booleanOptional.get()); + } + + @Test + public void testDaysElapsedFunction() { + final Map data = new HashMap<>(); + data.put("created_date", LocalDate.of(2023, 1, 1)); + final Try booleanOptional = booleanExpressionEvaluator.evaluate("days_elapsed(created_date) > 0", data); + assertTrue(booleanOptional.isSuccess()); + assertTrue(booleanOptional.get()); + } + + @Test + public void testDaysElapsedFunctionWithStringDate() { + final Map data = new HashMap<>(); + data.put("created_date", "2023-01-01"); + final Try booleanOptional = booleanExpressionEvaluator.evaluate("days_elapsed(created_date) > 300", data); + assertTrue(booleanOptional.isSuccess()); + assertTrue(booleanOptional.get()); + } + + @Test + public void testDaysElapsedFunctionWithDirectDate() { + final Map data = new HashMap<>(); + final Try booleanOptional = booleanExpressionEvaluator.evaluate("days_elapsed(2023-01-01) > 300", data); + assertTrue(booleanOptional.isSuccess()); + assertTrue(booleanOptional.get()); + } + + @Test + public void testDaysElapsedFunctionInComparison() { + final Map data = new HashMap<>(); + data.put("event_date", LocalDate.of(2023, 6, 15)); + data.put("threshold_days", 100); + final Try booleanOptional = booleanExpressionEvaluator.evaluate("days_elapsed(event_date) <= threshold_days", data); + assertTrue(booleanOptional.isSuccess()); + // This will depend on current date, so we just check it executes successfully + } } 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 ab3a9c0..1ef4499 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 @@ -5,6 +5,8 @@ import static org.junit.jupiter.api.Assertions.assertNull; import static org.junit.jupiter.api.Assertions.assertTrue; import java.math.BigDecimal; +import java.time.LocalDate; +import java.time.LocalDateTime; import org.junit.jupiter.api.Test; import com.github.sidhant92.boolparser.constant.DataType; import com.github.sidhant92.boolparser.constant.LogicalOperationType; @@ -466,6 +468,38 @@ public void testComparisonWithArithmetic() { assertEquals(arithmeticNode.getOperator(), Operator.ADD); } + @Test + public void testSingleDateToken() { + final Try nodeOptional = boolExpressionBoolParser.parseExpression("created_date = 2023-03-05"); + assertTrue(nodeOptional.isSuccess()); + verifyComparisonToken(nodeOptional.get(), "created_date", Operator.EQUALS); + verifyUnaryToken(((ComparisonNode) nodeOptional.get()).getRight(), LocalDate.of(2023, 3, 5), DataType.DATE); + } + + @Test + public void testSingleDateTimeToken() { + final Try nodeOptional = boolExpressionBoolParser.parseExpression("timestamp = 2023-03-05 14:30:00"); + assertTrue(nodeOptional.isSuccess()); + verifyComparisonToken(nodeOptional.get(), "timestamp", Operator.EQUALS); + verifyUnaryToken(((ComparisonNode) nodeOptional.get()).getRight(), LocalDateTime.of(2023, 3, 5, 14, 30, 0), DataType.DATETIME); + } + + @Test + public void testDateComparison() { + final Try nodeOptional = boolExpressionBoolParser.parseExpression("start_date > 2023-01-01"); + assertTrue(nodeOptional.isSuccess()); + verifyComparisonToken(nodeOptional.get(), "start_date", Operator.GREATER_THAN); + verifyUnaryToken(((ComparisonNode) nodeOptional.get()).getRight(), LocalDate.of(2023, 1, 1), DataType.DATE); + } + + @Test + public void testDateTimeComparison() { + final Try nodeOptional = boolExpressionBoolParser.parseExpression("last_login < 2023-12-31 23:59:59"); + assertTrue(nodeOptional.isSuccess()); + verifyComparisonToken(nodeOptional.get(), "last_login", Operator.LESS_THAN); + verifyUnaryToken(((ComparisonNode) nodeOptional.get()).getRight(), LocalDateTime.of(2023, 12, 31, 23, 59, 59), DataType.DATETIME); + } + private void verifyUnaryToken(final Node node, final Object value, final DataType dataType) { assertEquals(node.getTokenType().name(), NodeType.UNARY.name()); assertEquals(((UnaryNode)node).getValue(), value);