mirror of
https://github.com/golang/go
synced 2024-11-19 06:04:39 -07:00
40c93a5238
- adjusted switch syntax (no repeated case: case: anymore) - enabled some constant expressions that work now R=r OCL=14098 CL=14098
316 lines
6.1 KiB
Go
Executable File
316 lines
6.1 KiB
Go
Executable File
// 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 Importer
|
|
|
|
import Platform "platform"
|
|
import Utils "utils"
|
|
import Globals "globals"
|
|
import Object "object"
|
|
import Type "type"
|
|
import Universe "universe"
|
|
|
|
|
|
type Importer struct {
|
|
comp *Globals.Compilation;
|
|
debug bool;
|
|
buf string;
|
|
buf_pos int;
|
|
pkg_list [256] *Globals.Package;
|
|
pkg_ref int;
|
|
type_list [1024] *Globals.Type;
|
|
type_ref int;
|
|
};
|
|
|
|
|
|
func (I *Importer) ReadObject() *Globals.Object;
|
|
|
|
|
|
func (I *Importer) ReadByte() byte {
|
|
x := I.buf[I.buf_pos];
|
|
I.buf_pos++;
|
|
/*
|
|
if E.debug {
|
|
print " ", x;
|
|
}
|
|
*/
|
|
return x;
|
|
}
|
|
|
|
|
|
func (I *Importer) ReadInt() int {
|
|
x := 0;
|
|
s := 0; // TODO eventually Go will require this to be a uint!
|
|
b := I.ReadByte();
|
|
for b < 128 {
|
|
x |= int(b) << s;
|
|
s += 7;
|
|
b = I.ReadByte();
|
|
}
|
|
// b >= 128
|
|
x |= ((int(b) - 192) << s);
|
|
/*
|
|
if I.debug {
|
|
print " #", x;
|
|
}
|
|
*/
|
|
return x;
|
|
}
|
|
|
|
|
|
func (I *Importer) ReadString() string {
|
|
var buf [256] byte; // TODO this needs to be fixed
|
|
n := I.ReadInt();
|
|
for i := 0; i < n; i++ {
|
|
buf[i] = I.ReadByte();
|
|
}
|
|
s := string(buf)[0 : n];
|
|
if I.debug {
|
|
print ` "`, s, `"`;
|
|
}
|
|
return s;
|
|
}
|
|
|
|
|
|
func (I *Importer) ReadPackageTag() int {
|
|
tag := I.ReadInt();
|
|
if I.debug {
|
|
if tag >= 0 {
|
|
print " [P", tag, "]"; // package ref
|
|
} else {
|
|
print "\nP", I.pkg_ref, ":";
|
|
}
|
|
}
|
|
return tag;
|
|
}
|
|
|
|
|
|
func (I *Importer) ReadTypeTag() int {
|
|
tag := I.ReadInt();
|
|
if I.debug {
|
|
if tag >= 0 {
|
|
print " [T", tag, "]"; // type ref
|
|
} else {
|
|
print "\nT", I.type_ref, ": ", Type.FormStr(-tag);
|
|
}
|
|
}
|
|
return tag;
|
|
}
|
|
|
|
|
|
func (I *Importer) ReadObjectTag() int {
|
|
tag := I.ReadInt();
|
|
if tag < 0 {
|
|
panic "tag < 0";
|
|
}
|
|
if I.debug {
|
|
print "\n", Object.KindStr(tag);
|
|
}
|
|
return tag;
|
|
}
|
|
|
|
|
|
func (I *Importer) ReadPackage() *Globals.Package {
|
|
tag := I.ReadPackageTag();
|
|
if tag >= 0 {
|
|
return I.pkg_list[tag]; // package already imported
|
|
}
|
|
|
|
ident := I.ReadString();
|
|
file_name := I.ReadString();
|
|
key := I.ReadString();
|
|
|
|
// Canonicalize package - if it was imported before,
|
|
// use the primary import.
|
|
pkg := I.comp.Lookup(file_name);
|
|
if pkg == nil {
|
|
// new package
|
|
obj := Globals.NewObject(-1, Object.PACKAGE, ident);
|
|
pkg = Globals.NewPackage(file_name, obj, Globals.NewScope(nil));
|
|
I.comp.Insert(pkg);
|
|
if I.comp.flags.verbosity > 1 {
|
|
print `import: implicitly adding package `, ident, ` "`, file_name, `" (pno = `, obj.pnolev, ")\n";
|
|
}
|
|
} else if key != "" && key != pkg.key {
|
|
// the package was imported before but the package
|
|
// key has changed (a "" key indicates a forward-
|
|
// declared package - it's key is consistent with
|
|
// any actual package of the same name)
|
|
panic "package key inconsistency";
|
|
}
|
|
I.pkg_list[I.pkg_ref] = pkg;
|
|
I.pkg_ref++;
|
|
|
|
return pkg;
|
|
}
|
|
|
|
|
|
func (I *Importer) ReadScope(scope *Globals.Scope, allow_multiples bool) {
|
|
if I.debug {
|
|
print " {";
|
|
}
|
|
|
|
obj := I.ReadObject();
|
|
for obj != nil {
|
|
// allow_multiples is for debugging only - we should never
|
|
// have multiple imports where we don't expect them
|
|
if allow_multiples {
|
|
scope.InsertImport(obj);
|
|
} else {
|
|
scope.Insert(obj);
|
|
}
|
|
obj = I.ReadObject();
|
|
}
|
|
|
|
if I.debug {
|
|
print " }";
|
|
}
|
|
}
|
|
|
|
|
|
func (I *Importer) ReadType() *Globals.Type {
|
|
tag := I.ReadTypeTag();
|
|
if tag >= 0 {
|
|
return I.type_list[tag]; // type already imported
|
|
}
|
|
|
|
typ := Globals.NewType(-tag);
|
|
ptyp := typ; // primary type
|
|
|
|
ident := I.ReadString();
|
|
if len(ident) > 0 {
|
|
// named type
|
|
pkg := I.ReadPackage();
|
|
|
|
// create corresponding type object
|
|
obj := Globals.NewObject(0, Object.TYPE, ident);
|
|
obj.exported = true;
|
|
obj.typ = typ;
|
|
obj.pnolev = pkg.obj.pnolev;
|
|
typ.obj = obj;
|
|
|
|
// canonicalize type
|
|
// (if the type was seen before, use primary instance!)
|
|
ptyp = pkg.scope.InsertImport(obj).typ;
|
|
}
|
|
// insert the primary type into the type table but
|
|
// keep filling in the current type fields
|
|
I.type_list[I.type_ref] = ptyp;
|
|
I.type_ref++;
|
|
|
|
switch (typ.form) {
|
|
case Type.FORWARD:
|
|
typ.scope = Globals.NewScope(nil);
|
|
break;
|
|
|
|
case Type.ALIAS, Type.MAP:
|
|
typ.aux = I.ReadType();
|
|
typ.elt = I.ReadType();
|
|
|
|
case Type.ARRAY:
|
|
typ.len_ = I.ReadInt();
|
|
typ.elt = I.ReadType();
|
|
|
|
case Type.CHANNEL:
|
|
typ.flags = I.ReadInt();
|
|
typ.elt = I.ReadType();
|
|
|
|
case Type.FUNCTION:
|
|
typ.flags = I.ReadInt();
|
|
typ.scope = Globals.NewScope(nil);
|
|
I.ReadScope(typ.scope, false);
|
|
|
|
case Type.STRUCT, Type.INTERFACE:
|
|
typ.scope = Globals.NewScope(nil);
|
|
I.ReadScope(typ.scope, false);
|
|
|
|
case Type.POINTER, Type.REFERENCE:
|
|
typ.elt = I.ReadType();
|
|
|
|
default:
|
|
panic "UNREACHABLE";
|
|
}
|
|
|
|
return ptyp; // only use primary type
|
|
}
|
|
|
|
|
|
func (I *Importer) ReadObject() *Globals.Object {
|
|
tag := I.ReadObjectTag();
|
|
if tag == Object.END {
|
|
return nil;
|
|
}
|
|
|
|
if tag == Object.TYPE {
|
|
// named types are handled entirely by ReadType()
|
|
typ := I.ReadType();
|
|
if typ.obj.typ != typ {
|
|
panic "inconsistent named type";
|
|
}
|
|
return typ.obj;
|
|
}
|
|
|
|
ident := I.ReadString();
|
|
obj := Globals.NewObject(0, tag, ident);
|
|
obj.exported = true;
|
|
obj.typ = I.ReadType();
|
|
|
|
switch (tag) {
|
|
case Object.CONST:
|
|
I.ReadInt(); // should set the value field
|
|
|
|
case Object.VAR:
|
|
I.ReadInt(); // should set the address/offset field
|
|
|
|
case Object.FUNC:
|
|
I.ReadInt(); // should set the address/offset field
|
|
|
|
default:
|
|
panic "UNREACHABLE";
|
|
}
|
|
|
|
return obj;
|
|
}
|
|
|
|
|
|
func (I *Importer) Import(comp* Globals.Compilation, data string) *Globals.Package {
|
|
I.comp = comp;
|
|
I.debug = comp.flags.debug;
|
|
I.buf = data;
|
|
I.buf_pos = 0;
|
|
I.pkg_ref = 0;
|
|
I.type_ref = 0;
|
|
|
|
// check magic bits
|
|
if !Utils.Contains(data, Platform.MAGIC_obj_file, 0) {
|
|
return nil;
|
|
}
|
|
|
|
// Predeclared types are "pre-imported".
|
|
for p := Universe.types.first; p != nil; p = p.next {
|
|
if p.typ.ref != I.type_ref {
|
|
panic "incorrect ref for predeclared type";
|
|
}
|
|
I.type_list[I.type_ref] = p.typ;
|
|
I.type_ref++;
|
|
}
|
|
|
|
// import package
|
|
pkg := I.ReadPackage();
|
|
I.ReadScope(pkg.scope, true);
|
|
|
|
if I.debug {
|
|
print "\n(", I.buf_pos, " bytes)\n";
|
|
}
|
|
|
|
return pkg;
|
|
}
|
|
|
|
|
|
export func Import(comp *Globals.Compilation, data string) *Globals.Package {
|
|
var I Importer;
|
|
pkg := (&I).Import(comp, data);
|
|
return pkg;
|
|
}
|