rapydscript-ng 0.7.24 → 0.8.1
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 +28 -0
- package/README.md +80 -26
- package/bin/build.ts +117 -0
- package/bin/package.json +1 -0
- package/bin/rapydscript +65 -62
- package/build_wheels.py +133 -0
- package/editor-plugins/README.md +80 -0
- package/editor-plugins/nvim.lua +321 -0
- package/local-agent.md +28 -0
- package/package.json +4 -5
- package/publish.py +27 -17
- package/release/baselib-plain-pretty.js +448 -326
- package/release/baselib-plain-ugly.js +3 -3
- package/release/compiler.js +9027 -8139
- package/release/signatures.json +27 -27
- package/release/stdlib_modules.json +1 -0
- package/src/ast.pyj +428 -280
- package/src/baselib-builtins.pyj +49 -28
- package/src/baselib-containers.pyj +241 -226
- package/src/baselib-errors.pyj +8 -1
- package/src/baselib-internal.pyj +38 -23
- package/src/baselib-itertools.pyj +13 -7
- package/src/baselib-str.pyj +59 -84
- package/src/compiler.pyj +4 -4
- package/src/errors.pyj +3 -4
- package/src/lib/aes.pyj +46 -32
- package/src/lib/elementmaker.pyj +11 -9
- package/src/lib/encodings.pyj +15 -5
- package/src/lib/gettext.pyj +9 -4
- package/src/lib/math.pyj +106 -45
- package/src/lib/operator.pyj +10 -10
- package/src/lib/pythonize.pyj +2 -1
- package/src/lib/random.pyj +28 -21
- package/src/lib/re.pyj +492 -19
- package/src/lib/traceback.pyj +171 -29
- package/src/lib/uuid.pyj +2 -2
- package/src/output/classes.pyj +28 -27
- package/src/output/codegen.pyj +87 -83
- package/src/output/comments.pyj +8 -8
- package/src/output/exceptions.pyj +20 -21
- package/src/output/functions.pyj +66 -64
- package/src/output/literals.pyj +24 -23
- package/src/output/loops.pyj +84 -142
- package/src/output/modules.pyj +55 -68
- package/src/output/operators.pyj +40 -29
- package/src/output/statements.pyj +21 -15
- package/src/output/stream.pyj +82 -56
- package/src/output/utils.pyj +12 -8
- package/src/parse.pyj +971 -620
- package/src/string_interpolation.pyj +5 -3
- package/src/tokenizer.pyj +188 -148
- package/src/utils.pyj +32 -15
- 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 +291 -0
- package/test/generic.pyj +16 -3
- package/test/imports.pyj +8 -6
- package/test/internationalization.pyj +38 -37
- package/test/lint.pyj +120 -117
- package/test/lsp.pyj +257 -0
- package/test/repl.pyj +70 -65
- package/test/sourcemaps.pyj +315 -0
- package/test/starargs.pyj +46 -39
- package/test/str.pyj +8 -0
- 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 +531 -0
- package/tools/compile.mjs +205 -0
- package/tools/compiler.mjs +159 -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 +975 -0
- package/tools/{gettext.js → gettext.mjs} +46 -53
- package/tools/ini.mjs +175 -0
- package/tools/{lint.js → lint.mjs} +78 -55
- package/tools/lsp.mjs +964 -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} +56 -42
- package/tools/{self.js → self.mjs} +71 -46
- package/tools/sourcemap.mjs +123 -0
- package/tools/test.mjs +252 -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 +97 -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/highlights.scm +232 -0
- package/tree-sitter/queries/indents.scm +64 -0
- package/tree-sitter/queries/injections.scm +14 -0
- package/tree-sitter/queries/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/ini.js +0 -65
- package/tools/test.js +0 -110
package/src/parse.pyj
CHANGED
|
@@ -1,13 +1,11 @@
|
|
|
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
|
-
from utils import make_predicate, array_to_hash, defaults, has_prop, cache_file_name
|
|
7
|
-
from errors import SyntaxError, ImportError
|
|
8
6
|
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,
|
|
7
|
+
AST_ArgsDef, AST_Array, AST_Assign, AST_Binary, AST_BlockStatement, AST_Break,
|
|
8
|
+
AST_Call, AST_CallArg, AST_CallArgs, AST_Catch, AST_Class, AST_ClassCall, AST_Conditional,
|
|
11
9
|
AST_Constant, AST_Continue, AST_DWLoop, AST_Debugger, AST_Decorator,
|
|
12
10
|
AST_Definitions, AST_DictComprehension, AST_Directive, AST_Do, AST_Dot,
|
|
13
11
|
AST_Else, AST_EmptyStatement, AST_Except, AST_ExpressiveObject, AST_False, AST_Finally,
|
|
@@ -21,13 +19,16 @@ AST_SymbolCatch, AST_SymbolDefun, AST_SymbolFunarg,
|
|
|
21
19
|
AST_SymbolLambda, AST_SymbolNonlocal, AST_SymbolRef, AST_SymbolVar, AST_This,
|
|
22
20
|
AST_Throw, AST_Toplevel, AST_True, AST_Try, AST_UnaryPrefix,
|
|
23
21
|
AST_Undefined, AST_Var, AST_VarDef, AST_Verbatim, AST_While, AST_With, AST_WithClause,
|
|
24
|
-
AST_Yield, AST_Assert, AST_Existential, is_node_type
|
|
22
|
+
AST_Yield, AST_Await, AST_Assert, AST_Existential, is_node_type, TreeWalker
|
|
25
23
|
)
|
|
24
|
+
from errors import SyntaxError, ImportError
|
|
26
25
|
from tokenizer import tokenizer, is_token, RESERVED_WORDS
|
|
26
|
+
from utils import make_predicate, array_to_hash, defaults, has_prop, cache_file_name
|
|
27
27
|
|
|
28
28
|
|
|
29
29
|
COMPILER_VERSION = '__COMPILER_VERSION__'
|
|
30
|
-
PYTHON_FLAGS = {'dict_literals':True, 'overload_getitem':True, 'bound_methods':True, 'hash_literals':True}
|
|
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():
|
|
@@ -35,7 +36,7 @@ def get_compiler_version():
|
|
|
35
36
|
|
|
36
37
|
|
|
37
38
|
def static_predicate(names):
|
|
38
|
-
return {k:True for k in names.split(' ')}
|
|
39
|
+
return {k: True for k in names.split(' ')}
|
|
39
40
|
|
|
40
41
|
NATIVE_CLASSES = {
|
|
41
42
|
'Image': {},
|
|
@@ -59,14 +60,14 @@ NATIVE_CLASSES = {
|
|
|
59
60
|
)
|
|
60
61
|
},
|
|
61
62
|
'String': {
|
|
62
|
-
'static': static_predicate(
|
|
63
|
+
'static': static_predicate('fromCharCode')
|
|
63
64
|
},
|
|
64
65
|
'Array': {
|
|
65
|
-
'static': static_predicate(
|
|
66
|
+
'static': static_predicate('isArray from of')
|
|
66
67
|
},
|
|
67
68
|
'Function': {},
|
|
68
69
|
'Date': {
|
|
69
|
-
'static': static_predicate(
|
|
70
|
+
'static': static_predicate('UTC now parse')
|
|
70
71
|
},
|
|
71
72
|
'ArrayBuffer': {
|
|
72
73
|
'static': static_predicate('isView transfer')
|
|
@@ -116,34 +117,35 @@ UNARY_PREFIX = make_predicate('typeof void delete ~ - + ! @')
|
|
|
116
117
|
|
|
117
118
|
ASSIGNMENT = make_predicate('= += -= /= //= *= %= >>= <<= >>>= |= ^= &=')
|
|
118
119
|
|
|
119
|
-
PRECEDENCE = (def(a, ret):
|
|
120
|
+
PRECEDENCE = (def (a, ret):
|
|
120
121
|
for i in range(a.length):
|
|
121
122
|
b = a[i]
|
|
122
123
|
for j in range(b.length):
|
|
123
|
-
ret[b[j]] = i+1
|
|
124
|
+
ret[b[j]] = i + 1
|
|
124
125
|
return ret
|
|
125
126
|
)([
|
|
126
127
|
# lowest precedence
|
|
127
|
-
[
|
|
128
|
-
[
|
|
129
|
-
[
|
|
130
|
-
[
|
|
131
|
-
[
|
|
132
|
-
[
|
|
133
|
-
[
|
|
134
|
-
[
|
|
135
|
-
[
|
|
136
|
-
[
|
|
137
|
-
[
|
|
128
|
+
['||'],
|
|
129
|
+
['&&'],
|
|
130
|
+
['|'],
|
|
131
|
+
['^'],
|
|
132
|
+
['&'],
|
|
133
|
+
['==', '===', '!=', '!=='],
|
|
134
|
+
['<', '>', '<=', '>=', 'in', 'nin', 'instanceof'],
|
|
135
|
+
['>>', '<<', '>>>'],
|
|
136
|
+
['+', '-'],
|
|
137
|
+
['*', '/', '//', '%'],
|
|
138
|
+
['**']
|
|
138
139
|
# highest precedence
|
|
139
140
|
], {})
|
|
140
141
|
|
|
141
|
-
STATEMENTS_WITH_LABELS = array_to_hash([
|
|
142
|
+
STATEMENTS_WITH_LABELS = array_to_hash(['for', 'do', 'while', 'switch'])
|
|
142
143
|
|
|
143
|
-
ATOMIC_START_TOKEN = array_to_hash([
|
|
144
|
+
ATOMIC_START_TOKEN = array_to_hash(['atom', 'num', 'string', 'regexp', 'name', 'js'])
|
|
144
145
|
|
|
145
146
|
compile_time_decorators = ['staticmethod', 'external', 'property']
|
|
146
147
|
|
|
148
|
+
|
|
147
149
|
def has_simple_decorator(decorators, name):
|
|
148
150
|
remove = v'[]'
|
|
149
151
|
for v'var i = 0; i < decorators.length; i++':
|
|
@@ -157,6 +159,7 @@ def has_simple_decorator(decorators, name):
|
|
|
157
159
|
return True
|
|
158
160
|
return False
|
|
159
161
|
|
|
162
|
+
|
|
160
163
|
def has_setter_decorator(decorators, name):
|
|
161
164
|
remove = v'[]'
|
|
162
165
|
for v'var i = 0; i < decorators.length; i++':
|
|
@@ -170,9 +173,9 @@ def has_setter_decorator(decorators, name):
|
|
|
170
173
|
return True
|
|
171
174
|
return False
|
|
172
175
|
|
|
176
|
+
|
|
173
177
|
# -----[ Parser ]-----
|
|
174
178
|
def create_parser_ctx(S, import_dirs, module_id, baselib_items, imported_module_ids, imported_modules, importing_modules, options):
|
|
175
|
-
|
|
176
179
|
def next():
|
|
177
180
|
S.prev = S.token
|
|
178
181
|
if S.peeked.length:
|
|
@@ -206,26 +209,61 @@ def create_parser_ctx(S, import_dirs, module_id, baselib_items, imported_module_
|
|
|
206
209
|
def unexpected(token):
|
|
207
210
|
if token is undefined:
|
|
208
211
|
token = S.token
|
|
209
|
-
token_error(token,
|
|
212
|
+
token_error(token, 'Unexpected token: ' + token.type + ' «' + token.value + '»')
|
|
213
|
+
|
|
214
|
+
# --- Error recovery (only active when options.recover_errors is True) --------
|
|
215
|
+
# These helpers let the LSP obtain a usable AST from a file that contains
|
|
216
|
+
# syntax errors. They are never invoked on the normal compile path, so they
|
|
217
|
+
# cannot introduce a performance or behavior regression there.
|
|
218
|
+
|
|
219
|
+
def is_recoverable_error(e):
|
|
220
|
+
return v'e instanceof SyntaxError'
|
|
221
|
+
|
|
222
|
+
def record_recovery(e):
|
|
223
|
+
S.recovered_errors.push({
|
|
224
|
+
'message': e.message, 'line': e.line, 'col': e.col, 'pos': e.pos,
|
|
225
|
+
'endpos': e.endpos, 'is_eof': e.is_eof,
|
|
226
|
+
})
|
|
227
|
+
|
|
228
|
+
async def skip_to_recovery_point():
|
|
229
|
+
# Resynchronize after a syntax error: always consume at least one token
|
|
230
|
+
# (guaranteeing forward progress) then stop at the start of the next
|
|
231
|
+
# logical line, a block dedent, or eof. next() may itself raise a
|
|
232
|
+
# tokenizer level SyntaxError (e.g. an unterminated string on the skipped
|
|
233
|
+
# line); such errors are recorded and skipping continues. The tokenizer
|
|
234
|
+
# advances its position for every such error (and never raises for an
|
|
235
|
+
# unexpected character in recover mode), so this loop always terminates.
|
|
236
|
+
while not is_('eof'):
|
|
237
|
+
try:
|
|
238
|
+
next()
|
|
239
|
+
except as e:
|
|
240
|
+
if is_recoverable_error(e):
|
|
241
|
+
record_recovery(e)
|
|
242
|
+
if is_('eof'):
|
|
243
|
+
return
|
|
244
|
+
continue
|
|
245
|
+
raise
|
|
246
|
+
if is_('eof') or is_('punc', '}') or S.token.nlb:
|
|
247
|
+
return
|
|
210
248
|
|
|
211
249
|
def expect_token(type, val):
|
|
212
250
|
if is_(type, val):
|
|
213
251
|
return next()
|
|
214
|
-
token_error(S.token,
|
|
215
|
-
|
|
252
|
+
token_error(S.token, 'Unexpected token ' + S.token.type + ' «' + S.token.value + '»' +
|
|
253
|
+
', expected ' + type + ' «' + val + '»')
|
|
216
254
|
|
|
217
255
|
def expect(punc):
|
|
218
|
-
return expect_token(
|
|
256
|
+
return expect_token('punc', punc)
|
|
219
257
|
|
|
220
258
|
def semicolon():
|
|
221
|
-
if is_(
|
|
259
|
+
if is_('punc', ';'):
|
|
222
260
|
next()
|
|
223
261
|
S.token.nlb = True
|
|
224
262
|
|
|
225
263
|
def embed_tokens(parser):
|
|
226
|
-
def with_embedded_tokens():
|
|
264
|
+
async def with_embedded_tokens():
|
|
227
265
|
start = S.token
|
|
228
|
-
expr = parser()
|
|
266
|
+
expr = await parser()
|
|
229
267
|
if expr is undefined:
|
|
230
268
|
unexpected()
|
|
231
269
|
end = prev()
|
|
@@ -243,7 +281,7 @@ def create_parser_ctx(S, import_dirs, module_id, baselib_items, imported_module_
|
|
|
243
281
|
if obj.name:
|
|
244
282
|
ans.push(obj.name.name)
|
|
245
283
|
else:
|
|
246
|
-
token_error(obj.start,
|
|
284
|
+
token_error(obj.start, 'Top-level functions must have names')
|
|
247
285
|
else:
|
|
248
286
|
# skip inner scopes
|
|
249
287
|
if is_node_type(obj, AST_Scope):
|
|
@@ -262,7 +300,6 @@ def create_parser_ctx(S, import_dirs, module_id, baselib_items, imported_module_
|
|
|
262
300
|
if body.alternative:
|
|
263
301
|
ans = ans.concat(scan_for_top_level_callables(body.alternative))
|
|
264
302
|
|
|
265
|
-
|
|
266
303
|
return ans
|
|
267
304
|
|
|
268
305
|
def scan_for_classes(body):
|
|
@@ -305,10 +342,10 @@ def create_parser_ctx(S, import_dirs, module_id, baselib_items, imported_module_
|
|
|
305
342
|
|
|
306
343
|
def add_assign_lhs(lhs):
|
|
307
344
|
if is_node_type(lhs, AST_Seq):
|
|
308
|
-
lhs = new AST_Array({'elements':lhs.to_array()})
|
|
345
|
+
lhs = new AST_Array({'elements': lhs.to_array()})
|
|
309
346
|
if is_node_type(lhs, AST_Array):
|
|
310
347
|
# assignment to an implicit tuple
|
|
311
|
-
push(
|
|
348
|
+
push('ρσ_unpack')
|
|
312
349
|
scan_in_array(lhs.elements)
|
|
313
350
|
elif lhs.name:
|
|
314
351
|
# assignment to a single variable
|
|
@@ -317,7 +354,7 @@ def create_parser_ctx(S, import_dirs, module_id, baselib_items, imported_module_
|
|
|
317
354
|
def add_for_in(stmt):
|
|
318
355
|
if is_node_type(stmt.init, AST_Array):
|
|
319
356
|
# iteration via implicit tuple
|
|
320
|
-
push(
|
|
357
|
+
push('ρσ_unpack')
|
|
321
358
|
scan_in_array(stmt.init.elements)
|
|
322
359
|
else:
|
|
323
360
|
# iteration via a single variable
|
|
@@ -395,30 +432,28 @@ def create_parser_ctx(S, import_dirs, module_id, baselib_items, imported_module_
|
|
|
395
432
|
if opt:
|
|
396
433
|
vars = vars.concat(scan_for_nonlocal_defs(opt))
|
|
397
434
|
|
|
398
|
-
|
|
399
435
|
elif body.body:
|
|
400
436
|
vars = vars.concat(scan_for_nonlocal_defs(body.body))
|
|
401
437
|
if body.alternative:
|
|
402
438
|
vars = vars.concat(scan_for_nonlocal_defs(body.alternative))
|
|
403
439
|
|
|
404
|
-
|
|
405
440
|
return vars
|
|
406
441
|
|
|
407
|
-
def return_():
|
|
442
|
+
async def return_():
|
|
408
443
|
if is_('punc', ';'):
|
|
409
444
|
semicolon()
|
|
410
445
|
value = None
|
|
411
446
|
else:
|
|
412
|
-
is_end_of_statement = S.token.nlb or is_(
|
|
447
|
+
is_end_of_statement = S.token.nlb or is_('eof') or is_('punc', '}')
|
|
413
448
|
if is_end_of_statement:
|
|
414
449
|
value = None
|
|
415
450
|
else:
|
|
416
|
-
value = expression(True)
|
|
451
|
+
value = await expression(True)
|
|
417
452
|
semicolon()
|
|
418
453
|
return value
|
|
419
454
|
|
|
420
455
|
@embed_tokens
|
|
421
|
-
def statement():
|
|
456
|
+
async def statement():
|
|
422
457
|
# From Kovid: The next three lines were a hack to try to support statements
|
|
423
458
|
# starting with a regexp literal. However, it did not work, for example:
|
|
424
459
|
# echo 'f=1\n/asd/.test()' | rs -> parse error
|
|
@@ -433,83 +468,104 @@ def create_parser_ctx(S, import_dirs, module_id, baselib_items, imported_module_
|
|
|
433
468
|
p = prev()
|
|
434
469
|
if p and not S.token.nlb and ATOMIC_START_TOKEN[p.type] and not is_('punc', ':'):
|
|
435
470
|
unexpected()
|
|
436
|
-
if tmp_ is
|
|
437
|
-
return simple_statement()
|
|
438
|
-
elif tmp_ is
|
|
471
|
+
if tmp_ is 'string':
|
|
472
|
+
return await simple_statement()
|
|
473
|
+
elif tmp_ is 'shebang':
|
|
439
474
|
tmp_ = S.token.value
|
|
440
475
|
next()
|
|
441
476
|
return new AST_Directive({
|
|
442
477
|
'value': tmp_
|
|
443
478
|
})
|
|
444
|
-
elif tmp_ is
|
|
445
|
-
return simple_statement()
|
|
446
|
-
elif tmp_ is
|
|
479
|
+
elif tmp_ is 'num' or tmp_ is 'regexp' or tmp_ is 'operator' or tmp_ is 'atom' or tmp_ is 'js':
|
|
480
|
+
return await simple_statement()
|
|
481
|
+
elif tmp_ is 'punc':
|
|
447
482
|
tmp_ = S.token.value
|
|
448
|
-
if tmp_ is
|
|
483
|
+
if tmp_ is ':':
|
|
484
|
+
bs_body = await block_()
|
|
449
485
|
return new AST_BlockStatement({
|
|
450
486
|
'start': S.token,
|
|
451
|
-
'body':
|
|
487
|
+
'body': bs_body,
|
|
452
488
|
'end': prev()
|
|
453
489
|
})
|
|
454
|
-
elif tmp_ is
|
|
455
|
-
return simple_statement()
|
|
456
|
-
elif tmp_ is
|
|
490
|
+
elif tmp_ is '{' or tmp_ is '[' or tmp_ is '(':
|
|
491
|
+
return await simple_statement()
|
|
492
|
+
elif tmp_ is ';':
|
|
457
493
|
next()
|
|
458
|
-
return new AST_EmptyStatement({'stype':';', 'start':prev(), 'end':prev()})
|
|
494
|
+
return new AST_EmptyStatement({'stype': ';', 'start': prev(), 'end': prev()})
|
|
459
495
|
else:
|
|
460
496
|
unexpected()
|
|
461
|
-
elif tmp_ is
|
|
497
|
+
elif tmp_ is 'name':
|
|
462
498
|
if (is_token(peek(), 'punc', ':')) token_error(peek(), 'invalid syntax, colon not allowed here')
|
|
463
|
-
return simple_statement()
|
|
464
|
-
elif tmp_ is
|
|
499
|
+
return await simple_statement()
|
|
500
|
+
elif tmp_ is 'keyword':
|
|
465
501
|
tmp_ = S.token.value
|
|
466
502
|
next()
|
|
467
|
-
if tmp_ is
|
|
503
|
+
if tmp_ is 'break':
|
|
468
504
|
return break_cont(AST_Break)
|
|
469
|
-
elif tmp_ is
|
|
505
|
+
elif tmp_ is 'continue':
|
|
470
506
|
return break_cont(AST_Continue)
|
|
471
|
-
elif tmp_ is
|
|
507
|
+
elif tmp_ is 'debugger':
|
|
472
508
|
semicolon()
|
|
473
509
|
return new AST_Debugger()
|
|
474
|
-
elif tmp_ is
|
|
510
|
+
elif tmp_ is 'do':
|
|
511
|
+
do_body = await in_loop(statement)
|
|
512
|
+
do_cond = await (async def ():
|
|
513
|
+
expect('.')
|
|
514
|
+
expect_token('keyword', 'while')
|
|
515
|
+
tmp = await expression(True)
|
|
516
|
+
if is_node_type(tmp, AST_Assign):
|
|
517
|
+
croak('Assignments in do loop conditions are not allowed')
|
|
518
|
+
semicolon()
|
|
519
|
+
return tmp
|
|
520
|
+
)()
|
|
475
521
|
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
|
-
)()
|
|
522
|
+
'body': do_body,
|
|
523
|
+
'condition': do_cond,
|
|
486
524
|
})
|
|
487
|
-
elif tmp_ is
|
|
488
|
-
while_cond = expression(True)
|
|
525
|
+
elif tmp_ is 'while':
|
|
526
|
+
while_cond = await expression(True)
|
|
489
527
|
if is_node_type(while_cond, AST_Assign):
|
|
490
528
|
croak('Assignments in while loop conditions are not allowed')
|
|
491
529
|
if not is_('punc', ':'):
|
|
492
530
|
croak('Expected a colon after the while statement')
|
|
531
|
+
while_body = await in_loop(statement)
|
|
493
532
|
return new AST_While({
|
|
494
533
|
'condition': while_cond,
|
|
495
|
-
'body':
|
|
534
|
+
'body': while_body
|
|
496
535
|
})
|
|
497
|
-
elif tmp_ is
|
|
536
|
+
elif tmp_ is 'for':
|
|
498
537
|
if is_('js'):
|
|
499
|
-
return for_js()
|
|
500
|
-
return for_()
|
|
501
|
-
elif tmp_ is
|
|
502
|
-
return import_(True)
|
|
503
|
-
elif tmp_ is
|
|
504
|
-
return import_(False)
|
|
505
|
-
elif tmp_ is
|
|
506
|
-
return class_()
|
|
507
|
-
elif tmp_ is
|
|
538
|
+
return await for_js()
|
|
539
|
+
return await for_()
|
|
540
|
+
elif tmp_ is 'from':
|
|
541
|
+
return await import_(True)
|
|
542
|
+
elif tmp_ is 'import':
|
|
543
|
+
return await import_(False)
|
|
544
|
+
elif tmp_ is 'class':
|
|
545
|
+
return await class_()
|
|
546
|
+
elif tmp_ is 'async':
|
|
547
|
+
if not is_('keyword', 'def'):
|
|
548
|
+
croak("Expected 'def' after 'async'")
|
|
549
|
+
next()
|
|
550
|
+
start = prev()
|
|
551
|
+
func = await function_(S.in_class[-1], False, True)
|
|
552
|
+
func.start = start
|
|
553
|
+
func.end = prev()
|
|
554
|
+
chain = await subscripts(func, True)
|
|
555
|
+
if chain is func:
|
|
556
|
+
return func
|
|
557
|
+
else:
|
|
558
|
+
return new AST_SimpleStatement({
|
|
559
|
+
'start': start,
|
|
560
|
+
'body': chain,
|
|
561
|
+
'end': prev()
|
|
562
|
+
})
|
|
563
|
+
elif tmp_ is 'def':
|
|
508
564
|
start = prev()
|
|
509
|
-
func = function_(S.in_class[-1], False)
|
|
565
|
+
func = await function_(S.in_class[-1], False)
|
|
510
566
|
func.start = start
|
|
511
567
|
func.end = prev()
|
|
512
|
-
chain = subscripts(func, True)
|
|
568
|
+
chain = await subscripts(func, True)
|
|
513
569
|
if chain is func:
|
|
514
570
|
return func
|
|
515
571
|
else:
|
|
@@ -520,67 +576,75 @@ def create_parser_ctx(S, import_dirs, module_id, baselib_items, imported_module_
|
|
|
520
576
|
})
|
|
521
577
|
elif tmp_ is 'assert':
|
|
522
578
|
start = prev()
|
|
523
|
-
cond = expression(False)
|
|
579
|
+
cond = await expression(False)
|
|
524
580
|
msg = None
|
|
525
581
|
if is_('punc', ','):
|
|
526
582
|
next()
|
|
527
|
-
msg = expression(False)
|
|
528
|
-
return new AST_Assert({'start': start, 'condition':cond, 'message':msg, 'end':prev()})
|
|
529
|
-
elif tmp_ is
|
|
530
|
-
return if_()
|
|
531
|
-
elif tmp_ is
|
|
583
|
+
msg = await expression(False)
|
|
584
|
+
return new AST_Assert({'start': start, 'condition': cond, 'message': msg, 'end': prev()})
|
|
585
|
+
elif tmp_ is 'if':
|
|
586
|
+
return await if_()
|
|
587
|
+
elif tmp_ is 'pass':
|
|
532
588
|
semicolon()
|
|
533
|
-
return new AST_EmptyStatement({'stype':'pass', 'start':prev(), 'end':prev()})
|
|
534
|
-
elif tmp_ is
|
|
589
|
+
return new AST_EmptyStatement({'stype': 'pass', 'start': prev(), 'end': prev()})
|
|
590
|
+
elif tmp_ is 'return':
|
|
535
591
|
if S.in_function is 0:
|
|
536
592
|
croak("'return' outside of function")
|
|
537
593
|
if S.functions[-1].is_generator:
|
|
538
594
|
croak("'return' not allowed in a function with yield")
|
|
539
595
|
S.functions[-1].is_generator = False
|
|
540
596
|
|
|
541
|
-
|
|
542
|
-
|
|
543
|
-
|
|
544
|
-
|
|
597
|
+
ret_val = await return_()
|
|
598
|
+
return new AST_Return({'value': ret_val})
|
|
599
|
+
elif tmp_ is 'await':
|
|
600
|
+
if S.in_function is 0 or not S.functions[-1].is_async:
|
|
601
|
+
croak("'await' outside of async function")
|
|
602
|
+
value = await expr_atom(True)
|
|
603
|
+
node = new AST_Await({'value': value})
|
|
604
|
+
semicolon()
|
|
605
|
+
return new AST_SimpleStatement({'body': node})
|
|
606
|
+
elif tmp_ is 'yield':
|
|
607
|
+
return await yield_()
|
|
608
|
+
elif tmp_ is 'raise':
|
|
545
609
|
if S.token.nlb:
|
|
546
610
|
return new AST_Throw({
|
|
547
611
|
'value': new AST_SymbolCatch({
|
|
548
|
-
'name':
|
|
612
|
+
'name': 'ρσ_Exception'
|
|
549
613
|
})
|
|
550
614
|
})
|
|
551
615
|
|
|
552
|
-
tmp = expression(True)
|
|
616
|
+
tmp = await expression(True)
|
|
553
617
|
semicolon()
|
|
554
618
|
return new AST_Throw({
|
|
555
619
|
'value': tmp
|
|
556
620
|
})
|
|
557
|
-
elif tmp_ is
|
|
558
|
-
return try_()
|
|
559
|
-
elif tmp_ is
|
|
560
|
-
tmp = nonlocal_()
|
|
621
|
+
elif tmp_ is 'try':
|
|
622
|
+
return await try_()
|
|
623
|
+
elif tmp_ is 'nonlocal':
|
|
624
|
+
tmp = await nonlocal_()
|
|
561
625
|
semicolon()
|
|
562
626
|
return tmp
|
|
563
627
|
elif tmp_ is 'global':
|
|
564
|
-
tmp = nonlocal_(True)
|
|
628
|
+
tmp = await nonlocal_(True)
|
|
565
629
|
semicolon()
|
|
566
630
|
return tmp
|
|
567
|
-
elif tmp_ is
|
|
568
|
-
return with_()
|
|
631
|
+
elif tmp_ is 'with':
|
|
632
|
+
return await with_()
|
|
569
633
|
else:
|
|
570
634
|
unexpected()
|
|
571
635
|
|
|
572
|
-
def with_():
|
|
636
|
+
async def with_():
|
|
573
637
|
clauses = v'[]'
|
|
574
638
|
start = S.token
|
|
575
639
|
while True:
|
|
576
640
|
if is_('eof'):
|
|
577
641
|
unexpected()
|
|
578
|
-
expr = expression()
|
|
642
|
+
expr = await expression()
|
|
579
643
|
alias = None
|
|
580
644
|
if is_('keyword', 'as'):
|
|
581
645
|
next()
|
|
582
646
|
alias = as_symbol(AST_SymbolAlias)
|
|
583
|
-
clauses.push(new AST_WithClause({'expression':expr, 'alias':alias}))
|
|
647
|
+
clauses.push(new AST_WithClause({'expression': expr, 'alias': alias}))
|
|
584
648
|
if is_('punc', ','):
|
|
585
649
|
next()
|
|
586
650
|
continue
|
|
@@ -590,15 +654,15 @@ def create_parser_ctx(S, import_dirs, module_id, baselib_items, imported_module_
|
|
|
590
654
|
|
|
591
655
|
if not clauses.length:
|
|
592
656
|
token_error(start, 'with statement must have at least one clause')
|
|
593
|
-
body = statement()
|
|
657
|
+
body = await statement()
|
|
594
658
|
|
|
595
659
|
return new AST_With({
|
|
596
660
|
'clauses': clauses,
|
|
597
661
|
'body': body
|
|
598
662
|
})
|
|
599
663
|
|
|
600
|
-
def simple_statement(tmp):
|
|
601
|
-
tmp = expression(True)
|
|
664
|
+
async def simple_statement(tmp):
|
|
665
|
+
tmp = await expression(True)
|
|
602
666
|
semicolon()
|
|
603
667
|
return new AST_SimpleStatement({
|
|
604
668
|
'body': tmp
|
|
@@ -606,26 +670,29 @@ def create_parser_ctx(S, import_dirs, module_id, baselib_items, imported_module_
|
|
|
606
670
|
|
|
607
671
|
def break_cont(t):
|
|
608
672
|
if S.in_loop is 0:
|
|
609
|
-
croak(t.name.slice(4) +
|
|
673
|
+
croak(t.name.slice(4) + ' not inside a loop or switch')
|
|
610
674
|
semicolon()
|
|
611
675
|
return new t()
|
|
612
676
|
|
|
613
|
-
def yield_():
|
|
677
|
+
async def yield_():
|
|
614
678
|
if S.in_function is 0:
|
|
615
679
|
croak("'yield' outside of function")
|
|
680
|
+
if S.functions[-1].is_async:
|
|
681
|
+
croak("'yield' not allowed in an async function")
|
|
616
682
|
if S.functions[-1].is_generator is False:
|
|
617
683
|
croak("'yield' not allowed in a function with return")
|
|
618
684
|
S.functions[-1].is_generator = True
|
|
619
685
|
is_yield_from = is_('keyword', 'from')
|
|
620
686
|
if is_yield_from:
|
|
621
687
|
next()
|
|
622
|
-
|
|
688
|
+
yld_val = await return_()
|
|
689
|
+
return new AST_Yield({'is_yield_from': is_yield_from, 'value': yld_val})
|
|
623
690
|
|
|
624
|
-
def for_(list_comp):
|
|
691
|
+
async def for_(list_comp):
|
|
625
692
|
# expect("(")
|
|
626
693
|
init = None
|
|
627
|
-
if not is_(
|
|
628
|
-
init = expression(True, True)
|
|
694
|
+
if not is_('punc', ';'):
|
|
695
|
+
init = await expression(True, True)
|
|
629
696
|
# standardize AST_Seq into array now for consistency
|
|
630
697
|
if is_node_type(init, AST_Seq):
|
|
631
698
|
if is_node_type(init.car, AST_SymbolRef) and is_node_type(init.cdr, AST_SymbolRef):
|
|
@@ -639,17 +706,17 @@ def create_parser_ctx(S, import_dirs, module_id, baselib_items, imported_module_
|
|
|
639
706
|
'end': init.end
|
|
640
707
|
})
|
|
641
708
|
|
|
642
|
-
if is_(
|
|
709
|
+
if is_('operator', 'in'):
|
|
643
710
|
if is_node_type(init, AST_Var) and init.definitions.length > 1:
|
|
644
|
-
croak(
|
|
711
|
+
croak('Only one variable declaration allowed in for..in loop')
|
|
645
712
|
next()
|
|
646
|
-
return for_in(init, list_comp)
|
|
713
|
+
return await for_in(init, list_comp)
|
|
647
714
|
|
|
648
715
|
unexpected()
|
|
649
716
|
|
|
650
|
-
def for_in(init, list_comp):
|
|
717
|
+
async def for_in(init, list_comp):
|
|
651
718
|
lhs = init.definitions[0].name if is_node_type(init, AST_Var) else None
|
|
652
|
-
obj = expression(True)
|
|
719
|
+
obj = await expression(True)
|
|
653
720
|
# expect(")")
|
|
654
721
|
if list_comp:
|
|
655
722
|
return {
|
|
@@ -658,19 +725,21 @@ def create_parser_ctx(S, import_dirs, module_id, baselib_items, imported_module_
|
|
|
658
725
|
'object': obj
|
|
659
726
|
}
|
|
660
727
|
|
|
728
|
+
fi_body = await in_loop(statement)
|
|
661
729
|
return new AST_ForIn({
|
|
662
730
|
'init': init,
|
|
663
731
|
'name': lhs,
|
|
664
732
|
'object': obj,
|
|
665
|
-
'body':
|
|
733
|
+
'body': fi_body
|
|
666
734
|
})
|
|
667
735
|
|
|
668
736
|
# A native JavaScript for loop - for v"var i=0; i<5000; i++":
|
|
669
|
-
def for_js():
|
|
737
|
+
async def for_js():
|
|
670
738
|
condition = as_atom_node()
|
|
739
|
+
fj_body = await in_loop(statement)
|
|
671
740
|
return new AST_ForJS({
|
|
672
741
|
'condition': condition,
|
|
673
|
-
'body':
|
|
742
|
+
'body': fj_body
|
|
674
743
|
})
|
|
675
744
|
|
|
676
745
|
# scan function/class body for nested class declarations
|
|
@@ -688,7 +757,7 @@ def create_parser_ctx(S, import_dirs, module_id, baselib_items, imported_module_
|
|
|
688
757
|
return ERROR_CLASSES[expr.name]
|
|
689
758
|
|
|
690
759
|
# traverse in reverse to check local variables first
|
|
691
|
-
for s in range(S.classes.length-1, -1, -1):
|
|
760
|
+
for s in range(S.classes.length - 1, -1, -1):
|
|
692
761
|
if has_prop(S.classes[s], expr.name):
|
|
693
762
|
return S.classes[s][expr.name]
|
|
694
763
|
|
|
@@ -703,7 +772,7 @@ def create_parser_ctx(S, import_dirs, module_id, baselib_items, imported_module_
|
|
|
703
772
|
# now 'referenced_path' should contain the full path of potential class
|
|
704
773
|
if len(referenced_path) > 1:
|
|
705
774
|
class_name = referenced_path.join('.')
|
|
706
|
-
for s in range(S.classes.length-1, -1, -1):
|
|
775
|
+
for s in range(S.classes.length - 1, -1, -1):
|
|
707
776
|
if has_prop(S.classes[s], class_name):
|
|
708
777
|
return S.classes[s][class_name]
|
|
709
778
|
return False
|
|
@@ -712,72 +781,145 @@ def create_parser_ctx(S, import_dirs, module_id, baselib_items, imported_module_
|
|
|
712
781
|
ctx = S.input.context()
|
|
713
782
|
raise new ImportError(message, ctx.filename, ctx.tokline, ctx.tokcol, ctx.tokpos)
|
|
714
783
|
|
|
715
|
-
def do_import(key):
|
|
784
|
+
async def do_import(key):
|
|
716
785
|
if has_prop(imported_modules, key):
|
|
717
786
|
return
|
|
787
|
+
# Circular import check must come BEFORE loading_promises so we detect cycles
|
|
788
|
+
# even when the same module is being loaded by a parallel chain.
|
|
718
789
|
if has_prop(importing_modules, key) and importing_modules[key]:
|
|
719
790
|
import_error('Detected a recursive import of: ' + key + ' while importing: ' + module_id)
|
|
791
|
+
# If a parallel chain is already loading this module, wait for it instead of
|
|
792
|
+
# starting a duplicate load. loading_promises is shared across the entire
|
|
793
|
+
# compilation via options.loading_promises.
|
|
794
|
+
loading_promises = options.loading_promises
|
|
795
|
+
if has_prop(loading_promises, key):
|
|
796
|
+
await loading_promises[key]
|
|
797
|
+
return
|
|
720
798
|
|
|
721
|
-
#
|
|
722
|
-
|
|
723
|
-
|
|
724
|
-
|
|
799
|
+
# Register this load BEFORE the first await so that any parallel caller
|
|
800
|
+
# that reaches this point sees the in-progress entry and waits.
|
|
801
|
+
# Use a single-element list to capture the resolve function from the Promise
|
|
802
|
+
# executor without needing nonlocal (mutating a container, not rebinding).
|
|
803
|
+
_rfn = v'[null]'
|
|
725
804
|
|
|
726
|
-
|
|
727
|
-
|
|
728
|
-
|
|
729
|
-
return
|
|
805
|
+
def _capture_resolve(resolve):
|
|
806
|
+
_rfn[0] = resolve
|
|
807
|
+
loading_promises[key] = new Promise(_capture_resolve)
|
|
730
808
|
|
|
731
|
-
|
|
732
|
-
|
|
733
|
-
|
|
734
|
-
|
|
735
|
-
|
|
736
|
-
|
|
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
|
|
819
|
+
|
|
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
|
|
|
@@ -785,7 +927,7 @@ def create_parser_ctx(S, import_dirs, module_id, baselib_items, imported_module_
|
|
|
785
927
|
baselib_items[bitem] = True
|
|
786
928
|
|
|
787
929
|
def read_python_flags():
|
|
788
|
-
expect_token(
|
|
930
|
+
expect_token('keyword', 'import')
|
|
789
931
|
bracketed = is_('punc', '(')
|
|
790
932
|
if bracketed:
|
|
791
933
|
next()
|
|
@@ -809,15 +951,15 @@ def create_parser_ctx(S, import_dirs, module_id, baselib_items, imported_module_
|
|
|
809
951
|
else:
|
|
810
952
|
continue
|
|
811
953
|
break
|
|
812
|
-
return new AST_EmptyStatement({'stype':'scoped_flags', 'start':prev(), 'end':prev()})
|
|
954
|
+
return new AST_EmptyStatement({'stype': 'scoped_flags', 'start': prev(), 'end': prev()})
|
|
813
955
|
|
|
814
|
-
def import_(from_import):
|
|
815
|
-
ans = new AST_Imports({'imports':[]})
|
|
956
|
+
async def import_(from_import):
|
|
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
|
-
key =
|
|
962
|
+
key = '.' + tmp.property + key
|
|
821
963
|
tmp = last_tok = tmp.expression
|
|
822
964
|
key = tmp.name + key
|
|
823
965
|
if from_import and key is '__python__':
|
|
@@ -830,8 +972,8 @@ def create_parser_ctx(S, import_dirs, module_id, baselib_items, imported_module_
|
|
|
830
972
|
'module': name,
|
|
831
973
|
'key': key,
|
|
832
974
|
'alias': alias,
|
|
833
|
-
'argnames':None,
|
|
834
|
-
'body':def():
|
|
975
|
+
'argnames': None,
|
|
976
|
+
'body': def ():
|
|
835
977
|
return imported_modules[key]
|
|
836
978
|
})
|
|
837
979
|
aimp.start, aimp.end = tok.start, last_tok.end
|
|
@@ -844,12 +986,12 @@ 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
|
|
851
993
|
if from_import:
|
|
852
|
-
expect_token(
|
|
994
|
+
expect_token('keyword', 'import')
|
|
853
995
|
imp.argnames = argnames = []
|
|
854
996
|
bracketed = is_('punc', '(')
|
|
855
997
|
if bracketed:
|
|
@@ -880,16 +1022,16 @@ def create_parser_ctx(S, import_dirs, module_id, baselib_items, imported_module_
|
|
|
880
1022
|
obj = classes[argvar.name]
|
|
881
1023
|
if obj:
|
|
882
1024
|
key = argvar.alias.name if argvar.alias else argvar.name
|
|
883
|
-
S.classes[-1][key] = {
|
|
1025
|
+
S.classes[-1][key] = {'static': obj.static, 'bound': obj.bound, 'classvars': obj.classvars}
|
|
884
1026
|
else:
|
|
885
1027
|
for cname in Object.keys(classes):
|
|
886
1028
|
obj = classes[cname]
|
|
887
1029
|
key = imp.alias.name if imp.alias else imp.key
|
|
888
|
-
S.classes[-1][key + '.' + obj.name.name] = {
|
|
1030
|
+
S.classes[-1][key + '.' + obj.name.name] = {'static': obj.static, 'bound': obj.bound, 'classvars': obj.classvars}
|
|
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()
|
|
@@ -898,7 +1040,7 @@ def create_parser_ctx(S, import_dirs, module_id, baselib_items, imported_module_
|
|
|
898
1040
|
externaldecorator = has_simple_decorator(S.decorators, 'external')
|
|
899
1041
|
|
|
900
1042
|
class_details = {
|
|
901
|
-
|
|
1043
|
+
'static': {},
|
|
902
1044
|
'bound': v'[]',
|
|
903
1045
|
'classvars': {},
|
|
904
1046
|
'processing': name.name,
|
|
@@ -908,7 +1050,7 @@ def create_parser_ctx(S, import_dirs, module_id, baselib_items, imported_module_
|
|
|
908
1050
|
class_parent = None
|
|
909
1051
|
|
|
910
1052
|
# read the bases of the class, if any
|
|
911
|
-
if is_(
|
|
1053
|
+
if is_('punc', '('):
|
|
912
1054
|
S.in_parenthesized_expr = True
|
|
913
1055
|
next()
|
|
914
1056
|
while True:
|
|
@@ -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,10 +1067,37 @@ 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,
|
|
931
|
-
'module_id':module_id,
|
|
1100
|
+
'module_id': module_id,
|
|
932
1101
|
'dynamic_properties': Object.create(None),
|
|
933
1102
|
'parent': class_parent,
|
|
934
1103
|
'bases': bases,
|
|
@@ -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
|
|
@@ -975,10 +1119,11 @@ def create_parser_ctx(S, import_dirs, module_id, baselib_items, imported_module_
|
|
|
975
1119
|
if not descriptor:
|
|
976
1120
|
descriptor = definition.dynamic_properties[stmt.name.name] = {}
|
|
977
1121
|
descriptor['getter' if stmt.is_getter else 'setter'] = stmt
|
|
978
|
-
elif stmt.name.name is
|
|
1122
|
+
elif stmt.name.name is '__init__':
|
|
979
1123
|
definition.init = stmt
|
|
980
1124
|
# find the class variables
|
|
981
1125
|
class_var_names = {}
|
|
1126
|
+
|
|
982
1127
|
# Ensure that if a class variable refers to another class variable in
|
|
983
1128
|
# its initialization, the referenced variables' names is correctly
|
|
984
1129
|
# mangled.
|
|
@@ -996,7 +1141,7 @@ def create_parser_ctx(S, import_dirs, module_id, baselib_items, imported_module_
|
|
|
996
1141
|
class_var_names[varname] = True
|
|
997
1142
|
definition.classvars[varname] = True
|
|
998
1143
|
elif is_node_type(node, AST_SymbolRef) and has_prop(class_var_names, node.name):
|
|
999
|
-
node.thedef = new AST_SymbolDefun({'name':name.name + '.prototype.' + node.name})
|
|
1144
|
+
node.thedef = new AST_SymbolDefun({'name': name.name + '.prototype.' + node.name})
|
|
1000
1145
|
if descend:
|
|
1001
1146
|
descend.call(node)
|
|
1002
1147
|
this._visit = visit_node
|
|
@@ -1008,7 +1153,7 @@ def create_parser_ctx(S, import_dirs, module_id, baselib_items, imported_module_
|
|
|
1008
1153
|
definition.statements.push(stmt)
|
|
1009
1154
|
return definition
|
|
1010
1155
|
|
|
1011
|
-
def function_(in_class, is_expression):
|
|
1156
|
+
async def function_(in_class, is_expression, is_async=False):
|
|
1012
1157
|
name = as_symbol(AST_SymbolDefun if in_class else AST_SymbolLambda) if is_('name') else None
|
|
1013
1158
|
if in_class and not name:
|
|
1014
1159
|
croak('Cannot use anonymous function as class methods')
|
|
@@ -1024,196 +1169,214 @@ def create_parser_ctx(S, import_dirs, module_id, baselib_items, imported_module_
|
|
|
1024
1169
|
croak('A method cannot be both static and a property getter/setter')
|
|
1025
1170
|
S.classes[S.classes.length - 2][in_class].static[name.name] = True
|
|
1026
1171
|
staticmethod = True
|
|
1027
|
-
elif name.name is not
|
|
1172
|
+
elif name.name is not '__init__' and S.scoped_flags.get('bound_methods'):
|
|
1028
1173
|
S.classes[S.classes.length - 2][in_class].bound.push(name.name)
|
|
1029
1174
|
|
|
1030
|
-
expect(
|
|
1175
|
+
expect('(')
|
|
1031
1176
|
S.in_parenthesized_expr = True
|
|
1032
1177
|
ctor = AST_Method if in_class else AST_Function
|
|
1033
1178
|
return_annotation = None
|
|
1034
1179
|
is_generator = v'[]'
|
|
1035
1180
|
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
|
-
|
|
1074
|
-
sym = new AST_SymbolFunarg({
|
|
1075
|
-
'name': name_token.value,
|
|
1076
|
-
'start': S.token,
|
|
1077
|
-
'end': S.token,
|
|
1078
|
-
'annotation': annotation
|
|
1079
|
-
})
|
|
1080
|
-
return sym
|
|
1081
|
-
else:
|
|
1082
|
-
if not is_("name"):
|
|
1083
|
-
# there is no name, which is an error we should report on the
|
|
1084
|
-
# same line as the definition, so move to that is we're not already there.
|
|
1085
|
-
if S.input.context().tokline is not def_line:
|
|
1086
|
-
croak("Name expected", def_line)
|
|
1087
|
-
else:
|
|
1088
|
-
croak("Name expected")
|
|
1089
|
-
return None
|
|
1090
|
-
|
|
1091
|
-
sym = new AST_SymbolFunarg({
|
|
1092
|
-
'name': current_arg_name,
|
|
1093
|
-
'start': S.token,
|
|
1094
|
-
'end': S.token,
|
|
1095
|
-
'annotation': None
|
|
1096
|
-
})
|
|
1097
|
-
next()
|
|
1098
|
-
return sym
|
|
1099
1181
|
|
|
1100
|
-
|
|
1101
|
-
|
|
1102
|
-
|
|
1103
|
-
|
|
1104
|
-
|
|
1105
|
-
|
|
1106
|
-
|
|
1107
|
-
|
|
1108
|
-
|
|
1109
|
-
|
|
1110
|
-
|
|
1111
|
-
|
|
1112
|
-
|
|
1113
|
-
|
|
1114
|
-
|
|
1182
|
+
fn_argnames = await (async def ():
|
|
1183
|
+
a = v'[]'
|
|
1184
|
+
starargs_sym = undefined
|
|
1185
|
+
kwargs_sym = undefined
|
|
1186
|
+
defaults = {}
|
|
1187
|
+
has_defaults = False
|
|
1188
|
+
first = True
|
|
1189
|
+
seen_names = {}
|
|
1190
|
+
def_line = S.input.context().tokline
|
|
1191
|
+
current_arg_name = None
|
|
1192
|
+
name_token = None
|
|
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
|
+
# and now, do as_symbol without the next() at the end
|
|
1211
|
+
# since we are already at the next comma (or end bracket)
|
|
1212
|
+
if not is_token(name_token, 'name'):
|
|
1213
|
+
# assuming the previous context in case
|
|
1214
|
+
# the annotation was over the line
|
|
1215
|
+
if S.input.context().tokline is not def_line:
|
|
1216
|
+
croak('Name expected', name_ctx.tokline)
|
|
1217
|
+
else:
|
|
1218
|
+
croak('Name expected')
|
|
1219
|
+
return None
|
|
1220
|
+
sym = new AST_SymbolFunarg({
|
|
1221
|
+
'name': name_token.value,
|
|
1222
|
+
'start': S.token,
|
|
1223
|
+
'end': S.token,
|
|
1224
|
+
'annotation': annotation
|
|
1225
|
+
})
|
|
1226
|
+
return sym
|
|
1227
|
+
else:
|
|
1228
|
+
if not is_('name'):
|
|
1229
|
+
# there is no name, which is an error we should report on the
|
|
1230
|
+
# same line as the definition, so move to that is we're not already there.
|
|
1231
|
+
if S.input.context().tokline is not def_line:
|
|
1232
|
+
croak('Name expected', def_line)
|
|
1233
|
+
else:
|
|
1234
|
+
croak('Name expected')
|
|
1235
|
+
return None
|
|
1236
|
+
sym = new AST_SymbolFunarg({
|
|
1237
|
+
'name': current_arg_name,
|
|
1238
|
+
'start': S.token,
|
|
1239
|
+
'end': S.token,
|
|
1240
|
+
'annotation': None
|
|
1241
|
+
})
|
|
1242
|
+
next()
|
|
1243
|
+
return sym
|
|
1244
|
+
while not is_('punc', ')'):
|
|
1245
|
+
if first:
|
|
1246
|
+
first = False
|
|
1247
|
+
else:
|
|
1248
|
+
expect(',')
|
|
1249
|
+
if is_('punc', ')'):
|
|
1250
|
+
break
|
|
1251
|
+
if is_('operator', '**'):
|
|
1252
|
+
# **kwargs
|
|
1253
|
+
next()
|
|
1254
|
+
if kwargs_sym:
|
|
1255
|
+
token_error(name_token, "Can't define multiple **kwargs in function definition")
|
|
1256
|
+
kwargs_sym = await get_arg()
|
|
1257
|
+
elif is_('operator', '*'):
|
|
1258
|
+
# *args
|
|
1259
|
+
next()
|
|
1260
|
+
if starargs_sym:
|
|
1261
|
+
token_error(name_token, "Can't define multiple *args in function definition")
|
|
1262
|
+
if kwargs_sym:
|
|
1263
|
+
token_error(name_token, "Can't define *args after **kwargs in function definition")
|
|
1264
|
+
starargs_sym = await get_arg()
|
|
1265
|
+
else:
|
|
1266
|
+
if starargs_sym or kwargs_sym:
|
|
1267
|
+
token_error(name_token, "Can't define a formal parameter after *args or **kwargs")
|
|
1268
|
+
a.push(await get_arg())
|
|
1269
|
+
if is_('operator', '='):
|
|
1270
|
+
if kwargs_sym:
|
|
1271
|
+
token_error(name_token, "Can't define an optional formal parameter after **kwargs")
|
|
1115
1272
|
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()
|
|
1273
|
+
defaults[current_arg_name] = await expression(False)
|
|
1274
|
+
has_defaults = True
|
|
1121
1275
|
else:
|
|
1122
|
-
if
|
|
1123
|
-
token_error(name_token, "Can't define
|
|
1124
|
-
|
|
1125
|
-
|
|
1126
|
-
|
|
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")
|
|
1134
|
-
|
|
1276
|
+
if has_defaults:
|
|
1277
|
+
token_error(name_token, "Can't define required formal parameters after optional formal parameters")
|
|
1278
|
+
next()
|
|
1279
|
+
# check if we have a return type annotation
|
|
1280
|
+
if is_('punc', '->'):
|
|
1135
1281
|
next()
|
|
1136
|
-
|
|
1137
|
-
|
|
1138
|
-
|
|
1139
|
-
|
|
1140
|
-
|
|
1141
|
-
|
|
1142
|
-
|
|
1143
|
-
|
|
1144
|
-
|
|
1145
|
-
|
|
1282
|
+
nonlocal return_annotation
|
|
1283
|
+
return_annotation = await maybe_conditional()
|
|
1284
|
+
S.in_parenthesized_expr = False
|
|
1285
|
+
return new AST_ArgsDef({
|
|
1286
|
+
'args': a,
|
|
1287
|
+
'starargs': starargs_sym,
|
|
1288
|
+
'kwargs': kwargs_sym,
|
|
1289
|
+
'defaults': defaults,
|
|
1290
|
+
'has_defaults': has_defaults,
|
|
1291
|
+
'is_simple_func': not starargs_sym and not kwargs_sym and not has_defaults,
|
|
1292
|
+
})
|
|
1293
|
+
)()
|
|
1294
|
+
|
|
1295
|
+
fn_decorators = (def ():
|
|
1296
|
+
d = v'[]'
|
|
1297
|
+
for decorator in S.decorators:
|
|
1298
|
+
d.push(new AST_Decorator({
|
|
1299
|
+
'expression': decorator
|
|
1300
|
+
}))
|
|
1301
|
+
S.decorators = v'[]'
|
|
1302
|
+
return d
|
|
1303
|
+
)()
|
|
1304
|
+
|
|
1305
|
+
fn_body = await (async def (loop, labels):
|
|
1306
|
+
S.in_class.push(False)
|
|
1307
|
+
S.classes.push({})
|
|
1308
|
+
S.scoped_flags.push()
|
|
1309
|
+
S.in_function += 1
|
|
1310
|
+
S.functions.push({'is_async': is_async})
|
|
1311
|
+
S.in_loop = 0
|
|
1312
|
+
S.labels = []
|
|
1313
|
+
a = await block_(docstrings)
|
|
1314
|
+
S.in_function -= 1
|
|
1315
|
+
S.scoped_flags.pop()
|
|
1316
|
+
is_generator.push(bool(S.functions.pop().is_generator))
|
|
1317
|
+
S.classes.pop()
|
|
1318
|
+
S.in_class.pop()
|
|
1319
|
+
S.in_loop = loop
|
|
1320
|
+
S.labels = labels
|
|
1321
|
+
return a
|
|
1322
|
+
)(S.in_loop, S.labels)
|
|
1323
|
+
|
|
1324
|
+
definition = new ctor({
|
|
1325
|
+
'name': name,
|
|
1326
|
+
'is_expression': is_expression,
|
|
1327
|
+
'is_anonymous': is_anonymous,
|
|
1328
|
+
'argnames': fn_argnames,
|
|
1146
1329
|
'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
|
-
)(),
|
|
1330
|
+
'decorators': fn_decorators,
|
|
1156
1331
|
'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)
|
|
1332
|
+
'body': fn_body,
|
|
1175
1333
|
})
|
|
1176
1334
|
definition.return_annotation = return_annotation
|
|
1177
1335
|
definition.is_generator = is_generator[0]
|
|
1336
|
+
definition.is_async = is_async
|
|
1178
1337
|
if is_node_type(definition, AST_Method):
|
|
1179
1338
|
definition.static = staticmethod
|
|
1180
1339
|
definition.is_getter = property_getter
|
|
1181
1340
|
definition.is_setter = property_setter
|
|
1182
|
-
if definition.argnames.length < 1 and not definition.static:
|
|
1341
|
+
if definition.argnames.args.length < 1 and not definition.static:
|
|
1183
1342
|
croak('Methods of a class must have at least one argument, traditionally named self')
|
|
1184
1343
|
if definition.name and definition.name.name is '__init__':
|
|
1185
1344
|
if definition.is_generator:
|
|
1186
1345
|
croak('The __init__ method of a class cannot be a generator (yield not allowed)')
|
|
1346
|
+
if definition.is_async:
|
|
1347
|
+
croak('The __init__ method of a class cannot be async')
|
|
1187
1348
|
if property_getter or property_setter:
|
|
1188
1349
|
croak('The __init__ method of a class cannot be a property getter/setter')
|
|
1350
|
+
if definition.is_async and definition.is_generator:
|
|
1351
|
+
croak('A function cannot be both async and a generator')
|
|
1189
1352
|
if definition.is_generator:
|
|
1190
1353
|
baselib_items['yield'] = True
|
|
1191
1354
|
|
|
1192
1355
|
# detect local variables, strip function arguments
|
|
1193
1356
|
assignments = scan_for_local_vars(definition.body)
|
|
1194
1357
|
for i in range(assignments.length):
|
|
1195
|
-
for j in range(definition.argnames.length+1):
|
|
1196
|
-
if j is definition.argnames.length:
|
|
1358
|
+
for j in range(definition.argnames.args.length + 1):
|
|
1359
|
+
if j is definition.argnames.args.length:
|
|
1197
1360
|
definition.localvars.push(new_symbol(AST_SymbolVar, assignments[i]))
|
|
1198
|
-
elif j < definition.argnames.length and assignments[i] is definition.argnames[j].name:
|
|
1361
|
+
elif j < definition.argnames.args.length and assignments[i] is definition.argnames.args[j].name:
|
|
1199
1362
|
break
|
|
1200
1363
|
|
|
1201
1364
|
nonlocals = scan_for_nonlocal_defs(definition.body)
|
|
1202
1365
|
nonlocals = {name for name in nonlocals}
|
|
1203
|
-
definition.localvars = definition.localvars.filter(def(v): return not nonlocals.has(v.name);)
|
|
1366
|
+
definition.localvars = definition.localvars.filter(def (v): return not nonlocals.has(v.name);)
|
|
1204
1367
|
return definition
|
|
1205
1368
|
|
|
1206
|
-
def if_():
|
|
1207
|
-
cond = expression(True)
|
|
1208
|
-
body = statement()
|
|
1369
|
+
async def if_():
|
|
1370
|
+
cond = await expression(True)
|
|
1371
|
+
body = await statement()
|
|
1209
1372
|
belse = None
|
|
1210
|
-
if is_(
|
|
1211
|
-
if is_(
|
|
1373
|
+
if is_('keyword', 'elif') or is_('keyword', 'else'):
|
|
1374
|
+
if is_('keyword', 'else'):
|
|
1212
1375
|
next()
|
|
1213
1376
|
else:
|
|
1214
|
-
S.token.value =
|
|
1377
|
+
S.token.value = 'if'
|
|
1215
1378
|
# effectively converts 'elif' to 'else if'
|
|
1216
|
-
belse = statement()
|
|
1379
|
+
belse = await statement()
|
|
1217
1380
|
|
|
1218
1381
|
return new AST_If({
|
|
1219
1382
|
'condition': cond,
|
|
@@ -1227,15 +1390,27 @@ def create_parser_ctx(S, import_dirs, module_id, baselib_items, imported_module_
|
|
|
1227
1390
|
return stmt.body
|
|
1228
1391
|
return False
|
|
1229
1392
|
|
|
1230
|
-
def block_(docstrings):
|
|
1393
|
+
async def block_(docstrings):
|
|
1231
1394
|
prev_whitespace = S.token.leading_whitespace
|
|
1232
|
-
expect(
|
|
1395
|
+
expect(':')
|
|
1233
1396
|
a = v'[]'
|
|
1234
1397
|
if not S.token.nlb:
|
|
1235
1398
|
while not S.token.nlb:
|
|
1236
|
-
if is_(
|
|
1399
|
+
if is_('eof'):
|
|
1400
|
+
if options.recover_errors:
|
|
1401
|
+
break
|
|
1237
1402
|
unexpected()
|
|
1238
|
-
|
|
1403
|
+
if options.recover_errors:
|
|
1404
|
+
try:
|
|
1405
|
+
stmt = await statement()
|
|
1406
|
+
except as berr:
|
|
1407
|
+
if is_recoverable_error(berr):
|
|
1408
|
+
record_recovery(berr)
|
|
1409
|
+
await skip_to_recovery_point()
|
|
1410
|
+
continue
|
|
1411
|
+
raise
|
|
1412
|
+
else:
|
|
1413
|
+
stmt = await statement()
|
|
1239
1414
|
if docstrings:
|
|
1240
1415
|
ds = is_docstring(stmt)
|
|
1241
1416
|
if ds:
|
|
@@ -1246,11 +1421,21 @@ def create_parser_ctx(S, import_dirs, module_id, baselib_items, imported_module_
|
|
|
1246
1421
|
current_whitespace = S.token.leading_whitespace
|
|
1247
1422
|
if current_whitespace.length is 0 or prev_whitespace is current_whitespace:
|
|
1248
1423
|
croak('Expected an indented block')
|
|
1249
|
-
while not is_(
|
|
1250
|
-
if is_(
|
|
1424
|
+
while not is_('punc', '}'):
|
|
1425
|
+
if is_('eof'):
|
|
1251
1426
|
# end of file, terminate block automatically
|
|
1252
1427
|
return a
|
|
1253
|
-
|
|
1428
|
+
if options.recover_errors:
|
|
1429
|
+
try:
|
|
1430
|
+
stmt = await statement()
|
|
1431
|
+
except as berr:
|
|
1432
|
+
if is_recoverable_error(berr):
|
|
1433
|
+
record_recovery(berr)
|
|
1434
|
+
await skip_to_recovery_point()
|
|
1435
|
+
continue
|
|
1436
|
+
raise
|
|
1437
|
+
else:
|
|
1438
|
+
stmt = await statement()
|
|
1254
1439
|
if docstrings:
|
|
1255
1440
|
ds = is_docstring(stmt)
|
|
1256
1441
|
if ds:
|
|
@@ -1260,79 +1445,89 @@ def create_parser_ctx(S, import_dirs, module_id, baselib_items, imported_module_
|
|
|
1260
1445
|
next()
|
|
1261
1446
|
return a
|
|
1262
1447
|
|
|
1263
|
-
def try_():
|
|
1264
|
-
body = block_()
|
|
1448
|
+
async def try_():
|
|
1449
|
+
body = await block_()
|
|
1265
1450
|
bcatch = v'[]'
|
|
1266
1451
|
bfinally = None
|
|
1267
1452
|
belse = None
|
|
1268
|
-
while is_(
|
|
1453
|
+
while is_('keyword', 'except'):
|
|
1269
1454
|
start = S.token
|
|
1270
1455
|
next()
|
|
1271
1456
|
exceptions = []
|
|
1272
|
-
if not is_(
|
|
1457
|
+
if not is_('punc', ':') and not is_('keyword', 'as'):
|
|
1273
1458
|
exceptions.push(as_symbol(AST_SymbolVar))
|
|
1274
|
-
while is_(
|
|
1459
|
+
while is_('punc', ','):
|
|
1275
1460
|
next()
|
|
1276
1461
|
exceptions.push(as_symbol(AST_SymbolVar))
|
|
1277
1462
|
|
|
1278
1463
|
name = None
|
|
1279
|
-
if is_(
|
|
1464
|
+
if is_('keyword', 'as'):
|
|
1280
1465
|
next()
|
|
1281
1466
|
name = as_symbol(AST_SymbolCatch)
|
|
1282
1467
|
|
|
1468
|
+
except_body = await block_()
|
|
1283
1469
|
bcatch.push(new AST_Except({
|
|
1284
1470
|
'start': start,
|
|
1285
1471
|
'argname': name,
|
|
1286
1472
|
'errors': exceptions,
|
|
1287
|
-
'body':
|
|
1473
|
+
'body': except_body,
|
|
1288
1474
|
'end': prev()
|
|
1289
1475
|
}))
|
|
1290
1476
|
|
|
1291
|
-
if is_(
|
|
1477
|
+
if is_('keyword', 'else'):
|
|
1292
1478
|
start = S.token
|
|
1293
1479
|
next()
|
|
1480
|
+
belse_body = await block_()
|
|
1294
1481
|
belse = new AST_Else({
|
|
1295
1482
|
'start': start,
|
|
1296
|
-
'body':
|
|
1483
|
+
'body': belse_body,
|
|
1297
1484
|
'end': prev()
|
|
1298
1485
|
})
|
|
1299
1486
|
|
|
1300
|
-
if is_(
|
|
1487
|
+
if is_('keyword', 'finally'):
|
|
1301
1488
|
start = S.token
|
|
1302
1489
|
next()
|
|
1490
|
+
bfinally_body = await block_()
|
|
1303
1491
|
bfinally = new AST_Finally({
|
|
1304
1492
|
'start': start,
|
|
1305
|
-
'body':
|
|
1493
|
+
'body': bfinally_body,
|
|
1306
1494
|
'end': prev()
|
|
1307
1495
|
})
|
|
1308
1496
|
|
|
1309
1497
|
if not bcatch.length and not bfinally:
|
|
1310
|
-
croak(
|
|
1498
|
+
croak('Missing except/finally blocks')
|
|
1311
1499
|
|
|
1312
1500
|
return new AST_Try({
|
|
1313
1501
|
'body': body,
|
|
1314
|
-
'bcatch': (new AST_Catch({
|
|
1502
|
+
'bcatch': (new AST_Catch({'body': bcatch}) if bcatch.length else None),
|
|
1315
1503
|
'bfinally': bfinally,
|
|
1316
1504
|
'belse': belse
|
|
1317
1505
|
})
|
|
1318
1506
|
|
|
1319
|
-
def vardefs(symbol_class):
|
|
1507
|
+
async def vardefs(symbol_class):
|
|
1320
1508
|
a = []
|
|
1321
1509
|
while True:
|
|
1510
|
+
vd_start = S.token
|
|
1511
|
+
vd_name = as_symbol(symbol_class)
|
|
1512
|
+
if is_('operator', '='):
|
|
1513
|
+
next()
|
|
1514
|
+
varval = await expression(False)
|
|
1515
|
+
else:
|
|
1516
|
+
varval = None
|
|
1322
1517
|
a.push(new AST_VarDef({
|
|
1323
|
-
'start':
|
|
1324
|
-
'name':
|
|
1325
|
-
'value':
|
|
1518
|
+
'start': vd_start,
|
|
1519
|
+
'name': vd_name,
|
|
1520
|
+
'value': varval,
|
|
1326
1521
|
'end': prev()
|
|
1327
1522
|
}))
|
|
1328
|
-
if not is_(
|
|
1523
|
+
if not is_('punc', ','):
|
|
1329
1524
|
break
|
|
1330
1525
|
next()
|
|
1331
1526
|
|
|
1332
1527
|
return a
|
|
1333
1528
|
|
|
1334
|
-
def nonlocal_(is_global):
|
|
1335
|
-
defs = vardefs(AST_SymbolNonlocal)
|
|
1529
|
+
async def nonlocal_(is_global):
|
|
1530
|
+
defs = await vardefs(AST_SymbolNonlocal)
|
|
1336
1531
|
if is_global:
|
|
1337
1532
|
for vardef in defs:
|
|
1338
1533
|
S.globals.push(vardef.name.name)
|
|
@@ -1342,19 +1537,19 @@ def create_parser_ctx(S, import_dirs, module_id, baselib_items, imported_module_
|
|
|
1342
1537
|
'end': prev()
|
|
1343
1538
|
})
|
|
1344
1539
|
|
|
1345
|
-
def new_():
|
|
1540
|
+
async def new_():
|
|
1346
1541
|
start = S.token
|
|
1347
|
-
expect_token(
|
|
1348
|
-
newexp = expr_atom(False)
|
|
1542
|
+
expect_token('operator', 'new')
|
|
1543
|
+
newexp = await expr_atom(False)
|
|
1349
1544
|
|
|
1350
|
-
if is_(
|
|
1545
|
+
if is_('punc', '('):
|
|
1351
1546
|
S.in_parenthesized_expr = True
|
|
1352
1547
|
next()
|
|
1353
|
-
args = func_call_list()
|
|
1548
|
+
args = await func_call_list()
|
|
1354
1549
|
S.in_parenthesized_expr = False
|
|
1355
1550
|
else:
|
|
1356
|
-
args = func_call_list(True)
|
|
1357
|
-
return subscripts(new AST_New({
|
|
1551
|
+
args = await func_call_list(True)
|
|
1552
|
+
return await subscripts(new AST_New({
|
|
1358
1553
|
'start': start,
|
|
1359
1554
|
'expression': newexp,
|
|
1360
1555
|
'args': args,
|
|
@@ -1378,40 +1573,40 @@ def create_parser_ctx(S, import_dirs, module_id, baselib_items, imported_module_
|
|
|
1378
1573
|
def token_as_atom_node():
|
|
1379
1574
|
tok = S.token
|
|
1380
1575
|
tmp_ = tok.type
|
|
1381
|
-
if tmp_ is
|
|
1576
|
+
if tmp_ is 'name':
|
|
1382
1577
|
return token_as_symbol(tok, AST_SymbolRef)
|
|
1383
|
-
elif tmp_ is
|
|
1578
|
+
elif tmp_ is 'num':
|
|
1384
1579
|
return new AST_Number({
|
|
1385
1580
|
'start': tok,
|
|
1386
1581
|
'end': tok,
|
|
1387
1582
|
'value': tok.value
|
|
1388
1583
|
})
|
|
1389
|
-
elif tmp_ is
|
|
1584
|
+
elif tmp_ is 'string':
|
|
1390
1585
|
return string_()
|
|
1391
|
-
elif tmp_ is
|
|
1586
|
+
elif tmp_ is 'regexp':
|
|
1392
1587
|
return new AST_RegExp({
|
|
1393
1588
|
'start': tok,
|
|
1394
1589
|
'end': tok,
|
|
1395
1590
|
'value': tok.value
|
|
1396
1591
|
})
|
|
1397
|
-
elif tmp_ is
|
|
1592
|
+
elif tmp_ is 'atom':
|
|
1398
1593
|
tmp__ = tok.value
|
|
1399
|
-
if tmp__ is
|
|
1594
|
+
if tmp__ is 'False':
|
|
1400
1595
|
return new AST_False({
|
|
1401
1596
|
'start': tok,
|
|
1402
1597
|
'end': tok
|
|
1403
1598
|
})
|
|
1404
|
-
elif tmp__ is
|
|
1599
|
+
elif tmp__ is 'True':
|
|
1405
1600
|
return new AST_True({
|
|
1406
1601
|
'start': tok,
|
|
1407
1602
|
'end': tok
|
|
1408
1603
|
})
|
|
1409
|
-
elif tmp__ is
|
|
1604
|
+
elif tmp__ is 'None':
|
|
1410
1605
|
return new AST_Null({
|
|
1411
1606
|
'start': tok,
|
|
1412
1607
|
'end': tok
|
|
1413
1608
|
})
|
|
1414
|
-
elif tmp_ is
|
|
1609
|
+
elif tmp_ is 'js':
|
|
1415
1610
|
return new AST_Verbatim({
|
|
1416
1611
|
'start': tok,
|
|
1417
1612
|
'end': tok,
|
|
@@ -1424,22 +1619,22 @@ def create_parser_ctx(S, import_dirs, module_id, baselib_items, imported_module_
|
|
|
1424
1619
|
next()
|
|
1425
1620
|
return ret
|
|
1426
1621
|
|
|
1427
|
-
def expr_atom(allow_calls):
|
|
1428
|
-
if is_(
|
|
1429
|
-
return new_()
|
|
1622
|
+
async def expr_atom(allow_calls):
|
|
1623
|
+
if is_('operator', 'new'):
|
|
1624
|
+
return await new_()
|
|
1430
1625
|
|
|
1431
1626
|
start = S.token
|
|
1432
|
-
if is_(
|
|
1627
|
+
if is_('punc'):
|
|
1433
1628
|
tmp_ = start.value
|
|
1434
|
-
if tmp_ is
|
|
1629
|
+
if tmp_ is '(':
|
|
1435
1630
|
S.in_parenthesized_expr = True
|
|
1436
1631
|
next()
|
|
1437
1632
|
if is_('punc', ')'):
|
|
1438
1633
|
next()
|
|
1439
|
-
return new AST_Array({'elements':[]})
|
|
1440
|
-
ex = expression(True)
|
|
1634
|
+
return new AST_Array({'elements': []})
|
|
1635
|
+
ex = await expression(True)
|
|
1441
1636
|
if is_('keyword', 'for'):
|
|
1442
|
-
ret = read_comprehension(new AST_GeneratorComprehension({'statement': ex}), ')')
|
|
1637
|
+
ret = await read_comprehension(new AST_GeneratorComprehension({'statement': ex}), ')')
|
|
1443
1638
|
S.in_parenthesized_expr = False
|
|
1444
1639
|
return ret
|
|
1445
1640
|
ex.start = start
|
|
@@ -1447,153 +1642,168 @@ def create_parser_ctx(S, import_dirs, module_id, baselib_items, imported_module_
|
|
|
1447
1642
|
if is_node_type(ex, AST_SymbolRef):
|
|
1448
1643
|
ex.parens = True
|
|
1449
1644
|
if not is_node_type(ex, AST_GeneratorComprehension):
|
|
1450
|
-
expect(
|
|
1645
|
+
expect(')')
|
|
1451
1646
|
if is_node_type(ex, AST_UnaryPrefix):
|
|
1452
1647
|
ex.parenthesized = True
|
|
1453
1648
|
S.in_parenthesized_expr = False
|
|
1454
|
-
return subscripts(ex, allow_calls)
|
|
1455
|
-
elif tmp_ is
|
|
1456
|
-
return subscripts(array_(), allow_calls)
|
|
1457
|
-
elif tmp_ is
|
|
1458
|
-
return subscripts(object_(), allow_calls)
|
|
1649
|
+
return await subscripts(ex, allow_calls)
|
|
1650
|
+
elif tmp_ is '[':
|
|
1651
|
+
return await subscripts(await array_(), allow_calls)
|
|
1652
|
+
elif tmp_ is '{':
|
|
1653
|
+
return await subscripts(await object_(), allow_calls)
|
|
1459
1654
|
|
|
1460
1655
|
unexpected()
|
|
1461
1656
|
|
|
1462
|
-
if is_(
|
|
1657
|
+
if is_('keyword', 'class'):
|
|
1463
1658
|
next()
|
|
1464
|
-
cls = class_()
|
|
1659
|
+
cls = await class_()
|
|
1465
1660
|
cls.start = start
|
|
1466
1661
|
cls.end = prev()
|
|
1467
|
-
return subscripts(cls, allow_calls)
|
|
1662
|
+
return await subscripts(cls, allow_calls)
|
|
1468
1663
|
|
|
1469
|
-
if is_(
|
|
1664
|
+
if is_('keyword', 'async'):
|
|
1470
1665
|
next()
|
|
1471
|
-
|
|
1666
|
+
if not is_('keyword', 'def'):
|
|
1667
|
+
croak("Expected 'def' after 'async'")
|
|
1668
|
+
next()
|
|
1669
|
+
func = await function_(False, True, True)
|
|
1472
1670
|
func.start = start
|
|
1473
1671
|
func.end = prev()
|
|
1474
|
-
return subscripts(func, allow_calls)
|
|
1672
|
+
return await subscripts(func, allow_calls)
|
|
1673
|
+
|
|
1674
|
+
if is_('keyword', 'def'):
|
|
1675
|
+
next()
|
|
1676
|
+
func = await function_(False, True)
|
|
1677
|
+
func.start = start
|
|
1678
|
+
func.end = prev()
|
|
1679
|
+
return await subscripts(func, allow_calls)
|
|
1680
|
+
|
|
1681
|
+
if is_('keyword', 'await'):
|
|
1682
|
+
next()
|
|
1683
|
+
if S.in_function is 0 or not S.functions[-1].is_async:
|
|
1684
|
+
croak("'await' outside of async function")
|
|
1685
|
+
value = await expr_atom(True)
|
|
1686
|
+
return new AST_Await({'value': value})
|
|
1475
1687
|
|
|
1476
1688
|
if is_('keyword', 'yield'):
|
|
1477
1689
|
next()
|
|
1478
|
-
return yield_()
|
|
1690
|
+
return await yield_()
|
|
1479
1691
|
|
|
1480
1692
|
if ATOMIC_START_TOKEN[S.token.type]:
|
|
1481
|
-
return subscripts(as_atom_node(), allow_calls)
|
|
1693
|
+
return await subscripts(as_atom_node(), allow_calls)
|
|
1482
1694
|
|
|
1483
1695
|
unexpected()
|
|
1484
1696
|
|
|
1485
|
-
def expr_list(closing, allow_trailing_comma, allow_empty, func_call):
|
|
1697
|
+
async def expr_list(closing, allow_trailing_comma, allow_empty, func_call):
|
|
1486
1698
|
first = True
|
|
1487
1699
|
a = []
|
|
1488
1700
|
saw_starargs = False
|
|
1489
|
-
while not is_(
|
|
1701
|
+
while not is_('punc', closing):
|
|
1490
1702
|
if saw_starargs:
|
|
1491
|
-
token_error(prev(),
|
|
1703
|
+
token_error(prev(), '*args must be the last argument in a function call')
|
|
1492
1704
|
|
|
1493
1705
|
if first:
|
|
1494
1706
|
first = False
|
|
1495
1707
|
else:
|
|
1496
|
-
expect(
|
|
1497
|
-
if allow_trailing_comma and is_(
|
|
1708
|
+
expect(',')
|
|
1709
|
+
if allow_trailing_comma and is_('punc', closing):
|
|
1498
1710
|
break
|
|
1499
1711
|
|
|
1500
|
-
if is_(
|
|
1712
|
+
if is_('operator', '*') and func_call:
|
|
1501
1713
|
saw_starargs = True
|
|
1502
1714
|
next()
|
|
1503
1715
|
|
|
1504
|
-
if is_(
|
|
1716
|
+
if is_('punc', ',') and allow_empty:
|
|
1505
1717
|
a.push(new AST_Hole({
|
|
1506
1718
|
'start': S.token,
|
|
1507
1719
|
'end': S.token
|
|
1508
1720
|
}))
|
|
1509
1721
|
else:
|
|
1510
|
-
a.push(expression(False))
|
|
1722
|
+
a.push(await expression(False))
|
|
1511
1723
|
|
|
1724
|
+
next()
|
|
1512
1725
|
if func_call:
|
|
1513
|
-
|
|
1514
|
-
|
|
1726
|
+
pargs = []
|
|
1727
|
+
kwargs = []
|
|
1515
1728
|
for arg in a:
|
|
1516
1729
|
if is_node_type(arg, AST_Assign):
|
|
1517
|
-
|
|
1730
|
+
kwargs.push([arg.left, arg.right])
|
|
1518
1731
|
else:
|
|
1519
|
-
|
|
1520
|
-
|
|
1521
|
-
|
|
1522
|
-
next()
|
|
1523
|
-
if saw_starargs:
|
|
1524
|
-
a.starargs = True
|
|
1732
|
+
pargs.push(arg)
|
|
1733
|
+
return new AST_CallArgs({'args': pargs, 'kwargs': kwargs, 'kwarg_items': v'[]', 'starargs': saw_starargs})
|
|
1525
1734
|
return a
|
|
1526
1735
|
|
|
1527
|
-
def func_call_list(empty):
|
|
1736
|
+
async def func_call_list(empty):
|
|
1528
1737
|
a = v'[]'
|
|
1529
1738
|
first = True
|
|
1530
|
-
|
|
1531
|
-
|
|
1532
|
-
|
|
1739
|
+
kwargs = v'[]'
|
|
1740
|
+
kwarg_items = v'[]'
|
|
1741
|
+
starargs = False
|
|
1533
1742
|
if empty:
|
|
1534
|
-
return a
|
|
1743
|
+
return new AST_CallArgs({'args': a, 'kwargs': kwargs, 'kwarg_items': kwarg_items, 'starargs': starargs})
|
|
1535
1744
|
single_comprehension = False
|
|
1536
|
-
while not is_(
|
|
1745
|
+
while not is_('punc', ')') and not is_('eof'):
|
|
1537
1746
|
if not first:
|
|
1538
|
-
expect(
|
|
1747
|
+
expect(',')
|
|
1539
1748
|
if is_('punc', ')'):
|
|
1540
1749
|
break
|
|
1541
1750
|
if is_('operator', '*'):
|
|
1542
1751
|
next()
|
|
1543
|
-
arg = expression(False)
|
|
1544
|
-
arg
|
|
1545
|
-
|
|
1546
|
-
a.starargs = True
|
|
1752
|
+
arg = await expression(False)
|
|
1753
|
+
a.push(new AST_CallArg({'value': arg, 'is_array': True}))
|
|
1754
|
+
starargs = True
|
|
1547
1755
|
elif is_('operator', '**'):
|
|
1548
1756
|
next()
|
|
1549
|
-
|
|
1550
|
-
|
|
1757
|
+
kwarg_items.push(as_symbol(AST_SymbolRef, False))
|
|
1758
|
+
starargs = True
|
|
1551
1759
|
else:
|
|
1552
|
-
arg = expression(False)
|
|
1760
|
+
arg = await expression(False)
|
|
1553
1761
|
if is_node_type(arg, AST_Assign):
|
|
1554
|
-
|
|
1762
|
+
kwargs.push([arg.left, arg.right])
|
|
1555
1763
|
else:
|
|
1556
1764
|
if is_('keyword', 'for'):
|
|
1557
1765
|
if not first:
|
|
1558
1766
|
croak('Generator expression must be parenthesized if not sole argument')
|
|
1559
|
-
|
|
1767
|
+
comp = await read_comprehension(new AST_GeneratorComprehension({'statement': arg}), ')')
|
|
1768
|
+
a.push(new AST_CallArg({'value': comp, 'is_array': False}))
|
|
1560
1769
|
single_comprehension = True
|
|
1561
1770
|
break
|
|
1562
|
-
a.push(arg)
|
|
1771
|
+
a.push(new AST_CallArg({'value': arg, 'is_array': False}))
|
|
1563
1772
|
first = False
|
|
1564
1773
|
if not single_comprehension:
|
|
1565
1774
|
next()
|
|
1566
|
-
return a
|
|
1775
|
+
return new AST_CallArgs({'args': a, 'kwargs': kwargs, 'kwarg_items': kwarg_items, 'starargs': starargs})
|
|
1567
1776
|
|
|
1568
1777
|
@embed_tokens
|
|
1569
|
-
def array_():
|
|
1570
|
-
expect(
|
|
1778
|
+
async def array_():
|
|
1779
|
+
expect('[')
|
|
1571
1780
|
expr = []
|
|
1572
|
-
if not is_(
|
|
1573
|
-
expr.push(expression(False))
|
|
1574
|
-
if is_(
|
|
1781
|
+
if not is_('punc', ']'):
|
|
1782
|
+
expr.push(await expression(False))
|
|
1783
|
+
if is_('keyword', 'for'):
|
|
1575
1784
|
# list comprehension
|
|
1576
|
-
return read_comprehension(new AST_ListComprehension({'statement': expr[0]}), ']')
|
|
1785
|
+
return await read_comprehension(new AST_ListComprehension({'statement': expr[0]}), ']')
|
|
1577
1786
|
|
|
1578
|
-
if not is_(
|
|
1579
|
-
expect(
|
|
1787
|
+
if not is_('punc', ']'):
|
|
1788
|
+
expect(',')
|
|
1580
1789
|
|
|
1790
|
+
arr_rest = await expr_list(']', True, True)
|
|
1581
1791
|
return new AST_Array({
|
|
1582
|
-
'elements': expr.concat(
|
|
1792
|
+
'elements': expr.concat(arr_rest)
|
|
1583
1793
|
})
|
|
1584
1794
|
|
|
1585
1795
|
@embed_tokens
|
|
1586
|
-
def object_():
|
|
1587
|
-
expect(
|
|
1796
|
+
async def object_():
|
|
1797
|
+
expect('{')
|
|
1588
1798
|
first = True
|
|
1589
1799
|
has_non_const_keys = False
|
|
1590
1800
|
is_pydict = S.scoped_flags.get('dict_literals', False)
|
|
1591
1801
|
is_jshash = S.scoped_flags.get('hash_literals', False)
|
|
1592
1802
|
a = []
|
|
1593
|
-
while not is_(
|
|
1803
|
+
while not is_('punc', '}'):
|
|
1594
1804
|
if not first:
|
|
1595
|
-
expect(
|
|
1596
|
-
if is_(
|
|
1805
|
+
expect(',')
|
|
1806
|
+
if is_('punc', '}'):
|
|
1597
1807
|
# allow trailing comma
|
|
1598
1808
|
break
|
|
1599
1809
|
first = False
|
|
@@ -1603,26 +1813,27 @@ def create_parser_ctx(S, import_dirs, module_id, baselib_items, imported_module_
|
|
|
1603
1813
|
orig = ctx.expecting_object_literal_key
|
|
1604
1814
|
ctx.expecting_object_literal_key = True
|
|
1605
1815
|
try:
|
|
1606
|
-
left = expression(False)
|
|
1816
|
+
left = await expression(False)
|
|
1607
1817
|
finally:
|
|
1608
1818
|
ctx.expecting_object_literal_key = orig
|
|
1609
1819
|
if is_('keyword', 'for'):
|
|
1610
1820
|
# is_pydict is irrelevant here
|
|
1611
|
-
return read_comprehension(new AST_SetComprehension({'statement':left}), '}')
|
|
1821
|
+
return await read_comprehension(new AST_SetComprehension({'statement': left}), '}')
|
|
1612
1822
|
if a.length is 0 and (is_('punc', ',') or is_('punc', '}')):
|
|
1613
1823
|
end = prev()
|
|
1614
|
-
return set_(start, end, left)
|
|
1824
|
+
return await set_(start, end, left)
|
|
1615
1825
|
if not is_node_type(left, AST_Constant):
|
|
1616
1826
|
has_non_const_keys = True
|
|
1617
|
-
expect(
|
|
1827
|
+
expect(':')
|
|
1828
|
+
obj_val = await expression(False)
|
|
1618
1829
|
a.push(new AST_ObjectKeyVal({
|
|
1619
1830
|
'start': start,
|
|
1620
1831
|
'key': left,
|
|
1621
|
-
'value':
|
|
1832
|
+
'value': obj_val,
|
|
1622
1833
|
'end': prev()
|
|
1623
1834
|
}))
|
|
1624
1835
|
if a.length is 1 and is_('keyword', 'for'):
|
|
1625
|
-
return dict_comprehension(a, is_pydict, is_jshash)
|
|
1836
|
+
return await dict_comprehension(a, is_pydict, is_jshash)
|
|
1626
1837
|
|
|
1627
1838
|
next()
|
|
1628
1839
|
return new (AST_ExpressiveObject if has_non_const_keys else AST_Object)({
|
|
@@ -1631,50 +1842,58 @@ def create_parser_ctx(S, import_dirs, module_id, baselib_items, imported_module_
|
|
|
1631
1842
|
'is_jshash': is_jshash,
|
|
1632
1843
|
})
|
|
1633
1844
|
|
|
1634
|
-
def set_(start, end, expr):
|
|
1845
|
+
async def set_(start, end, expr):
|
|
1635
1846
|
ostart = start
|
|
1636
|
-
a = [new AST_SetItem({'start':start, 'end':end, 'value':expr})]
|
|
1637
|
-
while not is_(
|
|
1638
|
-
expect(
|
|
1847
|
+
a = [new AST_SetItem({'start': start, 'end': end, 'value': expr})]
|
|
1848
|
+
while not is_('punc', '}'):
|
|
1849
|
+
expect(',')
|
|
1639
1850
|
start = S.token
|
|
1640
|
-
if is_(
|
|
1851
|
+
if is_('punc', '}'):
|
|
1641
1852
|
# allow trailing comma
|
|
1642
1853
|
break
|
|
1643
|
-
|
|
1854
|
+
set_val = await expression(False)
|
|
1855
|
+
a.push(new AST_SetItem({'start': start, 'value': set_val, 'end': prev()}))
|
|
1644
1856
|
next()
|
|
1645
|
-
return new AST_Set({'items':a, 'start':ostart, 'end':prev()})
|
|
1857
|
+
return new AST_Set({'items': a, 'start': ostart, 'end': prev()})
|
|
1646
1858
|
|
|
1647
|
-
def read_comprehension(obj, terminator):
|
|
1859
|
+
async def read_comprehension(obj, terminator):
|
|
1648
1860
|
if is_node_type(obj, AST_GeneratorComprehension):
|
|
1649
1861
|
baselib_items['yield'] = True
|
|
1650
1862
|
S.in_comprehension = True
|
|
1651
1863
|
S.in_parenthesized_expr = False # in case we are already in a parenthesized expression
|
|
1652
1864
|
expect_token('keyword', 'for')
|
|
1653
|
-
forloop = for_(True)
|
|
1865
|
+
forloop = await for_(True)
|
|
1654
1866
|
obj.init = forloop.init
|
|
1655
1867
|
obj.name = forloop.name
|
|
1656
1868
|
obj.object = forloop.object
|
|
1657
|
-
|
|
1869
|
+
if is_('punc', terminator):
|
|
1870
|
+
obj.condition = None
|
|
1871
|
+
else:
|
|
1872
|
+
expect_token('keyword', 'if')
|
|
1873
|
+
obj.condition = await expression(True)
|
|
1658
1874
|
expect(terminator)
|
|
1659
1875
|
S.in_comprehension = False
|
|
1660
1876
|
return obj
|
|
1661
1877
|
|
|
1662
|
-
def dict_comprehension(a, is_pydict, is_jshash):
|
|
1878
|
+
async def dict_comprehension(a, is_pydict, is_jshash):
|
|
1663
1879
|
if a.length:
|
|
1664
1880
|
left, right = a[0].key, a[0].value
|
|
1665
1881
|
else:
|
|
1666
|
-
left = expression(False)
|
|
1882
|
+
left = await expression(False)
|
|
1667
1883
|
if not is_('punc', ':'):
|
|
1668
|
-
return read_comprehension(new AST_SetComprehension({'statement':left}), '}')
|
|
1884
|
+
return await read_comprehension(new AST_SetComprehension({'statement': left}), '}')
|
|
1669
1885
|
expect(':')
|
|
1670
|
-
right = expression(False)
|
|
1671
|
-
return read_comprehension(
|
|
1886
|
+
right = await expression(False)
|
|
1887
|
+
return await read_comprehension(
|
|
1888
|
+
new AST_DictComprehension({'statement': left, 'value_statement': right, 'is_pydict': is_pydict, 'is_jshash': is_jshash}),
|
|
1889
|
+
'}'
|
|
1890
|
+
)
|
|
1672
1891
|
|
|
1673
1892
|
def as_name():
|
|
1674
1893
|
tmp = S.token
|
|
1675
1894
|
next()
|
|
1676
1895
|
tmp_ = tmp.type
|
|
1677
|
-
if tmp_ is
|
|
1896
|
+
if tmp_ is 'name' or tmp_ is 'operator' or tmp_ is 'keyword' or tmp_ is 'atom':
|
|
1678
1897
|
return tmp.value
|
|
1679
1898
|
else:
|
|
1680
1899
|
unexpected()
|
|
@@ -1690,9 +1909,9 @@ def create_parser_ctx(S, import_dirs, module_id, baselib_items, imported_module_
|
|
|
1690
1909
|
})
|
|
1691
1910
|
|
|
1692
1911
|
def as_symbol(ttype, noerror):
|
|
1693
|
-
if not is_(
|
|
1912
|
+
if not is_('name'):
|
|
1694
1913
|
if not noerror:
|
|
1695
|
-
croak(
|
|
1914
|
+
croak('Name expected')
|
|
1696
1915
|
return None
|
|
1697
1916
|
|
|
1698
1917
|
sym = token_as_symbol(S.token, ttype)
|
|
@@ -1714,49 +1933,50 @@ def create_parser_ctx(S, import_dirs, module_id, baselib_items, imported_module_
|
|
|
1714
1933
|
else:
|
|
1715
1934
|
return False
|
|
1716
1935
|
|
|
1717
|
-
def getitem(expr, allow_calls):
|
|
1936
|
+
async def getitem(expr, allow_calls):
|
|
1718
1937
|
start = expr.start
|
|
1719
1938
|
next()
|
|
1720
1939
|
is_py_sub = S.scoped_flags.get('overload_getitem', False)
|
|
1721
1940
|
slice_bounds = v'[]'
|
|
1722
1941
|
is_slice = False
|
|
1723
|
-
if is_(
|
|
1942
|
+
if is_('punc', ':'):
|
|
1724
1943
|
# slice [:n]
|
|
1725
1944
|
slice_bounds.push(None)
|
|
1726
1945
|
else:
|
|
1727
|
-
slice_bounds.push(expression(False))
|
|
1946
|
+
slice_bounds.push(await expression(False))
|
|
1728
1947
|
|
|
1729
|
-
if is_(
|
|
1948
|
+
if is_('punc', ':'):
|
|
1730
1949
|
# slice [n:m?]
|
|
1731
1950
|
is_slice = True
|
|
1732
1951
|
next()
|
|
1733
|
-
if is_(
|
|
1952
|
+
if is_('punc', ':'):
|
|
1734
1953
|
slice_bounds.push(None)
|
|
1735
|
-
elif not is_(
|
|
1736
|
-
slice_bounds.push(expression(False))
|
|
1954
|
+
elif not is_('punc', ']'):
|
|
1955
|
+
slice_bounds.push(await expression(False))
|
|
1737
1956
|
|
|
1738
|
-
if is_(
|
|
1957
|
+
if is_('punc', ':'):
|
|
1739
1958
|
# slice [n:m:o?]
|
|
1740
1959
|
next()
|
|
1741
|
-
if is_(
|
|
1960
|
+
if is_('punc', ']'):
|
|
1742
1961
|
unexpected()
|
|
1743
1962
|
else:
|
|
1744
|
-
slice_bounds.push(expression(False))
|
|
1963
|
+
slice_bounds.push(await expression(False))
|
|
1745
1964
|
|
|
1746
|
-
expect(
|
|
1965
|
+
expect(']')
|
|
1747
1966
|
|
|
1748
1967
|
if is_slice:
|
|
1749
|
-
if is_(
|
|
1968
|
+
if is_('operator', '='):
|
|
1750
1969
|
# splice-assignment (arr[start:end] = ...)
|
|
1751
1970
|
next() # swallow the assignment
|
|
1752
|
-
|
|
1971
|
+
splice_assign = await expression(True)
|
|
1972
|
+
return await subscripts(new AST_Splice({
|
|
1753
1973
|
'start': start,
|
|
1754
1974
|
'expression': expr,
|
|
1755
1975
|
'property': slice_bounds[0] or new AST_Number({
|
|
1756
1976
|
'value': 0
|
|
1757
1977
|
}),
|
|
1758
1978
|
'property2': slice_bounds[1],
|
|
1759
|
-
'assignment':
|
|
1979
|
+
'assignment': splice_assign,
|
|
1760
1980
|
'end': prev()
|
|
1761
1981
|
}), allow_calls)
|
|
1762
1982
|
elif slice_bounds.length is 3:
|
|
@@ -1768,34 +1988,46 @@ def create_parser_ctx(S, import_dirs, module_id, baselib_items, imported_module_
|
|
|
1768
1988
|
slice_bounds.pop()
|
|
1769
1989
|
elif not slice_bounds[-2]:
|
|
1770
1990
|
slice_bounds[-2] = new AST_Undefined()
|
|
1771
|
-
|
|
1991
|
+
_ca = v'[]'
|
|
1992
|
+
_ca.push(new AST_CallArg({'value': expr, 'is_array': False}))
|
|
1993
|
+
for _sb in slice_bounds:
|
|
1994
|
+
_ca.push(new AST_CallArg({'value': _sb, 'is_array': False}))
|
|
1995
|
+
return await subscripts(new AST_Call({
|
|
1772
1996
|
'start': start,
|
|
1773
1997
|
'expression': new AST_SymbolRef({
|
|
1774
|
-
'name': 'ρσ_delslice' if S.in_delete else
|
|
1998
|
+
'name': 'ρσ_delslice' if S.in_delete else 'ρσ_eslice'
|
|
1775
1999
|
}),
|
|
1776
|
-
'args': [
|
|
2000
|
+
'args': new AST_CallArgs({'args': _ca, 'kwargs': v'[]', 'kwarg_items': v'[]', 'starargs': False}),
|
|
1777
2001
|
'end': prev()
|
|
1778
2002
|
}), allow_calls)
|
|
1779
2003
|
else:
|
|
1780
2004
|
# regular slice (arr[start:end])
|
|
1781
|
-
slice_bounds = [new AST_Number({'value':0}) if i is None else i for i in slice_bounds]
|
|
2005
|
+
slice_bounds = [new AST_Number({'value': 0}) if i is None else i for i in slice_bounds]
|
|
1782
2006
|
if S.in_delete:
|
|
1783
|
-
|
|
2007
|
+
_ca2 = v'[]'
|
|
2008
|
+
_ca2.push(new AST_CallArg({'value': expr, 'is_array': False}))
|
|
2009
|
+
_ca2.push(new AST_CallArg({'value': new AST_Number({'value': 1}), 'is_array': False}))
|
|
2010
|
+
for _sb in slice_bounds:
|
|
2011
|
+
_ca2.push(new AST_CallArg({'value': _sb, 'is_array': False}))
|
|
2012
|
+
return await subscripts(new AST_Call({
|
|
1784
2013
|
'start': start,
|
|
1785
2014
|
'expression': new AST_SymbolRef({'name': 'ρσ_delslice'}),
|
|
1786
|
-
'args':
|
|
2015
|
+
'args': new AST_CallArgs({'args': _ca2, 'kwargs': v'[]', 'kwarg_items': v'[]', 'starargs': False}),
|
|
1787
2016
|
'end': prev()
|
|
1788
2017
|
}), allow_calls)
|
|
1789
2018
|
|
|
1790
|
-
|
|
2019
|
+
_ca3 = v'[]'
|
|
2020
|
+
for _sb in slice_bounds:
|
|
2021
|
+
_ca3.push(new AST_CallArg({'value': _sb, 'is_array': False}))
|
|
2022
|
+
return await subscripts(new AST_Call({
|
|
1791
2023
|
'start': start,
|
|
1792
2024
|
'expression': new AST_Dot({
|
|
1793
2025
|
'start': start,
|
|
1794
2026
|
'expression': expr,
|
|
1795
|
-
'property':
|
|
2027
|
+
'property': 'slice',
|
|
1796
2028
|
'end': prev()
|
|
1797
2029
|
}),
|
|
1798
|
-
'args':
|
|
2030
|
+
'args': new AST_CallArgs({'args': _ca3, 'kwargs': v'[]', 'kwarg_items': v'[]', 'starargs': False}),
|
|
1799
2031
|
'end': prev()
|
|
1800
2032
|
}), allow_calls)
|
|
1801
2033
|
else:
|
|
@@ -1803,22 +2035,22 @@ def create_parser_ctx(S, import_dirs, module_id, baselib_items, imported_module_
|
|
|
1803
2035
|
if is_py_sub:
|
|
1804
2036
|
assignment = None
|
|
1805
2037
|
assign_operator = ''
|
|
1806
|
-
if is_(
|
|
2038
|
+
if is_('operator') and ASSIGNMENT[S.token.value]:
|
|
1807
2039
|
assign_operator = S.token.value[:-1]
|
|
1808
2040
|
next()
|
|
1809
|
-
assignment = expression(True)
|
|
1810
|
-
return subscripts(new AST_ItemAccess({
|
|
2041
|
+
assignment = await expression(True)
|
|
2042
|
+
return await subscripts(new AST_ItemAccess({
|
|
1811
2043
|
'start': start,
|
|
1812
2044
|
'expression': expr,
|
|
1813
2045
|
'property': slice_bounds[0] or new AST_Number({
|
|
1814
2046
|
'value': 0
|
|
1815
2047
|
}),
|
|
1816
|
-
'assignment':assignment,
|
|
2048
|
+
'assignment': assignment,
|
|
1817
2049
|
'assign_operator': assign_operator,
|
|
1818
2050
|
'end': prev()
|
|
1819
2051
|
}), allow_calls)
|
|
1820
2052
|
|
|
1821
|
-
return subscripts(new AST_Sub({
|
|
2053
|
+
return await subscripts(new AST_Sub({
|
|
1822
2054
|
'start': start,
|
|
1823
2055
|
'expression': expr,
|
|
1824
2056
|
'property': slice_bounds[0] or new AST_Number({
|
|
@@ -1827,16 +2059,17 @@ def create_parser_ctx(S, import_dirs, module_id, baselib_items, imported_module_
|
|
|
1827
2059
|
'end': prev()
|
|
1828
2060
|
}), allow_calls)
|
|
1829
2061
|
|
|
1830
|
-
def call_(expr):
|
|
2062
|
+
async def call_(expr):
|
|
1831
2063
|
start = expr.start
|
|
1832
2064
|
S.in_parenthesized_expr = True
|
|
1833
2065
|
next()
|
|
1834
2066
|
if not expr.parens and get_class_in_scope(expr):
|
|
1835
2067
|
# this is an object being created using a class
|
|
1836
|
-
|
|
2068
|
+
call_args = await func_call_list()
|
|
2069
|
+
ret = await subscripts(new AST_New({
|
|
1837
2070
|
'start': start,
|
|
1838
2071
|
'expression': expr,
|
|
1839
|
-
'args':
|
|
2072
|
+
'args': call_args,
|
|
1840
2073
|
'end': prev()
|
|
1841
2074
|
}), True)
|
|
1842
2075
|
S.in_parenthesized_expr = False
|
|
@@ -1849,52 +2082,55 @@ def create_parser_ctx(S, import_dirs, module_id, baselib_items, imported_module_
|
|
|
1849
2082
|
# generate class call
|
|
1850
2083
|
funcname = expr
|
|
1851
2084
|
|
|
1852
|
-
|
|
2085
|
+
classcall_args = await func_call_list()
|
|
2086
|
+
ret = await subscripts(new AST_ClassCall({
|
|
1853
2087
|
'start': start,
|
|
1854
|
-
|
|
2088
|
+
'class': expr.expression,
|
|
1855
2089
|
'method': funcname.property,
|
|
1856
|
-
|
|
1857
|
-
'args':
|
|
2090
|
+
'static': is_static_method(c, funcname.property),
|
|
2091
|
+
'args': classcall_args,
|
|
1858
2092
|
'end': prev()
|
|
1859
2093
|
}), True)
|
|
1860
2094
|
S.in_parenthesized_expr = False
|
|
1861
2095
|
return ret
|
|
1862
2096
|
elif is_node_type(expr, AST_SymbolRef):
|
|
1863
2097
|
tmp_ = expr.name
|
|
1864
|
-
if tmp_ is
|
|
2098
|
+
if tmp_ is 'jstype':
|
|
2099
|
+
jstype_args = await func_call_list()
|
|
1865
2100
|
ret = new AST_UnaryPrefix({
|
|
1866
2101
|
'start': start,
|
|
1867
|
-
'operator':
|
|
1868
|
-
'expression':
|
|
2102
|
+
'operator': 'typeof',
|
|
2103
|
+
'expression': jstype_args.args[0].value,
|
|
1869
2104
|
'end': prev()
|
|
1870
2105
|
})
|
|
1871
2106
|
S.in_parenthesized_expr = False
|
|
1872
2107
|
return ret
|
|
1873
|
-
elif tmp_ is
|
|
1874
|
-
args = func_call_list()
|
|
1875
|
-
if args.length is not 2:
|
|
2108
|
+
elif tmp_ is 'isinstance':
|
|
2109
|
+
args = await func_call_list()
|
|
2110
|
+
if args.args.length is not 2:
|
|
1876
2111
|
croak('isinstance() must be called with exactly two arguments')
|
|
1877
2112
|
ret = new AST_Binary({
|
|
1878
2113
|
'start': start,
|
|
1879
|
-
'left': args[0],
|
|
2114
|
+
'left': args.args[0].value,
|
|
1880
2115
|
'operator': 'instanceof',
|
|
1881
|
-
'right': args[1],
|
|
2116
|
+
'right': args.args[1].value,
|
|
1882
2117
|
'end': prev()
|
|
1883
2118
|
})
|
|
1884
2119
|
S.in_parenthesized_expr = False
|
|
1885
2120
|
return ret
|
|
1886
2121
|
|
|
1887
2122
|
# fall-through to basic function call
|
|
1888
|
-
|
|
2123
|
+
basic_args = await func_call_list()
|
|
2124
|
+
ret = await subscripts(new AST_Call({
|
|
1889
2125
|
'start': start,
|
|
1890
2126
|
'expression': expr,
|
|
1891
|
-
'args':
|
|
2127
|
+
'args': basic_args,
|
|
1892
2128
|
'end': prev()
|
|
1893
2129
|
}), True)
|
|
1894
2130
|
S.in_parenthesized_expr = False
|
|
1895
2131
|
return ret
|
|
1896
2132
|
|
|
1897
|
-
def get_attr(expr, allow_calls):
|
|
2133
|
+
async def get_attr(expr, allow_calls):
|
|
1898
2134
|
next()
|
|
1899
2135
|
prop = as_name()
|
|
1900
2136
|
c = get_class_in_scope(expr)
|
|
@@ -1903,15 +2139,15 @@ def create_parser_ctx(S, import_dirs, module_id, baselib_items, imported_module_
|
|
|
1903
2139
|
if classvars and v'classvars[prop]':
|
|
1904
2140
|
prop = 'prototype.' + prop
|
|
1905
2141
|
|
|
1906
|
-
return subscripts(new AST_Dot({
|
|
2142
|
+
return await subscripts(new AST_Dot({
|
|
1907
2143
|
'start': expr.start,
|
|
1908
2144
|
'expression': expr,
|
|
1909
2145
|
'property': prop,
|
|
1910
2146
|
'end': prev()
|
|
1911
2147
|
}), allow_calls)
|
|
1912
2148
|
|
|
1913
|
-
def existential(expr, allow_calls):
|
|
1914
|
-
ans = new AST_Existential({'start':expr.start, 'end':S.token, 'expression':expr})
|
|
2149
|
+
async def existential(expr, allow_calls):
|
|
2150
|
+
ans = new AST_Existential({'start': expr.start, 'end': S.token, 'expression': expr})
|
|
1915
2151
|
next()
|
|
1916
2152
|
ttype = S.token.type
|
|
1917
2153
|
val = S.token.value
|
|
@@ -1931,49 +2167,49 @@ def create_parser_ctx(S, import_dirs, module_id, baselib_items, imported_module_
|
|
|
1931
2167
|
else:
|
|
1932
2168
|
ans.after = None
|
|
1933
2169
|
return ans
|
|
1934
|
-
return subscripts(ans, allow_calls)
|
|
2170
|
+
return await subscripts(ans, allow_calls)
|
|
1935
2171
|
|
|
1936
|
-
ans.after = expression()
|
|
2172
|
+
ans.after = await expression()
|
|
1937
2173
|
return ans
|
|
1938
2174
|
|
|
1939
|
-
def subscripts(expr, allow_calls):
|
|
1940
|
-
if is_(
|
|
1941
|
-
return get_attr(expr, allow_calls)
|
|
2175
|
+
async def subscripts(expr, allow_calls):
|
|
2176
|
+
if is_('punc', '.'):
|
|
2177
|
+
return await get_attr(expr, allow_calls)
|
|
1942
2178
|
|
|
1943
|
-
if is_(
|
|
1944
|
-
return getitem(expr, allow_calls)
|
|
2179
|
+
if is_('punc', '[') and not S.token.nlb:
|
|
2180
|
+
return await getitem(expr, allow_calls)
|
|
1945
2181
|
|
|
1946
|
-
if allow_calls and is_(
|
|
1947
|
-
return call_(expr)
|
|
2182
|
+
if allow_calls and is_('punc', '(') and not S.token.nlb:
|
|
2183
|
+
return await call_(expr)
|
|
1948
2184
|
|
|
1949
2185
|
if is_('punc', '?'):
|
|
1950
|
-
return existential(expr, allow_calls)
|
|
2186
|
+
return await existential(expr, allow_calls)
|
|
1951
2187
|
|
|
1952
2188
|
return expr
|
|
1953
2189
|
|
|
1954
|
-
def maybe_unary(allow_calls):
|
|
2190
|
+
async def maybe_unary(allow_calls):
|
|
1955
2191
|
start = S.token
|
|
1956
2192
|
if is_('operator', '@'):
|
|
1957
2193
|
if S.parsing_decorator:
|
|
1958
2194
|
croak('Nested decorators are not allowed')
|
|
1959
2195
|
next()
|
|
1960
2196
|
S.parsing_decorator = True
|
|
1961
|
-
expr = expression()
|
|
2197
|
+
expr = await expression()
|
|
1962
2198
|
S.parsing_decorator = False
|
|
1963
2199
|
S.decorators.push(expr)
|
|
1964
|
-
return new AST_EmptyStatement({'stype':'@', 'start':prev(), 'end':prev()})
|
|
1965
|
-
if is_(
|
|
2200
|
+
return new AST_EmptyStatement({'stype': '@', 'start': prev(), 'end': prev()})
|
|
2201
|
+
if is_('operator') and UNARY_PREFIX[start.value]:
|
|
1966
2202
|
next()
|
|
1967
2203
|
is_parenthesized = is_('punc', '(')
|
|
1968
2204
|
S.in_delete = start.value is 'delete'
|
|
1969
|
-
expr = maybe_unary(allow_calls)
|
|
2205
|
+
expr = await maybe_unary(allow_calls)
|
|
1970
2206
|
S.in_delete = False
|
|
1971
2207
|
ex = make_unary(AST_UnaryPrefix, start.value, expr, is_parenthesized)
|
|
1972
2208
|
ex.start = start
|
|
1973
2209
|
ex.end = prev()
|
|
1974
2210
|
return ex
|
|
1975
2211
|
|
|
1976
|
-
val = expr_atom(allow_calls)
|
|
2212
|
+
val = await expr_atom(allow_calls)
|
|
1977
2213
|
return val
|
|
1978
2214
|
|
|
1979
2215
|
def make_unary(ctor, op, expr, is_parenthesized):
|
|
@@ -1983,19 +2219,19 @@ def create_parser_ctx(S, import_dirs, module_id, baselib_items, imported_module_
|
|
|
1983
2219
|
'parenthesized': is_parenthesized
|
|
1984
2220
|
})
|
|
1985
2221
|
|
|
1986
|
-
def expr_op(left, min_prec, no_in):
|
|
2222
|
+
async def expr_op(left, min_prec, no_in):
|
|
1987
2223
|
op = S.token.value if is_('operator') else None
|
|
1988
|
-
if op is
|
|
2224
|
+
if op is '!' and peek().type is 'operator' and peek().value is 'in':
|
|
1989
2225
|
next()
|
|
1990
2226
|
S.token.value = op = 'nin'
|
|
1991
2227
|
|
|
1992
|
-
if no_in and (op is
|
|
2228
|
+
if no_in and (op is 'in' or op is 'nin'):
|
|
1993
2229
|
op = None
|
|
1994
2230
|
|
|
1995
2231
|
prec = PRECEDENCE[op] if op is not None else None
|
|
1996
2232
|
if prec is not None and prec > min_prec:
|
|
1997
2233
|
next()
|
|
1998
|
-
right = expr_op(maybe_unary(True), prec, no_in)
|
|
2234
|
+
right = await expr_op(await maybe_unary(True), prec, no_in)
|
|
1999
2235
|
ret = new AST_Binary({
|
|
2000
2236
|
'start': left.start,
|
|
2001
2237
|
'left': left,
|
|
@@ -2003,24 +2239,25 @@ def create_parser_ctx(S, import_dirs, module_id, baselib_items, imported_module_
|
|
|
2003
2239
|
'right': right,
|
|
2004
2240
|
'end': right.end
|
|
2005
2241
|
})
|
|
2006
|
-
return expr_op(ret, min_prec, no_in)
|
|
2242
|
+
return await expr_op(ret, min_prec, no_in)
|
|
2007
2243
|
return left
|
|
2008
2244
|
|
|
2009
|
-
def expr_ops(no_in):
|
|
2010
|
-
return expr_op(maybe_unary(True), 0, no_in)
|
|
2245
|
+
async def expr_ops(no_in):
|
|
2246
|
+
return await expr_op(await maybe_unary(True), 0, no_in)
|
|
2011
2247
|
|
|
2012
|
-
def maybe_conditional(no_in):
|
|
2248
|
+
async def maybe_conditional(no_in):
|
|
2013
2249
|
start = S.token
|
|
2014
|
-
expr = expr_ops(no_in)
|
|
2250
|
+
expr = await expr_ops(no_in)
|
|
2015
2251
|
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
2252
|
next()
|
|
2017
|
-
ne = expression(False)
|
|
2253
|
+
ne = await expression(False)
|
|
2018
2254
|
expect_token('keyword', 'else')
|
|
2255
|
+
cond_alt = await expression(False, no_in)
|
|
2019
2256
|
conditional = new AST_Conditional({
|
|
2020
2257
|
'start': start,
|
|
2021
2258
|
'condition': ne,
|
|
2022
2259
|
'consequent': expr,
|
|
2023
|
-
'alternative':
|
|
2260
|
+
'alternative': cond_alt,
|
|
2024
2261
|
'end': peek()
|
|
2025
2262
|
})
|
|
2026
2263
|
return conditional
|
|
@@ -2044,28 +2281,30 @@ def create_parser_ctx(S, import_dirs, module_id, baselib_items, imported_module_
|
|
|
2044
2281
|
c.provisional_classvars[ans.left.name] = True
|
|
2045
2282
|
return ans
|
|
2046
2283
|
|
|
2047
|
-
def maybe_assign(no_in, only_plain_assignment):
|
|
2284
|
+
async def maybe_assign(no_in, only_plain_assignment):
|
|
2048
2285
|
start = S.token
|
|
2049
|
-
left = maybe_conditional(no_in)
|
|
2286
|
+
left = await maybe_conditional(no_in)
|
|
2050
2287
|
val = S.token.value
|
|
2051
|
-
if is_(
|
|
2288
|
+
if is_('operator') and ASSIGNMENT[val]:
|
|
2052
2289
|
if only_plain_assignment and val is not '=':
|
|
2053
2290
|
croak('Invalid assignment operator for chained assignment: ' + val)
|
|
2054
2291
|
next()
|
|
2292
|
+
assign_right = await maybe_assign(no_in, True)
|
|
2055
2293
|
return create_assign({
|
|
2056
2294
|
'start': start,
|
|
2057
2295
|
'left': left,
|
|
2058
2296
|
'operator': val,
|
|
2059
|
-
'right':
|
|
2297
|
+
'right': assign_right,
|
|
2060
2298
|
'end': prev()
|
|
2061
2299
|
})
|
|
2062
2300
|
return left
|
|
2063
2301
|
|
|
2064
|
-
def expression(commas, no_in):
|
|
2302
|
+
async def expression(commas, no_in):
|
|
2065
2303
|
# if there is an assignment, we want the sequences to pivot
|
|
2066
2304
|
# around it to allow for tuple packing/unpacking
|
|
2067
2305
|
start = S.token
|
|
2068
|
-
expr = maybe_assign(no_in)
|
|
2306
|
+
expr = await maybe_assign(no_in)
|
|
2307
|
+
|
|
2069
2308
|
def build_seq(a):
|
|
2070
2309
|
if a.length is 1:
|
|
2071
2310
|
return a[0]
|
|
@@ -2078,10 +2317,11 @@ def create_parser_ctx(S, import_dirs, module_id, baselib_items, imported_module_
|
|
|
2078
2317
|
})
|
|
2079
2318
|
if commas:
|
|
2080
2319
|
left = v'[ expr ]'
|
|
2081
|
-
while is_(
|
|
2320
|
+
while is_('punc', ',') and (not peek().nlb or S.in_parenthesized_expr):
|
|
2082
2321
|
next()
|
|
2083
2322
|
if is_node_type(expr, AST_Assign):
|
|
2084
2323
|
left[-1] = left[-1].left
|
|
2324
|
+
seq_cdr = await expression(True, no_in)
|
|
2085
2325
|
return create_assign({
|
|
2086
2326
|
'start': start,
|
|
2087
2327
|
'left': (left[0] if left.length is 1 else new AST_Array({
|
|
@@ -2090,12 +2330,12 @@ def create_parser_ctx(S, import_dirs, module_id, baselib_items, imported_module_
|
|
|
2090
2330
|
'operator': expr.operator,
|
|
2091
2331
|
'right': new AST_Seq({
|
|
2092
2332
|
'car': expr.right,
|
|
2093
|
-
'cdr':
|
|
2333
|
+
'cdr': seq_cdr
|
|
2094
2334
|
}),
|
|
2095
2335
|
'end': peek()
|
|
2096
2336
|
})
|
|
2097
2337
|
|
|
2098
|
-
expr = maybe_assign(no_in)
|
|
2338
|
+
expr = await maybe_assign(no_in)
|
|
2099
2339
|
left.push(expr)
|
|
2100
2340
|
|
|
2101
2341
|
# if last one was an assignment, fix it
|
|
@@ -2114,20 +2354,30 @@ def create_parser_ctx(S, import_dirs, module_id, baselib_items, imported_module_
|
|
|
2114
2354
|
return build_seq(left)
|
|
2115
2355
|
return expr
|
|
2116
2356
|
|
|
2117
|
-
def in_loop(cont):
|
|
2357
|
+
async def in_loop(cont):
|
|
2118
2358
|
S.in_loop += 1
|
|
2119
|
-
ret = cont()
|
|
2359
|
+
ret = await cont()
|
|
2120
2360
|
S.in_loop -= 1
|
|
2121
2361
|
return ret
|
|
2122
2362
|
|
|
2123
|
-
def run_parser():
|
|
2363
|
+
async def run_parser():
|
|
2124
2364
|
start = S.token = next()
|
|
2125
2365
|
body = v'[]'
|
|
2126
2366
|
docstrings = v'[]'
|
|
2127
2367
|
first_token = True
|
|
2128
2368
|
toplevel = options.toplevel
|
|
2129
|
-
while not is_(
|
|
2130
|
-
|
|
2369
|
+
while not is_('eof'):
|
|
2370
|
+
if options.recover_errors:
|
|
2371
|
+
try:
|
|
2372
|
+
element = await statement()
|
|
2373
|
+
except as rerr:
|
|
2374
|
+
if is_recoverable_error(rerr):
|
|
2375
|
+
record_recovery(rerr)
|
|
2376
|
+
await skip_to_recovery_point()
|
|
2377
|
+
continue
|
|
2378
|
+
raise
|
|
2379
|
+
else:
|
|
2380
|
+
element = await statement()
|
|
2131
2381
|
if first_token and is_node_type(element, AST_Directive) and element.value.indexOf('#!') is 0:
|
|
2132
2382
|
shebang = element.value
|
|
2133
2383
|
else:
|
|
@@ -2152,6 +2402,18 @@ def create_parser_ctx(S, import_dirs, module_id, baselib_items, imported_module_
|
|
|
2152
2402
|
'docstrings': docstrings,
|
|
2153
2403
|
})
|
|
2154
2404
|
|
|
2405
|
+
if options.recover_errors:
|
|
2406
|
+
# Combine parser-level recovered errors with any collected by the
|
|
2407
|
+
# tokenizer (e.g. skipped unexpected characters) for the LSP to report.
|
|
2408
|
+
recovered = S.recovered_errors
|
|
2409
|
+
try:
|
|
2410
|
+
tok_ctx = S.input.context()
|
|
2411
|
+
if tok_ctx and tok_ctx.recovered_errors and tok_ctx.recovered_errors.length:
|
|
2412
|
+
recovered = recovered.concat(tok_ctx.recovered_errors)
|
|
2413
|
+
except:
|
|
2414
|
+
pass
|
|
2415
|
+
toplevel.recovered_errors = recovered
|
|
2416
|
+
|
|
2155
2417
|
toplevel.nonlocalvars = scan_for_nonlocal_defs(toplevel.body).concat(S.globals)
|
|
2156
2418
|
toplevel.localvars = []
|
|
2157
2419
|
toplevel.exports = []
|
|
@@ -2182,21 +2444,102 @@ def create_parser_ctx(S, import_dirs, module_id, baselib_items, imported_module_
|
|
|
2182
2444
|
toplevel.scoped_flags = S.scoped_flags.stack[0]
|
|
2183
2445
|
importing_modules[module_id] = False
|
|
2184
2446
|
toplevel.comments_after = S.token.comments_before or v'[]'
|
|
2447
|
+
|
|
2448
|
+
if options._src_hash and options.filename and module_id is not '__main__':
|
|
2449
|
+
try:
|
|
2450
|
+
# Simplified class info (no full AST nodes) for lazy-shell reconstruction.
|
|
2451
|
+
classes_cache = {}
|
|
2452
|
+
for cname in Object.keys(toplevel.classes or {}):
|
|
2453
|
+
cls = toplevel.classes[cname]
|
|
2454
|
+
classes_cache[cname] = {'static': cls.static or {}, 'bound': cls.bound or [], 'classvars': cls.classvars or {}}
|
|
2455
|
+
# Single pass: compute has_side_effects + tree-shaking index.
|
|
2456
|
+
# The index lets the tree-shaker resolve the fixpoint iteration
|
|
2457
|
+
# (steps 4-5) without accessing mod.body — no AST deserialization
|
|
2458
|
+
# until step 6 (pruning), which needs actual nodes anyway.
|
|
2459
|
+
has_se = False
|
|
2460
|
+
idx_exec_refs_set = {}
|
|
2461
|
+
idx_import_bindings = {}
|
|
2462
|
+
idx_top_defs = {}
|
|
2463
|
+
|
|
2464
|
+
def _collect_refs_into(node, refs_set): # noqa
|
|
2465
|
+
def _rv(n): # noqa
|
|
2466
|
+
if is_node_type(n, AST_SymbolRef):
|
|
2467
|
+
refs_set[n.name] = True
|
|
2468
|
+
node.walk(new TreeWalker(_rv))
|
|
2469
|
+
|
|
2470
|
+
for idx_stmt in toplevel.body:
|
|
2471
|
+
if is_node_type(idx_stmt, AST_Function) or is_node_type(idx_stmt, AST_Class):
|
|
2472
|
+
if idx_stmt.name:
|
|
2473
|
+
idx_pinned = False
|
|
2474
|
+
if idx_stmt.decorators:
|
|
2475
|
+
for idx_dec in idx_stmt.decorators:
|
|
2476
|
+
if idx_dec.expression and is_node_type(idx_dec.expression, AST_SymbolRef) and idx_dec.expression.name == 'no_prune':
|
|
2477
|
+
idx_pinned = True
|
|
2478
|
+
break
|
|
2479
|
+
idx_def_refs = {}
|
|
2480
|
+
_collect_refs_into(idx_stmt, idx_def_refs)
|
|
2481
|
+
idx_top_defs[idx_stmt.name.name] = {'pinned': idx_pinned, 'refs': Object.keys(idx_def_refs)}
|
|
2482
|
+
elif is_node_type(idx_stmt, AST_Imports):
|
|
2483
|
+
for idx_imp in idx_stmt.imports:
|
|
2484
|
+
if idx_imp.argnames and idx_imp.argnames.length:
|
|
2485
|
+
for idx_arg in idx_imp.argnames:
|
|
2486
|
+
idx_local = idx_arg.alias.name if idx_arg.alias else idx_arg.name
|
|
2487
|
+
idx_import_bindings[idx_local] = {'source': idx_imp.key, 'imported_name': idx_arg.name, 'is_namespace': False}
|
|
2488
|
+
else:
|
|
2489
|
+
idx_local = idx_imp.alias.name if idx_imp.alias else idx_imp.key.split('.')[0]
|
|
2490
|
+
idx_import_bindings[idx_local] = {'source': idx_imp.key, 'imported_name': None, 'is_namespace': True}
|
|
2491
|
+
else:
|
|
2492
|
+
if not has_se:
|
|
2493
|
+
se_found = v'[false]'
|
|
2494
|
+
|
|
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
|
-
|
|
2530
|
+
|
|
2531
|
+
async def parse(text, options):
|
|
2190
2532
|
options = defaults(options, {
|
|
2191
|
-
'filename': None,
|
|
2192
|
-
'module_id':'__main__',
|
|
2533
|
+
'filename': None, # name of the file being parsed
|
|
2534
|
+
'module_id': '__main__', # The id of the module being parsed
|
|
2193
2535
|
'toplevel': None,
|
|
2194
|
-
'for_linting': False,
|
|
2536
|
+
'for_linting': False, # If True certain actions are not performed, such as importing modules
|
|
2195
2537
|
'import_dirs': v'[]',
|
|
2196
|
-
'classes': undefined,
|
|
2197
|
-
'scoped_flags': {},
|
|
2538
|
+
'classes': undefined, # Map of class names to AST_Class that are available in the global namespace (used by the REPL)
|
|
2539
|
+
'scoped_flags': {}, # Global scoped flags (used by the REPL)
|
|
2198
2540
|
'discard_asserts': False,
|
|
2199
2541
|
'module_cache_dir': '',
|
|
2542
|
+
'recover_errors': False, # When True, continue parsing past syntax errors (used by the LSP). See run_parser/block_.
|
|
2200
2543
|
})
|
|
2201
2544
|
import_dirs = [x for x in options.import_dirs]
|
|
2202
2545
|
for location in v'[options.libdir, options.basedir]':
|
|
@@ -2207,11 +2550,16 @@ def parse(text, options):
|
|
|
2207
2550
|
imported_module_ids = []
|
|
2208
2551
|
imported_modules = options.imported_modules or {}
|
|
2209
2552
|
importing_modules = options.importing_modules or {}
|
|
2553
|
+
# loading_promises tracks modules currently being loaded across the entire compilation.
|
|
2554
|
+
# It is shared by passing it through options so parallel sub-parse() calls all see it.
|
|
2555
|
+
if not options.loading_promises:
|
|
2556
|
+
options.loading_promises = {}
|
|
2210
2557
|
importing_modules[module_id] = True
|
|
2211
2558
|
|
|
2212
2559
|
# The internal state of the parser
|
|
2213
2560
|
S = {
|
|
2214
|
-
'input': tokenizer(text, options.filename) if jstype(text) is 'string' else text,
|
|
2561
|
+
'input': tokenizer(text, options.filename, options.recover_errors) if jstype(text) is 'string' else text,
|
|
2562
|
+
'recovered_errors': v'[]', # syntax errors swallowed during recovery (recover_errors mode only)
|
|
2215
2563
|
'token': None,
|
|
2216
2564
|
'prev': None,
|
|
2217
2565
|
'peeked': [],
|
|
@@ -2221,9 +2569,9 @@ def parse(text, options):
|
|
|
2221
2569
|
'in_parenthesized_expr': False,
|
|
2222
2570
|
'in_delete': False,
|
|
2223
2571
|
'in_loop': 0,
|
|
2224
|
-
'in_class': [
|
|
2225
|
-
'classes': [
|
|
2226
|
-
'functions': [
|
|
2572
|
+
'in_class': [False],
|
|
2573
|
+
'classes': [{}],
|
|
2574
|
+
'functions': [{}],
|
|
2227
2575
|
'labels': [],
|
|
2228
2576
|
'decorators': v'[]',
|
|
2229
2577
|
'parsing_decorator': False,
|
|
@@ -2247,6 +2595,9 @@ def parse(text, options):
|
|
|
2247
2595
|
if options.classes:
|
|
2248
2596
|
for cname in options.classes:
|
|
2249
2597
|
obj = options.classes[cname]
|
|
2250
|
-
S.classes[0][cname] = {
|
|
2598
|
+
S.classes[0][cname] = {'static': obj.static, 'bound': obj.bound, 'classvars': obj.classvars}
|
|
2599
|
+
|
|
2600
|
+
if jstype(text) is 'string' and not options._src_hash:
|
|
2601
|
+
options._src_hash = sha1sum(text)
|
|
2251
2602
|
|
|
2252
|
-
return create_parser_ctx(S, import_dirs, module_id, baselib_items, imported_module_ids, imported_modules, importing_modules, options)()
|
|
2603
|
+
return await create_parser_ctx(S, import_dirs, module_id, baselib_items, imported_module_ids, imported_modules, importing_modules, options)()
|