delorean_lang 0.0.34 → 0.0.38
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.
- data/LICENSE +2 -2
- data/README.md +8 -6
- data/delorean.gemspec +1 -1
- data/lib/delorean/base.rb +22 -10
- data/lib/delorean/const.rb +5 -0
- data/lib/delorean/delorean.rb +570 -416
- data/lib/delorean/delorean.treetop +35 -47
- data/lib/delorean/engine.rb +42 -25
- data/lib/delorean/functions.rb +53 -45
- data/lib/delorean/model.rb +3 -1
- data/lib/delorean/nodes.rb +68 -28
- data/lib/delorean/version.rb +1 -1
- data/spec/dev_spec.rb +4 -6
- data/spec/eval_spec.rb +114 -10
- data/spec/func_spec.rb +22 -18
- data/spec/parse_spec.rb +21 -0
- metadata +7 -6
|
@@ -10,27 +10,33 @@ grammar Delorean
|
|
|
10
10
|
/
|
|
11
11
|
sp i:identifier sp? '=' sp? e:expression <Formula>
|
|
12
12
|
/
|
|
13
|
-
n:
|
|
13
|
+
n:class_name ':' sp? mod:(m:class_name '::')? p:class_name <SubNode>
|
|
14
14
|
/
|
|
15
|
-
n:
|
|
15
|
+
n:class_name ':' <BaseNode>
|
|
16
16
|
/
|
|
17
|
-
'import' sp n:
|
|
17
|
+
'import' sp n:class_name sp v:integer <Import>
|
|
18
18
|
end
|
|
19
19
|
|
|
20
|
-
rule
|
|
20
|
+
rule class_name
|
|
21
21
|
[A-Z] [a-zA-Z0-9_]*
|
|
22
22
|
end
|
|
23
23
|
|
|
24
24
|
rule expression
|
|
25
25
|
op:unary_op sp? e:expression <UnOp>
|
|
26
26
|
/
|
|
27
|
-
'if'
|
|
28
|
-
'then'
|
|
29
|
-
'else'
|
|
27
|
+
'if' sp? v:expression sp?
|
|
28
|
+
'then' sp? e1:expression sp?
|
|
29
|
+
'else' sp? e2:expression <IfElse>
|
|
30
|
+
/
|
|
31
|
+
v:getattr_exp sp? op:binary_op sp? e:expression <BinOp>
|
|
30
32
|
/
|
|
31
|
-
v:
|
|
33
|
+
v:getattr_exp sp? '[' sp? args:fn_args sp? ']' <IndexOp>
|
|
32
34
|
/
|
|
33
|
-
|
|
35
|
+
getattr_exp
|
|
36
|
+
end
|
|
37
|
+
|
|
38
|
+
rule getattr_exp
|
|
39
|
+
v:value ga:(('.' identifier)*) <ExpGetAttr>
|
|
34
40
|
end
|
|
35
41
|
|
|
36
42
|
rule list_expr
|
|
@@ -47,6 +53,11 @@ grammar Delorean
|
|
|
47
53
|
rule hash_expr
|
|
48
54
|
'{}' <HashExpr>
|
|
49
55
|
/
|
|
56
|
+
'{' sp? el:expression sp? ':' sp? er:expression sp
|
|
57
|
+
'for' sp i:identifier sp 'in' sp e1:expression sp?
|
|
58
|
+
ifexp:('if' sp ei:expression sp?)?
|
|
59
|
+
'}' <HashComprehension>
|
|
60
|
+
/
|
|
50
61
|
'{' sp? args:hash_args sp? '}' <HashExpr>
|
|
51
62
|
end
|
|
52
63
|
|
|
@@ -61,26 +72,23 @@ grammar Delorean
|
|
|
61
72
|
end
|
|
62
73
|
|
|
63
74
|
rule value
|
|
64
|
-
number
|
|
65
|
-
string
|
|
66
|
-
boolean
|
|
67
|
-
nil_val
|
|
68
|
-
script_call
|
|
69
|
-
fn
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
'(' sp? e:expression sp? ')' <Expr>
|
|
75
|
+
number /
|
|
76
|
+
string /
|
|
77
|
+
boolean /
|
|
78
|
+
nil_val /
|
|
79
|
+
script_call /
|
|
80
|
+
fn /
|
|
81
|
+
model_fn /
|
|
82
|
+
identifier /
|
|
83
|
+
list_expr /
|
|
84
|
+
hash_expr /
|
|
85
|
+
mod:(m:class_name '::')? c:class_name <NodeAsValue> /
|
|
86
|
+
'(' sp? e:expression sp? ')' <Expr>
|
|
77
87
|
end
|
|
78
88
|
|
|
79
89
|
# built-in functions
|
|
80
90
|
rule fn
|
|
81
|
-
fn:fn_name '(' sp? ')' <Fn>
|
|
82
|
-
/
|
|
83
|
-
fn:fn_name '(' sp? args:fn_args sp? ')' <Fn>
|
|
91
|
+
fn:fn_name '(' sp? args:fn_args? sp? ')' <Fn>
|
|
84
92
|
end
|
|
85
93
|
|
|
86
94
|
rule fn_args
|
|
@@ -94,22 +102,16 @@ grammar Delorean
|
|
|
94
102
|
end
|
|
95
103
|
|
|
96
104
|
rule model_name
|
|
97
|
-
class_name '::' model_name
|
|
98
|
-
/
|
|
99
|
-
class_name
|
|
105
|
+
class_name ('::' model_name)?
|
|
100
106
|
end
|
|
101
107
|
|
|
102
108
|
rule fn_name
|
|
103
109
|
[A-Z] [A-Z0-9]*
|
|
104
110
|
end
|
|
105
111
|
|
|
106
|
-
rule class_name
|
|
107
|
-
[A-Z] [a-zA-Z0-9]*
|
|
108
|
-
end
|
|
109
|
-
|
|
110
112
|
# script calling
|
|
111
113
|
rule script_call
|
|
112
|
-
'@' mod:(m:
|
|
114
|
+
'@' mod:(m:class_name '::')? c:class_name '(' sp? al:kw_args sp? ')' <ScriptCallNode>
|
|
113
115
|
/
|
|
114
116
|
'@' i:identifier? '(' sp? al:kw_args sp? ')' <ScriptCall>
|
|
115
117
|
end
|
|
@@ -122,20 +124,6 @@ grammar Delorean
|
|
|
122
124
|
k:(i:identifier ':' sp?)? arg0:expression args_rest:(sp? ',' sp? al:kw_args)? <KwArgs>
|
|
123
125
|
end
|
|
124
126
|
|
|
125
|
-
rule node_getattr
|
|
126
|
-
n:node_name '.' i:identifier <NodeGetAttr>
|
|
127
|
-
end
|
|
128
|
-
|
|
129
|
-
rule model_fn_getattr
|
|
130
|
-
mfn:model_fn '.' i:identifier <ModelFnGetAttr>
|
|
131
|
-
end
|
|
132
|
-
|
|
133
|
-
rule getattr
|
|
134
|
-
i:identifier '.' ga:getattr <GetAttr>
|
|
135
|
-
/
|
|
136
|
-
identifier
|
|
137
|
-
end
|
|
138
|
-
|
|
139
127
|
rule number
|
|
140
128
|
decimal / integer
|
|
141
129
|
end
|
data/lib/delorean/engine.rb
CHANGED
|
@@ -1,10 +1,7 @@
|
|
|
1
|
+
require 'delorean/const'
|
|
1
2
|
require 'delorean/base'
|
|
2
3
|
|
|
3
4
|
module Delorean
|
|
4
|
-
SIG = "_SIG"
|
|
5
|
-
MOD = "DELOREAN__"
|
|
6
|
-
POST = "__D"
|
|
7
|
-
|
|
8
5
|
class Engine
|
|
9
6
|
attr_reader :last_node, :module_name, :line_no, :comp_set, :pm, :m, :imports
|
|
10
7
|
|
|
@@ -281,24 +278,36 @@ module Delorean
|
|
|
281
278
|
|
|
282
279
|
# enumerate all nodes
|
|
283
280
|
def enumerate_nodes
|
|
284
|
-
|
|
285
|
-
@node_attrs.keys.each {|k| n.add(k) }
|
|
286
|
-
n
|
|
281
|
+
SortedSet[* @node_attrs.keys]
|
|
287
282
|
end
|
|
288
283
|
|
|
289
284
|
# enumerate qualified list of all attrs
|
|
290
285
|
def enumerate_attrs
|
|
291
|
-
|
|
286
|
+
@node_attrs.keys.inject({}) { |h, node|
|
|
287
|
+
h[node] = enumerate_attrs_by_node(node)
|
|
288
|
+
h
|
|
289
|
+
}
|
|
292
290
|
end
|
|
293
291
|
|
|
294
|
-
# enumerate qualified list of attrs by node
|
|
292
|
+
# enumerate qualified list of attrs by node
|
|
295
293
|
def enumerate_attrs_by_node(node)
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
|
|
294
|
+
raise "bad node" unless node
|
|
295
|
+
|
|
296
|
+
# FIXME: for some reason, in rspec we get nodes which are String
|
|
297
|
+
# but .is_a?(String) fails.
|
|
298
|
+
begin
|
|
299
|
+
klass = node.class.name=="String" ? @m.module_eval(node) : node
|
|
300
|
+
rescue NameError
|
|
301
|
+
# FIXME: a little hacky. Should raise an exception.
|
|
302
|
+
return []
|
|
303
|
+
end
|
|
304
|
+
|
|
305
|
+
raise "bad node class #{klass}" unless klass.is_a?(Class)
|
|
306
|
+
|
|
307
|
+
klass.methods.map(&:to_s).select { |x|
|
|
308
|
+
x.end_with?(POST)
|
|
309
|
+
}.map { |x|
|
|
310
|
+
x.sub(/#{POST}$/, '')
|
|
302
311
|
}
|
|
303
312
|
end
|
|
304
313
|
|
|
@@ -310,9 +319,7 @@ module Delorean
|
|
|
310
319
|
# enumerate params by a single node
|
|
311
320
|
def enumerate_params_by_node(node)
|
|
312
321
|
attrs = enumerate_attrs_by_node(node)
|
|
313
|
-
|
|
314
|
-
attrs.each_value {|v| v.map {|p| ps.add(p) if @param_set.include?(p.to_s)}}
|
|
315
|
-
ps
|
|
322
|
+
Set.new( attrs.select {|a| @param_set.include?(a)} )
|
|
316
323
|
end
|
|
317
324
|
|
|
318
325
|
######################################################################
|
|
@@ -323,18 +330,29 @@ module Delorean
|
|
|
323
330
|
evaluate_attrs(node, [attr], params)[0]
|
|
324
331
|
end
|
|
325
332
|
|
|
333
|
+
def evaluate_attrs_hash(node, attrs, params={})
|
|
334
|
+
res = evaluate_attrs(node, attrs, params)
|
|
335
|
+
Hash[* attrs.zip(res).flatten(1)]
|
|
336
|
+
end
|
|
337
|
+
|
|
326
338
|
def evaluate_attrs(node, attrs, params={})
|
|
327
|
-
raise "bad
|
|
339
|
+
raise "bad params" unless params.is_a?(Hash)
|
|
328
340
|
|
|
329
|
-
|
|
330
|
-
klass =
|
|
331
|
-
|
|
332
|
-
|
|
341
|
+
if node.is_a?(Class)
|
|
342
|
+
klass = node
|
|
343
|
+
else
|
|
344
|
+
raise "bad node '#{node}'" unless node =~ /^[A-Z][a-zA-Z0-9_]*$/
|
|
345
|
+
|
|
346
|
+
begin
|
|
347
|
+
klass = @m.module_eval(node)
|
|
348
|
+
rescue NameError
|
|
349
|
+
err(UndefinedNodeError, "node #{node} is undefined")
|
|
350
|
+
end
|
|
333
351
|
end
|
|
334
352
|
|
|
335
353
|
params[:_engine] = self
|
|
336
354
|
|
|
337
|
-
attrs.map {|attr|
|
|
355
|
+
attrs.map { |attr|
|
|
338
356
|
raise "bad attribute '#{attr}'" unless attr =~ /^[a-z][A-Za-z0-9_]*$/
|
|
339
357
|
klass.send("#{attr}#{POST}".to_sym, params)
|
|
340
358
|
}
|
|
@@ -355,5 +373,4 @@ module Delorean
|
|
|
355
373
|
######################################################################
|
|
356
374
|
|
|
357
375
|
end
|
|
358
|
-
|
|
359
376
|
end
|
data/lib/delorean/functions.rb
CHANGED
|
@@ -1,8 +1,9 @@
|
|
|
1
1
|
module Delorean
|
|
2
2
|
module Functions
|
|
3
|
+
|
|
3
4
|
######################################################################
|
|
4
5
|
|
|
5
|
-
def MAX(*args)
|
|
6
|
+
def MAX(_e, *args)
|
|
6
7
|
args.max
|
|
7
8
|
end
|
|
8
9
|
|
|
@@ -10,7 +11,7 @@ module Delorean
|
|
|
10
11
|
|
|
11
12
|
######################################################################
|
|
12
13
|
|
|
13
|
-
def MIN(*args)
|
|
14
|
+
def MIN(_e, *args)
|
|
14
15
|
args.min
|
|
15
16
|
end
|
|
16
17
|
|
|
@@ -18,14 +19,14 @@ module Delorean
|
|
|
18
19
|
|
|
19
20
|
######################################################################
|
|
20
21
|
|
|
21
|
-
def MAXLIST(arg)
|
|
22
|
+
def MAXLIST(_e, arg)
|
|
22
23
|
raise "argument must be list" unless arg.is_a? Array
|
|
23
24
|
arg.max
|
|
24
25
|
end
|
|
25
26
|
|
|
26
27
|
MAXLIST_SIG = [ 1, 1 ]
|
|
27
28
|
|
|
28
|
-
def MINLIST(arg)
|
|
29
|
+
def MINLIST(_e, arg)
|
|
29
30
|
raise "argument must be list" unless arg.is_a? Array
|
|
30
31
|
arg.min
|
|
31
32
|
end
|
|
@@ -34,7 +35,7 @@ module Delorean
|
|
|
34
35
|
|
|
35
36
|
######################################################################
|
|
36
37
|
|
|
37
|
-
def ROUND(number, *args)
|
|
38
|
+
def ROUND(_e, number, *args)
|
|
38
39
|
number.round(*args)
|
|
39
40
|
end
|
|
40
41
|
|
|
@@ -42,7 +43,27 @@ module Delorean
|
|
|
42
43
|
|
|
43
44
|
######################################################################
|
|
44
45
|
|
|
45
|
-
def
|
|
46
|
+
def NUMBER(_e, s)
|
|
47
|
+
return s if s.is_a?(Float) || s.is_a?(Fixnum)
|
|
48
|
+
raise "Can't convert #{s} to number" unless
|
|
49
|
+
s =~ /^\d+(\.\d+)?$/
|
|
50
|
+
|
|
51
|
+
s.to_f
|
|
52
|
+
end
|
|
53
|
+
|
|
54
|
+
NUMBER_SIG = [ 1, 1 ]
|
|
55
|
+
|
|
56
|
+
######################################################################
|
|
57
|
+
|
|
58
|
+
def STRING(_e, obj)
|
|
59
|
+
obj.to_s
|
|
60
|
+
end
|
|
61
|
+
|
|
62
|
+
STRING_SIG = [ 1, 1 ]
|
|
63
|
+
|
|
64
|
+
######################################################################
|
|
65
|
+
|
|
66
|
+
def TIMEPART(_e, time, part)
|
|
46
67
|
if time == Float::INFINITY
|
|
47
68
|
return time if part == "d"
|
|
48
69
|
raise "Can only access date part of Infinity"
|
|
@@ -50,58 +71,54 @@ module Delorean
|
|
|
50
71
|
|
|
51
72
|
raise "non-time arg to TIMEPART" unless time.is_a?(Time)
|
|
52
73
|
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
74
|
+
case part
|
|
75
|
+
when "h" then time.hour
|
|
76
|
+
when "m" then time.min
|
|
77
|
+
when "s" then time.sec
|
|
78
|
+
when "d" then time.to_date
|
|
79
|
+
else
|
|
80
|
+
raise "unknown part arg to TIMEPART"
|
|
81
|
+
end
|
|
59
82
|
end
|
|
60
83
|
|
|
61
84
|
TIMEPART_SIG = [ 2, 2 ]
|
|
62
85
|
|
|
63
86
|
######################################################################
|
|
64
87
|
|
|
65
|
-
def DATEPART(date, part)
|
|
88
|
+
def DATEPART(_e, date, part)
|
|
66
89
|
raise "non-date arg to DATEPART" unless date.is_a?(Date)
|
|
67
90
|
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
91
|
+
case part
|
|
92
|
+
when "m" then date.month
|
|
93
|
+
when "d" then date.day
|
|
94
|
+
when "y" then date.year
|
|
95
|
+
else
|
|
96
|
+
raise "unknown part arg to DATEPART"
|
|
97
|
+
end
|
|
73
98
|
end
|
|
74
99
|
|
|
75
100
|
DATEPART_SIG = [ 2, 2 ]
|
|
76
101
|
|
|
77
102
|
######################################################################
|
|
78
103
|
|
|
79
|
-
def DATEADD(date, interval, part)
|
|
104
|
+
def DATEADD(_e, date, interval, part)
|
|
80
105
|
raise "non-date arg to DATEADD" unless date.is_a?(Date)
|
|
81
106
|
raise "non-integer interval arg to DATEADD" unless interval.is_a?(Fixnum)
|
|
82
107
|
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
108
|
+
case part
|
|
109
|
+
when "m" then date >> interval
|
|
110
|
+
when "d" then date + interval
|
|
111
|
+
when "y" then date >> (interval * 12)
|
|
112
|
+
else
|
|
113
|
+
raise "unknown part arg to DATEADD"
|
|
114
|
+
end
|
|
88
115
|
end
|
|
89
116
|
|
|
90
117
|
DATEADD_SIG = [ 3, 3 ]
|
|
91
118
|
|
|
92
119
|
######################################################################
|
|
93
120
|
|
|
94
|
-
def
|
|
95
|
-
raise "non-array arg to INDEX" unless array.is_a?(Array)
|
|
96
|
-
raise "non-integer index on call to INDEX" unless i.is_a?(Fixnum)
|
|
97
|
-
array.at(i)
|
|
98
|
-
end
|
|
99
|
-
|
|
100
|
-
INDEX_SIG = [ 2, 2 ]
|
|
101
|
-
|
|
102
|
-
######################################################################
|
|
103
|
-
|
|
104
|
-
def FLATTEN(array, *args)
|
|
121
|
+
def FLATTEN(_e, array, *args)
|
|
105
122
|
raise "non-array arg to FLATTEN" unless array.is_a?(Array)
|
|
106
123
|
raise "non-integer flatten on call to FLATTEN" unless
|
|
107
124
|
(args.empty? || args[0].is_a?(Fixnum))
|
|
@@ -112,7 +129,7 @@ module Delorean
|
|
|
112
129
|
|
|
113
130
|
######################################################################
|
|
114
131
|
|
|
115
|
-
def ERR(*args)
|
|
132
|
+
def ERR(_e, *args)
|
|
116
133
|
str = args.map(&:to_s).join(", ")
|
|
117
134
|
raise str
|
|
118
135
|
end
|
|
@@ -121,14 +138,5 @@ module Delorean
|
|
|
121
138
|
|
|
122
139
|
######################################################################
|
|
123
140
|
|
|
124
|
-
def TOSYM(s)
|
|
125
|
-
# raise "non-String arg to SYM" unless s.is_a?(String)
|
|
126
|
-
s.to_sym
|
|
127
|
-
end
|
|
128
|
-
|
|
129
|
-
TOSYM_SIG = [ 1, 1 ]
|
|
130
|
-
|
|
131
|
-
######################################################################
|
|
132
|
-
|
|
133
141
|
end
|
|
134
142
|
end
|
data/lib/delorean/model.rb
CHANGED
|
@@ -1,3 +1,5 @@
|
|
|
1
|
+
require 'delorean/const'
|
|
2
|
+
|
|
1
3
|
module Delorean
|
|
2
4
|
module Model
|
|
3
5
|
def self.included(base)
|
|
@@ -17,7 +19,7 @@ module Delorean
|
|
|
17
19
|
if sig
|
|
18
20
|
sig = [sig, sig] if sig.is_a? Fixnum
|
|
19
21
|
raise "Bad signature" unless (sig.is_a? Array and sig.length==2)
|
|
20
|
-
self.const_set(name.to_s.upcase+SIG, sig)
|
|
22
|
+
self.const_set(name.to_s.upcase+Delorean::SIG, sig)
|
|
21
23
|
end
|
|
22
24
|
end
|
|
23
25
|
end
|
data/lib/delorean/nodes.rb
CHANGED
|
@@ -80,7 +80,6 @@ eos
|
|
|
80
80
|
class SubNode < SNode
|
|
81
81
|
def check(context, *)
|
|
82
82
|
mname = mod.m.text_value if defined?(mod.m)
|
|
83
|
-
|
|
84
83
|
context.parse_define_node(n.text_value, p.text_value, mname)
|
|
85
84
|
end
|
|
86
85
|
|
|
@@ -117,6 +116,20 @@ eos
|
|
|
117
116
|
end
|
|
118
117
|
end
|
|
119
118
|
|
|
119
|
+
class NodeAsValue < SNode
|
|
120
|
+
def check(context, *)
|
|
121
|
+
mname = mod.m.text_value if defined?(mod.m)
|
|
122
|
+
context.parse_check_defined_mod_node(c.text_value, mname)
|
|
123
|
+
[]
|
|
124
|
+
end
|
|
125
|
+
|
|
126
|
+
def rewrite(context)
|
|
127
|
+
node_name = c.text_value
|
|
128
|
+
mname = mod.m.text_value if defined?(mod.m)
|
|
129
|
+
context.super_name(node_name, mname)
|
|
130
|
+
end
|
|
131
|
+
end
|
|
132
|
+
|
|
120
133
|
# unary operator
|
|
121
134
|
class UnOp < SNode
|
|
122
135
|
def check(context, *)
|
|
@@ -140,6 +153,17 @@ eos
|
|
|
140
153
|
end
|
|
141
154
|
end
|
|
142
155
|
|
|
156
|
+
class IndexOp < SNode
|
|
157
|
+
def check(context, *)
|
|
158
|
+
vc, ac = v.check(context), args.check(context)
|
|
159
|
+
ac + vc
|
|
160
|
+
end
|
|
161
|
+
|
|
162
|
+
def rewrite(context)
|
|
163
|
+
"_index(#{v.rewrite(context)}, [#{args.rewrite(context)}], _e)"
|
|
164
|
+
end
|
|
165
|
+
end
|
|
166
|
+
|
|
143
167
|
class Literal < SNode
|
|
144
168
|
def check(context, *)
|
|
145
169
|
[]
|
|
@@ -175,36 +199,19 @@ eos
|
|
|
175
199
|
end
|
|
176
200
|
end
|
|
177
201
|
|
|
178
|
-
class
|
|
179
|
-
def check(context, *)
|
|
180
|
-
context.parse_call_attr(n.text_value, i.text_value)
|
|
181
|
-
[text_value]
|
|
182
|
-
end
|
|
183
|
-
|
|
184
|
-
def rewrite(context)
|
|
185
|
-
text_value + POST + '(_e)'
|
|
186
|
-
end
|
|
187
|
-
end
|
|
188
|
-
|
|
189
|
-
class GetAttr < SNode
|
|
202
|
+
class ExpGetAttr < SNode
|
|
190
203
|
def check(context, *)
|
|
191
|
-
|
|
204
|
+
v.check(context)
|
|
192
205
|
end
|
|
193
206
|
|
|
194
207
|
def rewrite(context)
|
|
195
208
|
attr_list = ga.text_value.split('.')
|
|
196
|
-
attr_list.inject(i.rewrite(context)) {|x, y| "_get_attr(#{x}, '#{y}')"}
|
|
197
|
-
end
|
|
198
|
-
end
|
|
199
209
|
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
end
|
|
210
|
+
# If ga.text_value is not "", then we need to drop the 1st
|
|
211
|
+
# element since it'll be "".
|
|
212
|
+
attr_list.shift
|
|
204
213
|
|
|
205
|
-
|
|
206
|
-
x = mfn.rewrite(context)
|
|
207
|
-
"_get_attr(#{x}, '#{i.text_value}')"
|
|
214
|
+
attr_list.inject(v.rewrite(context)) {|x, y| "_get_attr(#{x}, '#{y}', _e)"}
|
|
208
215
|
end
|
|
209
216
|
end
|
|
210
217
|
|
|
@@ -218,7 +225,7 @@ eos
|
|
|
218
225
|
end
|
|
219
226
|
|
|
220
227
|
def rewrite(context)
|
|
221
|
-
fn.text_value + "(" + (defined?(args) ? args.rewrite(context) : "") + ")"
|
|
228
|
+
fn.text_value + "(_e, " + (defined?(args) ? args.rewrite(context) : "") + ")"
|
|
222
229
|
end
|
|
223
230
|
end
|
|
224
231
|
|
|
@@ -297,13 +304,46 @@ eos
|
|
|
297
304
|
end
|
|
298
305
|
|
|
299
306
|
def rewrite(context)
|
|
300
|
-
res = "(#{e1.rewrite(context)})
|
|
307
|
+
res = "(#{e1.rewrite(context)})"
|
|
301
308
|
context.parse_define_var(i.text_value)
|
|
302
|
-
res += "|#{i.rewrite(context)}| (#{e2.rewrite(context)}) }"
|
|
303
|
-
|
|
304
309
|
res += ".select{|#{i.rewrite(context)}| (#{ifexp.e3.rewrite(context)}) }" if
|
|
305
310
|
defined?(ifexp.e3)
|
|
311
|
+
res += ".map{"
|
|
312
|
+
res += "|#{i.rewrite(context)}| (#{e2.rewrite(context)}) }"
|
|
313
|
+
context.parse_undef_var(i.text_value)
|
|
314
|
+
res
|
|
315
|
+
end
|
|
316
|
+
end
|
|
306
317
|
|
|
318
|
+
class HashComprehension < SNode
|
|
319
|
+
def check(context, *)
|
|
320
|
+
vname = i.text_value
|
|
321
|
+
|
|
322
|
+
e1c = e1.check(context)
|
|
323
|
+
context.parse_define_var(vname)
|
|
324
|
+
# need to check el/er/ei in a context where the comprehension var
|
|
325
|
+
# is defined.
|
|
326
|
+
elc = el.check(context)
|
|
327
|
+
erc = er.check(context)
|
|
328
|
+
eic = defined?(ifexp.ei) ? ifexp.ei.check(context) : []
|
|
329
|
+
|
|
330
|
+
context.parse_undef_var(vname)
|
|
331
|
+
elc.delete(vname)
|
|
332
|
+
erc.delete(vname)
|
|
333
|
+
eic.delete(vname)
|
|
334
|
+
|
|
335
|
+
e1c + elc + erc + eic
|
|
336
|
+
end
|
|
337
|
+
|
|
338
|
+
def rewrite(context)
|
|
339
|
+
res = "(#{e1.rewrite(context)})"
|
|
340
|
+
context.parse_define_var(i.text_value)
|
|
341
|
+
iw = i.rewrite(context)
|
|
342
|
+
res += ".select{|#{iw}| (#{ifexp.ei.rewrite(context)}) }" if
|
|
343
|
+
defined?(ifexp.ei)
|
|
344
|
+
res += ".inject({}){"
|
|
345
|
+
res += "|_h#{iw}, #{iw}| "+
|
|
346
|
+
"_h#{iw}[#{el.rewrite(context)}]=(#{er.rewrite(context)}); _h#{iw}}"
|
|
307
347
|
context.parse_undef_var(i.text_value)
|
|
308
348
|
res
|
|
309
349
|
end
|