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.
- 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
|