rapydscript-ns 0.8.2 → 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 +39 -0
- package/HACKING.md +103 -103
- package/LICENSE +24 -24
- package/PYTHON_DIFFERENCES_REPORT.md +291 -0
- package/PYTHON_FEATURE_COVERAGE.md +106 -15
- package/README.md +831 -52
- package/TODO.md +4 -286
- 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 +4623 -0
- package/language-service/language-service.d.ts +40 -0
- package/package.json +9 -7
- 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 +99 -2
- package/src/baselib-containers.pyj +107 -4
- package/src/baselib-errors.pyj +44 -0
- package/src/baselib-internal.pyj +124 -5
- package/src/baselib-itertools.pyj +97 -97
- package/src/baselib-str.pyj +32 -1
- package/src/compiler.pyj +36 -36
- package/src/errors.pyj +30 -30
- package/src/lib/aes.pyj +646 -646
- package/src/lib/collections.pyj +1 -1
- 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/numpy.pyj +10 -10
- 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/analyzer.js +131 -9
- package/src/monaco-language-service/builtins.js +17 -2
- package/src/monaco-language-service/completions.js +170 -1
- package/src/monaco-language-service/diagnostics.js +25 -3
- package/src/monaco-language-service/dts.js +550 -550
- package/src/monaco-language-service/index.js +17 -0
- package/src/monaco-language-service/scope.js +3 -0
- package/src/output/classes.pyj +128 -11
- package/src/output/codegen.pyj +17 -3
- package/src/output/comments.pyj +45 -45
- package/src/output/exceptions.pyj +201 -105
- package/src/output/functions.pyj +13 -16
- package/src/output/jsx.pyj +164 -0
- package/src/output/literals.pyj +28 -2
- package/src/output/loops.pyj +0 -9
- package/src/output/modules.pyj +2 -5
- package/src/output/operators.pyj +22 -2
- package/src/output/statements.pyj +2 -2
- package/src/output/stream.pyj +1 -13
- package/src/output/treeshake.pyj +182 -182
- package/src/output/utils.pyj +72 -72
- package/src/parse.pyj +434 -114
- 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/baselib.pyj +4 -4
- package/test/classes.pyj +56 -17
- package/test/collections.pyj +5 -5
- 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_compat.pyj +326 -0
- package/test/python_features.pyj +129 -29
- package/test/regexp.pyj +55 -55
- package/test/repl.pyj +121 -121
- package/test/scoped_flags.pyj +76 -76
- package/test/slice.pyj +105 -0
- package/test/str.pyj +25 -0
- package/test/unit/fixtures/fibonacci_expected.js +1 -1
- package/test/unit/index.js +2296 -71
- package/test/unit/language-service-builtins.js +70 -0
- package/test/unit/language-service-bundle.js +5 -5
- package/test/unit/language-service-completions.js +180 -0
- package/test/unit/language-service-dts.js +543 -543
- package/test/unit/language-service-hover.js +455 -455
- package/test/unit/language-service-index.js +350 -0
- package/test/unit/language-service-scope.js +255 -0
- package/test/unit/language-service.js +625 -4
- package/test/unit/run-language-service.js +1 -0
- package/test/unit/web-repl.js +437 -0
- package/tools/build-language-service.js +2 -2
- package/tools/cli.js +547 -547
- package/tools/compile.js +219 -219
- package/tools/compiler.js +0 -24
- package/tools/completer.js +131 -131
- package/tools/embedded_compiler.js +251 -251
- package/tools/export.js +3 -37
- 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 +227 -139
- package/web-repl/sha1.js +25 -25
- package/hack_demo.pyj +0 -112
- package/web-repl/language-service.js +0 -4187
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,8 +1415,21 @@ 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
|
|
|
1421
|
+
# If this class is nested inside another class, register it under its
|
|
1422
|
+
# full dotted path (e.g. "Outer.Inner") in the module-level class scope
|
|
1423
|
+
# (S.classes[0]). This lets get_class_in_scope() find "Outer.Inner" as
|
|
1424
|
+
# a class and produce a correct AST_New constructor call instead of
|
|
1425
|
+
# treating it as a method call on Outer.
|
|
1426
|
+
outer_class_parts = []
|
|
1427
|
+
for _outer in S.in_class:
|
|
1428
|
+
if _outer:
|
|
1429
|
+
outer_class_parts.push(_outer)
|
|
1430
|
+
if outer_class_parts.length > 0:
|
|
1431
|
+
S.classes[0][outer_class_parts.join('.') + '.' + name.name] = class_details
|
|
1432
|
+
|
|
1419
1433
|
# read the bases of the class, if any
|
|
1420
1434
|
if is_("punc", "("):
|
|
1421
1435
|
S.in_parenthesized_expr = True
|
|
@@ -1425,10 +1439,14 @@ def create_parser_ctx(S, import_dirs, module_id, baselib_items, imported_module_
|
|
|
1425
1439
|
S.in_parenthesized_expr = False
|
|
1426
1440
|
next()
|
|
1427
1441
|
break
|
|
1428
|
-
a =
|
|
1429
|
-
if
|
|
1430
|
-
|
|
1431
|
-
|
|
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)
|
|
1432
1450
|
if is_('punc', ','):
|
|
1433
1451
|
next()
|
|
1434
1452
|
continue
|
|
@@ -1443,6 +1461,7 @@ def create_parser_ctx(S, import_dirs, module_id, baselib_items, imported_module_
|
|
|
1443
1461
|
'dynamic_properties': Object.create(None),
|
|
1444
1462
|
'parent': class_parent,
|
|
1445
1463
|
'bases': bases,
|
|
1464
|
+
'class_kwargs': class_kwargs,
|
|
1446
1465
|
'localvars': [],
|
|
1447
1466
|
'classvars': class_details.classvars,
|
|
1448
1467
|
'static': class_details.static,
|
|
@@ -1489,6 +1508,26 @@ def create_parser_ctx(S, import_dirs, module_id, baselib_items, imported_module_
|
|
|
1489
1508
|
descriptor['getter' if stmt.is_getter else 'setter'] = stmt
|
|
1490
1509
|
elif stmt.name.name is "__init__":
|
|
1491
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
|
|
1492
1531
|
# find the class variables
|
|
1493
1532
|
class_var_names = {}
|
|
1494
1533
|
# Ensure that if a class variable refers to another class variable in
|
|
@@ -1521,7 +1560,11 @@ def create_parser_ctx(S, import_dirs, module_id, baselib_items, imported_module_
|
|
|
1521
1560
|
visitor = new walker()
|
|
1522
1561
|
|
|
1523
1562
|
for stmt in definition.body:
|
|
1524
|
-
if
|
|
1563
|
+
if is_node_type(stmt, AST_Class):
|
|
1564
|
+
# Nested class: include in statements but don't walk through the
|
|
1565
|
+
# class-var mangling visitor (nested classes have their own scope).
|
|
1566
|
+
definition.statements.push(stmt)
|
|
1567
|
+
else:
|
|
1525
1568
|
stmt.walk(visitor)
|
|
1526
1569
|
definition.statements.push(stmt)
|
|
1527
1570
|
return definition
|
|
@@ -1714,7 +1757,7 @@ def create_parser_ctx(S, import_dirs, module_id, baselib_items, imported_module_
|
|
|
1714
1757
|
S.in_parenthesized_expr = False
|
|
1715
1758
|
a.defaults = defaults
|
|
1716
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
|
|
1717
|
-
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:
|
|
1718
1761
|
cm_cls_arg.push(a[0].name)
|
|
1719
1762
|
return a
|
|
1720
1763
|
)(v'[]'),
|
|
@@ -1732,7 +1775,7 @@ def create_parser_ctx(S, import_dirs, module_id, baselib_items, imported_module_
|
|
|
1732
1775
|
'body': (def(loop, labels):
|
|
1733
1776
|
S.in_class.push(False)
|
|
1734
1777
|
cm_pushed = v'[false]'
|
|
1735
|
-
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:
|
|
1736
1779
|
cm_ctx_entry = None
|
|
1737
1780
|
for v'var si = S.classes.length - 1; si >= 0; si--':
|
|
1738
1781
|
if has_prop(S.classes[si], in_class):
|
|
@@ -1962,9 +2005,18 @@ def create_parser_ctx(S, import_dirs, module_id, baselib_items, imported_module_
|
|
|
1962
2005
|
bcatch = v'[]'
|
|
1963
2006
|
bfinally = None
|
|
1964
2007
|
belse = None
|
|
2008
|
+
has_star = None # None = not yet seen, True/False = seen star/non-star
|
|
1965
2009
|
while is_("keyword", "except"):
|
|
1966
2010
|
start = S.token
|
|
1967
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")
|
|
1968
2020
|
exceptions = []
|
|
1969
2021
|
if not is_("punc", ":") and not is_("keyword", "as"):
|
|
1970
2022
|
# Accept both: except TypeError, ValueError:
|
|
@@ -1990,6 +2042,7 @@ def create_parser_ctx(S, import_dirs, module_id, baselib_items, imported_module_
|
|
|
1990
2042
|
'start': start,
|
|
1991
2043
|
'argname': name,
|
|
1992
2044
|
'errors': exceptions,
|
|
2045
|
+
'is_star': is_star,
|
|
1993
2046
|
'body': block_(),
|
|
1994
2047
|
'end': prev()
|
|
1995
2048
|
}))
|
|
@@ -2232,6 +2285,13 @@ def create_parser_ctx(S, import_dirs, module_id, baselib_items, imported_module_
|
|
|
2232
2285
|
if is_("operator", "*") and func_call:
|
|
2233
2286
|
saw_starargs = True
|
|
2234
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
|
|
2235
2295
|
|
|
2236
2296
|
if is_("punc", ",") and allow_empty:
|
|
2237
2297
|
a.push(new AST_Hole({
|
|
@@ -2278,7 +2338,7 @@ def create_parser_ctx(S, import_dirs, module_id, baselib_items, imported_module_
|
|
|
2278
2338
|
a.starargs = True
|
|
2279
2339
|
elif is_('operator', '**'):
|
|
2280
2340
|
next()
|
|
2281
|
-
a.kwarg_items.push(
|
|
2341
|
+
a.kwarg_items.push(expression(False))
|
|
2282
2342
|
a.starargs = True
|
|
2283
2343
|
else:
|
|
2284
2344
|
arg = expression(False)
|
|
@@ -2302,10 +2362,17 @@ def create_parser_ctx(S, import_dirs, module_id, baselib_items, imported_module_
|
|
|
2302
2362
|
expect("[")
|
|
2303
2363
|
expr = []
|
|
2304
2364
|
if not is_("punc", "]"):
|
|
2305
|
-
|
|
2306
|
-
|
|
2307
|
-
|
|
2308
|
-
|
|
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]}), ']')
|
|
2309
2376
|
|
|
2310
2377
|
if not is_("punc", "]"):
|
|
2311
2378
|
expect(",")
|
|
@@ -2340,6 +2407,12 @@ def create_parser_ctx(S, import_dirs, module_id, baselib_items, imported_module_
|
|
|
2340
2407
|
}))
|
|
2341
2408
|
has_non_const_keys = True
|
|
2342
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)
|
|
2343
2416
|
ctx = S.input.context()
|
|
2344
2417
|
orig = ctx.expecting_object_literal_key
|
|
2345
2418
|
ctx.expecting_object_literal_key = True
|
|
@@ -2372,18 +2445,25 @@ def create_parser_ctx(S, import_dirs, module_id, baselib_items, imported_module_
|
|
|
2372
2445
|
'is_jshash': is_jshash,
|
|
2373
2446
|
})
|
|
2374
2447
|
|
|
2375
|
-
def
|
|
2376
|
-
|
|
2377
|
-
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)"
|
|
2378
2450
|
while not is_("punc", "}"):
|
|
2379
2451
|
expect(",")
|
|
2380
|
-
|
|
2452
|
+
item_start = S.token
|
|
2381
2453
|
if is_("punc", "}"):
|
|
2382
2454
|
# allow trailing comma
|
|
2383
2455
|
break
|
|
2384
|
-
|
|
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()}))
|
|
2385
2462
|
next()
|
|
2386
|
-
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)
|
|
2387
2467
|
|
|
2388
2468
|
def _read_comp_conditions():
|
|
2389
2469
|
# Read zero or more consecutive `if` conditions, combining them with &&.
|
|
@@ -2586,6 +2666,20 @@ def create_parser_ctx(S, import_dirs, module_id, baselib_items, imported_module_
|
|
|
2586
2666
|
multi_arr = new AST_Array({'start': start, 'elements': multi_items, 'end': prev()})
|
|
2587
2667
|
multi_arr.is_subscript_tuple = True
|
|
2588
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)
|
|
2589
2683
|
if is_py_sub:
|
|
2590
2684
|
assignment = None
|
|
2591
2685
|
assign_operator = ''
|
|
@@ -2614,22 +2708,68 @@ def create_parser_ctx(S, import_dirs, module_id, baselib_items, imported_module_
|
|
|
2614
2708
|
S.in_parenthesized_expr = True
|
|
2615
2709
|
next()
|
|
2616
2710
|
if not expr.parens and get_class_in_scope(expr):
|
|
2617
|
-
|
|
2618
|
-
|
|
2619
|
-
|
|
2620
|
-
|
|
2621
|
-
'
|
|
2622
|
-
|
|
2623
|
-
|
|
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)
|
|
2624
2730
|
S.in_parenthesized_expr = False
|
|
2625
2731
|
return ret
|
|
2626
|
-
|
|
2627
|
-
if is_node_type(expr,
|
|
2628
|
-
|
|
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')
|
|
2629
2769
|
# super().method(args) → ParentClass.prototype.method.call(this, args)
|
|
2630
|
-
|
|
2631
|
-
|
|
2632
|
-
|
|
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)
|
|
2633
2773
|
this_node = new AST_This({
|
|
2634
2774
|
'name': 'this',
|
|
2635
2775
|
'start': start,
|
|
@@ -2640,100 +2780,119 @@ def create_parser_ctx(S, import_dirs, module_id, baselib_items, imported_module_
|
|
|
2640
2780
|
'start': start,
|
|
2641
2781
|
'class': super_node.parent,
|
|
2642
2782
|
'method': method_name,
|
|
2643
|
-
'static': False,
|
|
2783
|
+
'static': super_is_static or False,
|
|
2644
2784
|
'args': method_args,
|
|
2645
2785
|
'end': prev()
|
|
2646
2786
|
}), True)
|
|
2647
|
-
|
|
2648
|
-
|
|
2649
|
-
|
|
2650
|
-
|
|
2651
|
-
if
|
|
2652
|
-
|
|
2653
|
-
|
|
2654
|
-
|
|
2655
|
-
|
|
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({
|
|
2656
2800
|
'start': start,
|
|
2657
|
-
|
|
2658
|
-
|
|
2659
|
-
|
|
2660
|
-
|
|
2801
|
+
'expression': new AST_SymbolRef({
|
|
2802
|
+
'name': helper_name,
|
|
2803
|
+
'start': start,
|
|
2804
|
+
'end': start
|
|
2805
|
+
}),
|
|
2806
|
+
'args': args,
|
|
2661
2807
|
'end': prev()
|
|
2662
2808
|
}), True)
|
|
2663
2809
|
S.in_parenthesized_expr = False
|
|
2664
2810
|
return ret
|
|
2665
|
-
|
|
2666
|
-
|
|
2667
|
-
|
|
2668
|
-
|
|
2669
|
-
|
|
2670
|
-
'operator': "typeof",
|
|
2671
|
-
'expression': func_call_list()[0],
|
|
2672
|
-
'end': prev()
|
|
2673
|
-
})
|
|
2674
|
-
S.in_parenthesized_expr = False
|
|
2675
|
-
return ret
|
|
2676
|
-
elif tmp_ is "isinstance":
|
|
2677
|
-
args = func_call_list()
|
|
2678
|
-
if args.length is not 2:
|
|
2679
|
-
croak('isinstance() must be called with exactly two arguments')
|
|
2680
|
-
ret = new AST_Binary({
|
|
2681
|
-
'start': start,
|
|
2682
|
-
'left': args[0],
|
|
2683
|
-
'operator': 'instanceof',
|
|
2684
|
-
'right': args[1],
|
|
2685
|
-
'end': prev()
|
|
2686
|
-
})
|
|
2687
|
-
S.in_parenthesized_expr = False
|
|
2688
|
-
return ret
|
|
2689
|
-
elif tmp_ is "super":
|
|
2690
|
-
# Find the innermost enclosing class name
|
|
2691
|
-
current_class = None
|
|
2692
|
-
for v'var i = S.in_class.length - 1; i >= 0; i--':
|
|
2693
|
-
if S.in_class[i]:
|
|
2694
|
-
current_class = S.in_class[i]
|
|
2695
|
-
break
|
|
2696
|
-
if not current_class:
|
|
2697
|
-
croak('super() is only valid inside a class method')
|
|
2698
|
-
super_args = func_call_list()
|
|
2699
|
-
parent_expr = None
|
|
2700
|
-
if super_args.length is 0:
|
|
2701
|
-
# 0-arg form: use parent of current class
|
|
2702
|
-
for v'var s = S.classes.length - 1; s >= 0; s--':
|
|
2703
|
-
if has_prop(S.classes[s], current_class):
|
|
2704
|
-
parent_expr = S.classes[s][current_class].parent
|
|
2705
|
-
break
|
|
2706
|
-
if not parent_expr:
|
|
2707
|
-
croak('super() used in a class without a parent class')
|
|
2708
|
-
elif super_args.length is 2:
|
|
2709
|
-
# 2-arg form: super(ClassName, self) — use parent of ClassName
|
|
2710
|
-
cls_ref = super_args[0]
|
|
2711
|
-
cls_info = get_class_in_scope(cls_ref)
|
|
2712
|
-
if not cls_info or not cls_info.parent:
|
|
2713
|
-
croak('First argument to super() must be a subclass with a parent')
|
|
2714
|
-
parent_expr = cls_info.parent
|
|
2715
|
-
else:
|
|
2716
|
-
croak('super() takes 0 or 2 arguments (' + super_args.length + ' given)')
|
|
2717
|
-
super_node = new AST_Super({
|
|
2718
|
-
'start': start,
|
|
2719
|
-
'parent': parent_expr,
|
|
2720
|
-
'class_name': current_class,
|
|
2721
|
-
'end': prev()
|
|
2722
|
-
})
|
|
2723
|
-
S.in_parenthesized_expr = False
|
|
2724
|
-
# Call subscripts to handle subsequent .method(args) chain
|
|
2725
|
-
return subscripts(super_node, True)
|
|
2726
|
-
|
|
2727
|
-
# fall-through to basic function call
|
|
2728
|
-
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({
|
|
2729
2816
|
'start': start,
|
|
2730
|
-
|
|
2817
|
+
"class": expr.expression,
|
|
2818
|
+
'method': funcname.property,
|
|
2819
|
+
"static": is_static_method(c, funcname.property),
|
|
2731
2820
|
'args': func_call_list(),
|
|
2732
|
-
'end': prev()
|
|
2733
|
-
'python_truthiness': S.scoped_flags.get('truthiness', False) and is_node_type(expr, AST_SymbolRef)
|
|
2821
|
+
'end': prev()
|
|
2734
2822
|
}), True)
|
|
2735
2823
|
S.in_parenthesized_expr = False
|
|
2736
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
|
|
2737
2896
|
|
|
2738
2897
|
def get_attr(expr, allow_calls):
|
|
2739
2898
|
next()
|
|
@@ -2800,6 +2959,11 @@ def create_parser_ctx(S, import_dirs, module_id, baselib_items, imported_module_
|
|
|
2800
2959
|
|
|
2801
2960
|
def maybe_unary(allow_calls):
|
|
2802
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)
|
|
2803
2967
|
if is_('operator', '@'):
|
|
2804
2968
|
if S.parsing_decorator:
|
|
2805
2969
|
croak('Nested decorators are not allowed')
|
|
@@ -2827,6 +2991,162 @@ def create_parser_ctx(S, import_dirs, module_id, baselib_items, imported_module_
|
|
|
2827
2991
|
val = expr_atom(allow_calls)
|
|
2828
2992
|
return val
|
|
2829
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
|
+
|
|
2830
3150
|
def make_unary(ctor, op, expr, is_parenthesized):
|
|
2831
3151
|
return new ctor({
|
|
2832
3152
|
'operator': op,
|