Class: Ibex::Runtime::CST::SourceText

Inherits:
Object
  • Object
show all
Defined in:
lib/json5/generated_parser.rb

Overview

Immutable byte-oriented source with lazy line/column conversion.

Instance Attribute Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(text, file: nil) ⇒ SourceText

Returns a new instance of SourceText.

RBS:

  • (String text, ?file: String?) -> void



854
855
856
857
858
859
# File 'lib/json5/generated_parser.rb', line 854

def initialize(text, file: nil)
  @text = text.encoding == Encoding::BINARY && text.frozen? ? text : text.b.freeze
  @file = file&.then { |value| value.frozen? ? value : value.dup.freeze }
  @line_starts = build_line_starts.freeze #: Array[Integer]
  freeze
end

Instance Attribute Details

#fileObject (readonly)

Signature:

  • String?



851
852
853
# File 'lib/json5/generated_parser.rb', line 851

def file
  @file
end

#textObject (readonly)

RBS:

  • type position = [Integer, Integer]


850
851
852
# File 'lib/json5/generated_parser.rb', line 850

def text
  @text
end

Instance Method Details

#apply(edits) ⇒ Object

Apply non-overlapping byte edits expressed against this source.

RBS:

  • (Array[TextEdit] edits) -> SourceText



866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
# File 'lib/json5/generated_parser.rb', line 866

def apply(edits)
  ordered = TextEdit.normalize(edits)
  output = String.new(encoding: Encoding::BINARY)
  cursor = 0
  ordered.each do |edit|
    raise ArgumentError, "text edits overlap" if edit.start < cursor
    raise RangeError, "text edit exceeds source" if edit.range.end > @text.bytesize

    output << (@text.byteslice(cursor, edit.start - cursor) || "".b)
    output << edit.insert_text
    cursor = edit.range.end
  end
  output << (@text.byteslice(cursor, @text.bytesize - cursor) || "".b)
  SourceText.new(output, file: @file)
end

#bytesizeObject

RBS:

  • () -> Integer



862
# File 'lib/json5/generated_parser.rb', line 862

def bytesize = @text.bytesize

#line_text(line) ⇒ Object

RBS:

  • (Integer line) -> String

Raises:

  • (ArgumentError)


907
908
909
910
911
912
913
914
# File 'lib/json5/generated_parser.rb', line 907

def line_text(line)
  raise ArgumentError, "line must be positive" unless line.positive?

  start_offset = @line_starts.fetch(line - 1)
  end_offset = @line_starts.fetch(line, @text.bytesize)
  value = @text.byteslice(start_offset, end_offset - start_offset) || "".b
  value.delete_suffix("\n".b).delete_suffix("\r".b)
end

#location(range) ⇒ Object

RBS:

  • (Range[Integer] range) -> Ibex::Location



896
897
898
899
900
901
902
903
904
# File 'lib/json5/generated_parser.rb', line 896

def location(range)
  start_offset, end_offset = normalized_range(range)
  line, column = position(start_offset)
  end_line, end_column = position(end_offset)
  Ibex::Location.new(
    file: @file, line: line, column: column, end_line: end_line, end_column: end_column,
    start_byte: start_offset, end_byte: end_offset, source_line: line_text(line)
  )
end

#position(offset) ⇒ Object

Return one-based line and Unicode-scalar column for a byte offset. Invalid UTF-8 bytes count as one replacement scalar each.

RBS:

  • (Integer offset) -> position



885
886
887
888
889
890
891
892
893
# File 'lib/json5/generated_parser.rb', line 885

def position(offset)
  validate_offset(offset)
  line_index = @line_starts.bsearch_index { |start| start > offset }
  line_index = line_index ? line_index - 1 : @line_starts.length - 1
  line_start = @line_starts.fetch(line_index)
  prefix = @text.byteslice(line_start, offset - line_start) || "".b
  value = [line_index + 1, unicode_scalar_length(prefix) + 1] #: position
  value.freeze
end