Class: Opal::Nodes::ScopeNode
Direct Known Subclasses
BeginNode , ModuleNode , NodeWithArgs , SingletonClassNode , TopNode
Instance Attribute Summary collapse
-
#await_encountered ⇒ Object
Returns the value of attribute await_encountered.
-
#block_name ⇒ Object
The given block name for a def scope.
-
#catch_return ⇒ Object
Returns the value of attribute catch_return.
-
#defs ⇒ Object
true if singleton def, false otherwise.
-
#gvars ⇒ Object
readonly
Returns the value of attribute gvars.
-
#has_break ⇒ Object
Returns the value of attribute has_break.
-
#has_retry ⇒ Object
Returns the value of attribute has_retry.
-
#identity ⇒ Object
readonly
Returns the value of attribute identity.
-
#ivars ⇒ Object
readonly
Returns the value of attribute ivars.
-
#locals ⇒ Object
readonly
Returns the value of attribute locals.
-
#methods ⇒ Object
readonly
used by modules to know what methods to donate to includees.
-
#mid ⇒ Object
Returns the value of attribute mid.
-
#name ⇒ Object
The class or module name if this scope is a class scope.
-
#parent ⇒ Object
Every scope can have a parent scope.
-
#rescue_else_sexp ⇒ Object
Returns the value of attribute rescue_else_sexp.
-
#scope_name ⇒ Object
readonly
Returns the value of attribute scope_name.
Attributes inherited from Base
Attributes included from Closure::NodeSupport
Instance Method Summary collapse
- #accepts_using? ⇒ Boolean
- #add_arg(arg) ⇒ Object
- #add_proto_ivar(ivar) ⇒ Object
- #add_scope_gvar(gvar) ⇒ Object
- #add_scope_ivar(ivar) ⇒ Object
- #add_scope_local(local) ⇒ Object
- #add_scope_temp(tmp) ⇒ Object
-
#class? ⇒ Boolean
Returns true if this is strictly a class scope.
-
#class_scope? ⇒ Boolean
Returns true if this scope is a class/module body scope.
- #collect_refinements_temps(temps = []) ⇒ Object
- #current_rescue ⇒ Object
- #def? ⇒ Boolean
-
#def_in_class? ⇒ Boolean
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.
- #defines_lambda ⇒ Object
- #find_parent_def ⇒ Object
- #gen_retry_id ⇒ Object
- #has_local?(local) ⇒ Boolean
- #has_rescue_else? ⇒ Boolean
- #has_temp?(tmp) ⇒ Boolean
- #identify!(name = nil) ⇒ Object
- #in_ensure ⇒ Object
- #in_ensure? ⇒ Boolean
- #in_resbody ⇒ Object
- #in_resbody? ⇒ Boolean
- #in_rescue(node) ⇒ Object
- #in_scope ⇒ Object
- #in_while? ⇒ Boolean
-
#initialize ⇒ ScopeNode
constructor
A new instance of ScopeNode.
-
#is_lambda! ⇒ Object
rubocop:disable Naming/PredicateName.
-
#iter? ⇒ Boolean
True if a block/iter scope.
- #lambda? ⇒ Boolean
- #lambda_definition? ⇒ Boolean
-
#module? ⇒ Boolean
True if this is a module scope.
-
#nesting ⇒ Object
Returns '$nesting', but also ensures we compile the nesting chain.
- #new_refinements_temp ⇒ Object
- #new_temp ⇒ Object
- #next_temp ⇒ Object
- #pop_while ⇒ Object
- #prepare_block(block_name = nil) ⇒ Object
- #prepend_scope_temp(tmp) ⇒ Object
- #push_while ⇒ Object
- #queue_temp(name) ⇒ Object
- #refinements_temp ⇒ Object
-
#relative_access ⇒ Object
Returns '$$', but also ensures we compile it.
- #sclass? ⇒ Boolean
- #scope_locals ⇒ Object
-
#self ⇒ Object
Returns 'self', but also ensures that the self variable is set.
- #super_chain ⇒ Object
-
#to_vars ⇒ Object
Vars to use inside each scope.
-
#top? ⇒ Boolean
Returns true if this is a top scope (main file body).
- #uses_block! ⇒ Object
- #uses_block? ⇒ Boolean
Methods inherited from Base
#add_gvar , #add_ivar , #add_local , #add_temp , children , #children , #class_variable_owner , #class_variable_owner_nesting_level , #comments , #compile , #compile_to_fragments , #error , #expr , #expr? , #expr_or_empty , #expr_or_nil , #fragment , handle , handlers , #helper , #process , #push , #recv , #recv? , #s , #scope , #source_location , #stmt , #stmt? , #top_scope , truthy_optimize? , #unshift , #while_loop , #with_temp , #wrap
Methods included from Closure::NodeSupport
#closure_is? , #compile_catcher , #generate_thrower , #generate_thrower_without_catcher , #in_closure , #pop_closure , #push_closure , #select_closure , #thrower
Methods included from Helpers
#current_indent , #empty_line , #indent , #js_truthy , #js_truthy_optimize , #line , #mid_to_jsid , #property , #valid_name?
Constructor Details
#initialize ⇒ ScopeNode
Returns a new instance of ScopeNode.
34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56
# File 'opal/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
Instance Attribute Details
#await_encountered ⇒ Object
Returns the value of attribute await_encountered.
419 420 421
# File 'opal/lib/opal/nodes/scope.rb', line 419 def await_encountered @await_encountered end
#block_name ⇒ Object
The given block name for a def scope
15 16 17
# File 'opal/lib/opal/nodes/scope.rb', line 15 def block_name @block_name end
#catch_return ⇒ Object
Returns the value of attribute catch_return.
30 31 32
# File 'opal/lib/opal/nodes/scope.rb', line 30 def catch_return @catch_return end
#defs ⇒ Object
true if singleton def, false otherwise
25 26 27
# File 'opal/lib/opal/nodes/scope.rb', line 25 def defs @defs end
#gvars ⇒ Object (readonly)
Returns the value of attribute gvars.
20 21 22
# File 'opal/lib/opal/nodes/scope.rb', line 20 def gvars @gvars end
#has_break ⇒ Object
Returns the value of attribute has_break.
30 31 32
# File 'opal/lib/opal/nodes/scope.rb', line 30 def has_break @has_break end
#has_retry ⇒ Object
Returns the value of attribute has_retry.
30 31 32
# File 'opal/lib/opal/nodes/scope.rb', line 30 def has_retry @has_retry end
#identity ⇒ Object (readonly)
Returns the value of attribute identity.
277 278 279
# File 'opal/lib/opal/nodes/scope.rb', line 277 def identity @identity end
#ivars ⇒ Object (readonly)
Returns the value of attribute ivars.
19 20 21
# File 'opal/lib/opal/nodes/scope.rb', line 19 def ivars @ivars end
#locals ⇒ Object (readonly)
Returns the value of attribute locals.
18 19 20
# File 'opal/lib/opal/nodes/scope.rb', line 18 def locals @locals end
#methods ⇒ Object (readonly)
used by modules to know what methods to donate to includees
28 29 30
# File 'opal/lib/opal/nodes/scope.rb', line 28 def methods @methods end
#mid ⇒ Object
Returns the value of attribute mid.
22 23 24
# File 'opal/lib/opal/nodes/scope.rb', line 22 def mid @mid end
#name ⇒ Object
The class or module name if this scope is a class scope
12 13 14
# File 'opal/lib/opal/nodes/scope.rb', line 12 def name @name end
#parent ⇒ Object
Every scope can have a parent scope
9 10 11
# File 'opal/lib/opal/nodes/scope.rb', line 9 def parent @parent end
#rescue_else_sexp ⇒ Object
Returns the value of attribute rescue_else_sexp.
32 33 34
# File 'opal/lib/opal/nodes/scope.rb', line 32 def rescue_else_sexp @rescue_else_sexp end
#scope_name ⇒ Object (readonly)
Returns the value of attribute scope_name.
17 18 19
# File 'opal/lib/opal/nodes/scope.rb', line 17 def scope_name @scope_name end
Instance Method Details
#accepts_using? ⇒ Boolean
Returns:
- (Boolean)
365 366 367 368 369
# File 'opal/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
#add_arg(arg) ⇒ Object
172 173 174 175
# File 'opal/lib/opal/nodes/scope.rb', line 172 def add_arg(arg) @args << arg unless @args.include? arg arg end
#add_proto_ivar(ivar) ⇒ Object
168 169 170
# File 'opal/lib/opal/nodes/scope.rb', line 168 def add_proto_ivar(ivar) @proto_ivars << ivar unless @proto_ivars.include? ivar end
#add_scope_gvar(gvar) ⇒ Object
164 165 166
# File 'opal/lib/opal/nodes/scope.rb', line 164 def add_scope_gvar(gvar) @gvars << gvar unless @gvars.include? gvar end
#add_scope_ivar(ivar) ⇒ Object
156 157 158 159 160 161 162
# File 'opal/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
#add_scope_local(local) ⇒ Object
177 178 179 180 181
# File 'opal/lib/opal/nodes/scope.rb', line 177 def add_scope_local(local) return if has_local? local @locals << local end
#add_scope_temp(tmp) ⇒ Object
194 195 196 197 198
# File 'opal/lib/opal/nodes/scope.rb', line 194 def add_scope_temp(tmp) return if has_temp?(tmp) @temps.push(tmp) end
#class? ⇒ Boolean
Returns true if this is strictly a class scope
Returns:
- (Boolean)
73 74 75
# File 'opal/lib/opal/nodes/scope.rb', line 73 def class? @type == :class end
#class_scope? ⇒ Boolean
Returns true if this scope is a class/module body scope
Returns:
- (Boolean)
68 69 70
# File 'opal/lib/opal/nodes/scope.rb', line 68 def class_scope? @type == :class || @type == :module end
#collect_refinements_temps(temps = []) ⇒ Object
371 372 373 374 375
# File 'opal/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
#current_rescue ⇒ Object
328 329 330
# File 'opal/lib/opal/nodes/scope.rb', line 328 def current_rescue @rescues.last end
#def? ⇒ Boolean
Returns:
- (Boolean)
96 97 98
# File 'opal/lib/opal/nodes/scope.rb', line 96 def def? @type == :def || @type == :defs end
#def_in_class? ⇒ Boolean
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
Returns:
- (Boolean)
121 122 123
# File 'opal/lib/opal/nodes/scope.rb', line 121 def def_in_class? !@defs && @type == :def && @parent && @parent.class? end
#defines_lambda ⇒ Object
108 109 110 111 112
# File 'opal/lib/opal/nodes/scope.rb', line 108 def defines_lambda @lambda_definition = true yield @lambda_definition = false end
#find_parent_def ⇒ Object
279 280 281 282 283 284 285 286 287 288
# File 'opal/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
#gen_retry_id ⇒ Object
360 361 362 363
# File 'opal/lib/opal/nodes/scope.rb', line 360 def gen_retry_id @next_retry_id ||= 'retry_0' @next_retry_id = @next_retry_id.succ end
#has_local?(local) ⇒ Boolean
Returns:
- (Boolean)
183 184 185 186 187
# File 'opal/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
#has_rescue_else? ⇒ Boolean
Returns:
- (Boolean)
314 315 316
# File 'opal/lib/opal/nodes/scope.rb', line 314 def has_rescue_else? !rescue_else_sexp.nil? end
#has_temp?(tmp) ⇒ Boolean
Returns:
- (Boolean)
206 207 208
# File 'opal/lib/opal/nodes/scope.rb', line 206 def has_temp?(tmp) @temps.include? tmp end
#identify!(name = nil) ⇒ Object
255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275
# File 'opal/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
#in_ensure ⇒ Object
346 347 348 349 350 351 352 353 354
# File 'opal/lib/opal/nodes/scope.rb', line 346 def in_ensure return unless block_given? @in_ensure = true result = yield @in_ensure = false result end
#in_ensure? ⇒ Boolean
Returns:
- (Boolean)
356 357 358
# File 'opal/lib/opal/nodes/scope.rb', line 356 def in_ensure? @in_ensure end
#in_resbody ⇒ Object
332 333 334 335 336 337 338 339 340
# File 'opal/lib/opal/nodes/scope.rb', line 332 def in_resbody return unless block_given? @in_resbody = true result = yield @in_resbody = false result end
#in_resbody? ⇒ Boolean
Returns:
- (Boolean)
342 343 344
# File 'opal/lib/opal/nodes/scope.rb', line 342 def in_resbody? @in_resbody end
#in_rescue(node) ⇒ Object
318 319 320 321 322 323 324 325 326
# File 'opal/lib/opal/nodes/scope.rb', line 318 def in_rescue(node) @rescues ||= [] @rescues.push(node) result = yield @rescues.pop result end
#in_scope ⇒ Object
58 59 60 61 62 63 64 65
# File 'opal/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
#in_while? ⇒ Boolean
Returns:
- (Boolean)
242 243 244
# File 'opal/lib/opal/nodes/scope.rb', line 242 def in_while? !@while_stack.empty? end
#is_lambda! ⇒ Object
rubocop:disable Naming/PredicateName
104 105 106
# File 'opal/lib/opal/nodes/scope.rb', line 104 def is_lambda! # rubocop:disable Naming/PredicateName @is_lambda = true end
#iter? ⇒ Boolean
True if a block/iter scope
Returns:
- (Boolean)
92 93 94
# File 'opal/lib/opal/nodes/scope.rb', line 92 def iter? @type == :iter end
#lambda? ⇒ Boolean
Returns:
- (Boolean)
100 101 102
# File 'opal/lib/opal/nodes/scope.rb', line 100 def lambda? iter? && @is_lambda end
#lambda_definition? ⇒ Boolean
Returns:
- (Boolean)
114 115 116
# File 'opal/lib/opal/nodes/scope.rb', line 114 def lambda_definition? @lambda_definition end
#module? ⇒ Boolean
True if this is a module scope
Returns:
- (Boolean)
78 79 80
# File 'opal/lib/opal/nodes/scope.rb', line 78 def module? @type == :module end
#nesting ⇒ Object
Returns '$nesting', but also ensures we compile the nesting chain
396 397 398 399
# File 'opal/lib/opal/nodes/scope.rb', line 396 def nesting @define_nesting = true '$nesting' end
#new_refinements_temp ⇒ Object
377 378 379 380 381
# File 'opal/lib/opal/nodes/scope.rb', line 377 def new_refinements_temp var = compiler.unique_temp("$refn") add_scope_local(var) var end
#new_temp ⇒ Object
210 211 212 213 214 215 216
# File 'opal/lib/opal/nodes/scope.rb', line 210 def new_temp return @queue.pop unless @queue.empty? tmp = next_temp @temps << tmp tmp end
#next_temp ⇒ Object
218 219 220 221 222 223 224 225 226
# File 'opal/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
#pop_while ⇒ Object
238 239 240
# File 'opal/lib/opal/nodes/scope.rb', line 238 def pop_while @while_stack.pop end
#prepare_block(block_name = nil) ⇒ Object
407 408 409 410 411 412 413 414 415 416 417
# File 'opal/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
#prepend_scope_temp(tmp) ⇒ Object
200 201 202 203 204
# File 'opal/lib/opal/nodes/scope.rb', line 200 def prepend_scope_temp(tmp) return if has_temp?(tmp) @temps.unshift(tmp) end
#push_while ⇒ Object
232 233 234 235 236
# File 'opal/lib/opal/nodes/scope.rb', line 232 def push_while info = {} @while_stack.push info info end
#queue_temp(name) ⇒ Object
228 229 230
# File 'opal/lib/opal/nodes/scope.rb', line 228 def queue_temp(name) @queue << name end
#refinements_temp ⇒ Object
383 384 385 386 387
# File 'opal/lib/opal/nodes/scope.rb', line 383 def refinements_temp prev, curr = @refinements_temp, new_refinements_temp @refinements_temp = curr [prev, curr] end
#relative_access ⇒ Object
Returns '$$', but also ensures we compile it
402 403 404 405
# File 'opal/lib/opal/nodes/scope.rb', line 402 def relative_access @define_relative_access = @define_nesting = true '$$' end
#sclass? ⇒ Boolean
Returns:
- (Boolean)
82 83 84
# File 'opal/lib/opal/nodes/scope.rb', line 82 def sclass? @type == :sclass end
#scope_locals ⇒ Object
189 190 191 192
# File 'opal/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
#self ⇒ Object
Returns 'self', but also ensures that the self variable is set
390 391 392 393
# File 'opal/lib/opal/nodes/scope.rb', line 390 def self @define_self = true 'self' end
#super_chain ⇒ Object
290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308
# File 'opal/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[defdefs].include?(scope.type) defn = scope.identify! mid = "'#{scope.mid}'" break else break end end [chain, defn, mid] end
#to_vars ⇒ Object
Vars to use inside each scope
127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154
# File 'opal/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
#top? ⇒ Boolean
Returns true if this is a top scope (main file body)
Returns:
- (Boolean)
87 88 89
# File 'opal/lib/opal/nodes/scope.rb', line 87 def top? @type == :top end
#uses_block! ⇒ Object
246 247 248 249 250 251 252 253
# File 'opal/lib/opal/nodes/scope.rb', line 246 def uses_block! if @type == :iter && @parent @parent.uses_block! else @uses_block = true identify! end end
#uses_block? ⇒ Boolean
Returns:
- (Boolean)
310 311 312
# File 'opal/lib/opal/nodes/scope.rb', line 310 def uses_block? @uses_block end