rapydscript-ns 0.8.2 → 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 (141) 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 +39 -0
  5. package/HACKING.md +103 -103
  6. package/LICENSE +24 -24
  7. package/PYTHON_DIFFERENCES_REPORT.md +291 -0
  8. package/PYTHON_FEATURE_COVERAGE.md +106 -15
  9. package/README.md +831 -52
  10. package/TODO.md +4 -286
  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 +4623 -0
  17. package/language-service/language-service.d.ts +40 -0
  18. package/package.json +9 -7
  19. package/publish.py +37 -37
  20. package/release/baselib-plain-pretty.js +2006 -229
  21. package/release/baselib-plain-ugly.js +70 -3
  22. package/release/compiler.js +11554 -3870
  23. package/release/signatures.json +31 -29
  24. package/session.vim +4 -4
  25. package/setup.cfg +2 -2
  26. package/src/ast.pyj +93 -1
  27. package/src/baselib-builtins.pyj +99 -2
  28. package/src/baselib-containers.pyj +107 -4
  29. package/src/baselib-errors.pyj +44 -0
  30. package/src/baselib-internal.pyj +124 -5
  31. package/src/baselib-itertools.pyj +97 -97
  32. package/src/baselib-str.pyj +32 -1
  33. package/src/compiler.pyj +36 -36
  34. package/src/errors.pyj +30 -30
  35. package/src/lib/aes.pyj +646 -646
  36. package/src/lib/collections.pyj +1 -1
  37. package/src/lib/copy.pyj +120 -0
  38. package/src/lib/elementmaker.pyj +83 -83
  39. package/src/lib/encodings.pyj +126 -126
  40. package/src/lib/gettext.pyj +569 -569
  41. package/src/lib/itertools.pyj +580 -580
  42. package/src/lib/math.pyj +193 -193
  43. package/src/lib/numpy.pyj +10 -10
  44. package/src/lib/operator.pyj +11 -11
  45. package/src/lib/pythonize.pyj +20 -20
  46. package/src/lib/random.pyj +118 -118
  47. package/src/lib/re.pyj +470 -470
  48. package/src/lib/react.pyj +74 -0
  49. package/src/lib/traceback.pyj +63 -63
  50. package/src/lib/uuid.pyj +77 -77
  51. package/src/monaco-language-service/analyzer.js +131 -9
  52. package/src/monaco-language-service/builtins.js +17 -2
  53. package/src/monaco-language-service/completions.js +170 -1
  54. package/src/monaco-language-service/diagnostics.js +25 -3
  55. package/src/monaco-language-service/dts.js +550 -550
  56. package/src/monaco-language-service/index.js +17 -0
  57. package/src/monaco-language-service/scope.js +3 -0
  58. package/src/output/classes.pyj +128 -11
  59. package/src/output/codegen.pyj +17 -3
  60. package/src/output/comments.pyj +45 -45
  61. package/src/output/exceptions.pyj +201 -105
  62. package/src/output/functions.pyj +13 -16
  63. package/src/output/jsx.pyj +164 -0
  64. package/src/output/literals.pyj +28 -2
  65. package/src/output/loops.pyj +0 -9
  66. package/src/output/modules.pyj +2 -5
  67. package/src/output/operators.pyj +22 -2
  68. package/src/output/statements.pyj +2 -2
  69. package/src/output/stream.pyj +1 -13
  70. package/src/output/treeshake.pyj +182 -182
  71. package/src/output/utils.pyj +72 -72
  72. package/src/parse.pyj +434 -114
  73. package/src/string_interpolation.pyj +72 -72
  74. package/src/tokenizer.pyj +29 -0
  75. package/src/unicode_aliases.pyj +576 -576
  76. package/src/utils.pyj +192 -192
  77. package/test/_import_one.pyj +37 -37
  78. package/test/_import_two/__init__.pyj +11 -11
  79. package/test/_import_two/level2/deep.pyj +4 -4
  80. package/test/_import_two/other.pyj +6 -6
  81. package/test/_import_two/sub.pyj +13 -13
  82. package/test/aes_vectors.pyj +421 -421
  83. package/test/annotations.pyj +80 -80
  84. package/test/baselib.pyj +4 -4
  85. package/test/classes.pyj +56 -17
  86. package/test/collections.pyj +5 -5
  87. package/test/decorators.pyj +77 -77
  88. package/test/docstrings.pyj +39 -39
  89. package/test/elementmaker_test.pyj +45 -45
  90. package/test/functions.pyj +151 -151
  91. package/test/generators.pyj +41 -41
  92. package/test/generic.pyj +370 -370
  93. package/test/imports.pyj +72 -72
  94. package/test/internationalization.pyj +73 -73
  95. package/test/lint.pyj +164 -164
  96. package/test/loops.pyj +85 -85
  97. package/test/numpy.pyj +734 -734
  98. package/test/omit_function_metadata.pyj +20 -20
  99. package/test/python_compat.pyj +326 -0
  100. package/test/python_features.pyj +129 -29
  101. package/test/regexp.pyj +55 -55
  102. package/test/repl.pyj +121 -121
  103. package/test/scoped_flags.pyj +76 -76
  104. package/test/slice.pyj +105 -0
  105. package/test/str.pyj +25 -0
  106. package/test/unit/fixtures/fibonacci_expected.js +1 -1
  107. package/test/unit/index.js +2296 -71
  108. package/test/unit/language-service-builtins.js +70 -0
  109. package/test/unit/language-service-bundle.js +5 -5
  110. package/test/unit/language-service-completions.js +180 -0
  111. package/test/unit/language-service-dts.js +543 -543
  112. package/test/unit/language-service-hover.js +455 -455
  113. package/test/unit/language-service-index.js +350 -0
  114. package/test/unit/language-service-scope.js +255 -0
  115. package/test/unit/language-service.js +625 -4
  116. package/test/unit/run-language-service.js +1 -0
  117. package/test/unit/web-repl.js +437 -0
  118. package/tools/build-language-service.js +2 -2
  119. package/tools/cli.js +547 -547
  120. package/tools/compile.js +219 -219
  121. package/tools/compiler.js +0 -24
  122. package/tools/completer.js +131 -131
  123. package/tools/embedded_compiler.js +251 -251
  124. package/tools/export.js +3 -37
  125. package/tools/gettext.js +185 -185
  126. package/tools/ini.js +65 -65
  127. package/tools/msgfmt.js +187 -187
  128. package/tools/repl.js +223 -223
  129. package/tools/test.js +118 -118
  130. package/tools/utils.js +128 -128
  131. package/tools/web_repl.js +95 -95
  132. package/try +41 -41
  133. package/web-repl/env.js +196 -74
  134. package/web-repl/index.html +163 -163
  135. package/web-repl/main.js +252 -254
  136. package/web-repl/prism.css +139 -139
  137. package/web-repl/prism.js +113 -113
  138. package/web-repl/rapydscript.js +227 -139
  139. package/web-repl/sha1.js +25 -25
  140. package/hack_demo.pyj +0 -112
  141. package/web-repl/language-service.js +0 -4187
@@ -1,31 +1,33 @@
1
1
  {
2
- "ast": "7a1a1800d9ee7af7f7153eee38002e4e9dcfb71e",
3
- "baselib-builtins": "50927b38fded9bd9dbe14c42a20dd8e930ac021f",
4
- "baselib-containers": "f7ac21a4dfc6311693239ea1eb45e74fae45a3f5",
5
- "baselib-errors": "f2423e1e2489bdd7fb8c8725bb76436898c8008c",
6
- "baselib-internal": "1b77d40970a8ef2d886132dc7c21c9510d2eb4cd",
7
- "baselib-itertools": "ab1f3257642c8d26fab1ff9d392814a459a60cdb",
8
- "baselib-str": "8c396e4fae02ae34b6d3d805becf7bfdd36625ee",
9
- "compiler": "cfbfceb0439fed3302f78d80b303dca713b25e7b",
10
- "errors": "d1b33848d19b141e19cc079cf78421f29b6d2c05",
11
- "output/__init__": "da39a3ee5e6b4b0d3255bfef95601890afd80709",
12
- "output/classes": "d05c1992cc91b337a4e4ff137b0aa3d626e6624b",
13
- "output/codegen": "0519a88c2704fe60b98fe747ca39f6be43b9abf3",
14
- "output/comments": "78ec38d8b34da96c078653e2d0d4049d7003906b",
15
- "output/exceptions": "c7d90155694c7108e94d0940a160ae83725421d7",
16
- "output/functions": "abaa81b171359eb77be6ea87cbdf9d7421d4622b",
17
- "output/literals": "fdbfb744fec8dfea1e1c62cb49767c60160fd402",
18
- "output/loops": "f59cc623320f57edb01953f7877d712758e9f825",
19
- "output/modules": "bd3e3f3f6794fb6e401867b4d011c4e3aab98893",
20
- "output/operators": "f8142836a13b75680cb4874391db9e871fad0cad",
21
- "output/statements": "7d8dfdc0b43e3e430be7ce3b23ffaf1b41408d8c",
22
- "output/stream": "46375cb467477ac898546e818bfdfa5be738c352",
23
- "output/utils": "595968f96f6fdcc51eb41c34d64c92bb595e3cb1",
24
- "parse": "d5c1a77662dfcff841dfcd368d5dbb129a592f5d",
25
- "string_interpolation": "bff1cc76d772d24d35707f6c794f38734ca08376",
26
- "tokenizer": "00fc24a41edac9f9b31735e6290348005a623cef",
27
- "unicode_aliases": "79ac6eaa5e6be44a5397d62c561f854a8fe7528e",
28
- "utils": "c1666db819aa7c8db38697e34e18362e3cb45869",
29
- "#compiler#": "d98fcbb15d08dae74d9c7371ea28fea676642e67",
30
- "#compiled_with#": "d98fcbb15d08dae74d9c7371ea28fea676642e67"
2
+ "ast": "c8f6f1be6f7f73b1b9e2bbf470f5e2e5fff879df",
3
+ "baselib-builtins": "ced189b19392b1f425a1a180b90bc61e5e1b022f",
4
+ "baselib-containers": "d2f534e6530dfb309b074bf7fac082c65779e778",
5
+ "baselib-errors": "a9e8c63e450360fd0bd70642d4c107672d395ccf",
6
+ "baselib-internal": "b020b5154a7ee023ceb5852bf35eeee31e285d87",
7
+ "baselib-itertools": "425f5c45bbd5de894cae891e71ba1a9e9e2063d5",
8
+ "baselib-str": "a00bdd267521d31d97cdc76581f955b6fafb4bae",
9
+ "compiler": "bb16e915c60dc4ffb5bfe98bef411736d19fa297",
10
+ "errors": "257eca38b6de987e5fd80672bec9b9981847e1bd",
11
+ "output\\classes": "a88c3c84ded9049d7a5052fb151d51bdbb600dcd",
12
+ "output\\codegen": "69151b2cd53ff8b3270a122c65e1a0f56735150e",
13
+ "output\\comments": "63b39620f9d6f407aa2d4ddb557d1c60ef296b05",
14
+ "output\\exceptions": "e7d9119550403e6c5730d40b9bc9c923a23d6eb7",
15
+ "output\\functions": "58972ccc4562ab3422317f79f68ea3e00b765279",
16
+ "output\\jsx": "14f32c048301965de7764c5b74b651bc279de937",
17
+ "output\\literals": "287ec4222c79f1ebfa2c6efae925e794cbb931ab",
18
+ "output\\loops": "93afeea09e81382edf1c2f6009f4811430d0ebb8",
19
+ "output\\modules": "15735b9b07260d11ba231fc3439818bd1a54947e",
20
+ "output\\operators": "d9ebb70a00cfe6be60c5d75596edf7986f619644",
21
+ "output\\statements": "94ee0cd084f22aea451b96eb1a9a831084cc4267",
22
+ "output\\stream": "2723d80bc398468e0828f50fb0837095c52f45dc",
23
+ "output\\treeshake": "4a490ba097739d924db9e3cd9eb7718db5e24cae",
24
+ "output\\utils": "e957919bfccb9a3ab510d824a8f2ee3fc2689795",
25
+ "output\\__init__": "da39a3ee5e6b4b0d3255bfef95601890afd80709",
26
+ "parse": "1815f278b2b974ed79973f792a4dbcccfb35c2b8",
27
+ "string_interpolation": "88dce6c2c5ee75126a6838a1506841c6531a0d15",
28
+ "tokenizer": "6c06a87951cc4cfe6256dfa4f22ab3533967e856",
29
+ "unicode_aliases": "7fbcbc9c24adcb2e33fac8d69aaafe5047fcc2c2",
30
+ "utils": "35a2a707c841da851e18c64edac54e7c20b7dfc9",
31
+ "#compiler#": "724970153770773cd9e1ff1e588f17df9c607ee9",
32
+ "#compiled_with#": "724970153770773cd9e1ff1e588f17df9c607ee9"
31
33
  }
package/session.vim CHANGED
@@ -1,4 +1,4 @@
1
- set wildignore+=*.pyj-cached
2
- set wildignore+=node_modules
3
- imap <F4> ρσ_
4
- cmap <F4> ρσ_
1
+ set wildignore+=*.pyj-cached
2
+ set wildignore+=node_modules
3
+ imap <F4> ρσ_
4
+ cmap <F4> ρσ_
package/setup.cfg CHANGED
@@ -1,2 +1,2 @@
1
- [rapydscript]
2
- globals=assert,RapydScript
1
+ [rapydscript]
2
+ globals=assert,RapydScript
package/src/ast.pyj CHANGED
@@ -600,6 +600,9 @@ class AST_Class(AST_Scope):
600
600
  'statements': "[AST_Node*] list of statements in the class scope (excluding method definitions)",
601
601
  'dynamic_properties': '[dict] map of dynamic property names to property descriptors of the form {getter:AST_Method, setter:AST_Method',
602
602
  'classvars': '[dict] map containing all class variables as keys, to be used to easily test for existence of a class variable',
603
+ 'has_new': "[boolean] true if the class defines a __new__ method",
604
+ 'has_attr_dunders': "[boolean] true if the class defines any of __getattr__/__setattr__/__delattr__/__getattribute__",
605
+ 'class_kwargs': "[array] keyword arguments from class header (e.g. class C(Base, key=val):) as [[key_node, value_node], ...]",
603
606
  }
604
607
 
605
608
  def _walk(self, visitor):
@@ -610,6 +613,9 @@ class AST_Class(AST_Scope):
610
613
  self.name._walk(visitor)
611
614
  walk_body(self, visitor)
612
615
  if (self.parent) self.parent._walk(visitor)
616
+ if self.class_kwargs:
617
+ for kw in self.class_kwargs:
618
+ kw[1]._walk(visitor)
613
619
  )
614
620
 
615
621
  class AST_Method(AST_Lambda):
@@ -725,7 +731,8 @@ class AST_Except(AST_Block):
725
731
  "An `except` node for RapydScript, which resides inside the catch block"
726
732
  properties = {
727
733
  'argname': "[AST_SymbolCatch] symbol for the exception",
728
- 'errors': "[AST_SymbolVar*] error classes to catch in this block"
734
+ 'errors': "[AST_SymbolVar*] error classes to catch in this block",
735
+ 'is_star': '[bool] True for except* (exception group) clauses',
729
736
  }
730
737
 
731
738
  def _walk(self, visitor):
@@ -1161,6 +1168,17 @@ class AST_ObjectSpread(AST_Node):
1161
1168
  self.value._walk(visitor)
1162
1169
  )
1163
1170
 
1171
+ class AST_Spread(AST_Node):
1172
+ "A *expr spread item inside a list or set literal: [1, *a, 2]"
1173
+ properties = {
1174
+ 'expression': "[AST_Node] the expression being spread",
1175
+ }
1176
+
1177
+ def _walk(self, visitor):
1178
+ return visitor._visit(self, def():
1179
+ self.expression._walk(visitor)
1180
+ )
1181
+
1164
1182
  class AST_Set(AST_Node):
1165
1183
  "A set literal"
1166
1184
  properties = {
@@ -1360,6 +1378,80 @@ class TreeWalker:
1360
1378
  self = p
1361
1379
  # }}}
1362
1380
 
1381
+ # JSX nodes {{{
1382
+
1383
+ class AST_JSXElement(AST_Node):
1384
+ "A JSX element like <div>...</div> or <Component />"
1385
+ properties = {
1386
+ 'tag': "[string] The tag name (e.g. 'div', 'MyComponent')",
1387
+ 'props': "[AST_JSXAttribute[]] The props/attributes",
1388
+ 'children': "[AST_Node[]] The children",
1389
+ 'self_closing': "[bool] Whether self-closing (no children)"
1390
+ }
1391
+
1392
+ def _walk(self, visitor):
1393
+ return visitor._visit(self, def():
1394
+ for prop in self.props:
1395
+ prop._walk(visitor)
1396
+ for child in self.children:
1397
+ child._walk(visitor)
1398
+ )
1399
+
1400
+ class AST_JSXFragment(AST_Node):
1401
+ "A JSX fragment <>...</>"
1402
+ properties = {
1403
+ 'children': "[AST_Node[]] The children"
1404
+ }
1405
+
1406
+ def _walk(self, visitor):
1407
+ return visitor._visit(self, def():
1408
+ for child in self.children:
1409
+ child._walk(visitor)
1410
+ )
1411
+
1412
+ class AST_JSXAttribute(AST_Node):
1413
+ "A JSX attribute like prop='val', prop={expr}, or just prop (boolean)"
1414
+ properties = {
1415
+ 'name': "[string] The attribute name",
1416
+ 'value': "[AST_Node|null] The value (null for boolean attrs)"
1417
+ }
1418
+
1419
+ def _walk(self, visitor):
1420
+ return visitor._visit(self, def():
1421
+ if self.value:
1422
+ self.value._walk(visitor)
1423
+ )
1424
+
1425
+ class AST_JSXSpread(AST_Node):
1426
+ "A JSX spread attribute {...expr}"
1427
+ properties = {
1428
+ 'expression': "[AST_Node] The spread expression"
1429
+ }
1430
+
1431
+ def _walk(self, visitor):
1432
+ return visitor._visit(self, def():
1433
+ self.expression._walk(visitor)
1434
+ )
1435
+
1436
+ class AST_JSXText(AST_Node):
1437
+ "Text content inside a JSX element"
1438
+ properties = {
1439
+ 'value': "[string] The text content"
1440
+ }
1441
+
1442
+ class AST_JSXExprContainer(AST_Node):
1443
+ "A JSX expression container {expr}"
1444
+ properties = {
1445
+ 'expression': "[AST_Node] The expression"
1446
+ }
1447
+
1448
+ def _walk(self, visitor):
1449
+ return visitor._visit(self, def():
1450
+ self.expression._walk(visitor)
1451
+ )
1452
+
1453
+ # }}}
1454
+
1363
1455
  class Found(Exception):
1364
1456
  pass
1365
1457
 
@@ -20,6 +20,7 @@ def ρσ_bool(val):
20
20
  v'if ((typeof Set === "function" && val instanceof Set) || (typeof Map === "function" && val instanceof Map)) return val.size > 0'
21
21
  v'if (!val.constructor || val.constructor === Object) return Object.keys(val).length > 0'
22
22
  return True
23
+ ρσ_bool.__name__ = 'bool'
23
24
 
24
25
  def ρσ_print(*args, **kwargs):
25
26
  if v'typeof console' is 'object':
@@ -35,6 +36,7 @@ def ρσ_int(val, base):
35
36
  if isNaN(ans):
36
37
  raise ValueError('Invalid literal for int with base ' + (base or 10) + ': ' + val)
37
38
  return ans
39
+ ρσ_int.__name__ = 'int'
38
40
 
39
41
  def ρσ_float(val):
40
42
  if jstype(val) is "number":
@@ -44,6 +46,7 @@ def ρσ_float(val):
44
46
  if isNaN(ans):
45
47
  raise ValueError('Could not convert string to float: ' + arguments[0])
46
48
  return ans
49
+ ρσ_float.__name__ = 'float'
47
50
 
48
51
  def ρσ_arraylike_creator():
49
52
  names = 'Int8Array Uint8Array Uint8ClampedArray Int16Array Uint16Array Int32Array Uint32Array Float32Array Float64Array'.split(' ')
@@ -164,7 +167,22 @@ def ρσ_reversed(iterable):
164
167
  return ans
165
168
  raise TypeError('reversed() can only be called on arrays or strings')
166
169
 
167
- def ρσ_iter(iterable):
170
+ def ρσ_iter(iterable, sentinel):
171
+ # Two-argument form: iter(callable, sentinel) — call repeatedly until sentinel is returned
172
+ if arguments.length >= 2:
173
+ callable_ = iterable
174
+ ans = v'{"_callable":callable_,"_sentinel":sentinel,"_done":false}'
175
+ ans[ρσ_iterator_symbol] = def():
176
+ return this
177
+ ans['next'] = def():
178
+ if this._done:
179
+ return v"{'done':true}"
180
+ val = ρσ_callable_call(this._callable)
181
+ if v'val === this._sentinel':
182
+ this._done = True
183
+ return v"{'done':true}"
184
+ return v"{'done':false,'value':val}"
185
+ return ans
168
186
  # Generate a JavaScript iterator object from iterable
169
187
  if jstype(iterable[ρσ_iterator_symbol]) is 'function':
170
188
  return iterable.keys() if jstype(Map) is 'function' and v'iterable instanceof Map' else iterable[ρσ_iterator_symbol]()
@@ -267,6 +285,23 @@ def ρσ_hasattr(obj, name):
267
285
  def ρσ_get_module(name):
268
286
  return ρσ_modules[name]
269
287
 
288
+ def ρσ__import__(name, globals, locals, fromlist, level):
289
+ # Return the module from the already-compiled ρσ_modules registry.
290
+ # Like Python: without fromlist (or empty fromlist) returns the top-level
291
+ # package; with a non-empty fromlist returns the named (possibly dotted) module.
292
+ # NOTE: the module must have been statically imported elsewhere in the source;
293
+ # __import__ only provides a runtime reference to an already-compiled module.
294
+ if v'typeof ρσ_modules' is 'undefined':
295
+ raise ImportError('No module named \'' + name + '\'')
296
+ if fromlist is not undefined and fromlist is not None and fromlist.length:
297
+ lookup = name
298
+ else:
299
+ lookup = name.split('.')[0]
300
+ module = ρσ_modules[lookup]
301
+ if module is undefined:
302
+ raise ModuleNotFoundError('No module named \'' + lookup + '\'')
303
+ return module
304
+
270
305
  def ρσ_pow(x, y, z):
271
306
  ans = Math.pow(x, y)
272
307
  if z is not undefined:
@@ -307,6 +342,7 @@ def ρσ_hash(obj):
307
342
  }
308
343
  return ρσ_h;
309
344
  }'''
345
+ v'if (obj.__hash__ === null) throw new TypeError("unhashable type: \'" + (obj.constructor && obj.constructor.name ? obj.constructor.name : "object") + "\'")'
310
346
  v'if (typeof obj.__hash__ === "function") return obj.__hash__()'
311
347
  v'if (Array.isArray(obj)) throw new TypeError("unhashable type: \'list\'")'
312
348
  v'if (typeof ρσ_set === "function" && obj instanceof ρσ_set) throw new TypeError("unhashable type: \'set\'")'
@@ -363,11 +399,72 @@ def ρσ_max(*args, **kwargs):
363
399
  raise TypeError('expected at least one argument')
364
400
 
365
401
 
402
+ class ρσ_slice:
403
+ def __init__(self, start_or_stop, stop, step):
404
+ if arguments.length is 1:
405
+ self.start = None
406
+ self.stop = start_or_stop
407
+ self.step = None
408
+ elif arguments.length is 2:
409
+ self.start = start_or_stop
410
+ self.stop = stop
411
+ self.step = None
412
+ else:
413
+ self.start = start_or_stop
414
+ self.stop = stop
415
+ self.step = step
416
+
417
+ def indices(self, length):
418
+ step = 1 if self.step is None else self.step
419
+ if step is 0:
420
+ raise ValueError('slice step cannot be zero')
421
+ if step > 0:
422
+ lower = 0
423
+ upper = length
424
+ start = lower if self.start is None else self.start
425
+ stop = upper if self.stop is None else self.stop
426
+ else:
427
+ lower = -1
428
+ upper = length - 1
429
+ start = upper if self.start is None else self.start
430
+ stop = lower if self.stop is None else self.stop
431
+ # Only clamp values that were explicitly provided (None defaults are already correct).
432
+ if self.start is not None:
433
+ if start < 0:
434
+ start = max(start + length, lower)
435
+ if start > upper:
436
+ start = upper
437
+ if self.stop is not None:
438
+ if stop < 0:
439
+ stop = max(stop + length, lower)
440
+ if stop > upper:
441
+ stop = upper
442
+ return start, stop, step
443
+
444
+ def __repr__(self):
445
+ s = 'None' if self.start is None else String(self.start)
446
+ stop = 'None' if self.stop is None else String(self.stop)
447
+ step = 'None' if self.step is None else String(self.step)
448
+ return 'slice(' + s + ', ' + stop + ', ' + step + ')'
449
+
450
+ def __str__(self):
451
+ return self.__repr__()
452
+
453
+ def __eq__(self, other):
454
+ if not v'other instanceof ρσ_slice':
455
+ return False
456
+ return self.start is other.start and self.stop is other.stop and self.step is other.step
457
+
458
+ def __hash__(self):
459
+ raise TypeError("unhashable type: 'slice'")
460
+
461
+
366
462
  v'var abs = Math.abs, max = ρσ_max.bind(Math.max), min = ρσ_max.bind(Math.min), bool = ρσ_bool, type = ρσ_type'
367
463
  v'var float = ρσ_float, int = ρσ_int, arraylike = ρσ_arraylike_creator(), ρσ_arraylike = arraylike'
368
- v'var id = ρσ_id, get_module = ρσ_get_module, pow = ρσ_pow, divmod = ρσ_divmod'
464
+ v'var id = ρσ_id, get_module = ρσ_get_module, pow = ρσ_pow, divmod = ρσ_divmod, __import__ = ρσ__import__'
369
465
  v'var dir = ρσ_dir, ord = ρσ_ord, chr = ρσ_chr, bin = ρσ_bin, hex = ρσ_hex, callable = ρσ_callable, round = ρσ_round'
370
466
  v'var enumerate = ρσ_enumerate, iter = ρσ_iter, reversed = ρσ_reversed, len = ρσ_len'
371
467
  v'var range = ρσ_range, getattr = ρσ_getattr, setattr = ρσ_setattr, hasattr = ρσ_hasattr, issubclass = ρσ_issubclass, hash = ρσ_hash, next = ρσ_next'
372
468
  v'var ρσ_Ellipsis = Object.freeze({toString: function(){return "Ellipsis";}, __repr__: function(){return "Ellipsis";}})'
373
469
  v'var Ellipsis = ρσ_Ellipsis'
470
+ v'var slice = ρσ_slice'
@@ -140,7 +140,7 @@ def ρσ_list_sort(key=None, reverse=False):
140
140
  k = this[i] # noqa:undef
141
141
  keymap.set(k, key(k))
142
142
  posmap.set(k, i)
143
- this.sort(def (a, b): return mult * ρσ_list_sort_cmp(keymap.get(a), keymap.get(b), posmap.get(a), posmap.get(b));)
143
+ Array.prototype.sort.call(this, def (a, b): return mult * ρσ_list_sort_cmp(keymap.get(a), keymap.get(b), posmap.get(a), posmap.get(b));)
144
144
 
145
145
  def ρσ_list_concat(): # ensure concat() returns an object of type list
146
146
  ans = Array.prototype.concat.apply(this, arguments)
@@ -190,14 +190,18 @@ def ρσ_list_decorate(ans):
190
190
  ans.inspect = ρσ_list_to_string
191
191
  ans.extend = ρσ_list_extend
192
192
  ans.index = ρσ_list_index
193
- ans.pypop = ρσ_list_pop
193
+ ans.jspop = Array.prototype.pop # native JS pop (no bounds check, ignores args)
194
+ ans.pop = ρσ_list_pop # Python pop (bounds-checked, supports negative index)
195
+ ans.pypop = ρσ_list_pop # backward-compat alias for pop
194
196
  ans.remove = ρσ_list_remove
195
197
  ans.insert = ρσ_list_insert
196
198
  ans.copy = ρσ_list_copy
197
199
  ans.clear = ρσ_list_clear
198
200
  ans.count = ρσ_list_count
199
201
  ans.concat = ρσ_list_concat
200
- ans.pysort = ρσ_list_sort
202
+ ans.jssort = Array.prototype.sort # native JS sort (lexicographic by default)
203
+ ans.sort = ρσ_list_sort # Python sort (numeric by default)
204
+ ans.pysort = ρσ_list_sort # backward-compat alias for sort
201
205
  ans.slice = ρσ_list_slice
202
206
  ans.as_array = ρσ_list_as_array
203
207
  ans.__len__ = ρσ_list_len
@@ -235,10 +239,30 @@ v'var list = ρσ_list_constructor, list_wrap = ρσ_list_decorate'
235
239
 
236
240
  def sorted(iterable, key=None, reverse=False):
237
241
  ans = ρσ_list_constructor(iterable)
238
- ans.pysort(key, reverse)
242
+ ans.sort(key, reverse)
239
243
  return ans
240
244
  # }}}
241
245
 
246
+ # tuple {{{
247
+ def ρσ_tuple_constructor(iterable):
248
+ if iterable is undefined:
249
+ return v'[]'
250
+ if ρσ_arraylike(iterable):
251
+ return Array.prototype.slice.call(iterable)
252
+ if jstype(iterable[ρσ_iterator_symbol]) is 'function':
253
+ iterator = iterable.keys() if jstype(Map) is 'function' and v'iterable instanceof Map' else iterable[ρσ_iterator_symbol]()
254
+ ans = []
255
+ result = iterator.next()
256
+ while not result.done:
257
+ ans.push(result.value)
258
+ result = iterator.next()
259
+ return ans
260
+ return Object.keys(iterable)
261
+
262
+ ρσ_tuple_constructor.__name__ = 'tuple'
263
+ v'var tuple = ρσ_tuple_constructor'
264
+ # }}}
265
+
242
266
  # set {{{
243
267
  v'var ρσ_global_object_id = 0, ρσ_set_implementation'
244
268
 
@@ -694,6 +718,12 @@ def ρσ_dict_polyfill():
694
718
  return v"{'done':false, 'value':this._s[this._keys[this._i]]}"
695
719
  return ans
696
720
 
721
+ ρσ_dict_polyfill.prototype.forEach = def(callback):
722
+ keys = Object.keys(this._store)
723
+ for v'var ρσ_fi = 0; ρσ_fi < keys.length; ρσ_fi++':
724
+ entry = this._store[keys[v'ρσ_fi']]
725
+ callback(entry[1], entry[0], this)
726
+
697
727
  if jstype(Map) is not 'function' or jstype(Map.prototype.delete) is not 'function':
698
728
  v'ρσ_dict_implementation = ρσ_dict_polyfill'
699
729
  else:
@@ -858,6 +888,15 @@ Object.defineProperties(ρσ_dict.prototype, {
858
888
  r = iterator.next()
859
889
  return ans
860
890
 
891
+ ρσ_dict.prototype.toJSON = def():
892
+ ans = {}
893
+ iterator = this.jsmap.entries()
894
+ r = iterator.next()
895
+ while not r.done:
896
+ ans[r.value[0]] = r.value[1]
897
+ r = iterator.next()
898
+ return ans
899
+
861
900
  def ρσ_dict_wrap(x):
862
901
  ans = new ρσ_dict()
863
902
  ans.jsmap = x
@@ -865,4 +904,68 @@ def ρσ_dict_wrap(x):
865
904
 
866
905
  v'var dict = ρσ_dict, dict_wrap = ρσ_dict_wrap'
867
906
 
907
+ v'''
908
+ function ρσ_kwargs_to_dict(kw) {
909
+ // Augment the plain kwargs object with non-enumerable Python dict methods so
910
+ // that kw.items(), kw.keys(), kw.values() work in user code, while plain
911
+ // property access (kw.propname) and Object.keys(kw) are unaffected.
912
+ //
913
+ // items/keys/values return dual-mode arrays: they support both Array indexing
914
+ // (for ρσ_dict.prototype.update which does pairs[i]) and iterator protocol
915
+ // (for `for k, v in kw.items():` which calls .next()).
916
+ function _make_seq(arr) {
917
+ arr._ρσ_i = 0;
918
+ arr.next = function() {
919
+ return this._ρσ_i < this.length
920
+ ? {done: false, value: this[this._ρσ_i++]}
921
+ : {done: true, value: undefined};
922
+ };
923
+ arr[ρσ_iterator_symbol] = function() { this._ρσ_i = 0; return this; };
924
+ return arr;
925
+ }
926
+ function _def(name, fn) {
927
+ if (!Object.prototype.hasOwnProperty.call(kw, name)) {
928
+ Object.defineProperty(kw, name, {value: fn, configurable: true, writable: true, enumerable: false});
929
+ }
930
+ }
931
+ _def("items", function() {
932
+ var ks = Object.keys(kw), arr = [], i;
933
+ for (i = 0; i < ks.length; i++) arr.push([ks[i], kw[ks[i]]]);
934
+ return _make_seq(arr);
935
+ });
936
+ _def("entries", kw.items);
937
+ _def("keys", function() {
938
+ return _make_seq(Object.keys(kw).slice());
939
+ });
940
+ _def("values", function() {
941
+ var ks = Object.keys(kw), arr = [], i;
942
+ for (i = 0; i < ks.length; i++) arr.push(kw[ks[i]]);
943
+ return _make_seq(arr);
944
+ });
945
+ _def("get", function(k, d) {
946
+ return Object.prototype.hasOwnProperty.call(kw, k) ? kw[k] : (d !== undefined ? d : null);
947
+ });
948
+ _def("__contains__", function(k) { return Object.prototype.hasOwnProperty.call(kw, k); });
949
+ _def("has", function(k) { return Object.prototype.hasOwnProperty.call(kw, k); });
950
+ _def("__len__", function() { return Object.keys(kw).length; });
951
+ kw[ρσ_iterator_symbol] = function() {
952
+ var ks = Object.keys(kw), i = 0;
953
+ return {next: function() {
954
+ return i < ks.length ? {done: false, value: ks[i++]} : {done: true, value: undefined};
955
+ }};
956
+ };
957
+ return kw;
958
+ }
959
+ '''
960
+
961
+ v"""var ρσ_json_parse = function(text, reviver) {
962
+ function dict_reviver(key, value) {
963
+ if (value !== null && typeof value === "object" && !Array.isArray(value) && !(value instanceof ρσ_dict)) {
964
+ value = ρσ_dict(value);
965
+ }
966
+ return reviver ? reviver.call(this, key, value) : value;
967
+ }
968
+ return JSON.parse(text, dict_reviver);
969
+ };"""
970
+
868
971
  # }}}
@@ -38,3 +38,47 @@ class ZeroDivisionError(Exception):
38
38
 
39
39
  class StopIteration(Exception):
40
40
  pass
41
+
42
+ class ImportError(Exception):
43
+ pass
44
+
45
+ class ModuleNotFoundError(ImportError):
46
+ pass
47
+
48
+ def _is_exc_class(obj):
49
+ # True when obj is an Error subclass (or Error itself), not a plain predicate function
50
+ return jstype(obj) is 'function' and (obj is Error or (obj.prototype and isinstance(obj.prototype, Error)))
51
+
52
+
53
+ class ExceptionGroup(Exception):
54
+
55
+ def __init__(self, message, exceptions):
56
+ Exception.__init__(self, message)
57
+ self.exceptions = exceptions if exceptions else []
58
+
59
+ def subgroup(self, condition):
60
+ if _is_exc_class(condition):
61
+ matched = [e for e in self.exceptions if isinstance(e, condition)]
62
+ elif callable(condition):
63
+ matched = [e for e in self.exceptions if condition(e)]
64
+ else:
65
+ matched = [e for e in self.exceptions if isinstance(e, condition)]
66
+ return ExceptionGroup(self.message, matched) if matched else None
67
+
68
+ def split(self, condition):
69
+ if _is_exc_class(condition):
70
+ matched = [e for e in self.exceptions if isinstance(e, condition)]
71
+ rest = [e for e in self.exceptions if not isinstance(e, condition)]
72
+ elif callable(condition):
73
+ matched = [e for e in self.exceptions if condition(e)]
74
+ rest = [e for e in self.exceptions if not condition(e)]
75
+ else:
76
+ matched = [e for e in self.exceptions if isinstance(e, condition)]
77
+ rest = [e for e in self.exceptions if not isinstance(e, condition)]
78
+ return [
79
+ ExceptionGroup(self.message, matched) if matched else None,
80
+ ExceptionGroup(self.message, rest) if rest else None
81
+ ]
82
+
83
+ def __repr__(self):
84
+ return 'ExceptionGroup(' + repr(self.message) + ', ' + repr(self.exceptions) + ')'