class Opal::Nodes::DefinedNode

Public Instance Methods

compile() click to toggle source
# File lib/opal/nodes/defined.rb, line 12
def compile
  case value.type
  when :self, :nil, :false, :true
    push value.type.to_s.inspect
  when :lvasgn, :ivasgn, :gvasgn, :cvasgn, :casgn, :op_asgn, :or_asgn, :and_asgn
    push "'assignment'"
  when :lvar
    push "'local-variable'"
  when :begin
    if value.children.size == 1 && value.children[0].type == :masgn
      push "'assignment'"
    else
      push "'expression'"
    end
  when :send
    compile_defined_send(value)
    wrap '(', " ? 'method' : nil)"
  when :ivar
    compile_defined_ivar(value)
    wrap '(', " ? 'instance-variable' : nil)"
  when :zsuper, :super
    compile_defined_super
  when :yield
    compile_defined_yield
    wrap '(', " ? 'yield' : nil)"
  when :xstr
    compile_defined_xstr(value)
  when :const
    compile_defined_const(value)
    wrap '(', " ? 'constant' : nil)"
  when :cvar
    compile_defined_cvar(value)
    wrap '(', " ? 'class variable' : nil)"
  when :gvar
    compile_defined_gvar(value)
    wrap '(', " ? 'global-variable' : nil)"
  when :back_ref
    compile_defined_back_ref
    wrap '(', " ? 'global-variable' : nil)"
  when :nth_ref
    compile_defined_nth_ref
    wrap '(', " ? 'global-variable' : nil)"
  when :array
    compile_defined_array(value)
    wrap '(', " ? 'expression' : nil)"
  else
    push "'expression'"
  end
end
compile_defined(node) click to toggle source
# File lib/opal/nodes/defined.rb, line 62
def compile_defined(node)
  type = node.type

  if respond_to? "compile_defined_#{type}"
    __send__("compile_defined_#{type}", node)
  else
    node_tmp = scope.new_temp
    push "(#{node_tmp} = ", expr(node), ')'
    node_tmp
  end
end
compile_defined_array(node) click to toggle source
# File lib/opal/nodes/defined.rb, line 215
def compile_defined_array(node)
  node.children.each_with_index do |child, idx|
    push ' && ' unless idx == 0
    compile_defined(child)
  end
end
compile_defined_back_ref() click to toggle source
# File lib/opal/nodes/defined.rb, line 200
def compile_defined_back_ref
  helper :gvars
  back_ref_temp = scope.new_temp
  push "(#{back_ref_temp} = $gvars['~'], #{back_ref_temp} != null && #{back_ref_temp} !== nil)"
  back_ref_temp
end
compile_defined_const(node) click to toggle source
# File lib/opal/nodes/defined.rb, line 162
def compile_defined_const(node)
  const_scope, const_name = *node

  const_tmp = scope.new_temp

  if const_scope.nil?
    push "(#{const_tmp} = #{scope.relative_access}('#{const_name}', 'skip_raise'))"
  elsif const_scope == s(:cbase)
    push "(#{const_tmp} = #{top_scope.absolute_const}('::', '#{const_name}', 'skip_raise'))"
  else
    const_scope_tmp = compile_defined(const_scope)
    push " && (#{const_tmp} = #{top_scope.absolute_const}(#{const_scope_tmp}, '#{const_name}', 'skip_raise'))"
  end
  const_tmp
end
compile_defined_cvar(node) click to toggle source
# File lib/opal/nodes/defined.rb, line 178
def compile_defined_cvar(node)
  cvar_name, _ = *node
  cvar_tmp = scope.new_temp
  push "(#{cvar_tmp} = #{class_variable_owner}.$$cvars['#{cvar_name}'], #{cvar_tmp} != null)"
  cvar_tmp
end
compile_defined_gvar(node) click to toggle source
# File lib/opal/nodes/defined.rb, line 185
def compile_defined_gvar(node)
  helper :gvars

  name = node.children[0].to_s[1..-1]
  gvar_temp = scope.new_temp

  if %w[~ !].include? name
    push "(#{gvar_temp} = ", expr(node), ' || true)'
  else
    push "(#{gvar_temp} = $gvars[#{name.inspect}], #{gvar_temp} != null)"
  end

  gvar_temp
end
compile_defined_ivar(node) click to toggle source
# File lib/opal/nodes/defined.rb, line 135
def compile_defined_ivar(node)
  name = node.children[0].to_s[1..-1]
  # FIXME: this check should be positive for ivars initialized as nil too.
  # Since currently all known ivars are inialized to nil in the constructor
  # we can't tell if it was the user that put nil and made the ivar #defined?
  # or not.
  tmp = scope.new_temp
  push "(#{tmp} = #{scope.self}['#{name}'], #{tmp} != null && #{tmp} !== nil)"

  tmp
end
compile_defined_nth_ref() click to toggle source
# File lib/opal/nodes/defined.rb, line 207
def compile_defined_nth_ref
  helper :gvars

  nth_ref_tmp = scope.new_temp
  push "(#{nth_ref_tmp} = $gvars['~'], #{nth_ref_tmp} != null && #{nth_ref_tmp} != nil)"
  nth_ref_tmp
end
compile_defined_send(node) click to toggle source
# File lib/opal/nodes/defined.rb, line 94
def compile_defined_send(node)
  recv, method_name, *args = *node
  mid = mid_to_jsid(method_name.to_s)

  if recv
    recv_code = compile_defined(recv)
    push ' && '

    if recv.type == :send
      recv_code = compile_send_recv_doesnt_raise(recv_code)
      push ' && '
    end

    recv_tmp = scope.new_temp
    push "(#{recv_tmp} = ", recv_code, ", #{recv_tmp}) && "
  else
    recv_tmp = scope.self
  end

  recv_value_tmp = scope.new_temp
  push "(#{recv_value_tmp} = #{recv_tmp}) && "

  meth_tmp = scope.new_temp
  push "(((#{meth_tmp} = #{recv_value_tmp}#{mid}) && !#{meth_tmp}.$$stub)"

  push " || #{recv_value_tmp}['$respond_to_missing?']('#{method_name}'))"

  args.each do |arg|
    case arg.type
    when :block_pass
      # ignoring
    else
      push ' && '
      compile_defined(arg)
    end
  end

  wrap '(', ')'
  "#{meth_tmp}()"
end
compile_defined_super() click to toggle source
# File lib/opal/nodes/defined.rb, line 147
def compile_defined_super
  push expr s(:defined_super)
end
compile_defined_xstr(node) click to toggle source
# File lib/opal/nodes/defined.rb, line 158
def compile_defined_xstr(node)
  push '(typeof(', expr(node), ') !== "undefined")'
end
compile_defined_yield() click to toggle source
# File lib/opal/nodes/defined.rb, line 151
def compile_defined_yield
  scope.uses_block!
  block_name = scope.block_name || scope.find_parent_def.block_name
  push "(#{block_name} != null && #{block_name} !== nil)"
  block_name
end
compile_send_recv_doesnt_raise(recv_code) click to toggle source
# File lib/opal/nodes/defined.rb, line 90
def compile_send_recv_doesnt_raise(recv_code)
  wrap_with_try_catch(recv_code)
end
wrap_with_try_catch(code) click to toggle source
# File lib/opal/nodes/defined.rb, line 74
def wrap_with_try_catch(code)
  returning_tmp = scope.new_temp

  push "(#{returning_tmp} = (function() { try {"
  push "  return #{code};"
  push '} catch ($err) {'
  push '  if (Opal.rescue($err, [Opal.Exception])) {'
  push '    try {'
  push '      return false;'
  push '    } finally { Opal.pop_exception($err); }'
  push '  } else { throw $err; }'
  push '}})())'

  returning_tmp
end