}
/*
- * declare (possible list) n of type t.
- * append ODCL nodes to *init
+ * declaration stack & operations
*/
+static Sym* dclstack;
+
void
-dodclvar(Node *n, Type *t, NodeList **init)
+dcopy(Sym *a, Sym *b)
{
- if(n == N)
- return;
-
- if(t != T && (t->etype == TIDEAL || t->etype == TNIL))
- fatal("dodclvar %T", t);
- dowidth(t);
+ a->name = b->name;
+ a->def = b->def;
+ a->package = b->package;
+ a->undef = b->undef;
+ a->vargen = b->vargen;
+ a->block = b->block;
+ a->lastlineno = b->lastlineno;
+ a->offset = b->offset;
+}
- // in case of type checking error,
- // use "undefined" type for variable type,
- // to avoid fatal in addvar.
- if(t == T)
- t = typ(TFORW);
+Sym*
+push(void)
+{
+ Sym *d;
- addvar(n, t, dclcontext);
- autoexport(n->sym);
- if(funcdepth > 0)
- *init = list(*init, nod(ODCL, n, N));
+ d = mal(sizeof(*d));
+ d->link = dclstack;
+ dclstack = d;
+ return d;
}
-// TODO(rsc): cut
-void
-dodclconst(Node *n, Node *e)
+Sym*
+pushdcl(Sym *s)
{
- if(n == N)
- return;
- addconst(n, e, dclcontext);
- autoexport(n->sym);
+ Sym *d;
+
+ d = push();
+ dcopy(d, s);
+ return d;
}
-/*
- * introduce a type named n
- * but it is an unknown type for now
- */
-Type*
-dodcltype(Type *n)
+void
+popdcl(void)
{
- Sym *s;
+ Sym *d, *s;
- // if n has been forward declared,
- // use the Type* created then
- s = n->sym;
- if((funcdepth == 0 || s->block == block) && s->def != N && s->def->op == OTYPE) {
- switch(s->def->type->etype) {
- case TFORWSTRUCT:
- case TFORWINTER:
- n = s->def->type;
- if(s->block != block) {
- // completing forward struct from other file
- Dcl *d, *r;
- d = dcl();
- d->dsym = s;
- d->dtype = n;
- d->op = OTYPE;
- r = externdcl;
- d->back = r->back;
- r->back->forw = d;
- r->back = d;
- }
- goto found;
- }
+// if(dflag())
+// print("revert\n");
+
+ for(d=dclstack; d!=S; d=d->link) {
+ if(d->name == nil)
+ break;
+ s = pkglookup(d->name, d->package);
+ dcopy(s, d);
+ if(dflag())
+ print("\t%L pop %S\n", lineno, s);
}
+ if(d == S)
+ fatal("popdcl: no mark");
+ dclstack = d->link;
+ block = d->block;
+}
- // otherwise declare a new type
- addtyp(n, dclcontext);
+void
+poptodcl(void)
+{
+ Sym *d, *s;
-found:
- n->local = 1;
- autoexport(n->sym);
- return n;
+ for(d=dclstack; d!=S; d=d->link) {
+ if(d->name == nil)
+ break;
+ s = pkglookup(d->name, d->package);
+ dcopy(s, d);
+ if(dflag())
+ print("\t%L pop %S\n", lineno, s);
+ }
+ if(d == S)
+ fatal("poptodcl: no mark");
+ dclstack = d;
}
-/*
- * now we know what n is: it's t
- */
void
-updatetype(Type *n, Type *t)
+markdcl(void)
{
- Sym *s;
- int local, vargen;
- int maplineno, lno, etype;
+ Sym *d;
- if(t == T)
- return;
- s = n->sym;
- if(s == S || s->def == N || s->def->op != OTYPE || s->def->type != n)
- fatal("updatetype %T = %T", n, t);
+ d = push();
+ d->name = nil; // used as a mark in fifo
+ d->block = block;
- etype = n->etype;
- switch(n->etype) {
- case TFORW:
- break;
+ blockgen++;
+ block = blockgen;
- case TFORWSTRUCT:
- if(t->etype != TSTRUCT) {
- yyerror("%T forward declared as struct", n);
- return;
- }
- n->local = 1;
- break;
+// if(dflag())
+// print("markdcl\n");
+}
- case TFORWINTER:
- if(t->etype != TINTER) {
- yyerror("%T forward declared as interface", n);
- return;
- }
- break;
+void
+dumpdcl(char *st)
+{
+ Sym *s, *d;
+ int i;
- default:
- fatal("updatetype %T / %T", n, t);
+ i = 0;
+ for(d=dclstack; d!=S; d=d->link) {
+ i++;
+ print(" %.2d %p", i, d);
+ if(d->name == nil) {
+ print("\n");
+ continue;
+ }
+ print(" '%s'", d->name);
+ s = pkglookup(d->name, d->package);
+ print(" %lS\n", s);
}
+}
- // decl was
- // type n t;
- // copy t, but then zero out state associated with t
- // that is no longer associated with n.
- maplineno = n->maplineno;
- local = n->local;
- vargen = n->vargen;
- *n = *t;
- n->sym = s;
- n->local = local;
- n->siggen = 0;
- n->printed = 0;
- n->method = nil;
- n->vargen = vargen;
- n->nod = N;
-
- // catch declaration of incomplete type
- switch(n->etype) {
- case TFORWSTRUCT:
- case TFORWINTER:
- break;
- default:
- checkwidth(n);
- }
+void
+testdclstack(void)
+{
+ Sym *d;
- // double-check use of type as map key
- if(maplineno) {
- lno = lineno;
- lineno = maplineno;
- maptype(n, types[TBOOL]);
- lineno = lno;
+ for(d=dclstack; d!=S; d=d->link) {
+ if(d->name == nil) {
+ yyerror("mark left on the stack");
+ continue;
+ }
}
}
-
/*
- * return nelem of list
+ * declare individual names - var, typ, const
*/
-int
-structcount(Type *t)
+static void
+redeclare(char *str, Sym *s)
{
- int v;
- Iter s;
-
- v = 0;
- for(t = structfirst(&s, &t); t != T; t = structnext(&s))
- v++;
- return v;
+ if(s->block == block) {
+ yyerror("%s %S redeclared in this block", str, s);
+ print(" previous declaration at %L\n", s->lastlineno);
+ }
+ s->block = block;
+ s->lastlineno = lineno;
}
-/*
- * turn a parsed function declaration
- * into a type
- */
-Type*
-functype(Node *this, NodeList *in, NodeList *out)
+void
+addvar(Node *n, Type *t, int ctxt)
{
- Type *t;
- NodeList *rcvr;
-
- t = typ(TFUNC);
+ Dcl *r, *d;
+ Sym *s;
+ int gen;
- rcvr = nil;
- if(this)
- rcvr = list1(this);
- t->type = dostruct(rcvr, TFUNC);
- t->type->down = dostruct(out, TFUNC);
- t->type->down->down = dostruct(in, TFUNC);
+ if(n==N || n->sym == S || (n->op != ONAME && n->op != ONONAME) || t == T)
+ fatal("addvar: n=%N t=%T nil", n, t);
- if(this)
- t->thistuple = 1;
- t->outtuple = count(out);
- t->intuple = count(in);
+ s = n->sym;
- checkwidth(t);
- return t;
-}
+ if(ctxt == PEXTERN || ctxt == PFUNC) {
+ r = externdcl;
+ gen = 0;
+ } else {
+ r = autodcl;
+ vargen++;
+ gen = vargen;
+ pushdcl(s);
+ }
-int
-methcmp(Type *t1, Type *t2)
-{
- if(t1->etype != TFUNC)
- return 0;
- if(t2->etype != TFUNC)
- return 0;
+ redeclare("variable", s);
+ n->op = ONAME;
+ s->vargen = gen;
+ s->def = n;
+ s->offset = 0;
- t1 = t1->type->down; // skip this arg
- t2 = t2->type->down; // skip this arg
- for(;;) {
- if(t1 == t2)
- break;
- if(t1 == T || t2 == T)
- return 0;
- if(t1->etype != TSTRUCT || t2->etype != TSTRUCT)
- return 0;
+ n->funcdepth = funcdepth;
+ n->type = t;
+ n->vargen = gen;
+ n->class = ctxt;
- if(!eqtype(t1->type, t2->type))
- return 0;
+ d = dcl();
+ d->dsym = s;
+ d->dnode = n;
+ d->op = ONAME;
- t1 = t1->down;
- t2 = t2->down;
+ r->back->forw = d;
+ r->back = d;
+
+ if(dflag()) {
+ if(ctxt == PEXTERN)
+ print("extern var-dcl %S G%ld %T\n", s, s->vargen, t);
+ else if(ctxt == PFUNC)
+ print("extern func-dcl %S G%ld %T\n", s, s->vargen, t);
+ else
+ print("auto var-dcl %S G%ld %T\n", s, s->vargen, t);
}
- return 1;
}
-Sym*
-methodsym(Sym *nsym, Type *t0)
+void
+addtyp(Type *n, int ctxt)
{
+ Dcl *r, *d;
Sym *s;
- char buf[NSYMB];
- Type *t;
+ static int typgen;
- t = t0;
- if(t == T)
- goto bad;
- s = t->sym;
- if(s == S) {
- if(!isptr[t->etype])
- goto bad;
- t = t->type;
- if(t == T)
- goto bad;
- s = t->sym;
- if(s == S)
- goto bad;
+ if(n==T || n->sym == S)
+ fatal("addtyp: n=%T t=%T nil", n);
+
+ s = n->sym;
+
+ if(ctxt == PEXTERN)
+ r = externdcl;
+ else {
+ r = autodcl;
+ pushdcl(s);
+ n->vargen = ++typgen;
}
- // if t0 == *t and t0 has a sym,
- // we want to see *t, not t0, in the method name.
- if(t != t0 && t0->sym)
- t0 = ptrto(t);
+ redeclare("type", s);
+ s->def = typenod(n);
- snprint(buf, sizeof(buf), "%#hT·%s", t0, nsym->name);
-//print("methodname %s\n", buf);
- return pkglookup(buf, s->package);
+ d = dcl();
+ d->dsym = s;
+ d->dtype = n;
+ d->op = OTYPE;
-bad:
- yyerror("illegal <this> type: %T", t);
- return S;
-}
+ d->back = r->back;
+ r->back->forw = d;
+ r->back = d;
-Node*
-methodname(Node *n, Type *t)
-{
- Sym *s;
+ d = dcl();
+ d->dtype = n;
+ d->op = OTYPE;
- s = methodsym(n->sym, t);
- if(s == S)
- return n;
- return newname(s);
+ r = typelist;
+ d->back = r->back;
+ r->back->forw = d;
+ r->back = d;
+
+ if(dflag()) {
+ if(ctxt == PEXTERN)
+ print("extern typ-dcl %S G%ld %T\n", s, s->vargen, n);
+ else
+ print("auto typ-dcl %S G%ld %T\n", s, s->vargen, n);
+ }
}
-/*
- * add a method, declared as a function,
- * n is fieldname, pa is base type, t is function type
- */
+// TODO(rsc): cut
void
-addmethod(Node *n, Type *t, int local)
+addconst(Node *n, Node *e, int ctxt)
{
- Type *f, *d, *pa;
- Sym *sf;
-
- pa = nil;
- sf = nil;
-
- // get field sym
- if(n == N)
- goto bad;
- if(n->op != ONAME)
- goto bad;
- sf = n->sym;
- if(sf == S)
- goto bad;
-
- // get parent type sym
- pa = *getthis(t); // ptr to this structure
- if(pa == T)
- goto bad;
- pa = pa->type; // ptr to this field
- if(pa == T)
- goto bad;
- pa = pa->type; // ptr to this type
- if(pa == T)
- goto bad;
-
- f = methtype(pa);
- if(f == T)
- goto bad;
-
- pa = f;
- if(pkgimportname != S && !exportname(sf->name))
- sf = pkglookup(sf->name, pkgimportname->name);
+ Sym *s;
+ Dcl *r, *d;
- n = nod(ODCLFIELD, newname(sf), N);
- n->type = t;
+ if(n->op != ONAME && n->op != ONONAME)
+ fatal("addconst: not a name");
- d = T; // last found
- for(f=pa->method; f!=T; f=f->down) {
- d = f;
- if(f->etype != TFIELD)
- fatal("addmethod: not TFIELD: %N", f);
- if(strcmp(sf->name, f->sym->name) != 0)
- continue;
- if(!eqtype(t, f->type)) {
- yyerror("method redeclared: %T.%S", pa, sf);
- print("\t%T\n\t%T\n", f->type, t);
- }
+ if(e->op != OLITERAL) {
+ yyerror("expression must be a constant");
return;
}
- if(local && !pa->local) {
- // defining method on non-local type.
- // method must have been forward declared
- // elsewhere, i.e. where the type was.
- yyerror("cannot define new methods on non-local type %T", pa);
- return;
+ s = n->sym;
+
+ if(ctxt == PEXTERN)
+ r = externdcl;
+ else {
+ r = autodcl;
+ pushdcl(s);
}
- if(d == T)
- stotype(list1(n), 0, &pa->method);
- else
- stotype(list1(n), 0, &d->down);
+ redeclare("constant", s);
+ s->def = e;
+ e->sym = s;
- if(dflag())
- print("method %S of type %T\n", sf, pa);
- return;
+ d = dcl();
+ d->dsym = s;
+ d->dnode = e;
+ d->op = OLITERAL;
+ d->back = r->back;
+ r->back->forw = d;
+ r->back = d;
-bad:
- yyerror("invalid receiver type %T", pa);
+ if(dflag())
+ print("const-dcl %S %N\n", n->sym, n->sym->def);
}
/*
- * a function named init is a special case.
- * it is called by the initialization before
- * main is run. to make it unique within a
- * package and also uncallable, the name,
- * normally "pkg.init", is altered to "pkg.init·filename".
+ * declare (possible list) n of type t.
+ * append ODCL nodes to *init
*/
-Node*
-renameinit(Node *n)
+void
+dodclvar(Node *n, Type *t, NodeList **init)
{
- Sym *s;
+ if(n == N)
+ return;
- s = n->sym;
- if(s == S)
- return n;
- if(strcmp(s->name, "init") != 0)
- return n;
+ if(t != T && (t->etype == TIDEAL || t->etype == TNIL))
+ fatal("dodclvar %T", t);
+ dowidth(t);
- snprint(namebuf, sizeof(namebuf), "init·%s", filename);
- s = lookup(namebuf);
- return newname(s);
+ // in case of type checking error,
+ // use "undefined" type for variable type,
+ // to avoid fatal in addvar.
+ if(t == T)
+ t = typ(TFORW);
+
+ addvar(n, t, dclcontext);
+ autoexport(n->sym);
+ if(funcdepth > 0)
+ *init = list(*init, nod(ODCL, n, N));
}
-/*
- * declare the function proper.
- * and declare the arguments
- * called in extern-declaration context
- * returns in auto-declaration context.
- */
+// TODO(rsc): cut
void
-funchdr(Node *n)
+dodclconst(Node *n, Node *e)
{
- Node *on;
- Sym *s;
+ if(n == N)
+ return;
+ addconst(n, e, dclcontext);
+ autoexport(n->sym);
+}
- s = n->nname->sym;
- on = s->def;
- if(on != N && (on->op != ONAME || on->builtin))
- on = N;
+/*
+ * introduce a type named n
+ * but it is an unknown type for now
+ */
+Type*
+dodcltype(Type *n)
+{
+ Sym *s;
- // check for same types
- if(on != N) {
- if(eqtype(n->type, on->type)) {
- if(!eqargs(n->type, on->type)) {
- yyerror("function arg names changed: %S", s);
- print("\t%T\n\t%T\n", on->type, n->type);
+ // if n has been forward declared,
+ // use the Type* created then
+ s = n->sym;
+ if((funcdepth == 0 || s->block == block) && s->def != N && s->def->op == OTYPE) {
+ switch(s->def->type->etype) {
+ case TFORWSTRUCT:
+ case TFORWINTER:
+ n = s->def->type;
+ if(s->block != block) {
+ // completing forward struct from other file
+ Dcl *d, *r;
+ d = dcl();
+ d->dsym = s;
+ d->dtype = n;
+ d->op = OTYPE;
+ r = externdcl;
+ d->back = r->back;
+ r->back->forw = d;
+ r->back = d;
}
- } else {
- yyerror("function redeclared: %S", s);
- print("\t%T\n\t%T\n", on->type, n->type);
- on = N;
+ goto found;
}
}
- // check for forward declaration
- if(on == N) {
- // initial declaration or redeclaration
- // declare fun name, argument types and argument names
- n->nname->type = n->type;
- if(n->type->thistuple == 0)
- addvar(n->nname, n->type, PFUNC);
- else
- n->nname->class = PFUNC;
- } else {
- // identical redeclaration
- // steal previous names
- n->nname = on;
- n->type = on->type;
- n->class = on->class;
- n->sym = s;
- if(dflag())
- print("forew var-dcl %S %T\n", n->sym, n->type);
- }
-
- // change the declaration context from extern to auto
- autodcl = dcl();
- autodcl->back = autodcl;
-
- if(funcdepth == 0 && dclcontext != PEXTERN)
- fatal("funchdr: dclcontext");
+ // otherwise declare a new type
+ addtyp(n, dclcontext);
- dclcontext = PAUTO;
- markdcl();
- funcargs(n->type);
+found:
+ n->local = 1;
+ autoexport(n->sym);
+ return n;
}
+/*
+ * now we know what n is: it's t
+ */
void
-funcargs(Type *ft)
+updatetype(Type *n, Type *t)
{
- Type *t;
- Iter save;
- int all;
+ Sym *s;
+ int local, vargen;
+ int maplineno, lno, etype;
- funcdepth++;
+ if(t == T)
+ return;
+ s = n->sym;
+ if(s == S || s->def == N || s->def->op != OTYPE || s->def->type != n)
+ fatal("updatetype %T = %T", n, t);
- // declare the this/in arguments
- t = funcfirst(&save, ft);
- while(t != T) {
- if(t->nname != N) {
- t->nname->xoffset = t->width;
- addvar(t->nname, t->type, PPARAM);
+ etype = n->etype;
+ switch(n->etype) {
+ case TFORW:
+ break;
+
+ case TFORWSTRUCT:
+ if(t->etype != TSTRUCT) {
+ yyerror("%T forward declared as struct", n);
+ return;
}
- t = funcnext(&save);
- }
+ n->local = 1;
+ break;
- // declare the outgoing arguments
- all = 0;
- t = structfirst(&save, getoutarg(ft));
- while(t != T) {
- if(t->nname != N)
- t->nname->xoffset = t->width;
- if(t->nname != N) {
- addvar(t->nname, t->type, PPARAMOUT);
- all |= 1;
- } else
- all |= 2;
- t = structnext(&save);
+ case TFORWINTER:
+ if(t->etype != TINTER) {
+ yyerror("%T forward declared as interface", n);
+ return;
+ }
+ break;
+
+ default:
+ fatal("updatetype %T / %T", n, t);
}
- // this test is remarkedly similar to checkarglist
- if(all == 3)
- yyerror("cannot mix anonymous and named output arguments");
+ // decl was
+ // type n t;
+ // copy t, but then zero out state associated with t
+ // that is no longer associated with n.
+ maplineno = n->maplineno;
+ local = n->local;
+ vargen = n->vargen;
+ *n = *t;
+ n->sym = s;
+ n->local = local;
+ n->siggen = 0;
+ n->printed = 0;
+ n->method = nil;
+ n->vargen = vargen;
+ n->nod = N;
- ft->outnamed = 0;
- if(all == 1)
- ft->outnamed = 1;
+ // catch declaration of incomplete type
+ switch(n->etype) {
+ case TFORWSTRUCT:
+ case TFORWINTER:
+ break;
+ default:
+ checkwidth(n);
+ }
+
+ // double-check use of type as map key
+ if(maplineno) {
+ lno = lineno;
+ lineno = maplineno;
+ maptype(n, types[TBOOL]);
+ lineno = lno;
+ }
}
/*
- * compile the function.
- * called in auto-declaration context.
- * returns in extern-declaration context.
+ * declare variables from grammar
+ * new_name_list (type | [type] = expr_list)
*/
-void
-funcbody(Node *n)
+NodeList*
+variter(NodeList *vl, Node *t, NodeList *el)
{
+ int doexpr, gen;
+ Node *v, *e;
+ NodeList *init;
+ Sym *s;
+ Dcl *r, *d;
- compile(n);
-
- // change the declaration context from auto to extern
- if(dclcontext != PAUTO)
- fatal("funcbody: dclcontext");
- popdcl();
- funcdepth--;
- if(funcdepth == 0)
- dclcontext = PEXTERN;
-}
+ init = nil;
+ doexpr = el != nil;
+ for(; vl; vl=vl->next) {
+ if(doexpr) {
+ if(el == nil) {
+ yyerror("missing expr in var dcl");
+ break;
+ }
+ e = el->n;
+ el = el->next;
+ } else
+ e = N;
-Node*
-funclit0(Node *t)
-{
- Node *n;
+ v = vl->n;
+ s = v->sym;
+ if(dclcontext == PEXTERN || dclcontext == PFUNC) {
+ r = externdcl;
+ gen = 0;
+ } else {
+ r = autodcl;
+ gen = ++vargen;
+ pushdcl(s);
+ }
+
+ redeclare("variable", s);
+ s->def = v;
+ // TODO: vargen
+ s->offset = 0;
+ s->block = block;
- n = nod(OXXX, N, N);
- n->outer = funclit;
- n->dcl = autodcl;
- funclit = n;
+ v->op = ONAME;
+ v->class = dclcontext;
+ v->ntype = t;
+ v->funcdepth = funcdepth;
+ v->vargen = gen;
+ if(e != N || funcdepth > 0) {
+ if(funcdepth > 0)
+ init = list(init, nod(ODCL, v, N));
+ e = nod(OAS, v, e);
+ init = list(init, e);
+ if(e->right != N)
+ v->defn = e;
+ }
+
+ d = dcl();
+ d->dsym = s;
+ d->dnode = v;
+ d->op = ONAME;
+ r->back->forw = d;
+ r->back = d;
- // new declaration context
- autodcl = dcl();
- autodcl->back = autodcl;
-
- typecheck(&t, Etype);
- funcargs(t->type);
- return t;
+ autoexport(s);
+ }
+ if(el != nil)
+ yyerror("extra expr in var dcl");
+ return init;
}
-Node*
-funclit1(Node *ntype, NodeList *body)
+/*
+ * declare constants from grammar
+ * new_name_list [[type] = expr_list]
+ */
+NodeList*
+constiter(NodeList *vl, Node *t, NodeList *cl)
{
- Node *func;
- Type *type;
- Node *a, *d, *f, *n, *clos;
- Type *ft, *t;
- Iter save;
- int narg, shift;
- NodeList *args, *l, *in, *out;
-
- type = ntype->type;
- popdcl();
- func = funclit;
- funclit = func->outer;
-
- // build up type of func f that we're going to compile.
- // as we referred to variables from the outer function,
- // we accumulated a list of PHEAP names in func->cvars.
- narg = 0;
- // add PHEAP versions as function arguments.
- in = nil;
- for(l=func->cvars; l; l=l->next) {
- a = l->n;
- d = nod(ODCLFIELD, a, N);
- d->type = ptrto(a->type);
- in = list(in, d);
-
- // while we're here, set up a->heapaddr for back end
- n = nod(ONAME, N, N);
- snprint(namebuf, sizeof namebuf, "&%s", a->sym->name);
- n->sym = lookup(namebuf);
- n->type = ptrto(a->type);
- n->class = PPARAM;
- n->xoffset = narg*types[tptr]->width;
- n->addable = 1;
- n->ullman = 1;
- narg++;
- a->heapaddr = n;
-
- a->xoffset = 0;
+ Node *v, *c;
+ NodeList *vv;
+ Sym *s;
- // unlink from actual ONAME in symbol table
- a->closure->closure = a->outer;
+ vv = vl;
+ if(cl == nil) {
+ if(t != N)
+ yyerror("constdcl cannot have type without expr");
+ cl = lastconst;
+ t = lasttype;
+ } else {
+ lastconst = cl;
+ lasttype = t;
}
+ cl = listtreecopy(cl);
- // add a dummy arg for the closure's caller pc
- d = nod(ODCLFIELD, N, N);
- d->type = types[TUINTPTR];
- in = list(in, d);
-
- // slide param offset to make room for ptrs above.
- // narg+1 to skip over caller pc.
- shift = (narg+1)*types[tptr]->width;
-
- // now the original arguments.
- for(t=structfirst(&save, getinarg(type)); t; t=structnext(&save)) {
- d = nod(ODCLFIELD, t->nname, N);
- d->type = t->type;
- in = list(in, d);
-
- a = t->nname;
- if(a != N) {
- if(a->stackparam != N)
- a = a->stackparam;
- a->xoffset += shift;
+ for(; vl; vl=vl->next) {
+ if(cl == nil) {
+ yyerror("missing expr in const dcl");
+ break;
}
- }
+ c = cl->n;
+ cl = cl->next;
- // out arguments
- out = nil;
- for(t=structfirst(&save, getoutarg(type)); t; t=structnext(&save)) {
- d = nod(ODCLFIELD, t->nname, N);
- d->type = t->type;
- out = list(out, d);
+ v = vl->n;
+ s = v->sym;
+ if(dclcontext != PEXTERN)
+ pushdcl(s);
+ redeclare("constant", s);
+ s->def = v;
- a = t->nname;
- if(a != N) {
- if(a->stackparam != N)
- a = a->stackparam;
- a->xoffset += shift;
- }
+ v->op = OLITERAL;
+ v->ntype = t;
+ v->defn = c;
+ autoexport(s);
}
+ if(cl != nil)
+ yyerror("extra expr in const dcl");
+ iota += 1;
+ return vv;
+}
- ft = functype(N, in, out);
- ft->outnamed = type->outnamed;
+/*
+ * this generates a new name that is
+ * pushed down on the declaration list.
+ * no diagnostics are produced as this
+ * name will soon be declared.
+ */
+Node*
+newname(Sym *s)
+{
+ Node *n;
- // declare function.
- vargen++;
- snprint(namebuf, sizeof(namebuf), "_f%.3ld·%s", vargen, filename);
- f = newname(lookup(namebuf));
- addvar(f, ft, PFUNC);
- f->funcdepth = 0;
+ n = nod(ONAME, N, N);
+ n->sym = s;
+ n->type = T;
+ n->addable = 1;
+ n->ullman = 1;
+ n->xoffset = 0;
+ return n;
+}
- // compile function
- n = nod(ODCLFUNC, N, N);
- n->nname = f;
- n->type = ft;
- if(body == nil)
- body = list1(nod(OEMPTY, N, N));
- n->nbody = body;
- compile(n);
- funcdepth--;
- autodcl = func->dcl;
+Node*
+dclname(Sym *s)
+{
+ Node *n;
- // build up type for this instance of the closure func.
- in = nil;
- d = nod(ODCLFIELD, N, N); // siz
- d->type = types[TINT];
- in = list(in, d);
- d = nod(ODCLFIELD, N, N); // f
- d->type = ft;
- in = list(in, d);
- for(l=func->cvars; l; l=l->next) {
- a = l->n;
- d = nod(ODCLFIELD, N, N); // arg
- d->type = ptrto(a->type);
- in = list(in, d);
+ // top-level name: might already have been
+ // referred to, in which case s->def is already
+ // set to an ONONAME.
+ if(dclcontext == PEXTERN && s->block == 0) {
+ // toss predefined name like "close"
+ // TODO(rsc): put close in at the end.
+ if(s->def != N && s->def->etype)
+ s->def = N;
+ if(s->def == N)
+ oldname(s);
+ return s->def;
}
- d = nod(ODCLFIELD, N, N);
- d->type = type;
- out = list1(d);
-
- clos = syslook("closure", 1);
- clos->type = functype(N, in, out);
+ n = newname(s);
+ n->op = ONONAME; // caller will correct it
+ return n;
+}
- // literal expression is sys.closure(siz, f, arg0, arg1, ...)
- // which builds a function that calls f after filling in arg0,
- // arg1, ... for the PHEAP arguments above.
- args = nil;
- if(narg*widthptr > 100)
- yyerror("closure needs too many variables; runtime will reject it");
- a = nodintconst(narg*widthptr);
- args = list(args, a); // siz
- args = list(args, f); // f
- for(l=func->cvars; l; l=l->next) {
- a = l->n;
- d = oldname(a->sym);
- args = list(args, nod(OADDR, d, N));
+Node*
+typenod(Type *t)
+{
+ if(t->nod == N) {
+ t->nod = nod(OTYPE, N, N);
+ t->nod->type = t;
+ t->nod->sym = t->sym;
}
- typechecklist(args, Erv);
-
- n = nod(OCALL, clos, N);
- n->list = args;
- return n;
+ return t->nod;
}
+
/*
- * turn a parsed struct into a type
+ * this will return an old name
+ * that has already been pushed on the
+ * declaration list. a diagnostic is
+ * generated if no name has been defined.
*/
-Type**
-stotype(NodeList *l, int et, Type **t)
+Node*
+oldname(Sym *s)
{
- Type *f, *t1;
- Strlit *note;
- int lno;
- NodeList *init;
Node *n;
+ Node *c;
- init = nil;
- lno = lineno;
- for(; l; l=l->next) {
- n = l->n;
- lineno = n->lineno;
- note = nil;
-
- if(n->op != ODCLFIELD)
- fatal("stotype: oops %N\n", n);
- if(n->right != N) {
- typecheck(&n->right, Etype);
- n->type = n->right->type;
- n->right = N;
- if(n->embedded && n->type != T) {
- t1 = n->type;
- if(t1->sym == S && isptr[t1->etype])
+ n = s->def;
+ if(n == N) {
+ // maybe a top-level name will come along
+ // to give this a definition later.
+ n = newname(s);
+ n->op = ONONAME;
+ s->def = n;
+ }
+ if(n->funcdepth > 0 && n->funcdepth != funcdepth && n->op == ONAME) {
+ // inner func is referring to var
+ // in outer func.
+ if(n->closure == N || n->closure->funcdepth != funcdepth) {
+ typecheck(&n, Erv);
+ // create new closure var.
+ c = nod(ONAME, N, N);
+ c->sym = s;
+ c->class = PPARAMREF;
+ c->type = n->type;
+ c->addable = 0;
+ c->ullman = 2;
+ c->funcdepth = funcdepth;
+ c->outer = n->closure;
+ n->closure = c;
+ c->closure = n;
+ if(funclit != N)
+ funclit->cvars = list(funclit->cvars, c);
+ }
+ // return ref to closure var, not original
+ return n->closure;
+ }
+ return n;
+}
+
+/*
+ * same for types
+ */
+Type*
+newtype(Sym *s)
+{
+ Type *t;
+
+ t = typ(TFORW);
+ t->sym = s;
+ t->type = T;
+ return t;
+}
+
+Type*
+oldtype(Sym *s)
+{
+ Type *t;
+
+ if(s == S)
+ return T;
+ if(s->def == N || s->def->op != OTYPE) {
+ if(!s->undef)
+ yyerror("%S is not a type", s);
+ return T;
+ }
+ t = s->def->type;
+
+ /*
+ * If t is lowercase and not in our package
+ * and this isn't a reference during the parsing
+ * of import data, complain.
+ */
+ if(pkgimportname == S && !exportname(s->name) && strcmp(s->package, package) != 0)
+ yyerror("cannot use type %T", t);
+ return t;
+}
+
+/*
+ * type check top level declarations
+ */
+void
+dclchecks(void)
+{
+ Dcl *d;
+
+ for(d=externdcl; d!=D; d=d->forw) {
+ if(d->op != ONAME)
+ continue;
+ typecheck(&d->dnode, Erv);
+ }
+}
+
+
+/*
+ * structs, functions, and methods.
+ * they don't belong here, but where do they belong?
+ */
+
+
+/*
+ * turn a parsed struct into a type
+ */
+Type**
+stotype(NodeList *l, int et, Type **t)
+{
+ Type *f, *t1;
+ Strlit *note;
+ int lno;
+ NodeList *init;
+ Node *n;
+
+ init = nil;
+ lno = lineno;
+ for(; l; l=l->next) {
+ n = l->n;
+ lineno = n->lineno;
+ note = nil;
+
+ if(n->op != ODCLFIELD)
+ fatal("stotype: oops %N\n", n);
+ if(n->right != N) {
+ typecheck(&n->right, Etype);
+ n->type = n->right->type;
+ n->right = N;
+ if(n->embedded && n->type != T) {
+ t1 = n->type;
+ if(t1->sym == S && isptr[t1->etype])
t1 = t1->type;
if(t1 != T && isptr[t1->etype])
yyerror("embedded type cannot be a pointer");
return t;
}
-Type*
-sortinter(Type *t)
-{
- return t;
-}
-void
-dcopy(Sym *a, Sym *b)
+Node*
+embedded(Sym *s)
{
- a->name = b->name;
- a->def = b->def;
- a->package = b->package;
- a->undef = b->undef;
- a->vargen = b->vargen;
- a->block = b->block;
- a->lastlineno = b->lastlineno;
- a->offset = b->offset;
-}
+ Node *n;
+ char *name;
-Sym*
-push(void)
-{
- Sym *d;
+ // Names sometimes have disambiguation junk
+ // appended after a center dot. Discard it when
+ // making the name for the embedded struct field.
+ enum { CenterDot = 0xB7 };
+ name = s->name;
+ if(utfrune(s->name, CenterDot)) {
+ name = strdup(s->name);
+ *utfrune(name, CenterDot) = 0;
+ }
- d = mal(sizeof(*d));
- d->link = dclstack;
- dclstack = d;
- return d;
+ n = newname(lookup(name));
+ n = nod(ODCLFIELD, n, N);
+ n->embedded = 1;
+ if(s == S)
+ return n;
+ n->right = oldname(s);
+ return n;
}
-Sym*
-pushdcl(Sym *s)
+static Node*
+findtype(NodeList *l)
{
- Sym *d;
-
- d = push();
- dcopy(d, s);
- return d;
+ for(; l; l=l->next)
+ if(l->n->op == OKEY)
+ return l->n->right;
+ return N;
}
-void
-popdcl(void)
+static Node*
+xanondcl(Node *nt)
{
- Sym *d, *s;
-
-// if(dflag())
-// print("revert\n");
+ Node *n;
+ Type *t;
- for(d=dclstack; d!=S; d=d->link) {
- if(d->name == nil)
- break;
- s = pkglookup(d->name, d->package);
- dcopy(s, d);
- if(dflag())
- print("\t%L pop %S\n", lineno, s);
+ typecheck(&nt, Etype);
+ t = nt->type;
+ if(nt->op != OTYPE) {
+ yyerror("%S is not a type", nt->sym);
+ t = types[TINT32];
}
- if(d == S)
- fatal("popdcl: no mark");
- dclstack = d->link;
- block = d->block;
+ n = nod(ODCLFIELD, N, N);
+ n->type = t;
+ return n;
}
-void
-poptodcl(void)
+static Node*
+namedcl(Node *nn, Node *nt)
{
- Sym *d, *s;
+ Node *n;
+ Type *t;
- for(d=dclstack; d!=S; d=d->link) {
- if(d->name == nil)
- break;
- s = pkglookup(d->name, d->package);
- dcopy(s, d);
- if(dflag())
- print("\t%L pop %S\n", lineno, s);
+ if(nn->op == OKEY)
+ nn = nn->left;
+ if(nn->sym == S) {
+ typecheck(&nn, Etype);
+ yyerror("cannot mix anonymous %T with named arguments", nn->type);
+ return xanondcl(nn);
}
- if(d == S)
- fatal("poptodcl: no mark");
- dclstack = d;
+ t = types[TINT32];
+ if(nt == N)
+ yyerror("missing type for argument %S", nn->sym);
+ else {
+ typecheck(&nt, Etype);
+ if(nt->op != OTYPE)
+ yyerror("%S is not a type", nt->sym);
+ else
+ t = nt->type;
+ }
+ n = nod(ODCLFIELD, newname(nn->sym), N);
+ n->type = t;
+ return n;
}
-void
-markdcl(void)
+/*
+ * check that the list of declarations is either all anonymous or all named
+ */
+NodeList*
+checkarglist(NodeList *all)
{
- Sym *d;
-
- d = push();
- d->name = nil; // used as a mark in fifo
- d->block = block;
-
- blockgen++;
- block = blockgen;
+ int named;
+ Node *r;
+ NodeList *l;
-// if(dflag())
-// print("markdcl\n");
-}
-
-void
-dumpdcl(char *st)
-{
- Sym *s, *d;
- int i;
-
- print("\ndumpdcl: %s %p\n", st, b0stack);
-
- i = 0;
- for(d=dclstack; d!=S; d=d->link) {
- i++;
- print(" %.2d %p", i, d);
- if(d == b0stack)
- print(" (b0)");
- if(d->name == nil) {
- print("\n");
- continue;
- }
- print(" '%s'", d->name);
- s = pkglookup(d->name, d->package);
- print(" %lS\n", s);
- }
-}
-
-void
-testdclstack(void)
-{
- Sym *d;
-
- for(d=dclstack; d!=S; d=d->link) {
- if(d->name == nil) {
- yyerror("mark left on the stack");
- continue;
+ named = 0;
+ for(l=all; l; l=l->next) {
+ if(l->n->op == OKEY) {
+ named = 1;
+ break;
}
}
-}
-
-static void
-redeclare(char *str, Sym *s)
-{
- if(s->block == block) {
- yyerror("%s %S redeclared in this block", str, s);
- print(" previous declaration at %L\n", s->lastlineno);
- }
- s->block = block;
- s->lastlineno = lineno;
-}
-
-void
-addvar(Node *n, Type *t, int ctxt)
-{
- Dcl *r, *d;
- Sym *s;
- int gen;
-
- if(n==N || n->sym == S || (n->op != ONAME && n->op != ONONAME) || t == T)
- fatal("addvar: n=%N t=%T nil", n, t);
-
- s = n->sym;
-
- if(ctxt == PEXTERN || ctxt == PFUNC) {
- r = externdcl;
- gen = 0;
- } else {
- r = autodcl;
- vargen++;
- gen = vargen;
- pushdcl(s);
- }
-
- redeclare("variable", s);
- n->op = ONAME;
- s->vargen = gen;
- s->def = n;
- s->offset = 0;
-
- n->funcdepth = funcdepth;
- n->type = t;
- n->vargen = gen;
- n->class = ctxt;
-
- d = dcl();
- d->dsym = s;
- d->dnode = n;
- d->op = ONAME;
-
- r->back->forw = d;
- r->back = d;
-
- if(dflag()) {
- if(ctxt == PEXTERN)
- print("extern var-dcl %S G%ld %T\n", s, s->vargen, t);
- else if(ctxt == PFUNC)
- print("extern func-dcl %S G%ld %T\n", s, s->vargen, t);
- else
- print("auto var-dcl %S G%ld %T\n", s, s->vargen, t);
- }
-}
-
-void
-addtyp(Type *n, int ctxt)
-{
- Dcl *r, *d;
- Sym *s;
- static int typgen;
-
- if(n==T || n->sym == S)
- fatal("addtyp: n=%T t=%T nil", n);
-
- s = n->sym;
-
- if(ctxt == PEXTERN)
- r = externdcl;
- else {
- r = autodcl;
- pushdcl(s);
- n->vargen = ++typgen;
- }
-
- redeclare("type", s);
- s->def = typenod(n);
-
- d = dcl();
- d->dsym = s;
- d->dtype = n;
- d->op = OTYPE;
-
- d->back = r->back;
- r->back->forw = d;
- r->back = d;
-
- d = dcl();
- d->dtype = n;
- d->op = OTYPE;
-
- r = typelist;
- d->back = r->back;
- r->back->forw = d;
- r->back = d;
- if(dflag()) {
- if(ctxt == PEXTERN)
- print("extern typ-dcl %S G%ld %T\n", s, s->vargen, n);
+ for(l=all; l; l=l->next) {
+ if(named)
+ l->n = namedcl(l->n, findtype(l));
else
- print("auto typ-dcl %S G%ld %T\n", s, s->vargen, n);
+ l->n = xanondcl(l->n);
+ if(l->next != nil) {
+ r = l->n;
+ if(r != N && r->type != T && r->type->etype == TDDD)
+ yyerror("only last argument can have type ...");
+ }
}
+ return all;
}
-// TODO(rsc): cut
-void
-addconst(Node *n, Node *e, int ctxt)
-{
- Sym *s;
- Dcl *r, *d;
-
- if(n->op != ONAME && n->op != ONONAME)
- fatal("addconst: not a name");
-
- if(e->op != OLITERAL) {
- yyerror("expression must be a constant");
- return;
- }
-
- s = n->sym;
-
- if(ctxt == PEXTERN)
- r = externdcl;
- else {
- r = autodcl;
- pushdcl(s);
- }
-
- redeclare("constant", s);
- s->def = e;
- e->sym = s;
-
- d = dcl();
- d->dsym = s;
- d->dnode = e;
- d->op = OLITERAL;
- d->back = r->back;
- r->back->forw = d;
- r->back = d;
-
- if(dflag())
- print("const-dcl %S %N\n", n->sym, n->sym->def);
-}
Node*
fakethis(void)
}
/*
- * this generates a new name that is
- * pushed down on the declaration list.
- * no diagnostics are produced as this
- * name will soon be declared.
+ * turn a parsed function declaration
+ * into a type
*/
-Node*
-newname(Sym *s)
+Type*
+functype(Node *this, NodeList *in, NodeList *out)
{
- Node *n;
+ Type *t;
+ NodeList *rcvr;
- n = nod(ONAME, N, N);
- n->sym = s;
- n->type = T;
- n->addable = 1;
- n->ullman = 1;
- n->xoffset = 0;
- return n;
-}
+ t = typ(TFUNC);
-Node*
-dclname(Sym *s)
-{
- Node *n;
+ rcvr = nil;
+ if(this)
+ rcvr = list1(this);
+ t->type = dostruct(rcvr, TFUNC);
+ t->type->down = dostruct(out, TFUNC);
+ t->type->down->down = dostruct(in, TFUNC);
- // top-level name: might already have been
- // referred to, in which case s->def is already
- // set to an ONONAME.
- if(dclcontext == PEXTERN && s->block == 0) {
- // toss predefined name like "close"
- // TODO(rsc): put close in at the end.
- if(s->def != N && s->def->etype)
- s->def = N;
- if(s->def == N)
- oldname(s);
- return s->def;
- }
+ if(this)
+ t->thistuple = 1;
+ t->outtuple = count(out);
+ t->intuple = count(in);
- n = newname(s);
- n->op = ONONAME; // caller will correct it
- return n;
+ checkwidth(t);
+ return t;
}
-Node*
-typenod(Type *t)
+int
+methcmp(Type *t1, Type *t2)
{
- if(t->nod == N) {
- t->nod = nod(OTYPE, N, N);
- t->nod->type = t;
- t->nod->sym = t->sym;
- }
- return t->nod;
-}
+ if(t1->etype != TFUNC)
+ return 0;
+ if(t2->etype != TFUNC)
+ return 0;
+ t1 = t1->type->down; // skip this arg
+ t2 = t2->type->down; // skip this arg
+ for(;;) {
+ if(t1 == t2)
+ break;
+ if(t1 == T || t2 == T)
+ return 0;
+ if(t1->etype != TSTRUCT || t2->etype != TSTRUCT)
+ return 0;
-/*
- * this will return an old name
- * that has already been pushed on the
- * declaration list. a diagnostic is
- * generated if no name has been defined.
- */
-Node*
-oldname(Sym *s)
-{
- Node *n;
- Node *c;
+ if(!eqtype(t1->type, t2->type))
+ return 0;
- n = s->def;
- if(n == N) {
- // maybe a top-level name will come along
- // to give this a definition later.
- n = newname(s);
- n->op = ONONAME;
- s->def = n;
- }
- if(n->funcdepth > 0 && n->funcdepth != funcdepth && n->op == ONAME) {
- // inner func is referring to var
- // in outer func.
- if(n->closure == N || n->closure->funcdepth != funcdepth) {
- typecheck(&n, Erv);
- // create new closure var.
- c = nod(ONAME, N, N);
- c->sym = s;
- c->class = PPARAMREF;
- c->type = n->type;
- c->addable = 0;
- c->ullman = 2;
- c->funcdepth = funcdepth;
- c->outer = n->closure;
- n->closure = c;
- c->closure = n;
- if(funclit != N)
- funclit->cvars = list(funclit->cvars, c);
- }
- // return ref to closure var, not original
- return n->closure;
+ t1 = t1->down;
+ t2 = t2->down;
}
- return n;
+ return 1;
}
-/*
- * same for types
- */
-Type*
-newtype(Sym *s)
+Sym*
+methodsym(Sym *nsym, Type *t0)
{
+ Sym *s;
+ char buf[NSYMB];
Type *t;
- t = typ(TFORW);
- t->sym = s;
- t->type = T;
- return t;
-}
+ t = t0;
+ if(t == T)
+ goto bad;
+ s = t->sym;
+ if(s == S) {
+ if(!isptr[t->etype])
+ goto bad;
+ t = t->type;
+ if(t == T)
+ goto bad;
+ s = t->sym;
+ if(s == S)
+ goto bad;
+ }
-Type*
-oldtype(Sym *s)
-{
- Type *t;
+ // if t0 == *t and t0 has a sym,
+ // we want to see *t, not t0, in the method name.
+ if(t != t0 && t0->sym)
+ t0 = ptrto(t);
- if(s == S)
- return T;
- if(s->def == N || s->def->op != OTYPE) {
- if(!s->undef)
- yyerror("%S is not a type", s);
- return T;
- }
- t = s->def->type;
+ snprint(buf, sizeof(buf), "%#hT·%s", t0, nsym->name);
+//print("methodname %s\n", buf);
+ return pkglookup(buf, s->package);
- /*
- * If t is lowercase and not in our package
- * and this isn't a reference during the parsing
- * of import data, complain.
- */
- if(pkgimportname == S && !exportname(s->name) && strcmp(s->package, package) != 0)
- yyerror("cannot use type %T", t);
- return t;
+bad:
+ yyerror("illegal <this> type: %T", t);
+ return S;
}
-/*
- * n is a node with a name.
- * make it a declaration of the given type.
- */
Node*
-nametodcl(Node *n, Type *t)
+methodname(Node *n, Type *t)
{
- n = nod(ODCLFIELD, n, N);
- n->type = t;
- return n;
+ Sym *s;
+
+ s = methodsym(n->sym, t);
+ if(s == S)
+ return n;
+ return newname(s);
}
/*
- * make an anonymous declaration for t
+ * add a method, declared as a function,
+ * n is fieldname, pa is base type, t is function type
*/
-Node*
-anondcl(Type *t)
+void
+addmethod(Node *n, Type *t, int local)
{
- Node *n;
+ Type *f, *d, *pa;
+ Sym *sf;
- n = nod(ODCLFIELD, N, N);
- n->type = t;
- return n;
-}
+ pa = nil;
+ sf = nil;
-static Node*
-findtype(NodeList *l)
-{
- for(; l; l=l->next)
- if(l->n->op == OKEY)
- return l->n->right;
- return N;
-}
+ // get field sym
+ if(n == N)
+ goto bad;
+ if(n->op != ONAME)
+ goto bad;
+ sf = n->sym;
+ if(sf == S)
+ goto bad;
-static Node*
-xanondcl(Node *nt)
-{
- Node *n;
- Type *t;
+ // get parent type sym
+ pa = *getthis(t); // ptr to this structure
+ if(pa == T)
+ goto bad;
+ pa = pa->type; // ptr to this field
+ if(pa == T)
+ goto bad;
+ pa = pa->type; // ptr to this type
+ if(pa == T)
+ goto bad;
- typecheck(&nt, Etype);
- t = nt->type;
- if(nt->op != OTYPE) {
- yyerror("%S is not a type", nt->sym);
- t = types[TINT32];
- }
- n = nod(ODCLFIELD, N, N);
- n->type = t;
- return n;
-}
+ f = methtype(pa);
+ if(f == T)
+ goto bad;
-static Node*
-namedcl(Node *nn, Node *nt)
-{
- Node *n;
- Type *t;
+ pa = f;
+ if(pkgimportname != S && !exportname(sf->name))
+ sf = pkglookup(sf->name, pkgimportname->name);
- if(nn->op == OKEY)
- nn = nn->left;
- if(nn->sym == S) {
- typecheck(&nn, Etype);
- yyerror("cannot mix anonymous %T with named arguments", nn->type);
- return xanondcl(nn);
+ n = nod(ODCLFIELD, newname(sf), N);
+ n->type = t;
+
+ d = T; // last found
+ for(f=pa->method; f!=T; f=f->down) {
+ d = f;
+ if(f->etype != TFIELD)
+ fatal("addmethod: not TFIELD: %N", f);
+ if(strcmp(sf->name, f->sym->name) != 0)
+ continue;
+ if(!eqtype(t, f->type)) {
+ yyerror("method redeclared: %T.%S", pa, sf);
+ print("\t%T\n\t%T\n", f->type, t);
+ }
+ return;
}
- t = types[TINT32];
- if(nt == N)
- yyerror("missing type for argument %S", nn->sym);
- else {
- typecheck(&nt, Etype);
- if(nt->op != OTYPE)
- yyerror("%S is not a type", nt->sym);
- else
- t = nt->type;
+
+ if(local && !pa->local) {
+ // defining method on non-local type.
+ // method must have been forward declared
+ // elsewhere, i.e. where the type was.
+ yyerror("cannot define new methods on non-local type %T", pa);
+ return;
}
- n = nod(ODCLFIELD, newname(nn->sym), N);
- n->type = t;
- return n;
+
+ if(d == T)
+ stotype(list1(n), 0, &pa->method);
+ else
+ stotype(list1(n), 0, &d->down);
+ return;
+
+bad:
+ yyerror("invalid receiver type %T", pa);
}
/*
- * check that the list of declarations is either all anonymous or all named
+ * declare the function proper.
+ * and declare the arguments
+ * called in extern-declaration context
+ * returns in auto-declaration context.
*/
-NodeList*
-checkarglist(NodeList *all)
-{
- int named;
- Node *r;
- NodeList *l;
+void
+funchdr(Node *n)
+{
+ Node *on;
+ Sym *s;
- named = 0;
- for(l=all; l; l=l->next) {
- if(l->n->op == OKEY) {
- named = 1;
- break;
+ s = n->nname->sym;
+ on = s->def;
+ if(on != N && (on->op != ONAME || on->builtin))
+ on = N;
+
+ // check for same types
+ if(on != N) {
+ if(eqtype(n->type, on->type)) {
+ if(!eqargs(n->type, on->type)) {
+ yyerror("function arg names changed: %S", s);
+ print("\t%T\n\t%T\n", on->type, n->type);
+ }
+ } else {
+ yyerror("function redeclared: %S", s);
+ print("\t%T\n\t%T\n", on->type, n->type);
+ on = N;
}
}
- for(l=all; l; l=l->next) {
- if(named)
- l->n = namedcl(l->n, findtype(l));
+ // check for forward declaration
+ if(on == N) {
+ // initial declaration or redeclaration
+ // declare fun name, argument types and argument names
+ n->nname->type = n->type;
+ if(n->type->thistuple == 0)
+ addvar(n->nname, n->type, PFUNC);
else
- l->n = xanondcl(l->n);
- if(l->next != nil) {
- r = l->n;
- if(r != N && r->type != T && r->type->etype == TDDD)
- yyerror("only last argument can have type ...");
- }
+ n->nname->class = PFUNC;
+ } else {
+ // identical redeclaration
+ // steal previous names
+ n->nname = on;
+ n->type = on->type;
+ n->class = on->class;
+ n->sym = s;
}
- return all;
-}
-/*
- * hand-craft the following initialization code
- * var initdone·<file> uint8 (1)
- * func Init·<file>() (2)
- * if initdone·<file> { (3)
- * if initdone·<file> == 2 (4)
- * return
- * throw(); (5)
- * }
- * initdone.<file>++; (6)
- * // over all matching imported symbols
- * <pkg>.init·<file>() (7)
- * { <init stmts> } (8)
- * init·<file>() // if any (9)
- * initdone.<file>++; (10)
- * return (11)
- * }
- */
-int
-anyinit(NodeList *n)
-{
- uint32 h;
- Sym *s;
-
- // are there any init statements
- if(n != nil)
- return 1;
-
- // is this main
- if(strcmp(package, "main") == 0)
- return 1;
-
- // is there an explicit init function
- snprint(namebuf, sizeof(namebuf), "init·%s", filename);
- s = lookup(namebuf);
- if(s->def != N)
- return 1;
+ // change the declaration context from extern to auto
+ autodcl = dcl();
+ autodcl->back = autodcl;
- // are there any imported init functions
- for(h=0; h<NHASH; h++)
- for(s = hash[h]; s != S; s = s->link) {
- if(s->name[0] != 'I' || strncmp(s->name, "Init·", 6) != 0)
- continue;
- if(s->def == N)
- continue;
- return 1;
- }
+ if(funcdepth == 0 && dclcontext != PEXTERN)
+ fatal("funchdr: dclcontext");
- // then none
- return 0;
+ dclcontext = PAUTO;
+ markdcl();
+ funcargs(n->type);
}
void
-fninit(NodeList *n)
+funcargs(Type *ft)
{
- Node *gatevar;
- Node *a, *b, *fn;
- NodeList *r;
- uint32 h;
- Sym *s, *initsym;
-
- if(strcmp(package, "PACKAGE") == 0) {
- // sys.go or unsafe.go during compiler build
- return;
- }
-
- if(!anyinit(n))
- return;
-
- r = nil;
-
- // (1)
- snprint(namebuf, sizeof(namebuf), "initdone·%s", filename);
- gatevar = newname(lookup(namebuf));
- addvar(gatevar, types[TUINT8], PEXTERN);
-
- // (2)
-
- maxarg = 0;
- stksize = initstksize;
-
- snprint(namebuf, sizeof(namebuf), "Init·%s", filename);
-
- // this is a botch since we need a known name to
- // call the top level init function out of rt0
- if(strcmp(package, "main") == 0)
- snprint(namebuf, sizeof(namebuf), "init");
-
- fn = nod(ODCLFUNC, N, N);
- initsym = lookup(namebuf);
- fn->nname = newname(initsym);
- fn->type = functype(N, nil, nil);
- funchdr(fn);
-
- // (3)
- a = nod(OIF, N, N);
- a->ntest = nod(ONE, gatevar, nodintconst(0));
- r = list(r, a);
-
- // (4)
- b = nod(OIF, N, N);
- b->ntest = nod(OEQ, gatevar, nodintconst(2));
- b->nbody = list1(nod(ORETURN, N, N));
- a->nbody = list1(b);
-
- // (5)
- b = syslook("throwinit", 0);
- b = nod(OCALL, b, N);
- a->nbody = list(a->nbody, b);
-
- // (6)
- a = nod(OASOP, gatevar, nodintconst(1));
- a->etype = OADD;
- r = list(r, a);
+ Type *t;
+ Iter save;
+ int all;
- // (7)
- for(h=0; h<NHASH; h++)
- for(s = hash[h]; s != S; s = s->link) {
- if(s->name[0] != 'I' || strncmp(s->name, "Init·", 6) != 0)
- continue;
- if(s->def == N)
- continue;
- if(s == initsym)
- continue;
+ funcdepth++;
- // could check that it is fn of no args/returns
- a = nod(OCALL, s->def, N);
- r = list(r, a);
+ // declare the this/in arguments
+ t = funcfirst(&save, ft);
+ while(t != T) {
+ if(t->nname != N) {
+ t->nname->xoffset = t->width;
+ addvar(t->nname, t->type, PPARAM);
+ }
+ t = funcnext(&save);
}
- // (8)
- r = concat(r, initfix(n));
-
- // (9)
- // could check that it is fn of no args/returns
- snprint(namebuf, sizeof(namebuf), "init·%s", filename);
- s = lookup(namebuf);
- if(s->def != N) {
- a = nod(OCALL, s->def, N);
- r = list(r, a);
+ // declare the outgoing arguments
+ all = 0;
+ t = structfirst(&save, getoutarg(ft));
+ while(t != T) {
+ if(t->nname != N)
+ t->nname->xoffset = t->width;
+ if(t->nname != N) {
+ addvar(t->nname, t->type, PPARAMOUT);
+ all |= 1;
+ } else
+ all |= 2;
+ t = structnext(&save);
}
- // (10)
- a = nod(OASOP, gatevar, nodintconst(1));
- a->etype = OADD;
- r = list(r, a);
-
- // (11)
- a = nod(ORETURN, N, N);
- r = list(r, a);
-
- exportsym(fn->nname->sym);
-
- fn->nbody = r;
-//dump("b", fn);
-//dump("r", fn->nbody);
+ // this test is remarkedly similar to checkarglist
+ if(all == 3)
+ yyerror("cannot mix anonymous and named output arguments");
- popdcl();
- initflag = 1; // flag for loader static initialization
- compile(fn);
- initflag = 0;
+ ft->outnamed = 0;
+ if(all == 1)
+ ft->outnamed = 1;
}
-
/*
- * when a type's width should be known, we call checkwidth
- * to compute it. during a declaration like
- *
- * type T *struct { next T }
- *
- * it is necessary to defer the calculation of the struct width
- * until after T has been initialized to be a pointer to that struct.
- * similarly, during import processing structs may be used
- * before their definition. in those situations, calling
- * defercheckwidth() stops width calculations until
- * resumecheckwidth() is called, at which point all the
- * checkwidths that were deferred are executed.
- * sometimes it is okay to
+ * compile the function.
+ * called in auto-declaration context.
+ * returns in extern-declaration context.
*/
-typedef struct TypeList TypeList;
-struct TypeList {
- Type *t;
- TypeList *next;
-};
-
-static TypeList *tlfree;
-static TypeList *tlq;
-static int defercalc;
-
void
-checkwidth(Type *t)
+funcbody(Node *n)
{
- TypeList *l;
-
- // function arg structs should not be checked
- // outside of the enclosing function.
- if(t->funarg)
- fatal("checkwidth %T", t);
-
- if(!defercalc) {
- dowidth(t);
- return;
- }
- l = tlfree;
- if(l != nil)
- tlfree = l->next;
- else
- l = mal(sizeof *l);
+ compile(n);
- l->t = t;
- l->next = tlq;
- tlq = l;
+ // change the declaration context from auto to extern
+ if(dclcontext != PAUTO)
+ fatal("funcbody: dclcontext");
+ popdcl();
+ funcdepth--;
+ if(funcdepth == 0)
+ dclcontext = PEXTERN;
}
-void
-defercheckwidth(void)
+Node*
+funclit0(Node *t)
{
- // we get out of sync on syntax errors, so don't be pedantic.
- // if(defercalc)
- // fatal("defercheckwidth");
- defercalc = 1;
-}
+ Node *n;
-void
-resumecheckwidth(void)
-{
- TypeList *l;
+ n = nod(OXXX, N, N);
+ n->outer = funclit;
+ n->dcl = autodcl;
+ funclit = n;
- if(!defercalc)
- fatal("restartcheckwidth");
- defercalc = 0;
+ // new declaration context
+ autodcl = dcl();
+ autodcl->back = autodcl;
- for(l = tlq; l != nil; l = tlq) {
- dowidth(l->t);
- tlq = l->next;
- l->next = tlfree;
- tlfree = l;
- }
+ typecheck(&t, Etype);
+ funcargs(t->type);
+ return t;
}
Node*
-embedded(Sym *s)
+funclit1(Node *ntype, NodeList *body)
{
- Node *n;
- char *name;
+ Node *func;
+ Type *type;
+ Node *a, *d, *f, *n, *clos;
+ Type *ft, *t;
+ Iter save;
+ int narg, shift;
+ NodeList *args, *l, *in, *out;
- // Names sometimes have disambiguation junk
- // appended after a center dot. Discard it when
- // making the name for the embedded struct field.
- enum { CenterDot = 0xB7 };
- name = s->name;
- if(utfrune(s->name, CenterDot)) {
- name = strdup(s->name);
- *utfrune(name, CenterDot) = 0;
- }
+ type = ntype->type;
+ popdcl();
+ func = funclit;
+ funclit = func->outer;
- n = newname(lookup(name));
- n = nod(ODCLFIELD, n, N);
- n->embedded = 1;
- if(s == S)
- return n;
- n->right = oldname(s);
- return n;
-}
+ // build up type of func f that we're going to compile.
+ // as we referred to variables from the outer function,
+ // we accumulated a list of PHEAP names in func->cvars.
+ narg = 0;
+ // add PHEAP versions as function arguments.
+ in = nil;
+ for(l=func->cvars; l; l=l->next) {
+ a = l->n;
+ d = nod(ODCLFIELD, a, N);
+ d->type = ptrto(a->type);
+ in = list(in, d);
-/*
- * declare variables from grammar
- * new_name_list (type | [type] = expr_list)
- */
-NodeList*
-variter(NodeList *vl, Node *t, NodeList *el)
-{
- int doexpr, gen;
- Node *v, *e;
- NodeList *init;
- Sym *s;
- Dcl *r, *d;
+ // while we're here, set up a->heapaddr for back end
+ n = nod(ONAME, N, N);
+ snprint(namebuf, sizeof namebuf, "&%s", a->sym->name);
+ n->sym = lookup(namebuf);
+ n->type = ptrto(a->type);
+ n->class = PPARAM;
+ n->xoffset = narg*types[tptr]->width;
+ n->addable = 1;
+ n->ullman = 1;
+ narg++;
+ a->heapaddr = n;
- init = nil;
- doexpr = el != nil;
- for(; vl; vl=vl->next) {
- if(doexpr) {
- if(el == nil) {
- yyerror("missing expr in var dcl");
- break;
- }
- e = el->n;
- el = el->next;
- } else
- e = N;
+ a->xoffset = 0;
- v = vl->n;
- s = v->sym;
- if(dclcontext == PEXTERN || dclcontext == PFUNC) {
- r = externdcl;
- gen = 0;
- } else {
- r = autodcl;
- gen = ++vargen;
- pushdcl(s);
- }
+ // unlink from actual ONAME in symbol table
+ a->closure->closure = a->outer;
+ }
- redeclare("variable", s);
- s->def = v;
- // TODO: vargen
- s->offset = 0;
- s->block = block;
+ // add a dummy arg for the closure's caller pc
+ d = nod(ODCLFIELD, N, N);
+ d->type = types[TUINTPTR];
+ in = list(in, d);
- v->op = ONAME;
- v->class = dclcontext;
- v->ntype = t;
- v->funcdepth = funcdepth;
- v->vargen = gen;
- if(e != N || funcdepth > 0) {
- if(funcdepth > 0)
- init = list(init, nod(ODCL, v, N));
- e = nod(OAS, v, e);
- init = list(init, e);
- if(e->right != N)
- v->defn = e;
- }
+ // slide param offset to make room for ptrs above.
+ // narg+1 to skip over caller pc.
+ shift = (narg+1)*types[tptr]->width;
- d = dcl();
- d->dsym = s;
- d->dnode = v;
- d->op = ONAME;
- r->back->forw = d;
- r->back = d;
+ // now the original arguments.
+ for(t=structfirst(&save, getinarg(type)); t; t=structnext(&save)) {
+ d = nod(ODCLFIELD, t->nname, N);
+ d->type = t->type;
+ in = list(in, d);
- autoexport(s);
+ a = t->nname;
+ if(a != N) {
+ if(a->stackparam != N)
+ a = a->stackparam;
+ a->xoffset += shift;
+ }
}
- if(el != nil)
- yyerror("extra expr in var dcl");
- return init;
-}
-/*
- * declare constants from grammar
- * new_name_list [[type] = expr_list]
- */
-NodeList*
-constiter(NodeList *vl, Node *t, NodeList *cl)
-{
- Node *v, *c;
- NodeList *vv;
- Sym *s;
+ // out arguments
+ out = nil;
+ for(t=structfirst(&save, getoutarg(type)); t; t=structnext(&save)) {
+ d = nod(ODCLFIELD, t->nname, N);
+ d->type = t->type;
+ out = list(out, d);
- vv = vl;
- if(cl == nil) {
- if(t != N)
- yyerror("constdcl cannot have type without expr");
- cl = lastconst;
- t = lasttype;
- } else {
- lastconst = cl;
- lasttype = t;
+ a = t->nname;
+ if(a != N) {
+ if(a->stackparam != N)
+ a = a->stackparam;
+ a->xoffset += shift;
+ }
}
- cl = listtreecopy(cl);
- for(; vl; vl=vl->next) {
- if(cl == nil) {
- yyerror("missing expr in const dcl");
- break;
- }
- c = cl->n;
- cl = cl->next;
+ ft = functype(N, in, out);
+ ft->outnamed = type->outnamed;
- v = vl->n;
- s = v->sym;
- if(dclcontext != PEXTERN)
- pushdcl(s);
- redeclare("constant", s);
- s->def = v;
+ // declare function.
+ vargen++;
+ snprint(namebuf, sizeof(namebuf), "_f%.3ld·%s", vargen, filename);
+ f = newname(lookup(namebuf));
+ addvar(f, ft, PFUNC);
+ f->funcdepth = 0;
- v->op = OLITERAL;
- v->ntype = t;
- v->defn = c;
- autoexport(s);
- }
- if(cl != nil)
- yyerror("extra expr in const dcl");
- iota += 1;
- return vv;
-}
+ // compile function
+ n = nod(ODCLFUNC, N, N);
+ n->nname = f;
+ n->type = ft;
+ if(body == nil)
+ body = list1(nod(OEMPTY, N, N));
+ n->nbody = body;
+ compile(n);
+ funcdepth--;
+ autodcl = func->dcl;
-/*
- * look for
- * unsafe.Sizeof
- * unsafe.Offsetof
- * rewrite with a constant
- */
-Node*
-unsafenmagic(Node *fn, NodeList *args)
-{
- Node *r, *n;
- Sym *s;
- Type *t, *tr;
- long v;
- Val val;
-
- if(fn == N || fn->op != ONAME || (s = fn->sym) == S)
- goto no;
- if(strcmp(s->package, "unsafe") != 0)
- goto no;
-
- if(args == nil) {
- yyerror("missing argument for %S", s);
- goto no;
- }
- r = args->n;
-
- n = nod(OLITERAL, N, N);
- if(strcmp(s->name, "Sizeof") == 0) {
- typecheck(&r, Erv);
- tr = r->type;
- if(r->op == OLITERAL && r->val.ctype == CTSTR)
- tr = types[TSTRING];
- if(tr == T)
- goto no;
- v = tr->width;
- goto yes;
- }
- if(strcmp(s->name, "Offsetof") == 0) {
- if(r->op != ODOT && r->op != ODOTPTR)
- goto no;
- typecheck(&r, Erv);
- v = r->xoffset;
- goto yes;
- }
- if(strcmp(s->name, "Alignof") == 0) {
- typecheck(&r, Erv);
- tr = r->type;
- if(r->op == OLITERAL && r->val.ctype == CTSTR)
- tr = types[TSTRING];
- if(tr == T)
- goto no;
-
- // make struct { byte; T; }
- t = typ(TSTRUCT);
- t->type = typ(TFIELD);
- t->type->type = types[TUINT8];
- t->type->down = typ(TFIELD);
- t->type->down->type = tr;
- // compute struct widths
- dowidth(t);
-
- // the offset of T is its required alignment
- v = t->type->down->width;
- goto yes;
+ // build up type for this instance of the closure func.
+ in = nil;
+ d = nod(ODCLFIELD, N, N); // siz
+ d->type = types[TINT];
+ in = list(in, d);
+ d = nod(ODCLFIELD, N, N); // f
+ d->type = ft;
+ in = list(in, d);
+ for(l=func->cvars; l; l=l->next) {
+ a = l->n;
+ d = nod(ODCLFIELD, N, N); // arg
+ d->type = ptrto(a->type);
+ in = list(in, d);
}
-no:
- return N;
-
-yes:
- if(args->next != nil)
- yyerror("extra arguments for %S", s);
- // any side effects disappear; ignore init
- val.ctype = CTINT;
- val.u.xval = mal(sizeof(*n->val.u.xval));
- mpmovecfix(val.u.xval, v);
- n = nod(OLITERAL, N, N);
- n->val = val;
- n->type = types[TINT];
- return n;
-}
+ d = nod(ODCLFIELD, N, N);
+ d->type = type;
+ out = list1(d);
-void
-dclchecks(void)
-{
- Dcl *d;
+ clos = syslook("closure", 1);
+ clos->type = functype(N, in, out);
- for(d=externdcl; d!=D; d=d->forw) {
- if(d->op != ONAME)
- continue;
- typecheck(&d->dnode, Erv);
+ // literal expression is sys.closure(siz, f, arg0, arg1, ...)
+ // which builds a function that calls f after filling in arg0,
+ // arg1, ... for the PHEAP arguments above.
+ args = nil;
+ if(narg*widthptr > 100)
+ yyerror("closure needs too many variables; runtime will reject it");
+ a = nodintconst(narg*widthptr);
+ args = list(args, a); // siz
+ args = list(args, f); // f
+ for(l=func->cvars; l; l=l->next) {
+ a = l->n;
+ d = oldname(a->sym);
+ args = list(args, nod(OADDR, d, N));
}
+ typechecklist(args, Erv);
+
+ n = nod(OCALL, clos, N);
+ n->list = args;
+ return n;
}