]> Cypherpunks repositories - gostls13.git/commitdiff
go/*: permit "for range x"
authorRobert Griesemer <gri@golang.org>
Mon, 14 Jul 2014 23:17:17 +0000 (16:17 -0700)
committerRobert Griesemer <gri@golang.org>
Mon, 14 Jul 2014 23:17:17 +0000 (16:17 -0700)
LGTM=rsc
R=rsc
CC=golang-codereviews
https://golang.org/cl/112970044

src/pkg/go/ast/ast.go
src/pkg/go/parser/parser.go
src/pkg/go/parser/short_test.go
src/pkg/go/printer/nodes.go
src/pkg/go/printer/testdata/statements.golden
src/pkg/go/printer/testdata/statements.input

index 6e635cd0166962670fe7317674a67c53a4d3a596..312e3d1b9890e788c844048bbfc5f0a5568ddeb7 100644 (file)
@@ -699,9 +699,9 @@ type (
        // A RangeStmt represents a for statement with a range clause.
        RangeStmt struct {
                For        token.Pos   // position of "for" keyword
-               Key, Value Expr        // Value may be nil
-               TokPos     token.Pos   // position of Tok
-               Tok        token.Token // ASSIGN, DEFINE
+               Key, Value Expr        // Key, Value may be nil
+               TokPos     token.Pos   // position of Tok; invalid if Key == nil
+               Tok        token.Token // ILLEGAL if Key == nil, ASSIGN, DEFINE
                X          Expr        // value to range over
                Body       *BlockStmt
        }
index d16ba4cef36b065c9c180dd3289a8a9233319f2f..8291f3f42dff36e7f5988a68e5d06460fe49547b 100644 (file)
@@ -2041,7 +2041,16 @@ func (p *parser) parseForStmt() ast.Stmt {
                prevLev := p.exprLev
                p.exprLev = -1
                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 {
                        p.next()
@@ -2066,12 +2075,14 @@ func (p *parser) parseForStmt() ast.Stmt {
                // check lhs
                var key, value ast.Expr
                switch len(as.Lhs) {
-               case 2:
-                       key, value = as.Lhs[0], as.Lhs[1]
+               case 0:
+                       // nothing to do
                case 1:
                        key = as.Lhs[0]
+               case 2:
+                       key, value = as.Lhs[0], as.Lhs[1]
                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())}
                }
                // parseSimpleStmt returned a right-hand side that
index 9b8ac44717376a5adf91f150d085ef0daf7205e4..8a3c33868b71fb4979f9dabe77aabf27a89821e1 100644 (file)
@@ -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 _(x []int) { for range x {} }`,
 }
 
 func TestValid(t *testing.T) {
index 04b5f1a76a93eb1c7b9e09489e6646666776fd3b..6e26f9a636fc5d1adc94094f5c5dc699dc7665cf 100644 (file)
@@ -1216,14 +1216,17 @@ func (p *printer) stmt(stmt ast.Stmt, nextIsRBrace bool) {
 
        case *ast.RangeStmt:
                p.print(token.FOR, blank)
-               p.expr(s.Key)
-               if s.Value != nil {
-                       // use position of value following the comma as
-                       // comma position for correct comment placement
-                       p.print(s.Value.Pos(), token.COMMA, blank)
-                       p.expr(s.Value)
-               }
-               p.print(blank, s.TokPos, s.Tok, blank, token.RANGE, blank)
+               if s.Key != nil {
+                       p.expr(s.Key)
+                       if s.Value != nil {
+                               // use position of value following the comma as
+                               // comma position for correct comment placement
+                               p.print(s.Value.Pos(), token.COMMA, blank)
+                               p.expr(s.Value)
+                       }
+                       p.print(blank, s.TokPos, s.Tok, blank)
+               }
+               p.print(token.RANGE, blank)
                p.expr(stripParens(s.X))
                p.print(blank)
                p.block(s.Body, 1)
index 3b298f95ef1afe111977de90b1d8cdb37290d46e..324b6cdd0f4dbcc94c2efc16a462f4a2e012e9ee 100644 (file)
@@ -309,6 +309,9 @@ func _() {
        for x := expr; expr; expr = false {
                use(x)
        }
+       for range []int{} {
+               println("foo")
+       }
        for x := range []int{} {
                use(x)
        }
@@ -338,6 +341,12 @@ func _() {
                a[i] = i
        }       // multiple lines
 
+       for range a {
+       }
+       for _ = range a {
+       }
+       for _, _ = range a {
+       }
        for i := range a {
        }
        for i := range a {
index e7fcc0e5409927f48d5b6f4d079cd539bdfd651e..cade1576bf7845852c9b8e45eab0203ec6587e3e 100644 (file)
@@ -269,6 +269,8 @@ func _() {
        for x := expr;expr;expr = false {
        use(x)
        }
+       for range []int{} {
+       println("foo")}
        for x := range []int{} {
        use(x) }
        for x := range (([]int{})) {
@@ -289,6 +291,9 @@ func _() {
        for i := 0; i < len(a); 1++ { a[i] = i
        } // multiple lines
 
+       for range a{}
+       for _ = range a{}
+       for _, _ = range a{}
        for i := range a {}
        for i := range a { a[i] = i }
        for i := range a { a[i] = i