Class: Opal::Nodes::ScopeNode
- Inherits:
-
Base
- Object
- Base
- Opal::Nodes::ScopeNode
show all
- Defined in:
- opal/lib/opal/nodes/scope.rb
Instance Attribute Summary collapse
Attributes inherited from Base
#compiler, #sexp, #type
Instance Method Summary
collapse
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_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 Helpers
#current_indent, #empty_line, #indent, #js_truthy, #js_truthy_optimize, #line, #mid_to_jsid, #property, #valid_name?
Constructor Details
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
@proto_ivars = []
end
|
Instance Attribute Details
#await_encountered ⇒ Object
Returns the value of attribute await_encountered.
413
414
415
|
# File 'opal/lib/opal/nodes/scope.rb', line 413
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
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
Returns the value of attribute identity.
271
272
273
|
# File 'opal/lib/opal/nodes/scope.rb', line 271
def identity
@identity
end
|
#ivars ⇒ Object
Returns the value of attribute ivars.
19
20
21
|
# File 'opal/lib/opal/nodes/scope.rb', line 19
def ivars
@ivars
end
|
#locals ⇒ Object
Returns the value of attribute locals.
18
19
20
|
# File 'opal/lib/opal/nodes/scope.rb', line 18
def locals
@locals
end
|
#methods ⇒ Object
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
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
#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
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
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
365
366
367
368
369
|
# File 'opal/lib/opal/nodes/scope.rb', line 365
def collect_refinements_temps(temps = [])
temps << @refinements_temp if @refinements_temp
return parent.collect_refinements_temps(temps) if parent
temps
end
|
#current_rescue ⇒ Object
322
323
324
|
# File 'opal/lib/opal/nodes/scope.rb', line 322
def current_rescue
@rescues.last
end
|
#def? ⇒ 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
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
273
274
275
276
277
278
279
280
281
282
|
# File 'opal/lib/opal/nodes/scope.rb', line 273
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
354
355
356
357
|
# File 'opal/lib/opal/nodes/scope.rb', line 354
def gen_retry_id
@next_retry_id ||= 'retry_0'
@next_retry_id = @next_retry_id.succ
end
|
#has_local?(local) ⇒ 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
308
309
310
|
# File 'opal/lib/opal/nodes/scope.rb', line 308
def has_rescue_else?
!rescue_else_sexp.nil?
end
|
#has_temp?(tmp) ⇒ Boolean
200
201
202
|
# File 'opal/lib/opal/nodes/scope.rb', line 200
def has_temp?(tmp)
@temps.include? tmp
end
|
#identify!(name = nil) ⇒ Object
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
|
# File 'opal/lib/opal/nodes/scope.rb', line 249
def identify!(name = nil)
return @identity if @identity
if valid_name? mid
@identity = "$$#{mid}"
else
name ||= [(parent && (parent.name || parent.scope_name)), mid].compact.join('_')
@identity = @compiler.unique_temp(name)
end
@identity
end
|
#in_ensure ⇒ Object
340
341
342
343
344
345
346
347
348
|
# File 'opal/lib/opal/nodes/scope.rb', line 340
def in_ensure
return unless block_given?
@in_ensure = true
result = yield
@in_ensure = false
result
end
|
#in_ensure? ⇒ Boolean
350
351
352
|
# File 'opal/lib/opal/nodes/scope.rb', line 350
def in_ensure?
@in_ensure
end
|
#in_resbody ⇒ Object
326
327
328
329
330
331
332
333
334
|
# File 'opal/lib/opal/nodes/scope.rb', line 326
def in_resbody
return unless block_given?
@in_resbody = true
result = yield
@in_resbody = false
result
end
|
#in_resbody? ⇒ Boolean
336
337
338
|
# File 'opal/lib/opal/nodes/scope.rb', line 336
def in_resbody?
@in_resbody
end
|
#in_rescue(node) ⇒ Object
312
313
314
315
316
317
318
319
320
|
# File 'opal/lib/opal/nodes/scope.rb', line 312
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
236
237
238
|
# File 'opal/lib/opal/nodes/scope.rb', line 236
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! @is_lambda = true
end
|
#iter? ⇒ Boolean
True if a block/iter scope
92
93
94
|
# File 'opal/lib/opal/nodes/scope.rb', line 92
def iter?
@type == :iter
end
|
#lambda? ⇒ Boolean
100
101
102
|
# File 'opal/lib/opal/nodes/scope.rb', line 100
def lambda?
iter? && @is_lambda
end
|
#lambda_definition? ⇒ 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
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
390
391
392
393
|
# File 'opal/lib/opal/nodes/scope.rb', line 390
def nesting
@define_nesting = true
'$nesting'
end
|
#new_refinements_temp ⇒ Object
371
372
373
374
375
|
# File 'opal/lib/opal/nodes/scope.rb', line 371
def new_refinements_temp
var = compiler.unique_temp("$refn")
add_scope_local(var)
var
end
|
#new_temp ⇒ Object
204
205
206
207
208
209
210
|
# File 'opal/lib/opal/nodes/scope.rb', line 204
def new_temp
return @queue.pop unless @queue.empty?
tmp = next_temp
@temps << tmp
tmp
end
|
#next_temp ⇒ Object
212
213
214
215
216
217
218
219
220
|
# File 'opal/lib/opal/nodes/scope.rb', line 212
def next_temp
tmp = nil
loop do
tmp = "$#{@unique}"
@unique = @unique.succ
break unless has_local?(tmp)
end
tmp
end
|
#pop_while ⇒ Object
232
233
234
|
# File 'opal/lib/opal/nodes/scope.rb', line 232
def pop_while
@while_stack.pop
end
|
#prepare_block(block_name = nil) ⇒ Object
401
402
403
404
405
406
407
408
409
410
411
|
# File 'opal/lib/opal/nodes/scope.rb', line 401
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 "delete #{scope_name}.$$p;"
@block_prepared = true
end
end
|
#push_while ⇒ Object
226
227
228
229
230
|
# File 'opal/lib/opal/nodes/scope.rb', line 226
def push_while
info = {}
@while_stack.push info
info
end
|
#queue_temp(name) ⇒ Object
222
223
224
|
# File 'opal/lib/opal/nodes/scope.rb', line 222
def queue_temp(name)
@queue << name
end
|
#refinements_temp ⇒ Object
377
378
379
380
381
|
# File 'opal/lib/opal/nodes/scope.rb', line 377
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
396
397
398
399
|
# File 'opal/lib/opal/nodes/scope.rb', line 396
def relative_access
@define_relative_access = @define_nesting = true
'$$'
end
|
#sclass? ⇒ 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
384
385
386
387
|
# File 'opal/lib/opal/nodes/scope.rb', line 384
def self
@define_self = true
'self'
end
|
#super_chain ⇒ Object
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
|
# File 'opal/lib/opal/nodes/scope.rb', line 284
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
|
#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)
87
88
89
|
# File 'opal/lib/opal/nodes/scope.rb', line 87
def top?
@type == :top
end
|
#uses_block! ⇒ Object
240
241
242
243
244
245
246
247
|
# File 'opal/lib/opal/nodes/scope.rb', line 240
def uses_block!
if @type == :iter && @parent
@parent.uses_block!
else
@uses_block = true
identify!
end
end
|
#uses_block? ⇒ Boolean
304
305
306
|
# File 'opal/lib/opal/nodes/scope.rb', line 304
def uses_block?
@uses_block
end
|