Skip to content

Commit

Permalink
Add support for a relative offset within ast.SourceInfo (#836)
Browse files Browse the repository at this point in the history
  • Loading branch information
TristonianJones authored Sep 5, 2023
1 parent 92e92b5 commit ea648d7
Show file tree
Hide file tree
Showing 2 changed files with 69 additions and 0 deletions.
17 changes: 17 additions & 0 deletions common/ast/ast.go
Original file line number Diff line number Diff line change
Expand Up @@ -158,13 +158,24 @@ func MaxID(a *AST) int64 {
func NewSourceInfo(src common.Source) *SourceInfo {
var lineOffsets []int32
var desc string
baseLine := int32(0)
baseCol := int32(0)
if src != nil {
desc = src.Description()
lineOffsets = src.LineOffsets()
// Determine whether the source metadata should be computed relative
// to a base line and column value. This can be determined by requesting
// the location for offset 0 from the source object.
if loc, found := src.OffsetLocation(0); found {
baseLine = int32(loc.Line()) - 1
baseCol = int32(loc.Column())
}
}
return &SourceInfo{
desc: desc,
lines: lineOffsets,
baseLine: baseLine,
baseCol: baseCol,
offsetRanges: make(map[int64]OffsetRange),
macroCalls: make(map[int64]Expr),
}
Expand Down Expand Up @@ -200,6 +211,8 @@ type SourceInfo struct {
syntax string
desc string
lines []int32
baseLine int32
baseCol int32
offsetRanges map[int64]OffsetRange
macroCalls map[int64]Expr
}
Expand Down Expand Up @@ -332,6 +345,10 @@ func (s *SourceInfo) GetStopLocation(id int64) common.Location {

// ComputeOffset calculates the 0-based character offset from a 1-based line and 0-based column.
func (s *SourceInfo) ComputeOffset(line, col int32) int32 {
if s != nil {
line = s.baseLine + line
col = s.baseCol + col
}
if line == 1 {
return col
}
Expand Down
52 changes: 52 additions & 0 deletions common/ast/ast_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -294,3 +294,55 @@ func TestReferenceInfoAddOverload(t *testing.T) {
t.Error("repeated AddOverload() did not produce equal references")
}
}

func TestNewSourceInfoRelative(t *testing.T) {
sourceInfo := ast.NewSourceInfo(
mockRelativeSource(t,
"\n \n a || b ?\n cond1 :\n cond2",
[]int32{1, 2, 13, 25},
common.NewLocation(2, 1)))
tests := []struct {
loc common.Location
offset int32
}{
// All locations specify a line number starting at 1
// The location of line 2, offset 1 is the same as the
// relative offset at location 1, 0 (offset 2)
{loc: common.NewLocation(1, 0), offset: 2},
// Equivalent to line 3, column 4
{loc: common.NewLocation(2, 3), offset: 6},
// Equivalent to line 4, column 2
{loc: common.NewLocation(3, 1), offset: 15},
}
for _, tst := range tests {
gotOffset := sourceInfo.ComputeOffset(int32(tst.loc.Line()), int32(tst.loc.Column()))
if gotOffset != tst.offset {
t.Errorf("ComputeOffset() got %v, wanted %v", gotOffset, tst.offset)
}
}
}

func mockRelativeSource(t testing.TB, text string, lineOffsets []int32, baseLocation common.Location) common.Source {
t.Helper()
return &mockSource{
Source: common.NewTextSource(text),
lineOffsets: lineOffsets,
baseLocation: baseLocation}
}

type mockSource struct {
common.Source
lineOffsets []int32
baseLocation common.Location
}

func (src *mockSource) LineOffsets() []int32 {
return src.lineOffsets
}

func (src *mockSource) OffsetLocation(offset int32) (common.Location, bool) {
if offset == 0 {
return src.baseLocation, true
}
return src.Source.OffsetLocation(offset)
}

0 comments on commit ea648d7

Please sign in to comment.