spitewaste 0.1.001

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 (46) hide show
  1. checksums.yaml +7 -0
  2. data/Gemfile +8 -0
  3. data/README.md +55 -0
  4. data/Rakefile +10 -0
  5. data/TUTORIAL.md +125 -0
  6. data/bin/spw +10 -0
  7. data/demo/factorial-nicespace.png +0 -0
  8. data/demo/factorial.asm +47 -0
  9. data/demo/factorial.png +0 -0
  10. data/demo/factorial.wsa +5 -0
  11. data/lib/spitewaste.rb +35 -0
  12. data/lib/spitewaste/assembler.rb +56 -0
  13. data/lib/spitewaste/cli.rb +51 -0
  14. data/lib/spitewaste/cli/asm.rb +10 -0
  15. data/lib/spitewaste/cli/compile.rb +60 -0
  16. data/lib/spitewaste/cli/convert.rb +53 -0
  17. data/lib/spitewaste/cli/exec.rb +43 -0
  18. data/lib/spitewaste/cli/image.rb +53 -0
  19. data/lib/spitewaste/emitter.rb +10 -0
  20. data/lib/spitewaste/emitters/assembly.rb +7 -0
  21. data/lib/spitewaste/emitters/codegen.rb +72 -0
  22. data/lib/spitewaste/emitters/image.rb +135 -0
  23. data/lib/spitewaste/emitters/linefeed.png +0 -0
  24. data/lib/spitewaste/emitters/schemes.yaml +1143 -0
  25. data/lib/spitewaste/emitters/whitespace.rb +14 -0
  26. data/lib/spitewaste/emitters/wsassembly.rb +7 -0
  27. data/lib/spitewaste/libspw/array.spw +82 -0
  28. data/lib/spitewaste/libspw/bits.spw +72 -0
  29. data/lib/spitewaste/libspw/case.spw +32 -0
  30. data/lib/spitewaste/libspw/fun.spw +42 -0
  31. data/lib/spitewaste/libspw/io.spw +39 -0
  32. data/lib/spitewaste/libspw/math.spw +117 -0
  33. data/lib/spitewaste/libspw/prime.spw +46 -0
  34. data/lib/spitewaste/libspw/random.spw +10 -0
  35. data/lib/spitewaste/libspw/stack.spw +84 -0
  36. data/lib/spitewaste/libspw/string.spw +233 -0
  37. data/lib/spitewaste/libspw/syntax.spw +2 -0
  38. data/lib/spitewaste/libspw/test.spw +8 -0
  39. data/lib/spitewaste/libspw/util.spw +98 -0
  40. data/lib/spitewaste/parsers/assembly.rb +35 -0
  41. data/lib/spitewaste/parsers/fucktional.rb +72 -0
  42. data/lib/spitewaste/parsers/spitewaste.rb +192 -0
  43. data/lib/spitewaste/parsers/whitespace.rb +60 -0
  44. data/lib/spitewaste/version.rb +3 -0
  45. data/spitewaste.gemspec +17 -0
  46. metadata +88 -0
@@ -0,0 +1,10 @@
1
+ srand: push $seed swap store ret
2
+
3
+ rand:
4
+ push $seed dup dup load
5
+ push 3,13,10244807 mul mul mul
6
+ push 2,32 :pow mod
7
+ store load ret
8
+
9
+ rand_range: ; [a b]
10
+ copy 1 sub :rand swap mod add ret
@@ -0,0 +1,84 @@
1
+ roll:
2
+ push -10 dup store ; current heap index kept at -10
3
+
4
+ _roll_keep: ; [n]
5
+ dup jz _roll_remove
6
+ push -10 :dec
7
+ swap push -10 load swap store
8
+ push 1 sub jump _roll_keep
9
+
10
+ _roll_remove:
11
+ push 10 sub load
12
+ swap push -10 swap store
13
+
14
+ _roll_restore: ; i
15
+ dup load swap push 1 add
16
+ dup push 10 add jz _roll_done
17
+ jump _roll_restore
18
+
19
+ _roll_done: load ret
20
+
21
+ ;;;
22
+
23
+ bury:
24
+ push -10 dup store ; current heap index kept at -10
25
+ swap push -9 swap store ; preserve element to bury
26
+
27
+ _bury_keep: ; [n]
28
+ dup jz _bury_restore
29
+ push -10 :dec
30
+ swap push -10 load swap store
31
+ push 1 sub jump _bury_keep
32
+
33
+ _bury_restore:
34
+ push 9 sub load
35
+ push -10 load :_roll_restore pop ret
36
+
37
+ ;;;
38
+
39
+ dig: :roll pop ret
40
+
41
+ ;;;
42
+
43
+ to_a:
44
+ push -1 swap store
45
+ push -10 dup store
46
+
47
+ _to_a_loop:
48
+ dup push -1 load sub jz _to_a_sentinel
49
+ push -10 dup :dec load
50
+ swap store jump _to_a_loop
51
+
52
+ _to_a_sentinel: pop push -10
53
+
54
+ _to_a_restore:
55
+ dup push -10 load sub jz _to_a_done
56
+ push 1 sub dup load swap
57
+ jump _to_a_restore
58
+
59
+ _to_a_done: push -10 swap sub ret
60
+
61
+ ;;;
62
+
63
+ ; dynamic pop ; [n]
64
+ npop:
65
+ dup jz _npop_done
66
+ swap pop push 1 sub jump npop
67
+
68
+ _npop_done: pop ret
69
+
70
+ ; dynamic slide ; [n]
71
+ nslide:
72
+ swap push -1 swap store
73
+ :npop push -1 load ret
74
+
75
+ ncopy: push -10 dup store
76
+ _ncopy_loop:
77
+ dup jz _ncopy_save swap
78
+ push -10 dup :dec load swap store
79
+ push 1 sub jump _ncopy_loop
80
+ _ncopy_save: push 10 sub dup load swap copy 2 store
81
+ _ncopy_restore:
82
+ dup push 9 add jz _ncopy_done
83
+ dup load swap push 1 add jump _ncopy_restore
84
+ _ncopy_done: pop ret
@@ -0,0 +1,233 @@
1
+ import math
2
+ import case
3
+
4
+ ;;; String packing and unpacking
5
+
6
+ ; convert a 0-terminated string on the stack to a single base-128 integer
7
+ strpack: push 0 ; tally
8
+ _strpack_loop:
9
+ swap dup jz _strpack_done
10
+ copy 1 push 128 mul add
11
+ slide 1
12
+ jump _strpack_loop
13
+
14
+ _strpack_done: pop :strrev ret
15
+
16
+ ; convert a single base-128 integer to a 0-terminated string on the stack
17
+ strunpack:
18
+ :strrev push 0 swap ; terminator
19
+
20
+ _strunpack_loop:
21
+ dup jz _strunpack_done
22
+ dup push 128 mod swap push 128 div
23
+ jump _strunpack_loop
24
+
25
+ _strunpack_done: pop ret
26
+
27
+ ;;;
28
+
29
+ ; takes a packed string and just returns it log128 to give the length
30
+ strlen: push 128 :ilog ret
31
+
32
+ ;;;
33
+
34
+ ; takes two packed strings and returns their concatenation (as a packed string)
35
+ strcat:
36
+ push 128 copy 2 :strlen :pow
37
+ mul add ret
38
+
39
+ ;;;
40
+
41
+ ; reverses a packed string in-place (heapless) [s] => [s.reverse]
42
+ strrev: push 0 swap ; [tally string]
43
+
44
+ _strrev_loop: ; [t s]
45
+ dup jz _strrev_done
46
+ swap push 128 mul ; [s t]
47
+ copy 1 push 128 mod add
48
+ swap push 128 div
49
+ jump _strrev_loop
50
+
51
+ _strrev_done: pop ret
52
+
53
+ ;;;
54
+
55
+ ; takes a packed string, a start index, and a length and returns the
56
+ ; corresponding substring (simply by doing division with powers of 128; neat)
57
+ strslice:
58
+ swap push 128 swap :pow
59
+ copy 2 swap div
60
+ swap push 128 swap :pow
61
+ mod slide 1 ret
62
+
63
+ ;;;
64
+
65
+ ; index of substring t in string s ; [s t]
66
+ strindex: swap push 0
67
+
68
+ _strindex_loop: ; [t s i]
69
+ copy 1 copy 3 :strlen push 0 swap :strslice
70
+ copy 3 sub jz _strindex_found
71
+ push 1 add ; increment index
72
+ swap push 128 div dup jz _strindex_no
73
+ swap jump _strindex_loop
74
+
75
+ _strindex_no: push -1 slide 3 ret
76
+
77
+ _strindex_found: slide 2 ret
78
+
79
+ ;;;
80
+
81
+ charat: push 1 :strslice ret
82
+
83
+ ;;;
84
+
85
+ ; 1 if the character at the top of the stack is alphabetical, 0 otherwise
86
+ isalpha:
87
+ dup push 123 :lt jz _isalpha_no
88
+ dup push 64 :gt jz _isalpha_no
89
+ push 32 mod $-- push 32 mod push 26 :lt ret
90
+ _isalpha_no: dup sub ret
91
+
92
+ ;;;
93
+
94
+ ; repeat a string s n times [s n]
95
+ strrep: push 0 swap
96
+ _strrep_loop: ; [s t n]
97
+ dup jz _strrep_done
98
+ swap copy 2 :strcat
99
+ swap push 1 sub
100
+ jump _strrep_loop
101
+
102
+ _strrep_done: swap slide 2 ret
103
+
104
+ ;;; String alignment
105
+
106
+ ; helper function for ljustc and rjustc, since the only difference is whether
107
+ ; we swap before calling strcat.
108
+ _justc: swap copy 2 :strlen sub push 0 :max :strrep ret
109
+
110
+ ; Left-justify string s to width w with character c. [s w c]
111
+ ljustc: :_justc :strcat ret
112
+
113
+ ; Left-justify string s to width w with spaces. [s w]
114
+ ljust: push ' ' :ljustc ret
115
+
116
+ ; Right-justify string s to width w with character c. [s w c]
117
+ rjustc: :_justc swap :strcat ret
118
+
119
+ ; Right-justify string s to width w with spaces. [s w]
120
+ rjust: push ' ' :rjustc ret
121
+
122
+ ; Center string s to width w with character c. [s w c]
123
+ centerc:
124
+ swap dup copy 3 :strlen sub
125
+ push 0 :max push 2 div
126
+ copy 2 swap :strrep
127
+ copy 3 :strcat
128
+ swap copy 1 :strlen sub
129
+ push 0 :max
130
+ copy 2 swap :strrep :strcat
131
+ slide 2 ret
132
+
133
+ ; Center string s to width w with spaces. [s w]
134
+ center: push ' ' :centerc ret
135
+
136
+ ;;;
137
+
138
+ ; remove the last character of a string
139
+ strchop:
140
+ dup :strlen push 1 sub
141
+ push 0 swap :strslice ret
142
+
143
+ ; Split string s on delimiting character d.
144
+ ; ! clobbers heap addresses -1 and -2
145
+ strsplit: ; [s d]
146
+ push -3 push 1 store ; number of found substrings
147
+ push -2 swap store ; stash delimiter to allow some stack juggling
148
+ _strsplit_loop: ; [s]
149
+ dup dup push -2 load
150
+ :strindex dup jn _strsplit_done ; done when index of delimiter is -1
151
+ push 0 swap :strslice
152
+ swap copy 1 push -3 load
153
+ swap :strlen
154
+ swap push -3 swap push 1 add store ; update number of found
155
+ push 1 add push 128 swap :pow div ; shrink haystack
156
+ jump _strsplit_loop
157
+
158
+ _strsplit_done: push 2 sub slide 1 load ret
159
+
160
+ ;;;
161
+
162
+ ; [...strs n delim]
163
+ ; ! clobbers heap address -2 (strlen uses -1)
164
+ strjoinc:
165
+ dup :strlen pop ; get delimiter length into -1
166
+ push -2 swap store
167
+ map (push -2 load :strcat) ; add delimiter to all elements
168
+ swap push 128 copy 1 :strlen
169
+ push -2 load :strlen
170
+ sub :pow mod swap ; remove delimiter from last and flow
171
+ strjoin: reduce (:strcat) ret
172
+
173
+ ;;;
174
+
175
+ ; return the number of ocurrences of character c in string s [s c]
176
+ strcountc: swap push 0 swap
177
+
178
+ _strcountc_loop: ; c t s
179
+ dup jz _strcountc_done
180
+ dup push 128 mod copy 3 sub jz _strcountc_yes
181
+ push 128 div jump _strcountc_loop
182
+
183
+ _strcountc_yes:
184
+ swap push 1 add swap push 128 div
185
+ jump _strcountc_loop
186
+
187
+ _strcountc_done: swap slide 2 ret
188
+
189
+ ; number of ocurrences of all characters in string c [s c]
190
+ ; ! clobbers heap address -2
191
+ strcount:
192
+ swap push -2 swap store
193
+ :strunpack push 0 :to_a
194
+ map (push -2 load swap :strcountc)
195
+ reduce (add) ret
196
+
197
+ ;;;
198
+
199
+ ; Convert all characters in src to the corresponding characters in dest.
200
+ ; ! clobbers heap addresses -1, -2, and -3
201
+ strtrans: ; [string src dest]
202
+ push -3 swap store
203
+ push -2 swap store
204
+ dup :strlen push -1 swap store
205
+ :strunpack push -1 load
206
+ map (:_strtrans) pop
207
+ :strpack ret
208
+
209
+ _strtrans:
210
+ dup push -2 load swap :strindex
211
+ dup jn _strtrans_no
212
+ push -3 load swap :charat
213
+ slide 1 ret
214
+
215
+ _strtrans_no: pop ret
216
+
217
+ strexpand:
218
+ push 0 swap push 128 :divmod
219
+ swap :range :strpack :strrev ret
220
+
221
+ strsqueeze: push 0 swap ; [sentinel s]
222
+ _strsqueeze_loop: ; [s]
223
+ dup jz _strsqueeze_done
224
+ push 128 :divmod dup copy 3 sub jz _strsqueeze_skip
225
+ swap jump _strsqueeze_loop
226
+
227
+ _strsqueeze_skip: pop jump _strsqueeze_loop
228
+
229
+ _strsqueeze_done: pop :strpack :strrev ret
230
+
231
+ strsum: :strunpack push 0 :to_a :arysum ret
232
+
233
+ lines: push 10 :strsplit ret
@@ -0,0 +1,2 @@
1
+ $++ = push 1 add
2
+ $-- = push 1 sub
@@ -0,0 +1,8 @@
1
+ assert_eq:
2
+ dup copy 2 sub jz _assert_eq_yes
3
+ push "expected " :print onum
4
+ push ", got " :print onum
5
+ push " for test " :strcat :print :println
6
+ exit
7
+
8
+ _assert_eq_yes: pop pop pop ret
@@ -0,0 +1,98 @@
1
+ import syntax
2
+
3
+ ; Calling range() will insert between the top two stack values all of the
4
+ ; intervening consecutive elements: [9 10 3 7] -> [9 10 3 4 5 6 7]
5
+ range:
6
+ copy 1 push 1 add swap
7
+ copy 1 copy 1 sub jn range
8
+ pop ret
9
+
10
+ ;;;
11
+
12
+ die: :println exit
13
+ ;;;
14
+
15
+ alpha: push "0123456789abcdefghijklmnopqrstuvwxyz" ret
16
+
17
+ ; string to integer in base b
18
+ stoi: ; [s b]
19
+ swap push 0 ; tally
20
+
21
+ _stoi_loop: ; [b s t]
22
+ swap dup jz _stoi_done
23
+ swap copy 2 copy 2
24
+ :strlen push 1 sub :pow
25
+ copy 2 push 128 mod
26
+ :alpha swap :strindex
27
+ dup jn _stoi_invalid ; found something non-alphanumeric
28
+ mul add swap push 128 div swap
29
+ jump _stoi_loop
30
+
31
+ _stoi_invalid: pop pop slide 1 swap div ret
32
+
33
+ _stoi_done: swap slide 2 ret
34
+
35
+ ;;;
36
+
37
+ bin: push 2 :stoi ret
38
+ oct: push 8 :stoi ret
39
+ to_i: push 10 :stoi ret
40
+ hex: push 16 :stoi ret
41
+
42
+ ;;;
43
+
44
+ ; integer to string in base b
45
+ itos: ; [i b]
46
+ swap push 0 ; empty string
47
+
48
+ _itos_loop:
49
+ swap dup jz _itos_done
50
+ swap copy 1 copy 3 mod
51
+ :alpha swap :charat
52
+ swap :strcat
53
+ swap copy 2 div
54
+ swap jump _itos_loop
55
+
56
+ _itos_done: swap slide 2 ret
57
+
58
+ to_s: push 10 :itos ret
59
+
60
+ ;;;
61
+
62
+ digits: ; [ n d ]
63
+ copy 1 jz _digits_zero ; special case
64
+ push -1 swap store
65
+ push -1 swap ; sentinel value
66
+
67
+ _digits_loop:
68
+ dup jz _digits_done
69
+ push -1 load :divmod
70
+ swap jump _digits_loop
71
+
72
+ _digits_zero: dup div ret
73
+
74
+ _digits_done: push 1 sub :to_a ret
75
+
76
+ ; increment value at heap address n
77
+ inc: dup load $++ store ret
78
+
79
+ ; decrement value at heap address n
80
+ dec: dup load $-- store ret
81
+
82
+ ;;;
83
+
84
+ eq: sub jz _eq_yes push 0 ret
85
+ _eq_yes: push 1 ret
86
+
87
+ neq: sub jz _neq_no push 1 ret
88
+ _neq_no: push 0 ret
89
+
90
+ gt: swap
91
+ lt: sub jn _lt_yes push 0 ret
92
+ _lt_yes: push 1 ret
93
+
94
+ ;;;
95
+
96
+ heap_search:
97
+ $++ dup load copy 2 :eq jz heap_search
98
+ slide 1 ret
@@ -0,0 +1,35 @@
1
+ module Spitewaste
2
+ class AssemblyParser
3
+ OperatorError = Class.new Exception
4
+ SyntaxError = Class.new Exception
5
+
6
+ attr_reader :instructions, :error
7
+
8
+ def initialize program, **options
9
+ @program = program
10
+ end
11
+
12
+ def parse
13
+ mnemonics = OPERATORS_M2T.keys
14
+ @instructions = @program.lines.map.with_index(1) { |insn, no|
15
+ op, arg = insn.split
16
+
17
+ unless i = mnemonics.index(op = op.to_sym)
18
+ @error = [:unknown, op, [i, 1]]
19
+ raise OperatorError, "unknown operator '#{op}' (line #{no})", []
20
+ end
21
+
22
+ bad_arg = -> kind {
23
+ @error = [kind, op, [i, 1]]
24
+ raise SyntaxError, "#{kind} argument for #{op} operator (line #{no})", []
25
+ }
26
+
27
+ bad_arg[:missing] if i < 8 && !arg
28
+ bad_arg[:invalid] if i < 8 && !arg[/^-?\d+$/]
29
+ bad_arg[:useless] if i > 7 && arg
30
+
31
+ [op, arg && arg.to_i]
32
+ }
33
+ end
34
+ end
35
+ end