diff options
author | Robert Griesemer <gri@golang.org> | 2014-07-14 16:17:17 -0700 |
---|---|---|
committer | Robert Griesemer <gri@golang.org> | 2014-07-14 16:17:17 -0700 |
commit | 97d0820437c00773f24748d8221974add217a848 (patch) | |
tree | c11a3f2891d98acdb4e5bbf54c7ac9a647bdff0c /src | |
parent | 10069c9f29881402850a9583b2c0552218097396 (diff) | |
download | go-97d0820437c00773f24748d8221974add217a848.tar.gz |
go/*: permit "for range x"
LGTM=rsc
R=rsc
CC=golang-codereviews
https://codereview.appspot.com/112970044
Diffstat (limited to 'src')
-rw-r--r-- | src/pkg/go/ast/ast.go | 6 | ||||
-rw-r--r-- | src/pkg/go/parser/parser.go | 19 | ||||
-rw-r--r-- | src/pkg/go/parser/short_test.go | 1 | ||||
-rw-r--r-- | src/pkg/go/printer/nodes.go | 19 | ||||
-rw-r--r-- | src/pkg/go/printer/testdata/statements.golden | 9 | ||||
-rw-r--r-- | src/pkg/go/printer/testdata/statements.input | 5 |
6 files changed, 44 insertions, 15 deletions
diff --git a/src/pkg/go/ast/ast.go b/src/pkg/go/ast/ast.go index 6e635cd01..312e3d1b9 100644 --- a/src/pkg/go/ast/ast.go +++ b/src/pkg/go/ast/ast.go @@ -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 } diff --git a/src/pkg/go/parser/parser.go b/src/pkg/go/parser/parser.go index d16ba4cef..8291f3f42 100644 --- a/src/pkg/go/parser/parser.go +++ b/src/pkg/go/parser/parser.go @@ -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 diff --git a/src/pkg/go/parser/short_test.go b/src/pkg/go/parser/short_test.go index 9b8ac4471..8a3c33868 100644 --- a/src/pkg/go/parser/short_test.go +++ b/src/pkg/go/parser/short_test.go @@ -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) { diff --git a/src/pkg/go/printer/nodes.go b/src/pkg/go/printer/nodes.go index 04b5f1a76..6e26f9a63 100644 --- a/src/pkg/go/printer/nodes.go +++ b/src/pkg/go/printer/nodes.go @@ -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) diff --git a/src/pkg/go/printer/testdata/statements.golden b/src/pkg/go/printer/testdata/statements.golden index 3b298f95e..324b6cdd0 100644 --- a/src/pkg/go/printer/testdata/statements.golden +++ b/src/pkg/go/printer/testdata/statements.golden @@ -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 { diff --git a/src/pkg/go/printer/testdata/statements.input b/src/pkg/go/printer/testdata/statements.input index e7fcc0e54..cade1576b 100644 --- a/src/pkg/go/printer/testdata/statements.input +++ b/src/pkg/go/printer/testdata/statements.input @@ -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 |