github.com/rohankumardubey/syslog-redirector-golang@v0.0.0-20140320174030-4859f03d829a/src/cmd/gc/order.c (about) 1 // Copyright 2012 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 // Rewrite tree to use separate statements to enforce 6 // order of evaluation. Makes walk easier, because it 7 // can (after this runs) reorder at will within an expression. 8 9 #include <u.h> 10 #include <libc.h> 11 #include "go.h" 12 13 static void orderstmt(Node*, NodeList**); 14 static void orderstmtlist(NodeList*, NodeList**); 15 static void orderblock(NodeList **l); 16 static void orderexpr(Node**, NodeList**); 17 static void orderexprlist(NodeList*, NodeList**); 18 19 void 20 order(Node *fn) 21 { 22 orderblock(&fn->nbody); 23 } 24 25 static void 26 orderstmtlist(NodeList *l, NodeList **out) 27 { 28 for(; l; l=l->next) 29 orderstmt(l->n, out); 30 } 31 32 // Order the block of statements *l onto a new list, 33 // and then replace *l with that list. 34 static void 35 orderblock(NodeList **l) 36 { 37 NodeList *out; 38 39 out = nil; 40 orderstmtlist(*l, &out); 41 *l = out; 42 } 43 44 // Order the side effects in *np and leave them as 45 // the init list of the final *np. 46 static void 47 orderexprinplace(Node **np) 48 { 49 Node *n; 50 NodeList *out; 51 52 n = *np; 53 out = nil; 54 orderexpr(&n, &out); 55 addinit(&n, out); 56 *np = n; 57 } 58 59 // Like orderblock, but applied to a single statement. 60 static void 61 orderstmtinplace(Node **np) 62 { 63 Node *n; 64 NodeList *out; 65 66 n = *np; 67 out = nil; 68 orderstmt(n, &out); 69 *np = liststmt(out); 70 } 71 72 // Move n's init list to *out. 73 static void 74 orderinit(Node *n, NodeList **out) 75 { 76 orderstmtlist(n->ninit, out); 77 n->ninit = nil; 78 } 79 80 // Is the list l actually just f() for a multi-value function? 81 static int 82 ismulticall(NodeList *l) 83 { 84 Node *n; 85 86 // one arg only 87 if(l == nil || l->next != nil) 88 return 0; 89 n = l->n; 90 91 // must be call 92 switch(n->op) { 93 default: 94 return 0; 95 case OCALLFUNC: 96 case OCALLMETH: 97 case OCALLINTER: 98 break; 99 } 100 101 // call must return multiple values 102 return n->left->type->outtuple > 1; 103 } 104 105 // n is a multi-value function call. Add t1, t2, .. = n to out 106 // and return the list t1, t2, ... 107 static NodeList* 108 copyret(Node *n, NodeList **out) 109 { 110 Type *t; 111 Node *tmp, *as; 112 NodeList *l1, *l2; 113 Iter tl; 114 115 if(n->type->etype != TSTRUCT || !n->type->funarg) 116 fatal("copyret %T %d", n->type, n->left->type->outtuple); 117 118 l1 = nil; 119 l2 = nil; 120 for(t=structfirst(&tl, &n->type); t; t=structnext(&tl)) { 121 tmp = temp(t->type); 122 l1 = list(l1, tmp); 123 l2 = list(l2, tmp); 124 } 125 126 as = nod(OAS2, N, N); 127 as->list = l1; 128 as->rlist = list1(n); 129 typecheck(&as, Etop); 130 orderstmt(as, out); 131 132 return l2; 133 } 134 135 static void 136 ordercallargs(NodeList **l, NodeList **out) 137 { 138 if(ismulticall(*l)) { 139 // return f() where f() is multiple values. 140 *l = copyret((*l)->n, out); 141 } else { 142 orderexprlist(*l, out); 143 } 144 } 145 146 static void 147 ordercall(Node *n, NodeList **out) 148 { 149 orderexpr(&n->left, out); 150 ordercallargs(&n->list, out); 151 } 152 153 static void 154 orderstmt(Node *n, NodeList **out) 155 { 156 int lno; 157 NodeList *l; 158 Node *r; 159 160 if(n == N) 161 return; 162 163 lno = setlineno(n); 164 165 orderinit(n, out); 166 167 switch(n->op) { 168 default: 169 fatal("orderstmt %O", n->op); 170 171 case OAS2: 172 case OAS2DOTTYPE: 173 case OAS2MAPR: 174 case OAS: 175 case OASOP: 176 case OCLOSE: 177 case OCOPY: 178 case ODELETE: 179 case OPANIC: 180 case OPRINT: 181 case OPRINTN: 182 case ORECOVER: 183 case ORECV: 184 case OSEND: 185 orderexpr(&n->left, out); 186 orderexpr(&n->right, out); 187 orderexprlist(n->list, out); 188 orderexprlist(n->rlist, out); 189 *out = list(*out, n); 190 break; 191 192 case OAS2FUNC: 193 // Special: avoid copy of func call n->rlist->n. 194 orderexprlist(n->list, out); 195 ordercall(n->rlist->n, out); 196 *out = list(*out, n); 197 break; 198 199 case OAS2RECV: 200 // Special: avoid copy of receive. 201 orderexprlist(n->list, out); 202 orderexpr(&n->rlist->n->left, out); // arg to recv 203 *out = list(*out, n); 204 break; 205 206 case OBLOCK: 207 case OEMPTY: 208 // Special: does not save n onto out. 209 orderstmtlist(n->list, out); 210 break; 211 212 case OBREAK: 213 case OCONTINUE: 214 case ODCL: 215 case ODCLCONST: 216 case ODCLTYPE: 217 case OFALL: 218 case_OFALL: 219 case OGOTO: 220 case OLABEL: 221 case ORETJMP: 222 // Special: n->left is not an expression; save as is. 223 *out = list(*out, n); 224 break; 225 226 case OCALLFUNC: 227 case OCALLINTER: 228 case OCALLMETH: 229 // Special: handle call arguments. 230 ordercall(n, out); 231 *out = list(*out, n); 232 break; 233 234 case ODEFER: 235 case OPROC: 236 // Special: order arguments to inner call but not call itself. 237 ordercall(n->left, out); 238 *out = list(*out, n); 239 break; 240 241 case OFOR: 242 orderexprinplace(&n->ntest); 243 orderstmtinplace(&n->nincr); 244 orderblock(&n->nbody); 245 *out = list(*out, n); 246 break; 247 248 case OIF: 249 orderexprinplace(&n->ntest); 250 orderblock(&n->nbody); 251 orderblock(&n->nelse); 252 *out = list(*out, n); 253 break; 254 255 case ORANGE: 256 orderexpr(&n->right, out); 257 for(l=n->list; l; l=l->next) 258 orderexprinplace(&l->n); 259 orderblock(&n->nbody); 260 *out = list(*out, n); 261 break; 262 263 case ORETURN: 264 ordercallargs(&n->list, out); 265 *out = list(*out, n); 266 break; 267 268 case OSELECT: 269 for(l=n->list; l; l=l->next) { 270 if(l->n->op != OXCASE) 271 fatal("order select case %O", l->n->op); 272 r = l->n->left; 273 if(r == nil) 274 continue; 275 switch(r->op) { 276 case OSELRECV: 277 case OSELRECV2: 278 orderexprinplace(&r->left); 279 orderexprinplace(&r->ntest); 280 orderexpr(&r->right->left, &l->n->ninit); 281 break; 282 case OSEND: 283 orderexpr(&r->left, &l->n->ninit); 284 orderexpr(&r->right, &l->n->ninit); 285 break; 286 } 287 } 288 *out = list(*out, n); 289 break; 290 291 case OSWITCH: 292 orderexpr(&n->ntest, out); 293 for(l=n->list; l; l=l->next) { 294 if(l->n->op != OXCASE) 295 fatal("order switch case %O", l->n->op); 296 orderexpr(&l->n->left, &l->n->ninit); 297 } 298 *out = list(*out, n); 299 break; 300 301 case OXFALL: 302 yyerror("fallthrough statement out of place"); 303 n->op = OFALL; 304 goto case_OFALL; 305 } 306 307 lineno = lno; 308 } 309 310 static void 311 orderexprlist(NodeList *l, NodeList **out) 312 { 313 for(; l; l=l->next) 314 orderexpr(&l->n, out); 315 } 316 317 static void 318 orderexpr(Node **np, NodeList **out) 319 { 320 Node *n; 321 int lno; 322 323 n = *np; 324 if(n == N) 325 return; 326 327 lno = setlineno(n); 328 orderinit(n, out); 329 330 switch(n->op) { 331 default: 332 orderexpr(&n->left, out); 333 orderexpr(&n->right, out); 334 orderexprlist(n->list, out); 335 orderexprlist(n->rlist, out); 336 break; 337 338 case OANDAND: 339 case OOROR: 340 orderexpr(&n->left, out); 341 orderexprinplace(&n->right); 342 break; 343 344 case OCALLFUNC: 345 case OCALLMETH: 346 case OCALLINTER: 347 ordercall(n, out); 348 n = copyexpr(n, n->type, out); 349 break; 350 351 case ORECV: 352 n = copyexpr(n, n->type, out); 353 break; 354 } 355 356 lineno = lno; 357 358 *np = n; 359 }