Spec-Zone.ru › Ruby 3.4

класс SyntaxSuggest::CodeFrontier

Родитель:
Объект

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

  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 (массив)
Исходный код
# 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

Методы публичного экземпляра

<< (блок)
Исходный код
# 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 (блок)
Исходный код
# File lib/syntax_suggest/code_frontier.rb, line 140
def register_engulf_block(block)
end

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

register_indent_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

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

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

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

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

Spec-Zone.ru

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