delorean_lang 1.0.0 → 1.1.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -46,6 +46,16 @@ grammar Delorean
46
46
  getattr_exp
47
47
  end
48
48
 
49
+ rule block_args
50
+ sp4 sp4 sp? i:identifier sp? '=?' sp1? e:expression <BlockParameterDefault>
51
+ /
52
+ sp4 sp4 sp? i:identifier sp? '=?' <BlockParameter>
53
+ end
54
+
55
+ rule block_formulas
56
+ sp4 sp4 sp? i:identifier sp? '=' sp? e:expression <BlockFormula>
57
+ end
58
+
49
59
  rule getattr_exp
50
60
  v:value dotted:dotted <GetattrExp>
51
61
  /
@@ -61,7 +71,11 @@ grammar Delorean
61
71
  /
62
72
  '(' sp? al:kw_args? sp? ')' <NodeCall>
63
73
  /
74
+ '.' sp? i:identifier '(' sp? al:fn_args? sp? ')' b_args:block_args* expressions:block_formulas+ <BlockExpression>
75
+ /
64
76
  '.' sp? i:identifier '(' sp? al:fn_args? sp? ')' <Call>
77
+ /
78
+ '.' sp? i:identifier b_args:block_args* expressions:block_formulas+ <BlockExpression>
65
79
  /
66
80
  '.' sp? i:(identifier / integer) <GetAttr>
67
81
  end
@@ -159,6 +173,10 @@ grammar Delorean
159
173
  args_rest:(sp? ',' sp? al:kw_args?)? <KwArgs>
160
174
  end
161
175
 
176
+ # rule block_args
177
+ # '|' sp? args:unpack_args sp? '|'
178
+ # end
179
+
162
180
  rule decimal
163
181
  i:integer '.' [0-9]+ <Literal>
164
182
  end
@@ -168,7 +186,7 @@ grammar Delorean
168
186
  end
169
187
 
170
188
  rule identifier
171
- [a-z] [a-zA-Z0-9_]* <Identifier>
189
+ [a-z] [a-zA-Z0-9_]* '?'? <Identifier>
172
190
  end
173
191
 
174
192
  rule boolean
@@ -192,10 +210,15 @@ grammar Delorean
192
210
  ' '
193
211
  end
194
212
 
213
+ rule sp1
214
+ ' '
215
+ end
216
+
195
217
  rule sp
196
218
  [\s]+
197
219
  end
198
220
 
221
+
199
222
  rule string
200
223
  '"' ('\"' / !'"' .)* '"' <IString>
201
224
  /
@@ -252,7 +252,9 @@ module Delorean
252
252
  multi_line = nil
253
253
  @multi_no = nil
254
254
 
255
- source.each_line do |line|
255
+ lines = source.each_line.to_a
256
+
257
+ lines.each_with_index do |line, index|
256
258
  @line_no += 1
257
259
 
258
260
  # skip comments
@@ -279,6 +281,24 @@ module Delorean
279
281
  end
280
282
  end
281
283
 
284
+ # Initially Delorean code is parsed by single line.
285
+ # If line can not be parsed as valid Delorean expressions, parser
286
+ # would combine it with the following lines that are indented by more
287
+ # than 4 spaces and attempt to parse it again.
288
+
289
+ # However the first line of method with block can be parsed as a valid
290
+ # method or attribute call. In order to avoid that, we had to add this
291
+ # lookahead hack, that treats any expressions as multiline when
292
+ # the following line is indented by more that 4 spaces.
293
+ next_line = lines[index + 1] || ''
294
+
295
+ if /\A {5}/.match?(next_line)
296
+ multi_line ||= ''
297
+ multi_line += line
298
+ @multi_no ||= @line_no
299
+ next
300
+ end
301
+
282
302
  t = parser.parse(line)
283
303
 
284
304
  if !t
@@ -123,6 +123,14 @@ eos
123
123
 
124
124
  class Formula < SNode
125
125
  def check(context, *)
126
+ if i.text_value.include?('?')
127
+ raise Delorean::ParseError.new(
128
+ '? in formula names not supported',
129
+ context.module_name,
130
+ context.line_no
131
+ )
132
+ end
133
+
126
134
  context.parse_define_attr(i.text_value, e.check(context))
127
135
  end
128
136
 
@@ -410,6 +418,148 @@ eos
410
418
  end
411
419
  end
412
420
 
421
+ class BlockParameter < Parameter
422
+ def check(context)
423
+ context.parse_define_var(i.text_value)
424
+ context.parse_undef_var(i.text_value)
425
+ end
426
+
427
+ def rewrite(context)
428
+ a_name = i.text_value
429
+ expr = defined?(e) ? e.rewrite(context) : ''
430
+ expr = expr.strip
431
+
432
+ return "#{a_name}#{POST}" if expr.empty?
433
+
434
+ "#{a_name}#{POST} = #{expr}"
435
+ end
436
+
437
+ def force_def(context)
438
+ context.parse_define_var(i.text_value)
439
+ end
440
+
441
+ def force_undef(context)
442
+ context.parse_undef_var(i.text_value)
443
+ end
444
+ end
445
+
446
+ class BlockParameterDefault < BlockParameter
447
+ def check(context)
448
+ context.parse_define_var(i.text_value)
449
+
450
+ e.check(context)
451
+ context.parse_undef_var(i.text_value)
452
+ end
453
+ end
454
+
455
+ class BlockFormula < SNode
456
+ def check(context, *)
457
+ if i.text_value.include?('?')
458
+ raise Delorean::ParseError.new(
459
+ '? in formula names not supported',
460
+ context.module_name,
461
+ context.line_no
462
+ )
463
+ end
464
+
465
+ context.parse_define_var(i.text_value)
466
+ context.parse_undef_var(i.text_value)
467
+ end
468
+
469
+ def rewrite(context)
470
+ "#{i.text_value}#{POST} = #{e.rewrite(context)}"
471
+ end
472
+
473
+ def force_def(context)
474
+ context.parse_define_var(i.text_value)
475
+ end
476
+
477
+ def force_undef(context)
478
+ context.parse_undef_var(i.text_value)
479
+ end
480
+ end
481
+
482
+ class BlockExpression < SNode
483
+ def check(context, *)
484
+ if respond_to?(:al)
485
+ al.text_value.empty? ? [] : al.check(context)
486
+ end
487
+
488
+ b_args.elements.each do |element|
489
+ element.check(context)
490
+ element.force_def(context)
491
+ end
492
+
493
+ formulas = expressions.elements.select do |elem|
494
+ elem.is_a? BlockFormula
495
+ end
496
+
497
+ result_formula = formulas.find do |formula|
498
+ formula.i.text_value == 'result'
499
+ end
500
+
501
+ unless result_formula
502
+ raise Delorean::ParseError.new(
503
+ 'result formula is required in blocks',
504
+ context.module_name,
505
+ context.line_no
506
+ )
507
+ end
508
+
509
+ expressions.elements.each do |element|
510
+ element.check(context)
511
+ end
512
+
513
+ b_args.elements.each do |element|
514
+ element.force_undef(context)
515
+ end
516
+ end
517
+
518
+ def rewrite(context, vcode)
519
+ if !respond_to?(:al) || al.text_value.empty?
520
+ args_str = ''
521
+ arg_count = 0
522
+ else
523
+ args_str = al.rewrite(context)
524
+ arg_count = al.arg_count
525
+ end
526
+ if vcode.is_a?(ClassText)
527
+ # FIXME: Do we really need this check here?
528
+ # ruby class call
529
+ class_name = vcode.text
530
+ context.parse_check_call_fn(i.text_value, arg_count, class_name)
531
+ end
532
+
533
+ b_args.elements.each do |element|
534
+ element.force_def(context)
535
+ end
536
+
537
+ block_args_str = if b_args.elements.any?
538
+ block_args = b_args.elements.map do |v|
539
+ v.rewrite(context)
540
+ end
541
+
542
+ "|#{block_args.join(', ')}|"
543
+ else
544
+ ''
545
+ end
546
+
547
+ expr_arr = expressions.elements.map do |v|
548
+ v.rewrite(context)
549
+ end + ["result#{POST}"]
550
+
551
+ expression_str = expr_arr.join('; ')
552
+
553
+ b_args.elements.each do |element|
554
+ element.force_undef(context)
555
+ end
556
+
557
+ block = "{ #{block_args_str} #{expression_str} }"
558
+
559
+ "_instance_call(#{vcode}, '#{i.text_value}', [#{args_str}], _e) #{block}"
560
+ end
561
+ end
562
+
413
563
  class NodeCall < SNode
414
564
  def check(context, *)
415
565
  al.text_value.empty? ? [] : al.check(context)
@@ -18,44 +18,59 @@ module Delorean
18
18
  private
19
19
 
20
20
  def _add_default_methods
21
+ add_method :abs do |method|
22
+ method.called_on Numeric
23
+ end
24
+
25
+ add_method :all? do |method|
26
+ method.called_on Enumerable
27
+ end
28
+
29
+ add_method :any, match_to: :any?
30
+
31
+ add_method :any? do |method|
32
+ method.called_on Enumerable
33
+ end
34
+
21
35
  add_method :attributes do |method|
22
36
  method.called_on ActiveRecord::Base
23
37
  method.called_on ActiveRecord::Relation
24
38
  end
25
39
 
40
+ add_method :beginning_of_month do |method|
41
+ DT_TYPES.each do |type|
42
+ method.called_on type
43
+ end
44
+ end
45
+
46
+ add_method :between, match_to: :between?
47
+
26
48
  add_method :between? do |method|
27
49
  method.called_on String, with: [String, String]
28
50
  method.called_on Numeric, with: [Numeric, Numeric]
29
51
  end
30
52
 
31
- add_method :between, match_to: :between?
53
+ add_method :ceil do |method|
54
+ method.called_on Numeric
55
+ end
32
56
 
33
57
  add_method :compact do |method|
34
58
  method.called_on Array
35
59
  method.called_on Hash
36
60
  end
37
61
 
38
- add_method :to_set do |method|
39
- method.called_on Array
40
- end
41
-
42
- add_method :flatten do |method|
43
- method.called_on Array, with: [NUM_OR_NIL]
62
+ add_method :day do |method|
63
+ DT_TYPES.each do |type|
64
+ method.called_on type
65
+ end
44
66
  end
45
67
 
46
- add_method :length do |method|
68
+ add_method :downcase do |method|
47
69
  method.called_on String
48
- method.called_on Enumerable
49
70
  end
50
71
 
51
- add_method :max do |method|
52
- method.called_on Array
53
- end
54
-
55
- add_method :member, match_to: :member?
56
-
57
- add_method :member? do |method|
58
- method.called_on Enumerable, with: [Object]
72
+ add_method :each_slice do |method|
73
+ method.called_on Array, with: [Integer]
59
74
  end
60
75
 
61
76
  add_method :empty, match_to: :empty?
@@ -64,134 +79,101 @@ module Delorean
64
79
  method.called_on Enumerable
65
80
  end
66
81
 
67
- add_method :except do |method|
68
- method.called_on Hash, with: [String] + [[nil, String]] * 9
69
- end
70
-
71
- add_method :reverse do |method|
72
- method.called_on Array
73
- end
74
-
75
- add_method :slice do |method|
76
- method.called_on Array, with: [Integer, Integer]
77
- end
78
-
79
- add_method :each_slice do |method|
80
- method.called_on Array, with: [Integer]
82
+ add_method :end_of_month do |method|
83
+ DT_TYPES.each do |type|
84
+ method.called_on type
85
+ end
81
86
  end
82
87
 
83
- add_method :sort do |method|
84
- method.called_on Array
88
+ add_method :except do |method|
89
+ method.called_on Hash, with: [String] + [[nil, String]] * 9
85
90
  end
86
91
 
87
- add_method :split do |method|
88
- method.called_on String, with: [String]
92
+ add_method :fetch do |method|
93
+ method.called_on Hash, with: [Object, [Object]]
89
94
  end
90
95
 
91
- add_method :uniq do |method|
92
- method.called_on Array
96
+ add_method :find do |method|
97
+ method.called_on Enumerable
93
98
  end
94
99
 
95
- add_method :sum do |method|
96
- method.called_on Array
100
+ add_method :first do |method|
101
+ method.called_on ActiveRecord::Relation, with: [NUM_OR_NIL]
102
+ method.called_on Enumerable, with: [NUM_OR_NIL]
97
103
  end
98
104
 
99
- add_method :transpose do |method|
100
- method.called_on Array
105
+ add_method :flatten do |method|
106
+ method.called_on Array, with: [NUM_OR_NIL]
101
107
  end
102
108
 
103
- add_method :join do |method|
104
- method.called_on Array, with: [String]
109
+ add_method :floor do |method|
110
+ method.called_on Numeric
105
111
  end
106
112
 
107
- add_method :zip do |method|
108
- method.called_on Array, with: [Array, [Array, nil], [Array, nil]]
113
+ add_method :hour do |method|
114
+ DT_TYPES.each do |type|
115
+ method.called_on type
116
+ end
109
117
  end
110
118
 
111
119
  add_method :index do |method|
112
120
  method.called_on Array, with: [[Object]]
113
121
  end
114
122
 
115
- add_method :product do |method|
116
- method.called_on Array, with: [Array]
117
- end
118
-
119
- add_method :first do |method|
120
- method.called_on ActiveRecord::Relation, with: [NUM_OR_NIL]
121
- method.called_on Enumerable, with: [NUM_OR_NIL]
122
- end
123
-
124
- add_method :last do |method|
125
- method.called_on ActiveRecord::Relation, with: [NUM_OR_NIL]
126
- method.called_on Enumerable, with: [NUM_OR_NIL]
127
- end
128
-
129
123
  add_method :intersection do |method|
130
124
  method.called_on Set, with: [Enumerable]
131
125
  end
132
126
 
133
- add_method :union do |method|
134
- method.called_on Set, with: [Enumerable]
127
+ add_method :iso8601 do |method|
128
+ DT_TYPES.each do |type|
129
+ method.called_on type
130
+ end
135
131
  end
136
132
 
137
- add_method :keys do |method|
138
- method.called_on Hash
133
+ add_method :join do |method|
134
+ method.called_on Array, with: [String]
139
135
  end
140
136
 
141
- add_method :values do |method|
137
+ add_method :keys do |method|
142
138
  method.called_on Hash
143
139
  end
144
140
 
145
- add_method :fetch do |method|
146
- method.called_on Hash, with: [Object, [Object]]
147
- end
148
-
149
- add_method :upcase do |method|
150
- method.called_on String
141
+ add_method :last do |method|
142
+ method.called_on ActiveRecord::Relation, with: [NUM_OR_NIL]
143
+ method.called_on Enumerable, with: [NUM_OR_NIL]
151
144
  end
152
145
 
153
- add_method :downcase do |method|
146
+ add_method :length do |method|
154
147
  method.called_on String
148
+ method.called_on Enumerable
155
149
  end
156
150
 
157
151
  add_method :match do |method|
158
152
  method.called_on String, with: [[String], NUM_OR_NIL]
159
153
  end
160
154
 
161
- add_method :iso8601 do |method|
162
- DT_TYPES.each do |type|
163
- method.called_on type
164
- end
155
+ add_method :max do |method|
156
+ method.called_on Array
165
157
  end
166
158
 
167
- add_method :hour do |method|
168
- DT_TYPES.each do |type|
169
- method.called_on type
170
- end
159
+ add_method :max_by do |method|
160
+ method.called_on Enumerable
171
161
  end
172
162
 
173
- add_method :min do |method|
174
- (DT_TYPES + [Array]).each do |type|
175
- method.called_on type
176
- end
177
- end
163
+ add_method :member, match_to: :member?
178
164
 
179
- add_method :sec do |method|
180
- DT_TYPES.each do |type|
181
- method.called_on type
182
- end
165
+ add_method :member? do |method|
166
+ method.called_on Enumerable, with: [Object]
183
167
  end
184
168
 
185
- add_method :to_date do |method|
186
- (DT_TYPES + [String]).each do |type|
169
+ add_method :min do |method|
170
+ (DT_TYPES + [Array]).each do |type|
187
171
  method.called_on type
188
172
  end
189
173
  end
190
174
 
191
- add_method :to_time do |method|
192
- (DT_TYPES + [String]).each do |type|
193
- method.called_on type
194
- end
175
+ add_method :min_by do |method|
176
+ method.called_on Enumerable
195
177
  end
196
178
 
197
179
  add_method :month do |method|
@@ -200,19 +182,23 @@ module Delorean
200
182
  end
201
183
  end
202
184
 
203
- add_method :day do |method|
185
+ add_method :next_day do |method|
204
186
  DT_TYPES.each do |type|
205
- method.called_on type
187
+ method.called_on type, with: [NUM_OR_NIL]
206
188
  end
207
189
  end
208
190
 
209
- add_method :year do |method|
191
+ add_method :next_month do |method|
210
192
  DT_TYPES.each do |type|
211
- method.called_on type
193
+ method.called_on type, with: [NUM_OR_NIL]
212
194
  end
213
195
  end
214
196
 
215
- add_method :next_month do |method|
197
+ add_method :none? do |method|
198
+ method.called_on Enumerable
199
+ end
200
+
201
+ add_method :prev_day do |method|
216
202
  DT_TYPES.each do |type|
217
203
  method.called_on type, with: [NUM_OR_NIL]
218
204
  end
@@ -224,32 +210,64 @@ module Delorean
224
210
  end
225
211
  end
226
212
 
227
- add_method :beginning_of_month do |method|
228
- DT_TYPES.each do |type|
229
- method.called_on type
230
- end
213
+ add_method :product do |method|
214
+ method.called_on Array, with: [Array]
231
215
  end
232
216
 
233
- add_method :end_of_month do |method|
217
+ add_method :reduce do |method|
218
+ method.called_on Enumerable, with: [[nil, Object]]
219
+ end
220
+
221
+ add_method :reject do |method|
222
+ method.called_on Enumerable
223
+ end
224
+
225
+ add_method :reverse do |method|
226
+ method.called_on Array
227
+ end
228
+
229
+ add_method :round do |method|
230
+ method.called_on Numeric, with: [[nil, Integer]]
231
+ end
232
+
233
+ add_method :sec do |method|
234
234
  DT_TYPES.each do |type|
235
235
  method.called_on type
236
236
  end
237
237
  end
238
238
 
239
- add_method :next_day do |method|
240
- DT_TYPES.each do |type|
241
- method.called_on type, with: [NUM_OR_NIL]
242
- end
239
+ add_method :select do |method|
240
+ method.called_on Enumerable
243
241
  end
244
242
 
245
- add_method :prev_day do |method|
246
- DT_TYPES.each do |type|
247
- method.called_on type, with: [NUM_OR_NIL]
243
+ add_method :slice do |method|
244
+ method.called_on Array, with: [Integer, Integer]
245
+ end
246
+
247
+ add_method :sort do |method|
248
+ method.called_on Array
249
+ end
250
+
251
+ add_method :split do |method|
252
+ method.called_on String, with: [String]
253
+ end
254
+
255
+ add_method :sum do |method|
256
+ method.called_on Array
257
+ end
258
+
259
+ add_method :to_a do |method|
260
+ method.called_on Object
261
+ end
262
+
263
+ add_method :to_d do |method|
264
+ NUM_OR_STR.each do |type|
265
+ method.called_on type
248
266
  end
249
267
  end
250
268
 
251
- add_method :to_i do |method|
252
- (NUM_OR_STR + TI_TYPES).each do |type|
269
+ add_method :to_date do |method|
270
+ (DT_TYPES + [String]).each do |type|
253
271
  method.called_on type
254
272
  end
255
273
  end
@@ -260,42 +278,62 @@ module Delorean
260
278
  end
261
279
  end
262
280
 
263
- add_method :to_d do |method|
264
- NUM_OR_STR.each do |type|
281
+ add_method :to_i do |method|
282
+ (NUM_OR_STR + TI_TYPES).each do |type|
265
283
  method.called_on type
266
284
  end
267
285
  end
268
286
 
269
- add_method :to_s do |method|
287
+ add_method :to_json do |method|
270
288
  method.called_on Object
271
289
  end
272
290
 
273
- add_method :to_a do |method|
291
+ add_method :to_s do |method|
274
292
  method.called_on Object
275
293
  end
276
294
 
277
- add_method :to_json do |method|
278
- method.called_on Object
295
+ add_method :to_set do |method|
296
+ method.called_on Array
279
297
  end
280
298
 
281
- add_method :abs do |method|
282
- method.called_on Numeric
299
+ add_method :to_time do |method|
300
+ (DT_TYPES + [String]).each do |type|
301
+ method.called_on type
302
+ end
283
303
  end
284
304
 
285
- add_method :round do |method|
305
+ add_method :transpose do |method|
306
+ method.called_on Array
307
+ end
308
+
309
+ add_method :truncate do |method|
286
310
  method.called_on Numeric, with: [[nil, Integer]]
287
311
  end
288
312
 
289
- add_method :ceil do |method|
290
- method.called_on Numeric
313
+ add_method :union do |method|
314
+ method.called_on Set, with: [Enumerable]
291
315
  end
292
316
 
293
- add_method :floor do |method|
294
- method.called_on Numeric
317
+ add_method :uniq do |method|
318
+ method.called_on Enumerable
295
319
  end
296
320
 
297
- add_method :truncate do |method|
298
- method.called_on Numeric, with: [[nil, Integer]]
321
+ add_method :upcase do |method|
322
+ method.called_on String
323
+ end
324
+
325
+ add_method :values do |method|
326
+ method.called_on Hash
327
+ end
328
+
329
+ add_method :year do |method|
330
+ DT_TYPES.each do |type|
331
+ method.called_on type
332
+ end
333
+ end
334
+
335
+ add_method :zip do |method|
336
+ method.called_on Array, with: [Array, [Array, nil], [Array, nil]]
299
337
  end
300
338
  end
301
339
  end