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/baselib-internal.pyj
CHANGED
|
@@ -87,27 +87,24 @@ def ρσ_extends(child, parent):
|
|
|
87
87
|
child.prototype.constructor = child
|
|
88
88
|
Object.setPrototypeOf(child, parent)
|
|
89
89
|
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
return ρσ_list_contains.call(arr, val)
|
|
109
|
-
return Object.prototype.hasOwnProperty.call(arr, val)
|
|
110
|
-
)()
|
|
90
|
+
def ρσ_object_new(cls):
|
|
91
|
+
return v'Object.create(cls.prototype)'
|
|
92
|
+
|
|
93
|
+
def ρσ_new(parent, cls):
|
|
94
|
+
if parent and jstype(parent.__new__) is 'function':
|
|
95
|
+
return parent.__new__.apply(parent, v'Array.prototype.slice.call(arguments, 1)')
|
|
96
|
+
return v'Object.create(cls.prototype)'
|
|
97
|
+
|
|
98
|
+
def ρσ_in(val, arr):
|
|
99
|
+
if jstype(arr) is 'string':
|
|
100
|
+
return arr.indexOf(val) is not -1
|
|
101
|
+
if jstype(arr.__contains__) is 'function':
|
|
102
|
+
return arr.__contains__(val)
|
|
103
|
+
if jstype(Map) is 'function' and (v'arr instanceof Map' or v'arr instanceof Set'):
|
|
104
|
+
return arr.has(val)
|
|
105
|
+
if ρσ_arraylike(arr):
|
|
106
|
+
return ρσ_list_contains.call(arr, val)
|
|
107
|
+
return Object.prototype.hasOwnProperty.call(arr, val)
|
|
111
108
|
|
|
112
109
|
def ρσ_Iterable(iterable):
|
|
113
110
|
# Once ES6 is mature, change AST_ForIn to use the iterator protocol and get
|
|
@@ -125,23 +122,20 @@ def ρσ_Iterable(iterable):
|
|
|
125
122
|
# so we can use 'for ... in' syntax with objects, as we would with dicts in python
|
|
126
123
|
return Object.keys(iterable)
|
|
127
124
|
|
|
128
|
-
ρσ_desugar_kwargs
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
for v'var i = 0; i < arguments.length; i++':
|
|
140
|
-
keys = Object.keys(arguments[i])
|
|
125
|
+
def ρσ_desugar_kwargs():
|
|
126
|
+
ans = Object.create(None)
|
|
127
|
+
ans[ρσ_kwargs_symbol] = True
|
|
128
|
+
for v'var i = 0; i < arguments.length; i++':
|
|
129
|
+
arg = arguments[i]
|
|
130
|
+
if v'arg && arg.jsmap && typeof arg.jsmap.forEach === "function"':
|
|
131
|
+
v'arg.jsmap.forEach(function(v, k) { ans[k] = v; })'
|
|
132
|
+
elif jstype(Object.assign) is 'function':
|
|
133
|
+
Object.assign(ans, arg)
|
|
134
|
+
else:
|
|
135
|
+
keys = Object.keys(arg)
|
|
141
136
|
for v'var j = 0; j < keys.length; j++':
|
|
142
|
-
ans[keys[j]] =
|
|
143
|
-
|
|
144
|
-
)()
|
|
137
|
+
ans[keys[j]] = arg[keys[j]]
|
|
138
|
+
return ans
|
|
145
139
|
|
|
146
140
|
def ρσ_interpolate_kwargs(f, supplied_args):
|
|
147
141
|
if not f.__argnames__:
|
|
@@ -177,6 +171,8 @@ def ρσ_interpolate_kwargs_constructor(apply, f, supplied_args):
|
|
|
177
171
|
return this
|
|
178
172
|
|
|
179
173
|
def ρσ_getitem(obj, key):
|
|
174
|
+
if v'typeof obj === "function"' and obj.__class_getitem__:
|
|
175
|
+
return obj.__class_getitem__(key)
|
|
180
176
|
if obj.__getitem__:
|
|
181
177
|
return obj.__getitem__(key)
|
|
182
178
|
if v'typeof ρσ_slice !== "undefined" && key instanceof ρσ_slice':
|
|
@@ -249,6 +245,7 @@ def ρσ_splice(arr, val, start, end):
|
|
|
249
245
|
,'e': def(expr, alt):
|
|
250
246
|
return alt if expr is undefined or expr is None else expr
|
|
251
247
|
}
|
|
248
|
+
v'(typeof globalThis !== "undefined" ? globalThis : typeof window !== "undefined" ? window : global)["ρσ_exists"] = ρσ_exists'
|
|
252
249
|
|
|
253
250
|
def ρσ_mixin():
|
|
254
251
|
# Implement a depth-first left-to-right method resolution order This is not
|
|
@@ -278,55 +275,96 @@ def ρσ_mixin():
|
|
|
278
275
|
p = Object.getPrototypeOf(p)
|
|
279
276
|
Object.defineProperties(target, resolved_props)
|
|
280
277
|
|
|
278
|
+
# Returns a Python-style type name used in arithmetic TypeError messages.
|
|
279
|
+
def ρσ_arith_type_name(v):
|
|
280
|
+
if v is None or v is undefined:
|
|
281
|
+
return 'NoneType'
|
|
282
|
+
t = jstype(v)
|
|
283
|
+
if t is 'boolean':
|
|
284
|
+
return 'bool'
|
|
285
|
+
if t is 'number':
|
|
286
|
+
return 'int' if Number.isInteger(v) else 'float'
|
|
287
|
+
if t is 'string' or v'v instanceof String':
|
|
288
|
+
return 'str'
|
|
289
|
+
if Array.isArray(v):
|
|
290
|
+
return 'list'
|
|
291
|
+
if v.constructor and v.constructor.__name__:
|
|
292
|
+
return v.constructor.__name__
|
|
293
|
+
return t
|
|
294
|
+
|
|
281
295
|
# Arithmetic/bitwise operator overloading helpers.
|
|
282
296
|
# Each checks for the forward dunder method, then the reflected one, then
|
|
283
|
-
#
|
|
297
|
+
# enforces Python-style type compatibility before the native JS operation.
|
|
298
|
+
# Incompatible operand types raise TypeError, mirroring Python semantics.
|
|
284
299
|
def ρσ_op_add(a, b):
|
|
285
300
|
if a is not None and jstype(a.__add__) is 'function': return a.__add__(b)
|
|
286
301
|
if b is not None and jstype(b.__radd__) is 'function': return b.__radd__(a)
|
|
287
|
-
|
|
302
|
+
if Array.isArray(a) and Array.isArray(b): return ρσ_list_constructor(a.concat(b))
|
|
303
|
+
ta = jstype(a)
|
|
304
|
+
tb = jstype(b)
|
|
305
|
+
if (ta is 'number' or ta is 'boolean') and (tb is 'number' or tb is 'boolean'): return v'a + b'
|
|
306
|
+
if (ta is 'string' or v'a instanceof String') and (tb is 'string' or v'b instanceof String'): return v'a + b'
|
|
307
|
+
raise TypeError("unsupported operand type(s) for +: '" + ρσ_arith_type_name(a) + "' and '" + ρσ_arith_type_name(b) + "'")
|
|
288
308
|
|
|
289
309
|
def ρσ_op_sub(a, b):
|
|
290
310
|
if a is not None and jstype(a.__sub__) is 'function': return a.__sub__(b)
|
|
291
311
|
if b is not None and jstype(b.__rsub__) is 'function': return b.__rsub__(a)
|
|
292
|
-
|
|
312
|
+
ta = jstype(a)
|
|
313
|
+
tb = jstype(b)
|
|
314
|
+
if (ta is 'number' or ta is 'boolean') and (tb is 'number' or tb is 'boolean'): return a - b
|
|
315
|
+
raise TypeError("unsupported operand type(s) for -: '" + ρσ_arith_type_name(a) + "' and '" + ρσ_arith_type_name(b) + "'")
|
|
293
316
|
|
|
294
317
|
def ρσ_op_mul(a, b):
|
|
295
318
|
if a is not None and jstype(a.__mul__) is 'function': return a.__mul__(b)
|
|
296
319
|
if b is not None and jstype(b.__rmul__) is 'function': return b.__rmul__(a)
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
if
|
|
320
|
+
ta = jstype(a)
|
|
321
|
+
tb = jstype(b)
|
|
322
|
+
if (ta is 'string' or v'a instanceof String') and (tb is 'number' or tb is 'boolean'): return a.repeat(b)
|
|
323
|
+
if (tb is 'string' or v'b instanceof String') and (ta is 'number' or ta is 'boolean'): return b.repeat(a)
|
|
324
|
+
if Array.isArray(a) and (tb is 'number' or tb is 'boolean'):
|
|
300
325
|
result = v'[]'
|
|
301
326
|
for v'var ρσ_mi = 0; ρσ_mi < b; ρσ_mi++':
|
|
302
327
|
result = result.concat(a) # noqa:undef
|
|
303
328
|
return ρσ_list_constructor(result)
|
|
304
|
-
if Array.isArray(b) and
|
|
329
|
+
if Array.isArray(b) and (ta is 'number' or ta is 'boolean'):
|
|
305
330
|
result = v'[]'
|
|
306
331
|
for v'var ρσ_mi = 0; ρσ_mi < a; ρσ_mi++':
|
|
307
332
|
result = result.concat(b) # noqa:undef
|
|
308
333
|
return ρσ_list_constructor(result)
|
|
309
|
-
return a * b
|
|
334
|
+
if (ta is 'number' or ta is 'boolean') and (tb is 'number' or tb is 'boolean'): return a * b
|
|
335
|
+
raise TypeError("unsupported operand type(s) for *: '" + ρσ_arith_type_name(a) + "' and '" + ρσ_arith_type_name(b) + "'")
|
|
310
336
|
|
|
311
337
|
def ρσ_op_truediv(a, b):
|
|
312
338
|
if a is not None and jstype(a.__truediv__) is 'function': return a.__truediv__(b)
|
|
313
339
|
if b is not None and jstype(b.__rtruediv__) is 'function': return b.__rtruediv__(a)
|
|
314
|
-
|
|
340
|
+
ta = jstype(a)
|
|
341
|
+
tb = jstype(b)
|
|
342
|
+
if (ta is 'number' or ta is 'boolean') and (tb is 'number' or tb is 'boolean'): return a / b
|
|
343
|
+
raise TypeError("unsupported operand type(s) for /: '" + ρσ_arith_type_name(a) + "' and '" + ρσ_arith_type_name(b) + "'")
|
|
315
344
|
|
|
316
345
|
def ρσ_op_floordiv(a, b):
|
|
317
346
|
if a is not None and jstype(a.__floordiv__) is 'function': return a.__floordiv__(b)
|
|
318
347
|
if b is not None and jstype(b.__rfloordiv__) is 'function': return b.__rfloordiv__(a)
|
|
319
|
-
|
|
348
|
+
ta = jstype(a)
|
|
349
|
+
tb = jstype(b)
|
|
350
|
+
if (ta is 'number' or ta is 'boolean') and (tb is 'number' or tb is 'boolean'): return Math.floor(a / b)
|
|
351
|
+
raise TypeError("unsupported operand type(s) for //: '" + ρσ_arith_type_name(a) + "' and '" + ρσ_arith_type_name(b) + "'")
|
|
320
352
|
|
|
321
353
|
def ρσ_op_mod(a, b):
|
|
322
354
|
if a is not None and jstype(a.__mod__) is 'function': return a.__mod__(b)
|
|
323
355
|
if b is not None and jstype(b.__rmod__) is 'function': return b.__rmod__(a)
|
|
324
|
-
|
|
356
|
+
ta = jstype(a)
|
|
357
|
+
tb = jstype(b)
|
|
358
|
+
if (ta is 'number' or ta is 'boolean') and (tb is 'number' or tb is 'boolean'): return a % b
|
|
359
|
+
raise TypeError("unsupported operand type(s) for %: '" + ρσ_arith_type_name(a) + "' and '" + ρσ_arith_type_name(b) + "'")
|
|
325
360
|
|
|
326
361
|
def ρσ_op_pow(a, b):
|
|
327
362
|
if a is not None and jstype(a.__pow__) is 'function': return a.__pow__(b)
|
|
328
363
|
if b is not None and jstype(b.__rpow__) is 'function': return b.__rpow__(a)
|
|
329
|
-
|
|
364
|
+
ta = jstype(a)
|
|
365
|
+
tb = jstype(b)
|
|
366
|
+
if (ta is 'number' or ta is 'boolean') and (tb is 'number' or tb is 'boolean'): return Math.pow(a, b)
|
|
367
|
+
raise TypeError("unsupported operand type(s) for **: '" + ρσ_arith_type_name(a) + "' and '" + ρσ_arith_type_name(b) + "'")
|
|
330
368
|
|
|
331
369
|
def ρσ_op_and(a, b):
|
|
332
370
|
if a is not None and jstype(a.__and__) is 'function': return a.__and__(b)
|
|
@@ -353,12 +391,74 @@ def ρσ_op_rshift(a, b):
|
|
|
353
391
|
if b is not None and jstype(b.__rrshift__) is 'function': return b.__rrshift__(a)
|
|
354
392
|
return a >> b
|
|
355
393
|
|
|
394
|
+
# Ordered-comparison operator overloading helpers.
|
|
395
|
+
# ρσ_op_lt dispatches __lt__ (forward) then __gt__ (reflected), handles lists
|
|
396
|
+
# lexicographically, enforces type compatibility, and raises TypeError otherwise.
|
|
397
|
+
# ρσ_op_gt / ρσ_op_ge delegate to ρσ_op_lt / ρσ_op_le after dunder checks.
|
|
398
|
+
def ρσ_op_lt(a, b):
|
|
399
|
+
if a is not None and jstype(a.__lt__) is 'function': return a.__lt__(b)
|
|
400
|
+
if b is not None and jstype(b.__gt__) is 'function': return b.__gt__(a)
|
|
401
|
+
if Array.isArray(a) and Array.isArray(b):
|
|
402
|
+
n = Math.min(a.length, b.length)
|
|
403
|
+
for v'var ρσ_ci = 0; ρσ_ci < n; ρσ_ci++':
|
|
404
|
+
ea = v'a[ρσ_ci]'
|
|
405
|
+
eb = v'b[ρσ_ci]'
|
|
406
|
+
if ρσ_op_lt(ea, eb): return True
|
|
407
|
+
if ρσ_op_lt(eb, ea): return False
|
|
408
|
+
return v'a.length < b.length'
|
|
409
|
+
ta = jstype(a)
|
|
410
|
+
tb = jstype(b)
|
|
411
|
+
if (ta is 'number' or ta is 'boolean') and (tb is 'number' or tb is 'boolean'): return v'a < b'
|
|
412
|
+
if (ta is 'string' or v'a instanceof String') and (tb is 'string' or v'b instanceof String'): return v'a < b'
|
|
413
|
+
raise TypeError("'<' not supported between instances of '" + ρσ_arith_type_name(a) + "' and '" + ρσ_arith_type_name(b) + "'")
|
|
414
|
+
|
|
415
|
+
def ρσ_op_le(a, b):
|
|
416
|
+
if a is not None and jstype(a.__le__) is 'function': return a.__le__(b)
|
|
417
|
+
if b is not None and jstype(b.__ge__) is 'function': return b.__ge__(a)
|
|
418
|
+
if Array.isArray(a) and Array.isArray(b):
|
|
419
|
+
n = Math.min(a.length, b.length)
|
|
420
|
+
for v'var ρσ_ci = 0; ρσ_ci < n; ρσ_ci++':
|
|
421
|
+
ea = v'a[ρσ_ci]'
|
|
422
|
+
eb = v'b[ρσ_ci]'
|
|
423
|
+
if ρσ_op_lt(ea, eb): return True
|
|
424
|
+
if ρσ_op_lt(eb, ea): return False
|
|
425
|
+
return v'a.length <= b.length'
|
|
426
|
+
ta = jstype(a)
|
|
427
|
+
tb = jstype(b)
|
|
428
|
+
if (ta is 'number' or ta is 'boolean') and (tb is 'number' or tb is 'boolean'): return v'a <= b'
|
|
429
|
+
if (ta is 'string' or v'a instanceof String') and (tb is 'string' or v'b instanceof String'): return v'a <= b'
|
|
430
|
+
raise TypeError("'<=' not supported between instances of '" + ρσ_arith_type_name(a) + "' and '" + ρσ_arith_type_name(b) + "'")
|
|
431
|
+
|
|
432
|
+
def ρσ_op_gt(a, b):
|
|
433
|
+
if a is not None and jstype(a.__gt__) is 'function': return a.__gt__(b)
|
|
434
|
+
if b is not None and jstype(b.__lt__) is 'function': return b.__lt__(a)
|
|
435
|
+
if Array.isArray(a) and Array.isArray(b): return ρσ_op_lt(b, a)
|
|
436
|
+
ta = jstype(a)
|
|
437
|
+
tb = jstype(b)
|
|
438
|
+
if (ta is 'number' or ta is 'boolean') and (tb is 'number' or tb is 'boolean'): return v'a > b'
|
|
439
|
+
if (ta is 'string' or v'a instanceof String') and (tb is 'string' or v'b instanceof String'): return v'a > b'
|
|
440
|
+
raise TypeError("'>' not supported between instances of '" + ρσ_arith_type_name(a) + "' and '" + ρσ_arith_type_name(b) + "'")
|
|
441
|
+
|
|
442
|
+
def ρσ_op_ge(a, b):
|
|
443
|
+
if a is not None and jstype(a.__ge__) is 'function': return a.__ge__(b)
|
|
444
|
+
if b is not None and jstype(b.__le__) is 'function': return b.__le__(a)
|
|
445
|
+
if Array.isArray(a) and Array.isArray(b): return ρσ_op_le(b, a)
|
|
446
|
+
ta = jstype(a)
|
|
447
|
+
tb = jstype(b)
|
|
448
|
+
if (ta is 'number' or ta is 'boolean') and (tb is 'number' or tb is 'boolean'): return v'a >= b'
|
|
449
|
+
if (ta is 'string' or v'a instanceof String') and (tb is 'string' or v'b instanceof String'): return v'a >= b'
|
|
450
|
+
raise TypeError("'>=' not supported between instances of '" + ρσ_arith_type_name(a) + "' and '" + ρσ_arith_type_name(b) + "'")
|
|
451
|
+
|
|
356
452
|
# List-concatenation helpers (always available, no overload_operators required).
|
|
357
453
|
# ρσ_list_add: used for the + operator; creates a new list when both sides are arrays.
|
|
358
454
|
# NOTE: the fallback uses v'a + b' (verbatim JS) to avoid recursive self-compilation.
|
|
359
455
|
def ρσ_list_add(a, b):
|
|
360
456
|
if Array.isArray(a) and Array.isArray(b):
|
|
361
457
|
return ρσ_list_constructor(a.concat(b))
|
|
458
|
+
if a is not None and a is not undefined and jstype(a.__add__) is 'function':
|
|
459
|
+
return a.__add__(b)
|
|
460
|
+
if b is not None and b is not undefined and jstype(b.__radd__) is 'function':
|
|
461
|
+
return b.__radd__(a)
|
|
362
462
|
return v'a + b'
|
|
363
463
|
|
|
364
464
|
# ρσ_list_iadd: used for +=; extends a in-place when both sides are arrays (Python semantics).
|
|
@@ -366,6 +466,10 @@ def ρσ_list_iadd(a, b):
|
|
|
366
466
|
if Array.isArray(a) and Array.isArray(b):
|
|
367
467
|
v'Array.prototype.push.apply(a, b)'
|
|
368
468
|
return a
|
|
469
|
+
if a is not None and a is not undefined and jstype(a.__iadd__) is 'function':
|
|
470
|
+
return a.__iadd__(b)
|
|
471
|
+
if a is not None and a is not undefined and jstype(a.__add__) is 'function':
|
|
472
|
+
return a.__add__(b)
|
|
369
473
|
return v'a + b'
|
|
370
474
|
|
|
371
475
|
# Unary operator overloading helpers
|
|
@@ -430,6 +534,126 @@ def ρσ_op_irshift(a, b):
|
|
|
430
534
|
if a is not None and jstype(a.__irshift__) is 'function': return a.__irshift__(b)
|
|
431
535
|
return ρσ_op_rshift(a, b)
|
|
432
536
|
|
|
537
|
+
# No-strict (ns) variants: same dunder dispatch but JS native fallback instead of TypeError.
|
|
538
|
+
# Used when overload_operators is active but strict_arithmetic is disabled
|
|
539
|
+
# (from __python__ import no_strict_arithmetic).
|
|
540
|
+
def ρσ_op_add_ns(a, b):
|
|
541
|
+
if a is not None and jstype(a.__add__) is 'function': return a.__add__(b)
|
|
542
|
+
if b is not None and jstype(b.__radd__) is 'function': return b.__radd__(a)
|
|
543
|
+
if Array.isArray(a) and Array.isArray(b): return ρσ_list_constructor(a.concat(b))
|
|
544
|
+
return v'a + b'
|
|
545
|
+
|
|
546
|
+
def ρσ_op_sub_ns(a, b):
|
|
547
|
+
if a is not None and jstype(a.__sub__) is 'function': return a.__sub__(b)
|
|
548
|
+
if b is not None and jstype(b.__rsub__) is 'function': return b.__rsub__(a)
|
|
549
|
+
return v'a - b'
|
|
550
|
+
|
|
551
|
+
def ρσ_op_mul_ns(a, b):
|
|
552
|
+
if a is not None and jstype(a.__mul__) is 'function': return a.__mul__(b)
|
|
553
|
+
if b is not None and jstype(b.__rmul__) is 'function': return b.__rmul__(a)
|
|
554
|
+
ta = jstype(a)
|
|
555
|
+
tb = jstype(b)
|
|
556
|
+
if (ta is 'string' or v'a instanceof String') and (tb is 'number' or tb is 'boolean'): return a.repeat(b)
|
|
557
|
+
if (tb is 'string' or v'b instanceof String') and (ta is 'number' or ta is 'boolean'): return b.repeat(a)
|
|
558
|
+
if Array.isArray(a) and (tb is 'number' or tb is 'boolean'):
|
|
559
|
+
result = v'[]'
|
|
560
|
+
for v'var ρσ_mi = 0; ρσ_mi < b; ρσ_mi++':
|
|
561
|
+
result = result.concat(a) # noqa:undef
|
|
562
|
+
return ρσ_list_constructor(result)
|
|
563
|
+
if Array.isArray(b) and (ta is 'number' or ta is 'boolean'):
|
|
564
|
+
result = v'[]'
|
|
565
|
+
for v'var ρσ_mi = 0; ρσ_mi < a; ρσ_mi++':
|
|
566
|
+
result = result.concat(b) # noqa:undef
|
|
567
|
+
return ρσ_list_constructor(result)
|
|
568
|
+
return v'a * b'
|
|
569
|
+
|
|
570
|
+
def ρσ_op_truediv_ns(a, b):
|
|
571
|
+
if a is not None and jstype(a.__truediv__) is 'function': return a.__truediv__(b)
|
|
572
|
+
if b is not None and jstype(b.__rtruediv__) is 'function': return b.__rtruediv__(a)
|
|
573
|
+
return v'a / b'
|
|
574
|
+
|
|
575
|
+
def ρσ_op_floordiv_ns(a, b):
|
|
576
|
+
if a is not None and jstype(a.__floordiv__) is 'function': return a.__floordiv__(b)
|
|
577
|
+
if b is not None and jstype(b.__rfloordiv__) is 'function': return b.__rfloordiv__(a)
|
|
578
|
+
return Math.floor(v'a / b')
|
|
579
|
+
|
|
580
|
+
def ρσ_op_mod_ns(a, b):
|
|
581
|
+
if a is not None and jstype(a.__mod__) is 'function': return a.__mod__(b)
|
|
582
|
+
if b is not None and jstype(b.__rmod__) is 'function': return b.__rmod__(a)
|
|
583
|
+
return v'a % b'
|
|
584
|
+
|
|
585
|
+
def ρσ_op_pow_ns(a, b):
|
|
586
|
+
if a is not None and jstype(a.__pow__) is 'function': return a.__pow__(b)
|
|
587
|
+
if b is not None and jstype(b.__rpow__) is 'function': return b.__rpow__(a)
|
|
588
|
+
return Math.pow(a, b)
|
|
589
|
+
|
|
590
|
+
def ρσ_op_lt_ns(a, b):
|
|
591
|
+
if a is not None and jstype(a.__lt__) is 'function': return a.__lt__(b)
|
|
592
|
+
if b is not None and jstype(b.__gt__) is 'function': return b.__gt__(a)
|
|
593
|
+
if Array.isArray(a) and Array.isArray(b):
|
|
594
|
+
n = Math.min(a.length, b.length)
|
|
595
|
+
for v'var ρσ_ci = 0; ρσ_ci < n; ρσ_ci++':
|
|
596
|
+
ea = v'a[ρσ_ci]'
|
|
597
|
+
eb = v'b[ρσ_ci]'
|
|
598
|
+
if ρσ_op_lt_ns(ea, eb): return True
|
|
599
|
+
if ρσ_op_lt_ns(eb, ea): return False
|
|
600
|
+
return v'a.length < b.length'
|
|
601
|
+
return v'a < b'
|
|
602
|
+
|
|
603
|
+
def ρσ_op_le_ns(a, b):
|
|
604
|
+
if a is not None and jstype(a.__le__) is 'function': return a.__le__(b)
|
|
605
|
+
if b is not None and jstype(b.__ge__) is 'function': return b.__ge__(a)
|
|
606
|
+
if Array.isArray(a) and Array.isArray(b):
|
|
607
|
+
n = Math.min(a.length, b.length)
|
|
608
|
+
for v'var ρσ_ci = 0; ρσ_ci < n; ρσ_ci++':
|
|
609
|
+
ea = v'a[ρσ_ci]'
|
|
610
|
+
eb = v'b[ρσ_ci]'
|
|
611
|
+
if ρσ_op_lt_ns(ea, eb): return True
|
|
612
|
+
if ρσ_op_lt_ns(eb, ea): return False
|
|
613
|
+
return v'a.length <= b.length'
|
|
614
|
+
return v'a <= b'
|
|
615
|
+
|
|
616
|
+
def ρσ_op_gt_ns(a, b):
|
|
617
|
+
if a is not None and jstype(a.__gt__) is 'function': return a.__gt__(b)
|
|
618
|
+
if b is not None and jstype(b.__lt__) is 'function': return b.__lt__(a)
|
|
619
|
+
if Array.isArray(a) and Array.isArray(b): return ρσ_op_lt_ns(b, a)
|
|
620
|
+
return v'a > b'
|
|
621
|
+
|
|
622
|
+
def ρσ_op_ge_ns(a, b):
|
|
623
|
+
if a is not None and jstype(a.__ge__) is 'function': return a.__ge__(b)
|
|
624
|
+
if b is not None and jstype(b.__le__) is 'function': return b.__le__(a)
|
|
625
|
+
if Array.isArray(a) and Array.isArray(b): return ρσ_op_le_ns(b, a)
|
|
626
|
+
return v'a >= b'
|
|
627
|
+
|
|
628
|
+
# No-strict augmented-assignment helpers
|
|
629
|
+
def ρσ_op_iadd_ns(a, b):
|
|
630
|
+
if a is not None and jstype(a.__iadd__) is 'function': return a.__iadd__(b)
|
|
631
|
+
return ρσ_op_add_ns(a, b)
|
|
632
|
+
|
|
633
|
+
def ρσ_op_isub_ns(a, b):
|
|
634
|
+
if a is not None and jstype(a.__isub__) is 'function': return a.__isub__(b)
|
|
635
|
+
return ρσ_op_sub_ns(a, b)
|
|
636
|
+
|
|
637
|
+
def ρσ_op_imul_ns(a, b):
|
|
638
|
+
if a is not None and jstype(a.__imul__) is 'function': return a.__imul__(b)
|
|
639
|
+
return ρσ_op_mul_ns(a, b)
|
|
640
|
+
|
|
641
|
+
def ρσ_op_itruediv_ns(a, b):
|
|
642
|
+
if a is not None and jstype(a.__itruediv__) is 'function': return a.__itruediv__(b)
|
|
643
|
+
return ρσ_op_truediv_ns(a, b)
|
|
644
|
+
|
|
645
|
+
def ρσ_op_ifloordiv_ns(a, b):
|
|
646
|
+
if a is not None and jstype(a.__ifloordiv__) is 'function': return a.__ifloordiv__(b)
|
|
647
|
+
return ρσ_op_floordiv_ns(a, b)
|
|
648
|
+
|
|
649
|
+
def ρσ_op_imod_ns(a, b):
|
|
650
|
+
if a is not None and jstype(a.__imod__) is 'function': return a.__imod__(b)
|
|
651
|
+
return ρσ_op_mod_ns(a, b)
|
|
652
|
+
|
|
653
|
+
def ρσ_op_ipow_ns(a, b):
|
|
654
|
+
if a is not None and jstype(a.__ipow__) is 'function': return a.__ipow__(b)
|
|
655
|
+
return ρσ_op_pow_ns(a, b)
|
|
656
|
+
|
|
433
657
|
def ρσ_instanceof():
|
|
434
658
|
obj = arguments[0]
|
|
435
659
|
bases = ''
|
|
@@ -458,3 +682,76 @@ def ρσ_instanceof():
|
|
|
458
682
|
break
|
|
459
683
|
cls = p.constructor
|
|
460
684
|
return False
|
|
685
|
+
|
|
686
|
+
# ── Attribute-dunder support (__getattr__ / __setattr__ / __delattr__ / __getattribute__) ──
|
|
687
|
+
# We use a JavaScript Proxy to intercept attribute access/assignment/deletion on class instances
|
|
688
|
+
# that define any of the four attribute dunders.
|
|
689
|
+
|
|
690
|
+
# Cache the JS Proxy constructor with a ρσ_ name to avoid collisions with user-defined 'Proxy' classes.
|
|
691
|
+
v'var ρσ_JS_Proxy = typeof Proxy === "function" ? Proxy : null'
|
|
692
|
+
|
|
693
|
+
# Symbol (or fallback string key) used to retrieve the raw underlying target from a wrapped proxy.
|
|
694
|
+
v'var ρσ_proxy_target_symbol = typeof Symbol === "function" ? Symbol("ρσ_proxy_target") : "__ρσ_proxy_target__"'
|
|
695
|
+
|
|
696
|
+
ρσ_attr_proxy_handler = {
|
|
697
|
+
'get': def(target, prop, receiver):
|
|
698
|
+
# Always expose the raw target via the sentinel key (used by ρσ_object_* helpers).
|
|
699
|
+
if prop is ρσ_proxy_target_symbol:
|
|
700
|
+
return target
|
|
701
|
+
# Pass through JS symbols (Symbol.iterator, Symbol.toPrimitive, etc.) unchanged.
|
|
702
|
+
if jstype(prop) is 'symbol':
|
|
703
|
+
return v'Reflect.get(target, prop, receiver)'
|
|
704
|
+
# __getattribute__ overrides every attribute lookup (except itself, to avoid infinite recursion).
|
|
705
|
+
if jstype(target.__getattribute__) is 'function' and prop is not '__getattribute__':
|
|
706
|
+
try:
|
|
707
|
+
return target.__getattribute__.call(receiver, prop)
|
|
708
|
+
except AttributeError:
|
|
709
|
+
# AttributeError from __getattribute__ → try __getattr__ fallback.
|
|
710
|
+
if jstype(target.__getattr__) is 'function':
|
|
711
|
+
return target.__getattr__.call(receiver, prop)
|
|
712
|
+
raise
|
|
713
|
+
# Normal property lookup via prototype chain.
|
|
714
|
+
val = v'Reflect.get(target, prop, receiver)'
|
|
715
|
+
# __getattr__ is only called when the attribute is genuinely missing.
|
|
716
|
+
if val is undefined and jstype(target.__getattr__) is 'function' and not v'(prop in target)':
|
|
717
|
+
return target.__getattr__.call(receiver, prop)
|
|
718
|
+
return val
|
|
719
|
+
,
|
|
720
|
+
'set': def(target, prop, value, receiver):
|
|
721
|
+
if jstype(target.__setattr__) is 'function':
|
|
722
|
+
target.__setattr__.call(receiver, prop, value)
|
|
723
|
+
return True
|
|
724
|
+
# Pass 'target' as receiver (not proxy) to avoid infinite recursion through the Proxy set trap.
|
|
725
|
+
return v'Reflect.set(target, prop, value, target)'
|
|
726
|
+
,
|
|
727
|
+
'deleteProperty': def(target, prop):
|
|
728
|
+
if jstype(target.__delattr__) is 'function':
|
|
729
|
+
# deleteProperty has no receiver; pass target as 'this'.
|
|
730
|
+
# Inside __delattr__, use ρσ_object_delattr(self, name) for a direct delete.
|
|
731
|
+
target.__delattr__.call(target, prop)
|
|
732
|
+
return True
|
|
733
|
+
return v'Reflect.deleteProperty(target, prop)'
|
|
734
|
+
}
|
|
735
|
+
v'(typeof globalThis !== "undefined" ? globalThis : typeof window !== "undefined" ? window : global)["ρσ_attr_proxy_handler"] = ρσ_attr_proxy_handler'
|
|
736
|
+
|
|
737
|
+
def ρσ_object_setattr(obj, name, value):
|
|
738
|
+
# Bypass __setattr__ and set directly on the underlying object.
|
|
739
|
+
# Use this inside __setattr__ to avoid infinite recursion (like object.__setattr__ in Python).
|
|
740
|
+
target = obj[ρσ_proxy_target_symbol]
|
|
741
|
+
if target is undefined:
|
|
742
|
+
target = obj
|
|
743
|
+
v'target[name] = value'
|
|
744
|
+
|
|
745
|
+
def ρσ_object_getattr(obj, name):
|
|
746
|
+
# Bypass __getattribute__ and read directly from the underlying object.
|
|
747
|
+
target = obj[ρσ_proxy_target_symbol]
|
|
748
|
+
if target is undefined:
|
|
749
|
+
target = obj
|
|
750
|
+
return target[name]
|
|
751
|
+
|
|
752
|
+
def ρσ_object_delattr(obj, name):
|
|
753
|
+
# Bypass __delattr__ and delete directly from the underlying object.
|
|
754
|
+
target = obj[ρσ_proxy_target_symbol]
|
|
755
|
+
if target is undefined:
|
|
756
|
+
target = obj
|
|
757
|
+
v'delete target[name]'
|
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
# License: BSD
|
|
3
3
|
# Copyright: 2015, Kovid Goyal <kovid at kovidgoyal.net>
|
|
4
4
|
|
|
5
|
-
# globals: ρσ_iterator_symbol, ρσ_bool
|
|
5
|
+
# globals: ρσ_iterator_symbol, ρσ_bool, ρσ_kwargs_symbol
|
|
6
6
|
|
|
7
7
|
def sum(iterable, start):
|
|
8
8
|
if Array.isArray(iterable):
|
|
@@ -52,17 +52,30 @@ def filter(func_or_none, iterable):
|
|
|
52
52
|
return ans
|
|
53
53
|
|
|
54
54
|
def zip():
|
|
55
|
-
|
|
56
|
-
|
|
55
|
+
n = arguments.length
|
|
56
|
+
strict = False
|
|
57
|
+
if n > 0 and v'typeof arguments[n - 1] === "object" && arguments[n - 1] !== null' and arguments[n-1][ρσ_kwargs_symbol] is True:
|
|
58
|
+
strict = arguments[n-1]['strict'] or False
|
|
59
|
+
n -= 1
|
|
60
|
+
iterators = new Array(n)
|
|
61
|
+
for v'var i = 0; i < n; i++':
|
|
57
62
|
iterators[i] = iter(arguments[i]) # noqa:undef
|
|
58
|
-
ans = v"{'_iterators':iterators}"
|
|
63
|
+
ans = v"{'_iterators':iterators, '_strict':strict}"
|
|
59
64
|
ans[ρσ_iterator_symbol] = def():
|
|
60
65
|
return this
|
|
61
66
|
ans['next'] = def():
|
|
67
|
+
if not this._iterators.length:
|
|
68
|
+
return v"{'done':true}"
|
|
62
69
|
args = new Array(this._iterators.length)
|
|
63
70
|
for v'var i = 0; i < this._iterators.length; i++':
|
|
64
71
|
r = this._iterators[i].next()
|
|
65
72
|
if r.done:
|
|
73
|
+
if this._strict:
|
|
74
|
+
for v'var j = i + 1; j < this._iterators.length; j++':
|
|
75
|
+
if not this._iterators[j].next().done:
|
|
76
|
+
raise ValueError('zip() has arguments with different lengths')
|
|
77
|
+
if v'i > 0':
|
|
78
|
+
raise ValueError('zip() has arguments with different lengths')
|
|
66
79
|
return v"{'done':true}"
|
|
67
80
|
args[i] = r.value # noqa:undef
|
|
68
81
|
return v"{'done':false, 'value':args}"
|
package/src/baselib-str.pyj
CHANGED
|
@@ -109,7 +109,8 @@ define_str_func = def(name, func):
|
|
|
109
109
|
if func.__argnames__:
|
|
110
110
|
Object.defineProperty(f, '__argnames__', {'value':v"['string']".concat(func.__argnames__)})
|
|
111
111
|
|
|
112
|
-
ρσ_orig_split
|
|
112
|
+
ρσ_orig_split = String.prototype.split.call.bind(String.prototype.split)
|
|
113
|
+
ρσ_orig_replace = String.prototype.replace.call.bind(String.prototype.replace)
|
|
113
114
|
|
|
114
115
|
# format() {{{
|
|
115
116
|
define_str_func('format', def ():
|
|
@@ -367,9 +368,20 @@ define_str_func('format', def ():
|
|
|
367
368
|
idx += 1
|
|
368
369
|
if jstype(object) is 'function':
|
|
369
370
|
object = object()
|
|
370
|
-
|
|
371
|
-
if
|
|
372
|
-
|
|
371
|
+
# Apply !-conversion (transformer) before format spec, per Python semantics
|
|
372
|
+
if transformer is 'r':
|
|
373
|
+
object = ρσ_repr(object)
|
|
374
|
+
elif transformer is 's':
|
|
375
|
+
object = ρσ_str(object)
|
|
376
|
+
elif transformer is 'a':
|
|
377
|
+
object = ρσ_repr(object)
|
|
378
|
+
# Dispatch to __format__ when defined and no transformer was applied
|
|
379
|
+
if not transformer and object is not None and object is not undefined and v'typeof object.__format__ === "function"':
|
|
380
|
+
ans = object.__format__(format_spec or '')
|
|
381
|
+
else:
|
|
382
|
+
ans = '' + object
|
|
383
|
+
if format_spec:
|
|
384
|
+
ans = apply_formatting(ans, format_spec)
|
|
373
385
|
if ends_with_equal:
|
|
374
386
|
ans = f'{key}={ans}'
|
|
375
387
|
return ans
|
|
@@ -693,6 +705,12 @@ define_str_func('split', def(sep, maxsplit):
|
|
|
693
705
|
ans.push(extra)
|
|
694
706
|
return ρσ_list_decorate(ans)
|
|
695
707
|
)
|
|
708
|
+
# Patch String.prototype.split so that no-argument calls (text.split()) use Python
|
|
709
|
+
# semantics (split on whitespace) rather than JS semantics (return [text]).
|
|
710
|
+
String.prototype.split = def(sep, limit):
|
|
711
|
+
if sep is undefined:
|
|
712
|
+
return ρσ_str.prototype.split.call(this)
|
|
713
|
+
return ρσ_orig_split(this, sep, limit)
|
|
696
714
|
|
|
697
715
|
define_str_func('rsplit', def(sep, maxsplit):
|
|
698
716
|
if not maxsplit:
|
|
@@ -774,6 +792,29 @@ define_str_func('zfill', def(width):
|
|
|
774
792
|
return string
|
|
775
793
|
)
|
|
776
794
|
|
|
795
|
+
define_str_func('expandtabs', def(tabsize):
|
|
796
|
+
if tabsize is undefined:
|
|
797
|
+
tabsize = 8
|
|
798
|
+
string = this
|
|
799
|
+
ans = ''
|
|
800
|
+
col = 0
|
|
801
|
+
for v'var i = 0; i < string.length; i++':
|
|
802
|
+
ch = string[i] # noqa:undef
|
|
803
|
+
if ch is '\t':
|
|
804
|
+
if tabsize > 0:
|
|
805
|
+
spaces = tabsize - (col % tabsize)
|
|
806
|
+
ans += v'new Array(spaces + 1).join(" ")'
|
|
807
|
+
col += spaces
|
|
808
|
+
# tabsize <= 0: tab adds no spaces, col stays
|
|
809
|
+
elif ch is '\n' or ch is '\r':
|
|
810
|
+
ans += ch
|
|
811
|
+
col = 0
|
|
812
|
+
else:
|
|
813
|
+
ans += ch
|
|
814
|
+
col += 1
|
|
815
|
+
return ans
|
|
816
|
+
)
|
|
817
|
+
|
|
777
818
|
ρσ_str.uchrs = def(string, with_positions):
|
|
778
819
|
# Return iterator over unicode chars in string. Will yield the unicode
|
|
779
820
|
# replacement char U+FFFD for broken surrogate pairs
|
|
@@ -836,4 +877,5 @@ def ρσ_format(value, spec):
|
|
|
836
877
|
return ρσ_str(value)
|
|
837
878
|
return str.format('{:' + spec + '}', value)
|
|
838
879
|
|
|
880
|
+
ρσ_str.__name__ = 'str'
|
|
839
881
|
v'var str = ρσ_str, repr = ρσ_repr, format = ρσ_format'
|