2008-06-04 15:37:38 -06:00
|
|
|
// 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.
|
|
|
|
|
|
|
|
#include "go.h"
|
|
|
|
#include "y.tab.h"
|
|
|
|
|
2008-06-11 22:06:26 -06:00
|
|
|
int
|
|
|
|
dflag(void)
|
|
|
|
{
|
|
|
|
if(!debug['d'])
|
|
|
|
return 0;
|
|
|
|
if(debug['y'])
|
|
|
|
return 1;
|
|
|
|
if(inimportsys)
|
|
|
|
return 0;
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
|
2009-07-10 17:29:26 -06:00
|
|
|
/*
|
2009-08-04 19:43:32 -06:00
|
|
|
* declaration stack & operations
|
2009-07-10 17:29:26 -06:00
|
|
|
*/
|
2009-08-04 19:43:32 -06:00
|
|
|
static Sym* dclstack;
|
|
|
|
|
2008-06-04 15:37:38 -06:00
|
|
|
void
|
2009-08-04 19:43:32 -06:00
|
|
|
dcopy(Sym *a, Sym *b)
|
2008-06-04 15:37:38 -06:00
|
|
|
{
|
2009-08-04 19:43:32 -06:00
|
|
|
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;
|
|
|
|
}
|
2008-10-16 16:59:31 -06:00
|
|
|
|
2009-08-04 19:43:32 -06:00
|
|
|
Sym*
|
|
|
|
push(void)
|
|
|
|
{
|
|
|
|
Sym *d;
|
2008-10-16 16:59:31 -06:00
|
|
|
|
2009-08-04 19:43:32 -06:00
|
|
|
d = mal(sizeof(*d));
|
|
|
|
d->link = dclstack;
|
|
|
|
dclstack = d;
|
|
|
|
return d;
|
2008-06-04 15:37:38 -06:00
|
|
|
}
|
|
|
|
|
2009-08-04 19:43:32 -06:00
|
|
|
Sym*
|
|
|
|
pushdcl(Sym *s)
|
2008-06-04 15:37:38 -06:00
|
|
|
{
|
2009-08-04 19:43:32 -06:00
|
|
|
Sym *d;
|
|
|
|
|
|
|
|
d = push();
|
|
|
|
dcopy(d, s);
|
|
|
|
return d;
|
2008-06-04 15:37:38 -06:00
|
|
|
}
|
|
|
|
|
2009-08-04 19:43:32 -06:00
|
|
|
void
|
|
|
|
popdcl(void)
|
2008-06-04 15:37:38 -06:00
|
|
|
{
|
2009-08-04 19:43:32 -06:00
|
|
|
Sym *d, *s;
|
2008-06-04 15:37:38 -06:00
|
|
|
|
2009-08-04 19:43:32 -06:00
|
|
|
// 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);
|
2008-06-04 15:37:38 -06:00
|
|
|
}
|
2009-08-04 19:43:32 -06:00
|
|
|
if(d == S)
|
|
|
|
fatal("popdcl: no mark");
|
|
|
|
dclstack = d->link;
|
|
|
|
block = d->block;
|
|
|
|
}
|
2008-06-04 15:37:38 -06:00
|
|
|
|
2009-08-04 19:43:32 -06:00
|
|
|
void
|
|
|
|
poptodcl(void)
|
|
|
|
{
|
|
|
|
Sym *d, *s;
|
2008-10-07 13:42:57 -06:00
|
|
|
|
2009-08-04 19:43:32 -06:00
|
|
|
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;
|
2008-10-06 17:44:17 -06:00
|
|
|
}
|
|
|
|
|
|
|
|
void
|
2009-08-04 19:43:32 -06:00
|
|
|
markdcl(void)
|
2008-10-06 17:44:17 -06:00
|
|
|
{
|
2009-08-04 19:43:32 -06:00
|
|
|
Sym *d;
|
2008-06-04 15:37:38 -06:00
|
|
|
|
2009-08-04 19:43:32 -06:00
|
|
|
d = push();
|
|
|
|
d->name = nil; // used as a mark in fifo
|
|
|
|
d->block = block;
|
2008-06-04 15:37:38 -06:00
|
|
|
|
2009-08-04 19:43:32 -06:00
|
|
|
blockgen++;
|
|
|
|
block = blockgen;
|
2008-06-04 15:37:38 -06:00
|
|
|
|
2009-08-04 19:43:32 -06:00
|
|
|
// if(dflag())
|
|
|
|
// print("markdcl\n");
|
|
|
|
}
|
2008-10-03 17:15:55 -06:00
|
|
|
|
2009-08-04 19:43:32 -06:00
|
|
|
void
|
|
|
|
dumpdcl(char *st)
|
|
|
|
{
|
|
|
|
Sym *s, *d;
|
|
|
|
int i;
|
2008-06-04 15:37:38 -06:00
|
|
|
|
2009-08-04 19:43:32 -06:00
|
|
|
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);
|
2008-10-06 17:44:17 -06:00
|
|
|
}
|
2009-08-04 19:43:32 -06:00
|
|
|
}
|
2008-06-04 15:37:38 -06:00
|
|
|
|
2009-08-04 19:43:32 -06:00
|
|
|
void
|
|
|
|
testdclstack(void)
|
|
|
|
{
|
|
|
|
Sym *d;
|
2009-06-29 16:13:37 -06:00
|
|
|
|
2009-08-04 19:43:32 -06:00
|
|
|
for(d=dclstack; d!=S; d=d->link) {
|
|
|
|
if(d->name == nil) {
|
|
|
|
yyerror("mark left on the stack");
|
|
|
|
continue;
|
|
|
|
}
|
2009-06-25 22:02:39 -06:00
|
|
|
}
|
2008-06-04 15:37:38 -06:00
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
2009-08-04 19:43:32 -06:00
|
|
|
* declare individual names - var, typ, const
|
2008-06-04 15:37:38 -06:00
|
|
|
*/
|
2009-08-04 19:43:32 -06:00
|
|
|
static void
|
|
|
|
redeclare(char *str, Sym *s)
|
2009-05-07 11:30:22 -06:00
|
|
|
{
|
2009-08-04 19:43:32 -06:00
|
|
|
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;
|
2008-06-04 15:37:38 -06:00
|
|
|
}
|
|
|
|
|
2009-08-04 19:43:32 -06:00
|
|
|
void
|
|
|
|
addvar(Node *n, Type *t, int ctxt)
|
2008-06-04 15:37:38 -06:00
|
|
|
{
|
2009-08-04 19:43:32 -06:00
|
|
|
Dcl *r, *d;
|
|
|
|
Sym *s;
|
|
|
|
int gen;
|
2008-06-04 15:37:38 -06:00
|
|
|
|
2009-08-04 19:43:32 -06:00
|
|
|
if(n==N || n->sym == S || (n->op != ONAME && n->op != ONONAME) || t == T)
|
|
|
|
fatal("addvar: n=%N t=%T nil", n, t);
|
2008-06-04 15:37:38 -06:00
|
|
|
|
2009-08-04 19:43:32 -06:00
|
|
|
s = n->sym;
|
2008-06-04 15:37:38 -06:00
|
|
|
|
2009-08-04 19:43:32 -06:00
|
|
|
if(ctxt == PEXTERN || ctxt == PFUNC) {
|
|
|
|
r = externdcl;
|
|
|
|
gen = 0;
|
|
|
|
} else {
|
|
|
|
r = autodcl;
|
|
|
|
vargen++;
|
|
|
|
gen = vargen;
|
|
|
|
pushdcl(s);
|
|
|
|
}
|
2008-06-04 15:37:38 -06:00
|
|
|
|
2009-08-04 19:43:32 -06:00
|
|
|
redeclare("variable", s);
|
|
|
|
n->op = ONAME;
|
|
|
|
s->vargen = gen;
|
|
|
|
s->def = n;
|
|
|
|
s->offset = 0;
|
2008-06-04 15:37:38 -06:00
|
|
|
|
2009-08-04 19:43:32 -06:00
|
|
|
n->funcdepth = funcdepth;
|
|
|
|
n->type = t;
|
|
|
|
n->vargen = gen;
|
|
|
|
n->class = ctxt;
|
2008-06-04 15:37:38 -06:00
|
|
|
|
2009-08-04 19:43:32 -06:00
|
|
|
d = dcl();
|
|
|
|
d->dsym = s;
|
|
|
|
d->dnode = n;
|
|
|
|
d->op = ONAME;
|
2008-06-04 15:37:38 -06:00
|
|
|
|
2009-08-04 19:43:32 -06:00
|
|
|
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);
|
2008-06-04 15:37:38 -06:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2009-08-04 19:43:32 -06:00
|
|
|
void
|
|
|
|
addtyp(Type *n, int ctxt)
|
2008-06-04 15:37:38 -06:00
|
|
|
{
|
2009-08-04 19:43:32 -06:00
|
|
|
Dcl *r, *d;
|
2008-08-10 16:09:09 -06:00
|
|
|
Sym *s;
|
2009-08-04 19:43:32 -06:00
|
|
|
static int typgen;
|
2008-08-10 16:09:09 -06:00
|
|
|
|
2009-08-04 19:43:32 -06:00
|
|
|
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;
|
2009-01-08 15:30:00 -07:00
|
|
|
}
|
|
|
|
|
2009-08-04 19:43:32 -06:00
|
|
|
redeclare("type", s);
|
|
|
|
s->def = typenod(n);
|
2008-09-14 17:57:55 -06:00
|
|
|
|
2009-08-04 19:43:32 -06:00
|
|
|
d = dcl();
|
|
|
|
d->dsym = s;
|
|
|
|
d->dtype = n;
|
|
|
|
d->op = OTYPE;
|
2008-06-04 15:37:38 -06:00
|
|
|
|
2009-08-04 19:43:32 -06:00
|
|
|
d->back = r->back;
|
|
|
|
r->back->forw = d;
|
|
|
|
r->back = d;
|
2008-11-03 16:36:08 -07:00
|
|
|
|
2009-08-04 19:43:32 -06:00
|
|
|
d = dcl();
|
|
|
|
d->dtype = n;
|
|
|
|
d->op = OTYPE;
|
2008-11-14 17:35:08 -07:00
|
|
|
|
2009-08-04 19:43:32 -06:00
|
|
|
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);
|
|
|
|
}
|
2008-06-04 15:37:38 -06:00
|
|
|
}
|
|
|
|
|
2009-08-04 19:43:32 -06:00
|
|
|
// TODO(rsc): cut
|
2008-06-04 15:37:38 -06:00
|
|
|
void
|
2009-08-04 19:43:32 -06:00
|
|
|
addconst(Node *n, Node *e, int ctxt)
|
2008-06-04 15:37:38 -06:00
|
|
|
{
|
2009-08-04 19:43:32 -06:00
|
|
|
Sym *s;
|
|
|
|
Dcl *r, *d;
|
2009-01-16 16:35:07 -07:00
|
|
|
|
2009-08-04 19:43:32 -06:00
|
|
|
if(n->op != ONAME && n->op != ONONAME)
|
|
|
|
fatal("addconst: not a name");
|
2008-09-14 17:57:55 -06:00
|
|
|
|
2009-08-04 19:43:32 -06:00
|
|
|
if(e->op != OLITERAL) {
|
|
|
|
yyerror("expression must be a constant");
|
2008-09-15 20:07:23 -06:00
|
|
|
return;
|
2008-06-04 15:37:38 -06:00
|
|
|
}
|
|
|
|
|
2009-08-04 19:43:32 -06:00
|
|
|
s = n->sym;
|
|
|
|
|
|
|
|
if(ctxt == PEXTERN)
|
|
|
|
r = externdcl;
|
|
|
|
else {
|
|
|
|
r = autodcl;
|
|
|
|
pushdcl(s);
|
2009-06-29 16:13:37 -06:00
|
|
|
}
|
|
|
|
|
2009-08-04 19:43:32 -06:00
|
|
|
redeclare("constant", s);
|
|
|
|
s->def = e;
|
|
|
|
e->sym = s;
|
2008-09-14 17:57:55 -06:00
|
|
|
|
2009-08-04 19:43:32 -06:00
|
|
|
d = dcl();
|
|
|
|
d->dsym = s;
|
|
|
|
d->dnode = e;
|
|
|
|
d->op = OLITERAL;
|
|
|
|
d->back = r->back;
|
|
|
|
r->back->forw = d;
|
|
|
|
r->back = d;
|
2008-06-04 15:37:38 -06:00
|
|
|
|
2009-08-04 19:43:32 -06:00
|
|
|
if(dflag())
|
|
|
|
print("const-dcl %S %N\n", n->sym, n->sym->def);
|
2008-06-04 15:37:38 -06:00
|
|
|
}
|
|
|
|
|
2008-07-19 19:39:12 -06:00
|
|
|
/*
|
2009-08-04 19:43:32 -06:00
|
|
|
* declare (possible list) n of type t.
|
|
|
|
* append ODCL nodes to *init
|
2008-07-19 19:39:12 -06:00
|
|
|
*/
|
2009-08-04 19:43:32 -06:00
|
|
|
void
|
|
|
|
dodclvar(Node *n, Type *t, NodeList **init)
|
2008-07-19 19:39:12 -06:00
|
|
|
{
|
2009-08-04 19:43:32 -06:00
|
|
|
if(n == N)
|
|
|
|
return;
|
2008-07-19 19:39:12 -06:00
|
|
|
|
2009-08-04 19:43:32 -06:00
|
|
|
if(t != T && (t->etype == TIDEAL || t->etype == TNIL))
|
|
|
|
fatal("dodclvar %T", t);
|
|
|
|
dowidth(t);
|
2009-01-20 15:40:00 -07:00
|
|
|
|
2009-08-04 19:43:32 -06:00
|
|
|
// 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));
|
2008-07-19 19:39:12 -06:00
|
|
|
}
|
|
|
|
|
2009-08-04 19:43:32 -06:00
|
|
|
// TODO(rsc): cut
|
2008-06-04 15:37:38 -06:00
|
|
|
void
|
2009-08-04 19:43:32 -06:00
|
|
|
dodclconst(Node *n, Node *e)
|
2008-06-04 15:37:38 -06:00
|
|
|
{
|
2009-08-04 19:43:32 -06:00
|
|
|
if(n == N)
|
|
|
|
return;
|
|
|
|
addconst(n, e, dclcontext);
|
|
|
|
autoexport(n->sym);
|
|
|
|
}
|
2008-06-04 15:37:38 -06:00
|
|
|
|
2009-08-04 19:43:32 -06:00
|
|
|
/*
|
|
|
|
* introduce a type named n
|
|
|
|
* but it is an unknown type for now
|
|
|
|
*/
|
|
|
|
Type*
|
|
|
|
dodcltype(Type *n)
|
|
|
|
{
|
|
|
|
Sym *s;
|
2008-06-04 15:37:38 -06:00
|
|
|
|
2009-08-04 19:43:32 -06:00
|
|
|
// 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;
|
2008-10-24 15:56:54 -06:00
|
|
|
}
|
2009-08-04 19:43:32 -06:00
|
|
|
goto found;
|
2008-06-04 15:37:38 -06:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2009-08-04 19:43:32 -06:00
|
|
|
// otherwise declare a new type
|
|
|
|
addtyp(n, dclcontext);
|
2008-06-04 15:37:38 -06:00
|
|
|
|
2009-08-04 19:43:32 -06:00
|
|
|
found:
|
|
|
|
n->local = 1;
|
|
|
|
autoexport(n->sym);
|
|
|
|
return n;
|
2008-06-04 15:37:38 -06:00
|
|
|
}
|
|
|
|
|
2009-08-04 19:43:32 -06:00
|
|
|
/*
|
|
|
|
* now we know what n is: it's t
|
|
|
|
*/
|
2008-06-04 15:37:38 -06:00
|
|
|
void
|
2009-08-04 19:43:32 -06:00
|
|
|
updatetype(Type *n, Type *t)
|
2008-06-04 15:37:38 -06:00
|
|
|
{
|
2009-08-04 19:43:32 -06:00
|
|
|
Sym *s;
|
|
|
|
int local, vargen;
|
|
|
|
int maplineno, lno, etype;
|
2008-06-04 15:37:38 -06:00
|
|
|
|
2009-08-04 19:43:32 -06:00
|
|
|
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);
|
2009-02-06 14:47:10 -07:00
|
|
|
|
2009-08-04 19:43:32 -06:00
|
|
|
etype = n->etype;
|
|
|
|
switch(n->etype) {
|
|
|
|
case TFORW:
|
|
|
|
break;
|
|
|
|
|
|
|
|
case TFORWSTRUCT:
|
|
|
|
if(t->etype != TSTRUCT) {
|
|
|
|
yyerror("%T forward declared as struct", n);
|
|
|
|
return;
|
2008-07-17 16:03:39 -06:00
|
|
|
}
|
2009-08-04 19:43:32 -06:00
|
|
|
n->local = 1;
|
|
|
|
break;
|
2008-06-04 15:37:38 -06:00
|
|
|
|
2009-08-04 19:43:32 -06:00
|
|
|
case TFORWINTER:
|
|
|
|
if(t->etype != TINTER) {
|
|
|
|
yyerror("%T forward declared as interface", n);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
|
|
|
|
default:
|
|
|
|
fatal("updatetype %T / %T", n, t);
|
2008-07-05 13:49:25 -06:00
|
|
|
}
|
2008-10-02 21:51:10 -06:00
|
|
|
|
2009-08-04 19:43:32 -06:00
|
|
|
// 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;
|
2008-07-05 13:49:25 -06:00
|
|
|
|
2009-08-04 19:43:32 -06:00
|
|
|
// 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;
|
|
|
|
}
|
2008-06-04 15:37:38 -06:00
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
2009-08-04 19:43:32 -06:00
|
|
|
* declare variables from grammar
|
|
|
|
* new_name_list (type | [type] = expr_list)
|
2008-06-04 15:37:38 -06:00
|
|
|
*/
|
2009-08-04 19:43:32 -06:00
|
|
|
NodeList*
|
|
|
|
variter(NodeList *vl, Node *t, NodeList *el)
|
2008-06-04 15:37:38 -06:00
|
|
|
{
|
2009-08-04 19:43:32 -06:00
|
|
|
int doexpr, gen;
|
|
|
|
Node *v, *e;
|
|
|
|
NodeList *init;
|
|
|
|
Sym *s;
|
|
|
|
Dcl *r, *d;
|
2008-06-04 15:37:38 -06:00
|
|
|
|
2009-08-04 19:43:32 -06:00
|
|
|
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;
|
2009-02-06 14:47:10 -07:00
|
|
|
|
2009-08-04 19:43:32 -06:00
|
|
|
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;
|
2009-02-06 14:47:10 -07:00
|
|
|
|
2009-08-04 19:43:32 -06:00
|
|
|
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;
|
2009-02-06 14:47:10 -07:00
|
|
|
|
2009-08-04 19:43:32 -06:00
|
|
|
autoexport(s);
|
|
|
|
}
|
|
|
|
if(el != nil)
|
|
|
|
yyerror("extra expr in var dcl");
|
|
|
|
return init;
|
2008-06-04 15:37:38 -06:00
|
|
|
}
|
|
|
|
|
2009-08-04 19:43:32 -06:00
|
|
|
/*
|
|
|
|
* declare constants from grammar
|
|
|
|
* new_name_list [[type] = expr_list]
|
|
|
|
*/
|
|
|
|
NodeList*
|
|
|
|
constiter(NodeList *vl, Node *t, NodeList *cl)
|
2009-02-06 14:47:10 -07:00
|
|
|
{
|
2009-08-04 19:43:32 -06:00
|
|
|
Node *v, *c;
|
|
|
|
NodeList *vv;
|
|
|
|
Sym *s;
|
2009-07-28 21:01:00 -06:00
|
|
|
|
2009-08-04 19:43:32 -06:00
|
|
|
vv = vl;
|
|
|
|
if(cl == nil) {
|
|
|
|
if(t != N)
|
|
|
|
yyerror("constdcl cannot have type without expr");
|
|
|
|
cl = lastconst;
|
|
|
|
t = lasttype;
|
|
|
|
} else {
|
|
|
|
lastconst = cl;
|
|
|
|
lasttype = t;
|
2009-07-28 21:01:00 -06:00
|
|
|
}
|
2009-08-04 19:43:32 -06:00
|
|
|
cl = listtreecopy(cl);
|
2009-02-06 14:47:10 -07:00
|
|
|
|
2009-08-04 19:43:32 -06:00
|
|
|
for(; vl; vl=vl->next) {
|
|
|
|
if(cl == nil) {
|
|
|
|
yyerror("missing expr in const dcl");
|
|
|
|
break;
|
2009-02-06 14:47:10 -07:00
|
|
|
}
|
2009-08-04 19:43:32 -06:00
|
|
|
c = cl->n;
|
|
|
|
cl = cl->next;
|
2009-02-06 14:47:10 -07:00
|
|
|
|
2009-08-04 19:43:32 -06:00
|
|
|
v = vl->n;
|
|
|
|
s = v->sym;
|
|
|
|
if(dclcontext != PEXTERN)
|
|
|
|
pushdcl(s);
|
|
|
|
redeclare("constant", s);
|
|
|
|
s->def = v;
|
2009-07-28 21:01:00 -06:00
|
|
|
|
2009-08-04 19:43:32 -06:00
|
|
|
v->op = OLITERAL;
|
|
|
|
v->ntype = t;
|
|
|
|
v->defn = c;
|
|
|
|
autoexport(s);
|
2009-02-06 14:47:10 -07:00
|
|
|
}
|
2009-08-04 19:43:32 -06:00
|
|
|
if(cl != nil)
|
|
|
|
yyerror("extra expr in const dcl");
|
|
|
|
iota += 1;
|
|
|
|
return vv;
|
|
|
|
}
|
2009-02-06 14:47:10 -07:00
|
|
|
|
2009-08-04 19:43:32 -06:00
|
|
|
/*
|
|
|
|
* 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;
|
2009-07-28 21:01:00 -06:00
|
|
|
|
2009-08-04 19:43:32 -06:00
|
|
|
n = nod(ONAME, N, N);
|
|
|
|
n->sym = s;
|
|
|
|
n->type = T;
|
|
|
|
n->addable = 1;
|
|
|
|
n->ullman = 1;
|
|
|
|
n->xoffset = 0;
|
|
|
|
return n;
|
|
|
|
}
|
2009-02-06 14:47:10 -07:00
|
|
|
|
2009-08-04 19:43:32 -06:00
|
|
|
Node*
|
|
|
|
dclname(Sym *s)
|
|
|
|
{
|
|
|
|
Node *n;
|
2009-02-06 14:47:10 -07:00
|
|
|
|
2009-08-04 19:43:32 -06:00
|
|
|
// 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;
|
2009-02-06 14:47:10 -07:00
|
|
|
}
|
|
|
|
|
2009-08-04 19:43:32 -06:00
|
|
|
n = newname(s);
|
|
|
|
n->op = ONONAME; // caller will correct it
|
|
|
|
return n;
|
|
|
|
}
|
2009-02-06 14:47:10 -07:00
|
|
|
|
2009-08-04 19:43:32 -06:00
|
|
|
Node*
|
|
|
|
typenod(Type *t)
|
|
|
|
{
|
|
|
|
if(t->nod == N) {
|
|
|
|
t->nod = nod(OTYPE, N, N);
|
|
|
|
t->nod->type = t;
|
|
|
|
t->nod->sym = t->sym;
|
2009-02-06 14:47:10 -07:00
|
|
|
}
|
2009-08-04 19:43:32 -06:00
|
|
|
return t->nod;
|
2009-02-06 14:47:10 -07:00
|
|
|
}
|
|
|
|
|
2009-08-04 19:43:32 -06:00
|
|
|
|
2008-06-04 15:37:38 -06:00
|
|
|
/*
|
2009-08-04 19:43:32 -06:00
|
|
|
* 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.
|
2008-06-04 15:37:38 -06:00
|
|
|
*/
|
2009-08-04 19:43:32 -06:00
|
|
|
Node*
|
|
|
|
oldname(Sym *s)
|
2008-06-04 15:37:38 -06:00
|
|
|
{
|
2009-07-17 02:00:44 -06:00
|
|
|
Node *n;
|
2009-08-04 19:43:32 -06:00
|
|
|
Node *c;
|
2008-06-04 15:37:38 -06:00
|
|
|
|
2009-08-04 19:43:32 -06:00
|
|
|
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])
|
2009-07-14 00:38:39 -06:00
|
|
|
t1 = t1->type;
|
|
|
|
if(t1 != T && isptr[t1->etype])
|
|
|
|
yyerror("embedded type cannot be a pointer");
|
|
|
|
}
|
|
|
|
}
|
2008-06-04 15:37:38 -06:00
|
|
|
|
2009-07-14 00:38:39 -06:00
|
|
|
if(n->type == T) {
|
|
|
|
// assume error already printed
|
|
|
|
continue;
|
|
|
|
}
|
2009-02-16 17:36:18 -07:00
|
|
|
|
2009-07-14 00:38:39 -06:00
|
|
|
switch(n->val.ctype) {
|
|
|
|
case CTSTR:
|
|
|
|
if(et != TSTRUCT)
|
|
|
|
yyerror("interface method cannot have annotation");
|
|
|
|
note = n->val.u.sval;
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
if(et != TSTRUCT)
|
|
|
|
yyerror("interface method cannot have annotation");
|
|
|
|
else
|
|
|
|
yyerror("field annotation must be string");
|
|
|
|
case CTxxx:
|
|
|
|
note = nil;
|
|
|
|
break;
|
|
|
|
}
|
2008-10-30 16:13:09 -06:00
|
|
|
|
2009-07-14 00:38:39 -06:00
|
|
|
if(et == TINTER && n->left == N) {
|
|
|
|
// embedded interface - inline the methods
|
|
|
|
if(n->type->etype != TINTER) {
|
|
|
|
yyerror("interface contains embedded non-interface %T", t);
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
for(t1=n->type->type; t1!=T; t1=t1->down) {
|
|
|
|
// TODO(rsc): Is this really an error?
|
|
|
|
if(strcmp(t1->sym->package, package) != 0)
|
|
|
|
yyerror("embedded interface contains unexported method %S", t1->sym);
|
|
|
|
f = typ(TFIELD);
|
|
|
|
f->type = t1->type;
|
|
|
|
f->width = BADWIDTH;
|
|
|
|
f->nname = newname(t1->sym);
|
|
|
|
f->sym = t1->sym;
|
|
|
|
*t = f;
|
|
|
|
t = &f->down;
|
|
|
|
}
|
|
|
|
continue;
|
2009-02-16 17:36:18 -07:00
|
|
|
}
|
2009-07-14 00:38:39 -06:00
|
|
|
|
|
|
|
f = typ(TFIELD);
|
|
|
|
f->type = n->type;
|
|
|
|
f->note = note;
|
|
|
|
f->width = BADWIDTH;
|
|
|
|
|
|
|
|
if(n->left != N && n->left->op == ONAME) {
|
|
|
|
f->nname = n->left;
|
|
|
|
f->embedded = n->embedded;
|
|
|
|
f->sym = f->nname->sym;
|
|
|
|
if(pkgimportname != S && !exportname(f->sym->name))
|
|
|
|
f->sym = pkglookup(f->sym->name, structpkg);
|
2009-02-16 17:36:18 -07:00
|
|
|
}
|
|
|
|
|
2009-07-14 00:38:39 -06:00
|
|
|
*t = f;
|
|
|
|
t = &f->down;
|
2008-06-04 15:37:38 -06:00
|
|
|
}
|
|
|
|
|
2009-07-14 00:38:39 -06:00
|
|
|
*t = T;
|
|
|
|
lineno = lno;
|
|
|
|
return t;
|
2008-06-04 15:37:38 -06:00
|
|
|
}
|
|
|
|
|
|
|
|
Type*
|
2009-07-17 02:00:44 -06:00
|
|
|
dostruct(NodeList *l, int et)
|
2008-06-04 15:37:38 -06:00
|
|
|
{
|
|
|
|
Type *t;
|
2008-11-11 14:46:55 -07:00
|
|
|
int funarg;
|
2008-06-04 15:37:38 -06:00
|
|
|
|
|
|
|
/*
|
|
|
|
* convert a parsed id/type list into
|
|
|
|
* a type for struct/interface/arglist
|
|
|
|
*/
|
|
|
|
|
2008-11-11 14:46:55 -07:00
|
|
|
funarg = 0;
|
|
|
|
if(et == TFUNC) {
|
|
|
|
funarg = 1;
|
|
|
|
et = TSTRUCT;
|
|
|
|
}
|
2008-06-04 15:37:38 -06:00
|
|
|
t = typ(et);
|
2008-11-11 14:46:55 -07:00
|
|
|
t->funarg = funarg;
|
2009-07-17 02:00:44 -06:00
|
|
|
stotype(l, et, &t->type);
|
2008-11-11 14:46:55 -07:00
|
|
|
if(!funarg)
|
|
|
|
checkwidth(t);
|
2008-06-04 15:37:38 -06:00
|
|
|
return t;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2009-08-04 19:43:32 -06:00
|
|
|
Node*
|
|
|
|
embedded(Sym *s)
|
2008-06-04 15:37:38 -06:00
|
|
|
{
|
2009-08-04 19:43:32 -06:00
|
|
|
Node *n;
|
|
|
|
char *name;
|
2008-06-04 15:37:38 -06:00
|
|
|
|
2009-08-04 19:43:32 -06:00
|
|
|
// 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;
|
|
|
|
}
|
2008-06-04 15:37:38 -06:00
|
|
|
|
2009-08-04 19:43:32 -06:00
|
|
|
n = newname(lookup(name));
|
|
|
|
n = nod(ODCLFIELD, n, N);
|
|
|
|
n->embedded = 1;
|
|
|
|
if(s == S)
|
|
|
|
return n;
|
|
|
|
n->right = oldname(s);
|
|
|
|
return n;
|
2008-06-04 15:37:38 -06:00
|
|
|
}
|
|
|
|
|
2009-08-04 19:43:32 -06:00
|
|
|
static Node*
|
|
|
|
findtype(NodeList *l)
|
2008-06-04 15:37:38 -06:00
|
|
|
{
|
2009-08-04 19:43:32 -06:00
|
|
|
for(; l; l=l->next)
|
|
|
|
if(l->n->op == OKEY)
|
|
|
|
return l->n->right;
|
|
|
|
return N;
|
2008-06-04 15:37:38 -06:00
|
|
|
}
|
|
|
|
|
2009-08-04 19:43:32 -06:00
|
|
|
static Node*
|
|
|
|
xanondcl(Node *nt)
|
2008-06-04 15:37:38 -06:00
|
|
|
{
|
2009-08-04 19:43:32 -06:00
|
|
|
Node *n;
|
|
|
|
Type *t;
|
2008-06-13 19:16:23 -06:00
|
|
|
|
2009-08-04 19:43:32 -06:00
|
|
|
typecheck(&nt, Etype);
|
|
|
|
t = nt->type;
|
|
|
|
if(nt->op != OTYPE) {
|
|
|
|
yyerror("%S is not a type", nt->sym);
|
|
|
|
t = types[TINT32];
|
2008-06-04 15:37:38 -06:00
|
|
|
}
|
2009-08-04 19:43:32 -06:00
|
|
|
n = nod(ODCLFIELD, N, N);
|
|
|
|
n->type = t;
|
|
|
|
return n;
|
2008-06-04 15:37:38 -06:00
|
|
|
}
|
|
|
|
|
2009-08-04 19:43:32 -06:00
|
|
|
static Node*
|
|
|
|
namedcl(Node *nn, Node *nt)
|
2008-06-04 15:37:38 -06:00
|
|
|
{
|
2009-08-04 19:43:32 -06:00
|
|
|
Node *n;
|
|
|
|
Type *t;
|
2008-06-04 15:37:38 -06:00
|
|
|
|
2009-08-04 19:43:32 -06:00
|
|
|
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);
|
2008-06-04 15:37:38 -06:00
|
|
|
}
|
2009-08-04 19:43:32 -06:00
|
|
|
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;
|
2008-06-04 15:37:38 -06:00
|
|
|
}
|
|
|
|
|
2009-08-04 19:43:32 -06:00
|
|
|
/*
|
|
|
|
* check that the list of declarations is either all anonymous or all named
|
|
|
|
*/
|
|
|
|
NodeList*
|
|
|
|
checkarglist(NodeList *all)
|
2008-06-04 15:37:38 -06:00
|
|
|
{
|
2009-08-04 19:43:32 -06:00
|
|
|
int named;
|
|
|
|
Node *r;
|
|
|
|
NodeList *l;
|
2008-07-05 13:49:25 -06:00
|
|
|
|
2009-08-04 19:43:32 -06:00
|
|
|
named = 0;
|
|
|
|
for(l=all; l; l=l->next) {
|
|
|
|
if(l->n->op == OKEY) {
|
|
|
|
named = 1;
|
|
|
|
break;
|
2008-06-04 15:37:38 -06:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2009-08-04 19:43:32 -06:00
|
|
|
for(l=all; l; l=l->next) {
|
|
|
|
if(named)
|
|
|
|
l->n = namedcl(l->n, findtype(l));
|
2008-06-04 15:37:38 -06:00
|
|
|
else
|
2009-08-04 19:43:32 -06:00
|
|
|
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 ...");
|
|
|
|
}
|
2008-06-04 15:37:38 -06:00
|
|
|
}
|
2009-08-04 19:43:32 -06:00
|
|
|
return all;
|
2008-06-04 15:37:38 -06:00
|
|
|
}
|
|
|
|
|
2008-10-06 17:44:17 -06:00
|
|
|
|
2008-06-04 15:37:38 -06:00
|
|
|
Node*
|
|
|
|
fakethis(void)
|
|
|
|
{
|
|
|
|
Node *n;
|
|
|
|
|
|
|
|
n = nod(ODCLFIELD, N, N);
|
2009-05-07 14:42:47 -06:00
|
|
|
n->type = ptrto(typ(TSTRUCT));
|
2008-06-04 15:37:38 -06:00
|
|
|
return n;
|
|
|
|
}
|
|
|
|
|
2009-05-07 14:42:47 -06:00
|
|
|
/*
|
|
|
|
* Is this field a method on an interface?
|
|
|
|
* Those methods have an anonymous
|
|
|
|
* *struct{} as the receiver.
|
|
|
|
* (See fakethis above.)
|
|
|
|
*/
|
|
|
|
int
|
|
|
|
isifacemethod(Type *f)
|
|
|
|
{
|
|
|
|
Type *rcvr;
|
|
|
|
Type *t;
|
|
|
|
|
|
|
|
rcvr = getthisx(f->type)->type;
|
|
|
|
if(rcvr->sym != S)
|
|
|
|
return 0;
|
|
|
|
t = rcvr->type;
|
|
|
|
if(!isptr[t->etype])
|
|
|
|
return 0;
|
|
|
|
t = t->type;
|
|
|
|
if(t->sym != S || t->etype != TSTRUCT || t->type != T)
|
|
|
|
return 0;
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
|
2008-06-04 15:37:38 -06:00
|
|
|
/*
|
2009-08-04 19:43:32 -06:00
|
|
|
* turn a parsed function declaration
|
|
|
|
* into a type
|
2008-06-04 15:37:38 -06:00
|
|
|
*/
|
2009-08-04 19:43:32 -06:00
|
|
|
Type*
|
|
|
|
functype(Node *this, NodeList *in, NodeList *out)
|
2008-06-04 15:37:38 -06:00
|
|
|
{
|
2009-08-04 19:43:32 -06:00
|
|
|
Type *t;
|
|
|
|
NodeList *rcvr;
|
2008-06-04 15:37:38 -06:00
|
|
|
|
2009-08-04 19:43:32 -06:00
|
|
|
t = typ(TFUNC);
|
2008-06-04 15:37:38 -06:00
|
|
|
|
2009-08-04 19:43:32 -06:00
|
|
|
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);
|
2009-07-17 14:38:16 -06:00
|
|
|
|
2009-08-04 19:43:32 -06:00
|
|
|
if(this)
|
|
|
|
t->thistuple = 1;
|
|
|
|
t->outtuple = count(out);
|
|
|
|
t->intuple = count(in);
|
2009-07-17 14:38:16 -06:00
|
|
|
|
2009-08-04 19:43:32 -06:00
|
|
|
checkwidth(t);
|
|
|
|
return t;
|
2009-07-17 14:38:16 -06:00
|
|
|
}
|
|
|
|
|
2009-08-04 19:43:32 -06:00
|
|
|
int
|
|
|
|
methcmp(Type *t1, Type *t2)
|
2009-06-06 13:46:38 -06:00
|
|
|
{
|
2009-08-04 19:43:32 -06:00
|
|
|
if(t1->etype != TFUNC)
|
|
|
|
return 0;
|
|
|
|
if(t2->etype != TFUNC)
|
|
|
|
return 0;
|
2009-06-06 13:46:38 -06:00
|
|
|
|
2009-08-04 19:43:32 -06:00
|
|
|
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;
|
2009-06-06 13:46:38 -06:00
|
|
|
|
2009-08-04 19:43:32 -06:00
|
|
|
if(!eqtype(t1->type, t2->type))
|
|
|
|
return 0;
|
2008-06-04 15:37:38 -06:00
|
|
|
|
2009-08-04 19:43:32 -06:00
|
|
|
t1 = t1->down;
|
|
|
|
t2 = t2->down;
|
2009-02-06 14:47:10 -07:00
|
|
|
}
|
2009-08-04 19:43:32 -06:00
|
|
|
return 1;
|
2008-06-04 15:37:38 -06:00
|
|
|
}
|
|
|
|
|
2009-08-04 19:43:32 -06:00
|
|
|
Sym*
|
|
|
|
methodsym(Sym *nsym, Type *t0)
|
2008-06-04 15:37:38 -06:00
|
|
|
{
|
2009-08-04 19:43:32 -06:00
|
|
|
Sym *s;
|
|
|
|
char buf[NSYMB];
|
2008-06-04 15:37:38 -06:00
|
|
|
Type *t;
|
|
|
|
|
2009-08-04 19:43:32 -06:00
|
|
|
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;
|
|
|
|
}
|
2008-06-04 15:37:38 -06:00
|
|
|
|
2009-08-04 19:43:32 -06:00
|
|
|
// 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);
|
2008-06-04 15:37:38 -06:00
|
|
|
|
2009-08-04 19:43:32 -06:00
|
|
|
snprint(buf, sizeof(buf), "%#hT·%s", t0, nsym->name);
|
|
|
|
//print("methodname %s\n", buf);
|
|
|
|
return pkglookup(buf, s->package);
|
2009-06-06 13:46:38 -06:00
|
|
|
|
2009-08-04 19:43:32 -06:00
|
|
|
bad:
|
|
|
|
yyerror("illegal <this> type: %T", t);
|
|
|
|
return S;
|
2008-06-04 15:37:38 -06:00
|
|
|
}
|
|
|
|
|
fix up arg list parsing to handle any names:
type t1 int;
type t2 int;
type t3 int;
func f1(t1, t2, t3);
func f2(t1, t2, t3 bool);
func f3(t1, t2, x t3);
func f4(*t2, x t3); // error: cannot mix
func f5(t1, *t3);
func (x *t1) f6(y *[]t2) (t1, *t3);
func f7() (int, *string);
func f8(t1, *t2, x t3); // error: cannot mix
func f9() (x int, *string);
func f10(*t2, t3);
R=ken
OCL=16202
CL=16210
2008-09-30 13:53:11 -06:00
|
|
|
Node*
|
2009-08-04 19:43:32 -06:00
|
|
|
methodname(Node *n, Type *t)
|
fix up arg list parsing to handle any names:
type t1 int;
type t2 int;
type t3 int;
func f1(t1, t2, t3);
func f2(t1, t2, t3 bool);
func f3(t1, t2, x t3);
func f4(*t2, x t3); // error: cannot mix
func f5(t1, *t3);
func (x *t1) f6(y *[]t2) (t1, *t3);
func f7() (int, *string);
func f8(t1, *t2, x t3); // error: cannot mix
func f9() (x int, *string);
func f10(*t2, t3);
R=ken
OCL=16202
CL=16210
2008-09-30 13:53:11 -06:00
|
|
|
{
|
2009-08-04 19:43:32 -06:00
|
|
|
Sym *s;
|
|
|
|
|
|
|
|
s = methodsym(n->sym, t);
|
|
|
|
if(s == S)
|
|
|
|
return n;
|
|
|
|
return newname(s);
|
fix up arg list parsing to handle any names:
type t1 int;
type t2 int;
type t3 int;
func f1(t1, t2, t3);
func f2(t1, t2, t3 bool);
func f3(t1, t2, x t3);
func f4(*t2, x t3); // error: cannot mix
func f5(t1, *t3);
func (x *t1) f6(y *[]t2) (t1, *t3);
func f7() (int, *string);
func f8(t1, *t2, x t3); // error: cannot mix
func f9() (x int, *string);
func f10(*t2, t3);
R=ken
OCL=16202
CL=16210
2008-09-30 13:53:11 -06:00
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
2009-08-04 19:43:32 -06:00
|
|
|
* add a method, declared as a function,
|
|
|
|
* n is fieldname, pa is base type, t is function type
|
fix up arg list parsing to handle any names:
type t1 int;
type t2 int;
type t3 int;
func f1(t1, t2, t3);
func f2(t1, t2, t3 bool);
func f3(t1, t2, x t3);
func f4(*t2, x t3); // error: cannot mix
func f5(t1, *t3);
func (x *t1) f6(y *[]t2) (t1, *t3);
func f7() (int, *string);
func f8(t1, *t2, x t3); // error: cannot mix
func f9() (x int, *string);
func f10(*t2, t3);
R=ken
OCL=16202
CL=16210
2008-09-30 13:53:11 -06:00
|
|
|
*/
|
2009-08-04 19:43:32 -06:00
|
|
|
void
|
|
|
|
addmethod(Node *n, Type *t, int local)
|
fix up arg list parsing to handle any names:
type t1 int;
type t2 int;
type t3 int;
func f1(t1, t2, t3);
func f2(t1, t2, t3 bool);
func f3(t1, t2, x t3);
func f4(*t2, x t3); // error: cannot mix
func f5(t1, *t3);
func (x *t1) f6(y *[]t2) (t1, *t3);
func f7() (int, *string);
func f8(t1, *t2, x t3); // error: cannot mix
func f9() (x int, *string);
func f10(*t2, t3);
R=ken
OCL=16202
CL=16210
2008-09-30 13:53:11 -06:00
|
|
|
{
|
2009-08-04 19:43:32 -06:00
|
|
|
Type *f, *d, *pa;
|
|
|
|
Sym *sf;
|
fix up arg list parsing to handle any names:
type t1 int;
type t2 int;
type t3 int;
func f1(t1, t2, t3);
func f2(t1, t2, t3 bool);
func f3(t1, t2, x t3);
func f4(*t2, x t3); // error: cannot mix
func f5(t1, *t3);
func (x *t1) f6(y *[]t2) (t1, *t3);
func f7() (int, *string);
func f8(t1, *t2, x t3); // error: cannot mix
func f9() (x int, *string);
func f10(*t2, t3);
R=ken
OCL=16202
CL=16210
2008-09-30 13:53:11 -06:00
|
|
|
|
2009-08-04 19:43:32 -06:00
|
|
|
pa = nil;
|
|
|
|
sf = nil;
|
fix up arg list parsing to handle any names:
type t1 int;
type t2 int;
type t3 int;
func f1(t1, t2, t3);
func f2(t1, t2, t3 bool);
func f3(t1, t2, x t3);
func f4(*t2, x t3); // error: cannot mix
func f5(t1, *t3);
func (x *t1) f6(y *[]t2) (t1, *t3);
func f7() (int, *string);
func f8(t1, *t2, x t3); // error: cannot mix
func f9() (x int, *string);
func f10(*t2, t3);
R=ken
OCL=16202
CL=16210
2008-09-30 13:53:11 -06:00
|
|
|
|
2009-08-04 19:43:32 -06:00
|
|
|
// get field sym
|
|
|
|
if(n == N)
|
|
|
|
goto bad;
|
|
|
|
if(n->op != ONAME)
|
|
|
|
goto bad;
|
|
|
|
sf = n->sym;
|
|
|
|
if(sf == S)
|
|
|
|
goto bad;
|
2009-06-06 13:46:38 -06:00
|
|
|
|
2009-08-04 19:43:32 -06:00
|
|
|
// 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;
|
2009-06-06 13:46:38 -06:00
|
|
|
|
2009-08-04 19:43:32 -06:00
|
|
|
f = methtype(pa);
|
|
|
|
if(f == T)
|
|
|
|
goto bad;
|
2009-06-06 13:46:38 -06:00
|
|
|
|
2009-08-04 19:43:32 -06:00
|
|
|
pa = f;
|
|
|
|
if(pkgimportname != S && !exportname(sf->name))
|
|
|
|
sf = pkglookup(sf->name, pkgimportname->name);
|
2009-06-06 13:46:38 -06:00
|
|
|
|
2009-08-04 19:43:32 -06:00
|
|
|
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;
|
2009-06-06 13:46:38 -06:00
|
|
|
}
|
2009-08-04 19:43:32 -06:00
|
|
|
|
|
|
|
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;
|
2009-07-17 15:42:14 -06:00
|
|
|
}
|
2009-08-04 19:43:32 -06:00
|
|
|
|
|
|
|
if(d == T)
|
|
|
|
stotype(list1(n), 0, &pa->method);
|
|
|
|
else
|
|
|
|
stotype(list1(n), 0, &d->down);
|
|
|
|
return;
|
|
|
|
|
|
|
|
bad:
|
|
|
|
yyerror("invalid receiver type %T", pa);
|
2009-06-06 13:46:38 -06:00
|
|
|
}
|
|
|
|
|
fix up arg list parsing to handle any names:
type t1 int;
type t2 int;
type t3 int;
func f1(t1, t2, t3);
func f2(t1, t2, t3 bool);
func f3(t1, t2, x t3);
func f4(*t2, x t3); // error: cannot mix
func f5(t1, *t3);
func (x *t1) f6(y *[]t2) (t1, *t3);
func f7() (int, *string);
func f8(t1, *t2, x t3); // error: cannot mix
func f9() (x int, *string);
func f10(*t2, t3);
R=ken
OCL=16202
CL=16210
2008-09-30 13:53:11 -06:00
|
|
|
/*
|
2009-08-04 19:43:32 -06:00
|
|
|
* declare the function proper.
|
|
|
|
* and declare the arguments
|
|
|
|
* called in extern-declaration context
|
|
|
|
* returns in auto-declaration context.
|
fix up arg list parsing to handle any names:
type t1 int;
type t2 int;
type t3 int;
func f1(t1, t2, t3);
func f2(t1, t2, t3 bool);
func f3(t1, t2, x t3);
func f4(*t2, x t3); // error: cannot mix
func f5(t1, *t3);
func (x *t1) f6(y *[]t2) (t1, *t3);
func f7() (int, *string);
func f8(t1, *t2, x t3); // error: cannot mix
func f9() (x int, *string);
func f10(*t2, t3);
R=ken
OCL=16202
CL=16210
2008-09-30 13:53:11 -06:00
|
|
|
*/
|
2009-08-04 19:43:32 -06:00
|
|
|
void
|
|
|
|
funchdr(Node *n)
|
|
|
|
{
|
|
|
|
Node *on;
|
|
|
|
Sym *s;
|
2009-06-06 13:46:38 -06:00
|
|
|
|
2009-08-04 19:43:32 -06:00
|
|
|
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;
|
2009-07-17 02:00:44 -06:00
|
|
|
}
|
|
|
|
}
|
fix up arg list parsing to handle any names:
type t1 int;
type t2 int;
type t3 int;
func f1(t1, t2, t3);
func f2(t1, t2, t3 bool);
func f3(t1, t2, x t3);
func f4(*t2, x t3); // error: cannot mix
func f5(t1, *t3);
func (x *t1) f6(y *[]t2) (t1, *t3);
func f7() (int, *string);
func f8(t1, *t2, x t3); // error: cannot mix
func f9() (x int, *string);
func f10(*t2, t3);
R=ken
OCL=16202
CL=16210
2008-09-30 13:53:11 -06:00
|
|
|
|
2009-08-04 19:43:32 -06:00
|
|
|
// 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);
|
2009-07-17 02:00:44 -06:00
|
|
|
else
|
2009-08-04 19:43:32 -06:00
|
|
|
n->nname->class = PFUNC;
|
|
|
|
} else {
|
|
|
|
// identical redeclaration
|
|
|
|
// steal previous names
|
|
|
|
n->nname = on;
|
|
|
|
n->type = on->type;
|
|
|
|
n->class = on->class;
|
|
|
|
n->sym = s;
|
2009-07-17 02:00:44 -06:00
|
|
|
}
|
fix up arg list parsing to handle any names:
type t1 int;
type t2 int;
type t3 int;
func f1(t1, t2, t3);
func f2(t1, t2, t3 bool);
func f3(t1, t2, x t3);
func f4(*t2, x t3); // error: cannot mix
func f5(t1, *t3);
func (x *t1) f6(y *[]t2) (t1, *t3);
func f7() (int, *string);
func f8(t1, *t2, x t3); // error: cannot mix
func f9() (x int, *string);
func f10(*t2, t3);
R=ken
OCL=16202
CL=16210
2008-09-30 13:53:11 -06:00
|
|
|
|
2009-08-04 19:43:32 -06:00
|
|
|
// change the declaration context from extern to auto
|
|
|
|
autodcl = dcl();
|
|
|
|
autodcl->back = autodcl;
|
2009-05-01 19:55:16 -06:00
|
|
|
|
2009-08-04 19:43:32 -06:00
|
|
|
if(funcdepth == 0 && dclcontext != PEXTERN)
|
|
|
|
fatal("funchdr: dclcontext");
|
2009-05-01 19:55:16 -06:00
|
|
|
|
2009-08-04 19:43:32 -06:00
|
|
|
dclcontext = PAUTO;
|
|
|
|
markdcl();
|
|
|
|
funcargs(n->type);
|
2009-05-01 19:55:16 -06:00
|
|
|
}
|
|
|
|
|
2008-07-19 14:38:29 -06:00
|
|
|
void
|
2009-08-04 19:43:32 -06:00
|
|
|
funcargs(Type *ft)
|
2008-07-19 14:38:29 -06:00
|
|
|
{
|
2009-08-04 19:43:32 -06:00
|
|
|
Type *t;
|
|
|
|
Iter save;
|
|
|
|
int all;
|
2009-05-28 17:00:55 -06:00
|
|
|
|
2009-08-04 19:43:32 -06:00
|
|
|
funcdepth++;
|
2008-07-19 14:38:29 -06:00
|
|
|
|
2009-08-04 19:43:32 -06:00
|
|
|
// 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);
|
2008-07-19 14:38:29 -06:00
|
|
|
}
|
|
|
|
|
2009-08-04 19:43:32 -06:00
|
|
|
// 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);
|
2008-07-19 14:38:29 -06:00
|
|
|
}
|
|
|
|
|
2009-08-04 19:43:32 -06:00
|
|
|
// this test is remarkedly similar to checkarglist
|
|
|
|
if(all == 3)
|
|
|
|
yyerror("cannot mix anonymous and named output arguments");
|
2008-07-19 14:38:29 -06:00
|
|
|
|
2009-08-04 19:43:32 -06:00
|
|
|
ft->outnamed = 0;
|
|
|
|
if(all == 1)
|
|
|
|
ft->outnamed = 1;
|
2008-07-19 14:38:29 -06:00
|
|
|
}
|
2008-10-06 17:44:17 -06:00
|
|
|
|
|
|
|
/*
|
2009-08-04 19:43:32 -06:00
|
|
|
* compile the function.
|
|
|
|
* called in auto-declaration context.
|
|
|
|
* returns in extern-declaration context.
|
2008-10-06 17:44:17 -06:00
|
|
|
*/
|
|
|
|
void
|
2009-08-04 19:43:32 -06:00
|
|
|
funcbody(Node *n)
|
2008-10-06 17:44:17 -06:00
|
|
|
{
|
|
|
|
|
2009-08-04 19:43:32 -06:00
|
|
|
compile(n);
|
2008-10-06 17:44:17 -06:00
|
|
|
|
2009-08-04 19:43:32 -06:00
|
|
|
// change the declaration context from auto to extern
|
|
|
|
if(dclcontext != PAUTO)
|
|
|
|
fatal("funcbody: dclcontext");
|
|
|
|
popdcl();
|
|
|
|
funcdepth--;
|
|
|
|
if(funcdepth == 0)
|
|
|
|
dclcontext = PEXTERN;
|
2008-10-06 17:44:17 -06:00
|
|
|
}
|
|
|
|
|
2009-08-04 19:43:32 -06:00
|
|
|
Node*
|
|
|
|
funclit0(Node *t)
|
2008-10-06 17:44:17 -06:00
|
|
|
{
|
2009-08-04 19:43:32 -06:00
|
|
|
Node *n;
|
2008-10-06 17:44:17 -06:00
|
|
|
|
2009-08-04 19:43:32 -06:00
|
|
|
n = nod(OXXX, N, N);
|
|
|
|
n->outer = funclit;
|
|
|
|
n->dcl = autodcl;
|
|
|
|
funclit = n;
|
2008-10-06 17:44:17 -06:00
|
|
|
|
2009-08-04 19:43:32 -06:00
|
|
|
// new declaration context
|
|
|
|
autodcl = dcl();
|
|
|
|
autodcl->back = autodcl;
|
2008-10-06 17:44:17 -06:00
|
|
|
|
2009-08-04 19:43:32 -06:00
|
|
|
typecheck(&t, Etype);
|
|
|
|
funcargs(t->type);
|
|
|
|
return t;
|
2008-10-06 17:44:17 -06:00
|
|
|
}
|
2008-10-21 16:04:10 -06:00
|
|
|
|
|
|
|
Node*
|
2009-08-04 19:43:32 -06:00
|
|
|
funclit1(Node *ntype, NodeList *body)
|
2008-10-21 16:04:10 -06:00
|
|
|
{
|
2009-08-04 19:43:32 -06:00
|
|
|
Node *func;
|
|
|
|
Type *type;
|
|
|
|
Node *a, *d, *f, *n, *clos;
|
|
|
|
Type *ft, *t;
|
|
|
|
Iter save;
|
|
|
|
int narg, shift;
|
|
|
|
NodeList *args, *l, *in, *out;
|
2008-11-14 17:35:08 -07:00
|
|
|
|
2009-08-04 19:43:32 -06:00
|
|
|
type = ntype->type;
|
|
|
|
popdcl();
|
|
|
|
func = funclit;
|
|
|
|
funclit = func->outer;
|
2008-10-21 16:04:10 -06:00
|
|
|
|
2009-08-04 19:43:32 -06:00
|
|
|
// 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);
|
2008-12-04 16:33:40 -07:00
|
|
|
|
2009-08-04 19:43:32 -06:00
|
|
|
// 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;
|
2009-07-17 02:00:44 -06:00
|
|
|
|
2009-08-04 19:43:32 -06:00
|
|
|
a->xoffset = 0;
|
2008-12-04 16:33:40 -07:00
|
|
|
|
2009-08-04 19:43:32 -06:00
|
|
|
// unlink from actual ONAME in symbol table
|
|
|
|
a->closure->closure = a->outer;
|
|
|
|
}
|
2009-08-03 12:58:52 -06:00
|
|
|
|
2009-08-04 19:43:32 -06:00
|
|
|
// add a dummy arg for the closure's caller pc
|
|
|
|
d = nod(ODCLFIELD, N, N);
|
|
|
|
d->type = types[TUINTPTR];
|
|
|
|
in = list(in, d);
|
2009-08-04 17:53:06 -06:00
|
|
|
|
2009-08-04 19:43:32 -06:00
|
|
|
// slide param offset to make room for ptrs above.
|
|
|
|
// narg+1 to skip over caller pc.
|
|
|
|
shift = (narg+1)*types[tptr]->width;
|
2009-08-04 17:53:06 -06:00
|
|
|
|
2009-08-04 19:43:32 -06:00
|
|
|
// 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);
|
2009-08-04 17:53:06 -06:00
|
|
|
|
2009-08-04 19:43:32 -06:00
|
|
|
a = t->nname;
|
|
|
|
if(a != N) {
|
|
|
|
if(a->stackparam != N)
|
|
|
|
a = a->stackparam;
|
|
|
|
a->xoffset += shift;
|
|
|
|
}
|
2009-07-10 17:29:26 -06:00
|
|
|
}
|
2008-12-04 16:33:40 -07:00
|
|
|
|
2009-08-04 19:43:32 -06:00
|
|
|
// 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);
|
2008-12-04 16:33:40 -07:00
|
|
|
|
2009-08-04 19:43:32 -06:00
|
|
|
a = t->nname;
|
|
|
|
if(a != N) {
|
|
|
|
if(a->stackparam != N)
|
|
|
|
a = a->stackparam;
|
|
|
|
a->xoffset += shift;
|
|
|
|
}
|
2009-03-12 20:04:38 -06:00
|
|
|
}
|
2008-12-11 12:54:33 -07:00
|
|
|
|
2009-08-04 19:43:32 -06:00
|
|
|
ft = functype(N, in, out);
|
|
|
|
ft->outnamed = type->outnamed;
|
2009-07-17 02:00:44 -06:00
|
|
|
|
2009-08-04 19:43:32 -06:00
|
|
|
// declare function.
|
|
|
|
vargen++;
|
|
|
|
snprint(namebuf, sizeof(namebuf), "_f%.3ld·%s", vargen, filename);
|
|
|
|
f = newname(lookup(namebuf));
|
|
|
|
addvar(f, ft, PFUNC);
|
|
|
|
f->funcdepth = 0;
|
2009-07-17 14:38:16 -06:00
|
|
|
|
2009-08-04 19:43:32 -06:00
|
|
|
// 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;
|
2009-02-07 13:34:45 -07:00
|
|
|
|
2009-08-04 19:43:32 -06:00
|
|
|
// 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);
|
2009-02-07 13:34:45 -07:00
|
|
|
}
|
|
|
|
|
2009-08-04 19:43:32 -06:00
|
|
|
d = nod(ODCLFIELD, N, N);
|
|
|
|
d->type = type;
|
|
|
|
out = list1(d);
|
2009-08-04 17:53:06 -06:00
|
|
|
|
2009-08-04 19:43:32 -06:00
|
|
|
clos = syslook("closure", 1);
|
|
|
|
clos->type = functype(N, in, out);
|
2009-08-04 17:53:06 -06:00
|
|
|
|
2009-08-04 19:43:32 -06:00
|
|
|
// 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));
|
2009-08-04 17:53:06 -06:00
|
|
|
}
|
2009-08-04 19:43:32 -06:00
|
|
|
typechecklist(args, Erv);
|
|
|
|
|
|
|
|
n = nod(OCALL, clos, N);
|
|
|
|
n->list = args;
|
|
|
|
return n;
|
2009-08-04 17:53:06 -06:00
|
|
|
}
|