rapydscript-ns 0.8.3 → 0.8.4
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/.agignore +1 -1
- package/.github/workflows/ci.yml +38 -38
- package/=template.pyj +5 -5
- package/CHANGELOG.md +8 -0
- package/HACKING.md +103 -103
- package/LICENSE +24 -24
- package/PYTHON_DIFFERENCES_REPORT.md +2 -2
- package/PYTHON_FEATURE_COVERAGE.md +13 -13
- package/README.md +670 -6
- package/TODO.md +5 -6
- package/add-toc-to-readme +2 -2
- package/bin/export +75 -75
- package/bin/rapydscript +70 -70
- package/bin/web-repl-export +102 -102
- package/build +2 -2
- package/language-service/index.js +155 -6
- package/package.json +1 -1
- package/publish.py +37 -37
- package/release/baselib-plain-pretty.js +2006 -229
- package/release/baselib-plain-ugly.js +70 -3
- package/release/compiler.js +11554 -3870
- package/release/signatures.json +31 -29
- package/session.vim +4 -4
- package/setup.cfg +2 -2
- package/src/ast.pyj +93 -1
- package/src/baselib-builtins.pyj +22 -1
- package/src/baselib-containers.pyj +99 -0
- package/src/baselib-errors.pyj +44 -0
- package/src/baselib-internal.pyj +94 -4
- package/src/baselib-itertools.pyj +97 -97
- package/src/baselib-str.pyj +24 -0
- package/src/compiler.pyj +36 -36
- package/src/errors.pyj +30 -30
- package/src/lib/aes.pyj +646 -646
- package/src/lib/copy.pyj +120 -0
- package/src/lib/elementmaker.pyj +83 -83
- package/src/lib/encodings.pyj +126 -126
- package/src/lib/gettext.pyj +569 -569
- package/src/lib/itertools.pyj +580 -580
- package/src/lib/math.pyj +193 -193
- package/src/lib/operator.pyj +11 -11
- package/src/lib/pythonize.pyj +20 -20
- package/src/lib/random.pyj +118 -118
- package/src/lib/re.pyj +470 -470
- package/src/lib/react.pyj +74 -0
- package/src/lib/traceback.pyj +63 -63
- package/src/lib/uuid.pyj +77 -77
- package/src/monaco-language-service/builtins.js +5 -0
- package/src/monaco-language-service/diagnostics.js +25 -3
- package/src/monaco-language-service/dts.js +550 -550
- package/src/output/classes.pyj +108 -8
- package/src/output/codegen.pyj +16 -2
- package/src/output/comments.pyj +45 -45
- package/src/output/exceptions.pyj +201 -105
- package/src/output/functions.pyj +9 -0
- package/src/output/jsx.pyj +164 -0
- package/src/output/literals.pyj +28 -2
- package/src/output/modules.pyj +1 -1
- package/src/output/operators.pyj +8 -2
- package/src/output/statements.pyj +2 -2
- package/src/output/stream.pyj +1 -0
- package/src/output/treeshake.pyj +182 -182
- package/src/output/utils.pyj +72 -72
- package/src/parse.pyj +417 -113
- package/src/string_interpolation.pyj +72 -72
- package/src/tokenizer.pyj +29 -0
- package/src/unicode_aliases.pyj +576 -576
- package/src/utils.pyj +192 -192
- package/test/_import_one.pyj +37 -37
- package/test/_import_two/__init__.pyj +11 -11
- package/test/_import_two/level2/deep.pyj +4 -4
- package/test/_import_two/other.pyj +6 -6
- package/test/_import_two/sub.pyj +13 -13
- package/test/aes_vectors.pyj +421 -421
- package/test/annotations.pyj +80 -80
- package/test/decorators.pyj +77 -77
- package/test/docstrings.pyj +39 -39
- package/test/elementmaker_test.pyj +45 -45
- package/test/functions.pyj +151 -151
- package/test/generators.pyj +41 -41
- package/test/generic.pyj +370 -370
- package/test/imports.pyj +72 -72
- package/test/internationalization.pyj +73 -73
- package/test/lint.pyj +164 -164
- package/test/loops.pyj +85 -85
- package/test/numpy.pyj +734 -734
- package/test/omit_function_metadata.pyj +20 -20
- package/test/python_features.pyj +19 -6
- package/test/regexp.pyj +55 -55
- package/test/repl.pyj +121 -121
- package/test/scoped_flags.pyj +76 -76
- package/test/unit/index.js +2177 -64
- package/test/unit/language-service-dts.js +543 -543
- package/test/unit/language-service-hover.js +455 -455
- package/test/unit/language-service.js +590 -4
- package/test/unit/web-repl.js +303 -0
- package/tools/cli.js +547 -547
- package/tools/compile.js +219 -219
- package/tools/completer.js +131 -131
- package/tools/embedded_compiler.js +251 -251
- package/tools/gettext.js +185 -185
- package/tools/ini.js +65 -65
- package/tools/msgfmt.js +187 -187
- package/tools/repl.js +223 -223
- package/tools/test.js +118 -118
- package/tools/utils.js +128 -128
- package/tools/web_repl.js +95 -95
- package/try +41 -41
- package/web-repl/env.js +196 -74
- package/web-repl/index.html +163 -163
- package/web-repl/main.js +252 -254
- package/web-repl/prism.css +139 -139
- package/web-repl/prism.js +113 -113
- package/web-repl/rapydscript.js +224 -102
- package/web-repl/sha1.js +25 -25
- package/hack_demo.pyj +0 -112
package/src/parse.pyj
CHANGED
|
@@ -21,16 +21,17 @@ AST_SymbolCatch, AST_SymbolDefun, AST_SymbolFunarg,
|
|
|
21
21
|
AST_SymbolLambda, AST_SymbolNonlocal, AST_SymbolRef, AST_SymbolVar, AST_This,
|
|
22
22
|
AST_Throw, AST_Toplevel, AST_True, AST_Try, AST_UnaryPrefix,
|
|
23
23
|
AST_Undefined, AST_Var, AST_VarDef, AST_Verbatim, AST_While, AST_With, AST_WithClause,
|
|
24
|
-
AST_Yield, AST_Await, AST_Assert, AST_Existential, AST_NamedExpr, AST_AnnotatedAssign, AST_Super, AST_Starred, is_node_type,
|
|
24
|
+
AST_Yield, AST_Await, AST_Assert, AST_Existential, AST_NamedExpr, AST_AnnotatedAssign, AST_Super, AST_Starred, AST_Spread, is_node_type,
|
|
25
25
|
AST_Match, AST_MatchCase,
|
|
26
26
|
AST_MatchWildcard, AST_MatchCapture, AST_MatchLiteral, AST_MatchOr,
|
|
27
27
|
AST_MatchAs, AST_MatchStar, AST_MatchSequence, AST_MatchMapping, AST_MatchClass,
|
|
28
|
+
AST_JSXElement, AST_JSXFragment, AST_JSXAttribute, AST_JSXSpread, AST_JSXText, AST_JSXExprContainer,
|
|
28
29
|
TreeWalker
|
|
29
30
|
)
|
|
30
31
|
from tokenizer import tokenizer, is_token, RESERVED_WORDS
|
|
31
32
|
|
|
32
33
|
COMPILER_VERSION = '__COMPILER_VERSION__'
|
|
33
|
-
PYTHON_FLAGS = {'dict_literals':True, 'overload_getitem':True, 'bound_methods':True, 'hash_literals':True, 'overload_operators':True, 'truthiness':True}
|
|
34
|
+
PYTHON_FLAGS = {'dict_literals':True, 'overload_getitem':True, 'bound_methods':True, 'hash_literals':True, 'overload_operators':True, 'truthiness':True, 'jsx':True}
|
|
34
35
|
|
|
35
36
|
|
|
36
37
|
def get_compiler_version():
|
|
@@ -1414,6 +1415,7 @@ def create_parser_ctx(S, import_dirs, module_id, baselib_items, imported_module_
|
|
|
1414
1415
|
'provisional_classvars': {},
|
|
1415
1416
|
}
|
|
1416
1417
|
bases = v'[]'
|
|
1418
|
+
class_kwargs = v'[]'
|
|
1417
1419
|
class_parent = None
|
|
1418
1420
|
|
|
1419
1421
|
# If this class is nested inside another class, register it under its
|
|
@@ -1437,10 +1439,14 @@ def create_parser_ctx(S, import_dirs, module_id, baselib_items, imported_module_
|
|
|
1437
1439
|
S.in_parenthesized_expr = False
|
|
1438
1440
|
next()
|
|
1439
1441
|
break
|
|
1440
|
-
a =
|
|
1441
|
-
if
|
|
1442
|
-
|
|
1443
|
-
|
|
1442
|
+
a = expression(False)
|
|
1443
|
+
if is_node_type(a, AST_Assign):
|
|
1444
|
+
# key=value → class keyword argument for __init_subclass__
|
|
1445
|
+
class_kwargs.push([a.left, a.right])
|
|
1446
|
+
else:
|
|
1447
|
+
if class_parent is None:
|
|
1448
|
+
class_parent = a
|
|
1449
|
+
bases.push(a)
|
|
1444
1450
|
if is_('punc', ','):
|
|
1445
1451
|
next()
|
|
1446
1452
|
continue
|
|
@@ -1455,6 +1461,7 @@ def create_parser_ctx(S, import_dirs, module_id, baselib_items, imported_module_
|
|
|
1455
1461
|
'dynamic_properties': Object.create(None),
|
|
1456
1462
|
'parent': class_parent,
|
|
1457
1463
|
'bases': bases,
|
|
1464
|
+
'class_kwargs': class_kwargs,
|
|
1458
1465
|
'localvars': [],
|
|
1459
1466
|
'classvars': class_details.classvars,
|
|
1460
1467
|
'static': class_details.static,
|
|
@@ -1501,6 +1508,26 @@ def create_parser_ctx(S, import_dirs, module_id, baselib_items, imported_module_
|
|
|
1501
1508
|
descriptor['getter' if stmt.is_getter else 'setter'] = stmt
|
|
1502
1509
|
elif stmt.name.name is "__init__":
|
|
1503
1510
|
definition.init = stmt
|
|
1511
|
+
elif stmt.name.name is "__new__":
|
|
1512
|
+
definition.has_new = True
|
|
1513
|
+
class_details.has_new = True
|
|
1514
|
+
class_details.static['__new__'] = True
|
|
1515
|
+
stmt.static = True # suppress var cls = this in display_complex_body
|
|
1516
|
+
elif stmt.name.name is "__class_getitem__":
|
|
1517
|
+
stmt.is_classmethod = True
|
|
1518
|
+
class_details.classmethod['__class_getitem__'] = True
|
|
1519
|
+
elif stmt.name.name is "__init_subclass__":
|
|
1520
|
+
stmt.is_classmethod = True
|
|
1521
|
+
class_details.classmethod['__init_subclass__'] = True
|
|
1522
|
+
elif stmt.name.name in ['__getattr__', '__setattr__', '__delattr__', '__getattribute__']:
|
|
1523
|
+
definition.has_attr_dunders = True
|
|
1524
|
+
class_details.has_attr_dunders = True
|
|
1525
|
+
# Propagate has_attr_dunders from parent classes so subclasses are also Proxy-wrapped.
|
|
1526
|
+
if not definition.has_attr_dunders and definition.parent:
|
|
1527
|
+
parent_details = get_class_in_scope(definition.parent)
|
|
1528
|
+
if parent_details and parent_details.has_attr_dunders:
|
|
1529
|
+
definition.has_attr_dunders = True
|
|
1530
|
+
class_details.has_attr_dunders = True
|
|
1504
1531
|
# find the class variables
|
|
1505
1532
|
class_var_names = {}
|
|
1506
1533
|
# Ensure that if a class variable refers to another class variable in
|
|
@@ -1730,7 +1757,7 @@ def create_parser_ctx(S, import_dirs, module_id, baselib_items, imported_module_
|
|
|
1730
1757
|
S.in_parenthesized_expr = False
|
|
1731
1758
|
a.defaults = defaults
|
|
1732
1759
|
a.is_simple_func = not a.starargs and not a.kwargs and not a.has_defaults and not a.bare_star and not a.posonly_count
|
|
1733
|
-
if classmethod_flag and a.length > 0:
|
|
1760
|
+
if (classmethod_flag or (name and (name.name is '__new__' or name.name is '__class_getitem__' or name.name is '__init_subclass__'))) and a.length > 0:
|
|
1734
1761
|
cm_cls_arg.push(a[0].name)
|
|
1735
1762
|
return a
|
|
1736
1763
|
)(v'[]'),
|
|
@@ -1748,7 +1775,7 @@ def create_parser_ctx(S, import_dirs, module_id, baselib_items, imported_module_
|
|
|
1748
1775
|
'body': (def(loop, labels):
|
|
1749
1776
|
S.in_class.push(False)
|
|
1750
1777
|
cm_pushed = v'[false]'
|
|
1751
|
-
if classmethod_flag and in_class and cm_cls_arg.length > 0:
|
|
1778
|
+
if (classmethod_flag or (name and (name.name is '__new__' or name.name is '__class_getitem__' or name.name is '__init_subclass__'))) and in_class and cm_cls_arg.length > 0:
|
|
1752
1779
|
cm_ctx_entry = None
|
|
1753
1780
|
for v'var si = S.classes.length - 1; si >= 0; si--':
|
|
1754
1781
|
if has_prop(S.classes[si], in_class):
|
|
@@ -1978,9 +2005,18 @@ def create_parser_ctx(S, import_dirs, module_id, baselib_items, imported_module_
|
|
|
1978
2005
|
bcatch = v'[]'
|
|
1979
2006
|
bfinally = None
|
|
1980
2007
|
belse = None
|
|
2008
|
+
has_star = None # None = not yet seen, True/False = seen star/non-star
|
|
1981
2009
|
while is_("keyword", "except"):
|
|
1982
2010
|
start = S.token
|
|
1983
2011
|
next()
|
|
2012
|
+
is_star = False
|
|
2013
|
+
if is_("operator", "*"):
|
|
2014
|
+
is_star = True
|
|
2015
|
+
next()
|
|
2016
|
+
if has_star is None:
|
|
2017
|
+
has_star = is_star
|
|
2018
|
+
elif has_star is not is_star:
|
|
2019
|
+
croak("Cannot mix 'except' and 'except*' in the same try statement")
|
|
1984
2020
|
exceptions = []
|
|
1985
2021
|
if not is_("punc", ":") and not is_("keyword", "as"):
|
|
1986
2022
|
# Accept both: except TypeError, ValueError:
|
|
@@ -2006,6 +2042,7 @@ def create_parser_ctx(S, import_dirs, module_id, baselib_items, imported_module_
|
|
|
2006
2042
|
'start': start,
|
|
2007
2043
|
'argname': name,
|
|
2008
2044
|
'errors': exceptions,
|
|
2045
|
+
'is_star': is_star,
|
|
2009
2046
|
'body': block_(),
|
|
2010
2047
|
'end': prev()
|
|
2011
2048
|
}))
|
|
@@ -2248,6 +2285,13 @@ def create_parser_ctx(S, import_dirs, module_id, baselib_items, imported_module_
|
|
|
2248
2285
|
if is_("operator", "*") and func_call:
|
|
2249
2286
|
saw_starargs = True
|
|
2250
2287
|
next()
|
|
2288
|
+
elif is_("operator", "*") and not func_call:
|
|
2289
|
+
# Spread element in list literal: [1, *a, 2]
|
|
2290
|
+
start = S.token
|
|
2291
|
+
next()
|
|
2292
|
+
spread_expr = expression(False)
|
|
2293
|
+
a.push(new AST_Spread({'start': start, 'expression': spread_expr, 'end': prev()}))
|
|
2294
|
+
continue
|
|
2251
2295
|
|
|
2252
2296
|
if is_("punc", ",") and allow_empty:
|
|
2253
2297
|
a.push(new AST_Hole({
|
|
@@ -2294,7 +2338,7 @@ def create_parser_ctx(S, import_dirs, module_id, baselib_items, imported_module_
|
|
|
2294
2338
|
a.starargs = True
|
|
2295
2339
|
elif is_('operator', '**'):
|
|
2296
2340
|
next()
|
|
2297
|
-
a.kwarg_items.push(
|
|
2341
|
+
a.kwarg_items.push(expression(False))
|
|
2298
2342
|
a.starargs = True
|
|
2299
2343
|
else:
|
|
2300
2344
|
arg = expression(False)
|
|
@@ -2318,10 +2362,17 @@ def create_parser_ctx(S, import_dirs, module_id, baselib_items, imported_module_
|
|
|
2318
2362
|
expect("[")
|
|
2319
2363
|
expr = []
|
|
2320
2364
|
if not is_("punc", "]"):
|
|
2321
|
-
|
|
2322
|
-
|
|
2323
|
-
|
|
2324
|
-
|
|
2365
|
+
if is_("operator", "*"):
|
|
2366
|
+
# Spread as first element — no list comprehension possible
|
|
2367
|
+
start = S.token
|
|
2368
|
+
next()
|
|
2369
|
+
spread_expr = expression(False)
|
|
2370
|
+
expr.push(new AST_Spread({'start': start, 'expression': spread_expr, 'end': prev()}))
|
|
2371
|
+
else:
|
|
2372
|
+
expr.push(expression(False))
|
|
2373
|
+
if is_("keyword", "for"):
|
|
2374
|
+
# list comprehension
|
|
2375
|
+
return read_comprehension(new AST_ListComprehension({'statement': expr[0]}), ']')
|
|
2325
2376
|
|
|
2326
2377
|
if not is_("punc", "]"):
|
|
2327
2378
|
expect(",")
|
|
@@ -2356,6 +2407,12 @@ def create_parser_ctx(S, import_dirs, module_id, baselib_items, imported_module_
|
|
|
2356
2407
|
}))
|
|
2357
2408
|
has_non_const_keys = True
|
|
2358
2409
|
continue
|
|
2410
|
+
if is_('operator', '*'):
|
|
2411
|
+
# Must be a set literal with spread as first item: {*a, ...}
|
|
2412
|
+
next()
|
|
2413
|
+
spread_expr = expression(False)
|
|
2414
|
+
spread_node = new AST_Spread({'start': start, 'expression': spread_expr, 'end': prev()})
|
|
2415
|
+
return _read_set_items([spread_node], start)
|
|
2359
2416
|
ctx = S.input.context()
|
|
2360
2417
|
orig = ctx.expecting_object_literal_key
|
|
2361
2418
|
ctx.expecting_object_literal_key = True
|
|
@@ -2388,18 +2445,25 @@ def create_parser_ctx(S, import_dirs, module_id, baselib_items, imported_module_
|
|
|
2388
2445
|
'is_jshash': is_jshash,
|
|
2389
2446
|
})
|
|
2390
2447
|
|
|
2391
|
-
def
|
|
2392
|
-
|
|
2393
|
-
a = [new AST_SetItem({'start':start, 'end':end, 'value':expr})]
|
|
2448
|
+
def _read_set_items(a, ostart):
|
|
2449
|
+
"Read remaining items of a set literal into a (handles * spread)"
|
|
2394
2450
|
while not is_("punc", "}"):
|
|
2395
2451
|
expect(",")
|
|
2396
|
-
|
|
2452
|
+
item_start = S.token
|
|
2397
2453
|
if is_("punc", "}"):
|
|
2398
2454
|
# allow trailing comma
|
|
2399
2455
|
break
|
|
2400
|
-
|
|
2456
|
+
if is_("operator", "*"):
|
|
2457
|
+
next()
|
|
2458
|
+
spread_expr = expression(False)
|
|
2459
|
+
a.push(new AST_Spread({'start': item_start, 'expression': spread_expr, 'end': prev()}))
|
|
2460
|
+
else:
|
|
2461
|
+
a.push(new AST_SetItem({'start': item_start, 'value': expression(False), 'end': prev()}))
|
|
2401
2462
|
next()
|
|
2402
|
-
return new AST_Set({'items':a, 'start':ostart, 'end':prev()})
|
|
2463
|
+
return new AST_Set({'items': a, 'start': ostart, 'end': prev()})
|
|
2464
|
+
|
|
2465
|
+
def set_(start, end, expr):
|
|
2466
|
+
return _read_set_items([new AST_SetItem({'start':start, 'end':end, 'value':expr})], start)
|
|
2403
2467
|
|
|
2404
2468
|
def _read_comp_conditions():
|
|
2405
2469
|
# Read zero or more consecutive `if` conditions, combining them with &&.
|
|
@@ -2602,6 +2666,20 @@ def create_parser_ctx(S, import_dirs, module_id, baselib_items, imported_module_
|
|
|
2602
2666
|
multi_arr = new AST_Array({'start': start, 'elements': multi_items, 'end': prev()})
|
|
2603
2667
|
multi_arr.is_subscript_tuple = True
|
|
2604
2668
|
prop = multi_arr
|
|
2669
|
+
# __class_getitem__: Class[item] → Class.__class_getitem__(item)
|
|
2670
|
+
cls_info = get_class_in_scope(expr)
|
|
2671
|
+
if cls_info and is_static_method(cls_info, '__class_getitem__'):
|
|
2672
|
+
return subscripts(new AST_Call({
|
|
2673
|
+
'start': start,
|
|
2674
|
+
'expression': new AST_Dot({
|
|
2675
|
+
'start': start,
|
|
2676
|
+
'expression': expr,
|
|
2677
|
+
'property': '__class_getitem__',
|
|
2678
|
+
'end': prev()
|
|
2679
|
+
}),
|
|
2680
|
+
'args': [prop],
|
|
2681
|
+
'end': prev()
|
|
2682
|
+
}), allow_calls)
|
|
2605
2683
|
if is_py_sub:
|
|
2606
2684
|
assignment = None
|
|
2607
2685
|
assign_operator = ''
|
|
@@ -2630,22 +2708,68 @@ def create_parser_ctx(S, import_dirs, module_id, baselib_items, imported_module_
|
|
|
2630
2708
|
S.in_parenthesized_expr = True
|
|
2631
2709
|
next()
|
|
2632
2710
|
if not expr.parens and get_class_in_scope(expr):
|
|
2633
|
-
|
|
2634
|
-
|
|
2635
|
-
|
|
2636
|
-
|
|
2637
|
-
'
|
|
2638
|
-
|
|
2639
|
-
|
|
2711
|
+
c = get_class_in_scope(expr)
|
|
2712
|
+
# Class instantiation
|
|
2713
|
+
args = func_call_list()
|
|
2714
|
+
if c.has_new:
|
|
2715
|
+
# Class defines __new__: call without 'new' so __new__ controls
|
|
2716
|
+
# instantiation (the constructor dispatches via !(this instanceof ...))
|
|
2717
|
+
ret = subscripts(new AST_Call({
|
|
2718
|
+
'start': start,
|
|
2719
|
+
'expression': expr,
|
|
2720
|
+
'args': args,
|
|
2721
|
+
'end': prev()
|
|
2722
|
+
}), True)
|
|
2723
|
+
else:
|
|
2724
|
+
ret = subscripts(new AST_New({
|
|
2725
|
+
'start': start,
|
|
2726
|
+
'expression': expr,
|
|
2727
|
+
'args': args,
|
|
2728
|
+
'end': prev()
|
|
2729
|
+
}), True)
|
|
2640
2730
|
S.in_parenthesized_expr = False
|
|
2641
2731
|
return ret
|
|
2642
|
-
|
|
2643
|
-
if is_node_type(expr,
|
|
2644
|
-
|
|
2732
|
+
if is_node_type(expr, AST_Dot):
|
|
2733
|
+
if is_node_type(expr.expression, AST_Super):
|
|
2734
|
+
super_node = expr.expression
|
|
2735
|
+
method_name = expr.property
|
|
2736
|
+
method_args = func_call_list()
|
|
2737
|
+
if method_name is '__new__':
|
|
2738
|
+
if super_node.parent:
|
|
2739
|
+
# super().__new__(cls, ...) → ρσ_new(parent, cls, ...)
|
|
2740
|
+
method_args.unshift(super_node.parent)
|
|
2741
|
+
ret = subscripts(new AST_Call({
|
|
2742
|
+
'start': start,
|
|
2743
|
+
'expression': new AST_SymbolRef({
|
|
2744
|
+
'name': 'ρσ_new',
|
|
2745
|
+
'start': start,
|
|
2746
|
+
'end': start
|
|
2747
|
+
}),
|
|
2748
|
+
'args': method_args,
|
|
2749
|
+
'end': prev()
|
|
2750
|
+
}), True)
|
|
2751
|
+
else:
|
|
2752
|
+
# Root class: super().__new__(cls) → ρσ_object_new(cls)
|
|
2753
|
+
cls_args = v'[]'
|
|
2754
|
+
if method_args.length > 0:
|
|
2755
|
+
cls_args.push(method_args[0])
|
|
2756
|
+
ret = subscripts(new AST_Call({
|
|
2757
|
+
'start': start,
|
|
2758
|
+
'expression': new AST_SymbolRef({
|
|
2759
|
+
'name': 'ρσ_object_new',
|
|
2760
|
+
'start': start,
|
|
2761
|
+
'end': start
|
|
2762
|
+
}),
|
|
2763
|
+
'args': cls_args,
|
|
2764
|
+
'end': prev()
|
|
2765
|
+
}), True)
|
|
2766
|
+
else:
|
|
2767
|
+
if not super_node.parent:
|
|
2768
|
+
croak('super() used in a class without a parent class')
|
|
2645
2769
|
# super().method(args) → ParentClass.prototype.method.call(this, args)
|
|
2646
|
-
|
|
2647
|
-
|
|
2648
|
-
|
|
2770
|
+
# But for classmethods/static methods, use ParentClass.method.call(this, args)
|
|
2771
|
+
parent_cls_info = get_class_in_scope(super_node.parent)
|
|
2772
|
+
super_is_static = parent_cls_info and is_static_method(parent_cls_info, method_name)
|
|
2649
2773
|
this_node = new AST_This({
|
|
2650
2774
|
'name': 'this',
|
|
2651
2775
|
'start': start,
|
|
@@ -2656,100 +2780,119 @@ def create_parser_ctx(S, import_dirs, module_id, baselib_items, imported_module_
|
|
|
2656
2780
|
'start': start,
|
|
2657
2781
|
'class': super_node.parent,
|
|
2658
2782
|
'method': method_name,
|
|
2659
|
-
'static': False,
|
|
2783
|
+
'static': super_is_static or False,
|
|
2660
2784
|
'args': method_args,
|
|
2661
2785
|
'end': prev()
|
|
2662
2786
|
}), True)
|
|
2663
|
-
|
|
2664
|
-
|
|
2665
|
-
|
|
2666
|
-
|
|
2667
|
-
if
|
|
2668
|
-
|
|
2669
|
-
|
|
2670
|
-
|
|
2671
|
-
|
|
2787
|
+
S.in_parenthesized_expr = False
|
|
2788
|
+
return ret
|
|
2789
|
+
# Intercept object.__setattr__/object.__getattribute__/object.__delattr__
|
|
2790
|
+
# and compile them to the appropriate bypass helpers.
|
|
2791
|
+
if (is_node_type(expr.expression, AST_SymbolRef) and
|
|
2792
|
+
expr.expression.name is 'object' and
|
|
2793
|
+
expr.property in ['__setattr__', '__getattribute__', '__delattr__']):
|
|
2794
|
+
helper_name = (
|
|
2795
|
+
'ρσ_object_setattr' if expr.property is '__setattr__' else
|
|
2796
|
+
('ρσ_object_getattr' if expr.property is '__getattribute__' else 'ρσ_object_delattr')
|
|
2797
|
+
)
|
|
2798
|
+
args = func_call_list()
|
|
2799
|
+
ret = subscripts(new AST_Call({
|
|
2672
2800
|
'start': start,
|
|
2673
|
-
|
|
2674
|
-
|
|
2675
|
-
|
|
2676
|
-
|
|
2801
|
+
'expression': new AST_SymbolRef({
|
|
2802
|
+
'name': helper_name,
|
|
2803
|
+
'start': start,
|
|
2804
|
+
'end': start
|
|
2805
|
+
}),
|
|
2806
|
+
'args': args,
|
|
2677
2807
|
'end': prev()
|
|
2678
2808
|
}), True)
|
|
2679
2809
|
S.in_parenthesized_expr = False
|
|
2680
2810
|
return ret
|
|
2681
|
-
|
|
2682
|
-
|
|
2683
|
-
|
|
2684
|
-
|
|
2685
|
-
|
|
2686
|
-
'operator': "typeof",
|
|
2687
|
-
'expression': func_call_list()[0],
|
|
2688
|
-
'end': prev()
|
|
2689
|
-
})
|
|
2690
|
-
S.in_parenthesized_expr = False
|
|
2691
|
-
return ret
|
|
2692
|
-
elif tmp_ is "isinstance":
|
|
2693
|
-
args = func_call_list()
|
|
2694
|
-
if args.length is not 2:
|
|
2695
|
-
croak('isinstance() must be called with exactly two arguments')
|
|
2696
|
-
ret = new AST_Binary({
|
|
2697
|
-
'start': start,
|
|
2698
|
-
'left': args[0],
|
|
2699
|
-
'operator': 'instanceof',
|
|
2700
|
-
'right': args[1],
|
|
2701
|
-
'end': prev()
|
|
2702
|
-
})
|
|
2703
|
-
S.in_parenthesized_expr = False
|
|
2704
|
-
return ret
|
|
2705
|
-
elif tmp_ is "super":
|
|
2706
|
-
# Find the innermost enclosing class name
|
|
2707
|
-
current_class = None
|
|
2708
|
-
for v'var i = S.in_class.length - 1; i >= 0; i--':
|
|
2709
|
-
if S.in_class[i]:
|
|
2710
|
-
current_class = S.in_class[i]
|
|
2711
|
-
break
|
|
2712
|
-
if not current_class:
|
|
2713
|
-
croak('super() is only valid inside a class method')
|
|
2714
|
-
super_args = func_call_list()
|
|
2715
|
-
parent_expr = None
|
|
2716
|
-
if super_args.length is 0:
|
|
2717
|
-
# 0-arg form: use parent of current class
|
|
2718
|
-
for v'var s = S.classes.length - 1; s >= 0; s--':
|
|
2719
|
-
if has_prop(S.classes[s], current_class):
|
|
2720
|
-
parent_expr = S.classes[s][current_class].parent
|
|
2721
|
-
break
|
|
2722
|
-
if not parent_expr:
|
|
2723
|
-
croak('super() used in a class without a parent class')
|
|
2724
|
-
elif super_args.length is 2:
|
|
2725
|
-
# 2-arg form: super(ClassName, self) — use parent of ClassName
|
|
2726
|
-
cls_ref = super_args[0]
|
|
2727
|
-
cls_info = get_class_in_scope(cls_ref)
|
|
2728
|
-
if not cls_info or not cls_info.parent:
|
|
2729
|
-
croak('First argument to super() must be a subclass with a parent')
|
|
2730
|
-
parent_expr = cls_info.parent
|
|
2731
|
-
else:
|
|
2732
|
-
croak('super() takes 0 or 2 arguments (' + super_args.length + ' given)')
|
|
2733
|
-
super_node = new AST_Super({
|
|
2734
|
-
'start': start,
|
|
2735
|
-
'parent': parent_expr,
|
|
2736
|
-
'class_name': current_class,
|
|
2737
|
-
'end': prev()
|
|
2738
|
-
})
|
|
2739
|
-
S.in_parenthesized_expr = False
|
|
2740
|
-
# Call subscripts to handle subsequent .method(args) chain
|
|
2741
|
-
return subscripts(super_node, True)
|
|
2742
|
-
|
|
2743
|
-
# fall-through to basic function call
|
|
2744
|
-
ret = subscripts(new AST_Call({
|
|
2811
|
+
c = get_class_in_scope(expr.expression)
|
|
2812
|
+
if c:
|
|
2813
|
+
# generate class call
|
|
2814
|
+
funcname = expr
|
|
2815
|
+
ret = subscripts(new AST_ClassCall({
|
|
2745
2816
|
'start': start,
|
|
2746
|
-
|
|
2817
|
+
"class": expr.expression,
|
|
2818
|
+
'method': funcname.property,
|
|
2819
|
+
"static": is_static_method(c, funcname.property),
|
|
2747
2820
|
'args': func_call_list(),
|
|
2748
|
-
'end': prev()
|
|
2749
|
-
'python_truthiness': S.scoped_flags.get('truthiness', False) and is_node_type(expr, AST_SymbolRef)
|
|
2821
|
+
'end': prev()
|
|
2750
2822
|
}), True)
|
|
2751
2823
|
S.in_parenthesized_expr = False
|
|
2752
2824
|
return ret
|
|
2825
|
+
elif is_node_type(expr, AST_SymbolRef):
|
|
2826
|
+
tmp_ = expr.name
|
|
2827
|
+
if tmp_ is "jstype":
|
|
2828
|
+
ret = new AST_UnaryPrefix({
|
|
2829
|
+
'start': start,
|
|
2830
|
+
'operator': "typeof",
|
|
2831
|
+
'expression': func_call_list()[0],
|
|
2832
|
+
'end': prev()
|
|
2833
|
+
})
|
|
2834
|
+
S.in_parenthesized_expr = False
|
|
2835
|
+
return ret
|
|
2836
|
+
elif tmp_ is "isinstance":
|
|
2837
|
+
args = func_call_list()
|
|
2838
|
+
if args.length is not 2:
|
|
2839
|
+
croak('isinstance() must be called with exactly two arguments')
|
|
2840
|
+
ret = new AST_Binary({
|
|
2841
|
+
'start': start,
|
|
2842
|
+
'left': args[0],
|
|
2843
|
+
'operator': 'instanceof',
|
|
2844
|
+
'right': args[1],
|
|
2845
|
+
'end': prev()
|
|
2846
|
+
})
|
|
2847
|
+
S.in_parenthesized_expr = False
|
|
2848
|
+
return ret
|
|
2849
|
+
elif tmp_ is "super":
|
|
2850
|
+
# Find the innermost enclosing class name
|
|
2851
|
+
current_class = None
|
|
2852
|
+
for v'var i = S.in_class.length - 1; i >= 0; i--':
|
|
2853
|
+
if S.in_class[i]:
|
|
2854
|
+
current_class = S.in_class[i]
|
|
2855
|
+
break
|
|
2856
|
+
if not current_class:
|
|
2857
|
+
croak('super() is only valid inside a class method')
|
|
2858
|
+
super_args = func_call_list()
|
|
2859
|
+
parent_expr = None
|
|
2860
|
+
if super_args.length is 0:
|
|
2861
|
+
# 0-arg form: use parent of current class
|
|
2862
|
+
for v'var s = S.classes.length - 1; s >= 0; s--':
|
|
2863
|
+
if has_prop(S.classes[s], current_class):
|
|
2864
|
+
parent_expr = S.classes[s][current_class].parent
|
|
2865
|
+
break
|
|
2866
|
+
# parent_expr stays None for root classes; handled at method-call time
|
|
2867
|
+
# (super().__new__(cls) in a root class → ρσ_object_new(cls))
|
|
2868
|
+
elif super_args.length is 2:
|
|
2869
|
+
# 2-arg form: super(ClassName, self) — use parent of ClassName
|
|
2870
|
+
cls_ref = super_args[0]
|
|
2871
|
+
cls_info = get_class_in_scope(cls_ref)
|
|
2872
|
+
if not cls_info or not cls_info.parent:
|
|
2873
|
+
croak('First argument to super() must be a subclass with a parent')
|
|
2874
|
+
parent_expr = cls_info.parent
|
|
2875
|
+
else:
|
|
2876
|
+
croak('super() takes 0 or 2 arguments (' + super_args.length + ' given)')
|
|
2877
|
+
super_node = new AST_Super({
|
|
2878
|
+
'start': start,
|
|
2879
|
+
'parent': parent_expr,
|
|
2880
|
+
'class_name': current_class,
|
|
2881
|
+
'end': prev()
|
|
2882
|
+
})
|
|
2883
|
+
S.in_parenthesized_expr = False
|
|
2884
|
+
# Call subscripts to handle subsequent .method(args) chain
|
|
2885
|
+
return subscripts(super_node, True)
|
|
2886
|
+
# fall-through to basic function call
|
|
2887
|
+
ret = subscripts(new AST_Call({
|
|
2888
|
+
'start': start,
|
|
2889
|
+
'expression': expr,
|
|
2890
|
+
'args': func_call_list(),
|
|
2891
|
+
'end': prev(),
|
|
2892
|
+
'python_truthiness': S.scoped_flags.get('truthiness', False) and is_node_type(expr, AST_SymbolRef)
|
|
2893
|
+
}), True)
|
|
2894
|
+
S.in_parenthesized_expr = False
|
|
2895
|
+
return ret
|
|
2753
2896
|
|
|
2754
2897
|
def get_attr(expr, allow_calls):
|
|
2755
2898
|
next()
|
|
@@ -2816,6 +2959,11 @@ def create_parser_ctx(S, import_dirs, module_id, baselib_items, imported_module_
|
|
|
2816
2959
|
|
|
2817
2960
|
def maybe_unary(allow_calls):
|
|
2818
2961
|
start = S.token
|
|
2962
|
+
# JSX: detect <tag or <> in expression position
|
|
2963
|
+
if S.scoped_flags.get('jsx', False) and is_('operator', '<'):
|
|
2964
|
+
nxt = peek()
|
|
2965
|
+
if nxt.type is 'name' or (nxt.type is 'operator' and nxt.value is '>'):
|
|
2966
|
+
return subscripts(read_jsx_element(), allow_calls)
|
|
2819
2967
|
if is_('operator', '@'):
|
|
2820
2968
|
if S.parsing_decorator:
|
|
2821
2969
|
croak('Nested decorators are not allowed')
|
|
@@ -2843,6 +2991,162 @@ def create_parser_ctx(S, import_dirs, module_id, baselib_items, imported_module_
|
|
|
2843
2991
|
val = expr_atom(allow_calls)
|
|
2844
2992
|
return val
|
|
2845
2993
|
|
|
2994
|
+
# -----[ JSX parsing ]-----
|
|
2995
|
+
|
|
2996
|
+
def read_jsx_tag_name():
|
|
2997
|
+
# reads a tag name (identifier or dot-separated, e.g. "div", "MyComp", "Foo.Bar")
|
|
2998
|
+
if not is_('name'):
|
|
2999
|
+
croak('Expected JSX tag name')
|
|
3000
|
+
name = S.token.value
|
|
3001
|
+
next()
|
|
3002
|
+
while is_('punc', '.'):
|
|
3003
|
+
next() # consume .
|
|
3004
|
+
if not is_('name'):
|
|
3005
|
+
croak('Expected identifier after . in JSX tag name')
|
|
3006
|
+
name += '.' + S.token.value
|
|
3007
|
+
next()
|
|
3008
|
+
return name
|
|
3009
|
+
|
|
3010
|
+
def read_jsx_attr_name():
|
|
3011
|
+
# reads an attribute name; hyphens are allowed (e.g. aria-label, data-id)
|
|
3012
|
+
if not is_('name'):
|
|
3013
|
+
croak('Expected JSX attribute name')
|
|
3014
|
+
name = S.token.value
|
|
3015
|
+
next()
|
|
3016
|
+
while is_('operator', '-'):
|
|
3017
|
+
next() # consume -
|
|
3018
|
+
if not is_('name'):
|
|
3019
|
+
croak('Expected identifier after - in JSX attribute name')
|
|
3020
|
+
name += '-' + S.token.value
|
|
3021
|
+
next()
|
|
3022
|
+
return name
|
|
3023
|
+
|
|
3024
|
+
def read_jsx_attrs():
|
|
3025
|
+
# reads all attributes until > or /> is reached
|
|
3026
|
+
props = []
|
|
3027
|
+
while not is_('operator', '>') and not is_('operator', '/') and not is_('eof'):
|
|
3028
|
+
if is_('punc', '{'):
|
|
3029
|
+
# Spread attribute: {...expr}
|
|
3030
|
+
next() # consume {
|
|
3031
|
+
if not is_('atom', 'Ellipsis'):
|
|
3032
|
+
croak('Expected ... in JSX spread attribute')
|
|
3033
|
+
next() # consume ...
|
|
3034
|
+
expr = expression()
|
|
3035
|
+
expect('}')
|
|
3036
|
+
props.push(new AST_JSXSpread({'expression': expr, 'start': prev(), 'end': prev()}))
|
|
3037
|
+
elif is_('name'):
|
|
3038
|
+
attr_start = S.token
|
|
3039
|
+
name = read_jsx_attr_name()
|
|
3040
|
+
if is_('operator', '='):
|
|
3041
|
+
next() # consume =
|
|
3042
|
+
if is_('string'):
|
|
3043
|
+
val = new AST_String({'value': S.token.value, 'start': S.token, 'end': S.token, 'quote': S.token.quote})
|
|
3044
|
+
next()
|
|
3045
|
+
elif is_('punc', '{'):
|
|
3046
|
+
next() # consume {
|
|
3047
|
+
val = expression()
|
|
3048
|
+
expect('}')
|
|
3049
|
+
else:
|
|
3050
|
+
croak('Expected string or { in JSX attribute value')
|
|
3051
|
+
else:
|
|
3052
|
+
val = None # boolean attribute
|
|
3053
|
+
props.push(new AST_JSXAttribute({'name': name, 'value': val, 'start': attr_start, 'end': prev()}))
|
|
3054
|
+
else:
|
|
3055
|
+
unexpected()
|
|
3056
|
+
return props
|
|
3057
|
+
|
|
3058
|
+
def read_jsx_children_loop(close_tag):
|
|
3059
|
+
# S.token is already the first child token (jsx_text, OP(<), PUNC({))
|
|
3060
|
+
# JSX depth is currently >0 (entered before this call)
|
|
3061
|
+
children = []
|
|
3062
|
+
while True:
|
|
3063
|
+
if S.token.type is 'jsx_text':
|
|
3064
|
+
text = S.token.value
|
|
3065
|
+
children.push(new AST_JSXText({'value': text, 'start': S.token, 'end': S.token}))
|
|
3066
|
+
next() # still in JSX mode
|
|
3067
|
+
elif is_('operator', '<'):
|
|
3068
|
+
# Nested element or closing tag: exit JSX mode to tokenize tag content
|
|
3069
|
+
S.input.jsx_exit()
|
|
3070
|
+
next() # reads what follows < (/ or tag name)
|
|
3071
|
+
if is_('operator', '/'):
|
|
3072
|
+
# Closing tag
|
|
3073
|
+
next() # consume /
|
|
3074
|
+
if close_tag is None:
|
|
3075
|
+
# Fragment closing </> — next should be >
|
|
3076
|
+
if not is_('operator', '>'):
|
|
3077
|
+
croak('Expected > to close JSX fragment')
|
|
3078
|
+
return children # S.token = OP(>), don't consume
|
|
3079
|
+
else:
|
|
3080
|
+
if not is_('name'):
|
|
3081
|
+
croak('Expected closing tag name')
|
|
3082
|
+
if S.token.value is not close_tag:
|
|
3083
|
+
croak('JSX closing tag mismatch: expected </' + close_tag + '>, got </' + S.token.value + '>')
|
|
3084
|
+
next() # consume tag name
|
|
3085
|
+
if not is_('operator', '>'):
|
|
3086
|
+
croak('Expected > in closing JSX tag')
|
|
3087
|
+
return children # S.token = OP(>), don't consume
|
|
3088
|
+
else:
|
|
3089
|
+
# Nested element: S.token is first token of tag (or > for fragment)
|
|
3090
|
+
child = read_jsx_element_inner()
|
|
3091
|
+
children.push(child)
|
|
3092
|
+
# S.token = OP(>) — child's closing >, re-enter JSX mode then consume
|
|
3093
|
+
S.input.jsx_enter()
|
|
3094
|
+
next() # consume child's >, read next sibling in JSX mode
|
|
3095
|
+
elif is_('punc', '{'):
|
|
3096
|
+
# Expression container
|
|
3097
|
+
S.input.jsx_exit()
|
|
3098
|
+
next() # consume {
|
|
3099
|
+
expr = expression()
|
|
3100
|
+
if not is_('punc', '}'):
|
|
3101
|
+
croak('Expected } to close JSX expression')
|
|
3102
|
+
# Re-enter JSX mode BEFORE consuming } so next sibling reads in JSX mode
|
|
3103
|
+
S.input.jsx_enter()
|
|
3104
|
+
next() # consume }, read next sibling in JSX mode
|
|
3105
|
+
children.push(new AST_JSXExprContainer({'expression': expr, 'start': prev(), 'end': prev()}))
|
|
3106
|
+
elif is_('eof'):
|
|
3107
|
+
croak('Unterminated JSX element')
|
|
3108
|
+
else:
|
|
3109
|
+
unexpected()
|
|
3110
|
+
|
|
3111
|
+
def read_jsx_element_inner():
|
|
3112
|
+
# Called when S.token is NAME(tag) or OP(>) for fragment
|
|
3113
|
+
# NOT in JSX mode when entering
|
|
3114
|
+
start = S.prev # the < token (already consumed)
|
|
3115
|
+
if is_('operator', '>'):
|
|
3116
|
+
# Fragment: <>...</>
|
|
3117
|
+
S.input.jsx_enter()
|
|
3118
|
+
next() # consume >, first child in JSX mode
|
|
3119
|
+
children = read_jsx_children_loop(None)
|
|
3120
|
+
# S.token = OP(>) — closing >
|
|
3121
|
+
return new AST_JSXFragment({'start': start, 'children': children, 'end': S.token})
|
|
3122
|
+
else:
|
|
3123
|
+
tag = read_jsx_tag_name()
|
|
3124
|
+
props = read_jsx_attrs()
|
|
3125
|
+
if is_('operator', '/'):
|
|
3126
|
+
next() # consume /
|
|
3127
|
+
# S.token = OP(>) — self-closing
|
|
3128
|
+
return new AST_JSXElement({'start': start, 'tag': tag, 'props': props, 'children': [], 'self_closing': True, 'end': S.token})
|
|
3129
|
+
else:
|
|
3130
|
+
if not is_('operator', '>'):
|
|
3131
|
+
croak('Expected > or /> in JSX element')
|
|
3132
|
+
S.input.jsx_enter()
|
|
3133
|
+
next() # consume >, first child in JSX mode
|
|
3134
|
+
children = read_jsx_children_loop(tag)
|
|
3135
|
+
# S.token = OP(>) — closing >
|
|
3136
|
+
return new AST_JSXElement({'start': start, 'tag': tag, 'props': props, 'children': children, 'self_closing': False, 'end': S.token})
|
|
3137
|
+
|
|
3138
|
+
def read_jsx_element():
|
|
3139
|
+
# S.token = OP(<) — the opening <
|
|
3140
|
+
start = S.token
|
|
3141
|
+
next() # consume <, reads tag name or > for fragment (normal mode)
|
|
3142
|
+
el = read_jsx_element_inner()
|
|
3143
|
+
# S.token = OP(>) — closing >, consume it and return to normal mode
|
|
3144
|
+
next()
|
|
3145
|
+
el.end = prev()
|
|
3146
|
+
return el
|
|
3147
|
+
|
|
3148
|
+
# -----[ end JSX parsing ]-----
|
|
3149
|
+
|
|
2846
3150
|
def make_unary(ctor, op, expr, is_parenthesized):
|
|
2847
3151
|
return new ctor({
|
|
2848
3152
|
'operator': op,
|