diff options
Diffstat (limited to 'src/cmd/gc/export.c')
-rw-r--r-- | src/cmd/gc/export.c | 428 |
1 files changed, 428 insertions, 0 deletions
diff --git a/src/cmd/gc/export.c b/src/cmd/gc/export.c new file mode 100644 index 000000000..014f0c5f0 --- /dev/null +++ b/src/cmd/gc/export.c @@ -0,0 +1,428 @@ +// 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" + +static void dumpsym(Sym*); +static void dumpexporttype(Sym*); +static void dumpexportvar(Sym*); +static void dumpexportconst(Sym*); + +void +exportsym(Node *n) +{ + if(n == N || n->sym == S) + return; + if(n->sym->flags & (SymExport|SymPackage)) { + if(n->sym->flags & SymPackage) + yyerror("export/package mismatch: %S", n->sym); + return; + } + n->sym->flags |= SymExport; + + exportlist = list(exportlist, n); +} + +static void +packagesym(Node *n) +{ + if(n == N || n->sym == S) + return; + if(n->sym->flags & (SymExport|SymPackage)) { + if(n->sym->flags & SymExport) + yyerror("export/package mismatch: %S", n->sym); + return; + } + n->sym->flags |= SymPackage; + + exportlist = list(exportlist, n); +} + +int +exportname(char *s) +{ + Rune r; + + if((uchar)s[0] < Runeself) + return 'A' <= s[0] && s[0] <= 'Z'; + chartorune(&r, s); + return isupperrune(r); +} + +static int +initname(char *s) +{ + return strcmp(s, "init") == 0; +} + +void +autoexport(Node *n, int ctxt) +{ + if(n == N || n->sym == S) + return; + if((ctxt != PEXTERN && ctxt != PFUNC) || dclcontext != PEXTERN) + return; + if(n->ntype && n->ntype->op == OTFUNC && n->ntype->left) // method + return; + if(exportname(n->sym->name) || initname(n->sym->name)) + exportsym(n); + else + packagesym(n); +} + +static void +dumppkg(Pkg *p) +{ + char *suffix; + + if(p == nil || p == localpkg || p->exported) + return; + p->exported = 1; + suffix = ""; + if(!p->direct) + suffix = " // indirect"; + Bprint(bout, "\timport %s \"%Z\"%s\n", p->name, p->path, suffix); +} + +static void +dumpprereq(Type *t) +{ + if(t == T) + return; + + if(t->printed || t == types[t->etype]) + return; + t->printed = 1; + + if(t->sym != S) { + dumppkg(t->sym->pkg); + if(t->etype != TFIELD) + dumpsym(t->sym); + } + dumpprereq(t->type); + dumpprereq(t->down); +} + +static void +dumpexportconst(Sym *s) +{ + Node *n; + Type *t; + + n = s->def; + typecheck(&n, Erv); + if(n == N || n->op != OLITERAL) + fatal("dumpexportconst: oconst nil: %S", s); + + t = n->type; // may or may not be specified + if(t != T) + dumpprereq(t); + + Bprint(bout, "\t"); + Bprint(bout, "const %#S", s); + if(t != T && !isideal(t)) + Bprint(bout, " %#T", t); + Bprint(bout, " = "); + + switch(n->val.ctype) { + default: + fatal("dumpexportconst: unknown ctype: %S %d", s, n->val.ctype); + case CTINT: + Bprint(bout, "%B\n", n->val.u.xval); + break; + case CTBOOL: + if(n->val.u.bval) + Bprint(bout, "true\n"); + else + Bprint(bout, "false\n"); + break; + case CTFLT: + Bprint(bout, "%F\n", n->val.u.fval); + break; + case CTCPLX: + Bprint(bout, "(%F+%F)\n", &n->val.u.cval->real, &n->val.u.cval->imag); + break; + case CTSTR: + Bprint(bout, "\"%Z\"\n", n->val.u.sval); + break; + } +} + +static void +dumpexportvar(Sym *s) +{ + Node *n; + Type *t; + + n = s->def; + typecheck(&n, Erv); + if(n == N || n->type == T) { + yyerror("variable exported but not defined: %S", s); + return; + } + + t = n->type; + dumpprereq(t); + + Bprint(bout, "\t"); + if(t->etype == TFUNC && n->class == PFUNC) + Bprint(bout, "func %#S %#hhT", s, t); + else + Bprint(bout, "var %#S %#T", s, t); + Bprint(bout, "\n"); +} + +static void +dumpexporttype(Sym *s) +{ + Type *t; + + t = s->def->type; + dumpprereq(t); + Bprint(bout, "\t"); + switch (t->etype) { + case TFORW: + yyerror("export of incomplete type %T", t); + return; + } + if(Bprint(bout, "type %#T %l#T\n", t, t) < 0) + fatal("Bprint failed for %T", t); +} + +static int +methcmp(const void *va, const void *vb) +{ + Type *a, *b; + + a = *(Type**)va; + b = *(Type**)vb; + return strcmp(a->sym->name, b->sym->name); +} + +static void +dumpsym(Sym *s) +{ + Type *f, *t; + Type **m; + int i, n; + + if(s->flags & SymExported) + return; + s->flags |= SymExported; + + if(s->def == N) { + yyerror("unknown export symbol: %S", s); + return; + } + + dumppkg(s->pkg); + + switch(s->def->op) { + default: + yyerror("unexpected export symbol: %O %S", s->def->op, s); + break; + case OLITERAL: + dumpexportconst(s); + break; + case OTYPE: + t = s->def->type; + n = 0; + for(f=t->method; f!=T; f=f->down) { + dumpprereq(f); + n++; + } + m = mal(n*sizeof m[0]); + i = 0; + for(f=t->method; f!=T; f=f->down) + m[i++] = f; + qsort(m, n, sizeof m[0], methcmp); + + dumpexporttype(s); + for(i=0; i<n; i++) { + f = m[i]; + Bprint(bout, "\tfunc (%#T) %hS %#hhT\n", + f->type->type->type, f->sym, f->type); + } + break; + case ONAME: + dumpexportvar(s); + break; + } +} + +static void +dumptype(Type *t) +{ + // no need to re-dump type if already exported + if(t->printed) + return; + + // no need to dump type if it's not ours (was imported) + if(t->sym != S && t->sym->def == typenod(t) && !t->local) + return; + + Bprint(bout, "type %#T %l#T\n", t, t); +} + +void +dumpexport(void) +{ + NodeList *l; + int32 i, lno; + Pkg *p; + + lno = lineno; + + packagequotes = 1; + Bprint(bout, "\n$$ // exports\n"); + + Bprint(bout, " package %s", localpkg->name); + if(safemode) + Bprint(bout, " safe"); + Bprint(bout, "\n"); + + for(i=0; i<nelem(phash); i++) + for(p=phash[i]; p; p=p->link) + if(p->direct) + dumppkg(p); + + for(l=exportlist; l; l=l->next) { + lineno = l->n->lineno; + dumpsym(l->n->sym); + } + + Bprint(bout, "\n$$ // local types\n"); + + for(l=typelist; l; l=l->next) { + lineno = l->n->lineno; + dumptype(l->n->type); + } + + Bprint(bout, "\n$$\n"); + packagequotes = 0; + + lineno = lno; +} + +/* + * import + */ + +/* + * return the sym for ss, which should match lexical + */ +Sym* +importsym(Sym *s, int op) +{ + if(s->def != N && s->def->op != op) + redeclare(s, "during import"); + + // mark the symbol so it is not reexported + if(s->def == N) { + if(exportname(s->name) || initname(s->name)) + s->flags |= SymExport; + else + s->flags |= SymPackage; // package scope + } + return s; +} + +/* + * return the type pkg.name, forward declaring if needed + */ +Type* +pkgtype(Sym *s) +{ + Type *t; + + importsym(s, OTYPE); + if(s->def == N || s->def->op != OTYPE) { + t = typ(TFORW); + t->sym = s; + s->def = typenod(t); + } + if(s->def->type == T) + yyerror("pkgtype %lS", s); + return s->def->type; +} + +static int +mypackage(Sym *s) +{ + // we import all definitions for runtime. + // lowercase ones can only be used by the compiler. + return s->pkg == localpkg || s->pkg == runtimepkg; +} + +void +importconst(Sym *s, Type *t, Node *n) +{ + Node *n1; + + if(!exportname(s->name) && !mypackage(s)) + return; + importsym(s, OLITERAL); + convlit(&n, t); + if(s->def != N) { + // TODO: check if already the same. + return; + } + + if(n->op != OLITERAL) { + yyerror("expression must be a constant"); + return; + } + if(n->sym != S) { + n1 = nod(OXXX, N, N); + *n1 = *n; + n = n1; + } + n->sym = s; + declare(n, PEXTERN); + + if(debug['E']) + print("import const %S\n", s); +} + +void +importvar(Sym *s, Type *t, int ctxt) +{ + Node *n; + + if(!exportname(s->name) && !initname(s->name) && !mypackage(s)) + return; + + importsym(s, ONAME); + if(s->def != N && s->def->op == ONAME) { + if(eqtype(t, s->def->type)) + return; + yyerror("inconsistent definition for var %S during import\n\t%T\n\t%T", + s, s->def->type, t); + } + n = newname(s); + n->type = t; + declare(n, ctxt); + + if(debug['E']) + print("import var %S %lT\n", s, t); +} + +void +importtype(Type *pt, Type *t) +{ + if(pt != T && t != T) + typedcl2(pt, t); + + if(debug['E']) + print("import type %T %lT\n", pt, t); +} + +void +importmethod(Sym *s, Type *t) +{ + checkwidth(t); + addmethod(s, t, 0); +} + |