cue/parser: use a more robust exit mechanism
The panic raised when there are too many errors could be
overridden by unmatched closed lists, and the like, causing
the sentinel used of bailing out to be overridden.
The exit state is now explicitly marked in the parser, resulting
in a more robust exit mechanism.
Change-Id: I9eadd1076330539d3b228bc3016fa7abb5dfb3e8
Reviewed-on: https://cue-review.googlesource.com/c/cue/+/1641
Reviewed-by: Marcel van Lohuizen <mpvl@google.com>
diff --git a/cue/parser/interface.go b/cue/parser/interface.go
index a66fcbf..e2bfb82 100644
--- a/cue/parser/interface.go
+++ b/cue/parser/interface.go
@@ -147,11 +147,8 @@
var pp parser
defer func() {
- if e := recover(); e != nil {
- // resume same panic if it's not a bailout
- if _, ok := e.(bailout); !ok {
- panic(e)
- }
+ if pp.panicking {
+ recover()
}
// set result values
@@ -198,11 +195,8 @@
var p parser
defer func() {
- if e := recover(); e != nil {
- // resume same panic if it's not a bailout
- if _, ok := e.(bailout); !ok {
- panic(e)
- }
+ if p.panicking {
+ recover()
}
p.errors.Sort()
err = p.errors.Err()
diff --git a/cue/parser/parser.go b/cue/parser/parser.go
index 30b6114..2874049 100644
--- a/cue/parser/parser.go
+++ b/cue/parser/parser.go
@@ -33,9 +33,10 @@
scanner scanner.Scanner
// Tracing/debugging
- mode mode // parsing mode
- trace bool // == (mode & Trace != 0)
- indent int // indentation used for tracing output
+ mode mode // parsing mode
+ trace bool // == (mode & Trace != 0)
+ panicking bool // set if we are bailing out due to too many errors.
+ indent int // indentation used for tracing output
// Comments
leadComment *ast.CommentGroup
@@ -150,7 +151,9 @@
}
switch c.isList--; {
case c.isList < 0:
- panic("unmatched close list")
+ if !p.panicking {
+ panic("unmatched close list")
+ }
case c.isList == 0:
parent := c.parent
parent.groups = append(parent.groups, c.groups...)
@@ -161,7 +164,10 @@
func (c *commentState) closeNode(p *parser, n ast.Node) ast.Node {
if p.comments != c {
- panic("unmatched comments")
+ if !p.panicking {
+ panic("unmatched comments")
+ }
+ return n
}
p.comments = c.parent
if c.parent != nil {
@@ -336,9 +342,6 @@
}
}
-// A bailout panic is raised to indicate early termination.
-type bailout struct{}
-
func (p *parser) error(pos token.Pos, msg string) {
ePos := p.file.Position(pos)
@@ -351,7 +354,8 @@
return // discard - likely a spurious error
}
if n > 10 {
- panic(bailout{})
+ p.panicking = true
+ panic("too many errors")
}
}