rapydscript-ns 0.8.4 → 0.9.0

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 (132) 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 +18 -0
  5. package/HACKING.md +103 -103
  6. package/LICENSE +24 -24
  7. package/README.md +715 -169
  8. package/TODO.md +9 -2
  9. package/add-toc-to-readme +2 -2
  10. package/bin/export +75 -75
  11. package/bin/rapydscript +70 -70
  12. package/bin/web-repl-export +102 -102
  13. package/build +2 -2
  14. package/language-service/index.js +36 -27
  15. package/package.json +1 -1
  16. package/publish.py +37 -37
  17. package/release/baselib-plain-pretty.js +2358 -168
  18. package/release/baselib-plain-ugly.js +73 -3
  19. package/release/compiler.js +6282 -3092
  20. package/release/signatures.json +31 -30
  21. package/session.vim +4 -4
  22. package/setup.cfg +2 -2
  23. package/src/ast.pyj +1 -0
  24. package/src/baselib-builtins.pyj +340 -2
  25. package/src/baselib-bytes.pyj +664 -0
  26. package/src/baselib-errors.pyj +1 -1
  27. package/src/baselib-internal.pyj +267 -60
  28. package/src/baselib-itertools.pyj +110 -97
  29. package/src/baselib-str.pyj +22 -4
  30. package/src/compiler.pyj +36 -36
  31. package/src/errors.pyj +30 -30
  32. package/src/lib/abc.pyj +317 -0
  33. package/src/lib/aes.pyj +646 -646
  34. package/src/lib/copy.pyj +120 -120
  35. package/src/lib/dataclasses.pyj +532 -0
  36. package/src/lib/elementmaker.pyj +83 -83
  37. package/src/lib/encodings.pyj +126 -126
  38. package/src/lib/enum.pyj +125 -0
  39. package/src/lib/gettext.pyj +569 -569
  40. package/src/lib/itertools.pyj +580 -580
  41. package/src/lib/math.pyj +193 -193
  42. package/src/lib/operator.pyj +11 -11
  43. package/src/lib/pythonize.pyj +20 -20
  44. package/src/lib/random.pyj +118 -118
  45. package/src/lib/re.pyj +504 -470
  46. package/src/lib/react.pyj +74 -74
  47. package/src/lib/traceback.pyj +63 -63
  48. package/src/lib/typing.pyj +577 -0
  49. package/src/lib/uuid.pyj +77 -77
  50. package/src/monaco-language-service/builtins.js +14 -4
  51. package/src/monaco-language-service/diagnostics.js +19 -20
  52. package/src/monaco-language-service/dts.js +550 -550
  53. package/src/output/classes.pyj +62 -26
  54. package/src/output/comments.pyj +45 -45
  55. package/src/output/exceptions.pyj +201 -201
  56. package/src/output/functions.pyj +78 -5
  57. package/src/output/jsx.pyj +164 -164
  58. package/src/output/loops.pyj +5 -2
  59. package/src/output/operators.pyj +100 -34
  60. package/src/output/treeshake.pyj +182 -182
  61. package/src/output/utils.pyj +72 -72
  62. package/src/parse.pyj +80 -16
  63. package/src/string_interpolation.pyj +72 -72
  64. package/src/tokenizer.pyj +9 -4
  65. package/src/unicode_aliases.pyj +576 -576
  66. package/src/utils.pyj +192 -192
  67. package/test/_import_one.pyj +37 -37
  68. package/test/_import_two/__init__.pyj +11 -11
  69. package/test/_import_two/level2/deep.pyj +4 -4
  70. package/test/_import_two/other.pyj +6 -6
  71. package/test/_import_two/sub.pyj +13 -13
  72. package/test/abc.pyj +291 -0
  73. package/test/aes_vectors.pyj +421 -421
  74. package/test/annotations.pyj +80 -80
  75. package/test/arithmetic_nostrict.pyj +88 -0
  76. package/test/arithmetic_types.pyj +169 -0
  77. package/test/baselib.pyj +91 -0
  78. package/test/bytes.pyj +467 -0
  79. package/test/classes.pyj +1 -0
  80. package/test/comparison_ops.pyj +173 -0
  81. package/test/dataclasses.pyj +253 -0
  82. package/test/decorators.pyj +77 -77
  83. package/test/docstrings.pyj +39 -39
  84. package/test/elementmaker_test.pyj +45 -45
  85. package/test/enum.pyj +134 -0
  86. package/test/eval_exec.pyj +56 -0
  87. package/test/format.pyj +148 -0
  88. package/test/functions.pyj +151 -151
  89. package/test/generators.pyj +41 -41
  90. package/test/generic.pyj +370 -370
  91. package/test/imports.pyj +72 -72
  92. package/test/internationalization.pyj +73 -73
  93. package/test/lint.pyj +164 -164
  94. package/test/loops.pyj +85 -85
  95. package/test/numpy.pyj +734 -734
  96. package/test/object.pyj +64 -0
  97. package/test/omit_function_metadata.pyj +20 -20
  98. package/test/python_compat.pyj +17 -15
  99. package/test/python_features.pyj +70 -15
  100. package/test/regexp.pyj +83 -55
  101. package/test/repl.pyj +121 -121
  102. package/test/scoped_flags.pyj +76 -76
  103. package/test/tuples.pyj +96 -0
  104. package/test/typing.pyj +469 -0
  105. package/test/unit/index.js +116 -7
  106. package/test/unit/language-service-dts.js +543 -543
  107. package/test/unit/language-service-hover.js +455 -455
  108. package/test/unit/language-service.js +84 -0
  109. package/test/unit/web-repl.js +804 -1
  110. package/test/vars_locals_globals.pyj +94 -0
  111. package/tools/cli.js +558 -547
  112. package/tools/compile.js +224 -219
  113. package/tools/completer.js +131 -131
  114. package/tools/embedded_compiler.js +262 -251
  115. package/tools/gettext.js +185 -185
  116. package/tools/ini.js +65 -65
  117. package/tools/lint.js +16 -19
  118. package/tools/msgfmt.js +187 -187
  119. package/tools/repl.js +223 -223
  120. package/tools/test.js +118 -118
  121. package/tools/utils.js +128 -128
  122. package/tools/web_repl.js +95 -95
  123. package/try +41 -41
  124. package/web-repl/env.js +196 -196
  125. package/web-repl/index.html +163 -163
  126. package/web-repl/main.js +252 -252
  127. package/web-repl/prism.css +139 -139
  128. package/web-repl/prism.js +113 -113
  129. package/web-repl/rapydscript.js +224 -224
  130. package/web-repl/sha1.js +25 -25
  131. package/PYTHON_DIFFERENCES_REPORT.md +0 -291
  132. package/PYTHON_FEATURE_COVERAGE.md +0 -200
package/test/enum.pyj ADDED
@@ -0,0 +1,134 @@
1
+ # globals: assrt
2
+ # vim:fileencoding=utf-8
3
+ #
4
+ # enum.pyj
5
+ # Tests for the enum standard library (from enum import Enum).
6
+
7
+ ae = assrt.equal
8
+ ade = assrt.deepEqual
9
+ ok = assrt.ok
10
+
11
+ from enum import Enum
12
+
13
+ # ── 1. Basic member access: .name and .value ─────────────────────────────────
14
+ # STATUS: ✓ WORKS
15
+
16
+ class _Color(Enum):
17
+ RED = 1
18
+ GREEN = 2
19
+ BLUE = 3
20
+
21
+ ae(_Color.RED.name, 'RED')
22
+ ae(_Color.RED.value, 1)
23
+ ae(_Color.GREEN.name, 'GREEN')
24
+ ae(_Color.GREEN.value, 2)
25
+ ae(_Color.BLUE.name, 'BLUE')
26
+ ae(_Color.BLUE.value, 3)
27
+
28
+ # ── 2. Member singletons (identity) ──────────────────────────────────────────
29
+ # STATUS: ✓ WORKS
30
+
31
+ ok(_Color.RED is _Color.RED)
32
+ ok(_Color.RED is not _Color.GREEN)
33
+ ok(_Color.GREEN is not _Color.BLUE)
34
+
35
+ # ── 3. repr and str ──────────────────────────────────────────────────────────
36
+ # STATUS: ✓ WORKS
37
+ # Note: repr() for integer values uses the numeric representation.
38
+ # The class name in repr/str reflects the actual JS constructor name.
39
+
40
+ ae(repr(_Color.RED), '<_Color.RED: 1>')
41
+ ae(repr(_Color.GREEN), '<_Color.GREEN: 2>')
42
+ ae(str(_Color.RED), '_Color.RED')
43
+ ae(str(_Color.BLUE), '_Color.BLUE')
44
+
45
+ # ── 4. isinstance checks ─────────────────────────────────────────────────────
46
+ # STATUS: ✓ WORKS
47
+
48
+ ok(isinstance(_Color.RED, _Color))
49
+ ok(isinstance(_Color.RED, Enum))
50
+ ok(isinstance(_Color.GREEN, _Color))
51
+ ok(not isinstance(1, _Color))
52
+ ok(not isinstance(1, Enum))
53
+
54
+ # ── 5. Iteration via list() ───────────────────────────────────────────────────
55
+ # STATUS: ✓ WORKS
56
+
57
+ members = list(_Color)
58
+ ae(len(members), 3)
59
+ ae(members[0].name, 'RED')
60
+ ae(members[1].name, 'GREEN')
61
+ ae(members[2].name, 'BLUE')
62
+ ae(members[0].value, 1)
63
+ ae(members[1].value, 2)
64
+ ae(members[2].value, 3)
65
+
66
+ # ── 6. for loop iteration ─────────────────────────────────────────────────────
67
+ # STATUS: ✓ WORKS
68
+
69
+ _found_names = []
70
+ for _m in _Color:
71
+ _found_names.push(_m.name)
72
+ ade(_found_names, ['RED', 'GREEN', 'BLUE'])
73
+
74
+ _found_values = []
75
+ for _m in _Color:
76
+ _found_values.push(_m.value)
77
+ ade(_found_values, [1, 2, 3])
78
+
79
+ # ── 7. _member_names_ registry ───────────────────────────────────────────────
80
+ # STATUS: ✓ WORKS
81
+
82
+ ade(_Color._member_names_, ['RED', 'GREEN', 'BLUE'])
83
+
84
+ # ── 8. String-valued enum ─────────────────────────────────────────────────────
85
+ # STATUS: ✓ WORKS
86
+
87
+ class _Direction(Enum):
88
+ NORTH = 'north'
89
+ SOUTH = 'south'
90
+ EAST = 'east'
91
+ WEST = 'west'
92
+
93
+ ae(_Direction.NORTH.name, 'NORTH')
94
+ ae(_Direction.NORTH.value, 'north')
95
+ ae(_Direction.SOUTH.value, 'south')
96
+ # RapydScript repr() wraps strings in double quotes (JS convention)
97
+ ae(repr(_Direction.NORTH), '<_Direction.NORTH: "north">')
98
+ ae(str(_Direction.EAST), '_Direction.EAST')
99
+ ae(len(list(_Direction)), 4)
100
+
101
+ # ── 9. Enum subclass with extra methods ───────────────────────────────────────
102
+ # STATUS: ✓ WORKS
103
+
104
+ class _Status(Enum):
105
+ ACTIVE = 1
106
+ INACTIVE = 0
107
+
108
+ def is_active(self):
109
+ return this is _Status.ACTIVE
110
+
111
+ ok(_Status.ACTIVE.is_active())
112
+ ok(not _Status.INACTIVE.is_active())
113
+
114
+ # ── 10. Multiple Enum subclasses are independent ──────────────────────────────
115
+ # STATUS: ✓ WORKS
116
+
117
+ ae(len(list(_Color)), 3)
118
+ ae(len(list(_Direction)), 4)
119
+ ae(len(list(_Status)), 2)
120
+ ok(_Color._member_names_ is not _Direction._member_names_)
121
+ ok(_Color.RED is not _Status.ACTIVE) # different classes, different members
122
+
123
+ # ── 11. Members are not confused with plain class instances ───────────────────
124
+ # STATUS: ✓ WORKS
125
+
126
+ ok(isinstance(_Color.RED, _Color))
127
+ ok(_Color.RED is _Color.RED) # same object every time
128
+
129
+ # ── 12. Values from _members_by_value_ lookup ────────────────────────────────
130
+ # STATUS: ✓ WORKS
131
+
132
+ ae(_Color._members_by_value_[1].name, 'RED')
133
+ ae(_Color._members_by_value_[2].name, 'GREEN')
134
+ ae(_Color._members_by_value_[3].name, 'BLUE')
@@ -0,0 +1,56 @@
1
+ # vim:fileencoding=utf-8
2
+ # globals: assrt
3
+
4
+ ae = assrt.equal
5
+ ade = assrt.deepEqual
6
+ ok = assrt.ok
7
+
8
+ # ── eval — basic expression evaluation ────────────────────────────────────────
9
+
10
+ ae(eval("1 + 2"), 3)
11
+ ae(eval("10 * 5"), 50)
12
+ ae(eval("100 - 37"), 63)
13
+ ae(eval('"hello" + " world"'), "hello world")
14
+ ae(eval("Math.pow(2, 8)"), 256)
15
+ ae(eval("True"), True)
16
+ ae(eval("None"), None)
17
+
18
+ # ── eval — with explicit globals dict ─────────────────────────────────────────
19
+
20
+ ae(eval("x + y", {"x": 10, "y": 5}), 15)
21
+ ae(eval("a * b", {"a": 3, "b": 4}), 12)
22
+ ae(eval("n * n", {"n": 7}), 49)
23
+
24
+ # ── eval — locals override globals ────────────────────────────────────────────
25
+
26
+ ae(eval("x", {"x": 1}, {"x": 99}), 99)
27
+ ae(eval("x + y", {"x": 10, "y": 20}, {"y": 1}), 11)
28
+
29
+ # ── exec — always returns None ────────────────────────────────────────────────
30
+
31
+ ae(exec("1 + 2"), None)
32
+ ae(exec("_ignored = 42"), None)
33
+
34
+ # ── exec — side effects via mutable objects in globals ────────────────────────
35
+
36
+ log = []
37
+ exec("log.push('hello')", {"log": log})
38
+ ae(log[0], "hello")
39
+
40
+ exec("log.push(1 + 2)", {"log": log})
41
+ ae(log[1], 3)
42
+
43
+ # exec with a function in globals
44
+ out = []
45
+ def _adder(a, b): out.push(a + b);
46
+ exec("fn(10, 7)", {"fn": _adder, "out": out})
47
+ ae(out[0], 17)
48
+
49
+ # exec returns None even when globals/locals provided
50
+ ae(exec("1 + 1", {"x": 5}), None)
51
+
52
+ # ── exec — JS loop, mutation visible in caller ────────────────────────────────
53
+
54
+ nums = []
55
+ exec("for _i in range(4):\n nums.append(_i * _i)", {"nums": nums})
56
+ ade(nums, [0, 1, 4, 9])
@@ -0,0 +1,148 @@
1
+ # vim:fileencoding=utf-8
2
+ # License: BSD
3
+ # Tests for __format__ dunder dispatch in format(), str.format(), and f-strings
4
+ # globals: assrt
5
+
6
+ ae = assrt.equal
7
+
8
+ # ── Basic custom __format__ ───────────────────────────────────────────────────
9
+
10
+ class Currency:
11
+ def __init__(self, amount):
12
+ self.amount = amount
13
+ def __str__(self):
14
+ return str(self.amount)
15
+ def __format__(self, spec):
16
+ if spec == 'usd':
17
+ return '$' + str(self.amount)
18
+ if spec == 'eur':
19
+ return '€' + str(self.amount)
20
+ return format(self.amount, spec)
21
+
22
+ c = Currency(42)
23
+
24
+ # format() builtin dispatches to __format__
25
+ ae(format(c, 'usd'), '$42')
26
+ ae(format(c, 'eur'), '€42')
27
+ ae(format(c, '.2f'), '42.00')
28
+
29
+ # str.format() dispatches to __format__
30
+ ae(str.format('{:usd}', c), '$42')
31
+ ae(str.format('{:eur}', c), '€42')
32
+ ae(str.format('{:.2f}', c), '42.00')
33
+
34
+ # f-strings dispatch to __format__
35
+ ae(f'{c:usd}', '$42')
36
+ ae(f'{c:eur}', '€42')
37
+ ae(f'{c:.2f}', '42.00')
38
+
39
+ # ── format() with empty spec calls __format__('') ────────────────────────────
40
+
41
+ class Tagged:
42
+ def __init__(self, v):
43
+ self.v = v
44
+ def __str__(self):
45
+ return 'str:' + str(self.v)
46
+ def __format__(self, spec):
47
+ if not spec:
48
+ return 'fmt:' + str(self.v)
49
+ return 'fmt:' + format(self.v, spec)
50
+
51
+ t = Tagged(7)
52
+ ae(format(t), 'fmt:7')
53
+ ae(format(t, ''), 'fmt:7')
54
+ ae(str.format('{}', t), 'fmt:7')
55
+ ae(f'{t}', 'fmt:7')
56
+
57
+ # ── Default __format__ delegates to __str__ when spec is empty ────────────────
58
+
59
+ class Simple:
60
+ def __str__(self):
61
+ return 'simple!'
62
+
63
+ s = Simple()
64
+ ae(format(s), 'simple!')
65
+ ae(format(s, ''), 'simple!')
66
+ ae(str.format('{}', s), 'simple!')
67
+ ae(f'{s}', 'simple!')
68
+
69
+ # ── Default __format__ raises TypeError for non-empty spec ───────────────────
70
+
71
+ class Plain:
72
+ def __str__(self):
73
+ return 'plain'
74
+
75
+ p = Plain()
76
+ raised = False
77
+ try:
78
+ format(p, 'd')
79
+ except TypeError:
80
+ raised = True
81
+ ae(raised, True)
82
+
83
+ raised = False
84
+ try:
85
+ str.format('{:d}', p)
86
+ except TypeError:
87
+ raised = True
88
+ ae(raised, True)
89
+
90
+ # ── Inheritance: subclass inherits parent __format__ ─────────────────────────
91
+
92
+ class Base:
93
+ def __format__(self, spec):
94
+ return 'base:' + spec
95
+
96
+ class Child(Base):
97
+ pass
98
+
99
+ child = Child()
100
+ ae(format(child, 'x'), 'base:x')
101
+ ae(str.format('{:x}', child), 'base:x')
102
+ ae(f'{child:x}', 'base:x')
103
+
104
+ # ── Subclass can override __format__ ─────────────────────────────────────────
105
+
106
+ class Override(Base):
107
+ def __format__(self, spec):
108
+ return 'override:' + spec
109
+
110
+ o = Override()
111
+ ae(format(o, 'y'), 'override:y')
112
+ ae(str.format('{:y}', o), 'override:y')
113
+
114
+ # ── !r and !s transformers bypass __format__ ─────────────────────────────────
115
+
116
+ class WithRepr:
117
+ def __repr__(self):
118
+ return 'MyRepr'
119
+ def __str__(self):
120
+ return 'MyStr'
121
+ def __format__(self, spec):
122
+ return 'MyFmt'
123
+
124
+ wr = WithRepr()
125
+ # With no transformer, __format__ is called
126
+ ae(str.format('{}', wr), 'MyFmt')
127
+ # !s applies str(), result is a string (no __format__)
128
+ ae(str.format('{!s}', wr), 'MyStr')
129
+ # !r applies repr()
130
+ ae(str.format('{!r}', wr), 'MyRepr')
131
+
132
+ # ── Multiple fields with __format__ ──────────────────────────────────────────
133
+
134
+ class Qty:
135
+ def __init__(self, n):
136
+ self.n = n
137
+ def __str__(self):
138
+ return str(self.n)
139
+ def __format__(self, spec):
140
+ if spec == 'w':
141
+ words = ['zero', 'one', 'two', 'three', 'four', 'five']
142
+ return words[self.n] if self.n < len(words) else str(self.n)
143
+ return format(self.n, spec)
144
+
145
+ a, b = Qty(1), Qty(2)
146
+ ae(str.format('{:w} and {:w}', a, b), 'one and two')
147
+ ae(f'{a:w} + {b:w}', 'one + two')
148
+ ae(str.format('{0:d} + {1:d}', a, b), '1 + 2')
@@ -1,151 +1,151 @@
1
- # globals: assrt
2
-
3
- def nothing():
4
- pass
5
- assrt.equal(nothing(), undefined)
6
-
7
- add = def(a, b):
8
- return a+b
9
- def sub(a, b):
10
- return a-b
11
-
12
- mul = None
13
- (def():
14
- nonlocal mul
15
- mul = def(a, b):
16
- return a*b
17
-
18
- div = def(a, b): # noqa:unused-local
19
- return a/b
20
- )()
21
-
22
- assrt.equal(add(1,2), 3)
23
- assrt.equal(sub(1,2), -1)
24
- assrt.equal(mul(2,2), 4)
25
- # for some reason input to throws must be of type block, hence the 'def' wrapper
26
- assrt.throws(
27
- def():
28
- div(6,3) # noqa: undef
29
- ,
30
- /div is not defined/
31
- )
32
-
33
- arr = [8,4]
34
- assrt.equal(add(*arr), 12)
35
- assrt.ok(Array.isArray(arr))
36
-
37
- def sum(*args):
38
- ttl = 0
39
- for i in args:
40
- ttl += i
41
- return ttl
42
- assrt.equal(sum(1,2,3), 6)
43
- assrt.equal(sum(1,*[2,3]), 6)
44
-
45
- num = 4
46
- def():
47
- nonlocal num
48
- num = 5
49
- .call(this)
50
-
51
- assrt.equal(num, 5)
52
-
53
- x = "foo"
54
- y = 5
55
- def swap(x, y):
56
- return y, x
57
- x, y = swap(x, y)
58
- assrt.equal(x, 5)
59
- assrt.equal(y, "foo")
60
-
61
- count = 0
62
- f, r = (def():
63
- def fake_increment():
64
- count += 1
65
- def real_increment():
66
- nonlocal count
67
- count += 1
68
- return fake_increment, real_increment
69
- ).call(this)
70
-
71
- f()
72
- assrt.equal(count, 0)
73
- r()
74
- assrt.equal(count, 1)
75
-
76
- st = "this is a string"
77
- assrt.equal(jstype(st), v"typeof st")
78
-
79
- # testing inlined functions
80
- inlined = [
81
- def(x): return x+1;, def(x): return x+2;,
82
- def(x): return x+3
83
- ,
84
- def(x): return x+4
85
- ]
86
- assrt.equal(inlined[0](1), 2)
87
- assrt.equal(inlined[1](1), 3)
88
- assrt.equal(inlined[2](1), 4)
89
- assrt.equal(inlined[3](1), 5)
90
-
91
- # decorators
92
- def makebold(fn):
93
- def wrapped(arg):
94
- return "<b>" + fn(arg) + "</b>"
95
- return wrapped
96
-
97
- def makeitalic(fn):
98
- def wrapped(arg):
99
- return "<i>" + fn(arg) + "</i>"
100
- return wrapped
101
-
102
- @makebold
103
- @makeitalic
104
- def hello(something):
105
- return "hello " + something
106
-
107
- assrt.equal(hello("world"), "<b><i>hello world</i></b>")
108
- assrt.equal(hello.__module__, '__main__')
109
- assrt.equal(hello.__argnames__.length, 1)
110
- assrt.equal(hello.__argnames__[0], 'arg')
111
-
112
-
113
- def simple_wrapper(f):
114
- f.test_attr = 'test'
115
- return f
116
-
117
-
118
- @simple_wrapper
119
- def fw(x):
120
- pass
121
-
122
- assrt.equal(fw.__module__, '__main__')
123
- assrt.equal(fw.__argnames__.length, 1)
124
- assrt.equal(fw.__argnames__[0], 'x')
125
- # just because something is a reserved keyword in RapydScript, doesn't mean other libraries won't attempt to use it
126
- # let's make sure we parse that correctly
127
- five = {}
128
- v"five.is = function(n) { return 5 == n };"
129
- assrt.ok(five.is(5))
130
-
131
- # function assignment via conditional
132
- foo = (def(): return 5;) if 0 else (def(): return 6;)
133
- bar = (def(): return 5;) if 0 < 1 else (def(): return 6;)
134
- baz = (def():
135
- return 5
136
- ) if 1 else (def():
137
- return 6
138
- )
139
- assrt.equal(foo(), 6)
140
- assrt.equal(bar(), 5)
141
- assrt.equal(baz(), 5)
142
-
143
- def trailing_comma(a, b,):
144
- return a + b
145
- assrt.equal(trailing_comma(1, 2), 3)
146
- assrt.equal(trailing_comma(1, 2,), 3)
147
-
148
- def return_string_with_newline():
149
- return '''a
150
- b'''
151
- assrt.equal(return_string_with_newline(), 'a\nb')
1
+ # globals: assrt
2
+
3
+ def nothing():
4
+ pass
5
+ assrt.equal(nothing(), undefined)
6
+
7
+ add = def(a, b):
8
+ return a+b
9
+ def sub(a, b):
10
+ return a-b
11
+
12
+ mul = None
13
+ (def():
14
+ nonlocal mul
15
+ mul = def(a, b):
16
+ return a*b
17
+
18
+ div = def(a, b): # noqa:unused-local
19
+ return a/b
20
+ )()
21
+
22
+ assrt.equal(add(1,2), 3)
23
+ assrt.equal(sub(1,2), -1)
24
+ assrt.equal(mul(2,2), 4)
25
+ # for some reason input to throws must be of type block, hence the 'def' wrapper
26
+ assrt.throws(
27
+ def():
28
+ div(6,3) # noqa: undef
29
+ ,
30
+ /div is not defined/
31
+ )
32
+
33
+ arr = [8,4]
34
+ assrt.equal(add(*arr), 12)
35
+ assrt.ok(Array.isArray(arr))
36
+
37
+ def sum(*args):
38
+ ttl = 0
39
+ for i in args:
40
+ ttl += i
41
+ return ttl
42
+ assrt.equal(sum(1,2,3), 6)
43
+ assrt.equal(sum(1,*[2,3]), 6)
44
+
45
+ num = 4
46
+ def():
47
+ nonlocal num
48
+ num = 5
49
+ .call(this)
50
+
51
+ assrt.equal(num, 5)
52
+
53
+ x = "foo"
54
+ y = 5
55
+ def swap(x, y):
56
+ return y, x
57
+ x, y = swap(x, y)
58
+ assrt.equal(x, 5)
59
+ assrt.equal(y, "foo")
60
+
61
+ count = 0
62
+ f, r = (def():
63
+ def fake_increment():
64
+ count += 1
65
+ def real_increment():
66
+ nonlocal count
67
+ count += 1
68
+ return fake_increment, real_increment
69
+ ).call(this)
70
+
71
+ f()
72
+ assrt.equal(count, 0)
73
+ r()
74
+ assrt.equal(count, 1)
75
+
76
+ st = "this is a string"
77
+ assrt.equal(jstype(st), v"typeof st")
78
+
79
+ # testing inlined functions
80
+ inlined = [
81
+ def(x): return x+1;, def(x): return x+2;,
82
+ def(x): return x+3
83
+ ,
84
+ def(x): return x+4
85
+ ]
86
+ assrt.equal(inlined[0](1), 2)
87
+ assrt.equal(inlined[1](1), 3)
88
+ assrt.equal(inlined[2](1), 4)
89
+ assrt.equal(inlined[3](1), 5)
90
+
91
+ # decorators
92
+ def makebold(fn):
93
+ def wrapped(arg):
94
+ return "<b>" + fn(arg) + "</b>"
95
+ return wrapped
96
+
97
+ def makeitalic(fn):
98
+ def wrapped(arg):
99
+ return "<i>" + fn(arg) + "</i>"
100
+ return wrapped
101
+
102
+ @makebold
103
+ @makeitalic
104
+ def hello(something):
105
+ return "hello " + something
106
+
107
+ assrt.equal(hello("world"), "<b><i>hello world</i></b>")
108
+ assrt.equal(hello.__module__, '__main__')
109
+ assrt.equal(hello.__argnames__.length, 1)
110
+ assrt.equal(hello.__argnames__[0], 'arg')
111
+
112
+
113
+ def simple_wrapper(f):
114
+ f.test_attr = 'test'
115
+ return f
116
+
117
+
118
+ @simple_wrapper
119
+ def fw(x):
120
+ pass
121
+
122
+ assrt.equal(fw.__module__, '__main__')
123
+ assrt.equal(fw.__argnames__.length, 1)
124
+ assrt.equal(fw.__argnames__[0], 'x')
125
+ # just because something is a reserved keyword in RapydScript, doesn't mean other libraries won't attempt to use it
126
+ # let's make sure we parse that correctly
127
+ five = {}
128
+ v"five.is = function(n) { return 5 == n };"
129
+ assrt.ok(five.is(5))
130
+
131
+ # function assignment via conditional
132
+ foo = (def(): return 5;) if 0 else (def(): return 6;)
133
+ bar = (def(): return 5;) if 0 < 1 else (def(): return 6;)
134
+ baz = (def():
135
+ return 5
136
+ ) if 1 else (def():
137
+ return 6
138
+ )
139
+ assrt.equal(foo(), 6)
140
+ assrt.equal(bar(), 5)
141
+ assrt.equal(baz(), 5)
142
+
143
+ def trailing_comma(a, b,):
144
+ return a + b
145
+ assrt.equal(trailing_comma(1, 2), 3)
146
+ assrt.equal(trailing_comma(1, 2,), 3)
147
+
148
+ def return_string_with_newline():
149
+ return '''a
150
+ b'''
151
+ assrt.equal(return_string_with_newline(), 'a\nb')