The Go Programming Language

Text file src/cmd/gc/range.c

     1	// Copyright 2009 The Go Authors. All rights reserved.
     2	// Use of this source code is governed by a BSD-style
     3	// license that can be found in the LICENSE file.
     4	
     5	/*
     6	 * range
     7	 */
     8	
     9	#include "go.h"
    10	
    11	void
    12	typecheckrange(Node *n)
    13	{
    14		char *why;
    15		Type *t, *t1, *t2;
    16		Node *v1, *v2;
    17		NodeList *ll;
    18	
    19		// delicate little dance.  see typecheckas2
    20		for(ll=n->list; ll; ll=ll->next)
    21			if(ll->n->defn != n)
    22				typecheck(&ll->n, Erv | Easgn);
    23	
    24		typecheck(&n->right, Erv);
    25		if((t = n->right->type) == T)
    26			goto out;
    27		if(isptr[t->etype] && isfixedarray(t->type))
    28			t = t->type;
    29		n->type = t;
    30	
    31		switch(t->etype) {
    32		default:
    33			yyerror("cannot range over %+N", n->right);
    34			goto out;
    35	
    36		case TARRAY:
    37			t1 = types[TINT];
    38			t2 = t->type;
    39			break;
    40	
    41		case TMAP:
    42			t1 = t->down;
    43			t2 = t->type;
    44			break;
    45	
    46		case TCHAN:
    47			t1 = t->type;
    48			t2 = nil;
    49			if(count(n->list) == 2)
    50				goto toomany;
    51			break;
    52	
    53		case TSTRING:
    54			t1 = types[TINT];
    55			t2 = types[TINT];
    56			break;
    57		}
    58	
    59		if(count(n->list) > 2) {
    60		toomany:
    61			yyerror("too many variables in range");
    62		}
    63	
    64		v1 = n->list->n;
    65		v2 = N;
    66		if(n->list->next)
    67			v2 = n->list->next->n;
    68	
    69		if(v1->defn == n)
    70			v1->type = t1;
    71		else if(v1->type != T && assignop(t1, v1->type, &why) == 0)
    72			yyerror("cannot assign type %T to %+N in range%s", t1, v1, why);
    73		if(v2) {
    74			if(v2->defn == n)
    75				v2->type = t2;
    76			else if(v2->type != T && assignop(t2, v2->type, &why) == 0)
    77				yyerror("cannot assign type %T to %+N in range%s", t2, v2, why);
    78		}
    79	
    80	out:
    81		typechecklist(n->nbody, Etop);
    82	
    83		// second half of dance
    84		n->typecheck = 1;
    85		for(ll=n->list; ll; ll=ll->next)
    86			if(ll->n->typecheck == 0)
    87				typecheck(&ll->n, Erv | Easgn);
    88	}
    89	
    90	void
    91	walkrange(Node *n)
    92	{
    93		Node *ohv1, *hv1, *hv2;	// hidden (old) val 1, 2
    94		Node *ha, *hit;	// hidden aggregate, iterator
    95		Node *hn, *hp;	// hidden len, pointer
    96		Node *hb;  // hidden bool
    97		Node *a, *v1, *v2;	// not hidden aggregate, val 1, 2
    98		Node *fn, *tmp;
    99		NodeList *body, *init;
   100		Type *th, *t;
   101		int lno;
   102	
   103		t = n->type;
   104		init = nil;
   105	
   106		a = n->right;
   107		lno = setlineno(a);
   108		if(t->etype == TSTRING && !eqtype(t, types[TSTRING])) {
   109			a = nod(OCONV, n->right, N);
   110			a->type = types[TSTRING];
   111		}
   112	
   113		v1 = n->list->n;
   114		hv1 = N;
   115	
   116		v2 = N;
   117		if(n->list->next)
   118			v2 = n->list->next->n;
   119		hv2 = N;
   120	
   121		if(v2 == N && t->etype == TARRAY) {
   122			// will have just one reference to argument.
   123			// no need to make a potentially expensive copy.
   124			ha = a;
   125		} else {
   126			ha = nod(OXXX, N, N);
   127			tempname(ha, a->type);
   128			init = list(init, nod(OAS, ha, a));
   129		}
   130	
   131		switch(t->etype) {
   132		default:
   133			fatal("walkrange");
   134	
   135		case TARRAY:
   136			hv1 = nod(OXXX, N, n);
   137			tempname(hv1, types[TINT]);
   138			hn = nod(OXXX, N, N);
   139			tempname(hn, types[TINT]);
   140			hp = nil;
   141	
   142			init = list(init, nod(OAS, hv1, N));
   143			init = list(init, nod(OAS, hn, nod(OLEN, ha, N)));
   144			if(v2) {
   145				hp = nod(OXXX, N, N);
   146				tempname(hp, ptrto(n->type->type));
   147				tmp = nod(OINDEX, ha, nodintconst(0));
   148				tmp->etype = 1;	// no bounds check
   149				init = list(init, nod(OAS, hp, nod(OADDR, tmp, N)));
   150			}
   151	
   152			n->ntest = nod(OLT, hv1, hn);
   153			n->nincr = nod(OASOP, hv1, nodintconst(1));
   154			n->nincr->etype = OADD;
   155			body = list1(nod(OAS, v1, hv1));
   156			if(v2) {
   157				body = list(body, nod(OAS, v2, nod(OIND, hp, N)));
   158				tmp = nod(OADD, hp, nodintconst(t->type->width));
   159				tmp->type = hp->type;
   160				tmp->typecheck = 1;
   161				tmp->right->type = types[tptr];
   162				tmp->right->typecheck = 1;
   163				body = list(body, nod(OAS, hp, tmp));
   164			}
   165			break;
   166	
   167		case TMAP:
   168			th = typ(TARRAY);
   169			th->type = ptrto(types[TUINT8]);
   170			th->bound = (sizeof(struct Hiter) + widthptr - 1) / widthptr;
   171			hit = nod(OXXX, N, N);
   172			tempname(hit, th);
   173	
   174			fn = syslook("mapiterinit", 1);
   175			argtype(fn, t->down);
   176			argtype(fn, t->type);
   177			argtype(fn, th);
   178			init = list(init, mkcall1(fn, T, nil, typename(t), ha, nod(OADDR, hit, N)));
   179			n->ntest = nod(ONE, nod(OINDEX, hit, nodintconst(0)), nodnil());
   180	
   181			fn = syslook("mapiternext", 1);
   182			argtype(fn, th);
   183			n->nincr = mkcall1(fn, T, nil, nod(OADDR, hit, N));
   184	
   185			if(v2 == N) {
   186				fn = syslook("mapiter1", 1);
   187				argtype(fn, th);
   188				argtype(fn, t->down);
   189				a = nod(OAS, v1, mkcall1(fn, t->down, nil, nod(OADDR, hit, N)));
   190			} else {
   191				fn = syslook("mapiter2", 1);
   192				argtype(fn, th);
   193				argtype(fn, t->down);
   194				argtype(fn, t->type);
   195				a = nod(OAS2, N, N);
   196				a->list = list(list1(v1), v2);
   197				a->rlist = list1(mkcall1(fn, getoutargx(fn->type), nil, nod(OADDR, hit, N)));
   198			}
   199			body = list1(a);
   200			break;
   201	
   202		case TCHAN:
   203			hv1 = nod(OXXX, N, n);
   204			tempname(hv1, t->type);
   205			hb = nod(OXXX, N, N);
   206			tempname(hb, types[TBOOL]);
   207	
   208			n->ntest = nod(ONE, hb, nodbool(0));
   209			a = nod(OAS2RECV, N, N);
   210			a->typecheck = 1;
   211			a->list = list(list1(hv1), hb);
   212			a->rlist = list1(nod(ORECV, ha, N));
   213			n->ntest->ninit = list1(a);
   214			body = list1(nod(OAS, v1, hv1));
   215			break;
   216	
   217		case TSTRING:
   218			ohv1 = nod(OXXX, N, N);
   219			tempname(ohv1, types[TINT]);
   220	
   221			hv1 = nod(OXXX, N, N);
   222			tempname(hv1, types[TINT]);
   223			init = list(init, nod(OAS, hv1, N));
   224	
   225			if(v2 == N)
   226				a = nod(OAS, hv1, mkcall("stringiter", types[TINT], nil, ha, hv1));
   227			else {
   228				hv2 = nod(OXXX, N, N);
   229				tempname(hv2, types[TINT]);
   230				a = nod(OAS2, N, N);
   231				a->list = list(list1(hv1), hv2);
   232				fn = syslook("stringiter2", 0);
   233				a->rlist = list1(mkcall1(fn, getoutargx(fn->type), nil, ha, hv1));
   234			}
   235			n->ntest = nod(ONE, hv1, nodintconst(0));
   236			n->ntest->ninit = list(list1(nod(OAS, ohv1, hv1)), a);
   237	
   238			body = list1(nod(OAS, v1, ohv1));
   239			if(v2 != N)
   240				body = list(body, nod(OAS, v2, hv2));
   241			break;
   242		}
   243	
   244		n->op = OFOR;
   245		typechecklist(init, Etop);
   246		n->ninit = concat(n->ninit, init);
   247		typechecklist(n->ntest->ninit, Etop);
   248		typecheck(&n->ntest, Erv);
   249		typecheck(&n->nincr, Etop);
   250		typechecklist(body, Etop);
   251		n->nbody = concat(body, n->nbody);
   252		walkstmt(&n);
   253		
   254		lineno = lno;
   255	}
   256	

release.r60.3. Except as noted, this content is licensed under a Creative Commons Attribution 3.0 License.