From 00394a80501960ad26787b5c44435ed5ed67ad84 Mon Sep 17 00:00:00 2001 From: Alexander Neonxp Kiryukhin Date: Mon, 9 Mar 2026 23:05:42 +0300 Subject: =?UTF-8?q?=D0=9F=D0=BE=D0=BB=D0=BD=D0=BE=D1=81=D1=82=D1=8C=D1=8E?= =?UTF-8?q?=20=D0=BF=D0=B5=D1=80=D0=B5=D0=BF=D0=B8=D1=81=D0=B0=D0=BB=20?= =?UTF-8?q?=D0=B1=D0=B8=D0=B1=D0=BB=D0=B8=D0=BE=D1=82=D0=B5=D0=BA=D1=83.?= =?UTF-8?q?=20=D0=9F=D0=B5=D1=80=D0=B5=D0=B2=D1=91=D0=BB=20=D1=81=20EBNF?= =?UTF-8?q?=20=D0=BD=D0=B0=20PEG.?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- parser/errors.go | 107 +++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 107 insertions(+) create mode 100644 parser/errors.go (limited to 'parser/errors.go') diff --git a/parser/errors.go b/parser/errors.go new file mode 100644 index 0000000..c2ed049 --- /dev/null +++ b/parser/errors.go @@ -0,0 +1,107 @@ +package parser + +import ( + "bytes" + "errors" + "fmt" + "strings" +) + +type ErrorLister interface { + Errors() []error +} + +func (e errList) Errors() []error { + return e +} + +// ParserError is the public interface to errors of type parserError +type ParserError interface { + Error() string + InnerError() error + Pos() (int, int, int) + Expected() []string +} + +func (p *parserError) InnerError() error { + return p.Inner +} + +func (p *parserError) Pos() (line, col, offset int) { + return p.pos.line, p.pos.col, p.pos.offset +} + +func (p *parserError) Expected() []string { + return p.expected +} + +func CaretErrors(err error, input string) error { + if el, ok := err.(ErrorLister); ok { + var buffer bytes.Buffer + for _, e := range el.Errors() { + err1, shouldReturn := caretError(e, input, buffer, err) + if shouldReturn { + return err1 + } + } + return errors.New(buffer.String()) + } + return err +} + +func caretError(e error, input string, buffer bytes.Buffer, err error) (error, bool) { + if parserErr, ok := e.(ParserError); ok { + _, col, off := parserErr.Pos() + line := extractLine(input, off) + if col >= len(line) { + col = len(line) - 1 + } else { + if col > 0 { + col-- + } + } + if col < 0 { + col = 0 + } + pos := col + for _, chr := range line[:col] { + if chr == '\t' { + pos += 7 + } + } + fmt.Fprintf(&buffer, "%s\n%s\n%s\n", line, strings.Repeat(" ", pos)+"^", err.Error()) + + return err, true + } else { + return err, true + } + return nil, false +} + +func extractLine(input string, initPos int) string { + if initPos < 0 { + initPos = 0 + } + if initPos >= len(input) && len(input) > 0 { + initPos = len(input) - 1 + } + startPos := initPos + endPos := initPos + for ; startPos > 0; startPos-- { + if input[startPos] == '\n' { + if startPos != initPos { + startPos++ + break + } + } + } + for ; endPos < len(input); endPos++ { + if input[endPos] == '\n' { + if endPos == initPos { + endPos++ + } + break + } + } + return input[startPos:endPos] +} -- cgit v1.2.3