mirror of https://github.com/golang/go.git
go/*: permit "for range x"
LGTM=rsc R=rsc CC=golang-codereviews https://golang.org/cl/112970044
This commit is contained in:
parent
81e661aa45
commit
d3a2f58700
|
|
@ -699,9 +699,9 @@ type (
|
||||||
// A RangeStmt represents a for statement with a range clause.
|
// A RangeStmt represents a for statement with a range clause.
|
||||||
RangeStmt struct {
|
RangeStmt struct {
|
||||||
For token.Pos // position of "for" keyword
|
For token.Pos // position of "for" keyword
|
||||||
Key, Value Expr // Value may be nil
|
Key, Value Expr // Key, Value may be nil
|
||||||
TokPos token.Pos // position of Tok
|
TokPos token.Pos // position of Tok; invalid if Key == nil
|
||||||
Tok token.Token // ASSIGN, DEFINE
|
Tok token.Token // ILLEGAL if Key == nil, ASSIGN, DEFINE
|
||||||
X Expr // value to range over
|
X Expr // value to range over
|
||||||
Body *BlockStmt
|
Body *BlockStmt
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -2041,7 +2041,16 @@ func (p *parser) parseForStmt() ast.Stmt {
|
||||||
prevLev := p.exprLev
|
prevLev := p.exprLev
|
||||||
p.exprLev = -1
|
p.exprLev = -1
|
||||||
if p.tok != token.SEMICOLON {
|
if p.tok != token.SEMICOLON {
|
||||||
s2, isRange = p.parseSimpleStmt(rangeOk)
|
if p.tok == token.RANGE {
|
||||||
|
// "for range x" (nil lhs in assignment)
|
||||||
|
pos := p.pos
|
||||||
|
p.next()
|
||||||
|
y := []ast.Expr{&ast.UnaryExpr{OpPos: pos, Op: token.RANGE, X: p.parseRhs()}}
|
||||||
|
s2 = &ast.AssignStmt{Rhs: y}
|
||||||
|
isRange = true
|
||||||
|
} else {
|
||||||
|
s2, isRange = p.parseSimpleStmt(rangeOk)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
if !isRange && p.tok == token.SEMICOLON {
|
if !isRange && p.tok == token.SEMICOLON {
|
||||||
p.next()
|
p.next()
|
||||||
|
|
@ -2066,12 +2075,14 @@ func (p *parser) parseForStmt() ast.Stmt {
|
||||||
// check lhs
|
// check lhs
|
||||||
var key, value ast.Expr
|
var key, value ast.Expr
|
||||||
switch len(as.Lhs) {
|
switch len(as.Lhs) {
|
||||||
case 2:
|
case 0:
|
||||||
key, value = as.Lhs[0], as.Lhs[1]
|
// nothing to do
|
||||||
case 1:
|
case 1:
|
||||||
key = as.Lhs[0]
|
key = as.Lhs[0]
|
||||||
|
case 2:
|
||||||
|
key, value = as.Lhs[0], as.Lhs[1]
|
||||||
default:
|
default:
|
||||||
p.errorExpected(as.Lhs[0].Pos(), "1 or 2 expressions")
|
p.errorExpected(as.Lhs[len(as.Lhs)-1].Pos(), "at most 2 expressions")
|
||||||
return &ast.BadStmt{From: pos, To: p.safePos(body.End())}
|
return &ast.BadStmt{From: pos, To: p.safePos(body.End())}
|
||||||
}
|
}
|
||||||
// parseSimpleStmt returned a right-hand side that
|
// parseSimpleStmt returned a right-hand side that
|
||||||
|
|
|
||||||
|
|
@ -38,6 +38,7 @@ var valids = []string{
|
||||||
`package p; func ((T),) m() {}`,
|
`package p; func ((T),) m() {}`,
|
||||||
`package p; func ((*T),) m() {}`,
|
`package p; func ((*T),) m() {}`,
|
||||||
`package p; func (*(T),) m() {}`,
|
`package p; func (*(T),) m() {}`,
|
||||||
|
`package p; func _(x []int) { for range x {} }`,
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestValid(t *testing.T) {
|
func TestValid(t *testing.T) {
|
||||||
|
|
|
||||||
|
|
@ -1216,14 +1216,17 @@ func (p *printer) stmt(stmt ast.Stmt, nextIsRBrace bool) {
|
||||||
|
|
||||||
case *ast.RangeStmt:
|
case *ast.RangeStmt:
|
||||||
p.print(token.FOR, blank)
|
p.print(token.FOR, blank)
|
||||||
p.expr(s.Key)
|
if s.Key != nil {
|
||||||
if s.Value != nil {
|
p.expr(s.Key)
|
||||||
// use position of value following the comma as
|
if s.Value != nil {
|
||||||
// comma position for correct comment placement
|
// use position of value following the comma as
|
||||||
p.print(s.Value.Pos(), token.COMMA, blank)
|
// comma position for correct comment placement
|
||||||
p.expr(s.Value)
|
p.print(s.Value.Pos(), token.COMMA, blank)
|
||||||
|
p.expr(s.Value)
|
||||||
|
}
|
||||||
|
p.print(blank, s.TokPos, s.Tok, blank)
|
||||||
}
|
}
|
||||||
p.print(blank, s.TokPos, s.Tok, blank, token.RANGE, blank)
|
p.print(token.RANGE, blank)
|
||||||
p.expr(stripParens(s.X))
|
p.expr(stripParens(s.X))
|
||||||
p.print(blank)
|
p.print(blank)
|
||||||
p.block(s.Body, 1)
|
p.block(s.Body, 1)
|
||||||
|
|
|
||||||
|
|
@ -309,6 +309,9 @@ func _() {
|
||||||
for x := expr; expr; expr = false {
|
for x := expr; expr; expr = false {
|
||||||
use(x)
|
use(x)
|
||||||
}
|
}
|
||||||
|
for range []int{} {
|
||||||
|
println("foo")
|
||||||
|
}
|
||||||
for x := range []int{} {
|
for x := range []int{} {
|
||||||
use(x)
|
use(x)
|
||||||
}
|
}
|
||||||
|
|
@ -338,6 +341,12 @@ func _() {
|
||||||
a[i] = i
|
a[i] = i
|
||||||
} // multiple lines
|
} // multiple lines
|
||||||
|
|
||||||
|
for range a {
|
||||||
|
}
|
||||||
|
for _ = range a {
|
||||||
|
}
|
||||||
|
for _, _ = range a {
|
||||||
|
}
|
||||||
for i := range a {
|
for i := range a {
|
||||||
}
|
}
|
||||||
for i := range a {
|
for i := range a {
|
||||||
|
|
|
||||||
|
|
@ -269,6 +269,8 @@ func _() {
|
||||||
for x := expr;expr;expr = false {
|
for x := expr;expr;expr = false {
|
||||||
use(x)
|
use(x)
|
||||||
}
|
}
|
||||||
|
for range []int{} {
|
||||||
|
println("foo")}
|
||||||
for x := range []int{} {
|
for x := range []int{} {
|
||||||
use(x) }
|
use(x) }
|
||||||
for x := range (([]int{})) {
|
for x := range (([]int{})) {
|
||||||
|
|
@ -289,6 +291,9 @@ func _() {
|
||||||
for i := 0; i < len(a); 1++ { a[i] = i
|
for i := 0; i < len(a); 1++ { a[i] = i
|
||||||
} // multiple lines
|
} // multiple lines
|
||||||
|
|
||||||
|
for range a{}
|
||||||
|
for _ = range a{}
|
||||||
|
for _, _ = range a{}
|
||||||
for i := range a {}
|
for i := range a {}
|
||||||
for i := range a { a[i] = i }
|
for i := range a { a[i] = i }
|
||||||
for i := range a { a[i] = i
|
for i := range a { a[i] = i
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue