summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorRobert Griesemer <gri@golang.org>2014-07-14 16:17:17 -0700
committerRobert Griesemer <gri@golang.org>2014-07-14 16:17:17 -0700
commit97d0820437c00773f24748d8221974add217a848 (patch)
treec11a3f2891d98acdb4e5bbf54c7ac9a647bdff0c /src
parent10069c9f29881402850a9583b2c0552218097396 (diff)
downloadgo-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.go6
-rw-r--r--src/pkg/go/parser/parser.go19
-rw-r--r--src/pkg/go/parser/short_test.go1
-rw-r--r--src/pkg/go/printer/nodes.go19
-rw-r--r--src/pkg/go/printer/testdata/statements.golden9
-rw-r--r--src/pkg/go/printer/testdata/statements.input5
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