delorean_lang 0.3.24 → 0.3.25

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: c3b6cbfa5893e3c1fe6e5e8c72808ffb426a9b6e
4
- data.tar.gz: 277eacdb6725be1e1c06c9efe1926b62437ac19c
3
+ metadata.gz: 7a874caf5f4ff132d1358f1200e1bdbe8922d968
4
+ data.tar.gz: 2953cf29508714e114dc2f35b1cec643133fdfdb
5
5
  SHA512:
6
- metadata.gz: efee348e65cd6d9bd2ca26d25815e840122d40a45811aa4e55a73264506b3f57ea079dac101b5c8a93bdee073d7d794311e5d89d1fef39d6a22bf49dc776caee
7
- data.tar.gz: 2743e5e5b12e2165c60546dffcd808e189a6c5acd58efd0b07efba1156a25a692c7d090ebcbcb3c61018efa22cdd3a5991658567c4324f8810a5dd96c4e3ae75
6
+ metadata.gz: fcfc877b4bae858ce9988d371502ea9625b02e93b8046b7861c3f6f505b8b0f57a30878482b5d92bf3ef18935241383f9fddb3c61a243fec328ce0f6a483aef0
7
+ data.tar.gz: e2cfcda4485deca3b94169c26dfd5281778a1850b426fe08d42ad1c8edf3048f0c4452b2e2f262801aee9cde9a8ede2d63b56c99a5b8324bb0a141cf55a36d18
@@ -4,8 +4,9 @@ require 'bigdecimal'
4
4
 
5
5
  module Delorean
6
6
 
7
- # FIXME: add string.gsub; Also, should be able to index regex
8
- # matches. Need string.length.
7
+ DT_TYPES = [Date, Time, ActiveSupport::TimeWithZone]
8
+ NUM_OR_STR = [Numeric, String]
9
+ NUM_OR_NIL = [nil, Fixnum]
9
10
 
10
11
  # FIXME: the whitelist is quite hacky. It's currently difficult to
11
12
  # override it. A user will likely want to directly modify this
@@ -13,12 +14,12 @@ module Delorean
13
14
  # rethought.
14
15
  RUBY_WHITELIST = {
15
16
  attributes: [ActiveRecord::Base],
16
- between?: [[Numeric, String],[Numeric, String],[Numeric, String]],
17
+ between?: [NUM_OR_STR, NUM_OR_STR, NUM_OR_STR],
17
18
  between: "between?",
18
19
  compact: [Array],
19
20
  to_set: [Array],
20
- flatten: [Array, [Fixnum, nil]],
21
- length: [Enumerable],
21
+ flatten: [Array, NUM_OR_NIL],
22
+ length: [[String, Enumerable]],
22
23
  max: [Array],
23
24
  member: "member?",
24
25
  member?: [Enumerable, [Object]],
@@ -33,11 +34,11 @@ module Delorean
33
34
  sum: [Array],
34
35
  transpose: [Array],
35
36
  join: [Array, String],
36
- zip: [Array, [Array, Array, Array]],
37
+ zip: [Array, Array, [Array, nil], [Array, nil]],
37
38
  index: [Array, [Object]],
38
39
  product: [Array, Array],
39
- first: [[ActiveRecord::Relation, Enumerable], [nil, Fixnum]],
40
- last: [[ActiveRecord::Relation, Enumerable], [nil, Fixnum]],
40
+ first: [[ActiveRecord::Relation, Enumerable], NUM_OR_NIL],
41
+ last: [[ActiveRecord::Relation, Enumerable], NUM_OR_NIL],
41
42
  intersection: [Set, Enumerable],
42
43
  union: [Set, Enumerable],
43
44
 
@@ -45,39 +46,30 @@ module Delorean
45
46
  values: [Hash],
46
47
  upcase: [String],
47
48
  downcase: [String],
48
- match: [String, [String], [nil, Fixnum]],
49
-
50
- iso8601: [[Date, Time, ActiveSupport::TimeWithZone]],
51
- hour: [[Date, Time, ActiveSupport::TimeWithZone]],
52
- min: [[Date, Time, ActiveSupport::TimeWithZone, Array]],
53
- sec: [[Date, Time, ActiveSupport::TimeWithZone]],
54
- to_date: [[Date, Time, ActiveSupport::TimeWithZone, String]],
55
-
56
- month: [[Date, Time, ActiveSupport::TimeWithZone]],
57
- day: [[Date, Time, ActiveSupport::TimeWithZone]],
58
- year: [[Date, Time, ActiveSupport::TimeWithZone]],
59
-
60
- next_month: [[Date, Time, ActiveSupport::TimeWithZone],
61
- [nil, Fixnum],
62
- ],
63
- prev_month: [[Date, Time, ActiveSupport::TimeWithZone],
64
- [nil, Fixnum],
65
- ],
66
-
67
- beginning_of_month: [[Date, Time, ActiveSupport::TimeWithZone]],
68
-
69
- end_of_month: [[Date, Time, ActiveSupport::TimeWithZone]],
70
-
71
- next_day: [[Date, Time, ActiveSupport::TimeWithZone],
72
- [nil, Fixnum],
73
- ],
74
- prev_day: [[Date, Time, ActiveSupport::TimeWithZone],
75
- [nil, Fixnum],
76
- ],
77
-
78
- to_i: [[Numeric, String]],
79
- to_f: [[Numeric, String]],
80
- to_d: [[Numeric, String]],
49
+ match: [String, [String], NUM_OR_NIL],
50
+
51
+ iso8601: [DT_TYPES],
52
+ hour: [DT_TYPES],
53
+ min: [DT_TYPES+[Array]],
54
+ sec: [DT_TYPES],
55
+ to_date: [DT_TYPES+[String]],
56
+
57
+ month: [DT_TYPES],
58
+ day: [DT_TYPES],
59
+ year: [DT_TYPES],
60
+
61
+ next_month: [DT_TYPES, NUM_OR_NIL],
62
+ prev_month: [DT_TYPES, NUM_OR_NIL],
63
+
64
+ beginning_of_month: [DT_TYPES],
65
+ end_of_month: [DT_TYPES],
66
+
67
+ next_day: [DT_TYPES, NUM_OR_NIL],
68
+ prev_day: [DT_TYPES, NUM_OR_NIL],
69
+
70
+ to_i: [NUM_OR_STR],
71
+ to_f: [NUM_OR_STR],
72
+ to_d: [NUM_OR_STR],
81
73
  to_s: [Object],
82
74
  to_a: [Object],
83
75
  to_json: [Object],
@@ -97,15 +89,14 @@ module Delorean
97
89
  end
98
90
 
99
91
  def /(args)
100
- raise "non-array/string arg to /" unless
101
- args.is_a?(Array) || args.is_a?(String)
102
-
103
92
  begin
104
93
  case args
105
94
  when Array
106
95
  engine.eval_to_hash(node, args, params.clone)
107
96
  when String
108
97
  engine.evaluate(node, args, params.clone)
98
+ else
99
+ raise "non-array/string arg to /"
109
100
  end
110
101
  rescue => exc
111
102
  Delorean::Engine.grok_runtime_exception(exc)
@@ -134,30 +125,25 @@ module Delorean
134
125
 
135
126
  class BaseClass
136
127
  def self._get_attr(obj, attr, _e)
137
- # FIXME: even Javascript which is superpermissive raises an
138
- # exception on null getattr.
139
- return nil if obj.nil?
140
-
141
128
  # NOTE: should keep this function consistent with _index
142
-
143
- if obj.kind_of? ActiveRecord::Base
144
- klass = obj.class
145
-
146
- return obj.read_attribute(attr) if
147
- klass.attribute_names.member? attr
148
-
149
- return obj.send(attr.to_sym) if
150
- klass.reflect_on_all_associations.map(&:name).member? attr.to_sym
151
- elsif obj.instance_of?(NodeCall)
129
+ case obj
130
+ when nil
131
+ # FIXME: even Javascript which is superpermissive raises an
132
+ # exception on null getattr.
133
+ return nil
134
+ when ActiveRecord::Base
135
+ return obj.read_attribute(attr) if obj.has_attribute?(attr)
136
+ return obj.send(attr.to_sym) if obj.class.reflections[attr]
137
+ when NodeCall
152
138
  return obj.evaluate(attr)
153
- elsif obj.instance_of?(Hash)
139
+ when Hash
154
140
  # FIXME: this implementation doesn't handle something like
155
141
  # {}.length. i.e. length is a whitelisted function, but not
156
142
  # an attr. This implementation returns nil instead of 0.
157
143
  return obj[attr] if obj.member?(attr)
158
144
  return attr.is_a?(String) ? obj[attr.to_sym] : nil
159
- elsif obj.instance_of?(Class) && (obj < BaseClass)
160
- return obj.send((attr + POST).to_sym, _e)
145
+ when Class
146
+ return obj.send((attr + POST).to_sym, _e) if obj < BaseClass
161
147
  end
162
148
 
163
149
  begin
@@ -171,18 +157,19 @@ module Delorean
171
157
  ######################################################################
172
158
 
173
159
  def self._index(obj, args, _e)
174
- return nil if obj.nil?
175
-
176
160
  # NOTE: should keep this function consistent with _get_attr
177
-
178
- if obj.instance_of?(Hash) || obj.kind_of?(ActiveRecord::Base) ||
179
- obj.instance_of?(NodeCall) || obj.instance_of?(Class)
161
+ case obj
162
+ when nil
163
+ # FIXME: even Javascript which is superpermissive raises an
164
+ # exception on null getattr.
165
+ return nil
166
+ when Hash, ActiveRecord::Base, NodeCall, Class
180
167
  raise InvalidIndex unless args.length == 1
181
168
  _get_attr(obj, args[0], _e)
182
- elsif obj.instance_of?(Array) || obj.instance_of?(String)
183
- raise InvalidIndex unless args.length <= 2
184
- raise InvalidIndex unless
185
- args[0].is_a?(Fixnum) && (!args[1] || args[1].is_a?(Fixnum))
169
+ when Array, String, MatchData
170
+ raise InvalidIndex unless args.length <= 2 &&
171
+ args[0].is_a?(Fixnum) &&
172
+ (args[1].nil? || args[1].is_a?(Fixnum))
186
173
  obj[*args]
187
174
  else
188
175
  raise InvalidIndex
@@ -234,11 +221,9 @@ module Delorean
234
221
  return obj.send(msg, *args)
235
222
  end
236
223
 
237
- if obj.class.include?(Delorean::Model)
238
- sig = obj.class.delorean_instance_methods[msg]
239
- end
240
-
241
- sig = RUBY_WHITELIST[msg] unless sig
224
+ cls = obj.class
225
+ sig = (cls < Delorean::Model && cls.delorean_instance_methods[msg]) ||
226
+ RUBY_WHITELIST[msg]
242
227
 
243
228
  raise "no such method #{method}" unless sig
244
229
 
@@ -249,19 +234,15 @@ module Delorean
249
234
 
250
235
  arglist = [obj] + args
251
236
 
252
- sig.each_with_index { |s, i|
237
+ sig.each_with_index do |s, i|
253
238
  s = [s] unless s.is_a?(Array)
254
239
 
255
- ok, ai = false, arglist[i]
240
+ ai = arglist[i]
256
241
 
257
- s.each { |sc|
258
- if (sc.nil? && i>=arglist.length) || (sc && ai.class <= sc)
259
- ok = true
260
- break
261
- end
262
- }
263
- raise "bad arg #{i}, method #{method}: #{ai}/#{ai.class} #{s}" if !ok
264
- }
242
+ raise "bad arg #{i}, method #{method}: #{ai}/#{ai.class} #{s}" unless
243
+ (s.member?(nil) && i>=arglist.length) ||
244
+ s.detect {|sc| sc && ai.class <= sc}
245
+ end
265
246
 
266
247
  res = obj.send(msg, *args)
267
248
  # FIXME: can't freeze AR relations since then we can't chain
@@ -2234,142 +2234,154 @@ module Delorean
2234
2234
  r6 = SyntaxNode.new(input, (index-1)...index) if r6 == true
2235
2235
  r0 = r6
2236
2236
  else
2237
- if (match_len = has_terminal?('>', false, index))
2238
- r7 = true
2237
+ if (match_len = has_terminal?('**', false, index))
2238
+ r7 = instantiate_node(SyntaxNode,input, index...(index + match_len))
2239
2239
  @index += match_len
2240
2240
  else
2241
- terminal_parse_failure('\'>\'')
2241
+ terminal_parse_failure('\'**\'')
2242
2242
  r7 = nil
2243
2243
  end
2244
2244
  if r7
2245
2245
  r7 = SyntaxNode.new(input, (index-1)...index) if r7 == true
2246
2246
  r0 = r7
2247
2247
  else
2248
- if (match_len = has_terminal?('<', false, index))
2248
+ if (match_len = has_terminal?('>', false, index))
2249
2249
  r8 = true
2250
2250
  @index += match_len
2251
2251
  else
2252
- terminal_parse_failure('\'<\'')
2252
+ terminal_parse_failure('\'>\'')
2253
2253
  r8 = nil
2254
2254
  end
2255
2255
  if r8
2256
2256
  r8 = SyntaxNode.new(input, (index-1)...index) if r8 == true
2257
2257
  r0 = r8
2258
2258
  else
2259
- if (match_len = has_terminal?('+', false, index))
2259
+ if (match_len = has_terminal?('<', false, index))
2260
2260
  r9 = true
2261
2261
  @index += match_len
2262
2262
  else
2263
- terminal_parse_failure('\'+\'')
2263
+ terminal_parse_failure('\'<\'')
2264
2264
  r9 = nil
2265
2265
  end
2266
2266
  if r9
2267
2267
  r9 = SyntaxNode.new(input, (index-1)...index) if r9 == true
2268
2268
  r0 = r9
2269
2269
  else
2270
- if (match_len = has_terminal?('-', false, index))
2270
+ if (match_len = has_terminal?('+', false, index))
2271
2271
  r10 = true
2272
2272
  @index += match_len
2273
2273
  else
2274
- terminal_parse_failure('\'-\'')
2274
+ terminal_parse_failure('\'+\'')
2275
2275
  r10 = nil
2276
2276
  end
2277
2277
  if r10
2278
2278
  r10 = SyntaxNode.new(input, (index-1)...index) if r10 == true
2279
2279
  r0 = r10
2280
2280
  else
2281
- if (match_len = has_terminal?('*', false, index))
2281
+ if (match_len = has_terminal?('-', false, index))
2282
2282
  r11 = true
2283
2283
  @index += match_len
2284
2284
  else
2285
- terminal_parse_failure('\'*\'')
2285
+ terminal_parse_failure('\'-\'')
2286
2286
  r11 = nil
2287
2287
  end
2288
2288
  if r11
2289
2289
  r11 = SyntaxNode.new(input, (index-1)...index) if r11 == true
2290
2290
  r0 = r11
2291
2291
  else
2292
- if (match_len = has_terminal?('/', false, index))
2292
+ if (match_len = has_terminal?('*', false, index))
2293
2293
  r12 = true
2294
2294
  @index += match_len
2295
2295
  else
2296
- terminal_parse_failure('\'/\'')
2296
+ terminal_parse_failure('\'*\'')
2297
2297
  r12 = nil
2298
2298
  end
2299
2299
  if r12
2300
2300
  r12 = SyntaxNode.new(input, (index-1)...index) if r12 == true
2301
2301
  r0 = r12
2302
2302
  else
2303
- if (match_len = has_terminal?('%', false, index))
2303
+ if (match_len = has_terminal?('/', false, index))
2304
2304
  r13 = true
2305
2305
  @index += match_len
2306
2306
  else
2307
- terminal_parse_failure('\'%\'')
2307
+ terminal_parse_failure('\'/\'')
2308
2308
  r13 = nil
2309
2309
  end
2310
2310
  if r13
2311
2311
  r13 = SyntaxNode.new(input, (index-1)...index) if r13 == true
2312
2312
  r0 = r13
2313
2313
  else
2314
- if (match_len = has_terminal?('&', false, index))
2314
+ if (match_len = has_terminal?('%', false, index))
2315
2315
  r14 = true
2316
2316
  @index += match_len
2317
2317
  else
2318
- terminal_parse_failure('\'&\'')
2318
+ terminal_parse_failure('\'%\'')
2319
2319
  r14 = nil
2320
2320
  end
2321
2321
  if r14
2322
2322
  r14 = SyntaxNode.new(input, (index-1)...index) if r14 == true
2323
2323
  r0 = r14
2324
2324
  else
2325
- if (match_len = has_terminal?('^', false, index))
2325
+ if (match_len = has_terminal?('&', false, index))
2326
2326
  r15 = true
2327
2327
  @index += match_len
2328
2328
  else
2329
- terminal_parse_failure('\'^\'')
2329
+ terminal_parse_failure('\'&\'')
2330
2330
  r15 = nil
2331
2331
  end
2332
2332
  if r15
2333
2333
  r15 = SyntaxNode.new(input, (index-1)...index) if r15 == true
2334
2334
  r0 = r15
2335
2335
  else
2336
- if (match_len = has_terminal?('|', false, index))
2336
+ if (match_len = has_terminal?('^', false, index))
2337
2337
  r16 = true
2338
2338
  @index += match_len
2339
2339
  else
2340
- terminal_parse_failure('\'|\'')
2340
+ terminal_parse_failure('\'^\'')
2341
2341
  r16 = nil
2342
2342
  end
2343
2343
  if r16
2344
2344
  r16 = SyntaxNode.new(input, (index-1)...index) if r16 == true
2345
2345
  r0 = r16
2346
2346
  else
2347
- i17, s17 = index, []
2348
- if (match_len = has_terminal?('in', false, index))
2349
- r18 = instantiate_node(SyntaxNode,input, index...(index + match_len))
2347
+ if (match_len = has_terminal?('|', false, index))
2348
+ r17 = true
2350
2349
  @index += match_len
2351
2350
  else
2352
- terminal_parse_failure('\'in\'')
2353
- r18 = nil
2354
- end
2355
- s17 << r18
2356
- if r18
2357
- r19 = _nt_sp
2358
- s17 << r19
2359
- end
2360
- if s17.last
2361
- r17 = instantiate_node(SyntaxNode,input, i17...index, s17)
2362
- r17.extend(BinaryOp0)
2363
- else
2364
- @index = i17
2351
+ terminal_parse_failure('\'|\'')
2365
2352
  r17 = nil
2366
2353
  end
2367
2354
  if r17
2368
2355
  r17 = SyntaxNode.new(input, (index-1)...index) if r17 == true
2369
2356
  r0 = r17
2370
2357
  else
2371
- @index = i0
2372
- r0 = nil
2358
+ i18, s18 = index, []
2359
+ if (match_len = has_terminal?('in', false, index))
2360
+ r19 = instantiate_node(SyntaxNode,input, index...(index + match_len))
2361
+ @index += match_len
2362
+ else
2363
+ terminal_parse_failure('\'in\'')
2364
+ r19 = nil
2365
+ end
2366
+ s18 << r19
2367
+ if r19
2368
+ r20 = _nt_sp
2369
+ s18 << r20
2370
+ end
2371
+ if s18.last
2372
+ r18 = instantiate_node(SyntaxNode,input, i18...index, s18)
2373
+ r18.extend(BinaryOp0)
2374
+ else
2375
+ @index = i18
2376
+ r18 = nil
2377
+ end
2378
+ if r18
2379
+ r18 = SyntaxNode.new(input, (index-1)...index) if r18 == true
2380
+ r0 = r18
2381
+ else
2382
+ @index = i0
2383
+ r0 = nil
2384
+ end
2373
2385
  end
2374
2386
  end
2375
2387
  end
@@ -3423,7 +3435,7 @@ module Delorean
3423
3435
  r7 = nil
3424
3436
  terminal_parse_failure('\'"\'', true)
3425
3437
  else
3426
- terminal_failures.pop
3438
+ @terminal_failures.pop
3427
3439
  @index = i7
3428
3440
  r7 = instantiate_node(SyntaxNode,input, index...index)
3429
3441
  end
@@ -98,7 +98,7 @@ grammar Delorean
98
98
  # NOTE: some operations such as << have side-effects (e.g. on
99
99
  # Arrays). So, be cautious about which opertaions are added.
100
100
  rule binary_op
101
- '==' / '!=' / '>=' / '<=' / '&&' / '||' /
101
+ '==' / '!=' / '>=' / '<=' / '&&' / '||' / '**' /
102
102
  '>' / '<' / '+' / '-' / '*' / '/' / '%' /
103
103
  '&' / '^' / '|' / 'in' sp
104
104
  end
@@ -1,3 +1,3 @@
1
1
  module Delorean
2
- VERSION = "0.3.24"
2
+ VERSION = "0.3.25"
3
3
  end
@@ -22,12 +22,15 @@ describe "Delorean" do
22
22
  " x = -(a * 2)",
23
23
  " b = -(a + 1)",
24
24
  " c = -a + 1",
25
+ " d = a ** 3 - 10*0.2",
25
26
  )
26
27
 
27
28
  engine.evaluate_attrs("A", ["a"]).should == [123]
28
29
 
29
30
  r = engine.evaluate_attrs("A", ["x", "b"])
30
31
  r.should == [-246, -124]
32
+
33
+ expect(engine.evaluate("A", "d")).to eq 1860865.0
31
34
  end
32
35
 
33
36
  it "proper unary expression evaluation" do
@@ -118,6 +118,21 @@ describe "Delorean" do
118
118
  engine.evaluate("A", "b").should == x.flatten + x.flatten(1)
119
119
  end
120
120
 
121
+ it "should handle ZIP" do
122
+ a = [1, 2]
123
+ b = [4, 5, 6]
124
+ c = [7, 8]
125
+
126
+ engine.parse defn("A:",
127
+ " a = #{a}",
128
+ " b = #{b}",
129
+ " c = #{c}",
130
+ " d = a.zip(b) + a.zip(b, c)",
131
+ )
132
+
133
+ expect(engine.evaluate("A", "d")).to eq a.zip(b) + a.zip(b, c)
134
+ end
135
+
121
136
  it "should handle ERR" do
122
137
  engine.parse defn("A:",
123
138
  " a = ERR('hello')",
@@ -147,6 +162,7 @@ describe "Delorean" do
147
162
  " l = a.member(5)",
148
163
  " m = [a.member(5), a.member(55)]",
149
164
  " n = {'a':1, 'b':2, 'c':3}.length()",
165
+ " o = 'hello'.length",
150
166
  )
151
167
 
152
168
  engine.evaluate("A", "c").should == x.flatten(1)
@@ -158,6 +174,7 @@ describe "Delorean" do
158
174
  engine.evaluate("A", "gg").should == x.length
159
175
  engine.evaluate("A", "m").should == [x.member?(5), x.member?(55)]
160
176
  engine.evaluate("A", "n").should == 3
177
+ engine.evaluate("A", "o").should == 5
161
178
  end
162
179
 
163
180
  it "should be able to call function on hash" do
@@ -206,4 +223,13 @@ describe "Delorean" do
206
223
  expect(engine.evaluate("A", "b")).to eq([false, true])
207
224
  end
208
225
 
226
+ it "should handle MATCH" do
227
+ engine.parse defn("A:",
228
+ " a = 'this is a test'.match('(.*)( is )(.*)')",
229
+ " b = [a[0], a[1], a[2], a[3], a[4]]",
230
+ )
231
+
232
+ expect(engine.evaluate("A", "b")).
233
+ to eq(["this is a test", "this", " is ", "a test", nil])
234
+ end
209
235
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: delorean_lang
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.3.24
4
+ version: 0.3.25
5
5
  platform: ruby
6
6
  authors:
7
7
  - Arman Bostani
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2017-07-10 00:00:00.000000000 Z
11
+ date: 2017-08-08 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: treetop