Class: Steep::Typing

Inherits:
Object show all
Defined in:
lib/steep/typing.rb

Defined Under Namespace

Classes: CursorContext, UnknownNodeError

Instance Attribute Summary collapse

Class Method Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(source:, root_context:, parent: nil, parent_last_update: parent&.last_update, source_index: nil, cursor:) ⇒ Typing

Returns a new instance of Typing.



168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
# File 'lib/steep/typing.rb', line 168

def initialize(source:, root_context:, parent: nil, parent_last_update: parent&.last_update, source_index: nil, cursor:)
  @source = source

  @parent = parent
  @parent_last_update = parent_last_update
  @last_update = parent&.last_update || 0
  @should_update = false

  @errors = []
  (@typing = {}).compare_by_identity
  @root_context = root_context
  (@method_calls = {}).compare_by_identity

  @cursor_context = CursorContext.new(cursor)
  if root_context
    cursor_context.set(0..source.buffer.content&.size || 0, root_context)
  end

  @source_index = source_index || Index::SourceIndex.new(source: source)
end

Instance Attribute Details

#contextsObject (readonly)

Returns the value of attribute contexts.



162
163
164
# File 'lib/steep/typing.rb', line 162

def contexts
  @contexts
end

#cursor_contextObject (readonly)

Returns the value of attribute cursor_context.



166
167
168
# File 'lib/steep/typing.rb', line 166

def cursor_context
  @cursor_context
end

#errorsObject (readonly)

Returns the value of attribute errors.



156
157
158
# File 'lib/steep/typing.rb', line 156

def errors
  @errors
end

#last_updateObject (readonly)

Returns the value of attribute last_update.



160
161
162
# File 'lib/steep/typing.rb', line 160

def last_update
  @last_update
end

#method_callsObject (readonly)

Returns the value of attribute method_calls.



164
165
166
# File 'lib/steep/typing.rb', line 164

def method_calls
  @method_calls
end

#parentObject (readonly)

Returns the value of attribute parent.



158
159
160
# File 'lib/steep/typing.rb', line 158

def parent
  @parent
end

#parent_last_updateObject (readonly)

Returns the value of attribute parent_last_update.



159
160
161
# File 'lib/steep/typing.rb', line 159

def parent_last_update
  @parent_last_update
end

#root_contextObject (readonly)

Returns the value of attribute root_context.



163
164
165
# File 'lib/steep/typing.rb', line 163

def root_context
  @root_context
end

#should_updateObject (readonly)

Returns the value of attribute should_update.



161
162
163
# File 'lib/steep/typing.rb', line 161

def should_update
  @should_update
end

#sourceObject (readonly)

Returns the value of attribute source.



155
156
157
# File 'lib/steep/typing.rb', line 155

def source
  @source
end

#source_indexObject (readonly)

Returns the value of attribute source_index.



165
166
167
# File 'lib/steep/typing.rb', line 165

def source_index
  @source_index
end

#typingObject (readonly)

Returns the value of attribute typing.



157
158
159
# File 'lib/steep/typing.rb', line 157

def typing
  @typing
end

Class Method Details

.summary(node) ⇒ Object



271
272
273
274
275
276
277
# File 'lib/steep/typing.rb', line 271

def self.summary(node)
  src = node.loc.expression.source.split(/\n/).first
  line = node.loc.first_line
  col = node.loc.column

  "#{line}:#{col}:#{src}"
end

Instance Method Details

#add_call(node, call) ⇒ Object



200
201
202
203
204
# File 'lib/steep/typing.rb', line 200

def add_call(node, call)
  method_calls[node] = call

  call
end

#add_error(error) ⇒ Object



189
190
191
# File 'lib/steep/typing.rb', line 189

def add_error(error)
  errors << error
end

#add_typing(node, type, _context) ⇒ Object



193
194
195
196
197
198
# File 'lib/steep/typing.rb', line 193

def add_typing(node, type, _context)
  typing[node] = type
  @last_update += 1

  type
end

#block_range(node) ⇒ Object



238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
# File 'lib/steep/typing.rb', line 238

def block_range(node)
  case node.type
  when :block
    send_node, args_node, _ = node.children
    begin_pos = if send_node.type != :lambda && args_node.loc.expression
                  args_node.loc.expression.end_pos
                else
                  node.loc.begin.end_pos # steep:ignore NoMethod
                end
    end_pos = node.loc.end.begin_pos # steep:ignore NoMethod
  when :numblock
    send_node, _ = node.children
    begin_pos = node.loc.begin.end_pos # steep:ignore NoMethod
    end_pos = node.loc.end.begin_pos # steep:ignore NoMethod
  end

  begin_pos..end_pos
end

#call_of(node:) ⇒ Object



224
225
226
227
228
229
230
231
232
233
234
235
236
# File 'lib/steep/typing.rb', line 224

def call_of(node:)
  call = method_calls[node]

  if call
    call
  else
    if parent
      parent.call_of(node: node)
    else
      raise UnknownNodeError.new(:call, node: node)
    end
  end
end

#dump(io) ⇒ Object



257
258
259
260
261
262
263
264
265
266
267
268
269
# File 'lib/steep/typing.rb', line 257

def dump(io)
  # steep:ignore:start
  io.puts "Typing: "
  nodes.each_value do |node|
    io.puts "  #{Typing.summary(node)} => #{type_of(node: node).inspect}"
  end

  io.puts "Errors: "
  errors.each do |error|
    io.puts "  #{Typing.summary(error.node)} => #{error.inspect}"
  end
  # steep:ignore:end
end

#each_typing(&block) ⇒ Object



296
297
298
# File 'lib/steep/typing.rb', line 296

def each_typing(&block)
  typing.each(&block)
end

#has_type?(node) ⇒ Boolean

Returns:

  • (Boolean)


206
207
208
# File 'lib/steep/typing.rb', line 206

def has_type?(node)
  typing.key?(node)
end

#new_childObject



279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
# File 'lib/steep/typing.rb', line 279

def new_child()
  child = self.class.new(
    source: source,
    parent: self,
    root_context: root_context,
    source_index: source_index.new_child,
    cursor: cursor_context.index
  )
  @should_update = true

  if block_given?
    yield child
  else
    child
  end
end

#save!Object



300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
# File 'lib/steep/typing.rb', line 300

def save!
  raise "Unexpected save!" unless parent
  raise "Parent modified since #new_child: parent.last_update=#{parent.last_update}, parent_last_update=#{parent_last_update}" unless parent.last_update == parent_last_update

  each_typing do |node, type|
    parent.add_typing(node, type, nil)
  end

  parent.method_calls.merge!(method_calls)

  errors.each do |error|
    parent.add_error error
  end

  parent.cursor_context.set(cursor_context)

  parent.source_index.merge!(source_index)
end

#type_of(node:) ⇒ Object



210
211
212
213
214
215
216
217
218
219
220
221
222
# File 'lib/steep/typing.rb', line 210

def type_of(node:)
  type = typing[node]

  if type
    type
  else
    if parent
      parent.type_of(node: node)
    else
      raise UnknownNodeError.new(:type, node: node)
    end
  end
end