Browse Source

Merge 09357048aced6245f7bd41431b59d761d855d2d0 into 69760cb3accce488cc072772ca918ac2cbf384ba

Joongi Kim 6 years ago
parent
commit
7a48474fcc
3 changed files with 263 additions and 132 deletions
  1. 4
    1
      README.rst
  2. 211
    121
      syntax/python.vim
  3. 48
    10
      test.py

+ 4
- 1
README.rst View File

@@ -24,7 +24,8 @@ Features
24 24
 
25 25
 Changes from the original ``python.vim`` are:
26 26
 
27
-- Added support for Python 3 syntax highlighting
27
+- Added support for Python 3.5/3.6+ syntax highlighting, including f-string
28
+  literals and type annotations.
28 29
 - Added ``:Python2Syntax`` and ``:Python3Syntax`` commands which allow to
29 30
   switch between Python 2 and Python 3 syntaxes respectively without
30 31
   reloads/restarts
@@ -101,6 +102,8 @@ Options used by the script
101 102
   Highlight builtin objects only
102 103
 ``python_highlight_builtin_funcs``
103 104
   Highlight builtin functions only
105
+``python_highlight_type_annotations``
106
+  Highlight Python 3.5+ type annotations
104 107
 ``python_highlight_exceptions``
105 108
   Highlight standard exceptions
106 109
 ``python_highlight_string_formatting``

+ 211
- 121
syntax/python.vim View File

@@ -136,6 +136,7 @@ if s:Enabled("g:python_highlight_all")
136 136
     call s:EnableByDefault("g:python_highlight_builtin_objs")
137 137
     call s:EnableByDefault("g:python_highlight_builtin_funcs")
138 138
   endif
139
+  call s:EnableByDefault("g:python_highlight_type_annotations")
139 140
   call s:EnableByDefault("g:python_highlight_exceptions")
140 141
   call s:EnableByDefault("g:python_highlight_string_formatting")
141 142
   call s:EnableByDefault("g:python_highlight_string_format")
@@ -151,10 +152,12 @@ endif
151 152
 "
152 153
 
153 154
 syn keyword pythonStatement     break continue del
154
-syn keyword pythonStatement     exec return
155
+if s:Python2Syntax()
156
+  syn keyword pythonStatement     exec
157
+endif
158
+syn keyword pythonStatement     return
155 159
 syn keyword pythonStatement     pass raise
156 160
 syn keyword pythonStatement     global assert
157
-syn keyword pythonStatement     lambda
158 161
 syn keyword pythonStatement     with
159 162
 syn keyword pythonStatement     def class nextgroup=pythonFunction skipwhite
160 163
 syn keyword pythonRepeat        for while
@@ -163,8 +166,29 @@ syn keyword pythonConditional   if elif else
163 166
 " we provide a dummy group here to avoid crashing pyrex.vim.
164 167
 syn keyword pythonInclude       import
165 168
 syn keyword pythonImport        import
169
+syn match   pythonIdentifier    "\%([^[:cntrl:][:space:][:punct:][:digit:]]\|_\)\%([^[:cntrl:][:punct:][:space:]]\|_\)*" nextgroup=pythonFuncArgs,pythonTypeAnno display
166 170
 syn keyword pythonException     try except finally
167 171
 syn keyword pythonOperator      and in is not or
172
+syn match pythonLambdaExpr   "\<lambda[^:]*:"he=s+6 contains=@pythonExpression nextgroup=@pythonExpression
173
+
174
+syn region pythonDictSetExpr matchgroup=pythonDictSetExpr start='{' end='}' contains=@pythonExpression
175
+syn region pythonListSliceExpr matchgroup=pythonListSliceExpr start='\[' end='\]' contains=@pythonExpression
176
+syn region pythonFuncArgs    matchgroup=pythonFuncArgs    start='(' end=')' contained contains=@pythonTypeExpression,@pythonExpression
177
+
178
+if !s:Python2Syntax()
179
+  if s:Enabled("g:python_highlight_type_annotations")
180
+    syn match pythonTypeAnno @:\s*['"]\?\%([^[:cntrl:][:space:][:punct:][:digit:]]\|_\)\%([^[:cntrl:][:punct:][:space:]]\|_\)*\%(\.\%([^[:cntrl:][:space:][:punct:][:digit:]]\|_\)\%([^[:cntrl:][:punct:][:space:]]\|_\)*\)*['"]\?@hs=s+1 display contained contains=pythonType,pythonString nextgroup=pythonTypeUnion,pythonTypeArgs
181
+    syn match pythonTypeUnion @\s*|\s*['"]\?\%([^[:cntrl:][:space:][:punct:][:digit:]]\|_\)\%([^[:cntrl:][:punct:][:space:]]\|_\)*\%(\.\%([^[:cntrl:][:space:][:punct:][:digit:]]\|_\)\%([^[:cntrl:][:punct:][:space:]]\|_\)*\)*['"]\?@ display contained contains=pythonType,pythonString nextgroup=pythonTypeUnion
182
+    syn match pythonTypeAnnoReturn @->\s*['"]\?\%([^[:cntrl:][:space:][:punct:][:digit:]]\|_\)\%([^[:cntrl:][:punct:][:space:]]\|_\)*\%(\.\%([^[:cntrl:][:space:][:punct:][:digit:]]\|_\)\%([^[:cntrl:][:punct:][:space:]]\|_\)*\)*['"]\?@ display contains=pythonType,pythonString nextgroup=pythonTypeArgs
183
+    syn region pythonTypeArgs matchgroup=pythonTypeArgs start='\[' end='\]' display contained contains=pythonType,pythonString,pythonTypeArgs
184
+    syn keyword pythonType Any AnyStr Callable ClassVar Tuple Union Optional Type TypeVar None contained
185
+    syn keyword pythonType AbstractSet MutableSet Mapping MutableMapping Sequence MutableSequence ByteString Deque List contained
186
+    syn keyword pythonType Set FrozenSet MappingView KeysView ItemsView ValuesView Awaitable Coroutine AsyncIterable contained
187
+    syn keyword pythonType AsyncIterator ContextManager Dict DefaultDict Generator AsyncGenerator Text NamedTuple contained
188
+    syn keyword pythonType Iterable Iterator Reversible SupportsInt SupportsFloat SupportsAbs SupportsRound Container contained
189
+    syn keyword pythonType Hashable Sized Collection contained
190
+  endif
191
+endif
168 192
 
169 193
 syn match pythonStatement   "\<yield\>" display
170 194
 syn match pythonImport      "\<from\>" display
@@ -176,21 +200,66 @@ if s:Python2Syntax()
176 200
   syn keyword pythonImport      as
177 201
   syn match   pythonFunction    "[a-zA-Z_][a-zA-Z0-9_]*" display contained
178 202
 else
179
-  syn keyword pythonStatement   as nonlocal None
203
+  syn keyword pythonStatement   as nonlocal
180 204
   syn match   pythonStatement   "\<yield\s\+from\>" display
181
-  syn keyword pythonBoolean     True False
182
-  syn match   pythonFunction    "\%([^[:cntrl:][:space:][:punct:][:digit:]]\|_\)\%([^[:cntrl:][:punct:][:space:]]\|_\)*" display contained
183
-  syn keyword pythonStatement   await
184
-  syn match   pythonStatement   "\<async\s\+def\>" nextgroup=pythonFunction skipwhite
205
+  syn keyword pythonBuiltinObj  None True False
206
+  syn match   pythonFunction    "\%([^[:cntrl:][:space:][:punct:][:digit:]]\|_\)\%([^[:cntrl:][:punct:][:space:]]\|_\)*" nextgroup=pythonFuncArgs display contained
207
+  syn keyword pythonStatement   await async
208
+  syn match   pythonStatement   "\<async\s\+def\>" display nextgroup=pythonFunction skipwhite
185 209
   syn match   pythonStatement   "\<async\s\+with\>" display
186 210
   syn match   pythonStatement   "\<async\s\+for\>" display
187 211
 endif
188 212
 
213
+syn cluster pythonTypeExpression contains=pythonTypeAnno,pythonTypeUnion,pythonTypeArgs
214
+
215
+syn cluster pythonExpression contains=
216
+            \ pythonFuncArgs,
217
+            \ pythonDictSetExpr,
218
+            \ pythonListSliceExpr,
219
+            \ pythonLambdaExpr,
220
+            \ pythonStatement,
221
+            \ pythonRepeat,
222
+            \ pythonConditional,
223
+            \ pythonComment,
224
+            \ pythonOperator,
225
+            \ pythonNumber,
226
+            \ pythonNumberError,
227
+            \ pythonFloat,
228
+            \ pythonHexNumber,
229
+            \ pythonOctNumber,
230
+            \ pythonBytes,
231
+            \ pythonString,
232
+            \ pythonRawString,
233
+            \ pythonUniString,
234
+            \ pythonUniRawString,
235
+            \ pythonFString,
236
+            \ pythonExClass,
237
+            \ pythonBuiltinObj,
238
+            \ pythonBuiltinFunc
239
+
240
+syn cluster pythonFExpression contains=
241
+            \ pythonStatement,
242
+            \ pythonDictSetExpr,
243
+            \ pythonListSliceExpr,
244
+            \ pythonLambdaExpr,
245
+            \ pythonRepeat,
246
+            \ pythonConditional,
247
+            \ pythonOperator,
248
+            \ pythonNumber,
249
+            \ pythonHexNumber,
250
+            \ pythonOctNumber,
251
+            \ pythonBinNumber,
252
+            \ pythonFloat,
253
+            \ pythonString,
254
+            \ pythonBytes,
255
+            \ pythonBuiltinObj,
256
+            \ pythonBuiltinFunc
257
+
189 258
 "
190 259
 " Decorators (new in Python 2.4)
191 260
 "
192 261
 
193
-syn match   pythonDecorator	"@" display nextgroup=pythonDottedName skipwhite
262
+syn match   pythonDecorator     "^\s*\zs@" display nextgroup=pythonDottedName skipwhite
194 263
 if s:Python2Syntax()
195 264
   syn match   pythonDottedName "[a-zA-Z_][a-zA-Z0-9_]*\%(\.[a-zA-Z_][a-zA-Z0-9_]*\)*" display contained
196 265
 else
@@ -202,31 +271,31 @@ syn match   pythonDot        "\." display containedin=pythonDottedName
202 271
 " Comments
203 272
 "
204 273
 
205
-syn match   pythonComment	"#.*$" display contains=pythonTodo,@Spell
274
+syn match   pythonComment       "#.*$" display contains=pythonTodo,@Spell
206 275
 if !s:Enabled("g:python_highlight_file_headers_as_comments")
207
-  syn match   pythonRun		"\%^#!.*$"
208
-  syn match   pythonCoding	"\%^.*\%(\n.*\)\?#.*coding[:=]\s*[0-9A-Za-z-_.]\+.*$"
276
+  syn match   pythonRun         "\%^#!.*$"
277
+  syn match   pythonCoding      "\%^.*\%(\n.*\)\?#.*coding[:=]\s*[0-9A-Za-z-_.]\+.*$"
209 278
 endif
210
-syn keyword pythonTodo		TODO FIXME XXX contained
279
+syn keyword pythonTodo          TODO FIXME XXX contained
211 280
 
212 281
 "
213 282
 " Errors
214 283
 "
215 284
 
216
-syn match pythonError		"\<\d\+\D\+\>" display
217
-syn match pythonError		"[$?]" display
218
-syn match pythonError		"[&|]\{2,}" display
219
-syn match pythonError		"[=]\{3,}" display
285
+syn match pythonError           "\<\d\+\D\+\>" display
286
+syn match pythonError           "[$?]" display
287
+syn match pythonError           "[&|]\{2,}" display
288
+syn match pythonError           "[=]\{3,}" display
220 289
 
221 290
 " Mixing spaces and tabs also may be used for pretty formatting multiline
222 291
 " statements
223 292
 if s:Enabled("g:python_highlight_indent_errors")
224
-  syn match pythonIndentError	"^\s*\%( \t\|\t \)\s*\S"me=e-1 display
293
+  syn match pythonIndentError   "^\s*\%( \t\|\t \)\s*\S"me=e-1 display
225 294
 endif
226 295
 
227 296
 " Trailing space errors
228 297
 if s:Enabled("g:python_highlight_space_errors")
229
-  syn match pythonSpaceError	"\s\+$" display
298
+  syn match pythonSpaceError    "\s\+$" display
230 299
 endif
231 300
 
232 301
 "
@@ -241,10 +310,10 @@ if s:Python2Syntax()
241 310
   syn region pythonString   start=+[bB]\='''+ end=+'''+ keepend contains=pythonBytesEscape,pythonBytesEscapeError,pythonUniEscape,pythonUniEscapeError,pythonDocTest,pythonSpaceError,@Spell
242 311
 else
243 312
   " Python 3 byte strings
244
-  syn region pythonBytes		start=+[bB]'+ skip=+\\\\\|\\'\|\\$+ excludenl end=+'+ end=+$+ keepend contains=pythonBytesError,pythonBytesContent,@Spell
245
-  syn region pythonBytes		start=+[bB]"+ skip=+\\\\\|\\"\|\\$+ excludenl end=+"+ end=+$+ keepend contains=pythonBytesError,pythonBytesContent,@Spell
246
-  syn region pythonBytes		start=+[bB]"""+ end=+"""+ keepend contains=pythonBytesError,pythonBytesContent,pythonDocTest2,pythonSpaceError,@Spell
247
-  syn region pythonBytes		start=+[bB]'''+ end=+'''+ keepend contains=pythonBytesError,pythonBytesContent,pythonDocTest,pythonSpaceError,@Spell
313
+  syn region pythonBytes                start=+[bB]'+ skip=+\\\\\|\\'\|\\$+ excludenl end=+'+ end=+$+ keepend contains=pythonBytesError,pythonBytesContent,@Spell
314
+  syn region pythonBytes                start=+[bB]"+ skip=+\\\\\|\\"\|\\$+ excludenl end=+"+ end=+$+ keepend contains=pythonBytesError,pythonBytesContent,@Spell
315
+  syn region pythonBytes                start=+[bB]"""+ end=+"""+ keepend contains=pythonBytesError,pythonBytesContent,pythonDocTest2,pythonSpaceError,@Spell
316
+  syn region pythonBytes                start=+[bB]'''+ end=+'''+ keepend contains=pythonBytesError,pythonBytesContent,pythonDocTest,pythonSpaceError,@Spell
248 317
 
249 318
   syn match pythonBytesError    ".\+" display contained
250 319
   syn match pythonBytesContent  "[\u0000-\u00ff]\+" display contained contains=pythonBytesEscape,pythonBytesEscapeError
@@ -276,6 +345,11 @@ else
276 345
   syn region pythonString   start=+"+ skip=+\\\\\|\\"\|\\$+ excludenl end=+"+ end=+$+ keepend contains=pythonBytesEscape,pythonBytesEscapeError,pythonUniEscape,pythonUniEscapeError,@Spell
277 346
   syn region pythonString   start=+"""+ end=+"""+ keepend contains=pythonBytesEscape,pythonBytesEscapeError,pythonUniEscape,pythonUniEscapeError,pythonDocTest2,pythonSpaceError,@Spell
278 347
   syn region pythonString   start=+'''+ end=+'''+ keepend contains=pythonBytesEscape,pythonBytesEscapeError,pythonUniEscape,pythonUniEscapeError,pythonDocTest,pythonSpaceError,@Spell
348
+
349
+  syn region pythonFString  start=+[fF]'+ skip=+\\\\\|\\'\|\\$+ excludenl end=+'+ end=+$+ keepend contains=pythonBytesEscape,pythonBytesEscapeError,pythonUniEscape,pythonUniEscapeError,@Spell
350
+  syn region pythonFString  start=+[fF]"+ skip=+\\\\\|\\"\|\\$+ excludenl end=+"+ end=+$+ keepend contains=pythonBytesEscape,pythonBytesEscapeError,pythonUniEscape,pythonUniEscapeError,@Spell
351
+  syn region pythonFString  start=+[fF]"""+ end=+"""+ keepend contains=pythonBytesEscape,pythonBytesEscapeError,pythonUniEscape,pythonUniEscapeError,pythonDocTest2,pythonSpaceError,@Spell
352
+  syn region pythonFString  start=+[fF]'''+ end=+'''+ keepend contains=pythonBytesEscape,pythonBytesEscapeError,pythonUniEscape,pythonUniEscapeError,pythonDocTest,pythonSpaceError,@Spell
279 353
 endif
280 354
 
281 355
 if s:Python2Syntax()
@@ -312,11 +386,11 @@ syn match pythonRawEscape +\\['"]+ display transparent contained
312 386
 if s:Enabled("g:python_highlight_string_formatting")
313 387
   " % operator string formatting
314 388
   if s:Python2Syntax()
315
-    syn match pythonStrFormatting	"%\%(([^)]\+)\)\=[-#0 +]*\d*\%(\.\d\+\)\=[hlL]\=[diouxXeEfFgGcrs%]" contained containedin=pythonString,pythonUniString,pythonUniRawString,pythonRawString
316
-    syn match pythonStrFormatting	"%[-#0 +]*\%(\*\|\d\+\)\=\%(\.\%(\*\|\d\+\)\)\=[hlL]\=[diouxXeEfFgGcrs%]" contained containedin=pythonString,pythonUniString,pythonUniRawString,pythonRawString
389
+    syn match pythonStrFormatting       "%\%(([^)]\+)\)\=[-#0 +]*\d*\%(\.\d\+\)\=[hlL]\=[diouxXeEfFgGcrs%]" contained containedin=pythonString,pythonUniString,pythonUniRawString,pythonRawString
390
+    syn match pythonStrFormatting       "%[-#0 +]*\%(\*\|\d\+\)\=\%(\.\%(\*\|\d\+\)\)\=[hlL]\=[diouxXeEfFgGcrs%]" contained containedin=pythonString,pythonUniString,pythonUniRawString,pythonRawString
317 391
   else
318
-    syn match pythonStrFormatting	"%\%(([^)]\+)\)\=[-#0 +]*\d*\%(\.\d\+\)\=[hlL]\=[diouxXeEfFgGcrs%]" contained containedin=pythonString,pythonRawString
319
-    syn match pythonStrFormatting	"%[-#0 +]*\%(\*\|\d\+\)\=\%(\.\%(\*\|\d\+\)\)\=[hlL]\=[diouxXeEfFgGcrs%]" contained containedin=pythonString,pythonRawString
392
+    syn match pythonStrFormatting       "%\%(([^)]\+)\)\=[-#0 +]*\d*\%(\.\d\+\)\=[hlL]\=[diouxXeEfFgGcrs%]" contained containedin=pythonString,pythonRawString
393
+    syn match pythonStrFormatting       "%[-#0 +]*\%(\*\|\d\+\)\=\%(\.\%(\*\|\d\+\)\)\=[hlL]\=[diouxXeEfFgGcrs%]" contained containedin=pythonString,pythonRawString
320 394
   endif
321 395
 endif
322 396
 
@@ -324,30 +398,31 @@ if s:Enabled("g:python_highlight_string_format")
324 398
   " str.format syntax
325 399
   if s:Python2Syntax()
326 400
     syn match pythonStrFormat "{{\|}}" contained containedin=pythonString,pythonUniString,pythonUniRawString,pythonRawString
327
-    syn match pythonStrFormat	"{\%(\%([^[:cntrl:][:space:][:punct:][:digit:]]\|_\)\%([^[:cntrl:][:punct:][:space:]]\|_\)*\|\d\+\)\=\%(\.\%([^[:cntrl:][:space:][:punct:][:digit:]]\|_\)\%([^[:cntrl:][:punct:][:space:]]\|_\)*\|\[\%(\d\+\|[^!:\}]\+\)\]\)*\%(![rsa]\)\=\%(:\%({\%(\%([^[:cntrl:][:space:][:punct:][:digit:]]\|_\)\%([^[:cntrl:][:punct:][:space:]]\|_\)*\|\d\+\)}\|\%([^}]\=[<>=^]\)\=[ +-]\=#\=0\=\d*,\=\%(\.\d\+\)\=[bcdeEfFgGnosxX%]\=\)\=\)\=}" contained containedin=pythonString,pythonUniString,pythonUniRawString,pythonRawString
401
+    syn match pythonStrFormat   "{\%(\%([^[:cntrl:][:space:][:punct:][:digit:]]\|_\)\%([^[:cntrl:][:punct:][:space:]]\|_\)*\|\d\+\)\=\%(\.\%([^[:cntrl:][:space:][:punct:][:digit:]]\|_\)\%([^[:cntrl:][:punct:][:space:]]\|_\)*\|\[\%(\d\+\|[^!:\}]\+\)\]\)*\%(![rsa]\)\=\%(:\%({\%(\%([^[:cntrl:][:space:][:punct:][:digit:]]\|_\)\%([^[:cntrl:][:punct:][:space:]]\|_\)*\|\d\+\)}\|\%([^}]\=[<>=^]\)\=[ +-]\=#\=0\=\d*,\=\%(\.\d\+\)\=[bcdeEfFgGnosxX%]\=\)\=\)\=}" contained containedin=pythonString,pythonUniString,pythonUniRawString,pythonRawString
328 402
   else
329 403
     syn match pythonStrFormat "{{\|}}" contained containedin=pythonString,pythonRawString
330
-    syn match pythonStrFormat	"{\%(\%([^[:cntrl:][:space:][:punct:][:digit:]]\|_\)\%([^[:cntrl:][:punct:][:space:]]\|_\)*\|\d\+\)\=\%(\.\%([^[:cntrl:][:space:][:punct:][:digit:]]\|_\)\%([^[:cntrl:][:punct:][:space:]]\|_\)*\|\[\%(\d\+\|[^!:\}]\+\)\]\)*\%(![rsa]\)\=\%(:\%({\%(\%([^[:cntrl:][:space:][:punct:][:digit:]]\|_\)\%([^[:cntrl:][:punct:][:space:]]\|_\)*\|\d\+\)}\|\%([^}]\=[<>=^]\)\=[ +-]\=#\=0\=\d*,\=\%(\.\d\+\)\=[bcdeEfFgGnosxX%]\=\)\=\)\=}" contained containedin=pythonString,pythonRawString
404
+    syn match pythonStrFormat "{\%(\%([^[:cntrl:][:space:][:punct:][:digit:]]\|_\)\%([^[:cntrl:][:punct:][:space:]]\|_\)*\|\d\+\)\=\%(\.\%([^[:cntrl:][:space:][:punct:][:digit:]]\|_\)\%([^[:cntrl:][:punct:][:space:]]\|_\)*\|\[\%(\d\+\|[^!:\}]\+\)\]\)*\%(![rsa]\)\=\%(:\%({\%(\%([^[:cntrl:][:space:][:punct:][:digit:]]\|_\)\%([^[:cntrl:][:punct:][:space:]]\|_\)*\|\d\+\)}\|\%([^}]\=[<>=^]\)\=[ +-]\=#\=0\=\d*,\=\%(\.\d\+\)\=[bcdeEfFgGnosxX%]\=\)\=\)\=}" contained containedin=pythonString,pythonRawString
405
+    syn region pythonStrInterpRegion matchgroup=pythonStrInterpRegion start="{" end="}" extend contained containedin=pythonFString contains=@pythonFExpression
331 406
   endif
332 407
 endif
333 408
 
334 409
 if s:Enabled("g:python_highlight_string_templates")
335 410
   " string.Template format
336 411
   if s:Python2Syntax()
337
-    syn match pythonStrTemplate	"\$\$" contained containedin=pythonString,pythonUniString,pythonUniRawString,pythonRawString
338
-    syn match pythonStrTemplate	"\${[a-zA-Z_][a-zA-Z0-9_]*}" contained containedin=pythonString,pythonUniString,pythonUniRawString,pythonRawString
339
-    syn match pythonStrTemplate	"\$[a-zA-Z_][a-zA-Z0-9_]*" contained containedin=pythonString,pythonUniString,pythonUniRawString,pythonRawString
412
+    syn match pythonStrTemplate "\$\$" contained containedin=pythonString,pythonUniString,pythonUniRawString,pythonRawString
413
+    syn match pythonStrTemplate "\${[a-zA-Z_][a-zA-Z0-9_]*}" contained containedin=pythonString,pythonUniString,pythonUniRawString,pythonRawString
414
+    syn match pythonStrTemplate "\$[a-zA-Z_][a-zA-Z0-9_]*" contained containedin=pythonString,pythonUniString,pythonUniRawString,pythonRawString
340 415
   else
341
-    syn match pythonStrTemplate	"\$\$" contained containedin=pythonString,pythonRawString
342
-    syn match pythonStrTemplate	"\${[a-zA-Z_][a-zA-Z0-9_]*}" contained containedin=pythonString,pythonRawString
343
-    syn match pythonStrTemplate	"\$[a-zA-Z_][a-zA-Z0-9_]*" contained containedin=pythonString,pythonRawString
416
+    syn match pythonStrTemplate "\$\$" contained containedin=pythonString,pythonRawString
417
+    syn match pythonStrTemplate "\${[a-zA-Z_][a-zA-Z0-9_]*}" contained containedin=pythonString,pythonRawString
418
+    syn match pythonStrTemplate "\$[a-zA-Z_][a-zA-Z0-9_]*" contained containedin=pythonString,pythonRawString
344 419
   endif
345 420
 endif
346 421
 
347 422
 if s:Enabled("g:python_highlight_doctests")
348 423
   " DocTests
349
-  syn region pythonDocTest	start="^\s*>>>" end=+'''+he=s-1 end="^\s*$" contained
350
-  syn region pythonDocTest2	start="^\s*>>>" end=+"""+he=s-1 end="^\s*$" contained
424
+  syn region pythonDocTest      start="^\s*>>>" end=+'''+he=s-1 end="^\s*$" contained
425
+  syn region pythonDocTest2     start="^\s*>>>" end=+"""+he=s-1 end="^\s*$" contained
351 426
 endif
352 427
 
353 428
 "
@@ -355,55 +430,60 @@ endif
355 430
 "
356 431
 
357 432
 if s:Python2Syntax()
358
-  syn match   pythonHexError	"\<0[xX]\x*[g-zG-Z]\+\x*[lL]\=\>" display
359
-  syn match   pythonOctError	"\<0[oO]\=\o*\D\+\d*[lL]\=\>" display
360
-  syn match   pythonBinError	"\<0[bB][01]*\D\+\d*[lL]\=\>" display
433
+  syn match   pythonHexError    "\<0[xX]\x*[g-zG-Z]\+\x*[lL]\=\>" display
434
+  syn match   pythonOctError    "\<0[oO]\=\o*\D\+\d*[lL]\=\>" display
435
+  syn match   pythonBinError    "\<0[bB][01]*\D\+\d*[lL]\=\>" display
361 436
 
362
-  syn match   pythonHexNumber	"\<0[xX]\x\+[lL]\=\>" display
437
+  syn match   pythonHexNumber   "\<0[xX]\x\+[lL]\=\>" display
363 438
   syn match   pythonOctNumber "\<0[oO]\o\+[lL]\=\>" display
364 439
   syn match   pythonBinNumber "\<0[bB][01]\+[lL]\=\>" display
365 440
 
366
-  syn match   pythonNumberError	"\<\d\+\D[lL]\=\>" display
367
-  syn match   pythonNumber	"\<\d[lL]\=\>" display
368
-  syn match   pythonNumber	"\<[0-9]\d\+[lL]\=\>" display
369
-  syn match   pythonNumber	"\<\d\+[lLjJ]\>" display
441
+  syn match   pythonNumberError "\<\d\+\D[lL]\=\>" display
442
+  syn match   pythonNumber      "\<\d[lL]\=\>" display
443
+  syn match   pythonNumber      "\<[0-9]\d\+[lL]\=\>" display
444
+  syn match   pythonNumber      "\<\d\+[lLjJ]\>" display
370 445
 
371
-  syn match   pythonOctError	"\<0[oO]\=\o*[8-9]\d*[lL]\=\>" display
372
-  syn match   pythonBinError	"\<0[bB][01]*[2-9]\d*[lL]\=\>" display
446
+  syn match   pythonOctError    "\<0[oO]\=\o*[8-9]\d*[lL]\=\>" display
447
+  syn match   pythonBinError    "\<0[bB][01]*[2-9]\d*[lL]\=\>" display
448
+
449
+  syn match   pythonFloat       "\.\d\+\%([eE][+-]\=\d\+\)\=[jJ]\=\>" display
450
+  syn match   pythonFloat       "\<\d\+[eE][+-]\=\d\+[jJ]\=\>" display
451
+  syn match   pythonFloat       "\<\d\+\.\d*\%([eE][+-]\=\d\+\)\=[jJ]\=" display
373 452
 else
374
-  syn match   pythonHexError	"\<0[xX]\x*[g-zG-Z]\x*\>" display
375
-  syn match   pythonOctError	"\<0[oO]\=\o*\D\+\d*\>" display
376
-  syn match   pythonBinError	"\<0[bB][01]*\D\+\d*\>" display
377
-
378
-  syn match   pythonHexNumber	"\<0[xX]\x\+\>" display
379
-  syn match   pythonOctNumber "\<0[oO]\o\+\>" display
380
-  syn match   pythonBinNumber "\<0[bB][01]\+\>" display
381
-
382
-  syn match   pythonNumberError	"\<\d\+\D\>" display
383
-  syn match   pythonNumberError	"\<0\d\+\>" display
384
-  syn match   pythonNumber	"\<\d\>" display
385
-  syn match   pythonNumber	"\<[1-9]\d\+\>" display
386
-  syn match   pythonNumber	"\<\d\+[jJ]\>" display
387
-
388
-  syn match   pythonOctError	"\<0[oO]\=\o*[8-9]\d*\>" display
389
-  syn match   pythonBinError	"\<0[bB][01]*[2-9]\d*\>" display
453
+  syn match   pythonHexError    "\<0[xX]\x*[g-zG-Z]\x*\>" display
454
+  syn match   pythonOctError    "\<0[oO]\=\o*\D\+\d*\>" display
455
+  syn match   pythonBinError    "\<0[bB][01]*\D\+\d*\>" display
456
+
457
+  syn match   pythonHexNumber   "\<0[xX][_0-9a-fA-F]*\x\>" display
458
+  syn match   pythonOctNumber "\<0[oO][_0-7]*\o\>" display
459
+  syn match   pythonBinNumber "\<0[bB][_01]*[01]\>" display
460
+
461
+  syn match   pythonNumberError "\<\d[_0-9]*\D\>" display
462
+  syn match   pythonNumberError "\<0[_0-9]\+\>" display
463
+  syn match   pythonNumberError "\<\d[_0-9]*_\>" display
464
+  syn match   pythonNumber      "\<\d\>" display
465
+  syn match   pythonNumber      "\<[1-9][_0-9]*\d\>" display
466
+  syn match   pythonNumber      "\<\d[jJ]\>" display
467
+  syn match   pythonNumber      "\<[1-9][_0-9]*\d[jJ]\>" display
468
+
469
+  syn match   pythonOctError    "\<0[oO]\=\o*[8-9]\d*\>" display
470
+  syn match   pythonBinError    "\<0[bB][01]*[2-9]\d*\>" display
471
+
472
+  syn match   pythonFloat       "\.\d\%([_0-9]*\d\)\=\%([eE][+-]\=\d\%([_0-9]*\d\)\=\)\=[jJ]\=\>" display
473
+  syn match   pythonFloat       "\<\d\%([_0-9]*\d\)\=[eE][+-]\=\d\%([_0-9]*\d\)\=[jJ]\=\>" display
474
+  syn match   pythonFloat       "\<\d\%([_0-9]*\d\)\=\.\d\%([_0-9]*\d\)\=\%([eE][+-]\=\d\%([_0-9]*\d\)\=\)\=[jJ]\=" display
390 475
 endif
391 476
 
392
-syn match   pythonFloat		"\.\d\+\%([eE][+-]\=\d\+\)\=[jJ]\=\>" display
393
-syn match   pythonFloat		"\<\d\+[eE][+-]\=\d\+[jJ]\=\>" display
394
-syn match   pythonFloat		"\<\d\+\.\d*\%([eE][+-]\=\d\+\)\=[jJ]\=" display
395
-
396 477
 "
397 478
 " Builtin objects and types
398 479
 "
399 480
 
400 481
 if s:Enabled("g:python_highlight_builtin_objs")
401 482
   if s:Python2Syntax()
402
-    syn keyword pythonBuiltinObj	None
403
-    syn keyword pythonBoolean		True False
483
+    syn keyword pythonBuiltinObj        None False True
404 484
   endif
405
-  syn keyword pythonBuiltinObj	Ellipsis NotImplemented
406
-  syn keyword pythonBuiltinObj	__debug__ __doc__ __file__ __name__ __package__
485
+  syn keyword pythonBuiltinObj  Ellipsis NotImplemented self cls
486
+  syn keyword pythonBuiltinObj  __debug__ __doc__ __file__ __name__ __package__
407 487
 endif
408 488
 
409 489
 "
@@ -412,28 +492,28 @@ endif
412 492
 
413 493
 if s:Enabled("g:python_highlight_builtin_funcs")
414 494
   if s:Python2Syntax()
415
-    syn keyword pythonBuiltinFunc	apply basestring buffer callable coerce
416
-    syn keyword pythonBuiltinFunc	execfile file help intern long raw_input
417
-    syn keyword pythonBuiltinFunc	reduce reload unichr unicode xrange
495
+    syn match pythonBuiltinFunc '\v(\.)@<!\zs<(apply|basestring|buffer|callable|coerce)>\ze\(' nextgroup=pythonFuncArgs
496
+    syn match pythonBuiltinFunc '\v(\.)@<!\zs<(execfile|file|help|intern|long|raw_input)>\ze\(' nextgroup=pythonFuncArgs
497
+    syn match pythonBuiltinFunc '\v(\.)@<!\zs<(reduce|reload|unichr|unicode|xrange)>\ze\(' nextgroup=pythonFuncArgs
418 498
     if s:Enabled("g:python_print_as_function")
419
-      syn keyword pythonBuiltinFunc	print
499
+      syn match pythonBuiltinFunc       '\v(\.)@<!\zs<(print)>\ze\(' nextgroup=pythonFuncArgs
420 500
     endif
421 501
   else
422
-    syn keyword pythonBuiltinFunc	ascii exec memoryview print
502
+    syn match pythonBuiltinFunc '\v(\.)@<!\zs<(ascii|exec|memoryview|print)\ze\(' nextgroup=pythonFuncArgs
423 503
   endif
424
-  syn keyword pythonBuiltinFunc	__import__ abs all any
425
-  syn keyword pythonBuiltinFunc	bin bool bytearray bytes
426
-  syn keyword pythonBuiltinFunc	chr classmethod cmp compile complex
427
-  syn keyword pythonBuiltinFunc	delattr dict dir divmod enumerate eval
428
-  syn keyword pythonBuiltinFunc	filter float format frozenset getattr
429
-  syn keyword pythonBuiltinFunc	globals hasattr hash hex id
430
-  syn keyword pythonBuiltinFunc	input int isinstance
431
-  syn keyword pythonBuiltinFunc	issubclass iter len list locals map max
432
-  syn keyword pythonBuiltinFunc	min next object oct open ord
433
-  syn keyword pythonBuiltinFunc	pow property range
434
-  syn keyword pythonBuiltinFunc	repr reversed round set setattr
435
-  syn keyword pythonBuiltinFunc	slice sorted staticmethod str sum super tuple
436
-  syn keyword pythonBuiltinFunc	type vars zip
504
+  syn match pythonBuiltinFunc   '\v(\.)@<!\zs<(__import__|abs|all|any)>\ze\(' nextgroup=pythonFuncArgs
505
+  syn match pythonBuiltinFunc   '\v(\.)@<!\zs<(bin|bool|bytearray|bytes)>\ze\(' nextgroup=pythonFuncArgs
506
+  syn match pythonBuiltinFunc   '\v(\.)@<!\zs<(chr|classmethod|cmp|compile|complex)>\ze\(' nextgroup=pythonFuncArgs
507
+  syn match pythonBuiltinFunc   '\v(\.)@<!\zs<(delattr|dict|dir|divmod|enumerate|eval)>\ze\(' nextgroup=pythonFuncArgs
508
+  syn match pythonBuiltinFunc   '\v(\.)@<!\zs<(filter|float|format|frozenset|getattr)>\ze\(' nextgroup=pythonFuncArgs
509
+  syn match pythonBuiltinFunc   '\v(\.)@<!\zs<(globals|hasattr|hash|hex|id)>\ze\(' nextgroup=pythonFuncArgs
510
+  syn match pythonBuiltinFunc   '\v(\.)@<!\zs<(input|int|isinstance)>\ze\(' nextgroup=pythonFuncArgs
511
+  syn match pythonBuiltinFunc   '\v(\.)@<!\zs<(issubclass|iter|len|list|locals|map|max)>\ze\(' nextgroup=pythonFuncArgs
512
+  syn match pythonBuiltinFunc   '\v(\.)@<!\zs<(min|next|object|oct|open|ord)>\ze\(' nextgroup=pythonFuncArgs
513
+  syn match pythonBuiltinFunc   '\v(\.)@<!\zs<(pow|property|range)>\ze\(' nextgroup=pythonFuncArgs
514
+  syn match pythonBuiltinFunc   '\v(\.)@<!\zs<(repr|reversed|round|set|setattr)>\ze\(' nextgroup=pythonFuncArgs
515
+  syn match pythonBuiltinFunc   '\v(\.)@<!\zs<(slice|sorted|staticmethod|str|sum|super|tuple)>\ze\(' nextgroup=pythonFuncArgs
516
+  syn match pythonBuiltinFunc   '\v(\.)@<!\zs<(type|vars|zip)>\ze\(' nextgroup=pythonFuncArgs
437 517
 endif
438 518
 
439 519
 "
@@ -442,39 +522,39 @@ endif
442 522
 
443 523
 if s:Enabled("g:python_highlight_exceptions")
444 524
   if s:Python2Syntax()
445
-    syn keyword pythonExClass	StandardError
525
+    syn keyword pythonExClass   StandardError nextgroup=pythonFuncArgs
446 526
   else
447
-    syn keyword pythonExClass	BlockingIOError ChildProcessError
448
-    syn keyword pythonExClass	ConnectionError BrokenPipeError
449
-    syn keyword pythonExClass	ConnectionAbortedError ConnectionRefusedError
450
-    syn keyword pythonExClass	ConnectionResetError FileExistsError
451
-    syn keyword pythonExClass	FileNotFoundError InterruptedError
452
-    syn keyword pythonExClass	IsADirectoryError NotADirectoryError
453
-    syn keyword pythonExClass	PermissionError ProcessLookupError TimeoutError
454
-
455
-    syn keyword pythonExClass	ResourceWarning
527
+    syn keyword pythonExClass   BlockingIOError ChildProcessError nextgroup=pythonFuncArgs
528
+    syn keyword pythonExClass   ConnectionError BrokenPipeError nextgroup=pythonFuncArgs
529
+    syn keyword pythonExClass   ConnectionAbortedError ConnectionRefusedError nextgroup=pythonFuncArgs
530
+    syn keyword pythonExClass   ConnectionResetError FileExistsError nextgroup=pythonFuncArgs
531
+    syn keyword pythonExClass   FileNotFoundError InterruptedError nextgroup=pythonFuncArgs
532
+    syn keyword pythonExClass   IsADirectoryError NotADirectoryError nextgroup=pythonFuncArgs
533
+    syn keyword pythonExClass   PermissionError ProcessLookupError TimeoutError nextgroup=pythonFuncArgs
534
+
535
+    syn keyword pythonExClass   ResourceWarning nextgroup=pythonFuncArgs
456 536
   endif
457
-  syn keyword pythonExClass	BaseException
458
-  syn keyword pythonExClass	Exception ArithmeticError
459
-  syn keyword pythonExClass	LookupError EnvironmentError
460
-
461
-  syn keyword pythonExClass	AssertionError AttributeError BufferError EOFError
462
-  syn keyword pythonExClass	FloatingPointError GeneratorExit IOError
463
-  syn keyword pythonExClass	ImportError IndexError KeyError
464
-  syn keyword pythonExClass	KeyboardInterrupt MemoryError NameError
465
-  syn keyword pythonExClass	NotImplementedError OSError OverflowError
466
-  syn keyword pythonExClass	ReferenceError RuntimeError StopIteration
467
-  syn keyword pythonExClass	SyntaxError IndentationError TabError
468
-  syn keyword pythonExClass	SystemError SystemExit TypeError
469
-  syn keyword pythonExClass	UnboundLocalError UnicodeError
470
-  syn keyword pythonExClass	UnicodeEncodeError UnicodeDecodeError
471
-  syn keyword pythonExClass	UnicodeTranslateError ValueError VMSError
472
-  syn keyword pythonExClass	WindowsError ZeroDivisionError
473
-
474
-  syn keyword pythonExClass	Warning UserWarning BytesWarning DeprecationWarning
475
-  syn keyword pythonExClass	PendingDepricationWarning SyntaxWarning
476
-  syn keyword pythonExClass	RuntimeWarning FutureWarning
477
-  syn keyword pythonExClass	ImportWarning UnicodeWarning
537
+  syn keyword pythonExClass     BaseException nextgroup=pythonFuncArgs
538
+  syn keyword pythonExClass     Exception ArithmeticError nextgroup=pythonFuncArgs
539
+  syn keyword pythonExClass     LookupError EnvironmentError nextgroup=pythonFuncArgs
540
+
541
+  syn keyword pythonExClass     AssertionError AttributeError BufferError EOFError nextgroup=pythonFuncArgs
542
+  syn keyword pythonExClass     FloatingPointError GeneratorExit IOError nextgroup=pythonFuncArgs
543
+  syn keyword pythonExClass     ImportError IndexError KeyError nextgroup=pythonFuncArgs
544
+  syn keyword pythonExClass     KeyboardInterrupt MemoryError NameError nextgroup=pythonFuncArgs
545
+  syn keyword pythonExClass     NotImplementedError OSError OverflowError nextgroup=pythonFuncArgs
546
+  syn keyword pythonExClass     ReferenceError RuntimeError StopIteration nextgroup=pythonFuncArgs
547
+  syn keyword pythonExClass     SyntaxError IndentationError TabError nextgroup=pythonFuncArgs
548
+  syn keyword pythonExClass     SystemError SystemExit TypeError nextgroup=pythonFuncArgs
549
+  syn keyword pythonExClass     UnboundLocalError UnicodeError nextgroup=pythonFuncArgs
550
+  syn keyword pythonExClass     UnicodeEncodeError UnicodeDecodeError nextgroup=pythonFuncArgs
551
+  syn keyword pythonExClass     UnicodeTranslateError ValueError VMSError nextgroup=pythonFuncArgs
552
+  syn keyword pythonExClass     WindowsError ZeroDivisionError nextgroup=pythonFuncArgs
553
+
554
+  syn keyword pythonExClass     Warning UserWarning BytesWarning DeprecationWarning nextgroup=pythonFuncArgs
555
+  syn keyword pythonExClass     PendingDepricationWarning SyntaxWarning nextgroup=pythonFuncArgs
556
+  syn keyword pythonExClass     RuntimeWarning FutureWarning nextgroup=pythonFuncArgs
557
+  syn keyword pythonExClass     ImportWarning UnicodeWarning nextgroup=pythonFuncArgs
478 558
 endif
479 559
 
480 560
 if s:Enabled("g:python_slow_sync")
@@ -496,6 +576,7 @@ if version >= 508 || !exists("did_python_syn_inits")
496 576
   endif
497 577
 
498 578
   HiLink pythonStatement        Statement
579
+  HiLink pythonLambdaExpr       Statement
499 580
   HiLink pythonImport           Include
500 581
   HiLink pythonFunction         Function
501 582
   HiLink pythonConditional      Conditional
@@ -536,6 +617,8 @@ if version >= 508 || !exists("did_python_syn_inits")
536 617
     HiLink pythonBytesError         Error
537 618
     HiLink pythonBytesEscape        Special
538 619
     HiLink pythonBytesEscapeError   Error
620
+    HiLink pythonFString            String
621
+    HiLink pythonStrInterpRegion    Special
539 622
   endif
540 623
 
541 624
   HiLink pythonStrFormatting    Special
@@ -555,14 +638,21 @@ if version >= 508 || !exists("did_python_syn_inits")
555 638
   HiLink pythonHexError         Error
556 639
   HiLink pythonBinError         Error
557 640
 
558
-  HiLink pythonBoolean          Boolean
559
-
560 641
   HiLink pythonBuiltinObj       Structure
561 642
   HiLink pythonBuiltinFunc      Function
562 643
 
563 644
   HiLink pythonExClass          Structure
564 645
 
646
+  HiLink pythonTypeAnno         Optional
647
+  HiLink pythonTypeUnion        Optional
648
+  HiLink pythonTypeAnnoReturn   Optional
649
+  HiLink pythonTypeArgs         Optional
650
+  HiLink pythonType             Special
651
+
565 652
   delcommand HiLink
653
+
654
+  " default style for custom highlight group (may be overriden in colors)
655
+  hi Optional gui=italic cterm=italic
566 656
 endif
567 657
 
568 658
 let b:current_syntax = "python"

+ 48
- 10
test.py View File

@@ -8,9 +8,12 @@
8 8
 
9 9
 # Keywords.
10 10
 
11
-with break continue del exec return pass print raise global assert lambda yield
11
+with break continue del exec return pass print raise global assert yield
12 12
 for while if elif else import from as try except finally and in is not or
13 13
 
14
+lambda: a + 1
15
+lambda x, y: x + y
16
+
14 17
 yield from
15 18
 
16 19
 def functionname
@@ -23,19 +26,48 @@ async def Test
23 26
 async with
24 27
 async for
25 28
 
29
+# Type annotations
30
+
31
+def myfunc(a: str, something_other,
32
+           b: Callable[[str, str], int],
33
+           c: mypkg.MyType) -> 'runtime_resolved_type':
34
+    myval: float
35
+    mygood: Optional[int, Any] = b('wow', 'oops')
36
+    myarr: Sequence[int] = origarr[aa:bb] + (lambda: x)()
37
+    mykey = a
38
+    wow = {
39
+        mykey: this_should_not_be_type_anno[Any],
40
+        'b': some_data,
41
+    }
42
+    call_with_dict(a={
43
+        'a': asdf,
44
+        'b': 'zxcb',
45
+        mykey: this_should_not_be_type_anno[Any],
46
+    }, b=mydata['a'])
47
+    vanilla_lambda = lambda x, y: myval + 1.0
48
+    call_with_lambda(lambda x, y: myval + 1.0)
49
+    call_with_slice(mydata[range_start:range_end])
50
+
51
+
26 52
 # Builtin objects.
27 53
 
28 54
 True False Ellipsis None NotImplemented
29 55
 
30 56
 # Builtin function and types.
31 57
 
32
-__import__ abs all any apply basestring bool buffer callable chr classmethod
33
-cmp coerce compile complex delattr dict dir divmod enumerate eval execfile file
34
-filter float frozenset getattr globals hasattr hash help hex id input int
35
-intern isinstance issubclass iter len list locals long map max min object oct
36
-open ord pow property range raw_input reduce reload repr reversed round set
37
-setattr slice sorted staticmethod str sum super tuple type unichr unicode vars
38
-xrange zip
58
+__import__() abs() all() any() apply() basestring() bool() buffer() callable() chr() classmethod()
59
+cmp() coerce() compile() complex() delattr() dict() dir() divmod() enumerate() eval() execfile() file()
60
+filter() float() frozenset() getattr() globals() hasattr() hash() help() hex() id() input() int()
61
+intern() isinstance() issubclass() iter() len() list() locals() long() map() max() min() object() oct()
62
+open() ord() pow() property() range() raw_input() reduce() reload() repr() reversed() round() set()
63
+setattr() slice() sorted() staticmethod() str() sum() super() tuple() type() unichr() unicode() vars()
64
+xrange() zip()
65
+
66
+when_we_dont_call = a.float
67
+float = when_we_dont_call
68
+
69
+when_we_call = float(x)
70
+when_we_call = min(a, b)
39 71
 
40 72
 # Builtin exceptions and warnings.
41 73
 
@@ -61,11 +93,13 @@ RuntimeWarning FutureWarning ImportWarning UnicodeWarning
61 93
 
62 94
 # Numbers
63 95
 
64
-0 1 2 9 10 0x1f .3 12.34 0j 0j 34.2E-3 0b10 0o77 1023434 0x0
96
+0 1 2 9 10 0x1f .3 12.34 0j 124j 34.2E-3 0b10 0o77 1023434 0x0
97
+1_1 1_1.2_2 1_2j 0x_1f 0x1_f 34_56e-3 34_56e+3_1 0o7_7
65 98
 
66 99
 # Erroneous numbers
67 100
 
68
-077 100L 0xfffffffL 0L 08 0xk 0x  0b102 0o78 0o123LaB
101
+077 100L 0xfffffffL 0L 08 0xk 0x 0b102 0o78 0o123LaB
102
+0_ 0_1 0_x1f 0x1f_ 0_b77 0b77_ .2_ 1_j
69 103
 
70 104
 # Strings
71 105
 
@@ -103,6 +137,10 @@ b"{0.name!r:b} {0[n]} {name!s:  } {{test}} {{}} {} {.__len__:s}"
103 137
 "${test} ${test ${test}aname $$$ $test+nope"
104 138
 b"${test} ${test ${test}aname $$$ $test+nope"
105 139
 
140
+f"{var}...{arr[123]} normal {var['{'] // 0xff} \"xzcb\" 'xzcb' {var['}'] + 1} text"
141
+f"{expr1 if True or False else expr2} wow {','.join(c.lower() for c in 'asdf')}"
142
+f"hello {expr:.2f} yes {(lambda: 0b1)():#03x} lol {var!r}"
143
+
106 144
 # Doctests.
107 145
 
108 146
 """