subtle-lang 0.0.3 → 0.0.4

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