// Copyright 2016 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" ) func (g *goGen) genStruct(s Type) { //fmt.Printf("obj: %#v\ntyp: %#v\n", obj, typ) typ := s.Struct() g.Printf("\n// --- wrapping %s ---\n\n", s.sym.gofmt()) recv := newVar(s.pkg, types.NewPointer(s.GoType()), "self", s.GoName(), "") for i := 0; i < typ.NumFields(); i++ { f := typ.Field(i) if !f.Exported() { continue } ft := f.Type() // -- getter -- fget := Func{ pkg: s.pkg, sig: newSignature(s.pkg, recv, nil, []*Var{newVarFrom(s.pkg, f)}), typ: nil, name: f.Name(), desc: s.pkg.ImportPath() + "." + s.GoName() + "." + f.Name() + ".get", id: s.ID() + "_" + f.Name() + "_get", doc: "", ret: ft, err: false, } g.genFuncGetter(fget, s, s.sym) g.genMethod(s, fget) // -- setter -- fset := Func{ pkg: s.pkg, sig: newSignature(s.pkg, recv, []*Var{newVarFrom(s.pkg, f)}, nil), typ: nil, name: f.Name(), desc: s.pkg.ImportPath() + "." + s.GoName() + "." + f.Name() + ".set", id: s.ID() + "_" + f.Name() + "_set", doc: "", ret: nil, err: false, } g.genFuncSetter(fset, s, s.sym) g.genMethod(s, fset) } g.genFuncNew(s.funcs.new, s) g.genFunc(s.funcs.new) /* // empty interface converter g.Printf("//export cgo_func_%[1]s_eface\n", s.ID()) g.Printf("func cgo_func_%[1]s_eface(self %[2]s) interface{} {\n", s.sym.id, s.sym.cgoname, ) g.Indent() g.Printf("var v interface{} = ") if s.sym.isBasic() { g.Printf("%[1]s(self)\n", s.sym.gofmt()) } else { g.Printf("*(*%[1]s)(unsafe.Pointer(self))\n", s.sym.gofmt()) } g.Printf("return v\n") g.Outdent() g.Printf("}\n\n") */ // support for __str__ g.genFuncTPStr(s) g.genMethod(s, s.funcs.str) // g.genTypeTPCall(sym) // FIXME(sbinet) g.genTypeMethods(s) } func (g *goGen) genMethod(s Type, m Func) { g.Printf("\n// cgo_func_%[1]s wraps %[2]s.%[3]s\n", m.ID(), s.sym.gofmt(), m.GoName(), ) g.Printf("func cgo_func_%[1]s(out, in *seq.Buffer) {\n", m.ID()) g.Indent() g.genMethodBody(s, m) g.Outdent() g.Printf("}\n\n") g.regs = append(g.regs, goReg{ Descriptor: m.Descriptor(), ID: uhash(m.ID()), Func: m.ID(), }) } func (g *goGen) genMethodBody(s Type, m Func) { g.genRead("o", "in", s.sym.GoType()) sig := m.Signature() args := sig.Params() for i, arg := range args { g.Printf("// arg-%03d: %v\n", i, gofmt(g.pkg.Name(), arg.GoType())) g.genRead(fmt.Sprintf("_arg_%03d", i), "in", arg.GoType()) } results := sig.Results() if len(results) > 0 { for i := range results { if i > 0 { g.Printf(", ") } g.Printf("_res_%03d", i) } g.Printf(" := ") } if m.typ == nil { src := s.sym.GoType() dst := m.Signature().Recv().GoType() cnv := g.cnv(dst, src, "o") g.Printf("/*\nsrc: %s\ndst: %s */cgo_func_%s_(%s", src.String(), dst.String(), m.ID(), cnv) if len(args) > 0 { g.Printf(", ") } } else { g.Printf("o.%s(", m.GoName()) } for i, arg := range args { tail := "" if i+1 < len(args) { tail = ", " } switch typ := arg.GoType().Underlying().(type) { case *types.Struct: ptr := types.NewPointer(typ) g.Printf("%s%s", g.cnv(typ, ptr, fmt.Sprintf("_arg_%03d", i)), tail) default: g.Printf("_arg_%03d%s", i, tail) } } g.Printf(")\n") if len(results) <= 0 { return } for i, res := range results { g.genWrite(fmt.Sprintf("_res_%03d", i), "out", res.GoType()) } } func (g *goGen) genType(typ Type) { sym := typ.sym if !sym.isType() { return } if sym.isStruct() { g.genStruct(typ) return } if sym.isBasic() && !sym.isNamed() { return } g.Printf("\n// --- wrapping %s ---\n\n", sym.gofmt()) g.genFuncNew(typ.funcs.new, typ) g.genFunc(typ.funcs.new) /* // empty interface converter g.Printf("//export cgo_func_%[1]s_eface\n", sym.id) g.Printf("func cgo_func_%[1]s_eface(self %[2]s) interface{} {\n", sym.id, sym.cgoname, ) g.Indent() g.Printf("var v interface{} = ") if sym.isBasic() { g.Printf("%[1]s(self)\n", sym.gofmt()) } else { g.Printf("*(*%[1]s)(unsafe.Pointer(self))\n", sym.gofmt()) } g.Printf("return v\n") g.Outdent() g.Printf("}\n\n") */ // support for __str__ g.genFuncTPStr(typ) g.genMethod(typ, typ.funcs.str) if sym.isBasic() { pkg := typ.Package() t := typ.GoType() ptr := types.NewPointer(t) recv := newVar(pkg, ptr, "self", typ.GoName(), "") ut := t.Underlying() // -- getter -- fget := Func{ pkg: pkg, sig: newSignature( pkg, recv, nil, []*Var{newVar(pkg, ut, "ret", ut.String(), "")}, ), typ: nil, name: "get", desc: pkg.ImportPath() + "." + typ.GoName() + ".get", id: typ.ID() + "_get", doc: "", ret: ut, err: false, } g.genFuncGetter(fget, typ, typ.sym) g.genMethod(typ, fget) fmt.Printf("=== %v\ntyp: %s\nptr: %s\n", typ.sym.gofmt(), t.String(), ptr.String()) fmt.Printf("recv: %s\n", recv.sym.gofmt()) // -- setter -- fset := Func{ pkg: pkg, sig: newSignature( pkg, recv, []*Var{newVar(pkg, ut, "v", ut.String(), "")}, nil, ), typ: nil, name: "set", desc: pkg.ImportPath() + "." + typ.GoName() + ".set", id: typ.ID() + "_set", doc: "", ret: nil, err: false, } g.genFuncSetter(fset, typ, typ.sym) g.genMethod(typ, fset) } if sym.isArray() || sym.isSlice() { var etyp types.Type switch typ := sym.GoType().(type) { case *types.Array: etyp = typ.Elem() case *types.Slice: etyp = typ.Elem() case *types.Named: switch typ := typ.Underlying().(type) { case *types.Array: etyp = typ.Elem() case *types.Slice: etyp = typ.Elem() default: panic(fmt.Errorf("gopy: unhandled type [%#v]", typ)) } default: panic(fmt.Errorf("gopy: unhandled type [%#v]", typ)) } esym := g.pkg.syms.symtype(etyp) if esym == nil { panic(fmt.Errorf("gopy: could not retrieve element type of %#v", sym, )) } // support for __getitem__ g.Printf("//export cgo_func_%[1]s_item\n", sym.id) g.Printf( "func cgo_func_%[1]s_item(self %[2]s, i int) %[3]s {\n", sym.id, sym.cgoname, esym.cgotypename(), ) g.Indent() g.Printf("arr := (*%[1]s)(unsafe.Pointer(self))\n", sym.gofmt()) g.Printf("elt := (*arr)[i]\n") if !esym.isBasic() { g.Printf("cgopy_incref(unsafe.Pointer(&elt))\n") g.Printf("return (%[1]s)(unsafe.Pointer(&elt))\n", esym.cgotypename()) } else { if esym.isNamed() { g.Printf("return %[1]s(elt)\n", esym.cgotypename()) } else { g.Printf("return elt\n") } } g.Outdent() g.Printf("}\n\n") // support for __setitem__ g.Printf("//export cgo_func_%[1]s_ass_item\n", sym.id) g.Printf("func cgo_func_%[1]s_ass_item(self %[2]s, i int, v %[3]s) {\n", sym.id, sym.cgoname, esym.cgotypename(), ) g.Indent() g.Printf("arr := (*%[1]s)(unsafe.Pointer(self))\n", sym.gofmt()) g.Printf("(*arr)[i] = ") if !esym.isBasic() { g.Printf("*(*%[1]s)(unsafe.Pointer(v))\n", esym.gofmt()) } else { if esym.isNamed() { g.Printf("%[1]s(v)\n", esym.gofmt()) } else { g.Printf("v\n") } } g.Outdent() g.Printf("}\n\n") } if sym.isSlice() { etyp := sym.GoType().Underlying().(*types.Slice).Elem() esym := g.pkg.syms.symtype(etyp) if esym == nil { panic(fmt.Errorf("gopy: could not retrieve element type of %#v", sym, )) } // support for __append__ g.Printf("//export cgo_func_%[1]s_append\n", sym.id) g.Printf("func cgo_func_%[1]s_append(self %[2]s, v %[3]s) {\n", sym.id, sym.cgoname, esym.cgotypename(), ) g.Indent() g.Printf("slice := (*%[1]s)(unsafe.Pointer(self))\n", sym.gofmt()) g.Printf("*slice = append(*slice, ") if !esym.isBasic() { g.Printf("*(*%[1]s)(unsafe.Pointer(v))", esym.gofmt()) } else { if esym.isNamed() { g.Printf("%[1]s(v)", esym.gofmt()) } else { g.Printf("v") } } g.Printf(")\n") g.Outdent() g.Printf("}\n\n") } g.genTypeTPCall(sym) g.genTypeMethods(typ) } func (g *goGen) genTypeTPCall(sym *symbol) { if !sym.isSignature() { return } sig := sym.GoType().Underlying().(*types.Signature) if sig.Recv() != nil { // don't generate tp_call for methods. return } // support for __call__ g.Printf("//export cgo_func_%[1]s_call\n", sym.id) g.Printf("func cgo_func_%[1]s_call(self %[2]s", sym.id, sym.cgotypename()) params := sig.Params() res := sig.Results() if params != nil && params.Len() > 0 { for i := 0; i < params.Len(); i++ { arg := params.At(i) sarg := g.pkg.syms.symtype(arg.Type()) if sarg == nil { panic(fmt.Errorf( "gopy: could not find symtype for [%T]", arg.Type(), )) } g.Printf(", arg%03d %s", i, sarg.cgotypename()) } } g.Printf(")") if res != nil && res.Len() > 0 { g.Printf(" (") for i := 0; i < res.Len(); i++ { ret := res.At(i) sret := g.pkg.syms.symtype(ret.Type()) if sret == nil { panic(fmt.Errorf( "gopy: could not find symbol for [%T]", ret.Type(), )) } comma := ", " if i == 0 { comma = "" } g.Printf("%s%s", comma, sret.cgotypename()) } g.Printf(")") } g.Printf(" {\n") g.Indent() if res != nil && res.Len() > 0 { for i := 0; i < res.Len(); i++ { if i > 0 { g.Printf(", ") } g.Printf("res%03d", i) } g.Printf(" := ") } g.Printf("(*(*%[1]s)(unsafe.Pointer(self)))(", sym.gofmt()) if params != nil && params.Len() > 0 { for i := 0; i < params.Len(); i++ { comma := ", " if i == 0 { comma = "" } arg := params.At(i) sarg := g.pkg.syms.symtype(arg.Type()) if sarg.isBasic() { g.Printf("%sarg%03d", comma, i) } else { g.Printf( "%s*(*%s)(unsafe.Pointer(arg%03d))", comma, sarg.gofmt(), i, ) } } } g.Printf(")\n") if res != nil && res.Len() > 0 { for i := 0; i < res.Len(); i++ { ret := res.At(i) sret := g.pkg.syms.symtype(ret.Type()) if !needWrapType(sret.GoType()) { continue } g.Printf("cgopy_incref(unsafe.Pointer(&arg%03d))", i) } g.Printf("return ") for i := 0; i < res.Len(); i++ { if i > 0 { g.Printf(", ") } ret := res.At(i) sret := g.pkg.syms.symtype(ret.Type()) if needWrapType(ret.Type()) { g.Printf("%s(unsafe.Pointer(&", sret.cgotypename()) } g.Printf("res%03d", i) if needWrapType(ret.Type()) { g.Printf("))") } } g.Printf("\n") } g.Outdent() g.Printf("}\n\n") } func (g *goGen) genTypeMethods(T Type) { sym := T.sym if !sym.isNamed() { return } for _, m := range T.meths { g.genMethod(T, m) } return // FIXME(sbinet): remove all of this ? typ := sym.GoType().(*types.Named) for imeth := 0; imeth < typ.NumMethods(); imeth++ { m := typ.Method(imeth) if !m.Exported() { continue } mname := types.ObjectString(m, nil) msym := g.pkg.syms.sym(mname) if msym == nil { panic(fmt.Errorf( "gopy: could not find symbol for [%[1]T] (%#[1]v) (%[2]s)", m.Type(), m.Name()+" || "+m.FullName(), )) } g.Printf("//export cgo_func_%[1]s\n", msym.id) g.Printf("func cgo_func_%[1]s(self %[2]s", msym.id, sym.cgoname, ) sig := m.Type().(*types.Signature) params := sig.Params() if params != nil { for i := 0; i < params.Len(); i++ { arg := params.At(i) sarg := g.pkg.syms.symtype(arg.Type()) if sarg == nil { panic(fmt.Errorf( "gopy: could not find symbol for [%T]", arg.Type(), )) } g.Printf(", arg%03d %s", i, sarg.cgotypename()) } } g.Printf(") ") res := sig.Results() if res != nil { g.Printf("(") for i := 0; i < res.Len(); i++ { if i > 0 { g.Printf(", ") } ret := res.At(i) sret := g.pkg.syms.symtype(ret.Type()) if sret == nil { panic(fmt.Errorf( "gopy: could not find symbol for [%T]", ret.Type(), )) } g.Printf("%s", sret.cgotypename()) } g.Printf(")") } g.Printf(" {\n") g.Indent() if res != nil { for i := 0; i < res.Len(); i++ { if i > 0 { g.Printf(", ") } g.Printf("res%03d", i) } if res.Len() > 0 { g.Printf(" := ") } } if sym.isBasic() { g.Printf("(*%s)(unsafe.Pointer(&self)).%s(", sym.gofmt(), msym.goname, ) } else { g.Printf("(*%s)(unsafe.Pointer(self)).%s(", sym.gofmt(), msym.goname, ) } if params != nil { for i := 0; i < params.Len(); i++ { if i > 0 { g.Printf(", ") } sarg := g.pkg.syms.symtype(params.At(i).Type()) if needWrapType(sarg.GoType()) { g.Printf("*(*%s)(unsafe.Pointer(arg%03d))", sarg.gofmt(), i, ) } else { g.Printf("arg%03d", i) } } } g.Printf(")\n") if res == nil || res.Len() <= 0 { g.Outdent() g.Printf("}\n\n") continue } g.Printf("return ") for i := 0; i < res.Len(); i++ { if i > 0 { g.Printf(", ") } sret := g.pkg.syms.symtype(res.At(i).Type()) if needWrapType(sret.GoType()) { g.Printf( "%s(unsafe.Pointer(&", sret.cgoname, ) } g.Printf("res%03d", i) if needWrapType(sret.GoType()) { g.Printf("))") } } g.Printf("\n") g.Outdent() g.Printf("}\n\n") } }