github.com/rohankumardubey/syslog-redirector-golang@v0.0.0-20140320174030-4859f03d829a/src/cmd/gc/range.c (about)

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