mirror of
https://github.com/golang/go
synced 2024-11-26 07:47:57 -07:00
new switch implementation
in preparation of type switch. no functional change (yet). R=r OCL=25784 CL=25788
This commit is contained in:
parent
c93da7c70a
commit
bf983477a2
279
src/cmd/6g/gen.c
279
src/cmd/6g/gen.c
@ -260,8 +260,8 @@ loop:
|
||||
break;
|
||||
|
||||
case OFOR:
|
||||
p1 = gbranch(AJMP, T); // goto test
|
||||
sbreak = breakpc;
|
||||
p1 = gbranch(AJMP, T); // goto test
|
||||
breakpc = gbranch(AJMP, T); // break: goto done
|
||||
scontin = continpc;
|
||||
continpc = pc;
|
||||
@ -299,15 +299,15 @@ loop:
|
||||
break;
|
||||
|
||||
case OSWITCH:
|
||||
p1 = gbranch(AJMP, T); // goto test
|
||||
sbreak = breakpc;
|
||||
p1 = gbranch(AJMP, T); // goto test
|
||||
breakpc = gbranch(AJMP, T); // break: goto done
|
||||
patch(p1, pc); // test:
|
||||
if(labloop != L) {
|
||||
labloop->op = OFOR;
|
||||
labloop->breakpc = breakpc;
|
||||
}
|
||||
swgen(n); // switch(test) body
|
||||
gen(n->nbody, L); // switch(test) body
|
||||
patch(breakpc, pc); // done:
|
||||
breakpc = sbreak;
|
||||
break;
|
||||
@ -367,279 +367,6 @@ ret:
|
||||
lineno = lno;
|
||||
}
|
||||
|
||||
Case*
|
||||
csort(Case *l, int(*f)(Case*, Case*))
|
||||
{
|
||||
Case *l1, *l2, *le;
|
||||
|
||||
if(l == 0 || l->slink == 0)
|
||||
return l;
|
||||
|
||||
l1 = l;
|
||||
l2 = l;
|
||||
for(;;) {
|
||||
l2 = l2->slink;
|
||||
if(l2 == 0)
|
||||
break;
|
||||
l2 = l2->slink;
|
||||
if(l2 == 0)
|
||||
break;
|
||||
l1 = l1->slink;
|
||||
}
|
||||
|
||||
l2 = l1->slink;
|
||||
l1->slink = 0;
|
||||
l1 = csort(l, f);
|
||||
l2 = csort(l2, f);
|
||||
|
||||
/* set up lead element */
|
||||
if((*f)(l1, l2) < 0) {
|
||||
l = l1;
|
||||
l1 = l1->slink;
|
||||
} else {
|
||||
l = l2;
|
||||
l2 = l2->slink;
|
||||
}
|
||||
le = l;
|
||||
|
||||
for(;;) {
|
||||
if(l1 == 0) {
|
||||
while(l2) {
|
||||
le->slink = l2;
|
||||
le = l2;
|
||||
l2 = l2->slink;
|
||||
}
|
||||
le->slink = 0;
|
||||
break;
|
||||
}
|
||||
if(l2 == 0) {
|
||||
while(l1) {
|
||||
le->slink = l1;
|
||||
le = l1;
|
||||
l1 = l1->slink;
|
||||
}
|
||||
break;
|
||||
}
|
||||
if((*f)(l1, l2) < 0) {
|
||||
le->slink = l1;
|
||||
le = l1;
|
||||
l1 = l1->slink;
|
||||
} else {
|
||||
le->slink = l2;
|
||||
le = l2;
|
||||
l2 = l2->slink;
|
||||
}
|
||||
}
|
||||
le->slink = 0;
|
||||
return l;
|
||||
}
|
||||
|
||||
int
|
||||
casecmp(Case *c1, Case *c2)
|
||||
{
|
||||
int w;
|
||||
|
||||
w = whatis(c1->scase);
|
||||
if(w != whatis(c2->scase))
|
||||
fatal("casecmp1");
|
||||
|
||||
switch(w) {
|
||||
case Wlitfloat:
|
||||
return mpcmpfltflt(c1->scase->val.u.fval, c2->scase->val.u.fval);
|
||||
case Wlitint:
|
||||
return mpcmpfixfix(c1->scase->val.u.xval, c2->scase->val.u.xval);
|
||||
case Wlitstr:
|
||||
return cmpslit(c1->scase, c2->scase);
|
||||
// case Wlitbool:
|
||||
// case Wlitnil:
|
||||
}
|
||||
|
||||
fatal("casecmp2");
|
||||
return 0;
|
||||
}
|
||||
|
||||
void
|
||||
swconst(Case *sa, int nc, Node *n1, Node *tmp)
|
||||
{
|
||||
Case *s, *sb;
|
||||
Prog *p1, *p2, *p3;
|
||||
int n;
|
||||
|
||||
// small number of cases --
|
||||
// test them sequentially
|
||||
if(nc < 4) {
|
||||
for(s=sa; s!=C; s=s->slink) {
|
||||
setlineno(s->scase);
|
||||
memset(n1, 0, sizeof(*n1));
|
||||
n1->op = OEQ;
|
||||
n1->left = tmp;
|
||||
n1->right = s->scase;
|
||||
walktype(n1, Erv);
|
||||
bgen(n1, 1, s->sprog);
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
// large number of cases --
|
||||
// find the middle and recur on each half
|
||||
|
||||
n = nc/2;
|
||||
for(s=sa; s!=C; s=s->slink) {
|
||||
n--;
|
||||
if(n == 0)
|
||||
break;
|
||||
}
|
||||
n = nc/2;
|
||||
sb = s->slink;
|
||||
s->slink = C;
|
||||
|
||||
p1 = gbranch(AJMP, T); // goto midcmp
|
||||
p2 = pc; // low half of switch
|
||||
swconst(sa, n, n1, tmp);
|
||||
|
||||
p3 = gbranch(AJMP, T); // goto end
|
||||
patch(p1, pc);
|
||||
|
||||
setlineno(s->scase);
|
||||
memset(n1, 0, sizeof(*n1));
|
||||
n1->op = OLE;
|
||||
n1->left = tmp;
|
||||
n1->right = s->scase;
|
||||
walktype(n1, Erv);
|
||||
bgen(n1, 1, p2);
|
||||
|
||||
swconst(sb, nc-n, n1, tmp); // high half of switch
|
||||
patch(p3, pc);
|
||||
}
|
||||
|
||||
void
|
||||
swgen(Node *n)
|
||||
{
|
||||
Node *c1, *c2;
|
||||
Node n1, tmp;
|
||||
Case *s0, *se, *s, *sa;
|
||||
Prog *p1, *dflt;
|
||||
int32 lno;
|
||||
int any, nc;
|
||||
Iter save1, save2;
|
||||
|
||||
// botch - put most of this code in
|
||||
// walk. gen binary search for
|
||||
// sequence of constant cases
|
||||
|
||||
lno = setlineno(n);
|
||||
|
||||
p1 = gbranch(AJMP, T);
|
||||
s0 = C;
|
||||
se = C;
|
||||
|
||||
// walk thru the body placing breaks
|
||||
// and labels into the case statements
|
||||
|
||||
any = 0;
|
||||
dflt = P;
|
||||
c1 = listfirst(&save1, &n->nbody);
|
||||
while(c1 != N) {
|
||||
setlineno(c1);
|
||||
if(c1->op == OEMPTY)
|
||||
break;
|
||||
if(c1->op != OCASE) {
|
||||
if(s0 == C && dflt == P)
|
||||
yyerror("unreachable statements in a switch");
|
||||
gen(c1, L);
|
||||
|
||||
any = 1;
|
||||
if(c1->op == OFALL)
|
||||
any = 0;
|
||||
c1 = listnext(&save1);
|
||||
continue;
|
||||
}
|
||||
|
||||
// put in the break between cases
|
||||
if(any)
|
||||
patch(gbranch(AJMP, T), breakpc);
|
||||
any = 1;
|
||||
|
||||
// loop over case expressions
|
||||
c2 = listfirst(&save2, &c1->left);
|
||||
if(c2 == N)
|
||||
dflt = pc;
|
||||
|
||||
while(c2 != N) {
|
||||
s = mal(sizeof(*s));
|
||||
if(s0 == C)
|
||||
s0 = s;
|
||||
else
|
||||
se->slink = s;
|
||||
se = s;
|
||||
|
||||
s->scase = c2; // case expression
|
||||
s->sprog = pc; // where to go
|
||||
|
||||
c2 = listnext(&save2);
|
||||
}
|
||||
|
||||
c1 = listnext(&save1);
|
||||
}
|
||||
|
||||
lineno = lno;
|
||||
|
||||
if(any)
|
||||
patch(gbranch(AJMP, T), breakpc);
|
||||
|
||||
patch(p1, pc);
|
||||
|
||||
if(n->ntest != N)
|
||||
if(n->ntest->ninit != N)
|
||||
gen(n->ntest->ninit, L);
|
||||
tempname(&tmp, n->ntest->type);
|
||||
cgen(n->ntest, &tmp);
|
||||
|
||||
sa = C; // base of constant cases
|
||||
nc = 0;
|
||||
for(s=s0; s!=C; s=s->slink) {
|
||||
switch(whatis(s->scase)) {
|
||||
case Wlitfloat:
|
||||
case Wlitint:
|
||||
case Wlitstr:
|
||||
// case Wlitbool:
|
||||
// case Wlitnil:
|
||||
nc++;
|
||||
if(sa == C)
|
||||
sa = s;
|
||||
se = s;
|
||||
continue;
|
||||
}
|
||||
if(sa != C) {
|
||||
se->slink = C;
|
||||
sa = csort(sa, casecmp);
|
||||
swconst(sa, nc, &n1, &tmp);
|
||||
nc = 0;
|
||||
sa = C;
|
||||
}
|
||||
setlineno(s->scase);
|
||||
memset(&n1, 0, sizeof(n1));
|
||||
n1.op = OEQ;
|
||||
n1.left = &tmp;
|
||||
n1.right = s->scase;
|
||||
walktype(&n1, Erv);
|
||||
bgen(&n1, 1, s->sprog);
|
||||
}
|
||||
if(sa != C) {
|
||||
se->slink = C;
|
||||
sa = csort(sa, casecmp);
|
||||
swconst(sa, nc, &n1, &tmp);
|
||||
}
|
||||
if(dflt != P) {
|
||||
patch(gbranch(AJMP, T), dflt);
|
||||
goto ret;
|
||||
}
|
||||
patch(gbranch(AJMP, T), breakpc);
|
||||
|
||||
ret:
|
||||
lineno = lno;
|
||||
}
|
||||
|
||||
void
|
||||
inarggen(void)
|
||||
{
|
||||
|
@ -64,15 +64,6 @@ struct Sig
|
||||
Sig* link;
|
||||
};
|
||||
|
||||
typedef struct Case Case;
|
||||
struct Case
|
||||
{
|
||||
Prog* sprog;
|
||||
Node* scase;
|
||||
Case* slink;
|
||||
};
|
||||
#define C ((Case*)0)
|
||||
|
||||
typedef struct Pool Pool;
|
||||
struct Pool
|
||||
{
|
||||
@ -143,8 +134,6 @@ EXTERN int sizeof_Array; // runtime sizeof(Array)
|
||||
void compile(Node*);
|
||||
void proglist(void);
|
||||
void gen(Node*, Label*);
|
||||
void swgen(Node*);
|
||||
void selgen(Node*);
|
||||
Node* lookdot(Node*, Node*, int);
|
||||
void inarggen(void);
|
||||
void cgen_as(Node*, Node*);
|
||||
|
@ -21,6 +21,7 @@ OFILES=\
|
||||
dcl.$O\
|
||||
export.$O\
|
||||
walk.$O\
|
||||
swt.$O\
|
||||
const.$O\
|
||||
mparith1.$O\
|
||||
mparith2.$O\
|
||||
|
@ -812,8 +812,7 @@ void walktype(Node*, int);
|
||||
void walkconv(Node*);
|
||||
void walkas(Node*);
|
||||
void walkbool(Node*);
|
||||
Type* walkswitch(Node*, Type*(*)(Node*, Type*));
|
||||
int casebody(Node*);
|
||||
void walkswitch(Node*);
|
||||
void walkselect(Node*);
|
||||
int whatis(Node*);
|
||||
void walkdot(Node*);
|
||||
|
@ -547,8 +547,11 @@ loop:
|
||||
return;
|
||||
|
||||
case OCASE:
|
||||
// the right side points to the next case
|
||||
print("%O%J\n", n->op, n);
|
||||
// the right side points to label of the body
|
||||
if(n->right != N && n->right->op == OGOTO && n->right->left->op == ONAME)
|
||||
print("%O%J GOTO %N\n", n->op, n, n->right->left);
|
||||
else
|
||||
print("%O%J\n", n->op, n);
|
||||
dodump(n->left, dep+1);
|
||||
return;
|
||||
}
|
||||
@ -654,8 +657,8 @@ opnames[] =
|
||||
[OCMP] = "CMP",
|
||||
[OFALL] = "FALL",
|
||||
[OCOMPOS] = "COMPOS",
|
||||
[ODOTTYPE] = "DOTTYPE",
|
||||
[OCONV] = "CONV",
|
||||
[ODOTTYPE] = "DOTTYPE",
|
||||
[OCONV] = "CONV",
|
||||
[OCOM] = "COM",
|
||||
[OCONST] = "CONST",
|
||||
[OCONTINUE] = "CONTINUE",
|
||||
@ -724,7 +727,7 @@ opnames[] =
|
||||
[OPRINT] = "PRINT",
|
||||
[OPRINTN] = "PRINTN",
|
||||
[OPARAM] = "PARAM",
|
||||
[ODCL] = "DCL",
|
||||
[ODCL] = "DCL",
|
||||
[OXXX] = "XXX",
|
||||
};
|
||||
|
||||
|
333
src/cmd/gc/swt.c
Normal file
333
src/cmd/gc/swt.c
Normal file
@ -0,0 +1,333 @@
|
||||
// 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.
|
||||
|
||||
#include "go.h"
|
||||
|
||||
/*
|
||||
* walktype
|
||||
*/
|
||||
Type*
|
||||
sw0(Node *c, Type *place)
|
||||
{
|
||||
Node *r;
|
||||
|
||||
if(c == N)
|
||||
return T;
|
||||
if(c->op != OAS) {
|
||||
walktype(c, Erv);
|
||||
return T;
|
||||
}
|
||||
walktype(c->left, Elv);
|
||||
|
||||
r = c->right;
|
||||
if(c == N)
|
||||
return T;
|
||||
|
||||
switch(r->op) {
|
||||
default:
|
||||
goto bad;
|
||||
case ORECV:
|
||||
// <-chan
|
||||
walktype(r->left, Erv);
|
||||
if(!istype(r->left->type, TCHAN))
|
||||
goto bad;
|
||||
break;
|
||||
case OINDEX:
|
||||
// map[e]
|
||||
walktype(r->left, Erv);
|
||||
if(!istype(r->left->type, TMAP))
|
||||
goto bad;
|
||||
break;
|
||||
case ODOTTYPE:
|
||||
// interface.(type)
|
||||
walktype(r->left, Erv);
|
||||
if(!istype(r->left->type, TINTER))
|
||||
goto bad;
|
||||
break;
|
||||
}
|
||||
c->type = types[TBOOL];
|
||||
return T;
|
||||
|
||||
bad:
|
||||
yyerror("inappropriate assignment in a case statement");
|
||||
return T;
|
||||
}
|
||||
|
||||
/*
|
||||
* return the first type
|
||||
*/
|
||||
Type*
|
||||
sw1(Node *c, Type *place)
|
||||
{
|
||||
if(place == T)
|
||||
return c->type;
|
||||
return place;
|
||||
}
|
||||
|
||||
/*
|
||||
* return a suitable type
|
||||
*/
|
||||
Type*
|
||||
sw2(Node *c, Type *place)
|
||||
{
|
||||
return types[TINT]; // botch
|
||||
}
|
||||
|
||||
/*
|
||||
* check that switch type
|
||||
* is compat with all the cases
|
||||
*/
|
||||
Type*
|
||||
sw3(Node *c, Type *place)
|
||||
{
|
||||
if(place == T)
|
||||
return c->type;
|
||||
if(c->type == T)
|
||||
c->type = place;
|
||||
convlit(c, place);
|
||||
if(!ascompat(place, c->type))
|
||||
badtype(OSWITCH, place, c->type);
|
||||
return place;
|
||||
}
|
||||
|
||||
/*
|
||||
* over all cases, call paramenter function.
|
||||
* four passes of these are used to allocate
|
||||
* types to cases and switch
|
||||
*/
|
||||
Type*
|
||||
walkcases(Node *sw, Type*(*call)(Node*, Type*))
|
||||
{
|
||||
Iter save;
|
||||
Node *n;
|
||||
Type *place;
|
||||
int32 lno;
|
||||
|
||||
lno = setlineno(sw);
|
||||
place = call(sw->ntest, T);
|
||||
|
||||
n = listfirst(&save, &sw->nbody->left);
|
||||
if(n->op == OEMPTY)
|
||||
return T;
|
||||
|
||||
loop:
|
||||
if(n == N) {
|
||||
lineno = lno;
|
||||
return place;
|
||||
}
|
||||
|
||||
if(n->op != OCASE)
|
||||
fatal("walkcases: not case %O\n", n->op);
|
||||
|
||||
if(n->left != N) {
|
||||
setlineno(n->left);
|
||||
place = call(n->left, place);
|
||||
}
|
||||
n = listnext(&save);
|
||||
goto loop;
|
||||
}
|
||||
|
||||
Node*
|
||||
newlabel()
|
||||
{
|
||||
static int label;
|
||||
|
||||
label++;
|
||||
snprint(namebuf, sizeof(namebuf), "%.6d", label);
|
||||
return newname(lookup(namebuf));
|
||||
}
|
||||
|
||||
/*
|
||||
* build separate list of statements and cases
|
||||
* make labels between cases and statements
|
||||
* deal with fallthrough, break, unreachable statements
|
||||
*/
|
||||
void
|
||||
casebody(Node *sw)
|
||||
{
|
||||
Iter save;
|
||||
Node *os, *oc, *t, *c;
|
||||
Node *cas, *stat, *def;
|
||||
Node *go, *br;
|
||||
int32 lno;
|
||||
|
||||
lno = setlineno(sw);
|
||||
t = listfirst(&save, &sw->nbody);
|
||||
if(t == N || t->op == OEMPTY) {
|
||||
sw->nbody = nod(OLIST, N, N);
|
||||
return;
|
||||
}
|
||||
|
||||
cas = N; // cases
|
||||
stat = N; // statements
|
||||
def = N; // defaults
|
||||
os = N; // last statement
|
||||
oc = N; // last case
|
||||
br = nod(OBREAK, N, N);
|
||||
|
||||
loop:
|
||||
|
||||
if(t == N) {
|
||||
if(oc == N && os != N)
|
||||
yyerror("first switch statement must be a case");
|
||||
|
||||
stat = list(stat, br);
|
||||
cas = list(cas, def);
|
||||
|
||||
sw->nbody = nod(OLIST, rev(cas), rev(stat));
|
||||
//dump("case", sw->nbody->left);
|
||||
//dump("stat", sw->nbody->right);
|
||||
lineno = lno;
|
||||
return;
|
||||
}
|
||||
|
||||
lno = setlineno(t);
|
||||
|
||||
switch(t->op) {
|
||||
case OXCASE:
|
||||
t->op = OCASE;
|
||||
if(oc == N && os != N)
|
||||
yyerror("first switch statement must be a case");
|
||||
|
||||
if(os != N && os->op == OXFALL)
|
||||
os->op = OFALL;
|
||||
else
|
||||
stat = list(stat, br);
|
||||
|
||||
go = nod(OGOTO, newlabel(), N);
|
||||
|
||||
c = t->left;
|
||||
if(c == N) {
|
||||
if(def != N)
|
||||
yyerror("more than one default case");
|
||||
|
||||
// reuse original default case
|
||||
t->right = go;
|
||||
def = t;
|
||||
}
|
||||
|
||||
// expand multi-valued cases
|
||||
for(; c!=N; c=c->right) {
|
||||
if(c->op != OLIST) {
|
||||
// reuse original case
|
||||
t->left = c;
|
||||
t->right = go;
|
||||
cas = list(cas, t);
|
||||
break;
|
||||
}
|
||||
cas = list(cas, nod(OCASE, c->left, go));
|
||||
}
|
||||
stat = list(stat, nod(OLABEL, go->left, N));
|
||||
oc = t;
|
||||
os = N;
|
||||
break;
|
||||
|
||||
default:
|
||||
stat = list(stat, t);
|
||||
os = t;
|
||||
break;
|
||||
}
|
||||
t = listnext(&save);
|
||||
goto loop;
|
||||
}
|
||||
|
||||
/*
|
||||
* rebulid case statements into if .. goto
|
||||
*/
|
||||
void
|
||||
prepsw(Node *sw)
|
||||
{
|
||||
Iter save;
|
||||
Node *name, *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) {
|
||||
name = nod(OXXX, N, N);
|
||||
tempname(name, sw->ntest->type);
|
||||
cas = nod(OAS, name, sw->ntest);
|
||||
}
|
||||
|
||||
t = listfirst(&save, &sw->nbody->left);
|
||||
|
||||
loop:
|
||||
if(t == N) {
|
||||
sw->nbody->left = rev(cas);
|
||||
walkstate(sw->nbody->left);
|
||||
//dump("case", sw->nbody->left);
|
||||
return;
|
||||
}
|
||||
|
||||
if(t->left == N) {
|
||||
cas = list(cas, t->right); // goto default
|
||||
t = listnext(&save);
|
||||
goto loop;
|
||||
}
|
||||
|
||||
a = nod(OIF, N, N);
|
||||
a->nbody = t->right; // then goto l
|
||||
|
||||
switch(bool) {
|
||||
default:
|
||||
// not bool const
|
||||
a->ntest = nod(OEQ, name, t->left); // if name == val
|
||||
break;
|
||||
|
||||
case 1:
|
||||
// bool true
|
||||
a->ntest = t->left; // if val
|
||||
break;
|
||||
|
||||
case 2:
|
||||
// bool false
|
||||
a->ntest = nod(ONOT, t->left, N); // if !val
|
||||
break;
|
||||
}
|
||||
cas = list(cas, a);
|
||||
|
||||
t = listnext(&save);
|
||||
goto loop;
|
||||
}
|
||||
|
||||
void
|
||||
walkswitch(Node *n)
|
||||
{
|
||||
Type *t;
|
||||
|
||||
casebody(n);
|
||||
if(n->ntest == N)
|
||||
n->ntest = booltrue;
|
||||
|
||||
walkstate(n->ninit);
|
||||
walktype(n->ntest, Erv);
|
||||
walkstate(n->nbody);
|
||||
|
||||
// walktype
|
||||
walkcases(n, sw0);
|
||||
|
||||
// find common type
|
||||
t = n->ntest->type;
|
||||
if(t == T)
|
||||
t = walkcases(n, sw1);
|
||||
|
||||
// if that fails pick a type
|
||||
if(t == T)
|
||||
t = walkcases(n, sw2);
|
||||
|
||||
// set the type on all literals
|
||||
if(t != T) {
|
||||
walkcases(n, sw3);
|
||||
convlit(n->ntest, t);
|
||||
prepsw(n);
|
||||
}
|
||||
}
|
@ -4,9 +4,6 @@
|
||||
|
||||
#include "go.h"
|
||||
|
||||
static Type* sw1(Node*, Type*);
|
||||
static Type* sw2(Node*, Type*);
|
||||
static Type* sw3(Node*, Type*);
|
||||
static Node* curfn;
|
||||
|
||||
enum
|
||||
@ -318,26 +315,7 @@ loop:
|
||||
if(top != Etop)
|
||||
goto nottop;
|
||||
|
||||
casebody(n->nbody);
|
||||
if(n->ntest == N)
|
||||
n->ntest = booltrue;
|
||||
walkstate(n->ninit);
|
||||
walktype(n->ntest, Erv);
|
||||
walkstate(n->nbody);
|
||||
|
||||
// find common type
|
||||
if(n->ntest->type == T)
|
||||
n->ntest->type = walkswitch(n, sw1);
|
||||
|
||||
// if that fails pick a type
|
||||
if(n->ntest->type == T)
|
||||
n->ntest->type = walkswitch(n, sw2);
|
||||
|
||||
// set the type on all literals
|
||||
if(n->ntest->type != T)
|
||||
walkswitch(n, sw3);
|
||||
walktype(n->ntest, Erv); // BOTCH is this right
|
||||
walktype(n->nincr, Erv);
|
||||
walkswitch(n);
|
||||
goto ret;
|
||||
|
||||
case OSELECT:
|
||||
@ -577,7 +555,6 @@ loop:
|
||||
case OCASE:
|
||||
if(top != Etop)
|
||||
goto nottop;
|
||||
walktype(n->left, Erv);
|
||||
walkstate(n->right);
|
||||
goto ret;
|
||||
|
||||
@ -1251,124 +1228,11 @@ walkconv(Node *n)
|
||||
bad:
|
||||
if(l->type != T)
|
||||
yyerror("invalid conversion: %T to %T", l->type, t);
|
||||
else if(n->left->op == OLIST)
|
||||
else
|
||||
if(n->left->op == OLIST)
|
||||
yyerror("invalid type for composite literal: %T", t);
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* return the first type
|
||||
*/
|
||||
Type*
|
||||
sw1(Node *c, Type *place)
|
||||
{
|
||||
if(place == T)
|
||||
return c->type;
|
||||
return place;
|
||||
}
|
||||
|
||||
/*
|
||||
* return a suitable type
|
||||
*/
|
||||
Type*
|
||||
sw2(Node *c, Type *place)
|
||||
{
|
||||
return types[TINT]; // botch
|
||||
}
|
||||
|
||||
/*
|
||||
* check that switch type
|
||||
* is compat with all the cases
|
||||
*/
|
||||
Type*
|
||||
sw3(Node *c, Type *place)
|
||||
{
|
||||
if(place == T)
|
||||
return c->type;
|
||||
if(c->type == T)
|
||||
c->type = place;
|
||||
convlit(c, place);
|
||||
if(!ascompat(place, c->type))
|
||||
badtype(OSWITCH, place, c->type);
|
||||
return place;
|
||||
}
|
||||
|
||||
Type*
|
||||
walkswitch(Node *sw, Type*(*call)(Node*, Type*))
|
||||
{
|
||||
Node *n, *c;
|
||||
Type *place;
|
||||
place = call(sw->ntest, T);
|
||||
|
||||
setlineno(sw);
|
||||
|
||||
n = sw->nbody;
|
||||
if(n->op == OLIST)
|
||||
n = n->left;
|
||||
if(n->op == OEMPTY)
|
||||
return T;
|
||||
|
||||
for(; n!=N; n=n->right) {
|
||||
if(n->op != OCASE)
|
||||
fatal("walkswitch: not case %O\n", n->op);
|
||||
for(c=n->left; c!=N; c=c->right) {
|
||||
if(c->op != OLIST) {
|
||||
setlineno(c);
|
||||
place = call(c, place);
|
||||
break;
|
||||
}
|
||||
setlineno(c);
|
||||
place = call(c->left, place);
|
||||
}
|
||||
}
|
||||
return place;
|
||||
}
|
||||
|
||||
int
|
||||
casebody(Node *n)
|
||||
{
|
||||
Node *oc, *ot, *t;
|
||||
Iter save;
|
||||
|
||||
/*
|
||||
* look to see if statements at top level have
|
||||
* case labels attached to them. convert the illegal
|
||||
* ops XFALL and XCASE into legal ops FALL and CASE.
|
||||
* all unconverted ops will thus be caught as illegal
|
||||
*/
|
||||
|
||||
oc = N; // last case statement
|
||||
ot = N; // last statement (look for XFALL)
|
||||
t = listfirst(&save, &n);
|
||||
|
||||
loop:
|
||||
if(t == N) {
|
||||
/* empty switch */
|
||||
if(oc == N)
|
||||
return 0;
|
||||
return 1;
|
||||
}
|
||||
if(t->op == OXCASE) {
|
||||
/* rewrite and link top level cases */
|
||||
t->op = OCASE;
|
||||
if(oc != N)
|
||||
oc->right = t;
|
||||
oc = t;
|
||||
|
||||
/* rewrite top fall that preceed case */
|
||||
if(ot != N && ot->op == OXFALL)
|
||||
ot->op = OFALL;
|
||||
}
|
||||
|
||||
/* if first statement is not case */
|
||||
if(oc == N)
|
||||
return 0;
|
||||
|
||||
ot = t;
|
||||
t = listnext(&save);
|
||||
goto loop;
|
||||
}
|
||||
|
||||
Node*
|
||||
selcase(Node *n, Node *var)
|
||||
{
|
||||
@ -1477,21 +1341,58 @@ out:
|
||||
return r;
|
||||
}
|
||||
|
||||
/*
|
||||
* enumerate the special cases
|
||||
* of the case statement:
|
||||
* case v := <-chan // select and switch
|
||||
* case v := map[] // switch
|
||||
* case v := interface.(TYPE) // switch
|
||||
*/
|
||||
Node*
|
||||
selectas(Node *name, Node *expr)
|
||||
{
|
||||
Node *a;
|
||||
Type *t;
|
||||
|
||||
if(expr == N || expr->op != ORECV)
|
||||
if(expr == N)
|
||||
goto bad;
|
||||
walktype(expr->left, Erv);
|
||||
t = expr->left->type;
|
||||
if(t == T)
|
||||
switch(expr->op) {
|
||||
default:
|
||||
//dump("case", expr);
|
||||
goto bad;
|
||||
if(t->etype != TCHAN)
|
||||
goto bad;
|
||||
a = old2new(name, t->type);
|
||||
|
||||
case ORECV:
|
||||
walktype(expr->left, Erv);
|
||||
t = expr->left->type;
|
||||
if(t == T)
|
||||
goto bad;
|
||||
if(t->etype != TCHAN)
|
||||
goto bad;
|
||||
t = t->type;
|
||||
break;
|
||||
|
||||
case OINDEX:
|
||||
walktype(expr->left, Erv);
|
||||
walktype(expr->right, Erv);
|
||||
t = expr->left->type;
|
||||
if(t == T)
|
||||
goto bad;
|
||||
if(t->etype != TMAP)
|
||||
goto bad;
|
||||
t = t->type;
|
||||
break;
|
||||
|
||||
case ODOTTYPE:
|
||||
walktype(expr->left, Erv);
|
||||
t = expr->left->type;
|
||||
if(t == T)
|
||||
goto bad;
|
||||
if(t->etype != TINTER)
|
||||
goto bad;
|
||||
t = expr->type;
|
||||
break;
|
||||
}
|
||||
a = old2new(name, t);
|
||||
return a;
|
||||
|
||||
bad:
|
||||
@ -1523,7 +1424,7 @@ walkselect(Node *sel)
|
||||
oc = N; // last case
|
||||
def = N; // default case
|
||||
|
||||
for(count=0; n!=N; n=listnext(&iter)) {
|
||||
for(; n!=N; n=listnext(&iter)) {
|
||||
setlineno(n);
|
||||
|
||||
switch(n->op) {
|
||||
|
Loading…
Reference in New Issue
Block a user