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)

        with_temp do |redo_var|
          compiler.in_while do
            while_loop[:closure] = true if wrap_in_closure?
            while_loop[:redo_var] = redo_var

            body_code = indent { stmt(body) }
            if uses_redo?
              compile_with_redo(test_code, body_code, redo_var)
            else
              compile_without_redo(test_code, body_code)
            end
          end
        end

        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, body_code, redo_var)
        push "#{redo_var} = false; "
        compile_while(
          [redo_var, " || ", test_code],
          ["#{redo_var} = false;", body_code]
        )
      end

      def compile_without_redo(test_code, body_code)
        compile_while([test_code], [body_code])
      end

      def compile_while(test_code, body_code)
        push while_open, *test_code, while_close
        indent { line(*body_code) }
        line '}'
      end

      def while_open
        'while ('
      end

      def while_close
        ') {'
      end

      def uses_redo?
        while_loop[:use_redo]
      end

      def wrap_in_closure?
        expr? || recv?
      end
    end

    class UntilNode < WhileNode
      handle :until

      private

      def while_open
        'while (!('
      end

      def while_close
        ')) {'
      end
    end

    class WhilePostNode < WhileNode
      handle :while_post

      private

      def compile_while(test_code, body_code)
        push "do {"
        indent { line(*body_code) }
        line "} ", while_open, *test_code, while_close
      end

      def while_close
        ');'
      end
    end

    class UntilPostNode < WhilePostNode
      handle :until_post

      private

      def while_open
        'while(!('
      end

      def while_close
        '));'
      end
    end
  end
end