Skip to content

Commit ea648d7

Browse files
Add support for a relative offset within ast.SourceInfo (#836)
1 parent 92e92b5 commit ea648d7

File tree

2 files changed

+69
-0
lines changed

2 files changed

+69
-0
lines changed

‎common/ast/ast.go‎

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -158,13 +158,24 @@ func MaxID(a *AST) int64 {
158158
func NewSourceInfo(src common.Source) *SourceInfo {
159159
var lineOffsets []int32
160160
var desc string
161+
baseLine := int32(0)
162+
baseCol := int32(0)
161163
if src != nil {
162164
desc = src.Description()
163165
lineOffsets = src.LineOffsets()
166+
// Determine whether the source metadata should be computed relative
167+
// to a base line and column value. This can be determined by requesting
168+
// the location for offset 0 from the source object.
169+
if loc, found := src.OffsetLocation(0); found {
170+
baseLine = int32(loc.Line()) - 1
171+
baseCol = int32(loc.Column())
172+
}
164173
}
165174
return &SourceInfo{
166175
desc: desc,
167176
lines: lineOffsets,
177+
baseLine: baseLine,
178+
baseCol: baseCol,
168179
offsetRanges: make(map[int64]OffsetRange),
169180
macroCalls: make(map[int64]Expr),
170181
}
@@ -200,6 +211,8 @@ type SourceInfo struct {
200211
syntax string
201212
desc string
202213
lines []int32
214+
baseLine int32
215+
baseCol int32
203216
offsetRanges map[int64]OffsetRange
204217
macroCalls map[int64]Expr
205218
}
@@ -332,6 +345,10 @@ func (s *SourceInfo) GetStopLocation(id int64) common.Location {
332345

333346
// ComputeOffset calculates the 0-based character offset from a 1-based line and 0-based column.
334347
func (s *SourceInfo) ComputeOffset(line, col int32) int32 {
348+
if s != nil {
349+
line = s.baseLine + line
350+
col = s.baseCol + col
351+
}
335352
if line == 1 {
336353
return col
337354
}

‎common/ast/ast_test.go‎

Lines changed: 52 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -294,3 +294,55 @@ func TestReferenceInfoAddOverload(t *testing.T) {
294294
t.Error("repeated AddOverload() did not produce equal references")
295295
}
296296
}
297+
298+
func TestNewSourceInfoRelative(t *testing.T) {
299+
sourceInfo := ast.NewSourceInfo(
300+
mockRelativeSource(t,
301+
"\n \n a || b ?\n cond1 :\n cond2",
302+
[]int32{1, 2, 13, 25},
303+
common.NewLocation(2, 1)))
304+
tests := []struct {
305+
loc common.Location
306+
offset int32
307+
}{
308+
// All locations specify a line number starting at 1
309+
// The location of line 2, offset 1 is the same as the
310+
// relative offset at location 1, 0 (offset 2)
311+
{loc: common.NewLocation(1, 0), offset: 2},
312+
// Equivalent to line 3, column 4
313+
{loc: common.NewLocation(2, 3), offset: 6},
314+
// Equivalent to line 4, column 2
315+
{loc: common.NewLocation(3, 1), offset: 15},
316+
}
317+
for _, tst := range tests {
318+
gotOffset := sourceInfo.ComputeOffset(int32(tst.loc.Line()), int32(tst.loc.Column()))
319+
if gotOffset != tst.offset {
320+
t.Errorf("ComputeOffset() got %v, wanted %v", gotOffset, tst.offset)
321+
}
322+
}
323+
}
324+
325+
func mockRelativeSource(t testing.TB, text string, lineOffsets []int32, baseLocation common.Location) common.Source {
326+
t.Helper()
327+
return &mockSource{
328+
Source: common.NewTextSource(text),
329+
lineOffsets: lineOffsets,
330+
baseLocation: baseLocation}
331+
}
332+
333+
type mockSource struct {
334+
common.Source
335+
lineOffsets []int32
336+
baseLocation common.Location
337+
}
338+
339+
func (src *mockSource) LineOffsets() []int32 {
340+
return src.lineOffsets
341+
}
342+
343+
func (src *mockSource) OffsetLocation(offset int32) (common.Location, bool) {
344+
if offset == 0 {
345+
return src.baseLocation, true
346+
}
347+
return src.Source.OffsetLocation(offset)
348+
}

0 commit comments

Comments
 (0)