Commit aa347c4a authored by Russ Cox's avatar Russ Cox

move various bits of code around

and delete some dead code.
no actual changes here.

R=ken
OCL=32764
CL=32764
parent d169dcee
...@@ -15,28 +15,30 @@ YFILES=\ ...@@ -15,28 +15,30 @@ YFILES=\
go.y\ go.y\
OFILES=\ OFILES=\
reflect.$O\ align.$O\
y.tab.$O\ bits.$O\
lex.$O\ builtin.$O\
subr.$O\ compat.$O\
const.$O\
dcl.$O\ dcl.$O\
sinit.$O\
export.$O\ export.$O\
walk.$O\ gen.$O\
swt.$O\ init.$O\
const.$O\ lex.$O\
mparith1.$O\ mparith1.$O\
mparith2.$O\ mparith2.$O\
mparith3.$O\ mparith3.$O\
builtin.$O\
compat.$O\
bits.$O\
align.$O\
gen.$O\
obj.$O\ obj.$O\
print.$O\ print.$O\
typecheck.$O\ reflect.$O\
select.$O\ select.$O\
sinit.$O\
subr.$O\
swt.$O\
typecheck.$O\
unsafe.$O\
walk.$O\
y.tab.$O\
$(LIB): $(OFILES) $(LIB): $(OFILES)
ar rsc $(LIB) $(OFILES) ar rsc $(LIB) $(OFILES)
......
...@@ -18,697 +18,747 @@ dflag(void) ...@@ -18,697 +18,747 @@ dflag(void)
} }
/* /*
* declare (possible list) n of type t. * declaration stack & operations
* append ODCL nodes to *init
*/ */
static Sym* dclstack;
void void
dodclvar(Node *n, Type *t, NodeList **init) dcopy(Sym *a, Sym *b)
{ {
if(n == N) a->name = b->name;
return; a->def = b->def;
a->package = b->package;
if(t != T && (t->etype == TIDEAL || t->etype == TNIL)) a->undef = b->undef;
fatal("dodclvar %T", t); a->vargen = b->vargen;
dowidth(t); a->block = b->block;
a->lastlineno = b->lastlineno;
a->offset = b->offset;
}
// in case of type checking error, Sym*
// use "undefined" type for variable type, push(void)
// to avoid fatal in addvar. {
if(t == T) Sym *d;
t = typ(TFORW);
addvar(n, t, dclcontext); d = mal(sizeof(*d));
autoexport(n->sym); d->link = dclstack;
if(funcdepth > 0) dclstack = d;
*init = list(*init, nod(ODCL, n, N)); return d;
} }
// TODO(rsc): cut Sym*
void pushdcl(Sym *s)
dodclconst(Node *n, Node *e)
{ {
if(n == N) Sym *d;
return;
addconst(n, e, dclcontext); d = push();
autoexport(n->sym); dcopy(d, s);
return d;
} }
/* void
* introduce a type named n popdcl(void)
* but it is an unknown type for now
*/
Type*
dodcltype(Type *n)
{ {
Sym *s; Sym *d, *s;
// if n has been forward declared, // if(dflag())
// use the Type* created then // print("revert\n");
s = n->sym;
if((funcdepth == 0 || s->block == block) && s->def != N && s->def->op == OTYPE) { for(d=dclstack; d!=S; d=d->link) {
switch(s->def->type->etype) { if(d->name == nil)
case TFORWSTRUCT: break;
case TFORWINTER: s = pkglookup(d->name, d->package);
n = s->def->type; dcopy(s, d);
if(s->block != block) { if(dflag())
// completing forward struct from other file print("\t%L pop %S\n", lineno, s);
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(d == S)
fatal("popdcl: no mark");
dclstack = d->link;
block = d->block;
}
// otherwise declare a new type void
addtyp(n, dclcontext); poptodcl(void)
{
Sym *d, *s;
found: for(d=dclstack; d!=S; d=d->link) {
n->local = 1; if(d->name == nil)
autoexport(n->sym); break;
return n; 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 void
updatetype(Type *n, Type *t) markdcl(void)
{ {
Sym *s; Sym *d;
int local, vargen;
int maplineno, lno, etype;
if(t == T) d = push();
return; d->name = nil; // used as a mark in fifo
s = n->sym; d->block = block;
if(s == S || s->def == N || s->def->op != OTYPE || s->def->type != n)
fatal("updatetype %T = %T", n, t);
etype = n->etype; blockgen++;
switch(n->etype) { block = blockgen;
case TFORW:
break;
case TFORWSTRUCT: // if(dflag())
if(t->etype != TSTRUCT) { // print("markdcl\n");
yyerror("%T forward declared as struct", n); }
return;
}
n->local = 1;
break;
case TFORWINTER: void
if(t->etype != TINTER) { dumpdcl(char *st)
yyerror("%T forward declared as interface", n); {
return; Sym *s, *d;
} int i;
break;
default: i = 0;
fatal("updatetype %T / %T", n, t); 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 void
// type n t; testdclstack(void)
// copy t, but then zero out state associated with t {
// that is no longer associated with n. Sym *d;
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);
}
// double-check use of type as map key for(d=dclstack; d!=S; d=d->link) {
if(maplineno) { if(d->name == nil) {
lno = lineno; yyerror("mark left on the stack");
lineno = maplineno; continue;
maptype(n, types[TBOOL]); }
lineno = lno;
} }
} }
/* /*
* return nelem of list * declare individual names - var, typ, const
*/ */
int static void
structcount(Type *t) redeclare(char *str, Sym *s)
{ {
int v; if(s->block == block) {
Iter s; yyerror("%s %S redeclared in this block", str, s);
print(" previous declaration at %L\n", s->lastlineno);
v = 0; }
for(t = structfirst(&s, &t); t != T; t = structnext(&s)) s->block = block;
v++; s->lastlineno = lineno;
return v;
} }
/* void
* turn a parsed function declaration addvar(Node *n, Type *t, int ctxt)
* into a type
*/
Type*
functype(Node *this, NodeList *in, NodeList *out)
{ {
Type *t; Dcl *r, *d;
NodeList *rcvr; Sym *s;
int gen;
t = typ(TFUNC);
rcvr = nil; if(n==N || n->sym == S || (n->op != ONAME && n->op != ONONAME) || t == T)
if(this) fatal("addvar: n=%N t=%T nil", n, t);
rcvr = list1(this);
t->type = dostruct(rcvr, TFUNC);
t->type->down = dostruct(out, TFUNC);
t->type->down->down = dostruct(in, TFUNC);
if(this) s = n->sym;
t->thistuple = 1;
t->outtuple = count(out);
t->intuple = count(in);
checkwidth(t); if(ctxt == PEXTERN || ctxt == PFUNC) {
return t; r = externdcl;
} gen = 0;
} else {
r = autodcl;
vargen++;
gen = vargen;
pushdcl(s);
}
int redeclare("variable", s);
methcmp(Type *t1, Type *t2) n->op = ONAME;
{ s->vargen = gen;
if(t1->etype != TFUNC) s->def = n;
return 0; s->offset = 0;
if(t2->etype != TFUNC)
return 0;
t1 = t1->type->down; // skip this arg n->funcdepth = funcdepth;
t2 = t2->type->down; // skip this arg n->type = t;
for(;;) { n->vargen = gen;
if(t1 == t2) n->class = ctxt;
break;
if(t1 == T || t2 == T)
return 0;
if(t1->etype != TSTRUCT || t2->etype != TSTRUCT)
return 0;
if(!eqtype(t1->type, t2->type)) d = dcl();
return 0; d->dsym = s;
d->dnode = n;
d->op = ONAME;
t1 = t1->down; r->back->forw = d;
t2 = t2->down; 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* void
methodsym(Sym *nsym, Type *t0) addtyp(Type *n, int ctxt)
{ {
Dcl *r, *d;
Sym *s; Sym *s;
char buf[NSYMB]; static int typgen;
Type *t;
t = t0; if(n==T || n->sym == S)
if(t == T) fatal("addtyp: n=%T t=%T nil", n);
goto bad;
s = t->sym; s = n->sym;
if(s == S) {
if(!isptr[t->etype]) if(ctxt == PEXTERN)
goto bad; r = externdcl;
t = t->type; else {
if(t == T) r = autodcl;
goto bad; pushdcl(s);
s = t->sym; n->vargen = ++typgen;
if(s == S)
goto bad;
} }
// if t0 == *t and t0 has a sym, redeclare("type", s);
// we want to see *t, not t0, in the method name. s->def = typenod(n);
if(t != t0 && t0->sym)
t0 = ptrto(t);
snprint(buf, sizeof(buf), "%#hT·%s", t0, nsym->name); d = dcl();
//print("methodname %s\n", buf); d->dsym = s;
return pkglookup(buf, s->package); d->dtype = n;
d->op = OTYPE;
bad: d->back = r->back;
yyerror("illegal <this> type: %T", t); r->back->forw = d;
return S; r->back = d;
}
Node* d = dcl();
methodname(Node *n, Type *t) d->dtype = n;
{ d->op = OTYPE;
Sym *s;
s = methodsym(n->sym, t); r = typelist;
if(s == S) d->back = r->back;
return n; r->back->forw = d;
return newname(s); 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);
}
} }
/* // TODO(rsc): cut
* add a method, declared as a function,
* n is fieldname, pa is base type, t is function type
*/
void void
addmethod(Node *n, Type *t, int local) addconst(Node *n, Node *e, int ctxt)
{ {
Type *f, *d, *pa; Sym *s;
Sym *sf; Dcl *r, *d;
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);
n = nod(ODCLFIELD, newname(sf), N); if(n->op != ONAME && n->op != ONONAME)
n->type = t; fatal("addconst: not a name");
d = T; // last found if(e->op != OLITERAL) {
for(f=pa->method; f!=T; f=f->down) { yyerror("expression must be a constant");
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; return;
} }
if(local && !pa->local) { s = n->sym;
// defining method on non-local type.
// method must have been forward declared if(ctxt == PEXTERN)
// elsewhere, i.e. where the type was. r = externdcl;
yyerror("cannot define new methods on non-local type %T", pa); else {
return; r = autodcl;
pushdcl(s);
} }
if(d == T) redeclare("constant", s);
stotype(list1(n), 0, &pa->method); s->def = e;
else e->sym = s;
stotype(list1(n), 0, &d->down);
if(dflag()) d = dcl();
print("method %S of type %T\n", sf, pa); d->dsym = s;
return; d->dnode = e;
d->op = OLITERAL;
d->back = r->back;
r->back->forw = d;
r->back = d;
bad: if(dflag())
yyerror("invalid receiver type %T", pa); print("const-dcl %S %N\n", n->sym, n->sym->def);
} }
/* /*
* a function named init is a special case. * declare (possible list) n of type t.
* it is called by the initialization before * append ODCL nodes to *init
* main is run. to make it unique within a
* package and also uncallable, the name,
* normally "pkg.init", is altered to "pkg.init·filename".
*/ */
Node* void
renameinit(Node *n) dodclvar(Node *n, Type *t, NodeList **init)
{ {
Sym *s; if(n == N)
return;
s = n->sym; if(t != T && (t->etype == TIDEAL || t->etype == TNIL))
if(s == S) fatal("dodclvar %T", t);
return n; dowidth(t);
if(strcmp(s->name, "init") != 0)
return n;
snprint(namebuf, sizeof(namebuf), "init·%s", filename); // in case of type checking error,
s = lookup(namebuf); // use "undefined" type for variable type,
return newname(s); // 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));
} }
/* // TODO(rsc): cut
* declare the function proper.
* and declare the arguments
* called in extern-declaration context
* returns in auto-declaration context.
*/
void void
funchdr(Node *n) dodclconst(Node *n, Node *e)
{ {
Node *on; if(n == N)
Sym *s; return;
addconst(n, e, dclcontext);
autoexport(n->sym);
}
s = n->nname->sym; /*
on = s->def; * introduce a type named n
if(on != N && (on->op != ONAME || on->builtin)) * but it is an unknown type for now
on = N; */
Type*
dodcltype(Type *n)
{
Sym *s;
// check for same types // if n has been forward declared,
if(on != N) { // use the Type* created then
if(eqtype(n->type, on->type)) { s = n->sym;
if(!eqargs(n->type, on->type)) { if((funcdepth == 0 || s->block == block) && s->def != N && s->def->op == OTYPE) {
yyerror("function arg names changed: %S", s); switch(s->def->type->etype) {
print("\t%T\n\t%T\n", on->type, n->type); 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 { goto found;
yyerror("function redeclared: %S", s);
print("\t%T\n\t%T\n", on->type, n->type);
on = N;
} }
} }
// check for forward declaration // otherwise declare a new type
if(on == N) { addtyp(n, dclcontext);
// 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");
dclcontext = PAUTO; found:
markdcl(); n->local = 1;
funcargs(n->type); autoexport(n->sym);
return n;
} }
/*
* now we know what n is: it's t
*/
void void
funcargs(Type *ft) updatetype(Type *n, Type *t)
{ {
Type *t; Sym *s;
Iter save; int local, vargen;
int all; 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 etype = n->etype;
t = funcfirst(&save, ft); switch(n->etype) {
while(t != T) { case TFORW:
if(t->nname != N) { break;
t->nname->xoffset = t->width;
addvar(t->nname, t->type, PPARAM); 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 case TFORWINTER:
all = 0; if(t->etype != TINTER) {
t = structfirst(&save, getoutarg(ft)); yyerror("%T forward declared as interface", n);
while(t != T) { return;
if(t->nname != N) }
t->nname->xoffset = t->width; break;
if(t->nname != N) {
addvar(t->nname, t->type, PPARAMOUT); default:
all |= 1; fatal("updatetype %T / %T", n, t);
} else
all |= 2;
t = structnext(&save);
} }
// this test is remarkedly similar to checkarglist // decl was
if(all == 3) // type n t;
yyerror("cannot mix anonymous and named output arguments"); // 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; // catch declaration of incomplete type
if(all == 1) switch(n->etype) {
ft->outnamed = 1; 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. * declare variables from grammar
* called in auto-declaration context. * new_name_list (type | [type] = expr_list)
* returns in extern-declaration context.
*/ */
void NodeList*
funcbody(Node *n) variter(NodeList *vl, Node *t, NodeList *el)
{ {
int doexpr, gen;
Node *v, *e;
NodeList *init;
Sym *s;
Dcl *r, *d;
compile(n); init = nil;
doexpr = el != nil;
// change the declaration context from auto to extern for(; vl; vl=vl->next) {
if(dclcontext != PAUTO) if(doexpr) {
fatal("funcbody: dclcontext"); if(el == nil) {
popdcl(); yyerror("missing expr in var dcl");
funcdepth--; break;
if(funcdepth == 0) }
dclcontext = PEXTERN; e = el->n;
} el = el->next;
} else
e = N;
Node* v = vl->n;
funclit0(Node *t) s = v->sym;
{ if(dclcontext == PEXTERN || dclcontext == PFUNC) {
Node *n; 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); v->op = ONAME;
n->outer = funclit; v->class = dclcontext;
n->dcl = autodcl; v->ntype = t;
funclit = n; 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 autoexport(s);
autodcl = dcl(); }
autodcl->back = autodcl; if(el != nil)
yyerror("extra expr in var dcl");
typecheck(&t, Etype); return init;
funcargs(t->type);
return t;
} }
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; Node *v, *c;
Type *type; NodeList *vv;
Node *a, *d, *f, *n, *clos; Sym *s;
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;
// unlink from actual ONAME in symbol table vv = vl;
a->closure->closure = a->outer; 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 for(; vl; vl=vl->next) {
d = nod(ODCLFIELD, N, N); if(cl == nil) {
d->type = types[TUINTPTR]; yyerror("missing expr in const dcl");
in = list(in, d); break;
// 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;
} }
} c = cl->n;
cl = cl->next;
// out arguments v = vl->n;
out = nil; s = v->sym;
for(t=structfirst(&save, getoutarg(type)); t; t=structnext(&save)) { if(dclcontext != PEXTERN)
d = nod(ODCLFIELD, t->nname, N); pushdcl(s);
d->type = t->type; redeclare("constant", s);
out = list(out, d); s->def = v;
a = t->nname; v->op = OLITERAL;
if(a != N) { v->ntype = t;
if(a->stackparam != N) v->defn = c;
a = a->stackparam; autoexport(s);
a->xoffset += shift;
}
} }
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. n = nod(ONAME, N, N);
vargen++; n->sym = s;
snprint(namebuf, sizeof(namebuf), "_f%.3ld·%s", vargen, filename); n->type = T;
f = newname(lookup(namebuf)); n->addable = 1;
addvar(f, ft, PFUNC); n->ullman = 1;
f->funcdepth = 0; n->xoffset = 0;
return n;
}
// compile function Node*
n = nod(ODCLFUNC, N, N); dclname(Sym *s)
n->nname = f; {
n->type = ft; Node *n;
if(body == nil)
body = list1(nod(OEMPTY, N, N));
n->nbody = body;
compile(n);
funcdepth--;
autodcl = func->dcl;
// build up type for this instance of the closure func. // top-level name: might already have been
in = nil; // referred to, in which case s->def is already
d = nod(ODCLFIELD, N, N); // siz // set to an ONONAME.
d->type = types[TINT]; if(dclcontext == PEXTERN && s->block == 0) {
in = list(in, d); // toss predefined name like "close"
d = nod(ODCLFIELD, N, N); // f // TODO(rsc): put close in at the end.
d->type = ft; if(s->def != N && s->def->etype)
in = list(in, d); s->def = N;
for(l=func->cvars; l; l=l->next) { if(s->def == N)
a = l->n; oldname(s);
d = nod(ODCLFIELD, N, N); // arg return s->def;
d->type = ptrto(a->type);
in = list(in, d);
} }
d = nod(ODCLFIELD, N, N); n = newname(s);
d->type = type; n->op = ONONAME; // caller will correct it
out = list1(d); return n;
}
clos = syslook("closure", 1);
clos->type = functype(N, in, out);
// literal expression is sys.closure(siz, f, arg0, arg1, ...) Node*
// which builds a function that calls f after filling in arg0, typenod(Type *t)
// arg1, ... for the PHEAP arguments above. {
args = nil; if(t->nod == N) {
if(narg*widthptr > 100) t->nod = nod(OTYPE, N, N);
yyerror("closure needs too many variables; runtime will reject it"); t->nod->type = t;
a = nodintconst(narg*widthptr); t->nod->sym = t->sym;
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); return t->nod;
n = nod(OCALL, clos, N);
n->list = args;
return n;
} }
/* /*
* 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** Node*
stotype(NodeList *l, int et, Type **t) oldname(Sym *s)
{ {
Type *f, *t1;
Strlit *note;
int lno;
NodeList *init;
Node *n; Node *n;
Node *c;
init = nil; n = s->def;
lno = lineno; if(n == N) {
for(; l; l=l->next) { // maybe a top-level name will come along
n = l->n; // to give this a definition later.
lineno = n->lineno; n = newname(s);
note = nil; n->op = ONONAME;
s->def = n;
if(n->op != ODCLFIELD) }
fatal("stotype: oops %N\n", n); if(n->funcdepth > 0 && n->funcdepth != funcdepth && n->op == ONAME) {
if(n->right != N) { // inner func is referring to var
typecheck(&n->right, Etype); // in outer func.
n->type = n->right->type; if(n->closure == N || n->closure->funcdepth != funcdepth) {
n->right = N; typecheck(&n, Erv);
if(n->embedded && n->type != T) { // create new closure var.
t1 = n->type; c = nod(ONAME, N, N);
if(t1->sym == S && isptr[t1->etype]) 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; t1 = t1->type;
if(t1 != T && isptr[t1->etype]) if(t1 != T && isptr[t1->etype])
yyerror("embedded type cannot be a pointer"); yyerror("embedded type cannot be a pointer");
...@@ -803,289 +853,118 @@ dostruct(NodeList *l, int et) ...@@ -803,289 +853,118 @@ dostruct(NodeList *l, int et)
return t; return t;
} }
Type*
sortinter(Type *t)
{
return t;
}
void Node*
dcopy(Sym *a, Sym *b) embedded(Sym *s)
{ {
a->name = b->name; Node *n;
a->def = b->def; char *name;
a->package = b->package;
a->undef = b->undef;
a->vargen = b->vargen;
a->block = b->block;
a->lastlineno = b->lastlineno;
a->offset = b->offset;
}
Sym* // Names sometimes have disambiguation junk
push(void) // appended after a center dot. Discard it when
{ // making the name for the embedded struct field.
Sym *d; enum { CenterDot = 0xB7 };
name = s->name;
if(utfrune(s->name, CenterDot)) {
name = strdup(s->name);
*utfrune(name, CenterDot) = 0;
}
d = mal(sizeof(*d)); n = newname(lookup(name));
d->link = dclstack; n = nod(ODCLFIELD, n, N);
dclstack = d; n->embedded = 1;
return d; if(s == S)
return n;
n->right = oldname(s);
return n;
} }
Sym* static Node*
pushdcl(Sym *s) findtype(NodeList *l)
{ {
Sym *d; for(; l; l=l->next)
if(l->n->op == OKEY)
d = push(); return l->n->right;
dcopy(d, s); return N;
return d;
} }
void static Node*
popdcl(void) xanondcl(Node *nt)
{ {
Sym *d, *s; Node *n;
Type *t;
// if(dflag())
// print("revert\n");
for(d=dclstack; d!=S; d=d->link) { typecheck(&nt, Etype);
if(d->name == nil) t = nt->type;
break; if(nt->op != OTYPE) {
s = pkglookup(d->name, d->package); yyerror("%S is not a type", nt->sym);
dcopy(s, d); t = types[TINT32];
if(dflag())
print("\t%L pop %S\n", lineno, s);
} }
if(d == S) n = nod(ODCLFIELD, N, N);
fatal("popdcl: no mark"); n->type = t;
dclstack = d->link; return n;
block = d->block;
} }
void static Node*
poptodcl(void) namedcl(Node *nn, Node *nt)
{ {
Sym *d, *s; Node *n;
Type *t;
for(d=dclstack; d!=S; d=d->link) { if(nn->op == OKEY)
if(d->name == nil) nn = nn->left;
break; if(nn->sym == S) {
s = pkglookup(d->name, d->package); typecheck(&nn, Etype);
dcopy(s, d); yyerror("cannot mix anonymous %T with named arguments", nn->type);
if(dflag()) return xanondcl(nn);
print("\t%L pop %S\n", lineno, s);
} }
if(d == S) t = types[TINT32];
fatal("poptodcl: no mark"); if(nt == N)
dclstack = d; 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; int named;
Node *r;
d = push(); NodeList *l;
d->name = nil; // used as a mark in fifo
d->block = block;
blockgen++;
block = blockgen;
// if(dflag()) named = 0;
// print("markdcl\n"); for(l=all; l; l=l->next) {
} if(l->n->op == OKEY) {
named = 1;
void break;
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;
} }
} }
}
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()) { for(l=all; l; l=l->next) {
if(ctxt == PEXTERN) if(named)
print("extern typ-dcl %S G%ld %T\n", s, s->vargen, n); l->n = namedcl(l->n, findtype(l));
else 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* Node*
fakethis(void) fakethis(void)
...@@ -1122,730 +1001,469 @@ isifacemethod(Type *f) ...@@ -1122,730 +1001,469 @@ isifacemethod(Type *f)
} }
/* /*
* this generates a new name that is * turn a parsed function declaration
* pushed down on the declaration list. * into a type
* no diagnostics are produced as this
* name will soon be declared.
*/ */
Node* Type*
newname(Sym *s) functype(Node *this, NodeList *in, NodeList *out)
{ {
Node *n; Type *t;
NodeList *rcvr;
n = nod(ONAME, N, N); t = typ(TFUNC);
n->sym = s;
n->type = T;
n->addable = 1;
n->ullman = 1;
n->xoffset = 0;
return n;
}
Node* rcvr = nil;
dclname(Sym *s) if(this)
{ rcvr = list1(this);
Node *n; 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 if(this)
// referred to, in which case s->def is already t->thistuple = 1;
// set to an ONONAME. t->outtuple = count(out);
if(dclcontext == PEXTERN && s->block == 0) { t->intuple = count(in);
// 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;
}
n = newname(s); checkwidth(t);
n->op = ONONAME; // caller will correct it return t;
return n;
} }
Node* int
typenod(Type *t) methcmp(Type *t1, Type *t2)
{ {
if(t->nod == N) { if(t1->etype != TFUNC)
t->nod = nod(OTYPE, N, N); return 0;
t->nod->type = t; if(t2->etype != TFUNC)
t->nod->sym = t->sym; return 0;
}
return t->nod;
}
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;
/* if(!eqtype(t1->type, t2->type))
* this will return an old name return 0;
* 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;
n = s->def; t1 = t1->down;
if(n == N) { t2 = t2->down;
// 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; return 1;
} }
/* Sym*
* same for types methodsym(Sym *nsym, Type *t0)
*/
Type*
newtype(Sym *s)
{ {
Sym *s;
char buf[NSYMB];
Type *t; Type *t;
t = typ(TFORW); t = t0;
t->sym = s; if(t == T)
t->type = T; goto bad;
return t; 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* // if t0 == *t and t0 has a sym,
oldtype(Sym *s) // we want to see *t, not t0, in the method name.
{ if(t != t0 && t0->sym)
Type *t; t0 = ptrto(t);
if(s == S) snprint(buf, sizeof(buf), "%#hT·%s", t0, nsym->name);
return T; //print("methodname %s\n", buf);
if(s->def == N || s->def->op != OTYPE) { return pkglookup(buf, s->package);
if(!s->undef)
yyerror("%S is not a type", s);
return T;
}
t = s->def->type;
/* bad:
* If t is lowercase and not in our package yyerror("illegal <this> type: %T", t);
* and this isn't a reference during the parsing return S;
* of import data, complain.
*/
if(pkgimportname == S && !exportname(s->name) && strcmp(s->package, package) != 0)
yyerror("cannot use type %T", t);
return t;
} }
/*
* n is a node with a name.
* make it a declaration of the given type.
*/
Node* Node*
nametodcl(Node *n, Type *t) methodname(Node *n, Type *t)
{ {
n = nod(ODCLFIELD, n, N); Sym *s;
n->type = t;
return n; 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* void
anondcl(Type *t) addmethod(Node *n, Type *t, int local)
{ {
Node *n; Type *f, *d, *pa;
Sym *sf;
n = nod(ODCLFIELD, N, N); pa = nil;
n->type = t; sf = nil;
return n;
}
static Node* // get field sym
findtype(NodeList *l) if(n == N)
{ goto bad;
for(; l; l=l->next) if(n->op != ONAME)
if(l->n->op == OKEY) goto bad;
return l->n->right; sf = n->sym;
return N; if(sf == S)
} goto bad;
static Node* // get parent type sym
xanondcl(Node *nt) pa = *getthis(t); // ptr to this structure
{ if(pa == T)
Node *n; goto bad;
Type *t; 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); f = methtype(pa);
t = nt->type; if(f == T)
if(nt->op != OTYPE) { goto bad;
yyerror("%S is not a type", nt->sym);
t = types[TINT32];
}
n = nod(ODCLFIELD, N, N);
n->type = t;
return n;
}
static Node* pa = f;
namedcl(Node *nn, Node *nt) if(pkgimportname != S && !exportname(sf->name))
{ sf = pkglookup(sf->name, pkgimportname->name);
Node *n;
Type *t;
if(nn->op == OKEY) n = nod(ODCLFIELD, newname(sf), N);
nn = nn->left; n->type = t;
if(nn->sym == S) {
typecheck(&nn, Etype); d = T; // last found
yyerror("cannot mix anonymous %T with named arguments", nn->type); for(f=pa->method; f!=T; f=f->down) {
return xanondcl(nn); 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) if(local && !pa->local) {
yyerror("missing type for argument %S", nn->sym); // defining method on non-local type.
else { // method must have been forward declared
typecheck(&nt, Etype); // elsewhere, i.e. where the type was.
if(nt->op != OTYPE) yyerror("cannot define new methods on non-local type %T", pa);
yyerror("%S is not a type", nt->sym); return;
else
t = nt->type;
} }
n = nod(ODCLFIELD, newname(nn->sym), N);
n->type = t; if(d == T)
return n; 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* void
checkarglist(NodeList *all) funchdr(Node *n)
{ {
int named; Node *on;
Node *r; Sym *s;
NodeList *l;
named = 0; s = n->nname->sym;
for(l=all; l; l=l->next) { on = s->def;
if(l->n->op == OKEY) { if(on != N && (on->op != ONAME || on->builtin))
named = 1; on = N;
break;
// 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) { // check for forward declaration
if(named) if(on == N) {
l->n = namedcl(l->n, findtype(l)); // 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 else
l->n = xanondcl(l->n); n->nname->class = PFUNC;
if(l->next != nil) { } else {
r = l->n; // identical redeclaration
if(r != N && r->type != T && r->type->etype == TDDD) // steal previous names
yyerror("only last argument can have type ..."); n->nname = on;
} n->type = on->type;
n->class = on->class;
n->sym = s;
} }
return all;
}
/* // change the declaration context from extern to auto
* hand-craft the following initialization code autodcl = dcl();
* var initdone·<file> uint8 (1) autodcl->back = autodcl;
* 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;
// are there any imported init functions if(funcdepth == 0 && dclcontext != PEXTERN)
for(h=0; h<NHASH; h++) fatal("funchdr: dclcontext");
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;
}
// then none dclcontext = PAUTO;
return 0; markdcl();
funcargs(n->type);
} }
void void
fninit(NodeList *n) funcargs(Type *ft)
{ {
Node *gatevar; Type *t;
Node *a, *b, *fn; Iter save;
NodeList *r; int all;
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);
// (7) funcdepth++;
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;
// could check that it is fn of no args/returns // declare the this/in arguments
a = nod(OCALL, s->def, N); t = funcfirst(&save, ft);
r = list(r, a); while(t != T) {
if(t->nname != N) {
t->nname->xoffset = t->width;
addvar(t->nname, t->type, PPARAM);
}
t = funcnext(&save);
} }
// (8) // declare the outgoing arguments
r = concat(r, initfix(n)); all = 0;
t = structfirst(&save, getoutarg(ft));
// (9) while(t != T) {
// could check that it is fn of no args/returns if(t->nname != N)
snprint(namebuf, sizeof(namebuf), "init·%s", filename); t->nname->xoffset = t->width;
s = lookup(namebuf); if(t->nname != N) {
if(s->def != N) { addvar(t->nname, t->type, PPARAMOUT);
a = nod(OCALL, s->def, N); all |= 1;
r = list(r, a); } else
all |= 2;
t = structnext(&save);
} }
// (10) // this test is remarkedly similar to checkarglist
a = nod(OASOP, gatevar, nodintconst(1)); if(all == 3)
a->etype = OADD; yyerror("cannot mix anonymous and named output arguments");
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);
popdcl(); ft->outnamed = 0;
initflag = 1; // flag for loader static initialization if(all == 1)
compile(fn); ft->outnamed = 1;
initflag = 0;
} }
/* /*
* when a type's width should be known, we call checkwidth * compile the function.
* to compute it. during a declaration like * called in auto-declaration context.
* * returns in extern-declaration context.
* 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
*/ */
typedef struct TypeList TypeList;
struct TypeList {
Type *t;
TypeList *next;
};
static TypeList *tlfree;
static TypeList *tlq;
static int defercalc;
void 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; compile(n);
if(l != nil)
tlfree = l->next;
else
l = mal(sizeof *l);
l->t = t; // change the declaration context from auto to extern
l->next = tlq; if(dclcontext != PAUTO)
tlq = l; fatal("funcbody: dclcontext");
popdcl();
funcdepth--;
if(funcdepth == 0)
dclcontext = PEXTERN;
} }
void Node*
defercheckwidth(void) funclit0(Node *t)
{ {
// we get out of sync on syntax errors, so don't be pedantic. Node *n;
// if(defercalc)
// fatal("defercheckwidth");
defercalc = 1;
}
void n = nod(OXXX, N, N);
resumecheckwidth(void) n->outer = funclit;
{ n->dcl = autodcl;
TypeList *l; funclit = n;
if(!defercalc) // new declaration context
fatal("restartcheckwidth"); autodcl = dcl();
defercalc = 0; autodcl->back = autodcl;
for(l = tlq; l != nil; l = tlq) { typecheck(&t, Etype);
dowidth(l->t); funcargs(t->type);
tlq = l->next; return t;
l->next = tlfree;
tlfree = l;
}
} }
Node* Node*
embedded(Sym *s) funclit1(Node *ntype, NodeList *body)
{ {
Node *n; Node *func;
char *name; 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 type = ntype->type;
// appended after a center dot. Discard it when popdcl();
// making the name for the embedded struct field. func = funclit;
enum { CenterDot = 0xB7 }; funclit = func->outer;
name = s->name;
if(utfrune(s->name, CenterDot)) {
name = strdup(s->name);
*utfrune(name, CenterDot) = 0;
}
n = newname(lookup(name)); // build up type of func f that we're going to compile.
n = nod(ODCLFIELD, n, N); // as we referred to variables from the outer function,
n->embedded = 1; // we accumulated a list of PHEAP names in func->cvars.
if(s == S) narg = 0;
return n; // add PHEAP versions as function arguments.
n->right = oldname(s); in = nil;
return n; 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
* declare variables from grammar n = nod(ONAME, N, N);
* new_name_list (type | [type] = expr_list) snprint(namebuf, sizeof namebuf, "&%s", a->sym->name);
*/ n->sym = lookup(namebuf);
NodeList* n->type = ptrto(a->type);
variter(NodeList *vl, Node *t, NodeList *el) n->class = PPARAM;
{ n->xoffset = narg*types[tptr]->width;
int doexpr, gen; n->addable = 1;
Node *v, *e; n->ullman = 1;
NodeList *init; narg++;
Sym *s; a->heapaddr = n;
Dcl *r, *d;
init = nil; a->xoffset = 0;
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;
v = vl->n; // unlink from actual ONAME in symbol table
s = v->sym; a->closure->closure = a->outer;
if(dclcontext == PEXTERN || dclcontext == PFUNC) { }
r = externdcl;
gen = 0;
} else {
r = autodcl;
gen = ++vargen;
pushdcl(s);
}
redeclare("variable", s); // add a dummy arg for the closure's caller pc
s->def = v; d = nod(ODCLFIELD, N, N);
// TODO: vargen d->type = types[TUINTPTR];
s->offset = 0; in = list(in, d);
s->block = block;
v->op = ONAME; // slide param offset to make room for ptrs above.
v->class = dclcontext; // narg+1 to skip over caller pc.
v->ntype = t; shift = (narg+1)*types[tptr]->width;
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(); // now the original arguments.
d->dsym = s; for(t=structfirst(&save, getinarg(type)); t; t=structnext(&save)) {
d->dnode = v; d = nod(ODCLFIELD, t->nname, N);
d->op = ONAME; d->type = t->type;
r->back->forw = d; in = list(in, d);
r->back = 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;
}
/* // out arguments
* declare constants from grammar out = nil;
* new_name_list [[type] = expr_list] for(t=structfirst(&save, getoutarg(type)); t; t=structnext(&save)) {
*/ d = nod(ODCLFIELD, t->nname, N);
NodeList* d->type = t->type;
constiter(NodeList *vl, Node *t, NodeList *cl) out = list(out, d);
{
Node *v, *c;
NodeList *vv;
Sym *s;
vv = vl; a = t->nname;
if(cl == nil) { if(a != N) {
if(t != N) if(a->stackparam != N)
yyerror("constdcl cannot have type without expr"); a = a->stackparam;
cl = lastconst; a->xoffset += shift;
t = lasttype; }
} else {
lastconst = cl;
lasttype = t;
} }
cl = listtreecopy(cl);
for(; vl; vl=vl->next) { ft = functype(N, in, out);
if(cl == nil) { ft->outnamed = type->outnamed;
yyerror("missing expr in const dcl");
break;
}
c = cl->n;
cl = cl->next;
v = vl->n; // declare function.
s = v->sym; vargen++;
if(dclcontext != PEXTERN) snprint(namebuf, sizeof(namebuf), "_f%.3ld·%s", vargen, filename);
pushdcl(s); f = newname(lookup(namebuf));
redeclare("constant", s); addvar(f, ft, PFUNC);
s->def = v; f->funcdepth = 0;
v->op = OLITERAL; // compile function
v->ntype = t; n = nod(ODCLFUNC, N, N);
v->defn = c; n->nname = f;
autoexport(s); n->type = ft;
} if(body == nil)
if(cl != nil) body = list1(nod(OEMPTY, N, N));
yyerror("extra expr in const dcl"); n->nbody = body;
iota += 1; compile(n);
return vv; funcdepth--;
} autodcl = func->dcl;
/* // build up type for this instance of the closure func.
* look for in = nil;
* unsafe.Sizeof d = nod(ODCLFIELD, N, N); // siz
* unsafe.Offsetof d->type = types[TINT];
* rewrite with a constant in = list(in, d);
*/ d = nod(ODCLFIELD, N, N); // f
Node* d->type = ft;
unsafenmagic(Node *fn, NodeList *args) in = list(in, d);
{ for(l=func->cvars; l; l=l->next) {
Node *r, *n; a = l->n;
Sym *s; d = nod(ODCLFIELD, N, N); // arg
Type *t, *tr; d->type = ptrto(a->type);
long v; in = list(in, d);
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;
} }
no: d = nod(ODCLFIELD, N, N);
return N; d->type = type;
out = list1(d);
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;
}
void clos = syslook("closure", 1);
dclchecks(void) clos->type = functype(N, in, out);
{
Dcl *d;
for(d=externdcl; d!=D; d=d->forw) { // literal expression is sys.closure(siz, f, arg0, arg1, ...)
if(d->op != ONAME) // which builds a function that calls f after filling in arg0,
continue; // arg1, ... for the PHEAP arguments above.
typecheck(&d->dnode, Erv); 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;
} }
...@@ -601,8 +601,6 @@ EXTERN char namebuf[NSYMB]; ...@@ -601,8 +601,6 @@ EXTERN char namebuf[NSYMB];
EXTERN char lexbuf[NSYMB]; EXTERN char lexbuf[NSYMB];
EXTERN char debug[256]; EXTERN char debug[256];
EXTERN Sym* hash[NHASH]; EXTERN Sym* hash[NHASH];
EXTERN Sym* dclstack;
EXTERN Sym* b0stack;
EXTERN Sym* pkgmyname; // my name for package EXTERN Sym* pkgmyname; // my name for package
EXTERN Sym* pkgimportname; // package name from imported package EXTERN Sym* pkgimportname; // package name from imported package
EXTERN int tptr; // either TPTR32 or TPTR64 EXTERN int tptr; // either TPTR32 or TPTR64
...@@ -814,7 +812,6 @@ void argtype(Node*, Type*); ...@@ -814,7 +812,6 @@ void argtype(Node*, Type*);
int eqargs(Type*, Type*); int eqargs(Type*, Type*);
uint32 typehash(Type*, int, int); uint32 typehash(Type*, int, int);
void frame(int); void frame(int);
Node* dobad(void);
Node* nodintconst(int64); Node* nodintconst(int64);
void nodconst(Node*, Type*, int64); void nodconst(Node*, Type*, int64);
Node* nodnil(void); Node* nodnil(void);
...@@ -921,7 +918,6 @@ Type* newtype(Sym*); ...@@ -921,7 +918,6 @@ Type* newtype(Sym*);
Type* oldtype(Sym*); Type* oldtype(Sym*);
void fninit(NodeList*); void fninit(NodeList*);
Node* nametodcl(Node*, Type*); Node* nametodcl(Node*, Type*);
Node* anondcl(Type*);
NodeList* checkarglist(NodeList*); NodeList* checkarglist(NodeList*);
void checkwidth(Type*); void checkwidth(Type*);
void defercheckwidth(void); void defercheckwidth(void);
......
...@@ -1137,7 +1137,6 @@ fndcl: ...@@ -1137,7 +1137,6 @@ fndcl:
{ {
Node *n; Node *n;
b0stack = dclstack; // mark base for fn literals
$$ = nod(ODCLFUNC, N, N); $$ = nod(ODCLFUNC, N, N);
$$->nname = $1; $$->nname = $1;
if($3 == nil && $5 == nil) if($3 == nil && $5 == nil)
...@@ -1159,7 +1158,6 @@ fndcl: ...@@ -1159,7 +1158,6 @@ fndcl:
rcvr = N; rcvr = N;
} }
b0stack = dclstack; // mark base for fn literals
$$ = nod(ODCLFUNC, N, N); $$ = nod(ODCLFUNC, N, N);
$$->nname = $4; $$->nname = $4;
$$->nname = methodname($4, rcvr->type); $$->nname = methodname($4, rcvr->type);
......
// 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"
/*
* 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".
*/
Node*
renameinit(Node *n)
{
Sym *s;
s = n->sym;
if(s == S)
return n;
if(strcmp(s->name, "init") != 0)
return n;
snprint(namebuf, sizeof(namebuf), "init·%s", filename);
s = lookup(namebuf);
return newname(s);
}
/*
* 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;
// 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;
}
// then none
return 0;
}
void
fninit(NodeList *n)
{
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);
// (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;
// could check that it is fn of no args/returns
a = nod(OCALL, s->def, N);
r = list(r, a);
}
// (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);
}
// (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);
popdcl();
initflag = 1; // flag for loader static initialization
compile(fn);
initflag = 0;
}
...@@ -393,10 +393,11 @@ typ(int et) ...@@ -393,10 +393,11 @@ typ(int et)
return t; return t;
} }
Node*
dobad(void) Type*
sortinter(Type *t)
{ {
return nod(OBAD, N, N); return t;
} }
Node* Node*
...@@ -2636,23 +2637,25 @@ NodeList* ...@@ -2636,23 +2637,25 @@ NodeList*
structargs(Type **tl, int mustname) structargs(Type **tl, int mustname)
{ {
Iter savet; Iter savet;
Node *a; Node *a, *n;
NodeList *args; NodeList *args;
Type *t; Type *t;
char nam[100]; char buf[100];
int n; int gen;
args = nil; args = nil;
n = 0; gen = 0;
for(t = structfirst(&savet, tl); t != T; t = structnext(&savet)) { for(t = structfirst(&savet, tl); t != T; t = structnext(&savet)) {
n = N;
if(t->sym) if(t->sym)
a = nametodcl(newname(t->sym), t->type); n = newname(t->sym);
else if(mustname) { else if(mustname) {
// have to give it a name so we can refer to it in trampoline // have to give it a name so we can refer to it in trampoline
snprint(nam, sizeof nam, ".anon%d", n++); snprint(buf, sizeof buf, ".anon%d", gen++);
a = nametodcl(newname(lookup(nam)), t->type); n = newname(lookup(buf));
} else }
a = anondcl(t->type); a = nod(ODCLFIELD, n, N);
a->type = t->type;
args = list(args, a); args = list(args, a);
} }
return args; return args;
...@@ -2694,7 +2697,8 @@ genwrapper(Type *rcvr, Type *method, Sym *newnam) ...@@ -2694,7 +2697,8 @@ genwrapper(Type *rcvr, Type *method, Sym *newnam)
dclcontext = PEXTERN; dclcontext = PEXTERN;
markdcl(); markdcl();
this = nametodcl(newname(lookup(".this")), rcvr); this = nod(ODCLFIELD, newname(lookup(".this")), N);
this->type = rcvr;
in = structargs(getinarg(method->type), 1); in = structargs(getinarg(method->type), 1);
out = structargs(getoutarg(method->type), 0); out = structargs(getoutarg(method->type), 0);
...@@ -2982,6 +2986,9 @@ liststmt(NodeList *l) ...@@ -2982,6 +2986,9 @@ liststmt(NodeList *l)
return n; return n;
} }
/*
* return nelem of list
*/
int int
count(NodeList *l) count(NodeList *l)
{ {
...@@ -2992,3 +2999,96 @@ count(NodeList *l) ...@@ -2992,3 +2999,96 @@ count(NodeList *l)
n++; n++;
return n; return n;
} }
/*
* return nelem of list
*/
int
structcount(Type *t)
{
int v;
Iter s;
v = 0;
for(t = structfirst(&s, &t); t != T; t = structnext(&s))
v++;
return v;
}
/*
* 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
*/
typedef struct TypeList TypeList;
struct TypeList {
Type *t;
TypeList *next;
};
static TypeList *tlfree;
static TypeList *tlq;
static int defercalc;
void
checkwidth(Type *t)
{
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);
l->t = t;
l->next = tlq;
tlq = l;
}
void
defercheckwidth(void)
{
// we get out of sync on syntax errors, so don't be pedantic.
// if(defercalc)
// fatal("defercheckwidth");
defercalc = 1;
}
void
resumecheckwidth(void)
{
TypeList *l;
if(!defercalc)
fatal("restartcheckwidth");
defercalc = 0;
for(l = tlq; l != nil; l = tlq) {
dowidth(l->t);
tlq = l->next;
l->next = tlfree;
tlfree = l;
}
}
// 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"
/*
* 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;
}
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;
}
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment