Commit a4a10ed8 authored by Ken Thompson's avatar Ken Thompson

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
parent b0609f14
...@@ -329,7 +329,7 @@ enum ...@@ -329,7 +329,7 @@ enum
OKEY, OPARAM, OKEY, OPARAM,
OCOMPOS, OCOMPOS,
OCONV, OCONV,
ODOTTYPE, ODOTTYPE, OTYPESW,
OBAD, OBAD,
OEXTEND, // 6g internal OEXTEND, // 6g internal
...@@ -526,6 +526,7 @@ EXTERN Node* retnil; ...@@ -526,6 +526,7 @@ EXTERN Node* retnil;
EXTERN Node* fskel; EXTERN Node* fskel;
EXTERN Node* addtop; EXTERN Node* addtop;
EXTERN Node* typeswvar;
EXTERN char* context; EXTERN char* context;
EXTERN char* pkgcontext; EXTERN char* pkgcontext;
......
...@@ -18,7 +18,7 @@ ...@@ -18,7 +18,7 @@
%token <sym> LPACKAGE LIMPORT LDEFER %token <sym> LPACKAGE LIMPORT LDEFER
%token <sym> LMAP LCHAN LINTERFACE LFUNC LSTRUCT %token <sym> LMAP LCHAN LINTERFACE LFUNC LSTRUCT
%token <sym> LCOLAS LFALL LRETURN LDDD %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> LVAR LTYPE LCONST LCONVERT LSELECT LMAKE LNEW
%token <sym> LFOR LIF LELSE LSWITCH LCASE LDEFAULT %token <sym> LFOR LIF LELSE LSWITCH LCASE LDEFAULT
%token <sym> LBREAK LCONTINUE LGO LGOTO LRANGE %token <sym> LBREAK LCONTINUE LGO LGOTO LRANGE
...@@ -419,6 +419,10 @@ simple_stmt: ...@@ -419,6 +419,10 @@ simple_stmt:
{ {
if(addtop != N) if(addtop != N)
fatal("exprsym3_list_r LCOLAS expr_list"); fatal("exprsym3_list_r LCOLAS expr_list");
if($3->op == OTYPESW) {
$$ = nod(OTYPESW, $1, $3->left);
break;
}
$$ = rev($1); $$ = rev($1);
$$ = colas($$, $3); $$ = colas($$, $3);
$$ = nod(OAS, $$, $3); $$ = nod(OAS, $$, $3);
...@@ -507,6 +511,18 @@ complex_stmt: ...@@ -507,6 +511,18 @@ complex_stmt:
$$ = nod(OXCASE, $$, N); $$ = nod(OXCASE, $$, N);
addtotop($$); 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 ':' | LDEFAULT ':'
{ {
poptodcl(); poptodcl();
...@@ -648,10 +664,20 @@ if_header: ...@@ -648,10 +664,20 @@ if_header:
} }
if_body: 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; $$ = $1;
$$->nbody = $2; $$->nbody = $3;
typeswvar = typeswvar->left;
} }
if_stmt: if_stmt:
...@@ -836,6 +862,10 @@ pexpr: ...@@ -836,6 +862,10 @@ pexpr:
$$ = nod(ODOTTYPE, $1, N); $$ = nod(ODOTTYPE, $1, N);
$$->type = $4; $$->type = $4;
} }
| pexpr '.' '(' LTYPE ')'
{
$$ = nod(OTYPESW, $1, N);
}
| pexpr '[' expr ']' | pexpr '[' expr ']'
{ {
$$ = nod(OINDEX, $1, $3); $$ = nod(OINDEX, $1, $3);
...@@ -858,11 +888,6 @@ pexpr: ...@@ -858,11 +888,6 @@ pexpr:
{ {
$$ = nod(OCAP, $3, N); $$ = nod(OCAP, $3, N);
} }
| LTYPEOF '(' type ')'
{
$$ = nod(OTYPEOF, N, N);
$$->type = $3;
}
| LNEW '(' type ')' | LNEW '(' type ')'
{ {
$$ = nod(ONEW, N, N); $$ = nod(ONEW, N, N);
...@@ -1001,7 +1026,6 @@ sym3: ...@@ -1001,7 +1026,6 @@ sym3:
| LNEW | LNEW
| LMAKE | LMAKE
| LBASETYPE | LBASETYPE
| LTYPEOF
/* /*
* keywords that we can * keywords that we can
......
...@@ -1110,7 +1110,6 @@ static struct ...@@ -1110,7 +1110,6 @@ static struct
"switch", LSWITCH, Txxx, "switch", LSWITCH, Txxx,
"true", LTRUE, Txxx, "true", LTRUE, Txxx,
"type", LTYPE, Txxx, "type", LTYPE, Txxx,
"typeof", LTYPEOF, Txxx,
"var", LVAR, Txxx, "var", LVAR, Txxx,
"notwithstanding", LIGNORE, Txxx, "notwithstanding", LIGNORE, Txxx,
......
...@@ -715,6 +715,7 @@ opnames[] = ...@@ -715,6 +715,7 @@ opnames[] =
[OSELECT] = "SELECT", [OSELECT] = "SELECT",
[OSWITCH] = "SWITCH", [OSWITCH] = "SWITCH",
[OTYPE] = "TYPE", [OTYPE] = "TYPE",
[OTYPESW] = "TYPESW",
[OVAR] = "VAR", [OVAR] = "VAR",
[OIMPORT] = "IMPORT", [OIMPORT] = "IMPORT",
[OXOR] = "XOR", [OXOR] = "XOR",
......
...@@ -4,19 +4,38 @@ ...@@ -4,19 +4,38 @@
#include "go.h" #include "go.h"
enum
{
Snorm = 0,
Strue,
Sfalse,
Stype,
};
/* /*
* walktype * walktype
*/ */
Type* Type*
sw0(Node *c, Type *place) sw0(Node *c, Type *place, int arg)
{ {
Node *r; Node *r;
if(c == N) if(c == N)
return T; 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); walktype(c, Erv);
return T; return T;
case OTYPESW:
if(arg != Stype)
yyerror("inappropriate type case");
return T;
case OAS:
break;
} }
walktype(c->left, Elv); walktype(c->left, Elv);
...@@ -47,6 +66,8 @@ sw0(Node *c, Type *place) ...@@ -47,6 +66,8 @@ sw0(Node *c, Type *place)
break; break;
} }
c->type = types[TBOOL]; c->type = types[TBOOL];
if(arg != Strue)
goto bad;
return T; return T;
bad: bad:
...@@ -58,7 +79,7 @@ bad: ...@@ -58,7 +79,7 @@ bad:
* return the first type * return the first type
*/ */
Type* Type*
sw1(Node *c, Type *place) sw1(Node *c, Type *place, int arg)
{ {
if(place == T) if(place == T)
return c->type; return c->type;
...@@ -69,7 +90,7 @@ sw1(Node *c, Type *place) ...@@ -69,7 +90,7 @@ sw1(Node *c, Type *place)
* return a suitable type * return a suitable type
*/ */
Type* Type*
sw2(Node *c, Type *place) sw2(Node *c, Type *place, int arg)
{ {
return types[TINT]; // botch return types[TINT]; // botch
} }
...@@ -79,7 +100,7 @@ sw2(Node *c, Type *place) ...@@ -79,7 +100,7 @@ sw2(Node *c, Type *place)
* is compat with all the cases * is compat with all the cases
*/ */
Type* Type*
sw3(Node *c, Type *place) sw3(Node *c, Type *place, int arg)
{ {
if(place == T) if(place == T)
return c->type; return c->type;
...@@ -97,7 +118,7 @@ sw3(Node *c, Type *place) ...@@ -97,7 +118,7 @@ sw3(Node *c, Type *place)
* types to cases and switch * types to cases and switch
*/ */
Type* Type*
walkcases(Node *sw, Type*(*call)(Node*, Type*)) walkcases(Node *sw, Type*(*call)(Node*, Type*, int arg), int arg)
{ {
Iter save; Iter save;
Node *n; Node *n;
...@@ -105,10 +126,10 @@ walkcases(Node *sw, Type*(*call)(Node*, Type*)) ...@@ -105,10 +126,10 @@ walkcases(Node *sw, Type*(*call)(Node*, Type*))
int32 lno; int32 lno;
lno = setlineno(sw); lno = setlineno(sw);
place = call(sw->ntest, T); place = call(sw->ntest, T, arg);
n = listfirst(&save, &sw->nbody->left); n = listfirst(&save, &sw->nbody->left);
if(n->op == OEMPTY) if(n == N || n->op == OEMPTY)
return T; return T;
loop: loop:
...@@ -122,7 +143,7 @@ loop: ...@@ -122,7 +143,7 @@ loop:
if(n->left != N) { if(n->left != N) {
setlineno(n->left); setlineno(n->left);
place = call(n->left, place); place = call(n->left, place, arg);
} }
n = listnext(&save); n = listnext(&save);
goto loop; goto loop;
...@@ -190,6 +211,7 @@ loop: ...@@ -190,6 +211,7 @@ loop:
if(oc == N && os != N) if(oc == N && os != N)
yyerror("first switch statement must be a case"); yyerror("first switch statement must be a case");
// botch - shouldnt fall thru declaration
if(os != N && os->op == OXFALL) if(os != N && os->op == OXFALL)
os->op = OFALL; os->op = OFALL;
else else
...@@ -236,23 +258,17 @@ loop: ...@@ -236,23 +258,17 @@ loop:
* rebulid case statements into if .. goto * rebulid case statements into if .. goto
*/ */
void void
prepsw(Node *sw) prepsw(Node *sw, int arg)
{ {
Iter save; Iter save;
Node *name, *cas; Node *name, *bool, *cas;
Node *t, *a; 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; cas = N;
name = N; name = N;
if(bool == 0) { bool = N;
if(arg != Strue && arg != Sfalse) {
name = nod(OXXX, N, N); name = nod(OXXX, N, N);
tempname(name, sw->ntest->type); tempname(name, sw->ntest->type);
cas = nod(OAS, name, sw->ntest); cas = nod(OAS, name, sw->ntest);
...@@ -263,7 +279,6 @@ prepsw(Node *sw) ...@@ -263,7 +279,6 @@ prepsw(Node *sw)
loop: loop:
if(t == N) { if(t == N) {
sw->nbody->left = rev(cas); sw->nbody->left = rev(cas);
walkstate(sw->nbody->left);
//dump("case", sw->nbody->left); //dump("case", sw->nbody->left);
return; return;
} }
...@@ -274,22 +289,40 @@ loop: ...@@ -274,22 +289,40 @@ loop:
goto 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 = nod(OIF, N, N);
a->nbody = t->right; // then goto l a->nbody = t->right; // then goto l
switch(bool) { switch(arg) {
default: default:
// not bool const // not bool const
a->ntest = nod(OEQ, name, t->left); // if name == val a->ntest = nod(OEQ, name, t->left); // if name == val
break; break;
case 1: case Strue:
// bool true
a->ntest = t->left; // if val a->ntest = t->left; // if val
break; break;
case 2: case Sfalse:
// bool false
a->ntest = nod(ONOT, t->left, N); // if !val a->ntest = nod(ONOT, t->left, N); // if !val
break; break;
} }
...@@ -299,35 +332,141 @@ loop: ...@@ -299,35 +332,141 @@ loop:
goto loop; goto loop;
} }
/*
* convert switch of the form
* switch v := i.(type) { case t1: ..; case t2: ..; }
* into if statements
*/
void void
walkswitch(Node *n) typeswitch(Node *sw)
{ {
Type *t; Iter save;
Node *face, *bool, *cas;
Node *t, *a, *b;
casebody(n); //dump("typeswitch", sw);
if(n->ntest == N)
n->ntest = booltrue; 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); * predeclare variables for the interface var
walkstate(n->nbody); * and the boolean var
*/
face = nod(OXXX, N, N);
tempname(face, sw->ntest->right->type);
cas = nod(OAS, face, sw->ntest->right);
// walktype bool = nod(OXXX, N, N);
walkcases(n, sw0); tempname(bool, types[TBOOL]);
// find common type t = listfirst(&save, &sw->nbody->left);
t = n->ntest->type;
if(t == T)
t = walkcases(n, sw1);
// if that fails pick a type loop:
if(t == T) if(t == N) {
t = walkcases(n, sw2); sw->nbody->left = rev(cas);
walkstate(sw->nbody);
//dump("done", sw->nbody->left);
return;
}
// set the type on all literals if(t->left == N) {
if(t != T) { cas = list(cas, t->right); // goto default
walkcases(n, sw3); t = listnext(&save);
convlit(n->ntest, t); goto loop;
prepsw(n);
} }
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");
} }
...@@ -315,7 +315,7 @@ sys·ifaceI2T2(Sigt *st, Iface i, ...) ...@@ -315,7 +315,7 @@ sys·ifaceI2T2(Sigt *st, Iface i, ...)
ret = (byte*)(&i+1); ret = (byte*)(&i+1);
alg = st->hash & 0xFF; alg = st->hash & 0xFF;
wid = st->offset; wid = st->offset;
ok = (bool*)(ret+rnd(wid, 8)); ok = (bool*)(ret+rnd(wid, 1));
if(iface_debug) { if(iface_debug) {
prints("I2T2 sigt="); prints("I2T2 sigt=");
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment