delorean_lang 0.3.2 → 0.3.3
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.
- 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
|