mirror of
https://github.com/golang/go
synced 2024-10-02 22:25:08 +00:00
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:
|
||||
// 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);
|
||||
break;
|
||||
|
||||
|
|
|
@ -880,7 +880,11 @@ stmtfmt(Fmt *f, Node *n)
|
|||
fmtstrcpy(f, "for loop");
|
||||
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);
|
||||
break;
|
||||
|
||||
|
|
|
@ -613,6 +613,11 @@ range_stmt:
|
|||
$$->colas = 1;
|
||||
colasdefn($1, $$);
|
||||
}
|
||||
| LRANGE expr
|
||||
{
|
||||
$$ = nod(ORANGE, N, $2);
|
||||
$$->etype = 0; // := flag
|
||||
}
|
||||
|
||||
for_header:
|
||||
osimple_stmt ';' osimple_stmt ';' osimple_stmt
|
||||
|
|
|
@ -67,9 +67,11 @@ typecheckrange(Node *n)
|
|||
yyerror("too many variables in range");
|
||||
}
|
||||
|
||||
v1 = n->list->n;
|
||||
v1 = N;
|
||||
if(n->list)
|
||||
v1 = n->list->n;
|
||||
v2 = N;
|
||||
if(n->list->next)
|
||||
if(n->list && n->list->next)
|
||||
v2 = n->list->next->n;
|
||||
|
||||
// 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
|
||||
// present."
|
||||
if(isblank(v2)) {
|
||||
n->list = list1(v1);
|
||||
if(v1 != N)
|
||||
n->list = list1(v1);
|
||||
v2 = N;
|
||||
}
|
||||
|
||||
if(v1->defn == n)
|
||||
v1->type = t1;
|
||||
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(v1) {
|
||||
if(v1->defn == n)
|
||||
v1->type = t1;
|
||||
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->defn == n)
|
||||
v2->type = t2;
|
||||
|
@ -123,9 +128,11 @@ walkrange(Node *n)
|
|||
a = n->right;
|
||||
lno = setlineno(a);
|
||||
|
||||
v1 = n->list->n;
|
||||
v1 = N;
|
||||
if(n->list)
|
||||
v1 = n->list->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;
|
||||
// n->list has no meaning anymore, clear it
|
||||
// to avoid erroneous processing by racewalk.
|
||||
|
@ -154,7 +161,9 @@ walkrange(Node *n)
|
|||
|
||||
n->ntest = nod(OLT, hv1, hn);
|
||||
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));
|
||||
else {
|
||||
a = nod(OAS2, N, N);
|
||||
|
@ -205,16 +214,18 @@ walkrange(Node *n)
|
|||
|
||||
key = nod(ODOT, hit, keyname);
|
||||
key = nod(OIND, key, N);
|
||||
if(v2 == N) {
|
||||
a = nod(OAS, v1, key);
|
||||
if(v1 == N)
|
||||
body = nil;
|
||||
else if(v2 == N) {
|
||||
body = list1(nod(OAS, v1, key));
|
||||
} else {
|
||||
val = nod(ODOT, hit, valname);
|
||||
val = nod(OIND, val, N);
|
||||
a = nod(OAS2, N, N);
|
||||
a->list = list(list1(v1), v2);
|
||||
a->rlist = list(list1(key), val);
|
||||
body = list1(a);
|
||||
}
|
||||
body = list1(a);
|
||||
break;
|
||||
|
||||
case TCHAN:
|
||||
|
@ -223,6 +234,7 @@ walkrange(Node *n)
|
|||
n->ntest = N;
|
||||
|
||||
hv1 = temp(t->type);
|
||||
hv1->typecheck = 1;
|
||||
if(haspointers(t->type))
|
||||
init = list(init, nod(OAS, hv1, N));
|
||||
hb = temp(types[TBOOL]);
|
||||
|
@ -233,7 +245,10 @@ walkrange(Node *n)
|
|||
a->list = list(list1(hv1), hb);
|
||||
a->rlist = list1(nod(ORECV, ha, N));
|
||||
n->ntest->ninit = list1(a);
|
||||
body = list1(nod(OAS, v1, hv1));
|
||||
if(v1 == N)
|
||||
body = nil;
|
||||
else
|
||||
body = list1(nod(OAS, v1, hv1));
|
||||
break;
|
||||
|
||||
case TSTRING:
|
||||
|
@ -257,7 +272,10 @@ walkrange(Node *n)
|
|||
n->ntest = nod(ONE, hv1, nodintconst(0));
|
||||
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)
|
||||
body = list(body, nod(OAS, v2, hv2));
|
||||
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, ';',
|
||||
"missing import path; require quoted string"},
|
||||
|
||||
{378, ';',
|
||||
{380, ';',
|
||||
"missing { after if clause"},
|
||||
|
||||
{399, ';',
|
||||
{401, ';',
|
||||
"missing { after switch clause"},
|
||||
|
||||
{238, ';',
|
||||
{239, ';',
|
||||
"missing { after for clause"},
|
||||
|
||||
{476, LBODY,
|
||||
{478, LBODY,
|
||||
"missing { after for clause"},
|
||||
|
||||
{22, '{',
|
||||
|
@ -47,33 +47,33 @@ static struct {
|
|||
{37, ',',
|
||||
"unexpected comma in channel type"},
|
||||
|
||||
{439, LELSE,
|
||||
{441, LELSE,
|
||||
"unexpected semicolon or newline before else"},
|
||||
|
||||
{258, ',',
|
||||
{259, ',',
|
||||
"name list not allowed in interface type"},
|
||||
|
||||
{238, LVAR,
|
||||
{239, LVAR,
|
||||
"var declaration not allowed in for initializer"},
|
||||
|
||||
{65, '{',
|
||||
"unexpected { at end of statement"},
|
||||
|
||||
{377, '{',
|
||||
{379, '{',
|
||||
"unexpected { at end of statement"},
|
||||
|
||||
{126, ';',
|
||||
"argument to go/defer must be function call"},
|
||||
|
||||
{426, ';',
|
||||
{428, ';',
|
||||
"need trailing comma before newline in composite literal"},
|
||||
|
||||
{437, ';',
|
||||
{439, ';',
|
||||
"need trailing comma before newline in composite literal"},
|
||||
|
||||
{113, LNAME,
|
||||
"nested func not allowed"},
|
||||
|
||||
{645, ';',
|
||||
{647, ';',
|
||||
"else must be followed by if or statement block"}
|
||||
};
|
||||
|
|
|
@ -123,7 +123,7 @@ func pallmall(cols []int) {
|
|||
fmt.Println(msg)
|
||||
tot := 0
|
||||
// wait for all results
|
||||
for _ = range cols {
|
||||
for range cols {
|
||||
result := <-ended
|
||||
tot += result.met
|
||||
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"
|
||||
}
|
||||
|
||||
close(c)
|
||||
close(cs)
|
||||
close(cr) // ERROR "receive"
|
||||
|
|
|
@ -18,4 +18,6 @@ func main() {
|
|||
}
|
||||
for _ = range t {
|
||||
}
|
||||
for range t {
|
||||
}
|
||||
}
|
||||
|
|
|
@ -14,6 +14,8 @@ type matrix struct {
|
|||
func (a matrix) equal() bool {
|
||||
for _ = range a.e {
|
||||
}
|
||||
for range a.e {
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
|
|
|
@ -32,6 +32,13 @@ func testchan() {
|
|||
println("Wanted lowercase alphabet; got", s)
|
||||
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
|
||||
|
@ -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
|
||||
// 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 {
|
||||
nmake++
|
||||
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
|
||||
// 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
|
||||
// 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
|
||||
// exactly once per iteration.
|
||||
|
||||
|
@ -298,13 +385,18 @@ func main() {
|
|||
testchan()
|
||||
testarray()
|
||||
testarray1()
|
||||
testarray2()
|
||||
testarrayptr()
|
||||
testarrayptr1()
|
||||
testarrayptr2()
|
||||
testslice()
|
||||
testslice1()
|
||||
testslice2()
|
||||
teststring()
|
||||
teststring1()
|
||||
teststring2()
|
||||
testmap()
|
||||
testmap1()
|
||||
testmap2()
|
||||
testcalls()
|
||||
}
|
||||
|
|
|
@ -97,6 +97,8 @@ func (m intMap) Len() int { return len(m) }
|
|||
func (m intMap) RangeAll() {
|
||||
for _ = range m {
|
||||
}
|
||||
for range m {
|
||||
}
|
||||
}
|
||||
|
||||
func stressMaps() {
|
||||
|
|
Loading…
Reference in a new issue