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