spitewaste 0.2.0 → 0.2.01
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.
- checksums.yaml +4 -4
- data/Rakefile +2 -3
- data/lib/spitewaste/libspw/array.spw +50 -12
- data/lib/spitewaste/libspw/bits.spw +4 -4
- data/lib/spitewaste/libspw/docs.json +262 -3
- data/lib/spitewaste/libspw/fun.spw +22 -5
- data/lib/spitewaste/libspw/math.spw +6 -9
- data/lib/spitewaste/libspw/random.spw +27 -9
- data/lib/spitewaste/libspw/rational.spw +2 -2
- data/lib/spitewaste/libspw/stack.spw +11 -13
- data/lib/spitewaste/libspw/string.spw +23 -24
- data/lib/spitewaste/libspw/test.spw +3 -0
- data/lib/spitewaste/libspw/util.spw +11 -11
- data/lib/spitewaste/parsers/spitewaste.rb +4 -4
- data/lib/spitewaste/version.rb +1 -1
- metadata +1 -1
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 9ce4494399350d9afb01a0c84aef1ce504da4a24349b33a45de83d6b6f4fa10b
|
4
|
+
data.tar.gz: 330b14a9eb241ff0ac8986956c8f790dd88ce87db4823e08ff19edfc7db0aee1
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 04d8acb9a1ed8e1617447407ee511b38b35d2f15a0ef2cc836690138f67f1e036712eb912d3c1dc7331e4d4d2d8694b4fad67be4a0fdefec55515144c9b4a9ce
|
7
|
+
data.tar.gz: 3161a39f4f7b364a5204d4174bbe7f1aa3ac43c530c86d6273b3fe61a04a93eb450688c882d9709f06a105bed35e37479310183cdb39d1509cf90049f2f0fcf7
|
data/Rakefile
CHANGED
@@ -15,9 +15,8 @@ task :docs do |t|
|
|
15
15
|
|
16
16
|
Dir.chdir('lib/spitewaste/libspw') do |d|
|
17
17
|
Dir['*.spw'].sort.each do |path|
|
18
|
-
|
19
|
-
|
20
|
-
docs[lib] = extract_docs path
|
18
|
+
mod = File.basename path, '.spw'
|
19
|
+
docs[mod] = extract_docs path
|
21
20
|
end
|
22
21
|
|
23
22
|
File.open('docs.json', ?w) { |f|
|
@@ -10,6 +10,12 @@ import util ; dec, die!, eq
|
|
10
10
|
|
11
11
|
$amax = 1000
|
12
12
|
|
13
|
+
; prints the array A to stdout in the form [e1,e2,...]
|
14
|
+
; [A] => []
|
15
|
+
aryprint:
|
16
|
+
map (:to_s) push ',' :strjoinc
|
17
|
+
push '[' ochr :print push ']' ochr ret
|
18
|
+
|
13
19
|
; places an array of N elements E at the top of the stack
|
14
20
|
; [N E] => [A]
|
15
21
|
;
|
@@ -36,7 +42,23 @@ arysum: reduce (add) ret
|
|
36
42
|
; [7 50 10 2] => [7 50 10 2 50 10 2]
|
37
43
|
arydup:
|
38
44
|
dup $++ push -2 copy 1 store
|
39
|
-
times (
|
45
|
+
times (@-2 $-- :ncopy) ret
|
46
|
+
|
47
|
+
; returns 1 if the arrays A1 and A2 have the same length and
|
48
|
+
; contain the same elements in the same order, 0 otherwise
|
49
|
+
; [A1 A2] => [0 | 1]
|
50
|
+
;
|
51
|
+
; [1 2 3 3 1 2 3 3] => [1]
|
52
|
+
; [1 2 3 3 3 2 1 3] => [0]
|
53
|
+
; [1 2 2 1 2 3 3] => [0]
|
54
|
+
; [1 2 3 3 1 2 2] => [0]
|
55
|
+
; [7 10 2 7 10 2] => [1]
|
56
|
+
; [6 1 9 1] => [0]
|
57
|
+
aryeq: dup $++ :roll copy 1 copy 1 :eq jz _aryeq_difflen ; length mismatch
|
58
|
+
^-1 times (@-1 :ncopy :eq jz _aryeq_no)
|
59
|
+
push 1 @-1 :nslide ret
|
60
|
+
_aryeq_no: push 0 @-1 @-5 sub $-- :nslide ret ; ! -5 is magic from times()
|
61
|
+
_aryeq_difflen: add push 0 swap :nslide ret
|
40
62
|
|
41
63
|
; places the element E at the end of the array A, increasing its length by 1
|
42
64
|
; [A E] => [A']
|
@@ -99,15 +121,15 @@ arycat: dup $++ :roll add ret
|
|
99
121
|
;;;
|
100
122
|
|
101
123
|
arypack:
|
102
|
-
:arydup reduce (:max) $++
|
103
|
-
$-- times (
|
104
|
-
push $amax mul
|
105
|
-
push $amax mul
|
124
|
+
:arydup reduce (:max) $++ ^-1
|
125
|
+
$-- times (@-1 mul add)
|
126
|
+
push $amax mul @-1 add
|
127
|
+
push $amax mul @-10 add ret
|
106
128
|
|
107
129
|
aryunpack:
|
108
|
-
push $amax :divmod
|
109
|
-
push $amax :divmod
|
110
|
-
|
130
|
+
push $amax :divmod ^-2
|
131
|
+
push $amax :divmod ^-1
|
132
|
+
@-2 times (@-1 :divmod swap)
|
111
133
|
push 2 sub load ret
|
112
134
|
|
113
135
|
arylen: push $amax mod ret
|
@@ -161,8 +183,8 @@ _aryswap_noop: pop pop ret
|
|
161
183
|
; [6 8 -3 4 0 5] => [-3 8]
|
162
184
|
; [7 1] => [7 7]
|
163
185
|
minmax:
|
164
|
-
:arydup reduce (:max)
|
165
|
-
reduce (:min)
|
186
|
+
:arydup reduce (:max) ^-1
|
187
|
+
reduce (:min) @-1 ret
|
166
188
|
|
167
189
|
;;; TODO: make sort not atrociously inefficient
|
168
190
|
|
@@ -170,11 +192,27 @@ sort: push -3 copy 1 store ; preserve length
|
|
170
192
|
_sort_loop:
|
171
193
|
:arydup reduce (:min)
|
172
194
|
push -1 copy 1 store copy 1 $++ :bury ; stash minimum element
|
173
|
-
:arydup
|
195
|
+
:arydup @-1 :aryindex
|
174
196
|
copy 1 swap sub :dig $-- ; remove minimum element from array
|
175
197
|
push 0 copy 1 sub jn _sort_loop
|
176
198
|
push 3 sub load ret
|
177
199
|
|
200
|
+
; returns 0 if any of the elements in array A is
|
201
|
+
; strictly less than the one before it, 1 otherwise
|
202
|
+
; [A] => [0 | 1]
|
203
|
+
;
|
204
|
+
; [1 2 3 3] => [1]
|
205
|
+
; [3 2 1 3] => [0]
|
206
|
+
; [1 1 2 2 4] => [1]
|
207
|
+
; [1 2 3 4 3 5] => [0]
|
208
|
+
sorted?: $--
|
209
|
+
_sorted_loop:
|
210
|
+
copy 1 copy 3 sub jn _sorted_no
|
211
|
+
$-- dup jz _sorted_yes
|
212
|
+
slide 1 jump _sorted_loop
|
213
|
+
_sorted_no: $++ push 0 swap :nslide ret
|
214
|
+
_sorted_yes: push 1 slide 3 ret
|
215
|
+
|
178
216
|
; reverses the array A
|
179
217
|
; [A] => [A']
|
180
218
|
;
|
@@ -196,4 +234,4 @@ aryrep: push -1 swap push -3 copy 1 store store
|
|
196
234
|
_aryrep_loop:
|
197
235
|
push -1 dup :dec load jz _aryrep_done
|
198
236
|
:arydup jump _aryrep_loop
|
199
|
-
_aryrep_done:
|
237
|
+
_aryrep_done: @-3 $-- times (:arycat) ret
|
@@ -12,8 +12,8 @@ $bitfun(op, bit, done) {
|
|
12
12
|
push -2,1,-1,0 store store
|
13
13
|
_`op`_loop: push -1
|
14
14
|
copy 2 push 2 mod copy 2 push 2 mod `bit`
|
15
|
-
|
16
|
-
|
15
|
+
@-1 swap @-2 dup push 2 mul
|
16
|
+
^-2 mul add store
|
17
17
|
push 2 div swap push 2 div
|
18
18
|
dup copy 2 mul jz _`op`_done swap jump _`op`_loop
|
19
19
|
_`op`_done: `done` ret
|
@@ -35,7 +35,7 @@ band: $bitfun(band, mul, mul $-- load)
|
|
35
35
|
; [61 77] => [125] [93 65] => [93]
|
36
36
|
; [14 87] => [95] [71 37] => [103]
|
37
37
|
; [7 19] => [23] [38 92] => [126]
|
38
|
-
bor: $bitfun(bor, add $++ push 2 div, add
|
38
|
+
bor: $bitfun(bor, add $++ push 2 div, add @-2 mul @-1 add)
|
39
39
|
|
40
40
|
; returns the bitwise XOR of A and B
|
41
41
|
; [A B] => [A ^ B]
|
@@ -44,7 +44,7 @@ bor: $bitfun(bor, add $++ push 2 div, add push -2 load mul push -1 load add)
|
|
44
44
|
; [51 5] => [54] [97 77] => [44]
|
45
45
|
; [39 65] => [102] [12 26] => [22]
|
46
46
|
; [44 36] => [8] [6 21] => [19]
|
47
|
-
bxor: $bitfun(bxor, :neq, add
|
47
|
+
bxor: $bitfun(bxor, :neq, add @-2 mul @-1 add)
|
48
48
|
|
49
49
|
; returns the infinite-precision bitwise NOT of N by inverting all of its bits
|
50
50
|
; [N] => [~N]
|
@@ -135,6 +135,95 @@
|
|
135
135
|
]
|
136
136
|
]
|
137
137
|
},
|
138
|
+
"aryeq": {
|
139
|
+
"full": "returns 1 if the arrays A1 and A2 have the same length and\ncontain the same elements in the same order, 0 otherwise\n[A1 A2] => [0 | 1]\n\n[1 2 3 3 1 2 3 3] => [1]\n[1 2 3 3 3 2 1 3] => [0]\n[1 2 2 1 2 3 3] => [0]\n[1 2 3 3 1 2 2] => [0]\n[7 10 2 7 10 2] => [1]\n[6 1 9 1] => [0]\n",
|
140
|
+
"desc": "returns 1 if the arrays A1 and A2 have the same length and\ncontain the same elements in the same order, 0 otherwise",
|
141
|
+
"effect": "[A1 A2] => [0 | 1]",
|
142
|
+
"cases": [
|
143
|
+
[
|
144
|
+
[
|
145
|
+
1,
|
146
|
+
2,
|
147
|
+
3,
|
148
|
+
3,
|
149
|
+
1,
|
150
|
+
2,
|
151
|
+
3,
|
152
|
+
3
|
153
|
+
],
|
154
|
+
[
|
155
|
+
1
|
156
|
+
]
|
157
|
+
],
|
158
|
+
[
|
159
|
+
[
|
160
|
+
1,
|
161
|
+
2,
|
162
|
+
3,
|
163
|
+
3,
|
164
|
+
3,
|
165
|
+
2,
|
166
|
+
1,
|
167
|
+
3
|
168
|
+
],
|
169
|
+
[
|
170
|
+
0
|
171
|
+
]
|
172
|
+
],
|
173
|
+
[
|
174
|
+
[
|
175
|
+
1,
|
176
|
+
2,
|
177
|
+
2,
|
178
|
+
1,
|
179
|
+
2,
|
180
|
+
3,
|
181
|
+
3
|
182
|
+
],
|
183
|
+
[
|
184
|
+
0
|
185
|
+
]
|
186
|
+
],
|
187
|
+
[
|
188
|
+
[
|
189
|
+
1,
|
190
|
+
2,
|
191
|
+
3,
|
192
|
+
3,
|
193
|
+
1,
|
194
|
+
2,
|
195
|
+
2
|
196
|
+
],
|
197
|
+
[
|
198
|
+
0
|
199
|
+
]
|
200
|
+
],
|
201
|
+
[
|
202
|
+
[
|
203
|
+
7,
|
204
|
+
10,
|
205
|
+
2,
|
206
|
+
7,
|
207
|
+
10,
|
208
|
+
2
|
209
|
+
],
|
210
|
+
[
|
211
|
+
1
|
212
|
+
]
|
213
|
+
],
|
214
|
+
[
|
215
|
+
[
|
216
|
+
6,
|
217
|
+
1,
|
218
|
+
9,
|
219
|
+
1
|
220
|
+
],
|
221
|
+
[
|
222
|
+
0
|
223
|
+
]
|
224
|
+
]
|
225
|
+
]
|
226
|
+
},
|
138
227
|
"aryfill": {
|
139
228
|
"full": "places an array of N elements E at the top of the stack\n[N E] => [A]\n\n[3 0] => [0 0 0 3]\n[5 1] => [1 1 1 1 1 5]\n[4 -2] => [-2 -2 -2 -2 4]\n",
|
140
229
|
"desc": "places an array of N elements E at the top of the stack",
|
@@ -338,6 +427,14 @@
|
|
338
427
|
]
|
339
428
|
]
|
340
429
|
},
|
430
|
+
"aryprint": {
|
431
|
+
"full": "prints the array A to stdout in the form [e1,e2,...]\n[A] => []\n",
|
432
|
+
"desc": "prints the array A to stdout in the form [e1,e2,...]",
|
433
|
+
"effect": "[A] => []",
|
434
|
+
"cases": [
|
435
|
+
|
436
|
+
]
|
437
|
+
},
|
341
438
|
"arypush": {
|
342
439
|
"full": "places the element E at the end of the array A, increasing its length by 1\n[A E] => [A']\n\n[3 2 1 3 7] => [3 2 1 7 4]\n[4 2 2 0] => [4 2 0 3]\n[6 1 9] => [6 9 2]\n[7 5 8 2 4] => [7 5 8 4 3]\n",
|
343
440
|
"desc": "places the element E at the end of the array A, increasing its length by 1",
|
@@ -794,6 +891,60 @@
|
|
794
891
|
]
|
795
892
|
]
|
796
893
|
]
|
894
|
+
},
|
895
|
+
"sorted?": {
|
896
|
+
"full": "returns 0 if any of the elements in array A is\nstrictly less than the one before it, 1 otherwise\n[A] => [0 | 1]\n\n[1 2 3 3] => [1]\n[3 2 1 3] => [0]\n[1 1 2 2 4] => [1]\n[1 2 3 4 3 5] => [0]\n",
|
897
|
+
"desc": "returns 0 if any of the elements in array A is\nstrictly less than the one before it, 1 otherwise",
|
898
|
+
"effect": "[A] => [0 | 1]",
|
899
|
+
"cases": [
|
900
|
+
[
|
901
|
+
[
|
902
|
+
1,
|
903
|
+
2,
|
904
|
+
3,
|
905
|
+
3
|
906
|
+
],
|
907
|
+
[
|
908
|
+
1
|
909
|
+
]
|
910
|
+
],
|
911
|
+
[
|
912
|
+
[
|
913
|
+
3,
|
914
|
+
2,
|
915
|
+
1,
|
916
|
+
3
|
917
|
+
],
|
918
|
+
[
|
919
|
+
0
|
920
|
+
]
|
921
|
+
],
|
922
|
+
[
|
923
|
+
[
|
924
|
+
1,
|
925
|
+
1,
|
926
|
+
2,
|
927
|
+
2,
|
928
|
+
4
|
929
|
+
],
|
930
|
+
[
|
931
|
+
1
|
932
|
+
]
|
933
|
+
],
|
934
|
+
[
|
935
|
+
[
|
936
|
+
1,
|
937
|
+
2,
|
938
|
+
3,
|
939
|
+
4,
|
940
|
+
3,
|
941
|
+
5
|
942
|
+
],
|
943
|
+
[
|
944
|
+
0
|
945
|
+
]
|
946
|
+
]
|
947
|
+
]
|
797
948
|
}
|
798
949
|
},
|
799
950
|
"bits": {
|
@@ -1405,6 +1556,45 @@
|
|
1405
1556
|
]
|
1406
1557
|
]
|
1407
1558
|
},
|
1559
|
+
"collatz_len": {
|
1560
|
+
"full": "returns the length L of the Collatz sequence for integer N\n[N] => [L]\n\n[1] => [1]\n[4] => [3]\n[7] => [17]\n[189] => [107]\n",
|
1561
|
+
"desc": "returns the length L of the Collatz sequence for integer N",
|
1562
|
+
"effect": "[N] => [L]",
|
1563
|
+
"cases": [
|
1564
|
+
[
|
1565
|
+
[
|
1566
|
+
1
|
1567
|
+
],
|
1568
|
+
[
|
1569
|
+
1
|
1570
|
+
]
|
1571
|
+
],
|
1572
|
+
[
|
1573
|
+
[
|
1574
|
+
4
|
1575
|
+
],
|
1576
|
+
[
|
1577
|
+
3
|
1578
|
+
]
|
1579
|
+
],
|
1580
|
+
[
|
1581
|
+
[
|
1582
|
+
7
|
1583
|
+
],
|
1584
|
+
[
|
1585
|
+
17
|
1586
|
+
]
|
1587
|
+
],
|
1588
|
+
[
|
1589
|
+
[
|
1590
|
+
189
|
1591
|
+
],
|
1592
|
+
[
|
1593
|
+
107
|
1594
|
+
]
|
1595
|
+
]
|
1596
|
+
]
|
1597
|
+
},
|
1408
1598
|
"isop": {
|
1409
1599
|
"full": "returns the sum of the alphabetical characters in string S where A=1, B=2...\n[S] => [sum]\n\n[\"Math\"] => [42]\n[\"wizards\"] => [100]\n[\"AbCd\"] => [10]\n",
|
1410
1600
|
"desc": "returns the sum of the alphabetical characters in string S where A=1, B=2...",
|
@@ -2373,6 +2563,56 @@
|
|
2373
2563
|
]
|
2374
2564
|
}
|
2375
2565
|
},
|
2566
|
+
"random": {
|
2567
|
+
"dice": {
|
2568
|
+
"full": "returns an array A of N random integers between 1 and D (inclusive)\n[N D] => [A]\n",
|
2569
|
+
"desc": "returns an array A of N random integers between 1 and D (inclusive)",
|
2570
|
+
"effect": "[N D] => [A]",
|
2571
|
+
"cases": [
|
2572
|
+
|
2573
|
+
]
|
2574
|
+
},
|
2575
|
+
"rand": {
|
2576
|
+
"full": "returns the next number N in the linear congruential generator (better MINSTD)\n[] => [N]\n",
|
2577
|
+
"desc": "returns the next number N in the linear congruential generator (better MINSTD)",
|
2578
|
+
"effect": "[] => [N]",
|
2579
|
+
"cases": [
|
2580
|
+
|
2581
|
+
]
|
2582
|
+
},
|
2583
|
+
"rand_range": {
|
2584
|
+
"full": "returns a random integer I between A and B (inclusive)\n[A B] => [I]\n",
|
2585
|
+
"desc": "returns a random integer I between A and B (inclusive)",
|
2586
|
+
"effect": "[A B] => [I]",
|
2587
|
+
"cases": [
|
2588
|
+
|
2589
|
+
]
|
2590
|
+
},
|
2591
|
+
"shuffle": {
|
2592
|
+
"full": "shuffles the array A in-place using the modern Fisher-Yates algorithm\n[A] => [A']\n",
|
2593
|
+
"desc": "shuffles the array A in-place using the modern Fisher-Yates algorithm",
|
2594
|
+
"effect": "[A] => [A']",
|
2595
|
+
"cases": [
|
2596
|
+
|
2597
|
+
]
|
2598
|
+
},
|
2599
|
+
"srand": {
|
2600
|
+
"full": "seeds the random number generator with integer S\n[S] => []\n",
|
2601
|
+
"desc": "seeds the random number generator with integer S",
|
2602
|
+
"effect": "[S] => []",
|
2603
|
+
"cases": [
|
2604
|
+
|
2605
|
+
]
|
2606
|
+
},
|
2607
|
+
"strfry": {
|
2608
|
+
"full": "shuffles the characters of the string S, producing a random anagram\n[S] => [S']\n",
|
2609
|
+
"desc": "shuffles the characters of the string S, producing a random anagram",
|
2610
|
+
"effect": "[S] => [S']",
|
2611
|
+
"cases": [
|
2612
|
+
|
2613
|
+
]
|
2614
|
+
}
|
2615
|
+
},
|
2376
2616
|
"rational": {
|
2377
2617
|
"from_r": {
|
2378
2618
|
"full": "decomposes the rational number R into its numerator N and denominator D\n[R] => [N D]\n\n[R(22,7)] => [22 7]\n[R(-3,4)] => [-3 4]\n[R(3,-4)] => [-3 4]\n[R(4,8)] => [4 8] ; no implicit simplification\n",
|
@@ -4686,6 +4926,25 @@
|
|
4686
4926
|
]
|
4687
4927
|
]
|
4688
4928
|
},
|
4929
|
+
"strtoa": {
|
4930
|
+
"full": "gets the characters of the string S onto the stack as a pseudo-array, but\nwith a leading 0 on the assumption that it'll eventually be repacked\n\n[\"abc\"] => [0 99 98 97 3]\n",
|
4931
|
+
"desc": "gets the characters of the string S onto the stack as a pseudo-array, but",
|
4932
|
+
"effect": "with a leading 0 on the assumption that it'll eventually be repacked",
|
4933
|
+
"cases": [
|
4934
|
+
[
|
4935
|
+
[
|
4936
|
+
1634657
|
4937
|
+
],
|
4938
|
+
[
|
4939
|
+
0,
|
4940
|
+
99,
|
4941
|
+
98,
|
4942
|
+
97,
|
4943
|
+
3
|
4944
|
+
]
|
4945
|
+
]
|
4946
|
+
]
|
4947
|
+
},
|
4689
4948
|
"strtrans": {
|
4690
4949
|
"full": "translates all characters in A to the corresponding characters in B\nin string S, ; similar to the `tr` utility in Unix. A and B must be\nof the same length. TODO: make this smarter (ranges, length mismatch)\n[S A B] => [S']\n\n[\"abcd\" \"abc\" \"xyz\"] => [\"xyzd\"]\n[\"foobar\" \"oba\" \"ele\"] => [\"feeler\"]\n[\"abcdcba\" \"abcd\" \"xyz|\"] => [\"xyz|zyx\"]\n",
|
4691
4950
|
"desc": "translates all characters in A to the corresponding characters in B\nin string S, ; similar to the `tr` utility in Unix. A and B must be\nof the same length. TODO: make this smarter (ranges, length mismatch)",
|
@@ -4852,9 +5111,9 @@
|
|
4852
5111
|
]
|
4853
5112
|
},
|
4854
5113
|
"die!": {
|
4855
|
-
"full": "prints the string at the top of the stack and halts execution\n",
|
4856
|
-
"desc": "",
|
4857
|
-
"effect": "
|
5114
|
+
"full": "prints the string at the top of the stack and halts execution after pushing\nsomething onto the stack to signal abnormal termination/unclean exit\n[...] => [... 1]\n",
|
5115
|
+
"desc": "prints the string at the top of the stack and halts execution after pushing\nsomething onto the stack to signal abnormal termination/unclean exit",
|
5116
|
+
"effect": "[...] => [... 1]",
|
4858
5117
|
"cases": [
|
4859
5118
|
|
4860
5119
|
]
|
@@ -36,6 +36,12 @@ _isop_resume: sub add swap push 128 div jump _isop_loop
|
|
36
36
|
_isop_no: dup jump _isop_resume
|
37
37
|
_isop_done: pop ret
|
38
38
|
|
39
|
+
$_do_collatz() {
|
40
|
+
dup push 2 mod
|
41
|
+
swap copy 1 push 2 mul $++ mul
|
42
|
+
push 2 copy 2 sub div add
|
43
|
+
}
|
44
|
+
|
39
45
|
; returns the elements of the Collatz sequence for integer N as a pseudo-array
|
40
46
|
; ! may run forever on some as-yet-unknown input
|
41
47
|
; [N] => [A]
|
@@ -48,18 +54,29 @@ _isop_done: pop ret
|
|
48
54
|
collatz: push 1 ; sequence length
|
49
55
|
_collatz_loop:
|
50
56
|
copy 1 dup push 1 sub jz _collatz_done
|
51
|
-
|
52
|
-
swap copy 1 push 2 mul $++ mul
|
53
|
-
push 2 copy 2 sub div add
|
54
|
-
swap $++ jump _collatz_loop
|
57
|
+
$_do_collatz() swap $++ jump _collatz_loop
|
55
58
|
_collatz_done: pop ret
|
56
59
|
|
60
|
+
; returns the length L of the Collatz sequence for integer N
|
61
|
+
; ! may run forever on some as-yet-unknown input
|
62
|
+
; [N] => [L]
|
63
|
+
;
|
64
|
+
; [1] => [1]
|
65
|
+
; [4] => [3]
|
66
|
+
; [7] => [17]
|
67
|
+
; [189] => [107]
|
68
|
+
collatz_len: push 1 swap
|
69
|
+
_collatz_len_loop:
|
70
|
+
dup $-- jz _collatz_done
|
71
|
+
$_do_collatz() swap $++ swap jump _collatz_len_loop
|
72
|
+
copy 1 dup push 1 sub jz _collatz_done
|
73
|
+
|
57
74
|
; ruby:
|
58
75
|
; push "'" :strcat push "ruby -e 'p " swap :strcat shell ret
|
59
76
|
|
60
77
|
$_to_roman(r, v) {
|
61
78
|
push `v` :divmod swap push `r` swap :strrep
|
62
|
-
|
79
|
+
@-2 swap :strcat ^-2
|
63
80
|
}
|
64
81
|
|
65
82
|
; converts the number N to a string of roman numerals R
|
@@ -51,7 +51,7 @@ ilog: push -1,0 store ; accumulator at -1
|
|
51
51
|
_ilog_loop: ; [n b]
|
52
52
|
swap copy 1 div dup jz _ilog_done
|
53
53
|
push -1 :inc swap jump _ilog_loop
|
54
|
-
_ilog_done:
|
54
|
+
_ilog_done: @-1 slide 2 ret
|
55
55
|
|
56
56
|
; returns the greatest common divisor of A and B
|
57
57
|
; [A B] => [gcd(A, B)]
|
@@ -111,10 +111,7 @@ abs: dup :sign mul ret
|
|
111
111
|
; [42 6] => [7 0]
|
112
112
|
; [ 1 5] => [0 1]
|
113
113
|
; ! [9 0] => [!!] TODO: find a way to expect exceptions
|
114
|
-
divmod:
|
115
|
-
push -1 swap store
|
116
|
-
dup push -1 load div
|
117
|
-
swap push -1 load mod ret
|
114
|
+
divmod: ^-1 dup @-1 div swap @-1 mod ret
|
118
115
|
|
119
116
|
; returns whether N is greater than 0
|
120
117
|
; [N] => [N > 0]
|
@@ -138,11 +135,11 @@ neg?: :sign push -1 :eq ret
|
|
138
135
|
; [25] => [1 5 25 3] ; no duplicate for perfect squares
|
139
136
|
; [60] => [1 2 3 4 5 6 60 30 20 15 12 10 12]
|
140
137
|
divisors: ; [n]
|
141
|
-
dup
|
138
|
+
dup ^-1 ; preserve N because array operations
|
142
139
|
:isqrt push 1 swap :range dup ; 1..isqrt(N)
|
143
|
-
reject (
|
144
|
-
map (
|
145
|
-
|
140
|
+
reject (@-1 swap mod) :arydup ; get first half of divisors
|
141
|
+
map (@-1 swap div) :arycat ; map first half to second half
|
142
|
+
@-1 copy 2 dup mul sub jz _divisors_square ret
|
146
143
|
_divisors_square: slide 1 $-- ret ; de-duplicate when N is a perfect square
|
147
144
|
|
148
145
|
; returns the number of ways to choose K elements from a set of N
|
@@ -1,16 +1,34 @@
|
|
1
|
-
import math
|
1
|
+
import math ; pow
|
2
|
+
import string ; strtoa
|
2
3
|
|
3
|
-
|
4
|
+
; seeds the random number generator with integer S
|
5
|
+
; [S] => []
|
6
|
+
srand: ^$seed ret
|
4
7
|
|
8
|
+
; returns the next number N in the linear congruential generator (better MINSTD)
|
9
|
+
; [] => [N]
|
5
10
|
rand:
|
6
11
|
push $seed dup dup load
|
7
|
-
push
|
8
|
-
push 2,
|
12
|
+
push 48271 mul
|
13
|
+
push 2,31 :pow $-- mod
|
9
14
|
store load ret
|
10
15
|
|
11
|
-
|
12
|
-
|
16
|
+
; returns a random integer I between A and B (inclusive)
|
17
|
+
; [A B] => [I]
|
18
|
+
rand_range:
|
19
|
+
$++ copy 1 sub :rand swap mod add ret
|
13
20
|
|
14
|
-
|
15
|
-
|
16
|
-
|
21
|
+
; returns an array A of N random integers between 1 and D (inclusive)
|
22
|
+
; [N D] => [A]
|
23
|
+
dice: ^-2 dup ^-1 times (push 1 @-2 :rand_range) @-1 ret
|
24
|
+
|
25
|
+
; shuffles the array A in-place using the modern Fisher-Yates algorithm
|
26
|
+
; [A] => [A']
|
27
|
+
shuffle: dup $-- ^-3
|
28
|
+
_shuffle_loop:
|
29
|
+
push 0 @-3 :rand_range @-3 :aryswap
|
30
|
+
push -3 :dec @-3 push -1 mul jn _shuffle_loop ret
|
31
|
+
|
32
|
+
; shuffles the characters of the string S, producing a random anagram
|
33
|
+
; [S] => [S']
|
34
|
+
strfry: :strtoa :shuffle pop :strpack ret
|
@@ -187,9 +187,9 @@ _ratpow_neg: push -1 mul swap :ratinv swap :ratpow ret
|
|
187
187
|
; [R(355,113) 6] => [3 141592]
|
188
188
|
; [R(8675,309) 10] => [28 744336569] TODO: leading 0 is lost (bug)
|
189
189
|
; [R(2,4) 3] => [0 500]
|
190
|
-
to_f:
|
190
|
+
to_f: ^-2 :from_r :divmod push 0 swap
|
191
191
|
_to_f_loop:
|
192
|
-
|
192
|
+
@-1 :divmod swap
|
193
193
|
copy 2 push 10 mul add
|
194
194
|
swap push 10 mul
|
195
195
|
push 2 :dig
|
@@ -16,15 +16,13 @@ import util ; dec
|
|
16
16
|
; [1 2 3 4 5 3] => [1 3 4 5 2]
|
17
17
|
roll:
|
18
18
|
push -10 dup store ; current heap index kept at -10
|
19
|
-
_roll_keep:
|
19
|
+
_roll_keep:
|
20
20
|
dup jz _roll_remove
|
21
21
|
push -10 :dec
|
22
|
-
swap
|
22
|
+
swap @-10 swap store
|
23
23
|
push 1 sub jump _roll_keep
|
24
|
-
_roll_remove:
|
25
|
-
|
26
|
-
swap push -10 swap store
|
27
|
-
_roll_restore: ; i
|
24
|
+
_roll_remove: push 10 sub load swap ^-10
|
25
|
+
_roll_restore:
|
28
26
|
dup load swap push 1 add
|
29
27
|
dup push 10 add jz _roll_done
|
30
28
|
jump _roll_restore
|
@@ -37,15 +35,15 @@ _roll_done: load ret
|
|
37
35
|
; [1 2 3 4 5 8 5] => [8 1 2 3 4 5]
|
38
36
|
bury:
|
39
37
|
push -10 dup store ; current heap index kept at -10
|
40
|
-
swap
|
38
|
+
swap ^-9 ; preserve element to bury
|
41
39
|
_bury_keep: ; [n]
|
42
40
|
dup jz _bury_restore
|
43
41
|
push -10 :dec
|
44
|
-
swap
|
42
|
+
swap @-10 swap store
|
45
43
|
push 1 sub jump _bury_keep
|
46
44
|
_bury_restore:
|
47
45
|
push 9 sub load
|
48
|
-
|
46
|
+
@-10 :_roll_restore pop ret
|
49
47
|
|
50
48
|
|
51
49
|
; "digs" out the Ith element of the stack and discards it
|
@@ -63,14 +61,14 @@ dig: :roll pop ret
|
|
63
61
|
;
|
64
62
|
; [-1 9 8 7 -1] => [7 8 9 3]
|
65
63
|
; [0 'c' 'b' 'a' 0] => ['a' 'b' 'c' 3]
|
66
|
-
to_a:
|
64
|
+
to_a: ^-1 push -10 dup store
|
67
65
|
_to_a_loop:
|
68
|
-
dup
|
66
|
+
dup @-1 sub jz _to_a_sentinel
|
69
67
|
push -10 dup :dec load
|
70
68
|
swap store jump _to_a_loop
|
71
69
|
_to_a_sentinel: pop push -10
|
72
70
|
_to_a_restore:
|
73
|
-
dup
|
71
|
+
dup @-10 sub jz _to_a_done
|
74
72
|
push 1 sub dup load swap
|
75
73
|
jump _to_a_restore
|
76
74
|
_to_a_done: push -10 swap sub ret
|
@@ -88,7 +86,7 @@ _npop_done: pop ret
|
|
88
86
|
;
|
89
87
|
; [1 2 3 4 5 2] => [1 2 5]
|
90
88
|
; [1 2 3 4 1] => [1 2 4]
|
91
|
-
nslide: swap
|
89
|
+
nslide: swap ^-1 :npop @-1 ret
|
92
90
|
|
93
91
|
; copies the Nth element to the top of the stack; this does exactly what
|
94
92
|
; a `copy N` instruction would do, but we don't always know N in advance
|
@@ -224,13 +224,13 @@ _strchop_empty: ret
|
|
224
224
|
; ["foo,,bar" ','] => ["foo" "" "bar" 3]
|
225
225
|
; ["/foo/bar/" '/'] => ["" "foo" "bar" "" 4]
|
226
226
|
strsplit:
|
227
|
-
push -3
|
228
|
-
|
227
|
+
push -3,1 store ; number of found substrings
|
228
|
+
^-2 ; stash delimiter to allow some stack juggling
|
229
229
|
_strsplit_loop:
|
230
|
-
dup dup
|
230
|
+
dup dup @-2
|
231
231
|
:strindex dup jn _strsplit_done ; done when index of delimiter is -1
|
232
232
|
push 0 swap :strslice
|
233
|
-
swap copy 1
|
233
|
+
swap copy 1 @-3
|
234
234
|
swap :strlen
|
235
235
|
swap push -3 swap push 1 add store ; update number of found
|
236
236
|
push 1 add push 128 swap :pow div ; shrink haystack
|
@@ -248,11 +248,10 @@ lines: push 10 :strsplit ret
|
|
248
248
|
; ["foo" "bar" "baz" 3 '--'] => ["foo--bar--baz"]
|
249
249
|
; ["foo" 1 "?!"] => ["foo"]
|
250
250
|
strjoinc:
|
251
|
-
dup :strlen pop ; get delimiter length into -1
|
252
|
-
|
253
|
-
map (push -2 load :strcat) ; add delimiter to all elements
|
251
|
+
dup :strlen pop ^-2 ; get delimiter length into -1
|
252
|
+
map (@-2 :strcat) ; add delimiter to all elements
|
254
253
|
swap push 128 copy 1 :strlen
|
255
|
-
|
254
|
+
@-2 :strlen
|
256
255
|
sub :pow mod swap ; remove delimiter from last and flow into strjoin
|
257
256
|
|
258
257
|
; concatenates the pseudo-array of strings A into string S
|
@@ -289,9 +288,8 @@ _strcountc_done: swap slide 2 ret
|
|
289
288
|
; ["eunoia" "aeiou"] => [5]
|
290
289
|
; ["why" "aeiou"] => [0]
|
291
290
|
strcount:
|
292
|
-
swap push
|
293
|
-
|
294
|
-
map (push -2 load swap :strcountc)
|
291
|
+
swap ^-2 :strunpack push 0 :to_a
|
292
|
+
map (@-2 swap :strcountc)
|
295
293
|
reduce (add) ret
|
296
294
|
|
297
295
|
; translates all characters in A to the corresponding characters in B
|
@@ -303,16 +301,13 @@ strcount:
|
|
303
301
|
; ["abcd" "abc" "xyz"] => ["xyzd"]
|
304
302
|
; ["foobar" "oba" "ele"] => ["feeler"]
|
305
303
|
; ["abcdcba" "abcd" "xyz|"] => ["xyz|zyx"]
|
306
|
-
strtrans:
|
307
|
-
|
308
|
-
push -2 swap store
|
309
|
-
dup :strlen push -1 swap store
|
310
|
-
:strunpack push -1 load
|
304
|
+
strtrans: ^-3 ^-2
|
305
|
+
dup :strlen ^-1 :strunpack @-1
|
311
306
|
map (:_strtrans) pop :strpack ret
|
312
307
|
_strtrans:
|
313
|
-
dup
|
308
|
+
dup @-2 swap :strindex
|
314
309
|
dup jn _strtrans_no
|
315
|
-
|
310
|
+
@-3 swap :charat
|
316
311
|
slide 1 ret
|
317
312
|
_strtrans_no: pop ret
|
318
313
|
|
@@ -346,8 +341,8 @@ _strsqueeze_skip: pop jump _strsqueeze_loop
|
|
346
341
|
_strsqueeze_done: pop :strpack :strrev ret
|
347
342
|
|
348
343
|
$_strdel(cmp) {
|
349
|
-
:strunpack
|
350
|
-
select (
|
344
|
+
:strunpack @-1 :strlen
|
345
|
+
select (@-2 swap :strindex `cmp`)
|
351
346
|
pop :strpack ret
|
352
347
|
}
|
353
348
|
|
@@ -390,13 +385,17 @@ strrotl: push 128 swap copy 2 :strlen mod :pow :divmod :strcat ret
|
|
390
385
|
; ["abcd" 1] => ["dabc"]
|
391
386
|
; ["abcd" 5] => ["dabc"]
|
392
387
|
; ["foodbar" 3] => ["barfood"]
|
393
|
-
strrotr: push
|
388
|
+
strrotr: push -1 mul :strrotl ret
|
389
|
+
|
390
|
+
; gets the characters of the string S onto the stack as a pseudo-array, but
|
391
|
+
; with a leading 0 on the assumption that it'll eventually be repacked
|
392
|
+
;
|
393
|
+
; ["abc"] => [0 99 98 97 3]
|
394
|
+
strtoa: dup :strlen pop :strunpack @-1 $++ ret
|
394
395
|
|
395
396
|
; frobnicates the string S by XORing all its bytes with 42
|
396
397
|
; [S] => [S']
|
397
398
|
;
|
398
399
|
; ["foobar"] => ["LEEHKX"]
|
399
400
|
; ["LEEHKX"] => ["foobar"]
|
400
|
-
memfrob:
|
401
|
-
dup :strlen pop :strunpack push -1 load $++
|
402
|
-
map (push 42 :bxor) pop :strpack ret
|
401
|
+
memfrob: :strtoa map (push 42 :bxor) pop :strpack ret
|
@@ -26,7 +26,7 @@ _range_down:
|
|
26
26
|
|
27
27
|
$range_loop(fn, cmp) {
|
28
28
|
`fn`:
|
29
|
-
dup copy 2 add
|
29
|
+
dup copy 2 add @-1 `cmp` jz _`fn`_done
|
30
30
|
copy 1 copy 1 add swap jump `fn`
|
31
31
|
_`fn`_done: pop ret
|
32
32
|
}
|
@@ -50,8 +50,10 @@ steprange: swap push -1 copy 1 store copy 2 sub
|
|
50
50
|
$range_loop(_steprange_loop, :lte)
|
51
51
|
$range_loop(_steprange_down_loop, :gte)
|
52
52
|
|
53
|
-
; prints the string at the top of the stack and halts execution
|
54
|
-
|
53
|
+
; prints the string at the top of the stack and halts execution after pushing
|
54
|
+
; something onto the stack to signal abnormal termination/unclean exit
|
55
|
+
; [...] => [... 1]
|
56
|
+
die!: :println push 1 exit
|
55
57
|
|
56
58
|
; for stoi and itos
|
57
59
|
alpha: push "0123456789abcdefghijklmnopqrstuvwxyz" ret
|
@@ -72,7 +74,7 @@ alpha: push "0123456789abcdefghijklmnopqrstuvwxyz" ret
|
|
72
74
|
; ["-123" 10] => [-123]
|
73
75
|
; ["-ff" 16] => [-255]
|
74
76
|
stoi: swap dup :_stoi_sign swap copy 1 :eq
|
75
|
-
push 2 mul $--
|
77
|
+
push 2 mul $-- ^-2 push 0
|
76
78
|
_stoi_loop: ; [b s a]
|
77
79
|
swap dup jz _stoi_done
|
78
80
|
swap copy 2 copy 2
|
@@ -83,8 +85,8 @@ _stoi_loop: ; [b s a]
|
|
83
85
|
mul add swap push 128 div swap
|
84
86
|
jump _stoi_loop
|
85
87
|
_stoi_sign: dup push 0 :charat push '-' :eq copy 1 :strlen :strslice ret
|
86
|
-
_stoi_invalid: pop pop slide 1 swap div
|
87
|
-
_stoi_done: swap slide 2
|
88
|
+
_stoi_invalid: pop pop slide 1 swap div @-2 mul ret
|
89
|
+
_stoi_done: swap slide 2 @-2 mul ret
|
88
90
|
|
89
91
|
; creature comforts
|
90
92
|
|
@@ -111,7 +113,7 @@ _itos_loop:
|
|
111
113
|
swap :strcat
|
112
114
|
swap copy 2 div
|
113
115
|
swap jump _itos_loop
|
114
|
-
_itos_done: swap slide 2 push 45
|
116
|
+
_itos_done: swap slide 2 push 45 @-2 mul swap :strcat ret
|
115
117
|
|
116
118
|
; creature comforts
|
117
119
|
|
@@ -129,12 +131,10 @@ to_hex: push 16 :itos ret
|
|
129
131
|
; [256 16] => [1 0 0 3]
|
130
132
|
digits:
|
131
133
|
copy 1 jz _digits_zero ; special case
|
132
|
-
push -1 swap
|
133
|
-
push -1 swap ; sentinel value
|
134
|
+
^-1 push -1 swap ; sentinel value
|
134
135
|
_digits_loop:
|
135
136
|
dup jz _digits_done
|
136
|
-
|
137
|
-
swap jump _digits_loop
|
137
|
+
@-1 :divmod swap jump _digits_loop
|
138
138
|
_digits_zero: dup div ret
|
139
139
|
_digits_done: push 1 sub :to_a ret
|
140
140
|
|
@@ -118,9 +118,9 @@ module Spitewaste
|
|
118
118
|
# quick push (`push 1,2,3` desugars to individual pushes)
|
119
119
|
@src.gsub!(/push \S+/) { |m| m.split(?,) * ' push ' }
|
120
120
|
# quick store (`^2` = `push 2 swap store`)
|
121
|
-
@src.gsub!(/\^(
|
121
|
+
@src.gsub!(/\^(\S+)/, 'push \1 swap store')
|
122
122
|
# quick load (`@2` = `push 2 load`)
|
123
|
-
@src.gsub!(/@(
|
123
|
+
@src.gsub!(/@(\S+)/, 'push \1 load')
|
124
124
|
end
|
125
125
|
|
126
126
|
def gensym
|
@@ -141,10 +141,10 @@ module Spitewaste
|
|
141
141
|
parse = -> s { s.split(?,).map &:strip }
|
142
142
|
|
143
143
|
# Macro "functions" get handled first.
|
144
|
-
@src.gsub!(/(\$\S+?)\(([^)]
|
144
|
+
@src.gsub!(/(\$\S+?)\(([^)]*)\)\s*{(.+?)}/m) {
|
145
145
|
@macros[$1] ||= [$2, $3]; ''
|
146
146
|
}
|
147
|
-
@src.gsub!(/(\$\S+?)\(([^)]
|
147
|
+
@src.gsub!(/(\$\S+?)\(([^)]*)\)/) {
|
148
148
|
params, body = @macros[$1]
|
149
149
|
raise "no macro function '#$1'" unless body
|
150
150
|
map = parse[params].zip(parse[$2]).to_h
|
data/lib/spitewaste/version.rb
CHANGED