rapydscript-ns 0.8.3 → 0.9.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +26 -0
- package/README.md +1351 -141
- package/TODO.md +12 -6
- package/language-service/index.js +184 -26
- package/package.json +1 -1
- package/release/baselib-plain-pretty.js +5895 -1928
- package/release/baselib-plain-ugly.js +140 -3
- package/release/compiler.js +16282 -5408
- package/release/signatures.json +25 -22
- package/src/ast.pyj +94 -1
- package/src/baselib-builtins.pyj +362 -3
- package/src/baselib-bytes.pyj +664 -0
- package/src/baselib-containers.pyj +99 -0
- package/src/baselib-errors.pyj +45 -1
- package/src/baselib-internal.pyj +346 -49
- package/src/baselib-itertools.pyj +17 -4
- package/src/baselib-str.pyj +46 -4
- package/src/lib/abc.pyj +317 -0
- package/src/lib/copy.pyj +120 -0
- package/src/lib/dataclasses.pyj +532 -0
- package/src/lib/enum.pyj +125 -0
- package/src/lib/pythonize.pyj +1 -1
- package/src/lib/re.pyj +35 -1
- package/src/lib/react.pyj +74 -0
- package/src/lib/typing.pyj +577 -0
- package/src/monaco-language-service/builtins.js +19 -4
- package/src/monaco-language-service/diagnostics.js +40 -19
- package/src/output/classes.pyj +161 -25
- package/src/output/codegen.pyj +16 -2
- package/src/output/exceptions.pyj +97 -1
- package/src/output/functions.pyj +87 -5
- package/src/output/jsx.pyj +164 -0
- package/src/output/literals.pyj +28 -2
- package/src/output/loops.pyj +5 -2
- package/src/output/modules.pyj +1 -1
- package/src/output/operators.pyj +108 -36
- package/src/output/statements.pyj +2 -2
- package/src/output/stream.pyj +1 -0
- package/src/parse.pyj +496 -128
- package/src/tokenizer.pyj +38 -4
- package/test/abc.pyj +291 -0
- package/test/arithmetic_nostrict.pyj +88 -0
- package/test/arithmetic_types.pyj +169 -0
- package/test/baselib.pyj +91 -0
- package/test/bytes.pyj +467 -0
- package/test/classes.pyj +1 -0
- package/test/comparison_ops.pyj +173 -0
- package/test/dataclasses.pyj +253 -0
- package/test/enum.pyj +134 -0
- package/test/eval_exec.pyj +56 -0
- package/test/format.pyj +148 -0
- package/test/object.pyj +64 -0
- package/test/python_compat.pyj +17 -15
- package/test/python_features.pyj +89 -21
- package/test/regexp.pyj +29 -1
- package/test/tuples.pyj +96 -0
- package/test/typing.pyj +469 -0
- package/test/unit/index.js +2292 -70
- package/test/unit/language-service.js +674 -4
- package/test/unit/web-repl.js +1106 -0
- package/test/vars_locals_globals.pyj +94 -0
- package/tools/cli.js +11 -0
- package/tools/compile.js +5 -0
- package/tools/embedded_compiler.js +15 -4
- package/tools/lint.js +16 -19
- package/tools/repl.js +1 -1
- package/web-repl/env.js +122 -0
- package/web-repl/main.js +1 -3
- package/web-repl/rapydscript.js +125 -3
- package/PYTHON_DIFFERENCES_REPORT.md +0 -291
- package/PYTHON_FEATURE_COVERAGE.md +0 -200
- 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, 'strict_arithmetic':True}
|
|
34
35
|
|
|
35
36
|
|
|
36
37
|
def get_compiler_version():
|
|
@@ -143,7 +144,7 @@ PRECEDENCE = (def(a, ret):
|
|
|
143
144
|
|
|
144
145
|
STATEMENTS_WITH_LABELS = array_to_hash([ "for", "do", "while", "switch" ])
|
|
145
146
|
|
|
146
|
-
ATOMIC_START_TOKEN = array_to_hash([ "atom", "num", "string", "regexp", "name", "js" ])
|
|
147
|
+
ATOMIC_START_TOKEN = array_to_hash([ "atom", "num", "imaginary", "string", "bytes_literal", "regexp", "name", "js" ])
|
|
147
148
|
|
|
148
149
|
compile_time_decorators = ['staticmethod', 'classmethod', 'external', 'property']
|
|
149
150
|
|
|
@@ -511,7 +512,7 @@ def create_parser_ctx(S, import_dirs, module_id, baselib_items, imported_module_
|
|
|
511
512
|
p = prev()
|
|
512
513
|
if p and not S.token.nlb and ATOMIC_START_TOKEN[p.type] and not is_('punc', ':'):
|
|
513
514
|
unexpected()
|
|
514
|
-
if tmp_ is "string":
|
|
515
|
+
if tmp_ is "string" or tmp_ is "bytes_literal":
|
|
515
516
|
return simple_statement()
|
|
516
517
|
elif tmp_ is "shebang":
|
|
517
518
|
tmp_ = S.token.value
|
|
@@ -541,7 +542,7 @@ def create_parser_ctx(S, import_dirs, module_id, baselib_items, imported_module_
|
|
|
541
542
|
p = peek()
|
|
542
543
|
# 'match' is a soft keyword: treat as match statement when followed by
|
|
543
544
|
# a token that can start an expression subject (not an assignment/attr-access/call op)
|
|
544
|
-
if p.type is 'name' or p.type is 'string' or p.type is 'num' or p.type is 'atom' or p.type is 'js' or (p.type is 'punc' and (p.value is '[' or p.value is '(')):
|
|
545
|
+
if p.type is 'name' or p.type is 'string' or p.type is 'bytes_literal' or p.type is 'num' or p.type is 'atom' or p.type is 'js' or (p.type is 'punc' and (p.value is '[' or p.value is '(')):
|
|
545
546
|
next() # consume the 'match' name token
|
|
546
547
|
return match_()
|
|
547
548
|
if (is_token(peek(), 'punc', ':')):
|
|
@@ -1062,7 +1063,26 @@ def create_parser_ctx(S, import_dirs, module_id, baselib_items, imported_module_
|
|
|
1062
1063
|
})
|
|
1063
1064
|
|
|
1064
1065
|
def simple_statement(tmp):
|
|
1066
|
+
start = S.token
|
|
1065
1067
|
tmp = expression(True)
|
|
1068
|
+
# Handle annotated assignment with a complex target (e.g., self.x: Type = value).
|
|
1069
|
+
# Simple-name annotated assignments are caught earlier (annotated_var_statement),
|
|
1070
|
+
# but attribute/subscript targets reach here as a completed expression followed by ':'.
|
|
1071
|
+
if is_("punc", ":"):
|
|
1072
|
+
next() # consume ':'
|
|
1073
|
+
annotation = maybe_conditional()
|
|
1074
|
+
value = None
|
|
1075
|
+
if is_("operator", "="):
|
|
1076
|
+
next() # consume '='
|
|
1077
|
+
value = expression(True)
|
|
1078
|
+
semicolon()
|
|
1079
|
+
return new AST_AnnotatedAssign({
|
|
1080
|
+
'start': start,
|
|
1081
|
+
'target': tmp,
|
|
1082
|
+
'annotation': annotation,
|
|
1083
|
+
'value': value,
|
|
1084
|
+
'end': prev()
|
|
1085
|
+
})
|
|
1066
1086
|
semicolon()
|
|
1067
1087
|
return new AST_SimpleStatement({
|
|
1068
1088
|
'body': tmp
|
|
@@ -1188,17 +1208,18 @@ def create_parser_ctx(S, import_dirs, module_id, baselib_items, imported_module_
|
|
|
1188
1208
|
# to maintain a list of local variables for every AST_Scope and provide
|
|
1189
1209
|
# an easy way to walk the ast tree upwards.
|
|
1190
1210
|
if is_node_type(expr, AST_SymbolRef):
|
|
1191
|
-
# check
|
|
1211
|
+
# traverse in reverse to check local / imported classes first
|
|
1212
|
+
# (user-defined classes take priority over native JS classes)
|
|
1213
|
+
for s in range(S.classes.length-1, -1, -1):
|
|
1214
|
+
if has_prop(S.classes[s], expr.name):
|
|
1215
|
+
return S.classes[s][expr.name]
|
|
1216
|
+
|
|
1217
|
+
# fallback to Native JS classes
|
|
1192
1218
|
if has_prop(NATIVE_CLASSES, expr.name):
|
|
1193
1219
|
return NATIVE_CLASSES[expr.name]
|
|
1194
1220
|
if has_prop(ERROR_CLASSES, expr.name):
|
|
1195
1221
|
return ERROR_CLASSES[expr.name]
|
|
1196
1222
|
|
|
1197
|
-
# traverse in reverse to check local variables first
|
|
1198
|
-
for s in range(S.classes.length-1, -1, -1):
|
|
1199
|
-
if has_prop(S.classes[s], expr.name):
|
|
1200
|
-
return S.classes[s][expr.name]
|
|
1201
|
-
|
|
1202
1223
|
elif is_node_type(expr, AST_Dot):
|
|
1203
1224
|
referenced_path = []
|
|
1204
1225
|
# this one is for detecting classes inside modules and eventually nested classes
|
|
@@ -1414,6 +1435,7 @@ def create_parser_ctx(S, import_dirs, module_id, baselib_items, imported_module_
|
|
|
1414
1435
|
'provisional_classvars': {},
|
|
1415
1436
|
}
|
|
1416
1437
|
bases = v'[]'
|
|
1438
|
+
class_kwargs = v'[]'
|
|
1417
1439
|
class_parent = None
|
|
1418
1440
|
|
|
1419
1441
|
# If this class is nested inside another class, register it under its
|
|
@@ -1437,10 +1459,14 @@ def create_parser_ctx(S, import_dirs, module_id, baselib_items, imported_module_
|
|
|
1437
1459
|
S.in_parenthesized_expr = False
|
|
1438
1460
|
next()
|
|
1439
1461
|
break
|
|
1440
|
-
a =
|
|
1441
|
-
if
|
|
1442
|
-
|
|
1443
|
-
|
|
1462
|
+
a = expression(False)
|
|
1463
|
+
if is_node_type(a, AST_Assign):
|
|
1464
|
+
# key=value → class keyword argument for __init_subclass__
|
|
1465
|
+
class_kwargs.push([a.left, a.right])
|
|
1466
|
+
else:
|
|
1467
|
+
if class_parent is None:
|
|
1468
|
+
class_parent = a
|
|
1469
|
+
bases.push(a)
|
|
1444
1470
|
if is_('punc', ','):
|
|
1445
1471
|
next()
|
|
1446
1472
|
continue
|
|
@@ -1455,6 +1481,7 @@ def create_parser_ctx(S, import_dirs, module_id, baselib_items, imported_module_
|
|
|
1455
1481
|
'dynamic_properties': Object.create(None),
|
|
1456
1482
|
'parent': class_parent,
|
|
1457
1483
|
'bases': bases,
|
|
1484
|
+
'class_kwargs': class_kwargs,
|
|
1458
1485
|
'localvars': [],
|
|
1459
1486
|
'classvars': class_details.classvars,
|
|
1460
1487
|
'static': class_details.static,
|
|
@@ -1501,6 +1528,26 @@ def create_parser_ctx(S, import_dirs, module_id, baselib_items, imported_module_
|
|
|
1501
1528
|
descriptor['getter' if stmt.is_getter else 'setter'] = stmt
|
|
1502
1529
|
elif stmt.name.name is "__init__":
|
|
1503
1530
|
definition.init = stmt
|
|
1531
|
+
elif stmt.name.name is "__new__":
|
|
1532
|
+
definition.has_new = True
|
|
1533
|
+
class_details.has_new = True
|
|
1534
|
+
class_details.static['__new__'] = True
|
|
1535
|
+
stmt.static = True # suppress var cls = this in display_complex_body
|
|
1536
|
+
elif stmt.name.name is "__class_getitem__":
|
|
1537
|
+
stmt.is_classmethod = True
|
|
1538
|
+
class_details.classmethod['__class_getitem__'] = True
|
|
1539
|
+
elif stmt.name.name is "__init_subclass__":
|
|
1540
|
+
stmt.is_classmethod = True
|
|
1541
|
+
class_details.classmethod['__init_subclass__'] = True
|
|
1542
|
+
elif stmt.name.name in ['__getattr__', '__setattr__', '__delattr__', '__getattribute__']:
|
|
1543
|
+
definition.has_attr_dunders = True
|
|
1544
|
+
class_details.has_attr_dunders = True
|
|
1545
|
+
# Propagate has_attr_dunders from parent classes so subclasses are also Proxy-wrapped.
|
|
1546
|
+
if not definition.has_attr_dunders and definition.parent:
|
|
1547
|
+
parent_details = get_class_in_scope(definition.parent)
|
|
1548
|
+
if parent_details and parent_details.has_attr_dunders:
|
|
1549
|
+
definition.has_attr_dunders = True
|
|
1550
|
+
class_details.has_attr_dunders = True
|
|
1504
1551
|
# find the class variables
|
|
1505
1552
|
class_var_names = {}
|
|
1506
1553
|
# Ensure that if a class variable refers to another class variable in
|
|
@@ -1730,7 +1777,7 @@ def create_parser_ctx(S, import_dirs, module_id, baselib_items, imported_module_
|
|
|
1730
1777
|
S.in_parenthesized_expr = False
|
|
1731
1778
|
a.defaults = defaults
|
|
1732
1779
|
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:
|
|
1780
|
+
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
1781
|
cm_cls_arg.push(a[0].name)
|
|
1735
1782
|
return a
|
|
1736
1783
|
)(v'[]'),
|
|
@@ -1748,7 +1795,7 @@ def create_parser_ctx(S, import_dirs, module_id, baselib_items, imported_module_
|
|
|
1748
1795
|
'body': (def(loop, labels):
|
|
1749
1796
|
S.in_class.push(False)
|
|
1750
1797
|
cm_pushed = v'[false]'
|
|
1751
|
-
if classmethod_flag and in_class and cm_cls_arg.length > 0:
|
|
1798
|
+
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
1799
|
cm_ctx_entry = None
|
|
1753
1800
|
for v'var si = S.classes.length - 1; si >= 0; si--':
|
|
1754
1801
|
if has_prop(S.classes[si], in_class):
|
|
@@ -1978,9 +2025,18 @@ def create_parser_ctx(S, import_dirs, module_id, baselib_items, imported_module_
|
|
|
1978
2025
|
bcatch = v'[]'
|
|
1979
2026
|
bfinally = None
|
|
1980
2027
|
belse = None
|
|
2028
|
+
has_star = None # None = not yet seen, True/False = seen star/non-star
|
|
1981
2029
|
while is_("keyword", "except"):
|
|
1982
2030
|
start = S.token
|
|
1983
2031
|
next()
|
|
2032
|
+
is_star = False
|
|
2033
|
+
if is_("operator", "*"):
|
|
2034
|
+
is_star = True
|
|
2035
|
+
next()
|
|
2036
|
+
if has_star is None:
|
|
2037
|
+
has_star = is_star
|
|
2038
|
+
elif has_star is not is_star:
|
|
2039
|
+
croak("Cannot mix 'except' and 'except*' in the same try statement")
|
|
1984
2040
|
exceptions = []
|
|
1985
2041
|
if not is_("punc", ":") and not is_("keyword", "as"):
|
|
1986
2042
|
# Accept both: except TypeError, ValueError:
|
|
@@ -2006,6 +2062,7 @@ def create_parser_ctx(S, import_dirs, module_id, baselib_items, imported_module_
|
|
|
2006
2062
|
'start': start,
|
|
2007
2063
|
'argname': name,
|
|
2008
2064
|
'errors': exceptions,
|
|
2065
|
+
'is_star': is_star,
|
|
2009
2066
|
'body': block_(),
|
|
2010
2067
|
'end': prev()
|
|
2011
2068
|
}))
|
|
@@ -2097,6 +2154,26 @@ def create_parser_ctx(S, import_dirs, module_id, baselib_items, imported_module_
|
|
|
2097
2154
|
'value': strings.join('')
|
|
2098
2155
|
})
|
|
2099
2156
|
|
|
2157
|
+
def bytes_literal_():
|
|
2158
|
+
parts = v'[]'
|
|
2159
|
+
start = S.token
|
|
2160
|
+
while True:
|
|
2161
|
+
parts.push(S.token.value)
|
|
2162
|
+
if peek().type is not 'bytes_literal':
|
|
2163
|
+
break
|
|
2164
|
+
next()
|
|
2165
|
+
end_tok = S.token
|
|
2166
|
+
value = parts.join('')
|
|
2167
|
+
return new AST_Call({
|
|
2168
|
+
'start': start,
|
|
2169
|
+
'end': end_tok,
|
|
2170
|
+
'expression': new AST_SymbolRef({'name': 'bytes', 'start': start, 'end': start}),
|
|
2171
|
+
'args': [
|
|
2172
|
+
new AST_String({'start': start, 'end': end_tok, 'value': value}),
|
|
2173
|
+
new AST_String({'start': start, 'end': end_tok, 'value': 'latin-1'})
|
|
2174
|
+
]
|
|
2175
|
+
})
|
|
2176
|
+
|
|
2100
2177
|
def token_as_atom_node():
|
|
2101
2178
|
tok = S.token
|
|
2102
2179
|
tmp_ = tok.type
|
|
@@ -2108,8 +2185,20 @@ def create_parser_ctx(S, import_dirs, module_id, baselib_items, imported_module_
|
|
|
2108
2185
|
'end': tok,
|
|
2109
2186
|
'value': tok.value
|
|
2110
2187
|
})
|
|
2188
|
+
elif tmp_ is "imaginary":
|
|
2189
|
+
return new AST_Call({
|
|
2190
|
+
'start': tok,
|
|
2191
|
+
'end': tok,
|
|
2192
|
+
'expression': new AST_SymbolRef({'name': 'complex', 'start': tok, 'end': tok}),
|
|
2193
|
+
'args': [
|
|
2194
|
+
new AST_Number({'start': tok, 'end': tok, 'value': 0}),
|
|
2195
|
+
new AST_Number({'start': tok, 'end': tok, 'value': tok.value})
|
|
2196
|
+
]
|
|
2197
|
+
})
|
|
2111
2198
|
elif tmp_ is "string":
|
|
2112
2199
|
return string_()
|
|
2200
|
+
elif tmp_ is "bytes_literal":
|
|
2201
|
+
return bytes_literal_()
|
|
2113
2202
|
elif tmp_ is "regexp":
|
|
2114
2203
|
return new AST_RegExp({
|
|
2115
2204
|
'start': tok,
|
|
@@ -2164,17 +2253,28 @@ def create_parser_ctx(S, import_dirs, module_id, baselib_items, imported_module_
|
|
|
2164
2253
|
if is_('punc', ')'):
|
|
2165
2254
|
next()
|
|
2166
2255
|
return new AST_Array({'elements':[]})
|
|
2167
|
-
ex = expression(
|
|
2256
|
+
ex = expression(False)
|
|
2168
2257
|
if is_('keyword', 'for'):
|
|
2169
2258
|
ret = read_comprehension(new AST_GeneratorComprehension({'statement': ex}), ')')
|
|
2170
2259
|
S.in_parenthesized_expr = False
|
|
2171
2260
|
return ret
|
|
2261
|
+
if is_('punc', ','):
|
|
2262
|
+
# Tuple literal: (a,) or (a, b, c, ...) — compile to JS array
|
|
2263
|
+
elements = [ex]
|
|
2264
|
+
while is_('punc', ','):
|
|
2265
|
+
next()
|
|
2266
|
+
if is_('punc', ')'):
|
|
2267
|
+
break # trailing comma is OK
|
|
2268
|
+
elements.push(expression(False))
|
|
2269
|
+
expect(')')
|
|
2270
|
+
arr = new AST_Array({'elements': elements, 'start': start, 'end': prev()})
|
|
2271
|
+
S.in_parenthesized_expr = False
|
|
2272
|
+
return subscripts(arr, allow_calls)
|
|
2172
2273
|
ex.start = start
|
|
2173
2274
|
ex.end = S.token
|
|
2174
2275
|
if is_node_type(ex, AST_SymbolRef):
|
|
2175
2276
|
ex.parens = True
|
|
2176
|
-
|
|
2177
|
-
expect(")")
|
|
2277
|
+
expect(")")
|
|
2178
2278
|
if is_node_type(ex, AST_UnaryPrefix):
|
|
2179
2279
|
ex.parenthesized = True
|
|
2180
2280
|
S.in_parenthesized_expr = False
|
|
@@ -2248,6 +2348,13 @@ def create_parser_ctx(S, import_dirs, module_id, baselib_items, imported_module_
|
|
|
2248
2348
|
if is_("operator", "*") and func_call:
|
|
2249
2349
|
saw_starargs = True
|
|
2250
2350
|
next()
|
|
2351
|
+
elif is_("operator", "*") and not func_call:
|
|
2352
|
+
# Spread element in list literal: [1, *a, 2]
|
|
2353
|
+
start = S.token
|
|
2354
|
+
next()
|
|
2355
|
+
spread_expr = expression(False)
|
|
2356
|
+
a.push(new AST_Spread({'start': start, 'expression': spread_expr, 'end': prev()}))
|
|
2357
|
+
continue
|
|
2251
2358
|
|
|
2252
2359
|
if is_("punc", ",") and allow_empty:
|
|
2253
2360
|
a.push(new AST_Hole({
|
|
@@ -2294,7 +2401,7 @@ def create_parser_ctx(S, import_dirs, module_id, baselib_items, imported_module_
|
|
|
2294
2401
|
a.starargs = True
|
|
2295
2402
|
elif is_('operator', '**'):
|
|
2296
2403
|
next()
|
|
2297
|
-
a.kwarg_items.push(
|
|
2404
|
+
a.kwarg_items.push(expression(False))
|
|
2298
2405
|
a.starargs = True
|
|
2299
2406
|
else:
|
|
2300
2407
|
arg = expression(False)
|
|
@@ -2318,10 +2425,17 @@ def create_parser_ctx(S, import_dirs, module_id, baselib_items, imported_module_
|
|
|
2318
2425
|
expect("[")
|
|
2319
2426
|
expr = []
|
|
2320
2427
|
if not is_("punc", "]"):
|
|
2321
|
-
|
|
2322
|
-
|
|
2323
|
-
|
|
2324
|
-
|
|
2428
|
+
if is_("operator", "*"):
|
|
2429
|
+
# Spread as first element — no list comprehension possible
|
|
2430
|
+
start = S.token
|
|
2431
|
+
next()
|
|
2432
|
+
spread_expr = expression(False)
|
|
2433
|
+
expr.push(new AST_Spread({'start': start, 'expression': spread_expr, 'end': prev()}))
|
|
2434
|
+
else:
|
|
2435
|
+
expr.push(expression(False))
|
|
2436
|
+
if is_("keyword", "for"):
|
|
2437
|
+
# list comprehension
|
|
2438
|
+
return read_comprehension(new AST_ListComprehension({'statement': expr[0]}), ']')
|
|
2325
2439
|
|
|
2326
2440
|
if not is_("punc", "]"):
|
|
2327
2441
|
expect(",")
|
|
@@ -2356,6 +2470,12 @@ def create_parser_ctx(S, import_dirs, module_id, baselib_items, imported_module_
|
|
|
2356
2470
|
}))
|
|
2357
2471
|
has_non_const_keys = True
|
|
2358
2472
|
continue
|
|
2473
|
+
if is_('operator', '*'):
|
|
2474
|
+
# Must be a set literal with spread as first item: {*a, ...}
|
|
2475
|
+
next()
|
|
2476
|
+
spread_expr = expression(False)
|
|
2477
|
+
spread_node = new AST_Spread({'start': start, 'expression': spread_expr, 'end': prev()})
|
|
2478
|
+
return _read_set_items([spread_node], start)
|
|
2359
2479
|
ctx = S.input.context()
|
|
2360
2480
|
orig = ctx.expecting_object_literal_key
|
|
2361
2481
|
ctx.expecting_object_literal_key = True
|
|
@@ -2388,18 +2508,25 @@ def create_parser_ctx(S, import_dirs, module_id, baselib_items, imported_module_
|
|
|
2388
2508
|
'is_jshash': is_jshash,
|
|
2389
2509
|
})
|
|
2390
2510
|
|
|
2391
|
-
def
|
|
2392
|
-
|
|
2393
|
-
a = [new AST_SetItem({'start':start, 'end':end, 'value':expr})]
|
|
2511
|
+
def _read_set_items(a, ostart):
|
|
2512
|
+
"Read remaining items of a set literal into a (handles * spread)"
|
|
2394
2513
|
while not is_("punc", "}"):
|
|
2395
2514
|
expect(",")
|
|
2396
|
-
|
|
2515
|
+
item_start = S.token
|
|
2397
2516
|
if is_("punc", "}"):
|
|
2398
2517
|
# allow trailing comma
|
|
2399
2518
|
break
|
|
2400
|
-
|
|
2519
|
+
if is_("operator", "*"):
|
|
2520
|
+
next()
|
|
2521
|
+
spread_expr = expression(False)
|
|
2522
|
+
a.push(new AST_Spread({'start': item_start, 'expression': spread_expr, 'end': prev()}))
|
|
2523
|
+
else:
|
|
2524
|
+
a.push(new AST_SetItem({'start': item_start, 'value': expression(False), 'end': prev()}))
|
|
2401
2525
|
next()
|
|
2402
|
-
return new AST_Set({'items':a, 'start':ostart, 'end':prev()})
|
|
2526
|
+
return new AST_Set({'items': a, 'start': ostart, 'end': prev()})
|
|
2527
|
+
|
|
2528
|
+
def set_(start, end, expr):
|
|
2529
|
+
return _read_set_items([new AST_SetItem({'start':start, 'end':end, 'value':expr})], start)
|
|
2403
2530
|
|
|
2404
2531
|
def _read_comp_conditions():
|
|
2405
2532
|
# Read zero or more consecutive `if` conditions, combining them with &&.
|
|
@@ -2602,6 +2729,20 @@ def create_parser_ctx(S, import_dirs, module_id, baselib_items, imported_module_
|
|
|
2602
2729
|
multi_arr = new AST_Array({'start': start, 'elements': multi_items, 'end': prev()})
|
|
2603
2730
|
multi_arr.is_subscript_tuple = True
|
|
2604
2731
|
prop = multi_arr
|
|
2732
|
+
# __class_getitem__: Class[item] → Class.__class_getitem__(item)
|
|
2733
|
+
cls_info = get_class_in_scope(expr)
|
|
2734
|
+
if cls_info and is_static_method(cls_info, '__class_getitem__'):
|
|
2735
|
+
return subscripts(new AST_Call({
|
|
2736
|
+
'start': start,
|
|
2737
|
+
'expression': new AST_Dot({
|
|
2738
|
+
'start': start,
|
|
2739
|
+
'expression': expr,
|
|
2740
|
+
'property': '__class_getitem__',
|
|
2741
|
+
'end': prev()
|
|
2742
|
+
}),
|
|
2743
|
+
'args': [prop],
|
|
2744
|
+
'end': prev()
|
|
2745
|
+
}), allow_calls)
|
|
2605
2746
|
if is_py_sub:
|
|
2606
2747
|
assignment = None
|
|
2607
2748
|
assign_operator = ''
|
|
@@ -2630,22 +2771,68 @@ def create_parser_ctx(S, import_dirs, module_id, baselib_items, imported_module_
|
|
|
2630
2771
|
S.in_parenthesized_expr = True
|
|
2631
2772
|
next()
|
|
2632
2773
|
if not expr.parens and get_class_in_scope(expr):
|
|
2633
|
-
|
|
2634
|
-
|
|
2635
|
-
|
|
2636
|
-
|
|
2637
|
-
'
|
|
2638
|
-
|
|
2639
|
-
|
|
2774
|
+
c = get_class_in_scope(expr)
|
|
2775
|
+
# Class instantiation
|
|
2776
|
+
args = func_call_list()
|
|
2777
|
+
if c.has_new:
|
|
2778
|
+
# Class defines __new__: call without 'new' so __new__ controls
|
|
2779
|
+
# instantiation (the constructor dispatches via !(this instanceof ...))
|
|
2780
|
+
ret = subscripts(new AST_Call({
|
|
2781
|
+
'start': start,
|
|
2782
|
+
'expression': expr,
|
|
2783
|
+
'args': args,
|
|
2784
|
+
'end': prev()
|
|
2785
|
+
}), True)
|
|
2786
|
+
else:
|
|
2787
|
+
ret = subscripts(new AST_New({
|
|
2788
|
+
'start': start,
|
|
2789
|
+
'expression': expr,
|
|
2790
|
+
'args': args,
|
|
2791
|
+
'end': prev()
|
|
2792
|
+
}), True)
|
|
2640
2793
|
S.in_parenthesized_expr = False
|
|
2641
2794
|
return ret
|
|
2642
|
-
|
|
2643
|
-
if is_node_type(expr,
|
|
2644
|
-
|
|
2795
|
+
if is_node_type(expr, AST_Dot):
|
|
2796
|
+
if is_node_type(expr.expression, AST_Super):
|
|
2797
|
+
super_node = expr.expression
|
|
2798
|
+
method_name = expr.property
|
|
2799
|
+
method_args = func_call_list()
|
|
2800
|
+
if method_name is '__new__':
|
|
2801
|
+
if super_node.parent:
|
|
2802
|
+
# super().__new__(cls, ...) → ρσ_new(parent, cls, ...)
|
|
2803
|
+
method_args.unshift(super_node.parent)
|
|
2804
|
+
ret = subscripts(new AST_Call({
|
|
2805
|
+
'start': start,
|
|
2806
|
+
'expression': new AST_SymbolRef({
|
|
2807
|
+
'name': 'ρσ_new',
|
|
2808
|
+
'start': start,
|
|
2809
|
+
'end': start
|
|
2810
|
+
}),
|
|
2811
|
+
'args': method_args,
|
|
2812
|
+
'end': prev()
|
|
2813
|
+
}), True)
|
|
2814
|
+
else:
|
|
2815
|
+
# Root class: super().__new__(cls) → ρσ_object_new(cls)
|
|
2816
|
+
cls_args = v'[]'
|
|
2817
|
+
if method_args.length > 0:
|
|
2818
|
+
cls_args.push(method_args[0])
|
|
2819
|
+
ret = subscripts(new AST_Call({
|
|
2820
|
+
'start': start,
|
|
2821
|
+
'expression': new AST_SymbolRef({
|
|
2822
|
+
'name': 'ρσ_object_new',
|
|
2823
|
+
'start': start,
|
|
2824
|
+
'end': start
|
|
2825
|
+
}),
|
|
2826
|
+
'args': cls_args,
|
|
2827
|
+
'end': prev()
|
|
2828
|
+
}), True)
|
|
2829
|
+
else:
|
|
2830
|
+
if not super_node.parent:
|
|
2831
|
+
croak('super() used in a class without a parent class')
|
|
2645
2832
|
# super().method(args) → ParentClass.prototype.method.call(this, args)
|
|
2646
|
-
|
|
2647
|
-
|
|
2648
|
-
|
|
2833
|
+
# But for classmethods/static methods, use ParentClass.method.call(this, args)
|
|
2834
|
+
parent_cls_info = get_class_in_scope(super_node.parent)
|
|
2835
|
+
super_is_static = parent_cls_info and is_static_method(parent_cls_info, method_name)
|
|
2649
2836
|
this_node = new AST_This({
|
|
2650
2837
|
'name': 'this',
|
|
2651
2838
|
'start': start,
|
|
@@ -2656,100 +2843,119 @@ def create_parser_ctx(S, import_dirs, module_id, baselib_items, imported_module_
|
|
|
2656
2843
|
'start': start,
|
|
2657
2844
|
'class': super_node.parent,
|
|
2658
2845
|
'method': method_name,
|
|
2659
|
-
'static': False,
|
|
2846
|
+
'static': super_is_static or False,
|
|
2660
2847
|
'args': method_args,
|
|
2661
2848
|
'end': prev()
|
|
2662
2849
|
}), True)
|
|
2663
|
-
|
|
2664
|
-
|
|
2665
|
-
|
|
2666
|
-
|
|
2667
|
-
if
|
|
2668
|
-
|
|
2669
|
-
|
|
2670
|
-
|
|
2671
|
-
|
|
2850
|
+
S.in_parenthesized_expr = False
|
|
2851
|
+
return ret
|
|
2852
|
+
# Intercept object.__setattr__/object.__getattribute__/object.__delattr__
|
|
2853
|
+
# and compile them to the appropriate bypass helpers.
|
|
2854
|
+
if (is_node_type(expr.expression, AST_SymbolRef) and
|
|
2855
|
+
expr.expression.name is 'object' and
|
|
2856
|
+
expr.property in ['__setattr__', '__getattribute__', '__delattr__']):
|
|
2857
|
+
helper_name = (
|
|
2858
|
+
'ρσ_object_setattr' if expr.property is '__setattr__' else
|
|
2859
|
+
('ρσ_object_getattr' if expr.property is '__getattribute__' else 'ρσ_object_delattr')
|
|
2860
|
+
)
|
|
2861
|
+
args = func_call_list()
|
|
2862
|
+
ret = subscripts(new AST_Call({
|
|
2672
2863
|
'start': start,
|
|
2673
|
-
|
|
2674
|
-
|
|
2675
|
-
|
|
2676
|
-
|
|
2864
|
+
'expression': new AST_SymbolRef({
|
|
2865
|
+
'name': helper_name,
|
|
2866
|
+
'start': start,
|
|
2867
|
+
'end': start
|
|
2868
|
+
}),
|
|
2869
|
+
'args': args,
|
|
2677
2870
|
'end': prev()
|
|
2678
2871
|
}), True)
|
|
2679
2872
|
S.in_parenthesized_expr = False
|
|
2680
2873
|
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({
|
|
2874
|
+
c = get_class_in_scope(expr.expression)
|
|
2875
|
+
if c:
|
|
2876
|
+
# generate class call
|
|
2877
|
+
funcname = expr
|
|
2878
|
+
ret = subscripts(new AST_ClassCall({
|
|
2745
2879
|
'start': start,
|
|
2746
|
-
|
|
2880
|
+
"class": expr.expression,
|
|
2881
|
+
'method': funcname.property,
|
|
2882
|
+
"static": is_static_method(c, funcname.property),
|
|
2747
2883
|
'args': func_call_list(),
|
|
2748
|
-
'end': prev()
|
|
2749
|
-
'python_truthiness': S.scoped_flags.get('truthiness', False) and is_node_type(expr, AST_SymbolRef)
|
|
2884
|
+
'end': prev()
|
|
2750
2885
|
}), True)
|
|
2751
2886
|
S.in_parenthesized_expr = False
|
|
2752
2887
|
return ret
|
|
2888
|
+
elif is_node_type(expr, AST_SymbolRef):
|
|
2889
|
+
tmp_ = expr.name
|
|
2890
|
+
if tmp_ is "jstype":
|
|
2891
|
+
ret = new AST_UnaryPrefix({
|
|
2892
|
+
'start': start,
|
|
2893
|
+
'operator': "typeof",
|
|
2894
|
+
'expression': func_call_list()[0],
|
|
2895
|
+
'end': prev()
|
|
2896
|
+
})
|
|
2897
|
+
S.in_parenthesized_expr = False
|
|
2898
|
+
return ret
|
|
2899
|
+
elif tmp_ is "isinstance":
|
|
2900
|
+
args = func_call_list()
|
|
2901
|
+
if args.length is not 2:
|
|
2902
|
+
croak('isinstance() must be called with exactly two arguments')
|
|
2903
|
+
ret = new AST_Binary({
|
|
2904
|
+
'start': start,
|
|
2905
|
+
'left': args[0],
|
|
2906
|
+
'operator': 'instanceof',
|
|
2907
|
+
'right': args[1],
|
|
2908
|
+
'end': prev()
|
|
2909
|
+
})
|
|
2910
|
+
S.in_parenthesized_expr = False
|
|
2911
|
+
return ret
|
|
2912
|
+
elif tmp_ is "super":
|
|
2913
|
+
# Find the innermost enclosing class name
|
|
2914
|
+
current_class = None
|
|
2915
|
+
for v'var i = S.in_class.length - 1; i >= 0; i--':
|
|
2916
|
+
if S.in_class[i]:
|
|
2917
|
+
current_class = S.in_class[i]
|
|
2918
|
+
break
|
|
2919
|
+
if not current_class:
|
|
2920
|
+
croak('super() is only valid inside a class method')
|
|
2921
|
+
super_args = func_call_list()
|
|
2922
|
+
parent_expr = None
|
|
2923
|
+
if super_args.length is 0:
|
|
2924
|
+
# 0-arg form: use parent of current class
|
|
2925
|
+
for v'var s = S.classes.length - 1; s >= 0; s--':
|
|
2926
|
+
if has_prop(S.classes[s], current_class):
|
|
2927
|
+
parent_expr = S.classes[s][current_class].parent
|
|
2928
|
+
break
|
|
2929
|
+
# parent_expr stays None for root classes; handled at method-call time
|
|
2930
|
+
# (super().__new__(cls) in a root class → ρσ_object_new(cls))
|
|
2931
|
+
elif super_args.length is 2:
|
|
2932
|
+
# 2-arg form: super(ClassName, self) — use parent of ClassName
|
|
2933
|
+
cls_ref = super_args[0]
|
|
2934
|
+
cls_info = get_class_in_scope(cls_ref)
|
|
2935
|
+
if not cls_info or not cls_info.parent:
|
|
2936
|
+
croak('First argument to super() must be a subclass with a parent')
|
|
2937
|
+
parent_expr = cls_info.parent
|
|
2938
|
+
else:
|
|
2939
|
+
croak('super() takes 0 or 2 arguments (' + super_args.length + ' given)')
|
|
2940
|
+
super_node = new AST_Super({
|
|
2941
|
+
'start': start,
|
|
2942
|
+
'parent': parent_expr,
|
|
2943
|
+
'class_name': current_class,
|
|
2944
|
+
'end': prev()
|
|
2945
|
+
})
|
|
2946
|
+
S.in_parenthesized_expr = False
|
|
2947
|
+
# Call subscripts to handle subsequent .method(args) chain
|
|
2948
|
+
return subscripts(super_node, True)
|
|
2949
|
+
# fall-through to basic function call
|
|
2950
|
+
ret = subscripts(new AST_Call({
|
|
2951
|
+
'start': start,
|
|
2952
|
+
'expression': expr,
|
|
2953
|
+
'args': func_call_list(),
|
|
2954
|
+
'end': prev(),
|
|
2955
|
+
'python_truthiness': S.scoped_flags.get('truthiness', False) and is_node_type(expr, AST_SymbolRef)
|
|
2956
|
+
}), True)
|
|
2957
|
+
S.in_parenthesized_expr = False
|
|
2958
|
+
return ret
|
|
2753
2959
|
|
|
2754
2960
|
def get_attr(expr, allow_calls):
|
|
2755
2961
|
next()
|
|
@@ -2816,6 +3022,11 @@ def create_parser_ctx(S, import_dirs, module_id, baselib_items, imported_module_
|
|
|
2816
3022
|
|
|
2817
3023
|
def maybe_unary(allow_calls):
|
|
2818
3024
|
start = S.token
|
|
3025
|
+
# JSX: detect <tag or <> in expression position
|
|
3026
|
+
if S.scoped_flags.get('jsx', False) and is_('operator', '<'):
|
|
3027
|
+
nxt = peek()
|
|
3028
|
+
if nxt.type is 'name' or (nxt.type is 'operator' and nxt.value is '>'):
|
|
3029
|
+
return subscripts(read_jsx_element(), allow_calls)
|
|
2819
3030
|
if is_('operator', '@'):
|
|
2820
3031
|
if S.parsing_decorator:
|
|
2821
3032
|
croak('Nested decorators are not allowed')
|
|
@@ -2843,6 +3054,162 @@ def create_parser_ctx(S, import_dirs, module_id, baselib_items, imported_module_
|
|
|
2843
3054
|
val = expr_atom(allow_calls)
|
|
2844
3055
|
return val
|
|
2845
3056
|
|
|
3057
|
+
# -----[ JSX parsing ]-----
|
|
3058
|
+
|
|
3059
|
+
def read_jsx_tag_name():
|
|
3060
|
+
# reads a tag name (identifier or dot-separated, e.g. "div", "MyComp", "Foo.Bar")
|
|
3061
|
+
if not is_('name'):
|
|
3062
|
+
croak('Expected JSX tag name')
|
|
3063
|
+
name = S.token.value
|
|
3064
|
+
next()
|
|
3065
|
+
while is_('punc', '.'):
|
|
3066
|
+
next() # consume .
|
|
3067
|
+
if not is_('name'):
|
|
3068
|
+
croak('Expected identifier after . in JSX tag name')
|
|
3069
|
+
name += '.' + S.token.value
|
|
3070
|
+
next()
|
|
3071
|
+
return name
|
|
3072
|
+
|
|
3073
|
+
def read_jsx_attr_name():
|
|
3074
|
+
# reads an attribute name; hyphens are allowed (e.g. aria-label, data-id)
|
|
3075
|
+
if not is_('name'):
|
|
3076
|
+
croak('Expected JSX attribute name')
|
|
3077
|
+
name = S.token.value
|
|
3078
|
+
next()
|
|
3079
|
+
while is_('operator', '-'):
|
|
3080
|
+
next() # consume -
|
|
3081
|
+
if not is_('name'):
|
|
3082
|
+
croak('Expected identifier after - in JSX attribute name')
|
|
3083
|
+
name += '-' + S.token.value
|
|
3084
|
+
next()
|
|
3085
|
+
return name
|
|
3086
|
+
|
|
3087
|
+
def read_jsx_attrs():
|
|
3088
|
+
# reads all attributes until > or /> is reached
|
|
3089
|
+
props = []
|
|
3090
|
+
while not is_('operator', '>') and not is_('operator', '/') and not is_('eof'):
|
|
3091
|
+
if is_('punc', '{'):
|
|
3092
|
+
# Spread attribute: {...expr}
|
|
3093
|
+
next() # consume {
|
|
3094
|
+
if not is_('atom', 'Ellipsis'):
|
|
3095
|
+
croak('Expected ... in JSX spread attribute')
|
|
3096
|
+
next() # consume ...
|
|
3097
|
+
expr = expression()
|
|
3098
|
+
expect('}')
|
|
3099
|
+
props.push(new AST_JSXSpread({'expression': expr, 'start': prev(), 'end': prev()}))
|
|
3100
|
+
elif is_('name'):
|
|
3101
|
+
attr_start = S.token
|
|
3102
|
+
name = read_jsx_attr_name()
|
|
3103
|
+
if is_('operator', '='):
|
|
3104
|
+
next() # consume =
|
|
3105
|
+
if is_('string'):
|
|
3106
|
+
val = new AST_String({'value': S.token.value, 'start': S.token, 'end': S.token, 'quote': S.token.quote})
|
|
3107
|
+
next()
|
|
3108
|
+
elif is_('punc', '{'):
|
|
3109
|
+
next() # consume {
|
|
3110
|
+
val = expression()
|
|
3111
|
+
expect('}')
|
|
3112
|
+
else:
|
|
3113
|
+
croak('Expected string or { in JSX attribute value')
|
|
3114
|
+
else:
|
|
3115
|
+
val = None # boolean attribute
|
|
3116
|
+
props.push(new AST_JSXAttribute({'name': name, 'value': val, 'start': attr_start, 'end': prev()}))
|
|
3117
|
+
else:
|
|
3118
|
+
unexpected()
|
|
3119
|
+
return props
|
|
3120
|
+
|
|
3121
|
+
def read_jsx_children_loop(close_tag):
|
|
3122
|
+
# S.token is already the first child token (jsx_text, OP(<), PUNC({))
|
|
3123
|
+
# JSX depth is currently >0 (entered before this call)
|
|
3124
|
+
children = []
|
|
3125
|
+
while True:
|
|
3126
|
+
if S.token.type is 'jsx_text':
|
|
3127
|
+
text = S.token.value
|
|
3128
|
+
children.push(new AST_JSXText({'value': text, 'start': S.token, 'end': S.token}))
|
|
3129
|
+
next() # still in JSX mode
|
|
3130
|
+
elif is_('operator', '<'):
|
|
3131
|
+
# Nested element or closing tag: exit JSX mode to tokenize tag content
|
|
3132
|
+
S.input.jsx_exit()
|
|
3133
|
+
next() # reads what follows < (/ or tag name)
|
|
3134
|
+
if is_('operator', '/'):
|
|
3135
|
+
# Closing tag
|
|
3136
|
+
next() # consume /
|
|
3137
|
+
if close_tag is None:
|
|
3138
|
+
# Fragment closing </> — next should be >
|
|
3139
|
+
if not is_('operator', '>'):
|
|
3140
|
+
croak('Expected > to close JSX fragment')
|
|
3141
|
+
return children # S.token = OP(>), don't consume
|
|
3142
|
+
else:
|
|
3143
|
+
if not is_('name'):
|
|
3144
|
+
croak('Expected closing tag name')
|
|
3145
|
+
if S.token.value is not close_tag:
|
|
3146
|
+
croak('JSX closing tag mismatch: expected </' + close_tag + '>, got </' + S.token.value + '>')
|
|
3147
|
+
next() # consume tag name
|
|
3148
|
+
if not is_('operator', '>'):
|
|
3149
|
+
croak('Expected > in closing JSX tag')
|
|
3150
|
+
return children # S.token = OP(>), don't consume
|
|
3151
|
+
else:
|
|
3152
|
+
# Nested element: S.token is first token of tag (or > for fragment)
|
|
3153
|
+
child = read_jsx_element_inner()
|
|
3154
|
+
children.push(child)
|
|
3155
|
+
# S.token = OP(>) — child's closing >, re-enter JSX mode then consume
|
|
3156
|
+
S.input.jsx_enter()
|
|
3157
|
+
next() # consume child's >, read next sibling in JSX mode
|
|
3158
|
+
elif is_('punc', '{'):
|
|
3159
|
+
# Expression container
|
|
3160
|
+
S.input.jsx_exit()
|
|
3161
|
+
next() # consume {
|
|
3162
|
+
expr = expression()
|
|
3163
|
+
if not is_('punc', '}'):
|
|
3164
|
+
croak('Expected } to close JSX expression')
|
|
3165
|
+
# Re-enter JSX mode BEFORE consuming } so next sibling reads in JSX mode
|
|
3166
|
+
S.input.jsx_enter()
|
|
3167
|
+
next() # consume }, read next sibling in JSX mode
|
|
3168
|
+
children.push(new AST_JSXExprContainer({'expression': expr, 'start': prev(), 'end': prev()}))
|
|
3169
|
+
elif is_('eof'):
|
|
3170
|
+
croak('Unterminated JSX element')
|
|
3171
|
+
else:
|
|
3172
|
+
unexpected()
|
|
3173
|
+
|
|
3174
|
+
def read_jsx_element_inner():
|
|
3175
|
+
# Called when S.token is NAME(tag) or OP(>) for fragment
|
|
3176
|
+
# NOT in JSX mode when entering
|
|
3177
|
+
start = S.prev # the < token (already consumed)
|
|
3178
|
+
if is_('operator', '>'):
|
|
3179
|
+
# Fragment: <>...</>
|
|
3180
|
+
S.input.jsx_enter()
|
|
3181
|
+
next() # consume >, first child in JSX mode
|
|
3182
|
+
children = read_jsx_children_loop(None)
|
|
3183
|
+
# S.token = OP(>) — closing >
|
|
3184
|
+
return new AST_JSXFragment({'start': start, 'children': children, 'end': S.token})
|
|
3185
|
+
else:
|
|
3186
|
+
tag = read_jsx_tag_name()
|
|
3187
|
+
props = read_jsx_attrs()
|
|
3188
|
+
if is_('operator', '/'):
|
|
3189
|
+
next() # consume /
|
|
3190
|
+
# S.token = OP(>) — self-closing
|
|
3191
|
+
return new AST_JSXElement({'start': start, 'tag': tag, 'props': props, 'children': [], 'self_closing': True, 'end': S.token})
|
|
3192
|
+
else:
|
|
3193
|
+
if not is_('operator', '>'):
|
|
3194
|
+
croak('Expected > or /> in JSX element')
|
|
3195
|
+
S.input.jsx_enter()
|
|
3196
|
+
next() # consume >, first child in JSX mode
|
|
3197
|
+
children = read_jsx_children_loop(tag)
|
|
3198
|
+
# S.token = OP(>) — closing >
|
|
3199
|
+
return new AST_JSXElement({'start': start, 'tag': tag, 'props': props, 'children': children, 'self_closing': False, 'end': S.token})
|
|
3200
|
+
|
|
3201
|
+
def read_jsx_element():
|
|
3202
|
+
# S.token = OP(<) — the opening <
|
|
3203
|
+
start = S.token
|
|
3204
|
+
next() # consume <, reads tag name or > for fragment (normal mode)
|
|
3205
|
+
el = read_jsx_element_inner()
|
|
3206
|
+
# S.token = OP(>) — closing >, consume it and return to normal mode
|
|
3207
|
+
next()
|
|
3208
|
+
el.end = prev()
|
|
3209
|
+
return el
|
|
3210
|
+
|
|
3211
|
+
# -----[ end JSX parsing ]-----
|
|
3212
|
+
|
|
2846
3213
|
def make_unary(ctor, op, expr, is_parenthesized):
|
|
2847
3214
|
return new ctor({
|
|
2848
3215
|
'operator': op,
|
|
@@ -2874,6 +3241,7 @@ def create_parser_ctx(S, import_dirs, module_id, baselib_items, imported_module_
|
|
|
2874
3241
|
'right': right,
|
|
2875
3242
|
'end': right.end,
|
|
2876
3243
|
'overloaded': S.scoped_flags.get('overload_operators', False),
|
|
3244
|
+
'strict_arith': S.scoped_flags.get('overload_operators', False) and S.scoped_flags.get('strict_arithmetic', True),
|
|
2877
3245
|
'python_truthiness': S.scoped_flags.get('truthiness', False) and (op is '&&' or op is '||')
|
|
2878
3246
|
})
|
|
2879
3247
|
return expr_op(ret, min_prec, no_in)
|
|
@@ -2955,6 +3323,7 @@ def create_parser_ctx(S, import_dirs, module_id, baselib_items, imported_module_
|
|
|
2955
3323
|
})
|
|
2956
3324
|
if S.scoped_flags.get('overload_operators', False) and val is not '=':
|
|
2957
3325
|
asgn.overloaded = True
|
|
3326
|
+
asgn.strict_arith = S.scoped_flags.get('strict_arithmetic', True)
|
|
2958
3327
|
return asgn
|
|
2959
3328
|
return left
|
|
2960
3329
|
|
|
@@ -3168,9 +3537,8 @@ def parse(text, options):
|
|
|
3168
3537
|
'get': def (name, defval):
|
|
3169
3538
|
for v'var i = this.stack.length - 1; i >= 0; i--':
|
|
3170
3539
|
d = this.stack[i]
|
|
3171
|
-
|
|
3172
|
-
|
|
3173
|
-
return q
|
|
3540
|
+
if has_prop(d, name):
|
|
3541
|
+
return d[name]
|
|
3174
3542
|
return defval
|
|
3175
3543
|
,
|
|
3176
3544
|
'set': def (name, val): this.stack[-1][name] = val;,
|