Ejemplo n.º 1
0
func (e *exporter) addImport(pkg *types.Package) {
	if _, found := e.imports[pkg]; found {
		return
	}
	fmt.Fprintf(e.out, "import %s \"%s\"\n", pkg.Name(), pkg.Path())
	e.imports[pkg] = true
}
Ejemplo n.º 2
0
Archivo: exports.go Proyecto: pcc/llgo
func (x *exporter) export(pkg *types.Package) error {
	x.pkg = pkg
	x.writeFunc = true
	exportsFile := packageExportsFile(x.context, pkg.Path())
	err := os.MkdirAll(filepath.Dir(exportsFile), 0755)
	if err != nil && !os.IsExist(err) {
		return err
	}
	f2, err := os.Create(exportsFile)
	if err != nil {
		return err
	}
	defer f2.Close()
	x.writer = f2
	x.write("package %s\n", pkg.Name())
	for _, imp := range pkg.Imports() {
		x.write("\timport %s \"%s\"\n", imp.Name(), imp.Path())
	}
	for _, n := range pkg.Scope().Names() {
		if obj := pkg.Scope().Lookup(n); obj != nil {
			x.exportObject(obj)
		}
	}
	x.write("$$")
	return nil
}
Ejemplo n.º 3
0
// pkgpath returns a package path suitable for naming symbols.
func pkgpath(p *types.Package) string {
	path := p.Path()
	name := p.Name()
	if path == "" || name == "main" {
		path = p.Name()
	}
	return path
}
Ejemplo n.º 4
0
func typePackageToJson(p *types.Package) interface{} {
	if p == nil {
		return nil
	} else {
		return struct {
			Isa, Name, ImportPath string
		}{
			"Package", p.Name(), p.Path(),
		}
	}
}
Ejemplo n.º 5
0
// pkgString returns a string representation of a package's exported interface.
func pkgString(pkg *types.Package) string {
	var buf bytes.Buffer

	fmt.Fprintf(&buf, "package %s\n", pkg.Name())

	scope := pkg.Scope()
	for _, name := range scope.Names() {
		if exported(name) {
			obj := scope.Lookup(name)
			buf.WriteString(obj.String())

			switch obj := obj.(type) {
			case *types.Const:
				// For now only print constant values if they are not float
				// or complex. This permits comparing go/types results with
				// gc-generated gcimported package interfaces.
				info := obj.Type().Underlying().(*types.Basic).Info()
				if info&types.IsFloat == 0 && info&types.IsComplex == 0 {
					fmt.Fprintf(&buf, " = %s", obj.Val())
				}

			case *types.TypeName:
				// Print associated methods.
				// Basic types (e.g., unsafe.Pointer) have *types.Basic
				// type rather than *types.Named; so we need to check.
				if typ, _ := obj.Type().(*types.Named); typ != nil {
					if n := typ.NumMethods(); n > 0 {
						// Sort methods by name so that we get the
						// same order independent of whether the
						// methods got imported or coming directly
						// for the source.
						// TODO(gri) This should probably be done
						// in go/types.
						list := make([]*types.Func, n)
						for i := 0; i < n; i++ {
							list[i] = typ.Method(i)
						}
						sort.Sort(byName(list))

						buf.WriteString("\nmethods (\n")
						for _, m := range list {
							fmt.Fprintf(&buf, "\t%s\n", m)
						}
						buf.WriteString(")")
					}
				}
			}
			buf.WriteByte('\n')
		}
	}

	return buf.String()
}
Ejemplo n.º 6
0
func testExportImport(t *testing.T, pkg0 *types.Package, path string) (size, gcsize int) {
	data := ExportData(pkg0)
	size = len(data)

	imports := make(map[string]*types.Package)
	n, pkg1, err := ImportData(imports, data)
	if err != nil {
		t.Errorf("package %s: import failed: %s", pkg0.Name(), err)
		return
	}
	if n != size {
		t.Errorf("package %s: not all input data consumed", pkg0.Name())
		return
	}

	s0 := pkgString(pkg0)
	s1 := pkgString(pkg1)
	if s1 != s0 {
		t.Errorf("package %s: \nimport got:\n%s\nwant:\n%s\n", pkg0.Name(), s1, s0)
	}

	// If we have a standard library, compare also against the gcimported package.
	if path == "" {
		return // not std library
	}

	gcdata, err := gcExportData(path)
	gcsize = len(gcdata)

	imports = make(map[string]*types.Package)
	pkg2, err := gcImportData(imports, gcdata, path)
	if err != nil {
		t.Errorf("package %s: gcimport failed: %s", pkg0.Name(), err)
		return
	}

	s2 := pkgString(pkg2)
	if s2 != s0 {
		t.Errorf("package %s: \ngcimport got:\n%s\nwant:\n%s\n", pkg0.Name(), s2, s0)
	}

	return
}
Ejemplo n.º 7
0
func (p *exporter) pkg(pkg *types.Package) {
	if trace {
		p.tracef("package { ")
		defer p.tracef("} ")
	}

	if pkg == nil {
		panic("unexpected nil pkg")
	}

	// if the package was seen before, write its index (>= 0)
	if i, ok := p.pkgIndex[pkg]; ok {
		p.int(i)
		return
	}
	p.pkgIndex[pkg] = len(p.pkgIndex)

	// otherwise, write the package tag (< 0) and package data
	p.int(packageTag)
	p.string(pkg.Name())
	p.string(pkg.Path())
}
Ejemplo n.º 8
0
// ExportData serializes the interface (exported package objects)
// of package pkg and returns the corresponding data. The export
// format is described elsewhere (TODO).
func ExportData(pkg *types.Package) []byte {
	p := exporter{
		data:     []byte(magic),
		pkgIndex: make(map[*types.Package]int),
		typIndex: make(map[types.Type]int),
	}

	// populate typIndex with predeclared types
	for _, t := range types.Typ[1:] {
		p.typIndex[t] = len(p.typIndex)
	}
	p.typIndex[types.Universe.Lookup("error").Type()] = len(p.typIndex)

	if trace {
		p.tracef("export %s\n", pkg.Name())
		defer p.tracef("\n")
	}

	p.string(version)

	p.pkg(pkg)

	// collect exported objects from package scope
	var list []types.Object
	scope := pkg.Scope()
	for _, name := range scope.Names() {
		if exported(name) {
			list = append(list, scope.Lookup(name))
		}
	}

	// write objects
	p.int(len(list))
	for _, obj := range list {
		p.obj(obj)
	}

	return p.data
}
Ejemplo n.º 9
0
func (c *exporter) Export(pkg *types.Package) error {
	c.pkg = pkg
	c.writeFunc = true
	f2, err := os.Create(c.compiler.packageExportsFile(pkg.Path()))
	if err != nil {
		return err
	}
	defer f2.Close()
	c.writer = f2
	c.write("package %s\n", pkg.Name())
	for _, imp := range c.pkg.Imports() {
		c.write("\timport %s \"%s\"\n", imp.Name(), imp.Path())
	}

	for _, n := range pkg.Scope().Names() {
		if obj := pkg.Scope().Lookup(n); obj != nil {
			c.exportObject(obj)
		}
	}

	c.write("$$")
	return nil
}
Ejemplo n.º 10
0
func (p *printer) printPackage(pkg *types.Package, filter func(types.Object) bool) {
	// collect objects by kind
	var (
		consts   []*types.Const
		typem    []*types.Named    // non-interface types with methods
		typez    []*types.TypeName // interfaces or types without methods
		vars     []*types.Var
		funcs    []*types.Func
		builtins []*types.Builtin
		methods  = make(map[*types.Named][]*types.Selection) // method sets for named types
	)
	scope := pkg.Scope()
	for _, name := range scope.Names() {
		obj := scope.Lookup(name)
		if obj.Exported() {
			// collect top-level exported and possibly filtered objects
			if filter == nil || filter(obj) {
				switch obj := obj.(type) {
				case *types.Const:
					consts = append(consts, obj)
				case *types.TypeName:
					// group into types with methods and types without
					if named, m := methodsFor(obj); named != nil {
						typem = append(typem, named)
						methods[named] = m
					} else {
						typez = append(typez, obj)
					}
				case *types.Var:
					vars = append(vars, obj)
				case *types.Func:
					funcs = append(funcs, obj)
				case *types.Builtin:
					// for unsafe.Sizeof, etc.
					builtins = append(builtins, obj)
				}
			}
		} else if filter == nil {
			// no filtering: collect top-level unexported types with methods
			if obj, _ := obj.(*types.TypeName); obj != nil {
				// see case *types.TypeName above
				if named, m := methodsFor(obj); named != nil {
					typem = append(typem, named)
					methods[named] = m
				}
			}
		}
	}

	p.printf("package %s  // %q\n", pkg.Name(), pkg.Path())

	p.printDecl("const", len(consts), func() {
		for _, obj := range consts {
			p.printObj(obj)
			p.print("\n")
		}
	})

	p.printDecl("var", len(vars), func() {
		for _, obj := range vars {
			p.printObj(obj)
			p.print("\n")
		}
	})

	p.printDecl("type", len(typez), func() {
		for _, obj := range typez {
			p.printf("%s ", obj.Name())
			p.writeType(p.pkg, obj.Type().Underlying())
			p.print("\n")
		}
	})

	// non-interface types with methods
	for _, named := range typem {
		first := true
		if obj := named.Obj(); obj.Exported() {
			if first {
				p.print("\n")
				first = false
			}
			p.printf("type %s ", obj.Name())
			p.writeType(p.pkg, named.Underlying())
			p.print("\n")
		}
		for _, m := range methods[named] {
			if obj := m.Obj(); obj.Exported() {
				if first {
					p.print("\n")
					first = false
				}
				p.printFunc(m.Recv(), obj.(*types.Func))
				p.print("\n")
			}
		}
	}

	if len(funcs) > 0 {
		p.print("\n")
		for _, obj := range funcs {
			p.printFunc(nil, obj)
			p.print("\n")
		}
	}

	// TODO(gri) better handling of builtins (package unsafe only)
	if len(builtins) > 0 {
		p.print("\n")
		for _, obj := range builtins {
			p.printf("func %s() // builtin\n", obj.Name())
		}
	}

	p.print("\n")
}
Ejemplo n.º 11
0
func (p *printer) printPackage(pkg *types.Package, filter func(types.Object) bool) {
	// collect objects by kind
	var (
		consts   []*types.Const
		typez    []*types.TypeName // types without methods
		typem    []*types.TypeName // types with methods
		vars     []*types.Var
		funcs    []*types.Func
		builtins []*types.Builtin
	)
	scope := pkg.Scope()
	for _, name := range scope.Names() {
		obj := scope.Lookup(name)
		if !filter(obj) {
			continue
		}
		switch obj := obj.(type) {
		case *types.Const:
			consts = append(consts, obj)
		case *types.TypeName:
			if named, _ := obj.Type().(*types.Named); named != nil && named.NumMethods() > 0 {
				typem = append(typem, obj)
			} else {
				typez = append(typez, obj)
			}
		case *types.Var:
			vars = append(vars, obj)
		case *types.Func:
			funcs = append(funcs, obj)
		case *types.Builtin:
			// for unsafe.Sizeof, etc.
			builtins = append(builtins, obj)
		}
	}

	p.printf("package %s  // %q\n\n", pkg.Name(), pkg.Path())

	if len(consts) > 0 {
		p.print("const (\n")
		p.indent++
		for _, obj := range consts {
			p.printObj(obj)
			p.print("\n")
		}
		p.indent--
		p.print(")\n\n")
	}

	if len(vars) > 0 {
		p.print("var (\n")
		p.indent++
		for _, obj := range vars {
			p.printObj(obj)
			p.print("\n")
		}
		p.indent--
		p.print(")\n\n")
	}

	if len(typez) > 0 {
		p.print("type (\n")
		p.indent++
		for _, obj := range typez {
			p.printf("%s ", obj.Name())
			p.writeType(p.pkg, obj.Type().Underlying())
			p.print("\n")
		}
		p.indent--
		p.print(")\n\n")
	}

	for _, obj := range typem {
		p.printf("type %s ", obj.Name())
		typ := obj.Type().(*types.Named)
		p.writeType(p.pkg, typ.Underlying())
		p.print("\n")
		for i, n := 0, typ.NumMethods(); i < n; i++ {
			p.printFunc(typ.Method(i))
			p.print("\n")
		}
		p.print("\n")
	}

	for _, obj := range funcs {
		p.printFunc(obj)
		p.print("\n")
	}

	// TODO(gri) better handling of builtins (package unsafe only)
	for _, obj := range builtins {
		p.printf("func %s() // builtin\n", obj.Name())
	}

	p.print("\n")
}
Ejemplo n.º 12
0
func Write(pkg *types.Package, out io.Writer, sizes types.Sizes) {
	fmt.Fprintf(out, "package %s\n", pkg.Name())

	e := &exporter{pkg: pkg, imports: make(map[*types.Package]bool), out: out}

	for _, imp := range pkg.Imports() {
		e.addImport(imp)
	}

	for _, name := range pkg.Scope().Names() {
		obj := pkg.Scope().Lookup(name)

		_, isTypeName := obj.(*types.TypeName)
		if obj.Exported() || isTypeName {
			e.toExport = append(e.toExport, obj)
		}
	}

	for i := 0; i < len(e.toExport); i++ {
		switch o := e.toExport[i].(type) {
		case *types.TypeName:
			fmt.Fprintf(out, "type %s %s\n", e.makeName(o), e.makeType(o.Type().Underlying()))
			if _, isInterface := o.Type().Underlying().(*types.Interface); !isInterface {
				writeMethods := func(t types.Type) {
					methods := types.NewMethodSet(t)
					for i := 0; i < methods.Len(); i++ {
						m := methods.At(i)
						if len(m.Index()) > 1 {
							continue // method of embedded field
						}
						out.Write([]byte("func (? " + e.makeType(m.Recv()) + ") " + e.makeName(m.Obj()) + e.makeSignature(m.Type()) + "\n"))
					}
				}
				writeMethods(o.Type())
				writeMethods(types.NewPointer(o.Type()))
			}
		case *types.Func:
			out.Write([]byte("func " + e.makeName(o) + e.makeSignature(o.Type()) + "\n"))
		case *types.Const:
			optType := ""
			basic, isBasic := o.Type().(*types.Basic)
			if !isBasic || basic.Info()&types.IsUntyped == 0 {
				optType = " " + e.makeType(o.Type())
			}

			basic = o.Type().Underlying().(*types.Basic)
			var val string
			switch {
			case basic.Info()&types.IsBoolean != 0:
				val = strconv.FormatBool(exact.BoolVal(o.Val()))
			case basic.Info()&types.IsInteger != 0:
				if basic.Kind() == types.Uint64 {
					d, _ := exact.Uint64Val(o.Val())
					val = fmt.Sprintf("%#x", d)
					break
				}
				d, _ := exact.Int64Val(o.Val())
				if basic.Kind() == types.UntypedRune {
					switch {
					case d < 0 || d > unicode.MaxRune:
						val = fmt.Sprintf("('\\x00' + %d)", d)
					case d > 0xffff:
						val = fmt.Sprintf("'\\U%08x'", d)
					default:
						val = fmt.Sprintf("'\\u%04x'", d)
					}
					break
				}
				val = fmt.Sprintf("%#x", d)
			case basic.Info()&types.IsFloat != 0:
				f, _ := exact.Float64Val(o.Val())
				val = strconv.FormatFloat(f, 'b', -1, 64)
			case basic.Info()&types.IsComplex != 0:
				r, _ := exact.Float64Val(exact.Real(o.Val()))
				i, _ := exact.Float64Val(exact.Imag(o.Val()))
				val = fmt.Sprintf("(%s+%si)", strconv.FormatFloat(r, 'b', -1, 64), strconv.FormatFloat(i, 'b', -1, 64))
			case basic.Info()&types.IsString != 0:
				val = fmt.Sprintf("%#v", exact.StringVal(o.Val()))
			default:
				panic("Unhandled constant type: " + basic.String())
			}
			out.Write([]byte("const " + e.makeName(o) + optType + " = " + val + "\n"))
		case *types.Var:
			out.Write([]byte("var " + e.makeName(o) + " " + e.makeType(o.Type()) + "\n"))
		default:
			panic(fmt.Sprintf("Unhandled object: %T\n", o))
		}
	}

	fmt.Fprintf(out, "$$\n")
}