diff options
author | Robert Griesemer <gri@golang.org> | 2018-01-11 15:09:38 -0800 |
---|---|---|
committer | Robert Griesemer <gri@golang.org> | 2018-02-12 21:43:15 +0000 |
commit | c5f3a8b10797258cf527601a44bfdfa63d5ef1a7 (patch) | |
tree | 2cd37d7de773f0b981e9e0629cea88bd2f127abe /src/go/parser/parser.go | |
parent | 29461ccc7f7b6a73bc0104731cfbe0c2cbe86733 (diff) | |
download | go-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.go | 90 |
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) { |