Commit 23c16cf2 authored by Robert Griesemer's avatar Robert Griesemer

go/ast, parser: condition in if statement is mandatory

As a result, parsing a "control clause" is now sufficiently
different for if, switch, and for statements that the code
is not factored out anymore. The code is a bit longer but
clearer in each individual case.

Reflect the changes in AST.

R=r, r2
CC=golang-dev
https://golang.org/cl/4173075
parent a1368a6a
......@@ -597,7 +597,7 @@ type (
IfStmt struct {
If token.Pos // position of "if" keyword
Init Stmt // initalization statement; or nil
Cond Expr // condition; or nil
Cond Expr // condition
Body *BlockStmt
Else Stmt // else branch; or nil
}
......
......@@ -227,9 +227,7 @@ func Walk(v Visitor, node Node) {
if n.Init != nil {
Walk(v, n.Init)
}
if n.Cond != nil {
Walk(v, n.Cond)
}
Walk(v, n.Cond)
Walk(v, n.Body)
if n.Else != nil {
Walk(v, n.Else)
......
......@@ -1327,44 +1327,29 @@ func (p *parser) makeExpr(s ast.Stmt) ast.Expr {
}
func (p *parser) parseControlClause(isForStmt bool) (s1, s2, s3 ast.Stmt) {
if p.tok != token.LBRACE {
func (p *parser) parseIfStmt() *ast.IfStmt {
if p.trace {
defer un(trace(p, "IfStmt"))
}
pos := p.expect(token.IF)
var s ast.Stmt
var x ast.Expr
{
prevLev := p.exprLev
p.exprLev = -1
if p.tok != token.SEMICOLON {
s1 = p.parseSimpleStmt(false)
}
s = p.parseSimpleStmt(false)
if p.tok == token.SEMICOLON {
p.next()
if p.tok != token.LBRACE && p.tok != token.SEMICOLON {
s2 = p.parseSimpleStmt(false)
}
if isForStmt {
// for statements have a 3rd section
p.expectSemi()
if p.tok != token.LBRACE {
s3 = p.parseSimpleStmt(false)
}
}
x = p.parseExpr()
} else {
s1, s2 = nil, s1
x = p.makeExpr(s)
s = nil
}
p.exprLev = prevLev
}
return s1, s2, s3
}
func (p *parser) parseIfStmt() *ast.IfStmt {
if p.trace {
defer un(trace(p, "IfStmt"))
}
pos := p.expect(token.IF)
s1, s2, _ := p.parseControlClause(false)
body := p.parseBlockStmt()
var else_ ast.Stmt
if p.tok == token.ELSE {
......@@ -1374,7 +1359,7 @@ func (p *parser) parseIfStmt() *ast.IfStmt {
p.expectSemi()
}
return &ast.IfStmt{pos, s1, p.makeExpr(s2), body, else_}
return &ast.IfStmt{pos, s, x, body, else_}
}
......@@ -1457,7 +1442,22 @@ func (p *parser) parseSwitchStmt() ast.Stmt {
}
pos := p.expect(token.SWITCH)
s1, s2, _ := p.parseControlClause(false)
var s1, s2 ast.Stmt
if p.tok != token.LBRACE {
prevLev := p.exprLev
p.exprLev = -1
s2 = p.parseSimpleStmt(false)
if p.tok == token.SEMICOLON {
p.next()
s1 = s2
s2 = nil
if p.tok != token.LBRACE {
s2 = p.parseSimpleStmt(false)
}
}
p.exprLev = prevLev
}
if isExprSwitch(s2) {
lbrace := p.expect(token.LBRACE)
......@@ -1575,7 +1575,31 @@ func (p *parser) parseForStmt() ast.Stmt {
}
pos := p.expect(token.FOR)
s1, s2, s3 := p.parseControlClause(true)
var s1, s2, s3 ast.Stmt
if p.tok != token.LBRACE {
prevLev := p.exprLev
p.exprLev = -1
if p.tok != token.SEMICOLON {
s2 = p.parseSimpleStmt(false)
}
if p.tok == token.SEMICOLON {
p.next()
s1 = s2
s2 = nil
if p.tok != token.SEMICOLON {
s2 = p.parseSimpleStmt(false)
}
p.expectSemi()
if p.tok != token.LBRACE {
s3 = p.parseSimpleStmt(false)
}
}
p.exprLev = prevLev
}
body := p.parseBlockStmt()
p.expectSemi()
......
......@@ -18,6 +18,7 @@ var illegalInputs = []interface{}{
3.14,
[]byte(nil),
"foo!",
`package p; func f() { if /* should have condition */ {} };`,
}
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment