mirror of https://github.com/go-python/gopy.git
419 lines
7.7 KiB
Go
419 lines
7.7 KiB
Go
// Copyright 2015 The go-python 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 bind
|
|
|
|
import (
|
|
"fmt"
|
|
"go/types"
|
|
)
|
|
|
|
type Object interface {
|
|
Package() *Package
|
|
ID() string
|
|
Doc() string
|
|
GoName() string
|
|
}
|
|
|
|
type Type interface {
|
|
Object
|
|
GoType() types.Type
|
|
}
|
|
|
|
func needWrapType(typ types.Type) bool {
|
|
switch typ := typ.(type) {
|
|
case *types.Basic:
|
|
return false
|
|
case *types.Struct:
|
|
return true
|
|
case *types.Named:
|
|
switch ut := typ.Underlying().(type) {
|
|
case *types.Basic:
|
|
return false
|
|
default:
|
|
return needWrapType(ut)
|
|
}
|
|
case *types.Array:
|
|
return true
|
|
case *types.Map:
|
|
return true
|
|
case *types.Slice:
|
|
return true
|
|
case *types.Interface:
|
|
wrap := true
|
|
if typ.Underlying() == universe.syms["error"].GoType().Underlying() {
|
|
wrap = false
|
|
}
|
|
return wrap
|
|
case *types.Signature:
|
|
return true
|
|
case *types.Pointer:
|
|
return needWrapType(typ.Elem())
|
|
}
|
|
return false
|
|
}
|
|
|
|
///////////////////////////////////////////////////////////////////////////////////
|
|
// Struct
|
|
|
|
// Protocol encodes the various protocols a python type may implement
|
|
type Protocol int
|
|
|
|
const (
|
|
ProtoStringer Protocol = 1 << iota
|
|
)
|
|
|
|
// Struct collects informations about a go struct.
|
|
type Struct struct {
|
|
pkg *Package
|
|
sym *symbol
|
|
obj *types.TypeName
|
|
|
|
id string
|
|
doc string
|
|
ctors []Func
|
|
meths []Func
|
|
|
|
prots Protocol
|
|
}
|
|
|
|
func newStruct(p *Package, obj *types.TypeName) (Struct, error) {
|
|
sym := p.syms.symtype(obj.Type())
|
|
if sym == nil {
|
|
panic(fmt.Errorf("no such object [%s] in symbols table", obj.Id()))
|
|
}
|
|
sym.doc = p.getDoc("", obj)
|
|
s := Struct{
|
|
pkg: p,
|
|
sym: sym,
|
|
obj: obj,
|
|
}
|
|
return s, nil
|
|
}
|
|
|
|
func (s Struct) Package() *Package {
|
|
return s.pkg
|
|
}
|
|
|
|
func (s Struct) ID() string {
|
|
return s.sym.id
|
|
}
|
|
|
|
func (s Struct) Doc() string {
|
|
return s.sym.doc
|
|
}
|
|
|
|
func (s Struct) GoType() types.Type {
|
|
return s.sym.GoType()
|
|
}
|
|
|
|
func (s Struct) GoName() string {
|
|
return s.sym.goname
|
|
}
|
|
|
|
func (s Struct) Struct() *types.Struct {
|
|
return s.sym.GoType().Underlying().(*types.Struct)
|
|
}
|
|
|
|
///////////////////////////////////////////////////////////////////////////////////
|
|
// Interface
|
|
|
|
// Interface collects informations about a go struct.
|
|
type Interface struct {
|
|
pkg *Package
|
|
sym *symbol
|
|
obj *types.TypeName
|
|
|
|
id string
|
|
doc string
|
|
meths []Func
|
|
}
|
|
|
|
func newInterface(p *Package, obj *types.TypeName) (Interface, error) {
|
|
sym := p.syms.symtype(obj.Type())
|
|
if sym == nil {
|
|
panic(fmt.Errorf("no such object [%s] in symbols table", obj.Id()))
|
|
}
|
|
sym.doc = p.getDoc("", obj)
|
|
s := Interface{
|
|
pkg: p,
|
|
sym: sym,
|
|
obj: obj,
|
|
}
|
|
return s, nil
|
|
}
|
|
|
|
func (s Interface) Package() *Package {
|
|
return s.pkg
|
|
}
|
|
|
|
func (s Interface) ID() string {
|
|
return s.sym.id
|
|
}
|
|
|
|
func (s Interface) Doc() string {
|
|
return s.sym.doc
|
|
}
|
|
|
|
func (s Interface) GoType() types.Type {
|
|
return s.sym.GoType()
|
|
}
|
|
|
|
func (s Interface) GoName() string {
|
|
return s.sym.goname
|
|
}
|
|
|
|
func (s Interface) Interface() *types.Interface {
|
|
return s.sym.GoType().Underlying().(*types.Interface)
|
|
}
|
|
|
|
///////////////////////////////////////////////////////////////////////////////////
|
|
// Signature
|
|
|
|
// A Signature represents a (non-builtin) function or method type.
|
|
type Signature struct {
|
|
ret []*Var
|
|
args []*Var
|
|
recv *Var
|
|
}
|
|
|
|
func newSignatureFrom(pkg *Package, sig *types.Signature) *Signature {
|
|
var recv *Var
|
|
if sig.Recv() != nil {
|
|
recv = newVarFrom(pkg, sig.Recv())
|
|
}
|
|
|
|
return &Signature{
|
|
ret: newVarsFrom(pkg, sig.Results()),
|
|
args: newVarsFrom(pkg, sig.Params()),
|
|
recv: recv,
|
|
}
|
|
}
|
|
|
|
func newSignature(pkg *Package, recv *Var, params, results []*Var) *Signature {
|
|
return &Signature{
|
|
ret: results,
|
|
args: params,
|
|
recv: recv,
|
|
}
|
|
}
|
|
|
|
func (sig *Signature) Results() []*Var {
|
|
return sig.ret
|
|
}
|
|
|
|
func (sig *Signature) Params() []*Var {
|
|
return sig.args
|
|
}
|
|
|
|
func (sig *Signature) Recv() *Var {
|
|
return sig.recv
|
|
}
|
|
|
|
///////////////////////////////////////////////////////////////////////////////////
|
|
// Func
|
|
|
|
// Func collects informations about a go func/method.
|
|
type Func struct {
|
|
pkg *Package
|
|
sig *Signature
|
|
typ types.Type
|
|
name string
|
|
|
|
id string
|
|
doc string
|
|
ret types.Type // return type, if any
|
|
err bool // true if original go func has comma-error
|
|
ctor bool // true if this is a newXXX function
|
|
}
|
|
|
|
func newFuncFrom(p *Package, parent string, obj types.Object, sig *types.Signature) (Func, error) {
|
|
haserr := false
|
|
res := sig.Results()
|
|
var ret types.Type
|
|
|
|
switch res.Len() {
|
|
case 2:
|
|
if !isErrorType(res.At(1).Type()) {
|
|
return Func{}, fmt.Errorf(
|
|
"bind: second result value must be of type error: %s",
|
|
obj,
|
|
)
|
|
}
|
|
haserr = true
|
|
ret = res.At(0).Type()
|
|
|
|
case 1:
|
|
if isErrorType(res.At(0).Type()) {
|
|
haserr = true
|
|
ret = nil
|
|
} else {
|
|
ret = res.At(0).Type()
|
|
}
|
|
case 0:
|
|
ret = nil
|
|
default:
|
|
return Func{}, fmt.Errorf("bind: too many results to return: %v", obj)
|
|
}
|
|
|
|
id := obj.Pkg().Name() + "_" + obj.Name()
|
|
if parent != "" {
|
|
id = obj.Pkg().Name() + "_" + parent + "_" + obj.Name()
|
|
}
|
|
|
|
return Func{
|
|
pkg: p,
|
|
sig: newSignatureFrom(p, sig),
|
|
typ: obj.Type(),
|
|
name: obj.Name(),
|
|
id: id,
|
|
doc: p.getDoc(parent, obj),
|
|
ret: ret,
|
|
err: haserr,
|
|
}, nil
|
|
}
|
|
|
|
func (f Func) Package() *Package {
|
|
return f.pkg
|
|
}
|
|
|
|
func (f Func) ID() string {
|
|
return f.id
|
|
}
|
|
|
|
func (f Func) Doc() string {
|
|
return f.doc
|
|
}
|
|
|
|
func (f Func) GoType() types.Type {
|
|
return f.typ
|
|
}
|
|
|
|
func (f Func) GoName() string {
|
|
return f.name
|
|
}
|
|
|
|
func (f Func) GoFmt() string {
|
|
return f.pkg.Name() + "." + f.name
|
|
}
|
|
|
|
func (f Func) Signature() *Signature {
|
|
return f.sig
|
|
}
|
|
|
|
func (f Func) Return() types.Type {
|
|
return f.ret
|
|
}
|
|
|
|
///////////////////////////////////////////////////////////////////////////////////
|
|
// Const
|
|
|
|
type Const struct {
|
|
pkg *Package
|
|
sym *symbol
|
|
obj *types.Const
|
|
id string
|
|
doc string
|
|
f Func
|
|
}
|
|
|
|
func newConst(p *Package, o *types.Const) Const {
|
|
pkg := o.Pkg()
|
|
sym := p.syms.symtype(o.Type())
|
|
id := pkg.Name() + "_" + o.Name()
|
|
doc := p.getDoc("", o)
|
|
|
|
res := []*Var{newVar(p, o.Type(), "ret", o.Name(), doc)}
|
|
sig := newSignature(p, nil, nil, res)
|
|
fct := Func{
|
|
pkg: p,
|
|
sig: sig,
|
|
typ: nil,
|
|
name: o.Name(),
|
|
id: id + "_get",
|
|
doc: doc,
|
|
ret: o.Type(),
|
|
err: false,
|
|
}
|
|
|
|
return Const{
|
|
pkg: p,
|
|
sym: sym,
|
|
obj: o,
|
|
id: id,
|
|
doc: doc,
|
|
f: fct,
|
|
}
|
|
}
|
|
|
|
func (c Const) ID() string { return c.id }
|
|
func (c Const) Doc() string { return c.doc }
|
|
func (c Const) GoName() string { return c.obj.Name() }
|
|
func (c Const) GoType() types.Type { return c.obj.Type() }
|
|
|
|
///////////////////////////////////////////////////////////////////////////////////
|
|
// Var
|
|
|
|
type Var struct {
|
|
pkg *Package
|
|
sym *symbol // symbol associated with var's type
|
|
id string
|
|
doc string
|
|
name string
|
|
}
|
|
|
|
func (v *Var) Name() string {
|
|
return v.name
|
|
}
|
|
|
|
func newVar(p *Package, typ types.Type, objname, name, doc string) *Var {
|
|
sym := p.syms.symtype(typ)
|
|
if sym == nil {
|
|
panic(fmt.Errorf("could not find symbol for type [%s]!", typ.String()))
|
|
}
|
|
return &Var{
|
|
pkg: p,
|
|
sym: sym,
|
|
id: p.Name() + "_" + objname,
|
|
doc: doc,
|
|
name: name,
|
|
}
|
|
}
|
|
|
|
func newVarsFrom(p *Package, tuple *types.Tuple) []*Var {
|
|
vars := make([]*Var, 0, tuple.Len())
|
|
for i := 0; i < tuple.Len(); i++ {
|
|
vars = append(vars, newVarFrom(p, tuple.At(i)))
|
|
}
|
|
return vars
|
|
}
|
|
|
|
func newVarFrom(p *Package, v *types.Var) *Var {
|
|
return newVar(p, v.Type(), v.Name(), v.Name(), p.getDoc("", v))
|
|
}
|
|
|
|
func getTypeString(t types.Type) string {
|
|
return types.TypeString(t, func(*types.Package) string { return " " })
|
|
}
|
|
|
|
func (v *Var) GoType() types.Type {
|
|
return v.sym.gotyp
|
|
}
|
|
|
|
func (v *Var) CType() string {
|
|
return v.sym.cpyname
|
|
}
|
|
|
|
func (v *Var) CGoType() string {
|
|
return v.sym.cgoname
|
|
}
|
|
|
|
func (v *Var) isGoString() bool {
|
|
switch typ := v.GoType().(type) {
|
|
case *types.Basic:
|
|
return typ.Kind() == types.String
|
|
}
|
|
return false
|
|
}
|