added LocateError

This commit is contained in:
Özgür Kesim 2019-11-29 06:49:16 +01:00
parent 5173c86ded
commit a7c195f799

View File

@ -1,6 +1,10 @@
package goparsify package goparsify
import "fmt" import (
"bufio"
"fmt"
"strings"
)
// Error represents a parse error. These will often be set, the parser will back up a little and // Error represents a parse error. These will often be set, the parser will back up a little and
// find another viable path. In general when combining errors the longest error should be returned. // find another viable path. In general when combining errors the longest error should be returned.
@ -24,3 +28,50 @@ type UnparsedInputError struct {
func (e UnparsedInputError) Error() string { func (e UnparsedInputError) Error() string {
return "left unparsed: " + e.Remaining return "left unparsed: " + e.Remaining
} }
// LocalError locates the error position in the input string s and returns the
// error description along with a cursor to the input.
func (e *Error) LocateError(s string) string {
if len(s) < e.Pos() {
return e.Error()
}
pos := e.Pos()
// find the line.
var (
lino, prev, off int
line, indent []byte
)
byline := bufio.NewScanner(strings.NewReader(s))
for byline.Scan() {
lino++
line = byline.Bytes()
prev = off
off += len(line) + 1
// log.Printf("lino:%3d len:%4d prev:%4d pos:%4d off:%4d rel:%4d line: %s",
// lino, len(line), prev, pos, off, (pos - prev), string(line))
if prev <= pos && pos <= off {
break
}
}
indent = make([]byte, len(line[:pos-prev]))
for i, c := range indent {
if c != '\t' {
indent[i] = ' '
}
}
off = pos - prev
if off > 40 {
indent = indent[off-30:]
line = line[off-30:]
line[0] = '.'
line[1] = '.'
line[2] = '.'
}
if len(line) > 70 {
line = line[:70]
line[69], line[68], line[67] = '.', '.', '.'
}
return fmt.Sprintf("Parsing error in line %d:\n%s\n%s^\n%v\n", lino, string(line), string(indent), e.Error())
}