static Node* typeone(Node *t) { NodeList *init; Node *a, *b, *var; var = t->nname; init = nil; if(var == N) { typecheck(&nblank, Erv | Easgn); var = nblank; } else init = list1(nod(ODCL, var, N)); a = nod(OAS2, N, N); a->list = list(list1(var), boolname); // var,bool = b = nod(ODOTTYPE, facename, N); b->type = t->left->type; // interface.(type) a->rlist = list1(b); typecheck(&a, Etop); init = list(init, a); b = nod(OIF, N, N); b->ntest = boolname; b->nbody = list1(t->right); // if bool { goto l } a = liststmt(list(init, b)); return a; }
static Node* exprbsw(Case *c0, int ncase, int arg) { NodeList *cas; Node *a, *n; Case *c; int i, half, lno; cas = nil; if(ncase < Ncase) { for(i=0; i<ncase; i++) { n = c0->node; lno = setlineno(n); if(assignop(n->left->type, exprname->type, nil) == OCONVIFACE || assignop(exprname->type, n->left->type, nil) == OCONVIFACE) goto snorm; switch(arg) { case Strue: a = nod(OIF, N, N); a->ntest = n->left; // if val a->nbody = list1(n->right); // then goto l break; case Sfalse: a = nod(OIF, N, N); a->ntest = nod(ONOT, n->left, N); // if !val typecheck(&a->ntest, Erv); a->nbody = list1(n->right); // then goto l break; default: snorm: a = nod(OIF, N, N); a->ntest = nod(OEQ, exprname, n->left); // if name == val typecheck(&a->ntest, Erv); a->nbody = list1(n->right); // then goto l break; } cas = list(cas, a); c0 = c0->link; lineno = lno; } return liststmt(cas); } // find the middle and recur c = c0; half = ncase>>1; for(i=1; i<half; i++) c = c->link; a = nod(OIF, N, N); a->ntest = nod(OLE, exprname, c->node->left); typecheck(&a->ntest, Erv); a->nbody = list1(exprbsw(c0, half, arg)); a->nelse = list1(exprbsw(c->link, ncase-half, arg)); return a; }
Node* typebsw(Case *c0, int ncase) { NodeList *cas; Node *a, *n; Case *c; int i, half; Val v; cas = nil; if(ncase < Ncase) { for(i=0; i<ncase; i++) { n = c0->node; switch(c0->type) { case Ttypenil: v.ctype = CTNIL; a = nod(OIF, N, N); a->ntest = nod(OEQ, facename, nodlit(v)); typecheck(&a->ntest, Erv); a->nbody = list1(n->right); // if i==nil { goto l } cas = list(cas, a); break; case Ttypevar: a = typeone(n); cas = list(cas, a); break; case Ttypeconst: a = nod(OIF, N, N); a->ntest = nod(OEQ, hashname, nodintconst(c0->hash)); typecheck(&a->ntest, Erv); a->nbody = list1(typeone(n)); cas = list(cas, a); break; } c0 = c0->link; } return liststmt(cas); } // find the middle and recur c = c0; half = ncase>>1; for(i=1; i<half; i++) c = c->link; a = nod(OIF, N, N); a->ntest = nod(OLE, hashname, nodintconst(c->hash)); typecheck(&a->ntest, Erv); a->nbody = list1(typebsw(c0, half)); a->nelse = list1(typebsw(c->link, ncase-half)); return a; }
// Like orderblock, but applied to a single statement. static void orderstmtinplace(Node **np) { Node *n; NodeList *out; n = *np; out = nil; orderstmt(n, &out); *np = liststmt(out); }
static Node* typebsw(Case *c0, int ncase) { NodeList *cas; Node *a, *n; Case *c; int i, half; cas = nil; if(ncase < Ncase) { for(i=0; i<ncase; i++) { n = c0->node; if(c0->type != Ttypeconst) fatal("typebsw"); a = nod(OIF, N, N); a->ntest = nod(OEQ, hashname, nodintconst(c0->hash)); typecheck(&a->ntest, Erv); a->nbody = list1(n->right); cas = list(cas, a); c0 = c0->link; } return liststmt(cas); } // find the middle and recur c = c0; half = ncase>>1; for(i=1; i<half; i++) c = c->link; a = nod(OIF, N, N); a->ntest = nod(OLE, hashname, nodintconst(c->hash)); typecheck(&a->ntest, Erv); a->nbody = list1(typebsw(c0, half)); a->nelse = list1(typebsw(c->link, ncase-half)); return a; }
/* * convert switch of the form * switch v := i.(type) { case t1: ..; case t2: ..; } * into if statements */ static void typeswitch(Node *sw) { Node *def; NodeList *cas, *hash; Node *a, *n; Case *c, *c0, *c1; int ncase; Type *t; Val v; if(sw->ntest == nil) return; if(sw->ntest->right == nil) { setlineno(sw); yyerror("type switch must have an assignment"); return; } walkexpr(&sw->ntest->right, &sw->ninit); if(!istype(sw->ntest->right->type, TINTER)) { yyerror("type switch must be on an interface"); return; } cas = nil; /* * predeclare temporary variables * and the boolean var */ facename = temp(sw->ntest->right->type); a = nod(OAS, facename, sw->ntest->right); typecheck(&a, Etop); cas = list(cas, a); casebody(sw, facename); boolname = temp(types[TBOOL]); typecheck(&boolname, Erv); hashname = temp(types[TUINT32]); typecheck(&hashname, Erv); t = sw->ntest->right->type; if(isnilinter(t)) a = syslook("efacethash", 1); else a = syslook("ifacethash", 1); argtype(a, t); a = nod(OCALL, a, N); a->list = list1(facename); a = nod(OAS, hashname, a); typecheck(&a, Etop); cas = list(cas, a); c0 = mkcaselist(sw, Stype); if(c0 != C && c0->type == Tdefault) { def = c0->node->right; c0 = c0->link; } else { def = nod(OBREAK, N, N); } /* * insert if statement into each case block */ for(c=c0; c!=C; c=c->link) { n = c->node; switch(c->type) { case Ttypenil: v.ctype = CTNIL; a = nod(OIF, N, N); a->ntest = nod(OEQ, facename, nodlit(v)); typecheck(&a->ntest, Erv); a->nbody = list1(n->right); // if i==nil { goto l } n->right = a; break; case Ttypevar: case Ttypeconst: n->right = typeone(n); break; } } /* * generate list of if statements, binary search for constant sequences */ while(c0 != C) { if(c0->type != Ttypeconst) { n = c0->node; cas = list(cas, n->right); c0=c0->link; continue; } // identify run of constants c1 = c = c0; while(c->link!=C && c->link->type==Ttypeconst) c = c->link; c0 = c->link; c->link = nil; // sort by hash c1 = csort(c1, typecmp); // for debugging: linear search if(0) { for(c=c1; c!=C; c=c->link) { n = c->node; cas = list(cas, n->right); } continue; } // combine adjacent cases with the same hash ncase = 0; for(c=c1; c!=C; c=c->link) { ncase++; hash = list1(c->node->right); while(c->link != C && c->link->hash == c->hash) { hash = list(hash, c->link->node->right); c->link = c->link->link; } c->node->right = liststmt(hash); } // binary search among cases to narrow by hash cas = list(cas, typebsw(c1, ncase)); } if(nerrors == 0) { cas = list(cas, def); sw->nbody = concat(cas, sw->nbody); sw->list = nil; walkstmtlist(sw->nbody); } }