Class: Ibex::Location

Inherits:
Object
  • Object
show all
Defined in:
lib/ibex/location.rb

Overview

Immutable source range suitable for lexer tokens and parser diagnostics.

Coordinates are one-based. Byte offsets are optional, zero-based, and half-open. Keeping both forms lets Unicode-aware lexers report human columns without losing an exact source slice.

Instance Attribute Summary collapse

Class Method Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(line:, column:, file: nil, end_line: nil, end_column: nil, start_byte: nil, end_byte: nil, source_line: nil) ⇒ Location

Returns a new instance of Location.



22
23
24
25
26
27
28
29
30
31
32
33
34
# File 'lib/ibex/location.rb', line 22

def initialize(line:, column:, file: nil, end_line: nil, end_column: nil,
               start_byte: nil, end_byte: nil, source_line: nil)
  @file = file&.dup&.freeze
  @line = positive_coordinate(:line, line)
  @column = positive_coordinate(:column, column)
  @end_line = positive_coordinate(:end_line, end_line || line)
  @end_column = positive_coordinate(:end_column, end_column || column)
  @start_byte = optional_offset(:start_byte, start_byte)
  @end_byte = optional_offset(:end_byte, end_byte)
  @source_line = source_line&.dup&.freeze
  validate_order!
  freeze
end

Instance Attribute Details

#columnObject (readonly)

: Integer



13
14
15
# File 'lib/ibex/location.rb', line 13

def column
  @column
end

#end_byteObject (readonly)

: Integer?



17
18
19
# File 'lib/ibex/location.rb', line 17

def end_byte
  @end_byte
end

#end_columnObject (readonly)

: Integer



15
16
17
# File 'lib/ibex/location.rb', line 15

def end_column
  @end_column
end

#end_lineObject (readonly)

: Integer



14
15
16
# File 'lib/ibex/location.rb', line 14

def end_line
  @end_line
end

#fileObject (readonly)

: String?



11
12
13
# File 'lib/ibex/location.rb', line 11

def file
  @file
end

#lineObject (readonly)

: Integer



12
13
14
# File 'lib/ibex/location.rb', line 12

def line
  @line
end

#source_lineObject (readonly)

: String?



18
19
20
# File 'lib/ibex/location.rb', line 18

def source_line
  @source_line
end

#start_byteObject (readonly)

: Integer?



16
17
18
# File 'lib/ibex/location.rb', line 16

def start_byte
  @start_byte
end

Class Method Details

.join(locations) ⇒ Object

Fold a nonempty collection into one covering range.



53
54
55
56
57
# File 'lib/ibex/location.rb', line 53

def self.join(locations)
  values = locations.to_a
  first = values.shift || raise(ArgumentError, "locations must not be empty")
  values.reduce(first) { |combined, location| combined.join(location) }
end

Instance Method Details

#empty?Boolean

Returns:

  • (Boolean)


60
61
62
63
# File 'lib/ibex/location.rb', line 60

def empty?
  @line == @end_line && @column == @end_column &&
    (@start_byte.nil? || @end_byte.nil? || @start_byte == @end_byte)
end

#join(other) ⇒ Object

Return the smallest range covering both locations.

Raises:

  • (ArgumentError)


38
39
40
41
42
43
44
45
46
47
48
49
# File 'lib/ibex/location.rb', line 38

def join(other)
  raise ArgumentError, "location files differ" unless file == other.file

  first = before_or_equal?(self, other) ? self : other
  ending = before_or_equal_end?(self, other) ? other : self
  self.class.new(
    file: file, line: first.line, column: first.column,
    end_line: ending.end_line, end_column: ending.end_column,
    start_byte: joined_start_byte(other), end_byte: joined_end_byte(other),
    source_line: first.source_line
  )
end

#to_hObject



66
67
68
69
70
71
72
# File 'lib/ibex/location.rb', line 66

def to_h
  {
    file: @file, line: @line, column: @column,
    end_line: @end_line, end_column: @end_column,
    start_byte: @start_byte, end_byte: @end_byte
  }.compact
end