fix finding deepest user defined failing node
This commit is contained in:
parent
11ba9708d9
commit
692811a1a3
6
char.go
6
char.go
@ -95,6 +95,12 @@ 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) {
|
||||||
|
if c.offset > c.failOffset {
|
||||||
|
c.failOffset = c.offset
|
||||||
|
// println("clearing failing parser")
|
||||||
|
c.failingParser = nil
|
||||||
|
}
|
||||||
|
|
||||||
c.fail(c.offset)
|
c.fail(c.offset)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
48
choice.go
48
choice.go
@ -163,6 +163,8 @@ func (p *choiceParser) parse(c *context) {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// println("parsing choice", p.name, c.offset)
|
||||||
|
|
||||||
c.results.markPending(c.offset, p.id)
|
c.results.markPending(c.offset, p.id)
|
||||||
from := c.offset
|
from := c.offset
|
||||||
to := c.offset
|
to := c.offset
|
||||||
@ -175,12 +177,6 @@ func (p *choiceParser) parse(c *context) {
|
|||||||
// - if there is a failure already, it should be left alone
|
// - if there is a failure already, it should be left alone
|
||||||
// - what if reading more means that the previous failurs don't count
|
// - what if reading more means that the previous failurs don't count
|
||||||
initialFailOffset := c.failOffset
|
initialFailOffset := c.failOffset
|
||||||
initialFailingParser := c.failingParser
|
|
||||||
c.failingParser = nil
|
|
||||||
var (
|
|
||||||
failOffset int
|
|
||||||
failingParser parser
|
|
||||||
)
|
|
||||||
|
|
||||||
for {
|
for {
|
||||||
foundMatch = false
|
foundMatch = false
|
||||||
@ -192,13 +188,6 @@ 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
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -206,8 +195,6 @@ 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)
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -217,34 +204,23 @@ func (p *choiceParser) parse(c *context) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if match {
|
if match {
|
||||||
c.failOffset = initialFailOffset
|
if to >= c.failOffset {
|
||||||
c.failingParser = initialFailingParser
|
c.failOffset = -1
|
||||||
|
c.failingParser = nil
|
||||||
|
}
|
||||||
|
|
||||||
c.success(to)
|
c.success(to)
|
||||||
c.results.unmarkPending(from, p.id)
|
c.results.unmarkPending(from, p.id)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
if failOffset > initialFailOffset {
|
// TODO:
|
||||||
// println("recording choice failure", p.name, failOffset)
|
// - what if all of it pending?
|
||||||
c.failOffset = failOffset
|
if c.failOffset > initialFailOffset && c.failingParser == nil {
|
||||||
if failingParser == nil && p.commit&userDefined != 0 && p.commit&Whitespace == 0 {
|
if p.commitType()&userDefined != 0 && p.commitType()&Whitespace == 0 {
|
||||||
// println("setting failing choice parser", p.nodeName(), failOffset)
|
// println("recording choice failure", p.name, from, c.failOffset)
|
||||||
c.failingParser = p
|
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)
|
||||||
|
@ -23,6 +23,7 @@ func newContext(r io.RuneReader) *context {
|
|||||||
return &context{
|
return &context{
|
||||||
reader: r,
|
reader: r,
|
||||||
results: &results{},
|
results: &results{},
|
||||||
|
failOffset: -1,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -145,13 +146,17 @@ func (c *context) parseError(p parser) error {
|
|||||||
func (c *context) finalizeParse(root parser) error {
|
func (c *context) finalizeParse(root parser) error {
|
||||||
p := c.failingParser
|
p := c.failingParser
|
||||||
if p == nil {
|
if p == nil {
|
||||||
|
// println("failing parser is nil")
|
||||||
p = root
|
p = root
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// println("failing parser is", p.nodeName())
|
||||||
|
|
||||||
to, match, found := c.results.longestResult(0, root.nodeID())
|
to, match, found := c.results.longestResult(0, root.nodeID())
|
||||||
|
|
||||||
if found && match && to < c.readOffset {
|
if found && match && to < c.readOffset {
|
||||||
return c.parseError(root)
|
// println("forcing root", found, match, to, c.readOffset)
|
||||||
|
return c.parseError(p)
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO: test both cases
|
// TODO: test both cases
|
||||||
|
@ -149,7 +149,8 @@ func TestError(t *testing.T) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func TestErrorRecursive(t *testing.T) {
|
func TestErrorRecursive(t *testing.T) {
|
||||||
const doc = `a[b][1a]`
|
// const doc = `a[b][1a]`
|
||||||
|
const doc = `a[1a]`
|
||||||
|
|
||||||
s, err := openSyntaxFile("examples/mml.treerack")
|
s, err := openSyntaxFile("examples/mml.treerack")
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@ -157,7 +158,7 @@ func TestErrorRecursive(t *testing.T) {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
// println("starting")
|
// println("\n<<<< starting >>>>\n")
|
||||||
_, err = s.Parse(bytes.NewBufferString(doc))
|
_, err = s.Parse(bytes.NewBufferString(doc))
|
||||||
perr, ok := err.(*ParseError)
|
perr, ok := err.(*ParseError)
|
||||||
if !ok {
|
if !ok {
|
||||||
|
15
sequence.go
15
sequence.go
@ -307,13 +307,19 @@ func (p *sequenceParser) parse(c *context) {
|
|||||||
from := c.offset
|
from := c.offset
|
||||||
to := c.offset
|
to := c.offset
|
||||||
var parsed bool
|
var parsed bool
|
||||||
|
initialFailOffset := c.failOffset
|
||||||
|
|
||||||
for itemIndex < len(p.items) {
|
for itemIndex < len(p.items) {
|
||||||
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] {
|
||||||
// println("recording sequence failure", p.name, c.offset)
|
if c.failOffset > initialFailOffset && c.failingParser == nil {
|
||||||
c.recordFailure(c.offset, p)
|
if p.commitType()&userDefined != 0 && p.commitType()&Whitespace == 0 {
|
||||||
|
// println("recording sequence failure", p.name, from, c.failOffset)
|
||||||
|
c.failingParser = 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)
|
||||||
@ -346,6 +352,11 @@ func (p *sequenceParser) parse(c *context) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if to >= c.failOffset {
|
||||||
|
c.failOffset = -1
|
||||||
|
c.failingParser = nil
|
||||||
|
}
|
||||||
|
|
||||||
c.results.setMatch(from, p.id, to)
|
c.results.setMatch(from, p.id, to)
|
||||||
c.success(to)
|
c.success(to)
|
||||||
if !p.allChars {
|
if !p.allChars {
|
||||||
|
Loading…
Reference in New Issue
Block a user