diff options
author | Ken Thompson <ken@golang.org> | 2009-03-06 17:50:43 -0800 |
---|---|---|
committer | Ken Thompson <ken@golang.org> | 2009-03-06 17:50:43 -0800 |
commit | cbdd6270b79791c65ad0f4b5aafd33e139d3ecb9 (patch) | |
tree | f9f4d1fa8431dff7ce37f12f25dae8200817553e /src | |
parent | e747232d093282da97dccf3b7dec2abaa5d166ac (diff) | |
download | golang-cbdd6270b79791c65ad0f4b5aafd33e139d3ecb9.tar.gz |
1. type switches
2. fixed fault on bug128
3. got rid of typeof
4. fixed bug in t,ok = I2T
R=r
OCL=25873
CL=25873
Diffstat (limited to 'src')
-rw-r--r-- | src/cmd/gc/go.h | 3 | ||||
-rw-r--r-- | src/cmd/gc/go.y | 42 | ||||
-rw-r--r-- | src/cmd/gc/lex.c | 1 | ||||
-rw-r--r-- | src/cmd/gc/subr.c | 1 | ||||
-rw-r--r-- | src/cmd/gc/swt.c | 235 | ||||
-rw-r--r-- | src/runtime/iface.c | 2 |
6 files changed, 224 insertions, 60 deletions
diff --git a/src/cmd/gc/go.h b/src/cmd/gc/go.h index dfd975fba..e96a85cc5 100644 --- a/src/cmd/gc/go.h +++ b/src/cmd/gc/go.h @@ -329,7 +329,7 @@ enum OKEY, OPARAM, OCOMPOS, OCONV, - ODOTTYPE, + ODOTTYPE, OTYPESW, OBAD, OEXTEND, // 6g internal @@ -526,6 +526,7 @@ EXTERN Node* retnil; EXTERN Node* fskel; EXTERN Node* addtop; +EXTERN Node* typeswvar; EXTERN char* context; EXTERN char* pkgcontext; diff --git a/src/cmd/gc/go.y b/src/cmd/gc/go.y index e5a8faf22..7635e163c 100644 --- a/src/cmd/gc/go.y +++ b/src/cmd/gc/go.y @@ -18,7 +18,7 @@ %token <sym> LPACKAGE LIMPORT LDEFER %token <sym> LMAP LCHAN LINTERFACE LFUNC LSTRUCT %token <sym> LCOLAS LFALL LRETURN LDDD -%token <sym> LLEN LCAP LTYPEOF LPANIC LPANICN LPRINT LPRINTN +%token <sym> LLEN LCAP LPANIC LPANICN LPRINT LPRINTN %token <sym> LVAR LTYPE LCONST LCONVERT LSELECT LMAKE LNEW %token <sym> LFOR LIF LELSE LSWITCH LCASE LDEFAULT %token <sym> LBREAK LCONTINUE LGO LGOTO LRANGE @@ -419,6 +419,10 @@ simple_stmt: { if(addtop != N) fatal("exprsym3_list_r LCOLAS expr_list"); + if($3->op == OTYPESW) { + $$ = nod(OTYPESW, $1, $3->left); + break; + } $$ = rev($1); $$ = colas($$, $3); $$ = nod(OAS, $$, $3); @@ -507,6 +511,18 @@ complex_stmt: $$ = nod(OXCASE, $$, N); addtotop($$); } +| LCASE type ':' + { + poptodcl(); + if(typeswvar == N || typeswvar->right == N) { + yyerror("type case not in a type switch"); + $$ = N; + } else + $$ = old2new(typeswvar->right, $2); + $$ = nod(OTYPESW, $$, N); + $$ = nod(OXCASE, $$, N); + addtotop($$); + } | LDEFAULT ':' { poptodcl(); @@ -648,10 +664,20 @@ if_header: } if_body: - if_header compound_stmt + if_header + { + Node *n; + n = $1->ntest; + if(n != N && n->op == OTYPESW) + n = n->left; + else + n = N; + typeswvar = nod(OLIST, typeswvar, n); + } compound_stmt { $$ = $1; - $$->nbody = $2; + $$->nbody = $3; + typeswvar = typeswvar->left; } if_stmt: @@ -836,6 +862,10 @@ pexpr: $$ = nod(ODOTTYPE, $1, N); $$->type = $4; } +| pexpr '.' '(' LTYPE ')' + { + $$ = nod(OTYPESW, $1, N); + } | pexpr '[' expr ']' { $$ = nod(OINDEX, $1, $3); @@ -858,11 +888,6 @@ pexpr: { $$ = nod(OCAP, $3, N); } -| LTYPEOF '(' type ')' - { - $$ = nod(OTYPEOF, N, N); - $$->type = $3; - } | LNEW '(' type ')' { $$ = nod(ONEW, N, N); @@ -1001,7 +1026,6 @@ sym3: | LNEW | LMAKE | LBASETYPE -| LTYPEOF /* * keywords that we can diff --git a/src/cmd/gc/lex.c b/src/cmd/gc/lex.c index 3f7f2638b..7c9c8957b 100644 --- a/src/cmd/gc/lex.c +++ b/src/cmd/gc/lex.c @@ -1110,7 +1110,6 @@ static struct "switch", LSWITCH, Txxx, "true", LTRUE, Txxx, "type", LTYPE, Txxx, - "typeof", LTYPEOF, Txxx, "var", LVAR, Txxx, "notwithstanding", LIGNORE, Txxx, diff --git a/src/cmd/gc/subr.c b/src/cmd/gc/subr.c index aa8b01a53..0cf586eab 100644 --- a/src/cmd/gc/subr.c +++ b/src/cmd/gc/subr.c @@ -715,6 +715,7 @@ opnames[] = [OSELECT] = "SELECT", [OSWITCH] = "SWITCH", [OTYPE] = "TYPE", + [OTYPESW] = "TYPESW", [OVAR] = "VAR", [OIMPORT] = "IMPORT", [OXOR] = "XOR", diff --git a/src/cmd/gc/swt.c b/src/cmd/gc/swt.c index dc3266532..fb3e4b095 100644 --- a/src/cmd/gc/swt.c +++ b/src/cmd/gc/swt.c @@ -4,19 +4,38 @@ #include "go.h" +enum +{ + Snorm = 0, + Strue, + Sfalse, + Stype, +}; + /* * walktype */ Type* -sw0(Node *c, Type *place) +sw0(Node *c, Type *place, int arg) { Node *r; if(c == N) return T; - if(c->op != OAS) { + switch(c->op) { + default: + if(arg == Stype) { + yyerror("inappropriate case for a type switch"); + return T; + } walktype(c, Erv); return T; + case OTYPESW: + if(arg != Stype) + yyerror("inappropriate type case"); + return T; + case OAS: + break; } walktype(c->left, Elv); @@ -47,6 +66,8 @@ sw0(Node *c, Type *place) break; } c->type = types[TBOOL]; + if(arg != Strue) + goto bad; return T; bad: @@ -58,7 +79,7 @@ bad: * return the first type */ Type* -sw1(Node *c, Type *place) +sw1(Node *c, Type *place, int arg) { if(place == T) return c->type; @@ -69,7 +90,7 @@ sw1(Node *c, Type *place) * return a suitable type */ Type* -sw2(Node *c, Type *place) +sw2(Node *c, Type *place, int arg) { return types[TINT]; // botch } @@ -79,7 +100,7 @@ sw2(Node *c, Type *place) * is compat with all the cases */ Type* -sw3(Node *c, Type *place) +sw3(Node *c, Type *place, int arg) { if(place == T) return c->type; @@ -97,7 +118,7 @@ sw3(Node *c, Type *place) * types to cases and switch */ Type* -walkcases(Node *sw, Type*(*call)(Node*, Type*)) +walkcases(Node *sw, Type*(*call)(Node*, Type*, int arg), int arg) { Iter save; Node *n; @@ -105,10 +126,10 @@ walkcases(Node *sw, Type*(*call)(Node*, Type*)) int32 lno; lno = setlineno(sw); - place = call(sw->ntest, T); + place = call(sw->ntest, T, arg); n = listfirst(&save, &sw->nbody->left); - if(n->op == OEMPTY) + if(n == N || n->op == OEMPTY) return T; loop: @@ -122,7 +143,7 @@ loop: if(n->left != N) { setlineno(n->left); - place = call(n->left, place); + place = call(n->left, place, arg); } n = listnext(&save); goto loop; @@ -190,6 +211,7 @@ loop: if(oc == N && os != N) yyerror("first switch statement must be a case"); + // botch - shouldnt fall thru declaration if(os != N && os->op == OXFALL) os->op = OFALL; else @@ -236,23 +258,17 @@ loop: * rebulid case statements into if .. goto */ void -prepsw(Node *sw) +prepsw(Node *sw, int arg) { Iter save; - Node *name, *cas; + Node *name, *bool, *cas; Node *t, *a; - int bool; - - bool = 0; - if(whatis(sw->ntest) == Wlitbool) { - bool = 1; // true - if(sw->ntest->val.u.xval == 0) - bool = 2; // false - } cas = N; name = N; - if(bool == 0) { + bool = N; + + if(arg != Strue && arg != Sfalse) { name = nod(OXXX, N, N); tempname(name, sw->ntest->type); cas = nod(OAS, name, sw->ntest); @@ -263,7 +279,6 @@ prepsw(Node *sw) loop: if(t == N) { sw->nbody->left = rev(cas); - walkstate(sw->nbody->left); //dump("case", sw->nbody->left); return; } @@ -274,22 +289,40 @@ loop: goto loop; } + if(t->left->op == OAS) { + if(bool == N) { + bool = nod(OXXX, N, N); + tempname(bool, types[TBOOL]); + } +//dump("oas", t); + t->left->left = nod(OLIST, t->left->left, bool); + cas = list(cas, t->left); // v,bool = rhs + + a = nod(OIF, N, N); + a->nbody = t->right; // then goto l + a->ntest = bool; + if(arg != Strue) + a->ntest = nod(ONOT, bool, N); + cas = list(cas, a); // if bool goto l + + t = listnext(&save); + goto loop; + } + a = nod(OIF, N, N); a->nbody = t->right; // then goto l - switch(bool) { + switch(arg) { default: // not bool const a->ntest = nod(OEQ, name, t->left); // if name == val break; - case 1: - // bool true + case Strue: a->ntest = t->left; // if val break; - case 2: - // bool false + case Sfalse: a->ntest = nod(ONOT, t->left, N); // if !val break; } @@ -299,35 +332,141 @@ loop: goto loop; } +/* + * convert switch of the form + * switch v := i.(type) { case t1: ..; case t2: ..; } + * into if statements + */ void -walkswitch(Node *n) +typeswitch(Node *sw) { - Type *t; + Iter save; + Node *face, *bool, *cas; + Node *t, *a, *b; - casebody(n); - if(n->ntest == N) - n->ntest = booltrue; +//dump("typeswitch", sw); + + walktype(sw->ntest->right, Erv); + if(!istype(sw->ntest->right->type, TINTER)) { + yyerror("type switch must be on an interface"); + return; + } + walkcases(sw, sw0, Stype); - walkstate(n->ninit); - walktype(n->ntest, Erv); - walkstate(n->nbody); + /* + * predeclare variables for the interface var + * and the boolean var + */ + face = nod(OXXX, N, N); + tempname(face, sw->ntest->right->type); + cas = nod(OAS, face, sw->ntest->right); - // walktype - walkcases(n, sw0); + bool = nod(OXXX, N, N); + tempname(bool, types[TBOOL]); - // find common type - t = n->ntest->type; - if(t == T) - t = walkcases(n, sw1); + t = listfirst(&save, &sw->nbody->left); - // if that fails pick a type - if(t == T) - t = walkcases(n, sw2); +loop: + if(t == N) { + sw->nbody->left = rev(cas); + walkstate(sw->nbody); +//dump("done", sw->nbody->left); + return; + } - // set the type on all literals - if(t != T) { - walkcases(n, sw3); - convlit(n->ntest, t); - prepsw(n); + if(t->left == N) { + cas = list(cas, t->right); // goto default + t = listnext(&save); + goto loop; } + if(t->left->op != OTYPESW) { + t = listnext(&save); + goto loop; + } + + a = t->left->left; // var + a = nod(OLIST, a, bool); // var,bool + + b = nod(ODOTTYPE, face, N); + b->type = t->left->left->type; // interface.(type) + + a = nod(OAS, a, b); // var,bool = interface.(type) + cas = list(cas, a); + + a = nod(OIF, N, N); + a->ntest = bool; + a->nbody = t->right; // if bool { goto l } + cas = list(cas, a); + + t = listnext(&save); + goto loop; +} + +void +walkswitch(Node *sw) +{ + Type *t; + int arg; + +//dump("walkswitch", sw); + + /* + * reorder the body into (OLIST, cases, statements) + * cases have OGOTO into statements. + * both have inserted OBREAK statements + */ + walkstate(sw->ninit); + if(sw->ntest == N) + sw->ntest = booltrue; + casebody(sw); + + /* + * classify the switch test + * Strue or Sfalse if the test is a bool constant + * this allows cases to be map/chan/interface assignments + * as well as (boolean) expressions + * Stype if the test is v := interface.(type) + * this forces all cases to be types + * Snorm otherwise + * all cases are expressions + */ + if(sw->ntest->op == OTYPESW) { + typeswitch(sw); + return; + } + arg = Snorm; + if(whatis(sw->ntest) == Wlitbool) { + arg = Strue; + if(sw->ntest->val.u.xval == 0) + arg = Sfalse; + } + + /* + * init statement is nothing important + */ + walktype(sw->ntest, Erv); +//print("after walkwalks\n"); + + /* + * pass 0,1,2,3 + * walk the cases as appropriate for switch type + */ + walkcases(sw, sw0, arg); + t = sw->ntest->type; + if(t == T) + t = walkcases(sw, sw1, arg); + if(t == T) + t = walkcases(sw, sw2, arg); + if(t == T) + return; + walkcases(sw, sw3, arg); + convlit(sw->ntest, t); +//print("after walkcases\n"); + + /* + * convert the switch into OIF statements + */ + prepsw(sw, arg); + walkstate(sw->nbody); +//print("normal done\n"); } diff --git a/src/runtime/iface.c b/src/runtime/iface.c index c0d3f75aa..34c4a2da8 100644 --- a/src/runtime/iface.c +++ b/src/runtime/iface.c @@ -315,7 +315,7 @@ sys·ifaceI2T2(Sigt *st, Iface i, ...) ret = (byte*)(&i+1); alg = st->hash & 0xFF; wid = st->offset; - ok = (bool*)(ret+rnd(wid, 8)); + ok = (bool*)(ret+rnd(wid, 1)); if(iface_debug) { prints("I2T2 sigt="); |