class RubyRunJs::ByteCodeGenerator

Attributes

declared_vars[R]

Public Class Methods

new() click to toggle source
# File lib/ruby_run_js/bytecode_generator.rb, line 6
def initialize
  init()
  @label_id = 0
end

Public Instance Methods

emit(target, *args) click to toggle source
# File lib/ruby_run_js/bytecode_generator.rb, line 726
def emit(target, *args)
  if target.is_a?(Class)
    @bytecodes.push(target.new(*args))
  elsif target.is_a?(Array)
    target.each do |i|
      emit(i)
    end
  else
    method_symbol = ('parse' + target[:type].to_s).to_sym
    send_method = method(method_symbol)
    args = send_method.parameters.map { |param| target[param[1]] }
    args[-1] = target
    send(method_symbol, *args)
  end
end
init() click to toggle source
# File lib/ruby_run_js/bytecode_generator.rb, line 11
def init
  @bytecodes = []

  @implicit_breaks = []
  @implicit_continues = []

  @declared_continue_labels = {}
  @declared_break_labels = {}

  @function_declaration_codes = []
  @declared_vars = []

  @state = []
end
new_label() click to toggle source
# File lib/ruby_run_js/bytecode_generator.rb, line 51
def new_label
  id = @label_id
  @label_id += 1
  id
end
output_code() click to toggle source
# File lib/ruby_run_js/bytecode_generator.rb, line 26
def output_code
  codes = @bytecodes
  init()
  codes
end
parseArrayExpression(elements, node) click to toggle source
# File lib/ruby_run_js/bytecode_generator.rb, line 58
def parseArrayExpression(elements, node)
  elements.each do |e|
    if e.nil?
      emit(OPCODES::LOAD_UNDEFINED)
    else
      emit(e)
    end
  end
  emit(OPCODES::LOAD_ARRAY, elements.length)
end
parseAssignmentExpression(operator, left, right, node) click to toggle source
# File lib/ruby_run_js/bytecode_generator.rb, line 69
def parseAssignmentExpression(operator, left, right, node)
  if left[:type] == 'MemberExpression'
    emit(left[:object])
    if left[:computed]
      emit(left[:property])
      emit(right)
      if operator.length > 1 && operator[-1] == '='
        emit(OPCODES::STORE_MEMBER_OP, operator[0...-1])
      else
        emit(OPCODES::STORE_MEMBER)
      end
    else
      emit(right)
      if operator.length > 1 && operator[-1] == '='
        emit(OPCODES::STORE_MEMBER_DOT_OP, left[:property][:name], operator[0...-1])
      else
        emit(OPCODES::STORE_MEMBER_DOT, left[:property][:name])
      end
    end
  elsif left[:type] == 'Identifier'
    if ['true', 'false', 'this'].include?(left[:name])
      raise make_error('SyntaxError', 'Invalid left-hand side in assignment')
    end
    emit(right)
    if operator.length > 1 && operator[-1] == '='
      emit(OPCODES::STORE_OP, left[:name], operator[0...-1])
    else
      emit(OPCODES::STORE, left[:name])
    end
  else
    raise make_error('SyntaxError', 'Invalid left-hand side in assignment')
  end
end
parseBinaryExpression(operator, left, right, node) click to toggle source
# File lib/ruby_run_js/bytecode_generator.rb, line 103
def parseBinaryExpression(operator, left, right, node)
  emit(left)
  emit(right)
  emit(OPCODES::BINARY_OP, operator)
end
parseBlockStatement(body, node) click to toggle source
# File lib/ruby_run_js/bytecode_generator.rb, line 109
def parseBlockStatement(body, node)
  emit(body)
end
parseBreakStatement(label, node) click to toggle source
# File lib/ruby_run_js/bytecode_generator.rb, line 113
def parseBreakStatement(label, node)
  if label.nil?
    emit(OPCODES::JUMP, @implicit_breaks[-1])
  else
    label = label[:name]
    unless @declared_break_labels.key?(label)
      raise make_error('SyntaxError', "Undefined label '#{label}'")
    else
      emit(OPCODES::JUMP, @declared_break_labels[label])
    end
  end
end
parseCallExpression(callee, arguments, node) click to toggle source
# File lib/ruby_run_js/bytecode_generator.rb, line 126
def parseCallExpression(callee, arguments, node)
  if callee[:type] == 'MemberExpression'
    emit(callee[:object])
    if callee[:computed]
      emit(callee[:property])
      if arguments.length > 0
        arguments.each do |a|
          emit(a)
        end
        emit(OPCODES::LOAD_N_TUPLE, arguments.length)
        emit(OPCODES::CALL_METHOD)
      else
        emit(OPCODES::CALL_METHOD_NO_ARGS)
      end
    else
      prop_name = callee[:property][:name]
      if arguments.length > 0
        arguments.each do |a|
          emit(a)
        end
        emit(OPCODES::LOAD_N_TUPLE, arguments.length)
        emit(OPCODES::CALL_METHOD_DOT, prop_name)
      else
        emit(OPCODES::CALL_METHOD_DOT_NO_ARGS, prop_name)
      end
    end
  else
    emit(callee)
    if arguments.length > 0
      arguments.each do |a|
        emit(a)
      end
      emit(OPCODES::LOAD_N_TUPLE, arguments.length)
      emit(OPCODES::CALL)
    else
      emit(OPCODES::CALL_NO_ARGS)
    end
  end
end
parseConditionalExpression(test, consequent, alternate, node) click to toggle source
# File lib/ruby_run_js/bytecode_generator.rb, line 166
def parseConditionalExpression(test, consequent, alternate, node)
  label_alt = new_label()
  label_end = new_label()
  emit(test)
  emit(OPCODES::JUMP_IF_FALSE, label_alt)

  emit(consequent)
  emit(OPCODES::JUMP, label_end)

  emit(OPCODES::LABEL, label_alt)
  emit(alternate)

  emit(OPCODES::LABEL, label_end)
end
parseContinueStatement(label, node) click to toggle source
# File lib/ruby_run_js/bytecode_generator.rb, line 181
def parseContinueStatement(label, node)
  if label.nil?
    emit(OPCODES::JUMP, @implicit_continues[-1])
  else
    label = label[:name]
    if @declared_continue_labels.key?(label)
      raise make_error('SyntaxError', "Undefined label '#{label}'")
    else
      emit(OPCODES::JUMP, @declared_continue_labels[label])
    end
  end
end
parseDebuggerStatement(node) click to toggle source
# File lib/ruby_run_js/bytecode_generator.rb, line 194
def parseDebuggerStatement(node)
  parseEmptyStatement(node)
end
parseDoWhileStatement(body, test, node) click to toggle source
# File lib/ruby_run_js/bytecode_generator.rb, line 198
def parseDoWhileStatement(body, test, node)
  label_continue = new_label()
  label_break = new_label()
  label_do = new_label()

  emit(OPCODES::JUMP, label_do)
  emit(OPCODES::LABEL, label_continue)
  emit(test)
  emit(OPCODES::JUMP_IF_FALSE, label_break)
  emit(OPCODES::LABEL, label_do)

  @implicit_continues.push(label_continue)
  @implicit_breaks.push(label_break)
  emit(body)
  @implicit_continues.pop()
  @implicit_continues.pop()

  emit(OPCODES::JUMP, label_continue)
  emit(OPCODES::LABEL, label_break)
end
parseEmptyStatement(node) click to toggle source
# File lib/ruby_run_js/bytecode_generator.rb, line 219
def parseEmptyStatement(node)
end
parseExpressionStatement(expression, node) click to toggle source
# File lib/ruby_run_js/bytecode_generator.rb, line 222
def parseExpressionStatement(expression, node)
  emit(OPCODES::POP)
  emit(expression)
end
parseForInStatement(left, right, body, node) click to toggle source
# File lib/ruby_run_js/bytecode_generator.rb, line 266
def parseForInStatement(left, right, body, node)
  label_continue = new_label()
  label_break = new_label()
  label_start = new_label()

  if left[:type] == 'VariableDeclaration'
    if left[:declarations].length != 1
      raise make_error(
        'SyntaxError', 
        ' Invalid left-hand side in for-in loop: Must have a single binding.'
      )
    end
    emit(left)
    name = left[:declarations][0][:id][:name]
  elsif left[:type] == 'Identifier'
    name = left[:name]
  else
    raise make_error('SyntaxError',
                     'Invalid left-hand side in for-loop')
  end
  emit(right)
  emit(OPCODES::FOR_IN, name, label_start, label_continue, label_break)

  emit(OPCODES::LABEL, label_continue)
  emit(OPCODES::NOP)

  emit(OPCODES::LABEL, label_start)

  @implicit_continues.push(label_continue)
  @implicit_breaks.push(label_break)
  emit(OPCODES::LOAD_UNDEFINED)
  emit(body)
  @implicit_continues.pop()
  @implicit_breaks.pop()
  emit(OPCODES::LABEL, label_break)
end
parseForStatement(init, test, update, body, node) click to toggle source
# File lib/ruby_run_js/bytecode_generator.rb, line 227
def parseForStatement(init, test, update, body, node)
  label_continue = new_label()
  label_break = new_label()
  label_start = new_label()

  unless init.nil?
    emit(init)
    if init[:type] != 'VariableDeclaration'
      emit(OPCODES::POP)
    end
  end

  emit(OPCODES::JUMP, label_start)

  emit(OPCODES::LABEL, label_continue)
  
  unless update.nil?
    emit(update)
    emit(OPCODES::POP)
  end

  emit(OPCODES::LABEL, label_start)

  unless test.nil?
    emit(test)
    emit(OPCODES::JUMP_IF_FALSE, label_break)
  end

  @implicit_continues.push(label_continue)
  @implicit_breaks.push(label_break)
  emit(body)
  @implicit_continues.pop()
  @implicit_continues.pop()

  emit(OPCODES::JUMP, label_continue)
  emit(OPCODES::LABEL, label_break)

end
parseFunctionDeclaration(id, params, defaults, body, node) click to toggle source
# File lib/ruby_run_js/bytecode_generator.rb, line 303
def parseFunctionDeclaration(id, params, defaults, body, node)
  
  push_state()

  function_start = new_label()
  function_end = new_label()

  # just skip the function code when the function is not called
  emit(OPCODES::JUMP, function_end)

  emit(OPCODES::LABEL, function_start)

  cur_index = @bytecodes.length

  emit(body)
  emit(OPCODES::RETURN)

  @bytecodes = @bytecodes[0...cur_index].concat(@function_declaration_codes, @bytecodes[cur_index..])
  
  emit(OPCODES::LABEL, function_end)

  declared_vars = @declared_vars

  pop_state()

  name = id[:name]
  @declared_vars.push(name)

  # init the function declarations
  @function_declaration_codes.push(
    OPCODES::LOAD_FUNCTION.new(function_start, params.map { |p| p[:name] },\
       name, true, declared_vars )
  )
  @function_declaration_codes.push(
    OPCODES::STORE.new(name)
  )
  @function_declaration_codes.push(
    OPCODES::POP.new()
  )
end
parseFunctionExpression(id, params, defaults, body, node) click to toggle source
# File lib/ruby_run_js/bytecode_generator.rb, line 344
def parseFunctionExpression(id, params, defaults, body, node)
  push_state()

  function_start = new_label()
  function_end = new_label()

  # just skip the function code when the function is not being called
  emit(OPCODES::JUMP, function_end)

  emit(OPCODES::LABEL, function_start)

  cur_index = @bytecodes.length

  emit(body)
  emit(OPCODES::RETURN)

  @bytecodes = @bytecodes[0...cur_index].concat(@function_declaration_codes, @bytecodes[cur_index..])
  
  emit(OPCODES::LABEL, function_end)

  declared_vars = @declared_vars

  pop_state()

  name = id.nil? ? nil : id[:name]

  emit(OPCODES::LOAD_FUNCTION, function_start, params.map { |p| p[:name] },\
    name, false, declared_vars)
end
parseIdentifier(name, node) click to toggle source
# File lib/ruby_run_js/bytecode_generator.rb, line 374
def parseIdentifier(name, node)
  if name == 'undefined'
    emit(OPCODES::LOAD_UNDEFINED)
  else
    emit(OPCODES::LOAD, name)
  end
end
parseIfStatement(test, consequent, alternate, node) click to toggle source
# File lib/ruby_run_js/bytecode_generator.rb, line 382
def parseIfStatement(test, consequent, alternate, node)
  label_alt = new_label()
  label_end = new_label()

  emit(test)
  emit(OPCODES::JUMP_IF_FALSE, label_alt)

  emit(consequent)
  emit(OPCODES::JUMP, label_end)

  emit(OPCODES::LABEL, label_alt)
  unless alternate.nil?
    emit(alternate)
  else
    emit(OPCODES::NOP)
  end
  emit(OPCODES::LABEL, label_end)
end
parseLabeledStatement(label, body, node) click to toggle source
# File lib/ruby_run_js/bytecode_generator.rb, line 401
def parseLabeledStatement(label, body, node)
  label = label[:name]
  if ['WhileStatement', 'DoWhileStatement', \
      'ForStatement', 'ForInStatement'].include?(body[:type])
      @declared_continue_labels[label] = @label_id + 1
      @declared_break_labels[label] = @label_id + 2
      emit(body)
      @declared_break_labels.delete(label)
      @declared_continue_labels.delete(label)
  else
    label_break = new_label()
    @declared_break_labels[label] = label_break
    emit(body)
    emit(OPCODES::LABEL, label_break)
    @declared_break_labels.delete(label)
  end
end
parseLexicalDeclaration(declarations, kind, node) click to toggle source
# File lib/ruby_run_js/bytecode_generator.rb, line 675
def parseLexicalDeclaration(declarations, kind, node)
  raise "'Not supported by ECMA 5.1"
end
parseLiteral(value, node) click to toggle source
# File lib/ruby_run_js/bytecode_generator.rb, line 419
def parseLiteral(value, node)
  if value == nil
    emit(OPCODES::LOAD_NULL)
  elsif value == true || value == false
    emit(OPCODES::LOAD_BOOLEAN, value)
  elsif value.is_a?(String)
    emit(OPCODES::LOAD_STRING, value)
  elsif value.is_a?(Numeric)
    emit(OPCODES::LOAD_NUMBER, value.to_f)
  elsif node[:regexp] != nil
    emit(OPCODES::LOAD_REGEXP, node[:regexp][:pattern], node[:regexp][:flags])
  else
    raise "Unsupported literal: #{value}"
  end
end
parseLogicalExpression(left, right, operator, node) click to toggle source
# File lib/ruby_run_js/bytecode_generator.rb, line 435
def parseLogicalExpression(left, right, operator, node)
  label_end = new_label()
  if operator == '&&'
    emit(left)
    emit(OPCODES::JUMP_IF_FALSE_WITHOUT_POP, label_end)
    emit(OPCODES::POP)
    emit(right)
    emit(OPCODES::LABEL, label_end)
  elsif operator == '||'
    emit(left)
    emit(OPCODES::JUMP_IF_TRUE_WITHOUT_POP, label_end)
    emit(OPCODES::POP)
    emit(right)
    emit(OPCODES::LABEL, label_end)
  else
    raise "Unknown logical expression: #{operator}"
  end
end
parseMemberExpression(computed, object, property, node) click to toggle source
# File lib/ruby_run_js/bytecode_generator.rb, line 454
def parseMemberExpression(computed, object, property, node)
  if computed
    emit(object)
    emit(property)
    emit(OPCODES::LOAD_MEMBER)
  else
    emit(object)
    emit(OPCODES::LOAD_MEMBER_DOT, property[:name])
  end
end
parseNewExpression(callee, arguments, node) click to toggle source
# File lib/ruby_run_js/bytecode_generator.rb, line 465
def parseNewExpression(callee, arguments, node)
  emit(callee)
  if arguments.length > 0
    arguments.each do |a|
      emit(a)
    end
    emit(OPCODES::LOAD_N_TUPLE, arguments.length)
    emit(OPCODES::NEW)
  else
    emit(OPCODES::NEW_NO_ARGS)
  end
end
parseObjectExpression(properties, node) click to toggle source
# File lib/ruby_run_js/bytecode_generator.rb, line 495
def parseObjectExpression(properties, node)
  data = properties.map do |prop|
    emit(prop[:value])
    [to_key(prop[:key]), prop[:kind]]
  end
  emit(OPCODES::LOAD_OBJECT, data)
end
parseProgram(body, node) click to toggle source
# File lib/ruby_run_js/bytecode_generator.rb, line 503
def parseProgram(body, node)
  cur_index = @bytecodes.length
  emit(OPCODES::LOAD_UNDEFINED)
  emit(body)
  @bytecodes = @bytecodes[0...cur_index].concat(@function_declaration_codes, @bytecodes[cur_index..])
end
parseProperty(kind, key, computed, value, method, shorthand, node) click to toggle source
# File lib/ruby_run_js/bytecode_generator.rb, line 510
def parseProperty(kind, key, computed, value, method, shorthand, node)
  raise "Not available in ECMA 5.1"
end
parseRestElement(argument, node) click to toggle source
# File lib/ruby_run_js/bytecode_generator.rb, line 514
def parseRestElement(argument, node)
  raise "Not available in ECMA 5.1"
end
parseReturnStatement(argument, node) click to toggle source
# File lib/ruby_run_js/bytecode_generator.rb, line 518
def parseReturnStatement(argument, node)
  emit(OPCODES::POP)
  if argument.nil?
    emit(OPCODES::LOAD_UNDEFINED)
  else
    emit(argument)
  end
  emit(OPCODES::RETURN)
end
parseSequenceExpression(expressions, node) click to toggle source
# File lib/ruby_run_js/bytecode_generator.rb, line 528
def parseSequenceExpression(expressions, node)
  expressions.each_index do |i|
    emit(expressions[i])
    if i < expressions.length - 1
      emit(OPCODES::POP)
    end
  end
end
parseSwitchCase(test, consequent, node) click to toggle source
# File lib/ruby_run_js/bytecode_generator.rb, line 537
def parseSwitchCase(test, consequent, node)
  raise "Already implemented in SwitchStatement"
end
parseSwitchStatement(discriminant, cases, node) click to toggle source
# File lib/ruby_run_js/bytecode_generator.rb, line 541
def parseSwitchStatement(discriminant, cases, node)
  emit(discriminant)
  labels = cases.map { |c| new_label() }
  tests = cases.map { |c| c[:test] }
  consequents = cases.map { |c| c[:consequent] }
  label_switch_end = new_label()

  cases.length.times do |i|
    test = tests[i]
    if test.nil?
      # default
      emit(OPCODES::POP)
      emit(OPCODES::JUMP, labels[i])
    else
      emit(test)
      emit(OPCODES::JUMP_IF_EQ, labels[i])
    end
  end

  emit(OPCODES::POP)
  emit(OPCODES::JUMP, label_switch_end)

  @implicit_breaks << label_switch_end

  labels.length.times do |i|
    emit(OPCODES::LABEL, labels[i])
    consequents[i].each do |c|
      emit(c)
    end
  end
  @implicit_breaks.pop()

  emit(OPCODES::LABEL, label_switch_end)
end
parseThisExpression(node) click to toggle source
# File lib/ruby_run_js/bytecode_generator.rb, line 576
def parseThisExpression(node)
  emit(OPCODES::LOAD_THIS)
end
parseThrowStatement(argument, node) click to toggle source
# File lib/ruby_run_js/bytecode_generator.rb, line 580
def parseThrowStatement(argument, node)
  emit(OPCODES::POP)
  emit(argument)
  emit(OPCODES::THROW)
end
parseTryStatement(block, handlers, finalizer, node) click to toggle source
# File lib/ruby_run_js/bytecode_generator.rb, line 586
def parseTryStatement(block, handlers, finalizer, node)
  label_try = new_label()
  label_catch = new_label()
  label_finally = new_label()
  label_end = new_label()

  handler = handlers[0]

  catch_var_name = handler != nil ? handler[:param][:name] : nil

  emit(OPCODES::TRY_CATCH_FINALLY, label_try, label_catch, catch_var_name, label_finally, finalizer != nil, label_end)

  emit(OPCODES::LABEL, label_try)
  emit(OPCODES::LOAD_UNDEFINED)
  emit(block)
  emit(OPCODES::NOP)

  emit(OPCODES::LABEL, label_catch)
  emit(OPCODES::LOAD_UNDEFINED)
  if handler != nil
    emit(handler[:body])
  end
  emit(OPCODES::NOP)

  emit(OPCODES::LABEL, label_finally)
  emit(OPCODES::LOAD_UNDEFINED)
  if finalizer != nil
    emit(finalizer)
  end
  emit(OPCODES::NOP)

  emit(OPCODES::LABEL, label_end)

end
parseUnaryExpression(operator, argument, node) click to toggle source
# File lib/ruby_run_js/bytecode_generator.rb, line 621
def parseUnaryExpression(operator, argument, node)
  if operator == 'typeof' && argument[:type] == 'Identifier'
    emit(OPCODES::TYPEOF, argument[:name])
  elsif operator == 'delete'
    if argument[:type] == 'MemberExpression'
      emit(argument[:object])
      if argument[:property][:type] == 'Identifier'
        emit(OPCODES::LOAD_STRING, argument[:property][:name])
      else
        emit(argument[:property])
      end
      emit(OPCODES::DELETE_MEMBER)
    elsif argument[:type] == 'Identifier'
      emit(OPCODES::DELETE, argument[:name])
    else
      emit(OPCODES::LOAD_BOOLEAN, true)
    end
  elsif ['+', '-', '!', '~', 'void', 'typeof'].include?(operator)
    emit(argument)
    emit(OPCODES::UNARY_OP, operator)
  else
    raise make_error('SyntaxError', \
                     "Unknown unary operator #{operator}")
  end
end
parseUpdateExpression(operator, argument, prefix, node) click to toggle source
# File lib/ruby_run_js/bytecode_generator.rb, line 647
def parseUpdateExpression(operator, argument, prefix, node)
  incr = operator == '++'
  post = !prefix
  if argument[:type] == 'MemberExpression'
    if argument[:computed]
      emit(argument[:object])
      emit(argument[:property])
      emit(OPCODES::POSTFIX_MEMBER, post, incr)
    else
      emit(argument[:object])
      name = to_key(argument[:property])
      emit(OPCODES::POSTFIX_MEMBER_DOT, post, incr, name)
    end
  elsif argument[:type] == 'Identifier'
    name = to_key(argument)
    emit(OPCODES::POSTFIX, post, incr, name)
  else
    raise make_error('SyntaxError',
                    'Invalid left-hand side in assignment')
  end
end
parseVariableDeclaration(declarations, kind, node) click to toggle source
# File lib/ruby_run_js/bytecode_generator.rb, line 669
def parseVariableDeclaration(declarations, kind, node)
  declarations.each do |d|
    emit(d)
  end
end
parseVariableDeclarator(id, init, node) click to toggle source
# File lib/ruby_run_js/bytecode_generator.rb, line 679
def parseVariableDeclarator(id, init, node)
  name = id[:name]
  if ['true', 'false', 'this'].include?(name)
    raise make_error('SyntaxError',
      'Invalid left-hand side in assignment')
  end
  @declared_vars.push(name)
  if init != nil
    emit(init)
    emit(OPCODES::STORE, name)
    emit(OPCODES::POP)
  end
end
parseWhileStatement(test, body, node) click to toggle source
# File lib/ruby_run_js/bytecode_generator.rb, line 693
def parseWhileStatement(test, body, node)
  label_continue = new_label()
  label_break = new_label()

  emit(OPCODES::LABEL, label_continue)
  emit(test)
  emit(OPCODES::JUMP_IF_FALSE, label_break)

  @implicit_continues.append(label_continue)
  @implicit_breaks.append(label_break)
  emit(body)
  @implicit_continues.pop()
  @implicit_breaks.pop()

  emit(OPCODES::JUMP, label_continue)
  emit(OPCODES::LABEL, label_break)
end
parseWithStatement(object, body, node) click to toggle source
# File lib/ruby_run_js/bytecode_generator.rb, line 711
def parseWithStatement(object, body, node)
  label_start = new_label()
  label_end = new_label()

  emit(body)

  emit(OPCODES::WITH, label_start, label_end)

  emit(OPCODES::LABEL, label_start)
  emit(OPCODES::LOAD_UNDEFINED)
  emit(body)
  emit(OPCODES::NOP)
  emit(OPCODES::LABEL, label_end)
end
pop_state() click to toggle source
# File lib/ruby_run_js/bytecode_generator.rb, line 45
def pop_state()
  @implicit_breaks, @implicit_continues, \
  @declared_continue_labels, @declared_break_labels,\
  @function_declaration_codes, @declared_vars = @state.pop()
end
push_state() click to toggle source
# File lib/ruby_run_js/bytecode_generator.rb, line 32
def push_state()
  @state << [ @implicit_breaks, @implicit_continues,\
   @declared_continue_labels, @declared_break_labels,\
   @function_declaration_codes, @declared_vars ]

   @implicit_breaks = []
   @implicit_continues = []
   @declared_continue_labels = {}
   @declared_break_labels = {}
   @function_declaration_codes = []
   @declared_vars = []
end
to_key(node) click to toggle source
# File lib/ruby_run_js/bytecode_generator.rb, line 478
def to_key(node)
  if node[:type] == 'Identifier'
    return node[:name]
  end
  if node[:type] == 'Literal'
    v = node[:value]
    if v.js_type == :Number && v.to_i == v
      return v.to_i.to_s
    elsif node[:regexp] != nil
      return "/#{node[:body]}/#{node[:flags]}"
    elsif v == nil
      return 'null'
    end
    return v.to_s
  end
end