Module: Laser::Analysis::SexpExtensions::SourceLocation

Included in:
Laser::Analysis::Sexp
Defined in:
lib/laser/analysis/sexp_extensions/source_location.rb

Instance Method Summary (collapse)

Instance Method Details

- (Object) backtrack_expecting!(location, offset, expectation)

Attempts to backtrack for the given string from the given location. Returns true if successful.



149
150
151
152
153
154
# File 'lib/laser/analysis/sexp_extensions/source_location.rb', line 149

def backtrack_expecting!(location, offset, expectation)
  if text_at(location, offset, expectation.length) == expectation
    location[1] += offset
    true
  end
end

- (Object) backtrack_searching(location, expectation)

Searches for the given text starting at the given location, going backwards. Modifies the location to match the discovered expected text on success.

complexity: O(N) wrt input source location: [Fixnum, Fixnum] expectation: String returns: Boolean



110
111
112
113
114
115
116
117
118
119
120
121
122
123
# File 'lib/laser/analysis/sexp_extensions/source_location.rb', line 110

def backtrack_searching(location, expectation)
  result = location.dup
  line = lines[result[0] - 1]
  begin
    if (expectation_location = line.rindex(expectation, result[1]))
      result[1] = expectation_location
      return result
    end
    result[0] -= 1
    line = lines[result[0] - 1]
    result[1] = line.size
  end while result[0] >= 0
  location
end

- (Object) forwardtrack_searching(location, expectation)

Searches for the given text starting at the given location, going backwards. Modifies the location to match the discovered expected text on success.

complexity: O(N) wrt input source location: [Fixnum, Fixnum] expectation: String returns: Boolean



132
133
134
135
136
137
138
139
140
141
142
143
144
145
# File 'lib/laser/analysis/sexp_extensions/source_location.rb', line 132

def forwardtrack_searching(location, expectation)
  result = location.dup
  line = lines[result[0] - 1]
  begin
    if (expectation_location = line.index(expectation, result[1]))
      result[1] = expectation_location + expectation.size
      return result
    end
    result[0] += 1
    result[1] = 0
    line = lines[result[0] - 1]
  end while result[0] <= lines.size
  location
end

- (Object) line_number



5
6
7
# File 'lib/laser/analysis/sexp_extensions/source_location.rb', line 5

def line_number
  source_begin && source_begin[0]
end

- (Object) source_begin

Calculates, with some lossiness, the start position of the current node in the original text. This will sometimes fail, as the AST does not include sufficient information in many cases to determine where a node lies. We have to figure it out based on nearby identifiers and keywords.



13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
# File 'lib/laser/analysis/sexp_extensions/source_location.rb', line 13

def source_begin
  return @source_begin if @source_begin
  default_result = children.select { |child| Sexp === child }.
                            map(&:source_begin).compact.first
  @source_begin = 
      case type
      when :@ident, :@int, :@kw, :@float, :@tstring_content, :@regexp_end,
           :@ivar, :@cvar, :@gvar, :@const, :@label, :@CHAR, :@op
        children[1]
      when :regexp_literal
        result = default_result.dup
        if backtrack_expecting!(result, -1, '/') || backtrack_expecting!(result, -3, '%r')
          result
        end
      when :string_literal
        if default_result
          result = default_result.dup  # make a copy we can mutate
          if backtrack_expecting!(result, -1, "'") ||
             backtrack_expecting!(result, -1, '"') ||
             backtrack_expecting!(result, -3, '%q') ||
             backtrack_expecting!(result, -3, '%Q')
            result
          end
        end
      when :string_embexpr
        if default_result
          result = default_result.dup
          result[1] -= 2
          result
        end
      when :dyna_symbol
        if default_result
          result = default_result.dup
          result[1] -= 2
          result
        end
      when :symbol_literal
        result = default_result.dup
        result[1] -= 1
        result
      when :hash
        backtrack_searching(default_result, '{') if default_result
      when :array
        backtrack_searching(default_result, '[') if default_result
      when :def, :defs
        backtrack_searching(default_result, 'def')
      when :class, :sclass
        backtrack_searching(default_result, 'class')
      when :module
        backtrack_searching(default_result, 'module')
      else
        default_result
      end
end

- (Object) source_end

Calculates, with some lossiness, the end position of the current node in the original text. This will sometimes fail, as the AST does not include sufficient information in many cases to determine where a node ends. We have to figure it out based on nearby identifiers, keywords, and literals.



72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
# File 'lib/laser/analysis/sexp_extensions/source_location.rb', line 72

def source_end
  default_result = children.select { |child| Sexp === child }.
                            map(&:source_end).compact.last
  case type
  when :@ident, :@int, :@kw, :@float, :@tstring_content, :@regexp_end,
       :@ivar, :@cvar, :@gvar, :@const, :@label, :@CHAR, :@op
    text, location = children
    source_end = location.dup
    source_end[1] += text.size
    source_end
  when :string_literal
    if source_begin
      result = default_result.dup
      result[1] += 1
      result
    end
  when :string_embexpr, :dyna_symbol
    if default_result
      result = default_result.dup
      result[1] += 1
      result
    end
  when :hash
    forwardtrack_searching(default_result, '}') if default_result
  when :array
    forwardtrack_searching(default_result, ']') if default_result
  else
    default_result
  end
end

- (Object) text_at(location, offset, length)

Determines the text at the given location tuple, with some offset, and a given length.



158
159
160
161
# File 'lib/laser/analysis/sexp_extensions/source_location.rb', line 158

def text_at(location, offset, length)
  line = lines[location[0] - 1]
  line[location[1] + offset, length]
end