| // Copyright 2009 The Go Authors. All rights reserved. |
| // Use of this source code is governed by a BSD-style |
| // license that can be found in the LICENSE file. |
| |
| /* |
| * static initialization |
| */ |
| |
| #include "go.h" |
| |
| static void |
| init1(Node *n, NodeList **out) |
| { |
| NodeList *l; |
| |
| if(n == N) |
| return; |
| init1(n->left, out); |
| init1(n->right, out); |
| for(l=n->list; l; l=l->next) |
| init1(l->n, out); |
| |
| if(n->op != ONAME) |
| return; |
| switch(n->class) { |
| case PEXTERN: |
| case PFUNC: |
| break; |
| default: |
| return; |
| } |
| |
| if(n->initorder == 1) |
| return; |
| if(n->initorder == 2) |
| fatal("init loop"); |
| |
| // make sure that everything n depends on is initialized. |
| // n->defn is an assignment to n |
| n->initorder = 2; |
| if(n->defn != N) { |
| switch(n->defn->op) { |
| default: |
| goto bad; |
| |
| case ODCLFUNC: |
| for(l=n->defn->nbody; l; l=l->next) |
| init1(l->n, out); |
| break; |
| |
| case OAS: |
| if(n->defn->left != n) |
| goto bad; |
| n->defn->dodata = 1; |
| init1(n->defn->right, out); |
| if(debug['j']) |
| print("%S\n", n->sym); |
| *out = list(*out, n->defn); |
| break; |
| } |
| } |
| n->initorder = 1; |
| return; |
| |
| bad: |
| dump("defn", n->defn); |
| fatal("init1: bad defn"); |
| } |
| |
| static void |
| initreorder(NodeList *l, NodeList **out) |
| { |
| Node *n; |
| |
| for(; l; l=l->next) { |
| n = l->n; |
| switch(n->op) { |
| case ODCLFUNC: |
| case ODCLCONST: |
| case ODCLTYPE: |
| continue; |
| } |
| initreorder(n->ninit, out); |
| n->ninit = nil; |
| init1(n, out); |
| } |
| } |
| |
| NodeList* |
| initfix(NodeList *l) |
| { |
| NodeList *lout; |
| |
| lout = nil; |
| initreorder(l, &lout); |
| return lout; |
| } |
| |
| /* |
| * from here down is the walk analysis |
| * of composit literals. |
| * most of the work is to generate |
| * data statements for the constant |
| * part of the composit literal. |
| */ |
| |
| static int |
| isliteral(Node *n) |
| { |
| if(n->op == OLITERAL) |
| if(n->val.ctype != CTNIL) |
| return 1; |
| return 0; |
| } |
| |
| static int |
| simplename(Node *n) |
| { |
| if(n->op != ONAME) |
| goto no; |
| if(!n->addable) |
| goto no; |
| if(n->class & PHEAP) |
| goto no; |
| if(n->class == PPARAMREF) |
| goto no; |
| return 1; |
| |
| no: |
| return 0; |
| } |
| |
| static void arraylit(Node *n, Node *var, int pass, NodeList **init); |
| |
| static void |
| structlit(Node *n, Node *var, int pass, 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) |
| break; |
| a = nod(ODOT, var, newname(index->sym)); |
| arraylit(value, a, pass, init); |
| continue; |
| |
| case OSTRUCTLIT: |
| a = nod(ODOT, var, newname(index->sym)); |
| structlit(value, a, pass, 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 |
| arraylit(Node *n, Node *var, int pass, 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) |
| break; |
| a = nod(OINDEX, var, index); |
| arraylit(value, a, pass, init); |
| continue; |
| |
| case OSTRUCTLIT: |
| a = nod(OINDEX, var, index); |
| structlit(value, a, pass, 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 |
| slicelit(Node *n, Node *var, NodeList **init) |
| { |
| Node *r, *a; |
| NodeList *l; |
| Type *t; |
| Node *vstat, *vheap; |
| Node *index, *value; |
| |
| // make an array type |
| t = shallow(n->type); |
| t->bound = mpgetfix(n->right->val.u.xval); |
| t->width = 0; |
| dowidth(t); |
| |
| // make static initialized array |
| vstat = staticname(t); |
| arraylit(n, vstat, 1, init); |
| |
| // make new *array heap |
| vheap = nod(OXXX, N, N); |
| tempname(vheap, ptrto(t)); |
| |
| a = nod(ONEW, N, N); |
| a->list = list1(typenod(t)); |
| a = nod(OAS, vheap, a); |
| typecheck(&a, Etop); |
| walkexpr(&a, init); |
| *init = list(*init, a); |
| |
| // copy static to heap |
| a = nod(OIND, vheap, N); |
| a = nod(OAS, a, vstat); |
| typecheck(&a, Etop); |
| walkexpr(&a, init); |
| *init = list(*init, a); |
| |
| // make slice out of heap |
| a = nod(OAS, var, vheap); |
| typecheck(&a, Etop); |
| walkexpr(&a, init); |
| *init = list(*init, a); |
| |
| // put dynamics into slice |
| 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; |
| |
| switch(value->op) { |
| case OARRAYLIT: |
| if(value->type->bound < 0) |
| break; |
| a = nod(OINDEX, var, index); |
| arraylit(value, a, 2, init); |
| continue; |
| |
| case OSTRUCTLIT: |
| a = nod(OINDEX, var, index); |
| structlit(value, a, 2, init); |
| continue; |
| } |
| |
| if(isliteral(index) && isliteral(value)) |
| continue; |
| |
| // build list of var[c] = expr |
| a = nod(OINDEX, var, index); |
| a = nod(OAS, a, value); |
| typecheck(&a, Etop); |
| walkexpr(&a, init); // add any assignments in r to top |
| *init = list(*init, a); |
| } |
| } |
| |
| static void |
| maplit(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; |
| |
| // make the map var |
| nerr = nerrors; |
| |
| a = nod(OMAKE, N, N); |
| a->list = list1(typenod(n->type)); |
| a = nod(OAS, var, a); |
| typecheck(&a, Etop); |
| walkexpr(&a, init); |
| *init = list(*init, a); |
| |
| // 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); |
| 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 = nod(ODOT, a, newname(symb)); |
| |
| r = nod(OINDEX, vstat, index); |
| 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); |
| } |
| } |
| |
| void |
| anylit(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)) { |
| |
| // lay out static data |
| vstat = staticname(t); |
| structlit(n, vstat, 1, init); |
| |
| // copy static to automatic |
| a = nod(OAS, var, vstat); |
| typecheck(&a, Etop); |
| walkexpr(&a, init); |
| *init = list(*init, a); |
| |
| // add expressions to automatic |
| structlit(n, var, 2, 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(n, var, 3, init); |
| break; |
| |
| case OARRAYLIT: |
| if(t->etype != TARRAY) |
| fatal("anylit: not array"); |
| if(t->bound < 0) { |
| slicelit(n, var, init); |
| break; |
| } |
| |
| if(simplename(var)) { |
| |
| // lay out static data |
| vstat = staticname(t); |
| arraylit(n, vstat, 1, 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(n, var, 2, 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(n, var, 3, init); |
| break; |
| |
| case OMAPLIT: |
| if(t->etype != TMAP) |
| fatal("anylit: not map"); |
| maplit(n, var, init); |
| break; |
| } |
| } |
| |
| int |
| oaslit(Node *n, NodeList **init) |
| { |
| Type *t; |
| Node *vstat, *a; |
| |
| if(n->left == N || n->right == N) |
| goto no; |
| if(n->left->type == T || n->right->type == T) |
| goto no; |
| if(!simplename(n->left)) |
| goto no; |
| if(!eqtype(n->left->type, n->right->type)) |
| goto no; |
| if(n->dodata == 1) |
| goto initctxt; |
| |
| switch(n->right->op) { |
| default: |
| goto no; |
| |
| case OSTRUCTLIT: |
| case OARRAYLIT: |
| case OMAPLIT: |
| if(vmatch1(n->left, n->right)) |
| goto no; |
| anylit(n->right, n->left, init); |
| break; |
| } |
| n->op = OEMPTY; |
| return 1; |
| |
| no: |
| // not a special composit literal assignment |
| return 0; |
| |
| initctxt: |
| // in the initialization context |
| // we are trying to put data statements |
| // right into the initialized variables |
| switch(n->right->op) { |
| default: |
| goto no; |
| |
| case OSTRUCTLIT: |
| structlit(n->right, n->left, 1, init); |
| structlit(n->right, n->left, 2, init); |
| break; |
| |
| case OARRAYLIT: |
| t = n->right->type; |
| if(t == T) |
| goto no; |
| if(t->bound >= 0) { |
| arraylit(n->right, n->left, 1, init); |
| arraylit(n->right, n->left, 2, init); |
| break; |
| } |
| |
| // make a static slice |
| // make an array type |
| t = shallow(t); |
| t->bound = mpgetfix(n->right->right->val.u.xval); |
| t->width = 0; |
| dowidth(t); |
| |
| // make static initialized array |
| vstat = staticname(t); |
| arraylit(n->right, vstat, 1, init); |
| arraylit(n->right, vstat, 2, init); |
| |
| // copy static to slice |
| a = nod(OADDR, vstat, N); |
| a = nod(OAS, n->left, a); |
| typecheck(&a, Etop); |
| // turns into a function that is hard to parse |
| // in ggen where it is turned into DATA statements |
| // walkexpr(&a, init); |
| a->dodata = 2; |
| *init = list(*init, a); |
| break; |
| |
| case OMAPLIT: |
| maplit(n->right, n->left, init); |
| break; |
| } |
| n->op = OEMPTY; |
| return 1; |
| } |