From 0ebf532a30834a38ed1c62bcfc5fd8f6c6214e20 Mon Sep 17 00:00:00 2001 From: Arpad Ryszka Date: Sun, 26 Nov 2017 02:34:34 +0100 Subject: [PATCH] error message --- context.go | 2 +- errors_test.go | 50 ++++++++++++++++++++++++++++++++++++++++++++++++++ syntax.go | 23 ++++++++++++++++++++++- 3 files changed, 73 insertions(+), 2 deletions(-) diff --git a/context.go b/context.go index 4621e41..277fedf 100644 --- a/context.go +++ b/context.go @@ -103,7 +103,7 @@ func (c *context) recordFailure(p parser) { } c.failOffset = c.offset - if p.commitType()&userDefined != 0 { + if p.commitType()&userDefined != 0 && p.commitType()&Whitespace == 0 { c.failingParser = p } } diff --git a/errors_test.go b/errors_test.go index 5055786..9b95aa9 100644 --- a/errors_test.go +++ b/errors_test.go @@ -93,6 +93,11 @@ func TestError(t *testing.T) { return } + if perr.Input != "" { + t.Error("invalid default input name") + return + } + if perr.Offset != test.offset { t.Error("invalid error offset", perr.Offset, test.offset) return @@ -113,3 +118,48 @@ func TestError(t *testing.T) { }) } } + +func TestErrorMessage(t *testing.T) { + const expected = "foo:4:10:failed to parse definition: bar" + + perr := &ParseError{ + Input: "foo", + Offset: 42, + Line: 3, + Column: 9, + Definition: "bar", + } + + message := perr.Error() + if message != expected { + t.Error("failed to return the right error message") + t.Log("got: ", message) + t.Log("expected:", expected) + } +} + +func TestErrorVerbose(t *testing.T) { + const expected = ` +` + + const doc = `{ + "a": 1, + "b": 2, + "c": 3, + }` + + s, err := openSyntaxFile("examples/json.treerack") + if err != nil { + t.Error(err) + return + } + + _, err = s.Parse(bytes.NewBufferString(doc)) + perr, ok := err.(*ParseError) + if !ok { + t.Error("failed to return parse error") + return + } + + t.Log(perr.Error()) +} diff --git a/syntax.go b/syntax.go index ec41447..5573761 100644 --- a/syntax.go +++ b/syntax.go @@ -38,6 +38,10 @@ type SequenceItem struct { // the used syntax during parsing. type ParseError struct { + // Input is the name of the input file or if not + // available. + Input string + // Offset is the index of the right-most failing // token in the input text. Offset int @@ -55,6 +59,8 @@ type ParseError struct { // Definition tells the right-most unmatched parser definition. Definition string + + registry *registry } type Syntax struct { @@ -152,7 +158,17 @@ func intsContain(is []int, i int) bool { } func (pe *ParseError) Error() string { - return "parse error" + return fmt.Sprintf( + "%s:%d:%d:failed to parse definition: %s", + pe.Input, + pe.Line+1, + pe.Column+1, + pe.Definition, + ) +} + +func (pe *ParseError) Verbose() string { + return "" } func (s *Syntax) applyRoot(d definition) error { @@ -354,6 +370,11 @@ func (s *Syntax) Parse(r io.Reader) (*Node, error) { } if err := c.finalizeParse(s.parser); err != nil { + if perr, ok := err.(*ParseError); ok { + perr.Input = "" + perr.registry = s.registry + } + return nil, err }