mirror of https://github.com/golang/go.git
cmd/gc: implement 'for range x {'
Fixes #6102. LGTM=gri R=ken, r, gri CC=golang-codereviews https://golang.org/cl/113120043
This commit is contained in:
parent
26d0f75f2b
commit
8d504c4e97
|
|
@ -495,7 +495,7 @@ esc(EscState *e, Node *n, Node *up)
|
||||||
|
|
||||||
case ORANGE:
|
case ORANGE:
|
||||||
// Everything but fixed array is a dereference.
|
// Everything but fixed array is a dereference.
|
||||||
if(isfixedarray(n->type) && n->list->next)
|
if(isfixedarray(n->type) && n->list && n->list->next)
|
||||||
escassign(e, n->list->next->n, n->right);
|
escassign(e, n->list->next->n, n->right);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -880,7 +880,11 @@ stmtfmt(Fmt *f, Node *n)
|
||||||
fmtstrcpy(f, "for loop");
|
fmtstrcpy(f, "for loop");
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if(n->list == nil) {
|
||||||
|
fmtprint(f, "for range %N { %H }", n->right, n->nbody);
|
||||||
|
break;
|
||||||
|
}
|
||||||
fmtprint(f, "for %,H = range %N { %H }", n->list, n->right, n->nbody);
|
fmtprint(f, "for %,H = range %N { %H }", n->list, n->right, n->nbody);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -613,6 +613,11 @@ range_stmt:
|
||||||
$$->colas = 1;
|
$$->colas = 1;
|
||||||
colasdefn($1, $$);
|
colasdefn($1, $$);
|
||||||
}
|
}
|
||||||
|
| LRANGE expr
|
||||||
|
{
|
||||||
|
$$ = nod(ORANGE, N, $2);
|
||||||
|
$$->etype = 0; // := flag
|
||||||
|
}
|
||||||
|
|
||||||
for_header:
|
for_header:
|
||||||
osimple_stmt ';' osimple_stmt ';' osimple_stmt
|
osimple_stmt ';' osimple_stmt ';' osimple_stmt
|
||||||
|
|
|
||||||
|
|
@ -67,9 +67,11 @@ typecheckrange(Node *n)
|
||||||
yyerror("too many variables in range");
|
yyerror("too many variables in range");
|
||||||
}
|
}
|
||||||
|
|
||||||
v1 = n->list->n;
|
v1 = N;
|
||||||
|
if(n->list)
|
||||||
|
v1 = n->list->n;
|
||||||
v2 = N;
|
v2 = N;
|
||||||
if(n->list->next)
|
if(n->list && n->list->next)
|
||||||
v2 = n->list->next->n;
|
v2 = n->list->next->n;
|
||||||
|
|
||||||
// this is not only a optimization but also a requirement in the spec.
|
// this is not only a optimization but also a requirement in the spec.
|
||||||
|
|
@ -77,14 +79,17 @@ typecheckrange(Node *n)
|
||||||
// clause is equivalent to the same clause with only the first variable
|
// clause is equivalent to the same clause with only the first variable
|
||||||
// present."
|
// present."
|
||||||
if(isblank(v2)) {
|
if(isblank(v2)) {
|
||||||
n->list = list1(v1);
|
if(v1 != N)
|
||||||
|
n->list = list1(v1);
|
||||||
v2 = N;
|
v2 = N;
|
||||||
}
|
}
|
||||||
|
|
||||||
if(v1->defn == n)
|
if(v1) {
|
||||||
v1->type = t1;
|
if(v1->defn == n)
|
||||||
else if(v1->type != T && assignop(t1, v1->type, &why) == 0)
|
v1->type = t1;
|
||||||
yyerror("cannot assign type %T to %lN in range%s", t1, v1, why);
|
else if(v1->type != T && assignop(t1, v1->type, &why) == 0)
|
||||||
|
yyerror("cannot assign type %T to %lN in range%s", t1, v1, why);
|
||||||
|
}
|
||||||
if(v2) {
|
if(v2) {
|
||||||
if(v2->defn == n)
|
if(v2->defn == n)
|
||||||
v2->type = t2;
|
v2->type = t2;
|
||||||
|
|
@ -123,9 +128,11 @@ walkrange(Node *n)
|
||||||
a = n->right;
|
a = n->right;
|
||||||
lno = setlineno(a);
|
lno = setlineno(a);
|
||||||
|
|
||||||
v1 = n->list->n;
|
v1 = N;
|
||||||
|
if(n->list)
|
||||||
|
v1 = n->list->n;
|
||||||
v2 = N;
|
v2 = N;
|
||||||
if(n->list->next && !isblank(n->list->next->n))
|
if(n->list && n->list->next && !isblank(n->list->next->n))
|
||||||
v2 = n->list->next->n;
|
v2 = n->list->next->n;
|
||||||
// n->list has no meaning anymore, clear it
|
// n->list has no meaning anymore, clear it
|
||||||
// to avoid erroneous processing by racewalk.
|
// to avoid erroneous processing by racewalk.
|
||||||
|
|
@ -154,7 +161,9 @@ walkrange(Node *n)
|
||||||
|
|
||||||
n->ntest = nod(OLT, hv1, hn);
|
n->ntest = nod(OLT, hv1, hn);
|
||||||
n->nincr = nod(OAS, hv1, nod(OADD, hv1, nodintconst(1)));
|
n->nincr = nod(OAS, hv1, nod(OADD, hv1, nodintconst(1)));
|
||||||
if(v2 == N)
|
if(v1 == N)
|
||||||
|
body = nil;
|
||||||
|
else if(v2 == N)
|
||||||
body = list1(nod(OAS, v1, hv1));
|
body = list1(nod(OAS, v1, hv1));
|
||||||
else {
|
else {
|
||||||
a = nod(OAS2, N, N);
|
a = nod(OAS2, N, N);
|
||||||
|
|
@ -205,16 +214,18 @@ walkrange(Node *n)
|
||||||
|
|
||||||
key = nod(ODOT, hit, keyname);
|
key = nod(ODOT, hit, keyname);
|
||||||
key = nod(OIND, key, N);
|
key = nod(OIND, key, N);
|
||||||
if(v2 == N) {
|
if(v1 == N)
|
||||||
a = nod(OAS, v1, key);
|
body = nil;
|
||||||
|
else if(v2 == N) {
|
||||||
|
body = list1(nod(OAS, v1, key));
|
||||||
} else {
|
} else {
|
||||||
val = nod(ODOT, hit, valname);
|
val = nod(ODOT, hit, valname);
|
||||||
val = nod(OIND, val, N);
|
val = nod(OIND, val, N);
|
||||||
a = nod(OAS2, N, N);
|
a = nod(OAS2, N, N);
|
||||||
a->list = list(list1(v1), v2);
|
a->list = list(list1(v1), v2);
|
||||||
a->rlist = list(list1(key), val);
|
a->rlist = list(list1(key), val);
|
||||||
|
body = list1(a);
|
||||||
}
|
}
|
||||||
body = list1(a);
|
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case TCHAN:
|
case TCHAN:
|
||||||
|
|
@ -223,6 +234,7 @@ walkrange(Node *n)
|
||||||
n->ntest = N;
|
n->ntest = N;
|
||||||
|
|
||||||
hv1 = temp(t->type);
|
hv1 = temp(t->type);
|
||||||
|
hv1->typecheck = 1;
|
||||||
if(haspointers(t->type))
|
if(haspointers(t->type))
|
||||||
init = list(init, nod(OAS, hv1, N));
|
init = list(init, nod(OAS, hv1, N));
|
||||||
hb = temp(types[TBOOL]);
|
hb = temp(types[TBOOL]);
|
||||||
|
|
@ -233,7 +245,10 @@ walkrange(Node *n)
|
||||||
a->list = list(list1(hv1), hb);
|
a->list = list(list1(hv1), hb);
|
||||||
a->rlist = list1(nod(ORECV, ha, N));
|
a->rlist = list1(nod(ORECV, ha, N));
|
||||||
n->ntest->ninit = list1(a);
|
n->ntest->ninit = list1(a);
|
||||||
body = list1(nod(OAS, v1, hv1));
|
if(v1 == N)
|
||||||
|
body = nil;
|
||||||
|
else
|
||||||
|
body = list1(nod(OAS, v1, hv1));
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case TSTRING:
|
case TSTRING:
|
||||||
|
|
@ -257,7 +272,10 @@ walkrange(Node *n)
|
||||||
n->ntest = nod(ONE, hv1, nodintconst(0));
|
n->ntest = nod(ONE, hv1, nodintconst(0));
|
||||||
n->ntest->ninit = list(list1(nod(OAS, ohv1, hv1)), a);
|
n->ntest->ninit = list(list1(nod(OAS, ohv1, hv1)), a);
|
||||||
|
|
||||||
body = list1(nod(OAS, v1, ohv1));
|
|
||||||
|
body = nil;
|
||||||
|
if(v1 != N)
|
||||||
|
body = list1(nod(OAS, v1, ohv1));
|
||||||
if(v2 != N)
|
if(v2 != N)
|
||||||
body = list(body, nod(OAS, v2, hv2));
|
body = list(body, nod(OAS, v2, hv2));
|
||||||
break;
|
break;
|
||||||
|
|
|
||||||
2682
src/cmd/gc/y.tab.c
2682
src/cmd/gc/y.tab.c
File diff suppressed because it is too large
Load Diff
|
|
@ -20,16 +20,16 @@ static struct {
|
||||||
{32, ';',
|
{32, ';',
|
||||||
"missing import path; require quoted string"},
|
"missing import path; require quoted string"},
|
||||||
|
|
||||||
{378, ';',
|
{380, ';',
|
||||||
"missing { after if clause"},
|
"missing { after if clause"},
|
||||||
|
|
||||||
{399, ';',
|
{401, ';',
|
||||||
"missing { after switch clause"},
|
"missing { after switch clause"},
|
||||||
|
|
||||||
{238, ';',
|
{239, ';',
|
||||||
"missing { after for clause"},
|
"missing { after for clause"},
|
||||||
|
|
||||||
{476, LBODY,
|
{478, LBODY,
|
||||||
"missing { after for clause"},
|
"missing { after for clause"},
|
||||||
|
|
||||||
{22, '{',
|
{22, '{',
|
||||||
|
|
@ -47,33 +47,33 @@ static struct {
|
||||||
{37, ',',
|
{37, ',',
|
||||||
"unexpected comma in channel type"},
|
"unexpected comma in channel type"},
|
||||||
|
|
||||||
{439, LELSE,
|
{441, LELSE,
|
||||||
"unexpected semicolon or newline before else"},
|
"unexpected semicolon or newline before else"},
|
||||||
|
|
||||||
{258, ',',
|
{259, ',',
|
||||||
"name list not allowed in interface type"},
|
"name list not allowed in interface type"},
|
||||||
|
|
||||||
{238, LVAR,
|
{239, LVAR,
|
||||||
"var declaration not allowed in for initializer"},
|
"var declaration not allowed in for initializer"},
|
||||||
|
|
||||||
{65, '{',
|
{65, '{',
|
||||||
"unexpected { at end of statement"},
|
"unexpected { at end of statement"},
|
||||||
|
|
||||||
{377, '{',
|
{379, '{',
|
||||||
"unexpected { at end of statement"},
|
"unexpected { at end of statement"},
|
||||||
|
|
||||||
{126, ';',
|
{126, ';',
|
||||||
"argument to go/defer must be function call"},
|
"argument to go/defer must be function call"},
|
||||||
|
|
||||||
{426, ';',
|
{428, ';',
|
||||||
"need trailing comma before newline in composite literal"},
|
"need trailing comma before newline in composite literal"},
|
||||||
|
|
||||||
{437, ';',
|
{439, ';',
|
||||||
"need trailing comma before newline in composite literal"},
|
"need trailing comma before newline in composite literal"},
|
||||||
|
|
||||||
{113, LNAME,
|
{113, LNAME,
|
||||||
"nested func not allowed"},
|
"nested func not allowed"},
|
||||||
|
|
||||||
{645, ';',
|
{647, ';',
|
||||||
"else must be followed by if or statement block"}
|
"else must be followed by if or statement block"}
|
||||||
};
|
};
|
||||||
|
|
|
||||||
|
|
@ -123,7 +123,7 @@ func pallmall(cols []int) {
|
||||||
fmt.Println(msg)
|
fmt.Println(msg)
|
||||||
tot := 0
|
tot := 0
|
||||||
// wait for all results
|
// wait for all results
|
||||||
for _ = range cols {
|
for range cols {
|
||||||
result := <-ended
|
result := <-ended
|
||||||
tot += result.met
|
tot += result.met
|
||||||
fmt.Printf("%v%v\n", result.met, spell(result.same, true))
|
fmt.Printf("%v%v\n", result.met, spell(result.same, true))
|
||||||
|
|
|
||||||
|
|
@ -56,6 +56,9 @@ func main() {
|
||||||
for _ = range cs {// ERROR "receive"
|
for _ = range cs {// ERROR "receive"
|
||||||
}
|
}
|
||||||
|
|
||||||
|
for range cs {// ERROR "receive"
|
||||||
|
}
|
||||||
|
|
||||||
close(c)
|
close(c)
|
||||||
close(cs)
|
close(cs)
|
||||||
close(cr) // ERROR "receive"
|
close(cr) // ERROR "receive"
|
||||||
|
|
|
||||||
|
|
@ -18,4 +18,6 @@ func main() {
|
||||||
}
|
}
|
||||||
for _ = range t {
|
for _ = range t {
|
||||||
}
|
}
|
||||||
|
for range t {
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -14,6 +14,8 @@ type matrix struct {
|
||||||
func (a matrix) equal() bool {
|
func (a matrix) equal() bool {
|
||||||
for _ = range a.e {
|
for _ = range a.e {
|
||||||
}
|
}
|
||||||
|
for range a.e {
|
||||||
|
}
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -32,6 +32,13 @@ func testchan() {
|
||||||
println("Wanted lowercase alphabet; got", s)
|
println("Wanted lowercase alphabet; got", s)
|
||||||
panic("fail")
|
panic("fail")
|
||||||
}
|
}
|
||||||
|
n := 0
|
||||||
|
for range seq('a', 'z') {
|
||||||
|
n++
|
||||||
|
}
|
||||||
|
if n != 26 {
|
||||||
|
println("testchan wrong count", n, "want 26")
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// test that range over slice only evaluates
|
// test that range over slice only evaluates
|
||||||
|
|
@ -87,6 +94,22 @@ func testslice1() {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func testslice2() {
|
||||||
|
n := 0
|
||||||
|
nmake = 0
|
||||||
|
for range makeslice() {
|
||||||
|
n++
|
||||||
|
}
|
||||||
|
if nmake != 1 {
|
||||||
|
println("range called makeslice", nmake, "times")
|
||||||
|
panic("fail")
|
||||||
|
}
|
||||||
|
if n != 5 {
|
||||||
|
println("wrong count ranging over makeslice", n)
|
||||||
|
panic("fail")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// test that range over array only evaluates
|
// test that range over array only evaluates
|
||||||
// the expression after "range" once.
|
// the expression after "range" once.
|
||||||
|
|
||||||
|
|
@ -127,6 +150,22 @@ func testarray1() {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func testarray2() {
|
||||||
|
n := 0
|
||||||
|
nmake = 0
|
||||||
|
for range makearray() {
|
||||||
|
n++
|
||||||
|
}
|
||||||
|
if nmake != 1 {
|
||||||
|
println("range called makearray", nmake, "times")
|
||||||
|
panic("fail")
|
||||||
|
}
|
||||||
|
if n != 5 {
|
||||||
|
println("wrong count ranging over makearray", n)
|
||||||
|
panic("fail")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
func makearrayptr() *[5]int {
|
func makearrayptr() *[5]int {
|
||||||
nmake++
|
nmake++
|
||||||
return &[5]int{1, 2, 3, 4, 5}
|
return &[5]int{1, 2, 3, 4, 5}
|
||||||
|
|
@ -176,6 +215,22 @@ func testarrayptr1() {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func testarrayptr2() {
|
||||||
|
n := 0
|
||||||
|
nmake = 0
|
||||||
|
for range makearrayptr() {
|
||||||
|
n++
|
||||||
|
}
|
||||||
|
if nmake != 1 {
|
||||||
|
println("range called makearrayptr", nmake, "times")
|
||||||
|
panic("fail")
|
||||||
|
}
|
||||||
|
if n != 5 {
|
||||||
|
println("wrong count ranging over makearrayptr", n)
|
||||||
|
panic("fail")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// test that range over string only evaluates
|
// test that range over string only evaluates
|
||||||
// the expression after "range" once.
|
// the expression after "range" once.
|
||||||
|
|
||||||
|
|
@ -216,6 +271,22 @@ func teststring1() {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func teststring2() {
|
||||||
|
n := 0
|
||||||
|
nmake = 0
|
||||||
|
for range makestring() {
|
||||||
|
n++
|
||||||
|
}
|
||||||
|
if nmake != 1 {
|
||||||
|
println("range called makestring", nmake, "times")
|
||||||
|
panic("fail")
|
||||||
|
}
|
||||||
|
if n != 5 {
|
||||||
|
println("wrong count ranging over makestring", n)
|
||||||
|
panic("fail")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// test that range over map only evaluates
|
// test that range over map only evaluates
|
||||||
// the expression after "range" once.
|
// the expression after "range" once.
|
||||||
|
|
||||||
|
|
@ -256,6 +327,22 @@ func testmap1() {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func testmap2() {
|
||||||
|
n := 0
|
||||||
|
nmake = 0
|
||||||
|
for range makemap() {
|
||||||
|
n++
|
||||||
|
}
|
||||||
|
if nmake != 1 {
|
||||||
|
println("range called makemap", nmake, "times")
|
||||||
|
panic("fail")
|
||||||
|
}
|
||||||
|
if n != 5 {
|
||||||
|
println("wrong count ranging over makemap", n)
|
||||||
|
panic("fail")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// test that range evaluates the index and value expressions
|
// test that range evaluates the index and value expressions
|
||||||
// exactly once per iteration.
|
// exactly once per iteration.
|
||||||
|
|
||||||
|
|
@ -298,13 +385,18 @@ func main() {
|
||||||
testchan()
|
testchan()
|
||||||
testarray()
|
testarray()
|
||||||
testarray1()
|
testarray1()
|
||||||
|
testarray2()
|
||||||
testarrayptr()
|
testarrayptr()
|
||||||
testarrayptr1()
|
testarrayptr1()
|
||||||
|
testarrayptr2()
|
||||||
testslice()
|
testslice()
|
||||||
testslice1()
|
testslice1()
|
||||||
|
testslice2()
|
||||||
teststring()
|
teststring()
|
||||||
teststring1()
|
teststring1()
|
||||||
|
teststring2()
|
||||||
testmap()
|
testmap()
|
||||||
testmap1()
|
testmap1()
|
||||||
|
testmap2()
|
||||||
testcalls()
|
testcalls()
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -97,6 +97,8 @@ func (m intMap) Len() int { return len(m) }
|
||||||
func (m intMap) RangeAll() {
|
func (m intMap) RangeAll() {
|
||||||
for _ = range m {
|
for _ = range m {
|
||||||
}
|
}
|
||||||
|
for range m {
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func stressMaps() {
|
func stressMaps() {
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue