Class: Opal::Rewriters::ForRewriter

Inherits:
Base
  • Object
show all
Defined in:
opal/lib/opal/rewriters/for_rewriter.rb

Defined Under Namespace

Classes: LocalVariableAssigns

Class Method Summary collapse

Instance Method Summary collapse

Methods inherited from Base

#append_to_body, #prepend_to_body, #s, s

Class Method Details

.next_tmpObject



11
12
13
14
15
# File 'opal/lib/opal/rewriters/for_rewriter.rb', line 11

def self.next_tmp
  @counter ||= 0
  @counter += 1
  :$for_tmp#{@counter}"
end

.reset_tmp_counter!Object



7
8
9
# File 'opal/lib/opal/rewriters/for_rewriter.rb', line 7

def self.reset_tmp_counter!
  @counter = 0
end

Instance Method Details

#on_for(node) ⇒ Object

Handles for i in 0..3; j = i + 1; end

The problem here is that in Ruby for loop makes its loop variable + all local variables available outside. I.e. after this loop variable i is 3 and j is 4

This class rewrites it to the following code: j = nil i = nil (0..3).each { |__jstmp| i = __jstmp; j = i + 1 }

Complex stuff with multiple loop variables: for i, j in [[1, 2], [3, 4]]; end Becomes multiple left-hand assignment: i = nil j = nil [[1, 2], [3, 4]].each { |__jstmp| i, j = __jstmp }



36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
# File 'opal/lib/opal/rewriters/for_rewriter.rb', line 36

def on_for(node)
  loop_variable, iterating_value, loop_body = *node

  iterating_lvars        = LocalVariableAssigns.find(loop_variable) # [:i]
  lvars_declared_in_body = LocalVariableAssigns.find(loop_body)     # [:j]

  # i = nil; j = nil
  outer_assigns = (iterating_lvars + lvars_declared_in_body).map do |lvar_name|
    s(:lvdeclare, lvar_name)
  end

  # :__jstmp
  tmp_loop_variable = self.class.next_tmp
  get_tmp_loop_variable = s(:js_tmp, tmp_loop_variable)

  loop_variable_assignment = case loop_variable.type
  when :mlhs # multiple left-hand statement like in "for i,j in [[1, 2], [3, 4]]"
    # i, j = __jstmp
    s(:masgn, loop_variable, get_tmp_loop_variable)
  else # single argument like "for i in (0..3)"
    # i = __jstmp
    loop_variable << get_tmp_loop_variable
  end

  loop_body = prepend_to_body(loop_body, loop_variable_assignment)

  node = s(:send, iterating_value, :each,          # (0..3).each {
    s(:iter, s(:args, s(:arg, tmp_loop_variable)), #                |__jstmp|
    loop_body)                                     #                          i = __jstmp; j = i + 1 }
  )

  s(:begin, *outer_assigns, node)
end