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) {
if tok, ok := c.token(); !ok || !p.match(tok) {
c.fail(p, c.offset)
c.fail(c.offset)
return
}

View File

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

View File

@ -74,7 +74,7 @@ func (c *context) fromResults(p parser) bool {
if m {
c.success(to)
} else {
c.fail(p, c.offset)
c.fail(c.offset)
}
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.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)
c.failOffset = c.consumed
}
func (c *context) recordFailure(p parser) {
if c.offset < c.failOffset {
return
}
if c.failingParser != nil && c.offset == c.failOffset {
return
}
c.failOffset = c.offset
if p.commitType()&userDefined != 0 {
c.failingParser = p
}
}
}
func findLine(tokens []rune, offset int) (line, column int) {
tokens = tokens[:offset]
@ -114,13 +121,10 @@ func findLine(tokens []rune, offset int) (line, column int) {
return
}
func (c *context) parseError(root parser) error {
definition := root.nodeName()
func (c *context) parseError(p parser) error {
definition := p.nodeName()
if c.failingParser == nil {
println("setting fail", c.failOffset, c.consumed)
c.failOffset = c.consumed
} else {
definition = c.failingParser.nodeName()
}
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 {
if !c.matchLast {
return c.parseError(root)
p := c.failingParser
if p == nil {
p = root
}
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)
}
// TODO: test both cases
if !found || !match {
return c.parseError(p)
}
if !c.eof {
c.read()
if !c.eof {

View File

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

View File

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

View File

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