export.go 5.38 KB
Newer Older
1 2 3 4 5 6
// 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.

package Exporter

7
import Platform "platform"
Robert Griesemer's avatar
Robert Griesemer committed
8
import Utils "utils"
9 10 11
import Globals "globals"
import Object "object"
import Type "type"
12
import Universe "universe"
13 14 15


type Exporter struct {
16
	comp *Globals.Compilation;
17 18
	debug bool;
	buf [4*1024] byte;
19
	buf_pos int;
20 21 22 23 24 25 26 27 28
	pkg_ref int;
	type_ref int;
};


func (E *Exporter) WriteObject(obj *Globals.Object);


func (E *Exporter) WriteByte(x byte) {
29 30
	E.buf[E.buf_pos] = x;
	E.buf_pos++;
31
	/*
32
	if E.debug {
33
		print(" ", x);
34
	}
35
	*/
36 37 38 39
}


func (E *Exporter) WriteInt(x int) {
40
	x0 := x;
41 42 43 44 45 46
	for x < -64 || x >= 64 {
		E.WriteByte(byte(x & 127));
		x = int(uint(x >> 7));  // arithmetic shift
	}
	// -64 <= x && x < 64
	E.WriteByte(byte(x + 192));
47 48
	/*
	if E.debug {
49
		print(" #", x0);
50 51
	}
	*/
52 53 54 55 56 57 58 59 60
}


func (E *Exporter) WriteString(s string) {
	n := len(s);
	E.WriteInt(n);
	for i := 0; i < n; i++ {
		E.WriteByte(s[i]);
	}
61
	if E.debug {
62
		print(` "`, s, `"`);
63
	}
64 65 66
}


67
func (E *Exporter) WritePackageTag(tag int) {
68
	E.WriteInt(tag);
69
	if E.debug {
70
		if tag >= 0 {
71
			print(" [P", tag, "]");  // package ref
72
		} else {
73
			print("\nP", E.pkg_ref, ":");
74
		}
75 76 77 78 79
	}
}


func (E *Exporter) WriteTypeTag(tag int) {
80
	E.WriteInt(tag);
81
	if E.debug {
82
		if tag >= 0 {
83
			print(" [T", tag, "]");  // type ref
84
		} else {
85
			print("\nT", E.type_ref, ": ", Type.FormStr(-tag));
86 87 88 89 90
		}
	}
}


91 92
func (E *Exporter) WriteObjectTag(tag int) {
	if tag < 0 {
93
		panic("tag < 0");
94
	}
95
	E.WriteInt(tag);
96
	if E.debug {
97
		print("\n", Object.KindStr(tag));
98 99 100 101 102 103
	}
}


func (E *Exporter) WritePackage(pkg *Globals.Package) {
	if E.comp.pkg_list[pkg.obj.pnolev] != pkg {
104
		panic("inconsistent package object");
105 106 107 108 109
	}

	if pkg.ref >= 0 {
		E.WritePackageTag(pkg.ref);  // package already exported
		return;
110
	}
111 112 113 114 115 116 117 118

	E.WritePackageTag(-1);
	pkg.ref = E.pkg_ref;
	E.pkg_ref++;

	E.WriteString(pkg.obj.ident);
	E.WriteString(pkg.file_name);
	E.WriteString(pkg.key);
119 120 121
}


122
func (E *Exporter) WriteScope(scope *Globals.Scope) {
123
	if E.debug {
124
		print(" {");
125 126 127
	}

	for p := scope.entries.first; p != nil; p = p.next {
128 129 130
		if p.obj.exported {
			E.WriteObject(p.obj);
		}
131
	}
Robert Griesemer's avatar
Robert Griesemer committed
132
	E.WriteObject(nil);
Russ Cox's avatar
Russ Cox committed
133

134
	if E.debug {
135
		print(" }");
136 137 138 139 140 141
	}
}


func (E *Exporter) WriteType(typ *Globals.Type) {
	if typ.ref >= 0 {
142
		E.WriteTypeTag(typ.ref);  // type already exported
143 144 145
		return;
	}

146
	if -typ.form >= 0 {
147
		panic("conflict with ref numbers");
148
	}
149
	E.WriteTypeTag(-typ.form);
150 151 152
	typ.ref = E.type_ref;
	E.type_ref++;

153
	// if we have a named type, export the type identifier and package
154
	ident := "";
155
	if typ.obj != nil {
156
		// named type
157
		if typ.obj.typ != typ {
158
			panic("inconsistent named type");
159 160 161 162 163
		}
		ident = typ.obj.ident;
		if !typ.obj.exported {
			// the type is invisible (it's identifier is not exported)
			// prepend "." to the identifier to make it an illegal
164 165
			// identifier for importing packages and thus inaccessible
			// from those package's source code
166
			ident = "." + ident;
167
		}
168
	}
Russ Cox's avatar
Russ Cox committed
169

170 171
	E.WriteString(ident);
	if len(ident) > 0 {
172 173
		// named type
		E.WritePackage(E.comp.pkg_list[typ.obj.pnolev]);
174
	}
Russ Cox's avatar
Russ Cox committed
175

176
	switch typ.form {
177 178
	case Type.VOID:
		// for now until we have enough of the front-end working.
Russ Cox's avatar
Russ Cox committed
179

180 181 182
	case Type.FORWARD:
		// corresponding package must be forward-declared too
		if typ.obj == nil || E.comp.pkg_list[typ.obj.pnolev].key != "" {
183
			panic("inconsistency in package.type forward declaration");
184
		}
Russ Cox's avatar
Russ Cox committed
185

186
	case Type.ALIAS, Type.MAP:
187 188 189 190
		E.WriteType(typ.key);
		E.WriteType(typ.elt);

	case Type.TUPLE:
191 192
		E.WriteType(typ.elt);

193
	case Type.ARRAY:
194
		E.WriteInt(typ.len);
195
		E.WriteType(typ.elt);
196 197

	case Type.CHANNEL:
198
		E.WriteInt(typ.aux);
199
		E.WriteType(typ.elt);
200

201 202 203
	case Type.FUNCTION, Type.METHOD:
		E.WriteInt(typ.len);
		E.WriteType(typ.elt);
204
		E.WriteScope(typ.scope);
Russ Cox's avatar
Russ Cox committed
205

206
	case Type.STRUCT, Type.INTERFACE:
207
		E.WriteScope(typ.scope);
208

209
	case Type.POINTER:
210
		E.WriteType(typ.elt);
211 212

	default:
213
		panic("UNREACHABLE");
214 215 216 217
	}
}


218 219 220 221
func (E *Exporter) WriteObject(obj *Globals.Object) {
	if obj == nil {
		E.WriteObjectTag(Object.END);
		return;
222
	}
223 224 225 226 227
	E.WriteObjectTag(obj.kind);

	if obj.kind == Object.TYPE {
		// named types are handled entirely by WriteType()
		if obj.typ.obj != obj {
228
			panic("inconsistent named type");
229 230
		}
		E.WriteType(obj.typ);
231 232 233
		return;
	}

234 235
	E.WriteString(obj.ident);
	E.WriteType(obj.typ);
236

237 238 239 240
	switch obj.kind {
	case Object.CONST:
		E.WriteInt(0);  // should be the correct value

241
	case Object.VAR, Object.FIELD:
242
		E.WriteInt(0);  // should be the correct address/offset
Russ Cox's avatar
Russ Cox committed
243

244 245
	case Object.FUNC:
		E.WriteInt(0);  // should be the correct address/offset
Russ Cox's avatar
Russ Cox committed
246

247
	default:
248
		panic("UNREACHABLE");
249
	}
250 251 252
}


253
func (E *Exporter) Export(comp* Globals.Compilation) string {
254 255 256 257 258
	E.comp = comp;
	E.debug = comp.flags.debug;
	E.buf_pos = 0;
	E.pkg_ref = 0;
	E.type_ref = 0;
Russ Cox's avatar
Russ Cox committed
259

260 261 262 263 264
	// write magic bits
	magic := Platform.MAGIC_obj_file;  // TODO remove once len(constant) works
	for i := 0; i < len(magic); i++ {
		E.WriteByte(magic[i]);
	}
Russ Cox's avatar
Russ Cox committed
265

266 267 268 269 270
	// Predeclared types are "pre-exported".
	// TODO run the loop below only in debug mode
	{	i := 0;
		for p := Universe.types.first; p != nil; p = p.next {
			if p.typ.ref != i {
271
				panic("incorrect ref for predeclared type");
272 273 274 275
			}
			i++;
		}
	}
276
	E.type_ref = Universe.types.len;
Russ Cox's avatar
Russ Cox committed
277

278 279 280 281
	// export package 0
	pkg := comp.pkg_list[0];
	E.WritePackage(pkg);
	E.WriteScope(pkg.scope);
Russ Cox's avatar
Russ Cox committed
282

283
	if E.debug {
284
		print("\n(", E.buf_pos, " bytes)\n");
285
	}
Russ Cox's avatar
Russ Cox committed
286

287 288 289 290
	return string(E.buf)[0 : E.buf_pos];
}


Russ Cox's avatar
Russ Cox committed
291
func Export(comp* Globals.Compilation) string {
292
	var E Exporter;
293
	return (&E).Export(comp);
Robert Griesemer's avatar
Robert Griesemer committed
294
}