From b16311ef602d2ac18cd3bc12feb17437891708c2 Mon Sep 17 00:00:00 2001 From: Mikhail Golubev Date: Tue, 6 Sep 2016 20:57:13 +0300 Subject: [PATCH] PY-18972 Initial support of f-string literals Namely, Python lexer, compatibility inspection and unsupported features annotator are aware of them now. --- .../jetbrains/python/lexer/_PythonLexer.java | 556 +++++++++--------- .../python/lexer/PyStringLiteralLexer.java | 12 + .../com/jetbrains/python/lexer/Python.flex | 4 +- .../impl/PyStringLiteralExpressionImpl.java | 1 + .../validation/CompatibilityVisitor.java | 1 + .../testData/highlighting/fStringLiterals.py | 9 + .../stringLiteralExpression.py | 12 + python/testData/intentions/removeLeadingF.py | 1 + .../intentions/removeLeadingF_after.py | 1 + python/testData/psi/FStrings.py | 7 + python/testData/psi/FStrings.txt | 63 ++ .../python/PythonHighlightingTest.java | 4 + .../com/jetbrains/python/PythonLexerTest.java | 7 + .../jetbrains/python/PythonParsingTest.java | 5 + .../python/intentions/PyIntentionTest.java | 5 + 15 files changed, 411 insertions(+), 277 deletions(-) create mode 100644 python/testData/highlighting/fStringLiterals.py create mode 100644 python/testData/intentions/removeLeadingF.py create mode 100644 python/testData/intentions/removeLeadingF_after.py create mode 100644 python/testData/psi/FStrings.py create mode 100644 python/testData/psi/FStrings.txt diff --git a/python/gen/com/jetbrains/python/lexer/_PythonLexer.java b/python/gen/com/jetbrains/python/lexer/_PythonLexer.java index 51143eb991ce..c8b81989dc44 100644 --- a/python/gen/com/jetbrains/python/lexer/_PythonLexer.java +++ b/python/gen/com/jetbrains/python/lexer/_PythonLexer.java @@ -117,7 +117,7 @@ class _PythonLexer implements FlexLexer { static final char ZZ_CMAP_A[] = zzUnpackCMap( "\11\0\1\31\1\33\1\111\1\32\1\14\22\0\1\30\1\76\1\27\1\13\1\0\1\70\1\71\1\25"+ "\1\100\1\101\1\65\1\63\1\106\1\21\1\17\1\67\1\1\1\5\6\3\2\2\1\107\1\34\1\75"+ - "\1\64\1\74\1\0\1\66\1\4\1\11\1\23\1\4\1\20\1\4\3\15\1\22\1\15\1\12\2\15\1"+ + "\1\64\1\74\1\0\1\66\1\4\1\11\1\23\1\4\1\20\1\23\3\15\1\22\1\15\1\12\2\15\1"+ "\10\2\15\1\24\2\15\1\24\2\15\1\6\2\15\1\102\1\26\1\103\1\73\1\7\1\110\1\35"+ "\1\44\1\46\1\37\1\41\1\53\1\60\1\62\1\51\1\22\1\45\1\47\1\57\1\36\1\50\1\55"+ "\1\15\1\42\1\40\1\43\1\52\1\15\1\61\1\54\1\56\1\15\1\104\1\72\1\105\1\77\6"+ @@ -182,27 +182,27 @@ class _PythonLexer implements FlexLexer { "\1\16\1\17\1\20\1\21\1\22\1\23\1\24\1\25"+ "\1\26\1\27\1\30\1\1\1\31\1\32\1\33\1\34"+ "\1\35\1\36\1\37\1\40\1\41\1\42\2\43\1\44"+ - "\2\45\1\46\1\3\2\47\3\3\1\41\1\2\5\0"+ + "\2\45\1\46\1\3\2\47\4\3\1\41\1\2\5\0"+ "\1\2\1\50\1\0\1\51\1\0\1\3\1\50\1\52"+ "\1\53\3\7\1\54\3\7\15\3\1\55\1\56\1\57"+ "\1\60\10\3\1\61\1\62\1\63\1\64\1\65\1\66"+ "\1\67\1\70\1\71\1\72\1\73\1\74\1\75\1\76"+ "\1\77\1\100\1\101\1\0\3\45\1\102\3\45\1\3"+ - "\6\47\1\3\2\0\1\103\1\0\1\2\1\0\1\2"+ + "\6\47\2\3\2\0\1\103\1\0\1\2\1\0\1\2"+ "\1\0\1\2\1\0\1\50\1\0\1\3\1\0\1\7"+ "\1\104\1\105\1\0\1\104\1\106\1\3\1\107\1\110"+ "\1\111\5\3\1\112\6\3\1\113\5\3\1\114\1\115"+ "\1\116\1\117\1\0\1\45\1\120\1\121\1\0\1\120"+ - "\1\3\1\47\2\122\3\0\2\123\1\0\1\3\1\124"+ - "\1\125\10\3\1\126\1\3\1\127\3\3\3\0\2\121"+ - "\12\0\2\104\1\0\2\3\1\130\1\3\1\131\1\132"+ - "\4\3\1\133\1\3\1\134\3\0\2\120\4\0\2\122"+ + "\1\3\1\47\2\122\1\0\2\123\1\0\1\3\1\124"+ + "\1\125\10\3\1\126\1\3\1\127\3\3\1\0\2\121"+ + "\6\0\2\104\1\0\2\3\1\130\1\3\1\131\1\132"+ + "\4\3\1\133\1\3\1\134\1\0\2\120\2\0\2\122"+ "\1\0\3\104\1\135\1\136\1\137\1\3\1\140\1\141"+ "\1\3\1\142\3\120\3\122\1\123\1\0\1\143\2\0"+ "\1\3\1\144\4\0\2\104\1\145\2\120\2\122"; private static int [] zzUnpackAction() { - int [] result = new int[307]; + int [] result = new int[297]; int offset = 0; offset = zzUnpackAction(ZZ_ACTION_PACKED_0, offset, result); return result; @@ -236,39 +236,38 @@ class _PythonLexer implements FlexLexer { "\0\336\0\336\0\336\0\336\0\336\0\336\0\336\0\336"+ "\0\336\0\336\0\u0bda\0\u0c24\0\u0c6e\0\u0cb8\0\336\0\u0d02"+ "\0\u0d4c\0\u0d96\0\u0de0\0\u0e2a\0\u0e74\0\u0ebe\0\u0f08\0\u0f52"+ - "\0\u0f9c\0\u0fe6\0\u1030\0\u107a\0\336\0\u10c4\0\u110e\0\336"+ - "\0\u1158\0\u11a2\0\u11ec\0\336\0\336\0\u1236\0\u1280\0\u12ca"+ - "\0\336\0\u1314\0\u135e\0\u13a8\0\u13f2\0\u143c\0\u1486\0\u14d0"+ + "\0\u0f9c\0\u0fe6\0\u1030\0\u107a\0\u10c4\0\336\0\u110e\0\u1158"+ + "\0\336\0\u11a2\0\u11ec\0\u1236\0\336\0\336\0\u1280\0\u12ca"+ + "\0\u1314\0\336\0\u135e\0\u13a8\0\u13f2\0\u143c\0\u1486\0\u14d0"+ "\0\u151a\0\u1564\0\u15ae\0\u15f8\0\u1642\0\u168c\0\u16d6\0\u1720"+ - "\0\u176a\0\u01bc\0\u01bc\0\u01bc\0\u01bc\0\u17b4\0\u17fe\0\u1848"+ - "\0\u1892\0\u18dc\0\u1926\0\u1970\0\u19ba\0\336\0\336\0\336"+ - "\0\u1a04\0\336\0\336\0\u1a4e\0\336\0\336\0\336\0\336"+ - "\0\336\0\u1a98\0\336\0\336\0\u1ae2\0\336\0\u1b2c\0\u1b76"+ - "\0\u1bc0\0\u1c0a\0\336\0\u1c54\0\u1c9e\0\u1ce8\0\u1d32\0\u1d7c"+ - "\0\u1dc6\0\u1e10\0\u1e5a\0\u1ea4\0\u1eee\0\u1f38\0\u1f82\0\u0ebe"+ - "\0\336\0\u1fcc\0\u2016\0\u2060\0\u20aa\0\u20f4\0\u213e\0\u2188"+ - "\0\u21d2\0\u221c\0\u2266\0\u029a\0\u22b0\0\u22fa\0\336\0\u22b0"+ - "\0\u2344\0\u01bc\0\u238e\0\u01bc\0\u01bc\0\u01bc\0\u23d8\0\u2422"+ - "\0\u246c\0\u24b6\0\u2500\0\u01bc\0\u254a\0\u2594\0\u25de\0\u2628"+ - "\0\u2672\0\u26bc\0\u01bc\0\u2706\0\u2750\0\u279a\0\u27e4\0\u282e"+ - "\0\336\0\336\0\336\0\336\0\u2878\0\u28c2\0\u290c\0\336"+ - "\0\u28c2\0\u2956\0\u29a0\0\336\0\u29ea\0\u2a34\0\u2a7e\0\u2ac8"+ + "\0\u176a\0\u17b4\0\u01bc\0\u01bc\0\u01bc\0\u01bc\0\u17fe\0\u1848"+ + "\0\u1892\0\u18dc\0\u1926\0\u1970\0\u19ba\0\u1a04\0\336\0\336"+ + "\0\336\0\u1a4e\0\336\0\336\0\u1a98\0\336\0\336\0\336"+ + "\0\336\0\336\0\u1ae2\0\336\0\336\0\u1b2c\0\336\0\u1b76"+ + "\0\u1bc0\0\u1c0a\0\u1c54\0\336\0\u1c9e\0\u1ce8\0\u1d32\0\u1d7c"+ + "\0\u1dc6\0\u1e10\0\u1e5a\0\u1ea4\0\u1eee\0\u1f38\0\u1f82\0\u1fcc"+ + "\0\u2016\0\u0f08\0\336\0\u2060\0\u20aa\0\u20f4\0\u213e\0\u2188"+ + "\0\u21d2\0\u221c\0\u2266\0\u22b0\0\u22fa\0\u029a\0\u2344\0\u238e"+ + "\0\336\0\u2344\0\u23d8\0\u01bc\0\u2422\0\u01bc\0\u01bc\0\u01bc"+ + "\0\u246c\0\u24b6\0\u2500\0\u254a\0\u2594\0\u01bc\0\u25de\0\u2628"+ + "\0\u2672\0\u26bc\0\u2706\0\u2750\0\u01bc\0\u279a\0\u27e4\0\u282e"+ + "\0\u2878\0\u28c2\0\336\0\336\0\336\0\336\0\u290c\0\u2956"+ + "\0\u29a0\0\336\0\u2956\0\u29ea\0\u2a34\0\336\0\u2a7e\0\u2ac8"+ "\0\u2b12\0\u2b5c\0\u2ba6\0\u2bf0\0\u2c3a\0\u01bc\0\u01bc\0\u2c84"+ "\0\u2cce\0\u2d18\0\u2d62\0\u2dac\0\u2df6\0\u2e40\0\u2e8a\0\u01bc"+ "\0\u2ed4\0\u01bc\0\u2f1e\0\u2f68\0\u2fb2\0\u2ffc\0\u3046\0\u3090"+ "\0\u30da\0\u3124\0\u316e\0\u31b8\0\u3202\0\u324c\0\u3296\0\u32e0"+ - "\0\u332a\0\u3374\0\u33be\0\u3408\0\u3452\0\u349c\0\u34e6\0\u3530"+ - "\0\u357a\0\u01bc\0\u35c4\0\u01bc\0\u01bc\0\u360e\0\u3658\0\u36a2"+ - "\0\u36ec\0\u01bc\0\u3736\0\u01bc\0\u3780\0\u37ca\0\u3814\0\u385e"+ - "\0\u38a8\0\u38f2\0\u1dc6\0\u1eee\0\u393c\0\u3986\0\u39d0\0\u3a1a"+ - "\0\u3a64\0\u3aae\0\u3af8\0\u01bc\0\u01bc\0\u01bc\0\u3b42\0\u01bc"+ - "\0\u01bc\0\u3b8c\0\u01bc\0\u28c2\0\u3bd6\0\u3c20\0\336\0\u3c6a"+ - "\0\u3cb4\0\336\0\u3a64\0\336\0\u3cfe\0\u3d48\0\u3d92\0\u01bc"+ - "\0\u3ddc\0\u3e26\0\u3e70\0\u3eba\0\u3408\0\u34e6\0\u01bc\0\u3814"+ - "\0\u38f2\0\u393c\0\u3a1a"; + "\0\u332a\0\u3374\0\u33be\0\u01bc\0\u3408\0\u01bc\0\u01bc\0\u3452"+ + "\0\u349c\0\u34e6\0\u3530\0\u01bc\0\u357a\0\u01bc\0\u35c4\0\u360e"+ + "\0\u3658\0\u36a2\0\u36ec\0\u3736\0\u3780\0\u37ca\0\u3814\0\u385e"+ + "\0\u38a8\0\u01bc\0\u01bc\0\u01bc\0\u38f2\0\u01bc\0\u01bc\0\u393c"+ + "\0\u01bc\0\u2956\0\u3986\0\u39d0\0\336\0\u3a1a\0\u3a64\0\336"+ + "\0\u3814\0\336\0\u3aae\0\u3af8\0\u3b42\0\u01bc\0\u3b8c\0\u3bd6"+ + "\0\u3c20\0\u3c6a\0\u324c\0\u332a\0\u01bc\0\u35c4\0\u36a2\0\u36ec"+ + "\0\u37ca"; private static int [] zzUnpackRowMap() { - int [] result = new int[307]; + int [] result = new int[297]; int offset = 0; offset = zzUnpackRowMap(ZZ_ROWMAP_PACKED_0, offset, result); return result; @@ -302,257 +301,264 @@ class _PythonLexer implements FlexLexer { "\1\65\1\66\1\67\1\70\1\71\1\4\11\72\1\73"+ "\1\72\1\74\1\0\6\72\2\73\1\75\1\15\1\76"+ "\1\17\1\20\1\21\1\77\6\72\1\73\1\72\1\73"+ - "\1\72\1\73\3\72\1\73\36\72\1\0\1\4\1\5"+ + "\1\72\1\73\3\72\2\73\35\72\1\0\1\4\1\5"+ "\2\6\1\7\1\6\3\7\1\100\1\7\1\74\1\4"+ "\1\7\1\4\1\12\1\7\1\13\1\7\2\100\1\101"+ "\1\15\1\102\1\17\1\20\1\21\1\77\1\23\1\24"+ "\1\25\1\26\1\7\1\27\1\103\1\31\1\104\1\7"+ - "\1\105\1\34\1\35\1\36\1\100\1\37\1\7\1\40"+ + "\1\105\1\34\1\35\1\36\1\100\1\106\1\7\1\40"+ "\1\41\1\7\1\42\1\43\1\7\1\44\1\45\1\46"+ "\1\47\1\50\1\51\1\52\1\53\1\54\1\55\1\56"+ "\1\57\1\60\1\61\1\62\1\63\1\64\1\65\1\66"+ - "\1\67\1\106\1\71\1\4\113\0\1\107\1\110\1\107"+ - "\1\0\1\107\1\111\1\112\1\113\1\114\1\115\4\0"+ - "\1\116\1\117\1\0\1\120\16\0\1\117\2\0\1\114"+ - "\2\0\1\115\1\113\3\0\1\111\36\0\3\6\1\0"+ - "\1\6\1\0\1\121\2\0\1\115\4\0\1\116\1\117"+ - "\1\0\1\120\16\0\1\117\5\0\1\115\43\0\12\7"+ + "\1\67\1\107\1\71\1\4\113\0\1\110\1\111\1\110"+ + "\1\0\1\110\1\112\1\113\1\114\1\115\1\116\4\0"+ + "\1\117\1\120\1\0\1\121\16\0\1\120\2\0\1\115"+ + "\2\0\1\116\1\114\3\0\1\112\36\0\3\6\1\0"+ + "\1\6\1\0\1\122\2\0\1\116\4\0\1\117\1\120"+ + "\1\0\1\121\16\0\1\120\5\0\1\116\43\0\12\7"+ "\2\0\2\7\1\0\1\7\1\0\3\7\10\0\26\7"+ - "\30\0\10\7\1\122\1\7\2\0\2\7\1\0\1\7"+ - "\1\0\1\7\2\122\1\14\1\0\1\16\5\0\5\7"+ - "\1\122\1\7\1\122\1\7\1\122\3\7\1\122\10\7"+ - "\27\0\14\11\1\0\16\11\1\0\56\11\1\0\3\123"+ - "\1\0\1\123\170\0\1\124\7\0\1\125\15\0\14\126"+ - "\1\0\10\126\1\127\1\130\4\126\1\131\56\126\14\132"+ - "\1\0\11\132\1\133\1\134\3\132\1\131\56\132\1\0"+ + "\30\0\10\7\1\123\1\7\2\0\2\7\1\0\1\7"+ + "\1\0\1\7\2\123\1\14\1\0\1\16\5\0\5\7"+ + "\1\123\1\7\1\123\1\7\1\123\3\7\2\123\7\7"+ + "\27\0\14\11\1\0\16\11\1\0\56\11\1\0\3\124"+ + "\1\0\1\124\170\0\1\125\7\0\1\126\15\0\14\127"+ + "\1\0\10\127\1\130\1\131\4\127\1\132\56\127\14\133"+ + "\1\0\11\133\1\134\1\135\3\133\1\132\56\133\1\0"+ "\12\7\2\0\2\7\1\0\1\7\1\0\3\7\10\0"+ - "\1\7\1\135\1\7\1\136\22\7\30\0\12\7\2\0"+ - "\2\7\1\0\1\7\1\0\3\7\10\0\13\7\1\137"+ + "\1\7\1\136\1\7\1\137\22\7\30\0\12\7\2\0"+ + "\2\7\1\0\1\7\1\0\3\7\10\0\13\7\1\140"+ "\12\7\30\0\12\7\2\0\2\7\1\0\1\7\1\0"+ - "\3\7\10\0\4\7\1\140\21\7\30\0\12\7\2\0"+ - "\2\7\1\0\1\7\1\0\3\7\10\0\12\7\1\141"+ - "\4\7\1\142\6\7\30\0\10\7\1\122\1\7\2\0"+ - "\2\7\1\0\1\7\1\0\1\7\2\122\1\14\1\0"+ - "\1\16\5\0\1\143\3\7\1\144\1\122\1\7\1\122"+ - "\1\7\1\122\3\7\1\122\10\7\30\0\12\7\2\0"+ - "\2\7\1\0\1\7\1\0\3\7\10\0\5\7\1\145"+ - "\20\7\30\0\10\7\1\122\1\7\2\0\2\7\1\0"+ - "\1\7\1\0\1\7\2\122\1\14\1\0\1\16\5\0"+ - "\5\7\1\146\1\7\1\122\1\7\1\122\3\7\1\122"+ - "\10\7\30\0\10\7\1\122\1\7\2\0\2\7\1\0"+ - "\1\7\1\0\1\7\2\122\1\14\1\0\1\16\5\0"+ - "\5\7\1\122\1\7\1\122\1\7\1\122\1\147\1\150"+ - "\1\7\1\122\10\7\30\0\12\7\2\0\2\7\1\0"+ - "\1\7\1\0\3\7\10\0\1\151\25\7\30\0\12\7"+ + "\3\7\10\0\4\7\1\141\21\7\30\0\12\7\2\0"+ + "\2\7\1\0\1\7\1\0\3\7\10\0\12\7\1\142"+ + "\4\7\1\143\6\7\30\0\10\7\1\123\1\7\2\0"+ + "\2\7\1\0\1\7\1\0\1\7\2\123\1\14\1\0"+ + "\1\16\5\0\1\144\3\7\1\145\1\123\1\7\1\123"+ + "\1\7\1\123\3\7\2\123\7\7\30\0\12\7\2\0"+ + "\2\7\1\0\1\7\1\0\3\7\10\0\5\7\1\146"+ + "\20\7\30\0\10\7\1\123\1\7\2\0\2\7\1\0"+ + "\1\7\1\0\1\7\2\123\1\14\1\0\1\16\5\0"+ + "\5\7\1\147\1\7\1\123\1\7\1\123\3\7\2\123"+ + "\7\7\30\0\10\7\1\123\1\7\2\0\2\7\1\0"+ + "\1\7\1\0\1\7\2\123\1\14\1\0\1\16\5\0"+ + "\5\7\1\123\1\7\1\123\1\7\1\123\1\150\1\151"+ + "\1\7\2\123\7\7\30\0\12\7\2\0\2\7\1\0"+ + "\1\7\1\0\3\7\10\0\1\152\25\7\30\0\12\7"+ "\2\0\2\7\1\0\1\7\1\0\3\7\10\0\5\7"+ - "\1\152\20\7\30\0\12\7\2\0\2\7\1\0\1\7"+ - "\1\0\3\7\10\0\1\7\1\153\1\7\1\154\12\7"+ - "\1\155\3\7\1\156\3\7\30\0\12\7\2\0\2\7"+ - "\1\0\1\7\1\0\3\7\10\0\5\7\1\157\5\7"+ - "\1\160\1\161\11\7\30\0\12\7\2\0\2\7\1\0"+ - "\1\7\1\0\3\7\10\0\1\162\25\7\30\0\12\7"+ - "\2\0\2\7\1\0\1\7\1\0\3\7\10\0\14\7"+ - "\1\163\11\7\30\0\12\7\2\0\2\7\1\0\1\7"+ - "\1\0\3\7\10\0\12\7\1\164\13\7\30\0\12\7"+ - "\2\0\2\7\1\0\1\7\1\0\3\7\10\0\25\7"+ - "\1\165\113\0\1\166\111\0\1\167\111\0\1\170\1\171"+ - "\110\0\1\172\111\0\1\173\2\0\1\174\106\0\1\175"+ - "\111\0\1\176\111\0\1\177\111\0\1\200\111\0\1\201"+ - "\7\0\1\202\101\0\1\203\7\0\1\204\1\205\100\0"+ - "\1\206\36\0\1\207\11\0\2\207\1\75\1\0\1\76"+ - "\12\0\1\207\1\0\1\207\1\0\1\207\3\0\1\207"+ - "\37\0\14\74\1\0\16\74\1\0\56\74\14\210\1\0"+ - "\10\210\1\211\1\212\4\210\1\213\56\210\14\214\1\0"+ - "\11\214\1\215\1\216\3\214\1\213\56\214\1\0\10\7"+ - "\1\217\1\7\2\0\2\7\1\0\1\7\1\0\1\7"+ - "\2\217\1\101\1\0\1\102\5\0\5\7\1\217\1\7"+ - "\1\217\1\7\1\217\3\7\1\217\10\7\27\0\14\220"+ - "\1\0\10\220\1\221\1\222\4\220\1\0\56\220\14\223"+ - "\1\0\11\223\1\224\1\225\3\223\1\0\56\223\1\0"+ - "\10\7\1\217\1\7\2\0\2\7\1\0\1\7\1\0"+ - "\1\7\2\217\1\101\1\0\1\102\5\0\1\143\3\7"+ - "\1\144\1\217\1\7\1\217\1\7\1\217\3\7\1\217"+ - "\10\7\30\0\10\7\1\217\1\7\2\0\2\7\1\0"+ - "\1\7\1\0\1\7\2\217\1\101\1\0\1\102\5\0"+ - "\5\7\1\226\1\7\1\217\1\7\1\217\3\7\1\217"+ - "\10\7\30\0\10\7\1\217\1\7\2\0\2\7\1\0"+ - "\1\7\1\0\1\7\2\217\1\101\1\0\1\102\5\0"+ - "\5\7\1\217\1\7\1\217\1\7\1\217\1\147\1\150"+ - "\1\7\1\217\10\7\42\0\1\227\14\0\1\230\2\0"+ - "\1\231\57\0\1\107\1\110\1\107\1\0\1\107\1\0"+ - "\1\112\2\0\1\115\4\0\1\116\1\117\1\0\1\120"+ - "\16\0\1\117\5\0\1\115\43\0\3\110\1\0\1\110"+ - "\1\0\1\232\7\0\1\116\1\117\1\0\1\120\16\0"+ - "\1\117\51\0\5\233\1\0\1\234\1\0\1\233\6\0"+ - "\1\233\2\0\1\233\11\0\1\233\1\0\1\233\1\0"+ - "\1\233\2\0\1\233\1\0\1\233\4\0\1\233\37\0"+ - "\1\107\1\110\1\107\1\0\1\107\105\0\1\235\1\0"+ - "\1\235\1\0\1\235\1\0\1\236\103\0\1\237\3\0"+ - "\1\237\1\0\1\240\103\0\3\123\1\0\1\123\12\0"+ - "\1\117\1\0\1\120\16\0\1\117\51\0\3\241\1\0"+ - "\1\241\13\0\1\242\41\0\1\242\27\0\3\6\1\0"+ - "\1\6\105\0\10\7\1\243\1\7\2\0\2\7\1\0"+ - "\1\7\1\0\1\7\2\243\1\14\1\0\1\16\5\0"+ - "\5\7\1\243\1\7\1\243\1\7\1\243\3\7\1\243"+ - "\10\7\30\0\3\123\1\0\1\123\1\0\1\244\10\0"+ - "\1\117\1\0\1\120\16\0\1\117\50\0\14\126\1\0"+ - "\10\126\1\245\1\130\4\126\1\131\56\126\25\0\1\246"+ - "\1\247\1\0\2\250\1\0\2\131\55\0\112\126\14\132"+ - "\1\0\11\132\1\133\1\245\3\132\1\131\170\132\26\0"+ - "\1\247\1\251\2\250\1\0\2\131\56\0\12\7\2\0"+ - "\2\7\1\0\1\7\1\0\3\7\10\0\2\7\1\252"+ - "\23\7\30\0\12\7\2\0\2\7\1\0\1\7\1\0"+ - "\3\7\10\0\3\7\1\253\22\7\30\0\12\7\2\0"+ - "\2\7\1\0\1\7\1\0\3\7\10\0\6\7\1\254"+ - "\17\7\30\0\12\7\2\0\2\7\1\0\1\7\1\0"+ - "\3\7\10\0\12\7\1\255\3\7\1\256\7\7\30\0"+ - "\12\7\2\0\2\7\1\0\1\7\1\0\3\7\10\0"+ - "\3\7\1\257\10\7\1\260\11\7\30\0\12\7\2\0"+ - "\2\7\1\0\1\7\1\0\3\7\10\0\11\7\1\261"+ - "\14\7\30\0\12\7\2\0\2\7\1\0\1\7\1\0"+ - "\3\7\10\0\14\7\1\262\11\7\30\0\12\7\2\0"+ - "\2\7\1\0\1\7\1\0\3\7\10\0\6\7\1\263"+ - "\17\7\30\0\12\7\2\0\2\7\1\0\1\7\1\0"+ - "\3\7\10\0\21\7\1\264\4\7\30\0\10\7\1\243"+ - "\1\7\2\0\2\7\1\0\1\7\1\0\1\7\2\243"+ - "\1\14\1\0\1\16\5\0\4\7\1\265\1\243\1\7"+ - "\1\243\1\7\1\243\3\7\1\243\10\7\30\0\12\7"+ - "\2\0\2\7\1\0\1\7\1\0\3\7\10\0\1\266"+ + "\1\153\20\7\30\0\12\7\2\0\2\7\1\0\1\7"+ + "\1\0\3\7\10\0\1\7\1\154\1\7\1\155\12\7"+ + "\1\156\3\7\1\157\3\7\30\0\10\7\1\123\1\7"+ + "\2\0\2\7\1\0\1\7\1\0\1\7\2\123\1\14"+ + "\1\0\1\16\5\0\5\7\1\160\1\7\1\123\1\7"+ + "\1\123\1\7\1\161\1\162\2\123\7\7\30\0\12\7"+ + "\2\0\2\7\1\0\1\7\1\0\3\7\10\0\1\163"+ "\25\7\30\0\12\7\2\0\2\7\1\0\1\7\1\0"+ - "\3\7\10\0\1\7\1\267\24\7\30\0\12\7\2\0"+ - "\2\7\1\0\1\7\1\0\3\7\10\0\22\7\1\270"+ - "\3\7\30\0\12\7\2\0\2\7\1\0\1\7\1\0"+ - "\3\7\10\0\20\7\1\271\5\7\30\0\12\7\2\0"+ - "\2\7\1\0\1\7\1\0\3\7\10\0\13\7\1\272"+ - "\12\7\30\0\12\7\2\0\2\7\1\0\1\7\1\0"+ - "\3\7\10\0\5\7\1\273\20\7\30\0\12\7\2\0"+ - "\2\7\1\0\1\7\1\0\3\7\10\0\1\7\1\274"+ - "\24\7\30\0\12\7\2\0\2\7\1\0\1\7\1\0"+ - "\3\7\10\0\3\7\1\275\22\7\30\0\12\7\2\0"+ - "\2\7\1\0\1\7\1\0\3\7\10\0\4\7\1\276"+ - "\21\7\30\0\12\7\2\0\2\7\1\0\1\7\1\0"+ - "\3\7\10\0\13\7\1\277\12\7\30\0\12\7\2\0"+ - "\2\7\1\0\1\7\1\0\3\7\10\0\14\7\1\300"+ - "\11\7\113\0\1\301\111\0\1\302\111\0\1\303\111\0"+ - "\1\304\36\0\1\305\11\0\2\305\1\75\1\0\1\76"+ - "\12\0\1\305\1\0\1\305\1\0\1\305\3\0\1\305"+ - "\37\0\14\210\1\0\10\210\1\306\1\212\4\210\1\213"+ - "\56\210\25\0\1\307\1\310\1\0\2\311\1\0\2\213"+ - "\55\0\112\210\14\214\1\0\11\214\1\215\1\306\3\214"+ - "\1\213\170\214\26\0\1\310\1\312\2\311\1\0\2\213"+ - "\56\0\10\7\1\313\1\7\2\0\2\7\1\0\1\7"+ - "\1\0\1\7\2\313\1\101\1\0\1\102\5\0\5\7"+ - "\1\313\1\7\1\313\1\7\1\313\3\7\1\313\10\7"+ - "\27\0\14\220\1\0\10\220\1\314\1\222\4\220\1\0"+ - "\56\220\25\0\1\315\64\0\112\220\14\223\1\0\11\223"+ - "\1\224\1\314\3\223\1\0\170\223\27\0\1\316\63\0"+ - "\10\7\1\313\1\7\2\0\2\7\1\0\1\7\1\0"+ - "\1\7\2\313\1\101\1\0\1\102\5\0\4\7\1\265"+ - "\1\313\1\7\1\313\1\7\1\313\3\7\1\313\10\7"+ - "\27\0\14\227\1\0\16\227\1\231\56\227\1\0\3\110"+ - "\1\0\1\110\105\0\5\233\1\0\1\234\1\0\1\233"+ - "\1\115\5\0\1\233\2\0\1\233\11\0\1\233\1\0"+ - "\1\233\1\0\1\233\2\0\1\233\1\0\1\233\1\115"+ - "\3\0\1\233\37\0\5\233\3\0\1\233\6\0\1\233"+ - "\2\0\1\233\11\0\1\233\1\0\1\233\1\0\1\233"+ - "\2\0\1\233\1\0\1\233\4\0\1\233\37\0\1\235"+ - "\1\0\1\235\1\0\1\235\1\0\1\236\2\0\1\115"+ - "\34\0\1\115\43\0\1\235\1\0\1\235\1\0\1\235"+ - "\105\0\1\237\3\0\1\237\1\0\1\240\2\0\1\115"+ - "\34\0\1\115\43\0\1\237\3\0\1\237\105\0\3\241"+ - "\1\0\1\241\1\0\1\242\12\0\1\120\70\0\3\241"+ - "\1\0\1\241\105\0\12\7\2\0\2\7\1\0\1\7"+ - "\1\0\3\7\1\317\1\0\1\320\5\0\26\7\55\0"+ - "\1\247\1\0\2\250\1\0\2\131\55\0\25\246\1\321"+ - "\1\322\63\246\26\251\1\323\1\324\62\251\1\0\12\7"+ - "\2\0\2\7\1\0\1\7\1\0\3\7\10\0\4\7"+ - "\1\325\21\7\30\0\12\7\2\0\2\7\1\0\1\7"+ - "\1\0\3\7\10\0\4\7\1\326\21\7\30\0\12\7"+ - "\2\0\2\7\1\0\1\7\1\0\3\7\10\0\16\7"+ - "\1\327\7\7\30\0\12\7\2\0\2\7\1\0\1\7"+ - "\1\0\3\7\10\0\4\7\1\330\21\7\30\0\12\7"+ - "\2\0\2\7\1\0\1\7\1\0\3\7\10\0\3\7"+ - "\1\331\22\7\30\0\12\7\2\0\2\7\1\0\1\7"+ - "\1\0\3\7\10\0\15\7\1\332\10\7\30\0\12\7"+ - "\2\0\2\7\1\0\1\7\1\0\3\7\10\0\1\333"+ - "\25\7\30\0\12\7\2\0\2\7\1\0\1\7\1\0"+ - "\3\7\10\0\3\7\1\334\22\7\30\0\12\7\2\0"+ - "\2\7\1\0\1\7\1\0\3\7\10\0\6\7\1\335"+ - "\17\7\30\0\12\7\2\0\2\7\1\0\1\7\1\0"+ - "\3\7\10\0\7\7\1\336\16\7\30\0\12\7\2\0"+ - "\2\7\1\0\1\7\1\0\3\7\10\0\13\7\1\337"+ - "\12\7\30\0\12\7\2\0\2\7\1\0\1\7\1\0"+ - "\3\7\10\0\22\7\1\340\3\7\30\0\12\7\2\0"+ - "\2\7\1\0\1\7\1\0\3\7\10\0\1\341\25\7"+ - "\30\0\12\7\2\0\2\7\1\0\1\7\1\0\3\7"+ - "\10\0\3\7\1\342\22\7\30\0\12\7\2\0\2\7"+ - "\1\0\1\7\1\0\3\7\10\0\12\7\1\343\13\7"+ - "\30\0\12\7\2\0\2\7\1\0\1\7\1\0\3\7"+ - "\10\0\7\7\1\344\16\7\30\0\12\7\2\0\2\7"+ - "\1\0\1\7\1\0\3\7\10\0\12\7\1\345\13\7"+ - "\54\0\1\346\1\0\1\347\110\0\1\310\1\0\2\311"+ - "\1\0\2\213\55\0\25\307\1\350\1\351\63\307\26\312"+ - "\1\352\1\353\62\312\1\0\12\7\2\0\2\7\1\0"+ - "\1\7\1\0\3\7\1\354\1\0\1\355\5\0\26\7"+ - "\27\0\25\315\1\356\1\357\63\315\26\316\1\360\1\361"+ - "\62\316\25\0\1\362\113\0\1\363\62\0\25\246\1\364"+ - "\1\365\175\246\140\251\1\366\1\367\62\251\1\0\12\7"+ - "\2\0\2\7\1\0\1\7\1\0\3\7\10\0\5\7"+ - "\1\370\20\7\30\0\12\7\2\0\2\7\1\0\1\7"+ - "\1\0\3\7\10\0\20\7\1\371\5\7\30\0\12\7"+ - "\2\0\2\7\1\0\1\7\1\0\3\7\10\0\4\7"+ - "\1\372\21\7\30\0\12\7\2\0\2\7\1\0\1\7"+ - "\1\0\3\7\10\0\5\7\1\373\20\7\30\0\12\7"+ - "\2\0\2\7\1\0\1\7\1\0\3\7\10\0\10\7"+ - "\1\374\15\7\30\0\12\7\2\0\2\7\1\0\1\7"+ - "\1\0\3\7\10\0\3\7\1\375\22\7\30\0\12\7"+ - "\2\0\2\7\1\0\1\7\1\0\3\7\10\0\14\7"+ - "\1\376\11\7\30\0\12\7\2\0\2\7\1\0\1\7"+ - "\1\0\3\7\10\0\2\7\1\377\23\7\30\0\12\7"+ - "\2\0\2\7\1\0\1\7\1\0\3\7\10\0\5\7"+ - "\1\u0100\20\7\30\0\12\7\2\0\2\7\1\0\1\7"+ - "\1\0\3\7\10\0\12\7\1\u0101\13\7\30\0\12\7"+ - "\2\0\2\7\1\0\1\7\1\0\3\7\10\0\2\7"+ - "\1\u0102\23\7\30\0\12\7\2\0\2\7\1\0\1\7"+ - "\1\0\3\7\10\0\1\u0103\25\7\30\0\12\7\2\0"+ - "\2\7\1\0\1\7\1\0\3\7\10\0\4\7\1\u0104"+ - "\21\7\54\0\1\u0105\113\0\1\u0106\62\0\25\307\1\u0107"+ - "\1\u0108\175\307\140\312\1\u0109\1\u010a\62\312\25\0\1\u010b"+ - "\113\0\1\u010c\62\0\25\315\1\u010d\1\u010e\175\315\140\316"+ - "\1\u010f\1\u0110\62\316\25\0\1\246\113\0\1\251\62\0"+ - "\25\246\1\u0111\1\365\110\246\1\u0112\1\365\63\246\26\251"+ - "\1\366\1\u0113\110\251\1\366\1\u0111\62\251\1\0\12\7"+ - "\2\0\2\7\1\0\1\7\1\0\3\7\10\0\6\7"+ - "\1\u0114\17\7\30\0\12\7\2\0\2\7\1\0\1\7"+ - "\1\0\3\7\10\0\6\7\1\u0115\17\7\30\0\12\7"+ - "\2\0\2\7\1\0\1\7\1\0\3\7\10\0\1\7"+ - "\1\u0116\24\7\30\0\12\7\2\0\2\7\1\0\1\7"+ - "\1\0\3\7\10\0\1\7\1\u0117\24\7\30\0\12\7"+ - "\2\0\2\7\1\0\1\7\1\0\3\7\10\0\1\u0118"+ - "\25\7\30\0\12\7\2\0\2\7\1\0\1\7\1\0"+ - "\3\7\10\0\6\7\1\u0119\17\7\30\0\12\7\2\0"+ - "\2\7\1\0\1\7\1\0\3\7\10\0\12\7\1\u011a"+ + "\3\7\10\0\14\7\1\164\11\7\30\0\12\7\2\0"+ + "\2\7\1\0\1\7\1\0\3\7\10\0\12\7\1\165"+ "\13\7\30\0\12\7\2\0\2\7\1\0\1\7\1\0"+ - "\3\7\10\0\12\7\1\u011b\13\7\54\0\1\307\113\0"+ - "\1\312\62\0\25\307\1\u011c\1\u0108\110\307\1\u011d\1\u0108"+ - "\63\307\26\312\1\u0109\1\u011e\110\312\1\u0109\1\u011c\62\312"+ - "\25\315\1\u011f\1\u010e\110\315\1\u0120\1\u010e\63\315\26\316"+ - "\1\u010f\1\u0121\110\316\1\u010f\1\u011f\62\316\26\0\1\u0122"+ - "\1\0\2\u0123\1\0\2\u0124\55\0\25\246\1\u0125\1\365"+ - "\63\246\26\251\1\366\1\u0126\62\251\1\0\12\7\2\0"+ - "\2\7\1\0\1\7\1\0\3\7\10\0\15\7\1\u0127"+ - "\10\7\30\0\12\7\2\0\2\7\1\0\1\7\1\0"+ - "\3\7\10\0\21\7\1\u0128\4\7\27\0\25\307\1\u0129"+ - "\1\u0108\63\307\26\312\1\u0109\1\u012a\62\312\25\315\1\u012b"+ - "\1\u010e\63\315\26\316\1\u010f\1\u012c\62\316\25\246\1\u012d"+ - "\1\365\63\246\26\251\1\366\1\u012e\62\251\1\0\12\7"+ + "\3\7\10\0\25\7\1\166\113\0\1\167\111\0\1\170"+ + "\111\0\1\171\1\172\110\0\1\173\111\0\1\174\2\0"+ + "\1\175\106\0\1\176\111\0\1\177\111\0\1\200\111\0"+ + "\1\201\111\0\1\202\7\0\1\203\101\0\1\204\7\0"+ + "\1\205\1\206\100\0\1\207\36\0\1\210\11\0\2\210"+ + "\1\75\1\0\1\76\12\0\1\210\1\0\1\210\1\0"+ + "\1\210\3\0\2\210\36\0\14\74\1\0\16\74\1\0"+ + "\56\74\14\211\1\0\10\211\1\212\1\213\4\211\1\214"+ + "\56\211\14\215\1\0\11\215\1\216\1\217\3\215\1\214"+ + "\56\215\1\0\10\7\1\220\1\7\2\0\2\7\1\0"+ + "\1\7\1\0\1\7\2\220\1\101\1\0\1\102\5\0"+ + "\5\7\1\220\1\7\1\220\1\7\1\220\3\7\2\220"+ + "\7\7\27\0\14\221\1\0\10\221\1\222\1\223\4\221"+ + "\1\0\56\221\14\224\1\0\11\224\1\225\1\226\3\224"+ + "\1\0\56\224\1\0\10\7\1\220\1\7\2\0\2\7"+ + "\1\0\1\7\1\0\1\7\2\220\1\101\1\0\1\102"+ + "\5\0\1\144\3\7\1\145\1\220\1\7\1\220\1\7"+ + "\1\220\3\7\2\220\7\7\30\0\10\7\1\220\1\7"+ + "\2\0\2\7\1\0\1\7\1\0\1\7\2\220\1\101"+ + "\1\0\1\102\5\0\5\7\1\227\1\7\1\220\1\7"+ + "\1\220\3\7\2\220\7\7\30\0\10\7\1\220\1\7"+ + "\2\0\2\7\1\0\1\7\1\0\1\7\2\220\1\101"+ + "\1\0\1\102\5\0\5\7\1\220\1\7\1\220\1\7"+ + "\1\220\1\150\1\151\1\7\2\220\7\7\30\0\10\7"+ + "\1\220\1\7\2\0\2\7\1\0\1\7\1\0\1\7"+ + "\2\220\1\101\1\0\1\102\5\0\5\7\1\230\1\7"+ + "\1\220\1\7\1\220\1\7\1\161\1\162\2\220\7\7"+ + "\42\0\1\231\14\0\1\232\2\0\1\233\57\0\1\110"+ + "\1\111\1\110\1\0\1\110\1\0\1\113\2\0\1\116"+ + "\4\0\1\117\1\120\1\0\1\121\16\0\1\120\5\0"+ + "\1\116\43\0\3\111\1\0\1\111\1\0\1\234\7\0"+ + "\1\117\1\120\1\0\1\121\16\0\1\120\51\0\5\235"+ + "\1\0\1\236\1\0\1\235\6\0\1\235\2\0\1\235"+ + "\11\0\1\235\1\0\1\235\1\0\1\235\2\0\1\235"+ + "\1\0\1\235\4\0\1\235\37\0\1\110\1\111\1\110"+ + "\1\0\1\110\105\0\1\237\1\0\1\237\1\0\1\237"+ + "\1\0\1\240\103\0\1\241\3\0\1\241\1\0\1\242"+ + "\103\0\3\124\1\0\1\124\12\0\1\120\1\0\1\121"+ + "\16\0\1\120\51\0\3\243\1\0\1\243\13\0\1\244"+ + "\41\0\1\244\27\0\3\6\1\0\1\6\105\0\10\7"+ + "\1\245\1\7\2\0\2\7\1\0\1\7\1\0\1\7"+ + "\2\245\1\14\1\0\1\16\5\0\5\7\1\245\1\7"+ + "\1\245\1\7\1\245\3\7\2\245\7\7\30\0\3\124"+ + "\1\0\1\124\1\0\1\246\10\0\1\120\1\0\1\121"+ + "\16\0\1\120\50\0\14\127\1\0\10\127\1\247\1\131"+ + "\4\127\1\132\56\127\25\0\1\250\1\251\1\0\2\252"+ + "\1\0\2\132\55\0\112\127\14\133\1\0\11\133\1\134"+ + "\1\247\3\133\1\132\170\133\26\0\1\251\1\253\2\252"+ + "\1\0\2\132\56\0\12\7\2\0\2\7\1\0\1\7"+ + "\1\0\3\7\10\0\2\7\1\254\23\7\30\0\12\7"+ + "\2\0\2\7\1\0\1\7\1\0\3\7\10\0\3\7"+ + "\1\255\22\7\30\0\12\7\2\0\2\7\1\0\1\7"+ + "\1\0\3\7\10\0\6\7\1\256\17\7\30\0\12\7"+ + "\2\0\2\7\1\0\1\7\1\0\3\7\10\0\12\7"+ + "\1\257\3\7\1\260\7\7\30\0\12\7\2\0\2\7"+ + "\1\0\1\7\1\0\3\7\10\0\3\7\1\261\10\7"+ + "\1\262\11\7\30\0\12\7\2\0\2\7\1\0\1\7"+ + "\1\0\3\7\10\0\11\7\1\263\14\7\30\0\12\7"+ + "\2\0\2\7\1\0\1\7\1\0\3\7\10\0\14\7"+ + "\1\264\11\7\30\0\12\7\2\0\2\7\1\0\1\7"+ + "\1\0\3\7\10\0\6\7\1\265\17\7\30\0\12\7"+ + "\2\0\2\7\1\0\1\7\1\0\3\7\10\0\21\7"+ + "\1\266\4\7\30\0\10\7\1\245\1\7\2\0\2\7"+ + "\1\0\1\7\1\0\1\7\2\245\1\14\1\0\1\16"+ + "\5\0\4\7\1\267\1\245\1\7\1\245\1\7\1\245"+ + "\3\7\2\245\7\7\30\0\12\7\2\0\2\7\1\0"+ + "\1\7\1\0\3\7\10\0\1\270\25\7\30\0\12\7"+ + "\2\0\2\7\1\0\1\7\1\0\3\7\10\0\1\7"+ + "\1\271\24\7\30\0\12\7\2\0\2\7\1\0\1\7"+ + "\1\0\3\7\10\0\22\7\1\272\3\7\30\0\12\7"+ + "\2\0\2\7\1\0\1\7\1\0\3\7\10\0\20\7"+ + "\1\273\5\7\30\0\10\7\1\245\1\7\2\0\2\7"+ + "\1\0\1\7\1\0\1\7\2\245\1\14\1\0\1\16"+ + "\5\0\5\7\1\245\1\7\1\245\1\7\1\245\1\7"+ + "\1\274\1\7\2\245\7\7\30\0\12\7\2\0\2\7"+ + "\1\0\1\7\1\0\3\7\10\0\5\7\1\275\20\7"+ + "\30\0\12\7\2\0\2\7\1\0\1\7\1\0\3\7"+ + "\10\0\1\7\1\276\24\7\30\0\12\7\2\0\2\7"+ + "\1\0\1\7\1\0\3\7\10\0\3\7\1\277\22\7"+ + "\30\0\12\7\2\0\2\7\1\0\1\7\1\0\3\7"+ + "\10\0\4\7\1\300\21\7\30\0\12\7\2\0\2\7"+ + "\1\0\1\7\1\0\3\7\10\0\13\7\1\301\12\7"+ + "\30\0\12\7\2\0\2\7\1\0\1\7\1\0\3\7"+ + "\10\0\14\7\1\302\11\7\113\0\1\303\111\0\1\304"+ + "\111\0\1\305\111\0\1\306\36\0\1\307\11\0\2\307"+ + "\1\75\1\0\1\76\12\0\1\307\1\0\1\307\1\0"+ + "\1\307\3\0\2\307\36\0\14\211\1\0\10\211\1\310"+ + "\1\213\4\211\1\214\56\211\25\0\1\311\1\312\1\0"+ + "\2\313\1\0\2\214\55\0\112\211\14\215\1\0\11\215"+ + "\1\216\1\310\3\215\1\214\170\215\26\0\1\312\1\314"+ + "\2\313\1\0\2\214\56\0\10\7\1\315\1\7\2\0"+ + "\2\7\1\0\1\7\1\0\1\7\2\315\1\101\1\0"+ + "\1\102\5\0\5\7\1\315\1\7\1\315\1\7\1\315"+ + "\3\7\2\315\7\7\27\0\14\221\1\0\10\221\1\316"+ + "\1\223\4\221\1\0\56\221\25\0\1\317\64\0\112\221"+ + "\14\224\1\0\11\224\1\225\1\316\3\224\1\0\170\224"+ + "\27\0\1\320\63\0\10\7\1\315\1\7\2\0\2\7"+ + "\1\0\1\7\1\0\1\7\2\315\1\101\1\0\1\102"+ + "\5\0\4\7\1\267\1\315\1\7\1\315\1\7\1\315"+ + "\3\7\2\315\7\7\30\0\10\7\1\315\1\7\2\0"+ + "\2\7\1\0\1\7\1\0\1\7\2\315\1\101\1\0"+ + "\1\102\5\0\5\7\1\315\1\7\1\315\1\7\1\315"+ + "\1\7\1\274\1\7\2\315\7\7\27\0\14\231\1\0"+ + "\16\231\1\233\56\231\1\0\3\111\1\0\1\111\105\0"+ + "\5\235\1\0\1\236\1\0\1\235\1\116\5\0\1\235"+ + "\2\0\1\235\11\0\1\235\1\0\1\235\1\0\1\235"+ + "\2\0\1\235\1\0\1\235\1\116\3\0\1\235\37\0"+ + "\5\235\3\0\1\235\6\0\1\235\2\0\1\235\11\0"+ + "\1\235\1\0\1\235\1\0\1\235\2\0\1\235\1\0"+ + "\1\235\4\0\1\235\37\0\1\237\1\0\1\237\1\0"+ + "\1\237\1\0\1\240\2\0\1\116\34\0\1\116\43\0"+ + "\1\237\1\0\1\237\1\0\1\237\105\0\1\241\3\0"+ + "\1\241\1\0\1\242\2\0\1\116\34\0\1\116\43\0"+ + "\1\241\3\0\1\241\105\0\3\243\1\0\1\243\1\0"+ + "\1\244\12\0\1\121\70\0\3\243\1\0\1\243\105\0"+ + "\12\7\2\0\2\7\1\0\1\7\1\0\3\7\1\14"+ + "\1\0\1\16\5\0\26\7\55\0\1\251\1\0\2\252"+ + "\1\0\2\132\55\0\25\250\1\321\1\322\63\250\26\253"+ + "\1\323\1\324\62\253\1\0\12\7\2\0\2\7\1\0"+ + "\1\7\1\0\3\7\10\0\4\7\1\325\21\7\30\0"+ + "\12\7\2\0\2\7\1\0\1\7\1\0\3\7\10\0"+ + "\4\7\1\326\21\7\30\0\12\7\2\0\2\7\1\0"+ + "\1\7\1\0\3\7\10\0\16\7\1\327\7\7\30\0"+ + "\12\7\2\0\2\7\1\0\1\7\1\0\3\7\10\0"+ + "\4\7\1\330\21\7\30\0\12\7\2\0\2\7\1\0"+ + "\1\7\1\0\3\7\10\0\3\7\1\331\22\7\30\0"+ + "\12\7\2\0\2\7\1\0\1\7\1\0\3\7\10\0"+ + "\15\7\1\332\10\7\30\0\12\7\2\0\2\7\1\0"+ + "\1\7\1\0\3\7\10\0\1\333\25\7\30\0\12\7"+ + "\2\0\2\7\1\0\1\7\1\0\3\7\10\0\3\7"+ + "\1\334\22\7\30\0\12\7\2\0\2\7\1\0\1\7"+ + "\1\0\3\7\10\0\6\7\1\335\17\7\30\0\12\7"+ + "\2\0\2\7\1\0\1\7\1\0\3\7\10\0\7\7"+ + "\1\336\16\7\30\0\12\7\2\0\2\7\1\0\1\7"+ + "\1\0\3\7\10\0\13\7\1\337\12\7\30\0\12\7"+ + "\2\0\2\7\1\0\1\7\1\0\3\7\10\0\22\7"+ + "\1\340\3\7\30\0\12\7\2\0\2\7\1\0\1\7"+ + "\1\0\3\7\10\0\1\341\25\7\30\0\12\7\2\0"+ + "\2\7\1\0\1\7\1\0\3\7\10\0\3\7\1\342"+ + "\22\7\30\0\12\7\2\0\2\7\1\0\1\7\1\0"+ + "\3\7\10\0\12\7\1\343\13\7\30\0\12\7\2\0"+ + "\2\7\1\0\1\7\1\0\3\7\10\0\7\7\1\344"+ + "\16\7\30\0\12\7\2\0\2\7\1\0\1\7\1\0"+ + "\3\7\10\0\12\7\1\345\13\7\54\0\1\75\1\0"+ + "\1\76\110\0\1\312\1\0\2\313\1\0\2\214\55\0"+ + "\25\311\1\346\1\347\63\311\26\314\1\350\1\351\62\314"+ + "\1\0\12\7\2\0\2\7\1\0\1\7\1\0\3\7"+ + "\1\101\1\0\1\102\5\0\26\7\27\0\25\317\1\352"+ + "\1\353\63\317\26\320\1\354\1\355\62\320\25\250\1\356"+ + "\1\357\175\250\140\253\1\360\1\361\62\253\1\0\12\7"+ + "\2\0\2\7\1\0\1\7\1\0\3\7\10\0\5\7"+ + "\1\362\20\7\30\0\12\7\2\0\2\7\1\0\1\7"+ + "\1\0\3\7\10\0\20\7\1\363\5\7\30\0\12\7"+ "\2\0\2\7\1\0\1\7\1\0\3\7\10\0\4\7"+ - "\1\u012f\21\7\27\0\25\307\1\u0130\1\u0108\63\307\26\312"+ - "\1\u0109\1\u0131\62\312\25\315\1\u0132\1\u010e\63\315\26\316"+ - "\1\u010f\1\u0133\62\316"; + "\1\364\21\7\30\0\12\7\2\0\2\7\1\0\1\7"+ + "\1\0\3\7\10\0\5\7\1\365\20\7\30\0\12\7"+ + "\2\0\2\7\1\0\1\7\1\0\3\7\10\0\10\7"+ + "\1\366\15\7\30\0\12\7\2\0\2\7\1\0\1\7"+ + "\1\0\3\7\10\0\3\7\1\367\22\7\30\0\12\7"+ + "\2\0\2\7\1\0\1\7\1\0\3\7\10\0\14\7"+ + "\1\370\11\7\30\0\12\7\2\0\2\7\1\0\1\7"+ + "\1\0\3\7\10\0\2\7\1\371\23\7\30\0\12\7"+ + "\2\0\2\7\1\0\1\7\1\0\3\7\10\0\5\7"+ + "\1\372\20\7\30\0\12\7\2\0\2\7\1\0\1\7"+ + "\1\0\3\7\10\0\12\7\1\373\13\7\30\0\12\7"+ + "\2\0\2\7\1\0\1\7\1\0\3\7\10\0\2\7"+ + "\1\374\23\7\30\0\12\7\2\0\2\7\1\0\1\7"+ + "\1\0\3\7\10\0\1\375\25\7\30\0\12\7\2\0"+ + "\2\7\1\0\1\7\1\0\3\7\10\0\4\7\1\376"+ + "\21\7\27\0\25\311\1\377\1\u0100\175\311\140\314\1\u0101"+ + "\1\u0102\62\314\25\317\1\u0103\1\u0104\175\317\140\320\1\u0105"+ + "\1\u0106\62\320\25\250\1\u0107\1\357\110\250\1\u0108\1\357"+ + "\63\250\26\253\1\360\1\u0109\110\253\1\360\1\u0107\62\253"+ + "\1\0\12\7\2\0\2\7\1\0\1\7\1\0\3\7"+ + "\10\0\6\7\1\u010a\17\7\30\0\12\7\2\0\2\7"+ + "\1\0\1\7\1\0\3\7\10\0\6\7\1\u010b\17\7"+ + "\30\0\12\7\2\0\2\7\1\0\1\7\1\0\3\7"+ + "\10\0\1\7\1\u010c\24\7\30\0\12\7\2\0\2\7"+ + "\1\0\1\7\1\0\3\7\10\0\1\7\1\u010d\24\7"+ + "\30\0\12\7\2\0\2\7\1\0\1\7\1\0\3\7"+ + "\10\0\1\u010e\25\7\30\0\12\7\2\0\2\7\1\0"+ + "\1\7\1\0\3\7\10\0\6\7\1\u010f\17\7\30\0"+ + "\12\7\2\0\2\7\1\0\1\7\1\0\3\7\10\0"+ + "\12\7\1\u0110\13\7\30\0\12\7\2\0\2\7\1\0"+ + "\1\7\1\0\3\7\10\0\12\7\1\u0111\13\7\27\0"+ + "\25\311\1\u0112\1\u0100\110\311\1\u0113\1\u0100\63\311\26\314"+ + "\1\u0101\1\u0114\110\314\1\u0101\1\u0112\62\314\25\317\1\u0115"+ + "\1\u0104\110\317\1\u0116\1\u0104\63\317\26\320\1\u0105\1\u0117"+ + "\110\320\1\u0105\1\u0115\62\320\26\0\1\u0118\1\0\2\u0119"+ + "\1\0\2\u011a\55\0\25\250\1\u011b\1\357\63\250\26\253"+ + "\1\360\1\u011c\62\253\1\0\12\7\2\0\2\7\1\0"+ + "\1\7\1\0\3\7\10\0\15\7\1\u011d\10\7\30\0"+ + "\12\7\2\0\2\7\1\0\1\7\1\0\3\7\10\0"+ + "\21\7\1\u011e\4\7\27\0\25\311\1\u011f\1\u0100\63\311"+ + "\26\314\1\u0101\1\u0120\62\314\25\317\1\u0121\1\u0104\63\317"+ + "\26\320\1\u0105\1\u0122\62\320\25\250\1\u0123\1\357\63\250"+ + "\26\253\1\360\1\u0124\62\253\1\0\12\7\2\0\2\7"+ + "\1\0\1\7\1\0\3\7\10\0\4\7\1\u0125\21\7"+ + "\27\0\25\311\1\u0126\1\u0100\63\311\26\314\1\u0101\1\u0127"+ + "\62\314\25\317\1\u0128\1\u0104\63\317\26\320\1\u0105\1\u0129"+ + "\62\320"; private static int [] zzUnpackTrans() { - int [] result = new int[16132]; + int [] result = new int[15540]; int offset = 0; offset = zzUnpackTrans(ZZ_TRANS_PACKED_0, offset, result); return result; @@ -591,19 +597,19 @@ class _PythonLexer implements FlexLexer { private static final String ZZ_ATTRIBUTE_PACKED_0 = "\3\0\1\11\10\1\1\11\1\1\5\11\34\1\13\11"+ - "\4\1\1\11\10\1\5\0\1\11\1\1\1\0\1\11"+ + "\4\1\1\11\11\1\5\0\1\11\1\1\1\0\1\11"+ "\1\0\2\1\2\11\3\1\1\11\34\1\3\11\1\1"+ "\2\11\1\1\5\11\1\1\2\11\1\1\1\11\1\0"+ - "\3\1\1\11\13\1\2\0\1\11\1\0\1\1\1\0"+ + "\3\1\1\11\14\1\2\0\1\11\1\0\1\1\1\0"+ "\1\1\1\0\1\1\1\0\1\1\1\0\1\1\1\0"+ "\2\1\1\11\1\0\30\1\4\11\1\0\2\1\1\11"+ - "\1\0\2\1\1\11\2\1\3\0\2\1\1\0\21\1"+ - "\3\0\2\1\12\0\2\1\1\0\15\1\3\0\2\1"+ - "\4\0\2\1\1\0\16\1\1\11\2\1\1\11\1\0"+ + "\1\0\2\1\1\11\2\1\1\0\2\1\1\0\21\1"+ + "\1\0\2\1\6\0\2\1\1\0\15\1\1\0\2\1"+ + "\2\0\2\1\1\0\16\1\1\11\2\1\1\11\1\0"+ "\1\11\2\0\2\1\4\0\7\1"; private static int [] zzUnpackAttribute() { - int [] result = new int[307]; + int [] result = new int[297]; int offset = 0; offset = zzUnpackAttribute(ZZ_ATTRIBUTE_PACKED_0, offset, result); return result; diff --git a/python/src/com/jetbrains/python/lexer/PyStringLiteralLexer.java b/python/src/com/jetbrains/python/lexer/PyStringLiteralLexer.java index 1606ac65d543..20ec3a9b5251 100644 --- a/python/src/com/jetbrains/python/lexer/PyStringLiteralLexer.java +++ b/python/src/com/jetbrains/python/lexer/PyStringLiteralLexer.java @@ -48,6 +48,7 @@ public class PyStringLiteralLexer extends LexerBase { private boolean myIsRaw; private boolean myIsTriple; + private boolean myIsFormatted; private final IElementType myOriginalLiteralToken; private boolean mySeenEscapedSpacesOnly; @@ -74,6 +75,9 @@ public class PyStringLiteralLexer extends LexerBase { int offset = skipRawPrefix(buffer, i); if (offset > i) myIsRaw = true; i = offset; + offset = skipFormattedPrefix(buffer, i); + if (offset > i) myIsFormatted = true; + i = offset; i = skipEncodingPrefix(buffer, i); offset = skipRawPrefix(buffer, i); if (offset > i) myIsRaw = true; @@ -90,6 +94,14 @@ public class PyStringLiteralLexer extends LexerBase { myEnd = locateToken(myStart); } + public static int skipFormattedPrefix(CharSequence text, int startOffset) { + char c = Character.toUpperCase(text.charAt(startOffset)); + if (c == 'F') { + startOffset++; + } + return startOffset; + } + public static int skipRawPrefix(CharSequence text, int startOffset) { char c = Character.toUpperCase(text.charAt(startOffset)); if (c == 'R') { diff --git a/python/src/com/jetbrains/python/lexer/Python.flex b/python/src/com/jetbrains/python/lexer/Python.flex index 6450207ab542..c7f49f080c65 100644 --- a/python/src/com/jetbrains/python/lexer/Python.flex +++ b/python/src/com/jetbrains/python/lexer/Python.flex @@ -46,8 +46,8 @@ IMAGNUMBER=(({FLOATNUMBER})|({INTPART}))[Jj] //RAW_STRING=[Rr]{QUOTED_STRING} //QUOTED_STRING=({TRIPLE_APOS_LITERAL})|({QUOTED_LITERAL})|({DOUBLE_QUOTED_LITERAL})|({TRIPLE_QUOTED_LITERAL}) -SINGLE_QUOTED_STRING=[UuBbCcRr]{0,2}({QUOTED_LITERAL} | {DOUBLE_QUOTED_LITERAL}) -TRIPLE_QUOTED_STRING=[UuBbCcRr]{0,2}[UuBbCcRr]?({TRIPLE_QUOTED_LITERAL}|{TRIPLE_APOS_LITERAL}) +SINGLE_QUOTED_STRING=[UuBbCcRrFf]{0,3}({QUOTED_LITERAL} | {DOUBLE_QUOTED_LITERAL}) +TRIPLE_QUOTED_STRING=[UuBbCcRrFf]{0,3}({TRIPLE_QUOTED_LITERAL}|{TRIPLE_APOS_LITERAL}) DOCSTRING_LITERAL=({SINGLE_QUOTED_STRING}|{TRIPLE_QUOTED_STRING}) diff --git a/python/src/com/jetbrains/python/psi/impl/PyStringLiteralExpressionImpl.java b/python/src/com/jetbrains/python/psi/impl/PyStringLiteralExpressionImpl.java index d2bc6f5bc3e5..212dadf48f46 100644 --- a/python/src/com/jetbrains/python/psi/impl/PyStringLiteralExpressionImpl.java +++ b/python/src/com/jetbrains/python/psi/impl/PyStringLiteralExpressionImpl.java @@ -135,6 +135,7 @@ public class PyStringLiteralExpressionImpl extends PyElementImpl implements PySt int startOffset = 0; startOffset = PyStringLiteralLexer.skipEncodingPrefix(text, startOffset); startOffset = PyStringLiteralLexer.skipRawPrefix(text, startOffset); + startOffset = PyStringLiteralLexer.skipFormattedPrefix(text, startOffset); startOffset = PyStringLiteralLexer.skipEncodingPrefix(text, startOffset); startOffset = PyStringLiteralLexer.skipRawPrefix(text, startOffset); return startOffset; diff --git a/python/src/com/jetbrains/python/validation/CompatibilityVisitor.java b/python/src/com/jetbrains/python/validation/CompatibilityVisitor.java index fafbaca04a31..0be080329b5d 100644 --- a/python/src/com/jetbrains/python/validation/CompatibilityVisitor.java +++ b/python/src/com/jetbrains/python/validation/CompatibilityVisitor.java @@ -52,6 +52,7 @@ public abstract class CompatibilityVisitor extends PyAnnotator { AVAILABLE_PREFIXES.put(LanguageLevel.PYTHON30, Sets.newHashSet("R", "B")); AVAILABLE_PREFIXES.put(LanguageLevel.PYTHON31, Sets.newHashSet("R", "B", "BR")); AVAILABLE_PREFIXES.put(LanguageLevel.PYTHON32, Sets.newHashSet("R", "B", "BR")); + AVAILABLE_PREFIXES.put(LanguageLevel.PYTHON36, Sets.newHashSet("R", "U", "B", "BR", "RB", "F", "FR", "RF")); } private static final Set DEFAULT_PREFIXES = Sets.newHashSet(Sets.newHashSet("R", "U", "B", "BR", "RB")); diff --git a/python/testData/highlighting/fStringLiterals.py b/python/testData/highlighting/fStringLiterals.py new file mode 100644 index 000000000000..f9d47a00b205 --- /dev/null +++ b/python/testData/highlighting/fStringLiterals.py @@ -0,0 +1,9 @@ +a = f"" +a = F"" +a = rf"" +a = fr"" +a = fu"" +a = uf"" +a = bf"" +a = fb"" +a = ufr"" diff --git a/python/testData/inspections/PyCompatibilityInspection/stringLiteralExpression.py b/python/testData/inspections/PyCompatibilityInspection/stringLiteralExpression.py index aba46f914952..93e7740bf809 100644 --- a/python/testData/inspections/PyCompatibilityInspection/stringLiteralExpression.py +++ b/python/testData/inspections/PyCompatibilityInspection/stringLiteralExpression.py @@ -1,5 +1,17 @@ a = u"String" +# Python 3.6 + +a = f"" +a = F"" +a = rf"" +a = fr"" +a = fu"" +a = uf"" +a = bf"" +a = fb"" +a = ufr"" + # python 3.3 a = u"" diff --git a/python/testData/intentions/removeLeadingF.py b/python/testData/intentions/removeLeadingF.py new file mode 100644 index 000000000000..8eb9f652464b --- /dev/null +++ b/python/testData/intentions/removeLeadingF.py @@ -0,0 +1 @@ +a = f"{42}" \ No newline at end of file diff --git a/python/testData/intentions/removeLeadingF_after.py b/python/testData/intentions/removeLeadingF_after.py new file mode 100644 index 000000000000..641404c32f32 --- /dev/null +++ b/python/testData/intentions/removeLeadingF_after.py @@ -0,0 +1 @@ +a = "{42}" \ No newline at end of file diff --git a/python/testData/psi/FStrings.py b/python/testData/psi/FStrings.py new file mode 100644 index 000000000000..24ebfa1cd20d --- /dev/null +++ b/python/testData/psi/FStrings.py @@ -0,0 +1,7 @@ +s1 = f'' +s2 = fr'' +s3 = rf'' +s4 = F'' +s5 = bf'' +s6 = uf'' +s7 = ufr'' diff --git a/python/testData/psi/FStrings.txt b/python/testData/psi/FStrings.txt new file mode 100644 index 000000000000..d7825d5f2883 --- /dev/null +++ b/python/testData/psi/FStrings.txt @@ -0,0 +1,63 @@ +PyFile:FStrings.py + PyAssignmentStatement + PyTargetExpression: s1 + PsiElement(Py:IDENTIFIER)('s1') + PsiWhiteSpace(' ') + PsiElement(Py:EQ)('=') + PsiWhiteSpace(' ') + PyStringLiteralExpression: + PsiElement(Py:SINGLE_QUOTED_STRING)('f''') + PsiWhiteSpace(' \n') + PyAssignmentStatement + PyTargetExpression: s2 + PsiElement(Py:IDENTIFIER)('s2') + PsiWhiteSpace(' ') + PsiElement(Py:EQ)('=') + PsiWhiteSpace(' ') + PyStringLiteralExpression: + PsiElement(Py:SINGLE_QUOTED_STRING)('fr''') + PsiWhiteSpace('\n') + PyAssignmentStatement + PyTargetExpression: s3 + PsiElement(Py:IDENTIFIER)('s3') + PsiWhiteSpace(' ') + PsiElement(Py:EQ)('=') + PsiWhiteSpace(' ') + PyStringLiteralExpression: + PsiElement(Py:SINGLE_QUOTED_STRING)('rf''') + PsiWhiteSpace('\n') + PyAssignmentStatement + PyTargetExpression: s4 + PsiElement(Py:IDENTIFIER)('s4') + PsiWhiteSpace(' ') + PsiElement(Py:EQ)('=') + PsiWhiteSpace(' ') + PyStringLiteralExpression: + PsiElement(Py:SINGLE_QUOTED_STRING)('F''') + PsiWhiteSpace('\n') + PyAssignmentStatement + PyTargetExpression: s5 + PsiElement(Py:IDENTIFIER)('s5') + PsiWhiteSpace(' ') + PsiElement(Py:EQ)('=') + PsiWhiteSpace(' ') + PyStringLiteralExpression: + PsiElement(Py:SINGLE_QUOTED_STRING)('bf''') + PsiWhiteSpace('\n') + PyAssignmentStatement + PyTargetExpression: s6 + PsiElement(Py:IDENTIFIER)('s6') + PsiWhiteSpace(' ') + PsiElement(Py:EQ)('=') + PsiWhiteSpace(' ') + PyStringLiteralExpression: + PsiElement(Py:SINGLE_QUOTED_STRING)('uf''') + PsiWhiteSpace('\n') + PyAssignmentStatement + PyTargetExpression: s7 + PsiElement(Py:IDENTIFIER)('s7') + PsiWhiteSpace(' ') + PsiElement(Py:EQ)('=') + PsiWhiteSpace(' ') + PyStringLiteralExpression: + PsiElement(Py:SINGLE_QUOTED_STRING)('ufr''') \ No newline at end of file diff --git a/python/testSrc/com/jetbrains/python/PythonHighlightingTest.java b/python/testSrc/com/jetbrains/python/PythonHighlightingTest.java index 5991a6d16135..25f1fcff2fc3 100644 --- a/python/testSrc/com/jetbrains/python/PythonHighlightingTest.java +++ b/python/testSrc/com/jetbrains/python/PythonHighlightingTest.java @@ -301,6 +301,10 @@ public class PythonHighlightingTest extends PyTestCase { doTest(LanguageLevel.PYTHON36, true, false); } + public void testFStringLiterals() { + doTest(); + } + // --- private void doTest(final LanguageLevel languageLevel, final boolean checkWarnings, final boolean checkInfos) { PythonLanguageLevelPusher.setForcedLanguageLevel(myFixture.getProject(), languageLevel); diff --git a/python/testSrc/com/jetbrains/python/PythonLexerTest.java b/python/testSrc/com/jetbrains/python/PythonLexerTest.java index 4398fdd77be0..644496dd0a70 100644 --- a/python/testSrc/com/jetbrains/python/PythonLexerTest.java +++ b/python/testSrc/com/jetbrains/python/PythonLexerTest.java @@ -388,6 +388,13 @@ public class PythonLexerTest extends PyLexerTestCase { doTest("10_000_000J", "Py:IMAGINARY_LITERAL", "Py:STATEMENT_BREAK"); } + public void testFStringLiterals() { + doTest("s = f'{x}'", "Py:IDENTIFIER", "Py:SPACE", "Py:EQ", "Py:SPACE", "Py:SINGLE_QUOTED_STRING", "Py:STATEMENT_BREAK"); + doTest("s = rf\"{x}\"", "Py:IDENTIFIER", "Py:SPACE", "Py:EQ", "Py:SPACE", "Py:SINGLE_QUOTED_STRING", "Py:STATEMENT_BREAK"); + doTest("s = fr'''{x}\n'''", "Py:IDENTIFIER", "Py:SPACE", "Py:EQ", "Py:SPACE", "Py:TRIPLE_QUOTED_STRING", "Py:STATEMENT_BREAK"); + doTest("s = f\"\"\"{x}\n\"\"\"", "Py:IDENTIFIER", "Py:SPACE", "Py:EQ", "Py:SPACE", "Py:TRIPLE_QUOTED_STRING", "Py:STATEMENT_BREAK"); + } + private static void doTest(String text, String... expectedTokens) { PyLexerTestCase.doLexerTest(text, new PythonIndentingLexer(), expectedTokens); } diff --git a/python/testSrc/com/jetbrains/python/PythonParsingTest.java b/python/testSrc/com/jetbrains/python/PythonParsingTest.java index e90e63aff9f7..605b56ac0d78 100644 --- a/python/testSrc/com/jetbrains/python/PythonParsingTest.java +++ b/python/testSrc/com/jetbrains/python/PythonParsingTest.java @@ -506,6 +506,11 @@ public class PythonParsingTest extends ParsingTestCase { doTest(LanguageLevel.PYTHON35); } + // PY-18972 + public void testFStrings() { + doTest(LanguageLevel.PYTHON36); + } + // PY-19036 public void testAwaitInNonAsyncNestedFunction() { doTest(LanguageLevel.PYTHON35); diff --git a/python/testSrc/com/jetbrains/python/intentions/PyIntentionTest.java b/python/testSrc/com/jetbrains/python/intentions/PyIntentionTest.java index 53d2dc40c315..5aeb68f87bcb 100644 --- a/python/testSrc/com/jetbrains/python/intentions/PyIntentionTest.java +++ b/python/testSrc/com/jetbrains/python/intentions/PyIntentionTest.java @@ -105,6 +105,11 @@ public class PyIntentionTest extends PyTestCase { doTest(PyBundle.message("INTN.remove.leading.$0", "U"), LanguageLevel.PYTHON30); } + public void testRemoveLeadingF() { + doTest(PyBundle.message("INTN.remove.leading.$0", "F"), LanguageLevel.PYTHON35); + } + + // PY-18972 public void testRemoveTrailingL() { doTest(PyBundle.message("INTN.remove.trailing.l"), LanguageLevel.PYTHON30); }