Class: KatakataIrb::Scope
Constant Summary
Constants inherited
from BaseScope
BaseScope::BREAK_RESULT, BaseScope::NEXT_RESULT, BaseScope::PATTERNMATCH_BREAK, BaseScope::RETURN_RESULT
Instance Attribute Summary collapse
Attributes inherited from BaseScope
#self_object
Class Method Summary
collapse
Instance Method Summary
collapse
-
#[](name) ⇒ Object
-
#[]=(name, value) ⇒ Object
-
#base_scope ⇒ Object
-
#class_variables ⇒ Object
-
#conditional(&block) ⇒ Object
-
#constants ⇒ Object
-
#get_const(nesting, path, key = nil) ⇒ Object
-
#get_cvar(nesting, path, name, key = nil) ⇒ Object
-
#global_variables ⇒ Object
-
#has_own?(name) ⇒ Boolean
-
#initialize(parent, table = {}, trace_ivar: true, trace_lvar: true, self_type: nil, nesting: nil) ⇒ Scope
constructor
-
#instance_variables ⇒ Object
-
#level_of(name, var_type) ⇒ Object
-
#local_variables ⇒ Object
-
#merge_jumps ⇒ Object
-
#mutable? ⇒ Boolean
-
#never(&block) ⇒ Object
-
#run_branches(*blocks) ⇒ Object
-
#self_instance_variable_get(name) ⇒ Object
-
#self_type ⇒ Object
-
#set_const(nesting, path, value) ⇒ Object
-
#set_cvar(nesting, path, name, value) ⇒ Object
-
#store_jump(type, value, changes) ⇒ Object
-
#table_class_variables ⇒ Object
-
#table_constants ⇒ Object
-
#table_instance_variables ⇒ Object
-
#table_module_constants(mod) ⇒ Object
-
#terminate ⇒ Object
-
#terminate_with(type, value) ⇒ Object
-
#terminated? ⇒ Boolean
-
#trace?(name) ⇒ Boolean
-
#update(child_scope) ⇒ Object
Methods inherited from BaseScope
#module_own_constant?, type_by_name, type_of
Constructor Details
#initialize(parent, table = {}, trace_ivar: true, trace_lvar: true, self_type: nil, nesting: nil) ⇒ Scope
Returns a new instance of Scope.
115
116
117
118
119
120
121
122
123
124
125
|
# File 'lib/katakata_irb/scope.rb', line 115
def initialize(parent, table = {}, trace_ivar: true, trace_lvar: true, self_type: nil, nesting: nil)
@parent = parent
@level = parent.level + 1
@trace_ivar = trace_ivar
@trace_lvar = trace_lvar
@module_nesting = nesting ? [nesting, *parent.module_nesting] : parent.module_nesting
@self_type = self_type
@terminated = false
@jump_branches = []
@mergeable_changes = @table = table.transform_values { [level, _1] }
end
|
Instance Attribute Details
#level ⇒ Object
Returns the value of attribute level.
111
112
113
|
# File 'lib/katakata_irb/scope.rb', line 111
def level
@level
end
|
#mergeable_changes ⇒ Object
Returns the value of attribute mergeable_changes.
111
112
113
|
# File 'lib/katakata_irb/scope.rb', line 111
def mergeable_changes
@mergeable_changes
end
|
#module_nesting ⇒ Object
Returns the value of attribute module_nesting.
111
112
113
|
# File 'lib/katakata_irb/scope.rb', line 111
def module_nesting
@module_nesting
end
|
#parent ⇒ Object
Returns the value of attribute parent.
111
112
113
|
# File 'lib/katakata_irb/scope.rb', line 111
def parent
@parent
end
|
Class Method Details
.from_binding(binding, locals) ⇒ Object
113
|
# File 'lib/katakata_irb/scope.rb', line 113
def self.from_binding(binding, locals) = new(BaseScope.new(binding, binding.eval('self'), locals))
|
Instance Method Details
#[](name) ⇒ Object
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
|
# File 'lib/katakata_irb/scope.rb', line 184
def [](name)
type = BaseScope.type_by_name(name)
if type == :const
return get_const(nil, nil, name) || KatakataIrb::Types::NIL if name.include?('::')
module_nesting.each do |(nesting, path)|
value = get_const nesting, [*path, name]
return value if value
end
return KatakataIrb::Types::NIL
elsif type == :cvar
return get_cvar(nil, nil, nil, name) if name.include?('::')
nesting, path = module_nesting.first
return get_cvar(nesting, path, name)
end
level, value = @table[name]
if level
value
elsif trace? name
@parent[name]
elsif type == :ivar
self_instance_variable_get name
end
end
|
#[]=(name, value) ⇒ Object
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
|
# File 'lib/katakata_irb/scope.rb', line 220
def []=(name, value)
type = BaseScope.type_by_name(name)
if type == :const
if name.include?('::')
@table[name] = [0, value]
else
parent_module, parent_path = module_nesting.first
set_const parent_module, [*parent_path, name], value
end
return
elsif type == :cvar
if name.include?('::')
@table[name] = [0, value]
else
parent_module, parent_path = module_nesting.first
set_cvar parent_module, parent_path, name, value
end
return
end
variable_level = level_of name, type
@table[name] = [variable_level, value] if variable_level
end
|
#base_scope ⇒ Object
278
279
280
|
# File 'lib/katakata_irb/scope.rb', line 278
def base_scope
@parent.mutable? ? @parent.base_scope : @parent
end
|
#class_variables ⇒ Object
331
332
333
334
335
336
|
# File 'lib/katakata_irb/scope.rb', line 331
def class_variables
cvars = table_class_variables
m, = module_nesting.first
cvars |= m.class_variables.map(&:to_s) if m.is_a? Module
cvars
end
|
#conditional(&block) ⇒ Object
355
356
357
|
# File 'lib/katakata_irb/scope.rb', line 355
def conditional(&block)
run_branches(block, ->(_s) {}).first || KatakataIrb::Types::NIL
end
|
#constants ⇒ Object
338
339
340
341
342
|
# File 'lib/katakata_irb/scope.rb', line 338
def constants
module_nesting.flat_map do |nest,|
nest.constants
end.map(&:to_s) | table_constants
end
|
#get_const(nesting, path, key = nil) ⇒ Object
172
173
174
175
176
|
# File 'lib/katakata_irb/scope.rb', line 172
def get_const(nesting, path, key = nil)
key ||= [nesting.__id__, path].join('::')
_l, value = @table[key]
value || @parent.get_const(nesting, path, key)
end
|
#get_cvar(nesting, path, name, key = nil) ⇒ Object
178
179
180
181
182
|
# File 'lib/katakata_irb/scope.rb', line 178
def get_cvar(nesting, path, name, key = nil)
key ||= [name, nesting.__id__, path].join('::')
_l, value = @table[key]
value || @parent.get_cvar(nesting, path, name, key)
end
|
#global_variables ⇒ Object
247
248
249
250
251
252
|
# File 'lib/katakata_irb/scope.rb', line 247
def global_variables
gvar_keys = @table.keys.select do |name|
BaseScope.type_by_name(name) == :gvar
end
gvar_keys | @parent.global_variables
end
|
#has_own?(name) ⇒ Boolean
378
379
380
|
# File 'lib/katakata_irb/scope.rb', line 378
def has_own?(name)
@table.key? name
end
|
#instance_variables ⇒ Object
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
|
# File 'lib/katakata_irb/scope.rb', line 288
def instance_variables
self_singleton_types = self_type.types.grep(KatakataIrb::Types::SingletonType)
singleton_classes = self_type.types.grep(KatakataIrb::Types::InstanceType).map(&:klass).select(&:singleton_class?)
base_self = base_scope.self_object
self_instance_variables = singleton_classes.flat_map do |singleton_class|
if singleton_class.respond_to? :attached_object
singleton_class.attached_object.instance_variables.map(&:to_s)
elsif singleton_class == base_self.singleton_class
base_self.instance_variables.map(&:to_s)
else
[]
end
end
[
self_singleton_types.flat_map { _1.module_or_class.instance_variables.map(&:to_s) },
self_instance_variables || [],
table_instance_variables
].inject(:|)
end
|
#level_of(name, var_type) ⇒ Object
161
162
163
164
165
166
167
168
169
170
|
# File 'lib/katakata_irb/scope.rb', line 161
def level_of(name, var_type)
case var_type
when :ivar
return level unless @trace_ivar
when :gvar
return 0
end
variable_level, = @table[name]
variable_level || parent.level_of(name, var_type)
end
|
#local_variables ⇒ Object
254
255
256
257
258
259
260
|
# File 'lib/katakata_irb/scope.rb', line 254
def local_variables
lvar_keys = @table.keys.select do |name|
BaseScope.type_by_name(name) == :lvar
end
lvar_keys |= @parent.local_variables if @trace_lvar
lvar_keys
end
|
#merge_jumps ⇒ Object
344
345
346
347
348
349
350
351
352
353
|
# File 'lib/katakata_irb/scope.rb', line 344
def merge_jumps
if terminated?
@terminated = false
@table = @mergeable_changes
merge @jump_branches
@terminated = true
else
merge [*@jump_branches, {}]
end
end
|
#mutable? ⇒ Boolean
127
|
# File 'lib/katakata_irb/scope.rb', line 127
def mutable? = true
|
#run_branches(*blocks) ⇒ Object
363
364
365
366
367
368
369
370
371
372
373
374
375
376
|
# File 'lib/katakata_irb/scope.rb', line 363
def run_branches(*blocks)
results = []
branches = []
blocks.each do |block|
scope = Scope.new self
result = block.call scope
next if scope.terminated?
results << result
branches << scope.mergeable_changes
end
terminate if branches.empty?
merge branches
results
end
|
#self_instance_variable_get(name) ⇒ Object
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
|
# File 'lib/katakata_irb/scope.rb', line 308
def self_instance_variable_get(name)
self_objects = self_type.types.grep(KatakataIrb::Types::SingletonType).map(&:module_or_class)
singleton_classes = self_type.types.grep(KatakataIrb::Types::InstanceType).map(&:klass).select(&:singleton_class?)
base_self = base_scope.self_object
singleton_classes.each do |singleton_class|
if singleton_class.respond_to? :attached_object
self_objects << singleton_class.attached_object
elsif singleton_class == base_self.singleton_class
self_objects << base_self
end
end
types = self_objects.map do |object|
BaseScope.type_of(fallback: KatakataIrb::Types::NIL) { object.instance_variable_get name }
end
KatakataIrb::Types::UnionType[*types]
end
|
#self_type ⇒ Object
243
244
245
|
# File 'lib/katakata_irb/scope.rb', line 243
def self_type
@self_type || @parent.self_type
end
|
#set_const(nesting, path, value) ⇒ Object
210
211
212
213
|
# File 'lib/katakata_irb/scope.rb', line 210
def set_const(nesting, path, value)
key = [nesting.__id__, path].join('::')
@table[key] = [0, value]
end
|
#set_cvar(nesting, path, name, value) ⇒ Object
215
216
217
218
|
# File 'lib/katakata_irb/scope.rb', line 215
def set_cvar(nesting, path, name, value)
key = [name, nesting.__id__, path].join('::')
@table[key] = [0, value]
end
|
#store_jump(type, value, changes) ⇒ Object
139
140
141
142
143
144
145
146
147
|
# File 'lib/katakata_irb/scope.rb', line 139
def store_jump(type, value, changes)
return if terminated?
if has_own?(type)
changes[type] = [level, value]
@jump_branches << changes
elsif @parent.mutable?
@parent.store_jump(type, value, changes)
end
end
|
#table_class_variables ⇒ Object
325
326
327
328
329
|
# File 'lib/katakata_irb/scope.rb', line 325
def table_class_variables
cvars = @table.keys.filter_map { _1.split('::', 2).first if BaseScope.type_by_name(_1) == :cvar }
cvars |= @parent.table_class_variables if @parent.mutable?
cvars
end
|
#table_constants ⇒ Object
262
263
264
265
266
267
268
269
|
# File 'lib/katakata_irb/scope.rb', line 262
def table_constants
constants = module_nesting.flat_map do |mod, path|
prefix = [mod.__id__, *path].join('::') + '::'
@table.keys.select { _1.start_with? prefix }.map { _1.delete_prefix(prefix).split('::').first }
end.uniq
constants |= @parent.table_constants if @parent.mutable?
constants
end
|
#table_instance_variables ⇒ Object
282
283
284
285
286
|
# File 'lib/katakata_irb/scope.rb', line 282
def table_instance_variables
ivars = @table.keys.select { BaseScope.type_by_name(_1) == :ivar }
ivars |= @parent.table_instance_variables if @parent.mutable? && @trace_ivar
ivars
end
|
#table_module_constants(mod) ⇒ Object
271
272
273
274
275
276
|
# File 'lib/katakata_irb/scope.rb', line 271
def table_module_constants(mod)
prefix = "#{mod.__id__}::"
constants = @table.keys.select { _1.start_with? prefix }.map { _1.delete_prefix(prefix).split('::').first }
constants |= @parent.table_constants if @parent.mutable?
constants
end
|
#terminate ⇒ Object
149
150
151
152
153
|
# File 'lib/katakata_irb/scope.rb', line 149
def terminate
return if terminated?
@terminated = true
@table = @mergeable_changes.dup
end
|
#terminate_with(type, value) ⇒ Object
133
134
135
136
137
|
# File 'lib/katakata_irb/scope.rb', line 133
def terminate_with(type, value)
return if terminated?
store_jump type, value, @mergeable_changes
terminate
end
|
#terminated? ⇒ Boolean
129
130
131
|
# File 'lib/katakata_irb/scope.rb', line 129
def terminated?
@terminated
end
|
#trace?(name) ⇒ Boolean
155
156
157
158
159
|
# File 'lib/katakata_irb/scope.rb', line 155
def trace?(name)
return false unless @parent
type = BaseScope.type_by_name(name)
type == :ivar ? @trace_ivar : type == :lvar ? @trace_lvar : true
end
|
#update(child_scope) ⇒ Object
382
383
384
385
386
387
|
# File 'lib/katakata_irb/scope.rb', line 382
def update(child_scope)
current_level = level
child_scope.mergeable_changes.each do |name, (level, value)|
self[name] = value if level <= current_level
end
end
|