spitewaste 0.2.0 → 0.2.01

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 8cd3201a4c8647de4fb29c8529c45fb379c2633cd660a4155e28720931202f94
4
- data.tar.gz: 3ba703110341a406d476aa8afa8d89c8a57b9d6e136f319956f28f7d311b16e7
3
+ metadata.gz: 9ce4494399350d9afb01a0c84aef1ce504da4a24349b33a45de83d6b6f4fa10b
4
+ data.tar.gz: 330b14a9eb241ff0ac8986956c8f790dd88ce87db4823e08ff19edfc7db0aee1
5
5
  SHA512:
6
- metadata.gz: d103c80be7025cca6d784127444702460394e4d0f137f124581212b6d92523b80c7e95e15642f9c0036b26545e821dcee206686818d0728dbe57c7b57a388ef0
7
- data.tar.gz: 39f473d86a4df1a125a6edae3ff1e29c5a069da2aa72862834097b7151bd11c4fdfe93f8119b60c7009468e4f5c2a05ef60a92d99a9b9198485f79c42411f33d
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
- next if path['random']
19
- lib = File.basename path, '.spw'
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 (push -2 load $-- :ncopy) ret
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) $++ push -1 swap store
103
- $-- times (push -1 load mul add)
104
- push $amax mul push -1 load add
105
- push $amax mul push -10 load add ret
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 push -2 swap store
109
- push $amax :divmod push -1 swap store
110
- push -2 load times (push -1 load :divmod swap)
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) push -1 swap store
165
- reduce (:min) push -1 load ret
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 push -1 load :aryindex
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: push -3 load $-- times (:arycat) ret
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
- push -1 load swap push -2 load dup push 2 mul
16
- push -2 swap store mul add store
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 push -2 load mul push -1 load 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 push -2 load mul push -1 load 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": "prints the string at the top of the stack and halts execution",
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
- dup push 2 mod
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
- push -2 load swap :strcat push -2 swap store
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: push -1 load slide 2 ret
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 push -1 swap store ; preserve N because array operations
138
+ dup ^-1 ; preserve N because array operations
142
139
  :isqrt push 1 swap :range dup ; 1..isqrt(N)
143
- reject (push -1 load swap mod) :arydup ; get first half of divisors
144
- map (push -1 load swap div) :arycat ; map first half to second half
145
- push -1 load copy 2 dup mul sub jz _divisors_square ret
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 ; pow
1
+ import math ; pow
2
+ import string ; strtoa
2
3
 
3
- srand: push $seed swap store ret
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 3,13,10244807 mul mul mul
8
- push 2,32 :pow mod
12
+ push 48271 mul
13
+ push 2,31 :pow $-- mod
9
14
  store load ret
10
15
 
11
- rand_range: ; [a b]
12
- copy 1 sub :rand swap mod add ret
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
- dice:
15
- push -2 swap store push 1 :aryfill
16
- map (push -2 load :rand_range) ret
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: push -2 swap store :from_r :divmod push 0 swap
190
+ to_f: ^-2 :from_r :divmod push 0 swap
191
191
  _to_f_loop:
192
- push -1 load :divmod swap
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: ; [n]
19
+ _roll_keep:
20
20
  dup jz _roll_remove
21
21
  push -10 :dec
22
- swap push -10 load swap store
22
+ swap @-10 swap store
23
23
  push 1 sub jump _roll_keep
24
- _roll_remove:
25
- push 10 sub load
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 push -9 swap store ; preserve element to bury
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 push -10 load swap store
42
+ swap @-10 swap store
45
43
  push 1 sub jump _bury_keep
46
44
  _bury_restore:
47
45
  push 9 sub load
48
- push -10 load :_roll_restore pop ret
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: push -1 swap store push -10 dup store
64
+ to_a: ^-1 push -10 dup store
67
65
  _to_a_loop:
68
- dup push -1 load sub jz _to_a_sentinel
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 push -10 load sub jz _to_a_done
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 push -1 swap store :npop push -1 load ret
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 push 1 store ; number of found substrings
228
- push -2 swap store ; stash delimiter to allow some stack juggling
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 push -2 load
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 push -3 load
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
- push -2 swap store
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
- push -2 load :strlen
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 -2 swap store
293
- :strunpack push 0 :to_a
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
- push -3 swap store
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 push -2 load swap :strindex
308
+ dup @-2 swap :strindex
314
309
  dup jn _strtrans_no
315
- push -3 load swap :charat
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 push -1 load :strlen
350
- select (push -2 load swap :strindex `cmp`)
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 0 swap sub :strrotl ret
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
@@ -8,3 +8,6 @@ assert_eq:
8
8
  push ", got " :print onum
9
9
  push " for test " swap :strcat :die!
10
10
  _assert_eq_yes: pop pop pop ret
11
+
12
+ assert_nz: jz _assert_nz_no pop ret
13
+ _assert_nz_no: push "expected nonzero for test " swap :strcat :die!
@@ -26,7 +26,7 @@ _range_down:
26
26
 
27
27
  $range_loop(fn, cmp) {
28
28
  `fn`:
29
- dup copy 2 add push -1 load `cmp` jz _`fn`_done
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
- die!: :println exit
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 $-- push -2 swap store push 0
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 push -2 load mul ret
87
- _stoi_done: swap slide 2 push -2 load mul ret
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,-2 load mul swap :strcat ret
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 store
133
- push -1 swap ; sentinel value
134
+ ^-1 push -1 swap ; sentinel value
134
135
  _digits_loop:
135
136
  dup jz _digits_done
136
- push -1 load :divmod
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!(/\^(-?\d+)/, 'push \1 swap store')
121
+ @src.gsub!(/\^(\S+)/, 'push \1 swap store')
122
122
  # quick load (`@2` = `push 2 load`)
123
- @src.gsub!(/@(-?\d+)/, 'push \1 load')
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+?)\(([^)]+)\)\s*{(.+?)}/m) {
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
@@ -1,3 +1,3 @@
1
1
  module Spitewaste
2
- VERSION = '0.2.0'
2
+ VERSION = '0.2.01'
3
3
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: spitewaste
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.2.0
4
+ version: 0.2.01
5
5
  platform: ruby
6
6
  authors:
7
7
  - Collided Scope (collidedscope)