Consolidate subslice offset into a single SubsliceOffset function
Remove the private subsliceOffset methods from both parser.go and errors.go. Replace them with a single exported SubsliceOffset function in ast.go (next to the Range type it serves). SubsliceOffset finds the byte offset by comparing element addresses: &data[i] == &subslice[0]. This is well-defined Go pointer comparison on elements of the same backing array. This fixes the v2.3.0 regression (#1047) where the parser's subsliceOffset used len(data) - len(b), which only works for suffix slices, not arbitrary subslices like error highlights. It also removes the reflect-based implementation from errors.go. Fixes #1047 Co-authored-by: Thomas Pelletier <thomas@pelletier.dev>
This commit is contained in:
@@ -99,7 +99,7 @@ func (e *DecodeError) Key() Key {
|
|||||||
//
|
//
|
||||||
//nolint:funlen
|
//nolint:funlen
|
||||||
func wrapDecodeError(document []byte, de *unstable.ParserError) *DecodeError {
|
func wrapDecodeError(document []byte, de *unstable.ParserError) *DecodeError {
|
||||||
offset := subsliceOffset(document, de.Highlight)
|
offset := unstable.SubsliceOffset(document, de.Highlight)
|
||||||
|
|
||||||
errMessage := de.Error()
|
errMessage := de.Error()
|
||||||
errLine, errColumn := positionAtEnd(document[:offset])
|
errLine, errColumn := positionAtEnd(document[:offset])
|
||||||
@@ -261,17 +261,3 @@ func positionAtEnd(b []byte) (row int, column int) {
|
|||||||
|
|
||||||
return row, column
|
return row, column
|
||||||
}
|
}
|
||||||
|
|
||||||
// subsliceOffset finds the byte offset of subslice within data by
|
|
||||||
// scanning for the matching element address.
|
|
||||||
func subsliceOffset(data []byte, subslice []byte) int {
|
|
||||||
if len(subslice) == 0 {
|
|
||||||
return len(data)
|
|
||||||
}
|
|
||||||
for i := range data {
|
|
||||||
if &data[i] == &subslice[0] {
|
|
||||||
return i
|
|
||||||
}
|
|
||||||
}
|
|
||||||
panic("subslice is not within data")
|
|
||||||
}
|
|
||||||
|
|||||||
@@ -90,6 +90,21 @@ type Range struct {
|
|||||||
Length uint32
|
Length uint32
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// SubsliceOffset returns the byte offset of subslice within data.
|
||||||
|
// Subslice must be a subslice of data, meaning it must point into the
|
||||||
|
// same backing array. Panics if subslice is not within data.
|
||||||
|
func SubsliceOffset(data []byte, subslice []byte) int {
|
||||||
|
if len(subslice) == 0 {
|
||||||
|
return len(data)
|
||||||
|
}
|
||||||
|
for i := range data {
|
||||||
|
if &data[i] == &subslice[0] {
|
||||||
|
return i
|
||||||
|
}
|
||||||
|
}
|
||||||
|
panic("subslice is not within data")
|
||||||
|
}
|
||||||
|
|
||||||
// Next returns a pointer to the next node, or nil if there is no next node.
|
// Next returns a pointer to the next node, or nil if there is no next node.
|
||||||
func (n *Node) Next() *Node {
|
func (n *Node) Next() *Node {
|
||||||
if n.next < 0 {
|
if n.next < 0 {
|
||||||
|
|||||||
+2
-16
@@ -69,8 +69,8 @@ func (p *Parser) Data() []byte {
|
|||||||
// panics.
|
// panics.
|
||||||
func (p *Parser) Range(b []byte) Range {
|
func (p *Parser) Range(b []byte) Range {
|
||||||
return Range{
|
return Range{
|
||||||
Offset: uint32(p.subsliceOffset(b)), //nolint:gosec // TOML documents are small
|
Offset: uint32(SubsliceOffset(p.data, b)), //nolint:gosec // TOML documents are small
|
||||||
Length: uint32(len(b)), //nolint:gosec // TOML documents are small
|
Length: uint32(len(b)), //nolint:gosec // TOML documents are small
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -82,20 +82,6 @@ func (p *Parser) rangeOfToken(token, rest []byte) Range {
|
|||||||
return Range{Offset: uint32(offset), Length: uint32(len(token))} //nolint:gosec // TOML documents are small
|
return Range{Offset: uint32(offset), Length: uint32(len(token))} //nolint:gosec // TOML documents are small
|
||||||
}
|
}
|
||||||
|
|
||||||
// subsliceOffset finds the byte offset of subslice b within p.data
|
|
||||||
// by scanning for the matching element address.
|
|
||||||
func (p *Parser) subsliceOffset(b []byte) int {
|
|
||||||
if len(b) == 0 {
|
|
||||||
return len(p.data)
|
|
||||||
}
|
|
||||||
for i := range p.data {
|
|
||||||
if &p.data[i] == &b[0] {
|
|
||||||
return i
|
|
||||||
}
|
|
||||||
}
|
|
||||||
panic("subslice is not within parser data")
|
|
||||||
}
|
|
||||||
|
|
||||||
// Raw returns the slice corresponding to the bytes in the given range.
|
// Raw returns the slice corresponding to the bytes in the given range.
|
||||||
func (p *Parser) Raw(raw Range) []byte {
|
func (p *Parser) Raw(raw Range) []byte {
|
||||||
return p.data[raw.Offset : raw.Offset+raw.Length]
|
return p.data[raw.Offset : raw.Offset+raw.Length]
|
||||||
|
|||||||
Reference in New Issue
Block a user