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; }
/* * type check switch statement */ void typecheckswitch(Node *n) { int top, lno, ptr; char *nilonly; Type *t, *badtype, *missing, *have; NodeList *l, *ll; Node *ncase, *nvar; Node *def; lno = lineno; typechecklist(n->ninit, Etop); nilonly = nil; if(n->ntest != N && n->ntest->op == OTYPESW) { // type switch top = Etype; typecheck(&n->ntest->right, Erv); t = n->ntest->right->type; if(t != T && t->etype != TINTER) yyerror("cannot type switch on non-interface value %lN", n->ntest->right); } else { // value switch top = Erv; if(n->ntest) { typecheck(&n->ntest, Erv); defaultlit(&n->ntest, T); t = n->ntest->type; } else t = types[TBOOL]; if(t) { if(!okforeq[t->etype]) yyerror("cannot switch on %lN", n->ntest); else if(t->etype == TARRAY && !isfixedarray(t)) nilonly = "slice"; else if(t->etype == TARRAY && isfixedarray(t) && algtype1(t, nil) == ANOEQ) yyerror("cannot switch on %lN", n->ntest); else if(t->etype == TSTRUCT && algtype1(t, &badtype) == ANOEQ) yyerror("cannot switch on %lN (struct containing %T cannot be compared)", n->ntest, badtype); else if(t->etype == TFUNC) nilonly = "func"; else if(t->etype == TMAP) nilonly = "map"; } } n->type = t; def = N; for(l=n->list; l; l=l->next) { ncase = l->n; setlineno(n); if(ncase->list == nil) { // default if(def != N) yyerror("multiple defaults in switch (first at %L)", def->lineno); else def = ncase; } else { for(ll=ncase->list; ll; ll=ll->next) { setlineno(ll->n); typecheck(&ll->n, Erv | Etype); if(ll->n->type == T || t == T) continue; setlineno(ncase); switch(top) { case Erv: // expression switch defaultlit(&ll->n, t); if(ll->n->op == OTYPE) yyerror("type %T is not an expression", ll->n->type); else if(ll->n->type != T && !assignop(ll->n->type, t, nil) && !assignop(t, ll->n->type, nil)) { if(n->ntest) yyerror("invalid case %N in switch on %N (mismatched types %T and %T)", ll->n, n->ntest, ll->n->type, t); else yyerror("invalid case %N in switch (mismatched types %T and bool)", ll->n, ll->n->type); } else if(nilonly && !isconst(ll->n, CTNIL)) { yyerror("invalid case %N in switch (can only compare %s %N to nil)", ll->n, nilonly, n->ntest); } break; case Etype: // type switch if(ll->n->op == OLITERAL && istype(ll->n->type, TNIL)) { ; } else if(ll->n->op != OTYPE && ll->n->type != T) { // should this be ||? yyerror("%lN is not a type", ll->n); // reset to original type ll->n = n->ntest->right; } else if(ll->n->type->etype != TINTER && t->etype == TINTER && !implements(ll->n->type, t, &missing, &have, &ptr)) { if(have && !missing->broke && !have->broke) yyerror("impossible type switch case: %lN cannot have dynamic type %T" " (wrong type for %S method)\n\thave %S%hT\n\twant %S%hT", n->ntest->right, ll->n->type, missing->sym, have->sym, have->type, missing->sym, missing->type); else if(!missing->broke) yyerror("impossible type switch case: %lN cannot have dynamic type %T" " (missing %S method)", n->ntest->right, ll->n->type, missing->sym); } break; } } } if(top == Etype && n->type != T) { ll = ncase->list; nvar = ncase->nname; if(nvar != N) { if(ll && ll->next == nil && ll->n->type != T && !istype(ll->n->type, TNIL)) { // single entry type switch nvar->ntype = typenod(ll->n->type); } else { // multiple entry type switch or default nvar->ntype = typenod(n->type); } } } typechecklist(ncase->nbody, Etop); } lineno = lno; }
/******************************************************************************* This function is called to sequence through "blocks" of statements. The entire program is the outer-most block, and each foreach statement begins another one. That is, this function is RECURSIVE!!! *******************************************************************************/ Exprnode doblock(int begstmtidx, int endstmtidx) { Exprnode *lhsexprptr, result; int newdepth, i; int stmtidx; stmtidx = begstmtidx; while (stmtidx <= endstmtidx) { curstmtidx = stmtidx; /* global, for error messages */ switch (stmts[stmtidx].typ) { case PRINTF: case SPRINTF: printfmt(stmtidx); stmtidx++; break; case FOREACH: newdepth = stmts[stmtidx].s.foreach.fldidx; for (i=axistbl[newdepth].first; i<=axistbl[newdepth].last; i++){ curfldvalptrtbl[newdepth] = axistbl[newdepth].array[i]; /* this skips "outer joins" where there is no data */ if (stmts[stmtidx].s.foreach.restrictflag) { chk4badflds(stmts[stmtidx].s.foreach.fldbits, stmts[stmtidx].s.foreach.maxdepth); if (getcount(datarootptr, stmts[stmtidx].s.foreach.fldbits, 0, stmts[stmtidx].s.foreach.maxdepth) == 0) continue; /* skip doblock */ } doblock(stmtidx+1, stmts[stmtidx].s.foreach.next-1); } curfldvalptrtbl[newdepth] = NULL; stmtidx = stmts[stmtidx].s.foreach.next; break; case WHILE: result = *(stmts[stmtidx].s.while_.exprptr); evalexpr(&result); while (result.arg.ival) { doblock(stmtidx+1, stmts[stmtidx].s.while_.next-1); result = *(stmts[stmtidx].s.while_.exprptr); evalexpr(&result); } stmtidx = stmts[stmtidx].s.while_.next; break; case DO: result = *(stmts[stmtidx].s.dowhile.exprptr); evalexpr(&result); if (result.arg.ival) stmtidx = stmts[stmtidx].s.dowhile.next; else stmtidx++; break; case IF: result = *(stmts[stmtidx].s.if_.exprptr); evalexpr(&result); if (result.arg.ival) stmtidx++; else stmtidx = stmts[stmtidx].s.if_.next; break; case ELSE: stmtidx = stmts[stmtidx].s.else_.next; break; case ASSIGNOP: /* assign ops are STATMENTS */ switch (stmts[stmtidx].s.assign.lhsexprptr->typ) { case UFNCPARAMEXPR: lhsexprptr = &argstk[botargstkidx]+stmts[stmtidx].s. assign.lhsexprptr->arg.ival; break; case ARRAYVAREXPR: lhsexprptr = rtgetarrvaraddr( stmts[stmtidx].s.assign.lhsexprptr); break; default: /* an "ordinary" variable */ lhsexprptr = stmts[stmtidx].s.assign.lhsexprptr; break; } assignop(lhsexprptr, stmts[stmtidx].s.assign.optyp, stmts[stmtidx].s.assign.rhsexprptr); stmtidx++; break; case SORT: newdepth = stmts[stmtidx].s.sort.fldidx; sortaxisarray(stmts[stmtidx].s.sort.exprptr, newdepth, stmts[stmtidx].s.sort.reverseflag); stmtidx++; break; case FIRST: newdepth = stmts[stmtidx].s.fstlst.fldidx; result = *(stmts[stmtidx].s.fstlst.exprptr); evalexpr(&result); axistbl[newdepth].last = MIN(axistbl[newdepth].first+result.arg.ival-1, axistbl[newdepth].last); stmtidx++; break; case LAST: newdepth = stmts[stmtidx].s.fstlst.fldidx; result = *(stmts[stmtidx].s.fstlst.exprptr); evalexpr(&result); axistbl[newdepth].first = MAX(axistbl[newdepth].last-result.arg.ival+1, axistbl[newdepth].first); stmtidx++; break; case SYSTEM: result = *(stmts[stmtidx].s.system_.exprptr); evalexpr(&result); if (result.typ == STRING) { (void) system(result.arg.sval); } else { fprintf(stderr, "`system' must be called with a string argument"); } stmtidx++; break; case RETURN: if (stmts[stmtidx].s.return_.exprptr != NULL) { result = *(stmts[stmtidx].s.return_.exprptr); evalexpr(&result); } else { result.typ = NORETVALEXPR; } return result; case EXPRSTMT: result = *(stmts[stmtidx].s.expr.exprptr); evalexpr(&result); stmtidx++; break; case TRAP: updatetraptbl(stmts[stmtidx].s.trap.linnumexprptr, stmts[stmtidx].s.trap.ufncexprptr); stmtidx++; break; default: fatalerrlin("doblock: illegal statement type"); stmtidx++; break; } } result.typ = NORETVALEXPR; return result; }
void typecheckrange(Node *n) { char *why; Type *t, *t1, *t2; Node *v1, *v2; NodeList *ll; // delicate little dance. see typecheckas2 for(ll=n->list; ll; ll=ll->next) if(ll->n->defn != n) typecheck(&ll->n, Erv | Easgn); typecheck(&n->right, Erv); if((t = n->right->type) == T) goto out; if(isptr[t->etype] && isfixedarray(t->type)) t = t->type; n->type = t; switch(t->etype) { default: yyerror("cannot range over %lN", n->right); goto out; case TARRAY: t1 = types[TINT]; t2 = t->type; break; case TMAP: t1 = t->down; t2 = t->type; break; case TCHAN: if(!(t->chan & Crecv)) { yyerror("invalid operation: range %N (receive from send-only type %T)", n->right, n->right->type); goto out; } t1 = t->type; t2 = nil; if(count(n->list) == 2) goto toomany; break; case TSTRING: t1 = types[TINT]; t2 = runetype; break; } if(count(n->list) > 2) { toomany: yyerror("too many variables in range"); } v1 = n->list->n; v2 = N; if(n->list->next) v2 = n->list->next->n; if(v1->defn == n) v1->type = t1; else if(v1->type != T && assignop(t1, v1->type, &why) == 0) yyerror("cannot assign type %T to %lN in range%s", t1, v1, why); if(v2) { if(v2->defn == n) v2->type = t2; else if(v2->type != T && assignop(t2, v2->type, &why) == 0) yyerror("cannot assign type %T to %lN in range%s", t2, v2, why); } out: typechecklist(n->nbody, Etop); // second half of dance n->typecheck = 1; for(ll=n->list; ll; ll=ll->next) if(ll->n->typecheck == 0) typecheck(&ll->n, Erv | Easgn); }