spitewaste 0.1.001
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/Gemfile +8 -0
- data/README.md +55 -0
- data/Rakefile +10 -0
- data/TUTORIAL.md +125 -0
- data/bin/spw +10 -0
- data/demo/factorial-nicespace.png +0 -0
- data/demo/factorial.asm +47 -0
- data/demo/factorial.png +0 -0
- data/demo/factorial.wsa +5 -0
- data/lib/spitewaste.rb +35 -0
- data/lib/spitewaste/assembler.rb +56 -0
- data/lib/spitewaste/cli.rb +51 -0
- data/lib/spitewaste/cli/asm.rb +10 -0
- data/lib/spitewaste/cli/compile.rb +60 -0
- data/lib/spitewaste/cli/convert.rb +53 -0
- data/lib/spitewaste/cli/exec.rb +43 -0
- data/lib/spitewaste/cli/image.rb +53 -0
- data/lib/spitewaste/emitter.rb +10 -0
- data/lib/spitewaste/emitters/assembly.rb +7 -0
- data/lib/spitewaste/emitters/codegen.rb +72 -0
- data/lib/spitewaste/emitters/image.rb +135 -0
- data/lib/spitewaste/emitters/linefeed.png +0 -0
- data/lib/spitewaste/emitters/schemes.yaml +1143 -0
- data/lib/spitewaste/emitters/whitespace.rb +14 -0
- data/lib/spitewaste/emitters/wsassembly.rb +7 -0
- data/lib/spitewaste/libspw/array.spw +82 -0
- data/lib/spitewaste/libspw/bits.spw +72 -0
- data/lib/spitewaste/libspw/case.spw +32 -0
- data/lib/spitewaste/libspw/fun.spw +42 -0
- data/lib/spitewaste/libspw/io.spw +39 -0
- data/lib/spitewaste/libspw/math.spw +117 -0
- data/lib/spitewaste/libspw/prime.spw +46 -0
- data/lib/spitewaste/libspw/random.spw +10 -0
- data/lib/spitewaste/libspw/stack.spw +84 -0
- data/lib/spitewaste/libspw/string.spw +233 -0
- data/lib/spitewaste/libspw/syntax.spw +2 -0
- data/lib/spitewaste/libspw/test.spw +8 -0
- data/lib/spitewaste/libspw/util.spw +98 -0
- data/lib/spitewaste/parsers/assembly.rb +35 -0
- data/lib/spitewaste/parsers/fucktional.rb +72 -0
- data/lib/spitewaste/parsers/spitewaste.rb +192 -0
- data/lib/spitewaste/parsers/whitespace.rb +60 -0
- data/lib/spitewaste/version.rb +3 -0
- data/spitewaste.gemspec +17 -0
- metadata +88 -0
@@ -0,0 +1,14 @@
|
|
1
|
+
module Spitewaste
|
2
|
+
class WhitespaceEmitter < Emitter
|
3
|
+
def emit io:
|
4
|
+
instructions.each do |op, arg|
|
5
|
+
io.write OPERATORS_M2T[op]
|
6
|
+
io.write self.class.encode(arg) if arg
|
7
|
+
end
|
8
|
+
end
|
9
|
+
|
10
|
+
def self.encode n
|
11
|
+
(n < 0 ? ?\t : ' ') + n.abs.to_s(2).tr('01', " \t") + ?\n
|
12
|
+
end
|
13
|
+
end
|
14
|
+
end
|
@@ -0,0 +1,82 @@
|
|
1
|
+
$amax = 1000
|
2
|
+
|
3
|
+
arysum: reduce (add) ret
|
4
|
+
|
5
|
+
arydup:
|
6
|
+
dup $++ push -2 copy 1 store
|
7
|
+
times (push -2 load $-- :ncopy) ret
|
8
|
+
|
9
|
+
arypop: slide 1 $-- ret
|
10
|
+
|
11
|
+
aryshift: dup :dig $-- ret
|
12
|
+
|
13
|
+
arycat: dup $++ :roll add ret
|
14
|
+
|
15
|
+
arypack:
|
16
|
+
:arydup reduce (:max) $++ push -1 swap store
|
17
|
+
$-- times (push -1 load mul add)
|
18
|
+
push $amax mul push -1 load add
|
19
|
+
push $amax mul push -10 load add ret
|
20
|
+
|
21
|
+
aryunpack:
|
22
|
+
push $amax :divmod push -2 swap store
|
23
|
+
push $amax :divmod push -1 swap store
|
24
|
+
push -2 load times (push -1 load :divmod swap)
|
25
|
+
push 2 sub load ret
|
26
|
+
|
27
|
+
arylen: push $amax mod ret
|
28
|
+
|
29
|
+
;;;
|
30
|
+
|
31
|
+
aryindex: copy 1 ; two copies of length, one gets decremented, index is diff
|
32
|
+
_aryindex_loop: ; [h n l]
|
33
|
+
dup jn _aryindex_notfound
|
34
|
+
dup push 2 add :roll copy 2 :eq jz _aryindex_no
|
35
|
+
copy 2 copy 1 sub swap $++ :nslide ret
|
36
|
+
|
37
|
+
_aryindex_no: $-- jump _aryindex_loop
|
38
|
+
|
39
|
+
_aryindex_notfound: slide 1 ret
|
40
|
+
|
41
|
+
;;;
|
42
|
+
|
43
|
+
; element at index i
|
44
|
+
aryat: ; [a i]
|
45
|
+
dup jn _aryat_neg
|
46
|
+
copy 1 swap sub dup :pos? jz _aryat_oob
|
47
|
+
:roll swap $-- :nslide ret
|
48
|
+
|
49
|
+
_aryat_neg: copy 1 add dup jn _aryat_oob jump aryat
|
50
|
+
|
51
|
+
_aryat_oob: push "(aryat) index out of bounds!" :die
|
52
|
+
|
53
|
+
minmax:
|
54
|
+
:arydup reduce (:max)
|
55
|
+
push -1 swap store
|
56
|
+
reduce (:min) push -1 load ret
|
57
|
+
|
58
|
+
;;;
|
59
|
+
|
60
|
+
sort: push -3 copy 1 store ; preserve length
|
61
|
+
_sort_loop:
|
62
|
+
:arydup reduce (:min)
|
63
|
+
push -1 copy 1 store copy 1 $++ :bury ; stash minimum element
|
64
|
+
:arydup push -1 load :aryindex
|
65
|
+
copy 1 swap sub :dig $-- ; remove minimum element from array
|
66
|
+
push 0 copy 1 sub jn _sort_loop
|
67
|
+
push 3 sub load ret
|
68
|
+
|
69
|
+
aryrev: push -3 copy 1 store
|
70
|
+
_aryrev_loop:
|
71
|
+
swap copy 1 :bury $--
|
72
|
+
push 0 copy 1 sub jn _aryrev_loop
|
73
|
+
push 3 sub load ret
|
74
|
+
|
75
|
+
;;;
|
76
|
+
|
77
|
+
aryrep: push -1 swap push -3 copy 1 store store
|
78
|
+
_aryrep_loop:
|
79
|
+
push -1 dup :dec load jz _aryrep_done
|
80
|
+
:arydup jump _aryrep_loop
|
81
|
+
|
82
|
+
_aryrep_done: push -3 load $-- times (:arycat) ret
|
@@ -0,0 +1,72 @@
|
|
1
|
+
import math
|
2
|
+
|
3
|
+
; TODO: don't use strings for bitwise operations
|
4
|
+
|
5
|
+
; bitwise bitwise_and
|
6
|
+
; ! clobbers heap address -1
|
7
|
+
bitwise_and: ; [a b] => [a & b]
|
8
|
+
push -1 push 0 store ; empty string tally
|
9
|
+
|
10
|
+
_bitwise_and_loop:
|
11
|
+
copy 1 copy 1 add jz _bitwise_done
|
12
|
+
copy 1 push 2 mod
|
13
|
+
copy 1 push 2 mod
|
14
|
+
add push 2 sub jz _bitwise_and_yes
|
15
|
+
push '0' jump _bitwise_and_update
|
16
|
+
|
17
|
+
_bitwise_and_yes: push '1'
|
18
|
+
_bitwise_and_update: :_bitwise_update jump _bitwise_and_loop
|
19
|
+
|
20
|
+
_bitwise_update:
|
21
|
+
push -1 load swap :strcat
|
22
|
+
push -1 swap store
|
23
|
+
push 2 div swap push 2 div ret
|
24
|
+
|
25
|
+
_bitwise_done: push -1 load :strrev :bin slide 2 ret
|
26
|
+
|
27
|
+
; bitwise bitwise_or
|
28
|
+
; ! clobbers heap address -1
|
29
|
+
bitwise_or: ; [a b] => [a | b]
|
30
|
+
push -1 push 0 store ; empty string tally
|
31
|
+
|
32
|
+
_bitwise_or_loop:
|
33
|
+
copy 1 copy 1 add jz _bitwise_done
|
34
|
+
copy 1 push 2 mod
|
35
|
+
copy 1 push 2 mod
|
36
|
+
add jz _bitwise_or_no
|
37
|
+
push '1' jump _bitwise_or_update
|
38
|
+
|
39
|
+
_bitwise_or_no: push '0'
|
40
|
+
_bitwise_or_update: :_bitwise_update jump _bitwise_or_loop
|
41
|
+
|
42
|
+
; bitwise bitwise_xor
|
43
|
+
; ! clobbers heap address -1
|
44
|
+
bitwise_xor: ; [a b] => [a ^ b]
|
45
|
+
push -1 push 0 store ; empty string tally
|
46
|
+
|
47
|
+
_bitwise_xor_loop:
|
48
|
+
copy 1 copy 1 add jz _bitwise_done
|
49
|
+
copy 1 push 2 mod
|
50
|
+
copy 1 push 2 mod
|
51
|
+
add push 1 sub jz _bitwise_xor_yes
|
52
|
+
push '0' jump _bitwise_xor_update
|
53
|
+
|
54
|
+
_bitwise_xor_yes: push '1'
|
55
|
+
_bitwise_xor_update: :_bitwise_update jump _bitwise_xor_loop
|
56
|
+
|
57
|
+
; flip all bits in n ; [n]
|
58
|
+
bitwise_not:
|
59
|
+
dup push 0 swap push 1 add sub
|
60
|
+
swap push 2 :ilog push 2 swap :pow mod ret
|
61
|
+
|
62
|
+
;;;
|
63
|
+
|
64
|
+
; number of set bits in n ; [n]
|
65
|
+
popcount: push 2 :digits reduce (add) ret
|
66
|
+
|
67
|
+
;;;
|
68
|
+
|
69
|
+
; most significant set bit in n, as a power of 2 ; [n]
|
70
|
+
msb: dup jz _msb_zero
|
71
|
+
push 2 :itos :strlen $-- push 2 swap :pow ret
|
72
|
+
_msb_zero: ret
|
@@ -0,0 +1,32 @@
|
|
1
|
+
import bits
|
2
|
+
;;; Case conversion
|
3
|
+
|
4
|
+
upcase: :strunpack push 0 ; tally
|
5
|
+
_upcase_loop:
|
6
|
+
swap dup jz _upcase_done
|
7
|
+
dup :isalpha jz _upcase_cat
|
8
|
+
push 95 :bitwise_and
|
9
|
+
_upcase_cat:
|
10
|
+
:strcat jump _upcase_loop
|
11
|
+
|
12
|
+
_upcase_done: pop ret
|
13
|
+
|
14
|
+
downcase: :strunpack push 0 ; tally
|
15
|
+
_downcase_loop:
|
16
|
+
swap dup jz _downcase_done
|
17
|
+
dup :isalpha jz _downcase_cat
|
18
|
+
push 32 :bitwise_or
|
19
|
+
_downcase_cat:
|
20
|
+
:strcat jump _downcase_loop
|
21
|
+
|
22
|
+
_downcase_done: pop ret
|
23
|
+
|
24
|
+
swapcase: :strunpack push 0 ; tally
|
25
|
+
_swapcase_loop:
|
26
|
+
swap dup jz _swapcase_done
|
27
|
+
dup :isalpha jz _swapcase_cat
|
28
|
+
push 32 :bitwise_xor
|
29
|
+
_swapcase_cat:
|
30
|
+
:strcat jump _swapcase_loop
|
31
|
+
|
32
|
+
_swapcase_done: pop ret
|
@@ -0,0 +1,42 @@
|
|
1
|
+
import string
|
2
|
+
|
3
|
+
palindrome?: dup :strrev :eq ret
|
4
|
+
|
5
|
+
;;;
|
6
|
+
|
7
|
+
anagrams?:
|
8
|
+
:strunpack push 0 :to_a :sort :strjoin swap
|
9
|
+
:strunpack push 0 :to_a :sort :strjoin :eq ret
|
10
|
+
|
11
|
+
;;;
|
12
|
+
|
13
|
+
isop: :upcase push 0 swap ; tally
|
14
|
+
_isop_loop: ; [t s]
|
15
|
+
dup jz _isop_done
|
16
|
+
swap copy 1 push 128 mod
|
17
|
+
dup :isalpha jz _isop_no ; ignore non-alphabetical
|
18
|
+
push 64
|
19
|
+
_isop_resume:
|
20
|
+
sub add
|
21
|
+
swap push 128 div jump _isop_loop
|
22
|
+
|
23
|
+
_isop_no: dup jump _isop_resume
|
24
|
+
|
25
|
+
_isop_done: pop ret
|
26
|
+
|
27
|
+
;;;
|
28
|
+
|
29
|
+
collatz: push 1 ; sequence length
|
30
|
+
_collatz_loop:
|
31
|
+
copy 1 dup push 1 sub jz _collatz_done
|
32
|
+
dup push 2 mod ; m2 n m2
|
33
|
+
swap copy 1 push 2 mul $++ mul
|
34
|
+
push 2 copy 2 sub div add
|
35
|
+
swap $++ jump _collatz_loop
|
36
|
+
|
37
|
+
_collatz_done: pop ret
|
38
|
+
|
39
|
+
;;;
|
40
|
+
|
41
|
+
ruby:
|
42
|
+
push "'" :strcat push "ruby -e 'p " swap :strcat shell ret
|
@@ -0,0 +1,39 @@
|
|
1
|
+
; prints the character at the top of the stack until terminating zero
|
2
|
+
print: :strunpack
|
3
|
+
_print_loop:
|
4
|
+
dup jz _print_done
|
5
|
+
ochr jump _print_loop
|
6
|
+
_print_done: pop ret
|
7
|
+
|
8
|
+
; print with newline
|
9
|
+
println: :print push 10 ochr ret
|
10
|
+
|
11
|
+
;;;
|
12
|
+
|
13
|
+
; reads a line of input onto the top of the stack as a packed string
|
14
|
+
; ! clobbers heap address -1
|
15
|
+
getline: push 0 ; terminator for strpack
|
16
|
+
|
17
|
+
; read characters onto the stack until newline (10) or EOF (-1)
|
18
|
+
_getline_loop:
|
19
|
+
push -1 dup ichr load
|
20
|
+
dup jn _getline_eof
|
21
|
+
dup push 10 sub jz _getline_done
|
22
|
+
jump _getline_loop
|
23
|
+
|
24
|
+
_getline_eof: pop
|
25
|
+
_getline_done: :strpack :strrev ret
|
26
|
+
|
27
|
+
;;;
|
28
|
+
|
29
|
+
prompt: :print :getline ret
|
30
|
+
|
31
|
+
;;;
|
32
|
+
|
33
|
+
; consume stdin until EOF
|
34
|
+
readall: push 0 ; accumulated string
|
35
|
+
_readall_loop:
|
36
|
+
:getline dup jz _readall_done
|
37
|
+
:strcat jump _readall_loop
|
38
|
+
|
39
|
+
_readall_done: pop ret
|
@@ -0,0 +1,117 @@
|
|
1
|
+
import util (range) ; for factorial
|
2
|
+
|
3
|
+
; [b e] => [b^e]
|
4
|
+
pow:
|
5
|
+
push 1 swap
|
6
|
+
|
7
|
+
_pow_loop: ; [b n e]
|
8
|
+
dup jz _pow_done
|
9
|
+
swap copy 2 mul ; [b e n*b]
|
10
|
+
swap push 1 sub jump _pow_loop
|
11
|
+
|
12
|
+
_pow_done: ; b n e
|
13
|
+
pop slide 1 ret
|
14
|
+
|
15
|
+
;;;
|
16
|
+
|
17
|
+
; [n] => [n!]
|
18
|
+
factorial: push 0 swap :range
|
19
|
+
_fac_loop: swap dup jz _fac_done mul jump _fac_loop
|
20
|
+
_fac_done: pop ret
|
21
|
+
|
22
|
+
;;;
|
23
|
+
|
24
|
+
isqrt: ; [n] -> [isqrt(n)]
|
25
|
+
dup push 2 sub jn _isqrt_done
|
26
|
+
dup push 4 div :isqrt push 2 mul
|
27
|
+
dup push 1 add
|
28
|
+
copy 2 copy 1 dup mul sub jn _isqrt_cleanup
|
29
|
+
swap
|
30
|
+
_isqrt_cleanup: swap slide 2
|
31
|
+
_isqrt_done: ret
|
32
|
+
|
33
|
+
;;;
|
34
|
+
|
35
|
+
; intger logarithm ; [a b] => [log(a, b)]
|
36
|
+
; ! clobbers heap address -1 TODO: maybe not necessary?
|
37
|
+
ilog:
|
38
|
+
push -1 push 0 store ; tally
|
39
|
+
|
40
|
+
_ilog_loop: ; a b
|
41
|
+
swap dup jz _ilog_done
|
42
|
+
push -1 :inc
|
43
|
+
copy 1 div swap
|
44
|
+
jump _ilog_loop
|
45
|
+
|
46
|
+
_ilog_done: ; a b t
|
47
|
+
push -1 load slide 2 ret
|
48
|
+
|
49
|
+
;;;
|
50
|
+
|
51
|
+
; greatest common divisor
|
52
|
+
gcd: ; [a b]
|
53
|
+
dup jz _gcd_done
|
54
|
+
swap copy 1 mod
|
55
|
+
jump gcd
|
56
|
+
|
57
|
+
_gcd_done: pop ret
|
58
|
+
|
59
|
+
; least common multiple
|
60
|
+
lcm: ; [a b]
|
61
|
+
copy 1 mul
|
62
|
+
swap dup copy 2 swap div
|
63
|
+
:gcd div ret
|
64
|
+
|
65
|
+
;;;
|
66
|
+
|
67
|
+
min: ; [a b]
|
68
|
+
copy 1 copy 1 sub jn _min_done swap
|
69
|
+
_min_done: pop ret
|
70
|
+
|
71
|
+
max: ; [a b]
|
72
|
+
copy 1 copy 1 sub jn _max_done swap
|
73
|
+
_max_done: slide 1 ret
|
74
|
+
|
75
|
+
;;;
|
76
|
+
|
77
|
+
; -1, 0, or 1 to indicate the sign of the argument
|
78
|
+
sign: ; [n]
|
79
|
+
dup jz _sign_zero
|
80
|
+
jn _sign_neg
|
81
|
+
push 1 ret
|
82
|
+
_sign_zero: ret
|
83
|
+
_sign_neg: push -1 ret
|
84
|
+
|
85
|
+
; absolute value ; [n] => [abs(n)]
|
86
|
+
abs: dup :sign mul ret
|
87
|
+
|
88
|
+
;;;
|
89
|
+
|
90
|
+
divmod:
|
91
|
+
push -1 swap store
|
92
|
+
dup push -1 load div
|
93
|
+
swap push -1 load mod ret
|
94
|
+
|
95
|
+
;;;
|
96
|
+
|
97
|
+
pos?: :sign push 1 :eq ret
|
98
|
+
neg?: :sign push -1 :eq ret
|
99
|
+
|
100
|
+
;;;
|
101
|
+
|
102
|
+
divisors: ; [n]
|
103
|
+
dup push -1 swap store ; preserve n because array operations
|
104
|
+
:isqrt push 1 swap :range dup ; 1..n**0.5
|
105
|
+
reject (push -1 load swap mod) :arydup ; get first half of divisors
|
106
|
+
map (push -1 load swap div) :arycat ; map first half to second half
|
107
|
+
push -1 load copy 2 dup mul sub jz _divisors_square
|
108
|
+
ret
|
109
|
+
|
110
|
+
_divisors_square: slide 1 $-- ret ; de-duplicate when N is a perfect square
|
111
|
+
|
112
|
+
;;;
|
113
|
+
|
114
|
+
nCk:
|
115
|
+
copy 1 copy 1 sub :factorial
|
116
|
+
swap :factorial mul
|
117
|
+
swap :factorial swap div ret
|
@@ -0,0 +1,46 @@
|
|
1
|
+
; [n] => [0|1]
|
2
|
+
prime?: ; [n]
|
3
|
+
dup push 3 sub jn _prime_special ; special-case < 3
|
4
|
+
dup push 2 mod jz _prime_even ; otherwise, even -> false
|
5
|
+
push 3
|
6
|
+
|
7
|
+
_prime_loop: ; [n d]
|
8
|
+
copy 1 copy 1 dup mul sub jn _prime_yes ; divisor > isqrt(n), n is prime
|
9
|
+
copy 1 copy 1 mod jz _prime_no
|
10
|
+
push 2 add jump _prime_loop
|
11
|
+
|
12
|
+
_prime_yes:
|
13
|
+
pop dup div ret ; return 1
|
14
|
+
|
15
|
+
_prime_even:
|
16
|
+
push 1
|
17
|
+
_prime_no:
|
18
|
+
pop dup sub ret ; return 0
|
19
|
+
|
20
|
+
_prime_special: ; [n]
|
21
|
+
push 2 sub jz _prime_two
|
22
|
+
push 0 ret ; false for n < 2
|
23
|
+
|
24
|
+
_prime_two:
|
25
|
+
push 1 ret
|
26
|
+
|
27
|
+
;;;
|
28
|
+
|
29
|
+
next_prime: push 1 add dup :prime? jz next_prime ret
|
30
|
+
|
31
|
+
;;;
|
32
|
+
|
33
|
+
; prime factorization
|
34
|
+
factor: ; [n]
|
35
|
+
push 2 swap ; initial divisor
|
36
|
+
push -2,0 store ; number of prime factors
|
37
|
+
_factor_loop: ; [d n]
|
38
|
+
dup push 2 sub jn _factor_done
|
39
|
+
jump _divisor_loop ; prevent dead code elimination :(
|
40
|
+
_divisor_loop:
|
41
|
+
dup copy 2 :divmod jz _divisor_keep
|
42
|
+
pop swap :next_prime swap jump _factor_loop
|
43
|
+
|
44
|
+
_divisor_keep: push -2 :inc slide 1 copy 1 swap jump _factor_loop
|
45
|
+
|
46
|
+
_factor_done: slide 1 push 3 sub load ret
|