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
#closure
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_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
#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
Returns a new instance of ScopeNode.
[View source]
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.
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
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.
277
278
279
|
# File 'opal/lib/opal/nodes/scope.rb', line 277
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
#add_arg(arg) ⇒ Object
[View source]
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
[View source]
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
[View source]
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
[View source]
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
[View source]
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
[View source]
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
[View source]
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
[View source]
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
[View source]
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
[View source]
328
329
330
|
# File 'opal/lib/opal/nodes/scope.rb', line 328
def current_rescue
@rescues.last
end
|
#def? ⇒ Boolean
[View source]
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
[View source]
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
[View source]
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
[View source]
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
[View source]
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
[View source]
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
[View source]
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
[View source]
206
207
208
|
# File 'opal/lib/opal/nodes/scope.rb', line 206
def has_temp?(tmp)
@temps.include? tmp
end
|
#identify!(name = nil) ⇒ Object
[View source]
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
@identity = "$$#{mid}"
else
name ||= [(parent && (parent.name || parent.scope_name)), mid].compact.join('_')
@identity = @compiler.unique_temp(name)
end
@identity
end
|
#in_ensure ⇒ Object
[View source]
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
[View source]
356
357
358
|
# File 'opal/lib/opal/nodes/scope.rb', line 356
def in_ensure?
@in_ensure
end
|
#in_resbody ⇒ Object
[View source]
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
[View source]
342
343
344
|
# File 'opal/lib/opal/nodes/scope.rb', line 342
def in_resbody?
@in_resbody
end
|
#in_rescue(node) ⇒ Object
[View source]
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
[View source]
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
[View source]
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
[View source]
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
[View source]
92
93
94
|
# File 'opal/lib/opal/nodes/scope.rb', line 92
def iter?
@type == :iter
end
|
#lambda? ⇒ Boolean
[View source]
100
101
102
|
# File 'opal/lib/opal/nodes/scope.rb', line 100
def lambda?
iter? && @is_lambda
end
|
#lambda_definition? ⇒ Boolean
[View source]
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
[View source]
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
[View source]
396
397
398
399
|
# File 'opal/lib/opal/nodes/scope.rb', line 396
def nesting
@define_nesting = true
'$nesting'
end
|
#new_refinements_temp ⇒ Object
[View source]
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
[View source]
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
[View source]
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
[View source]
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
[View source]
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
[View source]
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
[View source]
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
[View source]
228
229
230
|
# File 'opal/lib/opal/nodes/scope.rb', line 228
def queue_temp(name)
@queue << name
end
|
#refinements_temp ⇒ Object
[View source]
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
[View source]
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
[View source]
82
83
84
|
# File 'opal/lib/opal/nodes/scope.rb', line 82
def sclass?
@type == :sclass
end
|
#scope_locals ⇒ Object
[View source]
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
[View source]
390
391
392
393
|
# File 'opal/lib/opal/nodes/scope.rb', line 390
def self
@define_self = true
'self'
end
|
#super_chain ⇒ Object
[View source]
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[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
[View source]
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)
[View source]
87
88
89
|
# File 'opal/lib/opal/nodes/scope.rb', line 87
def top?
@type == :top
end
|
#uses_block! ⇒ Object
[View source]
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
[View source]
310
311
312
|
# File 'opal/lib/opal/nodes/scope.rb', line 310
def uses_block?
@uses_block
end
|