delorean_lang 0.5.1 → 0.5.2

Sign up to get free protection for your applications and to get access to all the features.
Files changed (41) hide show
  1. checksums.yaml +5 -5
  2. data/.gitlab-ci.yml +1 -2
  3. data/.rubocop.yml +45 -5
  4. data/.rubocop_todo.yml +1 -634
  5. data/Gemfile +3 -1
  6. data/README.md +22 -0
  7. data/Rakefile +3 -1
  8. data/delorean.gemspec +18 -17
  9. data/lib/delorean/abstract_container.rb +4 -2
  10. data/lib/delorean/base.rb +30 -27
  11. data/lib/delorean/cache.rb +2 -0
  12. data/lib/delorean/cache/adapters.rb +2 -0
  13. data/lib/delorean/cache/adapters/base.rb +2 -0
  14. data/lib/delorean/cache/adapters/ruby_cache.rb +5 -0
  15. data/lib/delorean/const.rb +5 -3
  16. data/lib/delorean/debug.rb +6 -5
  17. data/lib/delorean/delorean.rb +466 -147
  18. data/lib/delorean/delorean.treetop +13 -1
  19. data/lib/delorean/engine.rb +61 -50
  20. data/lib/delorean/error.rb +2 -1
  21. data/lib/delorean/model.rb +12 -9
  22. data/lib/delorean/nodes.rb +130 -67
  23. data/lib/delorean/ruby.rb +2 -0
  24. data/lib/delorean/ruby/whitelists.rb +2 -0
  25. data/lib/delorean/ruby/whitelists/base.rb +7 -3
  26. data/lib/delorean/ruby/whitelists/default.rb +6 -6
  27. data/lib/delorean/ruby/whitelists/empty.rb +3 -2
  28. data/lib/delorean/ruby/whitelists/matchers.rb +2 -0
  29. data/lib/delorean/ruby/whitelists/matchers/arguments.rb +2 -0
  30. data/lib/delorean/ruby/whitelists/matchers/method.rb +5 -2
  31. data/lib/delorean/ruby/whitelists/whitelist_error.rb +2 -0
  32. data/lib/delorean/version.rb +3 -1
  33. data/lib/delorean_lang.rb +3 -1
  34. data/spec/cache_spec.rb +4 -2
  35. data/spec/dev_spec.rb +68 -69
  36. data/spec/eval_spec.rb +824 -729
  37. data/spec/func_spec.rb +172 -176
  38. data/spec/parse_spec.rb +516 -522
  39. data/spec/ruby/whitelist_spec.rb +6 -3
  40. data/spec/spec_helper.rb +26 -23
  41. metadata +27 -27
@@ -10,17 +10,28 @@ grammar Delorean
10
10
  /
11
11
  sp4 i:identifier sp? '=' sp? e:expression <Formula>
12
12
  /
13
+ n:class_name ':' sp? mod:(m:class_name_import_nested) <SubNodeNested> # FIXME: requires to be above SubNode statement, otherwise doesn't work
14
+ /
13
15
  n:class_name ':' sp? mod:(m:class_name '::')? p:class_name <SubNode>
14
16
  /
15
17
  n:class_name ':' <BaseNode>
16
18
  /
17
- 'import' sp n:class_name <Import>
19
+ 'import' sp n:class_name_import <Import>
18
20
  end
19
21
 
20
22
  rule class_name
21
23
  [A-Z] [a-zA-Z0-9_]*
22
24
  end
23
25
 
26
+ rule class_name_import
27
+ [A-Z] [a-zA-Z0-9_]* ('::' [A-Z] [a-zA-Z0-9_]*)*
28
+ end
29
+
30
+ # FIXME: Hacky way to skip Module::Node cases, so only Module::NestedModule::Node will pass
31
+ rule class_name_import_nested
32
+ [A-Z] [a-zA-Z0-9_]* (('::' [A-Z] [a-zA-Z0-9_]*) 2..)
33
+ end
34
+
24
35
  rule expression
25
36
  'ERR(' sp? args:fn_args? sp? ')' <ErrorOp>
26
37
  /
@@ -119,6 +130,7 @@ grammar Delorean
119
130
  list_expr /
120
131
  set_expr /
121
132
  hash_expr /
133
+ c:class_name_import <NodeAsValueNested> / # FIXME: requires to be above NodeAsValue statement, otherwise doesn't work
122
134
  mod:(m:class_name '::')? c:class_name <NodeAsValue> /
123
135
  '(' sp? e:expression sp? ')' <Expr>
124
136
  end
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  require 'delorean/const'
2
4
  require 'delorean/base'
3
5
  require 'set'
@@ -6,9 +8,9 @@ require 'pp'
6
8
  module Delorean
7
9
  class Engine
8
10
  attr_reader :last_node, :module_name, :line_no,
9
- :comp_set, :pm, :m, :imports, :sset
11
+ :comp_set, :pm, :m, :imports, :sset
10
12
 
11
- def initialize(module_name, sset=nil)
13
+ def initialize(module_name, sset = nil)
12
14
  # name of current module
13
15
  @module_name = module_name
14
16
  @sset = sset
@@ -16,9 +18,12 @@ module Delorean
16
18
  end
17
19
 
18
20
  def reset
19
- @m, @pm = nil, nil
20
- @last_node, @node_attrs = nil, {}
21
- @line_no, @multi_no = 0, nil
21
+ @m = nil
22
+ @pm = nil
23
+ @last_node = nil
24
+ @node_attrs = {}
25
+ @line_no = 0
26
+ @multi_no = nil
22
27
 
23
28
  # set of comprehension vars
24
29
  @comp_set = Set.new
@@ -41,24 +46,24 @@ module Delorean
41
46
  end
42
47
 
43
48
  def parse_import(name)
44
- err(ParseError, "No script set") unless sset
49
+ err(ParseError, 'No script set') unless sset
45
50
 
46
51
  err(ParseError, "Module #{name} importing itself") if
47
52
  name == module_name
48
53
 
49
54
  begin
50
55
  @imports[name] = sset.get_engine(name)
51
- rescue => exc
56
+ rescue StandardError => exc
52
57
  err(ImportError, exc.to_s)
53
58
  end
54
59
 
55
- @pm.const_set("#{MOD}#{name}", @imports[name].pm)
60
+ @pm.const_set("#{MOD}#{name.gsub('::', '__')}", @imports[name].pm)
56
61
  end
57
62
 
58
63
  def gen_import(name)
59
64
  @imports.merge!(@imports[name].imports)
60
65
 
61
- @m.const_set("#{MOD}#{name}", @imports[name].m)
66
+ @m.const_set("#{MOD}#{name.gsub('::', '__')}", @imports[name].m)
62
67
  end
63
68
 
64
69
  def get_import_engine(name)
@@ -66,7 +71,7 @@ module Delorean
66
71
  @imports[name]
67
72
  end
68
73
 
69
- def is_node_defined(name)
74
+ def node_defined?(name)
70
75
  @pm.constants.member? name.to_sym
71
76
  end
72
77
 
@@ -74,7 +79,7 @@ module Delorean
74
79
  # method about our expectation. flag=true means that we make sure
75
80
  # that name is defined. flag=false is the opposite.
76
81
  def parse_check_defined_node(name, flag)
77
- isdef = is_node_defined(name)
82
+ isdef = node_defined?(name)
78
83
 
79
84
  if isdef != flag
80
85
  isdef ? err(RedefinedError, "#{name} already defined") :
@@ -83,7 +88,7 @@ module Delorean
83
88
  end
84
89
 
85
90
  def super_name(pname, mname)
86
- mname ? "#{MOD}#{mname}::#{pname}" : pname
91
+ mname ? "#{MOD}#{mname.gsub('::', '__')}::#{pname}" : pname
87
92
  end
88
93
 
89
94
  def parse_check_defined_mod_node(pname, mname)
@@ -91,13 +96,15 @@ module Delorean
91
96
  engine.parse_check_defined_node(pname, true)
92
97
  end
93
98
 
94
- def parse_define_node(name, pname, mname=nil)
99
+ def parse_define_node(name, pname, mname = nil)
95
100
  parse_check_defined_node(name, false)
96
101
  parse_check_defined_mod_node(pname, mname) if pname
97
102
 
98
103
  sname = pname ? super_name(pname, mname) : 'Object'
99
104
 
100
- @pm.module_eval("class #{name} < #{sname}; end")
105
+ @pm.module_eval <<-RUBY, __FILE__, __LINE__ + 1
106
+ class #{name} < #{sname}; end
107
+ RUBY
101
108
 
102
109
  # latest defined node
103
110
  @last_node = name
@@ -125,20 +132,21 @@ module Delorean
125
132
 
126
133
  # Parse-time check to see if attr is available on current node.
127
134
  def parse_call_last_node_attr(attr_name)
128
- err(ParseError, "Not inside a node") unless @last_node
135
+ err(ParseError, 'Not inside a node') unless @last_node
129
136
  parse_call_attr(@last_node, attr_name)
130
137
  end
131
138
 
132
139
  def parse_define_var(var_name)
133
- err(RedefinedError,
134
- "List comprehension can't redefine variable '#{var_name}'") if
135
- comp_set.member? var_name
140
+ if comp_set.member? var_name
141
+ err(RedefinedError,
142
+ "List comprehension can't redefine variable '#{var_name}'")
143
+ end
136
144
 
137
145
  comp_set.add var_name
138
146
  end
139
147
 
140
148
  def parse_undef_var(var_name)
141
- err(ParseError, "internal error") unless comp_set.member? var_name
149
+ err(ParseError, 'internal error') unless comp_set.member? var_name
142
150
  comp_set.delete var_name
143
151
  end
144
152
 
@@ -152,10 +160,10 @@ module Delorean
152
160
 
153
161
  @node_attrs[@last_node] << name
154
162
 
155
- checks = spec.map { |a|
163
+ checks = spec.map do |a|
156
164
  n = a.index('.') ? a : "#{@last_node}.#{a}"
157
165
  "_x.member?('#{n}') ? raise('#{n}') : #{a}#{POST}(_x + ['#{n}'])"
158
- }.join(';')
166
+ end.join(';')
159
167
 
160
168
  code =
161
169
  "class #{@last_node}; def self.#{name}#{POST}(_x); #{checks}; end; end"
@@ -195,7 +203,7 @@ module Delorean
195
203
  raise exc.new(msg, @module_name, curr_line)
196
204
  end
197
205
 
198
- def parse_check_call_fn(fn, argcount, class_name=nil)
206
+ def parse_check_call_fn(fn, argcount, class_name = nil)
199
207
  klass = case class_name
200
208
  when nil
201
209
  @m::BaseClass
@@ -234,7 +242,7 @@ module Delorean
234
242
  # generate ruby code
235
243
  gen = t.rewrite(self)
236
244
  rescue RuntimeError => exc
237
- err(ParseError, "codegen error: " + exc.message)
245
+ err(ParseError, 'codegen error: ' + exc.message)
238
246
  end
239
247
 
240
248
  # puts gen
@@ -242,9 +250,9 @@ module Delorean
242
250
  begin
243
251
  # evaluate generated code in @m
244
252
  @m.module_eval(gen, "#{MOD}#{module_name}", curr_line)
245
- rescue => exc
253
+ rescue StandardError => exc
246
254
  # bad ruby code generated, shoudn't happen
247
- err(ParseError, "codegen error: " + exc.message)
255
+ err(ParseError, 'codegen error: ' + exc.message)
248
256
  end
249
257
  end
250
258
 
@@ -253,20 +261,22 @@ module Delorean
253
261
 
254
262
  # @m module is used at runtime for code evaluation. @pm module
255
263
  # is only used during parsing to check for errors.
256
- @m, @pm = BaseModule.clone, Module.new
264
+ @m = BaseModule.clone
265
+ @pm = Module.new
257
266
 
258
- multi_line, @multi_no = nil, nil
267
+ multi_line = nil
268
+ @multi_no = nil
259
269
 
260
270
  source.each_line do |line|
261
271
  @line_no += 1
262
272
 
263
273
  # skip comments
264
- next if line.match(/^\s*\#/)
274
+ next if line =~ /^\s*\#/
265
275
 
266
276
  # remove trailing blanks
267
277
  line.rstrip!
268
278
 
269
- next if line.length == 0
279
+ next if line.empty?
270
280
 
271
281
  if multi_line
272
282
  # if line starts with >4 spaces, assume it's a multline
@@ -276,17 +286,18 @@ module Delorean
276
286
  next
277
287
  else
278
288
  t = parser.parse(multi_line)
279
- err(ParseError, "syntax error") unless t
289
+ err(ParseError, 'syntax error') unless t
280
290
 
281
291
  generate(t)
282
- multi_line, @multi_no = nil, nil
292
+ multi_line = nil
293
+ @multi_no = nil
283
294
  end
284
295
  end
285
296
 
286
297
  t = parser.parse(line)
287
298
 
288
299
  if !t
289
- err(ParseError, "syntax error") unless line =~ /^\s+/
300
+ err(ParseError, 'syntax error') unless line =~ /^\s+/
290
301
 
291
302
  multi_line = line
292
303
  @multi_no = @line_no
@@ -297,7 +308,7 @@ module Delorean
297
308
 
298
309
  if multi_line
299
310
  t = parser.parse(multi_line)
300
- err(ParseError, "syntax error") unless t
311
+ err(ParseError, 'syntax error') unless t
301
312
  generate(t)
302
313
  end
303
314
  end
@@ -313,14 +324,14 @@ module Delorean
313
324
 
314
325
  # enumerate qualified list of all attrs
315
326
  def enumerate_attrs
316
- @node_attrs.keys.each_with_object({}) { |node, h|
327
+ @node_attrs.keys.each_with_object({}) do |node, h|
317
328
  h[node] = enumerate_attrs_by_node(node)
318
- }
329
+ end
319
330
  end
320
331
 
321
332
  # enumerate qualified list of attrs by node
322
333
  def enumerate_attrs_by_node(node)
323
- raise "bad node" unless node
334
+ raise 'bad node' unless node
324
335
 
325
336
  begin
326
337
  klass = node.is_a?(String) ? @m.module_eval(node) : node
@@ -331,11 +342,11 @@ module Delorean
331
342
 
332
343
  raise "bad node class #{klass}" unless klass.is_a?(Class)
333
344
 
334
- klass.methods.map(&:to_s).select { |x|
345
+ klass.methods.map(&:to_s).select do |x|
335
346
  x.end_with?(POST)
336
- }.map { |x|
347
+ end.map do |x|
337
348
  x.sub(/#{POST}$/, '')
338
- }
349
+ end
339
350
  end
340
351
 
341
352
  # enumerate all params
@@ -346,15 +357,15 @@ module Delorean
346
357
  # enumerate params by a single node
347
358
  def enumerate_params_by_node(node)
348
359
  attrs = enumerate_attrs_by_node(node)
349
- Set.new( attrs.select {|a| @param_set.include?(a)} )
360
+ Set.new(attrs.select { |a| @param_set.include?(a) })
350
361
  end
351
362
 
352
363
  ######################################################################
353
364
  # Runtime
354
365
  ######################################################################
355
366
 
356
- def evaluate(node, attrs, params={})
357
- raise "bad params" unless params.is_a?(Hash)
367
+ def evaluate(node, attrs, params = {})
368
+ raise 'bad params' unless params.is_a?(Hash)
358
369
 
359
370
  if node.is_a?(Class)
360
371
  klass = node
@@ -373,29 +384,29 @@ module Delorean
373
384
  type_arr = attrs.is_a?(Array)
374
385
  attrs = [attrs] unless type_arr
375
386
 
376
- res = attrs.map { |attr|
387
+ res = attrs.map do |attr|
377
388
  raise "bad attribute '#{attr}'" unless attr =~ /^[a-z][A-Za-z0-9_]*$/
389
+
378
390
  klass.send("#{attr}#{POST}".to_sym, params)
379
- }
391
+ end
380
392
  type_arr ? res : res[0]
381
393
  end
382
394
 
383
- def eval_to_hash(node, attrs, params={})
395
+ def eval_to_hash(node, attrs, params = {})
384
396
  res = evaluate(node, attrs, params)
385
397
  Hash[* attrs.zip(res).flatten(1)]
386
398
  end
387
399
 
388
400
  def self.grok_runtime_exception(exc)
389
401
  # parse out the delorean-related backtrace records
390
- bt = exc.backtrace.map{ |x|
391
- x.match(/^#{MOD}(.+?):(\d+)(|:in `(.+)')$/);
402
+ bt = exc.backtrace.map do |x|
403
+ x =~ /^#{MOD}(.+?):(\d+)(|:in `(.+)')$/
392
404
  $1 && [$1, $2.to_i, $4.sub(/#{POST}$/, '')]
393
- }.reject(&:!)
405
+ end.reject(&:!)
394
406
 
395
- {"error" => exc.message, "backtrace" => bt}
407
+ { 'error' => exc.message, 'backtrace' => bt }
396
408
  end
397
409
 
398
410
  ######################################################################
399
-
400
411
  end
401
412
  end
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module Delorean
2
4
  ######################################################################
3
5
  # Parse Errors
@@ -48,5 +50,4 @@ module Delorean
48
50
 
49
51
  class InvalidIndex < StandardError
50
52
  end
51
-
52
53
  end
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  require 'delorean/const'
2
4
 
3
5
  module Delorean
@@ -7,23 +9,24 @@ module Delorean
7
9
  end
8
10
 
9
11
  module ClassMethods
10
- def delorean_fn(name, options = {}, &block)
12
+ def delorean_fn(name, options = {})
11
13
  define_singleton_method(name) do |*args|
12
- block.call(*args)
14
+ yield(*args)
13
15
  end
14
16
 
15
17
  sig = options[:sig]
16
18
 
17
- raise "no signature" unless sig
19
+ raise 'no signature' unless sig
18
20
 
19
21
  if sig
20
22
  sig = [sig, sig] if sig.is_a? Integer
21
- raise "Bad signature" unless (sig.is_a? Array and sig.length==2)
22
- self.const_set(name.to_s.upcase+Delorean::SIG, sig)
23
+ raise 'Bad signature' unless sig.is_a?(Array) && (sig.length == 2)
24
+
25
+ const_set(name.to_s.upcase + Delorean::SIG, sig)
23
26
  end
24
27
  end
25
28
 
26
- # FIXME IDEA: we just make :cache an argument to delorean_fn.
29
+ # FIXME: IDEA: we just make :cache an argument to delorean_fn.
27
30
  # That way, we don't need the cached_ flavors. It'll make all
28
31
  # this code a lot simpler. We should also just add the :private
29
32
  # mechanism here.
@@ -33,11 +36,11 @@ module Delorean
33
36
  # values are ActiveRecord objects. Query results can be very
34
37
  # large lists which we count as one item in the cache. Caching
35
38
  # mechanism will result in large processes.
36
- def cached_delorean_fn(name, options = {}, &block)
39
+ def cached_delorean_fn(name, options = {})
37
40
  delorean_fn(name, options) do |*args|
38
41
  delorean_cache_adapter = ::Delorean::Cache.adapter
39
42
  # Check if caching should be performed
40
- next block.call(*args) unless delorean_cache_adapter.cache_item?(
43
+ next yield(*args) unless delorean_cache_adapter.cache_item?(
41
44
  klass: self, method_name: name, args: args
42
45
  )
43
46
 
@@ -50,7 +53,7 @@ module Delorean
50
53
 
51
54
  next cached_item if cached_item != :NF
52
55
 
53
- res = block.call(*args)
56
+ res = yield(*args)
54
57
 
55
58
  delorean_cache_adapter.cache_item(
56
59
  klass: self, cache_key: cache_key, item: res
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module Delorean
2
4
  class SNode < Treetop::Runtime::SyntaxNode
3
5
  end
@@ -6,6 +8,7 @@ module Delorean
6
8
  def check(context, *a)
7
9
  f.check(context, *a)
8
10
  end
11
+
9
12
  def rewrite(context)
10
13
  f.rewrite(context)
11
14
  end
@@ -24,11 +27,12 @@ module Delorean
24
27
  # in _e. If not, to compute it we check for the value in _e
25
28
  # (i.e. check for aname). Otherwise, we use the default value
26
29
  # if any.
27
- aname, cname = i.text_value, context.last_node
30
+ aname = i.text_value
31
+ cname = context.last_node
28
32
  not_found = defined?(e) ? e.rewrite(context) :
29
33
  "raise UndefinedParamError, 'undefined parameter #{aname}'"
30
34
 
31
- <<eos
35
+ <<eos
32
36
  class #{cname}
33
37
  def self.#{aname}#{POST}(_e)
34
38
  _e[self.name+'.#{aname}'] ||= _e.fetch('#{aname}') { #{not_found} }
@@ -58,7 +62,7 @@ eos
58
62
 
59
63
  def rewrite(context)
60
64
  context.gen_import(n.text_value)
61
- ""
65
+ ''
62
66
  end
63
67
  end
64
68
 
@@ -71,13 +75,13 @@ eos
71
75
  def def_class(context, base_name)
72
76
  # Nodes are simply translated to classes. Define our own
73
77
  # self.name() since it's extremely slow in MRI 2.0.
74
- "class #{n.text_value} < #{base_name}; " +
75
- "def self.module_name; '#{context.module_name}'; end;" +
78
+ "class #{n.text_value} < #{base_name}; " \
79
+ "def self.module_name; '#{context.module_name}'; end;" \
76
80
  "def self.name; '#{n.text_value}'; end; end"
77
81
  end
78
82
 
79
83
  def rewrite(context)
80
- def_class(context, "BaseClass")
84
+ def_class(context, 'BaseClass')
81
85
  end
82
86
  end
83
87
 
@@ -96,6 +100,27 @@ eos
96
100
  end
97
101
  end
98
102
 
103
+ class SubNodeNested < BaseNode
104
+ def check(context, *)
105
+ module_names = mod.m.text_value.split('::')
106
+ node_name = module_names.pop
107
+ mname = module_names.join('::') if module_names.any?
108
+
109
+ context.parse_define_node(n.text_value, node_name, mname)
110
+ end
111
+
112
+ def rewrite(context)
113
+ module_names = mod.m.text_value.split('::')
114
+ node_name = module_names.pop
115
+ mname = module_names.join('::') if module_names.any?
116
+
117
+ sname = context.super_name(node_name, mname)
118
+
119
+ # A sub-node (derived node) is just a subclass.
120
+ def_class(context, sname)
121
+ end
122
+ end
123
+
99
124
  class Formula < SNode
100
125
  def check(context, *)
101
126
  context.parse_define_attr(i.text_value, e.check(context))
@@ -106,12 +131,12 @@ eos
106
131
  debug = Debug.debug_set.member?(dname)
107
132
 
108
133
  # an attr is defined as a class function on the node class.
109
- "class #{context.last_node}; " +
134
+ "class #{context.last_node}; " \
110
135
  "def self.#{i.text_value}#{POST}(_e); " +
111
- (debug ? "_debug =" : '') +
136
+ (debug ? '_debug =' : '') +
112
137
  "_e[self.name+'.#{i.text_value}'] ||= #{e.rewrite(context)};" +
113
138
  (debug ? 'Delorean::Debug.log(_debug); _debug;' : '') +
114
- "end; end;"
139
+ 'end; end;'
115
140
  end
116
141
  end
117
142
 
@@ -133,7 +158,7 @@ eos
133
158
  end
134
159
 
135
160
  def +(other)
136
- self.to_s + other
161
+ to_s + other
137
162
  end
138
163
 
139
164
  def to_s
@@ -168,6 +193,37 @@ eos
168
193
  end
169
194
  end
170
195
 
196
+ class NodeAsValueNested < SNode
197
+ def check(context, *)
198
+ module_names = c.text_value.split('::')
199
+ node_name = module_names.pop
200
+ mname = module_names.join('::') if module_names.any?
201
+
202
+ begin
203
+ context.parse_check_defined_mod_node(node_name, mname)
204
+ rescue UndefinedError, ParseError
205
+ # Node is a non-Delorean ruby class
206
+ context.parse_class(text_value)
207
+ end
208
+ []
209
+ end
210
+
211
+ def rewrite(context)
212
+ module_names = c.text_value.split('::')
213
+ node_name = module_names.pop
214
+ mname = module_names.join('::') if module_names.any?
215
+
216
+ begin
217
+ context.parse_check_defined_mod_node(node_name, mname)
218
+ context.super_name(node_name, mname)
219
+ rescue UndefinedError, ParseError
220
+ # FIXME: wrap the class name so Call will be able to tell it
221
+ # apart from a regular value.
222
+ ClassText.new(text_value)
223
+ end
224
+ end
225
+ end
226
+
171
227
  # unary operator
172
228
  class UnOp < SNode
173
229
  def check(context, *)
@@ -181,7 +237,8 @@ eos
181
237
 
182
238
  class BinOp < SNode
183
239
  def check(context, *)
184
- vc, ec = v.check(context), e.check(context)
240
+ vc = v.check(context)
241
+ ec = e.check(context)
185
242
  # returns list of attrs used in RHS and LHS
186
243
  ec + vc
187
244
  end
@@ -198,11 +255,13 @@ eos
198
255
  # hacky, for backwards compatibility
199
256
  class ErrorOp < SNode
200
257
  def check(context, *)
201
- args.text_value=='' ? [] : args.check(context)
258
+ args.text_value == '' ? [] : args.check(context)
202
259
  end
203
260
 
204
261
  def rewrite(context, *)
205
- args.text_value!='' ? "_err(#{args.rewrite(context)})" : "binding.pry; 0"
262
+ args.text_value != '' ?
263
+ "_err(#{args.rewrite(context)})" :
264
+ 'binding.pry; 0'
206
265
  end
207
266
  end
208
267
 
@@ -217,41 +276,41 @@ eos
217
276
  end
218
277
 
219
278
  class Literal < SNode
220
- def check(context, *)
279
+ def check(_context, *)
221
280
  []
222
281
  end
223
282
 
224
283
  # Delorean literals have same syntax as Ruby
225
- def rewrite(context)
284
+ def rewrite(_context)
226
285
  text_value
227
286
  end
228
287
  end
229
288
 
230
289
  # _ is self -- a naive implementation of "self" for now.
231
290
  class Self < SNode
232
- def check(context, *)
291
+ def check(_context, *)
233
292
  []
234
293
  end
235
294
 
236
- def rewrite(context)
237
- "_sanitize_hash(_e)"
295
+ def rewrite(_context)
296
+ '_sanitize_hash(_e)'
238
297
  end
239
298
  end
240
299
 
241
300
  class Sup < SNode
242
- def check(context, *)
301
+ def check(_context, *)
243
302
  []
244
303
  end
245
304
 
246
- def rewrite(context)
247
- "superclass"
305
+ def rewrite(_context)
306
+ 'superclass'
248
307
  end
249
308
  end
250
309
 
251
310
  class IString < Literal
252
- def rewrite(context)
311
+ def rewrite(_context)
253
312
  # FIXME: hacky to just fail
254
- raise "String interpolation not supported" if text_value =~ /\#\{.*\}/
313
+ raise 'String interpolation not supported' if text_value =~ /\#\{.*\}/
255
314
 
256
315
  # FIXME: syntax check?
257
316
  text_value
@@ -259,7 +318,7 @@ eos
259
318
  end
260
319
 
261
320
  class DString < Literal
262
- def rewrite(context)
321
+ def rewrite(_context)
263
322
  # remove the quotes and requote. We don't want the likes of #{}
264
323
  # evals to just pass through.
265
324
  text_value[1..-2].inspect
@@ -277,7 +336,7 @@ eos
277
336
  # class method calls. POST is used in mangling the attr names.
278
337
  # _e is the environment. Comprehension vars (in comp_set) are
279
338
  # not passed the env arg.
280
- arg = context.comp_set.member?(text_value) ? "" : '(_e)'
339
+ arg = context.comp_set.member?(text_value) ? '' : '(_e)'
281
340
  text_value + POST + arg
282
341
  end
283
342
  end
@@ -315,11 +374,11 @@ eos
315
374
  end
316
375
 
317
376
  class GetAttr < SNode
318
- def check(context, *)
377
+ def check(_context, *)
319
378
  []
320
379
  end
321
380
 
322
- def rewrite(context, vcode)
381
+ def rewrite(_context, vcode)
323
382
  attr = i.text_value
324
383
  attr = "'#{attr}'" unless attr =~ /\A[0-9]+\z/
325
384
  "_get_attr(#{vcode}, #{attr}, _e)"
@@ -333,9 +392,11 @@ eos
333
392
 
334
393
  def rewrite(context, vcode)
335
394
  if al.text_value.empty?
336
- args_str, arg_count = "", 0
395
+ args_str = ''
396
+ arg_count = 0
337
397
  else
338
- args_str, arg_count = al.rewrite(context), al.arg_count
398
+ args_str = al.rewrite(context)
399
+ arg_count = al.arg_count
339
400
  end
340
401
 
341
402
  if vcode.is_a?(ClassText)
@@ -356,7 +417,7 @@ eos
356
417
 
357
418
  def rewrite(context, node_name)
358
419
  var = "_h#{context.hcount}"
359
- res = al.text_value.empty? ? "" : al.rewrite(context, var)
420
+ res = al.text_value.empty? ? '' : al.rewrite(context, var)
360
421
  "(#{var}={}; #{res}; _node_call(#{node_name}, _e, #{var}))"
361
422
  end
362
423
  end
@@ -375,7 +436,7 @@ eos
375
436
  # element since it'll be "".
376
437
  attrs.shift
377
438
 
378
- attrs.inject(v.rewrite(context)) {|x, y| "_get_attr(#{x}, '#{y}', _e)"}
439
+ attrs.inject(v.rewrite(context)) { |x, y| "_get_attr(#{x}, '#{y}', _e)" }
379
440
  end
380
441
  end
381
442
 
@@ -389,7 +450,7 @@ eos
389
450
  end
390
451
 
391
452
  def rewrite(context)
392
- rest = ", " + args_rest.args.rewrite(context) if
453
+ rest = ', ' + args_rest.args.rewrite(context) if
393
454
  defined?(args_rest.args) && !args_rest.args.text_value.empty?
394
455
 
395
456
  [arg0.rewrite(context), rest].compact.sum
@@ -403,8 +464,9 @@ eos
403
464
 
404
465
  class IfElse < SNode
405
466
  def check(context, *)
406
- vc, e1c, e2c =
407
- v.check(context), e1.check(context), e2.check(context)
467
+ vc = v.check(context)
468
+ e1c = e1.check(context)
469
+ e2c = e2.check(context)
408
470
  vc + e1c + e2c
409
471
  end
410
472
 
@@ -420,7 +482,7 @@ eos
420
482
  end
421
483
 
422
484
  def rewrite(context)
423
- "[" + (defined?(args) ? args.rewrite(context) : "") + "]"
485
+ '[' + (defined?(args) ? args.rewrite(context) : '') + ']'
424
486
  end
425
487
  end
426
488
 
@@ -434,7 +496,7 @@ eos
434
496
  def rewrite(context)
435
497
  arg0.rewrite(context) +
436
498
  (defined?(args_rest.args) && !args_rest.args.text_value.empty? ?
437
- ", " + args_rest.args.rewrite(context) : "")
499
+ ', ' + args_rest.args.rewrite(context) : '')
438
500
  end
439
501
  end
440
502
 
@@ -442,19 +504,18 @@ eos
442
504
  def check(context, *)
443
505
  unpack_vars = args.check(context)
444
506
  e1c = e1.check(context)
445
- unpack_vars.each {|vname| context.parse_define_var(vname)}
507
+ unpack_vars.each { |vname| context.parse_define_var(vname) }
446
508
 
447
509
  # need to check e2/e3 in a context where the comprehension var
448
510
  # is defined.
449
511
  e2c = e2.check(context)
450
512
  e3c = defined?(ifexp.e3) ? ifexp.e3.check(context) : []
451
513
 
452
- unpack_vars.each {
453
- |vname|
514
+ unpack_vars.each do |vname|
454
515
  context.parse_undef_var(vname)
455
516
  e2c.delete(vname)
456
517
  e3c.delete(vname)
457
- }
518
+ end
458
519
 
459
520
  e1c + e2c + e3c
460
521
  end
@@ -462,13 +523,13 @@ eos
462
523
  def rewrite(context)
463
524
  res = ["(#{e1.rewrite(context)})"]
464
525
  unpack_vars = args.check(context)
465
- unpack_vars.each {|vname| context.parse_define_var(vname)}
526
+ unpack_vars.each { |vname| context.parse_define_var(vname) }
466
527
  args_str = args.rewrite(context)
467
528
 
468
529
  res << ".select{|#{args_str}|(#{ifexp.e3.rewrite(context)})}" if
469
530
  defined?(ifexp.e3)
470
531
  res << ".map{|#{args_str}| (#{e2.rewrite(context)}) }"
471
- unpack_vars.each {|vname| context.parse_undef_var(vname)}
532
+ unpack_vars.each { |vname| context.parse_undef_var(vname) }
472
533
  res.sum
473
534
  end
474
535
  end
@@ -492,7 +553,7 @@ eos
492
553
  def check(context, *)
493
554
  unpack_vars = args.check(context)
494
555
  e1c = e1.check(context)
495
- unpack_vars.each {|vname| context.parse_define_var(vname)}
556
+ unpack_vars.each { |vname| context.parse_define_var(vname) }
496
557
 
497
558
  # need to check el/er/ei in a context where the comprehension var
498
559
  # is defined.
@@ -500,20 +561,19 @@ eos
500
561
  erc = er.check(context)
501
562
  eic = defined?(ifexp.ei) ? ifexp.ei.check(context) : []
502
563
 
503
- unpack_vars.each {
504
- |vname|
564
+ unpack_vars.each do |vname|
505
565
  context.parse_undef_var(vname)
506
566
  elc.delete(vname)
507
567
  erc.delete(vname)
508
568
  eic.delete(vname)
509
- }
569
+ end
510
570
  e1c + elc + erc + eic
511
571
  end
512
572
 
513
573
  def rewrite(context)
514
574
  res = ["(#{e1.rewrite(context)})"]
515
575
  unpack_vars = args.check(context)
516
- unpack_vars.each {|vname| context.parse_define_var(vname)}
576
+ unpack_vars.each { |vname| context.parse_define_var(vname) }
517
577
  args_str = args.rewrite(context)
518
578
 
519
579
  hid = @@comp_count += 1
@@ -523,10 +583,10 @@ eos
523
583
 
524
584
  unpack_str = unpack_vars.count > 1 ? "(#{args_str})" : args_str
525
585
 
526
- res << ".each_with_object({}){|#{unpack_str}, _h#{hid}| " +
527
- "_h#{hid}[#{el.rewrite(context)}]=(#{er.rewrite(context)})}"
586
+ res << ".each_with_object({}){|#{unpack_str}, _h#{hid}| " \
587
+ "_h#{hid}[#{el.rewrite(context)}]=(#{er.rewrite(context)})}"
528
588
 
529
- unpack_vars.each {|vname| context.parse_undef_var(vname)}
589
+ unpack_vars.each { |vname| context.parse_undef_var(vname) }
530
590
  res.sum
531
591
  end
532
592
  end
@@ -537,7 +597,8 @@ eos
537
597
  end
538
598
 
539
599
  def rewrite(context)
540
- return "{}" unless defined?(args)
600
+ return '{}' unless defined?(args)
601
+
541
602
  var = "_h#{context.hcount}"
542
603
  "(#{var}={}; " + args.rewrite(context, var) + "; #{var})"
543
604
  end
@@ -545,14 +606,15 @@ eos
545
606
 
546
607
  class KwArgs < SNode
547
608
  def check(context, *)
548
- [arg0.check(context),
549
- (ifexp.e3.check(context) if defined?(ifexp.e3)),
550
- (args_rest.al.check(context) if
551
- defined?(args_rest.al) && !args_rest.al.empty?)
609
+ [
610
+ arg0.check(context),
611
+ (ifexp.e3.check(context) if defined?(ifexp.e3)),
612
+ (args_rest.al.check(context) if
613
+ defined?(args_rest.al) && !args_rest.al.empty?)
552
614
  ].compact.sum
553
615
  end
554
616
 
555
- def rewrite(context, var, i=0)
617
+ def rewrite(context, var, i = 0)
556
618
  arg0_rw = arg0.rewrite(context)
557
619
 
558
620
  if defined?(splat)
@@ -564,7 +626,7 @@ eos
564
626
  end
565
627
 
566
628
  res += " if (#{ifexp.e3.rewrite(context)})" if defined?(ifexp.e3)
567
- res += ";"
629
+ res += ';'
568
630
  res += args_rest.al.rewrite(context, var, i) if
569
631
  defined?(args_rest.al) && !args_rest.al.text_value.empty?
570
632
  res
@@ -573,22 +635,23 @@ eos
573
635
 
574
636
  class HashArgs < SNode
575
637
  def check(context, *)
576
- [e0.check(context),
577
- (e1.check(context) unless defined?(splat)),
578
- (ifexp.e3.check(context) if defined?(ifexp.e3)),
579
- (args_rest.al.check(context) if
580
- defined?(args_rest.al) && !args_rest.al.empty?),
638
+ [
639
+ e0.check(context),
640
+ (e1.check(context) unless defined?(splat)),
641
+ (ifexp.e3.check(context) if defined?(ifexp.e3)),
642
+ (args_rest.al.check(context) if
643
+ defined?(args_rest.al) && !args_rest.al.empty?),
581
644
  ].compact.sum
582
645
  end
583
646
 
584
647
  def rewrite(context, var)
585
648
  res = if defined?(splat)
586
- "#{var}.merge!(#{e0.rewrite(context)})"
587
- else
588
- "#{var}[#{e0.rewrite(context)}]=(#{e1.rewrite(context)})"
589
- end
649
+ "#{var}.merge!(#{e0.rewrite(context)})"
650
+ else
651
+ "#{var}[#{e0.rewrite(context)}]=(#{e1.rewrite(context)})"
652
+ end
590
653
  res += " if (#{ifexp.e3.rewrite(context)})" if defined?(ifexp.e3)
591
- res += ";"
654
+ res += ';'
592
655
  res += args_rest.al.rewrite(context, var) if
593
656
  defined?(args_rest.al) && !args_rest.al.text_value.empty?
594
657
  res