// 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 Utils "utils" import Globals "globals" import Object "object" import Type "type" import Universe "universe" type Exporter struct { comp *Globals.Compilation; debug bool; buf [4*1024] byte; buf_pos int; pkg_ref int; type_ref int; }; func (E *Exporter) WriteType(typ *Globals.Type); func (E *Exporter) WriteObject(obj *Globals.Object); func (E *Exporter) WritePackage(pkg *Globals.Package); func (E *Exporter) WriteByte(x byte) { E.buf[E.buf_pos] = x; E.buf_pos++; /* if E.debug { print " ", x; } */ } func (E *Exporter) WriteInt(x int) { x0 := x; 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)); /* if E.debug { print " #", x0; } */ } func (E *Exporter) WriteString(s string) { n := len(s); E.WriteInt(n); for i := 0; i < n; i++ { E.WriteByte(s[i]); } if E.debug { print ` "`, s, `"`; } } func (E *Exporter) WriteObjectTag(tag int) { if tag < 0 { panic "tag < 0"; } E.WriteInt(tag); if E.debug { print "\n", Object.KindStr(tag); } } func (E *Exporter) WriteTypeTag(tag int) { E.WriteInt(tag); if E.debug { if tag >= 0 { print " [T", tag, "]"; // type ref } else { print "\nT", E.type_ref, ": ", Type.FormStr(-tag); } } } func (E *Exporter) WritePackageTag(tag int) { E.WriteInt(tag); if E.debug { if tag >= 0 { print " [P", tag, "]"; // package ref } else { print "\nP", E.pkg_ref, ": ", -tag; // package no } } } func (E *Exporter) WriteScope(scope *Globals.Scope) { if E.debug { print " {"; } for p := scope.entries.first; p != nil; p = p.next { if p.obj.exported { E.WriteObject(p.obj); } } E.WriteObjectTag(Object.EOS); if E.debug { print " }"; } } func (E *Exporter) WriteObject(obj *Globals.Object) { if !obj.exported { panic "!obj.exported"; } if obj.kind == Object.TYPE && obj.typ.obj == obj { // primary type object - handled entirely by WriteType() E.WriteObjectTag(Object.PTYPE); E.WriteType(obj.typ); } else { E.WriteObjectTag(obj.kind); E.WriteString(obj.ident); E.WriteType(obj.typ); E.WritePackage(E.comp.pkgs[obj.pnolev]); switch obj.kind { case Object.CONST: E.WriteInt(0); // should be the correct value case Object.TYPE: // nothing to do case Object.VAR: E.WriteInt(0); // should be the correct address/offset case Object.FUNC: E.WriteInt(0); // should be the correct address/offset default: panic "UNREACHABLE"; } } } func (E *Exporter) WriteType(typ *Globals.Type) { if typ.ref >= 0 { E.WriteTypeTag(typ.ref); // type already exported return; } if -typ.form >= 0 { panic "-typ.form >= 0"; // conflict with ref numbers } 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); E.WritePackage(E.comp.pkgs[typ.obj.pnolev]); } else { E.WriteString(""); } switch typ.form { case Type.ARRAY: E.WriteInt(typ.len_); E.WriteType(typ.elt); case Type.MAP: E.WriteType(typ.key); E.WriteType(typ.elt); case Type.CHANNEL: E.WriteInt(typ.flags); E.WriteType(typ.elt); case Type.FUNCTION: E.WriteInt(typ.flags); E.WriteScope(typ.scope); case Type.STRUCT, Type.INTERFACE: E.WriteScope(typ.scope); case Type.POINTER, Type.REFERENCE: E.WriteType(typ.elt); default: panic "UNREACHABLE"; } } func (E *Exporter) WritePackage(pkg *Globals.Package) { if pkg.ref >= 0 { E.WritePackageTag(pkg.ref); // package already exported return; } if -Object.PACKAGE >= 0 { panic "-Object.PACKAGE >= 0"; // conflict with ref numbers } E.WritePackageTag(-Object.PACKAGE); pkg.ref = E.pkg_ref; E.pkg_ref++; E.WriteString(pkg.obj.ident); E.WriteString(pkg.file_name); E.WriteString(pkg.key); } func (E *Exporter) Export(comp* Globals.Compilation, file_name string) { E.comp = comp; E.debug = comp.flags.debug; E.buf_pos = 0; E.pkg_ref = 0; E.type_ref = 0; if E.debug { print "exporting to ", file_name, "\n"; } // 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 { panic "incorrect ref for predeclared type"; } i++; } } E.type_ref = Universe.types.len_; pkg := comp.pkgs[0]; E.WritePackage(pkg); E.WriteScope(pkg.scope); if E.debug { print "\n(", E.buf_pos, " bytes)\n"; } data := string(E.buf)[0 : E.buf_pos]; ok := sys.writefile(file_name, data); if !ok { panic "export failed"; } } export Export func Export(comp* Globals.Compilation, pkg_name string) { var E Exporter; (&E).Export(comp, Utils.FixExt(Utils.BaseName(pkg_name))); }