rapydscript-ns 0.8.3 → 0.8.4

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.
Files changed (116) hide show
  1. package/.agignore +1 -1
  2. package/.github/workflows/ci.yml +38 -38
  3. package/=template.pyj +5 -5
  4. package/CHANGELOG.md +8 -0
  5. package/HACKING.md +103 -103
  6. package/LICENSE +24 -24
  7. package/PYTHON_DIFFERENCES_REPORT.md +2 -2
  8. package/PYTHON_FEATURE_COVERAGE.md +13 -13
  9. package/README.md +670 -6
  10. package/TODO.md +5 -6
  11. package/add-toc-to-readme +2 -2
  12. package/bin/export +75 -75
  13. package/bin/rapydscript +70 -70
  14. package/bin/web-repl-export +102 -102
  15. package/build +2 -2
  16. package/language-service/index.js +155 -6
  17. package/package.json +1 -1
  18. package/publish.py +37 -37
  19. package/release/baselib-plain-pretty.js +2006 -229
  20. package/release/baselib-plain-ugly.js +70 -3
  21. package/release/compiler.js +11554 -3870
  22. package/release/signatures.json +31 -29
  23. package/session.vim +4 -4
  24. package/setup.cfg +2 -2
  25. package/src/ast.pyj +93 -1
  26. package/src/baselib-builtins.pyj +22 -1
  27. package/src/baselib-containers.pyj +99 -0
  28. package/src/baselib-errors.pyj +44 -0
  29. package/src/baselib-internal.pyj +94 -4
  30. package/src/baselib-itertools.pyj +97 -97
  31. package/src/baselib-str.pyj +24 -0
  32. package/src/compiler.pyj +36 -36
  33. package/src/errors.pyj +30 -30
  34. package/src/lib/aes.pyj +646 -646
  35. package/src/lib/copy.pyj +120 -0
  36. package/src/lib/elementmaker.pyj +83 -83
  37. package/src/lib/encodings.pyj +126 -126
  38. package/src/lib/gettext.pyj +569 -569
  39. package/src/lib/itertools.pyj +580 -580
  40. package/src/lib/math.pyj +193 -193
  41. package/src/lib/operator.pyj +11 -11
  42. package/src/lib/pythonize.pyj +20 -20
  43. package/src/lib/random.pyj +118 -118
  44. package/src/lib/re.pyj +470 -470
  45. package/src/lib/react.pyj +74 -0
  46. package/src/lib/traceback.pyj +63 -63
  47. package/src/lib/uuid.pyj +77 -77
  48. package/src/monaco-language-service/builtins.js +5 -0
  49. package/src/monaco-language-service/diagnostics.js +25 -3
  50. package/src/monaco-language-service/dts.js +550 -550
  51. package/src/output/classes.pyj +108 -8
  52. package/src/output/codegen.pyj +16 -2
  53. package/src/output/comments.pyj +45 -45
  54. package/src/output/exceptions.pyj +201 -105
  55. package/src/output/functions.pyj +9 -0
  56. package/src/output/jsx.pyj +164 -0
  57. package/src/output/literals.pyj +28 -2
  58. package/src/output/modules.pyj +1 -1
  59. package/src/output/operators.pyj +8 -2
  60. package/src/output/statements.pyj +2 -2
  61. package/src/output/stream.pyj +1 -0
  62. package/src/output/treeshake.pyj +182 -182
  63. package/src/output/utils.pyj +72 -72
  64. package/src/parse.pyj +417 -113
  65. package/src/string_interpolation.pyj +72 -72
  66. package/src/tokenizer.pyj +29 -0
  67. package/src/unicode_aliases.pyj +576 -576
  68. package/src/utils.pyj +192 -192
  69. package/test/_import_one.pyj +37 -37
  70. package/test/_import_two/__init__.pyj +11 -11
  71. package/test/_import_two/level2/deep.pyj +4 -4
  72. package/test/_import_two/other.pyj +6 -6
  73. package/test/_import_two/sub.pyj +13 -13
  74. package/test/aes_vectors.pyj +421 -421
  75. package/test/annotations.pyj +80 -80
  76. package/test/decorators.pyj +77 -77
  77. package/test/docstrings.pyj +39 -39
  78. package/test/elementmaker_test.pyj +45 -45
  79. package/test/functions.pyj +151 -151
  80. package/test/generators.pyj +41 -41
  81. package/test/generic.pyj +370 -370
  82. package/test/imports.pyj +72 -72
  83. package/test/internationalization.pyj +73 -73
  84. package/test/lint.pyj +164 -164
  85. package/test/loops.pyj +85 -85
  86. package/test/numpy.pyj +734 -734
  87. package/test/omit_function_metadata.pyj +20 -20
  88. package/test/python_features.pyj +19 -6
  89. package/test/regexp.pyj +55 -55
  90. package/test/repl.pyj +121 -121
  91. package/test/scoped_flags.pyj +76 -76
  92. package/test/unit/index.js +2177 -64
  93. package/test/unit/language-service-dts.js +543 -543
  94. package/test/unit/language-service-hover.js +455 -455
  95. package/test/unit/language-service.js +590 -4
  96. package/test/unit/web-repl.js +303 -0
  97. package/tools/cli.js +547 -547
  98. package/tools/compile.js +219 -219
  99. package/tools/completer.js +131 -131
  100. package/tools/embedded_compiler.js +251 -251
  101. package/tools/gettext.js +185 -185
  102. package/tools/ini.js +65 -65
  103. package/tools/msgfmt.js +187 -187
  104. package/tools/repl.js +223 -223
  105. package/tools/test.js +118 -118
  106. package/tools/utils.js +128 -128
  107. package/tools/web_repl.js +95 -95
  108. package/try +41 -41
  109. package/web-repl/env.js +196 -74
  110. package/web-repl/index.html +163 -163
  111. package/web-repl/main.js +252 -254
  112. package/web-repl/prism.css +139 -139
  113. package/web-repl/prism.js +113 -113
  114. package/web-repl/rapydscript.js +224 -102
  115. package/web-repl/sha1.js +25 -25
  116. package/hack_demo.pyj +0 -112
package/.agignore CHANGED
@@ -1 +1 @@
1
- lib/*
1
+ lib/*
@@ -1,38 +1,38 @@
1
- name: CI
2
- on: [push, pull_request]
3
- env:
4
- CI: 'true'
5
-
6
- jobs:
7
- test:
8
- name: Test on ${{ matrix.os }} LANG ${{ matrix.lang }}
9
- runs-on: ${{ matrix.os }}
10
- env:
11
- LANG: ${{ matrix.lang }}
12
- LC_ALL: ${{ matrix.lang }}
13
- strategy:
14
- matrix:
15
- include:
16
- - { os: ubuntu-latest, lang: en_US.UTF-8 }
17
- - { os: ubuntu-latest, lang: de_DE.UTF-8}
18
- - { os: ubuntu-latest, lang: hi_IN.UTF-8 }
19
-
20
- - { os: macos-latest, lang: en_US.UTF-8 }
21
- - { os: windows-latest, lang: en_US.UTF-8 }
22
-
23
- steps:
24
- - name: Checkout source code
25
- uses: actions/checkout@master
26
- with:
27
- fetch-depth: 10
28
-
29
- - name: Set up Node ${{ matrix.node }}
30
- uses: actions/setup-node@master
31
-
32
- - name: Install deps
33
- run:
34
- npm install --no-optional
35
-
36
- - name: Test
37
- run:
38
- npm test
1
+ name: CI
2
+ on: [push, pull_request]
3
+ env:
4
+ CI: 'true'
5
+
6
+ jobs:
7
+ test:
8
+ name: Test on ${{ matrix.os }} LANG ${{ matrix.lang }}
9
+ runs-on: ${{ matrix.os }}
10
+ env:
11
+ LANG: ${{ matrix.lang }}
12
+ LC_ALL: ${{ matrix.lang }}
13
+ strategy:
14
+ matrix:
15
+ include:
16
+ - { os: ubuntu-latest, lang: en_US.UTF-8 }
17
+ - { os: ubuntu-latest, lang: de_DE.UTF-8}
18
+ - { os: ubuntu-latest, lang: hi_IN.UTF-8 }
19
+
20
+ - { os: macos-latest, lang: en_US.UTF-8 }
21
+ - { os: windows-latest, lang: en_US.UTF-8 }
22
+
23
+ steps:
24
+ - name: Checkout source code
25
+ uses: actions/checkout@master
26
+ with:
27
+ fetch-depth: 10
28
+
29
+ - name: Set up Node ${{ matrix.node }}
30
+ uses: actions/setup-node@master
31
+
32
+ - name: Install deps
33
+ run:
34
+ npm install --no-optional
35
+
36
+ - name: Test
37
+ run:
38
+ npm test
package/=template.pyj CHANGED
@@ -1,5 +1,5 @@
1
- # vim:fileencoding=utf-8
2
- # License: BSD Copyright: %YEAR%, %USER% <%MAIL%>
3
- from __python__ import hash_literals
4
-
5
- %HERE%
1
+ # vim:fileencoding=utf-8
2
+ # License: BSD Copyright: %YEAR%, %USER% <%MAIL%>
3
+ from __python__ import hash_literals
4
+
5
+ %HERE%
package/CHANGELOG.md CHANGED
@@ -1,3 +1,11 @@
1
+ version 0.8.4
2
+ =======================
3
+ * Added support for jsx
4
+ * Added support for basic React components
5
+ * support for __new__, __getattr__, __setattr__, __delattr__, __class_getitem__, __init_subclass__
6
+ * added `copy` standard library
7
+
8
+
1
9
  version 0.8.0 - 0.8.3
2
10
  =======================
3
11
 
package/HACKING.md CHANGED
@@ -1,103 +1,103 @@
1
- Hacking the RapydScript compiler
2
- =================================
3
-
4
- The RapydScript compiler is written in RapydScript itself and uses the
5
- RapydScript import system to modularize its code. The compiler source code is
6
- in the `src` directory. The compiled compiler is by default in the `release`
7
- directory.
8
-
9
- In order to start hacking on the compiler, run the command
10
-
11
- ```
12
- bin/rapydscript self --complete --test
13
- ```
14
-
15
- This will generate a build of the compiler in the `dev` directory. Now, the
16
- rapydscript command will automatically use this build, rather than the one in
17
- release. If you want to go back to the release build, simply delete the `dev`
18
- directory.
19
-
20
-
21
- Code organization
22
- -------------------
23
-
24
- The way the compiler works, given some RapydScript source code:
25
-
26
- * The source code is lexed into a stream of tokens (`src/tokenzier.pyj`)
27
-
28
- * The tokens are parsed into a Abstract Syntax Tree (`src/parse.pyj and src/ast.pyj`)
29
-
30
- * During parsing any import statement are resolved (this is different from
31
- python, where imports happen at run-time, not compile time).
32
-
33
- * The Abstract Syntax Tree is transformed into the output JavaScript (`src/output/*.pyj`)
34
-
35
- * Various bits of functionality in RapydScript depend upon the *Base Library*
36
- (`src/baselib*.pyj`). This includes things like the basic container types
37
- (list/set/dict) string functions such as `str.format()`, etc. The baselib
38
- is automatically inserted into the start of the output JavaScript.
39
-
40
- The RapydScript standard library can be found in `src/lib`. The various tools,
41
- such as the linter, gettext support, the REPL, etc. are in the `tools`
42
- directory.
43
-
44
- Tests
45
- --------
46
-
47
- The tests are in the test directory and can be run using the command:
48
- ```
49
- rapydscript test
50
- ```
51
-
52
- You can run individual test files by providing the name of the file, as
53
-
54
- ```
55
- rapydscript test classes
56
- ```
57
-
58
- Modifying the compiler
59
- -------------------------
60
-
61
- Edit the files in the `src` directory to make your changes, then use the
62
- `./try` script to test them. This script will compile an updated version of
63
- the compiler with your changes, if any, and use it to run the snippet of code
64
- you pass to it.
65
-
66
- For example:
67
-
68
- ```
69
- ./try 'print("Hello world")'
70
- ```
71
-
72
- will compile `print ("Hello world")` and show you the output on stdout. You can
73
- tell it to omit the baselib, so you can focus on the output, with the `-m`
74
- switch, like this:
75
-
76
- ```
77
- ./try -m 'print("Hello world")'
78
- ```
79
-
80
- You can also have it not print out the JavaScript, instead directly executing the output
81
- JavaScript with the `-x` switch, like this
82
-
83
- ```
84
- ./try -x 'print("Hello world")'
85
- ```
86
-
87
- If you want to test longer sections of code, you can use the `-f` switch to
88
- pass in the path to a RapydScript file to compile, like this:
89
-
90
- ```
91
- ./try -f myfile.pyj
92
- ```
93
-
94
- Once you are happy with your changes, you can build the compiler and run the
95
- test suite, all with a single command:
96
-
97
- ```
98
- ./build
99
- ```
100
-
101
- This will build the compiler with the updated version of itself and then run
102
- the test suite. If all test pass you can commit your changes and send a pull
103
- request :)
1
+ Hacking the RapydScript compiler
2
+ =================================
3
+
4
+ The RapydScript compiler is written in RapydScript itself and uses the
5
+ RapydScript import system to modularize its code. The compiler source code is
6
+ in the `src` directory. The compiled compiler is by default in the `release`
7
+ directory.
8
+
9
+ In order to start hacking on the compiler, run the command
10
+
11
+ ```
12
+ bin/rapydscript self --complete --test
13
+ ```
14
+
15
+ This will generate a build of the compiler in the `dev` directory. Now, the
16
+ rapydscript command will automatically use this build, rather than the one in
17
+ release. If you want to go back to the release build, simply delete the `dev`
18
+ directory.
19
+
20
+
21
+ Code organization
22
+ -------------------
23
+
24
+ The way the compiler works, given some RapydScript source code:
25
+
26
+ * The source code is lexed into a stream of tokens (`src/tokenzier.pyj`)
27
+
28
+ * The tokens are parsed into a Abstract Syntax Tree (`src/parse.pyj and src/ast.pyj`)
29
+
30
+ * During parsing any import statement are resolved (this is different from
31
+ python, where imports happen at run-time, not compile time).
32
+
33
+ * The Abstract Syntax Tree is transformed into the output JavaScript (`src/output/*.pyj`)
34
+
35
+ * Various bits of functionality in RapydScript depend upon the *Base Library*
36
+ (`src/baselib*.pyj`). This includes things like the basic container types
37
+ (list/set/dict) string functions such as `str.format()`, etc. The baselib
38
+ is automatically inserted into the start of the output JavaScript.
39
+
40
+ The RapydScript standard library can be found in `src/lib`. The various tools,
41
+ such as the linter, gettext support, the REPL, etc. are in the `tools`
42
+ directory.
43
+
44
+ Tests
45
+ --------
46
+
47
+ The tests are in the test directory and can be run using the command:
48
+ ```
49
+ rapydscript test
50
+ ```
51
+
52
+ You can run individual test files by providing the name of the file, as
53
+
54
+ ```
55
+ rapydscript test classes
56
+ ```
57
+
58
+ Modifying the compiler
59
+ -------------------------
60
+
61
+ Edit the files in the `src` directory to make your changes, then use the
62
+ `./try` script to test them. This script will compile an updated version of
63
+ the compiler with your changes, if any, and use it to run the snippet of code
64
+ you pass to it.
65
+
66
+ For example:
67
+
68
+ ```
69
+ ./try 'print("Hello world")'
70
+ ```
71
+
72
+ will compile `print ("Hello world")` and show you the output on stdout. You can
73
+ tell it to omit the baselib, so you can focus on the output, with the `-m`
74
+ switch, like this:
75
+
76
+ ```
77
+ ./try -m 'print("Hello world")'
78
+ ```
79
+
80
+ You can also have it not print out the JavaScript, instead directly executing the output
81
+ JavaScript with the `-x` switch, like this
82
+
83
+ ```
84
+ ./try -x 'print("Hello world")'
85
+ ```
86
+
87
+ If you want to test longer sections of code, you can use the `-f` switch to
88
+ pass in the path to a RapydScript file to compile, like this:
89
+
90
+ ```
91
+ ./try -f myfile.pyj
92
+ ```
93
+
94
+ Once you are happy with your changes, you can build the compiler and run the
95
+ test suite, all with a single command:
96
+
97
+ ```
98
+ ./build
99
+ ```
100
+
101
+ This will build the compiler with the updated version of itself and then run
102
+ the test suite. If all test pass you can commit your changes and send a pull
103
+ request :)
package/LICENSE CHANGED
@@ -1,24 +1,24 @@
1
- Copyright (c) 2015-, Kovid Goyal <kovid@kovidgoyal.net>
2
- Copyright (c) 2013-2014, Alexander Tsepkov <atsepkov@pyjeon.com>
3
- All rights reserved.
4
-
5
- Redistribution and use in source and binary forms, with or without
6
- modification, are permitted provided that the following conditions are met:
7
-
8
- * Redistributions of source code must retain the above copyright notice, this
9
- list of conditions and the following disclaimer.
10
-
11
- * Redistributions in binary form must reproduce the above copyright notice,
12
- this list of conditions and the following disclaimer in the documentation
13
- and/or other materials provided with the distribution.
14
-
15
- THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
16
- AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
17
- IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
18
- DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
19
- FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
20
- DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
21
- SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
22
- CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
23
- OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
24
- OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
1
+ Copyright (c) 2015-, Kovid Goyal <kovid@kovidgoyal.net>
2
+ Copyright (c) 2013-2014, Alexander Tsepkov <atsepkov@pyjeon.com>
3
+ All rights reserved.
4
+
5
+ Redistribution and use in source and binary forms, with or without
6
+ modification, are permitted provided that the following conditions are met:
7
+
8
+ * Redistributions of source code must retain the above copyright notice, this
9
+ list of conditions and the following disclaimer.
10
+
11
+ * Redistributions in binary form must reproduce the above copyright notice,
12
+ this list of conditions and the following disclaimer in the documentation
13
+ and/or other materials provided with the distribution.
14
+
15
+ THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
16
+ AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
17
+ IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
18
+ DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
19
+ FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
20
+ DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
21
+ SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
22
+ CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
23
+ OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
24
+ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
@@ -47,12 +47,12 @@ and notes which items are covered by tests.
47
47
  | 35 | `complex()` / `j` suffix | No complex number type | ✓ Yes | Noted in python_features.pyj #42, #59 (skipped) |
48
48
  | 36 | `b'...'` bytes literals | No bytes type; use `encodings` module | ✓ Yes | Noted in python_features.pyj #43 (skipped) |
49
49
  | 37 | `except*` (exception groups) | Not supported (Python 3.11+) | ✓ Yes | Noted in python_features.pyj #44 (skipped) |
50
- | 38 | `__new__` constructor hook | Not supported | ✓ Yes | Noted in python_features.pyj #45 (skipped) |
50
+ | 38 | `__new__` constructor hook | Supported `def __new__(cls, ...)` with `super().__new__(cls)` | ✓ Yes | Now supported; see unit tests `new_basic`, `new_singleton`, etc. |
51
51
  | 39 | `__del__` destructor | Not supported | ✓ Yes | Noted in python_features.pyj #46 (skipped) |
52
52
  | 40 | `__hash__` for set/dict membership | Not dispatched; uses JS identity (`===`) | ✓ Yes | Noted in python_features.pyj #47 (skipped) |
53
53
  | 41 | `__getattr__`/`__setattr__`/`__delattr__` | Not supported | ✓ Yes | Noted in python_features.pyj #48 (skipped) |
54
54
  | 42 | `__getattribute__` | Not supported | ✓ Yes | Noted in python_features.pyj #49 |
55
- | 43 | `__class_getitem__` | Not supported | ✓ Yes | Noted in python_features.pyj #51 (skipped) |
55
+ | 43 | `__class_getitem__` | Supported `Class[item]` compiles to `Class.__class_getitem__(item)` at compile time; implicit classmethod, subclasses inherit with correct `cls` | ✓ Yes | Now supported; see unit tests `class_getitem_*` |
56
56
  | 44 | `__init_subclass__` | Not supported | ✓ Yes | Noted in python_features.pyj #52 (skipped) |
57
57
 
58
58
  ---
@@ -7,6 +7,7 @@
7
7
  | `super()` — 0-arg and 2-arg forms | `super().method()` and `super(Cls, self).method()` both work |
8
8
  | `except TypeA, TypeB as e:` | RapydScript comma-separated form; catches multiple exception types |
9
9
  | `except (TypeA, TypeError) as e:` | Tuple form also supported |
10
+ | `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 |
10
11
  | `try / else` | `else` block runs only when no exception was raised |
11
12
  | `for / else` | `else` block runs when loop completes without `break`; nested break isolation works |
12
13
  | `while / else` | `else` block runs when loop condition becomes `False` without a `break`; nested `break` isolation correct |
@@ -22,6 +23,7 @@
22
23
  | `str.casefold()` | Maps to `.toLowerCase()` |
23
24
  | `str.removeprefix(prefix)` | Returns unchanged string if prefix not found |
24
25
  | `str.removesuffix(suffix)` | Returns unchanged string if suffix not found |
26
+ | `str.expandtabs(tabsize=8)` | Replaces `\t` with spaces to the next tab stop; `\n`/`\r` reset the column counter; `tabsize=0` removes all tabs; available as an instance method after `from pythonize import strings; strings()` |
25
27
  | `str * n` string repetition | Works when `from __python__ import overload_operators` is active |
26
28
  | `list * n` / `n * list` | Works with `overload_operators`; returns a proper RapydScript list |
27
29
  | `list + list` concatenation | `[1,2] + [3,4]` returns `[1, 2, 3, 4]`; `+=` extends in-place. No flag required. |
@@ -34,6 +36,9 @@
34
36
  | `+=`, `-=`, `*=`, `/=`, `//=`, `**=`, `%=`, `&=`, `\|=`, `^=`, `<<=`, `>>=` | All augmented assignments work |
35
37
  | `raise X from Y` exception chaining | Sets `__cause__` on the thrown exception; `from None` also supported |
36
38
  | Starred assignment `a, *b, c = ...` | Works |
39
+ | `[*a, 1, *b]` list spread | Works; any iterable; translates to `[...a, 1, ...b]` |
40
+ | `{*a, 1, *b}` set spread | Works; translates to `ρσ_set([...a, 1, ...b])` |
41
+ | `**expr` in function calls | Works with any expression (variable, attr access, call, dict literal), not just plain names |
37
42
  | `@classmethod`, `@staticmethod`, `@property` / `@prop.setter` | All work |
38
43
  | `{**dict1, **dict2}` dict spread | Works as merge replacement for the missing `\|` operator |
39
44
  | `dict.fromkeys()` | Works with `dict_literals` flag |
@@ -59,12 +64,17 @@
59
64
  | **Truthiness / `__bool__`** | Full Python truthiness via `from __python__ import truthiness`: empty `[]`, `{}`, `set()`, `''` are falsy; `__bool__` is dispatched; `and`/`or` return operand values; `not`, `if`, `while`, `assert`, ternary all use `ρσ_bool()`. |
60
65
  | `frozenset(iterable)` | Immutable set: construction from list/set/iterable; `in`, `len()`, iteration, `copy()`, `union()`, `intersection()`, `difference()`, `symmetric_difference()`, `issubset()`, `issuperset()`, `isdisjoint()` — all return `frozenset`. `isinstance(x, frozenset)` works. Compares equal to a `set` with the same elements via `__eq__`. No mutation methods (`add`, `remove`, etc.). |
61
66
  | `issubclass(cls, classinfo)` | Checks prototype chain; `classinfo` may be a class or tuple of classes; every class is a subclass of itself; raises `TypeError` for non-class arguments. |
62
- | `hash(obj)` | Numbers hash by value (int identity, float → int form if whole); strings use djb2; `None` → 0; booleans → 0/1; objects with `__hash__` dispatch to it; class instances get a stable identity hash; `list`, `set`, `dict` raise `TypeError`. |
67
+ | `hash(obj)` and `__hash__` dunder | Numbers hash by value (int identity, float → int form if whole); strings use djb2; `None` → 0; booleans → 0/1; `def __hash__(self)` in a class is dispatched by `hash()`; class instances without `__hash__` get a stable identity hash; defining `__eq__` without `__hash__` makes the class unhashable (Python semantics — `hash()` raises `TypeError`); `list`, `set`, `dict` raise `TypeError`. |
68
+ | `__getattr__` / `__setattr__` / `__delattr__` / `__getattribute__` dunders | Full attribute-access interception via JS `Proxy`. Classes defining any of these automatically wrap instances. `__getattr__` is called only for missing attributes; `__getattribute__` overrides all lookups; `__setattr__` intercepts every assignment (including those in `__init__`); `__delattr__` intercepts `del obj.attr`. Use `object.__setattr__(self, name, value)` / `object.__getattribute__(self, name)` / `object.__delattr__(self, name)` (compiled to `ρσ_object_setattr` / `ρσ_object_getattr` / `ρσ_object_delattr`) to bypass the hooks and avoid infinite recursion. Subclasses automatically inherit proxy wrapping. Requires a JS environment that supports `Proxy`; gracefully degrades to plain attribute access in environments without `Proxy`. |
69
+ | `__class_getitem__` dunder | `Class[item]` dispatches at compile time to `Class.__class_getitem__(item)`. Behaves as an implicit `@classmethod`: `cls` is bound to the calling class. Subclasses inherit `__class_getitem__` and receive the subclass as `cls`. Multi-argument subscripts (`Class[A, B]`) are passed as a JS array. |
70
+ | `__init_subclass__` hook | Called automatically on the parent class whenever a subclass is created (e.g. `class Child(Base):`). Implicit `@classmethod`: `cls` receives the new subclass. Keyword arguments in the class header (`class Child(Base, tag='x'):`) are forwarded to `__init_subclass__` as keyword arguments. `super().__init_subclass__(**kwargs)` propagates up the hierarchy. No explicit call needed — the compiler emits it after inheritance setup and identity properties are assigned. |
63
71
  | `next(iterator[, default])` | Advances a JS-protocol iterator (`{done, value}`); returns `default` when exhausted if provided, otherwise raises `StopIteration`. Works with `iter()`, `range()`, `enumerate()`, generators, and any object with a `.next()` or `__next__()` method. |
64
72
  | `StopIteration` exception | Defined as a builtin exception class; raised by `next()` when an iterator is exhausted and no default is given. |
65
73
  | `iter(callable, sentinel)` | Two-argument form calls `callable` (no args) repeatedly until the return value equals `sentinel` (strict `===`). Returns a lazy iterator compatible with `for` loops, `next()`, `list()`, and all iterator consumers. Works with plain functions and callable objects (`__call__`). |
66
74
  | `dict \| dict` and `dict \|= dict` (Python 3.9+) | Dict merge via `\|` creates a new merged dict (right-side values win); `\|=` updates in-place. Requires `from __python__ import overload_operators, dict_literals`. |
67
75
  | `slice(start, stop[, step])` | Full Python `slice` class: 1-, 2-, and 3-argument forms; `.start`, `.stop`, `.step` attributes; `.indices(length)` → `(start, stop, step)`; `str()` / `repr()`; `isinstance(s, slice)`; equality `==`; use as subscript `lst[s]` (read, write, `del`) all work. |
76
+ | `__import__(name[, globals, locals, fromlist, level])` | Runtime lookup in the compiled module registry (`ρσ_modules`). Without `fromlist` (or empty `fromlist`) returns the top-level package, matching Python's semantics. `ImportError` / `ModuleNotFoundError` raised for unknown modules. **Constraint**: the module must have been statically imported elsewhere in the source so it is present in `ρσ_modules`. |
77
+ | `ImportError`, `ModuleNotFoundError` | Both defined as runtime exception classes; `ModuleNotFoundError` is a subclass of `ImportError` (same as Python 3.6+). |
68
78
 
69
79
  ---
70
80
 
@@ -72,18 +82,16 @@
72
82
 
73
83
  | Feature | Priority |
74
84
  |-------------------------------------|------------------------------------------------------------------------|
75
- | `complex(real, imag)` | 🟢 Low — no complex number type |
76
85
  | `vars()` / `locals()` / `globals()` | 🟢 Low — not defined; use direct attribute access |
77
- | `str.expandtabs(tabsize)` | 🟢 Low |
78
86
  | `int.bit_length()` | 🟢 Low — useful for bit manipulation |
79
87
  | `float.is_integer()` | 🟢 Low |
80
88
  | `exec(code)` | 🟢 Low — use `v'eval(...)'` for inline JS evaluation |
81
89
  | `eval(expr)` | 🟢 Low — use `v'eval(...)'` for inline JS evaluation |
82
- | `__import__(name)` | 🟢 Low — not supported; use `import` statement |
83
90
  | `input(prompt)` | 🟢 Low — not built in; use `prompt()` via `v'prompt(...)'` |
84
91
  | `bytes(x)` / `bytearray(x)` | 🟢 Low — no built-in bytes type; use `Uint8Array` via verbatim JS |
85
92
  | `object()` | 🟢 Low — base `object` type not exposed; use plain `{}` or a class |
86
93
  | `abc` module — `ABC`, `@abstractmethod`, `Protocol` | 🟢 Low — no abc module; no enforcement of abstract methods |
94
+ | `complex(real, imag)` | 🟢 Low — no complex number type |
87
95
  | `compile()` | 🔴 N/A — Python compile/code objects have no JS equivalent |
88
96
  | `memoryview(obj)` | 🔴 N/A — no buffer protocol in browser context |
89
97
  | `open(path)` | 🔴 N/A — no filesystem access in browser context |
@@ -99,15 +107,8 @@
99
107
  | `__slots__` enforcement | 🟢 Low — accepted but does not restrict attribute assignment |
100
108
  | Complex number literals `3+4j` | 🟢 Low — no `j` suffix; no complex type |
101
109
  | `b'...'` bytes literals | 🟢 Low — no `b` prefix; use the `encodings` module for encoding work |
102
- | `except*` (exception groups, Python 3.11+) | 🟢 Low — no parser support |
103
- | `__new__` constructor hook | 🟢 Low — no alternative constructor support |
104
110
  | `__del__` destructor / finalizer | 🟢 Low — JS has no guaranteed finalizer |
105
- | `__hash__` dunder | 🟢 Low — not dispatched; set/dict use `===` object identity |
106
- | `__getattr__` / `__setattr__` / `__delattr__` | 🟢 Low — no attribute-access interception |
107
- | `__getattribute__` | 🟢 Low — no attribute-lookup override |
108
111
  | `__format__` dunder | 🟢 Low — `format()` builtin not defined; `__format__` not dispatched |
109
- | `__class_getitem__` | 🟢 Low — no `MyClass[T]` generic subscript syntax |
110
- | `__init_subclass__` hook | 🟢 Low |
111
112
 
112
113
  ---
113
114
 
@@ -125,10 +126,10 @@ Modules with a `src/lib/` implementation available are marked ✅. All others ar
125
126
  | `functools` | ✅ | `reduce`, `partial`, `wraps`, `lru_cache` |
126
127
  | `itertools` | ✅ | Common iteration tools |
127
128
  | `numpy` | ✅ | Full numpy-like library in `src/lib/numpy.pyj`; `numpy.random` and `numpy.linalg` sub-modules |
129
+ | `copy` | ✅ | `copy()` shallow copy and `deepcopy()` (circular-ref-safe via memo Map); `__copy__` / `__deepcopy__(memo)` hooks honoured; handles list, set, frozenset, dict, class instances, and plain JS objects |
128
130
  | `typing` | ❌ | `List`, `Dict`, `Optional`, `Union`, `Tuple`, `Generic`, `TypeVar` — none available |
129
131
  | `dataclasses` | ❌ | `@dataclass`, `field()`, `asdict()`, `astuple()` not available |
130
132
  | `contextlib` | ❌ | `contextmanager`, `suppress`, `ExitStack`, `asynccontextmanager` not available |
131
- | `copy` | ❌ | `copy()` / `deepcopy()` not available |
132
133
  | `string` | ❌ | Character constants, `Template`, `Formatter` not available |
133
134
  | `json` | ❌ | No Python wrapper; JS `JSON.parse` / `JSON.stringify` work directly via verbatim JS |
134
135
  | `datetime` | ❌ | `date`, `time`, `datetime`, `timedelta` not available |
@@ -174,7 +175,6 @@ Features that exist in RapydScript but behave differently from standard Python:
174
175
  | 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 |
175
176
  | `is` / `is not` with `NaN` | `math.nan is math.nan` → `True` (same object) | `x is NaN` compiles to `isNaN(x)` (not `x === NaN`), making NaN checks work correctly |
176
177
  | Arithmetic type coercion | `1 + '1'` raises `TypeError` | `1 + '1'` → `'11'`; JS coerces the number to a string |
177
- | `list + list` | Concatenation returns a new list | Now matches Python: `[1,2] + [3,4]` returns `[1, 2, 3, 4]`; `+=` extends the list in-place. No `overload_operators` flag required. (Pre-existing JS `+` coercion is replaced by a lightweight `ρσ_list_add` helper.) |
178
178
  | `<`, `>`, `<=`, `>=` on lists / containers | Element-wise lexicographic comparison | Falls through to JS coercion — operands are stringified first (e.g. `[10] < [9]` is `True` because `'[10]' < '[9]'`). Comparison dunders (`__lt__` etc.) can be defined and called directly but are not auto-dispatched by these operators. |
179
179
  | Default `{}` dict — missing key | `KeyError` raised | Returns `undefined`; use `from __python__ import dict_literals, overload_getitem` to get `KeyError` |
180
180
  | Default `{}` dict — numeric keys | Integer keys are stored as integers | Numeric keys are auto-coerced to strings by the JS engine: `d[1]` and `d['1']` refer to the same slot |