Ejemplo n.º 1
0
Archivo: swt.c Proyecto: 8l/go
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;
}
Ejemplo n.º 2
0
Archivo: swt.c Proyecto: 8l/go
/*
 * 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;
}
Ejemplo n.º 3
0
/*******************************************************************************
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;
}
Ejemplo n.º 4
0
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);
}