katakata_irb 0.1.3 → 0.1.5
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/Gemfile.lock +8 -2
- data/README.md +16 -26
- data/bin/console +2 -7
- data/katakata_irb.gemspec +2 -1
- data/lib/katakata_irb/completor.rb +128 -14
- data/lib/katakata_irb/{trex.rb → nesting_parser.rb} +47 -11
- data/lib/katakata_irb/scope.rb +248 -0
- data/lib/katakata_irb/type_simulator.rb +148 -332
- data/lib/katakata_irb/types.rb +96 -22
- data/lib/katakata_irb/version.rb +1 -1
- data/lib/katakata_irb.rb +5 -7
- metadata +21 -15
- data/exe/kirb +0 -11
- data/lib/katakata_irb/reline_patch.rb +0 -43
- data/lib/katakata_irb/reline_patches/escapeseq.patch +0 -45
- data/lib/katakata_irb/reline_patches/indent.patch +0 -25
- data/lib/katakata_irb/reline_patches/raw.patch +0 -95
- data/lib/katakata_irb/reline_patches/scrollbar.patch +0 -34
- data/lib/katakata_irb/reline_patches/wholelines.patch +0 -102
- data/lib/katakata_irb/ruby_lex_patch.rb +0 -221
@@ -0,0 +1,248 @@
|
|
1
|
+
require 'set'
|
2
|
+
require_relative 'types'
|
3
|
+
|
4
|
+
module KatakataIrb
|
5
|
+
class BaseScope
|
6
|
+
SELF = '%self'
|
7
|
+
BREAK_RESULT = '%break'
|
8
|
+
NEXT_RESULT = '%next'
|
9
|
+
RETURN_RESULT = '%return'
|
10
|
+
PATTERNMATCH_BREAK = '%match'
|
11
|
+
RAISE_BREAK = '%raise'
|
12
|
+
|
13
|
+
def initialize(binding, self_object)
|
14
|
+
@binding, @self_object = binding, self_object
|
15
|
+
@cache = { SELF => KatakataIrb::Types.type_from_object(self_object) }
|
16
|
+
@local_variables = binding.local_variables.map(&:to_s).to_set
|
17
|
+
end
|
18
|
+
|
19
|
+
def level() = 0
|
20
|
+
|
21
|
+
def level_of(name)
|
22
|
+
has?(name) ? 0 : nil
|
23
|
+
end
|
24
|
+
|
25
|
+
def mutable?() = false
|
26
|
+
|
27
|
+
def [](name)
|
28
|
+
@cache[name] ||= (
|
29
|
+
fallback = KatakataIrb::Types::NIL
|
30
|
+
case BaseScope.type_by_name name
|
31
|
+
when :cvar
|
32
|
+
BaseScope.type_of(fallback: fallback) { @self_object.class_variable_get name }
|
33
|
+
when :ivar
|
34
|
+
BaseScope.type_of(fallback: fallback) { @self_object.instance_variable_get name }
|
35
|
+
when :lvar
|
36
|
+
BaseScope.type_of(fallback: fallback) { @binding.local_variable_get(name) }
|
37
|
+
when :const
|
38
|
+
BaseScope.type_of(fallback: fallback) { @binding.eval name }
|
39
|
+
end
|
40
|
+
)
|
41
|
+
end
|
42
|
+
|
43
|
+
def self_type
|
44
|
+
self[SELF]
|
45
|
+
end
|
46
|
+
|
47
|
+
def local_variables
|
48
|
+
@local_variables.to_a
|
49
|
+
end
|
50
|
+
|
51
|
+
def self.type_of(fallback: KatakataIrb::Types::OBJECT)
|
52
|
+
begin
|
53
|
+
KatakataIrb::Types.type_from_object yield
|
54
|
+
rescue
|
55
|
+
fallback
|
56
|
+
end
|
57
|
+
end
|
58
|
+
|
59
|
+
def self.type_by_name(name)
|
60
|
+
if name.start_with? '@@'
|
61
|
+
:cvar
|
62
|
+
elsif name.start_with? '@'
|
63
|
+
:ivar
|
64
|
+
elsif name.start_with? '$'
|
65
|
+
:gvar
|
66
|
+
elsif name.start_with? '%'
|
67
|
+
:internal
|
68
|
+
elsif name[0].downcase != name[0]
|
69
|
+
:const
|
70
|
+
else
|
71
|
+
:lvar
|
72
|
+
end
|
73
|
+
end
|
74
|
+
|
75
|
+
def has?(name)
|
76
|
+
case BaseScope.type_by_name name
|
77
|
+
when :lvar
|
78
|
+
@local_variables.include? name
|
79
|
+
when :const
|
80
|
+
@binding.eval("#{name};true") rescue false
|
81
|
+
when :gvar, :cvar, :ivar
|
82
|
+
true
|
83
|
+
when :internal
|
84
|
+
true
|
85
|
+
end
|
86
|
+
end
|
87
|
+
end
|
88
|
+
|
89
|
+
class Scope < BaseScope
|
90
|
+
attr_reader :parent, :jump_branches, :mergeable_changes, :level
|
91
|
+
|
92
|
+
def self.from_binding(binding) = new(BaseScope.new(binding, binding.eval('self')))
|
93
|
+
|
94
|
+
def initialize(parent, table = {}, trace_cvar: true, trace_ivar: true, trace_lvar: true, passthrough: false)
|
95
|
+
@table = table
|
96
|
+
@parent = parent
|
97
|
+
@level = parent.level + (passthrough ? 0 : 1)
|
98
|
+
@trace_cvar = trace_cvar
|
99
|
+
@trace_ivar = trace_ivar
|
100
|
+
@trace_lvar = trace_lvar
|
101
|
+
@passthrough = passthrough
|
102
|
+
@terminated = false
|
103
|
+
@jump_branches = []
|
104
|
+
@mergeable_changes = @changes = table.transform_values { [level, _1] }
|
105
|
+
end
|
106
|
+
|
107
|
+
def mutable? = true
|
108
|
+
|
109
|
+
def terminated?
|
110
|
+
@terminated
|
111
|
+
end
|
112
|
+
|
113
|
+
def terminate_with(type, value)
|
114
|
+
return if terminated?
|
115
|
+
store_jump type, value, @mergeable_changes
|
116
|
+
terminate
|
117
|
+
end
|
118
|
+
|
119
|
+
def store_jump(type, value, changes)
|
120
|
+
return if terminated?
|
121
|
+
if has_own?(type)
|
122
|
+
changes[type] = [level, value]
|
123
|
+
@jump_branches << changes
|
124
|
+
elsif @parent.mutable?
|
125
|
+
@parent.store_jump(type, value, changes)
|
126
|
+
end
|
127
|
+
end
|
128
|
+
|
129
|
+
def terminate
|
130
|
+
return if terminated?
|
131
|
+
@terminated = true
|
132
|
+
@changes = @mergeable_changes.dup
|
133
|
+
end
|
134
|
+
|
135
|
+
def branch_table_clone() = @tables.last.dup
|
136
|
+
|
137
|
+
def trace?(name)
|
138
|
+
return false unless @parent
|
139
|
+
type = BaseScope.type_by_name(name)
|
140
|
+
type == :cvar ? @trace_cvar : type == :ivar ? @trace_ivar : type == :lvar ? @trace_lvar : true
|
141
|
+
end
|
142
|
+
|
143
|
+
def level_of(name)
|
144
|
+
variable_level, = @changes[name]
|
145
|
+
variable_level || parent.level_of(name)
|
146
|
+
end
|
147
|
+
|
148
|
+
def [](name)
|
149
|
+
level, value = @changes[name]
|
150
|
+
if level
|
151
|
+
value
|
152
|
+
elsif trace? name
|
153
|
+
@parent[name] if trace? name
|
154
|
+
end
|
155
|
+
end
|
156
|
+
|
157
|
+
def []=(name, value)
|
158
|
+
variable_level = level_of(name) || level
|
159
|
+
@changes[name] = [variable_level, value]
|
160
|
+
end
|
161
|
+
|
162
|
+
def self_type
|
163
|
+
self[SELF]
|
164
|
+
end
|
165
|
+
|
166
|
+
def local_variables
|
167
|
+
lvar_keys = @changes.keys.select do |name|
|
168
|
+
BaseScope.type_by_name(name) == :lvar
|
169
|
+
end
|
170
|
+
lvar_keys |= @parent.local_variables if @trace_lvar
|
171
|
+
lvar_keys
|
172
|
+
end
|
173
|
+
|
174
|
+
def merge_jumps
|
175
|
+
if terminated?
|
176
|
+
@terminated = false
|
177
|
+
@changes = @mergeable_changes
|
178
|
+
merge @jump_branches
|
179
|
+
@terminated = true
|
180
|
+
else
|
181
|
+
merge [*@jump_branches, {}]
|
182
|
+
end
|
183
|
+
end
|
184
|
+
|
185
|
+
def conditional(&block)
|
186
|
+
run_branches(block, ->(_s) {}).first || KatakataIrb::Types::NIL
|
187
|
+
end
|
188
|
+
|
189
|
+
def never(&block)
|
190
|
+
block.call Scope.new(self, { BREAK_RESULT => nil, NEXT_RESULT => nil, PATTERNMATCH_BREAK => nil, RETURN_RESULT => nil, RAISE_BREAK => nil }, passthrough: true)
|
191
|
+
end
|
192
|
+
|
193
|
+
def run(*args, **option)
|
194
|
+
scope = Scope.new(self, *args, **option)
|
195
|
+
yield scope
|
196
|
+
merge_jumps
|
197
|
+
update scope
|
198
|
+
end
|
199
|
+
|
200
|
+
def run_branches(*blocks)
|
201
|
+
results = []
|
202
|
+
branches = []
|
203
|
+
blocks.each do |block|
|
204
|
+
scope = Scope.new self, passthrough: true
|
205
|
+
result = block.call scope
|
206
|
+
next if scope.terminated?
|
207
|
+
results << result
|
208
|
+
branches << scope.mergeable_changes
|
209
|
+
end
|
210
|
+
terminate if branches.empty?
|
211
|
+
merge branches
|
212
|
+
results
|
213
|
+
end
|
214
|
+
|
215
|
+
def has?(name)
|
216
|
+
has_own?(name) || (trace?(name) && @parent.has?(name))
|
217
|
+
end
|
218
|
+
|
219
|
+
def has_own?(name)
|
220
|
+
@changes.key? name
|
221
|
+
end
|
222
|
+
|
223
|
+
def update(child_scope)
|
224
|
+
current_level = level
|
225
|
+
child_scope.mergeable_changes.each do |name, (level, value)|
|
226
|
+
self[name] = value if level <= current_level
|
227
|
+
end
|
228
|
+
end
|
229
|
+
|
230
|
+
protected
|
231
|
+
|
232
|
+
def merge(branches)
|
233
|
+
current_level = level
|
234
|
+
merge = {}
|
235
|
+
branches.each do |changes|
|
236
|
+
changes.each do |name, (level, value)|
|
237
|
+
next if current_level < level
|
238
|
+
(merge[name] ||= []) << value
|
239
|
+
end
|
240
|
+
end
|
241
|
+
merge.each do |name, values|
|
242
|
+
values << self[name] unless values.size == branches.size
|
243
|
+
values.compact!
|
244
|
+
self[name] = KatakataIrb::Types::UnionType[*values.compact] unless values.empty?
|
245
|
+
end
|
246
|
+
end
|
247
|
+
end
|
248
|
+
end
|