]> Cypherpunks repositories - gostls13.git/commitdiff
move select into its own file.
authorRuss Cox <rsc@golang.org>
Tue, 4 Aug 2009 19:57:48 +0000 (12:57 -0700)
committerRuss Cox <rsc@golang.org>
Tue, 4 Aug 2009 19:57:48 +0000 (12:57 -0700)
split into typecheck + walk

R=ken
OCL=32726
CL=32726

src/cmd/gc/Makefile
src/cmd/gc/go.h
src/cmd/gc/select.c [new file with mode: 0644]
src/cmd/gc/subr.c
src/cmd/gc/typecheck.c
src/cmd/gc/walk.c

index 9273e3a0feffb62ac991dd68d543ed958e96ef38..ec97020554657a28a0aa5837a32e8e77697235ef 100644 (file)
@@ -36,6 +36,7 @@ OFILES=\
        obj.$O\
        print.$O\
        typecheck.$O\
+       select.$O\
 
 $(LIB): $(OFILES)
        ar rsc $(LIB) $(OFILES)
index 4b81dd9599f5f96d2ca117fe72e08fb4a0e0df1f..71d34682b61924c2c0b754abe878da6cce3cff2e 100644 (file)
@@ -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 (file)
index 0000000..2fd63cc
--- /dev/null
@@ -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;
+}
index 52cd3a09da6ca3bfdbcf9c88cfa231c4d8e31a18..be99a2afc5c5f30cf1eac7f742da0fce98ff0bfc 100644 (file)
@@ -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) {
index b8139c3d8c2bd018c0edd15cb1bcdf4d3d6115be..66b2b6a87f8d7137ce1519697112f897173ba521 100644 (file)
@@ -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);
 }
-
index ad7c4254d5c4d538b8ceb83fb0c019ffefdd590a..a77163323c711c132f325ebf5ee0a7048c674a30 100644 (file)
@@ -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)
 {
@@ -991,232 +990,6 @@ bad:
                yyerror("invalid %s: %T to %T", what, l->type, t);
 }
 
-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)
 {
@@ -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;