delorean_lang 0.0.34 → 0.0.38

Sign up to get free protection for your applications and to get access to all the features.
@@ -10,27 +10,33 @@ grammar Delorean
10
10
  /
11
11
  sp i:identifier sp? '=' sp? e:expression <Formula>
12
12
  /
13
- n:node_name ':' sp? mod:(m:node_name '::')? p:node_name <SubNode>
13
+ n:class_name ':' sp? mod:(m:class_name '::')? p:class_name <SubNode>
14
14
  /
15
- n:node_name ':' <BaseNode>
15
+ n:class_name ':' <BaseNode>
16
16
  /
17
- 'import' sp n:node_name sp v:integer <Import>
17
+ 'import' sp n:class_name sp v:integer <Import>
18
18
  end
19
19
 
20
- rule node_name
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' sp? v:expression sp?
28
- 'then' sp? e1:expression sp?
29
- 'else' sp? e2:expression <IfElse>
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:value sp? op:binary_op sp? e:expression <BinOp>
33
+ v:getattr_exp sp? '[' sp? args:fn_args sp? ']' <IndexOp>
32
34
  /
33
- value
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
- model_fn_getattr /
71
- model_fn /
72
- node_getattr /
73
- getattr /
74
- list_expr /
75
- hash_expr /
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:node_name '::')? c:class_name '(' sp? al:kw_args sp? ')' <ScriptCallNode>
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
@@ -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
- n = SortedSet.new
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
- enumerate_attrs_by_node(nil)
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 (or all if nil is passed in)
292
+ # enumerate qualified list of attrs by node
295
293
  def enumerate_attrs_by_node(node)
296
- @node_attrs.keys.inject({}) { |h, n|
297
- klass = @m.module_eval(n)
298
- h[n] = klass.methods.map(&:to_s).select {|x| x.end_with?(POST)}.map {|x|
299
- x.sub(/#{POST}$/, '')
300
- } if node == n || node.nil?
301
- h
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
- ps = Set.new
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 node '#{node}'" unless node =~ /^[A-Z][a-zA-Z0-9_]*$/
339
+ raise "bad params" unless params.is_a?(Hash)
328
340
 
329
- begin
330
- klass = @m.module_eval(node)
331
- rescue NameError
332
- err(UndefinedNodeError, "node #{node} is undefined")
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
@@ -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 TIMEPART(time, part)
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
- return time.hour if part == "h"
54
- return time.min if part == "m"
55
- return time.sec if part == "s"
56
- return time.to_date if part == "d"
57
-
58
- raise "unknown part arg to TIMEPART"
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
- return date.month if part == "m"
69
- return date.day if part == "d"
70
- return date.year if part == "y"
71
-
72
- raise "unknown part arg to DATEPART"
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
- return date >> interval if part == "m"
84
- return date + interval if part == "d"
85
- return date >> (interval * 12) if part == "y"
86
-
87
- raise "unknown part arg to DATEADD"
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 INDEX(array, i)
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
@@ -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
@@ -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 NodeGetAttr < SNode
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
- i.check(context)
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
- class ModelFnGetAttr < SNode
201
- def check(context, *)
202
- mfn.check(context)
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
- def rewrite(context)
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)}).map{"
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