aboutsummaryrefslogtreecommitdiff
path: root/src/go/parser/parser.go
diff options
context:
space:
mode:
authorRobert Griesemer <gri@golang.org>2018-01-11 15:09:38 -0800
committerRobert Griesemer <gri@golang.org>2018-02-12 21:43:15 +0000
commitc5f3a8b10797258cf527601a44bfdfa63d5ef1a7 (patch)
tree2cd37d7de773f0b981e9e0629cea88bd2f127abe /src/go/parser/parser.go
parent29461ccc7f7b6a73bc0104731cfbe0c2cbe86733 (diff)
downloadgo-c5f3a8b10797258cf527601a44bfdfa63d5ef1a7.tar.gz
go-c5f3a8b10797258cf527601a44bfdfa63d5ef1a7.zip
go/parser: more robust error handling for 'if' headers
R=go1.11 To fix this, this CL borrows code from the new syntax package which has a better tuned parser at this point. Fixes #11377. Change-Id: Ib9212c945903d6f62abcc59ef5a5767d4ef36981 Reviewed-on: https://go-review.googlesource.com/87495 Reviewed-by: Matthew Dempsky <mdempsky@google.com>
Diffstat (limited to 'src/go/parser/parser.go')
-rw-r--r--src/go/parser/parser.go90
1 files changed, 66 insertions, 24 deletions
diff --git a/src/go/parser/parser.go b/src/go/parser/parser.go
index 2b58724521..88a5eb67d2 100644
--- a/src/go/parser/parser.go
+++ b/src/go/parser/parser.go
@@ -1808,48 +1808,90 @@ func (p *parser) parseBranchStmt(tok token.Token) *ast.BranchStmt {
return &ast.BranchStmt{TokPos: pos, Tok: tok, Label: label}
}
-func (p *parser) makeExpr(s ast.Stmt, kind string) ast.Expr {
+func (p *parser) makeExpr(s ast.Stmt, want string) ast.Expr {
if s == nil {
return nil
}
if es, isExpr := s.(*ast.ExprStmt); isExpr {
return p.checkExpr(es.X)
}
- p.error(s.Pos(), fmt.Sprintf("expected %s, found simple statement (missing parentheses around composite literal?)", kind))
+ found := "simple statement"
+ if _, isAss := s.(*ast.AssignStmt); isAss {
+ found = "assignment"
+ }
+ p.error(s.Pos(), fmt.Sprintf("expected %s, found %s (missing parentheses around composite literal?)", want, found))
return &ast.BadExpr{From: s.Pos(), To: p.safePos(s.End())}
}
-func (p *parser) parseIfStmt() *ast.IfStmt {
- if p.trace {
- defer un(trace(p, "IfStmt"))
+// parseIfHeader is an adjusted version of parser.header
+// in cmd/compile/internal/syntax/parser.go, which has
+// been tuned for better error handling.
+func (p *parser) parseIfHeader() (init ast.Stmt, cond ast.Expr) {
+ if p.tok == token.LBRACE {
+ p.error(p.pos, "missing condition in if statement")
+ return
}
+ // p.tok != token.LBRACE
- pos := p.expect(token.IF)
- p.openScope()
- defer p.closeScope()
+ outer := p.exprLev
+ p.exprLev = -1
- var s ast.Stmt
- var x ast.Expr
- {
- prevLev := p.exprLev
- p.exprLev = -1
+ if p.tok != token.SEMICOLON {
+ // accept potential variable declaration but complain
+ if p.tok == token.VAR {
+ p.next()
+ p.error(p.pos, fmt.Sprintf("var declaration not allowed in 'IF' initializer"))
+ }
+ init, _ = p.parseSimpleStmt(basic)
+ }
+
+ var condStmt ast.Stmt
+ var semi struct {
+ pos token.Pos
+ lit string // ";" or "\n"; valid if pos.IsValid()
+ }
+ if p.tok != token.LBRACE {
if p.tok == token.SEMICOLON {
+ semi.pos = p.pos
+ semi.lit = p.lit
p.next()
- x = p.parseRhs()
} else {
- s, _ = p.parseSimpleStmt(basic)
- if p.tok == token.SEMICOLON {
- p.next()
- x = p.parseRhs()
- } else {
- x = p.makeExpr(s, "boolean expression")
- s = nil
- }
+ p.expect(token.SEMICOLON)
}
- p.exprLev = prevLev
+ if p.tok != token.LBRACE {
+ condStmt, _ = p.parseSimpleStmt(basic)
+ }
+ } else {
+ condStmt = init
+ init = nil
+ }
+
+ if condStmt != nil {
+ cond = p.makeExpr(condStmt, "boolean expression")
+ } else if semi.pos.IsValid() {
+ if semi.lit == "\n" {
+ p.error(semi.pos, "unexpected newline, expecting { after if clause")
+ } else {
+ p.error(semi.pos, "missing condition in if statement")
+ }
+ }
+
+ p.exprLev = outer
+ return
+}
+
+func (p *parser) parseIfStmt() *ast.IfStmt {
+ if p.trace {
+ defer un(trace(p, "IfStmt"))
}
+ pos := p.expect(token.IF)
+ p.openScope()
+ defer p.closeScope()
+
+ init, cond := p.parseIfHeader()
body := p.parseBlockStmt()
+
var else_ ast.Stmt
if p.tok == token.ELSE {
p.next()
@@ -1867,7 +1909,7 @@ func (p *parser) parseIfStmt() *ast.IfStmt {
p.expectSemi()
}
- return &ast.IfStmt{If: pos, Init: s, Cond: x, Body: body, Else: else_}
+ return &ast.IfStmt{If: pos, Init: init, Cond: cond, Body: body, Else: else_}
}
func (p *parser) parseTypeList() (list []ast.Expr) {