class Opal::Rewriters::TargetedPatches

existing applications.
This should be a last resort and must not break functionality in
improvements against some libraries used with Opal.
This module attempts to run some optimizations or compatibility

def on_array(node)

def on_array(node)
  children = node.children
  # Optimize large arrays produced by lexer, but mainly we are interested
  # in improving compile times, by reducing the tree for the further
  # compilation efforts (also reducing the bundle size a bit)
  #
  # This particular patch reduces compile time of the following command
  # by 12.5%:
  #
  #     OPAL_CACHE_DISABLE=true OPAL_PREFORK_DISABLE=true bin/opal \
  #         --no-source-map -ropal-parser -ropal/platform -ce \
  #         'puts ::Opal.compile($stdin.read)' > _Cnow.js
  #
  # So, in short, an array of a kind:
  #
  #     [1, 2, 3, nil, nil, :something, :abc, nil, ...]
  #
  # Becomes compiled to:
  #
  #     Opal.large_array_unpack("1,2,3,,something,abc,,...")
  if children.length > 32
    ssin_array = children.all? do |child|
      # Break for wrong types
      next false unless %i[str sym int nil].include?(child.type)
      # Break for strings that may conflict with our numbers, nils and separator
      next false if %i[str sym].include?(child.type) && child.children.first.to_s =~ /\A[0-9-]|\A\z|,/
      # Break for too numbers out of range, as there may be decoding issues
      next false if child.type == :int && !(-1_000_000..1_000_000).cover?(child.children.first)
      true
    end
    if ssin_array
      str = children.map { |i| i.children.first.to_s }.join(',')
      node.updated(:jscall, [s(:js_tmp, :Opal), :large_array_unpack, s(:sym, str)])
    else
      super
    end
  else
    super
  end
end

def on_def(node)

def on_def(node)
  name, args, body = *node
  if body && body.type == :begin && body.children.length >= 2
    # parser/rubyxx.rb - racc generated code often looks like:
    #
    #     def _reduce_219(val, _values, result)
    #       result = @builder.op_assign(val[0], val[1], val[2])
    #       result
    #     end
    #
    # This converter transform this into just
    #
    #     def _reduce_219(val, _values, result)
    #       @builder.op_assign(val[0], val[1], val[2])
    #     end
    calls = body.children
    assignment, ret = calls.last(2)
    if assignment.type == :lvasgn && ret.type == :lvar &&
       assignment.children.first == ret.children.first
      if calls.length == 2
        node.updated(nil, [name, args, assignment.children[1]])
      else
        calls = calls[0..-3] << assignment.children[1]
        node.updated(nil, [name, args, body.updated(nil, calls)])
      end
    else
      super
    end
  else
    super
  end
end