spitewaste 0.1.010 → 0.2.2
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/Rakefile +7 -6
- data/lib/spitewaste.rb +4 -0
- data/lib/spitewaste/assembler.rb +1 -1
- data/lib/spitewaste/emitters/image.rb +1 -1
- data/lib/spitewaste/libspw/array.spw +118 -19
- data/lib/spitewaste/libspw/bits.spw +9 -5
- data/lib/spitewaste/libspw/docs.json +6279 -1
- data/lib/spitewaste/libspw/fun.spw +56 -4
- data/lib/spitewaste/libspw/io.spw +13 -11
- data/lib/spitewaste/libspw/math.spw +7 -11
- data/lib/spitewaste/libspw/random.spw +33 -6
- data/lib/spitewaste/libspw/rational.spw +30 -1
- data/lib/spitewaste/libspw/stack.spw +22 -13
- data/lib/spitewaste/libspw/string.spw +79 -26
- data/lib/spitewaste/libspw/terminal.spw +14 -0
- data/lib/spitewaste/libspw/test.spw +3 -0
- data/lib/spitewaste/libspw/util.spw +97 -21
- data/lib/spitewaste/parsers/fucktional.rb +7 -3
- data/lib/spitewaste/parsers/spitewaste.rb +21 -9
- data/lib/spitewaste/version.rb +1 -1
- metadata +3 -2
@@ -0,0 +1,14 @@
|
|
1
|
+
;;; Miscellaneous terminal-based functionality
|
2
|
+
|
3
|
+
import util ; hex2rgb
|
4
|
+
|
5
|
+
$_setg(code) {
|
6
|
+
push 91,27 ochr ochr
|
7
|
+
push `code` onum push 50,59 ochr ochr
|
8
|
+
:hex2rgb each (push 59 ochr onum)
|
9
|
+
push 109 ochr ret
|
10
|
+
}
|
11
|
+
|
12
|
+
setfg: $_setg(38)
|
13
|
+
setbg: $_setg(48)
|
14
|
+
reset: push 109,91,27 ochr ochr ochr ret
|
@@ -15,22 +15,24 @@ import string ; charat, strcat, strindex, strlen
|
|
15
15
|
; [0 -2] => [0 -1 -2]
|
16
16
|
; [-3 3] => [-3 -2 -1 0 1 2 3]
|
17
17
|
; [3 -3] => [3 2 1 0 -1 -2 -3]
|
18
|
-
; [4 4] => [4
|
19
|
-
range: dup copy 2 sub jn _range_down
|
18
|
+
; [4 4] => [4]
|
19
|
+
range: dup copy 2 sub jz _range_one dup copy 2 sub jn _range_down
|
20
20
|
copy 1 push 1 add swap
|
21
21
|
copy 1 copy 1 sub jn range pop ret
|
22
|
+
_range_one: pop ret
|
22
23
|
_range_down:
|
23
24
|
copy 1 push 1 sub swap
|
24
25
|
dup copy 2 sub jn _range_down pop ret
|
25
26
|
|
26
27
|
$range_loop(fn, cmp) {
|
27
28
|
`fn`:
|
28
|
-
copy
|
29
|
-
copy
|
29
|
+
dup copy 2 add @-1 `cmp` jz _`fn`_done
|
30
|
+
copy 1 copy 1 add swap jump `fn`
|
31
|
+
_`fn`_done: pop ret
|
30
32
|
}
|
31
33
|
|
32
|
-
; inserts between
|
33
|
-
;
|
34
|
+
; inserts between I and J the intervening consecutive elements, counting by
|
35
|
+
; step S up/down to (but never beyond) J
|
34
36
|
; [I J S] => [I I±S ... ~J]
|
35
37
|
;
|
36
38
|
; [1 4 1] => [1 2 3 4]
|
@@ -41,13 +43,17 @@ $range_loop(fn, cmp) {
|
|
41
43
|
; [25 -5 -10] => [25 15 5 -5]
|
42
44
|
; [4 20 3] => [4 7 10 13 16 19]
|
43
45
|
; [20 4 -3] => [20 17 14 11 8 5]
|
46
|
+
; [3 9 7] => [3]
|
47
|
+
; [9 3 -7] => [9]
|
44
48
|
steprange: swap push -1 copy 1 store copy 2 sub
|
45
49
|
jn _steprange_down_loop jump _steprange_loop ; prevent DCE
|
46
|
-
$range_loop(_steprange_loop, :
|
47
|
-
$range_loop(_steprange_down_loop, :
|
50
|
+
$range_loop(_steprange_loop, :lte)
|
51
|
+
$range_loop(_steprange_down_loop, :gte)
|
48
52
|
|
49
|
-
; prints the string at the top of the stack and halts execution
|
50
|
-
|
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
|
51
57
|
|
52
58
|
; for stoi and itos
|
53
59
|
alpha: push "0123456789abcdefghijklmnopqrstuvwxyz" ret
|
@@ -68,7 +74,7 @@ alpha: push "0123456789abcdefghijklmnopqrstuvwxyz" ret
|
|
68
74
|
; ["-123" 10] => [-123]
|
69
75
|
; ["-ff" 16] => [-255]
|
70
76
|
stoi: swap dup :_stoi_sign swap copy 1 :eq
|
71
|
-
push 2 mul $--
|
77
|
+
push 2 mul $-- ^-2 push 0
|
72
78
|
_stoi_loop: ; [b s a]
|
73
79
|
swap dup jz _stoi_done
|
74
80
|
swap copy 2 copy 2
|
@@ -79,10 +85,11 @@ _stoi_loop: ; [b s a]
|
|
79
85
|
mul add swap push 128 div swap
|
80
86
|
jump _stoi_loop
|
81
87
|
_stoi_sign: dup push 0 :charat push '-' :eq copy 1 :strlen :strslice ret
|
82
|
-
_stoi_invalid: pop pop slide 1 swap div
|
83
|
-
_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
|
84
90
|
|
85
91
|
; creature comforts
|
92
|
+
|
86
93
|
bin: push 2 :stoi ret
|
87
94
|
oct: push 8 :stoi ret
|
88
95
|
to_i: push 10 :stoi ret
|
@@ -92,11 +99,13 @@ hex: push 16 :stoi ret
|
|
92
99
|
; [N B]
|
93
100
|
;
|
94
101
|
; [42 2] => ["101010"]
|
102
|
+
; [-42 2] => ["-101010"]
|
95
103
|
; [511 8] => ["777"]
|
96
104
|
; [12345 10] => ["12345"]
|
105
|
+
; [-54321 10] => ["-54321"]
|
97
106
|
; [57005 16] => ["dead"]
|
98
107
|
; [81699 17] => ["gabe"]
|
99
|
-
itos: swap push
|
108
|
+
itos: swap push -2 copy 1 :neg? store :abs push 0
|
100
109
|
_itos_loop:
|
101
110
|
swap dup jz _itos_done
|
102
111
|
swap copy 1 copy 3 mod
|
@@ -104,9 +113,10 @@ _itos_loop:
|
|
104
113
|
swap :strcat
|
105
114
|
swap copy 2 div
|
106
115
|
swap jump _itos_loop
|
107
|
-
_itos_done: swap slide 2 ret
|
116
|
+
_itos_done: swap slide 2 push 45 @-2 mul swap :strcat ret
|
108
117
|
|
109
118
|
; creature comforts
|
119
|
+
|
110
120
|
to_bin: push 2 :itos ret
|
111
121
|
to_oct: push 8 :itos ret
|
112
122
|
to_s: push 10 :itos ret
|
@@ -121,12 +131,10 @@ to_hex: push 16 :itos ret
|
|
121
131
|
; [256 16] => [1 0 0 3]
|
122
132
|
digits:
|
123
133
|
copy 1 jz _digits_zero ; special case
|
124
|
-
push -1 swap
|
125
|
-
push -1 swap ; sentinel value
|
134
|
+
^-1 push -1 swap ; sentinel value
|
126
135
|
_digits_loop:
|
127
136
|
dup jz _digits_done
|
128
|
-
|
129
|
-
swap jump _digits_loop
|
137
|
+
@-1 :divmod swap jump _digits_loop
|
130
138
|
_digits_zero: dup div ret
|
131
139
|
_digits_done: push 1 sub :to_a ret
|
132
140
|
|
@@ -190,11 +198,79 @@ lte: swap ; intentionally flow into gte
|
|
190
198
|
gte: sub jn _gte_no push 1 ret
|
191
199
|
_gte_no: push 0 ret
|
192
200
|
|
201
|
+
; returns 1 if the number N is between A and B (inclusive), 0 otherwise
|
202
|
+
; ! A must be <= B for sensible results TODO: bug?
|
203
|
+
; [N A B]
|
204
|
+
;
|
205
|
+
; [5 0 10] => [1]
|
206
|
+
; [11 0 10] => [0]
|
207
|
+
; [4 0 4] => [1]
|
208
|
+
; [-1 0 4] => [0]
|
209
|
+
; [-5 -10 0] => [1]
|
210
|
+
; [3 4 2] => [0]
|
211
|
+
between?: copy 2 :gte swap copy 2 :lte mul slide 1 ret
|
212
|
+
|
193
213
|
; Though extremely rare, it's possible that we know a particular value is
|
194
214
|
; stored in the heap at some key, just not which one. This subroutine takes
|
195
215
|
; a value V to search for and a starting index I, and either returns the first
|
196
216
|
; key associated with that value or loops forever. Probably don't touch.
|
197
217
|
; [V I]
|
198
|
-
|
199
|
-
$++ dup load copy 2 :eq jz
|
218
|
+
heap-seeking_missile:
|
219
|
+
$++ dup load copy 2 :eq jz heap-seeking_missile
|
200
220
|
slide 1 ret
|
221
|
+
|
222
|
+
; converts the #RRGGBB (leading '#' optional) color string S to
|
223
|
+
; its individual RGB components as integers in the range 0-255
|
224
|
+
; [S] => [R G B]
|
225
|
+
;
|
226
|
+
; ["#000000"] => [0 0 0]
|
227
|
+
; ["ffffff"] => [255 255 255]
|
228
|
+
; ["#102030"] => [16 32 48]
|
229
|
+
; ["c0ffee"] => [192 255 238]
|
230
|
+
hex2rgb:
|
231
|
+
dup push 0 :charat push '#' :eq push 127 mul $++ div
|
232
|
+
push 128,2 :pow :divmod :hex swap
|
233
|
+
push 128,2 :pow :divmod :hex swap :hex ret
|
234
|
+
|
235
|
+
; converts R, G, and B components to length-6 hexadecimal string S
|
236
|
+
; ! dies if any of the values to convert aren't between 0 and 255
|
237
|
+
; [R G B] => [S]
|
238
|
+
;
|
239
|
+
; [0 0 0] => ["000000"]
|
240
|
+
; [255 255 255] => ["ffffff"]
|
241
|
+
; [16 32 48] => ["102030"]
|
242
|
+
; [192 255 238] => ["c0ffee"]
|
243
|
+
rgb2hex:
|
244
|
+
push 3 :arydup all (push 0,255 :between?) jz _rgb2hex_invalid
|
245
|
+
pop copy 2 push 256,2 :pow mul
|
246
|
+
copy 2 push 256 mul add add
|
247
|
+
slide 2 :to_hex push 6,48 :rjustc ret
|
248
|
+
_rgb2hex_invalid: push "(rgb2hex) invalid RGB" :die!
|
249
|
+
|
250
|
+
; stashes the array A in negative heap space starting at index I
|
251
|
+
; [A I] => []
|
252
|
+
aryheap:
|
253
|
+
$++ dup copy 2 store
|
254
|
+
swap times ($-- swap copy 1 swap store) pop ret
|
255
|
+
|
256
|
+
; restores the heaped array starting at index I
|
257
|
+
; [I] => [A]
|
258
|
+
heapary:
|
259
|
+
$++ dup load swap copy 1 sub swap
|
260
|
+
times (dup load swap $++) load ret
|
261
|
+
|
262
|
+
; swaps the elements in the heap at indices I and J
|
263
|
+
; ! TODO: make heap effects doctest-able
|
264
|
+
; [I J] => []
|
265
|
+
heapswap: dup load swap copy 2 load store store ret
|
266
|
+
|
267
|
+
; returns the number of nanoseconds N since the Unix epoch
|
268
|
+
; [] => [N]
|
269
|
+
time: push "date +%s%N" shell :to_i ret
|
270
|
+
|
271
|
+
$bench(insns) {
|
272
|
+
#insns :println
|
273
|
+
:time ^0 `insns` :time @0 sub
|
274
|
+
push 10,9 :pow :divmod swap onum
|
275
|
+
push '.' ochr :to_s push 9,48 :rjustc :println
|
276
|
+
}
|
@@ -64,9 +64,13 @@ maxby_lesser_%1$s: swap jump maxby_resume_%1$s
|
|
64
64
|
maxby_done_%1$s:
|
65
65
|
SPW
|
66
66
|
|
67
|
-
'minby'
|
68
|
-
'each'
|
69
|
-
'
|
67
|
+
'minby' => 'maxby (%2$s push -1 mul)',
|
68
|
+
'each' => 'dup times (dup call roll %2$s push 1 sub) pop',
|
69
|
+
'all' => 'map (%2$s) reduce (add) push -11 load call eq',
|
70
|
+
# TODO: optimize any to stop early if possible
|
71
|
+
'any' => 'map (%2$s) reduce (add) push 0 call gt',
|
72
|
+
'none' => 'map (%2$s) reduce (add) push 0 call eq',
|
73
|
+
'count' => 'select (%2$s) dup call nslide',
|
70
74
|
'select' => generate_filter_spw('select', 0, 1),
|
71
75
|
'reject' => generate_filter_spw('reject', 1, 0),
|
72
76
|
}
|
@@ -57,14 +57,14 @@ module Spitewaste
|
|
57
57
|
private
|
58
58
|
|
59
59
|
def preprocess!
|
60
|
-
@src
|
60
|
+
@src << "\nimport syntax"
|
61
61
|
resolve_imports
|
62
62
|
seed_prng if @seen.include? 'random'
|
63
63
|
resolve_strings
|
64
|
-
remove_comments
|
65
64
|
add_sugar
|
66
|
-
|
65
|
+
remove_comments
|
67
66
|
propagate_macros
|
67
|
+
fucktionalize
|
68
68
|
end
|
69
69
|
|
70
70
|
def resolve_imports
|
@@ -78,7 +78,13 @@ module Spitewaste
|
|
78
78
|
while @src['import']
|
79
79
|
imports = []
|
80
80
|
@src.gsub!(/import\s+(\S+).*/) {
|
81
|
-
|
81
|
+
if $1 == ?*
|
82
|
+
imports = Dir[LIBSPW + '/*.spw'].map {
|
83
|
+
File.read(_1) if @seen.add? File.basename(_1, '.spw')
|
84
|
+
}
|
85
|
+
else
|
86
|
+
imports << resolve($1) if @seen.add? $1
|
87
|
+
end
|
82
88
|
'' # remove import statement
|
83
89
|
}
|
84
90
|
@src << imports.join(?\n)
|
@@ -91,7 +97,7 @@ module Spitewaste
|
|
91
97
|
end
|
92
98
|
|
93
99
|
def seed_prng
|
94
|
-
@src.prepend "push $seed,#{rand 2**31} store $seed = -9001"
|
100
|
+
@src.prepend "push $seed,#{rand 2**31} store $seed = -9001\n"
|
95
101
|
end
|
96
102
|
|
97
103
|
def resolve_strings
|
@@ -111,6 +117,10 @@ module Spitewaste
|
|
111
117
|
@src.gsub!(/'(.)'/) { $1.ord }
|
112
118
|
# quick push (`push 1,2,3` desugars to individual pushes)
|
113
119
|
@src.gsub!(/push \S+/) { |m| m.split(?,) * ' push ' }
|
120
|
+
# quick store (`^2` = `push 2 swap store`)
|
121
|
+
@src.gsub!(/\^(\S+)/, 'push \1 swap store')
|
122
|
+
# quick load (`@2` = `push 2 load`)
|
123
|
+
@src.gsub!(/@(\S+)/, 'push \1 load')
|
114
124
|
end
|
115
125
|
|
116
126
|
def gensym
|
@@ -131,18 +141,20 @@ module Spitewaste
|
|
131
141
|
parse = -> s { s.split(?,).map &:strip }
|
132
142
|
|
133
143
|
# Macro "functions" get handled first.
|
134
|
-
@src.gsub!(/(\$\S+?)\(([^)]
|
144
|
+
@src.gsub!(/(\$\S+?)\(([^)]*)\)\s*{(.+?)}/m) {
|
135
145
|
@macros[$1] ||= [$2, $3]; ''
|
136
146
|
}
|
137
|
-
@src.gsub!(/(\$\S+?)\(([^)]
|
147
|
+
@src.gsub!(/(\$\S+?)\(([^)]*)\)/) {
|
138
148
|
params, body = @macros[$1]
|
139
149
|
raise "no macro function '#$1'" unless body
|
140
150
|
map = parse[params].zip(parse[$2]).to_h
|
141
|
-
body
|
151
|
+
body
|
152
|
+
.gsub(/`(.+?)`/) { map[$1] }
|
153
|
+
.gsub(/#(\S+)/) { "push #{Spitewaste.strpack map[$1]}" }
|
142
154
|
}
|
143
155
|
|
144
156
|
@src.gsub!(/(\$\S+)\s*=\s*(.+)/) { @macros[$1] ||= $2; '' }
|
145
|
-
@src.gsub!(/(
|
157
|
+
@src.gsub!(/(\$[^)\s]+)/) { @macros[$1] || raise("no macro '#$1'") }
|
146
158
|
end
|
147
159
|
|
148
160
|
def eliminate_dead_code!
|
data/lib/spitewaste/version.rb
CHANGED
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: spitewaste
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.2.2
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Collided Scope (collidedscope)
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date:
|
11
|
+
date: 2021-01-08 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: rake
|
@@ -110,6 +110,7 @@ files:
|
|
110
110
|
- lib/spitewaste/libspw/stack.spw
|
111
111
|
- lib/spitewaste/libspw/string.spw
|
112
112
|
- lib/spitewaste/libspw/syntax.spw
|
113
|
+
- lib/spitewaste/libspw/terminal.spw
|
113
114
|
- lib/spitewaste/libspw/test.spw
|
114
115
|
- lib/spitewaste/libspw/util.spw
|
115
116
|
- lib/spitewaste/parsers/assembly.rb
|