subtle-lang 0.0.3 → 0.0.4

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.
@@ -6,12 +6,10 @@ module Subtle
6
6
  @transform = Transform.new
7
7
  end
8
8
 
9
- def eval(string_or_tree)
10
- if String === string_or_tree
11
- parsed = @parser.parse string_or_tree
9
+ def eval(t)
10
+ if String === t
11
+ parsed = @parser.parse t
12
12
  t = @transform.apply parsed
13
- else
14
- t = string_or_tree
15
13
  end
16
14
 
17
15
  if Hash === t
@@ -19,12 +17,9 @@ module Subtle
19
17
 
20
18
  case type
21
19
  when :assignment
22
- identifier = t[:identifier]
23
- right = try_eval t[:right]
24
- @state[identifier] = right
20
+ @state[t[:identifier]] = try_eval t[:right]
25
21
  when :deassignment
26
- identifier = t[:identifier]
27
- @state[identifier]
22
+ @state[t[:identifier]]
28
23
  when :function
29
24
  t[:function]
30
25
  when :function_call
@@ -64,15 +59,7 @@ module Subtle
64
59
  verb = "**" if verb == "^"
65
60
 
66
61
  if adverb
67
- if Array === right
68
- if right.size < 2
69
- ae! t, "Need Array of size atleast 2 for a monadic adverb." +
70
- " Your Array had #{right.size} items."
71
- end
72
- else
73
- ae! t, "Can only apply monadic adverb on Arrays." +
74
- " You passed in #{right.class}."
75
- end
62
+ right = [right] unless Array === right
76
63
  case adverb
77
64
  when "//:"
78
65
  right.map do |r|
@@ -86,36 +73,47 @@ module Subtle
86
73
  right.map do |r|
87
74
  eval type: :monad, verb: verb, right: r
88
75
  end
76
+ when "\\" # Scan
77
+ [right.shift].tap do |scan|
78
+ right.each do |r|
79
+ scan << eval({type: :dyad, verb: verb, left: scan.last,
80
+ right: r})
81
+ end
82
+ end
89
83
  else
90
- nie! t, "Invalid adverb #{adverb} on Monads."
84
+ ae! t, "Invalid adverb #{adverb} on Monads."
91
85
  end
92
86
  else
93
87
  if Array === right
94
- else
95
- ae! t, "Can only apply monadic verb on Arrays." +
96
- " You passed in #{right.class}."
97
- end
98
- case verb
99
- when "&"
100
- [].tap do |ret|
101
- right.each_with_index do |r, i|
102
- r.times { ret << i }
88
+ case verb
89
+ when "&"
90
+ [].tap do |ret|
91
+ right.each_with_index do |r, i|
92
+ r.times { ret << i }
93
+ end
103
94
  end
95
+ when "~"
96
+ right.map do |r|
97
+ r == 0 ? 1 : 0
98
+ end
99
+ when "+"
100
+ if Array === right.first
101
+ right.transpose
102
+ else
103
+ right
104
+ end
105
+ when "|"
106
+ right.reverse
104
107
  end
105
- when "~"
106
- right.map do |r|
107
- r == 0 ? 1 : 0
108
- end
109
- when "+"
110
- if Array === right.first
111
- right.transpose
112
- else
108
+ elsif Numeric === right
109
+ case verb
110
+ when "&"
111
+ right.times.map { 0 }
112
+ when "~"
113
+ right == 0 ? 1 : 0
114
+ when "+", "|"
113
115
  right
114
116
  end
115
- when "|"
116
- right.reverse
117
- else
118
- nie! "Verb #{verb} without Adverb not implemented as a Monad"
119
117
  end
120
118
  end
121
119
  when :dyad
@@ -125,55 +123,67 @@ module Subtle
125
123
  verb = t[:verb]
126
124
  adverb = t[:adverb]
127
125
 
128
- # `^` in Subtle is `**` in Ruby.
126
+ # `^` in Subtle is `**` in Ruby,
129
127
  verb = "**" if verb == "^"
128
+ # `=` is `==`,
129
+ verb = "==" if verb == "="
130
+ # `&` is `min` and `|` is `max.
131
+ verb = "min" if verb == "&"
132
+ verb = "max" if verb == "|"
130
133
 
131
134
  if adverb
132
135
  case adverb
133
136
  when "/:" # Map each over right
134
137
  right.map do |r|
135
- eval({ type: :dyad, left: left, verb: verb, right: r })
138
+ eval type: :dyad, left: left, verb: verb, right: r
136
139
  end
137
140
  when "\\:" # Map each over left
138
141
  left.map do |l|
139
- eval({ type: :dyad, left: l, verb: verb, right: right })
142
+ eval type: :dyad, left: l, verb: verb, right: right
140
143
  end
141
144
  else
142
- nie! t, "Invalid Adverb #{adverb}"
145
+ ae! t, "Invalid Adverb #{adverb}"
143
146
  end
144
147
  else
145
148
  case verb
146
- when "+", "-", "*", "/", "%", "**"
149
+ when "+", "-", "*", "/", "%", "**", "==", "<", ">"
147
150
  if Numeric === left && Numeric === right
148
- left.send(verb, right)
151
+ ret = left.send(verb, right)
152
+ if %w{== < >}.include?(verb)
153
+ ret ? 1 : 0
154
+ else
155
+ ret
156
+ end
149
157
  elsif Array === left && Array === right
150
158
  if left.size != right.size
151
159
  ae! t, "Size of left array must be the same as the size of" +
152
160
  " right one, but #{left.size} != #{right.size}."
153
161
  end
154
162
 
155
- # Both have another dimension
156
- if Array === left.first && Array === right.first
157
- left.zip(right).map do |l, r|
163
+ left.zip(right).map do |l, r|
164
+ if Array === l || Array === r
158
165
  eval type: :dyad, verb: verb, left: l, right: r
159
- end
160
- elsif Array === left.first || Array === right.first
161
- left.zip(right).map do |l, r|
162
- eval type: :dyad, verb: verb, left: l, right: r
163
- end
164
- else
165
- left.zip(right).map do |l, r|
166
- (try_eval l).send(verb, try_eval(r))
166
+ else
167
+ ret = (try_eval l).send(verb, try_eval(r))
168
+ if %w{== < >}.include?(verb)
169
+ ret ? 1 : 0
170
+ else
171
+ ret
172
+ end
167
173
  end
168
174
  end
169
-
170
175
  elsif Array === left && Numeric === right
171
176
  left.map do |l|
172
177
  # Multi-dimensional arrays
173
178
  if Array === l
174
179
  eval type: :dyad, verb: verb, left: l, right: right
175
180
  else
176
- (try_eval l).send(verb, right)
181
+ ret = (try_eval l).send(verb, right)
182
+ if %w{== < >}.include?(verb)
183
+ ret ? 1 : 0
184
+ else
185
+ ret
186
+ end
177
187
  end
178
188
  end
179
189
  elsif Numeric === left && Array === right
@@ -182,17 +192,19 @@ module Subtle
182
192
  if Array === r
183
193
  eval type: :dyad, verb: verb, left: left, right: r
184
194
  else
185
- left.send(verb, r)
195
+ ret = left.send(verb, r)
196
+ if %w{== < >}.include?(verb)
197
+ ret ? 1 : 0
198
+ else
199
+ ret
200
+ end
186
201
  end
187
202
  end
188
203
  else
189
- nie! t, "Left and Array must be Numeric or Arrays." +
204
+ ae! t, "Left and Array must be Numeric or Arrays." +
190
205
  " You passed in #{left.class} and #{right.class}."
191
206
  end
192
- when "&", "|"
193
- verb = "min" if verb == "&"
194
- verb = "max" if verb == "|"
195
-
207
+ when "max", "min"
196
208
  if Numeric === left && Numeric === right
197
209
  [left, right].send(verb)
198
210
  elsif Array === left && Array === right
@@ -200,31 +212,38 @@ module Subtle
200
212
  ae! t, "Size of left array must be the same as the size of" +
201
213
  " right one, but #{left.size} != #{right.size}."
202
214
  end
203
-
204
- left.zip(right).map do |x, y|
205
- [x, y].send(verb)
215
+ left.zip(right).map do |l, r|
216
+ eval type: :dyad, verb: verb, left: l, right: r
206
217
  end
207
218
  elsif Array === left && Numeric === right
208
219
  left.map do |l|
209
- [l, right].send(verb)
220
+ if Array === l
221
+ eval type: :dyad, verb: verb, left: l, right: right
222
+ else
223
+ [l, right].send(verb)
224
+ end
210
225
  end
211
226
  elsif Numeric === left && Array === right
212
227
  right.map do |r|
213
- [left, r].send(verb)
228
+ if Array === r
229
+ eval type: :dyad, verb: verb, left: left, right: r
230
+ else
231
+ [left, r].send(verb)
232
+ end
214
233
  end
215
234
  else
216
- nie! t
235
+ ae! t
217
236
  end
218
237
  when "!"
219
238
  if Numeric === left && Array === right
239
+ right.rotate(left)
220
240
  else
221
241
  ae! t, "Left must be Numeric and right must be an Array for" +
222
242
  " rotate (`!`) dyad. You passed in #{left.class} and" +
223
243
  " #{right.class}"
224
244
  end
225
- right.rotate(left)
226
245
  else
227
- nie! t, "Invalid verb #{verb}."
246
+ ae! t, "Invalid verb #{verb}."
228
247
  end
229
248
  end
230
249
  when :enumerate
@@ -232,11 +251,11 @@ module Subtle
232
251
  if Numeric === last
233
252
  (0...last.floor).to_a
234
253
  else
235
- nie! t, "`last` must be Numeric for type: :enumerate. You passed" +
254
+ ae! t, "`last` must be Numeric for type: :enumerate. You passed" +
236
255
  " in #{last.class}."
237
256
  end
238
257
  else
239
- nie! t, "Type #{t[:type].inspect} not implemented."
258
+ ae! t, "Type #{t[:type].inspect} not implemented."
240
259
  end
241
260
  else
242
261
  t
@@ -250,9 +269,5 @@ module Subtle
250
269
  def ae!(tree, message = "")
251
270
  raise ArgumentError.new message << "\n" << tree.to_yaml
252
271
  end
253
-
254
- def nie!(tree, message = "")
255
- raise NotImplementedError.new message << "\n" << tree.to_yaml
256
- end
257
272
  end
258
273
  end
@@ -1,9 +1,9 @@
1
1
  module Subtle
2
2
  class Parser < Parslet::Parser
3
3
  def initialize
4
- @monadic_verbs = %w{+ - * / % ^ | & ~}
5
- @monadic_adverbs = %w{//: /: /}
6
- @dyadic_verbs = %w{+ - * / % ^ | & !}
4
+ @monadic_verbs = %w{+ - * / % ^ | & ~}
5
+ @monadic_adverbs = %w{//: /: / \\}
6
+ @dyadic_verbs = %w{+ - * / % ^ | & ! = < >}
7
7
  @dyadic_adverbs = %w{/: \:}
8
8
  @function_adverbs = %w{/:}
9
9
  end
@@ -17,14 +17,13 @@ module Subtle
17
17
  rule(:float) { (minus.maybe >> digits >> str(".") >> digits).
18
18
  as(:float) >> spaces? }
19
19
  rule(:identifier) { (match["a-zA-Z"] >> match["a-zA-Z0-9_"].repeat).
20
- as(:identifier) }
21
- rule(:assignment) { (identifier >> spaces? >> str(":") >> spaces? >>
20
+ as(:identifier) >> spaces? }
21
+ rule(:assignment) { (identifier >> str(":") >> spaces? >>
22
22
  word.as(:right)).as(:assignment) >> spaces? }
23
- rule(:deassignment) { identifier.as(:deassignment) >> spaces? }
23
+ rule(:deassignment) { identifier.as(:deassignment) }
24
24
 
25
25
  rule(:function) do
26
- str("{") >> spaces? >> word.as(:function) >> spaces? >> str("}") >>
27
- spaces?
26
+ str("{") >> spaces? >> word.as(:function) >> str("}") >> spaces?
28
27
  end
29
28
 
30
29
  rule :function_adverb do
@@ -39,7 +38,7 @@ module Subtle
39
38
 
40
39
  rule(:variable_call) do
41
40
  (identifier >> spaces? >> function_adverb.maybe >>
42
- (assignment | dyad | noun).as(:arguments)).as(:variable_call)
41
+ (assignment | dyad | noun).as(:arguments)).as(:variable_call) >> spaces?
43
42
  end
44
43
 
45
44
  rule(:atom) do
@@ -48,7 +47,7 @@ module Subtle
48
47
  end
49
48
 
50
49
  rule :array do
51
- atom_or_array = (array | (atom >> spaces?).repeat.as(:array)) >> spaces?
50
+ atom_or_array = (array | (atom >> spaces?).repeat.as(:array))
52
51
 
53
52
  (str("(") >> spaces? >> atom_or_array >>
54
53
  (str(";") >> spaces? >> atom_or_array).repeat >>
@@ -57,7 +56,7 @@ module Subtle
57
56
  end
58
57
 
59
58
  rule :enumerate do
60
- (str("!") >> spaces? >> (word).as(:last)).as(:enumerate)
59
+ (str("!") >> spaces? >> (word).as(:last)).as(:enumerate) >> spaces?
61
60
  end
62
61
 
63
62
  rule(:noun) { enumerate | array | atom }
@@ -82,11 +81,12 @@ module Subtle
82
81
 
83
82
  rule :dyad do
84
83
  (noun.as(:left) >> dyadic_verb >> dyadic_adverb.maybe >>
85
- word.as(:right)).as(:dyad)
84
+ word.as(:right)).as(:dyad) >> spaces?
86
85
  end
87
86
 
88
87
  rule :monad do
89
- (monadic_verb >> monadic_adverb.maybe >> word.as(:right)).as(:monad)
88
+ (monadic_verb >> monadic_adverb.maybe >> word.as(:right)).as(:monad) >>
89
+ spaces?
90
90
  end
91
91
 
92
92
  rule :word do
@@ -1,3 +1,3 @@
1
1
  module Subtle
2
- VERSION = "0.0.3"
2
+ VERSION = "0.0.4"
3
3
  end
@@ -27,10 +27,13 @@ describe Subtle::Evaluator do
27
27
  describe "on Arrays" do
28
28
  e "1 12 & 7 8", [1, 8]
29
29
  e "1 12 | 7 8", [7, 12]
30
+ e "(1; 0 1 1 0 0; 1) & (1; 0 1 0 1 0; 1)", [1, [0, 1, 0, 0, 0], 1]
30
31
  end
31
32
 
32
33
  describe "on Atoms and Arrays" do
33
34
  e "1 | 7 0 & 8 2 | 8 & 6 7 & 1", [7, 1]
35
+ e "1 | (0; 1 0; 0 1 0; (1 0 1 2))", [1, [1, 1], [1, 1, 1], [1, 1, 1, 2]]
36
+ e "(0; 1 0; 0 1 0; (1 0 1 2)) | 1", [1, [1, 1], [1, 1, 1], [1, 1, 1, 2]]
34
37
  end
35
38
  end
36
39
 
@@ -42,6 +45,26 @@ describe Subtle::Evaluator do
42
45
  e "-2 ! (1 2)", [1, 2]
43
46
  e "-2 ! (2 3; 4 5; 8)", [[4, 5], 8, [2, 3]]
44
47
  end
48
+
49
+ describe "Comparison (`=`, `<`, `>`)" do
50
+ describe "on Atoms" do
51
+ e "1 > 3", 0
52
+ e "7 < 8", 1
53
+ e "7 = 7", 1
54
+ end
55
+
56
+ describe "on Arrays" do
57
+ e "1 12 < 7 8", [1, 0]
58
+ e "1 12 > 7 8", [0, 1]
59
+ e "1 12 1 = 7 8 1", [0, 0, 1]
60
+ end
61
+
62
+ describe "on Atoms and Arrays" do
63
+ e "1 2 > 3", [0, 0]
64
+ e "7 < 8 0", [1, 0]
65
+ e "7 = 7 7", [1, 1]
66
+ end
67
+ end
45
68
  end
46
69
 
47
70
  describe "Enumerate (`!`)" do
@@ -87,35 +110,80 @@ describe Subtle::Evaluator do
87
110
  describe "on Monads" do
88
111
  describe "Map over each right (`/:`)" do
89
112
  # Where (`&`), Not (`~`), Transpose (`+`) and Reverse (`|`)
113
+ e "&/: 2", [[0, 0]]
114
+ e "&/: 2 1", [[0, 0], [0]]
90
115
  e "&/: (0 2; 2 1)", [[1, 1], [0, 0, 1]]
116
+
117
+ e "~/: 1", [0]
118
+ e "~/: 0 1", [1, 0]
91
119
  e "~/: (0 1; 0 1)", [[1, 0], [1, 0]]
120
+
121
+ e "+/: 1", [1]
122
+ e "+/: 1 2 3", [1, 2, 3]
92
123
  e "+/: ((1 2; 3 4); (5 6; 7 8))", [[[1, 3], [2, 4]], [[5, 7], [6, 8]]]
124
+
125
+ e "|/: 1", [1]
126
+ e "|/: 1 2", [1, 2]
93
127
  e "|/: (0 1; 0 2)", [[1, 0], [2, 0]]
94
128
  end
95
129
 
96
130
  describe "Map over and fold (`//:`)" do
131
+ e "+//: 1", [1]
132
+ e "+//: 1 2", [1, 2]
133
+ e "+//: (1; 2; 3 4)", [1, 2, 7]
97
134
  e "+//: (2 4; 3 1)", [6, 4]
98
135
  e "+//:+(2 4; 3 1)", [5, 5]
99
136
  end
137
+
138
+ describe "Scan (`\`)" do
139
+ e "+\\2", [2]
140
+ e "-\\2", [2]
141
+ e "*\\2", [2]
142
+ e "/\\2", [2]
143
+ e "%\\2", [2]
144
+ e "^\\2", [2]
145
+
146
+ e "+\\1 2 3 4 5", [1, 3, 6, 10, 15]
147
+ e "-\\1 2 3 4 5", [1, -1, -4, -8, -13]
148
+ e "*\\1 2 3 4 5", [1, 2, 6, 24, 120]
149
+ e "/\\8 4 3 2", [8, 2, 0, 0]
150
+ e "%\\8 6 3 1", [8, 2, 2, 0]
151
+ e "^\\2 1 3 4", [2, 2, 8, 4096]
152
+
153
+ e "+\\(1 2; 3 4; 5)", [[1, 2], [4, 6], [9, 11]]
154
+ e "-\\(1 2; 3 4; 5)", [[1, 2], [-2, -2], [-7, -7]]
155
+ e "*\\(1 2; 3 4; 5)", [[1, 2], [3, 8], [15, 40]]
156
+ e "/\\(8 4; 3; 2)", [[8, 4], [2, 1], [1, 0]]
157
+ e "%\\(8 6; 3; 1)", [[8, 6], [2, 0], [0, 0]]
158
+ e "^\\(2 1; 3; 4)", [[2, 1], [8, 1], [4096, 1]]
159
+ end
100
160
  end
101
161
  end
102
162
 
103
163
  describe "Monads" do
104
164
  describe "Where (`&`)" do
165
+ e "&1", [0]
166
+ e "&2", [0, 0]
105
167
  e "&1 0 1", [0, 2]
106
168
  e "&1 3 2", [0, 1, 1, 1, 2, 2]
107
169
  end
108
170
 
109
171
  describe "Not (`~`)" do
172
+ e "~0", 1
173
+ e "~1", 0
174
+ e "~4", 0
110
175
  e "~1 0 -1 1 7 8 0 0", [0, 1, 0, 0, 0, 0, 1, 1]
111
176
  end
112
177
 
113
178
  describe "Transpose (`+`)" do
179
+ e "+0", 0
180
+ e "+1", 1
114
181
  e "+1 2 3", [1, 2, 3]
115
182
  e "+(1 2; 3 4; 5 6)", [[1, 3, 5], [2, 4, 6]]
116
183
  end
117
184
 
118
185
  describe "Reverse (`|`)" do
186
+ e "|1", 1
119
187
  e "|1 2", [2, 1]
120
188
  e "|(1 2; 3; (6 7; 8))", [[[6, 7], 8], 3, [1, 2]]
121
189
  end
@@ -136,6 +204,7 @@ describe Subtle::Evaluator do
136
204
  e "2 ^ ((5 6; 0 1);1 2; 3 4)", [[[32, 64], [1, 2]], [2, 4], [8, 16]]
137
205
  e "(;1 2; 3 4) - 1", [[], [0, 1], [2, 3]]
138
206
  e "((5 6; 0 1);1 2; 3 4) ^ 2", [[[25, 36], [0, 1]], [1, 4], [9, 16]]
207
+ e "(1; 2 3; 4 5) + (1; 2 3; 4 5)", [2, [4, 6], [8, 10]]
139
208
  end
140
209
 
141
210
  describe "on 1D/2D/3D Arrays with 2D/3D Arrays" do
@@ -216,5 +285,9 @@ describe Subtle::Evaluator do
216
285
  ae! "1 2 ! 2 3"
217
286
  ae! "2 ! 1"
218
287
  end
288
+
289
+ describe "on Scan adverb" do
290
+ ae! "+\\(1 2; 3; 4 5 6)"
291
+ end
219
292
  end
220
293
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: subtle-lang
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.0.3
4
+ version: 0.0.4
5
5
  prerelease:
6
6
  platform: ruby
7
7
  authors:
@@ -9,7 +9,7 @@ authors:
9
9
  autorequire:
10
10
  bindir: bin
11
11
  cert_chain: []
12
- date: 2012-12-11 00:00:00.000000000 Z
12
+ date: 2012-12-15 00:00:00.000000000 Z
13
13
  dependencies:
14
14
  - !ruby/object:Gem::Dependency
15
15
  name: parslet