static Node* detachexpr(Node *n, NodeList **init) { Node *addr, *as, *ind, *l; addr = nod(OADDR, n, N); l = temp(ptrto(n->type)); as = nod(OAS, l, addr); typecheck(&as, Etop); walkexpr(&as, init); *init = list(*init, as); ind = nod(OIND, l, N); typecheck(&ind, Erv); walkexpr(&ind, init); return ind; }
static void arraylit(int ctxt, int pass, Node *n, Node *var, NodeList **init) { Node *r, *a; NodeList *l; Node *index, *value; for(l=n->list; l; l=l->next) { r = l->n; if(r->op != OKEY) fatal("arraylit: rhs not OKEY: %N", r); index = r->left; value = r->right; switch(value->op) { case OARRAYLIT: if(value->type->bound < 0) { if(pass == 1 && ctxt != 0) { a = nod(OINDEX, var, index); slicelit(ctxt, value, a, init); } else if(pass == 2 && ctxt == 0) { a = nod(OINDEX, var, index); slicelit(ctxt, value, a, init); } else if(pass == 3) break; continue; } a = nod(OINDEX, var, index); arraylit(ctxt, pass, value, a, init); continue; case OSTRUCTLIT: a = nod(OINDEX, var, index); structlit(ctxt, pass, value, a, init); continue; } if(isliteral(index) && isliteral(value)) { if(pass == 2) continue; } else if(pass == 1) continue; // build list of var[index] = value a = nod(OINDEX, var, index); a = nod(OAS, a, value); typecheck(&a, Etop); walkexpr(&a, init); // add any assignments in r to top if(pass == 1) { if(a->op != OAS) fatal("structlit: not as"); a->dodata = 2; } *init = list(*init, a); } }
static void structlit(int ctxt, int pass, Node *n, Node *var, NodeList **init) { Node *r, *a; NodeList *nl; Node *index, *value; for(nl=n->list; nl; nl=nl->next) { r = nl->n; if(r->op != OKEY) fatal("structlit: rhs not OKEY: %N", r); index = r->left; value = r->right; switch(value->op) { case OARRAYLIT: if(value->type->bound < 0) { if(pass == 1 && ctxt != 0) { a = nod(ODOT, var, newname(index->sym)); slicelit(ctxt, value, a, init); } else if(pass == 2 && ctxt == 0) { a = nod(ODOT, var, newname(index->sym)); slicelit(ctxt, value, a, init); } else if(pass == 3) break; continue; } a = nod(ODOT, var, newname(index->sym)); arraylit(ctxt, pass, value, a, init); continue; case OSTRUCTLIT: a = nod(ODOT, var, newname(index->sym)); structlit(ctxt, pass, value, a, init); continue; } if(isliteral(value)) { if(pass == 2) continue; } else if(pass == 1) continue; // build list of var.field = expr a = nod(ODOT, var, newname(index->sym)); a = nod(OAS, a, value); typecheck(&a, Etop); walkexpr(&a, init); if(pass == 1) { if(a->op != OAS) fatal("structlit: not as"); a->dodata = 2; } *init = list(*init, a); } }
static void litas(Node *l, Node *r, NodeList **init) { Node *a; a = nod(OAS, l, r); typecheck(&a, Etop); walkexpr(&a, init); *init = list(*init, a); }
/* * convert switch of the form * switch v := i.(type) { case t1: ..; case t2: ..; } * into if statements */ static void typeswitch(Node *sw) { Node *def; NodeList *cas, *hash; Node *a, *n; Case *c, *c0, *c1; int ncase; Type *t; Val v; if(sw->ntest == nil) return; if(sw->ntest->right == nil) { setlineno(sw); yyerror("type switch must have an assignment"); return; } walkexpr(&sw->ntest->right, &sw->ninit); if(!istype(sw->ntest->right->type, TINTER)) { yyerror("type switch must be on an interface"); return; } cas = nil; /* * predeclare temporary variables * and the boolean var */ facename = temp(sw->ntest->right->type); a = nod(OAS, facename, sw->ntest->right); typecheck(&a, Etop); cas = list(cas, a); casebody(sw, facename); boolname = temp(types[TBOOL]); typecheck(&boolname, Erv); hashname = temp(types[TUINT32]); typecheck(&hashname, Erv); t = sw->ntest->right->type; if(isnilinter(t)) a = syslook("efacethash", 1); else a = syslook("ifacethash", 1); argtype(a, t); a = nod(OCALL, a, N); a->list = list1(facename); a = nod(OAS, hashname, a); typecheck(&a, Etop); cas = list(cas, a); c0 = mkcaselist(sw, Stype); if(c0 != C && c0->type == Tdefault) { def = c0->node->right; c0 = c0->link; } else { def = nod(OBREAK, N, N); } /* * insert if statement into each case block */ for(c=c0; c!=C; c=c->link) { n = c->node; switch(c->type) { case Ttypenil: v.ctype = CTNIL; a = nod(OIF, N, N); a->ntest = nod(OEQ, facename, nodlit(v)); typecheck(&a->ntest, Erv); a->nbody = list1(n->right); // if i==nil { goto l } n->right = a; break; case Ttypevar: case Ttypeconst: n->right = typeone(n); break; } } /* * generate list of if statements, binary search for constant sequences */ while(c0 != C) { if(c0->type != Ttypeconst) { n = c0->node; cas = list(cas, n->right); c0=c0->link; continue; } // identify run of constants c1 = c = c0; while(c->link!=C && c->link->type==Ttypeconst) c = c->link; c0 = c->link; c->link = nil; // sort by hash c1 = csort(c1, typecmp); // for debugging: linear search if(0) { for(c=c1; c!=C; c=c->link) { n = c->node; cas = list(cas, n->right); } continue; } // combine adjacent cases with the same hash ncase = 0; for(c=c1; c!=C; c=c->link) { ncase++; hash = list1(c->node->right); while(c->link != C && c->link->hash == c->hash) { hash = list(hash, c->link->node->right); c->link = c->link->link; } c->node->right = liststmt(hash); } // binary search among cases to narrow by hash cas = list(cas, typebsw(c1, ncase)); } if(nerrors == 0) { cas = list(cas, def); sw->nbody = concat(cas, sw->nbody); sw->list = nil; walkstmtlist(sw->nbody); } }
/* * normal (expression) switch. * rebulid case statements into if .. goto */ static void exprswitch(Node *sw) { Node *def; NodeList *cas; Node *a; Case *c0, *c, *c1; Type *t; int arg, ncase; casebody(sw, N); arg = Snorm; if(isconst(sw->ntest, CTBOOL)) { arg = Strue; if(sw->ntest->val.u.bval == 0) arg = Sfalse; } walkexpr(&sw->ntest, &sw->ninit); t = sw->type; if(t == T) return; /* * convert the switch into OIF statements */ exprname = N; cas = nil; if(arg != Strue && arg != Sfalse) { exprname = temp(sw->ntest->type); cas = list1(nod(OAS, exprname, sw->ntest)); typechecklist(cas, Etop); } else { exprname = nodbool(arg == Strue); } c0 = mkcaselist(sw, arg); if(c0 != C && c0->type == Tdefault) { def = c0->node->right; c0 = c0->link; } else { def = nod(OBREAK, N, N); } loop: if(c0 == C) { cas = list(cas, def); sw->nbody = concat(cas, sw->nbody); sw->list = nil; walkstmtlist(sw->nbody); return; } // deal with the variables one-at-a-time if(!okforcmp[t->etype] || c0->type != Texprconst) { a = exprbsw(c0, 1, arg); cas = list(cas, a); c0 = c0->link; goto loop; } // do binary search on run of constants ncase = 1; for(c=c0; c->link!=C; c=c->link) { if(c->link->type != Texprconst) break; ncase++; } // break the chain at the count c1 = c->link; c->link = C; // sort and compile constants c0 = csort(c0, exprcmp); a = exprbsw(c0, ncase, arg); cas = list(cas, a); c0 = c1; goto loop; }
/* * convert switch of the form * switch v := i.(type) { case t1: ..; case t2: ..; } * into if statements */ void typeswitch(Node *sw) { Node *def; NodeList *cas; Node *a; Case *c, *c0, *c1; int ncase; Type *t; if(sw->ntest == nil) return; if(sw->ntest->right == nil) { setlineno(sw); yyerror("type switch must have an assignment"); return; } walkexpr(&sw->ntest->right, &sw->ninit); if(!istype(sw->ntest->right->type, TINTER)) { yyerror("type switch must be on an interface"); return; } cas = nil; /* * predeclare temporary variables * and the boolean var */ facename = nod(OXXX, N, N); tempname(facename, sw->ntest->right->type); a = nod(OAS, facename, sw->ntest->right); typecheck(&a, Etop); cas = list(cas, a); casebody(sw, facename); boolname = nod(OXXX, N, N); tempname(boolname, types[TBOOL]); typecheck(&boolname, Erv); hashname = nod(OXXX, N, N); tempname(hashname, types[TUINT32]); typecheck(&hashname, Erv); t = sw->ntest->right->type; if(isnilinter(t)) a = syslook("efacethash", 1); else a = syslook("ifacethash", 1); argtype(a, t); a = nod(OCALL, a, N); a->list = list1(facename); a = nod(OAS, hashname, a); typecheck(&a, Etop); cas = list(cas, a); c0 = mkcaselist(sw, Stype); if(c0 != C && c0->type == Tdefault) { def = c0->node->right; c0 = c0->link; } else { def = nod(OBREAK, N, N); } loop: if(c0 == C) { cas = list(cas, def); sw->nbody = concat(cas, sw->nbody); sw->list = nil; walkstmtlist(sw->nbody); return; } // deal with the variables one-at-a-time if(c0->type != Ttypeconst) { a = typebsw(c0, 1); cas = list(cas, a); c0 = c0->link; goto loop; } // do binary search on run of constants ncase = 1; for(c=c0; c->link!=C; c=c->link) { if(c->link->type != Ttypeconst) break; ncase++; } // break the chain at the count c1 = c->link; c->link = C; // sort and compile constants c0 = csort(c0, typecmp); a = typebsw(c0, ncase); cas = list(cas, a); c0 = c1; goto loop; }
void anylit(int ctxt, Node *n, Node *var, NodeList **init) { Type *t; Node *a, *vstat; t = n->type; switch(n->op) { default: fatal("anylit: not lit"); case OSTRUCTLIT: if(t->etype != TSTRUCT) fatal("anylit: not struct"); if(simplename(var)) { if(ctxt == 0) { // lay out static data vstat = staticname(t, ctxt); structlit(ctxt, 1, n, vstat, init); // copy static to var a = nod(OAS, var, vstat); typecheck(&a, Etop); walkexpr(&a, init); *init = list(*init, a); // add expressions to automatic structlit(ctxt, 2, n, var, init); break; } structlit(ctxt, 1, n, var, init); structlit(ctxt, 2, n, var, init); break; } // initialize of not completely specified if(count(n->list) < structcount(t)) { a = nod(OAS, var, N); typecheck(&a, Etop); walkexpr(&a, init); *init = list(*init, a); } structlit(ctxt, 3, n, var, init); break; case OARRAYLIT: if(t->etype != TARRAY) fatal("anylit: not array"); if(t->bound < 0) { slicelit(ctxt, n, var, init); break; } if(simplename(var)) { if(ctxt == 0) { // lay out static data vstat = staticname(t, ctxt); arraylit(1, 1, n, vstat, init); // copy static to automatic a = nod(OAS, var, vstat); typecheck(&a, Etop); walkexpr(&a, init); *init = list(*init, a); // add expressions to automatic arraylit(ctxt, 2, n, var, init); break; } arraylit(ctxt, 1, n, var, init); arraylit(ctxt, 2, n, var, init); break; } // initialize of not completely specified if(count(n->list) < t->bound) { a = nod(OAS, var, N); typecheck(&a, Etop); walkexpr(&a, init); *init = list(*init, a); } arraylit(ctxt, 3, n, var, init); break; case OMAPLIT: if(t->etype != TMAP) fatal("anylit: not map"); maplit(ctxt, n, var, init); break; } }
static void maplit(int ctxt, Node *n, Node *var, NodeList **init) { Node *r, *a; NodeList *l; int nerr, b; Type *t, *tk, *tv, *t1; Node *vstat, *index, *value; Sym *syma, *symb; ctxt = 0; // make the map var nerr = nerrors; a = nod(OMAKE, N, N); a->list = list1(typenod(n->type)); litas(var, a, init); // count the initializers b = 0; for(l=n->list; l; l=l->next) { r = l->n; if(r->op != OKEY) fatal("slicelit: rhs not OKEY: %N", r); index = r->left; value = r->right; if(isliteral(index) && isliteral(value)) b++; } t = T; if(b != 0) { // build type [count]struct { a Tindex, b Tvalue } t = n->type; tk = t->down; tv = t->type; symb = lookup("b"); t = typ(TFIELD); t->type = tv; t->sym = symb; syma = lookup("a"); t1 = t; t = typ(TFIELD); t->type = tk; t->sym = syma; t->down = t1; t1 = t; t = typ(TSTRUCT); t->type = t1; t1 = t; t = typ(TARRAY); t->bound = b; t->type = t1; dowidth(t); // make and initialize static array vstat = staticname(t, ctxt); b = 0; for(l=n->list; l; l=l->next) { r = l->n; if(r->op != OKEY) fatal("slicelit: rhs not OKEY: %N", r); index = r->left; value = r->right; if(isliteral(index) && isliteral(value)) { // build vstat[b].a = key; a = nodintconst(b); a = nod(OINDEX, vstat, a); a = nod(ODOT, a, newname(syma)); a = nod(OAS, a, index); typecheck(&a, Etop); walkexpr(&a, init); a->dodata = 2; *init = list(*init, a); // build vstat[b].b = value; a = nodintconst(b); a = nod(OINDEX, vstat, a); a = nod(ODOT, a, newname(symb)); a = nod(OAS, a, value); typecheck(&a, Etop); walkexpr(&a, init); a->dodata = 2; *init = list(*init, a); b++; } } // loop adding structure elements to map // for i = 0; i < len(vstat); i++ { // map[vstat[i].a] = vstat[i].b // } index = nod(OXXX, N, N); tempname(index, types[TINT]); a = nod(OINDEX, vstat, index); a->etype = 1; // no bounds checking a = nod(ODOT, a, newname(symb)); r = nod(OINDEX, vstat, index); r->etype = 1; // no bounds checking r = nod(ODOT, r, newname(syma)); r = nod(OINDEX, var, r); r = nod(OAS, r, a); a = nod(OFOR, N, N); a->nbody = list1(r); a->ninit = list1(nod(OAS, index, nodintconst(0))); a->ntest = nod(OLT, index, nodintconst(t->bound)); a->nincr = nod(OASOP, index, nodintconst(1)); a->nincr->etype = OADD; typecheck(&a, Etop); walkstmt(&a); *init = list(*init, a); } // put in dynamic entries one-at-a-time for(l=n->list; l; l=l->next) { r = l->n; if(r->op != OKEY) fatal("slicelit: rhs not OKEY: %N", r); index = r->left; value = r->right; if(isliteral(index) && isliteral(value)) continue; // build list of var[c] = expr a = nod(OINDEX, var, r->left); a = nod(OAS, a, r->right); typecheck(&a, Etop); walkexpr(&a, init); if(nerr != nerrors) break; *init = list(*init, a); } }
static void slicelit(int ctxt, Node *n, Node *var, NodeList **init) { Node *r, *a; NodeList *l; Type *t; Node *vstat, *vauto; Node *index, *value; int mode; // make an array type t = shallow(n->type); t->bound = mpgetfix(n->right->val.u.xval); t->width = 0; t->sym = nil; dowidth(t); if(ctxt != 0) { // put everything into static array vstat = staticname(t, ctxt); arraylit(ctxt, 1, n, vstat, init); arraylit(ctxt, 2, n, vstat, init); // copy static to slice a = nod(OSLICE, vstat, nod(OKEY, N, N)); a = nod(OAS, var, a); typecheck(&a, Etop); a->dodata = 2; *init = list(*init, a); return; } // recipe for var = []t{...} // 1. make a static array // var vstat [...]t // 2. assign (data statements) the constant part // vstat = constpart{} // 3. make an auto pointer to array and allocate heap to it // var vauto *[...]t = new([...]t) // 4. copy the static array to the auto array // *vauto = vstat // 5. assign slice of allocated heap to var // var = [0:]*auto // 6. for each dynamic part assign to the slice // var[i] = dynamic part // // an optimization is done if there is no constant part // 3. var vauto *[...]t = new([...]t) // 5. var = [0:]*auto // 6. var[i] = dynamic part // if the literal contains constants, // make static initialized array (1),(2) vstat = N; mode = getdyn(n, 1); if(mode & MODECONST) { vstat = staticname(t, ctxt); arraylit(ctxt, 1, n, vstat, init); } // make new auto *array (3 declare) vauto = nod(OXXX, N, N); tempname(vauto, ptrto(t)); // set auto to point at new heap (3 assign) a = nod(ONEW, N, N); a->list = list1(typenod(t)); a = nod(OAS, vauto, a); typecheck(&a, Etop); walkexpr(&a, init); *init = list(*init, a); if(vstat != N) { // copy static to heap (4) a = nod(OIND, vauto, N); a = nod(OAS, a, vstat); typecheck(&a, Etop); walkexpr(&a, init); *init = list(*init, a); } // make slice out of heap (5) a = nod(OAS, var, nod(OSLICE, vauto, nod(OKEY, N, N))); typecheck(&a, Etop); walkexpr(&a, init); *init = list(*init, a); // put dynamics into slice (6) for(l=n->list; l; l=l->next) { r = l->n; if(r->op != OKEY) fatal("slicelit: rhs not OKEY: %N", r); index = r->left; value = r->right; a = nod(OINDEX, var, index); a->etype = 1; // no bounds checking // TODO need to check bounds? switch(value->op) { case OARRAYLIT: if(value->type->bound < 0) break; arraylit(ctxt, 2, value, a, init); continue; case OSTRUCTLIT: structlit(ctxt, 2, value, a, init); continue; } if(isliteral(index) && isliteral(value)) continue; // build list of var[c] = expr a = nod(OAS, a, value); typecheck(&a, Etop); walkexpr(&a, init); *init = list(*init, a); } }