Spec-Zone.ru › Ruby 3.4

класс Prism::Translation::Parser

Этот класс является точкой входа для преобразования синтаксического дерева prism в синтаксическое дерево драгоценного камня whitequark/parser. Он наследуется от базового парсера для драгоценного камня parser и переопределяет методы parse*, чтобы анализировать с помощью prism и затем переводить.

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

default_encoding ()
Исходный код
# File lib/prism/translation/parser.rb, line 41
def default_encoding
  Encoding::UTF_8
end

По умолчанию кодировка для файлов Ruby — UTF-8.

parse (source_buffer)
Исходный код
# File lib/prism/translation/parser.rb, line 49
def parse(source_buffer)
  @source_buffer = source_buffer
  source = source_buffer.source

  offset_cache = build_offset_cache(source)
  result = unwrap(Prism.parse(source, filepath: source_buffer.name, version: convert_for_prism(version), partial_script: true, encoding: false), offset_cache)

  build_ast(result.value, offset_cache)
ensure
  @source_buffer = nil
end

Анализирует буфер исходного кода и возвращает AST.

parse_with_comments (source_buffer)
Исходный код
# File lib/prism/translation/parser.rb, line 62
def parse_with_comments(source_buffer)
  @source_buffer = source_buffer
  source = source_buffer.source

  offset_cache = build_offset_cache(source)
  result = unwrap(Prism.parse(source, filepath: source_buffer.name, version: convert_for_prism(version), partial_script: true, encoding: false), offset_cache)

  [
    build_ast(result.value, offset_cache),
    build_comments(result.comments, offset_cache)
  ]
ensure
  @source_buffer = nil
end

Анализирует буфер исходного кода и возвращает AST и комментарии к исходному коду.

tokenize (source_buffer, recover = false)
Исходный код
# File lib/prism/translation/parser.rb, line 79
def tokenize(source_buffer, recover = false)
  @source_buffer = source_buffer
  source = source_buffer.source

  offset_cache = build_offset_cache(source)
  result =
    begin
      unwrap(Prism.parse_lex(source, filepath: source_buffer.name, version: convert_for_prism(version), partial_script: true, encoding: false), offset_cache)
    rescue ::Parser::SyntaxError
      raise if !recover
    end

  program, tokens = result.value
  ast = build_ast(program, offset_cache) if result.success?

  [
    ast,
    build_comments(result.comments, offset_cache),
    build_tokens(tokens, offset_cache)
  ]
ensure
  @source_buffer = nil
end

Анализирует буфер исходного кода и возвращает AST, комментарии к исходному коду и токены, выпущенные лексическим анализатором.

try_declare_numparam (node)
Исходный код
# File lib/prism/translation/parser.rb, line 105
def try_declare_numparam(node)
  node.children[0].match?(/\A_[1-9]\z/)
end

Поскольку prism разрешает нам параметры num, нам не нужно поддерживать подобную логику здесь.

Приватные методы экземпляра

build_ast (program, offset_cache)
Исходный код
# File lib/prism/translation/parser.rb, line 263
def build_ast(program, offset_cache)
  program.accept(Compiler.new(self, offset_cache))
end

Создаёт AST драгоценного камня parser из AST prism.

build_comments (comments, offset_cache)
Исходный код
# File lib/prism/translation/parser.rb, line 268
def build_comments(comments, offset_cache)
  comments.map do |comment|
    ::Parser::Source::Comment.new(build_range(comment.location, offset_cache))
  end
end

Создаёт комментарии драгоценного камня parser из комментариев prism.

build_offset_cache (source)
Исходный код
# File lib/prism/translation/parser.rb, line 246
def build_offset_cache(source)
  if source.bytesize == source.length
    -> (offset) { offset }
  else
    offset_cache = []
    offset = 0

    source.each_char do |char|
      char.bytesize.times { offset_cache << offset }
      offset += 1
    end

    offset_cache << offset
  end
end

Prism работает с смещениями в байтах, а драгоценный камень parser — со смещениями в символах. Нам нужно выполнить это преобразование, чтобы создать AST драгоценного камня parser.

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

build_range (location, offset_cache)
Исходный код
# File lib/prism/translation/parser.rb, line 280
def build_range(location, offset_cache)
  ::Parser::Source::Range.new(
    source_buffer,
    offset_cache[location.start_offset],
    offset_cache[location.end_offset]
  )
end

Создаёт диапазон из расположения prism.

build_tokens (tokens, offset_cache)
Исходный код
# File lib/prism/translation/parser.rb, line 275
def build_tokens(tokens, offset_cache)
  Lexer.new(source_buffer, tokens, offset_cache).to_a
end

Создаёт токены драгоценного камня parser из токенов prism.

convert_for_prism (version)
Исходный код
# File lib/prism/translation/parser.rb, line 289
def convert_for_prism(version)
  case version
  when 33
    "3.3.1"
  when 34
    "3.4.0"
  else
    "latest"
  end
end

Преобразует формат версии, обрабатываемый Parser, в формат, обрабатываемый Prism.

error_diagnostic (error, offset_cache)
Исходный код
# File lib/prism/translation/parser.rb, line 124
def error_diagnostic(error, offset_cache)
  location = error.location
  diagnostic_location = build_range(location, offset_cache)

  case error.type
  when :argument_block_multi
    Diagnostic.new(:error, :block_and_blockarg, {}, diagnostic_location, [])
  when :argument_formal_constant
    Diagnostic.new(:error, :argument_const, {}, diagnostic_location, [])
  when :argument_formal_class
    Diagnostic.new(:error, :argument_cvar, {}, diagnostic_location, [])
  when :argument_formal_global
    Diagnostic.new(:error, :argument_gvar, {}, diagnostic_location, [])
  when :argument_formal_ivar
    Diagnostic.new(:error, :argument_ivar, {}, diagnostic_location, [])
  when :argument_no_forwarding_amp
    Diagnostic.new(:error, :no_anonymous_blockarg, {}, diagnostic_location, [])
  when :argument_no_forwarding_star
    Diagnostic.new(:error, :no_anonymous_restarg, {}, diagnostic_location, [])
  when :argument_no_forwarding_star_star
    Diagnostic.new(:error, :no_anonymous_kwrestarg, {}, diagnostic_location, [])
  when :begin_lonely_else
    location = location.copy(length: 4)
    diagnostic_location = build_range(location, offset_cache)
    Diagnostic.new(:error, :useless_else, {}, diagnostic_location, [])
  when :class_name, :module_name
    Diagnostic.new(:error, :module_name_const, {}, diagnostic_location, [])
  when :class_in_method
    Diagnostic.new(:error, :class_in_def, {}, diagnostic_location, [])
  when :def_endless_setter
    Diagnostic.new(:error, :endless_setter, {}, diagnostic_location, [])
  when :embdoc_term
    Diagnostic.new(:error, :embedded_document, {}, diagnostic_location, [])
  when :incomplete_variable_class, :incomplete_variable_class_3_3
    location = location.copy(length: location.length + 1)
    diagnostic_location = build_range(location, offset_cache)

    Diagnostic.new(:error, :cvar_name, { name: location.slice }, diagnostic_location, [])
  when :incomplete_variable_instance, :incomplete_variable_instance_3_3
    location = location.copy(length: location.length + 1)
    diagnostic_location = build_range(location, offset_cache)

    Diagnostic.new(:error, :ivar_name, { name: location.slice }, diagnostic_location, [])
  when :invalid_variable_global, :invalid_variable_global_3_3
    Diagnostic.new(:error, :gvar_name, { name: location.slice }, diagnostic_location, [])
  when :module_in_method
    Diagnostic.new(:error, :module_in_def, {}, diagnostic_location, [])
  when :numbered_parameter_ordinary
    Diagnostic.new(:error, :ordinary_param_defined, {}, diagnostic_location, [])
  when :numbered_parameter_outer_scope
    Diagnostic.new(:error, :numparam_used_in_outer_scope, {}, diagnostic_location, [])
  when :parameter_circular
    Diagnostic.new(:error, :circular_argument_reference, { var_name: location.slice }, diagnostic_location, [])
  when :parameter_name_repeat
    Diagnostic.new(:error, :duplicate_argument, {}, diagnostic_location, [])
  when :parameter_numbered_reserved
    Diagnostic.new(:error, :reserved_for_numparam, { name: location.slice }, diagnostic_location, [])
  when :regexp_unknown_options
    Diagnostic.new(:error, :regexp_options, { options: location.slice[1..] }, diagnostic_location, [])
  when :singleton_for_literals
    Diagnostic.new(:error, :singleton_literal, {}, diagnostic_location, [])
  when :string_literal_eof
    Diagnostic.new(:error, :string_eof, {}, diagnostic_location, [])
  when :unexpected_token_ignore
    Diagnostic.new(:error, :unexpected_token, { token: location.slice }, diagnostic_location, [])
  when :write_target_in_method
    Diagnostic.new(:error, :dynamic_const, {}, diagnostic_location, [])
  else
    PrismDiagnostic.new(error.message, :error, error.type, diagnostic_location)
  end
end

Создаёт диагностику из ошибки синтаксического анализа prism.

unwrap (result, offset_cache)
Исходный код
# File lib/prism/translation/parser.rb, line 224
def unwrap(result, offset_cache)
  result.errors.each do |error|
    next unless valid_error?(error)
    diagnostics.process(error_diagnostic(error, offset_cache))
  end

  result.warnings.each do |warning|
    next unless valid_warning?(warning)
    diagnostic = warning_diagnostic(warning, offset_cache)
    diagnostics.process(diagnostic) if diagnostic
  end

  result
end

Если при анализе возникла ошибка, то вызовите соответствующую ошибку синтаксиса. В противном случае верните результат.

valid_error? (error)
Исходный код
# File lib/prism/translation/parser.rb, line 113
def valid_error?(error)
  true
end

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

valid_warning? (warning)
Исходный код
# File lib/prism/translation/parser.rb, line 119
def valid_warning?(warning)
  true
end

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

warning_diagnostic (warning, offset_cache)
Исходный код
# File lib/prism/translation/parser.rb, line 197
def warning_diagnostic(warning, offset_cache)
  diagnostic_location = build_range(warning.location, offset_cache)

  case warning.type
  when :ambiguous_first_argument_plus
    Diagnostic.new(:warning, :ambiguous_prefix, { prefix: "+" }, diagnostic_location, [])
  when :ambiguous_first_argument_minus
    Diagnostic.new(:warning, :ambiguous_prefix, { prefix: "-" }, diagnostic_location, [])
  when :ambiguous_prefix_ampersand
    Diagnostic.new(:warning, :ambiguous_prefix, { prefix: "&" }, diagnostic_location, [])
  when :ambiguous_prefix_star
    Diagnostic.new(:warning, :ambiguous_prefix, { prefix: "*" }, diagnostic_location, [])
  when :ambiguous_prefix_star_star
    Diagnostic.new(:warning, :ambiguous_prefix, { prefix: "**" }, diagnostic_location, [])
  when :ambiguous_slash
    Diagnostic.new(:warning, :ambiguous_regexp, {}, diagnostic_location, [])
  when :dot_dot_dot_eol
    Diagnostic.new(:warning, :triple_dot_at_eol, {}, diagnostic_location, [])
  when :duplicated_hash_key
    # skip, parser does this on its own
  else
    PrismDiagnostic.new(warning.message, :warning, warning.type, diagnostic_location)
  end
end

Создаёт диагностику из предупреждения синтаксического анализа prism.

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