rapydscript-ns 0.9.3 → 0.9.5
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.agignore +1 -1
- package/.github/workflows/ci.yml +38 -38
- package/=template.pyj +5 -5
- package/CHANGELOG.md +18 -0
- package/HACKING.md +103 -103
- package/LICENSE +24 -24
- package/PYTHON_GAPS.md +52 -142
- package/README.md +51 -21
- package/TODO.md +1 -26
- package/add-toc-to-readme +2 -2
- package/bin/export +75 -75
- package/bin/rapydscript +0 -0
- package/bin/web-repl-export +102 -102
- package/build +2 -2
- package/language-service/index.js +88 -36
- package/package.json +1 -1
- package/publish.py +37 -37
- package/release/baselib-plain-pretty.js +157 -31
- package/release/baselib-plain-ugly.js +5 -5
- package/release/compiler.js +724 -426
- package/release/signatures.json +29 -29
- package/session.vim +4 -4
- package/setup.cfg +2 -2
- package/src/ast.pyj +7 -0
- package/src/baselib-containers.pyj +41 -4
- package/src/baselib-errors.pyj +4 -3
- package/src/baselib-internal.pyj +47 -18
- package/src/baselib-str.pyj +16 -3
- package/src/compiler.pyj +36 -36
- package/src/errors.pyj +30 -30
- package/src/lib/aes.pyj +646 -646
- package/src/lib/collections.pyj +227 -3
- package/src/lib/copy.pyj +120 -120
- package/src/lib/elementmaker.pyj +83 -83
- package/src/lib/encodings.pyj +126 -126
- package/src/lib/gettext.pyj +569 -569
- package/src/lib/itertools.pyj +580 -580
- package/src/lib/math.pyj +193 -193
- package/src/lib/operator.pyj +11 -11
- package/src/lib/pprint.pyj +455 -0
- package/src/lib/random.pyj +118 -118
- package/src/lib/react.pyj +74 -74
- package/src/lib/statistics.pyj +0 -0
- package/src/lib/traceback.pyj +63 -63
- package/src/lib/uuid.pyj +77 -77
- package/src/monaco-language-service/completions.js +21 -14
- package/src/monaco-language-service/diagnostics.js +2 -2
- package/src/monaco-language-service/dts.js +58 -15
- package/src/monaco-language-service/package.json +3 -0
- package/src/output/classes.pyj +25 -2
- package/src/output/codegen.pyj +4 -1
- package/src/output/comments.pyj +45 -45
- package/src/output/exceptions.pyj +201 -201
- package/src/output/jsx.pyj +164 -164
- package/src/output/treeshake.pyj +182 -182
- package/src/output/utils.pyj +72 -72
- package/src/parse.pyj +42 -7
- package/src/string_interpolation.pyj +72 -72
- package/src/tokenizer.pyj +18 -2
- package/src/unicode_aliases.pyj +576 -576
- package/src/utils.pyj +192 -192
- package/test/_import_one.pyj +37 -37
- package/test/_import_two/__init__.pyj +11 -11
- package/test/_import_two/level2/deep.pyj +4 -4
- package/test/_import_two/other.pyj +6 -6
- package/test/_import_two/sub.pyj +13 -13
- package/test/aes_vectors.pyj +421 -421
- package/test/annotations.pyj +80 -80
- package/test/baselib.pyj +23 -0
- package/test/chainmap.pyj +185 -0
- package/test/dataclasses.pyj +3 -4
- package/test/decorators.pyj +77 -77
- package/test/docstrings.pyj +39 -39
- package/test/elementmaker_test.pyj +45 -45
- package/test/enum.pyj +1 -1
- package/test/functions.pyj +151 -151
- package/test/generators.pyj +41 -41
- package/test/generic.pyj +370 -370
- package/test/internationalization.pyj +73 -73
- package/test/lint.pyj +164 -164
- package/test/loops.pyj +85 -85
- package/test/numpy.pyj +734 -734
- package/test/pprint.pyj +232 -0
- package/test/python_features.pyj +1 -1
- package/test/repl.pyj +121 -121
- package/test/scoped_flags.pyj +76 -76
- package/test/statistics.pyj +224 -0
- package/test/str.pyj +4 -4
- package/test/unit/index.js +455 -0
- package/test/unit/language-service-completions.js +2 -0
- package/test/unit/language-service-dts.js +113 -0
- package/test/unit/language-service-hover.js +455 -455
- package/test/unit/language-service.js +135 -2
- package/test/unit/web-repl.js +349 -1
- package/tools/compiler.d.ts +367 -367
- package/tools/completer.js +131 -131
- package/tools/export.js +4 -2
- package/tools/gettext.js +185 -185
- package/tools/ini.js +65 -65
- package/tools/msgfmt.js +187 -187
- package/tools/repl.js +223 -223
- package/tools/test.js +118 -118
- package/tools/utils.js +141 -128
- package/tools/web_repl.js +95 -95
- package/try +41 -41
- package/web-repl/env.js +196 -196
- package/web-repl/index.html +163 -163
- package/web-repl/prism.css +139 -139
- package/web-repl/prism.js +113 -113
- package/web-repl/rapydscript.js +228 -226
- package/web-repl/sha1.js +25 -25
package/PYTHON_GAPS.md
CHANGED
|
@@ -5,6 +5,9 @@ or behave differently in RapydScript-NS, with a focus on what is relevant and us
|
|
|
5
5
|
browser context. Server-side features (file I/O, subprocesses, sockets, threading, etc.)
|
|
6
6
|
are excluded as they do not apply.
|
|
7
7
|
|
|
8
|
+
Items that are fully supported — even if only behind a flag — are not listed here. See the
|
|
9
|
+
README for the full feature and module support tables.
|
|
10
|
+
|
|
8
11
|
---
|
|
9
12
|
|
|
10
13
|
## 1. Silent Behavioral Differences (Gotchas)
|
|
@@ -12,23 +15,7 @@ are excluded as they do not apply.
|
|
|
12
15
|
These features exist but behave differently from Python in ways that will silently produce
|
|
13
16
|
wrong results — no error is raised.
|
|
14
17
|
|
|
15
|
-
### 1.1
|
|
16
|
-
|
|
17
|
-
**Python:** `%` always returns a non-negative result (true modulo).
|
|
18
|
-
```python
|
|
19
|
-
-7 % 3 # → 2 (Python)
|
|
20
|
-
-7 % 3 # → -1 (RapydScript default — JS remainder semantics)
|
|
21
|
-
```
|
|
22
|
-
**Status:** Fixed when using `from __python__ import overload_operators` or
|
|
23
|
-
`from __python__ import python_modulo`. In bare mode (no flags) the JS remainder semantics
|
|
24
|
-
still apply.
|
|
25
|
-
|
|
26
|
-
**Impact:** Any algorithm relying on modular arithmetic (wrapping, circular indexing) may
|
|
27
|
-
produce wrong results in code that does not use the Python operator flags.
|
|
28
|
-
|
|
29
|
-
---
|
|
30
|
-
|
|
31
|
-
### 1.2 `is` / `is not` — Identity vs. Equality
|
|
18
|
+
### 1.1 `is` / `is not` — Identity vs. Equality
|
|
32
19
|
|
|
33
20
|
**Python:** `is` tests object identity (pointer comparison).
|
|
34
21
|
**RapydScript:** `is` compiles to `===` (strict equality), so `x is y` is true whenever
|
|
@@ -48,43 +35,7 @@ The recommended pattern — using a unique sentinel object — works correctly.
|
|
|
48
35
|
|
|
49
36
|
---
|
|
50
37
|
|
|
51
|
-
### 1.
|
|
52
|
-
|
|
53
|
-
**Python:** Too few or too many positional arguments raises `TypeError` at call time.
|
|
54
|
-
**RapydScript default:** Extra args are silently discarded; missing args become `undefined`.
|
|
55
|
-
|
|
56
|
-
```python
|
|
57
|
-
def f(a, b):
|
|
58
|
-
return a + b
|
|
59
|
-
|
|
60
|
-
f(1, 2, 3) # Python: TypeError. RapydScript default: silently returns 3
|
|
61
|
-
f(1) # Python: TypeError. RapydScript default: returns NaN (1 + undefined)
|
|
62
|
-
```
|
|
63
|
-
**Status:** Argument count and type-annotation enforcement is now available via the
|
|
64
|
-
`type_enforce` flag on function definitions (emits runtime checks). Not enabled by default
|
|
65
|
-
because it adds overhead to every call. Developers writing library code with strict APIs
|
|
66
|
-
should opt in.
|
|
67
|
-
|
|
68
|
-
---
|
|
69
|
-
|
|
70
|
-
### 1.4 Positional-Only and Keyword-Only Parameters Not Enforced
|
|
71
|
-
|
|
72
|
-
**Python:** Positional-only params (`/`) cannot be passed by keyword; keyword-only params
|
|
73
|
-
(`*`) cannot be passed positionally. Both raise `TypeError` on violations.
|
|
74
|
-
**RapydScript:** Violations are silently discarded — the param gets `undefined` with no error.
|
|
75
|
-
|
|
76
|
-
```python
|
|
77
|
-
def f(a, b, /, *, c):
|
|
78
|
-
return a + b + c
|
|
79
|
-
|
|
80
|
-
f(1, b=2, c=3) # Python: TypeError (b is positional-only)
|
|
81
|
-
# RapydScript: b silently becomes undefined, a=1, c=3
|
|
82
|
-
```
|
|
83
|
-
**Impact:** API design contracts expressed via param ordering are not enforced.
|
|
84
|
-
|
|
85
|
-
---
|
|
86
|
-
|
|
87
|
-
### 1.5 String Encoding — UTF-16 Surrogate Pairs
|
|
38
|
+
### 1.2 String Encoding — UTF-16 Surrogate Pairs
|
|
88
39
|
|
|
89
40
|
**Python:** Strings are sequences of Unicode code points (full 21-bit range).
|
|
90
41
|
**RapydScript:** Strings are JS strings — UTF-16. Emoji and other non-BMP characters
|
|
@@ -103,7 +54,7 @@ produce wrong lengths or corrupt characters when sliced.
|
|
|
103
54
|
|
|
104
55
|
---
|
|
105
56
|
|
|
106
|
-
### 1.
|
|
57
|
+
### 1.3 `global` Scoping in Nested Functions
|
|
107
58
|
|
|
108
59
|
**Python:** `global x` inside a nested function forces `x` to refer to the module-level
|
|
109
60
|
variable, bypassing any intermediate closure scopes.
|
|
@@ -115,7 +66,7 @@ scope silently.
|
|
|
115
66
|
|
|
116
67
|
---
|
|
117
68
|
|
|
118
|
-
### 1.
|
|
69
|
+
### 1.4 Numeric Dict Keys Are Coerced to Strings
|
|
119
70
|
|
|
120
71
|
**Python:** `d = {}; d[1] = 'a'; d['1'] = 'b'; len(d) == 2` (integer and string keys distinct).
|
|
121
72
|
**RapydScript:** The Python `dict` type (backed by ES6 `Map`) stores them distinctly, but
|
|
@@ -126,17 +77,7 @@ when interoperating with JS APIs that return plain objects.
|
|
|
126
77
|
|
|
127
78
|
---
|
|
128
79
|
|
|
129
|
-
### 1.
|
|
130
|
-
|
|
131
|
-
**Python:** `Exception('msg').args == ('msg',)` and `.message` is not a standard attribute.
|
|
132
|
-
**RapydScript:** `.message` is the primary attribute (JS `Error` convention). `.args` is
|
|
133
|
-
not populated as a tuple with the message.
|
|
134
|
-
|
|
135
|
-
**Impact:** Code accessing `.args[0]` to get the error message will get `undefined`.
|
|
136
|
-
|
|
137
|
-
---
|
|
138
|
-
|
|
139
|
-
### 1.9 Multiple Inheritance MRO
|
|
80
|
+
### 1.5 Multiple Inheritance MRO
|
|
140
81
|
|
|
141
82
|
**Python:** C3 linearization guarantees a deterministic and consistent method resolution order.
|
|
142
83
|
**RapydScript:** Built on the JS prototype chain. In diamond inheritance or complex hierarchies
|
|
@@ -149,18 +90,7 @@ name. Hard to debug because no error is raised.
|
|
|
149
90
|
|
|
150
91
|
## 2. Missing Language Features
|
|
151
92
|
|
|
152
|
-
### 2.1 `
|
|
153
|
-
|
|
154
|
-
`__slots__ = ['x', 'y']` is parsed and accepted but has no runtime effect — arbitrary
|
|
155
|
-
attributes can still be set on instances. No `AttributeError` is raised for assignments to
|
|
156
|
-
undeclared attributes.
|
|
157
|
-
|
|
158
|
-
**Browser relevance:** Used frequently for memory efficiency and API documentation. Enforcement
|
|
159
|
-
via `Object.seal()` or a `Proxy`-based guard would be possible in modern browsers.
|
|
160
|
-
|
|
161
|
-
---
|
|
162
|
-
|
|
163
|
-
### 2.2 `__del__` Destructor — No Guaranteed Finalizer
|
|
93
|
+
### 2.1 `__del__` Destructor — No Guaranteed Finalizer
|
|
164
94
|
|
|
165
95
|
`__del__` methods are not called reliably. JavaScript's GC is non-deterministic and provides
|
|
166
96
|
no equivalent to CPython's reference-counting finalizer.
|
|
@@ -173,15 +103,17 @@ that timing is not guaranteed.
|
|
|
173
103
|
|
|
174
104
|
---
|
|
175
105
|
|
|
176
|
-
### 2.
|
|
106
|
+
### 2.2 `locals()` Always Returns Empty Dict
|
|
177
107
|
|
|
178
|
-
|
|
179
|
-
|
|
108
|
+
`vars()`, `locals()`, and `globals()` all exist as builtins. JavaScript provides no mechanism
|
|
109
|
+
to introspect local variables at runtime, so `locals()` always returns an empty dict.
|
|
110
|
+
`globals()` works on module-level/global state, and `vars(obj)` introspects the passed object.
|
|
111
|
+
Python code that uses `locals()` for string template substitution
|
|
180
112
|
(e.g., `'{x}'.format(**locals())`) will break silently.
|
|
181
113
|
|
|
182
114
|
---
|
|
183
115
|
|
|
184
|
-
### 2.
|
|
116
|
+
### 2.3 `from module import *` Not Allowed
|
|
185
117
|
|
|
186
118
|
Star imports are intentionally unsupported to prevent namespace pollution. Python developers
|
|
187
119
|
who rely on them (e.g., `from math import *`) must enumerate imports explicitly.
|
|
@@ -190,13 +122,15 @@ who rely on them (e.g., `from math import *`) must enumerate imports explicitly.
|
|
|
190
122
|
|
|
191
123
|
---
|
|
192
124
|
|
|
193
|
-
### 2.
|
|
125
|
+
### 2.4 `asynccontextmanager` Not Available
|
|
194
126
|
|
|
195
127
|
`contextlib.asynccontextmanager` is absent. Only synchronous `@contextmanager` is implemented.
|
|
128
|
+
`async with` itself is also not supported — async context managers need `.acquire()`/`.release()`
|
|
129
|
+
calls instead.
|
|
196
130
|
|
|
197
131
|
---
|
|
198
132
|
|
|
199
|
-
### 2.
|
|
133
|
+
### 2.5 f-string Debugging Format `f'{x=}'` Not Supported
|
|
200
134
|
|
|
201
135
|
Python 3.8+ supports `f'{x=}'` which expands to `f'x={repr(x)}'`. This is not implemented.
|
|
202
136
|
|
|
@@ -207,7 +141,7 @@ print(f'{x=}') # Python: "x=42". RapydScript: syntax error or wrong output
|
|
|
207
141
|
|
|
208
142
|
---
|
|
209
143
|
|
|
210
|
-
### 2.
|
|
144
|
+
### 2.6 Ellipsis Evaluates to `undefined`
|
|
211
145
|
|
|
212
146
|
`...` (Ellipsis) parses as a valid expression but evaluates to JS `undefined` rather than
|
|
213
147
|
Python's `Ellipsis` singleton object. Code that stores `...` in containers or checks
|
|
@@ -219,26 +153,35 @@ Python's `Ellipsis` singleton object. Code that stores `...` in containers or ch
|
|
|
219
153
|
|
|
220
154
|
These are absent from `src/lib/` and have no substitute.
|
|
221
155
|
|
|
222
|
-
### 3.1 `
|
|
156
|
+
### 3.1 `enum.IntEnum`, `IntFlag`, and `Flag`
|
|
223
157
|
|
|
224
|
-
`
|
|
225
|
-
|
|
226
|
-
|
|
158
|
+
The `enum` module provides `Enum` but not `IntEnum` (auto-comparable with integers),
|
|
159
|
+
`StrEnum` (Python 3.11+), `IntFlag`, or `Flag` (bitfield enums). These are common in protocol
|
|
160
|
+
implementations, permission systems, and state machines.
|
|
161
|
+
|
|
162
|
+
```python
|
|
163
|
+
from enum import IntEnum
|
|
164
|
+
class Color(IntEnum):
|
|
165
|
+
RED = 1
|
|
166
|
+
GREEN = 2
|
|
167
|
+
Color.RED < Color.GREEN # True — comparison with int semantics
|
|
168
|
+
```
|
|
227
169
|
|
|
228
170
|
---
|
|
229
171
|
|
|
230
|
-
### 3.2 `
|
|
172
|
+
### 3.2 `hashlib` — Cryptographic Hashing
|
|
231
173
|
|
|
232
|
-
`
|
|
233
|
-
|
|
174
|
+
`hashlib.sha256`, `hashlib.md5`, etc. The Web Crypto API provides `crypto.subtle.digest`
|
|
175
|
+
but its async/buffer-based interface is awkward. A thin `hashlib`-compatible wrapper over
|
|
176
|
+
`crypto.subtle` with a synchronous-friendly API (using the sync `crypto.getRandomValues`)
|
|
177
|
+
for non-cryptographic hashes would be valuable.
|
|
234
178
|
|
|
235
179
|
---
|
|
236
180
|
|
|
237
|
-
### 3.3 `
|
|
181
|
+
### 3.3 `fractions` — Rational Arithmetic
|
|
238
182
|
|
|
239
|
-
`
|
|
240
|
-
|
|
241
|
-
is lighter-weight and doesn't require the full numpy import.
|
|
183
|
+
`Fraction(numerator, denominator)` with full arithmetic. Useful for music theory apps,
|
|
184
|
+
math tutoring tools, and any domain requiring exact rational computation.
|
|
242
185
|
|
|
243
186
|
---
|
|
244
187
|
|
|
@@ -249,42 +192,11 @@ for browser-based code editors, version comparison tools, and fuzzy matching UIs
|
|
|
249
192
|
|
|
250
193
|
---
|
|
251
194
|
|
|
252
|
-
### 3.5 `
|
|
253
|
-
|
|
254
|
-
`pprint.pformat` / `pprint.pprint`. Primarily a debugging/REPL aid. Given the in-browser
|
|
255
|
-
REPL in this project, implementing `pprint` would make output more readable.
|
|
256
|
-
|
|
257
|
-
---
|
|
195
|
+
### 3.5 `decimal` — Decimal Arithmetic
|
|
258
196
|
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
but its async/buffer-based interface is awkward. A thin `hashlib`-compatible wrapper over
|
|
263
|
-
`crypto.subtle` with a synchronous-friendly API (using the sync `crypto.getRandomValues`)
|
|
264
|
-
for non-cryptographic hashes would be valuable.
|
|
265
|
-
|
|
266
|
-
---
|
|
267
|
-
|
|
268
|
-
### 3.7 `enum.IntEnum` and `enum.Flag`
|
|
269
|
-
|
|
270
|
-
The `enum` module provides `Enum` but not `IntEnum` (auto-comparable with integers),
|
|
271
|
-
`StrEnum` (Python 3.11+), or `Flag` (bitfield enums). These are common in protocol
|
|
272
|
-
implementations, permission systems, and state machines.
|
|
273
|
-
|
|
274
|
-
```python
|
|
275
|
-
from enum import IntEnum
|
|
276
|
-
class Color(IntEnum):
|
|
277
|
-
RED = 1
|
|
278
|
-
GREEN = 2
|
|
279
|
-
Color.RED < Color.GREEN # True — comparison with int semantics
|
|
280
|
-
```
|
|
281
|
-
|
|
282
|
-
---
|
|
283
|
-
|
|
284
|
-
### 3.8 `collections.ChainMap`
|
|
285
|
-
|
|
286
|
-
`ChainMap` provides a multi-level dict lookup (like layered config or scope chains) without
|
|
287
|
-
copying. Not currently in `collections.pyj`.
|
|
197
|
+
`Decimal` arithmetic avoids floating-point rounding errors. Essential for financial
|
|
198
|
+
calculations in browser apps (e-commerce, budgeting tools). JS does not have a built-in
|
|
199
|
+
equivalent; a pure-JS implementation would need to be compiled in.
|
|
288
200
|
|
|
289
201
|
---
|
|
290
202
|
|
|
@@ -404,17 +316,15 @@ The `jstype()` builtin is the RS equivalent of JS's `typeof`.
|
|
|
404
316
|
|
|
405
317
|
## 5. Summary Priority Table
|
|
406
318
|
|
|
319
|
+
Priority weighs frequency-of-need, effort-to-implement, and whether a workaround exists.
|
|
320
|
+
|
|
407
321
|
| Priority | Feature | Effort | Impact |
|
|
408
322
|
|---|---|---|---|
|
|
409
|
-
| High | `enum.IntEnum`, `Flag` | Medium | Protocol and permission modeling |
|
|
410
|
-
|
|
|
411
|
-
| Medium | `pprint` module | Low | REPL output quality |
|
|
412
|
-
| Medium | `collections.ChainMap` | Low | Multi-level scope/config dicts |
|
|
413
|
-
| Medium | f-string `f'{x=}'` debugging format | Low | Developer experience |
|
|
414
|
-
| Medium | `__slots__` enforcement via `Proxy` | Medium | Memory + API documentation |
|
|
323
|
+
| High | `enum.IntEnum`, `IntFlag`, `Flag` | Medium | Protocol and permission modeling; bitfield enums |
|
|
324
|
+
| Medium | `hashlib` shim over Web Crypto | Medium | Avoids verbatim Web Crypto calls in user code |
|
|
415
325
|
| Medium | `fractions` module | Medium | Exact rational arithmetic |
|
|
416
|
-
| Medium | `
|
|
417
|
-
| Low | `
|
|
418
|
-
| Low | `difflib` module | High | Text diff, fuzzy matching |
|
|
419
|
-
| Low | `asynccontextmanager` | Medium | Async resource management |
|
|
326
|
+
| Medium | f-string `f'{x=}'` debugging format | Low | Developer experience |
|
|
327
|
+
| Low | `asynccontextmanager` + `async with` | Medium | Async resource management |
|
|
420
328
|
| Low | `__del__` via `FinalizationRegistry` | Medium | Resource cleanup (best-effort) |
|
|
329
|
+
| Low | `difflib` module | High | Text diff, fuzzy matching |
|
|
330
|
+
| Low | `decimal` module | High | Financial calculations |
|
package/README.md
CHANGED
|
@@ -1381,19 +1381,28 @@ ba += bytearray([7, 8]) # in-place concatenation
|
|
|
1381
1381
|
|
|
1382
1382
|
RapydScript provides a `long` builtin backed by JavaScript's native `BigInt`,
|
|
1383
1383
|
giving you arbitrary-precision integers beyond the safe range of JS `Number`.
|
|
1384
|
+
You can use the `long()` function or Python-style `n` suffix literals:
|
|
1384
1385
|
|
|
1385
1386
|
```python
|
|
1387
|
+
# Literal syntax (preferred)
|
|
1388
|
+
a = 10n
|
|
1389
|
+
b = 3n
|
|
1390
|
+
c = 0xFFn # hex
|
|
1391
|
+
d = 0b1010n # binary
|
|
1392
|
+
e = 0o77n # octal
|
|
1393
|
+
|
|
1394
|
+
# Function syntax
|
|
1386
1395
|
a = long(10)
|
|
1387
1396
|
b = long(3)
|
|
1388
1397
|
|
|
1389
|
-
a + b #
|
|
1390
|
-
a - b #
|
|
1391
|
-
a * b #
|
|
1392
|
-
a // b #
|
|
1393
|
-
a % b #
|
|
1394
|
-
a ** b #
|
|
1395
|
-
long(-7) // long(2) #
|
|
1396
|
-
long(-7) % long(3) #
|
|
1398
|
+
a + b # 13n
|
|
1399
|
+
a - b # 7n
|
|
1400
|
+
a * b # 30n
|
|
1401
|
+
a // b # 3n — floor division (Python semantics, not JS truncation)
|
|
1402
|
+
a % b # 1n — Python-style modulo (result has same sign as divisor)
|
|
1403
|
+
a ** b # 1000n
|
|
1404
|
+
long(-7) // long(2) # -4n — floors toward −∞ (JS BigInt would give −3)
|
|
1405
|
+
long(-7) % long(3) # 2n — result matches sign of divisor
|
|
1397
1406
|
```
|
|
1398
1407
|
|
|
1399
1408
|
#### Precision beyond JS Number
|
|
@@ -1402,9 +1411,13 @@ The main motivation for `long` is numbers outside the safe integer range of
|
|
|
1402
1411
|
JavaScript `Number` (`2^53 − 1 = 9007199254740991`):
|
|
1403
1412
|
|
|
1404
1413
|
```python
|
|
1405
|
-
n =
|
|
1406
|
-
str(n)
|
|
1407
|
-
str(n +
|
|
1414
|
+
n = 9007199254740993n # 2^53 + 1 — cannot be represented as a JS Number
|
|
1415
|
+
str(n) # '9007199254740993' (exact)
|
|
1416
|
+
str(n + 1n) # '9007199254740994' (still exact)
|
|
1417
|
+
|
|
1418
|
+
# equivalent using long():
|
|
1419
|
+
n = long('9007199254740993')
|
|
1420
|
+
str(n + long(1))
|
|
1408
1421
|
```
|
|
1409
1422
|
|
|
1410
1423
|
#### Operator overloading
|
|
@@ -3299,16 +3312,26 @@ finally:
|
|
|
3299
3312
|
cleanup()
|
|
3300
3313
|
```
|
|
3301
3314
|
|
|
3315
|
+
Like Python, exceptions accept variadic arguments stored in `.args`:
|
|
3316
|
+
|
|
3317
|
+
```py
|
|
3318
|
+
e = ValueError('bad input', 42)
|
|
3319
|
+
print(e.args) # ['bad input', 42]
|
|
3320
|
+
print(e.args[0]) # 'bad input'
|
|
3321
|
+
print(e.message) # 'bad input' (first arg, for JS Error compatibility)
|
|
3322
|
+
```
|
|
3323
|
+
|
|
3302
3324
|
You can create your own Exception classes by inheriting from `Exception`, which
|
|
3303
3325
|
is the JavaScript Error class, for more details on this, see the [MDN documentation](https://developer.mozilla.org/en-US/docs/JavaScript/Reference/Global_Objects/Error).
|
|
3304
3326
|
|
|
3305
3327
|
```py
|
|
3306
3328
|
class MyError(Exception):
|
|
3307
|
-
def __init__(self,
|
|
3308
|
-
self
|
|
3309
|
-
self.
|
|
3329
|
+
def __init__(self, code, detail):
|
|
3330
|
+
Exception.__init__(self, code, detail)
|
|
3331
|
+
self.code = code
|
|
3332
|
+
self.detail = detail
|
|
3310
3333
|
|
|
3311
|
-
raise MyError('
|
|
3334
|
+
raise MyError(404, 'not found')
|
|
3312
3335
|
```
|
|
3313
3336
|
|
|
3314
3337
|
You can catch multiple exception types in one `except` clause. Both the comma form and the tuple form are supported:
|
|
@@ -3455,7 +3478,7 @@ One of Python's main strengths is the number of libraries available to the devel
|
|
|
3455
3478
|
# fields(), asdict(), astuple(), replace(), is_dataclass(), frozen=True, order=True
|
|
3456
3479
|
abc # ABC base class, @abstractmethod, Protocol, @runtime_checkable;
|
|
3457
3480
|
# abstract enforcement at instantiation; ABC.register() virtual subclasses
|
|
3458
|
-
collections # namedtuple, deque, Counter, OrderedDict, defaultdict
|
|
3481
|
+
collections # namedtuple, deque, Counter, OrderedDict, defaultdict, ChainMap
|
|
3459
3482
|
copy # copy (shallow), deepcopy; honours __copy__ / __deepcopy__ hooks
|
|
3460
3483
|
typing # TYPE_CHECKING, Any, Union, Optional, List, Dict, Set, Tuple, TypeVar,
|
|
3461
3484
|
# Generic, Protocol, Callable, Literal, Final, TypedDict, NamedTuple,
|
|
@@ -3465,6 +3488,8 @@ One of Python's main strengths is the number of libraries available to the devel
|
|
|
3465
3488
|
# product, permutations, combinations, combinations_with_replacement
|
|
3466
3489
|
io # StringIO (in-memory text stream), BytesIO (in-memory binary stream)
|
|
3467
3490
|
base64 # b64encode/decode, urlsafe_b64encode/decode, b32encode/decode, b16encode/decode, encodebytes/decodebytes
|
|
3491
|
+
statistics # mean, median, mode, variance, stdev, quantiles, correlation,
|
|
3492
|
+
# linear_regression, NormalDist
|
|
3468
3493
|
|
|
3469
3494
|
For the most part, the logic implemented in these libraries functions identically to the Python versions. I'd be happy to include more libraries, if other members of the community want them. However, unlike most other Python-to-JavaScript compilers, RapydScript doesn't need them to be complete since there are already tons of available JavaScript libraries that it can use natively.
|
|
3470
3495
|
|
|
@@ -3998,6 +4023,7 @@ Python Feature Coverage
|
|
|
3998
4023
|
| `super()` — 0-arg and 2-arg forms | `super().method()` and `super(Cls, self).method()` both work |
|
|
3999
4024
|
| `except TypeA, TypeB as e:` | RapydScript comma-separated form; catches multiple exception types |
|
|
4000
4025
|
| `except (TypeA, TypeError) as e:` | Tuple form also supported |
|
|
4026
|
+
| `Exception.args` variadic constructor | `Exception('a', 'b').args == ['a', 'b']`; `.message` set to first arg for JS compatibility; works on all builtin and custom exception subclasses |
|
|
4001
4027
|
| `except*` / `ExceptionGroup` (Python 3.11+) | Full support: `ExceptionGroup` class with `subgroup()`/`split()`; `except*` dispatches to typed handlers, re-raises unmatched; bare `except*:` catches all remaining |
|
|
4002
4028
|
| `try / else` | `else` block runs only when no exception was raised |
|
|
4003
4029
|
| `for / else` | `else` block runs when loop completes without `break`; nested break isolation works |
|
|
@@ -4044,6 +4070,7 @@ Python Feature Coverage
|
|
|
4044
4070
|
| f-strings, `str.format()`, `format()` builtin, all common `str.*` methods | Fully supported; includes `f'{x=}'` debug format (prints `x=<value>`), format-spec (`f'{x=:.2f}'`), and conversion (`f'{x=!r}'`) |
|
|
4045
4071
|
| `abs()`, `divmod()`, `any()`, `all()`, `sum()`, `min()`, `max()` | All work |
|
|
4046
4072
|
| `sorted()`, `reversed()`, `zip()`, `map()`, `filter()` | All work |
|
|
4073
|
+
| `list.sort()` / `sorted()` — `key`, `reverse`, comparators, `__lt__` | `key` and `reverse` keyword arguments both work; a positional **two-argument** function is auto-detected as a comparator (JS-style `.sort((a, b) => …)` / `functools.cmp_to_key` semantics) while a one-argument function is treated as a `key`; custom objects are ordered through their `__lt__` method (with a reflected `__gt__` fallback); the sort is stable, so equal elements keep their original order even under `reverse=True` |
|
|
4047
4074
|
| `zip(strict=True)` | Raises `ValueError` when iterables have different lengths; equal-length iterables work normally |
|
|
4048
4075
|
| `set` with full union/intersection/difference API | Fully supported |
|
|
4049
4076
|
| `isinstance()`, `hasattr()`, `getattr()`, `setattr()`, `dir()` | All work |
|
|
@@ -4078,7 +4105,7 @@ Python Feature Coverage
|
|
|
4078
4105
|
| `float.is_integer()` | Returns `True` if the float has no fractional part (i.e. is a whole number), `False` otherwise. `float('inf').is_integer()` and `float('nan').is_integer()` both return `False`, matching Python semantics. Added to `Number.prototype` in the baselib so it works on any numeric literal or variable. |
|
|
4079
4106
|
| `int.bit_length()` | Returns the number of bits needed to represent the integer in binary, excluding the sign and leading zeros. `(0).bit_length()` → `0`; `(255).bit_length()` → `8`; `(256).bit_length()` → `9`; sign is ignored (`(-5).bit_length()` → `3`). Added to `Number.prototype` in the baselib. |
|
|
4080
4107
|
| Arithmetic type coercion — `TypeError` on incompatible operands | `1 + '1'` raises `TypeError: unsupported operand type(s) for +: 'int' and 'str'`; all arithmetic operators (`+`, `-`, `*`, `/`, `//`, `%`, `**`) enforce compatible types in their `ρσ_op_*` helpers. `bool` is treated as numeric (like Python's `int` subclass). Activated by `overload_operators` (on by default). String `+` string and numeric `+` numeric are allowed; mixed types raise `TypeError` with a Python-style message. |
|
|
4081
|
-
| `long(val[, base])` — arbitrary-precision integers
|
|
4108
|
+
| `long(val[, base])` and `42n` literal — arbitrary-precision integers | Backed by JS `BigInt`. Literal syntax: `42n`, `0xFFn`, `0b1010n`, `0o77n`. Function syntax: `long(42)`, `long('ff', 16)`, `long('1010', 2)`, `long(True)`. Arithmetic: `+`, `-`, `*`, `//`, `%`, `**` — `//` and `%` follow Python floor-division semantics (floor toward −∞), not JS BigInt truncation. `/` raises `TypeError` (use `//`). Bitwise: `&`, `\|`, `^`, `<<`, `>>`. Comparisons: `<`, `<=`, `>`, `>=`, `==`, `!=`. `isinstance(x, long)` works. Mixing `long` with `int` or `float` raises `TypeError`. Requires `BigInt` (Chrome 67+, Firefox 68+, Safari 14+, Node 10.3+). |
|
|
4082
4109
|
| `complex(real=0, imag=0)` and complex literals `3+4j` | Full complex number type via `ρσ_complex` class. `complex(real, imag)`, `complex(string)` (parses `'3+4j'`), and `j`/`J` imaginary literal suffix (e.g. `4j`, `3.5J`). Attributes: `.real`, `.imag`. Methods: `conjugate()`, `__abs__()`, `__bool__()`, `__repr__()`, `__str__()`. Arithmetic: `+`, `-`, `*`, `/`, `**` via dunder methods (or operator overloading with `overload_operators`). `abs(z)` dispatches `__abs__`. `isinstance(z, complex)` works. String representation matches Python: `(3+4j)`, `4j`, `(3-0j)`. |
|
|
4083
4110
|
| `eval(expr[, globals[, locals]])` | String literals are compiled as **RapydScript source** at compile time (the compiler parses and transpiles the string, just like Python's `eval` takes Python source). `eval(expr)` maps to native JS direct `eval` for scope access. `eval(expr, globals)` / `eval(expr, globals, locals)` use `Function` constructor with explicit bindings; `locals` override `globals`. Runtime `ρσ_` helpers referenced in the compiled string are automatically injected into the Function scope. Only string *literals* are transformed at compile time; dynamic strings are passed through unchanged. |
|
|
4084
4111
|
| `exec(code[, globals[, locals]])` | String literals are compiled as **RapydScript source** at compile time. Executes the compiled code string; always returns `None`. Without `globals`/`locals` uses native `eval` (scope access). With `globals`/`locals` uses `Function` constructor — mutable objects (lists, dicts) passed in `globals` are accessible by reference, so side-effects are visible after the call. `ρσ_dict` instances (created when `dict_literals` flag is active) are correctly unwrapped via their `jsmap` backing store. |
|
|
@@ -4142,7 +4169,6 @@ This restores the original RapydScript behavior: plain JS objects for `{}`, no o
|
|
|
4142
4169
|
|
|
4143
4170
|
| Feature | Notes |
|
|
4144
4171
|
|---------------------------------------|-----------------------------------------------------------------------------------------|
|
|
4145
|
-
| `__slots__` enforcement | Accepted, but does not restrict attribute assignment |
|
|
4146
4172
|
| `locals()` | Returns an empty `dict`. JS has no runtime mechanism for introspecting local variables. |
|
|
4147
4173
|
| `input(prompt)` | There is no simple cli input in browser; use `prompt()` |
|
|
4148
4174
|
| `compile()` | Python compile/code objects have no JS equivalent |
|
|
@@ -4163,7 +4189,7 @@ Modules with a `src/lib/` implementation available are marked ✅. All others ar
|
|
|
4163
4189
|
| `random` | ✅ | RC4-seeded PRNG in `src/lib/random.pyj` |
|
|
4164
4190
|
| `re` | ✅ | Regex wrapper in `src/lib/re.pyj`; uses the JS engine — full PCRE-level support on modern runtimes: positive/negative lookbehind (ES2018+, including variable-width), unicode via automatic `u` flag (ES2015+), `re.fullmatch()`, `re.S`/`re.NOFLAG` aliases. `MatchObject.start()`/`.end()` return exact positions on runtimes with the ES2022 `d` flag (Node 18+); heuristic fallback on older runtimes. Conditional groups `(?(id)yes\|no)` are not supported (JS limitation) and raise `re.error`. |
|
|
4165
4191
|
| `encodings` | ✅ | UTF-8 encode/decode helpers and low-level base64 utilities; for the standard Python API use the `base64` module instead |
|
|
4166
|
-
| `collections` | ✅ | `defaultdict`, `Counter`, `OrderedDict`, `deque`
|
|
4192
|
+
| `collections` | ✅ | `defaultdict`, `Counter`, `OrderedDict`, `deque`, `namedtuple`, `ChainMap` |
|
|
4167
4193
|
| `functools` | ✅ | `reduce`, `partial`, `wraps`, `lru_cache` |
|
|
4168
4194
|
| `itertools` | ✅ | Common iteration tools |
|
|
4169
4195
|
| `numpy` | ✅ | Full numpy-like library in `src/lib/numpy.pyj`; `numpy.random` and `numpy.linalg` sub-modules |
|
|
@@ -4187,11 +4213,15 @@ Modules with a `src/lib/` implementation available are marked ✅. All others ar
|
|
|
4187
4213
|
| `textwrap` | ✅ | `wrap(text[, width=70[, ...]])`, `fill(text[, width=70[, ...]])`, `shorten(text, width[, ...])`, `dedent(text)`, `indent(text, prefix[, predicate])`, `TextWrapper` class in `src/lib/textwrap.pyj`; `TextWrapper` supports all standard options: `width`, `initial_indent`, `subsequent_indent`, `expand_tabs`, `tabsize`, `replace_whitespace`, `fix_sentence_endings`, `break_long_words`, `break_on_hyphens`, `drop_whitespace`, `max_lines`, `placeholder`; module-level `wrap`/`fill`/`shorten` accept the same options as explicit keyword parameters; `shorten()` normalises internal whitespace before truncating; `break_on_hyphens=True` (default) splits on em-dashes (2+ hyphens) between word characters, matching Python 3 behaviour |
|
|
4188
4214
|
| `logging` | ✅ | `getLogger(name)`, `basicConfig(**kwargs)`, `debug/info/warning/error/critical/exception/log()` module-level shortcuts, `disable(level)`, `addLevelName(level, name)`, `getLevelName(level)`, `captureWarnings(capture)`, `makeLogRecord(dict)`, `setLogRecordFactory(factory)`, `getLogRecordFactory()` in `src/lib/logging.pyj`; `Logger` class with `setLevel`, `isEnabledFor`, `getEffectiveLevel`, `addHandler`, `removeHandler`, `hasHandlers`, `addFilter`, `removeFilter`, `debug/info/warning/error/critical/exception/log` methods; `Handler` base class; `StreamHandler(stream=None)` (writes to `console.debug/info/warn/error` when no stream given, or to any object with `.write(s)`); `NullHandler`; `Formatter(fmt, datefmt, style)` with full `%(attr)s/d/f` record formatting and `formatTime(record, datefmt)` (supports `%Y %m %d %H %M %S %f` strftime codes); `Filter(name)` and `Filterer` mixin; `LogRecord` with `getMessage()` supporting `%s/%d/%f/%e/%g/%x/%o/%%` %-formatting; level constants `NOTSET=0`, `DEBUG=10`, `INFO=20`, `WARNING=30`, `ERROR=40`, `CRITICAL=50`; full logger hierarchy (dotted names, `propagate`, `parent`); `lastResort` handler; note: `FileHandler` raises `NotImplementedError` (no file I/O in JS); `exception()` logs at ERROR without automatic exc_info capture |
|
|
4189
4215
|
| `heapq` | ✅ | `heappush(heap, item)`, `heappop(heap)`, `heapify(x)`, `heapreplace(heap, item)`, `heappushpop(heap, item)`, `nsmallest(n, iterable[, key])`, `nlargest(n, iterable[, key])` in `src/lib/heapq.pyj`; min-heap operations on plain lists; heap invariant maintained by sift-up/sift-down (ported from CPython); `nsmallest`/`nlargest` support an optional `key` function; `heappop` and `heapreplace` raise `IndexError` on an empty heap; original iterable is not mutated by `nsmallest`/`nlargest` |
|
|
4216
|
+
| `pprint` | ✅ | `pformat(object, ...)` → str, `pprint(object[, stream], ...)`, `pp(object, ...)` (same as `pprint` but `sort_dicts=False` by default), `saferepr(object)`, `isreadable(object)`, `isrecursive(object)`, `PrettyPrinter` class in `src/lib/pprint.pyj`; keyword options `indent` (default 1), `width` (default 80), `depth`, `compact`, `sort_dicts` (default True), `underscore_numbers` (accepted, currently a no-op); a value's `repr()` is used when it fits within `width`, otherwise lists/tuples/dicts/sets/frozensets are broken across multiple lines with Python-style indentation; recursive references are detected and rendered as `<Recursion on … with id=…>`; pretty-prints RapydScript `dict`/`set`/`frozenset`, plain JS objects, and arrays; `pprint`/`pp` write to a `stream` object's `.write()` (defaulting to stdout via `print()`) |
|
|
4217
|
+
| `statistics` | ✅ | `mean`, `fmean`, `geometric_mean`, `harmonic_mean`, `median`, `median_low`, `median_high`, `median_grouped`, `mode`, `multimode`, `variance`, `pvariance`, `stdev`, `pstdev`, `quantiles`, `covariance`, `correlation`, `linear_regression` in `src/lib/statistics.pyj`; `NormalDist` class (`.mean`/`.median`/`.mode`/`.stdev`/`.variance` properties, `pdf()`, `cdf()`, `inv_cdf()`, `quantiles()`, `zscore()`, `overlap()`, `samples(n[, seed])`, `from_samples()`, plus arithmetic with scalars and other `NormalDist` instances); `StatisticsError` (a `ValueError` subclass); every data argument may be a list, a JS array, a string, or any iterable; `correlation()` supports `method='ranked'` (Spearman); `quantiles()` supports `method='inclusive'`/`'exclusive'`; `linear_regression()` returns an object with `.slope`/`.intercept`; all computation is IEEE-754 double precision (no `Fraction`/`Decimal` preservation), and `cdf()`/`overlap()` use a rational error-function approximation accurate to ~1e-7 |
|
|
4218
|
+
| `decimal` | ❌ | Fixed-precision decimal arithmetic not available; JS `Number` is IEEE-754 only |
|
|
4219
|
+
| `fractions` | ❌ | Rational arithmetic (`Fraction(num, den)`) not available |
|
|
4220
|
+
| `difflib` | ❌ | `unified_diff`, `SequenceMatcher`, `get_close_matches` not available |
|
|
4190
4221
|
| `inspect` | ❌ | `signature`, `getmembers`, `isfunction` etc. not available |
|
|
4191
4222
|
| `struct` | ❌ | Binary packing/unpacking not available |
|
|
4192
4223
|
| `hashlib` | ❌ | MD5, SHA-256 etc. not available; use Web Crypto API via verbatim JS |
|
|
4193
4224
|
| `hmac` | ❌ | Keyed hashing not available |
|
|
4194
|
-
| `pprint` | ❌ | Pretty-printing not available |
|
|
4195
4225
|
| `unittest` | ❌ | Not available; RapydScript uses a custom test runner (`node bin/rapydscript test`) |
|
|
4196
4226
|
|
|
4197
4227
|
---
|
|
@@ -4206,7 +4236,7 @@ Features that exist in RapydScript but behave differently from standard Python:
|
|
|
4206
4236
|
| `//` floor division on floats | `math.floor(a/b)` always | uses `Math.floor` - same result for well-behaved floats |
|
|
4207
4237
|
| `%` on negative numbers | Result takes the sign of the divisor (`-7 % 3 == 2`) | Same as Python by default (via `python_modulo`, on by default). Disable with `from __python__ import no_python_modulo` to revert to raw JS remainder semantics. |
|
|
4208
4238
|
| `global` / `nonlocal` scoping | Full cross-scope declaration | `global` works for module-level; if a variable exists in both an intermediate outer scope **and** the module-level scope, the outer scope takes precedence (differs from Python where `global` always forces module-level) |
|
|
4209
|
-
| `Exception.message` | Not standard; use `.args[0]` | `.
|
|
4239
|
+
| `Exception.message` | Not standard; use `.args[0]` | `.args` is populated (like Python); `.message` also set to first arg for JS `Error` compatibility |
|
|
4210
4240
|
| Function call argument count | Too few args → `TypeError`; too many → `TypeError` | Too few args → extra params are `undefined`; too many → extras silently discarded. No `TypeError` is raised in either case. |
|
|
4211
4241
|
| Positional-only param enforcement | Passing by keyword raises `TypeError` | Passing by keyword is silently ignored — the named arg is discarded and the parameter gets `undefined` (no error raised) |
|
|
4212
4242
|
| Keyword-only param enforcement | Passing positionally raises `TypeError` | Passing positionally raises no error — the extra positional arg is silently discarded and the default value is used |
|
package/TODO.md
CHANGED
|
@@ -1,34 +1,9 @@
|
|
|
1
1
|
|
|
2
|
-
### libraries
|
|
3
|
-
|
|
4
|
-
- The 7n literal isn't supported by the parser — use BigInt()
|
|
5
|
-
|
|
6
2
|
- remove repl_mode and make repl make a new context for each "run" press
|
|
7
3
|
|
|
8
4
|
- vscode plugin based on language service?
|
|
9
5
|
|
|
10
6
|
|
|
11
|
-
I would like you to add support for [python
|
|
12
|
-
|
|
13
|
-
### Async generator example
|
|
14
|
-
|
|
15
|
-
```py
|
|
16
|
-
# `async def` + `yield` makes an async generator. The function returns an
|
|
17
|
-
# async iterator immediately; values are pulled with `await it.next()` or
|
|
18
|
-
# consumed with `async for`.
|
|
19
|
-
|
|
20
|
-
from asyncio import sleep
|
|
21
|
-
|
|
22
|
-
async def countdown(n):
|
|
23
|
-
while n > 0:
|
|
24
|
-
await sleep(0) # cooperative yield to the event loop
|
|
25
|
-
yield n
|
|
26
|
-
n -= 1
|
|
27
|
-
|
|
28
|
-
async def main():
|
|
29
|
-
async for x in countdown(3):
|
|
30
|
-
print(x) # prints 3, then 2, then 1
|
|
7
|
+
I would like you to add support for [python style __slots__ enforcement] to rapydscript. It should have the same syntax as the Python implementation, and be transpiled into equivalent javascript. Ensure with unit tests that it transpiles and the output JS runs correctly, and that the language service correctly handles it in parsed code. Make sure it works in the web-repl. Update the README if it has any outdated info about this, and the PYTHON_FEATURE_COVERAGE report. Add a simple example to the bottom of the TODO document using this feature (make no other changes to that file). Remove the suggestion from PYTHON_GAPS if it is there. Run the full unit test suite to check for regressions.
|
|
31
8
|
|
|
32
|
-
main()
|
|
33
|
-
```
|
|
34
9
|
|
package/add-toc-to-readme
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
#!/bin/sh
|
|
2
|
-
exec node_modules/doctoc/doctoc.js --title '**Contents**' README.md
|
|
1
|
+
#!/bin/sh
|
|
2
|
+
exec node_modules/doctoc/doctoc.js --title '**Contents**' README.md
|