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.
@@ -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