lib/opal/nodes/variables.rb
# frozen_string_literal: true
require 'opal/nodes/base'
module Opal
module Nodes
class LocalVariableNode < Base
handle :lvar
children :var_name
def using_irb?
compiler.irb? && scope.top?
end
def compile
return push(var_name.to_s) unless using_irb?
with_temp do |tmp|
push property(var_name.to_s)
wrap "((#{tmp} = Opal.irb_vars", ") == null ? nil : #{tmp})"
end
end
end
class LocalAssignNode < Base
handle :lvasgn
children :var_name, :value
def using_irb?
compiler.irb? && scope.top?
end
def compile
if using_irb?
push "Opal.irb_vars#{property var_name.to_s} = "
else
add_local var_name.to_s
push "#{var_name} = "
end
push expr(value)
wrap '(', ')' if (recv? || expr?) && value
end
end
class LocalDeclareNode < Base
handle :lvdeclare
children :var_name
def compile
add_local(var_name.to_s)
nil
end
end
class InstanceVariableNode < Base
handle :ivar
children :name
def var_name
name.to_s[1..-1]
end
def compile
name = property(var_name)
add_ivar name
push "#{scope.self}#{name}"
end
end
class InstanceAssignNode < Base
handle :ivasgn
children :name, :value
def var_name
name.to_s[1..-1]
end
def compile
name = property(var_name)
push "#{scope.self}#{name} = "
push expr(value)
wrap '(', ')' if (recv? || expr?) && value
end
end
class GlobalVariableNode < Base
handle :gvar
children :name
def var_name
name.to_s[1..-1]
end
def compile
helper :gvars
name = property var_name
add_gvar name
push "$gvars#{name}"
end
end
# back_ref can be:
# $`
# $'
# $&
# $+ (currently unsupported)
class BackRefNode < GlobalVariableNode
handle :back_ref
def compile
helper :gvars
case var_name
when '&'
handle_global_match
when "'"
handle_post_match
when '`'
handle_pre_match
when '+'
super
else
raise NotImplementedError
end
end
def handle_global_match
with_temp do |tmp|
push "((#{tmp} = $gvars['~']) === nil ? nil : #{tmp}['$[]'](0))"
end
end
def handle_pre_match
with_temp do |tmp|
push "((#{tmp} = $gvars['~']) === nil ? nil : #{tmp}.$pre_match())"
end
end
def handle_post_match
with_temp do |tmp|
push "((#{tmp} = $gvars['~']) === nil ? nil : #{tmp}.$post_match())"
end
end
end
class GlobalAssignNode < Base
handle :gvasgn
children :name, :value
def var_name
name.to_s[1..-1]
end
def compile
helper :gvars
name = property var_name
push "$gvars#{name} = "
push expr(value)
wrap '(', ')' if (recv? || expr?) && value
end
end
# $1 => s(:nth_ref, 1)
class NthrefNode < Base
handle :nth_ref
children :index
def compile
helper :gvars
with_temp do |tmp|
push "((#{tmp} = $gvars['~']) === nil ? nil : #{tmp}['$[]'](#{index}))"
end
end
end
class ClassVariableNode < Base
handle :cvar
children :name
def compile
helper :class_variable_get
tolerant = false
# We should be tolerant of expressions like: def x; @@notexist; 0; end
# (NB: Shouldn't we actually optimize them out?)
tolerant = true if stmt?
# We should be tolerant of expressions like: @@notexist ||= 6
# (those are handled with logical_operator_assignment)
push "$class_variable_get(#{class_variable_owner}, '#{name}', #{tolerant.inspect})"
end
end
class ClassVarAssignNode < Base
handle :cvasgn
children :name, :value
def compile
helper :class_variable_set
push "$class_variable_set(#{class_variable_owner}, '#{name}', ", expr(value), ')'
end
end
end
end