spitewaste 0.1.003 → 0.1.004

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.
@@ -1,3 +1,6 @@
1
+ import io ; print, println
2
+ import string ; strcat
3
+
1
4
  assert_eq:
2
5
  dup copy 2 sub jz _assert_eq_yes
3
6
  push "expected " :print onum
@@ -1,24 +1,41 @@
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]
1
+ import io ; println
2
+ import math ; divmod, pow
3
+ import stack ; to_a
4
+ import string ; charat, strcat, strindex, strlen
5
+
6
+ ; inserts between the top two stack values the intervening consecutive elements
7
+ ; ! TODO: Support step, and negative as well.
8
+ ; [I J] => [I I+1 ... J]
9
+ ;
10
+ ; [2 5] => [2 3 4 5]
11
+ ; [0 4] => [0 1 2 3 4]
12
+ ; [-2 0] => [-2 -1 0]
13
+ ; [-3 3] => [-3 -2 -1 0 1 2 3]
14
+ ; [4 4] => [4 5] TODO: bug
5
15
  range:
6
16
  copy 1 push 1 add swap
7
17
  copy 1 copy 1 sub jn range
8
18
  pop ret
9
19
 
10
- ;;;
11
-
12
- die: :println exit
13
- ;;;
20
+ ; prints the string at the top of the stack and halts execution
21
+ die!: :println exit
14
22
 
23
+ ; for stoi and itos
15
24
  alpha: push "0123456789abcdefghijklmnopqrstuvwxyz" ret
16
25
 
17
- ; string to integer in base b
18
- stoi: ; [s b]
19
- swap push 0 ; tally
20
-
21
- _stoi_loop: ; [b s t]
26
+ ; converts the string S to an integer in base B (2-36)
27
+ ; ! TODO: support prefixes?
28
+ ; [S B]
29
+ ;
30
+ ; ["101010" 2] => [42]
31
+ ; ["0777" 8] => [511]
32
+ ; ["12345" 10] => [12345]
33
+ ; ["123_" 10] => [123]
34
+ ; ["123____" 10] => [123000] ; TODO: bug
35
+ ; ["dead" 16] => [57005]
36
+ ; ["gabe" 17] => [81699]
37
+ stoi: swap push 0 ; accumulator
38
+ _stoi_loop: ; [b s a]
22
39
  swap dup jz _stoi_done
23
40
  swap copy 2 copy 2
24
41
  :strlen push 1 sub :pow
@@ -27,24 +44,24 @@ _stoi_loop: ; [b s t]
27
44
  dup jn _stoi_invalid ; found something non-alphanumeric
28
45
  mul add swap push 128 div swap
29
46
  jump _stoi_loop
30
-
31
- _stoi_invalid: pop pop slide 1 swap div ret
32
-
47
+ _stoi_invalid: pop pop slide 1 swap div ret ; return what we were able to parse
33
48
  _stoi_done: swap slide 2 ret
34
49
 
35
- ;;;
36
-
50
+ ;;; creature comforts
37
51
  bin: push 2 :stoi ret
38
52
  oct: push 8 :stoi ret
39
53
  to_i: push 10 :stoi ret
40
54
  hex: push 16 :stoi ret
41
55
 
42
- ;;;
43
-
44
- ; integer to string in base b
45
- itos: ; [i b]
46
- swap push 0 ; empty string
47
-
56
+ ; converts the integer N to a string in base B
57
+ ; [N B]
58
+ ;
59
+ ; [42 2] => ["101010"]
60
+ ; [511 8] => ["777"]
61
+ ; [12345 10] => ["12345"]
62
+ ; [57005 16] => ["dead"]
63
+ ; [81699 17] => ["gabe"]
64
+ itos: swap push 0 ; accumulator
48
65
  _itos_loop:
49
66
  swap dup jz _itos_done
50
67
  swap copy 1 copy 3 mod
@@ -52,47 +69,83 @@ _itos_loop:
52
69
  swap :strcat
53
70
  swap copy 2 div
54
71
  swap jump _itos_loop
55
-
56
72
  _itos_done: swap slide 2 ret
57
73
 
74
+ ; creature comfort
58
75
  to_s: push 10 :itos ret
59
76
 
60
- ;;;
61
-
62
- digits: ; [ n d ]
77
+ ; puts the digits of N in base B on the stack as a pseudo-array
78
+ ; [N B]
79
+ ;
80
+ ; [42 2] => [1 0 1 0 1 0 6]
81
+ ; [12345 10] => [1 2 3 4 5 5]
82
+ ; [255 16] => [15 15 2]
83
+ ; [256 16] => [1 0 0 3]
84
+ digits:
63
85
  copy 1 jz _digits_zero ; special case
64
86
  push -1 swap store
65
87
  push -1 swap ; sentinel value
66
-
67
88
  _digits_loop:
68
89
  dup jz _digits_done
69
90
  push -1 load :divmod
70
91
  swap jump _digits_loop
71
-
72
92
  _digits_zero: dup div ret
73
-
74
93
  _digits_done: push 1 sub :to_a ret
75
94
 
76
- ; increment value at heap address n
95
+ ; increments the value at heap address N TODO: make heap effects test-able ?
96
+ ; [N]
77
97
  inc: dup load $++ store ret
78
98
 
79
- ; decrement value at heap address n
99
+ ; decrements the value at heap address N
100
+ ; [N]
80
101
  dec: dup load $-- store ret
81
102
 
82
- ;;;
83
-
103
+ ; pops A and B and pushes 1 if they're equal, 0 otherwise
104
+ ; [A B] => [A == B]
105
+ ;
106
+ ; [1 2] => [0]
107
+ ; [3 3] => [1]
108
+ ; [-4 4] => [0]
109
+ ; ['A' 65] => [1]
110
+ ; ['B' 65] => [0]
84
111
  eq: sub jz _eq_yes push 0 ret
85
112
  _eq_yes: push 1 ret
86
113
 
114
+ ; pops A and B and pushes 1 if they're not equal, 0 otherwise
115
+ ; [A B] => [A != B]
116
+ ;
117
+ ; [1 2] => [1]
118
+ ; [3 3] => [0]
119
+ ; [-4 4] => [1]
120
+ ; ['A' 65] => [0]
121
+ ; ['B' 65] => [1]
87
122
  neq: sub jz _neq_no push 1 ret
88
123
  _neq_no: push 0 ret
89
124
 
90
- gt: swap
125
+ ; pops A and B and pushes 1 if A is greater than B, 0 otherwise
126
+ ; [A B] => [A > B]
127
+ ;
128
+ ; [4 3] => [1]
129
+ ; [3 4] => [0]
130
+ ; [2 2] => [0]
131
+ ; [2 1] => [1]
132
+ gt: swap ; intentionally flow into lt
133
+
134
+ ; pops A and B and pushes 1 if A is less than than B, 0 otherwise
135
+ ; [A B] => [A < B]
136
+ ;
137
+ ; [3 4] => [1]
138
+ ; [4 3] => [0]
139
+ ; [2 2] => [0]
140
+ ; [1 2] => [1]
91
141
  lt: sub jn _lt_yes push 0 ret
92
142
  _lt_yes: push 1 ret
93
143
 
94
- ;;;
95
-
96
- heap_search:
144
+ ; Though extremely rare, it's possible that we know a particular value is
145
+ ; stored in the heap at some key, just not which one. This subroutine takes
146
+ ; a value V to search for and a starting index I, and either returns the first
147
+ ; key associated with that value or loops forever. Probably don't touch.
148
+ ; [V I]
149
+ heap_seeking_missile:
97
150
  $++ dup load copy 2 :eq jz heap_search
98
151
  slide 1 ret
@@ -57,6 +57,7 @@ module Spitewaste
57
57
  private
58
58
 
59
59
  def preprocess!
60
+ @src.prepend "import syntax\n"
60
61
  resolve_imports
61
62
  seed_prng if @seen.include? 'random'
62
63
  resolve_strings
@@ -94,7 +95,7 @@ module Spitewaste
94
95
  end
95
96
 
96
97
  def resolve_strings
97
- @src.gsub!(/"([^"]+)"/m) {
98
+ @src.gsub!(/"([^"]*)"/m) {
98
99
  [0, *$1.reverse.bytes] * ' push ' + ' :strpack'
99
100
  }
100
101
  end
@@ -118,31 +119,22 @@ module Spitewaste
118
119
 
119
120
  def fucktionalize
120
121
  # Iteratively remove pseudo-fp calls until we can't to allow nesting.
121
- 1 while @src.gsub!(/(#{FUCKTIONAL.keys * ?|})\s*\((.+)\)/) do
122
+ 1 while @src.gsub!(/(#{FUCKTIONAL.keys * ?|})\s*\((.+?)\)/m) do
122
123
  FUCKTIONAL[$1] % [gensym, $2]
123
124
  end
124
125
  end
125
126
 
126
127
  def propagate_macros
127
- @src.gsub!(/(\$\S+)\s*=\s*(.+)/) { @macros[$1] = $2; '' }
128
+ # Macros are write-once, allowing user code to customize the special
129
+ # values that get used to drive certain behavior in the standard library.
130
+ @src.gsub!(/(\$\S+)\s*=\s*(.+)/) { @macros[$1] ||= $2; '' }
128
131
  @src.gsub!(/(\$\S+)/) { @macros[$1] || raise("no macro '#{$1}'") }
129
-
130
- # @src.gsub!(/(\$[^(]+)\s*\((.+)\)\s*{(.+)}/m) { @macros[$1] = $2, $3; '' }
131
- # @src.gsub!(/(\$[^(]+)\((.+?)\)/m) {
132
- # unless (params, body = @macros[$1])
133
- # raise "no macro function '#{$1}'"
134
- # end
135
-
136
- # params = params.split(?,).map &:strip
137
- # args = $2.split ?,
138
- # body.gsub /\b(#{params * ?|})\b/, params.zip(args).to_h
139
- # }
140
132
  end
141
133
 
142
134
  def eliminate_dead_code!
143
135
  tokens = @src.split
144
136
 
145
- # We need an entry point from which to begin determining which routines
137
+ # We need an entry point whence to begin determining which routines
146
138
  # are never invoked, but Whitespace programs aren't required to start
147
139
  # with a label. Here, we add an implcit "main" to the beginning of the
148
140
  # source unless it already contains an explicit entry point. TODO: better?
@@ -1,3 +1,3 @@
1
1
  module Spitewaste
2
- VERSION = '0.1.003'
2
+ VERSION = '0.1.004'
3
3
  end
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.1.003
4
+ version: 0.1.004
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: 2020-12-13 00:00:00.000000000 Z
11
+ date: 2020-12-14 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: rake
@@ -104,6 +104,7 @@ files:
104
104
  - lib/spitewaste/libspw/math.spw
105
105
  - lib/spitewaste/libspw/prime.spw
106
106
  - lib/spitewaste/libspw/random.spw
107
+ - lib/spitewaste/libspw/rational.spw
107
108
  - lib/spitewaste/libspw/stack.spw
108
109
  - lib/spitewaste/libspw/string.spw
109
110
  - lib/spitewaste/libspw/syntax.spw