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,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,7 @@
1
+ module Spitewaste
2
+ class WSAssemblyEmitter < Emitter
3
+ def emit io:
4
+ io.puts @instructions # actually just preprocessed Spitewaste
5
+ end
6
+ end
7
+ 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