// 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 Globals "globals" import Object "object" import Type "type" import Universe "universe" type Importer struct { comp *Globals.Compilation; debug bool; buf string; pos int; pkgs [256] *Globals.Package; npkgs int; types [1024] *Globals.Type; ntypes int; }; func (I *Importer) ReadType() *Globals.Type; func (I *Importer) ReadObject(tag int) *Globals.Object; func (I *Importer) ReadPackage() *Globals.Package; func (I *Importer) ReadByte() byte { x := I.buf[I.pos]; I.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) ReadObjTag() int { tag := I.ReadInt(); if tag < 0 { panic "tag < 0"; } if I.debug { print "\nObj: ", tag; // obj kind } return tag; } func (I *Importer) ReadTypeTag() int { tag := I.ReadInt(); if I.debug { if tag > 0 { print "\nTyp ", I.ntypes, ": ", tag; // type form } else { print " [Typ ", -tag, "]"; // type ref } } return tag; } func (I *Importer) ReadPackageTag() int { tag := I.ReadInt(); if I.debug { if tag > 0 { print "\nPkg ", I.npkgs, ": ", tag; // package tag } else { print " [Pkg ", -tag, "]"; // package ref } } return tag; } func (I *Importer) ReadTypeField() *Globals.Object { fld := Globals.NewObject(0, Object.VAR, ""); fld.typ = I.ReadType(); return fld; } func (I *Importer) ReadScope() *Globals.Scope { if I.debug { print " {"; } scope := Globals.NewScope(nil); for n := I.ReadInt(); n > 0; n-- { tag := I.ReadObjTag(); scope.Insert(I.ReadObject(tag)); } if I.debug { print " }"; } } func (I *Importer) ReadObject(tag int) *Globals.Object { if tag == Object.PTYPE { // primary type object - handled entirely by ReadType() typ := I.ReadType(); if typ.obj.typ != typ { panic "incorrect primary type"; } return typ.obj; } else { ident := I.ReadString(); obj := Globals.NewObject(0, tag, ident); obj.typ = I.ReadType(); obj.pnolev = I.ReadPackage().obj.pnolev; switch (tag) { default: fallthrough; case Object.BAD: fallthrough; case Object.PACKAGE: fallthrough; case Object.PTYPE: panic "UNREACHABLE"; case Object.CONST: I.ReadInt(); // should set the value field case Object.TYPE: // nothing to do case Object.VAR: I.ReadInt(); // should set the address/offset field case Object.FUNC: I.ReadInt(); // should set the address/offset field } return obj; } } func (I *Importer) ReadType() *Globals.Type { tag := I.ReadTypeTag(); if tag <= 0 { return I.types[-tag]; // type already imported } typ := Globals.NewType(tag); ptyp := typ; // primary type ident := I.ReadString(); if (len(ident) > 0) { // primary type obj := Globals.NewObject(0, Object.TYPE, ident); obj.typ = typ; typ.obj = obj; // canonicalize type pkg := I.ReadPackage(); obj.pnolev = pkg.obj.pnolev; obj = pkg.scope.InsertImport(obj); ptyp = obj.typ; } I.types[I.ntypes] = ptyp; I.ntypes++; switch (tag) { default: fallthrough; case Type.UNDEF: fallthrough; case Type.BAD: fallthrough; case Type.NIL: fallthrough; case Type.BOOL: fallthrough; case Type.UINT: fallthrough; case Type.INT: fallthrough; case Type.FLOAT: fallthrough; case Type.STRING: fallthrough; case Type.ANY: panic "UNREACHABLE"; 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(); fallthrough; case Type.STRUCT: fallthrough; case Type.INTERFACE: typ.scope = I.ReadScope(); case Type.POINTER: fallthrough; case Type.REFERENCE: typ.elt = I.ReadType(); } return ptyp; // only use primary type } func (I *Importer) ReadPackage() *Globals.Package { tag := I.ReadPackageTag(); if (tag <= 0) { return I.pkgs[-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 pkg = Globals.NewPackage(file_name); pkg.scope = Globals.NewScope(nil); pkg = I.comp.InsertImport(pkg); } else if (key != pkg.key) { // package inconsistency panic "package key inconsistency"; } I.pkgs[I.npkgs] = pkg; I.npkgs++; return pkg; } func (I *Importer) Import(comp* Globals.Compilation, file_name string) { if I.debug { print "importing from ", file_name; } buf, ok := sys.readfile(file_name); if !ok { panic "import failed"; } I.comp = comp; I.debug = true; I.buf = buf; I.pos = 0; I.npkgs = 0; I.ntypes = 0; // Predeclared types are "pre-exported". for p := Universe.types.first; p != nil; p = p.next { if p.typ.ref != I.ntypes { panic "incorrect ref for predeclared type"; } I.types[I.ntypes] = p.typ; I.ntypes++; } pkg := I.ReadPackage(); for { tag := I.ReadObjTag(); if tag == 0 { break; } obj := I.ReadObject(tag); obj.pnolev = pkg.obj.pnolev; pkg.scope.InsertImport(obj); } if I.debug { print "\n(", I.pos, " bytes)\n"; } }