class Opal::Rewriters::ForRewriter
Public Class Methods
next_tmp()
click to toggle source
# File lib/opal/rewriters/for_rewriter.rb, line 12 def self.next_tmp @counter ||= 0 @counter += 1 :"$for_tmp#{@counter}" end
reset_tmp_counter!()
click to toggle source
# File lib/opal/rewriters/for_rewriter.rb, line 8 def self.reset_tmp_counter! @counter = 0 end
Public Instance Methods
on_for(node)
click to toggle source
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 }
# File 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
Private Instance Methods
assign_loop_variable(loop_variable, tmp_loop_variable)
click to toggle source
# File lib/opal/rewriters/for_rewriter.rb, line 66 def assign_loop_variable(loop_variable, tmp_loop_variable) case loop_variable.type when :mlhs # multiple left-hand statement like in "for i,j in [[1, 2], [3, 4]]" loop_variable.updated(:masgn, [loop_variable, tmp_loop_variable]) else # single argument like "for i in (0..3)" loop_variable << tmp_loop_variable end end
generate_outer_assignments(loop_variable, loop_body)
click to toggle source
# File lib/opal/rewriters/for_rewriter.rb, line 59 def generate_outer_assignments(loop_variable, loop_body) loop_local_vars = LocalVariableAssigns.find(loop_variable) body_local_vars = LocalVariableAssigns.find(loop_body) (loop_local_vars + body_local_vars).map { |lvar_name| s(:lvdeclare, lvar_name) } end
transform_for_to_each_loop(node, loop_range, tmp_loop_variable, loop_body)
click to toggle source
rubocop:disable Layout/MultilineMethodCallBraceLayout,Layout/MultilineArrayBraceLayout
# File lib/opal/rewriters/for_rewriter.rb, line 76 def transform_for_to_each_loop(node, loop_range, tmp_loop_variable, loop_body) node.updated(:send, [loop_range, :each, # (0..3).each { node.updated(:iter, [s(:args, s(:arg, tmp_loop_variable)), # |__jstmp| process(loop_body) # i = __jstmp; j = i + 1 } ])]) end