| // 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 := uint(0); |
| 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, Object.FIELD: |
| 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; |
| } |