Class: Opal::Rewriters::ForRewriter

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

Defined Under Namespace

Classes: LocalVariableAssigns

Constant Summary

Constants inherited from Base

Base::DUMMY_LOCATION

Instance Attribute Summary

Attributes inherited from Base

#current_node

Class Method Summary collapse

Instance Method Summary collapse

Methods inherited from Base

#append_to_body, #begin_with_stmts, #dynamic!, #error, #on_top, #prepend_to_body, #process, s, #s, #stmts_of

Class Method Details

.next_tmpObject



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

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

.reset_tmp_counter!Object



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

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 }



38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
# File 'opal/lib/opal/rewriters/for_rewriter.rb', line 38

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

  # Declare local variables used in the loop and the loop body at the outer scope
  outer_assignments = generate_outer_assignments(loop_variable, loop_body)

  # Generate temporary loop variable
  tmp_loop_variable = self.class.next_tmp
  get_tmp_loop_variable = s(:js_tmp, tmp_loop_variable)

  # Assign the loop variables in the loop body
  loop_body = prepend_to_body(loop_body, assign_loop_variable(loop_variable, get_tmp_loop_variable))

  # Transform the for-loop into each-loop with updated loop body
  node = transform_for_to_each_loop(node, loop_range, tmp_loop_variable, loop_body)

  node.updated(:begin, [*outer_assignments, node])
end