Class: Opal::Nodes::ScopeNode
Direct Known Subclasses
BeginNode, ModuleNode, NodeWithArgs, SingletonClassNode, TopNode
Instance Attribute Summary collapse
-
#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.
-
#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.
-
#uses_super ⇒ Object
uses parents super method.
-
#uses_zuper ⇒ Object
Returns the value of attribute uses_zuper.
Attributes inherited from Base
Instance Method Summary collapse
- #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.
- #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.
- #find_parent_def ⇒ Object
- #get_super_chain ⇒ Object
- #has_local?(local) ⇒ Boolean
- #has_rescue_else? ⇒ Boolean
- #has_temp?(tmp) ⇒ Boolean
- #identify!(name = nil) ⇒ Object
- #identity ⇒ Object
- #in_ensure ⇒ Object
- #in_ensure? ⇒ Boolean
- #in_scope(&block) ⇒ Object
- #in_while? ⇒ Boolean
-
#initialize ⇒ ScopeNode
constructor
A new instance of ScopeNode.
-
#iter? ⇒ Boolean
True if a block/iter scope.
-
#module? ⇒ Boolean
True if this is a module scope.
- #new_temp ⇒ Object
- #next_temp ⇒ Object
- #pop_while ⇒ Object
-
#proto ⇒ Object
Inside a class or module scope, the javascript variable name returned by this function points to the classes' prototype.
- #push_while ⇒ Object
- #queue_temp(name) ⇒ Object
- #sclass? ⇒ Boolean
-
#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, #closest_module_node, #comments, #compile, #compile_to_fragments, #error, #expr, #expr?, #expr_or_nil, #fragment, handle, handlers, #helper, #process, #push, #recv, #recv?, #s, #scope, #stmt, #stmt?, truthy_optimize?, #unshift, #while_loop, #with_temp, #wrap
Methods included from Helpers
#conditional_send, #current_indent, #empty_line, #indent, #js_falsy, #js_truthy, #js_truthy_optimize, #line, #mid_to_jsid, #property, #valid_name?
Constructor Details
#initialize ⇒ ScopeNode
Returns a new instance of ScopeNode
38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 |
# File 'opal/lib/opal/nodes/scope.rb', line 38 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
#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
34 35 36 |
# File 'opal/lib/opal/nodes/scope.rb', line 34 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
34 35 36 |
# File 'opal/lib/opal/nodes/scope.rb', line 34 def has_break @has_break 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
36 37 38 |
# File 'opal/lib/opal/nodes/scope.rb', line 36 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 |
#uses_super ⇒ Object
uses parents super method
31 32 33 |
# File 'opal/lib/opal/nodes/scope.rb', line 31 def uses_super @uses_super end |
#uses_zuper ⇒ Object
Returns the value of attribute uses_zuper
32 33 34 |
# File 'opal/lib/opal/nodes/scope.rb', line 32 def uses_zuper @uses_zuper end |
Instance Method Details
#add_arg(arg) ⇒ Object
164 165 166 167 |
# File 'opal/lib/opal/nodes/scope.rb', line 164 def add_arg(arg) @args << arg unless @args.include? arg arg end |
#add_proto_ivar(ivar) ⇒ Object
160 161 162 |
# File 'opal/lib/opal/nodes/scope.rb', line 160 def add_proto_ivar(ivar) @proto_ivars << ivar unless @proto_ivars.include? ivar end |
#add_scope_gvar(gvar) ⇒ Object
156 157 158 |
# File 'opal/lib/opal/nodes/scope.rb', line 156 def add_scope_gvar(gvar) @gvars << gvar unless @gvars.include? gvar end |
#add_scope_ivar(ivar) ⇒ Object
148 149 150 151 152 153 154 |
# File 'opal/lib/opal/nodes/scope.rb', line 148 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
169 170 171 172 173 |
# File 'opal/lib/opal/nodes/scope.rb', line 169 def add_scope_local(local) return if has_local? local @locals << local end |
#add_scope_temp(tmp) ⇒ Object
181 182 183 184 185 |
# File 'opal/lib/opal/nodes/scope.rb', line 181 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
77 78 79 |
# File 'opal/lib/opal/nodes/scope.rb', line 77 def class? @type == :class end |
#class_scope? ⇒ Boolean
Returns true if this scope is a class/module body scope
72 73 74 |
# File 'opal/lib/opal/nodes/scope.rb', line 72 def class_scope? @type == :class or @type == :module end |
#def? ⇒ Boolean
100 101 102 |
# File 'opal/lib/opal/nodes/scope.rb', line 100 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
107 108 109 |
# File 'opal/lib/opal/nodes/scope.rb', line 107 def def_in_class? !@defs && @type == :def && @parent && @parent.class? end |
#find_parent_def ⇒ Object
252 253 254 255 256 257 258 259 260 261 |
# File 'opal/lib/opal/nodes/scope.rb', line 252 def find_parent_def scope = self while scope = scope.parent if scope.def? return scope end end nil end |
#get_super_chain ⇒ Object
263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 |
# File 'opal/lib/opal/nodes/scope.rb', line 263 def get_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 [:def, :defs].include?(scope.type) defn = scope.identify! mid = "'#{scope.mid}'" break else break end end [chain, defn, mid] end |
#has_local?(local) ⇒ Boolean
175 176 177 178 179 |
# File 'opal/lib/opal/nodes/scope.rb', line 175 def has_local?(local) return true if @locals.include? local or @args.include? local or @temps.include? local return @parent.has_local?(local) if @parent and @type == :iter false end |
#has_rescue_else? ⇒ Boolean
287 288 289 |
# File 'opal/lib/opal/nodes/scope.rb', line 287 def has_rescue_else? !!rescue_else_sexp end |
#has_temp?(tmp) ⇒ Boolean
187 188 189 |
# File 'opal/lib/opal/nodes/scope.rb', line 187 def has_temp?(tmp) @temps.include? tmp end |
#identify!(name = nil) ⇒ Object
237 238 239 240 241 242 243 244 245 246 |
# File 'opal/lib/opal/nodes/scope.rb', line 237 def identify!(name = nil) return @identity if @identity # Parent scope is the defining module/class name ||= [(parent && (parent.name || parent.scope_name)), self.mid].compact.join('_') @identity = @compiler.unique_temp(name) @parent.add_scope_temp @identity if @parent @identity end |
#identity ⇒ Object
248 249 250 |
# File 'opal/lib/opal/nodes/scope.rb', line 248 def identity @identity end |
#in_ensure ⇒ Object
291 292 293 294 295 296 297 298 299 |
# File 'opal/lib/opal/nodes/scope.rb', line 291 def in_ensure return unless block_given? @in_ensure = true result = yield @in_ensure = false result end |
#in_ensure? ⇒ Boolean
301 302 303 |
# File 'opal/lib/opal/nodes/scope.rb', line 301 def in_ensure? !!@in_ensure end |
#in_scope(&block) ⇒ Object
62 63 64 65 66 67 68 69 |
# File 'opal/lib/opal/nodes/scope.rb', line 62 def in_scope(&block) indent do @parent = compiler.scope compiler.scope = self block.call self compiler.scope = @parent end end |
#in_while? ⇒ Boolean
224 225 226 |
# File 'opal/lib/opal/nodes/scope.rb', line 224 def in_while? !@while_stack.empty? end |
#iter? ⇒ Boolean
True if a block/iter scope
96 97 98 |
# File 'opal/lib/opal/nodes/scope.rb', line 96 def iter? @type == :iter end |
#module? ⇒ Boolean
True if this is a module scope
82 83 84 |
# File 'opal/lib/opal/nodes/scope.rb', line 82 def module? @type == :module end |
#new_temp ⇒ Object
191 192 193 194 195 196 197 |
# File 'opal/lib/opal/nodes/scope.rb', line 191 def new_temp return @queue.pop unless @queue.empty? tmp = next_temp @temps << tmp tmp end |
#next_temp ⇒ Object
199 200 201 202 203 204 205 206 207 208 |
# File 'opal/lib/opal/nodes/scope.rb', line 199 def next_temp while true tmp = "$#{@unique}" @unique = @unique.succ unless has_local?(tmp) break end end tmp end |
#pop_while ⇒ Object
220 221 222 |
# File 'opal/lib/opal/nodes/scope.rb', line 220 def pop_while @while_stack.pop end |
#proto ⇒ Object
Inside a class or module scope, the javascript variable name returned by this function points to the classes' prototype. This is the target to where methods are actually added inside a class body.
114 115 116 |
# File 'opal/lib/opal/nodes/scope.rb', line 114 def proto "def" end |
#push_while ⇒ Object
214 215 216 217 218 |
# File 'opal/lib/opal/nodes/scope.rb', line 214 def push_while info = {} @while_stack.push info info end |
#queue_temp(name) ⇒ Object
210 211 212 |
# File 'opal/lib/opal/nodes/scope.rb', line 210 def queue_temp(name) @queue << name end |
#sclass? ⇒ Boolean
86 87 88 |
# File 'opal/lib/opal/nodes/scope.rb', line 86 def sclass? @type == :sclass end |
#to_vars ⇒ Object
Vars to use inside each scope
120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 |
# File 'opal/lib/opal/nodes/scope.rb', line 120 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 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? and !@proto_ivars.empty? #raise "FIXME to_vars" pvars = @proto_ivars.map { |i| "#{proto}#{i}"}.join(' = ') result = "%s\n%s%s = nil;" % [str, indent, pvars] else result = str end fragment(result) end |
#top? ⇒ Boolean
Returns true if this is a top scope (main file body)
91 92 93 |
# File 'opal/lib/opal/nodes/scope.rb', line 91 def top? @type == :top end |
#uses_block! ⇒ Object
228 229 230 231 232 233 234 235 |
# File 'opal/lib/opal/nodes/scope.rb', line 228 def uses_block! if @type == :iter && @parent @parent.uses_block! else @uses_block = true identify! end end |
#uses_block? ⇒ Boolean
283 284 285 |
# File 'opal/lib/opal/nodes/scope.rb', line 283 def uses_block? @uses_block end |