// 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 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) ReadType() *Globals.Type; func (I *Importer) ReadObject() *Globals.Object; func (I *Importer) ReadPackage() *Globals.Package; 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) ReadObjectTag() int { tag := I.ReadInt(); if tag < 0 { panic "tag < 0"; } if I.debug { print "\n", Object.KindStr(tag); } 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) 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) ReadScope() *Globals.Scope { if I.debug { print " {"; } scope := Globals.NewScope(nil); obj := I.ReadObject(); for obj != nil { scope.InsertImport(obj); obj = I.ReadObject(); } if I.debug { print " }"; } return scope; } func (I *Importer) ReadObject() *Globals.Object { tag := I.ReadObjectTag(); if tag == Object.END { return nil; } if tag == Object.TYPE { // named types are always primary types // and handled entirely by ReadType() typ := I.ReadType(); if typ.obj.typ != typ { panic "inconsistent primary type"; } return typ.obj; } ident := I.ReadString(); obj := Globals.NewObject(0, tag, ident); 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) 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 { // primary 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.ALIAS: typ.elt = I.ReadType(); case Type.ARRAY: typ.len_ = I.ReadInt(); typ.elt = I.ReadType(); case Type.MAP: typ.key = I.ReadType(); typ.elt = I.ReadType(); case Type.CHANNEL: typ.flags = I.ReadInt(); typ.elt = I.ReadType(); case Type.FUNCTION: typ.flags = I.ReadInt(); typ.scope = I.ReadScope(); case Type.STRUCT, Type.INTERFACE: typ.scope = I.ReadScope(); case Type.POINTER, Type.REFERENCE: typ.elt = I.ReadType(); default: panic "UNREACHABLE"; } return ptyp; // only use primary type } 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(); pkg := I.comp.Lookup(file_name); if pkg == nil { // new package obj := Globals.NewObject(-1, Object.PACKAGE, ident); pkg = Globals.NewPackage(file_name, obj); pkg.scope = Globals.NewScope(nil); pkg = I.comp.InsertImport(pkg); } else if key != pkg.key { // package inconsistency panic "package key inconsistency"; } I.pkg_list[I.pkg_ref] = pkg; I.pkg_ref++; return pkg; } func (I *Importer) Import(comp* Globals.Compilation, file_name string) *Globals.Package { I.comp = comp; I.debug = comp.flags.debug; I.buf = ""; I.buf_pos = 0; I.pkg_ref = 0; I.type_ref = 0; if I.debug { print "importing from ", file_name, "\n"; } buf, ok := sys.readfile(file_name); if !ok { return nil; } I.buf = buf; // 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++; } pkg := I.ReadPackage(); obj := I.ReadObject(); for obj != nil { obj.pnolev = pkg.obj.pnolev; pkg.scope.InsertImport(obj); obj = I.ReadObject(); } if I.debug { print "\n(", I.buf_pos, " bytes)\n"; } return pkg; } export Import func Import(comp* Globals.Compilation, pkg_name string) *Globals.Package { var I Importer; return (&I).Import(comp, Utils.FixExt(pkg_name)); }