Skip to content
Merged
Show file tree
Hide file tree
Changes from 11 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -138,24 +138,24 @@ expected_event_ids = [98]
notes = "regexp doesn't support character classes"
query = '''
//
// ?".*?net1\s+localgroup.*?")
process where match(command_line, ?".*?net1[ ]+localgroup.*?")
// """.*?net1\s+localgroup.*?""")
process where match(command_line, """.*?net1[ ]+localgroup.*?""")
'''

[[queries]]
name = "matchLiteAdditional"
expected_event_ids = [98]
query = '''
process where matchLite(command_line, ?".*?net1.*?")
process where matchLite(command_line, """.*?net1.*?""")
'''

[[queries]]
name = "matchWithCharacterClasses2"
expected_event_ids = [98]
notes = "regexp doesn't support predefined character classes (like \\s)"
query = '''
// ?".*?net1\s+\w{4,15}\s+.*?"
process where match(command_line, ?".*?net1[ ]+[a-z]{4,15}[ ]+.*?")
// """.*?net1\s+\w{4,15}\s+.*?"""
process where match(command_line, """.*?net1[ ]+[a-z]{4,15}[ ]+.*?""")
'''


Expand Down
10 changes: 5 additions & 5 deletions x-pack/plugin/eql/qa/common/src/main/resources/test_queries.toml
Original file line number Diff line number Diff line change
Expand Up @@ -1399,35 +1399,35 @@ registry where bytes_written_string_list[1] == "en"
[[queries]]
name = "matchLite1"
query = '''
process where matchLite(command_line, ?".*?net1\s+localgroup\s+.*?")
process where matchLite(command_line, """.*?net1\s+localgroup\s+.*?""")
'''
expected_event_ids = [98]

[[queries]]
name = "matchLite2"
query = '''
process where matchLite(command_line, ?".*?net1\s+\w+\s+.*?")
process where matchLite(command_line, """.*?net1\s+\w+\s+.*?""")
'''
expected_event_ids = [98]

[[queries]]
name = "matchLite3"
query = '''
process where matchLite(command_line, ?".*?net1\s+\w{4,15}\s+.*?")
process where matchLite(command_line, """.*?net1\s+\w{4,15}\s+.*?""")
'''
expected_event_ids = [98]

[[queries]]
name = "match1"
expected_event_ids = [98]
query = '''
process where match(command_line, ?".*?net1\s+\w{4,15}\s+.*?")
process where match(command_line, """.*?net1\s+\w{4,15}\s+.*?""")
'''

[[queries]]
name = "matchLite4"
query = '''
process where matchLite(command_line, ?".*?net1\s+[localgrup]{4,15}\s+.*?")
process where matchLite(command_line, """.*?net1\s+[localgrup]{4,15}\s+.*?""")
'''
expected_event_ids = [98]

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -797,35 +797,35 @@ registry where bytes_written_string_list[1] == "en"
[[queries]]
name = "matchLite1"
query = '''
process where matchLite(command_line, ?".*?net1\s+localgroup\s+.*?")
process where matchLite(command_line, """.*?net1\s+localgroup\s+.*?""")
'''
expected_event_ids = [98]

[[queries]]
name = "matchLite2"
query = '''
process where matchLite(command_line, ?".*?net1\s+\w+\s+.*?")
process where matchLite(command_line, """.*?net1\s+\w+\s+.*?""")
'''
expected_event_ids = [98]

[[queries]]
name = "matchLite3"
query = '''
process where matchLite(command_line, ?".*?net1\s+\w{4,15}\s+.*?")
process where matchLite(command_line, """.*?net1\s+\w{4,15}\s+.*?""")
'''
expected_event_ids = [98]

[[queries]]
name = "match1"
expected_event_ids = [98]
query = '''
process where match(command_line, ?".*?net1\s+\w{4,15}\s+.*?")
process where match(command_line, """.*?net1\s+\w{4,15}\s+.*?""")
'''

[[queries]]
name = "matchLite4"
query = '''
process where matchLite(command_line, ?".*?net1\s+[localgrup]{4,15}\s+.*?")
process where matchLite(command_line, """.*?net1\s+[localgrup]{4,15}\s+.*?""")
'''
expected_event_ids = [98]

Expand Down
1 change: 1 addition & 0 deletions x-pack/plugin/eql/src/main/antlr/EqlBase.g4
Original file line number Diff line number Diff line change
Expand Up @@ -200,6 +200,7 @@ STRING
| '"' ('\\' [btnfr"'\\] | ~[\r\n"\\])* '"'
| '?"' ('\\"' |~["\r\n])* '"'
| '?\'' ('\\\'' |~['\r\n])* '\''
| '"""' ('\\"' |~[\r\n])*? '"""'
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think this could really come to bite us. Mostly because it means that a raw string is not a raw string. With this, there's no way to express a literal \" anywhere in the string.

This branch allows a literal \":
matriv/elasticsearch@replace-unescaped-triple-doublequotes...rw-access:raw-string-changes

Copy link
Contributor Author

@matriv matriv Oct 1, 2020

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This grammar has other issues:

"""""hello\"""world!\"""" == """"foo"\""bar""\""""

=>

org.elasticsearch.xpack.eql.parser.ParsingException: line 1:21: token recognition error at: '!\'

and with the proposed solution you can have a \" literal if you double escape it \\"

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We could replace \" with " only if part of an escaped triple double quote sequence, but I think that produces more confusion for a user.

Copy link
Contributor

@rw-access rw-access Oct 2, 2020

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

but it should give that syntax error because it's invalid syntax. the string was completed after seeing """.

that sounds like the correct behavior. If we introduce any escapes at all we defeat the purpose of this being a raw string, and require some potentially complex parsing logic and strange edge cases. although I don't think we should stop immediately when seeing """ because then a string can't end with """. we could process a few more quotes after without issue. then a string will be able to end with quotes, too.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

"""""hello\"""world!\"""" it's a valid syntax, it has a closing """.
The previous ?" couldn't accept any " and every " should be escaped.
With this approach we only need to escape a """ which is very rare to occur.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

There are a number of issues at hand:

  1. " is a common character. To avoid escaping it too often, the raw string relies on 3 triple quotes """. This however can become a problem at the end of the raw string where a trailing " can mess up quoting
  2. " are allowed inside and can be escaped to avoid closing a string """ through \. This again is it occurs at the end of the string.

To wit:

  1. """ dir "c:\dir"""" <-- 4 ending quotes
  2. """ dir c:\dir\""" <-- \ escapes the """

Due to file paths on windows 2, aka \" is likely a common occurrence.
I see several options to solve this:

A. Require raw strings to not end with " and advice folks to add a space for example:
""" dir "c:\dir" """
B. Use a different escape character from \, say |. It solves 2 but not 1.
C. Do not allow escaping inside raw strings. This solves 2 but not 1.
D. Use a different set for quoting characters. Say "?""and""?`. However this does not solve the problem, rather just minimizes the occurrences in which they appear. Which might be a win in itself.

Considering \ is traditionally used for escaping and in Window paths, I have a preference for C over B. That's because introducing a new character for escaping is surprising and might backfire again depending on the raw string .
B however mean that one cannot escape """ inside a raw string but then for that there's the regular string definition. Unfortunately this doesn't solve 1 either...

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

A. I thing introducing a mandatory whitespace can lead to other issues, and is it only one space? what happens with more spaces, we keep all but one?, or with tabs?
B. I also don't like a new escape char, doesn't address the main issue no1.
D. I definitely don't like D since it still contains the ? char which usually refers to regex or query param.

C. I'm ok with C so if a user needs to escape chars or needs a """, he/she has to resort to the normal "....." syntax and properly escape what's needed.

Copy link
Contributor

@rw-access rw-access Oct 2, 2020

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

option E:

Allow for two optional additional trailing quotes with no escape sequences. then you can solve the trailing quotes issue without escapes.

The string can't contain """ anywhere inside. If you ever need to write a string with that sequence, a raw string is insufficient, so users will need to switch to a traditional escaped " string.

"""[^\r\n]*?""""?"?

Screenshot_20201002-055915~2.png

and it doesn't suffer from these contextual issues with \"
Screenshot_20201002-055234~2.png

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

confirmed that """ isn't allowed anywhere in the string but "" is;

Screenshot_20201002-060749~2.png

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@rw-access I'm also happy with that, pushed the change and fixed all relevant tests.

;

INTEGER_VALUE
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -122,10 +122,15 @@ public static String unquoteString(Source source) {
return null;
}

// unescaped strings can be interpreted directly
// catch old method of ?" and ?' to define unescaped strings
if (text.startsWith("?")) {
checkForSingleQuotedString(source, text, 1);
return text.substring(2, text.length() - 1);
throw new ParsingException(source,
"Use triple double quotes [\"\"\"] to define unescaped string literals, not [?{}]", text.charAt(1));
}

// unescaped strings can be interpreted directly
if (text.startsWith("\"\"\"")) {
return text.substring(3, text.length() - 3).replace("\\\"", "\"");
}

checkForSingleQuotedString(source, text, 0);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -106,7 +106,7 @@ public EqlBaseLexer(CharStream input) {
public ATN getATN() { return _ATN; }

public static final String _serializedATN =
"\3\u0430\ud6d1\u8206\uad2d\u4417\uaef1\u8d80\uaadd\2.\u0189\b\1\4\2\t"+
"\3\u0430\ud6d1\u8206\uad2d\u4417\uaef1\u8d80\uaadd\2.\u0198\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\t\31"+
Expand All @@ -124,38 +124,39 @@ public EqlBaseLexer(CharStream input) {
"\13&\3&\3&\3\'\3\'\3\'\3\'\7\'\u00ef\n\'\f\'\16\'\u00f2\13\'\3\'\3\'\3"+
"\'\3\'\3\'\7\'\u00f9\n\'\f\'\16\'\u00fc\13\'\3\'\3\'\3\'\3\'\3\'\3\'\3"+
"\'\7\'\u0105\n\'\f\'\16\'\u0108\13\'\3\'\3\'\3\'\3\'\3\'\3\'\3\'\7\'\u0111"+
"\n\'\f\'\16\'\u0114\13\'\3\'\5\'\u0117\n\'\3(\6(\u011a\n(\r(\16(\u011b"+
"\3)\6)\u011f\n)\r)\16)\u0120\3)\3)\7)\u0125\n)\f)\16)\u0128\13)\3)\3)"+
"\6)\u012c\n)\r)\16)\u012d\3)\6)\u0131\n)\r)\16)\u0132\3)\3)\7)\u0137\n"+
")\f)\16)\u013a\13)\5)\u013c\n)\3)\3)\3)\3)\6)\u0142\n)\r)\16)\u0143\3"+
")\3)\5)\u0148\n)\3*\3*\5*\u014c\n*\3*\3*\3*\7*\u0151\n*\f*\16*\u0154\13"+
"*\3+\3+\5+\u0158\n+\3+\6+\u015b\n+\r+\16+\u015c\3,\3,\3-\3-\3.\3.\3.\3"+
".\7.\u0167\n.\f.\16.\u016a\13.\3.\5.\u016d\n.\3.\5.\u0170\n.\3.\3.\3/"+
"\3/\3/\3/\3/\7/\u0179\n/\f/\16/\u017c\13/\3/\3/\3/\3/\3/\3\60\6\60\u0184"+
"\n\60\r\60\16\60\u0185\3\60\3\60\3\u017a\2\61\3\3\5\4\7\5\t\6\13\7\r\b"+
"\17\t\21\n\23\13\25\f\27\r\31\16\33\17\35\20\37\21!\22#\23%\24\'\25)\26"+
"+\27-\30/\31\61\32\63\33\65\34\67\359\36;\37= ?!A\"C#E$G%I&K\'M(O)Q*S"+
"+U\2W\2Y\2[,]-_.\3\2\17\3\2bb\n\2$$))^^ddhhppttvv\6\2\f\f\17\17))^^\6"+
"\2\f\f\17\17$$^^\5\2\f\f\17\17$$\5\2\f\f\17\17))\4\2BBaa\4\2GGgg\4\2-"+
"-//\3\2\62;\4\2C\\c|\4\2\f\f\17\17\5\2\13\f\17\17\"\"\u01a9\2\3\3\2\2"+
"\2\2\5\3\2\2\2\2\7\3\2\2\2\2\t\3\2\2\2\2\13\3\2\2\2\2\r\3\2\2\2\2\17\3"+
"\2\2\2\2\21\3\2\2\2\2\23\3\2\2\2\2\25\3\2\2\2\2\27\3\2\2\2\2\31\3\2\2"+
"\2\2\33\3\2\2\2\2\35\3\2\2\2\2\37\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\61\3\2"+
"\2\2\2\63\3\2\2\2\2\65\3\2\2\2\2\67\3\2\2\2\29\3\2\2\2\2;\3\2\2\2\2=\3"+
"\2\2\2\2?\3\2\2\2\2A\3\2\2\2\2C\3\2\2\2\2E\3\2\2\2\2G\3\2\2\2\2I\3\2\2"+
"\2\2K\3\2\2\2\2M\3\2\2\2\2O\3\2\2\2\2Q\3\2\2\2\2S\3\2\2\2\2[\3\2\2\2\2"+
"]\3\2\2\2\2_\3\2\2\2\3a\3\2\2\2\5e\3\2\2\2\7i\3\2\2\2\tl\3\2\2\2\13r\3"+
"\2\2\2\rw\3\2\2\2\17z\3\2\2\2\21\177\3\2\2\2\23\u0087\3\2\2\2\25\u008b"+
"\3\2\2\2\27\u0090\3\2\2\2\31\u0093\3\2\2\2\33\u0096\3\2\2\2\35\u009f\3"+
"\2\2\2\37\u00a4\3\2\2\2!\u00aa\3\2\2\2#\u00b0\3\2\2\2%\u00b5\3\2\2\2\'"+
"\u00b7\3\2\2\2)\u00ba\3\2\2\2+\u00bd\3\2\2\2-\u00bf\3\2\2\2/\u00c2\3\2"+
"\2\2\61\u00c4\3\2\2\2\63\u00c7\3\2\2\2\65\u00c9\3\2\2\2\67\u00cb\3\2\2"+
"\29\u00cd\3\2\2\2;\u00cf\3\2\2\2=\u00d1\3\2\2\2?\u00d3\3\2\2\2A\u00d5"+
"\n\'\f\'\16\'\u0114\13\'\3\'\3\'\3\'\3\'\3\'\3\'\3\'\3\'\7\'\u011e\n\'"+
"\f\'\16\'\u0121\13\'\3\'\3\'\3\'\5\'\u0126\n\'\3(\6(\u0129\n(\r(\16(\u012a"+
"\3)\6)\u012e\n)\r)\16)\u012f\3)\3)\7)\u0134\n)\f)\16)\u0137\13)\3)\3)"+
"\6)\u013b\n)\r)\16)\u013c\3)\6)\u0140\n)\r)\16)\u0141\3)\3)\7)\u0146\n"+
")\f)\16)\u0149\13)\5)\u014b\n)\3)\3)\3)\3)\6)\u0151\n)\r)\16)\u0152\3"+
")\3)\5)\u0157\n)\3*\3*\5*\u015b\n*\3*\3*\3*\7*\u0160\n*\f*\16*\u0163\13"+
"*\3+\3+\5+\u0167\n+\3+\6+\u016a\n+\r+\16+\u016b\3,\3,\3-\3-\3.\3.\3.\3"+
".\7.\u0176\n.\f.\16.\u0179\13.\3.\5.\u017c\n.\3.\5.\u017f\n.\3.\3.\3/"+
"\3/\3/\3/\3/\7/\u0188\n/\f/\16/\u018b\13/\3/\3/\3/\3/\3/\3\60\6\60\u0193"+
"\n\60\r\60\16\60\u0194\3\60\3\60\4\u011f\u0189\2\61\3\3\5\4\7\5\t\6\13"+
"\7\r\b\17\t\21\n\23\13\25\f\27\r\31\16\33\17\35\20\37\21!\22#\23%\24\'"+
"\25)\26+\27-\30/\31\61\32\63\33\65\34\67\359\36;\37= ?!A\"C#E$G%I&K\'"+
"M(O)Q*S+U\2W\2Y\2[,]-_.\3\2\17\3\2bb\n\2$$))^^ddhhppttvv\6\2\f\f\17\17"+
"))^^\6\2\f\f\17\17$$^^\5\2\f\f\17\17$$\5\2\f\f\17\17))\4\2\f\f\17\17\4"+
"\2BBaa\4\2GGgg\4\2--//\3\2\62;\4\2C\\c|\5\2\13\f\17\17\"\"\u01bb\2\3\3"+
"\2\2\2\2\5\3\2\2\2\2\7\3\2\2\2\2\t\3\2\2\2\2\13\3\2\2\2\2\r\3\2\2\2\2"+
"\17\3\2\2\2\2\21\3\2\2\2\2\23\3\2\2\2\2\25\3\2\2\2\2\27\3\2\2\2\2\31\3"+
"\2\2\2\2\33\3\2\2\2\2\35\3\2\2\2\2\37\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\61"+
"\3\2\2\2\2\63\3\2\2\2\2\65\3\2\2\2\2\67\3\2\2\2\29\3\2\2\2\2;\3\2\2\2"+
"\2=\3\2\2\2\2?\3\2\2\2\2A\3\2\2\2\2C\3\2\2\2\2E\3\2\2\2\2G\3\2\2\2\2I"+
"\3\2\2\2\2K\3\2\2\2\2M\3\2\2\2\2O\3\2\2\2\2Q\3\2\2\2\2S\3\2\2\2\2[\3\2"+
"\2\2\2]\3\2\2\2\2_\3\2\2\2\3a\3\2\2\2\5e\3\2\2\2\7i\3\2\2\2\tl\3\2\2\2"+
"\13r\3\2\2\2\rw\3\2\2\2\17z\3\2\2\2\21\177\3\2\2\2\23\u0087\3\2\2\2\25"+
"\u008b\3\2\2\2\27\u0090\3\2\2\2\31\u0093\3\2\2\2\33\u0096\3\2\2\2\35\u009f"+
"\3\2\2\2\37\u00a4\3\2\2\2!\u00aa\3\2\2\2#\u00b0\3\2\2\2%\u00b5\3\2\2\2"+
"\'\u00b7\3\2\2\2)\u00ba\3\2\2\2+\u00bd\3\2\2\2-\u00bf\3\2\2\2/\u00c2\3"+
"\2\2\2\61\u00c4\3\2\2\2\63\u00c7\3\2\2\2\65\u00c9\3\2\2\2\67\u00cb\3\2"+
"\2\29\u00cd\3\2\2\2;\u00cf\3\2\2\2=\u00d1\3\2\2\2?\u00d3\3\2\2\2A\u00d5"+
"\3\2\2\2C\u00d7\3\2\2\2E\u00d9\3\2\2\2G\u00db\3\2\2\2I\u00dd\3\2\2\2K"+
"\u00df\3\2\2\2M\u0116\3\2\2\2O\u0119\3\2\2\2Q\u0147\3\2\2\2S\u014b\3\2"+
"\2\2U\u0155\3\2\2\2W\u015e\3\2\2\2Y\u0160\3\2\2\2[\u0162\3\2\2\2]\u0173"+
"\3\2\2\2_\u0183\3\2\2\2ab\7c\2\2bc\7p\2\2cd\7f\2\2d\4\3\2\2\2ef\7c\2\2"+
"\u00df\3\2\2\2M\u0125\3\2\2\2O\u0128\3\2\2\2Q\u0156\3\2\2\2S\u015a\3\2"+
"\2\2U\u0164\3\2\2\2W\u016d\3\2\2\2Y\u016f\3\2\2\2[\u0171\3\2\2\2]\u0182"+
"\3\2\2\2_\u0192\3\2\2\2ab\7c\2\2bc\7p\2\2cd\7f\2\2d\4\3\2\2\2ef\7c\2\2"+
"fg\7p\2\2gh\7{\2\2h\6\3\2\2\2ij\7d\2\2jk\7{\2\2k\b\3\2\2\2lm\7h\2\2mn"+
"\7c\2\2no\7n\2\2op\7u\2\2pq\7g\2\2q\n\3\2\2\2rs\7h\2\2st\7q\2\2tu\7t\2"+
"\2uv\7m\2\2v\f\3\2\2\2wx\7k\2\2xy\7p\2\2y\16\3\2\2\2z{\7l\2\2{|\7q\2\2"+
Expand Down Expand Up @@ -190,59 +191,65 @@ public EqlBaseLexer(CharStream input) {
"\2\2\u00e9L\3\2\2\2\u00ea\u00f0\7)\2\2\u00eb\u00ec\7^\2\2\u00ec\u00ef"+
"\t\3\2\2\u00ed\u00ef\n\4\2\2\u00ee\u00eb\3\2\2\2\u00ee\u00ed\3\2\2\2\u00ef"+
"\u00f2\3\2\2\2\u00f0\u00ee\3\2\2\2\u00f0\u00f1\3\2\2\2\u00f1\u00f3\3\2"+
"\2\2\u00f2\u00f0\3\2\2\2\u00f3\u0117\7)\2\2\u00f4\u00fa\7$\2\2\u00f5\u00f6"+
"\2\2\u00f2\u00f0\3\2\2\2\u00f3\u0126\7)\2\2\u00f4\u00fa\7$\2\2\u00f5\u00f6"+
"\7^\2\2\u00f6\u00f9\t\3\2\2\u00f7\u00f9\n\5\2\2\u00f8\u00f5\3\2\2\2\u00f8"+
"\u00f7\3\2\2\2\u00f9\u00fc\3\2\2\2\u00fa\u00f8\3\2\2\2\u00fa\u00fb\3\2"+
"\2\2\u00fb\u00fd\3\2\2\2\u00fc\u00fa\3\2\2\2\u00fd\u0117\7$\2\2\u00fe"+
"\2\2\u00fb\u00fd\3\2\2\2\u00fc\u00fa\3\2\2\2\u00fd\u0126\7$\2\2\u00fe"+
"\u00ff\7A\2\2\u00ff\u0100\7$\2\2\u0100\u0106\3\2\2\2\u0101\u0102\7^\2"+
"\2\u0102\u0105\7$\2\2\u0103\u0105\n\6\2\2\u0104\u0101\3\2\2\2\u0104\u0103"+
"\3\2\2\2\u0105\u0108\3\2\2\2\u0106\u0104\3\2\2\2\u0106\u0107\3\2\2\2\u0107"+
"\u0109\3\2\2\2\u0108\u0106\3\2\2\2\u0109\u0117\7$\2\2\u010a\u010b\7A\2"+
"\u0109\3\2\2\2\u0108\u0106\3\2\2\2\u0109\u0126\7$\2\2\u010a\u010b\7A\2"+
"\2\u010b\u010c\7)\2\2\u010c\u0112\3\2\2\2\u010d\u010e\7^\2\2\u010e\u0111"+
"\7)\2\2\u010f\u0111\n\7\2\2\u0110\u010d\3\2\2\2\u0110\u010f\3\2\2\2\u0111"+
"\u0114\3\2\2\2\u0112\u0110\3\2\2\2\u0112\u0113\3\2\2\2\u0113\u0115\3\2"+
"\2\2\u0114\u0112\3\2\2\2\u0115\u0117\7)\2\2\u0116\u00ea\3\2\2\2\u0116"+
"\u00f4\3\2\2\2\u0116\u00fe\3\2\2\2\u0116\u010a\3\2\2\2\u0117N\3\2\2\2"+
"\u0118\u011a\5W,\2\u0119\u0118\3\2\2\2\u011a\u011b\3\2\2\2\u011b\u0119"+
"\3\2\2\2\u011b\u011c\3\2\2\2\u011cP\3\2\2\2\u011d\u011f\5W,\2\u011e\u011d"+
"\3\2\2\2\u011f\u0120\3\2\2\2\u0120\u011e\3\2\2\2\u0120\u0121\3\2\2\2\u0121"+
"\u0122\3\2\2\2\u0122\u0126\5=\37\2\u0123\u0125\5W,\2\u0124\u0123\3\2\2"+
"\2\u0125\u0128\3\2\2\2\u0126\u0124\3\2\2\2\u0126\u0127\3\2\2\2\u0127\u0148"+
"\3\2\2\2\u0128\u0126\3\2\2\2\u0129\u012b\5=\37\2\u012a\u012c\5W,\2\u012b"+
"\u012a\3\2\2\2\u012c\u012d\3\2\2\2\u012d\u012b\3\2\2\2\u012d\u012e\3\2"+
"\2\2\u012e\u0148\3\2\2\2\u012f\u0131\5W,\2\u0130\u012f\3\2\2\2\u0131\u0132"+
"\3\2\2\2\u0132\u0130\3\2\2\2\u0132\u0133\3\2\2\2\u0133\u013b\3\2\2\2\u0134"+
"\u0138\5=\37\2\u0135\u0137\5W,\2\u0136\u0135\3\2\2\2\u0137\u013a\3\2\2"+
"\2\u0138\u0136\3\2\2\2\u0138\u0139\3\2\2\2\u0139\u013c\3\2\2\2\u013a\u0138"+
"\3\2\2\2\u013b\u0134\3\2\2\2\u013b\u013c\3\2\2\2\u013c\u013d\3\2\2\2\u013d"+
"\u013e\5U+\2\u013e\u0148\3\2\2\2\u013f\u0141\5=\37\2\u0140\u0142\5W,\2"+
"\u0141\u0140\3\2\2\2\u0142\u0143\3\2\2\2\u0143\u0141\3\2\2\2\u0143\u0144"+
"\3\2\2\2\u0144\u0145\3\2\2\2\u0145\u0146\5U+\2\u0146\u0148\3\2\2\2\u0147"+
"\u011e\3\2\2\2\u0147\u0129\3\2\2\2\u0147\u0130\3\2\2\2\u0147\u013f\3\2"+
"\2\2\u0148R\3\2\2\2\u0149\u014c\5Y-\2\u014a\u014c\t\b\2\2\u014b\u0149"+
"\3\2\2\2\u014b\u014a\3\2\2\2\u014c\u0152\3\2\2\2\u014d\u0151\5Y-\2\u014e"+
"\u0151\5W,\2\u014f\u0151\7a\2\2\u0150\u014d\3\2\2\2\u0150\u014e\3\2\2"+
"\2\u0150\u014f\3\2\2\2\u0151\u0154\3\2\2\2\u0152\u0150\3\2\2\2\u0152\u0153"+
"\3\2\2\2\u0153T\3\2\2\2\u0154\u0152\3\2\2\2\u0155\u0157\t\t\2\2\u0156"+
"\u0158\t\n\2\2\u0157\u0156\3\2\2\2\u0157\u0158\3\2\2\2\u0158\u015a\3\2"+
"\2\2\u0159\u015b\5W,\2\u015a\u0159\3\2\2\2\u015b\u015c\3\2\2\2\u015c\u015a"+
"\3\2\2\2\u015c\u015d\3\2\2\2\u015dV\3\2\2\2\u015e\u015f\t\13\2\2\u015f"+
"X\3\2\2\2\u0160\u0161\t\f\2\2\u0161Z\3\2\2\2\u0162\u0163\7\61\2\2\u0163"+
"\u0164\7\61\2\2\u0164\u0168\3\2\2\2\u0165\u0167\n\r\2\2\u0166\u0165\3"+
"\2\2\2\u0167\u016a\3\2\2\2\u0168\u0166\3\2\2\2\u0168\u0169\3\2\2\2\u0169"+
"\u016c\3\2\2\2\u016a\u0168\3\2\2\2\u016b\u016d\7\17\2\2\u016c\u016b\3"+
"\2\2\2\u016c\u016d\3\2\2\2\u016d\u016f\3\2\2\2\u016e\u0170\7\f\2\2\u016f"+
"\u016e\3\2\2\2\u016f\u0170\3\2\2\2\u0170\u0171\3\2\2\2\u0171\u0172\b."+
"\2\2\u0172\\\3\2\2\2\u0173\u0174\7\61\2\2\u0174\u0175\7,\2\2\u0175\u017a"+
"\3\2\2\2\u0176\u0179\5]/\2\u0177\u0179\13\2\2\2\u0178\u0176\3\2\2\2\u0178"+
"\u0177\3\2\2\2\u0179\u017c\3\2\2\2\u017a\u017b\3\2\2\2\u017a\u0178\3\2"+
"\2\2\u017b\u017d\3\2\2\2\u017c\u017a\3\2\2\2\u017d\u017e\7,\2\2\u017e"+
"\u017f\7\61\2\2\u017f\u0180\3\2\2\2\u0180\u0181\b/\2\2\u0181^\3\2\2\2"+
"\u0182\u0184\t\16\2\2\u0183\u0182\3\2\2\2\u0184\u0185\3\2\2\2\u0185\u0183"+
"\3\2\2\2\u0185\u0186\3\2\2\2\u0186\u0187\3\2\2\2\u0187\u0188\b\60\2\2"+
"\u0188`\3\2\2\2\"\2\u00e3\u00e5\u00ee\u00f0\u00f8\u00fa\u0104\u0106\u0110"+
"\u0112\u0116\u011b\u0120\u0126\u012d\u0132\u0138\u013b\u0143\u0147\u014b"+
"\u0150\u0152\u0157\u015c\u0168\u016c\u016f\u0178\u017a\u0185\3\2\3\2";
"\2\2\u0114\u0112\3\2\2\2\u0115\u0126\7)\2\2\u0116\u0117\7$\2\2\u0117\u0118"+
"\7$\2\2\u0118\u0119\7$\2\2\u0119\u011f\3\2\2\2\u011a\u011b\7^\2\2\u011b"+
"\u011e\7$\2\2\u011c\u011e\n\b\2\2\u011d\u011a\3\2\2\2\u011d\u011c\3\2"+
"\2\2\u011e\u0121\3\2\2\2\u011f\u0120\3\2\2\2\u011f\u011d\3\2\2\2\u0120"+
"\u0122\3\2\2\2\u0121\u011f\3\2\2\2\u0122\u0123\7$\2\2\u0123\u0124\7$\2"+
"\2\u0124\u0126\7$\2\2\u0125\u00ea\3\2\2\2\u0125\u00f4\3\2\2\2\u0125\u00fe"+
"\3\2\2\2\u0125\u010a\3\2\2\2\u0125\u0116\3\2\2\2\u0126N\3\2\2\2\u0127"+
"\u0129\5W,\2\u0128\u0127\3\2\2\2\u0129\u012a\3\2\2\2\u012a\u0128\3\2\2"+
"\2\u012a\u012b\3\2\2\2\u012bP\3\2\2\2\u012c\u012e\5W,\2\u012d\u012c\3"+
"\2\2\2\u012e\u012f\3\2\2\2\u012f\u012d\3\2\2\2\u012f\u0130\3\2\2\2\u0130"+
"\u0131\3\2\2\2\u0131\u0135\5=\37\2\u0132\u0134\5W,\2\u0133\u0132\3\2\2"+
"\2\u0134\u0137\3\2\2\2\u0135\u0133\3\2\2\2\u0135\u0136\3\2\2\2\u0136\u0157"+
"\3\2\2\2\u0137\u0135\3\2\2\2\u0138\u013a\5=\37\2\u0139\u013b\5W,\2\u013a"+
"\u0139\3\2\2\2\u013b\u013c\3\2\2\2\u013c\u013a\3\2\2\2\u013c\u013d\3\2"+
"\2\2\u013d\u0157\3\2\2\2\u013e\u0140\5W,\2\u013f\u013e\3\2\2\2\u0140\u0141"+
"\3\2\2\2\u0141\u013f\3\2\2\2\u0141\u0142\3\2\2\2\u0142\u014a\3\2\2\2\u0143"+
"\u0147\5=\37\2\u0144\u0146\5W,\2\u0145\u0144\3\2\2\2\u0146\u0149\3\2\2"+
"\2\u0147\u0145\3\2\2\2\u0147\u0148\3\2\2\2\u0148\u014b\3\2\2\2\u0149\u0147"+
"\3\2\2\2\u014a\u0143\3\2\2\2\u014a\u014b\3\2\2\2\u014b\u014c\3\2\2\2\u014c"+
"\u014d\5U+\2\u014d\u0157\3\2\2\2\u014e\u0150\5=\37\2\u014f\u0151\5W,\2"+
"\u0150\u014f\3\2\2\2\u0151\u0152\3\2\2\2\u0152\u0150\3\2\2\2\u0152\u0153"+
"\3\2\2\2\u0153\u0154\3\2\2\2\u0154\u0155\5U+\2\u0155\u0157\3\2\2\2\u0156"+
"\u012d\3\2\2\2\u0156\u0138\3\2\2\2\u0156\u013f\3\2\2\2\u0156\u014e\3\2"+
"\2\2\u0157R\3\2\2\2\u0158\u015b\5Y-\2\u0159\u015b\t\t\2\2\u015a\u0158"+
"\3\2\2\2\u015a\u0159\3\2\2\2\u015b\u0161\3\2\2\2\u015c\u0160\5Y-\2\u015d"+
"\u0160\5W,\2\u015e\u0160\7a\2\2\u015f\u015c\3\2\2\2\u015f\u015d\3\2\2"+
"\2\u015f\u015e\3\2\2\2\u0160\u0163\3\2\2\2\u0161\u015f\3\2\2\2\u0161\u0162"+
"\3\2\2\2\u0162T\3\2\2\2\u0163\u0161\3\2\2\2\u0164\u0166\t\n\2\2\u0165"+
"\u0167\t\13\2\2\u0166\u0165\3\2\2\2\u0166\u0167\3\2\2\2\u0167\u0169\3"+
"\2\2\2\u0168\u016a\5W,\2\u0169\u0168\3\2\2\2\u016a\u016b\3\2\2\2\u016b"+
"\u0169\3\2\2\2\u016b\u016c\3\2\2\2\u016cV\3\2\2\2\u016d\u016e\t\f\2\2"+
"\u016eX\3\2\2\2\u016f\u0170\t\r\2\2\u0170Z\3\2\2\2\u0171\u0172\7\61\2"+
"\2\u0172\u0173\7\61\2\2\u0173\u0177\3\2\2\2\u0174\u0176\n\b\2\2\u0175"+
"\u0174\3\2\2\2\u0176\u0179\3\2\2\2\u0177\u0175\3\2\2\2\u0177\u0178\3\2"+
"\2\2\u0178\u017b\3\2\2\2\u0179\u0177\3\2\2\2\u017a\u017c\7\17\2\2\u017b"+
"\u017a\3\2\2\2\u017b\u017c\3\2\2\2\u017c\u017e\3\2\2\2\u017d\u017f\7\f"+
"\2\2\u017e\u017d\3\2\2\2\u017e\u017f\3\2\2\2\u017f\u0180\3\2\2\2\u0180"+
"\u0181\b.\2\2\u0181\\\3\2\2\2\u0182\u0183\7\61\2\2\u0183\u0184\7,\2\2"+
"\u0184\u0189\3\2\2\2\u0185\u0188\5]/\2\u0186\u0188\13\2\2\2\u0187\u0185"+
"\3\2\2\2\u0187\u0186\3\2\2\2\u0188\u018b\3\2\2\2\u0189\u018a\3\2\2\2\u0189"+
"\u0187\3\2\2\2\u018a\u018c\3\2\2\2\u018b\u0189\3\2\2\2\u018c\u018d\7,"+
"\2\2\u018d\u018e\7\61\2\2\u018e\u018f\3\2\2\2\u018f\u0190\b/\2\2\u0190"+
"^\3\2\2\2\u0191\u0193\t\16\2\2\u0192\u0191\3\2\2\2\u0193\u0194\3\2\2\2"+
"\u0194\u0192\3\2\2\2\u0194\u0195\3\2\2\2\u0195\u0196\3\2\2\2\u0196\u0197"+
"\b\60\2\2\u0197`\3\2\2\2$\2\u00e3\u00e5\u00ee\u00f0\u00f8\u00fa\u0104"+
"\u0106\u0110\u0112\u011d\u011f\u0125\u012a\u012f\u0135\u013c\u0141\u0147"+
"\u014a\u0152\u0156\u015a\u015f\u0161\u0166\u016b\u0177\u017b\u017e\u0187"+
"\u0189\u0194\3\2\3\2";
public static final ATN _ATN =
new ATNDeserializer().deserialize(_serializedATN.toCharArray());
static {
Expand Down
Loading