delorean_lang 0.3.2 → 0.3.3
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +8 -8
- data/lib/delorean/base.rb +71 -64
- data/lib/delorean/delorean.rb +173 -167
- data/lib/delorean/delorean.treetop +13 -13
- data/lib/delorean/engine.rb +8 -1
- data/lib/delorean/nodes.rb +40 -18
- data/lib/delorean/version.rb +1 -1
- data/spec/eval_spec.rb +67 -6
- data/spec/parse_spec.rb +34 -10
- data/spec/spec_helper.rb +10 -0
- metadata +2 -2
checksums.yaml
CHANGED
@@ -1,15 +1,15 @@
|
|
1
1
|
---
|
2
2
|
!binary "U0hBMQ==":
|
3
3
|
metadata.gz: !binary |-
|
4
|
-
|
4
|
+
YWFmZDRkMDU1OTkwMWE1NjVmN2NjYTQ2Yzg3MDZiYjQwMTFkYTM2OQ==
|
5
5
|
data.tar.gz: !binary |-
|
6
|
-
|
6
|
+
NTY5YmVjNmY3NDgwNDUzOTU0NjIxODhlZmJhZTdmNzVmN2FiNDMyMQ==
|
7
7
|
SHA512:
|
8
8
|
metadata.gz: !binary |-
|
9
|
-
|
10
|
-
|
11
|
-
|
9
|
+
YmVjYWJlMmRmYzFjNTZkOThjYTg4YzM1MzMxODFmNThjNTNkOWZmNTllNTEy
|
10
|
+
MDJmNWUyZjY5ZjQxZWRlNmJkZmQyZDU4MDI2OTZkMzExMDFkYmMyOTY0MmQ2
|
11
|
+
Mzc5ZTQyZjdlODM0OWU0OWE3ZTkyMjQyZWQ5NzgwMTBjYmEzNmE=
|
12
12
|
data.tar.gz: !binary |-
|
13
|
-
|
14
|
-
|
15
|
-
|
13
|
+
YmIzN2IxNGU0OTQ2MGVmYzVjMTUzZWJiMjRjM2VhYmQyNGNiNmEzNDk5YzNm
|
14
|
+
NmI2ZDU1M2JlZmY2YmM4ZDllOTIzNzZhNGNmM2FlOTNiNTBmODk4OTQyY2Y1
|
15
|
+
ODBlZDJmYWNkOGFkNWYwM2U2ZjQ2MjdhODNhNGIzNTU4ZmFiYzE=
|
data/lib/delorean/base.rb
CHANGED
@@ -7,62 +7,65 @@ module Delorean
|
|
7
7
|
# hash. The whole whitelist mechanism should be eventually
|
8
8
|
# rethought.
|
9
9
|
RUBY_WHITELIST = {
|
10
|
-
compact:
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
member
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
|
42
|
-
|
43
|
-
|
44
|
-
|
45
|
-
|
46
|
-
|
47
|
-
|
10
|
+
compact: [Array],
|
11
|
+
to_set: [Array],
|
12
|
+
flatten: [Array, [Fixnum, nil]],
|
13
|
+
length: [[Array, String]],
|
14
|
+
max: [Array],
|
15
|
+
member: "member?",
|
16
|
+
member?: [Array, [Fixnum, String]],
|
17
|
+
reverse: [Array],
|
18
|
+
slice: [Array, Fixnum, Fixnum],
|
19
|
+
sort: [Array],
|
20
|
+
split: [String, String],
|
21
|
+
uniq: [Array],
|
22
|
+
sum: [Array],
|
23
|
+
zip: [Array, [Array, Array, Array]],
|
24
|
+
index: [Array, [Integer, Numeric, String, Array, Fixnum]],
|
25
|
+
product: [Array, Array],
|
26
|
+
first: [Enumerable, [nil, Fixnum]],
|
27
|
+
intersection: [Set, Enumerable],
|
28
|
+
union: [Set, Enumerable],
|
29
|
+
|
30
|
+
keys: [Hash],
|
31
|
+
values: [Hash],
|
32
|
+
upcase: [String],
|
33
|
+
downcase: [String],
|
34
|
+
match: [String, [String], [nil, Fixnum]],
|
35
|
+
|
36
|
+
hour: [[Date, Time, ActiveSupport::TimeWithZone]],
|
37
|
+
min: [[Date, Time, ActiveSupport::TimeWithZone, Array]],
|
38
|
+
sec: [[Date, Time, ActiveSupport::TimeWithZone]],
|
39
|
+
to_date: [[Date, Time, ActiveSupport::TimeWithZone]],
|
40
|
+
|
41
|
+
month: [[Date, Time, ActiveSupport::TimeWithZone]],
|
42
|
+
day: [[Date, Time, ActiveSupport::TimeWithZone]],
|
43
|
+
year: [[Date, Time, ActiveSupport::TimeWithZone]],
|
44
|
+
|
45
|
+
next_month: [[Date, Time, ActiveSupport::TimeWithZone],
|
46
|
+
[nil, Fixnum],
|
47
|
+
],
|
48
|
+
prev_month: [[Date, Time, ActiveSupport::TimeWithZone],
|
49
|
+
[nil, Fixnum],
|
50
|
+
],
|
48
51
|
|
49
52
|
beginning_of_month: [[Date, Time, ActiveSupport::TimeWithZone]],
|
50
53
|
|
51
54
|
end_of_month: [[Date, Time, ActiveSupport::TimeWithZone]],
|
52
55
|
|
53
|
-
next_day:
|
54
|
-
|
55
|
-
|
56
|
-
prev_day:
|
57
|
-
|
58
|
-
|
59
|
-
|
60
|
-
to_i:
|
61
|
-
to_f:
|
62
|
-
to_d:
|
63
|
-
to_s:
|
64
|
-
abs:
|
65
|
-
round:
|
56
|
+
next_day: [[Date, Time, ActiveSupport::TimeWithZone],
|
57
|
+
[nil, Fixnum],
|
58
|
+
],
|
59
|
+
prev_day: [[Date, Time, ActiveSupport::TimeWithZone],
|
60
|
+
[nil, Fixnum],
|
61
|
+
],
|
62
|
+
|
63
|
+
to_i: [[Numeric, String]],
|
64
|
+
to_f: [[Numeric, String]],
|
65
|
+
to_d: [[Numeric, String]],
|
66
|
+
to_s: [Object],
|
67
|
+
abs: [Numeric],
|
68
|
+
round: [Numeric, [nil, Integer]],
|
66
69
|
}
|
67
70
|
|
68
71
|
module BaseModule
|
@@ -110,14 +113,6 @@ module Delorean
|
|
110
113
|
|
111
114
|
return obj.send(attr.to_sym) if
|
112
115
|
klass.reflect_on_all_associations.map(&:name).member? attr.to_sym
|
113
|
-
|
114
|
-
# FIXME: should call _instance_call for other types as well.
|
115
|
-
# Too lazy to implement this now.
|
116
|
-
begin
|
117
|
-
return _instance_call(obj, attr, [])
|
118
|
-
rescue
|
119
|
-
raise InvalidGetAttribute, "ActiveRecord lookup '#{attr}' on #{obj}"
|
120
|
-
end
|
121
116
|
elsif obj.instance_of?(NodeCall)
|
122
117
|
return obj.evaluate(attr)
|
123
118
|
elsif obj.instance_of?(Hash)
|
@@ -126,8 +121,13 @@ module Delorean
|
|
126
121
|
elsif obj.instance_of?(Class) && (obj < BaseClass)
|
127
122
|
return obj.send((attr + POST).to_sym, _e)
|
128
123
|
end
|
129
|
-
|
130
|
-
|
124
|
+
|
125
|
+
begin
|
126
|
+
return _instance_call(obj, attr, [], _e)
|
127
|
+
rescue
|
128
|
+
raise InvalidGetAttribute,
|
129
|
+
"bad attribute lookup '#{attr}' on <#{obj.class}> #{obj}"
|
130
|
+
end
|
131
131
|
end
|
132
132
|
|
133
133
|
######################################################################
|
@@ -156,7 +156,7 @@ module Delorean
|
|
156
156
|
def self._sanitize_hash(_e)
|
157
157
|
_e.each_with_object({}) do
|
158
158
|
|(k,v), h|
|
159
|
-
h[k] = v if k =~ /\A[a-z][A-Za-z0-9_]*\z/
|
159
|
+
h[k] = v if k.is_a?(Integer) || k =~ /\A[a-z][A-Za-z0-9_]*\z/
|
160
160
|
end
|
161
161
|
end
|
162
162
|
|
@@ -182,19 +182,26 @@ module Delorean
|
|
182
182
|
|
183
183
|
######################################################################
|
184
184
|
|
185
|
-
def self._instance_call(obj, method, args)
|
185
|
+
def self._instance_call(obj, method, args, _e)
|
186
186
|
begin
|
187
187
|
msg = method.to_sym
|
188
188
|
rescue NoMethodError
|
189
189
|
raise "bad method #{method}"
|
190
190
|
end
|
191
191
|
|
192
|
+
# FIXME: this is pretty hacky -- should probably merge
|
193
|
+
# RUBY_WHITELIST and SIG mechanisms.
|
194
|
+
if obj.is_a?(Class)
|
195
|
+
_e[:_engine].parse_check_call_fn(method, args.count, obj)
|
196
|
+
return obj.send(msg, *args)
|
197
|
+
end
|
198
|
+
|
192
199
|
sig = RUBY_WHITELIST[msg]
|
193
200
|
|
194
201
|
raise "no such method #{method}" unless sig
|
195
202
|
|
196
203
|
# if sig is a string, then method mapped to another name
|
197
|
-
return _instance_call(obj, sig, args) if sig.is_a? String
|
204
|
+
return _instance_call(obj, sig, args, _e) if sig.is_a? String
|
198
205
|
|
199
206
|
raise "too many args to #{method}" if args.length>(sig.length-1)
|
200
207
|
|
data/lib/delorean/delorean.rb
CHANGED
@@ -1133,7 +1133,19 @@ module Delorean
|
|
1133
1133
|
end
|
1134
1134
|
s31 << r33
|
1135
1135
|
if r33
|
1136
|
-
|
1136
|
+
i35 = index
|
1137
|
+
r36 = _nt_identifier
|
1138
|
+
if r36
|
1139
|
+
r35 = r36
|
1140
|
+
else
|
1141
|
+
r37 = _nt_integer
|
1142
|
+
if r37
|
1143
|
+
r35 = r37
|
1144
|
+
else
|
1145
|
+
@index = i35
|
1146
|
+
r35 = nil
|
1147
|
+
end
|
1148
|
+
end
|
1137
1149
|
s31 << r35
|
1138
1150
|
end
|
1139
1151
|
end
|
@@ -2288,136 +2300,141 @@ module Delorean
|
|
2288
2300
|
end
|
2289
2301
|
|
2290
2302
|
i0 = index
|
2291
|
-
r1 =
|
2303
|
+
r1 = _nt_decimal
|
2292
2304
|
if r1
|
2293
2305
|
r0 = r1
|
2294
2306
|
else
|
2295
|
-
r2 =
|
2307
|
+
r2 = _nt_integer
|
2296
2308
|
if r2
|
2297
2309
|
r0 = r2
|
2298
2310
|
else
|
2299
|
-
r3 =
|
2311
|
+
r3 = _nt_string
|
2300
2312
|
if r3
|
2301
2313
|
r0 = r3
|
2302
2314
|
else
|
2303
|
-
r4 =
|
2315
|
+
r4 = _nt_boolean
|
2304
2316
|
if r4
|
2305
2317
|
r0 = r4
|
2306
2318
|
else
|
2307
|
-
r5 =
|
2319
|
+
r5 = _nt_nil_val
|
2308
2320
|
if r5
|
2309
2321
|
r0 = r5
|
2310
2322
|
else
|
2311
|
-
r6 =
|
2323
|
+
r6 = _nt_identifier
|
2312
2324
|
if r6
|
2313
2325
|
r0 = r6
|
2314
2326
|
else
|
2315
|
-
r7 =
|
2327
|
+
r7 = _nt_self
|
2316
2328
|
if r7
|
2317
2329
|
r0 = r7
|
2318
2330
|
else
|
2319
|
-
r8 =
|
2331
|
+
r8 = _nt_list_expr
|
2320
2332
|
if r8
|
2321
2333
|
r0 = r8
|
2322
2334
|
else
|
2323
|
-
r9 =
|
2335
|
+
r9 = _nt_set_expr
|
2324
2336
|
if r9
|
2325
2337
|
r0 = r9
|
2326
2338
|
else
|
2327
|
-
|
2328
|
-
i12, s12 = index, []
|
2329
|
-
r13 = _nt_class_name
|
2330
|
-
s12 << r13
|
2331
|
-
if r13
|
2332
|
-
if has_terminal?('::', false, index)
|
2333
|
-
r14 = instantiate_node(SyntaxNode,input, index...(index + 2))
|
2334
|
-
@index += 2
|
2335
|
-
else
|
2336
|
-
terminal_parse_failure('::')
|
2337
|
-
r14 = nil
|
2338
|
-
end
|
2339
|
-
s12 << r14
|
2340
|
-
end
|
2341
|
-
if s12.last
|
2342
|
-
r12 = instantiate_node(SyntaxNode,input, i12...index, s12)
|
2343
|
-
r12.extend(Value0)
|
2344
|
-
else
|
2345
|
-
@index = i12
|
2346
|
-
r12 = nil
|
2347
|
-
end
|
2348
|
-
if r12
|
2349
|
-
r11 = r12
|
2350
|
-
else
|
2351
|
-
r11 = instantiate_node(SyntaxNode,input, index...index)
|
2352
|
-
end
|
2353
|
-
s10 << r11
|
2354
|
-
if r11
|
2355
|
-
r15 = _nt_class_name
|
2356
|
-
s10 << r15
|
2357
|
-
end
|
2358
|
-
if s10.last
|
2359
|
-
r10 = instantiate_node(NodeAsValue,input, i10...index, s10)
|
2360
|
-
r10.extend(Value1)
|
2361
|
-
else
|
2362
|
-
@index = i10
|
2363
|
-
r10 = nil
|
2364
|
-
end
|
2339
|
+
r10 = _nt_hash_expr
|
2365
2340
|
if r10
|
2366
2341
|
r0 = r10
|
2367
2342
|
else
|
2368
|
-
|
2369
|
-
|
2370
|
-
|
2371
|
-
|
2343
|
+
i11, s11 = index, []
|
2344
|
+
i13, s13 = index, []
|
2345
|
+
r14 = _nt_class_name
|
2346
|
+
s13 << r14
|
2347
|
+
if r14
|
2348
|
+
if has_terminal?('::', false, index)
|
2349
|
+
r15 = instantiate_node(SyntaxNode,input, index...(index + 2))
|
2350
|
+
@index += 2
|
2351
|
+
else
|
2352
|
+
terminal_parse_failure('::')
|
2353
|
+
r15 = nil
|
2354
|
+
end
|
2355
|
+
s13 << r15
|
2356
|
+
end
|
2357
|
+
if s13.last
|
2358
|
+
r13 = instantiate_node(SyntaxNode,input, i13...index, s13)
|
2359
|
+
r13.extend(Value0)
|
2360
|
+
else
|
2361
|
+
@index = i13
|
2362
|
+
r13 = nil
|
2363
|
+
end
|
2364
|
+
if r13
|
2365
|
+
r12 = r13
|
2366
|
+
else
|
2367
|
+
r12 = instantiate_node(SyntaxNode,input, index...index)
|
2368
|
+
end
|
2369
|
+
s11 << r12
|
2370
|
+
if r12
|
2371
|
+
r16 = _nt_class_name
|
2372
|
+
s11 << r16
|
2373
|
+
end
|
2374
|
+
if s11.last
|
2375
|
+
r11 = instantiate_node(NodeAsValue,input, i11...index, s11)
|
2376
|
+
r11.extend(Value1)
|
2372
2377
|
else
|
2373
|
-
|
2374
|
-
|
2378
|
+
@index = i11
|
2379
|
+
r11 = nil
|
2375
2380
|
end
|
2376
|
-
|
2377
|
-
|
2378
|
-
|
2379
|
-
|
2380
|
-
|
2381
|
+
if r11
|
2382
|
+
r0 = r11
|
2383
|
+
else
|
2384
|
+
i17, s17 = index, []
|
2385
|
+
if has_terminal?('(', false, index)
|
2386
|
+
r18 = instantiate_node(SyntaxNode,input, index...(index + 1))
|
2387
|
+
@index += 1
|
2381
2388
|
else
|
2382
|
-
|
2389
|
+
terminal_parse_failure('(')
|
2390
|
+
r18 = nil
|
2383
2391
|
end
|
2384
|
-
|
2392
|
+
s17 << r18
|
2385
2393
|
if r18
|
2386
|
-
r20 =
|
2387
|
-
s16 << r20
|
2394
|
+
r20 = _nt_sp
|
2388
2395
|
if r20
|
2389
|
-
|
2390
|
-
|
2391
|
-
|
2392
|
-
|
2393
|
-
|
2394
|
-
|
2395
|
-
|
2396
|
+
r19 = r20
|
2397
|
+
else
|
2398
|
+
r19 = instantiate_node(SyntaxNode,input, index...index)
|
2399
|
+
end
|
2400
|
+
s17 << r19
|
2401
|
+
if r19
|
2402
|
+
r21 = _nt_expression
|
2403
|
+
s17 << r21
|
2396
2404
|
if r21
|
2397
|
-
|
2398
|
-
|
2399
|
-
|
2405
|
+
r23 = _nt_sp
|
2406
|
+
if r23
|
2407
|
+
r22 = r23
|
2400
2408
|
else
|
2401
|
-
|
2402
|
-
|
2409
|
+
r22 = instantiate_node(SyntaxNode,input, index...index)
|
2410
|
+
end
|
2411
|
+
s17 << r22
|
2412
|
+
if r22
|
2413
|
+
if has_terminal?(')', false, index)
|
2414
|
+
r24 = instantiate_node(SyntaxNode,input, index...(index + 1))
|
2415
|
+
@index += 1
|
2416
|
+
else
|
2417
|
+
terminal_parse_failure(')')
|
2418
|
+
r24 = nil
|
2419
|
+
end
|
2420
|
+
s17 << r24
|
2403
2421
|
end
|
2404
|
-
s16 << r23
|
2405
2422
|
end
|
2406
2423
|
end
|
2407
2424
|
end
|
2408
|
-
|
2409
|
-
|
2410
|
-
|
2411
|
-
|
2412
|
-
|
2413
|
-
|
2414
|
-
|
2415
|
-
|
2416
|
-
|
2417
|
-
|
2418
|
-
|
2419
|
-
|
2420
|
-
|
2425
|
+
if s17.last
|
2426
|
+
r17 = instantiate_node(Expr,input, i17...index, s17)
|
2427
|
+
r17.extend(Value2)
|
2428
|
+
else
|
2429
|
+
@index = i17
|
2430
|
+
r17 = nil
|
2431
|
+
end
|
2432
|
+
if r17
|
2433
|
+
r0 = r17
|
2434
|
+
else
|
2435
|
+
@index = i0
|
2436
|
+
r0 = nil
|
2437
|
+
end
|
2421
2438
|
end
|
2422
2439
|
end
|
2423
2440
|
end
|
@@ -2810,37 +2827,11 @@ module Delorean
|
|
2810
2827
|
r0
|
2811
2828
|
end
|
2812
2829
|
|
2813
|
-
|
2814
|
-
|
2815
|
-
|
2816
|
-
cached = node_cache[:number][index]
|
2817
|
-
if cached
|
2818
|
-
cached = SyntaxNode.new(input, index...(index + 1)) if cached == true
|
2819
|
-
@index = cached.interval.end
|
2820
|
-
end
|
2821
|
-
return cached
|
2822
|
-
end
|
2823
|
-
|
2824
|
-
i0 = index
|
2825
|
-
r1 = _nt_decimal
|
2826
|
-
if r1
|
2827
|
-
r0 = r1
|
2828
|
-
else
|
2829
|
-
r2 = _nt_integer
|
2830
|
-
if r2
|
2831
|
-
r0 = r2
|
2832
|
-
else
|
2833
|
-
@index = i0
|
2834
|
-
r0 = nil
|
2835
|
-
end
|
2830
|
+
module Decimal0
|
2831
|
+
def i
|
2832
|
+
elements[0]
|
2836
2833
|
end
|
2837
2834
|
|
2838
|
-
node_cache[:number][start_index] = r0
|
2839
|
-
|
2840
|
-
r0
|
2841
|
-
end
|
2842
|
-
|
2843
|
-
module Decimal0
|
2844
2835
|
end
|
2845
2836
|
|
2846
2837
|
def _nt_decimal
|
@@ -2855,58 +2846,39 @@ module Delorean
|
|
2855
2846
|
end
|
2856
2847
|
|
2857
2848
|
i0, s0 = index, []
|
2858
|
-
|
2859
|
-
loop do
|
2860
|
-
if has_terminal?('\G[0-9]', true, index)
|
2861
|
-
r2 = true
|
2862
|
-
@index += 1
|
2863
|
-
else
|
2864
|
-
r2 = nil
|
2865
|
-
end
|
2866
|
-
if r2
|
2867
|
-
s1 << r2
|
2868
|
-
else
|
2869
|
-
break
|
2870
|
-
end
|
2871
|
-
end
|
2872
|
-
if s1.empty?
|
2873
|
-
@index = i1
|
2874
|
-
r1 = nil
|
2875
|
-
else
|
2876
|
-
r1 = instantiate_node(SyntaxNode,input, i1...index, s1)
|
2877
|
-
end
|
2849
|
+
r1 = _nt_integer
|
2878
2850
|
s0 << r1
|
2879
2851
|
if r1
|
2880
2852
|
if has_terminal?('.', false, index)
|
2881
|
-
|
2853
|
+
r2 = instantiate_node(SyntaxNode,input, index...(index + 1))
|
2882
2854
|
@index += 1
|
2883
2855
|
else
|
2884
2856
|
terminal_parse_failure('.')
|
2885
|
-
|
2857
|
+
r2 = nil
|
2886
2858
|
end
|
2887
|
-
s0 <<
|
2888
|
-
if
|
2889
|
-
|
2859
|
+
s0 << r2
|
2860
|
+
if r2
|
2861
|
+
s3, i3 = [], index
|
2890
2862
|
loop do
|
2891
2863
|
if has_terminal?('\G[0-9]', true, index)
|
2892
|
-
|
2864
|
+
r4 = true
|
2893
2865
|
@index += 1
|
2894
2866
|
else
|
2895
|
-
|
2867
|
+
r4 = nil
|
2896
2868
|
end
|
2897
|
-
if
|
2898
|
-
|
2869
|
+
if r4
|
2870
|
+
s3 << r4
|
2899
2871
|
else
|
2900
2872
|
break
|
2901
2873
|
end
|
2902
2874
|
end
|
2903
|
-
if
|
2904
|
-
@index =
|
2905
|
-
|
2875
|
+
if s3.empty?
|
2876
|
+
@index = i3
|
2877
|
+
r3 = nil
|
2906
2878
|
else
|
2907
|
-
|
2879
|
+
r3 = instantiate_node(SyntaxNode,input, i3...index, s3)
|
2908
2880
|
end
|
2909
|
-
s0 <<
|
2881
|
+
s0 << r3
|
2910
2882
|
end
|
2911
2883
|
end
|
2912
2884
|
if s0.last
|
@@ -2922,6 +2894,9 @@ module Delorean
|
|
2922
2894
|
r0
|
2923
2895
|
end
|
2924
2896
|
|
2897
|
+
module Integer0
|
2898
|
+
end
|
2899
|
+
|
2925
2900
|
def _nt_integer
|
2926
2901
|
start_index = index
|
2927
2902
|
if node_cache[:integer].has_key?(index)
|
@@ -2933,25 +2908,56 @@ module Delorean
|
|
2933
2908
|
return cached
|
2934
2909
|
end
|
2935
2910
|
|
2936
|
-
|
2937
|
-
|
2938
|
-
|
2939
|
-
|
2911
|
+
i0 = index
|
2912
|
+
if has_terminal?('0', false, index)
|
2913
|
+
r1 = instantiate_node(Literal,input, index...(index + 1))
|
2914
|
+
@index += 1
|
2915
|
+
else
|
2916
|
+
terminal_parse_failure('0')
|
2917
|
+
r1 = nil
|
2918
|
+
end
|
2919
|
+
if r1
|
2920
|
+
r0 = r1
|
2921
|
+
else
|
2922
|
+
i2, s2 = index, []
|
2923
|
+
if has_terminal?('\G[1-9]', true, index)
|
2924
|
+
r3 = true
|
2940
2925
|
@index += 1
|
2941
2926
|
else
|
2942
|
-
|
2927
|
+
r3 = nil
|
2943
2928
|
end
|
2944
|
-
|
2945
|
-
|
2929
|
+
s2 << r3
|
2930
|
+
if r3
|
2931
|
+
s4, i4 = [], index
|
2932
|
+
loop do
|
2933
|
+
if has_terminal?('\G[0-9]', true, index)
|
2934
|
+
r5 = true
|
2935
|
+
@index += 1
|
2936
|
+
else
|
2937
|
+
r5 = nil
|
2938
|
+
end
|
2939
|
+
if r5
|
2940
|
+
s4 << r5
|
2941
|
+
else
|
2942
|
+
break
|
2943
|
+
end
|
2944
|
+
end
|
2945
|
+
r4 = instantiate_node(SyntaxNode,input, i4...index, s4)
|
2946
|
+
s2 << r4
|
2947
|
+
end
|
2948
|
+
if s2.last
|
2949
|
+
r2 = instantiate_node(Literal,input, i2...index, s2)
|
2950
|
+
r2.extend(Integer0)
|
2946
2951
|
else
|
2947
|
-
|
2952
|
+
@index = i2
|
2953
|
+
r2 = nil
|
2954
|
+
end
|
2955
|
+
if r2
|
2956
|
+
r0 = r2
|
2957
|
+
else
|
2958
|
+
@index = i0
|
2959
|
+
r0 = nil
|
2948
2960
|
end
|
2949
|
-
end
|
2950
|
-
if s0.empty?
|
2951
|
-
@index = i0
|
2952
|
-
r0 = nil
|
2953
|
-
else
|
2954
|
-
r0 = instantiate_node(Literal,input, i0...index, s0)
|
2955
2961
|
end
|
2956
2962
|
|
2957
2963
|
node_cache[:integer][start_index] = r0
|
@@ -3267,7 +3273,7 @@ module Delorean
|
|
3267
3273
|
end
|
3268
3274
|
end
|
3269
3275
|
if s1.last
|
3270
|
-
r1 = instantiate_node(
|
3276
|
+
r1 = instantiate_node(IString,input, i1...index, s1)
|
3271
3277
|
r1.extend(String1)
|
3272
3278
|
else
|
3273
3279
|
@index = i1
|
@@ -52,7 +52,7 @@ grammar Delorean
|
|
52
52
|
/
|
53
53
|
'.' sp? i:identifier '(' sp? al:kw_args? sp? ')' <Call>
|
54
54
|
/
|
55
|
-
'.' sp? i:identifier <GetAttr>
|
55
|
+
'.' sp? i:(identifier / integer) <GetAttr>
|
56
56
|
end
|
57
57
|
|
58
58
|
rule list_expr
|
@@ -92,7 +92,8 @@ grammar Delorean
|
|
92
92
|
# Arrays). So, be cautious about which opertaions are added.
|
93
93
|
rule binary_op
|
94
94
|
'==' / '!=' / '>=' / '<=' / '&&' / '||' /
|
95
|
-
'>'
|
95
|
+
'>' / '<' / '+' / '-' / '*' / '/' / '%' /
|
96
|
+
'&' / '^' / '|'
|
96
97
|
end
|
97
98
|
|
98
99
|
rule unary_op
|
@@ -100,7 +101,8 @@ grammar Delorean
|
|
100
101
|
end
|
101
102
|
|
102
103
|
rule value
|
103
|
-
|
104
|
+
decimal /
|
105
|
+
integer /
|
104
106
|
string /
|
105
107
|
boolean /
|
106
108
|
nil_val /
|
@@ -110,7 +112,7 @@ grammar Delorean
|
|
110
112
|
set_expr /
|
111
113
|
hash_expr /
|
112
114
|
mod:(m:class_name '::')? c:class_name <NodeAsValue> /
|
113
|
-
'(' sp? e:expression sp? ')'
|
115
|
+
'(' sp? e:expression sp? ')' <Expr>
|
114
116
|
end
|
115
117
|
|
116
118
|
rule fn_args
|
@@ -118,23 +120,21 @@ grammar Delorean
|
|
118
120
|
end
|
119
121
|
|
120
122
|
rule hash_args
|
121
|
-
e0:expression sp? ':' sp? e1:expression
|
123
|
+
e0:expression sp? ':' sp? e1:expression
|
124
|
+
args_rest:(sp? ',' sp? al:hash_args?)? <HashArgs>
|
122
125
|
end
|
123
126
|
|
124
127
|
rule kw_args
|
125
|
-
k:(i:identifier sp? '=' sp?)? arg0:expression
|
126
|
-
|
127
|
-
|
128
|
-
rule number
|
129
|
-
decimal / integer
|
128
|
+
k:(i:identifier sp? '=' sp?)? arg0:expression
|
129
|
+
args_rest:(sp? ',' sp? al:kw_args?)? <KwArgs>
|
130
130
|
end
|
131
131
|
|
132
132
|
rule decimal
|
133
|
-
|
133
|
+
i:integer '.' [0-9]+ <Literal>
|
134
134
|
end
|
135
135
|
|
136
136
|
rule integer
|
137
|
-
[0-9]
|
137
|
+
'0' <Literal> / [1-9] [0-9]* <Literal>
|
138
138
|
end
|
139
139
|
|
140
140
|
rule identifier
|
@@ -163,7 +163,7 @@ grammar Delorean
|
|
163
163
|
end
|
164
164
|
|
165
165
|
rule string
|
166
|
-
'"' ('\"' / !'"' .)* '"' <
|
166
|
+
'"' ('\"' / !'"' .)* '"' <IString>
|
167
167
|
/
|
168
168
|
"'" [^']* "'" <DString>
|
169
169
|
end
|
data/lib/delorean/engine.rb
CHANGED
@@ -189,7 +189,14 @@ module Delorean
|
|
189
189
|
end
|
190
190
|
|
191
191
|
def parse_check_call_fn(fn, argcount, class_name=nil)
|
192
|
-
klass =
|
192
|
+
klass = case class_name
|
193
|
+
when nil
|
194
|
+
@m::BaseClass
|
195
|
+
when String
|
196
|
+
parse_class(class_name)
|
197
|
+
else
|
198
|
+
class_name
|
199
|
+
end
|
193
200
|
|
194
201
|
err(UndefinedFunctionError, "Function #{fn} not found") unless
|
195
202
|
klass.methods.member? fn.to_sym
|
data/lib/delorean/nodes.rb
CHANGED
@@ -105,8 +105,7 @@ eos
|
|
105
105
|
# an attr is defined as a class function on the node class.
|
106
106
|
"class #{context.last_node}; " +
|
107
107
|
"def self.#{i.text_value}#{POST}(_e); " +
|
108
|
-
"_e[self.name+'.#{i.text_value}'] ||= "
|
109
|
-
e.rewrite(context) + "; end; end;"
|
108
|
+
"_e[self.name+'.#{i.text_value}'] ||= #{e.rewrite(context)}; end; end;"
|
110
109
|
end
|
111
110
|
end
|
112
111
|
|
@@ -116,7 +115,19 @@ eos
|
|
116
115
|
end
|
117
116
|
|
118
117
|
def rewrite(context)
|
119
|
-
"(
|
118
|
+
"(#{e.rewrite(context)})"
|
119
|
+
end
|
120
|
+
end
|
121
|
+
|
122
|
+
class ClassText
|
123
|
+
attr_reader :text
|
124
|
+
|
125
|
+
def initialize(text)
|
126
|
+
@text = text
|
127
|
+
end
|
128
|
+
|
129
|
+
def to_s
|
130
|
+
text
|
120
131
|
end
|
121
132
|
end
|
122
133
|
|
@@ -140,9 +151,9 @@ eos
|
|
140
151
|
context.parse_check_defined_mod_node(node_name, mname)
|
141
152
|
context.super_name(node_name, mname)
|
142
153
|
rescue UndefinedError, ParseError
|
143
|
-
#
|
144
|
-
#
|
145
|
-
|
154
|
+
# FIXME: wrap the class name so Call will be able to tell it
|
155
|
+
# apart from a regular value.
|
156
|
+
ClassText.new(text_value)
|
146
157
|
end
|
147
158
|
end
|
148
159
|
end
|
@@ -213,6 +224,16 @@ eos
|
|
213
224
|
end
|
214
225
|
end
|
215
226
|
|
227
|
+
class IString < Literal
|
228
|
+
def rewrite(context)
|
229
|
+
# FIXME: hacky to just fail
|
230
|
+
raise "String interpolation not supported" if text_value =~ /\#\{.*\}/
|
231
|
+
|
232
|
+
# FIXME: syntax check?
|
233
|
+
text_value
|
234
|
+
end
|
235
|
+
end
|
236
|
+
|
216
237
|
class DString < Literal
|
217
238
|
def rewrite(context)
|
218
239
|
# remove the quotes and requote. We don't want the likes of #{}
|
@@ -275,7 +296,9 @@ eos
|
|
275
296
|
end
|
276
297
|
|
277
298
|
def rewrite(context, vcode)
|
278
|
-
|
299
|
+
attr = i.text_value
|
300
|
+
attr = "'#{attr}'" unless attr =~ /\A[0-9]+\z/
|
301
|
+
"_get_attr(#{vcode}, #{attr}, _e)"
|
279
302
|
end
|
280
303
|
end
|
281
304
|
|
@@ -293,13 +316,13 @@ eos
|
|
293
316
|
|
294
317
|
args_str = args.reverse.join(',')
|
295
318
|
|
296
|
-
if vcode.is_a?
|
319
|
+
if vcode.is_a?(ClassText)
|
297
320
|
# ruby class call
|
298
|
-
class_name = vcode
|
321
|
+
class_name = vcode.text
|
299
322
|
context.parse_check_call_fn(i.text_value, args.count, class_name)
|
300
323
|
"#{class_name}.#{i.text_value}(#{args_str})"
|
301
324
|
else
|
302
|
-
"_instance_call(#{vcode}, '#{i.text_value}', [#{args_str}])"
|
325
|
+
"_instance_call(#{vcode}, '#{i.text_value}', [#{args_str}], _e)"
|
303
326
|
end
|
304
327
|
|
305
328
|
end
|
@@ -314,10 +337,9 @@ eos
|
|
314
337
|
def rewrite(context, node_name)
|
315
338
|
args, kw = al.text_value.empty? ? [[], {}] : al.rewrite(context)
|
316
339
|
|
317
|
-
|
318
|
-
|
319
|
-
|
320
|
-
kw_str = kw.map {|k, v| "'#{k}' => #{v}"}.join(',')
|
340
|
+
kw_str =
|
341
|
+
(kw.map {|k, v| "'#{k}' => #{v}"} +
|
342
|
+
args.each_with_index.map {|v, i| "#{i} => #{v}"}).join(',')
|
321
343
|
|
322
344
|
"_node_call(#{node_name}, _e, {#{kw_str}})"
|
323
345
|
end
|
@@ -331,13 +353,13 @@ eos
|
|
331
353
|
end
|
332
354
|
|
333
355
|
def rewrite(context)
|
334
|
-
|
356
|
+
attrs = ga.text_value.split('.')
|
335
357
|
|
336
358
|
# If ga.text_value is not "", then we need to drop the 1st
|
337
359
|
# element since it'll be "".
|
338
|
-
|
360
|
+
attrs.shift
|
339
361
|
|
340
|
-
|
362
|
+
attrs.inject(v.rewrite(context)) {|x, y| "_get_attr(#{x}, '#{y}', _e)"}
|
341
363
|
end
|
342
364
|
end
|
343
365
|
|
@@ -403,7 +425,7 @@ eos
|
|
403
425
|
def rewrite(context)
|
404
426
|
res = "(#{e1.rewrite(context)})"
|
405
427
|
context.parse_define_var(i.text_value)
|
406
|
-
res += ".select{|#{i.rewrite(context)}|
|
428
|
+
res += ".select{|#{i.rewrite(context)}|(#{ifexp.e3.rewrite(context)})}" if
|
407
429
|
defined?(ifexp.e3)
|
408
430
|
res += ".map{|#{i.rewrite(context)}| (#{e2.rewrite(context)}) }"
|
409
431
|
context.parse_undef_var(i.text_value)
|
data/lib/delorean/version.rb
CHANGED
data/spec/eval_spec.rb
CHANGED
@@ -40,6 +40,15 @@ describe "Delorean" do
|
|
40
40
|
r.should == -122
|
41
41
|
end
|
42
42
|
|
43
|
+
it "proper string interpolation" do
|
44
|
+
engine.parse defn("A:",
|
45
|
+
' a = "\n123\n"',
|
46
|
+
)
|
47
|
+
|
48
|
+
r = engine.evaluate("A", "a")
|
49
|
+
r.should == "\n123\n"
|
50
|
+
end
|
51
|
+
|
43
52
|
it "should handle getattr in expressions" do
|
44
53
|
engine.parse defn("A:",
|
45
54
|
" a = {'x':123, 'y':456, 'z':789}",
|
@@ -48,6 +57,14 @@ describe "Delorean" do
|
|
48
57
|
engine.evaluate_attrs("A", ["b"]).should == [123*456-789]
|
49
58
|
end
|
50
59
|
|
60
|
+
it "should handle numeric getattr" do
|
61
|
+
engine.parse defn("A:",
|
62
|
+
" a = {1:123, 0:456, 'z':789, 2: {'a':444}}",
|
63
|
+
" b = A.a.1 * A.a.0 - A.a.z - A.a.2.a",
|
64
|
+
)
|
65
|
+
engine.evaluate_attrs("A", ["b"]).should == [123*456-789-444]
|
66
|
+
end
|
67
|
+
|
51
68
|
it "should be able to evaluate multiple node attrs" do
|
52
69
|
engine.parse defn("A:",
|
53
70
|
" a =? 123",
|
@@ -63,7 +80,7 @@ describe "Delorean" do
|
|
63
80
|
it "should give error when accessing undefined attr" do
|
64
81
|
engine.parse defn("A:",
|
65
82
|
" a = 1",
|
66
|
-
" c = a.
|
83
|
+
" c = a.to_ss",
|
67
84
|
)
|
68
85
|
|
69
86
|
lambda {
|
@@ -71,6 +88,15 @@ describe "Delorean" do
|
|
71
88
|
}.should raise_error(Delorean::InvalidGetAttribute)
|
72
89
|
end
|
73
90
|
|
91
|
+
it "should be able to call 0-ary functions without ()" do
|
92
|
+
engine.parse defn("A:",
|
93
|
+
" a = 1",
|
94
|
+
" d = a.to_s",
|
95
|
+
)
|
96
|
+
|
97
|
+
engine.evaluate("A", "d").should == "1"
|
98
|
+
end
|
99
|
+
|
74
100
|
it "should handle default param values" do
|
75
101
|
engine.parse defn("A:",
|
76
102
|
" a =? 123",
|
@@ -170,6 +196,16 @@ describe "Delorean" do
|
|
170
196
|
res["backtrace"].should == [["XXX", 2, "b"]]
|
171
197
|
end
|
172
198
|
|
199
|
+
it "should handle optional args to external fns" do
|
200
|
+
engine.parse defn("A:",
|
201
|
+
" b = Dummy.one_or_two(['a', 'b'])",
|
202
|
+
" c = Dummy.one_or_two([1,2,3], ['a', 'b'])",
|
203
|
+
)
|
204
|
+
|
205
|
+
engine.evaluate("A", "b").should == [['a', 'b'], nil]
|
206
|
+
engine.evaluate("A", "c").should == [[1,2,3], ['a', 'b']]
|
207
|
+
end
|
208
|
+
|
173
209
|
it "should handle operator precedence properly" do
|
174
210
|
engine.parse defn("A:",
|
175
211
|
" b = 3+2*4-1",
|
@@ -216,6 +252,18 @@ describe "Delorean" do
|
|
216
252
|
r.should == 123*123 + 5
|
217
253
|
end
|
218
254
|
|
255
|
+
it "should be able to access nodes and node attrs dynamically " do
|
256
|
+
engine.parse defn("A:",
|
257
|
+
" b = 123",
|
258
|
+
"B:",
|
259
|
+
" b = A",
|
260
|
+
" c = b.b * 456",
|
261
|
+
)
|
262
|
+
|
263
|
+
r = engine.evaluate("B", "c")
|
264
|
+
r.should == 123*456
|
265
|
+
end
|
266
|
+
|
219
267
|
it "should be able to call class methods on ActiveRecord classes" do
|
220
268
|
engine.parse defn("A:",
|
221
269
|
" b = Dummy.call_me_maybe(1, 2, 3, 4)",
|
@@ -324,13 +372,13 @@ eoc
|
|
324
372
|
r.should == 867 + 5309
|
325
373
|
end
|
326
374
|
|
327
|
-
it "should
|
375
|
+
it "should be able to use AR classes as values and call their methods" do
|
328
376
|
engine.parse defn("A:",
|
329
|
-
|
377
|
+
" a = M::LittleDummy",
|
378
|
+
" b = a.heres_my_number(867, 5309)",
|
330
379
|
)
|
331
|
-
|
332
|
-
r
|
333
|
-
r.should == '#{this is a test}'
|
380
|
+
r = engine.evaluate("A", "b")
|
381
|
+
r.should == 867 + 5309
|
334
382
|
end
|
335
383
|
|
336
384
|
it "should ignore undeclared params sent to eval which match attr names" do
|
@@ -827,4 +875,17 @@ eof
|
|
827
875
|
engine.evaluate("A", "y", {"a"=>1, "b"=>2, "c"=>3}).should == h
|
828
876
|
engine.evaluate("A", "z", {"a"=>1, "b"=>2, "c"=>3}).should == -1
|
829
877
|
end
|
878
|
+
|
879
|
+
it "implements positional args in node calls" do
|
880
|
+
engine.parse defn("B:",
|
881
|
+
" a =?",
|
882
|
+
" b =?",
|
883
|
+
" x = (_.0 - _.1) * (a - b)",
|
884
|
+
"A:",
|
885
|
+
" a = _.0 - _.1",
|
886
|
+
" z = B(10, 20, a=3, b=7).x",
|
887
|
+
)
|
888
|
+
engine.evaluate_attrs("A", ["a", "z"], {0 => 123, 1 => 456}).should ==
|
889
|
+
[123-456, -40]
|
890
|
+
end
|
830
891
|
end
|
data/spec/parse_spec.rb
CHANGED
@@ -60,7 +60,8 @@ describe "Delorean" do
|
|
60
60
|
it "should accept default param definitions" do
|
61
61
|
lambda {
|
62
62
|
engine.parse defn("A:",
|
63
|
-
"
|
63
|
+
" a =? 0.0123",
|
64
|
+
" b =? 0",
|
64
65
|
" c =? -1.1",
|
65
66
|
" d = b + c",
|
66
67
|
)
|
@@ -83,6 +84,22 @@ describe "Delorean" do
|
|
83
84
|
}.should raise_error(Delorean::ParseError)
|
84
85
|
end
|
85
86
|
|
87
|
+
it "should disallow leading 0s in numbers" do
|
88
|
+
lambda {
|
89
|
+
engine.parse defn("A:",
|
90
|
+
" a = 00.123",
|
91
|
+
)
|
92
|
+
}.should raise_error(Delorean::ParseError)
|
93
|
+
end
|
94
|
+
|
95
|
+
it "should disallow leading 0s in numbers (2)" do
|
96
|
+
lambda {
|
97
|
+
engine.parse defn("A:",
|
98
|
+
" a = 0123",
|
99
|
+
)
|
100
|
+
}.should raise_error(Delorean::ParseError)
|
101
|
+
end
|
102
|
+
|
86
103
|
it "should disallow bad attr names" do
|
87
104
|
lambda {
|
88
105
|
engine.parse defn("A:",
|
@@ -648,15 +665,10 @@ describe "Delorean" do
|
|
648
665
|
)
|
649
666
|
end
|
650
667
|
|
651
|
-
it "should
|
652
|
-
|
653
|
-
|
654
|
-
|
655
|
-
)
|
656
|
-
raise "fail"
|
657
|
-
rescue Delorean::ParseError => exc
|
658
|
-
exc.line.should == 2
|
659
|
-
end
|
668
|
+
it "should allow positional args to node calls" do
|
669
|
+
engine.parse defn("A:",
|
670
|
+
" d = A(1, 2, 3, a=123, b=456)",
|
671
|
+
)
|
660
672
|
end
|
661
673
|
|
662
674
|
it "should parse instance calls" do
|
@@ -728,6 +740,18 @@ describe "Delorean" do
|
|
728
740
|
end
|
729
741
|
end
|
730
742
|
|
743
|
+
# this is a parsing limitation which should go away
|
744
|
+
it "should not parse interpolated strings" do
|
745
|
+
begin
|
746
|
+
engine.parse defn("A:",
|
747
|
+
' d = "#{this is a test}"',
|
748
|
+
)
|
749
|
+
raise "fail"
|
750
|
+
rescue Delorean::ParseError => exc
|
751
|
+
exc.line.should == 2
|
752
|
+
end
|
753
|
+
end
|
754
|
+
|
731
755
|
it "should parse imports" do
|
732
756
|
engine.parse defn("import AAA",
|
733
757
|
"A:",
|
data/spec/spec_helper.rb
CHANGED
@@ -30,6 +30,8 @@ ActiveRecord::Migration.create_table :dummies do |t|
|
|
30
30
|
end
|
31
31
|
|
32
32
|
class Dummy < ActiveRecord::Base
|
33
|
+
include Delorean::Model
|
34
|
+
|
33
35
|
attr_accessible :name, :number, :dummy
|
34
36
|
belongs_to :dummy
|
35
37
|
|
@@ -64,6 +66,14 @@ class Dummy < ActiveRecord::Base
|
|
64
66
|
def name2
|
65
67
|
"#{name}-#{number}"
|
66
68
|
end
|
69
|
+
|
70
|
+
delorean_fn :one_or_two, sig: [1, 2] do
|
71
|
+
|*args|
|
72
|
+
# FIXME: |a,b| will not work properly with delorean_fn
|
73
|
+
a, b = args
|
74
|
+
|
75
|
+
[a, b]
|
76
|
+
end
|
67
77
|
end
|
68
78
|
|
69
79
|
module M
|
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.
|
4
|
+
version: 0.3.3
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Arman Bostani
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2014-05-
|
11
|
+
date: 2014-05-16 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: treetop
|