fix choice error reporting

This commit is contained in:
Arpad Ryszka 2017-11-25 22:01:02 +01:00
parent 41fdcbdef0
commit b06dc6d207
6 changed files with 44 additions and 34 deletions

View File

@ -58,7 +58,7 @@ func (p *charParser) match(t rune) bool {
func (p *charParser) parse(c *context) { func (p *charParser) parse(c *context) {
if tok, ok := c.token(); !ok || !p.match(tok) { if tok, ok := c.token(); !ok || !p.match(tok) {
c.fail(p, c.offset) c.fail(c.offset)
return return
} }

View File

@ -141,7 +141,7 @@ func (p *choiceParser) parse(c *context) {
} }
if c.results.pending(c.offset, p.id) { if c.results.pending(c.offset, p.id) {
c.fail(p, c.offset) c.fail(c.offset)
return return
} }
@ -186,7 +186,8 @@ func (p *choiceParser) parse(c *context) {
} }
c.results.setNoMatch(from, p.id) c.results.setNoMatch(from, p.id)
c.fail(p, from) c.recordFailure(p)
c.fail(from)
c.results.unmarkPending(from, p.id) c.results.unmarkPending(from, p.id)
} }

View File

@ -74,7 +74,7 @@ func (c *context) fromResults(p parser) bool {
if m { if m {
c.success(to) c.success(to)
} else { } else {
c.fail(p, c.offset) c.fail(c.offset)
} }
return true return true
@ -88,18 +88,25 @@ func (c *context) success(to int) {
} }
} }
func (c *context) fail(p parser, offset int) { func (c *context) fail(offset int) {
c.offset = offset c.offset = offset
c.matchLast = false c.matchLast = false
if c.failingParser == nil || c.consumed > c.failOffset { }
// TODO: choice can be retried
println("setting fail", p.nodeName(), c.failingParser == nil, c.failOffset, c.consumed) func (c *context) recordFailure(p parser) {
c.failOffset = c.consumed if c.offset < c.failOffset {
return
}
if c.failingParser != nil && c.offset == c.failOffset {
return
}
c.failOffset = c.offset
if p.commitType()&userDefined != 0 { if p.commitType()&userDefined != 0 {
c.failingParser = p c.failingParser = p
} }
} }
}
func findLine(tokens []rune, offset int) (line, column int) { func findLine(tokens []rune, offset int) (line, column int) {
tokens = tokens[:offset] tokens = tokens[:offset]
@ -114,13 +121,10 @@ func findLine(tokens []rune, offset int) (line, column int) {
return return
} }
func (c *context) parseError(root parser) error { func (c *context) parseError(p parser) error {
definition := root.nodeName() definition := p.nodeName()
if c.failingParser == nil { if c.failingParser == nil {
println("setting fail", c.failOffset, c.consumed)
c.failOffset = c.consumed c.failOffset = c.consumed
} else {
definition = c.failingParser.nodeName()
} }
line, col := findLine(c.tokens, c.failOffset) line, col := findLine(c.tokens, c.failOffset)
@ -134,17 +138,22 @@ func (c *context) parseError(root parser) error {
} }
func (c *context) finalizeParse(root parser) error { func (c *context) finalizeParse(root parser) error {
if !c.matchLast { p := c.failingParser
return c.parseError(root) if p == nil {
p = root
} }
to, match, found := c.results.longestResult(0, root.nodeID()) to, match, found := c.results.longestResult(0, root.nodeID())
// TODO: test all three cases if found && match && to < c.readOffset {
if !found || !match || to < c.readOffset {
return c.parseError(root) return c.parseError(root)
} }
// TODO: test both cases
if !found || !match {
return c.parseError(p)
}
if !c.eof { if !c.eof {
c.read() c.read()
if !c.eof { if !c.eof {

View File

@ -53,26 +53,26 @@ func TestError(t *testing.T) {
column: 2, column: 2,
definition: "c", definition: "c",
}, { }, {
title: "choice, longer option fails", title: "choice succeeds, document fails",
syntax: `a = "12"; b = "1"; c:root = a | b`, syntax: `a = "12"; b = "1"; c:root = a | b`,
text: "13", text: "13",
offset: 1, offset: 1,
column: 1, column: 1,
definition: "a", definition: "c",
}, { }, {
title: "choice, shorter option fails", title: "choice fails",
syntax: `a = "2"; b = "12"; c:root = a | b`,
text: "123",
offset: 0,
column: 0,
definition: "1",
}, {
title: "choice, both options fail",
syntax: `a = "12"; b = "2"; c:root = a | b`, syntax: `a = "12"; b = "2"; c:root = a | b`,
text: "13", text: "13",
offset: 1, offset: 1,
column: 1, column: 1,
definition: "a", definition: "a",
}, {
title: "choice fails, longer option reported",
syntax: `a = "12"; b = "134"; c:root = a | b`,
text: "135",
offset: 2,
column: 2,
definition: "b",
}} { }} {
t.Run(test.title, func(t *testing.T) { t.Run(test.title, func(t *testing.T) {
s, err := openSyntaxString(test.syntax) s, err := openSyntaxString(test.syntax)

View File

@ -17,7 +17,6 @@ func openSyntaxReader(r io.Reader) (*Syntax, error) {
return nil, err return nil, err
} }
println("starting")
s := &Syntax{} s := &Syntax{}
if err := define(s, doc); err != nil { if err := define(s, doc); err != nil {
return nil, err return nil, err

View File

@ -175,7 +175,7 @@ func (p *sequenceParser) commitType() CommitType { return p.commit }
func (p *sequenceParser) parse(c *context) { func (p *sequenceParser) parse(c *context) {
if !p.allChars { if !p.allChars {
if c.results.pending(c.offset, p.id) { if c.results.pending(c.offset, p.id) {
c.fail(p, c.offset) c.fail(c.offset)
return return
} }
@ -192,7 +192,8 @@ func (p *sequenceParser) parse(c *context) {
p.items[itemIndex].parse(c) p.items[itemIndex].parse(c)
if !c.matchLast { if !c.matchLast {
if currentCount < p.ranges[itemIndex][0] { if currentCount < p.ranges[itemIndex][0] {
c.fail(p, from) c.recordFailure(p)
c.fail(from)
if !p.allChars { if !p.allChars {
c.results.unmarkPending(from, p.id) c.results.unmarkPending(from, p.id)
} }