fix choice error reporting
This commit is contained in:
parent
41fdcbdef0
commit
b06dc6d207
2
char.go
2
char.go
@ -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
|
||||
}
|
||||
|
||||
|
@ -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)
|
||||
}
|
||||
|
||||
|
41
context.go
41
context.go
@ -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 {
|
||||
|
@ -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)
|
||||
|
@ -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
|
||||
|
@ -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)
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user