lib/opal/nodes/case.rb



# frozen_string_literal: true

require 'opal/nodes/base'

module Opal
  module Nodes
    class CaseNode < Base
      handle :case

      children :condition

      def compile
        compiler.in_case do
          compile_code

          wrap '(function() {', '})()' if needs_closure?
        end
      end

      def compile_code
        handled_else = false

        if condition
          case_stmt[:cond] = true
          add_local '$case'

          push '$case = ', expr(condition), ';'
        end

        case_parts.each_with_index do |wen, idx|
          next unless wen
          line
          case wen.type
          when :when
            wen = compiler.returns(wen) if needs_closure?
            push 'else ' unless idx == 0
            push stmt(wen)
          else # s(:else)
            handled_else = true
            wen = compiler.returns(wen) if needs_closure?
            push 'else {', stmt(wen), '}'
          end
        end

        # if we are having a closure, we must return a usable value
        if needs_closure? && !handled_else
          line
          push 'else { return nil }'
        end
      end

      def needs_closure?
        !stmt?
      end

      def case_parts
        children[1..-1]
      end

      def case_stmt
        compiler.case_stmt
      end
    end

    class WhenNode < Base
      handle :when

      children :whens, :body

      def compile
        push 'if ('

        when_checks.each_with_index do |check, idx|
          push ' || ' unless idx == 0

          if check.type == :splat
            push '(function($splt) { for (var i = 0, ii = $splt.length; i < ii; i++) {'
            if case_stmt[:cond]
              push "if ($splt[i]['$===']($case)) { return true; }"
            else
              push 'if (', js_truthy(check), ')) { return true; }'
            end
            push '} return false; })(', expr(check.children[0]), ')'
          elsif case_stmt[:cond]
            call = s(:send, check, :===, s(:arglist, s(:js_tmp, '$case')))
            push expr(call)
          else
            push js_truthy(check)
          end
        end

        push ') {', process(body_code, @level), '}'
      end

      def when_checks
        children[0..-2]
      end

      def case_stmt
        compiler.case_stmt
      end

      def body_code
        children.last || s(:nil)
      end
    end
  end
end