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:
@@ -54,11 +54,14 @@ func (s *strict) MissingTable(node *unstable.Node) {
|
||||
return
|
||||
}
|
||||
|
||||
s.missing = append(s.missing, unstable.ParserError{
|
||||
Highlight: s.keyLocation(node),
|
||||
highlight, offset := s.keyLocation(node)
|
||||
pe := unstable.ParserError{
|
||||
Highlight: highlight,
|
||||
Message: "missing table",
|
||||
Key: s.key.Key(),
|
||||
})
|
||||
}
|
||||
pe.SetOffset(offset)
|
||||
s.missing = append(s.missing, pe)
|
||||
}
|
||||
|
||||
func (s *strict) MissingField(node *unstable.Node) {
|
||||
@@ -66,11 +69,14 @@ func (s *strict) MissingField(node *unstable.Node) {
|
||||
return
|
||||
}
|
||||
|
||||
s.missing = append(s.missing, unstable.ParserError{
|
||||
Highlight: s.keyLocation(node),
|
||||
highlight, offset := s.keyLocation(node)
|
||||
pe := unstable.ParserError{
|
||||
Highlight: highlight,
|
||||
Message: "missing field",
|
||||
Key: s.key.Key(),
|
||||
})
|
||||
}
|
||||
pe.SetOffset(offset)
|
||||
s.missing = append(s.missing, pe)
|
||||
}
|
||||
|
||||
func (s *strict) Error(doc []byte) error {
|
||||
@@ -90,7 +96,7 @@ func (s *strict) Error(doc []byte) error {
|
||||
return err
|
||||
}
|
||||
|
||||
func (s *strict) keyLocation(node *unstable.Node) []byte {
|
||||
func (s *strict) keyLocation(node *unstable.Node) ([]byte, int) {
|
||||
k := node.Key()
|
||||
|
||||
hasOne := k.Next()
|
||||
@@ -98,7 +104,6 @@ func (s *strict) keyLocation(node *unstable.Node) []byte {
|
||||
panic("should not be called with empty key")
|
||||
}
|
||||
|
||||
// Get the range from the first key to the last key.
|
||||
firstRaw := k.Node().Raw
|
||||
lastRaw := firstRaw
|
||||
|
||||
@@ -106,9 +111,8 @@ func (s *strict) keyLocation(node *unstable.Node) []byte {
|
||||
lastRaw = k.Node().Raw
|
||||
}
|
||||
|
||||
// Compute the slice from the document using the ranges.
|
||||
start := firstRaw.Offset
|
||||
end := lastRaw.Offset + lastRaw.Length
|
||||
|
||||
return s.doc[start:end]
|
||||
return s.doc[start:end], int(start)
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user