Spec-Zone.ru › Ruby 3.4
  1. SyntaxSuggest::
  2. CodeFrontier

class SyntaxSuggest::CodeFrontier

Родительский класс:
Object

В алгоритме есть три основных этапа:

  1. Очистка и форматирование исходного кода

  2. Поиск некорректных блоков

  3. Форматирование некорректных блоков в понятный вид

Фронтир кода — важная часть второго этапа

## Отслеживание пройденного пути

После создания блока кода он добавляется во фронтир. Затем блоки сортируются по отступам, и фронтир можно отфильтровать. Большие блоки, полностью охватывающие меньший блок, приводят к удалению меньшего блока.

CodeFrontier#<<(block) # Adds block to frontier
CodeFrontier#pop # Removes block from frontier

## Определение дальнейшего пути

Внутри фронтир отслеживает «непосещённые» строки, доступные через `next_indent_line`. При вызове этот метод возвращает строку кода с наибольшим отступом.

Возвращённую строку кода можно использовать для создания CodeBlock, а затем этот блок кода добавляется обратно во фронтир. После этого строки удаляются из списка «непосещённых», чтобы не создавать один и тот же блок повторно.

CodeFrontier#next_indent_line # Shows next line
CodeFrontier#register_indent_block(block) # Removes lines from unvisited

## Определение момента остановки

Фронтир умеет проверять весь документ на наличие синтаксической ошибки. При добавлении блоков во фронтир они удаляются из документа. Когда во фронтир добавлены все блоки, содержащие синтаксические ошибки, документ можно будет разобрать без синтаксической ошибки, и поиск можно остановить.

CodeFrontier#holds_all_syntax_errors? # Returns true when frontier holds all syntax errors

## Фильтрация ложных срабатываний

После завершения поиска во фронтире может быть несколько блоков, не содержащих синтаксическую ошибку. Чтобы ограничить результат наименьшим набором «некорректных блоков», вызовите:

CodeFrontier#detect_invalid_blocks

Открытые методы класса

combination (array) Показать исходный код
# File lib/syntax_suggest/code_frontier.rb, line 162
def self.combination(array)
  guesses = []
  1.upto(array.length).each do |size|
    guesses.concat(array.combination(size).to_a)
  end
  guesses
end

Пример:

combination([:a, :b, :c, :d])
# => [[:a], [:b], [:c], [:d], [:a, :b], [:a, :c], [:a, :d], [:b, :c], [:b, :d], [:c, :d], [:a, :b, :c], [:a, :b, :d], [:a, :c, :d], [:b, :c, :d], [:a, :b, :c, :d]]
new (code_lines:, unvisited: UnvisitedLines.new(code_lines: code_lines)) Показать исходный код
# File lib/syntax_suggest/code_frontier.rb, line 53
def initialize(code_lines:, unvisited: UnvisitedLines.new(code_lines: code_lines))
  @code_lines = code_lines
  @unvisited = unvisited
  @queue = PriorityEngulfQueue.new

  @check_next = true
end

Открытые методы экземпляра

<< (block) Показать исходный код
# File lib/syntax_suggest/code_frontier.rb, line 148
def <<(block)
  @unvisited.visit_block(block)

  @queue.push(block)

  @check_next = true if block.invalid?

  self
end

Добавляет блок во фронтир

Этот метод гарантирует, что фронтир всегда отсортирован по отступам, а строки каждого блока кода удалены из хеш-таблицы отступов, чтобы повторно не обрабатывать одну и ту же строку.

count () Показать исходный код
# File lib/syntax_suggest/code_frontier.rb, line 61
def count
  @queue.length
end
detect_invalid_blocks () Показать исходный код
# File lib/syntax_suggest/code_frontier.rb, line 172
def detect_invalid_blocks
  self.class.combination(@queue.to_a.select(&:invalid?)).detect do |block_array|
    holds_all_syntax_errors?(block_array, can_cache: false)
  end || []
end

Зная, что синтаксическая ошибка находится где-то во фронтире, мы хотим найти наименьший возможный набор блоков, содержащих все синтаксические ошибки.

expand? () Показать исходный код
# File lib/syntax_suggest/code_frontier.rb, line 111
def expand?
  return false if @queue.empty?
  return true if @unvisited.empty?

  frontier_indent = @queue.peek.current_indent
  unvisited_indent = next_indent_line.indent

  if ENV["SYNTAX_SUGGEST_DEBUG"]
    puts "```"
    puts @queue.peek
    puts "```"
    puts "  @frontier indent:  #{frontier_indent}"
    puts "  @unvisited indent: #{unvisited_indent}"
  end

  # Expand all blocks before moving to unvisited lines
  frontier_indent >= unvisited_indent
end
holds_all_syntax_errors? (block_array = @queue, can_cache: true) Показать исходный код
# File lib/syntax_suggest/code_frontier.rb, line 89
def holds_all_syntax_errors?(block_array = @queue, can_cache: true)
  return false if can_cache && can_skip_check?

  without_lines = block_array.to_a.flat_map do |block|
    block.lines
  end

  SyntaxSuggest.valid_without?(
    without_lines: without_lines,
    code_lines: @code_lines
  )
end

Возвращает true, если документ корректен после удаления всех строк. По умолчанию проверяются все блоки в массиве фронтира, но метод также можно использовать с произвольными массивами блоков кода.

next_indent_line () Показать исходный код
# File lib/syntax_suggest/code_frontier.rb, line 107
def next_indent_line
  @unvisited.peek
end
pop () Показать исходный код
# File lib/syntax_suggest/code_frontier.rb, line 103
def pop
  @queue.pop
end

Возвращает блок кода с максимально возможным отступом.

register_engulf_block (block) Показать исходный код
# File lib/syntax_suggest/code_frontier.rb, line 140
def register_engulf_block(block)
end

Если один элемент полностью охватывает другой, мы удаляем меньший блок из фронтира. Это предотвращает повторное расширение и прочее непредсказуемое поведение. Однако поддержание этой гарантии обходится довольно дорого.

register_indent_block (block) Показать исходный код
# File lib/syntax_suggest/code_frontier.rb, line 132
def register_indent_block(block)
  @unvisited.visit_block(block)
  self
end

Отслеживает, какие строки уже добавлены в блоки, а какие ещё не посещены.

Закрытые методы экземпляра

can_skip_check? () Показать исходный код
# File lib/syntax_suggest/code_frontier.rb, line 74
        def can_skip_check?
  check_next = @check_next
  @check_next = false

  if check_next
    false
  else
    true
  end
end

Оптимизация производительности

Разбор с помощью ripper требует больших затрат. Если мы знаем, что у нас нет блоков с некорректным синтаксисом, значит, мы ещё не могли обнаружить ошибочный синтаксис.

Когда некорректный блок добавляется во фронтир, проверяется состояние документа.

Ruby Core © 1993–2025 Yukihiro Matsumoto
Licensed under the Ruby License.
Ruby Standard Library © contributors
Licensed under their own licenses.

Spec-Zone.ru

Настройки Оффлайн Что нового Помощь О нас
Spec-Zone .ru
спецификации, руководства, описания, API