diff --git a/docs/reference/modules/scripting/painless.asciidoc b/docs/reference/modules/scripting/painless.asciidoc index cb28e735e5c..20b301bda31 100644 --- a/docs/reference/modules/scripting/painless.asciidoc +++ b/docs/reference/modules/scripting/painless.asciidoc @@ -202,12 +202,15 @@ POST hockey/player/1/_update // CONSOLE [float] +[[modules-scripting-painless-regex]] === Regular expressions Painless's native support for regular expressions has syntax constructs: * `/pattern/`: Pattern literals create patterns. This is the only way to create -a pattern in painless. +a pattern in painless. The pattern inside the `/`s are just +http://docs.oracle.com/javase/8/docs/api/java/util/regex/Pattern.html[Java regular expressions]. +See <> for more. * `=~`: The find operator return a `boolean`, `true` if a subsequence of the text matches, `false` otherwise. * `==~`: The match operator returns a `boolean`, `true` if the text matches, @@ -265,14 +268,35 @@ Note: all of the `_update_by_query` examples above could really do with a because script queries aren't able to use the inverted index to limit the documents that they have to check. -The pattern syntax is just -http://docs.oracle.com/javase/8/docs/api/java/util/regex/Pattern.html[Java regular expressions]. We intentionally don't allow scripts to call `Pattern.compile` to get a new pattern on the fly because building a `Pattern` is (comparatively) slow. Pattern literals (`/apattern/`) have fancy constant extraction so no matter where they show up in the painless script they are built only when the script is first used. It is fairly similar to how `String` literals work in Java. +[float] +[[modules-scripting-painless-regex-flags]] +==== Regular expression flags + +You can define flags on patterns in Painless by adding characters after the +trailing `/` like `/foo/i` or `/foo \w #comment/iUx`. Painless exposes all the +flags from +https://docs.oracle.com/javase/7/docs/api/java/util/regex/Pattern.html[Java's Pattern class] +using these characters: + +[cols="<,<,<",options="header",] +|======================================================================= +| Character | Java Constant | Example +|`c` | CANON_EQ | `'å' ==~ /å/c` (open in hex editor to see) +|`i` | CASE_INSENSITIVE | `'A' ==~ /a/i` +|`l` | LITERAL | `'[a]' ==~ /[a]/l` +|`m` | MULTILINE | `'a\nb\nc' =~ /^b$/m` +|`s` | DOTALL (aka single line) | `'a\nb\nc' =~ /.b./s` +|`U` | UNICODE_CHARACTER_CLASS | `'Ɛ' ==~ /\\w/U` +|`u` | UNICODE_CASE | `'Ɛ' ==~ /ɛ/iu` +|`x` | COMMENTS (aka extended) | `'a' ==~ /a #comment/x` +|======================================================================= + [[painless-api]] [float] diff --git a/modules/lang-painless/src/main/antlr/PainlessLexer.g4 b/modules/lang-painless/src/main/antlr/PainlessLexer.g4 index a31c50ee198..62a154db40c 100644 --- a/modules/lang-painless/src/main/antlr/PainlessLexer.g4 +++ b/modules/lang-painless/src/main/antlr/PainlessLexer.g4 @@ -104,7 +104,7 @@ INTEGER: ( '0' | [1-9] [0-9]* ) [lLfFdD]?; DECIMAL: ( '0' | [1-9] [0-9]* ) (DOT [0-9]+)? ( [eE] [+\-]? [0-9]+ )? [fF]?; STRING: ( '"' ( '\\"' | '\\\\' | ~[\\"] )*? '"' ) | ( '\'' ( '\\\'' | '\\\\' | ~[\\"] )*? '\'' ); -REGEX: '/' ( ~('/' | '\n') | '\\' ~'\n' )+ '/' { SlashStrategy.slashIsRegex(_factory) }?; +REGEX: '/' ( ~('/' | '\n') | '\\' ~'\n' )+ '/' [cilmsUux]* { SlashStrategy.slashIsRegex(_factory) }?; TRUE: 'true'; FALSE: 'false'; diff --git a/modules/lang-painless/src/main/antlr/PainlessParser.g4 b/modules/lang-painless/src/main/antlr/PainlessParser.g4 index a020b0d7d73..6dbaa50c73d 100644 --- a/modules/lang-painless/src/main/antlr/PainlessParser.g4 +++ b/modules/lang-painless/src/main/antlr/PainlessParser.g4 @@ -189,7 +189,7 @@ argument ; lambda - : ( lamtype | LP ( lamtype ( COMMA lamtype )* )? RP ) ARROW block + : ( lamtype | LP ( lamtype ( COMMA lamtype )* )? RP ) ARROW ( block | expression ) ; lamtype diff --git a/modules/lang-painless/src/main/java/org/elasticsearch/painless/WriterConstants.java b/modules/lang-painless/src/main/java/org/elasticsearch/painless/WriterConstants.java index d798bb5ca68..7906a125f35 100644 --- a/modules/lang-painless/src/main/java/org/elasticsearch/painless/WriterConstants.java +++ b/modules/lang-painless/src/main/java/org/elasticsearch/painless/WriterConstants.java @@ -79,7 +79,7 @@ public final class WriterConstants { * because it can do it statically. This is both faster and prevents the script from doing something super slow like building a regex * per time it is run. */ - public final static Method PATTERN_COMPILE = getAsmMethod(Pattern.class, "compile", String.class); + public final static Method PATTERN_COMPILE = getAsmMethod(Pattern.class, "compile", String.class, int.class); public final static Method PATTERN_MATCHER = getAsmMethod(Matcher.class, "matcher", CharSequence.class); public final static Method MATCHER_MATCHES = getAsmMethod(boolean.class, "matches"); public final static Method MATCHER_FIND = getAsmMethod(boolean.class, "find"); @@ -131,7 +131,7 @@ public final class WriterConstants { // not Java 9 - we set it null, so MethodWriter uses StringBuilder: bs = null; } - INDY_STRING_CONCAT_BOOTSTRAP_HANDLE = bs; + INDY_STRING_CONCAT_BOOTSTRAP_HANDLE = null; // Disabled until https://github.com/elastic/elasticsearch/issues/18929 } public final static int MAX_INDY_STRING_CONCAT_ARGS = 200; diff --git a/modules/lang-painless/src/main/java/org/elasticsearch/painless/antlr/PainlessLexer.java b/modules/lang-painless/src/main/java/org/elasticsearch/painless/antlr/PainlessLexer.java index 040d17c521b..cf0ac8605f0 100644 --- a/modules/lang-painless/src/main/java/org/elasticsearch/painless/antlr/PainlessLexer.java +++ b/modules/lang-painless/src/main/java/org/elasticsearch/painless/antlr/PainlessLexer.java @@ -160,7 +160,7 @@ class PainlessLexer extends Lexer { } public static final String _serializedATN = - "\3\u0430\ud6d1\u8206\uad2d\u4417\uaef1\u8d80\uaadd\2R\u0233\b\1\b\1\4"+ + "\3\u0430\ud6d1\u8206\uad2d\u4417\uaef1\u8d80\uaadd\2R\u0239\b\1\b\1\4"+ "\2\t\2\4\3\t\3\4\4\t\4\4\5\t\5\4\6\t\6\4\7\t\7\4\b\t\b\4\t\t\t\4\n\t\n"+ "\4\13\t\13\4\f\t\f\4\r\t\r\4\16\t\16\4\17\t\17\4\20\t\20\4\21\t\21\4\22"+ "\t\22\4\23\t\23\4\24\t\24\4\25\t\25\4\26\t\26\4\27\t\27\4\30\t\30\4\31"+ @@ -191,171 +191,174 @@ class PainlessLexer extends Lexer { "\5H\u01c8\nH\3H\3H\5H\u01cc\nH\3H\6H\u01cf\nH\rH\16H\u01d0\5H\u01d3\n"+ "H\3H\5H\u01d6\nH\3I\3I\3I\3I\3I\3I\7I\u01de\nI\fI\16I\u01e1\13I\3I\3I"+ "\3I\3I\3I\3I\3I\7I\u01ea\nI\fI\16I\u01ed\13I\3I\5I\u01f0\nI\3J\3J\3J\3"+ - "J\6J\u01f6\nJ\rJ\16J\u01f7\3J\3J\3J\3K\3K\3K\3K\3K\3L\3L\3L\3L\3L\3L\3"+ - "M\3M\3M\3M\3M\3N\3N\3N\3N\7N\u0211\nN\fN\16N\u0214\13N\3N\3N\3O\3O\7O"+ - "\u021a\nO\fO\16O\u021d\13O\3P\3P\3P\7P\u0222\nP\fP\16P\u0225\13P\5P\u0227"+ - "\nP\3P\3P\3Q\3Q\7Q\u022d\nQ\fQ\16Q\u0230\13Q\3Q\3Q\6\u00b1\u00bb\u01df"+ - "\u01eb\2R\4\3\6\4\b\5\n\6\f\7\16\b\20\t\22\n\24\13\26\f\30\r\32\16\34"+ - "\17\36\20 \21\"\22$\23&\24(\25*\26,\27.\30\60\31\62\32\64\33\66\348\35"+ - ":\36<\37> @!B\"D#F$H%J&L\'N(P)R*T+V,X-Z.\\/^\60`\61b\62d\63f\64h\65j\66"+ - "l\67n8p9r:t;v|?~@\u0080A\u0082B\u0084C\u0086D\u0088E\u008aF\u008c"+ - "G\u008eH\u0090I\u0092J\u0094K\u0096L\u0098M\u009aN\u009cO\u009eP\u00a0"+ - "Q\u00a2R\4\2\3\23\5\2\13\f\17\17\"\"\4\2\f\f\17\17\3\2\629\4\2NNnn\4\2"+ - "ZZzz\5\2\62;CHch\3\2\63;\3\2\62;\b\2FFHHNNffhhnn\4\2GGgg\4\2--//\4\2H"+ - "Hhh\4\2$$^^\4\2\f\f\61\61\3\2\f\f\5\2C\\aac|\6\2\62;C\\aac|\u0252\2\4"+ - "\3\2\2\2\2\6\3\2\2\2\2\b\3\2\2\2\2\n\3\2\2\2\2\f\3\2\2\2\2\16\3\2\2\2"+ - "\2\20\3\2\2\2\2\22\3\2\2\2\2\24\3\2\2\2\2\26\3\2\2\2\2\30\3\2\2\2\2\32"+ - "\3\2\2\2\2\34\3\2\2\2\2\36\3\2\2\2\2 \3\2\2\2\2\"\3\2\2\2\2$\3\2\2\2\2"+ - "&\3\2\2\2\2(\3\2\2\2\2*\3\2\2\2\2,\3\2\2\2\2.\3\2\2\2\2\60\3\2\2\2\2\62"+ - "\3\2\2\2\2\64\3\2\2\2\2\66\3\2\2\2\28\3\2\2\2\2:\3\2\2\2\2<\3\2\2\2\2"+ - ">\3\2\2\2\2@\3\2\2\2\2B\3\2\2\2\2D\3\2\2\2\2F\3\2\2\2\2H\3\2\2\2\2J\3"+ - "\2\2\2\2L\3\2\2\2\2N\3\2\2\2\2P\3\2\2\2\2R\3\2\2\2\2T\3\2\2\2\2V\3\2\2"+ - "\2\2X\3\2\2\2\2Z\3\2\2\2\2\\\3\2\2\2\2^\3\2\2\2\2`\3\2\2\2\2b\3\2\2\2"+ - "\2d\3\2\2\2\2f\3\2\2\2\2h\3\2\2\2\2j\3\2\2\2\2l\3\2\2\2\2n\3\2\2\2\2p"+ - "\3\2\2\2\2r\3\2\2\2\2t\3\2\2\2\2v\3\2\2\2\2x\3\2\2\2\2z\3\2\2\2\2|\3\2"+ - "\2\2\2~\3\2\2\2\2\u0080\3\2\2\2\2\u0082\3\2\2\2\2\u0084\3\2\2\2\2\u0086"+ - "\3\2\2\2\2\u0088\3\2\2\2\2\u008a\3\2\2\2\2\u008c\3\2\2\2\2\u008e\3\2\2"+ - "\2\2\u0090\3\2\2\2\2\u0092\3\2\2\2\2\u0094\3\2\2\2\2\u0096\3\2\2\2\2\u0098"+ - "\3\2\2\2\2\u009a\3\2\2\2\2\u009c\3\2\2\2\2\u009e\3\2\2\2\3\u00a0\3\2\2"+ - "\2\3\u00a2\3\2\2\2\4\u00a5\3\2\2\2\6\u00c0\3\2\2\2\b\u00c4\3\2\2\2\n\u00c6"+ - "\3\2\2\2\f\u00c8\3\2\2\2\16\u00ca\3\2\2\2\20\u00cc\3\2\2\2\22\u00ce\3"+ - "\2\2\2\24\u00d0\3\2\2\2\26\u00d4\3\2\2\2\30\u00d6\3\2\2\2\32\u00d8\3\2"+ - "\2\2\34\u00db\3\2\2\2\36\u00e0\3\2\2\2 \u00e6\3\2\2\2\"\u00e9\3\2\2\2"+ - "$\u00ed\3\2\2\2&\u00f6\3\2\2\2(\u00fc\3\2\2\2*\u0103\3\2\2\2,\u0107\3"+ - "\2\2\2.\u010b\3\2\2\2\60\u0111\3\2\2\2\62\u0117\3\2\2\2\64\u011c\3\2\2"+ - "\2\66\u011e\3\2\2\28\u0120\3\2\2\2:\u0122\3\2\2\2<\u0125\3\2\2\2>\u0127"+ - "\3\2\2\2@\u0129\3\2\2\2B\u012b\3\2\2\2D\u012e\3\2\2\2F\u0131\3\2\2\2H"+ - "\u0135\3\2\2\2J\u0137\3\2\2\2L\u013a\3\2\2\2N\u013c\3\2\2\2P\u013f\3\2"+ - "\2\2R\u0142\3\2\2\2T\u0146\3\2\2\2V\u0149\3\2\2\2X\u014d\3\2\2\2Z\u014f"+ - "\3\2\2\2\\\u0151\3\2\2\2^\u0153\3\2\2\2`\u0156\3\2\2\2b\u0159\3\2\2\2"+ - "d\u015b\3\2\2\2f\u015d\3\2\2\2h\u0160\3\2\2\2j\u0163\3\2\2\2l\u0166\3"+ - "\2\2\2n\u016a\3\2\2\2p\u016d\3\2\2\2r\u0170\3\2\2\2t\u0172\3\2\2\2v\u0175"+ - "\3\2\2\2x\u0178\3\2\2\2z\u017b\3\2\2\2|\u017e\3\2\2\2~\u0181\3\2\2\2\u0080"+ - "\u0184\3\2\2\2\u0082\u0187\3\2\2\2\u0084\u018a\3\2\2\2\u0086\u018e\3\2"+ - "\2\2\u0088\u0192\3\2\2\2\u008a\u0197\3\2\2\2\u008c\u01a0\3\2\2\2\u008e"+ - "\u01b2\3\2\2\2\u0090\u01bf\3\2\2\2\u0092\u01ef\3\2\2\2\u0094\u01f1\3\2"+ - "\2\2\u0096\u01fc\3\2\2\2\u0098\u0201\3\2\2\2\u009a\u0207\3\2\2\2\u009c"+ - "\u020c\3\2\2\2\u009e\u0217\3\2\2\2\u00a0\u0226\3\2\2\2\u00a2\u022a\3\2"+ - "\2\2\u00a4\u00a6\t\2\2\2\u00a5\u00a4\3\2\2\2\u00a6\u00a7\3\2\2\2\u00a7"+ - "\u00a5\3\2\2\2\u00a7\u00a8\3\2\2\2\u00a8\u00a9\3\2\2\2\u00a9\u00aa\b\2"+ - "\2\2\u00aa\5\3\2\2\2\u00ab\u00ac\7\61\2\2\u00ac\u00ad\7\61\2\2\u00ad\u00b1"+ - "\3\2\2\2\u00ae\u00b0\13\2\2\2\u00af\u00ae\3\2\2\2\u00b0\u00b3\3\2\2\2"+ - "\u00b1\u00b2\3\2\2\2\u00b1\u00af\3\2\2\2\u00b2\u00b4\3\2\2\2\u00b3\u00b1"+ - "\3\2\2\2\u00b4\u00c1\t\3\2\2\u00b5\u00b6\7\61\2\2\u00b6\u00b7\7,\2\2\u00b7"+ - "\u00bb\3\2\2\2\u00b8\u00ba\13\2\2\2\u00b9\u00b8\3\2\2\2\u00ba\u00bd\3"+ - "\2\2\2\u00bb\u00bc\3\2\2\2\u00bb\u00b9\3\2\2\2\u00bc\u00be\3\2\2\2\u00bd"+ - "\u00bb\3\2\2\2\u00be\u00bf\7,\2\2\u00bf\u00c1\7\61\2\2\u00c0\u00ab\3\2"+ - "\2\2\u00c0\u00b5\3\2\2\2\u00c1\u00c2\3\2\2\2\u00c2\u00c3\b\3\2\2\u00c3"+ - "\7\3\2\2\2\u00c4\u00c5\7}\2\2\u00c5\t\3\2\2\2\u00c6\u00c7\7\177\2\2\u00c7"+ - "\13\3\2\2\2\u00c8\u00c9\7]\2\2\u00c9\r\3\2\2\2\u00ca\u00cb\7_\2\2\u00cb"+ - "\17\3\2\2\2\u00cc\u00cd\7*\2\2\u00cd\21\3\2\2\2\u00ce\u00cf\7+\2\2\u00cf"+ - "\23\3\2\2\2\u00d0\u00d1\7\60\2\2\u00d1\u00d2\3\2\2\2\u00d2\u00d3\b\n\3"+ - "\2\u00d3\25\3\2\2\2\u00d4\u00d5\7.\2\2\u00d5\27\3\2\2\2\u00d6\u00d7\7"+ - "=\2\2\u00d7\31\3\2\2\2\u00d8\u00d9\7k\2\2\u00d9\u00da\7h\2\2\u00da\33"+ - "\3\2\2\2\u00db\u00dc\7g\2\2\u00dc\u00dd\7n\2\2\u00dd\u00de\7u\2\2\u00de"+ - "\u00df\7g\2\2\u00df\35\3\2\2\2\u00e0\u00e1\7y\2\2\u00e1\u00e2\7j\2\2\u00e2"+ - "\u00e3\7k\2\2\u00e3\u00e4\7n\2\2\u00e4\u00e5\7g\2\2\u00e5\37\3\2\2\2\u00e6"+ - "\u00e7\7f\2\2\u00e7\u00e8\7q\2\2\u00e8!\3\2\2\2\u00e9\u00ea\7h\2\2\u00ea"+ - "\u00eb\7q\2\2\u00eb\u00ec\7t\2\2\u00ec#\3\2\2\2\u00ed\u00ee\7e\2\2\u00ee"+ - "\u00ef\7q\2\2\u00ef\u00f0\7p\2\2\u00f0\u00f1\7v\2\2\u00f1\u00f2\7k\2\2"+ - "\u00f2\u00f3\7p\2\2\u00f3\u00f4\7w\2\2\u00f4\u00f5\7g\2\2\u00f5%\3\2\2"+ - "\2\u00f6\u00f7\7d\2\2\u00f7\u00f8\7t\2\2\u00f8\u00f9\7g\2\2\u00f9\u00fa"+ - "\7c\2\2\u00fa\u00fb\7m\2\2\u00fb\'\3\2\2\2\u00fc\u00fd\7t\2\2\u00fd\u00fe"+ - "\7g\2\2\u00fe\u00ff\7v\2\2\u00ff\u0100\7w\2\2\u0100\u0101\7t\2\2\u0101"+ - "\u0102\7p\2\2\u0102)\3\2\2\2\u0103\u0104\7p\2\2\u0104\u0105\7g\2\2\u0105"+ - "\u0106\7y\2\2\u0106+\3\2\2\2\u0107\u0108\7v\2\2\u0108\u0109\7t\2\2\u0109"+ - "\u010a\7{\2\2\u010a-\3\2\2\2\u010b\u010c\7e\2\2\u010c\u010d\7c\2\2\u010d"+ - "\u010e\7v\2\2\u010e\u010f\7e\2\2\u010f\u0110\7j\2\2\u0110/\3\2\2\2\u0111"+ - "\u0112\7v\2\2\u0112\u0113\7j\2\2\u0113\u0114\7t\2\2\u0114\u0115\7q\2\2"+ - "\u0115\u0116\7y\2\2\u0116\61\3\2\2\2\u0117\u0118\7v\2\2\u0118\u0119\7"+ - "j\2\2\u0119\u011a\7k\2\2\u011a\u011b\7u\2\2\u011b\63\3\2\2\2\u011c\u011d"+ - "\7#\2\2\u011d\65\3\2\2\2\u011e\u011f\7\u0080\2\2\u011f\67\3\2\2\2\u0120"+ - "\u0121\7,\2\2\u01219\3\2\2\2\u0122\u0123\7\61\2\2\u0123\u0124\6\35\2\2"+ - "\u0124;\3\2\2\2\u0125\u0126\7\'\2\2\u0126=\3\2\2\2\u0127\u0128\7-\2\2"+ - "\u0128?\3\2\2\2\u0129\u012a\7/\2\2\u012aA\3\2\2\2\u012b\u012c\7>\2\2\u012c"+ - "\u012d\7>\2\2\u012dC\3\2\2\2\u012e\u012f\7@\2\2\u012f\u0130\7@\2\2\u0130"+ - "E\3\2\2\2\u0131\u0132\7@\2\2\u0132\u0133\7@\2\2\u0133\u0134\7@\2\2\u0134"+ - "G\3\2\2\2\u0135\u0136\7>\2\2\u0136I\3\2\2\2\u0137\u0138\7>\2\2\u0138\u0139"+ - "\7?\2\2\u0139K\3\2\2\2\u013a\u013b\7@\2\2\u013bM\3\2\2\2\u013c\u013d\7"+ - "@\2\2\u013d\u013e\7?\2\2\u013eO\3\2\2\2\u013f\u0140\7?\2\2\u0140\u0141"+ - "\7?\2\2\u0141Q\3\2\2\2\u0142\u0143\7?\2\2\u0143\u0144\7?\2\2\u0144\u0145"+ - "\7?\2\2\u0145S\3\2\2\2\u0146\u0147\7#\2\2\u0147\u0148\7?\2\2\u0148U\3"+ - "\2\2\2\u0149\u014a\7#\2\2\u014a\u014b\7?\2\2\u014b\u014c\7?\2\2\u014c"+ - "W\3\2\2\2\u014d\u014e\7(\2\2\u014eY\3\2\2\2\u014f\u0150\7`\2\2\u0150["+ - "\3\2\2\2\u0151\u0152\7~\2\2\u0152]\3\2\2\2\u0153\u0154\7(\2\2\u0154\u0155"+ - "\7(\2\2\u0155_\3\2\2\2\u0156\u0157\7~\2\2\u0157\u0158\7~\2\2\u0158a\3"+ - "\2\2\2\u0159\u015a\7A\2\2\u015ac\3\2\2\2\u015b\u015c\7<\2\2\u015ce\3\2"+ - "\2\2\u015d\u015e\7<\2\2\u015e\u015f\7<\2\2\u015fg\3\2\2\2\u0160\u0161"+ - "\7/\2\2\u0161\u0162\7@\2\2\u0162i\3\2\2\2\u0163\u0164\7?\2\2\u0164\u0165"+ - "\7\u0080\2\2\u0165k\3\2\2\2\u0166\u0167\7?\2\2\u0167\u0168\7?\2\2\u0168"+ - "\u0169\7\u0080\2\2\u0169m\3\2\2\2\u016a\u016b\7-\2\2\u016b\u016c\7-\2"+ - "\2\u016co\3\2\2\2\u016d\u016e\7/\2\2\u016e\u016f\7/\2\2\u016fq\3\2\2\2"+ - "\u0170\u0171\7?\2\2\u0171s\3\2\2\2\u0172\u0173\7-\2\2\u0173\u0174\7?\2"+ - "\2\u0174u\3\2\2\2\u0175\u0176\7/\2\2\u0176\u0177\7?\2\2\u0177w\3\2\2\2"+ - "\u0178\u0179\7,\2\2\u0179\u017a\7?\2\2\u017ay\3\2\2\2\u017b\u017c\7\61"+ - "\2\2\u017c\u017d\7?\2\2\u017d{\3\2\2\2\u017e\u017f\7\'\2\2\u017f\u0180"+ - "\7?\2\2\u0180}\3\2\2\2\u0181\u0182\7(\2\2\u0182\u0183\7?\2\2\u0183\177"+ - "\3\2\2\2\u0184\u0185\7`\2\2\u0185\u0186\7?\2\2\u0186\u0081\3\2\2\2\u0187"+ - "\u0188\7~\2\2\u0188\u0189\7?\2\2\u0189\u0083\3\2\2\2\u018a\u018b\7>\2"+ - "\2\u018b\u018c\7>\2\2\u018c\u018d\7?\2\2\u018d\u0085\3\2\2\2\u018e\u018f"+ - "\7@\2\2\u018f\u0190\7@\2\2\u0190\u0191\7?\2\2\u0191\u0087\3\2\2\2\u0192"+ - "\u0193\7@\2\2\u0193\u0194\7@\2\2\u0194\u0195\7@\2\2\u0195\u0196\7?\2\2"+ - "\u0196\u0089\3\2\2\2\u0197\u0199\7\62\2\2\u0198\u019a\t\4\2\2\u0199\u0198"+ - "\3\2\2\2\u019a\u019b\3\2\2\2\u019b\u0199\3\2\2\2\u019b\u019c\3\2\2\2\u019c"+ - "\u019e\3\2\2\2\u019d\u019f\t\5\2\2\u019e\u019d\3\2\2\2\u019e\u019f\3\2"+ - "\2\2\u019f\u008b\3\2\2\2\u01a0\u01a1\7\62\2\2\u01a1\u01a3\t\6\2\2\u01a2"+ - "\u01a4\t\7\2\2\u01a3\u01a2\3\2\2\2\u01a4\u01a5\3\2\2\2\u01a5\u01a3\3\2"+ - "\2\2\u01a5\u01a6\3\2\2\2\u01a6\u01a8\3\2\2\2\u01a7\u01a9\t\5\2\2\u01a8"+ - "\u01a7\3\2\2\2\u01a8\u01a9\3\2\2\2\u01a9\u008d\3\2\2\2\u01aa\u01b3\7\62"+ - "\2\2\u01ab\u01af\t\b\2\2\u01ac\u01ae\t\t\2\2\u01ad\u01ac\3\2\2\2\u01ae"+ - "\u01b1\3\2\2\2\u01af\u01ad\3\2\2\2\u01af\u01b0\3\2\2\2\u01b0\u01b3\3\2"+ - "\2\2\u01b1\u01af\3\2\2\2\u01b2\u01aa\3\2\2\2\u01b2\u01ab\3\2\2\2\u01b3"+ - "\u01b5\3\2\2\2\u01b4\u01b6\t\n\2\2\u01b5\u01b4\3\2\2\2\u01b5\u01b6\3\2"+ - "\2\2\u01b6\u008f\3\2\2\2\u01b7\u01c0\7\62\2\2\u01b8\u01bc\t\b\2\2\u01b9"+ - "\u01bb\t\t\2\2\u01ba\u01b9\3\2\2\2\u01bb\u01be\3\2\2\2\u01bc\u01ba\3\2"+ - "\2\2\u01bc\u01bd\3\2\2\2\u01bd\u01c0\3\2\2\2\u01be\u01bc\3\2\2\2\u01bf"+ - "\u01b7\3\2\2\2\u01bf\u01b8\3\2\2\2\u01c0\u01c7\3\2\2\2\u01c1\u01c3\5\24"+ - "\n\2\u01c2\u01c4\t\t\2\2\u01c3\u01c2\3\2\2\2\u01c4\u01c5\3\2\2\2\u01c5"+ - "\u01c3\3\2\2\2\u01c5\u01c6\3\2\2\2\u01c6\u01c8\3\2\2\2\u01c7\u01c1\3\2"+ - "\2\2\u01c7\u01c8\3\2\2\2\u01c8\u01d2\3\2\2\2\u01c9\u01cb\t\13\2\2\u01ca"+ - "\u01cc\t\f\2\2\u01cb\u01ca\3\2\2\2\u01cb\u01cc\3\2\2\2\u01cc\u01ce\3\2"+ - "\2\2\u01cd\u01cf\t\t\2\2\u01ce\u01cd\3\2\2\2\u01cf\u01d0\3\2\2\2\u01d0"+ - "\u01ce\3\2\2\2\u01d0\u01d1\3\2\2\2\u01d1\u01d3\3\2\2\2\u01d2\u01c9\3\2"+ - "\2\2\u01d2\u01d3\3\2\2\2\u01d3\u01d5\3\2\2\2\u01d4\u01d6\t\r\2\2\u01d5"+ - "\u01d4\3\2\2\2\u01d5\u01d6\3\2\2\2\u01d6\u0091\3\2\2\2\u01d7\u01df\7$"+ - "\2\2\u01d8\u01d9\7^\2\2\u01d9\u01de\7$\2\2\u01da\u01db\7^\2\2\u01db\u01de"+ - "\7^\2\2\u01dc\u01de\n\16\2\2\u01dd\u01d8\3\2\2\2\u01dd\u01da\3\2\2\2\u01dd"+ - "\u01dc\3\2\2\2\u01de\u01e1\3\2\2\2\u01df\u01e0\3\2\2\2\u01df\u01dd\3\2"+ - "\2\2\u01e0\u01e2\3\2\2\2\u01e1\u01df\3\2\2\2\u01e2\u01f0\7$\2\2\u01e3"+ - "\u01eb\7)\2\2\u01e4\u01e5\7^\2\2\u01e5\u01ea\7)\2\2\u01e6\u01e7\7^\2\2"+ - "\u01e7\u01ea\7^\2\2\u01e8\u01ea\n\16\2\2\u01e9\u01e4\3\2\2\2\u01e9\u01e6"+ - "\3\2\2\2\u01e9\u01e8\3\2\2\2\u01ea\u01ed\3\2\2\2\u01eb\u01ec\3\2\2\2\u01eb"+ - "\u01e9\3\2\2\2\u01ec\u01ee\3\2\2\2\u01ed\u01eb\3\2\2\2\u01ee\u01f0\7)"+ - "\2\2\u01ef\u01d7\3\2\2\2\u01ef\u01e3\3\2\2\2\u01f0\u0093\3\2\2\2\u01f1"+ - "\u01f5\7\61\2\2\u01f2\u01f6\n\17\2\2\u01f3\u01f4\7^\2\2\u01f4\u01f6\n"+ - "\20\2\2\u01f5\u01f2\3\2\2\2\u01f5\u01f3\3\2\2\2\u01f6\u01f7\3\2\2\2\u01f7"+ - "\u01f5\3\2\2\2\u01f7\u01f8\3\2\2\2\u01f8\u01f9\3\2\2\2\u01f9\u01fa\7\61"+ - "\2\2\u01fa\u01fb\6J\3\2\u01fb\u0095\3\2\2\2\u01fc\u01fd\7v\2\2\u01fd\u01fe"+ - "\7t\2\2\u01fe\u01ff\7w\2\2\u01ff\u0200\7g\2\2\u0200\u0097\3\2\2\2\u0201"+ - "\u0202\7h\2\2\u0202\u0203\7c\2\2\u0203\u0204\7n\2\2\u0204\u0205\7u\2\2"+ - "\u0205\u0206\7g\2\2\u0206\u0099\3\2\2\2\u0207\u0208\7p\2\2\u0208\u0209"+ - "\7w\2\2\u0209\u020a\7n\2\2\u020a\u020b\7n\2\2\u020b\u009b\3\2\2\2\u020c"+ - "\u0212\5\u009eO\2\u020d\u020e\5\24\n\2\u020e\u020f\5\u009eO\2\u020f\u0211"+ - "\3\2\2\2\u0210\u020d\3\2\2\2\u0211\u0214\3\2\2\2\u0212\u0210\3\2\2\2\u0212"+ - "\u0213\3\2\2\2\u0213\u0215\3\2\2\2\u0214\u0212\3\2\2\2\u0215\u0216\6N"+ - "\4\2\u0216\u009d\3\2\2\2\u0217\u021b\t\21\2\2\u0218\u021a\t\22\2\2\u0219"+ - "\u0218\3\2\2\2\u021a\u021d\3\2\2\2\u021b\u0219\3\2\2\2\u021b\u021c\3\2"+ - "\2\2\u021c\u009f\3\2\2\2\u021d\u021b\3\2\2\2\u021e\u0227\7\62\2\2\u021f"+ - "\u0223\t\b\2\2\u0220\u0222\t\t\2\2\u0221\u0220\3\2\2\2\u0222\u0225\3\2"+ - "\2\2\u0223\u0221\3\2\2\2\u0223\u0224\3\2\2\2\u0224\u0227\3\2\2\2\u0225"+ - "\u0223\3\2\2\2\u0226\u021e\3\2\2\2\u0226\u021f\3\2\2\2\u0227\u0228\3\2"+ - "\2\2\u0228\u0229\bP\4\2\u0229\u00a1\3\2\2\2\u022a\u022e\t\21\2\2\u022b"+ - "\u022d\t\22\2\2\u022c\u022b\3\2\2\2\u022d\u0230\3\2\2\2\u022e\u022c\3"+ - "\2\2\2\u022e\u022f\3\2\2\2\u022f\u0231\3\2\2\2\u0230\u022e\3\2\2\2\u0231"+ - "\u0232\bQ\4\2\u0232\u00a3\3\2\2\2#\2\3\u00a7\u00b1\u00bb\u00c0\u019b\u019e"+ + "J\6J\u01f6\nJ\rJ\16J\u01f7\3J\3J\7J\u01fc\nJ\fJ\16J\u01ff\13J\3J\3J\3"+ + "K\3K\3K\3K\3K\3L\3L\3L\3L\3L\3L\3M\3M\3M\3M\3M\3N\3N\3N\3N\7N\u0217\n"+ + "N\fN\16N\u021a\13N\3N\3N\3O\3O\7O\u0220\nO\fO\16O\u0223\13O\3P\3P\3P\7"+ + "P\u0228\nP\fP\16P\u022b\13P\5P\u022d\nP\3P\3P\3Q\3Q\7Q\u0233\nQ\fQ\16"+ + "Q\u0236\13Q\3Q\3Q\6\u00b1\u00bb\u01df\u01eb\2R\4\3\6\4\b\5\n\6\f\7\16"+ + "\b\20\t\22\n\24\13\26\f\30\r\32\16\34\17\36\20 \21\"\22$\23&\24(\25*\26"+ + ",\27.\30\60\31\62\32\64\33\66\348\35:\36<\37> @!B\"D#F$H%J&L\'N(P)R*T"+ + "+V,X-Z.\\/^\60`\61b\62d\63f\64h\65j\66l\67n8p9r:t;v|?~@\u0080A\u0082"+ + "B\u0084C\u0086D\u0088E\u008aF\u008cG\u008eH\u0090I\u0092J\u0094K\u0096"+ + "L\u0098M\u009aN\u009cO\u009eP\u00a0Q\u00a2R\4\2\3\24\5\2\13\f\17\17\""+ + "\"\4\2\f\f\17\17\3\2\629\4\2NNnn\4\2ZZzz\5\2\62;CHch\3\2\63;\3\2\62;\b"+ + "\2FFHHNNffhhnn\4\2GGgg\4\2--//\4\2HHhh\4\2$$^^\4\2\f\f\61\61\3\2\f\f\t"+ + "\2WWeekknouuwwzz\5\2C\\aac|\6\2\62;C\\aac|\u0259\2\4\3\2\2\2\2\6\3\2\2"+ + "\2\2\b\3\2\2\2\2\n\3\2\2\2\2\f\3\2\2\2\2\16\3\2\2\2\2\20\3\2\2\2\2\22"+ + "\3\2\2\2\2\24\3\2\2\2\2\26\3\2\2\2\2\30\3\2\2\2\2\32\3\2\2\2\2\34\3\2"+ + "\2\2\2\36\3\2\2\2\2 \3\2\2\2\2\"\3\2\2\2\2$\3\2\2\2\2&\3\2\2\2\2(\3\2"+ + "\2\2\2*\3\2\2\2\2,\3\2\2\2\2.\3\2\2\2\2\60\3\2\2\2\2\62\3\2\2\2\2\64\3"+ + "\2\2\2\2\66\3\2\2\2\28\3\2\2\2\2:\3\2\2\2\2<\3\2\2\2\2>\3\2\2\2\2@\3\2"+ + "\2\2\2B\3\2\2\2\2D\3\2\2\2\2F\3\2\2\2\2H\3\2\2\2\2J\3\2\2\2\2L\3\2\2\2"+ + "\2N\3\2\2\2\2P\3\2\2\2\2R\3\2\2\2\2T\3\2\2\2\2V\3\2\2\2\2X\3\2\2\2\2Z"+ + "\3\2\2\2\2\\\3\2\2\2\2^\3\2\2\2\2`\3\2\2\2\2b\3\2\2\2\2d\3\2\2\2\2f\3"+ + "\2\2\2\2h\3\2\2\2\2j\3\2\2\2\2l\3\2\2\2\2n\3\2\2\2\2p\3\2\2\2\2r\3\2\2"+ + "\2\2t\3\2\2\2\2v\3\2\2\2\2x\3\2\2\2\2z\3\2\2\2\2|\3\2\2\2\2~\3\2\2\2\2"+ + "\u0080\3\2\2\2\2\u0082\3\2\2\2\2\u0084\3\2\2\2\2\u0086\3\2\2\2\2\u0088"+ + "\3\2\2\2\2\u008a\3\2\2\2\2\u008c\3\2\2\2\2\u008e\3\2\2\2\2\u0090\3\2\2"+ + "\2\2\u0092\3\2\2\2\2\u0094\3\2\2\2\2\u0096\3\2\2\2\2\u0098\3\2\2\2\2\u009a"+ + "\3\2\2\2\2\u009c\3\2\2\2\2\u009e\3\2\2\2\3\u00a0\3\2\2\2\3\u00a2\3\2\2"+ + "\2\4\u00a5\3\2\2\2\6\u00c0\3\2\2\2\b\u00c4\3\2\2\2\n\u00c6\3\2\2\2\f\u00c8"+ + "\3\2\2\2\16\u00ca\3\2\2\2\20\u00cc\3\2\2\2\22\u00ce\3\2\2\2\24\u00d0\3"+ + "\2\2\2\26\u00d4\3\2\2\2\30\u00d6\3\2\2\2\32\u00d8\3\2\2\2\34\u00db\3\2"+ + "\2\2\36\u00e0\3\2\2\2 \u00e6\3\2\2\2\"\u00e9\3\2\2\2$\u00ed\3\2\2\2&\u00f6"+ + "\3\2\2\2(\u00fc\3\2\2\2*\u0103\3\2\2\2,\u0107\3\2\2\2.\u010b\3\2\2\2\60"+ + "\u0111\3\2\2\2\62\u0117\3\2\2\2\64\u011c\3\2\2\2\66\u011e\3\2\2\28\u0120"+ + "\3\2\2\2:\u0122\3\2\2\2<\u0125\3\2\2\2>\u0127\3\2\2\2@\u0129\3\2\2\2B"+ + "\u012b\3\2\2\2D\u012e\3\2\2\2F\u0131\3\2\2\2H\u0135\3\2\2\2J\u0137\3\2"+ + "\2\2L\u013a\3\2\2\2N\u013c\3\2\2\2P\u013f\3\2\2\2R\u0142\3\2\2\2T\u0146"+ + "\3\2\2\2V\u0149\3\2\2\2X\u014d\3\2\2\2Z\u014f\3\2\2\2\\\u0151\3\2\2\2"+ + "^\u0153\3\2\2\2`\u0156\3\2\2\2b\u0159\3\2\2\2d\u015b\3\2\2\2f\u015d\3"+ + "\2\2\2h\u0160\3\2\2\2j\u0163\3\2\2\2l\u0166\3\2\2\2n\u016a\3\2\2\2p\u016d"+ + "\3\2\2\2r\u0170\3\2\2\2t\u0172\3\2\2\2v\u0175\3\2\2\2x\u0178\3\2\2\2z"+ + "\u017b\3\2\2\2|\u017e\3\2\2\2~\u0181\3\2\2\2\u0080\u0184\3\2\2\2\u0082"+ + "\u0187\3\2\2\2\u0084\u018a\3\2\2\2\u0086\u018e\3\2\2\2\u0088\u0192\3\2"+ + "\2\2\u008a\u0197\3\2\2\2\u008c\u01a0\3\2\2\2\u008e\u01b2\3\2\2\2\u0090"+ + "\u01bf\3\2\2\2\u0092\u01ef\3\2\2\2\u0094\u01f1\3\2\2\2\u0096\u0202\3\2"+ + "\2\2\u0098\u0207\3\2\2\2\u009a\u020d\3\2\2\2\u009c\u0212\3\2\2\2\u009e"+ + "\u021d\3\2\2\2\u00a0\u022c\3\2\2\2\u00a2\u0230\3\2\2\2\u00a4\u00a6\t\2"+ + "\2\2\u00a5\u00a4\3\2\2\2\u00a6\u00a7\3\2\2\2\u00a7\u00a5\3\2\2\2\u00a7"+ + "\u00a8\3\2\2\2\u00a8\u00a9\3\2\2\2\u00a9\u00aa\b\2\2\2\u00aa\5\3\2\2\2"+ + "\u00ab\u00ac\7\61\2\2\u00ac\u00ad\7\61\2\2\u00ad\u00b1\3\2\2\2\u00ae\u00b0"+ + "\13\2\2\2\u00af\u00ae\3\2\2\2\u00b0\u00b3\3\2\2\2\u00b1\u00b2\3\2\2\2"+ + "\u00b1\u00af\3\2\2\2\u00b2\u00b4\3\2\2\2\u00b3\u00b1\3\2\2\2\u00b4\u00c1"+ + "\t\3\2\2\u00b5\u00b6\7\61\2\2\u00b6\u00b7\7,\2\2\u00b7\u00bb\3\2\2\2\u00b8"+ + "\u00ba\13\2\2\2\u00b9\u00b8\3\2\2\2\u00ba\u00bd\3\2\2\2\u00bb\u00bc\3"+ + "\2\2\2\u00bb\u00b9\3\2\2\2\u00bc\u00be\3\2\2\2\u00bd\u00bb\3\2\2\2\u00be"+ + "\u00bf\7,\2\2\u00bf\u00c1\7\61\2\2\u00c0\u00ab\3\2\2\2\u00c0\u00b5\3\2"+ + "\2\2\u00c1\u00c2\3\2\2\2\u00c2\u00c3\b\3\2\2\u00c3\7\3\2\2\2\u00c4\u00c5"+ + "\7}\2\2\u00c5\t\3\2\2\2\u00c6\u00c7\7\177\2\2\u00c7\13\3\2\2\2\u00c8\u00c9"+ + "\7]\2\2\u00c9\r\3\2\2\2\u00ca\u00cb\7_\2\2\u00cb\17\3\2\2\2\u00cc\u00cd"+ + "\7*\2\2\u00cd\21\3\2\2\2\u00ce\u00cf\7+\2\2\u00cf\23\3\2\2\2\u00d0\u00d1"+ + "\7\60\2\2\u00d1\u00d2\3\2\2\2\u00d2\u00d3\b\n\3\2\u00d3\25\3\2\2\2\u00d4"+ + "\u00d5\7.\2\2\u00d5\27\3\2\2\2\u00d6\u00d7\7=\2\2\u00d7\31\3\2\2\2\u00d8"+ + "\u00d9\7k\2\2\u00d9\u00da\7h\2\2\u00da\33\3\2\2\2\u00db\u00dc\7g\2\2\u00dc"+ + "\u00dd\7n\2\2\u00dd\u00de\7u\2\2\u00de\u00df\7g\2\2\u00df\35\3\2\2\2\u00e0"+ + "\u00e1\7y\2\2\u00e1\u00e2\7j\2\2\u00e2\u00e3\7k\2\2\u00e3\u00e4\7n\2\2"+ + "\u00e4\u00e5\7g\2\2\u00e5\37\3\2\2\2\u00e6\u00e7\7f\2\2\u00e7\u00e8\7"+ + "q\2\2\u00e8!\3\2\2\2\u00e9\u00ea\7h\2\2\u00ea\u00eb\7q\2\2\u00eb\u00ec"+ + "\7t\2\2\u00ec#\3\2\2\2\u00ed\u00ee\7e\2\2\u00ee\u00ef\7q\2\2\u00ef\u00f0"+ + "\7p\2\2\u00f0\u00f1\7v\2\2\u00f1\u00f2\7k\2\2\u00f2\u00f3\7p\2\2\u00f3"+ + "\u00f4\7w\2\2\u00f4\u00f5\7g\2\2\u00f5%\3\2\2\2\u00f6\u00f7\7d\2\2\u00f7"+ + "\u00f8\7t\2\2\u00f8\u00f9\7g\2\2\u00f9\u00fa\7c\2\2\u00fa\u00fb\7m\2\2"+ + "\u00fb\'\3\2\2\2\u00fc\u00fd\7t\2\2\u00fd\u00fe\7g\2\2\u00fe\u00ff\7v"+ + "\2\2\u00ff\u0100\7w\2\2\u0100\u0101\7t\2\2\u0101\u0102\7p\2\2\u0102)\3"+ + "\2\2\2\u0103\u0104\7p\2\2\u0104\u0105\7g\2\2\u0105\u0106\7y\2\2\u0106"+ + "+\3\2\2\2\u0107\u0108\7v\2\2\u0108\u0109\7t\2\2\u0109\u010a\7{\2\2\u010a"+ + "-\3\2\2\2\u010b\u010c\7e\2\2\u010c\u010d\7c\2\2\u010d\u010e\7v\2\2\u010e"+ + "\u010f\7e\2\2\u010f\u0110\7j\2\2\u0110/\3\2\2\2\u0111\u0112\7v\2\2\u0112"+ + "\u0113\7j\2\2\u0113\u0114\7t\2\2\u0114\u0115\7q\2\2\u0115\u0116\7y\2\2"+ + "\u0116\61\3\2\2\2\u0117\u0118\7v\2\2\u0118\u0119\7j\2\2\u0119\u011a\7"+ + "k\2\2\u011a\u011b\7u\2\2\u011b\63\3\2\2\2\u011c\u011d\7#\2\2\u011d\65"+ + "\3\2\2\2\u011e\u011f\7\u0080\2\2\u011f\67\3\2\2\2\u0120\u0121\7,\2\2\u0121"+ + "9\3\2\2\2\u0122\u0123\7\61\2\2\u0123\u0124\6\35\2\2\u0124;\3\2\2\2\u0125"+ + "\u0126\7\'\2\2\u0126=\3\2\2\2\u0127\u0128\7-\2\2\u0128?\3\2\2\2\u0129"+ + "\u012a\7/\2\2\u012aA\3\2\2\2\u012b\u012c\7>\2\2\u012c\u012d\7>\2\2\u012d"+ + "C\3\2\2\2\u012e\u012f\7@\2\2\u012f\u0130\7@\2\2\u0130E\3\2\2\2\u0131\u0132"+ + "\7@\2\2\u0132\u0133\7@\2\2\u0133\u0134\7@\2\2\u0134G\3\2\2\2\u0135\u0136"+ + "\7>\2\2\u0136I\3\2\2\2\u0137\u0138\7>\2\2\u0138\u0139\7?\2\2\u0139K\3"+ + "\2\2\2\u013a\u013b\7@\2\2\u013bM\3\2\2\2\u013c\u013d\7@\2\2\u013d\u013e"+ + "\7?\2\2\u013eO\3\2\2\2\u013f\u0140\7?\2\2\u0140\u0141\7?\2\2\u0141Q\3"+ + "\2\2\2\u0142\u0143\7?\2\2\u0143\u0144\7?\2\2\u0144\u0145\7?\2\2\u0145"+ + "S\3\2\2\2\u0146\u0147\7#\2\2\u0147\u0148\7?\2\2\u0148U\3\2\2\2\u0149\u014a"+ + "\7#\2\2\u014a\u014b\7?\2\2\u014b\u014c\7?\2\2\u014cW\3\2\2\2\u014d\u014e"+ + "\7(\2\2\u014eY\3\2\2\2\u014f\u0150\7`\2\2\u0150[\3\2\2\2\u0151\u0152\7"+ + "~\2\2\u0152]\3\2\2\2\u0153\u0154\7(\2\2\u0154\u0155\7(\2\2\u0155_\3\2"+ + "\2\2\u0156\u0157\7~\2\2\u0157\u0158\7~\2\2\u0158a\3\2\2\2\u0159\u015a"+ + "\7A\2\2\u015ac\3\2\2\2\u015b\u015c\7<\2\2\u015ce\3\2\2\2\u015d\u015e\7"+ + "<\2\2\u015e\u015f\7<\2\2\u015fg\3\2\2\2\u0160\u0161\7/\2\2\u0161\u0162"+ + "\7@\2\2\u0162i\3\2\2\2\u0163\u0164\7?\2\2\u0164\u0165\7\u0080\2\2\u0165"+ + "k\3\2\2\2\u0166\u0167\7?\2\2\u0167\u0168\7?\2\2\u0168\u0169\7\u0080\2"+ + "\2\u0169m\3\2\2\2\u016a\u016b\7-\2\2\u016b\u016c\7-\2\2\u016co\3\2\2\2"+ + "\u016d\u016e\7/\2\2\u016e\u016f\7/\2\2\u016fq\3\2\2\2\u0170\u0171\7?\2"+ + "\2\u0171s\3\2\2\2\u0172\u0173\7-\2\2\u0173\u0174\7?\2\2\u0174u\3\2\2\2"+ + "\u0175\u0176\7/\2\2\u0176\u0177\7?\2\2\u0177w\3\2\2\2\u0178\u0179\7,\2"+ + "\2\u0179\u017a\7?\2\2\u017ay\3\2\2\2\u017b\u017c\7\61\2\2\u017c\u017d"+ + "\7?\2\2\u017d{\3\2\2\2\u017e\u017f\7\'\2\2\u017f\u0180\7?\2\2\u0180}\3"+ + "\2\2\2\u0181\u0182\7(\2\2\u0182\u0183\7?\2\2\u0183\177\3\2\2\2\u0184\u0185"+ + "\7`\2\2\u0185\u0186\7?\2\2\u0186\u0081\3\2\2\2\u0187\u0188\7~\2\2\u0188"+ + "\u0189\7?\2\2\u0189\u0083\3\2\2\2\u018a\u018b\7>\2\2\u018b\u018c\7>\2"+ + "\2\u018c\u018d\7?\2\2\u018d\u0085\3\2\2\2\u018e\u018f\7@\2\2\u018f\u0190"+ + "\7@\2\2\u0190\u0191\7?\2\2\u0191\u0087\3\2\2\2\u0192\u0193\7@\2\2\u0193"+ + "\u0194\7@\2\2\u0194\u0195\7@\2\2\u0195\u0196\7?\2\2\u0196\u0089\3\2\2"+ + "\2\u0197\u0199\7\62\2\2\u0198\u019a\t\4\2\2\u0199\u0198\3\2\2\2\u019a"+ + "\u019b\3\2\2\2\u019b\u0199\3\2\2\2\u019b\u019c\3\2\2\2\u019c\u019e\3\2"+ + "\2\2\u019d\u019f\t\5\2\2\u019e\u019d\3\2\2\2\u019e\u019f\3\2\2\2\u019f"+ + "\u008b\3\2\2\2\u01a0\u01a1\7\62\2\2\u01a1\u01a3\t\6\2\2\u01a2\u01a4\t"+ + "\7\2\2\u01a3\u01a2\3\2\2\2\u01a4\u01a5\3\2\2\2\u01a5\u01a3\3\2\2\2\u01a5"+ + "\u01a6\3\2\2\2\u01a6\u01a8\3\2\2\2\u01a7\u01a9\t\5\2\2\u01a8\u01a7\3\2"+ + "\2\2\u01a8\u01a9\3\2\2\2\u01a9\u008d\3\2\2\2\u01aa\u01b3\7\62\2\2\u01ab"+ + "\u01af\t\b\2\2\u01ac\u01ae\t\t\2\2\u01ad\u01ac\3\2\2\2\u01ae\u01b1\3\2"+ + "\2\2\u01af\u01ad\3\2\2\2\u01af\u01b0\3\2\2\2\u01b0\u01b3\3\2\2\2\u01b1"+ + "\u01af\3\2\2\2\u01b2\u01aa\3\2\2\2\u01b2\u01ab\3\2\2\2\u01b3\u01b5\3\2"+ + "\2\2\u01b4\u01b6\t\n\2\2\u01b5\u01b4\3\2\2\2\u01b5\u01b6\3\2\2\2\u01b6"+ + "\u008f\3\2\2\2\u01b7\u01c0\7\62\2\2\u01b8\u01bc\t\b\2\2\u01b9\u01bb\t"+ + "\t\2\2\u01ba\u01b9\3\2\2\2\u01bb\u01be\3\2\2\2\u01bc\u01ba\3\2\2\2\u01bc"+ + "\u01bd\3\2\2\2\u01bd\u01c0\3\2\2\2\u01be\u01bc\3\2\2\2\u01bf\u01b7\3\2"+ + "\2\2\u01bf\u01b8\3\2\2\2\u01c0\u01c7\3\2\2\2\u01c1\u01c3\5\24\n\2\u01c2"+ + "\u01c4\t\t\2\2\u01c3\u01c2\3\2\2\2\u01c4\u01c5\3\2\2\2\u01c5\u01c3\3\2"+ + "\2\2\u01c5\u01c6\3\2\2\2\u01c6\u01c8\3\2\2\2\u01c7\u01c1\3\2\2\2\u01c7"+ + "\u01c8\3\2\2\2\u01c8\u01d2\3\2\2\2\u01c9\u01cb\t\13\2\2\u01ca\u01cc\t"+ + "\f\2\2\u01cb\u01ca\3\2\2\2\u01cb\u01cc\3\2\2\2\u01cc\u01ce\3\2\2\2\u01cd"+ + "\u01cf\t\t\2\2\u01ce\u01cd\3\2\2\2\u01cf\u01d0\3\2\2\2\u01d0\u01ce\3\2"+ + "\2\2\u01d0\u01d1\3\2\2\2\u01d1\u01d3\3\2\2\2\u01d2\u01c9\3\2\2\2\u01d2"+ + "\u01d3\3\2\2\2\u01d3\u01d5\3\2\2\2\u01d4\u01d6\t\r\2\2\u01d5\u01d4\3\2"+ + "\2\2\u01d5\u01d6\3\2\2\2\u01d6\u0091\3\2\2\2\u01d7\u01df\7$\2\2\u01d8"+ + "\u01d9\7^\2\2\u01d9\u01de\7$\2\2\u01da\u01db\7^\2\2\u01db\u01de\7^\2\2"+ + "\u01dc\u01de\n\16\2\2\u01dd\u01d8\3\2\2\2\u01dd\u01da\3\2\2\2\u01dd\u01dc"+ + "\3\2\2\2\u01de\u01e1\3\2\2\2\u01df\u01e0\3\2\2\2\u01df\u01dd\3\2\2\2\u01e0"+ + "\u01e2\3\2\2\2\u01e1\u01df\3\2\2\2\u01e2\u01f0\7$\2\2\u01e3\u01eb\7)\2"+ + "\2\u01e4\u01e5\7^\2\2\u01e5\u01ea\7)\2\2\u01e6\u01e7\7^\2\2\u01e7\u01ea"+ + "\7^\2\2\u01e8\u01ea\n\16\2\2\u01e9\u01e4\3\2\2\2\u01e9\u01e6\3\2\2\2\u01e9"+ + "\u01e8\3\2\2\2\u01ea\u01ed\3\2\2\2\u01eb\u01ec\3\2\2\2\u01eb\u01e9\3\2"+ + "\2\2\u01ec\u01ee\3\2\2\2\u01ed\u01eb\3\2\2\2\u01ee\u01f0\7)\2\2\u01ef"+ + "\u01d7\3\2\2\2\u01ef\u01e3\3\2\2\2\u01f0\u0093\3\2\2\2\u01f1\u01f5\7\61"+ + "\2\2\u01f2\u01f6\n\17\2\2\u01f3\u01f4\7^\2\2\u01f4\u01f6\n\20\2\2\u01f5"+ + "\u01f2\3\2\2\2\u01f5\u01f3\3\2\2\2\u01f6\u01f7\3\2\2\2\u01f7\u01f5\3\2"+ + "\2\2\u01f7\u01f8\3\2\2\2\u01f8\u01f9\3\2\2\2\u01f9\u01fd\7\61\2\2\u01fa"+ + "\u01fc\t\21\2\2\u01fb\u01fa\3\2\2\2\u01fc\u01ff\3\2\2\2\u01fd\u01fb\3"+ + "\2\2\2\u01fd\u01fe\3\2\2\2\u01fe\u0200\3\2\2\2\u01ff\u01fd\3\2\2\2\u0200"+ + "\u0201\6J\3\2\u0201\u0095\3\2\2\2\u0202\u0203\7v\2\2\u0203\u0204\7t\2"+ + "\2\u0204\u0205\7w\2\2\u0205\u0206\7g\2\2\u0206\u0097\3\2\2\2\u0207\u0208"+ + "\7h\2\2\u0208\u0209\7c\2\2\u0209\u020a\7n\2\2\u020a\u020b\7u\2\2\u020b"+ + "\u020c\7g\2\2\u020c\u0099\3\2\2\2\u020d\u020e\7p\2\2\u020e\u020f\7w\2"+ + "\2\u020f\u0210\7n\2\2\u0210\u0211\7n\2\2\u0211\u009b\3\2\2\2\u0212\u0218"+ + "\5\u009eO\2\u0213\u0214\5\24\n\2\u0214\u0215\5\u009eO\2\u0215\u0217\3"+ + "\2\2\2\u0216\u0213\3\2\2\2\u0217\u021a\3\2\2\2\u0218\u0216\3\2\2\2\u0218"+ + "\u0219\3\2\2\2\u0219\u021b\3\2\2\2\u021a\u0218\3\2\2\2\u021b\u021c\6N"+ + "\4\2\u021c\u009d\3\2\2\2\u021d\u0221\t\22\2\2\u021e\u0220\t\23\2\2\u021f"+ + "\u021e\3\2\2\2\u0220\u0223\3\2\2\2\u0221\u021f\3\2\2\2\u0221\u0222\3\2"+ + "\2\2\u0222\u009f\3\2\2\2\u0223\u0221\3\2\2\2\u0224\u022d\7\62\2\2\u0225"+ + "\u0229\t\b\2\2\u0226\u0228\t\t\2\2\u0227\u0226\3\2\2\2\u0228\u022b\3\2"+ + "\2\2\u0229\u0227\3\2\2\2\u0229\u022a\3\2\2\2\u022a\u022d\3\2\2\2\u022b"+ + "\u0229\3\2\2\2\u022c\u0224\3\2\2\2\u022c\u0225\3\2\2\2\u022d\u022e\3\2"+ + "\2\2\u022e\u022f\bP\4\2\u022f\u00a1\3\2\2\2\u0230\u0234\t\22\2\2\u0231"+ + "\u0233\t\23\2\2\u0232\u0231\3\2\2\2\u0233\u0236\3\2\2\2\u0234\u0232\3"+ + "\2\2\2\u0234\u0235\3\2\2\2\u0235\u0237\3\2\2\2\u0236\u0234\3\2\2\2\u0237"+ + "\u0238\bQ\4\2\u0238\u00a3\3\2\2\2$\2\3\u00a7\u00b1\u00bb\u00c0\u019b\u019e"+ "\u01a5\u01a8\u01af\u01b2\u01b5\u01bc\u01bf\u01c5\u01c7\u01cb\u01d0\u01d2"+ - "\u01d5\u01dd\u01df\u01e9\u01eb\u01ef\u01f5\u01f7\u0212\u021b\u0223\u0226"+ - "\u022e\5\b\2\2\4\3\2\4\2\2"; + "\u01d5\u01dd\u01df\u01e9\u01eb\u01ef\u01f5\u01f7\u01fd\u0218\u0221\u0229"+ + "\u022c\u0234\5\b\2\2\4\3\2\4\2\2"; public static final ATN _ATN = new ATNDeserializer().deserialize(_serializedATN.toCharArray()); static { diff --git a/modules/lang-painless/src/main/java/org/elasticsearch/painless/antlr/PainlessParser.java b/modules/lang-painless/src/main/java/org/elasticsearch/painless/antlr/PainlessParser.java index ba3798bb414..7b994e699a2 100644 --- a/modules/lang-painless/src/main/java/org/elasticsearch/painless/antlr/PainlessParser.java +++ b/modules/lang-painless/src/main/java/org/elasticsearch/painless/antlr/PainlessParser.java @@ -2754,9 +2754,6 @@ class PainlessParser extends Parser { public static class LambdaContext extends ParserRuleContext { public TerminalNode ARROW() { return getToken(PainlessParser.ARROW, 0); } - public BlockContext block() { - return getRuleContext(BlockContext.class,0); - } public List lamtype() { return getRuleContexts(LamtypeContext.class); } @@ -2765,6 +2762,12 @@ class PainlessParser extends Parser { } public TerminalNode LP() { return getToken(PainlessParser.LP, 0); } public TerminalNode RP() { return getToken(PainlessParser.RP, 0); } + public BlockContext block() { + return getRuleContext(BlockContext.class,0); + } + public ExpressionContext expression() { + return getRuleContext(ExpressionContext.class,0); + } public List COMMA() { return getTokens(PainlessParser.COMMA); } public TerminalNode COMMA(int i) { return getToken(PainlessParser.COMMA, i); @@ -2834,8 +2837,21 @@ class PainlessParser extends Parser { } setState(448); match(ARROW); - setState(449); - block(); + setState(451); + switch ( getInterpreter().adaptivePredict(_input,38,_ctx) ) { + case 1: + { + setState(449); + block(); + } + break; + case 2: + { + setState(450); + expression(0); + } + break; + } } } catch (RecognitionException re) { @@ -2872,16 +2888,16 @@ class PainlessParser extends Parser { try { enterOuterAlt(_localctx, 1); { - setState(452); + setState(454); _la = _input.LA(1); if (_la==TYPE) { { - setState(451); + setState(453); decltype(); } } - setState(454); + setState(456); match(ID); } } @@ -2924,33 +2940,33 @@ class PainlessParser extends Parser { FuncrefContext _localctx = new FuncrefContext(_ctx, getState()); enterRule(_localctx, 50, RULE_funcref); try { - setState(460); - switch ( getInterpreter().adaptivePredict(_input,39,_ctx) ) { + setState(462); + switch ( getInterpreter().adaptivePredict(_input,40,_ctx) ) { case 1: enterOuterAlt(_localctx, 1); { - setState(456); + setState(458); classFuncref(); } break; case 2: enterOuterAlt(_localctx, 2); { - setState(457); + setState(459); constructorFuncref(); } break; case 3: enterOuterAlt(_localctx, 3); { - setState(458); + setState(460); capturingFuncref(); } break; case 4: enterOuterAlt(_localctx, 4); { - setState(459); + setState(461); localFuncref(); } break; @@ -2988,11 +3004,11 @@ class PainlessParser extends Parser { try { enterOuterAlt(_localctx, 1); { - setState(462); - match(TYPE); - setState(463); - match(REF); setState(464); + match(TYPE); + setState(465); + match(REF); + setState(466); match(ID); } } @@ -3030,11 +3046,11 @@ class PainlessParser extends Parser { try { enterOuterAlt(_localctx, 1); { - setState(466); - decltype(); - setState(467); - match(REF); setState(468); + decltype(); + setState(469); + match(REF); + setState(470); match(NEW); } } @@ -3072,12 +3088,12 @@ class PainlessParser extends Parser { try { enterOuterAlt(_localctx, 1); { - setState(470); - match(ID); - setState(471); - match(REF); setState(472); match(ID); + setState(473); + match(REF); + setState(474); + match(ID); } } catch (RecognitionException re) { @@ -3112,11 +3128,11 @@ class PainlessParser extends Parser { try { enterOuterAlt(_localctx, 1); { - setState(474); - match(THIS); - setState(475); - match(REF); setState(476); + match(THIS); + setState(477); + match(REF); + setState(478); match(ID); } } @@ -3223,7 +3239,7 @@ class PainlessParser extends Parser { } public static final String _serializedATN = - "\3\u0430\ud6d1\u8206\uad2d\u4417\uaef1\u8d80\uaadd\3R\u01e1\4\2\t\2\4"+ + "\3\u0430\ud6d1\u8206\uad2d\u4417\uaef1\u8d80\uaadd\3R\u01e3\4\2\t\2\4"+ "\3\t\3\4\4\t\4\4\5\t\5\4\6\t\6\4\7\t\7\4\b\t\b\4\t\t\t\4\n\t\n\4\13\t"+ "\13\4\f\t\f\4\r\t\r\4\16\t\16\4\17\t\17\4\20\t\20\4\21\t\21\4\22\t\22"+ "\4\23\t\23\4\24\t\24\4\25\t\25\4\26\t\26\4\27\t\27\4\30\t\30\4\31\t\31"+ @@ -3257,152 +3273,153 @@ class PainlessParser extends Parser { "\u019c\n\25\3\26\3\26\3\26\3\26\3\27\3\27\3\27\3\27\7\27\u01a6\n\27\f"+ "\27\16\27\u01a9\13\27\5\27\u01ab\n\27\3\27\3\27\3\30\3\30\3\30\5\30\u01b2"+ "\n\30\3\31\3\31\3\31\3\31\3\31\7\31\u01b9\n\31\f\31\16\31\u01bc\13\31"+ - "\5\31\u01be\n\31\3\31\5\31\u01c1\n\31\3\31\3\31\3\31\3\32\5\32\u01c7\n"+ - "\32\3\32\3\32\3\33\3\33\3\33\3\33\5\33\u01cf\n\33\3\34\3\34\3\34\3\34"+ - "\3\35\3\35\3\35\3\35\3\36\3\36\3\36\3\36\3\37\3\37\3\37\3\37\3\37\2\3"+ - "\36 \2\4\6\b\n\f\16\20\22\24\26\30\32\34\36 \"$&(*,.\60\62\64\668:<\2"+ - "\r\3\2:E\3\2\35\37\3\2 !\3\2\66\67\3\2\"$\3\2%(\3\2),\3\289\3\2FI\4\2"+ - "\33\34 !\3\2QR\u020f\2A\3\2\2\2\4L\3\2\2\2\6Q\3\2\2\2\b\u00af\3\2\2\2"+ - "\n\u00b3\3\2\2\2\f\u00b5\3\2\2\2\16\u00be\3\2\2\2\20\u00c2\3\2\2\2\22"+ - "\u00c4\3\2\2\2\24\u00c6\3\2\2\2\26\u00cf\3\2\2\2\30\u00d7\3\2\2\2\32\u00dc"+ - "\3\2\2\2\34\u00e8\3\2\2\2\36\u00f3\3\2\2\2 \u0155\3\2\2\2\"\u0179\3\2"+ - "\2\2$\u018e\3\2\2\2&\u0194\3\2\2\2(\u019b\3\2\2\2*\u019d\3\2\2\2,\u01a1"+ - "\3\2\2\2.\u01b1\3\2\2\2\60\u01c0\3\2\2\2\62\u01c6\3\2\2\2\64\u01ce\3\2"+ - "\2\2\66\u01d0\3\2\2\28\u01d4\3\2\2\2:\u01d8\3\2\2\2<\u01dc\3\2\2\2>@\5"+ - "\4\3\2?>\3\2\2\2@C\3\2\2\2A?\3\2\2\2AB\3\2\2\2BG\3\2\2\2CA\3\2\2\2DF\5"+ - "\b\5\2ED\3\2\2\2FI\3\2\2\2GE\3\2\2\2GH\3\2\2\2HJ\3\2\2\2IG\3\2\2\2JK\7"+ - "\2\2\3K\3\3\2\2\2LM\5\26\f\2MN\7P\2\2NO\5\6\4\2OP\5\f\7\2P\5\3\2\2\2Q"+ - "]\7\t\2\2RS\5\26\f\2SZ\7P\2\2TU\7\f\2\2UV\5\26\f\2VW\7P\2\2WY\3\2\2\2"+ - "XT\3\2\2\2Y\\\3\2\2\2ZX\3\2\2\2Z[\3\2\2\2[^\3\2\2\2\\Z\3\2\2\2]R\3\2\2"+ - "\2]^\3\2\2\2^_\3\2\2\2_`\7\n\2\2`\7\3\2\2\2ab\7\16\2\2bc\7\t\2\2cd\5\36"+ - "\20\2de\7\n\2\2ei\5\n\6\2fg\7\17\2\2gj\5\n\6\2hj\6\5\2\2if\3\2\2\2ih\3"+ - "\2\2\2j\u00b0\3\2\2\2kl\7\20\2\2lm\7\t\2\2mn\5\36\20\2nq\7\n\2\2or\5\n"+ - "\6\2pr\5\16\b\2qo\3\2\2\2qp\3\2\2\2r\u00b0\3\2\2\2st\7\21\2\2tu\5\f\7"+ - "\2uv\7\20\2\2vw\7\t\2\2wx\5\36\20\2xy\7\n\2\2yz\5\34\17\2z\u00b0\3\2\2"+ - "\2{|\7\22\2\2|~\7\t\2\2}\177\5\20\t\2~}\3\2\2\2~\177\3\2\2\2\177\u0080"+ - "\3\2\2\2\u0080\u0082\7\r\2\2\u0081\u0083\5\36\20\2\u0082\u0081\3\2\2\2"+ - "\u0082\u0083\3\2\2\2\u0083\u0084\3\2\2\2\u0084\u0086\7\r\2\2\u0085\u0087"+ - "\5\22\n\2\u0086\u0085\3\2\2\2\u0086\u0087\3\2\2\2\u0087\u0088\3\2\2\2"+ - "\u0088\u008b\7\n\2\2\u0089\u008c\5\n\6\2\u008a\u008c\5\16\b\2\u008b\u0089"+ - "\3\2\2\2\u008b\u008a\3\2\2\2\u008c\u00b0\3\2\2\2\u008d\u008e\7\22\2\2"+ - "\u008e\u008f\7\t\2\2\u008f\u0090\5\26\f\2\u0090\u0091\7P\2\2\u0091\u0092"+ - "\7\63\2\2\u0092\u0093\5\36\20\2\u0093\u0094\7\n\2\2\u0094\u0095\5\n\6"+ - "\2\u0095\u00b0\3\2\2\2\u0096\u0097\5\24\13\2\u0097\u0098\5\34\17\2\u0098"+ - "\u00b0\3\2\2\2\u0099\u009a\7\23\2\2\u009a\u00b0\5\34\17\2\u009b\u009c"+ - "\7\24\2\2\u009c\u00b0\5\34\17\2\u009d\u009e\7\25\2\2\u009e\u009f\5\36"+ - "\20\2\u009f\u00a0\5\34\17\2\u00a0\u00b0\3\2\2\2\u00a1\u00a2\7\27\2\2\u00a2"+ - "\u00a4\5\f\7\2\u00a3\u00a5\5\32\16\2\u00a4\u00a3\3\2\2\2\u00a5\u00a6\3"+ - "\2\2\2\u00a6\u00a4\3\2\2\2\u00a6\u00a7\3\2\2\2\u00a7\u00b0\3\2\2\2\u00a8"+ - "\u00a9\7\31\2\2\u00a9\u00aa\5\36\20\2\u00aa\u00ab\5\34\17\2\u00ab\u00b0"+ - "\3\2\2\2\u00ac\u00ad\5\36\20\2\u00ad\u00ae\5\34\17\2\u00ae\u00b0\3\2\2"+ - "\2\u00afa\3\2\2\2\u00afk\3\2\2\2\u00afs\3\2\2\2\u00af{\3\2\2\2\u00af\u008d"+ - "\3\2\2\2\u00af\u0096\3\2\2\2\u00af\u0099\3\2\2\2\u00af\u009b\3\2\2\2\u00af"+ - "\u009d\3\2\2\2\u00af\u00a1\3\2\2\2\u00af\u00a8\3\2\2\2\u00af\u00ac\3\2"+ - "\2\2\u00b0\t\3\2\2\2\u00b1\u00b4\5\f\7\2\u00b2\u00b4\5\b\5\2\u00b3\u00b1"+ - "\3\2\2\2\u00b3\u00b2\3\2\2\2\u00b4\13\3\2\2\2\u00b5\u00b9\7\5\2\2\u00b6"+ - "\u00b8\5\b\5\2\u00b7\u00b6\3\2\2\2\u00b8\u00bb\3\2\2\2\u00b9\u00b7\3\2"+ - "\2\2\u00b9\u00ba\3\2\2\2\u00ba\u00bc\3\2\2\2\u00bb\u00b9\3\2\2\2\u00bc"+ - "\u00bd\7\6\2\2\u00bd\r\3\2\2\2\u00be\u00bf\7\r\2\2\u00bf\17\3\2\2\2\u00c0"+ - "\u00c3\5\24\13\2\u00c1\u00c3\5\36\20\2\u00c2\u00c0\3\2\2\2\u00c2\u00c1"+ - "\3\2\2\2\u00c3\21\3\2\2\2\u00c4\u00c5\5\36\20\2\u00c5\23\3\2\2\2\u00c6"+ - "\u00c7\5\26\f\2\u00c7\u00cc\5\30\r\2\u00c8\u00c9\7\f\2\2\u00c9\u00cb\5"+ - "\30\r\2\u00ca\u00c8\3\2\2\2\u00cb\u00ce\3\2\2\2\u00cc\u00ca\3\2\2\2\u00cc"+ - "\u00cd\3\2\2\2\u00cd\25\3\2\2\2\u00ce\u00cc\3\2\2\2\u00cf\u00d4\7O\2\2"+ - "\u00d0\u00d1\7\7\2\2\u00d1\u00d3\7\b\2\2\u00d2\u00d0\3\2\2\2\u00d3\u00d6"+ - "\3\2\2\2\u00d4\u00d2\3\2\2\2\u00d4\u00d5\3\2\2\2\u00d5\27\3\2\2\2\u00d6"+ - "\u00d4\3\2\2\2\u00d7\u00da\7P\2\2\u00d8\u00d9\7:\2\2\u00d9\u00db\5\36"+ - "\20\2\u00da\u00d8\3\2\2\2\u00da\u00db\3\2\2\2\u00db\31\3\2\2\2\u00dc\u00dd"+ - "\7\30\2\2\u00dd\u00de\7\t\2\2\u00de\u00df\7O\2\2\u00df\u00e0\7P\2\2\u00e0"+ - "\u00e1\7\n\2\2\u00e1\u00e2\5\f\7\2\u00e2\33\3\2\2\2\u00e3\u00e9\7\r\2"+ - "\2\u00e4\u00e9\7\2\2\3\u00e5\u00e6\b\17\1\2\u00e6\u00e7\7\6\2\2\u00e7"+ - "\u00e9\b\17\1\2\u00e8\u00e3\3\2\2\2\u00e8\u00e4\3\2\2\2\u00e8\u00e5\3"+ - "\2\2\2\u00e9\35\3\2\2\2\u00ea\u00eb\b\20\1\2\u00eb\u00ec\5\"\22\2\u00ec"+ - "\u00ed\t\2\2\2\u00ed\u00ee\5\36\20\3\u00ee\u00ef\b\20\1\2\u00ef\u00f4"+ - "\3\2\2\2\u00f0\u00f1\5 \21\2\u00f1\u00f2\b\20\1\2\u00f2\u00f4\3\2\2\2"+ - "\u00f3\u00ea\3\2\2\2\u00f3\u00f0\3\2\2\2\u00f4\u0135\3\2\2\2\u00f5\u00f6"+ - "\f\17\2\2\u00f6\u00f7\t\3\2\2\u00f7\u00f8\5\36\20\20\u00f8\u00f9\b\20"+ - "\1\2\u00f9\u0134\3\2\2\2\u00fa\u00fb\f\16\2\2\u00fb\u00fc\t\4\2\2\u00fc"+ - "\u00fd\5\36\20\17\u00fd\u00fe\b\20\1\2\u00fe\u0134\3\2\2\2\u00ff\u0100"+ - "\f\r\2\2\u0100\u0101\t\5\2\2\u0101\u0102\5\36\20\16\u0102\u0103\b\20\1"+ - "\2\u0103\u0134\3\2\2\2\u0104\u0105\f\f\2\2\u0105\u0106\t\6\2\2\u0106\u0107"+ - "\5\36\20\r\u0107\u0108\b\20\1\2\u0108\u0134\3\2\2\2\u0109\u010a\f\13\2"+ - "\2\u010a\u010b\t\7\2\2\u010b\u010c\5\36\20\f\u010c\u010d\b\20\1\2\u010d"+ - "\u0134\3\2\2\2\u010e\u010f\f\n\2\2\u010f\u0110\t\b\2\2\u0110\u0111\5\36"+ - "\20\13\u0111\u0112\b\20\1\2\u0112\u0134\3\2\2\2\u0113\u0114\f\t\2\2\u0114"+ - "\u0115\7-\2\2\u0115\u0116\5\36\20\n\u0116\u0117\b\20\1\2\u0117\u0134\3"+ - "\2\2\2\u0118\u0119\f\b\2\2\u0119\u011a\7.\2\2\u011a\u011b\5\36\20\t\u011b"+ - "\u011c\b\20\1\2\u011c\u0134\3\2\2\2\u011d\u011e\f\7\2\2\u011e\u011f\7"+ - "/\2\2\u011f\u0120\5\36\20\b\u0120\u0121\b\20\1\2\u0121\u0134\3\2\2\2\u0122"+ - "\u0123\f\6\2\2\u0123\u0124\7\60\2\2\u0124\u0125\5\36\20\7\u0125\u0126"+ - "\b\20\1\2\u0126\u0134\3\2\2\2\u0127\u0128\f\5\2\2\u0128\u0129\7\61\2\2"+ - "\u0129\u012a\5\36\20\6\u012a\u012b\b\20\1\2\u012b\u0134\3\2\2\2\u012c"+ - "\u012d\f\4\2\2\u012d\u012e\7\62\2\2\u012e\u012f\5\36\20\2\u012f\u0130"+ - "\7\63\2\2\u0130\u0131\5\36\20\4\u0131\u0132\b\20\1\2\u0132\u0134\3\2\2"+ - "\2\u0133\u00f5\3\2\2\2\u0133\u00fa\3\2\2\2\u0133\u00ff\3\2\2\2\u0133\u0104"+ - "\3\2\2\2\u0133\u0109\3\2\2\2\u0133\u010e\3\2\2\2\u0133\u0113\3\2\2\2\u0133"+ - "\u0118\3\2\2\2\u0133\u011d\3\2\2\2\u0133\u0122\3\2\2\2\u0133\u0127\3\2"+ - "\2\2\u0133\u012c\3\2\2\2\u0134\u0137\3\2\2\2\u0135\u0133\3\2\2\2\u0135"+ - "\u0136\3\2\2\2\u0136\37\3\2\2\2\u0137\u0135\3\2\2\2\u0138\u0139\6\21\17"+ - "\3\u0139\u013a\t\t\2\2\u013a\u0156\5\"\22\2\u013b\u013c\6\21\20\3\u013c"+ - "\u013d\5\"\22\2\u013d\u013e\t\t\2\2\u013e\u0156\3\2\2\2\u013f\u0140\6"+ - "\21\21\3\u0140\u0156\5\"\22\2\u0141\u0142\6\21\22\3\u0142\u0143\t\n\2"+ - "\2\u0143\u0156\b\21\1\2\u0144\u0145\6\21\23\3\u0145\u0146\7L\2\2\u0146"+ - "\u0156\b\21\1\2\u0147\u0148\6\21\24\3\u0148\u0149\7M\2\2\u0149\u0156\b"+ - "\21\1\2\u014a\u014b\6\21\25\3\u014b\u014c\7N\2\2\u014c\u0156\b\21\1\2"+ - "\u014d\u014e\6\21\26\3\u014e\u014f\t\13\2\2\u014f\u0156\5 \21\2\u0150"+ - "\u0151\7\t\2\2\u0151\u0152\5\26\f\2\u0152\u0153\7\n\2\2\u0153\u0154\5"+ - " \21\2\u0154\u0156\3\2\2\2\u0155\u0138\3\2\2\2\u0155\u013b\3\2\2\2\u0155"+ - "\u013f\3\2\2\2\u0155\u0141\3\2\2\2\u0155\u0144\3\2\2\2\u0155\u0147\3\2"+ - "\2\2\u0155\u014a\3\2\2\2\u0155\u014d\3\2\2\2\u0155\u0150\3\2\2\2\u0156"+ - "!\3\2\2\2\u0157\u015b\5$\23\2\u0158\u015a\5&\24\2\u0159\u0158\3\2\2\2"+ - "\u015a\u015d\3\2\2\2\u015b\u0159\3\2\2\2\u015b\u015c\3\2\2\2\u015c\u017a"+ - "\3\2\2\2\u015d\u015b\3\2\2\2\u015e\u015f\5\26\f\2\u015f\u0163\5(\25\2"+ - "\u0160\u0162\5&\24\2\u0161\u0160\3\2\2\2\u0162\u0165\3\2\2\2\u0163\u0161"+ - "\3\2\2\2\u0163\u0164\3\2\2\2\u0164\u017a\3\2\2\2\u0165\u0163\3\2\2\2\u0166"+ - "\u0167\7\26\2\2\u0167\u016c\7O\2\2\u0168\u0169\7\7\2\2\u0169\u016a\5\36"+ - "\20\2\u016a\u016b\7\b\2\2\u016b\u016d\3\2\2\2\u016c\u0168\3\2\2\2\u016d"+ - "\u016e\3\2\2\2\u016e\u016c\3\2\2\2\u016e\u016f\3\2\2\2\u016f\u0177\3\2"+ - "\2\2\u0170\u0174\5(\25\2\u0171\u0173\5&\24\2\u0172\u0171\3\2\2\2\u0173"+ - "\u0176\3\2\2\2\u0174\u0172\3\2\2\2\u0174\u0175\3\2\2\2\u0175\u0178\3\2"+ - "\2\2\u0176\u0174\3\2\2\2\u0177\u0170\3\2\2\2\u0177\u0178\3\2\2\2\u0178"+ - "\u017a\3\2\2\2\u0179\u0157\3\2\2\2\u0179\u015e\3\2\2\2\u0179\u0166\3\2"+ - "\2\2\u017a#\3\2\2\2\u017b\u017c\6\23\27\3\u017c\u017d\7\t\2\2\u017d\u017e"+ - "\5\36\20\2\u017e\u017f\7\n\2\2\u017f\u0180\b\23\1\2\u0180\u018f\3\2\2"+ - "\2\u0181\u0182\6\23\30\3\u0182\u0183\7\t\2\2\u0183\u0184\5 \21\2\u0184"+ - "\u0185\7\n\2\2\u0185\u018f\3\2\2\2\u0186\u018f\7J\2\2\u0187\u018f\7K\2"+ - "\2\u0188\u018f\7P\2\2\u0189\u018a\7P\2\2\u018a\u018f\5,\27\2\u018b\u018c"+ - "\7\26\2\2\u018c\u018d\7O\2\2\u018d\u018f\5,\27\2\u018e\u017b\3\2\2\2\u018e"+ - "\u0181\3\2\2\2\u018e\u0186\3\2\2\2\u018e\u0187\3\2\2\2\u018e\u0188\3\2"+ - "\2\2\u018e\u0189\3\2\2\2\u018e\u018b\3\2\2\2\u018f%\3\2\2\2\u0190\u0191"+ - "\6\24\31\3\u0191\u0195\5(\25\2\u0192\u0193\6\24\32\3\u0193\u0195\5*\26"+ - "\2\u0194\u0190\3\2\2\2\u0194\u0192\3\2\2\2\u0195\'\3\2\2\2\u0196\u0197"+ - "\7\13\2\2\u0197\u0198\7R\2\2\u0198\u019c\5,\27\2\u0199\u019a\7\13\2\2"+ - "\u019a\u019c\t\f\2\2\u019b\u0196\3\2\2\2\u019b\u0199\3\2\2\2\u019c)\3"+ - "\2\2\2\u019d\u019e\7\7\2\2\u019e\u019f\5\36\20\2\u019f\u01a0\7\b\2\2\u01a0"+ - "+\3\2\2\2\u01a1\u01aa\7\t\2\2\u01a2\u01a7\5.\30\2\u01a3\u01a4\7\f\2\2"+ - "\u01a4\u01a6\5.\30\2\u01a5\u01a3\3\2\2\2\u01a6\u01a9\3\2\2\2\u01a7\u01a5"+ - "\3\2\2\2\u01a7\u01a8\3\2\2\2\u01a8\u01ab\3\2\2\2\u01a9\u01a7\3\2\2\2\u01aa"+ - "\u01a2\3\2\2\2\u01aa\u01ab\3\2\2\2\u01ab\u01ac\3\2\2\2\u01ac\u01ad\7\n"+ - "\2\2\u01ad-\3\2\2\2\u01ae\u01b2\5\36\20\2\u01af\u01b2\5\60\31\2\u01b0"+ - "\u01b2\5\64\33\2\u01b1\u01ae\3\2\2\2\u01b1\u01af\3\2\2\2\u01b1\u01b0\3"+ - "\2\2\2\u01b2/\3\2\2\2\u01b3\u01c1\5\62\32\2\u01b4\u01bd\7\t\2\2\u01b5"+ - "\u01ba\5\62\32\2\u01b6\u01b7\7\f\2\2\u01b7\u01b9\5\62\32\2\u01b8\u01b6"+ - "\3\2\2\2\u01b9\u01bc\3\2\2\2\u01ba\u01b8\3\2\2\2\u01ba\u01bb\3\2\2\2\u01bb"+ - "\u01be\3\2\2\2\u01bc\u01ba\3\2\2\2\u01bd\u01b5\3\2\2\2\u01bd\u01be\3\2"+ - "\2\2\u01be\u01bf\3\2\2\2\u01bf\u01c1\7\n\2\2\u01c0\u01b3\3\2\2\2\u01c0"+ - "\u01b4\3\2\2\2\u01c1\u01c2\3\2\2\2\u01c2\u01c3\7\65\2\2\u01c3\u01c4\5"+ - "\f\7\2\u01c4\61\3\2\2\2\u01c5\u01c7\5\26\f\2\u01c6\u01c5\3\2\2\2\u01c6"+ - "\u01c7\3\2\2\2\u01c7\u01c8\3\2\2\2\u01c8\u01c9\7P\2\2\u01c9\63\3\2\2\2"+ - "\u01ca\u01cf\5\66\34\2\u01cb\u01cf\58\35\2\u01cc\u01cf\5:\36\2\u01cd\u01cf"+ - "\5<\37\2\u01ce\u01ca\3\2\2\2\u01ce\u01cb\3\2\2\2\u01ce\u01cc\3\2\2\2\u01ce"+ - "\u01cd\3\2\2\2\u01cf\65\3\2\2\2\u01d0\u01d1\7O\2\2\u01d1\u01d2\7\64\2"+ - "\2\u01d2\u01d3\7P\2\2\u01d3\67\3\2\2\2\u01d4\u01d5\5\26\f\2\u01d5\u01d6"+ - "\7\64\2\2\u01d6\u01d7\7\26\2\2\u01d79\3\2\2\2\u01d8\u01d9\7P\2\2\u01d9"+ - "\u01da\7\64\2\2\u01da\u01db\7P\2\2\u01db;\3\2\2\2\u01dc\u01dd\7\32\2\2"+ - "\u01dd\u01de\7\64\2\2\u01de\u01df\7P\2\2\u01df=\3\2\2\2*AGZ]iq~\u0082"+ + "\5\31\u01be\n\31\3\31\5\31\u01c1\n\31\3\31\3\31\3\31\5\31\u01c6\n\31\3"+ + "\32\5\32\u01c9\n\32\3\32\3\32\3\33\3\33\3\33\3\33\5\33\u01d1\n\33\3\34"+ + "\3\34\3\34\3\34\3\35\3\35\3\35\3\35\3\36\3\36\3\36\3\36\3\37\3\37\3\37"+ + "\3\37\3\37\2\3\36 \2\4\6\b\n\f\16\20\22\24\26\30\32\34\36 \"$&(*,.\60"+ + "\62\64\668:<\2\r\3\2:E\3\2\35\37\3\2 !\3\2\66\67\3\2\"$\3\2%(\3\2),\3"+ + "\289\3\2FI\4\2\33\34 !\3\2QR\u0212\2A\3\2\2\2\4L\3\2\2\2\6Q\3\2\2\2\b"+ + "\u00af\3\2\2\2\n\u00b3\3\2\2\2\f\u00b5\3\2\2\2\16\u00be\3\2\2\2\20\u00c2"+ + "\3\2\2\2\22\u00c4\3\2\2\2\24\u00c6\3\2\2\2\26\u00cf\3\2\2\2\30\u00d7\3"+ + "\2\2\2\32\u00dc\3\2\2\2\34\u00e8\3\2\2\2\36\u00f3\3\2\2\2 \u0155\3\2\2"+ + "\2\"\u0179\3\2\2\2$\u018e\3\2\2\2&\u0194\3\2\2\2(\u019b\3\2\2\2*\u019d"+ + "\3\2\2\2,\u01a1\3\2\2\2.\u01b1\3\2\2\2\60\u01c0\3\2\2\2\62\u01c8\3\2\2"+ + "\2\64\u01d0\3\2\2\2\66\u01d2\3\2\2\28\u01d6\3\2\2\2:\u01da\3\2\2\2<\u01de"+ + "\3\2\2\2>@\5\4\3\2?>\3\2\2\2@C\3\2\2\2A?\3\2\2\2AB\3\2\2\2BG\3\2\2\2C"+ + "A\3\2\2\2DF\5\b\5\2ED\3\2\2\2FI\3\2\2\2GE\3\2\2\2GH\3\2\2\2HJ\3\2\2\2"+ + "IG\3\2\2\2JK\7\2\2\3K\3\3\2\2\2LM\5\26\f\2MN\7P\2\2NO\5\6\4\2OP\5\f\7"+ + "\2P\5\3\2\2\2Q]\7\t\2\2RS\5\26\f\2SZ\7P\2\2TU\7\f\2\2UV\5\26\f\2VW\7P"+ + "\2\2WY\3\2\2\2XT\3\2\2\2Y\\\3\2\2\2ZX\3\2\2\2Z[\3\2\2\2[^\3\2\2\2\\Z\3"+ + "\2\2\2]R\3\2\2\2]^\3\2\2\2^_\3\2\2\2_`\7\n\2\2`\7\3\2\2\2ab\7\16\2\2b"+ + "c\7\t\2\2cd\5\36\20\2de\7\n\2\2ei\5\n\6\2fg\7\17\2\2gj\5\n\6\2hj\6\5\2"+ + "\2if\3\2\2\2ih\3\2\2\2j\u00b0\3\2\2\2kl\7\20\2\2lm\7\t\2\2mn\5\36\20\2"+ + "nq\7\n\2\2or\5\n\6\2pr\5\16\b\2qo\3\2\2\2qp\3\2\2\2r\u00b0\3\2\2\2st\7"+ + "\21\2\2tu\5\f\7\2uv\7\20\2\2vw\7\t\2\2wx\5\36\20\2xy\7\n\2\2yz\5\34\17"+ + "\2z\u00b0\3\2\2\2{|\7\22\2\2|~\7\t\2\2}\177\5\20\t\2~}\3\2\2\2~\177\3"+ + "\2\2\2\177\u0080\3\2\2\2\u0080\u0082\7\r\2\2\u0081\u0083\5\36\20\2\u0082"+ + "\u0081\3\2\2\2\u0082\u0083\3\2\2\2\u0083\u0084\3\2\2\2\u0084\u0086\7\r"+ + "\2\2\u0085\u0087\5\22\n\2\u0086\u0085\3\2\2\2\u0086\u0087\3\2\2\2\u0087"+ + "\u0088\3\2\2\2\u0088\u008b\7\n\2\2\u0089\u008c\5\n\6\2\u008a\u008c\5\16"+ + "\b\2\u008b\u0089\3\2\2\2\u008b\u008a\3\2\2\2\u008c\u00b0\3\2\2\2\u008d"+ + "\u008e\7\22\2\2\u008e\u008f\7\t\2\2\u008f\u0090\5\26\f\2\u0090\u0091\7"+ + "P\2\2\u0091\u0092\7\63\2\2\u0092\u0093\5\36\20\2\u0093\u0094\7\n\2\2\u0094"+ + "\u0095\5\n\6\2\u0095\u00b0\3\2\2\2\u0096\u0097\5\24\13\2\u0097\u0098\5"+ + "\34\17\2\u0098\u00b0\3\2\2\2\u0099\u009a\7\23\2\2\u009a\u00b0\5\34\17"+ + "\2\u009b\u009c\7\24\2\2\u009c\u00b0\5\34\17\2\u009d\u009e\7\25\2\2\u009e"+ + "\u009f\5\36\20\2\u009f\u00a0\5\34\17\2\u00a0\u00b0\3\2\2\2\u00a1\u00a2"+ + "\7\27\2\2\u00a2\u00a4\5\f\7\2\u00a3\u00a5\5\32\16\2\u00a4\u00a3\3\2\2"+ + "\2\u00a5\u00a6\3\2\2\2\u00a6\u00a4\3\2\2\2\u00a6\u00a7\3\2\2\2\u00a7\u00b0"+ + "\3\2\2\2\u00a8\u00a9\7\31\2\2\u00a9\u00aa\5\36\20\2\u00aa\u00ab\5\34\17"+ + "\2\u00ab\u00b0\3\2\2\2\u00ac\u00ad\5\36\20\2\u00ad\u00ae\5\34\17\2\u00ae"+ + "\u00b0\3\2\2\2\u00afa\3\2\2\2\u00afk\3\2\2\2\u00afs\3\2\2\2\u00af{\3\2"+ + "\2\2\u00af\u008d\3\2\2\2\u00af\u0096\3\2\2\2\u00af\u0099\3\2\2\2\u00af"+ + "\u009b\3\2\2\2\u00af\u009d\3\2\2\2\u00af\u00a1\3\2\2\2\u00af\u00a8\3\2"+ + "\2\2\u00af\u00ac\3\2\2\2\u00b0\t\3\2\2\2\u00b1\u00b4\5\f\7\2\u00b2\u00b4"+ + "\5\b\5\2\u00b3\u00b1\3\2\2\2\u00b3\u00b2\3\2\2\2\u00b4\13\3\2\2\2\u00b5"+ + "\u00b9\7\5\2\2\u00b6\u00b8\5\b\5\2\u00b7\u00b6\3\2\2\2\u00b8\u00bb\3\2"+ + "\2\2\u00b9\u00b7\3\2\2\2\u00b9\u00ba\3\2\2\2\u00ba\u00bc\3\2\2\2\u00bb"+ + "\u00b9\3\2\2\2\u00bc\u00bd\7\6\2\2\u00bd\r\3\2\2\2\u00be\u00bf\7\r\2\2"+ + "\u00bf\17\3\2\2\2\u00c0\u00c3\5\24\13\2\u00c1\u00c3\5\36\20\2\u00c2\u00c0"+ + "\3\2\2\2\u00c2\u00c1\3\2\2\2\u00c3\21\3\2\2\2\u00c4\u00c5\5\36\20\2\u00c5"+ + "\23\3\2\2\2\u00c6\u00c7\5\26\f\2\u00c7\u00cc\5\30\r\2\u00c8\u00c9\7\f"+ + "\2\2\u00c9\u00cb\5\30\r\2\u00ca\u00c8\3\2\2\2\u00cb\u00ce\3\2\2\2\u00cc"+ + "\u00ca\3\2\2\2\u00cc\u00cd\3\2\2\2\u00cd\25\3\2\2\2\u00ce\u00cc\3\2\2"+ + "\2\u00cf\u00d4\7O\2\2\u00d0\u00d1\7\7\2\2\u00d1\u00d3\7\b\2\2\u00d2\u00d0"+ + "\3\2\2\2\u00d3\u00d6\3\2\2\2\u00d4\u00d2\3\2\2\2\u00d4\u00d5\3\2\2\2\u00d5"+ + "\27\3\2\2\2\u00d6\u00d4\3\2\2\2\u00d7\u00da\7P\2\2\u00d8\u00d9\7:\2\2"+ + "\u00d9\u00db\5\36\20\2\u00da\u00d8\3\2\2\2\u00da\u00db\3\2\2\2\u00db\31"+ + "\3\2\2\2\u00dc\u00dd\7\30\2\2\u00dd\u00de\7\t\2\2\u00de\u00df\7O\2\2\u00df"+ + "\u00e0\7P\2\2\u00e0\u00e1\7\n\2\2\u00e1\u00e2\5\f\7\2\u00e2\33\3\2\2\2"+ + "\u00e3\u00e9\7\r\2\2\u00e4\u00e9\7\2\2\3\u00e5\u00e6\b\17\1\2\u00e6\u00e7"+ + "\7\6\2\2\u00e7\u00e9\b\17\1\2\u00e8\u00e3\3\2\2\2\u00e8\u00e4\3\2\2\2"+ + "\u00e8\u00e5\3\2\2\2\u00e9\35\3\2\2\2\u00ea\u00eb\b\20\1\2\u00eb\u00ec"+ + "\5\"\22\2\u00ec\u00ed\t\2\2\2\u00ed\u00ee\5\36\20\3\u00ee\u00ef\b\20\1"+ + "\2\u00ef\u00f4\3\2\2\2\u00f0\u00f1\5 \21\2\u00f1\u00f2\b\20\1\2\u00f2"+ + "\u00f4\3\2\2\2\u00f3\u00ea\3\2\2\2\u00f3\u00f0\3\2\2\2\u00f4\u0135\3\2"+ + "\2\2\u00f5\u00f6\f\17\2\2\u00f6\u00f7\t\3\2\2\u00f7\u00f8\5\36\20\20\u00f8"+ + "\u00f9\b\20\1\2\u00f9\u0134\3\2\2\2\u00fa\u00fb\f\16\2\2\u00fb\u00fc\t"+ + "\4\2\2\u00fc\u00fd\5\36\20\17\u00fd\u00fe\b\20\1\2\u00fe\u0134\3\2\2\2"+ + "\u00ff\u0100\f\r\2\2\u0100\u0101\t\5\2\2\u0101\u0102\5\36\20\16\u0102"+ + "\u0103\b\20\1\2\u0103\u0134\3\2\2\2\u0104\u0105\f\f\2\2\u0105\u0106\t"+ + "\6\2\2\u0106\u0107\5\36\20\r\u0107\u0108\b\20\1\2\u0108\u0134\3\2\2\2"+ + "\u0109\u010a\f\13\2\2\u010a\u010b\t\7\2\2\u010b\u010c\5\36\20\f\u010c"+ + "\u010d\b\20\1\2\u010d\u0134\3\2\2\2\u010e\u010f\f\n\2\2\u010f\u0110\t"+ + "\b\2\2\u0110\u0111\5\36\20\13\u0111\u0112\b\20\1\2\u0112\u0134\3\2\2\2"+ + "\u0113\u0114\f\t\2\2\u0114\u0115\7-\2\2\u0115\u0116\5\36\20\n\u0116\u0117"+ + "\b\20\1\2\u0117\u0134\3\2\2\2\u0118\u0119\f\b\2\2\u0119\u011a\7.\2\2\u011a"+ + "\u011b\5\36\20\t\u011b\u011c\b\20\1\2\u011c\u0134\3\2\2\2\u011d\u011e"+ + "\f\7\2\2\u011e\u011f\7/\2\2\u011f\u0120\5\36\20\b\u0120\u0121\b\20\1\2"+ + "\u0121\u0134\3\2\2\2\u0122\u0123\f\6\2\2\u0123\u0124\7\60\2\2\u0124\u0125"+ + "\5\36\20\7\u0125\u0126\b\20\1\2\u0126\u0134\3\2\2\2\u0127\u0128\f\5\2"+ + "\2\u0128\u0129\7\61\2\2\u0129\u012a\5\36\20\6\u012a\u012b\b\20\1\2\u012b"+ + "\u0134\3\2\2\2\u012c\u012d\f\4\2\2\u012d\u012e\7\62\2\2\u012e\u012f\5"+ + "\36\20\2\u012f\u0130\7\63\2\2\u0130\u0131\5\36\20\4\u0131\u0132\b\20\1"+ + "\2\u0132\u0134\3\2\2\2\u0133\u00f5\3\2\2\2\u0133\u00fa\3\2\2\2\u0133\u00ff"+ + "\3\2\2\2\u0133\u0104\3\2\2\2\u0133\u0109\3\2\2\2\u0133\u010e\3\2\2\2\u0133"+ + "\u0113\3\2\2\2\u0133\u0118\3\2\2\2\u0133\u011d\3\2\2\2\u0133\u0122\3\2"+ + "\2\2\u0133\u0127\3\2\2\2\u0133\u012c\3\2\2\2\u0134\u0137\3\2\2\2\u0135"+ + "\u0133\3\2\2\2\u0135\u0136\3\2\2\2\u0136\37\3\2\2\2\u0137\u0135\3\2\2"+ + "\2\u0138\u0139\6\21\17\3\u0139\u013a\t\t\2\2\u013a\u0156\5\"\22\2\u013b"+ + "\u013c\6\21\20\3\u013c\u013d\5\"\22\2\u013d\u013e\t\t\2\2\u013e\u0156"+ + "\3\2\2\2\u013f\u0140\6\21\21\3\u0140\u0156\5\"\22\2\u0141\u0142\6\21\22"+ + "\3\u0142\u0143\t\n\2\2\u0143\u0156\b\21\1\2\u0144\u0145\6\21\23\3\u0145"+ + "\u0146\7L\2\2\u0146\u0156\b\21\1\2\u0147\u0148\6\21\24\3\u0148\u0149\7"+ + "M\2\2\u0149\u0156\b\21\1\2\u014a\u014b\6\21\25\3\u014b\u014c\7N\2\2\u014c"+ + "\u0156\b\21\1\2\u014d\u014e\6\21\26\3\u014e\u014f\t\13\2\2\u014f\u0156"+ + "\5 \21\2\u0150\u0151\7\t\2\2\u0151\u0152\5\26\f\2\u0152\u0153\7\n\2\2"+ + "\u0153\u0154\5 \21\2\u0154\u0156\3\2\2\2\u0155\u0138\3\2\2\2\u0155\u013b"+ + "\3\2\2\2\u0155\u013f\3\2\2\2\u0155\u0141\3\2\2\2\u0155\u0144\3\2\2\2\u0155"+ + "\u0147\3\2\2\2\u0155\u014a\3\2\2\2\u0155\u014d\3\2\2\2\u0155\u0150\3\2"+ + "\2\2\u0156!\3\2\2\2\u0157\u015b\5$\23\2\u0158\u015a\5&\24\2\u0159\u0158"+ + "\3\2\2\2\u015a\u015d\3\2\2\2\u015b\u0159\3\2\2\2\u015b\u015c\3\2\2\2\u015c"+ + "\u017a\3\2\2\2\u015d\u015b\3\2\2\2\u015e\u015f\5\26\f\2\u015f\u0163\5"+ + "(\25\2\u0160\u0162\5&\24\2\u0161\u0160\3\2\2\2\u0162\u0165\3\2\2\2\u0163"+ + "\u0161\3\2\2\2\u0163\u0164\3\2\2\2\u0164\u017a\3\2\2\2\u0165\u0163\3\2"+ + "\2\2\u0166\u0167\7\26\2\2\u0167\u016c\7O\2\2\u0168\u0169\7\7\2\2\u0169"+ + "\u016a\5\36\20\2\u016a\u016b\7\b\2\2\u016b\u016d\3\2\2\2\u016c\u0168\3"+ + "\2\2\2\u016d\u016e\3\2\2\2\u016e\u016c\3\2\2\2\u016e\u016f\3\2\2\2\u016f"+ + "\u0177\3\2\2\2\u0170\u0174\5(\25\2\u0171\u0173\5&\24\2\u0172\u0171\3\2"+ + "\2\2\u0173\u0176\3\2\2\2\u0174\u0172\3\2\2\2\u0174\u0175\3\2\2\2\u0175"+ + "\u0178\3\2\2\2\u0176\u0174\3\2\2\2\u0177\u0170\3\2\2\2\u0177\u0178\3\2"+ + "\2\2\u0178\u017a\3\2\2\2\u0179\u0157\3\2\2\2\u0179\u015e\3\2\2\2\u0179"+ + "\u0166\3\2\2\2\u017a#\3\2\2\2\u017b\u017c\6\23\27\3\u017c\u017d\7\t\2"+ + "\2\u017d\u017e\5\36\20\2\u017e\u017f\7\n\2\2\u017f\u0180\b\23\1\2\u0180"+ + "\u018f\3\2\2\2\u0181\u0182\6\23\30\3\u0182\u0183\7\t\2\2\u0183\u0184\5"+ + " \21\2\u0184\u0185\7\n\2\2\u0185\u018f\3\2\2\2\u0186\u018f\7J\2\2\u0187"+ + "\u018f\7K\2\2\u0188\u018f\7P\2\2\u0189\u018a\7P\2\2\u018a\u018f\5,\27"+ + "\2\u018b\u018c\7\26\2\2\u018c\u018d\7O\2\2\u018d\u018f\5,\27\2\u018e\u017b"+ + "\3\2\2\2\u018e\u0181\3\2\2\2\u018e\u0186\3\2\2\2\u018e\u0187\3\2\2\2\u018e"+ + "\u0188\3\2\2\2\u018e\u0189\3\2\2\2\u018e\u018b\3\2\2\2\u018f%\3\2\2\2"+ + "\u0190\u0191\6\24\31\3\u0191\u0195\5(\25\2\u0192\u0193\6\24\32\3\u0193"+ + "\u0195\5*\26\2\u0194\u0190\3\2\2\2\u0194\u0192\3\2\2\2\u0195\'\3\2\2\2"+ + "\u0196\u0197\7\13\2\2\u0197\u0198\7R\2\2\u0198\u019c\5,\27\2\u0199\u019a"+ + "\7\13\2\2\u019a\u019c\t\f\2\2\u019b\u0196\3\2\2\2\u019b\u0199\3\2\2\2"+ + "\u019c)\3\2\2\2\u019d\u019e\7\7\2\2\u019e\u019f\5\36\20\2\u019f\u01a0"+ + "\7\b\2\2\u01a0+\3\2\2\2\u01a1\u01aa\7\t\2\2\u01a2\u01a7\5.\30\2\u01a3"+ + "\u01a4\7\f\2\2\u01a4\u01a6\5.\30\2\u01a5\u01a3\3\2\2\2\u01a6\u01a9\3\2"+ + "\2\2\u01a7\u01a5\3\2\2\2\u01a7\u01a8\3\2\2\2\u01a8\u01ab\3\2\2\2\u01a9"+ + "\u01a7\3\2\2\2\u01aa\u01a2\3\2\2\2\u01aa\u01ab\3\2\2\2\u01ab\u01ac\3\2"+ + "\2\2\u01ac\u01ad\7\n\2\2\u01ad-\3\2\2\2\u01ae\u01b2\5\36\20\2\u01af\u01b2"+ + "\5\60\31\2\u01b0\u01b2\5\64\33\2\u01b1\u01ae\3\2\2\2\u01b1\u01af\3\2\2"+ + "\2\u01b1\u01b0\3\2\2\2\u01b2/\3\2\2\2\u01b3\u01c1\5\62\32\2\u01b4\u01bd"+ + "\7\t\2\2\u01b5\u01ba\5\62\32\2\u01b6\u01b7\7\f\2\2\u01b7\u01b9\5\62\32"+ + "\2\u01b8\u01b6\3\2\2\2\u01b9\u01bc\3\2\2\2\u01ba\u01b8\3\2\2\2\u01ba\u01bb"+ + "\3\2\2\2\u01bb\u01be\3\2\2\2\u01bc\u01ba\3\2\2\2\u01bd\u01b5\3\2\2\2\u01bd"+ + "\u01be\3\2\2\2\u01be\u01bf\3\2\2\2\u01bf\u01c1\7\n\2\2\u01c0\u01b3\3\2"+ + "\2\2\u01c0\u01b4\3\2\2\2\u01c1\u01c2\3\2\2\2\u01c2\u01c5\7\65\2\2\u01c3"+ + "\u01c6\5\f\7\2\u01c4\u01c6\5\36\20\2\u01c5\u01c3\3\2\2\2\u01c5\u01c4\3"+ + "\2\2\2\u01c6\61\3\2\2\2\u01c7\u01c9\5\26\f\2\u01c8\u01c7\3\2\2\2\u01c8"+ + "\u01c9\3\2\2\2\u01c9\u01ca\3\2\2\2\u01ca\u01cb\7P\2\2\u01cb\63\3\2\2\2"+ + "\u01cc\u01d1\5\66\34\2\u01cd\u01d1\58\35\2\u01ce\u01d1\5:\36\2\u01cf\u01d1"+ + "\5<\37\2\u01d0\u01cc\3\2\2\2\u01d0\u01cd\3\2\2\2\u01d0\u01ce\3\2\2\2\u01d0"+ + "\u01cf\3\2\2\2\u01d1\65\3\2\2\2\u01d2\u01d3\7O\2\2\u01d3\u01d4\7\64\2"+ + "\2\u01d4\u01d5\7P\2\2\u01d5\67\3\2\2\2\u01d6\u01d7\5\26\f\2\u01d7\u01d8"+ + "\7\64\2\2\u01d8\u01d9\7\26\2\2\u01d99\3\2\2\2\u01da\u01db\7P\2\2\u01db"+ + "\u01dc\7\64\2\2\u01dc\u01dd\7P\2\2\u01dd;\3\2\2\2\u01de\u01df\7\32\2\2"+ + "\u01df\u01e0\7\64\2\2\u01e0\u01e1\7P\2\2\u01e1=\3\2\2\2+AGZ]iq~\u0082"+ "\u0086\u008b\u00a6\u00af\u00b3\u00b9\u00c2\u00cc\u00d4\u00da\u00e8\u00f3"+ "\u0133\u0135\u0155\u015b\u0163\u016e\u0174\u0177\u0179\u018e\u0194\u019b"+ - "\u01a7\u01aa\u01b1\u01ba\u01bd\u01c0\u01c6\u01ce"; + "\u01a7\u01aa\u01b1\u01ba\u01bd\u01c0\u01c5\u01c8\u01d0"; public static final ATN _ATN = new ATNDeserializer().deserialize(_serializedATN.toCharArray()); static { diff --git a/modules/lang-painless/src/main/java/org/elasticsearch/painless/antlr/Walker.java b/modules/lang-painless/src/main/java/org/elasticsearch/painless/antlr/Walker.java index f57e3aef049..474e47599a8 100644 --- a/modules/lang-painless/src/main/java/org/elasticsearch/painless/antlr/Walker.java +++ b/modules/lang-painless/src/main/java/org/elasticsearch/painless/antlr/Walker.java @@ -834,9 +834,12 @@ public final class Walker extends PainlessParserBaseVisitor { @Override public Object visitRegex(RegexContext ctx) { - String pattern = ctx.REGEX().getText().substring(1, ctx.REGEX().getText().length() - 1); + String text = ctx.REGEX().getText(); + int lastSlash = text.lastIndexOf('/'); + String pattern = text.substring(1, lastSlash); + String flags = text.substring(lastSlash + 1); List links = new ArrayList<>(); - links.add(new LRegex(location(ctx), pattern)); + links.add(new LRegex(location(ctx), pattern, flags)); return links; } @@ -959,8 +962,14 @@ public final class Walker extends PainlessParserBaseVisitor { paramNames.add(lamtype.ID().getText()); } - for (StatementContext statement : ctx.block().statement()) { - statements.add((AStatement)visit(statement)); + if (ctx.expression() != null) { + // single expression + AExpression expression = (AExpression) visitExpression(ctx.expression()); + statements.add(new SReturn(location(ctx), expression)); + } else { + for (StatementContext statement : ctx.block().statement()) { + statements.add((AStatement)visit(statement)); + } } String name = nextLambda(); diff --git a/modules/lang-painless/src/main/java/org/elasticsearch/painless/node/LRegex.java b/modules/lang-painless/src/main/java/org/elasticsearch/painless/node/LRegex.java index 720e9d45969..324b6d72cf1 100644 --- a/modules/lang-painless/src/main/java/org/elasticsearch/painless/node/LRegex.java +++ b/modules/lang-painless/src/main/java/org/elasticsearch/painless/node/LRegex.java @@ -35,14 +35,20 @@ import org.elasticsearch.painless.WriterConstants; */ public final class LRegex extends ALink { private final String pattern; + private final int flags; private Constant constant; - public LRegex(Location location, String pattern) { + public LRegex(Location location, String pattern, String flagsString) { super(location, 1); this.pattern = pattern; + int flags = 0; + for (int c = 0; c < flagsString.length(); c++) { + flags |= flagForChar(flagsString.charAt(c)); + } + this.flags = flags; try { // Compile the pattern early after parsing so we can throw an error to the user with the location - Pattern.compile(pattern); + Pattern.compile(pattern, flags); } catch (PatternSyntaxException e) { throw createError(e); } @@ -82,6 +88,21 @@ public final class LRegex extends ALink { private void initializeConstant(MethodWriter writer) { writer.push(pattern); + writer.push(flags); writer.invokeStatic(Definition.PATTERN_TYPE.type, WriterConstants.PATTERN_COMPILE); } + + private int flagForChar(char c) { + switch (c) { + case 'c': return Pattern.CANON_EQ; + case 'i': return Pattern.CASE_INSENSITIVE; + case 'l': return Pattern.LITERAL; + case 'm': return Pattern.MULTILINE; + case 's': return Pattern.DOTALL; + case 'U': return Pattern.UNICODE_CHARACTER_CLASS; + case 'u': return Pattern.UNICODE_CASE; + case 'x': return Pattern.COMMENTS; + default: throw new IllegalArgumentException("Unknown flag [" + c + "]"); + } + } } diff --git a/modules/lang-painless/src/main/resources/org/elasticsearch/painless/java.util.regex.txt b/modules/lang-painless/src/main/resources/org/elasticsearch/painless/java.util.regex.txt index a8982871a33..6befc865731 100644 --- a/modules/lang-painless/src/main/resources/org/elasticsearch/painless/java.util.regex.txt +++ b/modules/lang-painless/src/main/resources/org/elasticsearch/painless/java.util.regex.txt @@ -25,7 +25,14 @@ class Pattern -> java.util.regex.Pattern extends Object { # Pattern compile(String) Intentionally not included. We don't want dynamic patterns because they allow regexes to be generated per time # the script is run which is super slow. LRegex generates code that calls this method but it skips these checks. + Predicate asPredicate() + int flags() Matcher matcher(CharSequence) + String pattern() + String quote(String) + String[] split(CharSequence) + String[] split(CharSequence,int) + Stream splitAsStream(CharSequence) } class Matcher -> java.util.regex.Matcher extends Object { diff --git a/modules/lang-painless/src/test/java/org/elasticsearch/painless/LambdaTests.java b/modules/lang-painless/src/test/java/org/elasticsearch/painless/LambdaTests.java index 1e7eb78be73..5001e28a954 100644 --- a/modules/lang-painless/src/test/java/org/elasticsearch/painless/LambdaTests.java +++ b/modules/lang-painless/src/test/java/org/elasticsearch/painless/LambdaTests.java @@ -22,59 +22,81 @@ package org.elasticsearch.painless; public class LambdaTests extends ScriptTestCase { public void testNoArgLambda() { - assertEquals(1, exec("Optional.empty().orElseGet(() -> { return 1; });")); + assertEquals(1, exec("Optional.empty().orElseGet(() -> 1);")); } public void testNoArgLambdaDef() { - assertEquals(1, exec("def x = Optional.empty(); x.orElseGet(() -> { return 1; });")); + assertEquals(1, exec("def x = Optional.empty(); x.orElseGet(() -> 1);")); } public void testLambdaWithArgs() { assertEquals("short", exec("List l = new ArrayList(); l.add('looooong'); l.add('short'); " - + "l.sort((a, b) -> { a.length() - b.length(); }); return l.get(0)")); + + "l.sort((a, b) -> a.length() - b.length()); return l.get(0)")); } public void testLambdaWithTypedArgs() { assertEquals("short", exec("List l = new ArrayList(); l.add('looooong'); l.add('short'); " - + "l.sort((String a, String b) -> { (a.length() - b.length()); }); return l.get(0)")); + + "l.sort((String a, String b) -> a.length() - b.length()); return l.get(0)")); } public void testPrimitiveLambdas() { assertEquals(4, exec("List l = new ArrayList(); l.add(1); l.add(1); " - + "return l.stream().mapToInt(x -> { x + 1; }).sum();")); + + "return l.stream().mapToInt(x -> x + 1).sum();")); } public void testPrimitiveLambdasWithTypedArgs() { assertEquals(4, exec("List l = new ArrayList(); l.add(1); l.add(1); " - + "return l.stream().mapToInt(int x -> { x + 1; }).sum();")); + + "return l.stream().mapToInt(int x -> x + 1).sum();")); } public void testPrimitiveLambdasDef() { assertEquals(4, exec("def l = new ArrayList(); l.add(1); l.add(1); " - + "return l.stream().mapToInt(x -> { x + 1; }).sum();")); + + "return l.stream().mapToInt(x -> x + 1).sum();")); } public void testPrimitiveLambdasWithTypedArgsDef() { assertEquals(4, exec("def l = new ArrayList(); l.add(1); l.add(1); " - + "return l.stream().mapToInt(int x -> { x + 1; }).sum();")); + + "return l.stream().mapToInt(int x -> x + 1).sum();")); } public void testPrimitiveLambdasConvertible() { assertEquals(2, exec("List l = new ArrayList(); l.add(1); l.add(1); " - + "return l.stream().mapToInt(byte x -> { return x; }).sum();")); + + "return l.stream().mapToInt(byte x -> x).sum();")); } public void testPrimitiveArgs() { - assertEquals(2, exec("int applyOne(IntFunction arg) { arg.apply(1) } applyOne(x -> { x + 1; })")); + assertEquals(2, exec("int applyOne(IntFunction arg) { arg.apply(1) } applyOne(x -> x + 1)")); } public void testPrimitiveArgsTyped() { - assertEquals(2, exec("int applyOne(IntFunction arg) { arg.apply(1) } applyOne(int x -> { x + 1; })")); + assertEquals(2, exec("int applyOne(IntFunction arg) { arg.apply(1) } applyOne(int x -> x + 1)")); } public void testPrimitiveArgsTypedOddly() { - assertEquals(2L, exec("long applyOne(IntFunction arg) { arg.apply(1) } applyOne(long x -> { x + 1; })")); + assertEquals(2L, exec("long applyOne(IntFunction arg) { arg.apply(1) } applyOne(long x -> x + 1)")); + } + + public void testMultipleStatements() { + assertEquals(2, exec("int applyOne(IntFunction arg) { arg.apply(1) } applyOne(x -> { x = x + 1; return x;})")); + } + + public void testTwoLambdas() { + assertEquals("testingcdefg", exec( + "org.elasticsearch.painless.FeatureTest test = new org.elasticsearch.painless.FeatureTest(2,3);" + + "return test.twoFunctionsOfX(x -> 'testing'.concat(x), y -> 'abcdefg'.substring(y))")); + } + + public void testNestedLambdas() { + assertEquals(1, exec("Optional.empty().orElseGet(() -> Optional.empty().orElseGet(() -> 1));")); + } + + public void testLambdaInLoop() { + assertEquals(100, exec("int sum = 0; " + + "for (int i = 0; i < 100; i++) {" + + " sum += Optional.empty().orElseGet(() -> 1);" + + "}" + + "return sum;")); } } diff --git a/modules/lang-painless/src/test/java/org/elasticsearch/painless/RegexTests.java b/modules/lang-painless/src/test/java/org/elasticsearch/painless/RegexTests.java index ee281e4656b..a36eedd7058 100644 --- a/modules/lang-painless/src/test/java/org/elasticsearch/painless/RegexTests.java +++ b/modules/lang-painless/src/test/java/org/elasticsearch/painless/RegexTests.java @@ -19,8 +19,12 @@ package org.elasticsearch.painless; +import java.util.Arrays; +import java.util.HashSet; +import java.util.regex.Pattern; import java.util.regex.PatternSyntaxException; +import static java.util.Collections.emptyMap; import static java.util.Collections.singletonMap; import static org.hamcrest.Matchers.containsString; @@ -125,6 +129,52 @@ public class RegexTests extends ScriptTestCase { assertEquals("o", exec("Matcher m = /(?f)(?o)o/.matcher('foo'); m.find(); return m.namedGroup('second')")); } + // Make sure some methods on Pattern are whitelisted + public void testSplit() { + assertArrayEquals(new String[] {"cat", "dog"}, (String[]) exec("/,/.split('cat,dog')")); + } + + public void testSplitAsStream() { + assertEquals(new HashSet<>(Arrays.asList("cat", "dog")), exec("/,/.splitAsStream('cat,dog').collect(Collectors.toSet())")); + } + + // Make sure the flags are set + public void testMultilineFlag() { + assertEquals(Pattern.MULTILINE, exec("/./m.flags()")); + } + + public void testSinglelineFlag() { + assertEquals(Pattern.DOTALL, exec("/./s.flags()")); + } + + public void testInsensitiveFlag() { + assertEquals(Pattern.CASE_INSENSITIVE, exec("/./i.flags()")); + } + + public void testExtendedFlag() { + assertEquals(Pattern.COMMENTS, exec("/./x.flags()")); + } + + public void testUnicodeCaseFlag() { + assertEquals(Pattern.UNICODE_CASE, exec("/./u.flags()")); + } + + public void testUnicodeCharacterClassFlag() { + assertEquals(Pattern.UNICODE_CASE | Pattern.UNICODE_CHARACTER_CLASS, exec("/./U.flags()")); + } + + public void testLiteralFlag() { + assertEquals(Pattern.LITERAL, exec("/./l.flags()")); + } + + public void testCanonicalEquivalenceFlag() { + assertEquals(Pattern.CANON_EQ, exec("/./c.flags()")); + } + + public void testManyFlags() { + assertEquals(Pattern.CANON_EQ | Pattern.CASE_INSENSITIVE | Pattern.UNICODE_CASE | Pattern.COMMENTS, exec("/./ciux.flags()")); + } + public void testCantUsePatternCompile() { IllegalArgumentException e = expectScriptThrows(IllegalArgumentException.class, () -> { exec("Pattern.compile('aa')"); @@ -146,4 +196,11 @@ public class RegexTests extends ScriptTestCase { }); assertEquals("Cannot cast from [int] to [String].", e.getMessage()); } + + public void testBogusRegexFlag() { + IllegalArgumentException e = expectScriptThrows(IllegalArgumentException.class, () -> { + exec("/asdf/b", emptyMap(), emptyMap(), null); // Not picky so we get a non-assertion error + }); + assertEquals("invalid sequence of tokens near ['b'].", e.getMessage()); + } } diff --git a/modules/lang-painless/src/test/java/org/elasticsearch/painless/StringTests.java b/modules/lang-painless/src/test/java/org/elasticsearch/painless/StringTests.java index 80b5675a6e1..873e773b9a3 100644 --- a/modules/lang-painless/src/test/java/org/elasticsearch/painless/StringTests.java +++ b/modules/lang-painless/src/test/java/org/elasticsearch/painless/StringTests.java @@ -221,4 +221,8 @@ public class StringTests extends ScriptTestCase { exec("def x = null; def y = null; x += y"); }); } + + public void testAppendStringIntoMap() { + assertEquals("nullcat", exec("def a = new HashMap(); a.cat += 'cat'")); + } }