rapydscript-ns 0.9.2 → 0.9.3
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 +19 -0
- package/HACKING.md +103 -103
- package/LICENSE +24 -24
- package/PYTHON_GAPS.md +420 -0
- package/README.md +153 -29
- package/TODO.md +16 -118
- package/add-toc-to-readme +2 -2
- package/bin/export +75 -75
- package/bin/rapydscript +70 -70
- package/bin/web-repl-export +102 -102
- package/build +2 -2
- package/language-service/index.js +237 -8
- package/memory/project_string_impl.md +43 -0
- package/package.json +1 -1
- package/publish.py +37 -37
- package/release/baselib-plain-pretty.js +248 -38
- package/release/baselib-plain-ugly.js +8 -8
- package/release/compiler.js +778 -277
- package/release/signatures.json +30 -30
- package/session.vim +4 -4
- package/setup.cfg +2 -2
- package/src/ast.pyj +4 -1
- package/src/baselib-builtins.pyj +56 -2
- package/src/baselib-containers.pyj +2 -0
- package/src/baselib-errors.pyj +7 -3
- package/src/baselib-internal.pyj +51 -6
- package/src/baselib-str.pyj +5 -3
- package/src/compiler.pyj +36 -36
- package/src/errors.pyj +30 -30
- package/src/lib/aes.pyj +646 -646
- package/src/lib/asyncio.pyj +534 -0
- package/src/lib/base64.pyj +399 -0
- package/src/lib/bisect.pyj +73 -0
- package/src/lib/collections.pyj +1 -1
- package/src/lib/copy.pyj +120 -120
- package/src/lib/csv.pyj +494 -0
- package/src/lib/elementmaker.pyj +83 -83
- package/src/lib/encodings.pyj +126 -126
- package/src/lib/gettext.pyj +569 -569
- package/src/lib/heapq.pyj +98 -0
- package/src/lib/html.pyj +382 -0
- package/src/lib/http/__init__.pyj +98 -0
- package/src/lib/http/client.pyj +304 -0
- package/src/lib/http/cookies.pyj +236 -0
- package/src/lib/itertools.pyj +580 -580
- package/src/lib/logging.pyj +672 -0
- package/src/lib/math.pyj +193 -193
- package/src/lib/operator.pyj +11 -11
- package/src/lib/pythonize.pyj +20 -20
- package/src/lib/random.pyj +118 -118
- package/src/lib/react.pyj +74 -74
- package/src/lib/string.pyj +357 -0
- package/src/lib/textwrap.pyj +329 -0
- package/src/lib/traceback.pyj +63 -63
- package/src/lib/urllib/__init__.pyj +14 -0
- package/src/lib/urllib/error.pyj +66 -0
- package/src/lib/urllib/parse.pyj +475 -0
- package/src/lib/urllib/request.pyj +86 -0
- package/src/lib/uuid.pyj +77 -77
- package/src/monaco-language-service/analyzer.js +5 -2
- package/src/monaco-language-service/completions.js +26 -0
- package/src/monaco-language-service/diagnostics.js +202 -3
- package/src/monaco-language-service/dts.js +550 -550
- package/src/monaco-language-service/scope.js +1 -0
- package/src/output/comments.pyj +45 -45
- package/src/output/exceptions.pyj +201 -201
- package/src/output/functions.pyj +152 -6
- package/src/output/jsx.pyj +164 -164
- package/src/output/loops.pyj +17 -2
- package/src/output/modules.pyj +1 -1
- package/src/output/operators.pyj +15 -0
- package/src/output/stream.pyj +0 -1
- package/src/output/treeshake.pyj +182 -182
- package/src/output/utils.pyj +72 -72
- package/src/parse.pyj +80 -17
- package/src/string_interpolation.pyj +72 -72
- package/src/tokenizer.pyj +1 -1
- 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/async_generators.pyj +144 -0
- package/test/asyncio.pyj +307 -0
- package/test/base64.pyj +202 -0
- package/test/bisect.pyj +178 -0
- package/test/csv.pyj +405 -0
- package/test/decorators.pyj +77 -77
- package/test/docstrings.pyj +39 -39
- package/test/elementmaker_test.pyj +45 -45
- package/test/float_special.pyj +64 -0
- package/test/functions.pyj +151 -151
- package/test/generators.pyj +41 -41
- package/test/generic.pyj +370 -370
- package/test/heapq.pyj +174 -0
- package/test/html.pyj +212 -0
- package/test/http.pyj +259 -0
- package/test/imports.pyj +79 -72
- package/test/internationalization.pyj +73 -73
- package/test/lint.pyj +164 -164
- package/test/logging.pyj +356 -0
- package/test/long.pyj +130 -0
- package/test/loops.pyj +85 -85
- package/test/numpy.pyj +734 -734
- package/test/parenthesized_with.pyj +141 -0
- package/test/python_compat.pyj +3 -5
- package/test/python_modulo.pyj +76 -0
- package/test/python_modulo_off.pyj +21 -0
- package/test/repl.pyj +121 -121
- package/test/scoped_flags.pyj +76 -76
- package/test/str.pyj +14 -0
- package/test/string.pyj +245 -0
- package/test/textwrap.pyj +172 -0
- package/test/type_display.pyj +48 -0
- package/test/type_enforcement.pyj +164 -0
- package/test/unit/index.js +14 -6
- package/test/unit/language-service-completions.js +119 -0
- package/test/unit/language-service-dts.js +543 -543
- package/test/unit/language-service-hover.js +455 -455
- package/test/unit/language-service-scope.js +32 -0
- package/test/unit/language-service.js +127 -3
- package/test/unit/run-language-service.js +17 -3
- package/test/unit/web-repl.js +2094 -29
- package/test/urllib.pyj +193 -0
- package/tools/compile.js +1 -1
- package/tools/compiler.d.ts +367 -367
- package/tools/completer.js +131 -131
- package/tools/embedded_compiler.js +7 -7
- package/tools/gettext.js +185 -185
- package/tools/ini.js +65 -65
- package/tools/msgfmt.js +187 -187
- package/tools/repl.js +223 -223
- package/tools/test.js +118 -118
- package/tools/utils.js +128 -128
- package/tools/web_repl.js +95 -95
- package/try +41 -41
- package/web-repl/env.js +196 -196
- package/web-repl/index.html +163 -163
- package/web-repl/main.js +1 -1
- package/web-repl/prism.css +139 -139
- package/web-repl/prism.js +113 -113
- package/web-repl/rapydscript.js +224 -224
- package/web-repl/sha1.js +25 -25
- package/test/omit_function_metadata.pyj +0 -20
package/PYTHON_GAPS.md
ADDED
|
@@ -0,0 +1,420 @@
|
|
|
1
|
+
# RapydScript-NS: Python Compatibility Gaps & Browser-Friendly Additions
|
|
2
|
+
|
|
3
|
+
This document identifies features an experienced Python developer would expect that are missing
|
|
4
|
+
or behave differently in RapydScript-NS, with a focus on what is relevant and useful in a
|
|
5
|
+
browser context. Server-side features (file I/O, subprocesses, sockets, threading, etc.)
|
|
6
|
+
are excluded as they do not apply.
|
|
7
|
+
|
|
8
|
+
---
|
|
9
|
+
|
|
10
|
+
## 1. Silent Behavioral Differences (Gotchas)
|
|
11
|
+
|
|
12
|
+
These features exist but behave differently from Python in ways that will silently produce
|
|
13
|
+
wrong results — no error is raised.
|
|
14
|
+
|
|
15
|
+
### 1.1 `%` Modulo on Negative Numbers *(partially resolved)*
|
|
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
|
|
32
|
+
|
|
33
|
+
**Python:** `is` tests object identity (pointer comparison).
|
|
34
|
+
**RapydScript:** `is` compiles to `===` (strict equality), so `x is y` is true whenever
|
|
35
|
+
`x === y`, including for equal primitive values that would be distinct Python objects.
|
|
36
|
+
|
|
37
|
+
```python
|
|
38
|
+
a = 1000
|
|
39
|
+
b = 1000
|
|
40
|
+
a is b # False in Python (separate int objects)
|
|
41
|
+
# True in RapydScript (1000 === 1000)
|
|
42
|
+
```
|
|
43
|
+
**Impact:** Code that checks `obj is None` or `obj is sentinel_value` works correctly.
|
|
44
|
+
Code that expects `is` to return `False` for equal-but-distinct numeric values will be wrong.
|
|
45
|
+
|
|
46
|
+
**Note:** This is already documented in the README, but it is subtle and trips up experts.
|
|
47
|
+
The recommended pattern — using a unique sentinel object — works correctly.
|
|
48
|
+
|
|
49
|
+
---
|
|
50
|
+
|
|
51
|
+
### 1.3 Function Arguments: `TypeError` on Wrong Count *(opt-in, not default)*
|
|
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
|
|
88
|
+
|
|
89
|
+
**Python:** Strings are sequences of Unicode code points (full 21-bit range).
|
|
90
|
+
**RapydScript:** Strings are JS strings — UTF-16. Emoji and other non-BMP characters
|
|
91
|
+
(U+10000–U+10FFFF) are represented as surrogate pairs and count as length 2.
|
|
92
|
+
|
|
93
|
+
```python
|
|
94
|
+
s = '😀'
|
|
95
|
+
len(s) # 1 in Python, 2 in RapydScript
|
|
96
|
+
s[0] # '😀' in Python, '\uD83D' (broken surrogate) in RapydScript
|
|
97
|
+
```
|
|
98
|
+
**RapydScript provides:** `str.ulen()`, `str.uchrs()`, `str.uslice()` for code-point-aware
|
|
99
|
+
operations, but they must be used consciously.
|
|
100
|
+
|
|
101
|
+
**Impact:** Any code handling emoji, Asian CJK extension, or mathematical symbols may silently
|
|
102
|
+
produce wrong lengths or corrupt characters when sliced.
|
|
103
|
+
|
|
104
|
+
---
|
|
105
|
+
|
|
106
|
+
### 1.6 `global` Scoping in Nested Functions
|
|
107
|
+
|
|
108
|
+
**Python:** `global x` inside a nested function forces `x` to refer to the module-level
|
|
109
|
+
variable, bypassing any intermediate closure scopes.
|
|
110
|
+
**RapydScript:** If a variable named `x` exists in an intermediate outer function scope,
|
|
111
|
+
that scope takes precedence over the module-level scope, even with `global x`.
|
|
112
|
+
|
|
113
|
+
**Impact:** Code with complex nested closures + `global` declarations may write to the wrong
|
|
114
|
+
scope silently.
|
|
115
|
+
|
|
116
|
+
---
|
|
117
|
+
|
|
118
|
+
### 1.7 Numeric Dict Keys Are Coerced to Strings
|
|
119
|
+
|
|
120
|
+
**Python:** `d = {}; d[1] = 'a'; d['1'] = 'b'; len(d) == 2` (integer and string keys distinct).
|
|
121
|
+
**RapydScript:** The Python `dict` type (backed by ES6 `Map`) stores them distinctly, but
|
|
122
|
+
literal `{1: 'a', '1': 'b'}` and plain JS object interop may coerce integer keys to strings.
|
|
123
|
+
|
|
124
|
+
**Impact:** Code mixing numeric keys with the same string representation may produce collisions
|
|
125
|
+
when interoperating with JS APIs that return plain objects.
|
|
126
|
+
|
|
127
|
+
---
|
|
128
|
+
|
|
129
|
+
### 1.8 `Exception.args` vs `.message`
|
|
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
|
|
140
|
+
|
|
141
|
+
**Python:** C3 linearization guarantees a deterministic and consistent method resolution order.
|
|
142
|
+
**RapydScript:** Built on the JS prototype chain. In diamond inheritance or complex hierarchies
|
|
143
|
+
the order may differ from Python's C3 MRO.
|
|
144
|
+
|
|
145
|
+
**Impact:** Unexpected method is called when multiple parent classes define the same method
|
|
146
|
+
name. Hard to debug because no error is raised.
|
|
147
|
+
|
|
148
|
+
---
|
|
149
|
+
|
|
150
|
+
## 2. Missing Language Features
|
|
151
|
+
|
|
152
|
+
### 2.1 `__slots__` Not Enforced
|
|
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
|
|
164
|
+
|
|
165
|
+
`__del__` methods are not called reliably. JavaScript's GC is non-deterministic and provides
|
|
166
|
+
no equivalent to CPython's reference-counting finalizer.
|
|
167
|
+
|
|
168
|
+
**Browser relevance:** Low — most `__del__` usage is for file handles or network connections
|
|
169
|
+
that do not exist in the browser. However, the `FinalizationRegistry` API (available in all
|
|
170
|
+
modern browsers since 2021) could provide best-effort `__del__` support for cleanup of
|
|
171
|
+
external resources like WebGL buffers, WebSockets, etc. Worth adding with a clear caveat
|
|
172
|
+
that timing is not guaranteed.
|
|
173
|
+
|
|
174
|
+
---
|
|
175
|
+
|
|
176
|
+
### 2.3 `locals()` Always Returns Empty Dict
|
|
177
|
+
|
|
178
|
+
JavaScript provides no mechanism to introspect local variables at runtime. `locals()` always
|
|
179
|
+
returns an empty dict. Python code that uses `locals()` for string template substitution
|
|
180
|
+
(e.g., `'{x}'.format(**locals())`) will break silently.
|
|
181
|
+
|
|
182
|
+
---
|
|
183
|
+
|
|
184
|
+
### 2.4 `from module import *` Not Allowed
|
|
185
|
+
|
|
186
|
+
Star imports are intentionally unsupported to prevent namespace pollution. Python developers
|
|
187
|
+
who rely on them (e.g., `from math import *`) must enumerate imports explicitly.
|
|
188
|
+
|
|
189
|
+
**Impact:** Not a behavioral difference, but a friction point when porting code.
|
|
190
|
+
|
|
191
|
+
---
|
|
192
|
+
|
|
193
|
+
### 2.5 `asynccontextmanager` Not Available
|
|
194
|
+
|
|
195
|
+
`contextlib.asynccontextmanager` is absent. Only synchronous `@contextmanager` is implemented.
|
|
196
|
+
|
|
197
|
+
---
|
|
198
|
+
|
|
199
|
+
### 2.6 f-string Debugging Format `f'{x=}'` Not Supported
|
|
200
|
+
|
|
201
|
+
Python 3.8+ supports `f'{x=}'` which expands to `f'x={repr(x)}'`. This is not implemented.
|
|
202
|
+
|
|
203
|
+
```python
|
|
204
|
+
x = 42
|
|
205
|
+
print(f'{x=}') # Python: "x=42". RapydScript: syntax error or wrong output
|
|
206
|
+
```
|
|
207
|
+
|
|
208
|
+
---
|
|
209
|
+
|
|
210
|
+
### 2.7 Ellipsis Evaluates to `undefined`
|
|
211
|
+
|
|
212
|
+
`...` (Ellipsis) parses as a valid expression but evaluates to JS `undefined` rather than
|
|
213
|
+
Python's `Ellipsis` singleton object. Code that stores `...` in containers or checks
|
|
214
|
+
`x is Ellipsis` will behave incorrectly.
|
|
215
|
+
|
|
216
|
+
---
|
|
217
|
+
|
|
218
|
+
## 3. Missing Standard Library Modules (Browser-Relevant)
|
|
219
|
+
|
|
220
|
+
These are absent from `src/lib/` and have no substitute.
|
|
221
|
+
|
|
222
|
+
### 3.1 `decimal` — Decimal Arithmetic
|
|
223
|
+
|
|
224
|
+
`Decimal` arithmetic avoids floating-point rounding errors. Essential for financial
|
|
225
|
+
calculations in browser apps (e-commerce, budgeting tools). JS does not have a built-in
|
|
226
|
+
equivalent; a pure-JS implementation would need to be compiled in.
|
|
227
|
+
|
|
228
|
+
---
|
|
229
|
+
|
|
230
|
+
### 3.2 `fractions` — Rational Arithmetic
|
|
231
|
+
|
|
232
|
+
`Fraction(numerator, denominator)` with full arithmetic. Useful for music theory apps,
|
|
233
|
+
math tutoring tools, and any domain requiring exact rational computation.
|
|
234
|
+
|
|
235
|
+
---
|
|
236
|
+
|
|
237
|
+
### 3.3 `statistics` — Statistical Functions
|
|
238
|
+
|
|
239
|
+
`mean`, `median`, `mode`, `stdev`, `variance`, `quantiles`. Very commonly needed in
|
|
240
|
+
data-visualization browser apps. Currently `numpy` covers much of this but `statistics`
|
|
241
|
+
is lighter-weight and doesn't require the full numpy import.
|
|
242
|
+
|
|
243
|
+
---
|
|
244
|
+
|
|
245
|
+
### 3.4 `difflib` — Sequence Comparison
|
|
246
|
+
|
|
247
|
+
`difflib.unified_diff`, `difflib.SequenceMatcher`, `difflib.get_close_matches`. Useful
|
|
248
|
+
for browser-based code editors, version comparison tools, and fuzzy matching UIs.
|
|
249
|
+
|
|
250
|
+
---
|
|
251
|
+
|
|
252
|
+
### 3.5 `pprint` — Pretty Printing
|
|
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
|
+
---
|
|
258
|
+
|
|
259
|
+
### 3.6 `hashlib` — Cryptographic Hashing
|
|
260
|
+
|
|
261
|
+
`hashlib.sha256`, `hashlib.md5`, etc. The Web Crypto API provides `crypto.subtle.digest`
|
|
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`.
|
|
288
|
+
|
|
289
|
+
---
|
|
290
|
+
|
|
291
|
+
## 4. Tricky Patterns That Require Workarounds
|
|
292
|
+
|
|
293
|
+
These are not missing features but patterns that silently work differently or require
|
|
294
|
+
non-obvious syntax.
|
|
295
|
+
|
|
296
|
+
### 4.1 Python String Methods on String Literals
|
|
297
|
+
|
|
298
|
+
String literals in RapydScript do NOT have Python methods (`.strip()`, `.join()`, etc.)
|
|
299
|
+
available by default in all contexts. Using string methods requires:
|
|
300
|
+
|
|
301
|
+
- `from pythonize import strings; strings()` (patches `String.prototype` at runtime), or
|
|
302
|
+
- the `--pythonize-strings` compiler option, or
|
|
303
|
+
- calling `str.strip(s)` (module-level form) instead of `s.strip()`
|
|
304
|
+
|
|
305
|
+
**Impact:** The most common pattern in Python — `s.strip().split(',')` — will throw a
|
|
306
|
+
`TypeError` in some contexts without the above setup.
|
|
307
|
+
|
|
308
|
+
---
|
|
309
|
+
|
|
310
|
+
### 4.2 Multi-line Anonymous Functions in Call Arguments
|
|
311
|
+
|
|
312
|
+
Multi-line `def` blocks cannot be used as inline arguments to function calls:
|
|
313
|
+
|
|
314
|
+
```python
|
|
315
|
+
# Does NOT compile correctly:
|
|
316
|
+
result = map(def(x):
|
|
317
|
+
return x * 2
|
|
318
|
+
, my_list)
|
|
319
|
+
|
|
320
|
+
# Must use a named helper:
|
|
321
|
+
def double(x):
|
|
322
|
+
return x * 2
|
|
323
|
+
result = map(double, my_list)
|
|
324
|
+
```
|
|
325
|
+
|
|
326
|
+
---
|
|
327
|
+
|
|
328
|
+
### 4.3 JavaScript Reserved Words as Identifiers
|
|
329
|
+
|
|
330
|
+
All JavaScript reserved words are also forbidden in RapydScript. Common Python identifiers
|
|
331
|
+
that break: `default`, `delete`, `switch`, `case`, `break`, `var`, `void`, `typeof`,
|
|
332
|
+
`instanceof`. Also cannot be used as keyword argument names in function calls.
|
|
333
|
+
|
|
334
|
+
```python
|
|
335
|
+
def configure(default=None): # 'default' is reserved — compile error
|
|
336
|
+
...
|
|
337
|
+
# Must rename: def configure(dflt=None):
|
|
338
|
+
```
|
|
339
|
+
|
|
340
|
+
---
|
|
341
|
+
|
|
342
|
+
### 4.4 Class Named `Error` Shadows JS `Error`
|
|
343
|
+
|
|
344
|
+
Defining a class named `Error` (e.g., `class Error(Exception)`) compiles to a JS function
|
|
345
|
+
that shadows the global `JS Error` constructor. If that class is then imported in another
|
|
346
|
+
module context (e.g., the web REPL), the import line `var Error = ρσ_modules.mymod.Error`
|
|
347
|
+
shadows the native `Error`, causing infinite recursion in `Exception.__init__`.
|
|
348
|
+
|
|
349
|
+
**Workaround:** Never name a RapydScript class `Error`. Use `MyError`, `AppError`,
|
|
350
|
+
`ValueError` (which is already defined in baselib), etc.
|
|
351
|
+
|
|
352
|
+
---
|
|
353
|
+
|
|
354
|
+
### 4.5 `Cls.method(arg)` vs `@Cls.method`
|
|
355
|
+
|
|
356
|
+
`Cls.method(arg)` compiles to `Cls.prototype.method.call(arg)` (unbound Python 2 style).
|
|
357
|
+
`@Cls.method` as a decorator stores the constructor property and calls it differently.
|
|
358
|
+
These are different lookup paths. A method that must work both as a decorator and as a
|
|
359
|
+
direct class call needs to be installed on both `cls.property` and `cls.prototype.property`.
|
|
360
|
+
|
|
361
|
+
---
|
|
362
|
+
|
|
363
|
+
### 4.6 `range` Cannot Be Shadowed as a Parameter Name
|
|
364
|
+
|
|
365
|
+
```python
|
|
366
|
+
def histogram(data, range): # compile/runtime error — range shadows builtin
|
|
367
|
+
...
|
|
368
|
+
# Must rename: def histogram(data, data_range):
|
|
369
|
+
```
|
|
370
|
+
|
|
371
|
+
This extends to other builtins: prefer prefixed parameter names when a parameter naturally
|
|
372
|
+
matches a builtin name.
|
|
373
|
+
|
|
374
|
+
---
|
|
375
|
+
|
|
376
|
+
### 4.7 Verbatim Blocks Are Truly Verbatim — No Escape Processing
|
|
377
|
+
|
|
378
|
+
Inside `v'...'` blocks, Python escape sequences are NOT processed. `\n` in a v-block
|
|
379
|
+
becomes a literal backslash-n in the JS output, not a newline.
|
|
380
|
+
|
|
381
|
+
```python
|
|
382
|
+
# Wrong — \n is not a newline in the regex:
|
|
383
|
+
pat = v'/foo\nbar/'
|
|
384
|
+
|
|
385
|
+
# Right — write the exact JS you want:
|
|
386
|
+
pat = v'/foo\nbar/' # only works as a real newline if you have a literal newline
|
|
387
|
+
```
|
|
388
|
+
For regex literals, write exactly the JS you want. Double-escaping (`\\n`) produces `\\n`
|
|
389
|
+
in JS (two characters), not a newline.
|
|
390
|
+
|
|
391
|
+
---
|
|
392
|
+
|
|
393
|
+
### 4.8 `jstype(x) is 'number'` for `typeof` Checks
|
|
394
|
+
|
|
395
|
+
Python's `type(x)` does not return a string. For JS-style `typeof` checks:
|
|
396
|
+
|
|
397
|
+
```python
|
|
398
|
+
jstype(x) is 'number' # correct
|
|
399
|
+
type(x) is int # also works for pure RS objects
|
|
400
|
+
```
|
|
401
|
+
The `jstype()` builtin is the RS equivalent of JS's `typeof`.
|
|
402
|
+
|
|
403
|
+
---
|
|
404
|
+
|
|
405
|
+
## 5. Summary Priority Table
|
|
406
|
+
|
|
407
|
+
| Priority | Feature | Effort | Impact |
|
|
408
|
+
|---|---|---|---|
|
|
409
|
+
| High | `enum.IntEnum`, `Flag` | Medium | Protocol and permission modeling |
|
|
410
|
+
| High | `statistics` module | Low | Data analysis without full numpy import |
|
|
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 |
|
|
415
|
+
| Medium | `fractions` module | Medium | Exact rational arithmetic |
|
|
416
|
+
| Medium | `hashlib` shim over Web Crypto | Medium | Hashing without verbatim JS |
|
|
417
|
+
| Low | `decimal` module | High | Financial calculations |
|
|
418
|
+
| Low | `difflib` module | High | Text diff, fuzzy matching |
|
|
419
|
+
| Low | `asynccontextmanager` | Medium | Async resource management |
|
|
420
|
+
| Low | `__del__` via `FinalizationRegistry` | Medium | Resource cleanup (best-effort) |
|