lib/opal/nodes/while.rb
# frozen_string_literal: true
require 'opal/nodes/base'
module Opal
module Nodes
class WhileNode < Base
handle :while
children :test, :body
def compile
test_code = js_truthy(test)
@redo_var = scope.new_temp if uses_redo?
compiler.in_while do
while_loop[:closure] = true if wrap_in_closure?
while_loop[:redo_var] = @redo_var
in_closure(Closure::LOOP | Closure::JS_LOOP | (wrap_in_closure? ? Closure::JS_FUNCTION : 0)) do
in_closure(Closure::LOOP_INSIDE | Closure::JS_LOOP_INSIDE) do
line(indent { stmt(body) })
end
if uses_redo?
compile_with_redo(test_code)
else
compile_without_redo(test_code)
end
end
end
scope.queue_temp(@redo_var) if uses_redo?
if wrap_in_closure?
if scope.await_encountered
wrap '(await (async function() {', '; return nil; })())'
else
wrap '(function() {', '; return nil; })()'
end
end
end
private
def compile_with_redo(test_code)
compile_while(test_code, "#{@redo_var} = false;")
end
def compile_without_redo(test_code)
compile_while(test_code)
end
def compile_while(test_code, redo_code = nil)
unshift redo_code if redo_code
unshift while_open, test_code, while_close
unshift redo_code if redo_code
line '}'
end
def while_open
if uses_redo?
redo_part = "#{@redo_var} || "
end
"while (#{redo_part}"
end
def while_close
') {'
end
def uses_redo?
@sexp.meta[:has_redo]
end
def wrap_in_closure?
expr? || recv?
end
end
class UntilNode < WhileNode
handle :until
private
def while_open
if uses_redo?
redo_part = "#{@redo_var} || "
end
"while (#{redo_part}!("
end
def while_close
')) {'
end
end
class WhilePostNode < WhileNode
handle :while_post
private
def compile_while(test_code, redo_code = nil)
unshift redo_code if redo_code
unshift "do {"
line "} ", while_open, test_code, while_close
end
def while_close
');'
end
end
class UntilPostNode < WhilePostNode
handle :until_post
private
def while_open
if uses_redo?
redo_part = "#{@redo_var} || "
end
"while (#{redo_part}!("
end
def while_close
'));'
end
end
end
end