Cache error offset in ParserError for safer position tracking
Instead of requiring downstream consumers to re-derive the byte offset from pointer arithmetic on the Highlight slice, compute and cache the offset inside the parser at error-capture time via setErrOffset(). This is safer because: - The parser is the one place where the backing-array guarantee is known to hold (Highlight is always a subslice of the parse buffer) - Downstream consumers (wrapDecodeError) can use the cached offset directly, avoiding the need for pointer comparison - Errors created outside the parser (strict.go) set the offset from existing Raw ranges, which are already correct by construction Add ParserError.SetOffset/Offset methods for setting and retrieving the cached offset. Update wrapDecodeError to prefer the cached offset when available, falling back to subsliceOffset for backward compatibility. Co-authored-by: Thomas Pelletier <thomas@pelletier.dev>
This commit is contained in:
@@ -766,6 +766,54 @@ func TestErrorHighlightPositions(t *testing.T) {
|
||||
}
|
||||
}
|
||||
|
||||
func TestParserError_CachedOffset(t *testing.T) {
|
||||
examples := []struct {
|
||||
desc string
|
||||
input string
|
||||
wantOffset int
|
||||
}{
|
||||
{
|
||||
desc: "error after comment",
|
||||
input: "# comment\n= \"value\"",
|
||||
wantOffset: 10,
|
||||
},
|
||||
{
|
||||
desc: "error on first line",
|
||||
input: "= \"value\"",
|
||||
wantOffset: 0,
|
||||
},
|
||||
{
|
||||
desc: "error after two lines",
|
||||
input: "a = 1\n= \"value\"",
|
||||
wantOffset: 6,
|
||||
},
|
||||
}
|
||||
|
||||
for _, e := range examples {
|
||||
t.Run(e.desc, func(t *testing.T) {
|
||||
p := Parser{}
|
||||
p.Reset([]byte(e.input))
|
||||
for p.NextExpression() {
|
||||
}
|
||||
err := p.Error()
|
||||
if err == nil {
|
||||
t.Fatal("expected an error")
|
||||
}
|
||||
var perr *ParserError
|
||||
if !errors.As(err, &perr) {
|
||||
t.Fatalf("expected ParserError, got %T", err)
|
||||
}
|
||||
offset, ok := perr.Offset()
|
||||
if !ok {
|
||||
t.Fatal("expected offset to be set")
|
||||
}
|
||||
if offset != e.wantOffset {
|
||||
t.Errorf("cached offset: got %d, want %d", offset, e.wantOffset)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func ExampleParser() {
|
||||
doc := `
|
||||
hello = "world"
|
||||
|
||||
Reference in New Issue
Block a user