class Prism::Source

这表示一个已解析的 Ruby 代码的来源。它与位置结合使用,允许它们解析行号和源范围。

属性

offsets[R]

源代码中换行符字节偏移量的列表。

source[R]

此源对象表示的源代码。

start_line[R]

此源开始的行号。

公共类方法

for(source, start_line = 1, offsets = []) 点击切换源代码

使用给定的源代码创建一个新的源对象。此方法应替代 ‘new` 使用,如果源代码中不存在多字节字符,它将返回 `Source` 或专门且性能更高的 `ASCIISource`。

# File prism/parse_result.rb, line 12
def self.for(source, start_line = 1, offsets = [])
  if source.ascii_only?
    ASCIISource.new(source, start_line, offsets)
  elsif source.encoding == Encoding::BINARY
    source.force_encoding(Encoding::UTF_8)

    if source.valid_encoding?
      new(source, start_line, offsets)
    else
      # This is an extremely niche use case where the file is marked as
      # binary, contains multi-byte characters, and those characters are not
      # valid UTF-8. In this case we'll mark it as binary and fall back to
      # treating everything as a single-byte character. This _may_ cause
      # problems when asking for code units, but it appears to be the
      # cleanest solution at the moment.
      source.force_encoding(Encoding::BINARY)
      ASCIISource.new(source, start_line, offsets)
    end
  else
    new(source, start_line, offsets)
  end
end
new(source, start_line = 1, offsets = []) 点击切换源代码

使用给定的源代码创建一个新的源对象。

# File prism/parse_result.rb, line 45
def initialize(source, start_line = 1, offsets = [])
  @source = source
  @start_line = start_line # set after parsing is done
  @offsets = offsets # set after parsing is done
end

公共实例方法

character_column(byte_offset) 点击切换源代码

返回给定字节偏移量的字符列号。

# File prism/parse_result.rb, line 97
def character_column(byte_offset)
  character_offset(byte_offset) - character_offset(line_start(byte_offset))
end
character_offset(byte_offset) 点击切换源代码

返回给定字节偏移量的字符偏移量。

# File prism/parse_result.rb, line 92
def character_offset(byte_offset)
  (source.byteslice(0, byte_offset) or raise).length
end
code_units_cache(encoding) 点击切换源代码

生成一个针对特定编码的缓存,用于计算代码单元偏移量。

# File prism/parse_result.rb, line 125
def code_units_cache(encoding)
  CodeUnitsCache.new(source, encoding)
end
code_units_column(byte_offset, encoding) 点击切换源代码

返回给定字节偏移量的给定编码的代码单元列号。

# File prism/parse_result.rb, line 131
def code_units_column(byte_offset, encoding)
  code_units_offset(byte_offset, encoding) - code_units_offset(line_start(byte_offset), encoding)
end
code_units_offset(byte_offset, encoding) 点击切换源代码

返回给定字节偏移量的文件起始偏移量,以给定编码的代码单元计数。

此方法已使用 UTF-8、UTF-16 和 UTF-32 进行测试。如果存在代码单元的概念,它与其它编码中的字符数量不同,则此处不捕获。

我们在此转换中有意将无效和未定义的字符替换为替换字符。发生这种情况有两个原因。首先,给定的字节偏移量可能不会出现在字符边界上。其次,源代码可能包含在给定编码中没有等效字符的字符。

# File prism/parse_result.rb, line 113
def code_units_offset(byte_offset, encoding)
  byteslice = (source.byteslice(0, byte_offset) or raise).encode(encoding, invalid: :replace, undef: :replace)

  if encoding == Encoding::UTF_16LE || encoding == Encoding::UTF_16BE
    byteslice.bytesize / 2
  else
    byteslice.length
  end
end
column(byte_offset) 点击切换源代码

返回给定字节偏移量的列号。

# File prism/parse_result.rb, line 87
def column(byte_offset)
  byte_offset - line_start(byte_offset)
end
encoding() 点击切换源代码

返回源代码的编码,该编码由解析器的参数或编码魔术注释设置。

# File prism/parse_result.rb, line 53
def encoding
  source.encoding
end
line(byte_offset) 点击切换源代码

通过偏移量进行二进制搜索,以查找给定字节偏移量的行号。

# File prism/parse_result.rb, line 70
def line(byte_offset)
  start_line + find_line(byte_offset)
end
line_end(byte_offset) 点击切换源代码

返回与给定字节偏移量对应的行尾的字节偏移量。

# File prism/parse_result.rb, line 82
def line_end(byte_offset)
  offsets[find_line(byte_offset) + 1] || source.bytesize
end
line_start(byte_offset) 点击切换源代码

返回与给定字节偏移量对应的行首的字节偏移量。

# File prism/parse_result.rb, line 76
def line_start(byte_offset)
  offsets[find_line(byte_offset)]
end
lines() 点击切换源代码

将源代码的行作为字符串数组返回。

# File prism/parse_result.rb, line 58
def lines
  source.lines
end
slice(byte_offset, length) 点击切换源代码

使用给定的字节偏移量和字节长度对源代码执行字节切片。

# File prism/parse_result.rb, line 64
def slice(byte_offset, length)
  source.byteslice(byte_offset, length) or raise
end

私有实例方法

find_line(byte_offset) 点击切换源代码

通过偏移量进行二进制搜索,以查找给定字节偏移量的行号。

# File prism/parse_result.rb, line 139
def find_line(byte_offset)
  left = 0
  right = offsets.length - 1

  while left <= right
    mid = left + (right - left) / 2
    return mid if (offset = offsets[mid]) == byte_offset

    if offset < byte_offset
      left = mid + 1
    else
      right = mid - 1
    end
  end

  left - 1
end