Class: SyntaxErrorSearch::CodeSearch
- Defined in:
- lib/syntax_search/code_search.rb
Overview
Searches code for a syntax error
The bulk of the heavy lifting is done in:
- CodeFrontier (Holds information for generating blocks and determining if we can stop searching)
- ParseBlocksFromLine (Creates blocks into the frontier)
- BlockExpand (Expands existing blocks to search more code
## Syntax error detection
When the frontier holds the syntax error, we can stop searching
search = CodeSearch.new(<<~EOM)
def dog
def lol
end
EOM
search.call
search.invalid_blocks.map(&:to_s) # =>
# => ["def lol\n"]
Instance Attribute Summary collapse
-
#code_lines ⇒ Object
readonly
Returns the value of attribute code_lines.
-
#invalid_blocks ⇒ Object
readonly
Returns the value of attribute invalid_blocks.
-
#record_dir ⇒ Object
readonly
Returns the value of attribute record_dir.
Instance Method Summary collapse
-
#add_invalid_blocks ⇒ Object
Parses the most indented lines into blocks that are marked and added to the frontier.
-
#call ⇒ Object
Main search loop.
-
#expand_invalid_block ⇒ Object
Given an already existing block in the frontier, expand it to see if it contains our invalid syntax.
-
#initialize(string, record_dir: ENV["SYNTAX_SEARCH_RECORD_DIR"]) ⇒ CodeSearch
constructor
A new instance of CodeSearch.
- #push(block, name:) ⇒ Object
-
#record(block:, name: "record") ⇒ Object
Used for debugging.
Constructor Details
#initialize(string, record_dir: ENV["SYNTAX_SEARCH_RECORD_DIR"]) ⇒ CodeSearch
Returns a new instance of CodeSearch.
31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 |
# File 'lib/syntax_search/code_search.rb', line 31 def initialize(string, record_dir: ENV["SYNTAX_SEARCH_RECORD_DIR"]) if record_dir @time = Time.now.strftime('%Y-%m-%d-%H-%M-%s-%N') @record_dir = Pathname(record_dir).join(@time).tap {|p| p.mkpath } @write_count = 0 end @code_lines = string.lines.map.with_index do |line, i| CodeLine.new(line: line, index: i) end @frontier = CodeFrontier.new(code_lines: @code_lines) @invalid_blocks = [] @name_tick = Hash.new {|hash, k| hash[k] = 0 } @tick = 0 @block_expand = BlockExpand.new(code_lines: code_lines) @parse_blocks_from_indent_line = ParseBlocksFromIndentLine.new(code_lines: @code_lines) end |
Instance Attribute Details
#code_lines ⇒ Object (readonly)
Returns the value of attribute code_lines.
29 30 31 |
# File 'lib/syntax_search/code_search.rb', line 29 def code_lines @code_lines end |
#invalid_blocks ⇒ Object (readonly)
Returns the value of attribute invalid_blocks.
29 30 31 |
# File 'lib/syntax_search/code_search.rb', line 29 def invalid_blocks @invalid_blocks end |
#record_dir ⇒ Object (readonly)
Returns the value of attribute record_dir.
29 30 31 |
# File 'lib/syntax_search/code_search.rb', line 29 def record_dir @record_dir end |
Instance Method Details
#add_invalid_blocks ⇒ Object
Parses the most indented lines into blocks that are marked and added to the frontier
83 84 85 86 87 88 89 90 91 92 93 94 95 |
# File 'lib/syntax_search/code_search.rb', line 83 def add_invalid_blocks max_indent = frontier.next_indent_line&.indent while (line = frontier.next_indent_line) && (line.indent == max_indent) @parse_blocks_from_indent_line.each_neighbor_block(frontier.next_indent_line) do |block| record(block: block, name: "add") block.mark_invisible if block.valid? push(block, name: "add") end end end |
#call ⇒ Object
Main search loop
111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 |
# File 'lib/syntax_search/code_search.rb', line 111 def call until frontier.holds_all_syntax_errors? @tick += 1 if frontier. else add_invalid_blocks end end @invalid_blocks.concat(frontier.detect_invalid_blocks ) @invalid_blocks.sort_by! {|block| block.starts_at } self end |
#expand_invalid_block ⇒ Object
Given an already existing block in the frontier, expand it to see if it contains our invalid syntax
99 100 101 102 103 104 105 106 107 108 |
# File 'lib/syntax_search/code_search.rb', line 99 def block = frontier.pop return unless block record(block: block, name: "pop") # block = block.expand_until_next_boundry block = @block_expand.call(block) push(block, name: "expand") end |
#push(block, name:) ⇒ Object
70 71 72 73 74 75 76 77 78 79 |
# File 'lib/syntax_search/code_search.rb', line 70 def push(block, name: ) record(block: block, name: name) if block.valid? block.lines.each(&:mark_invisible) frontier << block else frontier << block end end |
#record(block:, name: "record") ⇒ Object
Used for debugging
49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 |
# File 'lib/syntax_search/code_search.rb', line 49 def record(block:, name: "record") return if !@record_dir @name_tick[name] += 1 filename = "#{@write_count += 1}-#{name}-#{@name_tick[name]}.txt" if ENV["DEBUG"] puts "\n\n==== #{filename} ====" puts "\n```#{block.starts_at}:#{block.ends_at}" puts "#{block.to_s}" puts "```" puts " block indent: #{block.current_indent}" end @record_dir.join(filename).open(mode: "a") do |f| display = DisplayInvalidBlocks.new( blocks: block, terminal: false, code_lines: @code_lines, ) f.write(display.indent display.code_with_lines) end end |