spitewaste 0.1.003 → 0.1.004

Sign up to get free protection for your applications and to get access to all the features.
@@ -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