rapydscript-ng 0.7.23 → 0.8.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +24 -0
- package/README.md +72 -26
- package/bin/package.json +1 -0
- package/bin/rapydscript +65 -62
- package/editor-plugins/nvim/rapydscript/README.md +184 -0
- package/editor-plugins/nvim/rapydscript/bin/rapydscript.so +0 -0
- package/editor-plugins/nvim/rapydscript/ftdetect/rapydscript.lua +10 -0
- package/editor-plugins/nvim/rapydscript/lua/rapydscript/health.lua +88 -0
- package/editor-plugins/nvim/rapydscript/lua/rapydscript/init.lua +279 -0
- package/local-agent.md +28 -0
- package/package.json +4 -5
- package/release/baselib-plain-pretty.js +448 -326
- package/release/baselib-plain-ugly.js +3 -3
- package/release/compiler.js +2528 -1672
- package/release/signatures.json +17 -17
- package/src/ast.pyj +73 -25
- package/src/baselib-builtins.pyj +2 -2
- package/src/baselib-containers.pyj +153 -151
- package/src/baselib-internal.pyj +3 -3
- package/src/baselib-str.pyj +5 -5
- package/src/lib/aes.pyj +1 -1
- package/src/lib/encodings.pyj +1 -1
- package/src/lib/pythonize.pyj +1 -1
- package/src/lib/re.pyj +2 -2
- package/src/lib/traceback.pyj +165 -28
- package/src/lib/uuid.pyj +1 -1
- package/src/output/codegen.pyj +10 -3
- package/src/output/functions.pyj +31 -40
- package/src/output/literals.pyj +11 -14
- package/src/output/loops.pyj +25 -87
- package/src/output/modules.pyj +5 -47
- package/src/output/statements.pyj +1 -1
- package/src/output/stream.pyj +58 -31
- package/src/parse.pyj +777 -427
- package/src/tokenizer.pyj +16 -4
- package/src/utils.pyj +1 -1
- package/test/_treeshake_mod.pyj +30 -0
- package/test/_treeshake_side_effect.pyj +9 -0
- package/test/ast_serialization.pyj +392 -0
- package/test/async.pyj +95 -0
- package/test/baselib.pyj +1 -2
- package/test/embedded_compiler.pyj +57 -0
- package/test/fmt.pyj +201 -0
- package/test/generic.pyj +7 -3
- package/test/imports.pyj +8 -6
- package/test/internationalization.pyj +38 -37
- package/test/lint.pyj +120 -115
- package/test/lsp.pyj +222 -0
- package/test/repl.pyj +70 -65
- package/test/sourcemaps.pyj +315 -0
- package/test/starargs.pyj +46 -39
- package/test/traceback.pyj +263 -0
- package/test/treeshaking.pyj +181 -0
- package/test/web_repl_export.pyj +88 -0
- package/tools/ast_serialize.mjs +557 -0
- package/tools/cli.mjs +510 -0
- package/tools/compile.mjs +201 -0
- package/tools/compiler.mjs +127 -0
- package/tools/{completer.js → completer.mjs} +6 -6
- package/tools/{embedded_compiler.js → embedded_compiler.mjs} +17 -13
- package/tools/export.js +109 -56
- package/tools/fmt.mjs +735 -0
- package/tools/{gettext.js → gettext.mjs} +46 -53
- package/tools/{ini.js → ini.mjs} +9 -10
- package/tools/{lint.js → lint.mjs} +107 -56
- package/tools/lsp.mjs +914 -0
- package/tools/lsp_protocol.mjs +259 -0
- package/tools/lsp_symbols.mjs +418 -0
- package/tools/{msgfmt.js → msgfmt.mjs} +18 -18
- package/tools/{repl.js → repl.mjs} +52 -41
- package/tools/{self.js → self.mjs} +56 -46
- package/tools/sourcemap.mjs +123 -0
- package/tools/test.mjs +152 -0
- package/tools/treeshake.mjs +400 -0
- package/tools/{utils.js → utils.mjs} +26 -23
- package/tools/{web_repl.js → web_repl.mjs} +15 -13
- package/tools/web_repl_export.mjs +93 -0
- package/tree-sitter/README.md +101 -0
- package/tree-sitter/grammar.js +992 -0
- package/tree-sitter/package.json +43 -0
- package/tree-sitter/queries/rapydscript/highlights.scm +232 -0
- package/tree-sitter/queries/rapydscript/indents.scm +64 -0
- package/tree-sitter/queries/rapydscript/injections.scm +14 -0
- package/tree-sitter/queries/rapydscript/locals.scm +108 -0
- package/tree-sitter/src/grammar.json +4976 -0
- package/tree-sitter/src/node-types.json +2901 -0
- package/tree-sitter/src/parser.c +196465 -0
- package/tree-sitter/src/scanner.c +294 -0
- package/tree-sitter/src/tree_sitter/alloc.h +54 -0
- package/tree-sitter/src/tree_sitter/array.h +330 -0
- package/tree-sitter/src/tree_sitter/parser.h +286 -0
- package/tree-sitter/test/corpus/chaining.txt +99 -0
- package/tree-sitter/test/corpus/classes.txt +147 -0
- package/tree-sitter/test/corpus/comprehensions.txt +155 -0
- package/tree-sitter/test/corpus/containers.txt +242 -0
- package/tree-sitter/test/corpus/control_flow.txt +361 -0
- package/tree-sitter/test/corpus/decorators.txt +64 -0
- package/tree-sitter/test/corpus/existential.txt +102 -0
- package/tree-sitter/test/corpus/functions.txt +293 -0
- package/tree-sitter/test/corpus/imports.txt +117 -0
- package/tree-sitter/test/corpus/literals.txt +135 -0
- package/tree-sitter/test/corpus/operators.txt +296 -0
- package/tree-sitter/test/corpus/statements.txt +189 -0
- package/tree-sitter/test/corpus/strings.txt +90 -0
- package/tree-sitter/test/corpus/subscripts.txt +227 -0
- package/tree-sitter/tree-sitter.json +36 -0
- package/web-repl/env.js +35 -23
- package/web-repl/main.js +8 -8
- package/bin/export +0 -75
- package/bin/web-repl-export +0 -102
- package/tools/cli.js +0 -523
- package/tools/compile.js +0 -184
- package/tools/compiler.js +0 -84
- package/tools/test.js +0 -110
package/src/parse.pyj
CHANGED
|
@@ -1,13 +1,13 @@
|
|
|
1
1
|
# vim:fileencoding=utf-8
|
|
2
2
|
# License: BSD Copyright: 2016, Kovid Goyal <kovid at kovidgoyal.net>
|
|
3
|
-
# globals: readfile
|
|
3
|
+
# globals: readfile, writefile, stat_file, sha1sum, ast_from_json, ast_to_json, make_lazy_ast_module, decode_cache, encode_cache
|
|
4
4
|
from __python__ import hash_literals
|
|
5
5
|
|
|
6
6
|
from utils import make_predicate, array_to_hash, defaults, has_prop, cache_file_name
|
|
7
7
|
from errors import SyntaxError, ImportError
|
|
8
8
|
from ast import (
|
|
9
|
-
AST_Array, AST_Assign, AST_Binary, AST_BlockStatement, AST_Break,
|
|
10
|
-
AST_Call, AST_Catch, AST_Class, AST_ClassCall, AST_Conditional,
|
|
9
|
+
AST_ArgsDef, AST_Array, AST_Assign, AST_Binary, AST_BlockStatement, AST_Break,
|
|
10
|
+
AST_Call, AST_CallArg, AST_CallArgs, AST_Catch, AST_Class, AST_ClassCall, AST_Conditional,
|
|
11
11
|
AST_Constant, AST_Continue, AST_DWLoop, AST_Debugger, AST_Decorator,
|
|
12
12
|
AST_Definitions, AST_DictComprehension, AST_Directive, AST_Do, AST_Dot,
|
|
13
13
|
AST_Else, AST_EmptyStatement, AST_Except, AST_ExpressiveObject, AST_False, AST_Finally,
|
|
@@ -21,13 +21,14 @@ AST_SymbolCatch, AST_SymbolDefun, AST_SymbolFunarg,
|
|
|
21
21
|
AST_SymbolLambda, AST_SymbolNonlocal, AST_SymbolRef, AST_SymbolVar, AST_This,
|
|
22
22
|
AST_Throw, AST_Toplevel, AST_True, AST_Try, AST_UnaryPrefix,
|
|
23
23
|
AST_Undefined, AST_Var, AST_VarDef, AST_Verbatim, AST_While, AST_With, AST_WithClause,
|
|
24
|
-
AST_Yield, AST_Assert, AST_Existential, is_node_type
|
|
24
|
+
AST_Yield, AST_Await, AST_Assert, AST_Existential, is_node_type, TreeWalker
|
|
25
25
|
)
|
|
26
26
|
from tokenizer import tokenizer, is_token, RESERVED_WORDS
|
|
27
27
|
|
|
28
28
|
|
|
29
29
|
COMPILER_VERSION = '__COMPILER_VERSION__'
|
|
30
30
|
PYTHON_FLAGS = {'dict_literals':True, 'overload_getitem':True, 'bound_methods':True, 'hash_literals':True}
|
|
31
|
+
CACHE_VERSION = 1
|
|
31
32
|
|
|
32
33
|
|
|
33
34
|
def get_compiler_version():
|
|
@@ -208,6 +209,41 @@ def create_parser_ctx(S, import_dirs, module_id, baselib_items, imported_module_
|
|
|
208
209
|
token = S.token
|
|
209
210
|
token_error(token, "Unexpected token: " + token.type + " «" + token.value + "»")
|
|
210
211
|
|
|
212
|
+
# --- Error recovery (only active when options.recover_errors is True) --------
|
|
213
|
+
# These helpers let the LSP obtain a usable AST from a file that contains
|
|
214
|
+
# syntax errors. They are never invoked on the normal compile path, so they
|
|
215
|
+
# cannot introduce a performance or behavior regression there.
|
|
216
|
+
|
|
217
|
+
def is_recoverable_error(e):
|
|
218
|
+
return v'e instanceof SyntaxError'
|
|
219
|
+
|
|
220
|
+
def record_recovery(e):
|
|
221
|
+
S.recovered_errors.push({
|
|
222
|
+
'message': e.message, 'line': e.line, 'col': e.col, 'pos': e.pos,
|
|
223
|
+
'endpos': e.endpos, 'is_eof': e.is_eof,
|
|
224
|
+
})
|
|
225
|
+
|
|
226
|
+
async def skip_to_recovery_point():
|
|
227
|
+
# Resynchronize after a syntax error: always consume at least one token
|
|
228
|
+
# (guaranteeing forward progress) then stop at the start of the next
|
|
229
|
+
# logical line, a block dedent, or eof. next() may itself raise a
|
|
230
|
+
# tokenizer level SyntaxError (e.g. an unterminated string on the skipped
|
|
231
|
+
# line); such errors are recorded and skipping continues. The tokenizer
|
|
232
|
+
# advances its position for every such error (and never raises for an
|
|
233
|
+
# unexpected character in recover mode), so this loop always terminates.
|
|
234
|
+
while not is_("eof"):
|
|
235
|
+
try:
|
|
236
|
+
next()
|
|
237
|
+
except as e:
|
|
238
|
+
if is_recoverable_error(e):
|
|
239
|
+
record_recovery(e)
|
|
240
|
+
if is_("eof"):
|
|
241
|
+
return
|
|
242
|
+
continue
|
|
243
|
+
raise
|
|
244
|
+
if is_("eof") or is_("punc", "}") or S.token.nlb:
|
|
245
|
+
return
|
|
246
|
+
|
|
211
247
|
def expect_token(type, val):
|
|
212
248
|
if is_(type, val):
|
|
213
249
|
return next()
|
|
@@ -223,9 +259,9 @@ def create_parser_ctx(S, import_dirs, module_id, baselib_items, imported_module_
|
|
|
223
259
|
S.token.nlb = True
|
|
224
260
|
|
|
225
261
|
def embed_tokens(parser):
|
|
226
|
-
def with_embedded_tokens():
|
|
262
|
+
async def with_embedded_tokens():
|
|
227
263
|
start = S.token
|
|
228
|
-
expr = parser()
|
|
264
|
+
expr = await parser()
|
|
229
265
|
if expr is undefined:
|
|
230
266
|
unexpected()
|
|
231
267
|
end = prev()
|
|
@@ -404,7 +440,7 @@ def create_parser_ctx(S, import_dirs, module_id, baselib_items, imported_module_
|
|
|
404
440
|
|
|
405
441
|
return vars
|
|
406
442
|
|
|
407
|
-
def return_():
|
|
443
|
+
async def return_():
|
|
408
444
|
if is_('punc', ';'):
|
|
409
445
|
semicolon()
|
|
410
446
|
value = None
|
|
@@ -413,12 +449,12 @@ def create_parser_ctx(S, import_dirs, module_id, baselib_items, imported_module_
|
|
|
413
449
|
if is_end_of_statement:
|
|
414
450
|
value = None
|
|
415
451
|
else:
|
|
416
|
-
value = expression(True)
|
|
452
|
+
value = await expression(True)
|
|
417
453
|
semicolon()
|
|
418
454
|
return value
|
|
419
455
|
|
|
420
456
|
@embed_tokens
|
|
421
|
-
def statement():
|
|
457
|
+
async def statement():
|
|
422
458
|
# From Kovid: The next three lines were a hack to try to support statements
|
|
423
459
|
# starting with a regexp literal. However, it did not work, for example:
|
|
424
460
|
# echo 'f=1\n/asd/.test()' | rs -> parse error
|
|
@@ -434,7 +470,7 @@ def create_parser_ctx(S, import_dirs, module_id, baselib_items, imported_module_
|
|
|
434
470
|
if p and not S.token.nlb and ATOMIC_START_TOKEN[p.type] and not is_('punc', ':'):
|
|
435
471
|
unexpected()
|
|
436
472
|
if tmp_ is "string":
|
|
437
|
-
return simple_statement()
|
|
473
|
+
return await simple_statement()
|
|
438
474
|
elif tmp_ is "shebang":
|
|
439
475
|
tmp_ = S.token.value
|
|
440
476
|
next()
|
|
@@ -442,17 +478,18 @@ def create_parser_ctx(S, import_dirs, module_id, baselib_items, imported_module_
|
|
|
442
478
|
'value': tmp_
|
|
443
479
|
})
|
|
444
480
|
elif tmp_ is "num" or tmp_ is "regexp" or tmp_ is "operator" or tmp_ is "atom" or tmp_ is "js":
|
|
445
|
-
return simple_statement()
|
|
481
|
+
return await simple_statement()
|
|
446
482
|
elif tmp_ is "punc":
|
|
447
483
|
tmp_ = S.token.value
|
|
448
484
|
if tmp_ is ":":
|
|
485
|
+
bs_body = await block_()
|
|
449
486
|
return new AST_BlockStatement({
|
|
450
487
|
'start': S.token,
|
|
451
|
-
'body':
|
|
488
|
+
'body': bs_body,
|
|
452
489
|
'end': prev()
|
|
453
490
|
})
|
|
454
491
|
elif tmp_ is "{" or tmp_ is "[" or tmp_ is "(":
|
|
455
|
-
return simple_statement()
|
|
492
|
+
return await simple_statement()
|
|
456
493
|
elif tmp_ is ";":
|
|
457
494
|
next()
|
|
458
495
|
return new AST_EmptyStatement({'stype':';', 'start':prev(), 'end':prev()})
|
|
@@ -460,7 +497,7 @@ def create_parser_ctx(S, import_dirs, module_id, baselib_items, imported_module_
|
|
|
460
497
|
unexpected()
|
|
461
498
|
elif tmp_ is "name":
|
|
462
499
|
if (is_token(peek(), 'punc', ':')) token_error(peek(), 'invalid syntax, colon not allowed here')
|
|
463
|
-
return simple_statement()
|
|
500
|
+
return await simple_statement()
|
|
464
501
|
elif tmp_ is "keyword":
|
|
465
502
|
tmp_ = S.token.value
|
|
466
503
|
next()
|
|
@@ -472,44 +509,64 @@ def create_parser_ctx(S, import_dirs, module_id, baselib_items, imported_module_
|
|
|
472
509
|
semicolon()
|
|
473
510
|
return new AST_Debugger()
|
|
474
511
|
elif tmp_ is "do":
|
|
512
|
+
do_body = await in_loop(statement)
|
|
513
|
+
do_cond = await (async def():
|
|
514
|
+
expect(".")
|
|
515
|
+
expect_token("keyword", "while")
|
|
516
|
+
tmp = await expression(True)
|
|
517
|
+
if is_node_type(tmp, AST_Assign):
|
|
518
|
+
croak('Assignments in do loop conditions are not allowed')
|
|
519
|
+
semicolon()
|
|
520
|
+
return tmp
|
|
521
|
+
)()
|
|
475
522
|
return new AST_Do({
|
|
476
|
-
'body':
|
|
477
|
-
'condition':
|
|
478
|
-
expect(".")
|
|
479
|
-
expect_token("keyword", "while")
|
|
480
|
-
tmp = expression(True)
|
|
481
|
-
if is_node_type(tmp, AST_Assign):
|
|
482
|
-
croak('Assignments in do loop conditions are not allowed')
|
|
483
|
-
semicolon()
|
|
484
|
-
return tmp
|
|
485
|
-
)()
|
|
523
|
+
'body': do_body,
|
|
524
|
+
'condition': do_cond,
|
|
486
525
|
})
|
|
487
526
|
elif tmp_ is "while":
|
|
488
|
-
while_cond = expression(True)
|
|
527
|
+
while_cond = await expression(True)
|
|
489
528
|
if is_node_type(while_cond, AST_Assign):
|
|
490
529
|
croak('Assignments in while loop conditions are not allowed')
|
|
491
530
|
if not is_('punc', ':'):
|
|
492
531
|
croak('Expected a colon after the while statement')
|
|
532
|
+
while_body = await in_loop(statement)
|
|
493
533
|
return new AST_While({
|
|
494
534
|
'condition': while_cond,
|
|
495
|
-
'body':
|
|
535
|
+
'body': while_body
|
|
496
536
|
})
|
|
497
537
|
elif tmp_ is "for":
|
|
498
538
|
if is_('js'):
|
|
499
|
-
return for_js()
|
|
500
|
-
return for_()
|
|
539
|
+
return await for_js()
|
|
540
|
+
return await for_()
|
|
501
541
|
elif tmp_ is "from":
|
|
502
|
-
return import_(True)
|
|
542
|
+
return await import_(True)
|
|
503
543
|
elif tmp_ is "import":
|
|
504
|
-
return import_(False)
|
|
544
|
+
return await import_(False)
|
|
505
545
|
elif tmp_ is "class":
|
|
506
|
-
return class_()
|
|
546
|
+
return await class_()
|
|
547
|
+
elif tmp_ is "async":
|
|
548
|
+
if not is_('keyword', 'def'):
|
|
549
|
+
croak("Expected 'def' after 'async'")
|
|
550
|
+
next()
|
|
551
|
+
start = prev()
|
|
552
|
+
func = await function_(S.in_class[-1], False, True)
|
|
553
|
+
func.start = start
|
|
554
|
+
func.end = prev()
|
|
555
|
+
chain = await subscripts(func, True)
|
|
556
|
+
if chain is func:
|
|
557
|
+
return func
|
|
558
|
+
else:
|
|
559
|
+
return new AST_SimpleStatement({
|
|
560
|
+
'start': start,
|
|
561
|
+
'body': chain,
|
|
562
|
+
'end': prev()
|
|
563
|
+
})
|
|
507
564
|
elif tmp_ is "def":
|
|
508
565
|
start = prev()
|
|
509
|
-
func = function_(S.in_class[-1], False)
|
|
566
|
+
func = await function_(S.in_class[-1], False)
|
|
510
567
|
func.start = start
|
|
511
568
|
func.end = prev()
|
|
512
|
-
chain = subscripts(func, True)
|
|
569
|
+
chain = await subscripts(func, True)
|
|
513
570
|
if chain is func:
|
|
514
571
|
return func
|
|
515
572
|
else:
|
|
@@ -520,14 +577,14 @@ def create_parser_ctx(S, import_dirs, module_id, baselib_items, imported_module_
|
|
|
520
577
|
})
|
|
521
578
|
elif tmp_ is 'assert':
|
|
522
579
|
start = prev()
|
|
523
|
-
cond = expression(False)
|
|
580
|
+
cond = await expression(False)
|
|
524
581
|
msg = None
|
|
525
582
|
if is_('punc', ','):
|
|
526
583
|
next()
|
|
527
|
-
msg = expression(False)
|
|
584
|
+
msg = await expression(False)
|
|
528
585
|
return new AST_Assert({'start': start, 'condition':cond, 'message':msg, 'end':prev()})
|
|
529
586
|
elif tmp_ is "if":
|
|
530
|
-
return if_()
|
|
587
|
+
return await if_()
|
|
531
588
|
elif tmp_ is "pass":
|
|
532
589
|
semicolon()
|
|
533
590
|
return new AST_EmptyStatement({'stype':'pass', 'start':prev(), 'end':prev()})
|
|
@@ -538,9 +595,17 @@ def create_parser_ctx(S, import_dirs, module_id, baselib_items, imported_module_
|
|
|
538
595
|
croak("'return' not allowed in a function with yield")
|
|
539
596
|
S.functions[-1].is_generator = False
|
|
540
597
|
|
|
541
|
-
|
|
598
|
+
ret_val = await return_()
|
|
599
|
+
return new AST_Return({'value':ret_val})
|
|
600
|
+
elif tmp_ is "await":
|
|
601
|
+
if S.in_function is 0 or not S.functions[-1].is_async:
|
|
602
|
+
croak("'await' outside of async function")
|
|
603
|
+
value = await expr_atom(True)
|
|
604
|
+
node = new AST_Await({'value': value})
|
|
605
|
+
semicolon()
|
|
606
|
+
return new AST_SimpleStatement({'body': node})
|
|
542
607
|
elif tmp_ is "yield":
|
|
543
|
-
return yield_()
|
|
608
|
+
return await yield_()
|
|
544
609
|
elif tmp_ is "raise":
|
|
545
610
|
if S.token.nlb:
|
|
546
611
|
return new AST_Throw({
|
|
@@ -549,33 +614,33 @@ def create_parser_ctx(S, import_dirs, module_id, baselib_items, imported_module_
|
|
|
549
614
|
})
|
|
550
615
|
})
|
|
551
616
|
|
|
552
|
-
tmp = expression(True)
|
|
617
|
+
tmp = await expression(True)
|
|
553
618
|
semicolon()
|
|
554
619
|
return new AST_Throw({
|
|
555
620
|
'value': tmp
|
|
556
621
|
})
|
|
557
622
|
elif tmp_ is "try":
|
|
558
|
-
return try_()
|
|
623
|
+
return await try_()
|
|
559
624
|
elif tmp_ is "nonlocal":
|
|
560
|
-
tmp = nonlocal_()
|
|
625
|
+
tmp = await nonlocal_()
|
|
561
626
|
semicolon()
|
|
562
627
|
return tmp
|
|
563
628
|
elif tmp_ is 'global':
|
|
564
|
-
tmp = nonlocal_(True)
|
|
629
|
+
tmp = await nonlocal_(True)
|
|
565
630
|
semicolon()
|
|
566
631
|
return tmp
|
|
567
632
|
elif tmp_ is "with":
|
|
568
|
-
return with_()
|
|
633
|
+
return await with_()
|
|
569
634
|
else:
|
|
570
635
|
unexpected()
|
|
571
636
|
|
|
572
|
-
def with_():
|
|
637
|
+
async def with_():
|
|
573
638
|
clauses = v'[]'
|
|
574
639
|
start = S.token
|
|
575
640
|
while True:
|
|
576
641
|
if is_('eof'):
|
|
577
642
|
unexpected()
|
|
578
|
-
expr = expression()
|
|
643
|
+
expr = await expression()
|
|
579
644
|
alias = None
|
|
580
645
|
if is_('keyword', 'as'):
|
|
581
646
|
next()
|
|
@@ -590,15 +655,15 @@ def create_parser_ctx(S, import_dirs, module_id, baselib_items, imported_module_
|
|
|
590
655
|
|
|
591
656
|
if not clauses.length:
|
|
592
657
|
token_error(start, 'with statement must have at least one clause')
|
|
593
|
-
body = statement()
|
|
658
|
+
body = await statement()
|
|
594
659
|
|
|
595
660
|
return new AST_With({
|
|
596
661
|
'clauses': clauses,
|
|
597
662
|
'body': body
|
|
598
663
|
})
|
|
599
664
|
|
|
600
|
-
def simple_statement(tmp):
|
|
601
|
-
tmp = expression(True)
|
|
665
|
+
async def simple_statement(tmp):
|
|
666
|
+
tmp = await expression(True)
|
|
602
667
|
semicolon()
|
|
603
668
|
return new AST_SimpleStatement({
|
|
604
669
|
'body': tmp
|
|
@@ -610,22 +675,25 @@ def create_parser_ctx(S, import_dirs, module_id, baselib_items, imported_module_
|
|
|
610
675
|
semicolon()
|
|
611
676
|
return new t()
|
|
612
677
|
|
|
613
|
-
def yield_():
|
|
678
|
+
async def yield_():
|
|
614
679
|
if S.in_function is 0:
|
|
615
680
|
croak("'yield' outside of function")
|
|
681
|
+
if S.functions[-1].is_async:
|
|
682
|
+
croak("'yield' not allowed in an async function")
|
|
616
683
|
if S.functions[-1].is_generator is False:
|
|
617
684
|
croak("'yield' not allowed in a function with return")
|
|
618
685
|
S.functions[-1].is_generator = True
|
|
619
686
|
is_yield_from = is_('keyword', 'from')
|
|
620
687
|
if is_yield_from:
|
|
621
688
|
next()
|
|
622
|
-
|
|
689
|
+
yld_val = await return_()
|
|
690
|
+
return new AST_Yield({'is_yield_from':is_yield_from, 'value': yld_val})
|
|
623
691
|
|
|
624
|
-
def for_(list_comp):
|
|
692
|
+
async def for_(list_comp):
|
|
625
693
|
# expect("(")
|
|
626
694
|
init = None
|
|
627
695
|
if not is_("punc", ";"):
|
|
628
|
-
init = expression(True, True)
|
|
696
|
+
init = await expression(True, True)
|
|
629
697
|
# standardize AST_Seq into array now for consistency
|
|
630
698
|
if is_node_type(init, AST_Seq):
|
|
631
699
|
if is_node_type(init.car, AST_SymbolRef) and is_node_type(init.cdr, AST_SymbolRef):
|
|
@@ -643,13 +711,13 @@ def create_parser_ctx(S, import_dirs, module_id, baselib_items, imported_module_
|
|
|
643
711
|
if is_node_type(init, AST_Var) and init.definitions.length > 1:
|
|
644
712
|
croak("Only one variable declaration allowed in for..in loop")
|
|
645
713
|
next()
|
|
646
|
-
return for_in(init, list_comp)
|
|
714
|
+
return await for_in(init, list_comp)
|
|
647
715
|
|
|
648
716
|
unexpected()
|
|
649
717
|
|
|
650
|
-
def for_in(init, list_comp):
|
|
718
|
+
async def for_in(init, list_comp):
|
|
651
719
|
lhs = init.definitions[0].name if is_node_type(init, AST_Var) else None
|
|
652
|
-
obj = expression(True)
|
|
720
|
+
obj = await expression(True)
|
|
653
721
|
# expect(")")
|
|
654
722
|
if list_comp:
|
|
655
723
|
return {
|
|
@@ -658,19 +726,21 @@ def create_parser_ctx(S, import_dirs, module_id, baselib_items, imported_module_
|
|
|
658
726
|
'object': obj
|
|
659
727
|
}
|
|
660
728
|
|
|
729
|
+
fi_body = await in_loop(statement)
|
|
661
730
|
return new AST_ForIn({
|
|
662
731
|
'init': init,
|
|
663
732
|
'name': lhs,
|
|
664
733
|
'object': obj,
|
|
665
|
-
'body':
|
|
734
|
+
'body': fi_body
|
|
666
735
|
})
|
|
667
736
|
|
|
668
737
|
# A native JavaScript for loop - for v"var i=0; i<5000; i++":
|
|
669
|
-
def for_js():
|
|
738
|
+
async def for_js():
|
|
670
739
|
condition = as_atom_node()
|
|
740
|
+
fj_body = await in_loop(statement)
|
|
671
741
|
return new AST_ForJS({
|
|
672
742
|
'condition': condition,
|
|
673
|
-
'body':
|
|
743
|
+
'body': fj_body
|
|
674
744
|
})
|
|
675
745
|
|
|
676
746
|
# scan function/class body for nested class declarations
|
|
@@ -712,72 +782,144 @@ def create_parser_ctx(S, import_dirs, module_id, baselib_items, imported_module_
|
|
|
712
782
|
ctx = S.input.context()
|
|
713
783
|
raise new ImportError(message, ctx.filename, ctx.tokline, ctx.tokcol, ctx.tokpos)
|
|
714
784
|
|
|
715
|
-
def do_import(key):
|
|
785
|
+
async def do_import(key):
|
|
716
786
|
if has_prop(imported_modules, key):
|
|
717
787
|
return
|
|
788
|
+
# Circular import check must come BEFORE loading_promises so we detect cycles
|
|
789
|
+
# even when the same module is being loaded by a parallel chain.
|
|
718
790
|
if has_prop(importing_modules, key) and importing_modules[key]:
|
|
719
791
|
import_error('Detected a recursive import of: ' + key + ' while importing: ' + module_id)
|
|
792
|
+
# If a parallel chain is already loading this module, wait for it instead of
|
|
793
|
+
# starting a duplicate load. loading_promises is shared across the entire
|
|
794
|
+
# compilation via options.loading_promises.
|
|
795
|
+
loading_promises = options.loading_promises
|
|
796
|
+
if has_prop(loading_promises, key):
|
|
797
|
+
await loading_promises[key]
|
|
798
|
+
return
|
|
720
799
|
|
|
721
|
-
#
|
|
722
|
-
|
|
723
|
-
|
|
724
|
-
|
|
800
|
+
# Register this load BEFORE the first await so that any parallel caller
|
|
801
|
+
# that reaches this point sees the in-progress entry and waits.
|
|
802
|
+
# Use a single-element list to capture the resolve function from the Promise
|
|
803
|
+
# executor without needing nonlocal (mutating a container, not rebinding).
|
|
804
|
+
_rfn = v'[null]'
|
|
805
|
+
def _capture_resolve(resolve):
|
|
806
|
+
_rfn[0] = resolve
|
|
807
|
+
loading_promises[key] = new Promise(_capture_resolve)
|
|
725
808
|
|
|
726
|
-
|
|
727
|
-
|
|
728
|
-
|
|
729
|
-
|
|
809
|
+
try:
|
|
810
|
+
# Ensure that the package containing this module is also imported
|
|
811
|
+
package_module_id = key.split('.')[:-1].join('.')
|
|
812
|
+
if len(package_module_id) > 0:
|
|
813
|
+
await do_import(package_module_id)
|
|
814
|
+
|
|
815
|
+
if options.for_linting:
|
|
816
|
+
imported_modules[key] = {'is_cached':True, 'classes':{}, 'module_id':key, 'exports':[],
|
|
817
|
+
'nonlocalvars':[], 'baselib':{}, 'outputs':{}, 'discard_asserts':options.discard_asserts}
|
|
818
|
+
return
|
|
730
819
|
|
|
731
|
-
|
|
732
|
-
|
|
733
|
-
|
|
734
|
-
|
|
735
|
-
|
|
736
|
-
|
|
820
|
+
# stat_file returns {mtimeMs, content?}. For real filesystems mtimeMs is a
|
|
821
|
+
# number and content is absent; for virtual filesystems content holds the
|
|
822
|
+
# already-read source to avoid a double read.
|
|
823
|
+
async def safe_stat(base_path): # noqa
|
|
824
|
+
for i, path in enumerate([base_path + '.pyj', base_path + '/__init__.pyj']):
|
|
825
|
+
try:
|
|
826
|
+
st = await stat_file(path)
|
|
827
|
+
return [st.mtimeMs, path, st.content if has_prop(st, 'content') else None]
|
|
828
|
+
except as e:
|
|
829
|
+
if e.code is 'ENOENT' or e.code is 'EPERM' or e.code is 'EACCESS':
|
|
830
|
+
if i is 1:
|
|
831
|
+
return None, None, None
|
|
737
832
|
if i is 1:
|
|
738
|
-
|
|
739
|
-
if i is 1:
|
|
740
|
-
raise
|
|
833
|
+
raise
|
|
741
834
|
|
|
742
|
-
|
|
743
|
-
|
|
835
|
+
file_mtime = filename = prefetched_src = None
|
|
836
|
+
modpath = key.replace(/\./g, '/')
|
|
744
837
|
|
|
745
|
-
|
|
746
|
-
|
|
747
|
-
|
|
748
|
-
|
|
749
|
-
|
|
750
|
-
|
|
751
|
-
|
|
752
|
-
import_error("Failed Import: '" + key + "' module doesn't exist in any of the import directories: " + import_dirs.join(':'))
|
|
838
|
+
for location in import_dirs:
|
|
839
|
+
if location:
|
|
840
|
+
file_mtime, filename, prefetched_src = await safe_stat(location + '/' + modpath)
|
|
841
|
+
if filename is not None:
|
|
842
|
+
break
|
|
843
|
+
if filename is None:
|
|
844
|
+
import_error("Failed Import: '" + key + "' module doesn't exist in any of the import directories: " + import_dirs.join(':'))
|
|
753
845
|
|
|
754
|
-
|
|
755
|
-
|
|
756
|
-
|
|
757
|
-
cached = None
|
|
846
|
+
# Read the cache file. I/O starts here; any CPU work done before the
|
|
847
|
+
# await can overlap with the disk read.
|
|
848
|
+
cache_read = readfile(cache_file_name(filename, options.module_cache_dir))
|
|
758
849
|
|
|
759
|
-
|
|
760
|
-
|
|
761
|
-
|
|
762
|
-
|
|
763
|
-
|
|
764
|
-
|
|
765
|
-
|
|
766
|
-
|
|
767
|
-
|
|
768
|
-
|
|
769
|
-
|
|
770
|
-
|
|
771
|
-
|
|
772
|
-
|
|
773
|
-
|
|
774
|
-
|
|
775
|
-
|
|
776
|
-
'
|
|
777
|
-
|
|
778
|
-
|
|
779
|
-
|
|
780
|
-
|
|
850
|
+
cached = None
|
|
851
|
+
ast_json_str = None
|
|
852
|
+
try:
|
|
853
|
+
_split = decode_cache(await cache_read)
|
|
854
|
+
if _split is not None:
|
|
855
|
+
cached = JSON.parse(_split.meta)
|
|
856
|
+
ast_json_str = _split.ast
|
|
857
|
+
except:
|
|
858
|
+
cached = None
|
|
859
|
+
|
|
860
|
+
srchash = src_code = None
|
|
861
|
+
cache_ok = cached and cached.v is CACHE_VERSION and cached.compiler_version is COMPILER_VERSION
|
|
862
|
+
if cache_ok and file_mtime is not None and cached.mtime is not None and cached.mtime is file_mtime:
|
|
863
|
+
# Fast path: mtime matches — source file is unchanged, skip reading and hashing it
|
|
864
|
+
srchash = cached.signature
|
|
865
|
+
else:
|
|
866
|
+
# Need source content to validate with sha1sum (or to re-parse on miss)
|
|
867
|
+
src_code = prefetched_src or await readfile(filename, 'utf-8')
|
|
868
|
+
srchash = sha1sum(src_code)
|
|
869
|
+
if not cache_ok or cached.signature is not srchash:
|
|
870
|
+
cached = None
|
|
871
|
+
|
|
872
|
+
if cached is not None:
|
|
873
|
+
# Load all deps in parallel — cached module deps have been pre-validated as
|
|
874
|
+
# non-circular so Promise.all is safe. The loading_promises dict ensures
|
|
875
|
+
# that if two parallel chains try to load the same dep, only one actually
|
|
876
|
+
# does the work; the other waits.
|
|
877
|
+
pending = v'[]'
|
|
878
|
+
for ikey in cached.imported_module_ids:
|
|
879
|
+
if not has_prop(imported_modules, ikey):
|
|
880
|
+
pending.push(do_import(ikey))
|
|
881
|
+
if pending.length > 0:
|
|
882
|
+
await Promise.all(pending)
|
|
883
|
+
# Reconstruct classes dict from the simplified cache (no full AST nodes).
|
|
884
|
+
classes = {}
|
|
885
|
+
for cname in Object.keys(cached.classes or {}):
|
|
886
|
+
ci = cached.classes[cname]
|
|
887
|
+
classes[cname] = {'name': {'name': cname}, 'static': ci.static or {}, 'bound': ci.bound or [], 'classvars': ci.classvars or {}}
|
|
888
|
+
meta = {
|
|
889
|
+
'module_id': key,
|
|
890
|
+
'filename': filename,
|
|
891
|
+
'import_order': Object.keys(imported_modules).length,
|
|
892
|
+
'imports': imported_modules,
|
|
893
|
+
'exports': [{'name': n} for n in cached.exported_names],
|
|
894
|
+
'baselib': cached.baselib or {},
|
|
895
|
+
'classes': classes,
|
|
896
|
+
}
|
|
897
|
+
if cached.has_side_effects is not undefined:
|
|
898
|
+
meta['_has_side_effects'] = cached.has_side_effects
|
|
899
|
+
if cached.index is not undefined:
|
|
900
|
+
meta['_cache_index'] = cached.index
|
|
901
|
+
module = make_lazy_ast_module(ast_json_str, meta)
|
|
902
|
+
imported_modules[key] = module
|
|
903
|
+
else:
|
|
904
|
+
await parse(src_code, {
|
|
905
|
+
'filename': filename,
|
|
906
|
+
'toplevel': None,
|
|
907
|
+
'basedir': options.basedir,
|
|
908
|
+
'libdir': options.libdir,
|
|
909
|
+
'import_dirs': options.import_dirs,
|
|
910
|
+
'module_id': key,
|
|
911
|
+
'imported_modules': imported_modules,
|
|
912
|
+
'importing_modules': importing_modules,
|
|
913
|
+
'discard_asserts': options.discard_asserts,
|
|
914
|
+
'module_cache_dir': options.module_cache_dir,
|
|
915
|
+
'_src_hash': srchash,
|
|
916
|
+
'_file_mtime': file_mtime,
|
|
917
|
+
'loading_promises': loading_promises,
|
|
918
|
+
}) # This function will add the module to imported_modules itself
|
|
919
|
+
finally:
|
|
920
|
+
del loading_promises[key]
|
|
921
|
+
if _rfn[0]:
|
|
922
|
+
_rfn[0](None)
|
|
781
923
|
|
|
782
924
|
imported_modules[key].srchash = srchash
|
|
783
925
|
|
|
@@ -811,10 +953,10 @@ def create_parser_ctx(S, import_dirs, module_id, baselib_items, imported_module_
|
|
|
811
953
|
break
|
|
812
954
|
return new AST_EmptyStatement({'stype':'scoped_flags', 'start':prev(), 'end':prev()})
|
|
813
955
|
|
|
814
|
-
def import_(from_import):
|
|
956
|
+
async def import_(from_import):
|
|
815
957
|
ans = new AST_Imports({'imports':[]})
|
|
816
958
|
while True:
|
|
817
|
-
tok = tmp = name = last_tok = expression(False)
|
|
959
|
+
tok = tmp = name = last_tok = await expression(False)
|
|
818
960
|
key = ''
|
|
819
961
|
while is_node_type(tmp, AST_Dot):
|
|
820
962
|
key = "." + tmp.property + key
|
|
@@ -844,7 +986,7 @@ def create_parser_ctx(S, import_dirs, module_id, baselib_items, imported_module_
|
|
|
844
986
|
break
|
|
845
987
|
|
|
846
988
|
for imp in ans['imports']:
|
|
847
|
-
do_import(imp.key)
|
|
989
|
+
await do_import(imp.key)
|
|
848
990
|
if imported_module_ids.indexOf(imp.key) is -1:
|
|
849
991
|
imported_module_ids.push(imp.key)
|
|
850
992
|
classes = imported_modules[key].classes
|
|
@@ -889,7 +1031,7 @@ def create_parser_ctx(S, import_dirs, module_id, baselib_items, imported_module_
|
|
|
889
1031
|
|
|
890
1032
|
return ans
|
|
891
1033
|
|
|
892
|
-
def class_():
|
|
1034
|
+
async def class_():
|
|
893
1035
|
name = as_symbol(AST_SymbolDefun)
|
|
894
1036
|
if not name:
|
|
895
1037
|
unexpected()
|
|
@@ -916,7 +1058,7 @@ def create_parser_ctx(S, import_dirs, module_id, baselib_items, imported_module_
|
|
|
916
1058
|
S.in_parenthesized_expr = False
|
|
917
1059
|
next()
|
|
918
1060
|
break
|
|
919
|
-
a = expr_atom(False)
|
|
1061
|
+
a = await expr_atom(False)
|
|
920
1062
|
if class_parent is None:
|
|
921
1063
|
class_parent = a
|
|
922
1064
|
bases.push(a)
|
|
@@ -925,6 +1067,33 @@ def create_parser_ctx(S, import_dirs, module_id, baselib_items, imported_module_
|
|
|
925
1067
|
continue
|
|
926
1068
|
|
|
927
1069
|
docstrings = v'[]'
|
|
1070
|
+
cls_decorators = (def():
|
|
1071
|
+
d = []
|
|
1072
|
+
for decorator in S.decorators:
|
|
1073
|
+
d.push(new AST_Decorator({
|
|
1074
|
+
'expression': decorator
|
|
1075
|
+
}))
|
|
1076
|
+
S.decorators = v'[]'
|
|
1077
|
+
return d
|
|
1078
|
+
)()
|
|
1079
|
+
cls_body = await (async def(loop, labels):
|
|
1080
|
+
# navigate to correct location in the module tree and append the class
|
|
1081
|
+
S.in_class.push(name.name)
|
|
1082
|
+
S.classes[S.classes.length - 1][name.name] = class_details
|
|
1083
|
+
S.classes.push({})
|
|
1084
|
+
S.scoped_flags.push()
|
|
1085
|
+
S.in_function += 1
|
|
1086
|
+
S.in_loop = 0
|
|
1087
|
+
S.labels = []
|
|
1088
|
+
a = await block_(docstrings)
|
|
1089
|
+
S.in_function -= 1
|
|
1090
|
+
S.scoped_flags.pop()
|
|
1091
|
+
S.classes.pop()
|
|
1092
|
+
S.in_class.pop()
|
|
1093
|
+
S.in_loop = loop
|
|
1094
|
+
S.labels = labels
|
|
1095
|
+
return a
|
|
1096
|
+
)(S.in_loop, S.labels)
|
|
928
1097
|
definition = new AST_Class({
|
|
929
1098
|
'name': name,
|
|
930
1099
|
'docstrings': docstrings,
|
|
@@ -938,33 +1107,8 @@ def create_parser_ctx(S, import_dirs, module_id, baselib_items, imported_module_
|
|
|
938
1107
|
'external': externaldecorator,
|
|
939
1108
|
'bound': class_details.bound,
|
|
940
1109
|
'statements': [],
|
|
941
|
-
'decorators':
|
|
942
|
-
|
|
943
|
-
for decorator in S.decorators:
|
|
944
|
-
d.push(new AST_Decorator({
|
|
945
|
-
'expression': decorator
|
|
946
|
-
}))
|
|
947
|
-
S.decorators = v'[]'
|
|
948
|
-
return d
|
|
949
|
-
)(),
|
|
950
|
-
'body': (def(loop, labels):
|
|
951
|
-
# navigate to correct location in the module tree and append the class
|
|
952
|
-
S.in_class.push(name.name)
|
|
953
|
-
S.classes[S.classes.length - 1][name.name] = class_details
|
|
954
|
-
S.classes.push({})
|
|
955
|
-
S.scoped_flags.push()
|
|
956
|
-
S.in_function += 1
|
|
957
|
-
S.in_loop = 0
|
|
958
|
-
S.labels = []
|
|
959
|
-
a = block_(docstrings)
|
|
960
|
-
S.in_function -= 1
|
|
961
|
-
S.scoped_flags.pop()
|
|
962
|
-
S.classes.pop()
|
|
963
|
-
S.in_class.pop()
|
|
964
|
-
S.in_loop = loop
|
|
965
|
-
S.labels = labels
|
|
966
|
-
return a
|
|
967
|
-
)(S.in_loop, S.labels)
|
|
1110
|
+
'decorators': cls_decorators,
|
|
1111
|
+
'body': cls_body,
|
|
968
1112
|
})
|
|
969
1113
|
class_details.processing = False
|
|
970
1114
|
# find the constructor
|
|
@@ -1008,7 +1152,7 @@ def create_parser_ctx(S, import_dirs, module_id, baselib_items, imported_module_
|
|
|
1008
1152
|
definition.statements.push(stmt)
|
|
1009
1153
|
return definition
|
|
1010
1154
|
|
|
1011
|
-
def function_(in_class, is_expression):
|
|
1155
|
+
async def function_(in_class, is_expression, is_async=False):
|
|
1012
1156
|
name = as_symbol(AST_SymbolDefun if in_class else AST_SymbolLambda) if is_('name') else None
|
|
1013
1157
|
if in_class and not name:
|
|
1014
1158
|
croak('Cannot use anonymous function as class methods')
|
|
@@ -1033,169 +1177,193 @@ def create_parser_ctx(S, import_dirs, module_id, baselib_items, imported_module_
|
|
|
1033
1177
|
return_annotation = None
|
|
1034
1178
|
is_generator = v'[]'
|
|
1035
1179
|
docstrings = v'[]'
|
|
1036
|
-
definition = new ctor({
|
|
1037
|
-
'name': name,
|
|
1038
|
-
'is_expression': is_expression,
|
|
1039
|
-
'is_anonymous': is_anonymous,
|
|
1040
|
-
'argnames': (def(a):
|
|
1041
|
-
defaults = {}
|
|
1042
|
-
first = True
|
|
1043
|
-
seen_names = {}
|
|
1044
|
-
def_line = S.input.context().tokline
|
|
1045
|
-
current_arg_name = None
|
|
1046
|
-
name_token = None
|
|
1047
|
-
|
|
1048
|
-
def get_arg():
|
|
1049
|
-
nonlocal current_arg_name, name_token
|
|
1050
|
-
current_arg_name = S.token.value
|
|
1051
|
-
if has_prop(seen_names, current_arg_name):
|
|
1052
|
-
token_error(prev(), "Can't repeat parameter names")
|
|
1053
|
-
if current_arg_name is 'arguments':
|
|
1054
|
-
token_error(prev(), "Can't use the name arguments as a parameter name, it is reserved by JavaScript")
|
|
1055
|
-
seen_names[current_arg_name] = True
|
|
1056
|
-
# save these in order to move back if we have an annotation
|
|
1057
|
-
name_token = S.token
|
|
1058
|
-
name_ctx = S.input.context()
|
|
1059
|
-
# check if we have an argument annotation
|
|
1060
|
-
ntok = peek()
|
|
1061
|
-
if ntok.type is 'punc' and ntok.value is ':':
|
|
1062
|
-
next()
|
|
1063
|
-
expect(':')
|
|
1064
|
-
annotation = maybe_conditional()
|
|
1065
|
-
|
|
1066
|
-
# and now, do as_symbol without the next() at the end
|
|
1067
|
-
# since we are already at the next comma (or end bracket)
|
|
1068
|
-
if not is_token(name_token, "name"):
|
|
1069
|
-
# assuming the previous context in case
|
|
1070
|
-
# the annotation was over the line
|
|
1071
|
-
croak("Name expected", name_ctx.tokline)
|
|
1072
|
-
return None
|
|
1073
1180
|
|
|
1074
|
-
|
|
1075
|
-
|
|
1076
|
-
|
|
1077
|
-
|
|
1078
|
-
|
|
1079
|
-
|
|
1080
|
-
|
|
1081
|
-
|
|
1082
|
-
|
|
1083
|
-
|
|
1084
|
-
|
|
1085
|
-
|
|
1086
|
-
|
|
1087
|
-
|
|
1088
|
-
|
|
1089
|
-
|
|
1090
|
-
|
|
1091
|
-
|
|
1092
|
-
|
|
1093
|
-
|
|
1094
|
-
|
|
1095
|
-
|
|
1096
|
-
|
|
1097
|
-
|
|
1098
|
-
|
|
1181
|
+
fn_argnames = await (async def():
|
|
1182
|
+
a = v'[]'
|
|
1183
|
+
starargs_sym = undefined
|
|
1184
|
+
kwargs_sym = undefined
|
|
1185
|
+
defaults = {}
|
|
1186
|
+
has_defaults = False
|
|
1187
|
+
first = True
|
|
1188
|
+
seen_names = {}
|
|
1189
|
+
def_line = S.input.context().tokline
|
|
1190
|
+
current_arg_name = None
|
|
1191
|
+
name_token = None
|
|
1192
|
+
|
|
1193
|
+
async def get_arg():
|
|
1194
|
+
nonlocal current_arg_name, name_token
|
|
1195
|
+
current_arg_name = S.token.value
|
|
1196
|
+
if has_prop(seen_names, current_arg_name):
|
|
1197
|
+
token_error(prev(), "Can't repeat parameter names")
|
|
1198
|
+
if current_arg_name is 'arguments':
|
|
1199
|
+
token_error(prev(), "Can't use the name arguments as a parameter name, it is reserved by JavaScript")
|
|
1200
|
+
seen_names[current_arg_name] = True
|
|
1201
|
+
# save these in order to move back if we have an annotation
|
|
1202
|
+
name_token = S.token
|
|
1203
|
+
name_ctx = S.input.context()
|
|
1204
|
+
# check if we have an argument annotation
|
|
1205
|
+
ntok = peek()
|
|
1206
|
+
if ntok.type is 'punc' and ntok.value is ':':
|
|
1207
|
+
next()
|
|
1208
|
+
expect(':')
|
|
1209
|
+
annotation = await maybe_conditional()
|
|
1210
|
+
|
|
1211
|
+
# and now, do as_symbol without the next() at the end
|
|
1212
|
+
# since we are already at the next comma (or end bracket)
|
|
1213
|
+
if not is_token(name_token, "name"):
|
|
1214
|
+
# assuming the previous context in case
|
|
1215
|
+
# the annotation was over the line
|
|
1216
|
+
if S.input.context().tokline is not def_line:
|
|
1217
|
+
croak("Name expected", name_ctx.tokline)
|
|
1218
|
+
else:
|
|
1219
|
+
croak("Name expected")
|
|
1220
|
+
return None
|
|
1221
|
+
|
|
1222
|
+
sym = new AST_SymbolFunarg({
|
|
1223
|
+
'name': name_token.value,
|
|
1224
|
+
'start': S.token,
|
|
1225
|
+
'end': S.token,
|
|
1226
|
+
'annotation': annotation
|
|
1227
|
+
})
|
|
1228
|
+
return sym
|
|
1229
|
+
else:
|
|
1230
|
+
if not is_("name"):
|
|
1231
|
+
# there is no name, which is an error we should report on the
|
|
1232
|
+
# same line as the definition, so move to that is we're not already there.
|
|
1233
|
+
if S.input.context().tokline is not def_line:
|
|
1234
|
+
croak("Name expected", def_line)
|
|
1235
|
+
else:
|
|
1236
|
+
croak("Name expected")
|
|
1237
|
+
return None
|
|
1238
|
+
|
|
1239
|
+
sym = new AST_SymbolFunarg({
|
|
1240
|
+
'name': current_arg_name,
|
|
1241
|
+
'start': S.token,
|
|
1242
|
+
'end': S.token,
|
|
1243
|
+
'annotation': None
|
|
1244
|
+
})
|
|
1245
|
+
next()
|
|
1246
|
+
return sym
|
|
1099
1247
|
|
|
1100
|
-
|
|
1101
|
-
|
|
1102
|
-
|
|
1103
|
-
|
|
1104
|
-
|
|
1105
|
-
|
|
1106
|
-
|
|
1107
|
-
|
|
1108
|
-
|
|
1109
|
-
|
|
1110
|
-
|
|
1111
|
-
|
|
1112
|
-
|
|
1113
|
-
|
|
1114
|
-
|
|
1248
|
+
while not is_("punc", ")"):
|
|
1249
|
+
if first:
|
|
1250
|
+
first = False
|
|
1251
|
+
else:
|
|
1252
|
+
expect(",")
|
|
1253
|
+
if is_('punc', ')'):
|
|
1254
|
+
break
|
|
1255
|
+
if is_('operator', '**'):
|
|
1256
|
+
# **kwargs
|
|
1257
|
+
next()
|
|
1258
|
+
if kwargs_sym:
|
|
1259
|
+
token_error(name_token, "Can't define multiple **kwargs in function definition")
|
|
1260
|
+
kwargs_sym = await get_arg()
|
|
1261
|
+
elif is_('operator', '*'):
|
|
1262
|
+
# *args
|
|
1263
|
+
next()
|
|
1264
|
+
if starargs_sym:
|
|
1265
|
+
token_error(name_token, "Can't define multiple *args in function definition")
|
|
1266
|
+
if kwargs_sym:
|
|
1267
|
+
token_error(name_token, "Can't define *args after **kwargs in function definition")
|
|
1268
|
+
starargs_sym = await get_arg()
|
|
1269
|
+
else:
|
|
1270
|
+
if starargs_sym or kwargs_sym:
|
|
1271
|
+
token_error(name_token, "Can't define a formal parameter after *args or **kwargs")
|
|
1272
|
+
a.push(await get_arg())
|
|
1273
|
+
if is_("operator", "="):
|
|
1274
|
+
if kwargs_sym:
|
|
1275
|
+
token_error(name_token, "Can't define an optional formal parameter after **kwargs")
|
|
1115
1276
|
next()
|
|
1116
|
-
|
|
1117
|
-
|
|
1118
|
-
if a.kwargs:
|
|
1119
|
-
token_error(name_token, "Can't define *args after **kwargs in function definition")
|
|
1120
|
-
a.starargs = get_arg()
|
|
1277
|
+
defaults[current_arg_name] = await expression(False)
|
|
1278
|
+
has_defaults = True
|
|
1121
1279
|
else:
|
|
1122
|
-
if
|
|
1123
|
-
token_error(name_token, "Can't define
|
|
1124
|
-
a.push(get_arg())
|
|
1125
|
-
if is_("operator", "="):
|
|
1126
|
-
if a.kwargs:
|
|
1127
|
-
token_error(name_token, "Can't define an optional formal parameter after **kwargs")
|
|
1128
|
-
next()
|
|
1129
|
-
defaults[current_arg_name] = expression(False)
|
|
1130
|
-
a.has_defaults = True
|
|
1131
|
-
else:
|
|
1132
|
-
if a.has_defaults:
|
|
1133
|
-
token_error(name_token, "Can't define required formal parameters after optional formal parameters")
|
|
1280
|
+
if has_defaults:
|
|
1281
|
+
token_error(name_token, "Can't define required formal parameters after optional formal parameters")
|
|
1134
1282
|
|
|
1283
|
+
next()
|
|
1284
|
+
# check if we have a return type annotation
|
|
1285
|
+
if is_("punc", "->"):
|
|
1135
1286
|
next()
|
|
1136
|
-
|
|
1137
|
-
|
|
1138
|
-
|
|
1139
|
-
|
|
1140
|
-
|
|
1141
|
-
|
|
1142
|
-
|
|
1143
|
-
|
|
1144
|
-
|
|
1145
|
-
|
|
1287
|
+
nonlocal return_annotation
|
|
1288
|
+
return_annotation = await maybe_conditional()
|
|
1289
|
+
S.in_parenthesized_expr = False
|
|
1290
|
+
return new AST_ArgsDef({
|
|
1291
|
+
'args': a,
|
|
1292
|
+
'starargs': starargs_sym,
|
|
1293
|
+
'kwargs': kwargs_sym,
|
|
1294
|
+
'defaults': defaults,
|
|
1295
|
+
'has_defaults': has_defaults,
|
|
1296
|
+
'is_simple_func': not starargs_sym and not kwargs_sym and not has_defaults,
|
|
1297
|
+
})
|
|
1298
|
+
)()
|
|
1299
|
+
|
|
1300
|
+
fn_decorators = (def():
|
|
1301
|
+
d = v'[]'
|
|
1302
|
+
for decorator in S.decorators:
|
|
1303
|
+
d.push(new AST_Decorator({
|
|
1304
|
+
'expression': decorator
|
|
1305
|
+
}))
|
|
1306
|
+
S.decorators = v'[]'
|
|
1307
|
+
return d
|
|
1308
|
+
)()
|
|
1309
|
+
|
|
1310
|
+
fn_body = await (async def(loop, labels):
|
|
1311
|
+
S.in_class.push(False)
|
|
1312
|
+
S.classes.push({})
|
|
1313
|
+
S.scoped_flags.push()
|
|
1314
|
+
S.in_function += 1
|
|
1315
|
+
S.functions.push({'is_async': is_async})
|
|
1316
|
+
S.in_loop = 0
|
|
1317
|
+
S.labels = []
|
|
1318
|
+
a = await block_(docstrings)
|
|
1319
|
+
S.in_function -= 1
|
|
1320
|
+
S.scoped_flags.pop()
|
|
1321
|
+
is_generator.push(bool(S.functions.pop().is_generator))
|
|
1322
|
+
S.classes.pop()
|
|
1323
|
+
S.in_class.pop()
|
|
1324
|
+
S.in_loop = loop
|
|
1325
|
+
S.labels = labels
|
|
1326
|
+
return a
|
|
1327
|
+
)(S.in_loop, S.labels)
|
|
1328
|
+
|
|
1329
|
+
definition = new ctor({
|
|
1330
|
+
'name': name,
|
|
1331
|
+
'is_expression': is_expression,
|
|
1332
|
+
'is_anonymous': is_anonymous,
|
|
1333
|
+
'argnames': fn_argnames,
|
|
1146
1334
|
'localvars': [],
|
|
1147
|
-
'decorators':
|
|
1148
|
-
d = v'[]'
|
|
1149
|
-
for decorator in S.decorators:
|
|
1150
|
-
d.push(new AST_Decorator({
|
|
1151
|
-
'expression': decorator
|
|
1152
|
-
}))
|
|
1153
|
-
S.decorators = v'[]'
|
|
1154
|
-
return d
|
|
1155
|
-
)(),
|
|
1335
|
+
'decorators': fn_decorators,
|
|
1156
1336
|
'docstrings': docstrings,
|
|
1157
|
-
'body':
|
|
1158
|
-
S.in_class.push(False)
|
|
1159
|
-
S.classes.push({})
|
|
1160
|
-
S.scoped_flags.push()
|
|
1161
|
-
S.in_function += 1
|
|
1162
|
-
S.functions.push({})
|
|
1163
|
-
S.in_loop = 0
|
|
1164
|
-
S.labels = []
|
|
1165
|
-
a = block_(docstrings)
|
|
1166
|
-
S.in_function -= 1
|
|
1167
|
-
S.scoped_flags.pop()
|
|
1168
|
-
is_generator.push(bool(S.functions.pop().is_generator))
|
|
1169
|
-
S.classes.pop()
|
|
1170
|
-
S.in_class.pop()
|
|
1171
|
-
S.in_loop = loop
|
|
1172
|
-
S.labels = labels
|
|
1173
|
-
return a
|
|
1174
|
-
)(S.in_loop, S.labels)
|
|
1337
|
+
'body': fn_body,
|
|
1175
1338
|
})
|
|
1176
1339
|
definition.return_annotation = return_annotation
|
|
1177
1340
|
definition.is_generator = is_generator[0]
|
|
1341
|
+
definition.is_async = is_async
|
|
1178
1342
|
if is_node_type(definition, AST_Method):
|
|
1179
1343
|
definition.static = staticmethod
|
|
1180
1344
|
definition.is_getter = property_getter
|
|
1181
1345
|
definition.is_setter = property_setter
|
|
1182
|
-
if definition.argnames.length < 1 and not definition.static:
|
|
1346
|
+
if definition.argnames.args.length < 1 and not definition.static:
|
|
1183
1347
|
croak('Methods of a class must have at least one argument, traditionally named self')
|
|
1184
1348
|
if definition.name and definition.name.name is '__init__':
|
|
1185
1349
|
if definition.is_generator:
|
|
1186
1350
|
croak('The __init__ method of a class cannot be a generator (yield not allowed)')
|
|
1351
|
+
if definition.is_async:
|
|
1352
|
+
croak('The __init__ method of a class cannot be async')
|
|
1187
1353
|
if property_getter or property_setter:
|
|
1188
1354
|
croak('The __init__ method of a class cannot be a property getter/setter')
|
|
1355
|
+
if definition.is_async and definition.is_generator:
|
|
1356
|
+
croak('A function cannot be both async and a generator')
|
|
1189
1357
|
if definition.is_generator:
|
|
1190
1358
|
baselib_items['yield'] = True
|
|
1191
1359
|
|
|
1192
1360
|
# detect local variables, strip function arguments
|
|
1193
1361
|
assignments = scan_for_local_vars(definition.body)
|
|
1194
1362
|
for i in range(assignments.length):
|
|
1195
|
-
for j in range(definition.argnames.length+1):
|
|
1196
|
-
if j is definition.argnames.length:
|
|
1363
|
+
for j in range(definition.argnames.args.length+1):
|
|
1364
|
+
if j is definition.argnames.args.length:
|
|
1197
1365
|
definition.localvars.push(new_symbol(AST_SymbolVar, assignments[i]))
|
|
1198
|
-
elif j < definition.argnames.length and assignments[i] is definition.argnames[j].name:
|
|
1366
|
+
elif j < definition.argnames.args.length and assignments[i] is definition.argnames.args[j].name:
|
|
1199
1367
|
break
|
|
1200
1368
|
|
|
1201
1369
|
nonlocals = scan_for_nonlocal_defs(definition.body)
|
|
@@ -1203,9 +1371,9 @@ def create_parser_ctx(S, import_dirs, module_id, baselib_items, imported_module_
|
|
|
1203
1371
|
definition.localvars = definition.localvars.filter(def(v): return not nonlocals.has(v.name);)
|
|
1204
1372
|
return definition
|
|
1205
1373
|
|
|
1206
|
-
def if_():
|
|
1207
|
-
cond = expression(True)
|
|
1208
|
-
body = statement()
|
|
1374
|
+
async def if_():
|
|
1375
|
+
cond = await expression(True)
|
|
1376
|
+
body = await statement()
|
|
1209
1377
|
belse = None
|
|
1210
1378
|
if is_("keyword", "elif") or is_("keyword", "else"):
|
|
1211
1379
|
if is_("keyword", "else"):
|
|
@@ -1213,7 +1381,7 @@ def create_parser_ctx(S, import_dirs, module_id, baselib_items, imported_module_
|
|
|
1213
1381
|
else:
|
|
1214
1382
|
S.token.value = "if"
|
|
1215
1383
|
# effectively converts 'elif' to 'else if'
|
|
1216
|
-
belse = statement()
|
|
1384
|
+
belse = await statement()
|
|
1217
1385
|
|
|
1218
1386
|
return new AST_If({
|
|
1219
1387
|
'condition': cond,
|
|
@@ -1227,15 +1395,27 @@ def create_parser_ctx(S, import_dirs, module_id, baselib_items, imported_module_
|
|
|
1227
1395
|
return stmt.body
|
|
1228
1396
|
return False
|
|
1229
1397
|
|
|
1230
|
-
def block_(docstrings):
|
|
1398
|
+
async def block_(docstrings):
|
|
1231
1399
|
prev_whitespace = S.token.leading_whitespace
|
|
1232
1400
|
expect(":")
|
|
1233
1401
|
a = v'[]'
|
|
1234
1402
|
if not S.token.nlb:
|
|
1235
1403
|
while not S.token.nlb:
|
|
1236
1404
|
if is_("eof"):
|
|
1405
|
+
if options.recover_errors:
|
|
1406
|
+
break
|
|
1237
1407
|
unexpected()
|
|
1238
|
-
|
|
1408
|
+
if options.recover_errors:
|
|
1409
|
+
try:
|
|
1410
|
+
stmt = await statement()
|
|
1411
|
+
except as berr:
|
|
1412
|
+
if is_recoverable_error(berr):
|
|
1413
|
+
record_recovery(berr)
|
|
1414
|
+
await skip_to_recovery_point()
|
|
1415
|
+
continue
|
|
1416
|
+
raise
|
|
1417
|
+
else:
|
|
1418
|
+
stmt = await statement()
|
|
1239
1419
|
if docstrings:
|
|
1240
1420
|
ds = is_docstring(stmt)
|
|
1241
1421
|
if ds:
|
|
@@ -1250,7 +1430,17 @@ def create_parser_ctx(S, import_dirs, module_id, baselib_items, imported_module_
|
|
|
1250
1430
|
if is_("eof"):
|
|
1251
1431
|
# end of file, terminate block automatically
|
|
1252
1432
|
return a
|
|
1253
|
-
|
|
1433
|
+
if options.recover_errors:
|
|
1434
|
+
try:
|
|
1435
|
+
stmt = await statement()
|
|
1436
|
+
except as berr:
|
|
1437
|
+
if is_recoverable_error(berr):
|
|
1438
|
+
record_recovery(berr)
|
|
1439
|
+
await skip_to_recovery_point()
|
|
1440
|
+
continue
|
|
1441
|
+
raise
|
|
1442
|
+
else:
|
|
1443
|
+
stmt = await statement()
|
|
1254
1444
|
if docstrings:
|
|
1255
1445
|
ds = is_docstring(stmt)
|
|
1256
1446
|
if ds:
|
|
@@ -1260,8 +1450,8 @@ def create_parser_ctx(S, import_dirs, module_id, baselib_items, imported_module_
|
|
|
1260
1450
|
next()
|
|
1261
1451
|
return a
|
|
1262
1452
|
|
|
1263
|
-
def try_():
|
|
1264
|
-
body = block_()
|
|
1453
|
+
async def try_():
|
|
1454
|
+
body = await block_()
|
|
1265
1455
|
bcatch = v'[]'
|
|
1266
1456
|
bfinally = None
|
|
1267
1457
|
belse = None
|
|
@@ -1280,29 +1470,32 @@ def create_parser_ctx(S, import_dirs, module_id, baselib_items, imported_module_
|
|
|
1280
1470
|
next()
|
|
1281
1471
|
name = as_symbol(AST_SymbolCatch)
|
|
1282
1472
|
|
|
1473
|
+
except_body = await block_()
|
|
1283
1474
|
bcatch.push(new AST_Except({
|
|
1284
1475
|
'start': start,
|
|
1285
1476
|
'argname': name,
|
|
1286
1477
|
'errors': exceptions,
|
|
1287
|
-
'body':
|
|
1478
|
+
'body': except_body,
|
|
1288
1479
|
'end': prev()
|
|
1289
1480
|
}))
|
|
1290
1481
|
|
|
1291
1482
|
if is_("keyword", "else"):
|
|
1292
1483
|
start = S.token
|
|
1293
1484
|
next()
|
|
1485
|
+
belse_body = await block_()
|
|
1294
1486
|
belse = new AST_Else({
|
|
1295
1487
|
'start': start,
|
|
1296
|
-
'body':
|
|
1488
|
+
'body': belse_body,
|
|
1297
1489
|
'end': prev()
|
|
1298
1490
|
})
|
|
1299
1491
|
|
|
1300
1492
|
if is_("keyword", "finally"):
|
|
1301
1493
|
start = S.token
|
|
1302
1494
|
next()
|
|
1495
|
+
bfinally_body = await block_()
|
|
1303
1496
|
bfinally = new AST_Finally({
|
|
1304
1497
|
'start': start,
|
|
1305
|
-
'body':
|
|
1498
|
+
'body': bfinally_body,
|
|
1306
1499
|
'end': prev()
|
|
1307
1500
|
})
|
|
1308
1501
|
|
|
@@ -1316,13 +1509,20 @@ def create_parser_ctx(S, import_dirs, module_id, baselib_items, imported_module_
|
|
|
1316
1509
|
'belse': belse
|
|
1317
1510
|
})
|
|
1318
1511
|
|
|
1319
|
-
def vardefs(symbol_class):
|
|
1512
|
+
async def vardefs(symbol_class):
|
|
1320
1513
|
a = []
|
|
1321
1514
|
while True:
|
|
1515
|
+
vd_start = S.token
|
|
1516
|
+
vd_name = as_symbol(symbol_class)
|
|
1517
|
+
if is_('operator', '='):
|
|
1518
|
+
next()
|
|
1519
|
+
varval = await expression(False)
|
|
1520
|
+
else:
|
|
1521
|
+
varval = None
|
|
1322
1522
|
a.push(new AST_VarDef({
|
|
1323
|
-
'start':
|
|
1324
|
-
'name':
|
|
1325
|
-
'value':
|
|
1523
|
+
'start': vd_start,
|
|
1524
|
+
'name': vd_name,
|
|
1525
|
+
'value': varval,
|
|
1326
1526
|
'end': prev()
|
|
1327
1527
|
}))
|
|
1328
1528
|
if not is_("punc", ","):
|
|
@@ -1331,8 +1531,8 @@ def create_parser_ctx(S, import_dirs, module_id, baselib_items, imported_module_
|
|
|
1331
1531
|
|
|
1332
1532
|
return a
|
|
1333
1533
|
|
|
1334
|
-
def nonlocal_(is_global):
|
|
1335
|
-
defs = vardefs(AST_SymbolNonlocal)
|
|
1534
|
+
async def nonlocal_(is_global):
|
|
1535
|
+
defs = await vardefs(AST_SymbolNonlocal)
|
|
1336
1536
|
if is_global:
|
|
1337
1537
|
for vardef in defs:
|
|
1338
1538
|
S.globals.push(vardef.name.name)
|
|
@@ -1342,19 +1542,19 @@ def create_parser_ctx(S, import_dirs, module_id, baselib_items, imported_module_
|
|
|
1342
1542
|
'end': prev()
|
|
1343
1543
|
})
|
|
1344
1544
|
|
|
1345
|
-
def new_():
|
|
1545
|
+
async def new_():
|
|
1346
1546
|
start = S.token
|
|
1347
1547
|
expect_token("operator", "new")
|
|
1348
|
-
newexp = expr_atom(False)
|
|
1548
|
+
newexp = await expr_atom(False)
|
|
1349
1549
|
|
|
1350
1550
|
if is_("punc", "("):
|
|
1351
1551
|
S.in_parenthesized_expr = True
|
|
1352
1552
|
next()
|
|
1353
|
-
args = func_call_list()
|
|
1553
|
+
args = await func_call_list()
|
|
1354
1554
|
S.in_parenthesized_expr = False
|
|
1355
1555
|
else:
|
|
1356
|
-
args = func_call_list(True)
|
|
1357
|
-
return subscripts(new AST_New({
|
|
1556
|
+
args = await func_call_list(True)
|
|
1557
|
+
return await subscripts(new AST_New({
|
|
1358
1558
|
'start': start,
|
|
1359
1559
|
'expression': newexp,
|
|
1360
1560
|
'args': args,
|
|
@@ -1424,9 +1624,9 @@ def create_parser_ctx(S, import_dirs, module_id, baselib_items, imported_module_
|
|
|
1424
1624
|
next()
|
|
1425
1625
|
return ret
|
|
1426
1626
|
|
|
1427
|
-
def expr_atom(allow_calls):
|
|
1627
|
+
async def expr_atom(allow_calls):
|
|
1428
1628
|
if is_("operator", "new"):
|
|
1429
|
-
return new_()
|
|
1629
|
+
return await new_()
|
|
1430
1630
|
|
|
1431
1631
|
start = S.token
|
|
1432
1632
|
if is_("punc"):
|
|
@@ -1437,9 +1637,9 @@ def create_parser_ctx(S, import_dirs, module_id, baselib_items, imported_module_
|
|
|
1437
1637
|
if is_('punc', ')'):
|
|
1438
1638
|
next()
|
|
1439
1639
|
return new AST_Array({'elements':[]})
|
|
1440
|
-
ex = expression(True)
|
|
1640
|
+
ex = await expression(True)
|
|
1441
1641
|
if is_('keyword', 'for'):
|
|
1442
|
-
ret = read_comprehension(new AST_GeneratorComprehension({'statement': ex}), ')')
|
|
1642
|
+
ret = await read_comprehension(new AST_GeneratorComprehension({'statement': ex}), ')')
|
|
1443
1643
|
S.in_parenthesized_expr = False
|
|
1444
1644
|
return ret
|
|
1445
1645
|
ex.start = start
|
|
@@ -1451,38 +1651,55 @@ def create_parser_ctx(S, import_dirs, module_id, baselib_items, imported_module_
|
|
|
1451
1651
|
if is_node_type(ex, AST_UnaryPrefix):
|
|
1452
1652
|
ex.parenthesized = True
|
|
1453
1653
|
S.in_parenthesized_expr = False
|
|
1454
|
-
return subscripts(ex, allow_calls)
|
|
1654
|
+
return await subscripts(ex, allow_calls)
|
|
1455
1655
|
elif tmp_ is "[":
|
|
1456
|
-
return subscripts(array_(), allow_calls)
|
|
1656
|
+
return await subscripts(await array_(), allow_calls)
|
|
1457
1657
|
elif tmp_ is "{":
|
|
1458
|
-
return subscripts(object_(), allow_calls)
|
|
1658
|
+
return await subscripts(await object_(), allow_calls)
|
|
1459
1659
|
|
|
1460
1660
|
unexpected()
|
|
1461
1661
|
|
|
1462
1662
|
if is_("keyword", "class"):
|
|
1463
1663
|
next()
|
|
1464
|
-
cls = class_()
|
|
1664
|
+
cls = await class_()
|
|
1465
1665
|
cls.start = start
|
|
1466
1666
|
cls.end = prev()
|
|
1467
|
-
return subscripts(cls, allow_calls)
|
|
1667
|
+
return await subscripts(cls, allow_calls)
|
|
1668
|
+
|
|
1669
|
+
if is_("keyword", "async"):
|
|
1670
|
+
next()
|
|
1671
|
+
if not is_("keyword", "def"):
|
|
1672
|
+
croak("Expected 'def' after 'async'")
|
|
1673
|
+
next()
|
|
1674
|
+
func = await function_(False, True, True)
|
|
1675
|
+
func.start = start
|
|
1676
|
+
func.end = prev()
|
|
1677
|
+
return await subscripts(func, allow_calls)
|
|
1468
1678
|
|
|
1469
1679
|
if is_("keyword", "def"):
|
|
1470
1680
|
next()
|
|
1471
|
-
func = function_(False, True)
|
|
1681
|
+
func = await function_(False, True)
|
|
1472
1682
|
func.start = start
|
|
1473
1683
|
func.end = prev()
|
|
1474
|
-
return subscripts(func, allow_calls)
|
|
1684
|
+
return await subscripts(func, allow_calls)
|
|
1685
|
+
|
|
1686
|
+
if is_('keyword', 'await'):
|
|
1687
|
+
next()
|
|
1688
|
+
if S.in_function is 0 or not S.functions[-1].is_async:
|
|
1689
|
+
croak("'await' outside of async function")
|
|
1690
|
+
value = await expr_atom(True)
|
|
1691
|
+
return new AST_Await({'value': value})
|
|
1475
1692
|
|
|
1476
1693
|
if is_('keyword', 'yield'):
|
|
1477
1694
|
next()
|
|
1478
|
-
return yield_()
|
|
1695
|
+
return await yield_()
|
|
1479
1696
|
|
|
1480
1697
|
if ATOMIC_START_TOKEN[S.token.type]:
|
|
1481
|
-
return subscripts(as_atom_node(), allow_calls)
|
|
1698
|
+
return await subscripts(as_atom_node(), allow_calls)
|
|
1482
1699
|
|
|
1483
1700
|
unexpected()
|
|
1484
1701
|
|
|
1485
|
-
def expr_list(closing, allow_trailing_comma, allow_empty, func_call):
|
|
1702
|
+
async def expr_list(closing, allow_trailing_comma, allow_empty, func_call):
|
|
1486
1703
|
first = True
|
|
1487
1704
|
a = []
|
|
1488
1705
|
saw_starargs = False
|
|
@@ -1507,31 +1724,28 @@ def create_parser_ctx(S, import_dirs, module_id, baselib_items, imported_module_
|
|
|
1507
1724
|
'end': S.token
|
|
1508
1725
|
}))
|
|
1509
1726
|
else:
|
|
1510
|
-
a.push(expression(False))
|
|
1727
|
+
a.push(await expression(False))
|
|
1511
1728
|
|
|
1729
|
+
next()
|
|
1512
1730
|
if func_call:
|
|
1513
|
-
|
|
1514
|
-
|
|
1731
|
+
pargs = []
|
|
1732
|
+
kwargs = []
|
|
1515
1733
|
for arg in a:
|
|
1516
1734
|
if is_node_type(arg, AST_Assign):
|
|
1517
|
-
|
|
1735
|
+
kwargs.push([arg.left, arg.right])
|
|
1518
1736
|
else:
|
|
1519
|
-
|
|
1520
|
-
|
|
1521
|
-
|
|
1522
|
-
next()
|
|
1523
|
-
if saw_starargs:
|
|
1524
|
-
a.starargs = True
|
|
1737
|
+
pargs.push(arg)
|
|
1738
|
+
return new AST_CallArgs({'args': pargs, 'kwargs': kwargs, 'kwarg_items': v'[]', 'starargs': saw_starargs})
|
|
1525
1739
|
return a
|
|
1526
1740
|
|
|
1527
|
-
def func_call_list(empty):
|
|
1741
|
+
async def func_call_list(empty):
|
|
1528
1742
|
a = v'[]'
|
|
1529
1743
|
first = True
|
|
1530
|
-
|
|
1531
|
-
|
|
1532
|
-
|
|
1744
|
+
kwargs = v'[]'
|
|
1745
|
+
kwarg_items = v'[]'
|
|
1746
|
+
starargs = False
|
|
1533
1747
|
if empty:
|
|
1534
|
-
return a
|
|
1748
|
+
return new AST_CallArgs({'args': a, 'kwargs': kwargs, 'kwarg_items': kwarg_items, 'starargs': starargs})
|
|
1535
1749
|
single_comprehension = False
|
|
1536
1750
|
while not is_("punc", ')') and not is_('eof'):
|
|
1537
1751
|
if not first:
|
|
@@ -1540,50 +1754,51 @@ def create_parser_ctx(S, import_dirs, module_id, baselib_items, imported_module_
|
|
|
1540
1754
|
break
|
|
1541
1755
|
if is_('operator', '*'):
|
|
1542
1756
|
next()
|
|
1543
|
-
arg = expression(False)
|
|
1544
|
-
arg
|
|
1545
|
-
|
|
1546
|
-
a.starargs = True
|
|
1757
|
+
arg = await expression(False)
|
|
1758
|
+
a.push(new AST_CallArg({'value': arg, 'is_array': True}))
|
|
1759
|
+
starargs = True
|
|
1547
1760
|
elif is_('operator', '**'):
|
|
1548
1761
|
next()
|
|
1549
|
-
|
|
1550
|
-
|
|
1762
|
+
kwarg_items.push(as_symbol(AST_SymbolRef, False))
|
|
1763
|
+
starargs = True
|
|
1551
1764
|
else:
|
|
1552
|
-
arg = expression(False)
|
|
1765
|
+
arg = await expression(False)
|
|
1553
1766
|
if is_node_type(arg, AST_Assign):
|
|
1554
|
-
|
|
1767
|
+
kwargs.push([arg.left, arg.right])
|
|
1555
1768
|
else:
|
|
1556
1769
|
if is_('keyword', 'for'):
|
|
1557
1770
|
if not first:
|
|
1558
1771
|
croak('Generator expression must be parenthesized if not sole argument')
|
|
1559
|
-
|
|
1772
|
+
comp = await read_comprehension(new AST_GeneratorComprehension({'statement': arg}), ')')
|
|
1773
|
+
a.push(new AST_CallArg({'value': comp, 'is_array': False}))
|
|
1560
1774
|
single_comprehension = True
|
|
1561
1775
|
break
|
|
1562
|
-
a.push(arg)
|
|
1776
|
+
a.push(new AST_CallArg({'value': arg, 'is_array': False}))
|
|
1563
1777
|
first = False
|
|
1564
1778
|
if not single_comprehension:
|
|
1565
1779
|
next()
|
|
1566
|
-
return a
|
|
1780
|
+
return new AST_CallArgs({'args': a, 'kwargs': kwargs, 'kwarg_items': kwarg_items, 'starargs': starargs})
|
|
1567
1781
|
|
|
1568
1782
|
@embed_tokens
|
|
1569
|
-
def array_():
|
|
1783
|
+
async def array_():
|
|
1570
1784
|
expect("[")
|
|
1571
1785
|
expr = []
|
|
1572
1786
|
if not is_("punc", "]"):
|
|
1573
|
-
expr.push(expression(False))
|
|
1787
|
+
expr.push(await expression(False))
|
|
1574
1788
|
if is_("keyword", "for"):
|
|
1575
1789
|
# list comprehension
|
|
1576
|
-
return read_comprehension(new AST_ListComprehension({'statement': expr[0]}), ']')
|
|
1790
|
+
return await read_comprehension(new AST_ListComprehension({'statement': expr[0]}), ']')
|
|
1577
1791
|
|
|
1578
1792
|
if not is_("punc", "]"):
|
|
1579
1793
|
expect(",")
|
|
1580
1794
|
|
|
1795
|
+
arr_rest = await expr_list("]", True, True)
|
|
1581
1796
|
return new AST_Array({
|
|
1582
|
-
'elements': expr.concat(
|
|
1797
|
+
'elements': expr.concat(arr_rest)
|
|
1583
1798
|
})
|
|
1584
1799
|
|
|
1585
1800
|
@embed_tokens
|
|
1586
|
-
def object_():
|
|
1801
|
+
async def object_():
|
|
1587
1802
|
expect("{")
|
|
1588
1803
|
first = True
|
|
1589
1804
|
has_non_const_keys = False
|
|
@@ -1603,26 +1818,27 @@ def create_parser_ctx(S, import_dirs, module_id, baselib_items, imported_module_
|
|
|
1603
1818
|
orig = ctx.expecting_object_literal_key
|
|
1604
1819
|
ctx.expecting_object_literal_key = True
|
|
1605
1820
|
try:
|
|
1606
|
-
left = expression(False)
|
|
1821
|
+
left = await expression(False)
|
|
1607
1822
|
finally:
|
|
1608
1823
|
ctx.expecting_object_literal_key = orig
|
|
1609
1824
|
if is_('keyword', 'for'):
|
|
1610
1825
|
# is_pydict is irrelevant here
|
|
1611
|
-
return read_comprehension(new AST_SetComprehension({'statement':left}), '}')
|
|
1826
|
+
return await read_comprehension(new AST_SetComprehension({'statement':left}), '}')
|
|
1612
1827
|
if a.length is 0 and (is_('punc', ',') or is_('punc', '}')):
|
|
1613
1828
|
end = prev()
|
|
1614
|
-
return set_(start, end, left)
|
|
1829
|
+
return await set_(start, end, left)
|
|
1615
1830
|
if not is_node_type(left, AST_Constant):
|
|
1616
1831
|
has_non_const_keys = True
|
|
1617
1832
|
expect(":")
|
|
1833
|
+
obj_val = await expression(False)
|
|
1618
1834
|
a.push(new AST_ObjectKeyVal({
|
|
1619
1835
|
'start': start,
|
|
1620
1836
|
'key': left,
|
|
1621
|
-
'value':
|
|
1837
|
+
'value': obj_val,
|
|
1622
1838
|
'end': prev()
|
|
1623
1839
|
}))
|
|
1624
1840
|
if a.length is 1 and is_('keyword', 'for'):
|
|
1625
|
-
return dict_comprehension(a, is_pydict, is_jshash)
|
|
1841
|
+
return await dict_comprehension(a, is_pydict, is_jshash)
|
|
1626
1842
|
|
|
1627
1843
|
next()
|
|
1628
1844
|
return new (AST_ExpressiveObject if has_non_const_keys else AST_Object)({
|
|
@@ -1631,7 +1847,7 @@ def create_parser_ctx(S, import_dirs, module_id, baselib_items, imported_module_
|
|
|
1631
1847
|
'is_jshash': is_jshash,
|
|
1632
1848
|
})
|
|
1633
1849
|
|
|
1634
|
-
def set_(start, end, expr):
|
|
1850
|
+
async def set_(start, end, expr):
|
|
1635
1851
|
ostart = start
|
|
1636
1852
|
a = [new AST_SetItem({'start':start, 'end':end, 'value':expr})]
|
|
1637
1853
|
while not is_("punc", "}"):
|
|
@@ -1640,35 +1856,40 @@ def create_parser_ctx(S, import_dirs, module_id, baselib_items, imported_module_
|
|
|
1640
1856
|
if is_("punc", "}"):
|
|
1641
1857
|
# allow trailing comma
|
|
1642
1858
|
break
|
|
1643
|
-
|
|
1859
|
+
set_val = await expression(False)
|
|
1860
|
+
a.push(new AST_SetItem({'start':start, 'value':set_val, 'end':prev()}))
|
|
1644
1861
|
next()
|
|
1645
1862
|
return new AST_Set({'items':a, 'start':ostart, 'end':prev()})
|
|
1646
1863
|
|
|
1647
|
-
def read_comprehension(obj, terminator):
|
|
1864
|
+
async def read_comprehension(obj, terminator):
|
|
1648
1865
|
if is_node_type(obj, AST_GeneratorComprehension):
|
|
1649
1866
|
baselib_items['yield'] = True
|
|
1650
1867
|
S.in_comprehension = True
|
|
1651
1868
|
S.in_parenthesized_expr = False # in case we are already in a parenthesized expression
|
|
1652
1869
|
expect_token('keyword', 'for')
|
|
1653
|
-
forloop = for_(True)
|
|
1870
|
+
forloop = await for_(True)
|
|
1654
1871
|
obj.init = forloop.init
|
|
1655
1872
|
obj.name = forloop.name
|
|
1656
1873
|
obj.object = forloop.object
|
|
1657
|
-
|
|
1874
|
+
if is_('punc', terminator):
|
|
1875
|
+
obj.condition = None
|
|
1876
|
+
else:
|
|
1877
|
+
expect_token("keyword", "if")
|
|
1878
|
+
obj.condition = await expression(True)
|
|
1658
1879
|
expect(terminator)
|
|
1659
1880
|
S.in_comprehension = False
|
|
1660
1881
|
return obj
|
|
1661
1882
|
|
|
1662
|
-
def dict_comprehension(a, is_pydict, is_jshash):
|
|
1883
|
+
async def dict_comprehension(a, is_pydict, is_jshash):
|
|
1663
1884
|
if a.length:
|
|
1664
1885
|
left, right = a[0].key, a[0].value
|
|
1665
1886
|
else:
|
|
1666
|
-
left = expression(False)
|
|
1887
|
+
left = await expression(False)
|
|
1667
1888
|
if not is_('punc', ':'):
|
|
1668
|
-
return read_comprehension(new AST_SetComprehension({'statement':left}), '}')
|
|
1889
|
+
return await read_comprehension(new AST_SetComprehension({'statement':left}), '}')
|
|
1669
1890
|
expect(':')
|
|
1670
|
-
right = expression(False)
|
|
1671
|
-
return read_comprehension(new AST_DictComprehension({'statement':left, 'value_statement':right, 'is_pydict':is_pydict, 'is_jshash':is_jshash}), '}')
|
|
1891
|
+
right = await expression(False)
|
|
1892
|
+
return await read_comprehension(new AST_DictComprehension({'statement':left, 'value_statement':right, 'is_pydict':is_pydict, 'is_jshash':is_jshash}), '}')
|
|
1672
1893
|
|
|
1673
1894
|
def as_name():
|
|
1674
1895
|
tmp = S.token
|
|
@@ -1714,7 +1935,7 @@ def create_parser_ctx(S, import_dirs, module_id, baselib_items, imported_module_
|
|
|
1714
1935
|
else:
|
|
1715
1936
|
return False
|
|
1716
1937
|
|
|
1717
|
-
def getitem(expr, allow_calls):
|
|
1938
|
+
async def getitem(expr, allow_calls):
|
|
1718
1939
|
start = expr.start
|
|
1719
1940
|
next()
|
|
1720
1941
|
is_py_sub = S.scoped_flags.get('overload_getitem', False)
|
|
@@ -1724,7 +1945,7 @@ def create_parser_ctx(S, import_dirs, module_id, baselib_items, imported_module_
|
|
|
1724
1945
|
# slice [:n]
|
|
1725
1946
|
slice_bounds.push(None)
|
|
1726
1947
|
else:
|
|
1727
|
-
slice_bounds.push(expression(False))
|
|
1948
|
+
slice_bounds.push(await expression(False))
|
|
1728
1949
|
|
|
1729
1950
|
if is_("punc", ":"):
|
|
1730
1951
|
# slice [n:m?]
|
|
@@ -1733,7 +1954,7 @@ def create_parser_ctx(S, import_dirs, module_id, baselib_items, imported_module_
|
|
|
1733
1954
|
if is_("punc", ":"):
|
|
1734
1955
|
slice_bounds.push(None)
|
|
1735
1956
|
elif not is_("punc", "]"):
|
|
1736
|
-
slice_bounds.push(expression(False))
|
|
1957
|
+
slice_bounds.push(await expression(False))
|
|
1737
1958
|
|
|
1738
1959
|
if is_("punc", ":"):
|
|
1739
1960
|
# slice [n:m:o?]
|
|
@@ -1741,7 +1962,7 @@ def create_parser_ctx(S, import_dirs, module_id, baselib_items, imported_module_
|
|
|
1741
1962
|
if is_("punc", "]"):
|
|
1742
1963
|
unexpected()
|
|
1743
1964
|
else:
|
|
1744
|
-
slice_bounds.push(expression(False))
|
|
1965
|
+
slice_bounds.push(await expression(False))
|
|
1745
1966
|
|
|
1746
1967
|
expect("]")
|
|
1747
1968
|
|
|
@@ -1749,14 +1970,15 @@ def create_parser_ctx(S, import_dirs, module_id, baselib_items, imported_module_
|
|
|
1749
1970
|
if is_("operator", '='):
|
|
1750
1971
|
# splice-assignment (arr[start:end] = ...)
|
|
1751
1972
|
next() # swallow the assignment
|
|
1752
|
-
|
|
1973
|
+
splice_assign = await expression(True)
|
|
1974
|
+
return await subscripts(new AST_Splice({
|
|
1753
1975
|
'start': start,
|
|
1754
1976
|
'expression': expr,
|
|
1755
1977
|
'property': slice_bounds[0] or new AST_Number({
|
|
1756
1978
|
'value': 0
|
|
1757
1979
|
}),
|
|
1758
1980
|
'property2': slice_bounds[1],
|
|
1759
|
-
'assignment':
|
|
1981
|
+
'assignment': splice_assign,
|
|
1760
1982
|
'end': prev()
|
|
1761
1983
|
}), allow_calls)
|
|
1762
1984
|
elif slice_bounds.length is 3:
|
|
@@ -1768,26 +1990,38 @@ def create_parser_ctx(S, import_dirs, module_id, baselib_items, imported_module_
|
|
|
1768
1990
|
slice_bounds.pop()
|
|
1769
1991
|
elif not slice_bounds[-2]:
|
|
1770
1992
|
slice_bounds[-2] = new AST_Undefined()
|
|
1771
|
-
|
|
1993
|
+
_ca = v'[]'
|
|
1994
|
+
_ca.push(new AST_CallArg({'value': expr, 'is_array': False}))
|
|
1995
|
+
for _sb in slice_bounds:
|
|
1996
|
+
_ca.push(new AST_CallArg({'value': _sb, 'is_array': False}))
|
|
1997
|
+
return await subscripts(new AST_Call({
|
|
1772
1998
|
'start': start,
|
|
1773
1999
|
'expression': new AST_SymbolRef({
|
|
1774
2000
|
'name': 'ρσ_delslice' if S.in_delete else "ρσ_eslice"
|
|
1775
2001
|
}),
|
|
1776
|
-
'args': [
|
|
2002
|
+
'args': new AST_CallArgs({'args': _ca, 'kwargs': v'[]', 'kwarg_items': v'[]', 'starargs': False}),
|
|
1777
2003
|
'end': prev()
|
|
1778
2004
|
}), allow_calls)
|
|
1779
2005
|
else:
|
|
1780
2006
|
# regular slice (arr[start:end])
|
|
1781
2007
|
slice_bounds = [new AST_Number({'value':0}) if i is None else i for i in slice_bounds]
|
|
1782
2008
|
if S.in_delete:
|
|
1783
|
-
|
|
2009
|
+
_ca2 = v'[]'
|
|
2010
|
+
_ca2.push(new AST_CallArg({'value': expr, 'is_array': False}))
|
|
2011
|
+
_ca2.push(new AST_CallArg({'value': new AST_Number({'value': 1}), 'is_array': False}))
|
|
2012
|
+
for _sb in slice_bounds:
|
|
2013
|
+
_ca2.push(new AST_CallArg({'value': _sb, 'is_array': False}))
|
|
2014
|
+
return await subscripts(new AST_Call({
|
|
1784
2015
|
'start': start,
|
|
1785
2016
|
'expression': new AST_SymbolRef({'name': 'ρσ_delslice'}),
|
|
1786
|
-
'args':
|
|
2017
|
+
'args': new AST_CallArgs({'args': _ca2, 'kwargs': v'[]', 'kwarg_items': v'[]', 'starargs': False}),
|
|
1787
2018
|
'end': prev()
|
|
1788
2019
|
}), allow_calls)
|
|
1789
2020
|
|
|
1790
|
-
|
|
2021
|
+
_ca3 = v'[]'
|
|
2022
|
+
for _sb in slice_bounds:
|
|
2023
|
+
_ca3.push(new AST_CallArg({'value': _sb, 'is_array': False}))
|
|
2024
|
+
return await subscripts(new AST_Call({
|
|
1791
2025
|
'start': start,
|
|
1792
2026
|
'expression': new AST_Dot({
|
|
1793
2027
|
'start': start,
|
|
@@ -1795,7 +2029,7 @@ def create_parser_ctx(S, import_dirs, module_id, baselib_items, imported_module_
|
|
|
1795
2029
|
'property': "slice",
|
|
1796
2030
|
'end': prev()
|
|
1797
2031
|
}),
|
|
1798
|
-
'args':
|
|
2032
|
+
'args': new AST_CallArgs({'args': _ca3, 'kwargs': v'[]', 'kwarg_items': v'[]', 'starargs': False}),
|
|
1799
2033
|
'end': prev()
|
|
1800
2034
|
}), allow_calls)
|
|
1801
2035
|
else:
|
|
@@ -1806,8 +2040,8 @@ def create_parser_ctx(S, import_dirs, module_id, baselib_items, imported_module_
|
|
|
1806
2040
|
if is_("operator") and ASSIGNMENT[S.token.value]:
|
|
1807
2041
|
assign_operator = S.token.value[:-1]
|
|
1808
2042
|
next()
|
|
1809
|
-
assignment = expression(True)
|
|
1810
|
-
return subscripts(new AST_ItemAccess({
|
|
2043
|
+
assignment = await expression(True)
|
|
2044
|
+
return await subscripts(new AST_ItemAccess({
|
|
1811
2045
|
'start': start,
|
|
1812
2046
|
'expression': expr,
|
|
1813
2047
|
'property': slice_bounds[0] or new AST_Number({
|
|
@@ -1818,7 +2052,7 @@ def create_parser_ctx(S, import_dirs, module_id, baselib_items, imported_module_
|
|
|
1818
2052
|
'end': prev()
|
|
1819
2053
|
}), allow_calls)
|
|
1820
2054
|
|
|
1821
|
-
return subscripts(new AST_Sub({
|
|
2055
|
+
return await subscripts(new AST_Sub({
|
|
1822
2056
|
'start': start,
|
|
1823
2057
|
'expression': expr,
|
|
1824
2058
|
'property': slice_bounds[0] or new AST_Number({
|
|
@@ -1827,16 +2061,17 @@ def create_parser_ctx(S, import_dirs, module_id, baselib_items, imported_module_
|
|
|
1827
2061
|
'end': prev()
|
|
1828
2062
|
}), allow_calls)
|
|
1829
2063
|
|
|
1830
|
-
def call_(expr):
|
|
2064
|
+
async def call_(expr):
|
|
1831
2065
|
start = expr.start
|
|
1832
2066
|
S.in_parenthesized_expr = True
|
|
1833
2067
|
next()
|
|
1834
2068
|
if not expr.parens and get_class_in_scope(expr):
|
|
1835
2069
|
# this is an object being created using a class
|
|
1836
|
-
|
|
2070
|
+
call_args = await func_call_list()
|
|
2071
|
+
ret = await subscripts(new AST_New({
|
|
1837
2072
|
'start': start,
|
|
1838
2073
|
'expression': expr,
|
|
1839
|
-
'args':
|
|
2074
|
+
'args': call_args,
|
|
1840
2075
|
'end': prev()
|
|
1841
2076
|
}), True)
|
|
1842
2077
|
S.in_parenthesized_expr = False
|
|
@@ -1849,12 +2084,13 @@ def create_parser_ctx(S, import_dirs, module_id, baselib_items, imported_module_
|
|
|
1849
2084
|
# generate class call
|
|
1850
2085
|
funcname = expr
|
|
1851
2086
|
|
|
1852
|
-
|
|
2087
|
+
classcall_args = await func_call_list()
|
|
2088
|
+
ret = await subscripts(new AST_ClassCall({
|
|
1853
2089
|
'start': start,
|
|
1854
2090
|
"class": expr.expression,
|
|
1855
2091
|
'method': funcname.property,
|
|
1856
2092
|
"static": is_static_method(c, funcname.property),
|
|
1857
|
-
'args':
|
|
2093
|
+
'args': classcall_args,
|
|
1858
2094
|
'end': prev()
|
|
1859
2095
|
}), True)
|
|
1860
2096
|
S.in_parenthesized_expr = False
|
|
@@ -1862,39 +2098,41 @@ def create_parser_ctx(S, import_dirs, module_id, baselib_items, imported_module_
|
|
|
1862
2098
|
elif is_node_type(expr, AST_SymbolRef):
|
|
1863
2099
|
tmp_ = expr.name
|
|
1864
2100
|
if tmp_ is "jstype":
|
|
2101
|
+
jstype_args = await func_call_list()
|
|
1865
2102
|
ret = new AST_UnaryPrefix({
|
|
1866
2103
|
'start': start,
|
|
1867
2104
|
'operator': "typeof",
|
|
1868
|
-
'expression':
|
|
2105
|
+
'expression': jstype_args.args[0].value,
|
|
1869
2106
|
'end': prev()
|
|
1870
2107
|
})
|
|
1871
2108
|
S.in_parenthesized_expr = False
|
|
1872
2109
|
return ret
|
|
1873
2110
|
elif tmp_ is "isinstance":
|
|
1874
|
-
args = func_call_list()
|
|
1875
|
-
if args.length is not 2:
|
|
2111
|
+
args = await func_call_list()
|
|
2112
|
+
if args.args.length is not 2:
|
|
1876
2113
|
croak('isinstance() must be called with exactly two arguments')
|
|
1877
2114
|
ret = new AST_Binary({
|
|
1878
2115
|
'start': start,
|
|
1879
|
-
'left': args[0],
|
|
2116
|
+
'left': args.args[0].value,
|
|
1880
2117
|
'operator': 'instanceof',
|
|
1881
|
-
'right': args[1],
|
|
2118
|
+
'right': args.args[1].value,
|
|
1882
2119
|
'end': prev()
|
|
1883
2120
|
})
|
|
1884
2121
|
S.in_parenthesized_expr = False
|
|
1885
2122
|
return ret
|
|
1886
2123
|
|
|
1887
2124
|
# fall-through to basic function call
|
|
1888
|
-
|
|
2125
|
+
basic_args = await func_call_list()
|
|
2126
|
+
ret = await subscripts(new AST_Call({
|
|
1889
2127
|
'start': start,
|
|
1890
2128
|
'expression': expr,
|
|
1891
|
-
'args':
|
|
2129
|
+
'args': basic_args,
|
|
1892
2130
|
'end': prev()
|
|
1893
2131
|
}), True)
|
|
1894
2132
|
S.in_parenthesized_expr = False
|
|
1895
2133
|
return ret
|
|
1896
2134
|
|
|
1897
|
-
def get_attr(expr, allow_calls):
|
|
2135
|
+
async def get_attr(expr, allow_calls):
|
|
1898
2136
|
next()
|
|
1899
2137
|
prop = as_name()
|
|
1900
2138
|
c = get_class_in_scope(expr)
|
|
@@ -1903,14 +2141,14 @@ def create_parser_ctx(S, import_dirs, module_id, baselib_items, imported_module_
|
|
|
1903
2141
|
if classvars and v'classvars[prop]':
|
|
1904
2142
|
prop = 'prototype.' + prop
|
|
1905
2143
|
|
|
1906
|
-
return subscripts(new AST_Dot({
|
|
2144
|
+
return await subscripts(new AST_Dot({
|
|
1907
2145
|
'start': expr.start,
|
|
1908
2146
|
'expression': expr,
|
|
1909
2147
|
'property': prop,
|
|
1910
2148
|
'end': prev()
|
|
1911
2149
|
}), allow_calls)
|
|
1912
2150
|
|
|
1913
|
-
def existential(expr, allow_calls):
|
|
2151
|
+
async def existential(expr, allow_calls):
|
|
1914
2152
|
ans = new AST_Existential({'start':expr.start, 'end':S.token, 'expression':expr})
|
|
1915
2153
|
next()
|
|
1916
2154
|
ttype = S.token.type
|
|
@@ -1931,34 +2169,34 @@ def create_parser_ctx(S, import_dirs, module_id, baselib_items, imported_module_
|
|
|
1931
2169
|
else:
|
|
1932
2170
|
ans.after = None
|
|
1933
2171
|
return ans
|
|
1934
|
-
return subscripts(ans, allow_calls)
|
|
2172
|
+
return await subscripts(ans, allow_calls)
|
|
1935
2173
|
|
|
1936
|
-
ans.after = expression()
|
|
2174
|
+
ans.after = await expression()
|
|
1937
2175
|
return ans
|
|
1938
2176
|
|
|
1939
|
-
def subscripts(expr, allow_calls):
|
|
2177
|
+
async def subscripts(expr, allow_calls):
|
|
1940
2178
|
if is_("punc", "."):
|
|
1941
|
-
return get_attr(expr, allow_calls)
|
|
2179
|
+
return await get_attr(expr, allow_calls)
|
|
1942
2180
|
|
|
1943
2181
|
if is_("punc", "[") and not S.token.nlb:
|
|
1944
|
-
return getitem(expr, allow_calls)
|
|
2182
|
+
return await getitem(expr, allow_calls)
|
|
1945
2183
|
|
|
1946
2184
|
if allow_calls and is_("punc", "(") and not S.token.nlb:
|
|
1947
|
-
return call_(expr)
|
|
2185
|
+
return await call_(expr)
|
|
1948
2186
|
|
|
1949
2187
|
if is_('punc', '?'):
|
|
1950
|
-
return existential(expr, allow_calls)
|
|
2188
|
+
return await existential(expr, allow_calls)
|
|
1951
2189
|
|
|
1952
2190
|
return expr
|
|
1953
2191
|
|
|
1954
|
-
def maybe_unary(allow_calls):
|
|
2192
|
+
async def maybe_unary(allow_calls):
|
|
1955
2193
|
start = S.token
|
|
1956
2194
|
if is_('operator', '@'):
|
|
1957
2195
|
if S.parsing_decorator:
|
|
1958
2196
|
croak('Nested decorators are not allowed')
|
|
1959
2197
|
next()
|
|
1960
2198
|
S.parsing_decorator = True
|
|
1961
|
-
expr = expression()
|
|
2199
|
+
expr = await expression()
|
|
1962
2200
|
S.parsing_decorator = False
|
|
1963
2201
|
S.decorators.push(expr)
|
|
1964
2202
|
return new AST_EmptyStatement({'stype':'@', 'start':prev(), 'end':prev()})
|
|
@@ -1966,14 +2204,14 @@ def create_parser_ctx(S, import_dirs, module_id, baselib_items, imported_module_
|
|
|
1966
2204
|
next()
|
|
1967
2205
|
is_parenthesized = is_('punc', '(')
|
|
1968
2206
|
S.in_delete = start.value is 'delete'
|
|
1969
|
-
expr = maybe_unary(allow_calls)
|
|
2207
|
+
expr = await maybe_unary(allow_calls)
|
|
1970
2208
|
S.in_delete = False
|
|
1971
2209
|
ex = make_unary(AST_UnaryPrefix, start.value, expr, is_parenthesized)
|
|
1972
2210
|
ex.start = start
|
|
1973
2211
|
ex.end = prev()
|
|
1974
2212
|
return ex
|
|
1975
2213
|
|
|
1976
|
-
val = expr_atom(allow_calls)
|
|
2214
|
+
val = await expr_atom(allow_calls)
|
|
1977
2215
|
return val
|
|
1978
2216
|
|
|
1979
2217
|
def make_unary(ctor, op, expr, is_parenthesized):
|
|
@@ -1983,7 +2221,7 @@ def create_parser_ctx(S, import_dirs, module_id, baselib_items, imported_module_
|
|
|
1983
2221
|
'parenthesized': is_parenthesized
|
|
1984
2222
|
})
|
|
1985
2223
|
|
|
1986
|
-
def expr_op(left, min_prec, no_in):
|
|
2224
|
+
async def expr_op(left, min_prec, no_in):
|
|
1987
2225
|
op = S.token.value if is_('operator') else None
|
|
1988
2226
|
if op is "!" and peek().type is "operator" and peek().value is "in":
|
|
1989
2227
|
next()
|
|
@@ -1995,7 +2233,7 @@ def create_parser_ctx(S, import_dirs, module_id, baselib_items, imported_module_
|
|
|
1995
2233
|
prec = PRECEDENCE[op] if op is not None else None
|
|
1996
2234
|
if prec is not None and prec > min_prec:
|
|
1997
2235
|
next()
|
|
1998
|
-
right = expr_op(maybe_unary(True), prec, no_in)
|
|
2236
|
+
right = await expr_op(await maybe_unary(True), prec, no_in)
|
|
1999
2237
|
ret = new AST_Binary({
|
|
2000
2238
|
'start': left.start,
|
|
2001
2239
|
'left': left,
|
|
@@ -2003,24 +2241,25 @@ def create_parser_ctx(S, import_dirs, module_id, baselib_items, imported_module_
|
|
|
2003
2241
|
'right': right,
|
|
2004
2242
|
'end': right.end
|
|
2005
2243
|
})
|
|
2006
|
-
return expr_op(ret, min_prec, no_in)
|
|
2244
|
+
return await expr_op(ret, min_prec, no_in)
|
|
2007
2245
|
return left
|
|
2008
2246
|
|
|
2009
|
-
def expr_ops(no_in):
|
|
2010
|
-
return expr_op(maybe_unary(True), 0, no_in)
|
|
2247
|
+
async def expr_ops(no_in):
|
|
2248
|
+
return await expr_op(await maybe_unary(True), 0, no_in)
|
|
2011
2249
|
|
|
2012
|
-
def maybe_conditional(no_in):
|
|
2250
|
+
async def maybe_conditional(no_in):
|
|
2013
2251
|
start = S.token
|
|
2014
|
-
expr = expr_ops(no_in)
|
|
2252
|
+
expr = await expr_ops(no_in)
|
|
2015
2253
|
if (is_('keyword', 'if') and (S.in_parenthesized_expr or (S.statement_starting_token is not S.token and not S.in_comprehension and not S.token.nlb))):
|
|
2016
2254
|
next()
|
|
2017
|
-
ne = expression(False)
|
|
2255
|
+
ne = await expression(False)
|
|
2018
2256
|
expect_token('keyword', 'else')
|
|
2257
|
+
cond_alt = await expression(False, no_in)
|
|
2019
2258
|
conditional = new AST_Conditional({
|
|
2020
2259
|
'start': start,
|
|
2021
2260
|
'condition': ne,
|
|
2022
2261
|
'consequent': expr,
|
|
2023
|
-
'alternative':
|
|
2262
|
+
'alternative': cond_alt,
|
|
2024
2263
|
'end': peek()
|
|
2025
2264
|
})
|
|
2026
2265
|
return conditional
|
|
@@ -2044,28 +2283,29 @@ def create_parser_ctx(S, import_dirs, module_id, baselib_items, imported_module_
|
|
|
2044
2283
|
c.provisional_classvars[ans.left.name] = True
|
|
2045
2284
|
return ans
|
|
2046
2285
|
|
|
2047
|
-
def maybe_assign(no_in, only_plain_assignment):
|
|
2286
|
+
async def maybe_assign(no_in, only_plain_assignment):
|
|
2048
2287
|
start = S.token
|
|
2049
|
-
left = maybe_conditional(no_in)
|
|
2288
|
+
left = await maybe_conditional(no_in)
|
|
2050
2289
|
val = S.token.value
|
|
2051
2290
|
if is_("operator") and ASSIGNMENT[val]:
|
|
2052
2291
|
if only_plain_assignment and val is not '=':
|
|
2053
2292
|
croak('Invalid assignment operator for chained assignment: ' + val)
|
|
2054
2293
|
next()
|
|
2294
|
+
assign_right = await maybe_assign(no_in, True)
|
|
2055
2295
|
return create_assign({
|
|
2056
2296
|
'start': start,
|
|
2057
2297
|
'left': left,
|
|
2058
2298
|
'operator': val,
|
|
2059
|
-
'right':
|
|
2299
|
+
'right': assign_right,
|
|
2060
2300
|
'end': prev()
|
|
2061
2301
|
})
|
|
2062
2302
|
return left
|
|
2063
2303
|
|
|
2064
|
-
def expression(commas, no_in):
|
|
2304
|
+
async def expression(commas, no_in):
|
|
2065
2305
|
# if there is an assignment, we want the sequences to pivot
|
|
2066
2306
|
# around it to allow for tuple packing/unpacking
|
|
2067
2307
|
start = S.token
|
|
2068
|
-
expr = maybe_assign(no_in)
|
|
2308
|
+
expr = await maybe_assign(no_in)
|
|
2069
2309
|
def build_seq(a):
|
|
2070
2310
|
if a.length is 1:
|
|
2071
2311
|
return a[0]
|
|
@@ -2082,6 +2322,7 @@ def create_parser_ctx(S, import_dirs, module_id, baselib_items, imported_module_
|
|
|
2082
2322
|
next()
|
|
2083
2323
|
if is_node_type(expr, AST_Assign):
|
|
2084
2324
|
left[-1] = left[-1].left
|
|
2325
|
+
seq_cdr = await expression(True, no_in)
|
|
2085
2326
|
return create_assign({
|
|
2086
2327
|
'start': start,
|
|
2087
2328
|
'left': (left[0] if left.length is 1 else new AST_Array({
|
|
@@ -2090,12 +2331,12 @@ def create_parser_ctx(S, import_dirs, module_id, baselib_items, imported_module_
|
|
|
2090
2331
|
'operator': expr.operator,
|
|
2091
2332
|
'right': new AST_Seq({
|
|
2092
2333
|
'car': expr.right,
|
|
2093
|
-
'cdr':
|
|
2334
|
+
'cdr': seq_cdr
|
|
2094
2335
|
}),
|
|
2095
2336
|
'end': peek()
|
|
2096
2337
|
})
|
|
2097
2338
|
|
|
2098
|
-
expr = maybe_assign(no_in)
|
|
2339
|
+
expr = await maybe_assign(no_in)
|
|
2099
2340
|
left.push(expr)
|
|
2100
2341
|
|
|
2101
2342
|
# if last one was an assignment, fix it
|
|
@@ -2114,20 +2355,30 @@ def create_parser_ctx(S, import_dirs, module_id, baselib_items, imported_module_
|
|
|
2114
2355
|
return build_seq(left)
|
|
2115
2356
|
return expr
|
|
2116
2357
|
|
|
2117
|
-
def in_loop(cont):
|
|
2358
|
+
async def in_loop(cont):
|
|
2118
2359
|
S.in_loop += 1
|
|
2119
|
-
ret = cont()
|
|
2360
|
+
ret = await cont()
|
|
2120
2361
|
S.in_loop -= 1
|
|
2121
2362
|
return ret
|
|
2122
2363
|
|
|
2123
|
-
def run_parser():
|
|
2364
|
+
async def run_parser():
|
|
2124
2365
|
start = S.token = next()
|
|
2125
2366
|
body = v'[]'
|
|
2126
2367
|
docstrings = v'[]'
|
|
2127
2368
|
first_token = True
|
|
2128
2369
|
toplevel = options.toplevel
|
|
2129
2370
|
while not is_("eof"):
|
|
2130
|
-
|
|
2371
|
+
if options.recover_errors:
|
|
2372
|
+
try:
|
|
2373
|
+
element = await statement()
|
|
2374
|
+
except as rerr:
|
|
2375
|
+
if is_recoverable_error(rerr):
|
|
2376
|
+
record_recovery(rerr)
|
|
2377
|
+
await skip_to_recovery_point()
|
|
2378
|
+
continue
|
|
2379
|
+
raise
|
|
2380
|
+
else:
|
|
2381
|
+
element = await statement()
|
|
2131
2382
|
if first_token and is_node_type(element, AST_Directive) and element.value.indexOf('#!') is 0:
|
|
2132
2383
|
shebang = element.value
|
|
2133
2384
|
else:
|
|
@@ -2152,6 +2403,18 @@ def create_parser_ctx(S, import_dirs, module_id, baselib_items, imported_module_
|
|
|
2152
2403
|
'docstrings': docstrings,
|
|
2153
2404
|
})
|
|
2154
2405
|
|
|
2406
|
+
if options.recover_errors:
|
|
2407
|
+
# Combine parser-level recovered errors with any collected by the
|
|
2408
|
+
# tokenizer (e.g. skipped unexpected characters) for the LSP to report.
|
|
2409
|
+
recovered = S.recovered_errors
|
|
2410
|
+
try:
|
|
2411
|
+
tok_ctx = S.input.context()
|
|
2412
|
+
if tok_ctx and tok_ctx.recovered_errors and tok_ctx.recovered_errors.length:
|
|
2413
|
+
recovered = recovered.concat(tok_ctx.recovered_errors)
|
|
2414
|
+
except:
|
|
2415
|
+
pass
|
|
2416
|
+
toplevel.recovered_errors = recovered
|
|
2417
|
+
|
|
2155
2418
|
toplevel.nonlocalvars = scan_for_nonlocal_defs(toplevel.body).concat(S.globals)
|
|
2156
2419
|
toplevel.localvars = []
|
|
2157
2420
|
toplevel.exports = []
|
|
@@ -2182,11 +2445,89 @@ def create_parser_ctx(S, import_dirs, module_id, baselib_items, imported_module_
|
|
|
2182
2445
|
toplevel.scoped_flags = S.scoped_flags.stack[0]
|
|
2183
2446
|
importing_modules[module_id] = False
|
|
2184
2447
|
toplevel.comments_after = S.token.comments_before or v'[]'
|
|
2448
|
+
|
|
2449
|
+
if options._src_hash and options.filename and module_id is not '__main__':
|
|
2450
|
+
try:
|
|
2451
|
+
# Simplified class info (no full AST nodes) for lazy-shell reconstruction.
|
|
2452
|
+
classes_cache = {}
|
|
2453
|
+
for cname in Object.keys(toplevel.classes or {}):
|
|
2454
|
+
cls = toplevel.classes[cname]
|
|
2455
|
+
classes_cache[cname] = {'static': cls.static or {}, 'bound': cls.bound or [], 'classvars': cls.classvars or {}}
|
|
2456
|
+
# Single pass: compute has_side_effects + tree-shaking index.
|
|
2457
|
+
# The index lets the tree-shaker resolve the fixpoint iteration
|
|
2458
|
+
# (steps 4-5) without accessing mod.body — no AST deserialization
|
|
2459
|
+
# until step 6 (pruning), which needs actual nodes anyway.
|
|
2460
|
+
has_se = False
|
|
2461
|
+
idx_exec_refs_set = {}
|
|
2462
|
+
idx_import_bindings = {}
|
|
2463
|
+
idx_top_defs = {}
|
|
2464
|
+
|
|
2465
|
+
def _collect_refs_into(node, refs_set): # noqa
|
|
2466
|
+
def _rv(n): # noqa
|
|
2467
|
+
if is_node_type(n, AST_SymbolRef):
|
|
2468
|
+
refs_set[n.name] = True
|
|
2469
|
+
node.walk(new TreeWalker(_rv))
|
|
2470
|
+
|
|
2471
|
+
for idx_stmt in toplevel.body:
|
|
2472
|
+
if is_node_type(idx_stmt, AST_Function) or is_node_type(idx_stmt, AST_Class):
|
|
2473
|
+
if idx_stmt.name:
|
|
2474
|
+
idx_pinned = False
|
|
2475
|
+
if idx_stmt.decorators:
|
|
2476
|
+
for idx_dec in idx_stmt.decorators:
|
|
2477
|
+
if idx_dec.expression and is_node_type(idx_dec.expression, AST_SymbolRef) and idx_dec.expression.name == 'no_prune':
|
|
2478
|
+
idx_pinned = True
|
|
2479
|
+
break
|
|
2480
|
+
idx_def_refs = {}
|
|
2481
|
+
_collect_refs_into(idx_stmt, idx_def_refs)
|
|
2482
|
+
idx_top_defs[idx_stmt.name.name] = {'pinned': idx_pinned, 'refs': Object.keys(idx_def_refs)}
|
|
2483
|
+
elif is_node_type(idx_stmt, AST_Imports):
|
|
2484
|
+
for idx_imp in idx_stmt.imports:
|
|
2485
|
+
if idx_imp.argnames and idx_imp.argnames.length:
|
|
2486
|
+
for idx_arg in idx_imp.argnames:
|
|
2487
|
+
idx_local = idx_arg.alias.name if idx_arg.alias else idx_arg.name
|
|
2488
|
+
idx_import_bindings[idx_local] = {'source': idx_imp.key, 'imported_name': idx_arg.name, 'is_namespace': False}
|
|
2489
|
+
else:
|
|
2490
|
+
idx_local = idx_imp.alias.name if idx_imp.alias else idx_imp.key.split('.')[0]
|
|
2491
|
+
idx_import_bindings[idx_local] = {'source': idx_imp.key, 'imported_name': None, 'is_namespace': True}
|
|
2492
|
+
else:
|
|
2493
|
+
if not has_se:
|
|
2494
|
+
se_found = v'[false]'
|
|
2495
|
+
def se_check(se_node, se_descend): # noqa
|
|
2496
|
+
if is_node_type(se_node, AST_Call):
|
|
2497
|
+
se_found[0] = True
|
|
2498
|
+
return True
|
|
2499
|
+
idx_stmt.walk(new TreeWalker(se_check))
|
|
2500
|
+
if se_found[0]:
|
|
2501
|
+
has_se = True
|
|
2502
|
+
_collect_refs_into(idx_stmt, idx_exec_refs_set)
|
|
2503
|
+
|
|
2504
|
+
cache_meta = {
|
|
2505
|
+
'v': CACHE_VERSION,
|
|
2506
|
+
'signature': options._src_hash,
|
|
2507
|
+
'compiler_version': COMPILER_VERSION,
|
|
2508
|
+
'imported_module_ids': toplevel.imported_module_ids,
|
|
2509
|
+
'exported_names': [sym.name for sym in toplevel.exports],
|
|
2510
|
+
'baselib': toplevel.baselib or {},
|
|
2511
|
+
'classes': classes_cache,
|
|
2512
|
+
'has_side_effects': has_se,
|
|
2513
|
+
'index': {
|
|
2514
|
+
'exec_refs': Object.keys(idx_exec_refs_set),
|
|
2515
|
+
'import_bindings': idx_import_bindings,
|
|
2516
|
+
'top_defs': idx_top_defs,
|
|
2517
|
+
},
|
|
2518
|
+
}
|
|
2519
|
+
if options._file_mtime is not None and options._file_mtime is not undefined:
|
|
2520
|
+
cache_meta['mtime'] = options._file_mtime
|
|
2521
|
+
# Binary format: metadata JSON followed by newline and binary AST pool.
|
|
2522
|
+
await writefile(cache_file_name(options.filename, options.module_cache_dir), encode_cache(JSON.stringify(cache_meta), toplevel))
|
|
2523
|
+
except as e:
|
|
2524
|
+
console.error('Failed to write AST cache file:', options.filename, 'with error:', e)
|
|
2525
|
+
|
|
2185
2526
|
return toplevel
|
|
2186
2527
|
|
|
2187
2528
|
return run_parser
|
|
2188
2529
|
|
|
2189
|
-
def parse(text, options):
|
|
2530
|
+
async def parse(text, options):
|
|
2190
2531
|
options = defaults(options, {
|
|
2191
2532
|
'filename': None, # name of the file being parsed
|
|
2192
2533
|
'module_id':'__main__', # The id of the module being parsed
|
|
@@ -2197,6 +2538,7 @@ def parse(text, options):
|
|
|
2197
2538
|
'scoped_flags': {}, # Global scoped flags (used by the REPL)
|
|
2198
2539
|
'discard_asserts': False,
|
|
2199
2540
|
'module_cache_dir': '',
|
|
2541
|
+
'recover_errors': False, # When True, continue parsing past syntax errors (used by the LSP). See run_parser/block_.
|
|
2200
2542
|
})
|
|
2201
2543
|
import_dirs = [x for x in options.import_dirs]
|
|
2202
2544
|
for location in v'[options.libdir, options.basedir]':
|
|
@@ -2207,11 +2549,16 @@ def parse(text, options):
|
|
|
2207
2549
|
imported_module_ids = []
|
|
2208
2550
|
imported_modules = options.imported_modules or {}
|
|
2209
2551
|
importing_modules = options.importing_modules or {}
|
|
2552
|
+
# loading_promises tracks modules currently being loaded across the entire compilation.
|
|
2553
|
+
# It is shared by passing it through options so parallel sub-parse() calls all see it.
|
|
2554
|
+
if not options.loading_promises:
|
|
2555
|
+
options.loading_promises = {}
|
|
2210
2556
|
importing_modules[module_id] = True
|
|
2211
2557
|
|
|
2212
2558
|
# The internal state of the parser
|
|
2213
2559
|
S = {
|
|
2214
|
-
'input': tokenizer(text, options.filename) if jstype(text) is 'string' else text,
|
|
2560
|
+
'input': tokenizer(text, options.filename, options.recover_errors) if jstype(text) is 'string' else text,
|
|
2561
|
+
'recovered_errors': v'[]', # syntax errors swallowed during recovery (recover_errors mode only)
|
|
2215
2562
|
'token': None,
|
|
2216
2563
|
'prev': None,
|
|
2217
2564
|
'peeked': [],
|
|
@@ -2249,4 +2596,7 @@ def parse(text, options):
|
|
|
2249
2596
|
obj = options.classes[cname]
|
|
2250
2597
|
S.classes[0][cname] = { 'static':obj.static, 'bound':obj.bound, 'classvars': obj.classvars }
|
|
2251
2598
|
|
|
2252
|
-
|
|
2599
|
+
if jstype(text) is 'string' and not options._src_hash:
|
|
2600
|
+
options._src_hash = sha1sum(text)
|
|
2601
|
+
|
|
2602
|
+
return await create_parser_ctx(S, import_dirs, module_id, baselib_items, imported_module_ids, imported_modules, importing_modules, options)()
|