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
}