The Go Programming Language

Text file src/cmd/gc/export.c

     1	// Copyright 2009 The Go Authors. All rights reserved.
     2	// Use of this source code is governed by a BSD-style
     3	// license that can be found in the LICENSE file.
     4	
     5	#include	"go.h"
     6	#include	"y.tab.h"
     7	
     8	static	void dumpsym(Sym*);
     9	static	void	dumpexporttype(Sym*);
    10	static	void	dumpexportvar(Sym*);
    11	static	void	dumpexportconst(Sym*);
    12	
    13	void
    14	exportsym(Node *n)
    15	{
    16		if(n == N || n->sym == S)
    17			return;
    18		if(n->sym->flags & (SymExport|SymPackage)) {
    19			if(n->sym->flags & SymPackage)
    20				yyerror("export/package mismatch: %S", n->sym);
    21			return;
    22		}
    23		n->sym->flags |= SymExport;
    24	
    25		exportlist = list(exportlist, n);
    26	}
    27	
    28	static void
    29	packagesym(Node *n)
    30	{
    31		if(n == N || n->sym == S)
    32			return;
    33		if(n->sym->flags & (SymExport|SymPackage)) {
    34			if(n->sym->flags & SymExport)
    35				yyerror("export/package mismatch: %S", n->sym);
    36			return;
    37		}
    38		n->sym->flags |= SymPackage;
    39	
    40		exportlist = list(exportlist, n);
    41	}
    42	
    43	int
    44	exportname(char *s)
    45	{
    46		Rune r;
    47	
    48		if((uchar)s[0] < Runeself)
    49			return 'A' <= s[0] && s[0] <= 'Z';
    50		chartorune(&r, s);
    51		return isupperrune(r);
    52	}
    53	
    54	static int
    55	initname(char *s)
    56	{
    57		return strcmp(s, "init") == 0;
    58	}
    59	
    60	void
    61	autoexport(Node *n, int ctxt)
    62	{
    63		if(n == N || n->sym == S)
    64			return;
    65		if((ctxt != PEXTERN && ctxt != PFUNC) || dclcontext != PEXTERN)
    66			return;
    67		if(n->ntype && n->ntype->op == OTFUNC && n->ntype->left)	// method
    68			return;
    69		if(exportname(n->sym->name) || initname(n->sym->name))
    70			exportsym(n);
    71		else
    72			packagesym(n);
    73	}
    74	
    75	static void
    76	dumppkg(Pkg *p)
    77	{
    78		char *suffix;
    79	
    80		if(p == nil || p == localpkg || p->exported)
    81			return;
    82		p->exported = 1;
    83		suffix = "";
    84		if(!p->direct)
    85			suffix = " // indirect";
    86		Bprint(bout, "\timport %s \"%Z\"%s\n", p->name, p->path, suffix);
    87	}
    88	
    89	static void
    90	dumpprereq(Type *t)
    91	{
    92		if(t == T)
    93			return;
    94	
    95		if(t->printed || t == types[t->etype])
    96			return;
    97		t->printed = 1;
    98	
    99		if(t->sym != S) {
   100			dumppkg(t->sym->pkg);
   101			if(t->etype != TFIELD)
   102				dumpsym(t->sym);
   103		}
   104		dumpprereq(t->type);
   105		dumpprereq(t->down);
   106	}
   107	
   108	static void
   109	dumpexportconst(Sym *s)
   110	{
   111		Node *n;
   112		Type *t;
   113	
   114		n = s->def;
   115		typecheck(&n, Erv);
   116		if(n == N || n->op != OLITERAL)
   117			fatal("dumpexportconst: oconst nil: %S", s);
   118	
   119		t = n->type;	// may or may not be specified
   120		if(t != T)
   121			dumpprereq(t);
   122	
   123		Bprint(bout, "\t");
   124		Bprint(bout, "const %#S", s);
   125		if(t != T && !isideal(t))
   126			Bprint(bout, " %#T", t);
   127		Bprint(bout, " = ");
   128	
   129		switch(n->val.ctype) {
   130		default:
   131			fatal("dumpexportconst: unknown ctype: %S %d", s, n->val.ctype);
   132		case CTINT:
   133			Bprint(bout, "%B\n", n->val.u.xval);
   134			break;
   135		case CTBOOL:
   136			if(n->val.u.bval)
   137				Bprint(bout, "true\n");
   138			else
   139				Bprint(bout, "false\n");
   140			break;
   141		case CTFLT:
   142			Bprint(bout, "%F\n", n->val.u.fval);
   143			break;
   144		case CTCPLX:
   145			Bprint(bout, "(%F+%F)\n", &n->val.u.cval->real, &n->val.u.cval->imag);
   146			break;
   147		case CTSTR:
   148			Bprint(bout, "\"%Z\"\n", n->val.u.sval);
   149			break;
   150		}
   151	}
   152	
   153	static void
   154	dumpexportvar(Sym *s)
   155	{
   156		Node *n;
   157		Type *t;
   158	
   159		n = s->def;
   160		typecheck(&n, Erv);
   161		if(n == N || n->type == T) {
   162			yyerror("variable exported but not defined: %S", s);
   163			return;
   164		}
   165	
   166		t = n->type;
   167		dumpprereq(t);
   168	
   169		Bprint(bout, "\t");
   170		if(t->etype == TFUNC && n->class == PFUNC)
   171			Bprint(bout, "func %#S %#hhT", s, t);
   172		else
   173			Bprint(bout, "var %#S %#T", s, t);
   174		Bprint(bout, "\n");
   175	}
   176	
   177	static void
   178	dumpexporttype(Sym *s)
   179	{
   180		Type *t;
   181	
   182		t = s->def->type;
   183		dumpprereq(t);
   184		Bprint(bout, "\t");
   185		switch (t->etype) {
   186		case TFORW:
   187			yyerror("export of incomplete type %T", t);
   188			return;
   189		}
   190		if(Bprint(bout, "type %#T %l#T\n",  t, t) < 0)
   191			fatal("Bprint failed for %T", t);
   192	}
   193	
   194	static int
   195	methcmp(const void *va, const void *vb)
   196	{
   197		Type *a, *b;
   198		
   199		a = *(Type**)va;
   200		b = *(Type**)vb;
   201		return strcmp(a->sym->name, b->sym->name);
   202	}
   203	
   204	static void
   205	dumpsym(Sym *s)
   206	{
   207		Type *f, *t;
   208		Type **m;
   209		int i, n;
   210	
   211		if(s->flags & SymExported)
   212			return;
   213		s->flags |= SymExported;
   214	
   215		if(s->def == N) {
   216			yyerror("unknown export symbol: %S", s);
   217			return;
   218		}
   219		
   220		dumppkg(s->pkg);
   221	
   222		switch(s->def->op) {
   223		default:
   224			yyerror("unexpected export symbol: %O %S", s->def->op, s);
   225			break;
   226		case OLITERAL:
   227			dumpexportconst(s);
   228			break;
   229		case OTYPE:
   230			t = s->def->type;
   231			n = 0;
   232			for(f=t->method; f!=T; f=f->down) {	
   233				dumpprereq(f);
   234				n++;
   235			}
   236			m = mal(n*sizeof m[0]);
   237			i = 0;
   238			for(f=t->method; f!=T; f=f->down)
   239				m[i++] = f;
   240			qsort(m, n, sizeof m[0], methcmp);
   241	
   242			dumpexporttype(s);
   243			for(i=0; i<n; i++) {
   244				f = m[i];
   245				Bprint(bout, "\tfunc (%#T) %hS %#hhT\n",
   246					f->type->type->type, f->sym, f->type);
   247			}
   248			break;
   249		case ONAME:
   250			dumpexportvar(s);
   251			break;
   252		}
   253	}
   254	
   255	static void
   256	dumptype(Type *t)
   257	{
   258		// no need to re-dump type if already exported
   259		if(t->printed)
   260			return;
   261	
   262		// no need to dump type if it's not ours (was imported)
   263		if(t->sym != S && t->sym->def == typenod(t) && !t->local)
   264			return;
   265	
   266		Bprint(bout, "type %#T %l#T\n",  t, t);
   267	}
   268	
   269	void
   270	dumpexport(void)
   271	{
   272		NodeList *l;
   273		int32 i, lno;
   274		Pkg *p;
   275	
   276		lno = lineno;
   277	
   278		packagequotes = 1;
   279		Bprint(bout, "\n$$  // exports\n");
   280	
   281		Bprint(bout, "    package %s", localpkg->name);
   282		if(safemode)
   283			Bprint(bout, " safe");
   284		Bprint(bout, "\n");
   285	
   286		for(i=0; i<nelem(phash); i++)
   287			for(p=phash[i]; p; p=p->link)
   288				if(p->direct)
   289					dumppkg(p);
   290	
   291		for(l=exportlist; l; l=l->next) {
   292			lineno = l->n->lineno;
   293			dumpsym(l->n->sym);
   294		}
   295	
   296		Bprint(bout, "\n$$  // local types\n");
   297	
   298		for(l=typelist; l; l=l->next) {
   299			lineno = l->n->lineno;
   300			dumptype(l->n->type);
   301		}
   302	
   303		Bprint(bout, "\n$$\n");
   304		packagequotes = 0;
   305	
   306		lineno = lno;
   307	}
   308	
   309	/*
   310	 * import
   311	 */
   312	
   313	/*
   314	 * return the sym for ss, which should match lexical
   315	 */
   316	Sym*
   317	importsym(Sym *s, int op)
   318	{
   319		if(s->def != N && s->def->op != op)
   320			redeclare(s, "during import");
   321	
   322		// mark the symbol so it is not reexported
   323		if(s->def == N) {
   324			if(exportname(s->name) || initname(s->name))
   325				s->flags |= SymExport;
   326			else
   327				s->flags |= SymPackage;	// package scope
   328		}
   329		return s;
   330	}
   331	
   332	/*
   333	 * return the type pkg.name, forward declaring if needed
   334	 */
   335	Type*
   336	pkgtype(Sym *s)
   337	{
   338		Type *t;
   339	
   340		importsym(s, OTYPE);
   341		if(s->def == N || s->def->op != OTYPE) {
   342			t = typ(TFORW);
   343			t->sym = s;
   344			s->def = typenod(t);
   345		}
   346		if(s->def->type == T)
   347			yyerror("pkgtype %lS", s);
   348		return s->def->type;
   349	}
   350	
   351	static int
   352	mypackage(Sym *s)
   353	{
   354		// we import all definitions for runtime.
   355		// lowercase ones can only be used by the compiler.
   356		return s->pkg == localpkg || s->pkg == runtimepkg;
   357	}
   358	
   359	void
   360	importconst(Sym *s, Type *t, Node *n)
   361	{
   362		Node *n1;
   363	
   364		if(!exportname(s->name) && !mypackage(s))
   365			return;
   366		importsym(s, OLITERAL);
   367		convlit(&n, t);
   368		if(s->def != N) {
   369			// TODO: check if already the same.
   370			return;
   371		}
   372	
   373		if(n->op != OLITERAL) {
   374			yyerror("expression must be a constant");
   375			return;
   376		}
   377		if(n->sym != S) {
   378			n1 = nod(OXXX, N, N);
   379			*n1 = *n;
   380			n = n1;
   381		}
   382		n->sym = s;
   383		declare(n, PEXTERN);
   384	
   385		if(debug['E'])
   386			print("import const %S\n", s);
   387	}
   388	
   389	void
   390	importvar(Sym *s, Type *t, int ctxt)
   391	{
   392		Node *n;
   393	
   394		if(!exportname(s->name) && !initname(s->name) && !mypackage(s))
   395			return;
   396	
   397		importsym(s, ONAME);
   398		if(s->def != N && s->def->op == ONAME) {
   399			if(eqtype(t, s->def->type))
   400				return;
   401			yyerror("inconsistent definition for var %S during import\n\t%T\n\t%T",
   402				s, s->def->type, t);
   403		}
   404		n = newname(s);
   405		n->type = t;
   406		declare(n, ctxt);
   407	
   408		if(debug['E'])
   409			print("import var %S %lT\n", s, t);
   410	}
   411	
   412	void
   413	importtype(Type *pt, Type *t)
   414	{
   415		if(pt != T && t != T)
   416			typedcl2(pt, t);
   417	
   418		if(debug['E'])
   419			print("import type %T %lT\n", pt, t);
   420	}
   421	
   422	void
   423	importmethod(Sym *s, Type *t)
   424	{
   425		checkwidth(t);
   426		addmethod(s, t, 0);
   427	}
   428	

release.r60.3. Except as noted, this content is licensed under a Creative Commons Attribution 3.0 License.