78 lines
1.9 KiB
Go
78 lines
1.9 KiB
Go
package goparsify
|
|
|
|
import (
|
|
"bufio"
|
|
"fmt"
|
|
"strings"
|
|
)
|
|
|
|
// 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.
|
|
type Error struct {
|
|
pos int
|
|
expected string
|
|
}
|
|
|
|
// Pos is the offset into the document the error was found
|
|
func (e *Error) Pos() int { return e.pos }
|
|
|
|
// Error satisfies the golang error interface
|
|
func (e *Error) Error() string { return fmt.Sprintf("offset %d: expected %s", e.pos, e.expected) }
|
|
|
|
// UnparsedInputError is returned by Run when not all of the input was consumed. There may still be a valid result
|
|
type UnparsedInputError struct {
|
|
Remaining string
|
|
}
|
|
|
|
// Error satisfies the golang error interface
|
|
func (e UnparsedInputError) Error() string {
|
|
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())
|
|
}
|