summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorRuss Cox <rsc@golang.org>2009-08-04 12:57:48 -0700
committerRuss Cox <rsc@golang.org>2009-08-04 12:57:48 -0700
commit3c1978753e224aaa40f2ec3d817ba4f59c4794c9 (patch)
tree32a38aa58208c62e97a0fa2f6e011f685ae940b7
parent1e2833c42ac62b80c2f2798aa3cf0b606f6b6e03 (diff)
downloadgolang-3c1978753e224aaa40f2ec3d817ba4f59c4794c9.tar.gz
move select into its own file.
split into typecheck + walk R=ken OCL=32726 CL=32726
-rw-r--r--src/cmd/gc/Makefile1
-rw-r--r--src/cmd/gc/go.h5
-rw-r--r--src/cmd/gc/select.c163
-rw-r--r--src/cmd/gc/subr.c9
-rw-r--r--src/cmd/gc/typecheck.c6
-rw-r--r--src/cmd/gc/walk.c237
6 files changed, 184 insertions, 237 deletions
diff --git a/src/cmd/gc/Makefile b/src/cmd/gc/Makefile
index 9273e3a0f..ec9702055 100644
--- a/src/cmd/gc/Makefile
+++ b/src/cmd/gc/Makefile
@@ -36,6 +36,7 @@ OFILES=\
obj.$O\
print.$O\
typecheck.$O\
+ select.$O\
$(LIB): $(OFILES)
ar rsc $(LIB) $(OFILES)
diff --git a/src/cmd/gc/go.h b/src/cmd/gc/go.h
index 4b81dd959..71d34682b 100644
--- a/src/cmd/gc/go.h
+++ b/src/cmd/gc/go.h
@@ -363,6 +363,7 @@ enum
OSLICE, OSLICEARR, OSLICESTR,
ORECV,
ORUNESTR,
+ OSELRECV,
// stmts
OBLOCK,
@@ -973,6 +974,9 @@ void walkswitch(Node*);
void walkselect(Node*);
void walkdot(Node*, NodeList**);
void walkexpr(Node**, NodeList**);
+Node* mkcall(char*, Type*, NodeList**, ...);
+Node* mkcall1(Node*, Type*, NodeList**, ...);
+Node* chanfn(char*, int, Type*);
Node* ascompatee1(int, Node*, Node*, NodeList**);
NodeList* ascompatee(int, NodeList*, NodeList*, NodeList**);
NodeList* ascompatet(int, NodeList*, Type**, int, NodeList**);
@@ -1000,6 +1004,7 @@ void walkdeflist(NodeList*);
void walkdef(Node*);
void typechecklist(NodeList*, int);
void typecheckswitch(Node*);
+void typecheckselect(Node*);
Node* typecheckconv(Node*, Node*, Type*, int);
Node* typecheck(Node**, int);
diff --git a/src/cmd/gc/select.c b/src/cmd/gc/select.c
new file mode 100644
index 000000000..2fd63cc7c
--- /dev/null
+++ b/src/cmd/gc/select.c
@@ -0,0 +1,163 @@
+// 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.
+
+/*
+ * select
+ */
+
+#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)
+{
+ Node *ncase, *n, *def;
+ NodeList *l;
+ int lno, count;
+
+ def = nil;
+ lno = setlineno(sel);
+ count = 0;
+ typechecklist(sel->ninit, Etop);
+ for(l=sel->list; l; l=l->next) {
+ count++;
+ ncase = l->n;
+ setlineno(ncase);
+ if(ncase->op != OXCASE)
+ fatal("typecheckselect %O", ncase->op);
+
+ if(ncase->list == nil) {
+ // default
+ if(def != N)
+ yyerror("multiple defaults in select (first at %L)", def->lineno);
+ else
+ def = ncase;
+ } else if(ncase->list->next) {
+ yyerror("select cases cannot be lists");
+ } else {
+ n = typecheck(&ncase->list->n, Etop);
+ ncase->left = n;
+ ncase->list = nil;
+ setlineno(n);
+ switch(n->op) {
+ case OAS:
+ // convert x = <-c into OSELRECV(x, c)
+ if(n->right->op != ORECV) {
+ yyerror("select assignment must have receive on right hand side");
+ break;
+ }
+ n->op = OSELRECV;
+ n->right = n->right->left;
+ break;
+
+ case ORECV:
+ // convert <-c into OSELRECV(N, c)
+ n->op = OSELRECV;
+ n->right = n->left;
+ n->left = N;
+ break;
+
+ case OSEND:
+ break;
+ }
+ }
+ typechecklist(ncase->nbody, Etop);
+ }
+ sel->xoffset = count;
+ if(count == 0)
+ yyerror("empty select");
+ lineno = lno;
+}
+
+void
+walkselect(Node *sel)
+{
+ int lno;
+ Node *n, *ncase, *r, *a, *tmp, *var;
+ NodeList *l, *init;
+
+ lno = setlineno(sel);
+ init = sel->ninit;
+ sel->ninit = nil;
+
+ // generate sel-struct
+ var = nod(OXXX, N, N);
+ tempname(var, ptrto(types[TUINT8]));
+ r = nod(OAS, var, mkcall("newselect", var->type, nil, nodintconst(sel->xoffset)));
+ typecheck(&r, Etop);
+ init = list(init, r);
+
+ if(sel->list == nil)
+ fatal("double walkselect"); // already rewrote
+
+ // register cases
+ for(l=sel->list; l; l=l->next) {
+ ncase = l->n;
+ n = ncase->left;
+ r = nod(OIF, N, N);
+ r->nbody = ncase->ninit;
+ ncase->ninit = nil;
+ if(n == nil) {
+ // selectdefault(sel *byte);
+ r->ntest = mkcall("selectdefault", types[TBOOL], &init, var);
+ } else if(n->op == OSEND) {
+ // selectsend(sel *byte, hchan *chan any, elem any) (selected bool);
+ r->ntest = mkcall1(chanfn("selectsend", 2, n->left->type), types[TBOOL], &init, var, n->left, n->right);
+ } else if(n->op == OSELRECV) {
+ tmp = N;
+ if(n->left == N)
+ a = nodnil();
+ else {
+ // introduce temporary until we're sure this will succeed.
+ tmp = nod(OXXX, N, N);
+ tempname(tmp, n->left->type);
+ a = nod(OADDR, tmp, N);
+ }
+ // selectrecv(sel *byte, hchan *chan any, elem *any) (selected bool);
+ r->ntest = mkcall1(chanfn("selectrecv", 2, n->right->type), types[TBOOL], &init, var, n->right, a);
+ if(tmp != N) {
+ a = nod(OAS, n->left, tmp);
+ typecheck(&a, Etop);
+ r->nbody = list(r->nbody, a);
+ }
+ } else
+ fatal("select %O", n->op);
+ r->nbody = concat(r->nbody, ncase->nbody);
+ r->nbody = list(r->nbody, nod(OBREAK, N, N));
+ init = list(init, r);
+ }
+
+ // run the select
+ init = list(init, mkcall("selectgo", T, nil, var));
+ sel->nbody = init;
+ sel->list = nil;
+ walkstmtlist(init);
+
+ lineno = lno;
+}
diff --git a/src/cmd/gc/subr.c b/src/cmd/gc/subr.c
index 52cd3a09d..be99a2afc 100644
--- a/src/cmd/gc/subr.c
+++ b/src/cmd/gc/subr.c
@@ -575,6 +575,15 @@ dodump(Node *n, int dep)
print("%O%J\n", n->op, n);
dodump(n->left, dep+1);
break;
+
+ case OXCASE:
+ print("%N\n", n);
+ dodump(n->left, dep+1);
+ dodump(n->right, dep+1);
+ indent(dep);
+ print("%O-nbody\n", n->op);
+ dodumplist(n->nbody, dep+1);
+ break;
}
if(n->ntype != nil) {
diff --git a/src/cmd/gc/typecheck.c b/src/cmd/gc/typecheck.c
index b8139c3d8..66b2b6a87 100644
--- a/src/cmd/gc/typecheck.c
+++ b/src/cmd/gc/typecheck.c
@@ -12,7 +12,6 @@
*
* TODO:
* trailing ... section of function calls
- * select
* range
*/
@@ -859,9 +858,7 @@ reswitch:
goto ret;
case OSELECT:
- typechecklist(n->ninit, Etop);
- typecheck(&n->ntest, Erv);
- typechecklist(n->list, Etop);
+ typecheckselect(n);
goto ret;
case OSWITCH:
@@ -1757,4 +1754,3 @@ typecheckas2(Node *n)
mismatch:
yyerror("assignment count mismatch: %d = %d", cl, cr);
}
-
diff --git a/src/cmd/gc/walk.c b/src/cmd/gc/walk.c
index ad7c4254d..a77163323 100644
--- a/src/cmd/gc/walk.c
+++ b/src/cmd/gc/walk.c
@@ -5,10 +5,7 @@
#include "go.h"
static Node* walkprint(Node*, NodeList**);
-static Node* mkcall(char*, Type*, NodeList**, ...);
-static Node* mkcall1(Node*, Type*, NodeList**, ...);
static Node* conv(Node*, Type*);
-static Node* chanfn(char*, int, Type*);
static Node* mapfn(char*, Type*);
static Node* makenewvar(Type*, NodeList**, Node**);
enum
@@ -929,6 +926,7 @@ makenewvar(Type *t, NodeList **init, Node **nstar)
return nvar;
}
+// TODO(rsc): cut
void
walkdottype(Node *n, NodeList **init)
{
@@ -942,6 +940,7 @@ walkdottype(Node *n, NodeList **init)
}
}
+// TODO(rsc): cut
void
walkconv(Node **np, NodeList **init)
{
@@ -992,232 +991,6 @@ bad:
}
Node*
-selcase(Node *n, Node *var, NodeList **init)
-{
- Node *a, *r, *c;
- Type *t;
-
- if(n->list == nil)
- goto dflt;
- c = n->list->n;
- if(c->op == ORECV)
- goto recv;
-
- walkexpr(&c->left, init); // chan
- walkexpr(&c->right, init); // elem
-
- t = fixchan(c->left->type);
- if(t == T)
- return N;
-
- if(!(t->chan & Csend)) {
- yyerror("cannot send on %T", t);
- return N;
- }
-
- convlit(&c->right, t->type);
-
- // selectsend(sel *byte, hchan *chan any, elem any) (selected bool);
- a = mkcall1(chanfn("selectsend", 2, t), types[TBOOL], init, var, c->left, c->right);
- goto out;
-
-recv:
- if(c->right != N)
- goto recv2;
-
- walkexpr(&c->left, init); // chan
-
- t = fixchan(c->left->type);
- if(t == T)
- return N;
-
- if(!(t->chan & Crecv)) {
- yyerror("cannot receive from %T", t);
- return N;
- }
-
- // selectrecv(sel *byte, hchan *chan any, elem *any) (selected bool);
- a = mkcall1(chanfn("selectrecv", 2, t), types[TBOOL], init, var, c->left, nodnil());
- goto out;
-
-recv2:
- walkexpr(&c->right, init); // chan
-
- t = fixchan(c->right->type);
- if(t == T)
- return N;
-
- if(!(t->chan & Crecv)) {
- yyerror("cannot receive from %T", t);
- return N;
- }
-
- walkexpr(&c->left, init);
-
- // selectrecv(sel *byte, hchan *chan any, elem *any) (selected bool);
- a = mkcall1(chanfn("selectrecv", 2, t), types[TBOOL], init, var, c->right, nod(OADDR, c->left, N));
- goto out;
-
-dflt:
- // selectdefault(sel *byte);
- a = mkcall("selectdefault", types[TBOOL], init, var);
- goto out;
-
-out:
- r = nod(OIF, N, N);
- r->ntest = a;
-
- return r;
-}
-
-/*
- * enumerate the special cases
- * of the case statement:
- * case v := <-chan // select and switch
- */
-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
-walkselect(Node *sel)
-{
- Node *n, *l, *oc, *on, *r;
- Node *var, *def;
- NodeList *res, *bod, *nbod, *init, *ln;
- int count, op;
- int32 lno;
-
- lno = setlineno(sel);
-
- init = nil;
-
- // generate sel-struct
- var = nod(OXXX, N, N);
- tempname(var, ptrto(types[TUINT8]));
-
- if(sel->list == nil) {
- yyerror("empty select");
- return;
- }
-
- count = 0; // number of cases
- res = nil; // entire select body
- bod = nil; // body of each case
- oc = N; // last case
- def = N; // default case
- for(ln=sel->list; ln; ln=ln->next) {
- n = ln->n;
- setlineno(n);
- if(n->op != OXCASE)
- fatal("walkselect %O", n->op);
-
- count++;
- l = N;
- if(n->list == nil) {
- op = ORECV; // actual value not used
- if(def != N)
- yyerror("repeated default; first at %L", def->lineno);
- def = n;
- } else {
- l = n->list->n;
- op = l->op;
- if(n->list->next) {
- yyerror("select cases cannot be lists");
- continue;
- }
- }
-
- nbod = nil;
- switch(op) {
- default:
- yyerror("select cases must be send, recv or default %O", op);
- continue;
-
- case OAS:
- // convert new syntax (a=recv(chan)) to (recv(a,chan))
- if(l->right == N || l->right->op != ORECV) {
- yyerror("select cases must be send, recv or default %O", l->right->op);
- break;
- }
- r = l->right; // rcv
- r->right = r->left;
- r->left = l->left;
- n->list->n = r;
-
- // convert case x := foo: body
- // to case tmp := foo: x := tmp; body.
- // if x escapes and must be allocated
- // on the heap, this delays the allocation
- // until after the select has chosen this branch.
- if(n->ninit != nil && n->ninit->n->op == ODCL) {
- on = nod(OXXX, N, N);
- tempname(on, l->left->type);
- on->sym = lookup("!tmpselect!");
- r->left = on;
- on = nod(OAS, l->left, on);
- typecheck(&on, Etop);
- nbod = list(n->ninit, on);
- n->ninit = nil;
- }
- break;
-
- case OSEND:
- case OSENDNB:
- case ORECV:
- break;
- }
-
- nbod = concat(nbod, n->nbody);
- nbod = list(nbod, nod(OBREAK, N, N));
- n->nbody = nil;
-
- oc = selcase(n, var, &init);
- if(oc != N) {
- oc->nbody = nbod;
- res = list(res, oc);
- }
- }
- setlineno(sel);
-
- // selectgo(sel *byte);
- res = list(res, mkcall("selectgo", T, nil, var));
-
- // newselect(size uint32) (sel *byte);
- r = nod(OAS, var, mkcall("newselect", var->type, nil, nodintconst(count)));
- typecheck(&r, Etop);
- typechecklist(res, Etop);
-
- sel->ninit = list1(r);
- sel->nbody = res;
- sel->left = N;
-
- walkstmtlist(sel->ninit);
- walkstmtlist(sel->nbody);
-//dump("sel", sel);
-
- sel->ninit = concat(sel->ninit, init);
- lineno = lno;
-}
-
-Node*
ascompatee1(int op, Node *l, Node *r, NodeList **init)
{
return convas(nod(OAS, l, r), init);
@@ -2805,7 +2578,7 @@ vmkcall(Node *fn, Type *t, NodeList **init, va_list va)
return r;
}
-static Node*
+Node*
mkcall(char *name, Type *t, NodeList **init, ...)
{
Node *r;
@@ -2817,7 +2590,7 @@ mkcall(char *name, Type *t, NodeList **init, ...)
return r;
}
-static Node*
+Node*
mkcall1(Node *fn, Type *t, NodeList **init, ...)
{
Node *r;
@@ -2840,7 +2613,7 @@ conv(Node *n, Type *t)
return n;
}
-static Node*
+Node*
chanfn(char *name, int n, Type *t)
{
Node *fn;