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
|
@@ -22,19 +22,33 @@ const MESSAGES = {
|
|
|
22
22
|
'dup-method': 'The method "{name}" was defined previously at line: {line}',
|
|
23
23
|
};
|
|
24
24
|
|
|
25
|
+
// Built-in stdlib modules that are always available in RapydScript (bundled
|
|
26
|
+
// with the compiler from src/lib/). These should never produce 'Unknown module'
|
|
27
|
+
// errors regardless of what virtualFiles or stdlibFiles are configured.
|
|
28
|
+
export const STDLIB_MODULES = [
|
|
29
|
+
'abc', 'aes', 'collections', 'copy', 'dataclasses', 'elementmaker', 'encodings', 'enum',
|
|
30
|
+
'functools', 'gettext', 'itertools', 'math', 'numpy', 'operator',
|
|
31
|
+
'pythonize', 'random', 're', 'react', 'traceback', 'typing', 'uuid',
|
|
32
|
+
// Pseudo-modules for language feature flags (from __python__ import ...)
|
|
33
|
+
'__python__', '__builtins__',
|
|
34
|
+
];
|
|
35
|
+
|
|
36
|
+
const _STDLIB_MODULE_SET = Object.create(null);
|
|
37
|
+
STDLIB_MODULES.forEach(m => { _STDLIB_MODULE_SET[m] = true; });
|
|
38
|
+
|
|
25
39
|
// Symbols always available in RapydScript (from tools/lint.js BUILTINS list).
|
|
26
40
|
export const BASE_BUILTINS = (
|
|
27
41
|
'this self window document chr ord iterator_symbol print len range dir' +
|
|
28
|
-
' eval undefined arguments abs max min enumerate pow callable reversed sum' +
|
|
42
|
+
' eval exec undefined arguments abs max min enumerate pow callable reversed sum' +
|
|
29
43
|
' getattr isFinite setattr hasattr parseInt parseFloat options_object' +
|
|
30
44
|
' isNaN JSON Math list set list_wrap ρσ_modules require bool int bin' +
|
|
31
|
-
' float iter Error EvalError set_wrap frozenset RangeError ReferenceError SyntaxError' +
|
|
45
|
+
' float complex iter Error EvalError set_wrap frozenset RangeError ReferenceError SyntaxError' +
|
|
32
46
|
' str TypeError URIError Exception AssertionError IndexError AttributeError KeyError' +
|
|
33
|
-
' ValueError ZeroDivisionError map hex filter zip dict dict_wrap UnicodeDecodeError HTMLCollection' +
|
|
47
|
+
' ValueError ZeroDivisionError ImportError ModuleNotFoundError StopIteration map hex filter zip dict dict_wrap UnicodeDecodeError HTMLCollection' +
|
|
34
48
|
' NodeList alert console Node Symbol NamedNodeMap ρσ_eslice ρσ_delslice Number' +
|
|
35
49
|
' Boolean encodeURIComponent decodeURIComponent setTimeout setInterval' +
|
|
36
50
|
' setImmediate clearTimeout clearInterval clearImmediate requestAnimationFrame' +
|
|
37
|
-
' id repr sorted __name__ equals get_module ρσ_str jstype divmod NaN super Ellipsis slice'
|
|
51
|
+
' id repr sorted __name__ equals get_module ρσ_str jstype divmod NaN super Ellipsis slice all any next __import__ ρσ_new ρσ_object_new hash ρσ_object_setattr ρσ_object_getattr ρσ_object_delattr ExceptionGroup BaseExceptionGroup tuple bytes bytearray format object vars locals globals'
|
|
38
52
|
).split(' ');
|
|
39
53
|
|
|
40
54
|
// ---------------------------------------------------------------------------
|
|
@@ -384,7 +398,13 @@ function Linter(RS, toplevel, code, builtins, knownModules) {
|
|
|
384
398
|
};
|
|
385
399
|
|
|
386
400
|
this.handle_symbol_funarg = function() {
|
|
387
|
-
this.
|
|
401
|
+
const node = this.current_node;
|
|
402
|
+
this.add_binding(node.name);
|
|
403
|
+
// Suppress undefined-symbol errors for type names used in argument
|
|
404
|
+
// annotations: `def foo(x: MyType):` — MyType is a hint, not a ref.
|
|
405
|
+
if (node.annotation instanceof RS.AST_SymbolRef) {
|
|
406
|
+
node.annotation.lint_visited = true;
|
|
407
|
+
}
|
|
388
408
|
};
|
|
389
409
|
|
|
390
410
|
this.handle_comprehension = function() {
|
|
@@ -403,24 +423,23 @@ function Linter(RS, toplevel, code, builtins, knownModules) {
|
|
|
403
423
|
|
|
404
424
|
this.handle_for_in = function() {
|
|
405
425
|
const node = this.current_node;
|
|
426
|
+
const add_loop_var = (cnode) => {
|
|
427
|
+
if (cnode instanceof RS.AST_Seq) {
|
|
428
|
+
cnode.to_array().forEach(add_loop_var);
|
|
429
|
+
} else if (cnode instanceof RS.AST_Array) {
|
|
430
|
+
cnode.elements.forEach(add_loop_var);
|
|
431
|
+
} else if (cnode instanceof RS.AST_SymbolRef) {
|
|
432
|
+
this.current_node = cnode;
|
|
433
|
+
cnode.lint_visited = true;
|
|
434
|
+
this.add_binding(cnode.name).is_loop = true;
|
|
435
|
+
this.current_node = node;
|
|
436
|
+
}
|
|
437
|
+
};
|
|
406
438
|
if (node.init instanceof RS.AST_SymbolRef) {
|
|
407
439
|
this.add_binding(node.init.name).is_loop = true;
|
|
408
440
|
node.init.lint_visited = true;
|
|
409
441
|
} else if (node.init instanceof RS.AST_Array) {
|
|
410
|
-
node.init.elements.forEach(
|
|
411
|
-
if (cnode instanceof RS.AST_Seq) cnode = cnode.to_array();
|
|
412
|
-
if (cnode instanceof RS.AST_SymbolRef) cnode = [cnode];
|
|
413
|
-
if (Array.isArray(cnode)) {
|
|
414
|
-
cnode.forEach(elem => {
|
|
415
|
-
if (elem instanceof RS.AST_SymbolRef) {
|
|
416
|
-
this.current_node = elem;
|
|
417
|
-
elem.lint_visited = true;
|
|
418
|
-
this.add_binding(elem.name).is_loop = true;
|
|
419
|
-
this.current_node = node;
|
|
420
|
-
}
|
|
421
|
-
});
|
|
422
|
-
}
|
|
423
|
-
});
|
|
442
|
+
node.init.elements.forEach(add_loop_var);
|
|
424
443
|
}
|
|
425
444
|
};
|
|
426
445
|
|
|
@@ -681,6 +700,8 @@ export class Diagnostics {
|
|
|
681
700
|
const sf = options.stdlibFiles;
|
|
682
701
|
if ((vf && Object.keys(vf).length > 0) || (sf && Object.keys(sf).length > 0)) {
|
|
683
702
|
knownModules = Object.create(null);
|
|
703
|
+
// Always include built-in stdlib so they never produce bad-import errors.
|
|
704
|
+
Object.assign(knownModules, _STDLIB_MODULE_SET);
|
|
684
705
|
if (vf) Object.keys(vf).forEach(k => { knownModules[k] = true; });
|
|
685
706
|
if (sf) Object.keys(sf).forEach(k => { knownModules[k] = true; });
|
|
686
707
|
}
|
package/src/output/classes.pyj
CHANGED
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
# License: BSD Copyright: 2016, Kovid Goyal <kovid at kovidgoyal.net>
|
|
3
3
|
from __python__ import hash_literals
|
|
4
4
|
|
|
5
|
-
from ast import AST_Class, AST_Method, is_node_type
|
|
5
|
+
from ast import AST_Class, AST_Method, AST_AnnotatedAssign, AST_SymbolRef, is_node_type
|
|
6
6
|
from output.functions import decorate, function_definition, function_annotation
|
|
7
7
|
from output.utils import create_doctring
|
|
8
8
|
from utils import has_prop
|
|
@@ -82,19 +82,75 @@ def print_class(output):
|
|
|
82
82
|
output.with_block(def():
|
|
83
83
|
output.indent()
|
|
84
84
|
cname = self.name.name
|
|
85
|
-
|
|
86
|
-
|
|
85
|
+
if self.has_new:
|
|
86
|
+
# When __new__ is defined, call it to get the instance
|
|
87
|
+
output.print('if (!(this instanceof ' + cname + '))')
|
|
88
|
+
output.space()
|
|
89
|
+
output.with_block(def():
|
|
90
|
+
output.indent()
|
|
91
|
+
output.print('var ρσ_instance = ')
|
|
92
|
+
self.name.print(output)
|
|
93
|
+
output.print('.__new__(')
|
|
94
|
+
self.name.print(output)
|
|
95
|
+
output.print(', ...arguments)')
|
|
96
|
+
output.end_statement()
|
|
97
|
+
output.indent()
|
|
98
|
+
output.print('if (ρσ_instance instanceof ')
|
|
99
|
+
self.name.print(output)
|
|
100
|
+
output.print(')')
|
|
101
|
+
output.space()
|
|
102
|
+
output.with_block(def():
|
|
103
|
+
output.indent()
|
|
104
|
+
output.spaced('if', '(ρσ_instance.ρσ_object_id', '===', 'undefined)', 'Object.defineProperty(ρσ_instance,', '"ρσ_object_id",', '{"value":++ρσ_object_counter})')
|
|
105
|
+
output.end_statement()
|
|
106
|
+
if self.bound.length:
|
|
107
|
+
output.indent()
|
|
108
|
+
self.name.print(output), output.print('.prototype.__bind_methods__ && ')
|
|
109
|
+
self.name.print(output), output.print('.prototype.__bind_methods__.call(ρσ_instance)')
|
|
110
|
+
output.end_statement()
|
|
111
|
+
output.indent()
|
|
112
|
+
self.name.print(output)
|
|
113
|
+
output.print('.prototype.__init__.apply(ρσ_instance'), output.comma(), output.print('arguments)')
|
|
114
|
+
output.end_statement()
|
|
115
|
+
)
|
|
116
|
+
output.newline()
|
|
117
|
+
output.indent()
|
|
118
|
+
output.print('return ρσ_instance')
|
|
119
|
+
output.end_statement()
|
|
120
|
+
)
|
|
121
|
+
output.newline()
|
|
122
|
+
else:
|
|
123
|
+
output.print('if (!(this instanceof ' + cname + ')) return new ' + cname + '(...arguments);')
|
|
124
|
+
output.newline()
|
|
87
125
|
output.indent()
|
|
88
126
|
output.spaced('if', '(this.ρσ_object_id', '===', 'undefined)', 'Object.defineProperty(this,', '"ρσ_object_id",', '{"value":++ρσ_object_counter})')
|
|
89
127
|
output.end_statement()
|
|
90
|
-
if self.
|
|
128
|
+
if self.has_attr_dunders:
|
|
129
|
+
# Wrap in a Proxy so __getattr__/__setattr__/__delattr__/__getattribute__ are triggered.
|
|
91
130
|
output.indent()
|
|
92
|
-
|
|
131
|
+
output.print('var ρσ_proxy = ρσ_JS_Proxy ? new ρσ_JS_Proxy(this, ρσ_attr_proxy_handler) : this')
|
|
132
|
+
output.end_statement()
|
|
133
|
+
if self.bound.length:
|
|
134
|
+
output.indent()
|
|
135
|
+
self.name.print(output), output.print(".prototype.__bind_methods__ && ")
|
|
136
|
+
self.name.print(output), output.print(".prototype.__bind_methods__.call(ρσ_proxy)")
|
|
137
|
+
output.end_statement()
|
|
138
|
+
output.indent()
|
|
139
|
+
self.name.print(output)
|
|
140
|
+
output.print(".prototype.__init__.apply(ρσ_proxy"), output.comma(), output.print('arguments)')
|
|
141
|
+
output.end_statement()
|
|
142
|
+
output.indent()
|
|
143
|
+
output.print('return ρσ_proxy')
|
|
144
|
+
output.end_statement()
|
|
145
|
+
else:
|
|
146
|
+
if self.bound.length:
|
|
147
|
+
output.indent()
|
|
148
|
+
self.name.print(output), output.print(".prototype.__bind_methods__.call(this)")
|
|
149
|
+
output.end_statement()
|
|
150
|
+
output.indent()
|
|
151
|
+
self.name.print(output)
|
|
152
|
+
output.print(".prototype.__init__.apply(this"), output.comma(), output.print('arguments)')
|
|
93
153
|
output.end_statement()
|
|
94
|
-
output.indent()
|
|
95
|
-
self.name.print(output)
|
|
96
|
-
output.print(".prototype.__init__.apply(this"), output.comma(), output.print('arguments)')
|
|
97
|
-
output.end_statement()
|
|
98
154
|
)
|
|
99
155
|
|
|
100
156
|
decorators = self.decorators or v'[]'
|
|
@@ -235,6 +291,24 @@ def print_class(output):
|
|
|
235
291
|
output.end_statement()
|
|
236
292
|
)
|
|
237
293
|
|
|
294
|
+
if not defined_methods['__format__']:
|
|
295
|
+
define_default_method('__format__', def():
|
|
296
|
+
if self.parent:
|
|
297
|
+
output.print('if('), self.parent.print(output), output.spaced('.prototype.__format__)', 'return', self.parent)
|
|
298
|
+
output.print('.prototype.__format__.call(this, arguments[0])'), output.end_statement()
|
|
299
|
+
output.indent(), output.spaced('if', '(!arguments[0])', 'return', 'this.__str__()')
|
|
300
|
+
output.end_statement()
|
|
301
|
+
output.indent(), output.spaced('throw', 'new TypeError("unsupported format specification")')
|
|
302
|
+
output.end_statement()
|
|
303
|
+
)
|
|
304
|
+
|
|
305
|
+
# Python semantics: defining __eq__ without __hash__ makes the class unhashable
|
|
306
|
+
if defined_methods['__eq__'] and not defined_methods['__hash__']:
|
|
307
|
+
output.indent()
|
|
308
|
+
self.name.print(output)
|
|
309
|
+
output.print('.prototype.__hash__ = null')
|
|
310
|
+
output.end_statement()
|
|
311
|
+
|
|
238
312
|
# Multiple inheritance
|
|
239
313
|
add_hidden_property('__bases__', def():
|
|
240
314
|
output.print('[')
|
|
@@ -256,22 +330,10 @@ def print_class(output):
|
|
|
256
330
|
output.print('.prototype, "__class__", {get: function() { return this.constructor; }, configurable: true})')
|
|
257
331
|
output.end_statement()
|
|
258
332
|
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
for v'var i = 1; i < self.bases.length; i++':
|
|
264
|
-
output.comma()
|
|
265
|
-
self.bases[i].print(output)
|
|
266
|
-
output.print(')'), output.end_statement()
|
|
267
|
-
|
|
268
|
-
# Docstring
|
|
269
|
-
if self.docstrings and self.docstrings.length and output.options.keep_docstrings:
|
|
270
|
-
add_hidden_property('__doc__', def():
|
|
271
|
-
output.print(JSON.stringify(create_doctring(self.docstrings)))
|
|
272
|
-
)
|
|
273
|
-
|
|
274
|
-
# Other statements in the class context (including nested class definitions)
|
|
333
|
+
# Other statements in the class context (including nested class definitions).
|
|
334
|
+
# Emitted BEFORE __init_subclass__ so that the hook can see class variables.
|
|
335
|
+
# This matches Python's behaviour: the class body executes first, then the
|
|
336
|
+
# hook is called with the fully-populated class namespace.
|
|
275
337
|
for stmt in self.statements:
|
|
276
338
|
if is_node_type(stmt, AST_Class):
|
|
277
339
|
# Print the nested class in full, then attach it to the outer class.
|
|
@@ -295,6 +357,80 @@ def print_class(output):
|
|
|
295
357
|
stmt.print(output)
|
|
296
358
|
output.newline()
|
|
297
359
|
|
|
360
|
+
# Emit __annotations__ for annotated class variables so that @dataclass and
|
|
361
|
+
# similar decorators can introspect field names and their declaration order.
|
|
362
|
+
# Only annotation-with-value statements (x: T = v) AND annotation-only
|
|
363
|
+
# statements (x: T) are collected; the value (if any) is already emitted
|
|
364
|
+
# above as a prototype assignment. We store null as the type since type
|
|
365
|
+
# information is erased in the JS output.
|
|
366
|
+
annotated_field_names = []
|
|
367
|
+
for stmt in self.statements:
|
|
368
|
+
if is_node_type(stmt, AST_AnnotatedAssign) and is_node_type(stmt.target, AST_SymbolRef):
|
|
369
|
+
annotated_field_names.push(stmt.target.name)
|
|
370
|
+
if annotated_field_names.length:
|
|
371
|
+
output.indent()
|
|
372
|
+
self.name.print(output)
|
|
373
|
+
output.print('.__annotations__ = {')
|
|
374
|
+
for i in range(annotated_field_names.length):
|
|
375
|
+
if i > 0:
|
|
376
|
+
output.comma()
|
|
377
|
+
output.print(JSON.stringify(annotated_field_names[i]) + ': null')
|
|
378
|
+
output.print('}')
|
|
379
|
+
output.end_statement()
|
|
380
|
+
|
|
381
|
+
# __init_subclass__ hook: call after identity properties and class variables
|
|
382
|
+
# so cls.__name__ is correct and cls.prototype reflects the full class body.
|
|
383
|
+
if self.parent:
|
|
384
|
+
output.indent()
|
|
385
|
+
output.print('if (typeof ')
|
|
386
|
+
self.parent.print(output)
|
|
387
|
+
output.print('.__init_subclass__ === "function")')
|
|
388
|
+
output.space()
|
|
389
|
+
kws = self.class_kwargs
|
|
390
|
+
if kws and kws.length:
|
|
391
|
+
output.with_block(def():
|
|
392
|
+
output.indent()
|
|
393
|
+
output.print('var ρσ_isc_kw = {')
|
|
394
|
+
for v'var ρσ_kwi = 0; ρσ_kwi < kws.length; ρσ_kwi++':
|
|
395
|
+
if ρσ_kwi > 0:
|
|
396
|
+
output.comma()
|
|
397
|
+
output.print(kws[ρσ_kwi][0].name + ':')
|
|
398
|
+
output.space()
|
|
399
|
+
kws[ρσ_kwi][1].print(output)
|
|
400
|
+
output.print('}')
|
|
401
|
+
output.end_statement()
|
|
402
|
+
output.indent()
|
|
403
|
+
output.print('ρσ_isc_kw[ρσ_kwargs_symbol] = true')
|
|
404
|
+
output.end_statement()
|
|
405
|
+
output.indent()
|
|
406
|
+
self.parent.print(output)
|
|
407
|
+
output.print('.__init_subclass__.call(')
|
|
408
|
+
self.name.print(output)
|
|
409
|
+
output.print(', ρσ_isc_kw)')
|
|
410
|
+
output.end_statement()
|
|
411
|
+
)
|
|
412
|
+
else:
|
|
413
|
+
self.parent.print(output)
|
|
414
|
+
output.print('.__init_subclass__.call(')
|
|
415
|
+
self.name.print(output)
|
|
416
|
+
output.print(')')
|
|
417
|
+
output.end_statement()
|
|
418
|
+
|
|
419
|
+
if self.bases.length > 1:
|
|
420
|
+
output.indent()
|
|
421
|
+
output.print("ρσ_mixin(")
|
|
422
|
+
self.name.print(output)
|
|
423
|
+
for v'var i = 1; i < self.bases.length; i++':
|
|
424
|
+
output.comma()
|
|
425
|
+
self.bases[i].print(output)
|
|
426
|
+
output.print(')'), output.end_statement()
|
|
427
|
+
|
|
428
|
+
# Docstring
|
|
429
|
+
if self.docstrings and self.docstrings.length and output.options.keep_docstrings:
|
|
430
|
+
add_hidden_property('__doc__', def():
|
|
431
|
+
output.print(JSON.stringify(create_doctring(self.docstrings)))
|
|
432
|
+
)
|
|
433
|
+
|
|
298
434
|
if decorators.length:
|
|
299
435
|
output.indent()
|
|
300
436
|
output.assign(self.name)
|
package/src/output/codegen.pyj
CHANGED
|
@@ -13,13 +13,14 @@ from ast import (
|
|
|
13
13
|
AST_EmptyStatement, AST_Exit, AST_ExpressiveObject, AST_ForIn,
|
|
14
14
|
AST_ForJS, AST_Function, AST_Hole, AST_If, AST_Imports, AST_Infinity,
|
|
15
15
|
AST_Lambda, AST_ListComprehension, AST_LoopControl, AST_NaN, AST_NamedExpr, AST_New, AST_Node,
|
|
16
|
-
AST_Number, AST_Object, AST_ObjectKeyVal, AST_ObjectProperty, AST_ObjectSpread, AST_PropAccess,
|
|
16
|
+
AST_Number, AST_Object, AST_ObjectKeyVal, AST_ObjectProperty, AST_ObjectSpread, AST_Spread, AST_PropAccess,
|
|
17
17
|
AST_RegExp, AST_Return, AST_Set, AST_Seq, AST_SimpleStatement, AST_Splice,
|
|
18
18
|
AST_Statement, AST_StatementWithBody, AST_String, AST_Sub, AST_ItemAccess,
|
|
19
19
|
AST_Symbol, AST_This, AST_Throw, AST_Toplevel, AST_Try, AST_Unary,
|
|
20
20
|
AST_UnaryPrefix, AST_Undefined, AST_Var, AST_VarDef, AST_Assert,
|
|
21
21
|
AST_Verbatim, AST_While, AST_With, AST_Yield, AST_Await, TreeWalker, AST_Existential,
|
|
22
|
-
AST_Match, AST_AnnotatedAssign, AST_Super
|
|
22
|
+
AST_Match, AST_AnnotatedAssign, AST_Super,
|
|
23
|
+
AST_JSXElement, AST_JSXFragment, AST_JSXAttribute, AST_JSXSpread, AST_JSXText, AST_JSXExprContainer
|
|
23
24
|
)
|
|
24
25
|
from output.exceptions import print_try
|
|
25
26
|
from output.classes import print_class
|
|
@@ -34,6 +35,7 @@ from output.operators import (
|
|
|
34
35
|
)
|
|
35
36
|
from output.functions import print_function, print_function_call
|
|
36
37
|
from output.statements import print_bracketed, first_in_statement, force_statement, print_with, print_assert, print_match, print_annotated_assign
|
|
38
|
+
from output.jsx import print_jsx_element, print_jsx_fragment, print_jsx_attribute, print_jsx_spread, print_jsx_text, print_jsx_expr_container
|
|
37
39
|
from output.utils import make_block, make_num
|
|
38
40
|
|
|
39
41
|
# -----[ code generators ]-----
|
|
@@ -486,6 +488,10 @@ def generate_code():
|
|
|
486
488
|
output.print('**')
|
|
487
489
|
self.value.print(output)
|
|
488
490
|
)
|
|
491
|
+
DEFPRINT(AST_Spread, def(self, output):
|
|
492
|
+
output.print('...')
|
|
493
|
+
self.expression.print(output)
|
|
494
|
+
)
|
|
489
495
|
DEFPRINT(AST_Set, print_set)
|
|
490
496
|
|
|
491
497
|
AST_Symbol.prototype.definition = def():
|
|
@@ -525,3 +531,11 @@ def generate_code():
|
|
|
525
531
|
output.print(make_num(self.value))
|
|
526
532
|
)
|
|
527
533
|
DEFPRINT(AST_RegExp, print_regexp)
|
|
534
|
+
|
|
535
|
+
# -----[ JSX ]-----
|
|
536
|
+
DEFPRINT(AST_JSXElement, print_jsx_element)
|
|
537
|
+
DEFPRINT(AST_JSXFragment, print_jsx_fragment)
|
|
538
|
+
DEFPRINT(AST_JSXAttribute, print_jsx_attribute)
|
|
539
|
+
DEFPRINT(AST_JSXSpread, print_jsx_spread)
|
|
540
|
+
DEFPRINT(AST_JSXText, print_jsx_text)
|
|
541
|
+
DEFPRINT(AST_JSXExprContainer, print_jsx_expr_container)
|
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
# License: BSD Copyright: 2016, Kovid Goyal <kovid at kovidgoyal.net>
|
|
3
3
|
from __python__ import hash_literals
|
|
4
4
|
|
|
5
|
-
from output.statements import print_bracketed
|
|
5
|
+
from output.statements import print_bracketed, display_body
|
|
6
6
|
|
|
7
7
|
|
|
8
8
|
def print_try(self, output):
|
|
@@ -28,6 +28,10 @@ def print_try(self, output):
|
|
|
28
28
|
|
|
29
29
|
|
|
30
30
|
def print_catch(self, output):
|
|
31
|
+
# Dispatch to except* handler when any clause is an exception group handler
|
|
32
|
+
if self.body.length and self.body[0].is_star:
|
|
33
|
+
print_catch_star(self, output)
|
|
34
|
+
return
|
|
31
35
|
output.print("catch")
|
|
32
36
|
output.space()
|
|
33
37
|
output.with_parens(def():
|
|
@@ -83,6 +87,98 @@ def print_catch(self, output):
|
|
|
83
87
|
)
|
|
84
88
|
|
|
85
89
|
|
|
90
|
+
def _eg_type_cond(errors, varname):
|
|
91
|
+
# Build a JS condition string testing varname against each error type
|
|
92
|
+
parts = []
|
|
93
|
+
for err in errors:
|
|
94
|
+
if err.name is 'Exception':
|
|
95
|
+
parts.push(varname + " instanceof Error")
|
|
96
|
+
else:
|
|
97
|
+
parts.push(varname + " instanceof " + err.name)
|
|
98
|
+
return parts.join(" || ")
|
|
99
|
+
|
|
100
|
+
|
|
101
|
+
def print_catch_star(self, output):
|
|
102
|
+
output.print("catch")
|
|
103
|
+
output.space()
|
|
104
|
+
output.with_parens(def():
|
|
105
|
+
output.print("ρσ_Exception")
|
|
106
|
+
)
|
|
107
|
+
output.space()
|
|
108
|
+
output.with_block(def():
|
|
109
|
+
output.indent()
|
|
110
|
+
output.spaced('ρσ_last_exception', '=', 'ρσ_Exception'), output.end_statement()
|
|
111
|
+
|
|
112
|
+
# Normalise: wrap non-ExceptionGroup exception into a one-element array
|
|
113
|
+
output.indent()
|
|
114
|
+
output.print("var ρσ_eg_exceptions = (ρσ_Exception instanceof ExceptionGroup) ? ρσ_Exception.exceptions.slice() : [ρσ_Exception]")
|
|
115
|
+
output.semicolon(), output.newline()
|
|
116
|
+
output.indent()
|
|
117
|
+
output.print("var ρσ_eg_raised = []")
|
|
118
|
+
output.semicolon(), output.newline()
|
|
119
|
+
|
|
120
|
+
for ei, exception in enumerate(self.body):
|
|
121
|
+
idx = str(ei)
|
|
122
|
+
if exception.errors.length:
|
|
123
|
+
cond = _eg_type_cond(exception.errors, "ρσ_et")
|
|
124
|
+
output.indent()
|
|
125
|
+
output.print("var ρσ_eg_matched_" + idx + " = ρσ_eg_exceptions.filter(function(ρσ_et) { return " + cond + "; })")
|
|
126
|
+
output.semicolon(), output.newline()
|
|
127
|
+
output.indent()
|
|
128
|
+
output.print("ρσ_eg_exceptions = ρσ_eg_exceptions.filter(function(ρσ_et) { return !(" + cond + "); })")
|
|
129
|
+
output.semicolon(), output.newline()
|
|
130
|
+
else:
|
|
131
|
+
# Bare except*: take all remaining
|
|
132
|
+
output.indent()
|
|
133
|
+
output.print("var ρσ_eg_matched_" + idx + " = ρσ_eg_exceptions.slice()")
|
|
134
|
+
output.semicolon(), output.newline()
|
|
135
|
+
output.indent()
|
|
136
|
+
output.print("ρσ_eg_exceptions = []")
|
|
137
|
+
output.semicolon(), output.newline()
|
|
138
|
+
|
|
139
|
+
output.indent()
|
|
140
|
+
output.print("if (ρσ_eg_matched_" + idx + ".length > 0)")
|
|
141
|
+
output.space()
|
|
142
|
+
output.with_block(def():
|
|
143
|
+
if exception.argname:
|
|
144
|
+
output.indent()
|
|
145
|
+
output.print("var ")
|
|
146
|
+
output.assign(exception.argname)
|
|
147
|
+
output.print("(ρσ_Exception instanceof ExceptionGroup) ? new ExceptionGroup(ρσ_Exception.message, ρσ_eg_matched_" + idx + ") : ρσ_eg_matched_" + idx + "[0]")
|
|
148
|
+
output.semicolon(), output.newline()
|
|
149
|
+
output.indent()
|
|
150
|
+
output.print("try")
|
|
151
|
+
output.space()
|
|
152
|
+
output.with_block(def():
|
|
153
|
+
display_body(exception.body, False, output)
|
|
154
|
+
)
|
|
155
|
+
output.print(" catch (ρσ_eg_exc_" + idx + ")")
|
|
156
|
+
output.space()
|
|
157
|
+
output.with_block(def():
|
|
158
|
+
output.indent()
|
|
159
|
+
output.print("ρσ_eg_raised.push(ρσ_eg_exc_" + idx + ")")
|
|
160
|
+
output.semicolon(), output.newline()
|
|
161
|
+
)
|
|
162
|
+
output.newline()
|
|
163
|
+
)
|
|
164
|
+
output.newline()
|
|
165
|
+
|
|
166
|
+
# Re-raise unmatched exceptions and any raised by handlers
|
|
167
|
+
output.indent()
|
|
168
|
+
output.print("var ρσ_eg_unhandled = ρσ_eg_exceptions.concat(ρσ_eg_raised)")
|
|
169
|
+
output.semicolon(), output.newline()
|
|
170
|
+
output.indent()
|
|
171
|
+
output.print("if (ρσ_eg_unhandled.length > 0)")
|
|
172
|
+
output.space()
|
|
173
|
+
output.with_block(def():
|
|
174
|
+
output.indent()
|
|
175
|
+
output.print("throw (ρσ_eg_unhandled.length === 1 && !(ρσ_Exception instanceof ExceptionGroup)) ? ρσ_eg_unhandled[0] : new ExceptionGroup((ρσ_Exception instanceof ExceptionGroup) ? ρσ_Exception.message : \"unhandled exceptions\", ρσ_eg_unhandled)")
|
|
176
|
+
output.semicolon(), output.newline()
|
|
177
|
+
)
|
|
178
|
+
output.newline()
|
|
179
|
+
)
|
|
180
|
+
|
|
181
|
+
|
|
86
182
|
def print_finally(self, output, belse, else_var_name):
|
|
87
183
|
output.print("finally")
|
|
88
184
|
output.space()
|
package/src/output/functions.pyj
CHANGED
|
@@ -2,8 +2,9 @@
|
|
|
2
2
|
# License: BSD Copyright: 2016, Kovid Goyal <kovid at kovidgoyal.net>
|
|
3
3
|
from __python__ import hash_literals
|
|
4
4
|
|
|
5
|
-
from ast import AST_ClassCall, AST_New, has_calls, AST_Dot, AST_SymbolRef, is_node_type
|
|
5
|
+
from ast import AST_ClassCall, AST_New, has_calls, AST_Dot, AST_SymbolRef, AST_String, is_node_type
|
|
6
6
|
from output.stream import OutputStream
|
|
7
|
+
from parse import parse as ρσ_rs_parse
|
|
7
8
|
from output.statements import print_bracketed
|
|
8
9
|
from output.utils import create_doctring
|
|
9
10
|
from output.operators import print_getattr
|
|
@@ -150,6 +151,15 @@ def function_preamble(node, output, offset):
|
|
|
150
151
|
output.print('.pop()')
|
|
151
152
|
output.end_statement()
|
|
152
153
|
|
|
154
|
+
# Convert the plain JS kwargs object to a proper Python dict so that
|
|
155
|
+
# kw.items(), kw.keys(), etc. work in the function body.
|
|
156
|
+
# This must happen AFTER defaults/kwonly/starargs processing which rely on
|
|
157
|
+
# plain property access (kw.name) and ρσ_kwargs_symbol checks.
|
|
158
|
+
if a.kwargs:
|
|
159
|
+
output.indent()
|
|
160
|
+
output.spaced(kw, '=', 'ρσ_kwargs_to_dict(' + kw + ')')
|
|
161
|
+
output.end_statement()
|
|
162
|
+
|
|
153
163
|
def has_annotations(self):
|
|
154
164
|
if self.return_annotation:
|
|
155
165
|
return True
|
|
@@ -440,6 +450,73 @@ def print_function_call(self, output):
|
|
|
440
450
|
output.comma()
|
|
441
451
|
a.print(output)
|
|
442
452
|
)
|
|
453
|
+
elif (is_node_type(self.expression, AST_SymbolRef) and
|
|
454
|
+
self.expression.name is 'vars' and self.args.length is 0):
|
|
455
|
+
# vars() with no args → vars(this) so it captures the caller's instance
|
|
456
|
+
output.print('ρσ_vars')
|
|
457
|
+
output.with_parens(def():
|
|
458
|
+
output.print('this')
|
|
459
|
+
)
|
|
460
|
+
elif (is_node_type(self.expression, AST_SymbolRef) and
|
|
461
|
+
(self.expression.name is 'eval' or self.expression.name is 'exec') and
|
|
462
|
+
self.args.length >= 1 and is_node_type(self.args[0], AST_String)):
|
|
463
|
+
# Compile-time RapydScript → JS transformation for eval/exec string literals.
|
|
464
|
+
# The RapydScript source string is parsed and compiled to JS now; the emitted
|
|
465
|
+
# call receives the compiled JS string instead of the original RapydScript.
|
|
466
|
+
fn_name = self.expression.name
|
|
467
|
+
source = self.args[0].value
|
|
468
|
+
inner_ast = ρσ_rs_parse(source, {
|
|
469
|
+
'filename': '<eval>',
|
|
470
|
+
'module_id': '__eval__',
|
|
471
|
+
'for_linting': True,
|
|
472
|
+
'discard_asserts': output.options.discard_asserts,
|
|
473
|
+
})
|
|
474
|
+
inner_os = OutputStream({
|
|
475
|
+
'beautify': False,
|
|
476
|
+
'js_version': output.options.js_version,
|
|
477
|
+
'private_scope': False,
|
|
478
|
+
'write_name': False,
|
|
479
|
+
'omit_baselib': True,
|
|
480
|
+
'discard_asserts': output.options.discard_asserts,
|
|
481
|
+
})
|
|
482
|
+
inner_ast.print(inner_os)
|
|
483
|
+
compiled_js = v'inner_os.get().trim()'
|
|
484
|
+
|
|
485
|
+
def _print_extra_args():
|
|
486
|
+
for a in self.args.slice(1):
|
|
487
|
+
output.comma()
|
|
488
|
+
a.print(output)
|
|
489
|
+
|
|
490
|
+
if fn_name is 'eval' and self.args.length is 1:
|
|
491
|
+
# eval("expr") → native direct eval for scope access
|
|
492
|
+
output.print('eval')
|
|
493
|
+
output.with_parens(def():
|
|
494
|
+
output.print(JSON.stringify(compiled_js))
|
|
495
|
+
)
|
|
496
|
+
elif fn_name is 'eval':
|
|
497
|
+
# eval("expr", globals, locals) → ρσ_eval(compiled_js, globals, locals)
|
|
498
|
+
output.print('ρσ_eval')
|
|
499
|
+
output.with_parens(def():
|
|
500
|
+
output.print(JSON.stringify(compiled_js))
|
|
501
|
+
_print_extra_args()
|
|
502
|
+
)
|
|
503
|
+
else:
|
|
504
|
+
# exec("code", ...) → ρσ_exec(compiled_js, ...)
|
|
505
|
+
output.print('ρσ_exec')
|
|
506
|
+
output.with_parens(def():
|
|
507
|
+
output.print(JSON.stringify(compiled_js))
|
|
508
|
+
_print_extra_args()
|
|
509
|
+
)
|
|
510
|
+
elif is_node_type(self.expression, AST_SymbolRef) and self.expression.name is 'eval' and self.args.length > 1:
|
|
511
|
+
# eval(dynamic_expr, globals, locals) → ρσ_eval(dynamic_expr, globals, locals)
|
|
512
|
+
# The 1-arg form eval(expr) is left as native JS direct eval for scope access.
|
|
513
|
+
output.print('ρσ_eval')
|
|
514
|
+
output.with_parens(def():
|
|
515
|
+
for i, a in enumerate(self.args):
|
|
516
|
+
if i:
|
|
517
|
+
output.comma()
|
|
518
|
+
a.print(output)
|
|
519
|
+
)
|
|
443
520
|
elif is_node_type(self.expression, AST_SymbolRef) and self.python_truthiness:
|
|
444
521
|
# __call__-aware dispatch when from __python__ import truthiness is active
|
|
445
522
|
output.print('ρσ_callable_call(')
|
|
@@ -452,10 +529,15 @@ def print_function_call(self, output):
|
|
|
452
529
|
# Method calls and other complex expressions — keep existing behaviour
|
|
453
530
|
print_function_name()
|
|
454
531
|
output.with_parens(def():
|
|
455
|
-
|
|
456
|
-
|
|
457
|
-
|
|
458
|
-
|
|
532
|
+
# .split() with no args: default to ' ' so JS splits on space
|
|
533
|
+
# rather than returning [whole_string] (native JS no-arg behavior)
|
|
534
|
+
if is_node_type(self.expression, AST_Dot) and self.expression.property is 'split' and not self.args.length:
|
|
535
|
+
output.print('" "')
|
|
536
|
+
else:
|
|
537
|
+
for i, a in enumerate(self.args):
|
|
538
|
+
if i:
|
|
539
|
+
output.comma()
|
|
540
|
+
a.print(output)
|
|
459
541
|
)
|
|
460
542
|
return
|
|
461
543
|
|