2008-07-15 16:37:14 -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.
|
|
|
|
|
|
|
|
package Exporter
|
|
|
|
|
|
|
|
import Globals "globals"
|
|
|
|
import Object "object"
|
|
|
|
import Type "type"
|
2008-07-18 15:04:21 -06:00
|
|
|
import Universe "universe"
|
2008-07-15 16:37:14 -06:00
|
|
|
|
|
|
|
|
2008-07-18 15:04:21 -06:00
|
|
|
export Exporter // really only want to export Export()
|
2008-07-15 16:37:14 -06:00
|
|
|
type Exporter struct {
|
2008-07-18 15:04:21 -06:00
|
|
|
comp *Globals.Compilation;
|
2008-07-15 16:37:14 -06:00
|
|
|
debug bool;
|
|
|
|
buf [4*1024] byte;
|
|
|
|
pos int;
|
|
|
|
pkg_ref int;
|
|
|
|
type_ref int;
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
func (E *Exporter) WriteType(typ *Globals.Type);
|
|
|
|
func (E *Exporter) WriteObject(obj *Globals.Object);
|
2008-07-18 15:04:21 -06:00
|
|
|
func (E *Exporter) WritePackage(pkg *Globals.Package);
|
2008-07-15 16:37:14 -06:00
|
|
|
|
|
|
|
|
|
|
|
func (E *Exporter) WriteByte(x byte) {
|
|
|
|
E.buf[E.pos] = x;
|
|
|
|
E.pos++;
|
2008-07-18 15:04:21 -06:00
|
|
|
/*
|
2008-07-15 16:37:14 -06:00
|
|
|
if E.debug {
|
|
|
|
print " ", x;
|
|
|
|
}
|
2008-07-18 15:04:21 -06:00
|
|
|
*/
|
2008-07-15 16:37:14 -06:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
func (E *Exporter) WriteInt(x int) {
|
2008-07-18 15:04:21 -06:00
|
|
|
/*
|
2008-07-15 16:37:14 -06:00
|
|
|
if E.debug {
|
|
|
|
print " #", x;
|
|
|
|
}
|
2008-07-18 15:04:21 -06:00
|
|
|
*/
|
2008-07-15 16:37:14 -06:00
|
|
|
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));
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
func (E *Exporter) WriteString(s string) {
|
|
|
|
if E.debug {
|
2008-07-18 15:04:21 -06:00
|
|
|
print ` "`, s, `"`;
|
2008-07-15 16:37:14 -06:00
|
|
|
}
|
|
|
|
n := len(s);
|
|
|
|
E.WriteInt(n);
|
|
|
|
for i := 0; i < n; i++ {
|
|
|
|
E.WriteByte(s[i]);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
func (E *Exporter) WriteObjTag(tag int) {
|
|
|
|
if tag < 0 {
|
|
|
|
panic "tag < 0";
|
|
|
|
}
|
|
|
|
if E.debug {
|
2008-07-18 15:04:21 -06:00
|
|
|
print "\nObj: ", tag; // obj kind
|
2008-07-15 16:37:14 -06:00
|
|
|
}
|
|
|
|
E.WriteInt(tag);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
func (E *Exporter) WriteTypeTag(tag int) {
|
|
|
|
if E.debug {
|
|
|
|
if tag > 0 {
|
2008-07-18 15:04:21 -06:00
|
|
|
print "\nTyp ", E.type_ref, ": ", tag; // type form
|
2008-07-15 16:37:14 -06:00
|
|
|
} else {
|
2008-07-18 15:04:21 -06:00
|
|
|
print " [Typ ", -tag, "]"; // type ref
|
2008-07-15 16:37:14 -06:00
|
|
|
}
|
|
|
|
}
|
|
|
|
E.WriteInt(tag);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
func (E *Exporter) WritePackageTag(tag int) {
|
|
|
|
if E.debug {
|
|
|
|
if tag > 0 {
|
2008-07-18 15:04:21 -06:00
|
|
|
print "\nPkg ", E.pkg_ref, ": ", tag; // package no
|
2008-07-15 16:37:14 -06:00
|
|
|
} else {
|
2008-07-18 15:04:21 -06:00
|
|
|
print " [Pkg ", -tag, "]"; // package ref
|
2008-07-15 16:37:14 -06:00
|
|
|
}
|
|
|
|
}
|
|
|
|
E.WriteInt(tag);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
func (E *Exporter) WriteTypeField(fld *Globals.Object) {
|
|
|
|
if fld.kind != Object.VAR {
|
|
|
|
panic "fld.kind != Object.VAR";
|
|
|
|
}
|
|
|
|
E.WriteType(fld.typ);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
func (E *Exporter) WriteScope(scope *Globals.Scope) {
|
|
|
|
if E.debug {
|
|
|
|
print " {";
|
|
|
|
}
|
|
|
|
|
|
|
|
// determine number of objects to export
|
|
|
|
n := 0;
|
|
|
|
for p := scope.entries.first; p != nil; p = p.next {
|
2008-07-29 13:03:06 -06:00
|
|
|
if p.obj.exported {
|
2008-07-15 16:37:14 -06:00
|
|
|
n++;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// export the objects, if any
|
|
|
|
if n > 0 {
|
|
|
|
for p := scope.entries.first; p != nil; p = p.next {
|
2008-07-29 13:03:06 -06:00
|
|
|
if p.obj.exported {
|
2008-07-15 16:37:14 -06:00
|
|
|
E.WriteObject(p.obj);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if E.debug {
|
|
|
|
print " }";
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
func (E *Exporter) WriteObject(obj *Globals.Object) {
|
2008-07-29 13:03:06 -06:00
|
|
|
if obj == nil || !obj.exported {
|
|
|
|
panic "obj == nil || !obj.exported";
|
2008-07-15 16:37:14 -06:00
|
|
|
}
|
|
|
|
|
|
|
|
if obj.kind == Object.TYPE && obj.typ.obj == obj {
|
|
|
|
// primary type object - handled entirely by WriteType()
|
|
|
|
E.WriteObjTag(Object.PTYPE);
|
|
|
|
E.WriteType(obj.typ);
|
|
|
|
|
|
|
|
} else {
|
|
|
|
E.WriteObjTag(obj.kind);
|
|
|
|
E.WriteString(obj.ident);
|
|
|
|
E.WriteType(obj.typ);
|
2008-07-23 17:04:11 -06:00
|
|
|
//E.WritePackage(E.comp.pkgs[obj.pnolev]);
|
2008-07-15 16:37:14 -06:00
|
|
|
|
|
|
|
switch obj.kind {
|
|
|
|
case Object.CONST:
|
|
|
|
E.WriteInt(0); // should be the correct value
|
2008-07-23 17:04:11 -06:00
|
|
|
|
2008-07-15 16:37:14 -06:00
|
|
|
case Object.TYPE:
|
|
|
|
// nothing to do
|
2008-07-23 17:04:11 -06:00
|
|
|
|
2008-07-15 16:37:14 -06:00
|
|
|
case Object.VAR:
|
|
|
|
E.WriteInt(0); // should be the correct address/offset
|
2008-07-23 17:04:11 -06:00
|
|
|
|
2008-07-15 16:37:14 -06:00
|
|
|
case Object.FUNC:
|
|
|
|
E.WriteInt(0); // should be the correct address/offset
|
2008-07-23 17:04:11 -06:00
|
|
|
|
2008-07-15 16:37:14 -06:00
|
|
|
default:
|
2008-07-23 17:04:11 -06:00
|
|
|
print "obj.kind = ", obj.kind, "\n";
|
2008-07-15 16:37:14 -06:00
|
|
|
panic "UNREACHABLE";
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
func (E *Exporter) WriteType(typ *Globals.Type) {
|
|
|
|
if typ == nil {
|
|
|
|
panic "typ == nil";
|
|
|
|
}
|
|
|
|
|
|
|
|
if typ.ref >= 0 {
|
|
|
|
E.WriteTypeTag(-typ.ref); // type already exported
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
if typ.form <= 0 {
|
|
|
|
panic "typ.form <= 0";
|
|
|
|
}
|
|
|
|
E.WriteTypeTag(typ.form);
|
|
|
|
typ.ref = E.type_ref;
|
|
|
|
E.type_ref++;
|
|
|
|
|
|
|
|
if typ.obj != nil {
|
|
|
|
if typ.obj.typ != typ {
|
|
|
|
panic "typ.obj.type() != typ"; // primary type
|
|
|
|
}
|
|
|
|
E.WriteString(typ.obj.ident);
|
2008-07-18 15:04:21 -06:00
|
|
|
E.WritePackage(E.comp.pkgs[typ.obj.pnolev]);
|
2008-07-15 16:37:14 -06:00
|
|
|
} else {
|
|
|
|
E.WriteString("");
|
|
|
|
}
|
|
|
|
|
|
|
|
switch typ.form {
|
|
|
|
case Type.ARRAY:
|
|
|
|
E.WriteInt(typ.len_);
|
2008-07-23 17:04:11 -06:00
|
|
|
E.WriteType(typ.elt);
|
2008-07-15 16:37:14 -06:00
|
|
|
|
|
|
|
case Type.MAP:
|
2008-07-23 17:04:11 -06:00
|
|
|
E.WriteType(typ.key);
|
|
|
|
E.WriteType(typ.elt);
|
2008-07-15 16:37:14 -06:00
|
|
|
|
|
|
|
case Type.CHANNEL:
|
|
|
|
E.WriteInt(typ.flags);
|
2008-07-23 17:04:11 -06:00
|
|
|
E.WriteType(typ.elt);
|
2008-07-15 16:37:14 -06:00
|
|
|
|
|
|
|
case Type.FUNCTION:
|
|
|
|
E.WriteInt(typ.flags);
|
2008-07-23 17:04:11 -06:00
|
|
|
E.WriteScope(typ.scope);
|
|
|
|
|
|
|
|
case Type.STRUCT, Type.INTERFACE:
|
2008-07-15 16:37:14 -06:00
|
|
|
E.WriteScope(typ.scope);
|
|
|
|
|
2008-07-23 17:04:11 -06:00
|
|
|
case Type.POINTER, Type.REFERENCE:
|
|
|
|
E.WriteType(typ.elt);
|
2008-07-15 16:37:14 -06:00
|
|
|
|
|
|
|
default:
|
2008-07-23 17:04:11 -06:00
|
|
|
print "typ.form = ", typ.form, "\n";
|
2008-07-15 16:37:14 -06:00
|
|
|
panic "UNREACHABLE";
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2008-07-17 15:53:13 -06:00
|
|
|
func (E *Exporter) WritePackage(pkg *Globals.Package) {
|
2008-07-15 16:37:14 -06:00
|
|
|
if pkg.ref >= 0 {
|
|
|
|
E.WritePackageTag(-pkg.ref); // package already exported
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
if Object.PACKAGE <= 0 {
|
|
|
|
panic "Object.PACKAGE <= 0";
|
|
|
|
}
|
|
|
|
E.WritePackageTag(Object.PACKAGE);
|
|
|
|
pkg.ref = E.pkg_ref;
|
|
|
|
E.pkg_ref++;
|
|
|
|
|
2008-07-17 19:02:10 -06:00
|
|
|
E.WriteString(pkg.obj.ident);
|
2008-07-16 18:00:48 -06:00
|
|
|
E.WriteString(pkg.file_name);
|
2008-07-15 16:37:14 -06:00
|
|
|
E.WriteString(pkg.key);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2008-07-18 15:04:21 -06:00
|
|
|
func (E *Exporter) Export(comp* Globals.Compilation, file_name string) {
|
2008-07-18 15:23:04 -06:00
|
|
|
if E.debug {
|
|
|
|
print "exporting to ", file_name;
|
|
|
|
}
|
|
|
|
|
2008-07-15 16:37:14 -06:00
|
|
|
E.comp = comp;
|
2008-07-18 15:04:21 -06:00
|
|
|
E.debug = true;
|
|
|
|
E.pos = 0;
|
|
|
|
E.pkg_ref = 0;
|
|
|
|
E.type_ref = 0;
|
|
|
|
|
2008-07-15 16:37:14 -06:00
|
|
|
// Predeclared types are "pre-exported".
|
2008-07-18 15:04:21 -06:00
|
|
|
// 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 {
|
|
|
|
panic "incorrect ref for predeclared type";
|
|
|
|
}
|
|
|
|
i++;
|
|
|
|
}
|
2008-07-15 16:37:14 -06:00
|
|
|
}
|
2008-07-18 15:04:21 -06:00
|
|
|
E.type_ref = Universe.types.len_;
|
2008-07-15 16:37:14 -06:00
|
|
|
|
2008-07-18 15:04:21 -06:00
|
|
|
pkg := comp.pkgs[0];
|
2008-07-15 16:37:14 -06:00
|
|
|
E.WritePackage(pkg);
|
|
|
|
for p := pkg.scope.entries.first; p != nil; p = p.next {
|
2008-07-29 13:03:06 -06:00
|
|
|
if p.obj.exported {
|
2008-07-15 16:37:14 -06:00
|
|
|
E.WriteObject(p.obj);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
E.WriteObjTag(0);
|
|
|
|
|
|
|
|
if E.debug {
|
2008-07-18 15:04:21 -06:00
|
|
|
print "\n(", E.pos, " bytes)\n";
|
2008-07-15 16:37:14 -06:00
|
|
|
}
|
2008-07-18 15:04:21 -06:00
|
|
|
|
|
|
|
data := string(E.buf)[0 : E.pos];
|
|
|
|
ok := sys.writefile(file_name, data);
|
2008-07-18 15:23:04 -06:00
|
|
|
|
|
|
|
if !ok {
|
|
|
|
panic "export failed";
|
|
|
|
}
|
2008-07-15 16:37:14 -06:00
|
|
|
}
|