rapydscript-ns 0.9.3 → 0.9.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 (98) 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 +9 -0
  5. package/HACKING.md +103 -103
  6. package/LICENSE +24 -24
  7. package/PYTHON_GAPS.md +48 -116
  8. package/README.md +35 -15
  9. package/TODO.md +1 -26
  10. package/add-toc-to-readme +2 -2
  11. package/bin/export +75 -75
  12. package/bin/rapydscript +0 -0
  13. package/bin/web-repl-export +102 -102
  14. package/build +2 -2
  15. package/language-service/index.js +9 -7
  16. package/package.json +1 -1
  17. package/publish.py +37 -37
  18. package/session.vim +4 -4
  19. package/setup.cfg +2 -2
  20. package/src/ast.pyj +6 -0
  21. package/src/baselib-containers.pyj +23 -1
  22. package/src/baselib-str.pyj +13 -2
  23. package/src/compiler.pyj +36 -36
  24. package/src/errors.pyj +30 -30
  25. package/src/lib/aes.pyj +646 -646
  26. package/src/lib/collections.pyj +227 -3
  27. package/src/lib/copy.pyj +120 -120
  28. package/src/lib/elementmaker.pyj +83 -83
  29. package/src/lib/encodings.pyj +126 -126
  30. package/src/lib/gettext.pyj +569 -569
  31. package/src/lib/itertools.pyj +580 -580
  32. package/src/lib/math.pyj +193 -193
  33. package/src/lib/operator.pyj +11 -11
  34. package/src/lib/pprint.pyj +455 -0
  35. package/src/lib/random.pyj +118 -118
  36. package/src/lib/react.pyj +74 -74
  37. package/src/lib/statistics.pyj +0 -0
  38. package/src/lib/traceback.pyj +63 -63
  39. package/src/lib/uuid.pyj +77 -77
  40. package/src/monaco-language-service/diagnostics.js +2 -2
  41. package/src/monaco-language-service/dts.js +550 -550
  42. package/src/output/codegen.pyj +4 -1
  43. package/src/output/comments.pyj +45 -45
  44. package/src/output/exceptions.pyj +201 -201
  45. package/src/output/jsx.pyj +164 -164
  46. package/src/output/treeshake.pyj +182 -182
  47. package/src/output/utils.pyj +72 -72
  48. package/src/parse.pyj +28 -7
  49. package/src/string_interpolation.pyj +72 -72
  50. package/src/tokenizer.pyj +18 -2
  51. package/src/unicode_aliases.pyj +576 -576
  52. package/src/utils.pyj +192 -192
  53. package/test/_import_one.pyj +37 -37
  54. package/test/_import_two/__init__.pyj +11 -11
  55. package/test/_import_two/level2/deep.pyj +4 -4
  56. package/test/_import_two/other.pyj +6 -6
  57. package/test/_import_two/sub.pyj +13 -13
  58. package/test/aes_vectors.pyj +421 -421
  59. package/test/annotations.pyj +80 -80
  60. package/test/baselib.pyj +23 -0
  61. package/test/chainmap.pyj +185 -0
  62. package/test/decorators.pyj +77 -77
  63. package/test/docstrings.pyj +39 -39
  64. package/test/elementmaker_test.pyj +45 -45
  65. package/test/functions.pyj +151 -151
  66. package/test/generators.pyj +41 -41
  67. package/test/generic.pyj +370 -370
  68. package/test/internationalization.pyj +73 -73
  69. package/test/lint.pyj +164 -164
  70. package/test/loops.pyj +85 -85
  71. package/test/numpy.pyj +734 -734
  72. package/test/pprint.pyj +232 -0
  73. package/test/repl.pyj +121 -121
  74. package/test/scoped_flags.pyj +76 -76
  75. package/test/statistics.pyj +224 -0
  76. package/test/unit/index.js +80 -0
  77. package/test/unit/language-service-completions.js +2 -0
  78. package/test/unit/language-service-dts.js +543 -543
  79. package/test/unit/language-service-hover.js +455 -455
  80. package/test/unit/language-service.js +63 -2
  81. package/test/unit/web-repl.js +323 -0
  82. package/tools/compiler.d.ts +367 -367
  83. package/tools/completer.js +131 -131
  84. package/tools/export.js +4 -2
  85. package/tools/gettext.js +185 -185
  86. package/tools/ini.js +65 -65
  87. package/tools/msgfmt.js +187 -187
  88. package/tools/repl.js +223 -223
  89. package/tools/test.js +118 -118
  90. package/tools/utils.js +128 -128
  91. package/tools/web_repl.js +95 -95
  92. package/try +41 -41
  93. package/web-repl/env.js +196 -196
  94. package/web-repl/index.html +163 -163
  95. package/web-repl/prism.css +139 -139
  96. package/web-repl/prism.js +113 -113
  97. package/web-repl/rapydscript.js +228 -226
  98. package/web-repl/sha1.js +25 -25
@@ -900,13 +900,14 @@ function make_tests(Diagnostics, RS, STDLIB_MODULES) {
900
900
  description: "Importing all collections classes produces no errors",
901
901
  run: function () {
902
902
  var markers = d().check([
903
- "from collections import defaultdict, Counter, OrderedDict, deque, namedtuple",
903
+ "from collections import defaultdict, Counter, OrderedDict, deque, namedtuple, ChainMap",
904
904
  "d = defaultdict(list)",
905
905
  "c = Counter([1, 2, 2, 3])",
906
906
  "od = OrderedDict()",
907
907
  "dq = deque([1, 2, 3])",
908
908
  "Point = namedtuple('Point', 'x y')",
909
- "print(d, c, od, dq, Point)",
909
+ "cm = ChainMap({'a': 1}, {'b': 2})",
910
+ "print(d, c, od, dq, Point, cm)",
910
911
  ].join("\n"),
911
912
  { virtualFiles: { mymod: "def foo(): pass" } }
912
913
  );
@@ -930,6 +931,36 @@ function make_tests(Diagnostics, RS, STDLIB_MODULES) {
930
931
  },
931
932
  },
932
933
 
934
+ {
935
+ name: "stdlib_statistics_no_bad_import",
936
+ description: "Importing and using statistics functions produces no errors",
937
+ run: function () {
938
+ var markers = d().check([
939
+ "from statistics import mean, median, mode, stdev, variance",
940
+ "from statistics import quantiles, correlation, linear_regression",
941
+ "from statistics import NormalDist, StatisticsError",
942
+ "data = [1, 2, 3, 4, 5]",
943
+ "m = mean(data)",
944
+ "md = median(data)",
945
+ "mo = mode(data)",
946
+ "sd = stdev(data)",
947
+ "v = variance(data)",
948
+ "q = quantiles(data)",
949
+ "c = correlation(data, data)",
950
+ "lr = linear_regression(data, data)",
951
+ "nd = NormalDist(0, 1)",
952
+ "print(m, md, mo, sd, v, q, c, lr.slope, lr.intercept)",
953
+ "print(nd.mean, nd.stdev, nd.cdf(0), nd.pdf(0), StatisticsError)",
954
+ ].join("\n"),
955
+ { virtualFiles: { sentinel: "x = 1" } }
956
+ );
957
+ var errors = markers.filter(function (m) { return m.severity === SEV_ERROR; });
958
+ assert.deepStrictEqual(errors, [],
959
+ "Expected no errors for statistics imports and usage, got: " +
960
+ JSON.stringify(errors.map(function (m) { return m.message; })));
961
+ },
962
+ },
963
+
933
964
  {
934
965
  name: "copy_no_bad_import",
935
966
  description: "from copy import copy, deepcopy produces no bad-import error",
@@ -1591,6 +1622,36 @@ function make_tests(Diagnostics, RS, STDLIB_MODULES) {
1591
1622
  },
1592
1623
  },
1593
1624
 
1625
+ // ── BigInt literals ──────────────────────────────────────────────
1626
+
1627
+ {
1628
+ name: "bigint_literal_no_errors",
1629
+ description: "BigInt literals (42n, 0xFFn, 0b1010n, 0o77n) produce no markers",
1630
+ run: function () {
1631
+ var markers = d().check([
1632
+ "x = 42n",
1633
+ "y = 0xFFn",
1634
+ "z = 0b1010n",
1635
+ "w = 0o77n",
1636
+ ].join("\n"));
1637
+ assert.deepStrictEqual(markers, [],
1638
+ "Expected no markers for bigint literals, got: " + JSON.stringify(markers));
1639
+ },
1640
+ },
1641
+
1642
+ {
1643
+ name: "bigint_literal_assignment_no_errors",
1644
+ description: "BigInt literal assignment and arithmetic produce no markers",
1645
+ run: function () {
1646
+ var markers = d().check([
1647
+ "x = 42n",
1648
+ "y = x + 1n",
1649
+ ].join("\n"));
1650
+ assert.deepStrictEqual(markers, [],
1651
+ "Expected no markers for bigint assignment, got: " + JSON.stringify(markers));
1652
+ },
1653
+ },
1654
+
1594
1655
  ];
1595
1656
 
1596
1657
  return TESTS;
@@ -270,6 +270,95 @@ var TESTS = [
270
270
  },
271
271
  },
272
272
 
273
+ {
274
+ name: "bundle_chainmap_basic",
275
+ description: "ChainMap construction and first-map-wins lookup work in the web-repl bundle",
276
+ run: function () {
277
+ var repl = RS.web_repl();
278
+ var js = bundle_compile(repl, [
279
+ "from collections import ChainMap",
280
+ "defaults = {'color': 'red', 'user': 'guest'}",
281
+ "overrides = {'user': 'admin'}",
282
+ "cm = ChainMap(overrides, defaults)",
283
+ "assrt.equal(cm['user'], 'admin')",
284
+ "assrt.equal(cm['color'], 'red')",
285
+ "assrt.equal(len(cm), 2)",
286
+ "assrt.ok('color' in cm)",
287
+ "assrt.ok('missing' not in cm)",
288
+ "assrt.equal(cm.get('missing', 'fallback'), 'fallback')",
289
+ ].join("\n"));
290
+ run_js(js);
291
+ },
292
+ },
293
+
294
+ {
295
+ name: "bundle_chainmap_writes",
296
+ description: "ChainMap writes, deletes and updates affect only the first map in the bundle",
297
+ run: function () {
298
+ var repl = RS.web_repl();
299
+ var js = bundle_compile(repl, [
300
+ "from collections import ChainMap",
301
+ "defaults = {'depth': 1}",
302
+ "cm = ChainMap({}, defaults)",
303
+ "cm['depth'] = 99",
304
+ "assrt.equal(cm['depth'], 99)",
305
+ "assrt.equal(defaults['depth'], 1)",
306
+ "del cm['depth']",
307
+ "assrt.equal(cm['depth'], 1)",
308
+ "cm.update({'a': 1}, b=2)",
309
+ "assrt.equal(cm['a'], 1)",
310
+ "assrt.equal(cm['b'], 2)",
311
+ "assrt.equal(cm.pop('a'), 1)",
312
+ "assrt.equal(cm.pop('depth', 'dflt'), 'dflt')",
313
+ "assrt.equal(cm.setdefault('new', 7), 7)",
314
+ "assrt.equal(cm['new'], 7)",
315
+ ].join("\n"));
316
+ run_js(js);
317
+ },
318
+ },
319
+
320
+ {
321
+ name: "bundle_chainmap_new_child",
322
+ description: "ChainMap new_child and parents work in the web-repl bundle",
323
+ run: function () {
324
+ var repl = RS.web_repl();
325
+ var js = bundle_compile(repl, [
326
+ "from collections import ChainMap",
327
+ "base = ChainMap({'x': 1})",
328
+ "child = base.new_child({'x': 2, 'y': 3})",
329
+ "assrt.equal(child['x'], 2)",
330
+ "assrt.equal(child['y'], 3)",
331
+ "assrt.equal(base['x'], 1)",
332
+ "assrt.equal(child.maps.length, 2)",
333
+ "parents = child.parents",
334
+ "assrt.equal(parents['x'], 1)",
335
+ "assrt.equal(parents.maps.length, 1)",
336
+ ].join("\n"));
337
+ run_js(js);
338
+ },
339
+ },
340
+
341
+ {
342
+ name: "bundle_chainmap_iteration",
343
+ description: "ChainMap keys/values/items, iteration order and copy work in the bundle",
344
+ run: function () {
345
+ var repl = RS.web_repl();
346
+ var js = bundle_compile(repl, [
347
+ "from collections import ChainMap",
348
+ "cm = ChainMap({'a': 1, 'b': 2}, {'c': 3})",
349
+ "assrt.deepEqual(list(cm), ['c', 'a', 'b'])",
350
+ "assrt.deepEqual(cm.keys(), ['c', 'a', 'b'])",
351
+ "assrt.deepEqual(cm.values(), [3, 1, 2])",
352
+ "dup = cm.copy()",
353
+ "dup['a'] = 100",
354
+ "assrt.equal(cm['a'], 1)",
355
+ "assrt.equal(dup['a'], 100)",
356
+ "assrt.equal(dup['c'], 3)",
357
+ ].join("\n"));
358
+ run_js(js);
359
+ },
360
+ },
361
+
273
362
  {
274
363
  name: "bundle_operator_overloading",
275
364
  description: "overload_operators flag works in the web-repl bundle",
@@ -3914,6 +4003,121 @@ var TESTS = [
3914
4003
  },
3915
4004
  },
3916
4005
 
4006
+ // ── pprint stdlib ────────────────────────────────────────────────────────
4007
+
4008
+ {
4009
+ name: "bundle_pprint_basic",
4010
+ description: "pprint stdlib: pformat of atoms and short containers in the web-repl bundle",
4011
+ run: function () {
4012
+ var repl = RS.web_repl();
4013
+ var js = bundle_compile(repl, [
4014
+ "from pprint import pformat",
4015
+ // atoms -> repr()
4016
+ "assrt.equal(pformat(None), 'None')",
4017
+ "assrt.equal(pformat(True), 'True')",
4018
+ "assrt.equal(pformat(42), '42')",
4019
+ "assrt.equal(pformat('hi'), '\"hi\"')",
4020
+ // empty containers
4021
+ "assrt.equal(pformat([]), '[]')",
4022
+ "assrt.equal(pformat({}), '{}')",
4023
+ "assrt.equal(pformat(set()), 'set()')",
4024
+ // short containers fit on one line
4025
+ "assrt.equal(pformat([1, 2, 3]), '[1, 2, 3]')",
4026
+ "assrt.equal(pformat({'a': 1, 'b': 2}), '{\"a\": 1, \"b\": 2}')",
4027
+ "assrt.equal(pformat(frozenset([1])), 'frozenset({1})')",
4028
+ ].join("\n"));
4029
+ run_js(js);
4030
+ },
4031
+ },
4032
+
4033
+ {
4034
+ name: "bundle_pprint_wrap",
4035
+ description: "pprint stdlib: wide containers break across lines in the web-repl bundle",
4036
+ run: function () {
4037
+ var repl = RS.web_repl();
4038
+ var js = bundle_compile(repl, [
4039
+ "from pprint import pformat",
4040
+ // wide list breaks one element per line
4041
+ "assrt.equal(pformat([1, 2, 3], width=5), '[1,\\n 2,\\n 3]')",
4042
+ // wide dict breaks, keys sorted by default
4043
+ "assrt.equal(pformat({'name': 'Al', 'age': 3}, width=12), '{\"age\": 3,\\n \"name\": \"Al\"}')",
4044
+ // indent parameter widens inner indentation
4045
+ "assrt.equal(pformat([1, 2, 3], width=5, indent=4), '[ 1,\\n 2,\\n 3]')",
4046
+ // single-element containers never break
4047
+ "assrt.equal(pformat([42], width=1), '[42]')",
4048
+ ].join("\n"));
4049
+ run_js(js);
4050
+ },
4051
+ },
4052
+
4053
+ {
4054
+ name: "bundle_pprint_features",
4055
+ description: "pprint stdlib: depth, compact, sort_dicts, and pp() in the web-repl bundle",
4056
+ run: function () {
4057
+ var repl = RS.web_repl();
4058
+ var js = bundle_compile(repl, [
4059
+ "from pprint import pformat, pp",
4060
+ // depth limits expansion
4061
+ "assrt.equal(pformat([1, [2, [3]]], depth=1), '[1, [...]]')",
4062
+ "assrt.equal(pformat([1, [2, [3]]], depth=2), '[1, [2, [...]]]')",
4063
+ // sort_dicts=False keeps insertion order (ρσ_dict preserves it)
4064
+ "d = dict()",
4065
+ "d.set('c', 1)",
4066
+ "d.set('a', 2)",
4067
+ "assrt.equal(pformat(d, sort_dicts=False), '{\"c\": 1, \"a\": 2}')",
4068
+ "assrt.equal(pformat(d, sort_dicts=True), '{\"a\": 2, \"c\": 1}')",
4069
+ // compact packs multiple items per line
4070
+ "compact_out = pformat([1, 2, 3, 4, 5, 6, 7, 8], compact=True, width=15)",
4071
+ "assrt.equal(compact_out, '[1, 2, 3, 4, 5,\\n 6, 7, 8]')",
4072
+ // pp() writes to a custom stream and defaults sort_dicts=False
4073
+ "class _C:",
4074
+ " def __init__(self):",
4075
+ " self.parts = []",
4076
+ " def write(self, s):",
4077
+ " self.parts.push(s)",
4078
+ "col = _C()",
4079
+ "pp(d, stream=col)",
4080
+ "assrt.equal(col.parts.join(''), '{\"c\": 1, \"a\": 2}\\n')",
4081
+ ].join("\n"));
4082
+ run_js(js);
4083
+ },
4084
+ },
4085
+
4086
+ {
4087
+ name: "bundle_pprint_safe",
4088
+ description: "pprint stdlib: saferepr, isreadable, isrecursive, PrettyPrinter in the web-repl bundle",
4089
+ run: function () {
4090
+ var repl = RS.web_repl();
4091
+ var js = bundle_compile(repl, [
4092
+ "from pprint import saferepr, isreadable, isrecursive, PrettyPrinter",
4093
+ // saferepr of normal structures == single-line repr
4094
+ "assrt.equal(saferepr([1, 2, 3]), '[1, 2, 3]')",
4095
+ "assrt.equal(saferepr({'a': 1}), '{\"a\": 1}')",
4096
+ // isreadable / isrecursive on plain structures
4097
+ "assrt.ok(isreadable([1, 2, 3]))",
4098
+ "assrt.ok(not isrecursive([1, 2, 3]))",
4099
+ // self-referential list -> recursion detected and marked
4100
+ "cyclic = [1, 2]",
4101
+ "cyclic.push(cyclic)",
4102
+ "assrt.ok(isrecursive(cyclic))",
4103
+ "assrt.ok(not isreadable(cyclic))",
4104
+ "assrt.ok(saferepr(cyclic).indexOf('<Recursion on') >= 0)",
4105
+ // PrettyPrinter class: pformat + instance predicates
4106
+ "p = PrettyPrinter(indent=2, width=8)",
4107
+ "assrt.equal(p.pformat([10, 20, 30]), '[ 10,\\n 20,\\n 30]')",
4108
+ "assrt.ok(p.isrecursive(cyclic))",
4109
+ // invalid args raise ValueError
4110
+ "caught = False",
4111
+ "try:",
4112
+ " PrettyPrinter(depth=0)",
4113
+ "except ValueError:",
4114
+ " caught = True",
4115
+ "assrt.ok(caught)",
4116
+ ].join("\n"));
4117
+ run_js(js);
4118
+ },
4119
+ },
4120
+
3917
4121
  {
3918
4122
  name: "bundle_type_enforcement_basic",
3919
4123
  description: "type_enforcement: max args, missing required, type annotations",
@@ -4275,6 +4479,125 @@ var TESTS = [
4275
4479
  },
4276
4480
  },
4277
4481
 
4482
+ // ── statistics ───────────────────────────────────────────────────────────
4483
+
4484
+ {
4485
+ name: "bundle_statistics_averages",
4486
+ description: "statistics stdlib: averages and central location in the web-repl bundle",
4487
+ run: function () {
4488
+ var repl = RS.web_repl();
4489
+ var js = bundle_compile(repl, [
4490
+ "from statistics import mean, fmean, median, median_low, median_high",
4491
+ "from statistics import mode, multimode, harmonic_mean, geometric_mean",
4492
+ "assrt.equal(mean([1, 2, 3, 4]), 2.5)",
4493
+ "assrt.equal(mean([1, 2, 3]), 2)",
4494
+ "assrt.equal(fmean([1, 2, 3, 4]), 2.5)",
4495
+ "assrt.equal(median([1, 3, 5]), 3)",
4496
+ "assrt.equal(median([1, 3, 5, 7]), 4)",
4497
+ "assrt.equal(median([5, 1, 3]), 3)", // unsorted input
4498
+ "assrt.equal(median_low([1, 3, 5, 7]), 3)",
4499
+ "assrt.equal(median_high([1, 3, 5, 7]), 5)",
4500
+ "assrt.equal(mode([1, 1, 2, 3, 3, 3]), 3)",
4501
+ "assrt.equal(mode(['x', 'y', 'x']), 'x')",
4502
+ "assrt.deepEqual(multimode([1, 1, 2, 2, 3]), [1, 2])",
4503
+ "assrt.ok(Math.abs(harmonic_mean([40, 60]) - 48.0) < 1e-9)",
4504
+ "assrt.ok(Math.abs(geometric_mean([2, 8]) - 4.0) < 1e-9)",
4505
+ ].join("\n"));
4506
+ run_js(js);
4507
+ },
4508
+ },
4509
+
4510
+ {
4511
+ name: "bundle_statistics_spread",
4512
+ description: "statistics stdlib: variance, stdev and quantiles in the web-repl bundle",
4513
+ run: function () {
4514
+ var repl = RS.web_repl();
4515
+ var js = bundle_compile(repl, [
4516
+ "from statistics import variance, pvariance, stdev, pstdev, quantiles",
4517
+ "assrt.equal(variance([1, 2, 3, 4, 5]), 2.5)",
4518
+ "assrt.equal(pvariance([1, 2, 3, 4, 5]), 2.0)",
4519
+ "assrt.ok(Math.abs(stdev([1, 2, 3, 4, 5]) - Math.sqrt(2.5)) < 1e-9)",
4520
+ "assrt.ok(Math.abs(pstdev([1, 2, 3, 4, 5]) - Math.sqrt(2.0)) < 1e-9)",
4521
+ "assrt.deepEqual(quantiles([1, 2, 3, 4]), [1.25, 2.5, 3.75])",
4522
+ "q = quantiles([1, 2, 3, 4, 5, 6, 7, 8, 9, 10], n=10)",
4523
+ "assrt.equal(q.length, 9)",
4524
+ ].join("\n"));
4525
+ run_js(js);
4526
+ },
4527
+ },
4528
+
4529
+ {
4530
+ name: "bundle_statistics_relations",
4531
+ description: "statistics stdlib: covariance, correlation, linear_regression in the bundle",
4532
+ run: function () {
4533
+ var repl = RS.web_repl();
4534
+ var js = bundle_compile(repl, [
4535
+ "from statistics import covariance, correlation, linear_regression",
4536
+ "x = [1, 2, 3, 4, 5, 6, 7, 8, 9]",
4537
+ "y = [1, 2, 3, 1, 2, 3, 1, 2, 3]",
4538
+ "assrt.ok(Math.abs(covariance(x, y) - 0.75) < 1e-9)",
4539
+ "assrt.ok(Math.abs(correlation(x, x) - 1.0) < 1e-9)",
4540
+ "lr = linear_regression([1, 2, 3, 4, 5], [2, 4, 6, 8, 10])",
4541
+ "assrt.ok(Math.abs(lr.slope - 2.0) < 1e-9)",
4542
+ "assrt.ok(Math.abs(lr.intercept - 0.0) < 1e-9)",
4543
+ ].join("\n"));
4544
+ run_js(js);
4545
+ },
4546
+ },
4547
+
4548
+ {
4549
+ name: "bundle_statistics_normaldist",
4550
+ description: "statistics stdlib: NormalDist in the web-repl bundle",
4551
+ run: function () {
4552
+ var repl = RS.web_repl();
4553
+ var js = bundle_compile(repl, [
4554
+ "from statistics import NormalDist",
4555
+ "nd = NormalDist(100, 15)",
4556
+ "assrt.equal(nd.mean, 100)",
4557
+ "assrt.equal(nd.stdev, 15)",
4558
+ "assrt.equal(nd.variance, 225)",
4559
+ "assrt.ok(Math.abs(nd.cdf(100) - 0.5) < 1e-6)",
4560
+ "assrt.equal(nd.inv_cdf(0.5), 100)",
4561
+ "assrt.equal(nd.zscore(115), 1.0)",
4562
+ "fs = NormalDist.from_samples([1, 2, 3, 4, 5])",
4563
+ "assrt.ok(Math.abs(fs.mean - 3.0) < 1e-9)",
4564
+ // operator overloading dispatches to __add__
4565
+ "combined = nd + NormalDist(50, 20)",
4566
+ "assrt.equal(combined.mean, 150)",
4567
+ "assrt.equal(combined.stdev, 25)",
4568
+ ].join("\n"));
4569
+ run_js(js);
4570
+ },
4571
+ },
4572
+
4573
+ // ── list sort: comparator detection + __lt__ dispatch ────────────────────
4574
+
4575
+ {
4576
+ name: "bundle_sort_comparator_and_lt",
4577
+ description: "list sort: positional comparator and __lt__ dispatch in the web-repl bundle",
4578
+ run: function () {
4579
+ var repl = RS.web_repl();
4580
+ var js = bundle_compile(repl, [
4581
+ // a positional two-argument function is treated as a comparator
4582
+ "assrt.deepEqual(sorted([3, 1, 2, 10], def(x, y): return x - y;), [1, 2, 3, 10])",
4583
+ "m = [5, 2, 8, 1]",
4584
+ "m.sort(def(x, y): return y - x;)",
4585
+ "assrt.deepEqual(m, [8, 5, 2, 1])",
4586
+ // a one-argument function is still a key function
4587
+ "assrt.deepEqual(sorted([3, 1, 2], key=def(x): return -x;), [3, 2, 1])",
4588
+ // custom objects are ordered through their __lt__ method
4589
+ "class Ord:",
4590
+ " def __init__(self, v):",
4591
+ " self.v = v",
4592
+ " def __lt__(self, other):",
4593
+ " return self.v < other.v",
4594
+ "s = sorted([Ord(3), Ord(1), Ord(2)])",
4595
+ "assrt.deepEqual([s[0].v, s[1].v, s[2].v], [1, 2, 3])",
4596
+ ].join("\n"));
4597
+ run_js(js);
4598
+ },
4599
+ },
4600
+
4278
4601
  ];
4279
4602
 
4280
4603
  // ---------------------------------------------------------------------------