class Opal::Nodes::ScopeNode
Attributes
The given block name for a def scope
true if singleton def, false otherwise
used by modules to know what methods to donate to includees
The class or module name if this scope is a class scope
Every scope can have a parent scope
Public Class Methods
Opal::Nodes::Base::new
# File lib/opal/nodes/scope.rb, line 34 def initialize(*) super @locals = [] @temps = [] @args = [] @ivars = [] @gvars = [] @parent = nil @queue = [] @unique = 'a' @while_stack = [] @identity = nil @defs = nil @methods = [] @uses_block = false @in_ensure = false # used by classes to store all ivars used in direct def methods @proto_ivars = [] end
Public Instance Methods
# File lib/opal/nodes/scope.rb, line 365 def accepts_using? # IterNode of a special kind of Module.new {} is accepted... # though we don't check for it that thoroughly. [TopNode, ModuleNode, ClassNode, IterNode].include? self.class end
# File lib/opal/nodes/scope.rb, line 172 def add_arg(arg) @args << arg unless @args.include? arg arg end
# File lib/opal/nodes/scope.rb, line 168 def add_proto_ivar(ivar) @proto_ivars << ivar unless @proto_ivars.include? ivar end
# File lib/opal/nodes/scope.rb, line 164 def add_scope_gvar(gvar) @gvars << gvar unless @gvars.include? gvar end
# File lib/opal/nodes/scope.rb, line 156 def add_scope_ivar(ivar) if def_in_class? @parent.add_proto_ivar ivar else @ivars << ivar unless @ivars.include? ivar end end
# File lib/opal/nodes/scope.rb, line 177 def add_scope_local(local) return if has_local? local @locals << local end
# File lib/opal/nodes/scope.rb, line 194 def add_scope_temp(tmp) return if has_temp?(tmp) @temps.push(tmp) end
Returns true if this is strictly a class scope
# File lib/opal/nodes/scope.rb, line 73 def class? @type == :class end
Returns true if this scope is a class/module body scope
# File lib/opal/nodes/scope.rb, line 68 def class_scope? @type == :class || @type == :module end
# File lib/opal/nodes/scope.rb, line 371 def collect_refinements_temps(temps = []) temps << @refinements_temp if @refinements_temp return parent.collect_refinements_temps(temps) if parent temps end
# File lib/opal/nodes/scope.rb, line 328 def current_rescue @rescues.last end
# File lib/opal/nodes/scope.rb, line 96 def def? @type == :def || @type == :defs end
Is this a normal def method directly inside a class? This is used for optimizing ivars as we can set them to nil in the class body
# File lib/opal/nodes/scope.rb, line 121 def def_in_class? !@defs && @type == :def && @parent && @parent.class? end
# File lib/opal/nodes/scope.rb, line 108 def defines_lambda @lambda_definition = true yield @lambda_definition = false end
# File lib/opal/nodes/scope.rb, line 279 def find_parent_def scope = self while scope = scope.parent if scope.def? || scope.lambda? return scope end end nil end
# File lib/opal/nodes/scope.rb, line 360 def gen_retry_id @next_retry_id ||= 'retry_0' @next_retry_id = @next_retry_id.succ end
# File lib/opal/nodes/scope.rb, line 183 def has_local?(local) return true if @locals.include?(local) || @args.include?(local) || @temps.include?(local) return @parent.has_local?(local) if @parent && @type == :iter false end
# File lib/opal/nodes/scope.rb, line 314 def has_rescue_else? !rescue_else_sexp.nil? end
# File lib/opal/nodes/scope.rb, line 206 def has_temp?(tmp) @temps.include? tmp end
# File lib/opal/nodes/scope.rb, line 255 def identify!(name = nil) return @identity if @identity if valid_name? mid # There are some special utf8 chars that can be used as valid JS # identifiers, some examples: # # utf8_pond = 'ⵌ' # utf8_question = 'ʔ̣' # utf8_exclamation 'ǃ' # # For now we're just using $$, to maintain compatibility with older IEs. @identity = "$$#{mid}" else # Parent scope is the defining module/class name ||= [(parent && (parent.name || parent.scope_name)), mid].compact.join('_') @identity = @compiler.unique_temp(name) end @identity end
# File lib/opal/nodes/scope.rb, line 346 def in_ensure return unless block_given? @in_ensure = true result = yield @in_ensure = false result end
# File lib/opal/nodes/scope.rb, line 356 def in_ensure? @in_ensure end
# File lib/opal/nodes/scope.rb, line 332 def in_resbody return unless block_given? @in_resbody = true result = yield @in_resbody = false result end
# File lib/opal/nodes/scope.rb, line 342 def in_resbody? @in_resbody end
# File lib/opal/nodes/scope.rb, line 318 def in_rescue(node) @rescues ||= [] @rescues.push(node) result = yield @rescues.pop result end
# File lib/opal/nodes/scope.rb, line 58 def in_scope indent do @parent = compiler.scope compiler.scope = self yield self compiler.scope = @parent end end
# File lib/opal/nodes/scope.rb, line 242 def in_while? !@while_stack.empty? end
# File lib/opal/nodes/scope.rb, line 104 def is_lambda! # rubocop:disable Naming/PredicateName @is_lambda = true end
True if a block/iter scope
# File lib/opal/nodes/scope.rb, line 92 def iter? @type == :iter end
# File lib/opal/nodes/scope.rb, line 100 def lambda? iter? && @is_lambda end
# File lib/opal/nodes/scope.rb, line 114 def lambda_definition? @lambda_definition end
True if this is a module scope
# File lib/opal/nodes/scope.rb, line 78 def module? @type == :module end
Returns ‘$nesting’, but also ensures we compile the nesting chain
# File lib/opal/nodes/scope.rb, line 396 def nesting @define_nesting = true '$nesting' end
# File lib/opal/nodes/scope.rb, line 377 def new_refinements_temp var = compiler.unique_temp("$refn") add_scope_local(var) var end
# File lib/opal/nodes/scope.rb, line 210 def new_temp return @queue.pop unless @queue.empty? tmp = next_temp @temps << tmp tmp end
# File lib/opal/nodes/scope.rb, line 218 def next_temp tmp = nil loop do tmp = "$#{@unique}" @unique = @unique.succ break unless has_local?(tmp) end tmp end
# File lib/opal/nodes/scope.rb, line 238 def pop_while @while_stack.pop end
# File lib/opal/nodes/scope.rb, line 407 def prepare_block(block_name = nil) scope_name = scope.identity self.block_name = block_name if block_name add_temp "#{self.block_name} = #{scope_name}.$$p || nil" unless @block_prepared line "#{scope_name}.$$p = null;" @block_prepared = true end end
# File lib/opal/nodes/scope.rb, line 200 def prepend_scope_temp(tmp) return if has_temp?(tmp) @temps.unshift(tmp) end
# File lib/opal/nodes/scope.rb, line 232 def push_while info = {} @while_stack.push info info end
# File lib/opal/nodes/scope.rb, line 228 def queue_temp(name) @queue << name end
# File lib/opal/nodes/scope.rb, line 383 def refinements_temp prev, curr = @refinements_temp, new_refinements_temp @refinements_temp = curr [prev, curr] end
Returns ‘$$’, but also ensures we compile it
# File lib/opal/nodes/scope.rb, line 402 def relative_access @define_relative_access = @define_nesting = true '$$' end
# File lib/opal/nodes/scope.rb, line 82 def sclass? @type == :sclass end
# File lib/opal/nodes/scope.rb, line 189 def scope_locals locals = @locals | @args | (@parent && @type == :iter ? @parent.scope_locals : []) locals.reject { |i| i.to_s.start_with?('$') } end
Returns ‘self’, but also ensures that the self variable is set
# File lib/opal/nodes/scope.rb, line 390 def self @define_self = true 'self' end
# File lib/opal/nodes/scope.rb, line 290 def super_chain chain, scope, defn, mid = [], self, 'null', 'null' while scope if scope.type == :iter chain << scope.identify! scope = scope.parent if scope.parent elsif %i[def defs].include?(scope.type) defn = scope.identify! mid = "'#{scope.mid}'" break else break end end [chain, defn, mid] end
Vars to use inside each scope
# File lib/opal/nodes/scope.rb, line 127 def to_vars vars = @temps.dup vars.push(*@locals.map { |l| "#{l} = nil" }) iv = ivars.map do |ivar| "if (self#{ivar} == null) self#{ivar} = nil;\n" end gv = gvars.map do |gvar| "if ($gvars#{gvar} == null) $gvars#{gvar} = nil;\n" end if class? && !@proto_ivars.empty? vars << '$proto = self.$$prototype' end indent = @compiler.parser_indent str = vars.empty? ? '' : "var #{vars.join ', '};\n" str += "#{indent}#{iv.join indent}" unless ivars.empty? str += "#{indent}#{gv.join indent}" unless gvars.empty? if class? && !@proto_ivars.empty? pvars = @proto_ivars.map { |i| "$proto#{i}" }.join(' = ') str = "#{str}\n#{indent}#{pvars} = nil;" end fragment(str) end
Returns true if this is a top scope (main file body)
# File lib/opal/nodes/scope.rb, line 87 def top? @type == :top end
# File lib/opal/nodes/scope.rb, line 246 def uses_block! if @type == :iter && @parent @parent.uses_block! else @uses_block = true identify! end end
# File lib/opal/nodes/scope.rb, line 310 def uses_block? @uses_block end