initial error reporting
This commit is contained in:
parent
0ebf532a30
commit
11ba9708d9
47
choice.go
47
choice.go
@ -171,6 +171,17 @@ func (p *choiceParser) parse(c *context) {
|
|||||||
var optionIndex int
|
var optionIndex int
|
||||||
var foundMatch bool
|
var foundMatch bool
|
||||||
|
|
||||||
|
// TODO:
|
||||||
|
// - if there is a failure already, it should be left alone
|
||||||
|
// - what if reading more means that the previous failurs don't count
|
||||||
|
initialFailOffset := c.failOffset
|
||||||
|
initialFailingParser := c.failingParser
|
||||||
|
c.failingParser = nil
|
||||||
|
var (
|
||||||
|
failOffset int
|
||||||
|
failingParser parser
|
||||||
|
)
|
||||||
|
|
||||||
for {
|
for {
|
||||||
foundMatch = false
|
foundMatch = false
|
||||||
optionIndex = 0
|
optionIndex = 0
|
||||||
@ -181,6 +192,13 @@ func (p *choiceParser) parse(c *context) {
|
|||||||
|
|
||||||
if !c.matchLast || match && c.offset <= to {
|
if !c.matchLast || match && c.offset <= to {
|
||||||
c.offset = from
|
c.offset = from
|
||||||
|
if c.failOffset > failOffset {
|
||||||
|
failOffset = c.failOffset
|
||||||
|
failingParser = c.failingParser
|
||||||
|
}
|
||||||
|
|
||||||
|
c.failOffset = initialFailOffset
|
||||||
|
c.failingParser = nil
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -188,7 +206,8 @@ func (p *choiceParser) parse(c *context) {
|
|||||||
foundMatch = true
|
foundMatch = true
|
||||||
to = c.offset
|
to = c.offset
|
||||||
c.offset = from
|
c.offset = from
|
||||||
|
c.failOffset = initialFailOffset
|
||||||
|
c.failingParser = nil
|
||||||
c.results.setMatch(from, p.id, to)
|
c.results.setMatch(from, p.id, to)
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -198,13 +217,37 @@ func (p *choiceParser) parse(c *context) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if match {
|
if match {
|
||||||
|
c.failOffset = initialFailOffset
|
||||||
|
c.failingParser = initialFailingParser
|
||||||
c.success(to)
|
c.success(to)
|
||||||
c.results.unmarkPending(from, p.id)
|
c.results.unmarkPending(from, p.id)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if failOffset > initialFailOffset {
|
||||||
|
// println("recording choice failure", p.name, failOffset)
|
||||||
|
c.failOffset = failOffset
|
||||||
|
if failingParser == nil && p.commit&userDefined != 0 && p.commit&Whitespace == 0 {
|
||||||
|
// println("setting failing choice parser", p.nodeName(), failOffset)
|
||||||
|
c.failingParser = p
|
||||||
|
} else {
|
||||||
|
c.failingParser = failingParser
|
||||||
|
}
|
||||||
|
} else if failOffset == initialFailOffset && initialFailingParser == nil {
|
||||||
|
// println("recording choice failure", p.name, failOffset)
|
||||||
|
c.failOffset = failOffset
|
||||||
|
if failingParser == nil && p.commit&userDefined != 0 && p.commit&Whitespace == 0 {
|
||||||
|
// println("setting failing choice parser", p.nodeName(), failOffset)
|
||||||
|
c.failingParser = p
|
||||||
|
} else {
|
||||||
|
c.failingParser = failingParser
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
c.failOffset = initialFailOffset
|
||||||
|
c.failingParser = initialFailingParser
|
||||||
|
}
|
||||||
|
|
||||||
c.results.setNoMatch(from, p.id)
|
c.results.setNoMatch(from, p.id)
|
||||||
c.recordFailure(p)
|
|
||||||
c.fail(from)
|
c.fail(from)
|
||||||
c.results.unmarkPending(from, p.id)
|
c.results.unmarkPending(from, p.id)
|
||||||
}
|
}
|
||||||
|
13
context.go
13
context.go
@ -93,17 +93,22 @@ func (c *context) fail(offset int) {
|
|||||||
c.matchLast = false
|
c.matchLast = false
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *context) recordFailure(p parser) {
|
// TODO:
|
||||||
if c.offset < c.failOffset {
|
// - need to know which choice branch the failure happened on because if there is a non-user branch that has the
|
||||||
|
// longest failure, it can be reported to an unrelevant user defined choice on another branch
|
||||||
|
|
||||||
|
func (c *context) recordFailure(offset int, p parser) {
|
||||||
|
if offset < c.failOffset {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
if c.failingParser != nil && c.offset == c.failOffset {
|
if c.failingParser != nil && offset == c.failOffset {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
c.failOffset = c.offset
|
c.failOffset = offset
|
||||||
if p.commitType()&userDefined != 0 && p.commitType()&Whitespace == 0 {
|
if p.commitType()&userDefined != 0 && p.commitType()&Whitespace == 0 {
|
||||||
|
// println("setting failing sequence parser", p.nodeName(), offset)
|
||||||
c.failingParser = p
|
c.failingParser = p
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -73,6 +73,34 @@ func TestError(t *testing.T) {
|
|||||||
offset: 2,
|
offset: 2,
|
||||||
column: 2,
|
column: 2,
|
||||||
definition: "b",
|
definition: "b",
|
||||||
|
}, {
|
||||||
|
title: "failing choice on the failing branch",
|
||||||
|
syntax: `a = "123"; b:root = a | "13"`,
|
||||||
|
text: "124",
|
||||||
|
offset: 2,
|
||||||
|
column: 2,
|
||||||
|
definition: "a",
|
||||||
|
}, {
|
||||||
|
title: "failing choice on a shorter branch",
|
||||||
|
syntax: `a = "13"; b:root = "123" | a`,
|
||||||
|
text: "124",
|
||||||
|
offset: 2,
|
||||||
|
column: 2,
|
||||||
|
definition: "b",
|
||||||
|
}, {
|
||||||
|
title: "longer failure on a later pass",
|
||||||
|
syntax: `a = "12"; b = "34"; c = "1" b; d:root = a | c`,
|
||||||
|
text: "135",
|
||||||
|
offset: 2,
|
||||||
|
column: 2,
|
||||||
|
definition: "b",
|
||||||
|
}, {
|
||||||
|
title: "char as a choice option",
|
||||||
|
syntax: `a = "12"; b = [a] | [b]; c = a b`,
|
||||||
|
text: "12c",
|
||||||
|
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)
|
||||||
@ -81,6 +109,7 @@ func TestError(t *testing.T) {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// println("starting")
|
||||||
_, err = s.Parse(bytes.NewBufferString(test.text))
|
_, err = s.Parse(bytes.NewBufferString(test.text))
|
||||||
if err == nil {
|
if err == nil {
|
||||||
t.Error("failed to fail")
|
t.Error("failed to fail")
|
||||||
@ -119,8 +148,28 @@ func TestError(t *testing.T) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestErrorRecursive(t *testing.T) {
|
||||||
|
const doc = `a[b][1a]`
|
||||||
|
|
||||||
|
s, err := openSyntaxFile("examples/mml.treerack")
|
||||||
|
if err != nil {
|
||||||
|
t.Error(err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// println("starting")
|
||||||
|
_, err = s.Parse(bytes.NewBufferString(doc))
|
||||||
|
perr, ok := err.(*ParseError)
|
||||||
|
if !ok {
|
||||||
|
t.Error("failed to return parse error")
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
t.Log(perr)
|
||||||
|
}
|
||||||
|
|
||||||
func TestErrorMessage(t *testing.T) {
|
func TestErrorMessage(t *testing.T) {
|
||||||
const expected = "foo:4:10:failed to parse definition: bar"
|
const expected = "foo:4:10:failed to parse input, expecting: bar"
|
||||||
|
|
||||||
perr := &ParseError{
|
perr := &ParseError{
|
||||||
Input: "foo",
|
Input: "foo",
|
||||||
|
@ -312,7 +312,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.recordFailure(p)
|
// println("recording sequence failure", p.name, c.offset)
|
||||||
|
c.recordFailure(c.offset, p)
|
||||||
c.fail(from)
|
c.fail(from)
|
||||||
if !p.allChars {
|
if !p.allChars {
|
||||||
c.results.unmarkPending(from, p.id)
|
c.results.unmarkPending(from, p.id)
|
||||||
|
@ -159,7 +159,7 @@ func intsContain(is []int, i int) bool {
|
|||||||
|
|
||||||
func (pe *ParseError) Error() string {
|
func (pe *ParseError) Error() string {
|
||||||
return fmt.Sprintf(
|
return fmt.Sprintf(
|
||||||
"%s:%d:%d:failed to parse definition: %s",
|
"%s:%d:%d:failed to parse input, expecting: %s",
|
||||||
pe.Input,
|
pe.Input,
|
||||||
pe.Line+1,
|
pe.Line+1,
|
||||||
pe.Column+1,
|
pe.Column+1,
|
||||||
|
Loading…
Reference in New Issue
Block a user