1
0
mirror of https://github.com/golang/go synced 2024-11-12 04:50:21 -07:00

delay range processing. old2new is gone

R=ken
OCL=32780
CL=32780
This commit is contained in:
Russ Cox 2009-08-05 02:33:30 -07:00
parent 54b403723b
commit 2609731736
9 changed files with 286 additions and 363 deletions

View File

@ -30,6 +30,7 @@ OFILES=\
mparith3.$O\
obj.$O\
print.$O\
range.$O\
reflect.$O\
select.$O\
sinit.$O\

View File

@ -594,39 +594,12 @@ colasname(Node *n)
return 0;
}
Node*
old2new(Node *n, Type *t, NodeList **init)
{
Node *l;
if(!colasname(n)) {
yyerror("left side of := must be a name");
return n;
}
if(t != T && t->funarg) {
yyerror("use of multi func value as single value in :=");
return n;
}
l = newname(n->sym);
dodclvar(l, t, init);
return l;
}
Node*
colas(NodeList *left, NodeList *right)
void
colasdefn(NodeList *left, Node *defn)
{
int nnew;
Node *n, *as;
NodeList *l;
if(count(left) == 1 && count(right) == 1)
as = nod(OAS, left->n, right->n);
else {
as = nod(OAS2, N, N);
as->list = left;
as->rlist = right;
}
as->colas = 1;
Node *n;
nnew = 0;
for(l=left; l; l=l->next) {
@ -640,14 +613,34 @@ colas(NodeList *left, NodeList *right)
nnew++;
n = newname(n->sym);
declare(n, dclcontext);
if(as->op == OAS)
as->left = n;
n->defn = as;
as->ninit = list(as->ninit, nod(ODCL, n, N));
n->defn = defn;
defn->ninit = list(defn->ninit, nod(ODCL, n, N));
l->n = n;
}
if(nnew == 0)
yyerror("no new variables on left side of :=");
}
Node*
colas(NodeList *left, NodeList *right)
{
Node *as;
as = nod(OAS2, N, N);
as->list = left;
as->rlist = right;
as->colas = 1;
colasdefn(left, as);
// make the tree prettier; not necessary
if(count(left) == 1 && count(right) == 1) {
as->left = as->list->n;
as->right = as->rlist->n;
as->list = nil;
as->rlist = nil;
as->op = OAS;
}
return as;
}

View File

@ -332,7 +332,7 @@ enum
OCOMPSLICE, OCOMPMAP,
OCONV, OCONVNOP, OCONVA2S, OCONVIFACE, OCONVSLICE,
ODCL, ODCLFUNC, ODCLFIELD, ODCLARG,
ODOT, ODOTPTR, ODOTMETH, ODOTINTER,
ODOT, ODOTPTR, ODOTMETH, ODOTINTER, OXDOT,
ODOTTYPE,
OEQ, ONE, OLT, OLE, OGE, OGT,
OFUNC,
@ -948,6 +948,7 @@ void walkconv(Node**, NodeList**);
void walkdottype(Node*, NodeList**);
void walkas(Node*);
void walkswitch(Node*);
void walkrange(Node*);
void walkselect(Node*);
void walkdot(Node*, NodeList**);
void walkexpr(Node**, NodeList**);
@ -967,22 +968,22 @@ void ifacecheck(Type*, Type*, int, int);
void runifacechecks(void);
Node* convas(Node*, NodeList**);
Node* colas(NodeList*, NodeList*);
Node* dorange(Node*);
void colasdefn(NodeList*, Node*);
NodeList* reorder1(NodeList*);
NodeList* reorder3(NodeList*);
NodeList* reorder4(NodeList*);
Node* structlit(Node*, Node*, NodeList**);
Node* arraylit(Node*, Node*, NodeList**);
Node* maplit(Node*, Node*, NodeList**);
Node* selectas(Node*, Node*, NodeList**);
Node* old2new(Node*, Type*, NodeList**);
void heapmoves(void);
void walkdeflist(NodeList*);
void walkdef(Node*);
void typechecklist(NodeList*, int);
void typecheckswitch(Node*);
void typecheckselect(Node*);
void typecheckrange(Node*);
Node* typecheckconv(Node*, Node*, Type*, int);
int checkconv(Type*, Type*, int, int*, int*);
Node* typecheck(Node**, int);
/*

View File

@ -464,8 +464,7 @@ simple_stmt:
case:
LCASE expr_or_type_list ':'
{
int e;
Node *n;
Node *n, *ntype;
// will be converted to OCASE
// right will point to next case
@ -474,29 +473,18 @@ case:
$$ = nod(OXCASE, N, N);
if(typeswvar != N && typeswvar->right != N) {
// type switch
n = $2->n;
ntype = $2->n;
if($2->next != nil)
yyerror("type switch case cannot be list");
if(n->op == OLITERAL && n->val.ctype == CTNIL) {
if(ntype->op == OLITERAL && ntype->val.ctype == CTNIL) {
// case nil
$$->list = list1(nod(OTYPECASE, N, N));
break;
}
// TODO: move
e = nerrors;
typecheck(&n, Etype | Erv);
if(n->op == OTYPE) {
n = old2new(typeswvar->right, n->type, &$$->ninit);
$$->list = list1(nod(OTYPECASE, n, N));
break;
}
// maybe typecheck found problems that keep
// e from being valid even outside a type switch.
// only complain if typecheck didn't print new errors.
if(nerrors == e)
yyerror("non-type case in type switch");
$$->diag = 1;
n = newname(typeswvar->right->sym);
declare(n, dclcontext);
n->ntype = ntype;
$$->list = list1(nod(OTYPECASE, n, N));
} else {
// expr switch
$$->list = $2;
@ -519,7 +507,6 @@ case:
// done in casebody()
poptodcl();
$$ = nod(OXCASE, N, N);
// $$->list = list1(nod(OAS, selectas($2, $4, &$$->ninit), $4));
$$->list = list1(colas(list1($2), list1($4)));
}
| LDEFAULT ':'
@ -590,7 +577,8 @@ range_stmt:
{
$$ = nod(ORANGE, N, $4);
$$->list = $1;
$$->etype = 1;
$$->colas = 1;
colasdefn($1, $$);
}
for_header:
@ -612,9 +600,6 @@ for_header:
$$->ntest = $1;
}
| range_stmt
{
$$ = dorange($1);
}
for_body:
for_header loop_body
@ -850,8 +835,7 @@ pexpr:
$$ = oldname(s);
break;
}
$$ = nod(ODOT, $1, newname($3));
$$ = adddot($$);
$$ = nod(OXDOT, $1, newname($3));
}
| '(' expr_or_type ')'
{
@ -1041,8 +1025,7 @@ dotname:
$$ = oldname(s);
break;
}
$$ = nod(ODOT, $1, newname($3));
$$ = adddot($$);
$$ = nod(OXDOT, $1, newname($3));
}
othertype:

216
src/cmd/gc/range.c Normal file
View File

@ -0,0 +1,216 @@
// Copyright 2009 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
/*
* range
*/
#include "go.h"
void
typecheckrange(Node *n)
{
int op, et;
Type *t, *t1, *t2;
Node *v1, *v2;
NodeList *ll;
// delicate little dance. see typecheckas2
for(ll=n->list; ll; ll=ll->next)
if(ll->n->defn != n)
typecheck(&ll->n, Erv);
typecheck(&n->right, Erv);
if((t = n->right->type) == T)
goto out;
n->type = t;
switch(t->etype) {
default:
yyerror("cannot range over %+N", n->right);
goto out;
case TARRAY:
t1 = types[TINT];
t2 = t->type;
break;
case TMAP:
t1 = t->down;
t2 = t->type;
break;
case TCHAN:
t1 = t->type;
t2 = nil;
if(count(n->list) == 2)
goto toomany;
break;
case TSTRING:
t1 = types[TINT];
t2 = types[TINT];
break;
}
if(count(n->list) > 2) {
toomany:
yyerror("too many variables in range");
}
v1 = n->list->n;
v2 = N;
if(n->list->next)
v2 = n->list->next->n;
if(v1->defn == n)
v1->type = t1;
else if(v1->type != T && checkconv(t1, v1->type, 0, &op, &et) < 0)
yyerror("cannot assign type %T to %+N", t1, v1);
if(v2) {
if(v2->defn == n)
v2->type = t2;
else if(v2->type != T && checkconv(t2, v2->type, 0, &op, &et) < 0)
yyerror("cannot assign type %T to %+N", t1, v1);
}
out:
typechecklist(n->nbody, Etop);
// second half of dance
n->typecheck = 1;
for(ll=n->list; ll; ll=ll->next)
if(ll->n->typecheck == 0)
typecheck(&ll->n, Erv);
}
void
walkrange(Node *n)
{
Node *ohv1, *hv1, *hv2; // hidden (old) val 1, 2
Node *ha, *hit; // hidden aggregate, iterator
Node *a, *v1, *v2; // not hidden aggregate, val 1, 2
Node *fn;
NodeList *body, *init;
Type *th, *t;
t = n->type;
init = nil;
a = n->right;
if(t->etype == TSTRING && !eqtype(t, types[TSTRING])) {
a = nod(OCONV, n->right, N);
a->type = types[TSTRING];
}
ha = nod(OXXX, N, N);
tempname(ha, a->type);
init = list(init, nod(OAS, ha, a));
v1 = n->list->n;
hv1 = N;
v2 = N;
if(n->list->next)
v2 = n->list->next->n;
hv2 = N;
switch(t->etype) {
default:
fatal("walkrange");
case TARRAY:
hv1 = nod(OXXX, N, n);
tempname(hv1, v1->type);
init = list(init, nod(OAS, hv1, N));
n->ntest = nod(OLT, hv1, nod(OLEN, ha, N));
n->nincr = nod(OASOP, hv1, nodintconst(1));
n->nincr->etype = OADD;
body = list1(nod(OAS, v1, hv1));
if(v2)
body = list(body, nod(OAS, v2, nod(OINDEX, ha, hv1)));
break;
case TMAP:
th = typ(TARRAY);
th->type = ptrto(types[TUINT8]);
th->bound = (sizeof(struct Hiter) + widthptr - 1) / widthptr;
hit = nod(OXXX, N, N);
tempname(hit, th);
fn = syslook("mapiterinit", 1);
argtype(fn, t->down);
argtype(fn, t->type);
argtype(fn, th);
init = list(init, mkcall1(fn, T, nil, ha, nod(OADDR, hit, N)));
n->ntest = nod(ONE, nod(OINDEX, hit, nodintconst(0)), nodnil());
fn = syslook("mapiternext", 1);
argtype(fn, th);
n->nincr = mkcall1(fn, T, nil, nod(OADDR, hit, N));
if(v2 == N) {
fn = syslook("mapiter1", 1);
argtype(fn, th);
argtype(fn, t->down);
a = nod(OAS, v1, mkcall1(fn, t->down, nil, nod(OADDR, hit, N)));
} else {
fn = syslook("mapiter2", 1);
argtype(fn, th);
argtype(fn, t->down);
argtype(fn, t->type);
a = nod(OAS2, N, N);
a->list = list(list1(v1), v2);
a->rlist = list1(mkcall1(fn, getoutargx(fn->type), nil, nod(OADDR, hit, N)));
}
body = list1(a);
break;
case TCHAN:
hv1 = nod(OXXX, N, n);
tempname(hv1, v1->type);
n->ntest = nod(ONOT, nod(OCLOSED, ha, N), N);
n->ntest->ninit = list1(nod(OAS, hv1, nod(ORECV, ha, N)));
body = list1(nod(OAS, v1, hv1));
break;
case TSTRING:
ohv1 = nod(OXXX, N, N);
tempname(ohv1, types[TINT]);
hv1 = nod(OXXX, N, N);
tempname(hv1, types[TINT]);
init = list(init, nod(OAS, hv1, N));
if(v2 == N)
a = nod(OAS, hv1, mkcall("stringiter", types[TINT], nil, ha, hv1));
else {
hv2 = nod(OXXX, N, N);
tempname(hv2, types[TINT]);
a = nod(OAS2, N, N);
a->list = list(list1(hv1), hv2);
fn = syslook("stringiter2", 0);
a->rlist = list1(mkcall1(fn, getoutargx(fn->type), nil, ha, hv1));
}
n->ntest = nod(ONE, hv1, nodintconst(0));
n->ntest->ninit = list(list1(nod(OAS, ohv1, hv1)), a);
body = list1(nod(OAS, v1, ohv1));
if(v2 != N)
body = list(body, nod(OAS, v2, hv2));
break;
}
n->op = OFOR;
typechecklist(init, Etop);
n->ninit = concat(n->ninit, init);
typechecklist(n->ntest->ninit, Etop);
typecheck(&n->ntest, Erv);
typecheck(&n->nincr, Etop);
typechecklist(body, Etop);
n->nbody = concat(body, n->nbody);
walkstmt(&n);
}

View File

@ -8,32 +8,6 @@
#include "go.h"
/*
* declare v in
* case v := <-chan // select and switch
* called during parse
*/
Node*
selectas(Node *name, Node *expr, NodeList **init)
{
Type *t;
if(expr == N || expr->op != ORECV)
goto bad;
walkexpr(&expr->left, init);
t = expr->left->type;
if(t == T)
goto bad;
if(t->etype != TCHAN)
goto bad;
t = t->type;
return old2new(name, t, init);
bad:
return name;
}
void
typecheckselect(Node *sel)
{

View File

@ -582,11 +582,6 @@ dodump(Node *n, int dep)
print("%O-ntype\n", n->op);
dodump(n->ntype, dep+1);
}
if(n->defn != nil && n->defn->op != OAS && n->defn->op != OAS2) {
indent(dep);
print("%O-defn\n", n->op);
dodump(n->defn, dep+1);
}
if(n->list != nil) {
indent(dep);
print("%O-list\n", n->op);
@ -597,6 +592,11 @@ dodump(Node *n, int dep)
print("%O-rlist\n", n->op);
dodumplist(n->rlist, dep+1);
}
if(n->nbody != nil) {
indent(dep);
print("%O-nbody\n", n->op);
dodumplist(n->nbody, dep+1);
}
}
void
@ -2466,10 +2466,8 @@ out:
yyerror("ambiguous DOT reference %T.%S", t, s);
// rebuild elided dots
for(c=d-1; c>=0; c--) {
n = nod(ODOT, n, n->right);
n->left->right = newname(dotlist[c].field->sym);
}
for(c=d-1; c>=0; c--)
n->left = nod(ODOT, n->left, newname(dotlist[c].field->sym));
ret:
return n;
}
@ -2705,7 +2703,7 @@ genwrapper(Type *rcvr, Type *method, Sym *newnam)
args = list(args, l->n->left);
// generate call
call = nod(OCALL, adddot(nod(ODOT, this->left, newname(method->sym))), N);
call = nod(OCALL, adddot(nod(OXDOT, this->left, newname(method->sym))), N);
call->list = args;
fn->nbody = list1(call);
if(method->type->outtuple > 0) {

View File

@ -12,7 +12,6 @@
*
* TODO:
* trailing ... section of function calls
* range
*/
#include "go.h"
@ -376,6 +375,10 @@ reswitch:
goto error;
goto ret;
case OXDOT:
n = adddot(n);
n->op = ODOT;
// fall through
case ODOT:
l = typecheck(&n->left, Erv);
if((t = l->type) == T)
@ -882,6 +885,11 @@ reswitch:
typecheckswitch(n);
goto ret;
case ORANGE:
ok |= Etop;
typecheckrange(n);
goto ret;
case OTYPECASE:
ok |= Etop | Erv;
typecheck(&n->left, Erv);
@ -1069,7 +1077,7 @@ nokeys(NodeList *l)
return 1;
}
static int
int
checkconv(Type *nt, Type *t, int explicit, int *op, int *et)
{
*op = OCONV;

View File

@ -285,7 +285,10 @@ walkstmt(Node **np)
case OFOR:
walkstmtlist(n->ninit);
walkexpr(&n->ntest, &n->ntest->ninit);
if(n->ntest != N) {
walkstmtlist(n->ntest->ninit);
walkexpr(&n->ntest, &n->ntest->ninit);
}
walkstmt(&n->nincr);
walkstmtlist(n->nbody);
break;
@ -319,6 +322,10 @@ walkstmt(Node **np)
walkswitch(n);
break;
case ORANGE:
walkrange(n);
break;
case OXFALL:
yyerror("fallthrough statement out of place");
n->op = OFALL;
@ -1702,264 +1709,6 @@ out:
return n;
}
/*
* rewrite a range statement
* k and v are names/new_names
* m is an array or map
* local is 0 (meaning =) or 1 (meaning :=)
*/
Node*
dorange(Node *nn)
{
Node *k, *v, *m;
Node *n, *hv, *hc, *ha, *hk, *ohk, *on, *r, *a, *as;
NodeList *init, *args;
Type *t, *th;
int local;
NodeList *nl;
if(nn->op != ORANGE)
fatal("dorange not ORANGE");
nl = nn->list;
k = nl->n;
if((nl = nl->next) != nil) {
v = nl->n;
nl = nl->next;
} else
v = N;
if(nl != nil)
yyerror("too many variables in range");
n = nod(OFOR, N, N);
init = nil;
typecheck(&nn->right, Erv);
m = nn->right;
local = nn->etype;
t = m->type;
if(t == T)
goto out;
if(t->etype == TARRAY)
goto ary;
if(t->etype == TMAP)
goto map;
if(t->etype == TCHAN)
goto chan;
if(t->etype == TSTRING)
goto strng;
yyerror("range must be over map/array/chan/string");
goto out;
ary:
hk = nod(OXXX, N, N); // hidden key
tempname(hk, types[TINT]);
ha = nod(OXXX, N, N); // hidden array
tempname(ha, t);
a = nod(OAS, hk, nodintconst(0));
init = list(init, a);
a = nod(OAS, ha, m);
init = list(init, a);
n->ntest = nod(OLT, hk, nod(OLEN, ha, N));
n->nincr = nod(OASOP, hk, nodintconst(1));
n->nincr->etype = OADD;
if(local)
k = old2new(k, hk->type, &init);
n->nbody = list1(nod(OAS, k, hk));
if(v != N) {
if(local)
v = old2new(v, t->type, &init);
n->nbody = list(n->nbody,
nod(OAS, v, nod(OINDEX, ha, hk)) );
}
goto out;
map:
th = typ(TARRAY);
th->type = ptrto(types[TUINT8]);
th->bound = (sizeof(struct Hiter) + types[tptr]->width - 1) /
types[tptr]->width;
hk = nod(OXXX, N, N); // hidden iterator
tempname(hk, th); // hashmap hash_iter
on = syslook("mapiterinit", 1);
argtype(on, t->down);
argtype(on, t->type);
argtype(on, th);
a = nod(OADDR, hk, N);
r = nod(OCALL, on, N);
r->list = list(list1(m), a);
init = list(init, r);
r = nod(OINDEX, hk, nodintconst(0));
a = nod(OLITERAL, N, N);
a->val.ctype = CTNIL;
a->type = types[TNIL];
r = nod(ONE, r, a);
n->ntest = r;
on = syslook("mapiternext", 1);
argtype(on, th);
r = nod(OADDR, hk, N);
args = list1(r);
r = nod(OCALL, on, N);
r->list = args;
n->nincr = r;
if(local)
k = old2new(k, t->down, &init);
if(v == N) {
on = syslook("mapiter1", 1);
argtype(on, th);
argtype(on, t->down);
r = nod(OADDR, hk, N);
args = list1(r);
r = nod(OCALL, on, N);
r->list = args;
n->nbody = list1(nod(OAS, k, r));
goto out;
}
if(local)
v = old2new(v, t->type, &init);
on = syslook("mapiter2", 1);
argtype(on, th);
argtype(on, t->down);
argtype(on, t->type);
r = nod(OADDR, hk, N);
args = list1(r);
r = nod(OCALL, on, N);
r->list = args;
as = nod(OAS2, N, N);
as->list = list(list1(k), v);
as->rlist = list1(r);
n->nbody = list1(as);
goto out;
chan:
if(v != N)
yyerror("chan range can only have one variable");
hc = nod(OXXX, N, N); // hidden chan
tempname(hc, t);
hv = nod(OXXX, N, N); // hidden value
tempname(hv, t->type);
a = nod(OAS, hc, m);
init = list(init, a);
a = nod(ORECV, hc, N);
a = nod(OAS, hv, a);
init = list(init, a);
a = nod(OCLOSED, N, N);
a->list = list1(hc);
n->ntest = nod(ONOT, a, N);
n->nincr = nod(OAS, hv, nod(ORECV, hc, N));
if(local)
k = old2new(k, hv->type, &init);
n->nbody = list1(nod(OAS, k, hv));
goto out;
strng:
hk = nod(OXXX, N, N); // hidden key
tempname(hk, types[TINT]);
ohk = nod(OXXX, N, N); // old hidden key
tempname(ohk, types[TINT]);
ha = nod(OXXX, N, N); // hidden string
tempname(ha, types[TSTRING]);
hv = N;
if(v != N) {
hv = nod(OXXX, N, N); // hidden value
tempname(hv, types[TINT]);
}
if(local) {
k = old2new(k, types[TINT], &init);
if(v != N)
v = old2new(v, types[TINT], &init);
}
// ha = s
a = nod(OCONV, m, N);
a->type = ha->type;
a = nod(OAS, ha, a);
init = list(init, a);
// ohk = 0
a = nod(OAS, ohk, nodintconst(0));
init = list(init, a);
// hk[,hv] = stringiter(ha,hk)
if(v != N) {
// hk,v = stringiter2(ha, hk)
on = syslook("stringiter2", 0);
a = nod(OCALL, on, N);
a->list = list(list1(ha), nodintconst(0));
as = nod(OAS2, N, N);
as->list = list(list1(hk), hv);
as->rlist = list1(a);
a = as;
} else {
// hk = stringiter(ha, hk)
on = syslook("stringiter", 0);
a = nod(OCALL, on, N);
a->list = list(list1(ha), nodintconst(0));
a = nod(OAS, hk, a);
}
init = list(init, a);
// while(hk != 0)
n->ntest = nod(ONE, hk, nodintconst(0));
// hk[,hv] = stringiter(ha,hk)
if(v != N) {
// hk,hv = stringiter2(ha, hk)
on = syslook("stringiter2", 0);
a = nod(OCALL, on, N);
a->list = list(list1(ha), hk);
as = nod(OAS2, N, N);
as->list = list(list1(hk), hv);
as->rlist = list1(a);
a = as;
} else {
// hk = stringiter(ha, hk)
on = syslook("stringiter", 0);
a = nod(OCALL, on, N);
a->list = list(list1(ha), hk);
a = nod(OAS, hk, a);
}
n->nincr = a;
// k,ohk[,v] = ohk,hk,[,hv]
a = nod(OAS, k, ohk);
n->nbody = list1(a);
a = nod(OAS, ohk, hk);
n->nbody = list(n->nbody, a);
if(v != N) {
a = nod(OAS, v, hv);
n->nbody = list(n->nbody, a);
}
out:
n->ninit = concat(n->ninit, init);
return n;
}
/*
* from ascompat[te]
* evaluating actual function arguments.