Skip to content

Commit 2e14a8f

Browse files
committed
Add O(1) lookup methods to Visitor
`code_line.rb` was calling `visitor.consecutive_lines.include?` which is an O(n) array scan inside an O(n) loop over source lines — O(n²) total. `token.rb` was calling `visitor.endless_def_keyword_locs.include?` which is O(n) per token. Add `consecutive_line?(line)` backed by the existing hash for O(1) lookup, and `endless_def_loc?(location)` backed by a new hash keyed on `start_offset` for O(1) lookup. Freeze both hashes after `visit` to signal they are read-only after construction.
1 parent 1f53514 commit 2e14a8f

3 files changed

Lines changed: 17 additions & 3 deletions

File tree

lib/syntax_suggest/code_line.rb

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -43,7 +43,7 @@ def self.from_source(source)
4343
line: line,
4444
index: index,
4545
tokens: tokens_for_line[index + 1],
46-
consecutive: visitor.consecutive_lines.include?(index + 1)
46+
consecutive: visitor.consecutive_line?(index + 1)
4747
)
4848
end
4949
end

lib/syntax_suggest/token.rb

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -29,7 +29,7 @@ def initialize(prism_token, previous_prism_token, visitor)
2929
# Prism lexes `:module` as SYMBOL_BEGIN, KEYWORD_MODULE
3030
# https://github.com/ruby/prism/issues/3940
3131
symbol_content = previous_prism_token&.type == :SYMBOL_BEGIN
32-
@is_kw = KW_TYPES.include?(@type) && !symbol_content && !visitor.endless_def_keyword_locs.include?(@location)
32+
@is_kw = KW_TYPES.include?(@type) && !symbol_content && !visitor.endless_def_loc?(@location)
3333
@is_end = @type == :KEYWORD_END
3434
end
3535

lib/syntax_suggest/visitor.rb

Lines changed: 15 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -34,16 +34,27 @@ class Visitor < Prism::Visitor
3434

3535
def initialize
3636
@endless_def_keyword_locs = []
37+
@endless_def_offsets = {}
3738
@consecutive_lines_hash = {}
3839
@consecutive_lines = []
3940
end
4041

4142
def visit(ast)
4243
super(ast)
4344
@consecutive_lines = @consecutive_lines_hash.keys.sort
45+
@consecutive_lines_hash.freeze
46+
@endless_def_offsets.freeze
4447
self
4548
end
4649

50+
def consecutive_line?(line)
51+
@consecutive_lines_hash.key?(line)
52+
end
53+
54+
def endless_def_loc?(location)
55+
@endless_def_offsets.key?(location.start_offset)
56+
end
57+
4758
# Called by Prism::Visitor for every method-call node in the AST
4859
# (e.g. `foo.bar`, `foo.bar.baz`).
4960
def visit_call_node(node)
@@ -77,7 +88,10 @@ def visit_call_node(node)
7788
# like `def foo = 123`. These are valid without a matching `end`,
7889
# so Token must exclude them when deciding if a line is a keyword.
7990
def visit_def_node(node)
80-
@endless_def_keyword_locs << node.def_keyword_loc if node.equal_loc
91+
if node.equal_loc
92+
@endless_def_keyword_locs << node.def_keyword_loc
93+
@endless_def_offsets[node.def_keyword_loc.start_offset] = true
94+
end
8195
super
8296
end
8397
end

0 commit comments

Comments
 (0)