@@ -43,9 +43,10 @@ func main() {
|
||||
val := mod.GetAttr(key)
|
||||
doc := val.GetAttrString(c.Str("__doc__"))
|
||||
sym := cjson.Object()
|
||||
sym.SetItem(c.Str("type"), cjson.String(val.Type().Name().CStr()))
|
||||
sym.SetItem(c.Str("name"), cjson.String(key.CStr()))
|
||||
sym.SetItem(c.Str("doc"), cjson.String(doc.CStr()))
|
||||
if val.Callable() != 0 && false {
|
||||
if val.Callable() != 0 {
|
||||
sig := inspect.Signature(val)
|
||||
sym.SetItem(c.Str("sig"), cjson.String(sig.Str().CStr()))
|
||||
}
|
||||
|
||||
157
chore/llpyg/llpyg.go
Normal file
157
chore/llpyg/llpyg.go
Normal file
@@ -0,0 +1,157 @@
|
||||
/*
|
||||
* Copyright (c) 2024 The GoPlus Authors (goplus.org). All rights reserved.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package main
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"go/ast"
|
||||
"go/token"
|
||||
"go/types"
|
||||
"log"
|
||||
"os"
|
||||
"os/exec"
|
||||
"strings"
|
||||
|
||||
"github.com/goplus/gogen"
|
||||
)
|
||||
|
||||
type symbol struct {
|
||||
Name string `json:"name"`
|
||||
Type string `json:"type"`
|
||||
Doc string `json:"doc"`
|
||||
Sig string `json:"sig"`
|
||||
}
|
||||
|
||||
type module struct {
|
||||
Name string `json:"name"`
|
||||
Items []*symbol `json:"items"`
|
||||
}
|
||||
|
||||
func main() {
|
||||
if len(os.Args) < 2 {
|
||||
fmt.Fprintln(os.Stderr, "Usage: llpyg <pythonLibPath>")
|
||||
return
|
||||
}
|
||||
pyLib := os.Args[1]
|
||||
|
||||
var out bytes.Buffer
|
||||
pydump := exec.Command("pydump", pyLib)
|
||||
pydump.Stdout = &out
|
||||
pydump.Run()
|
||||
|
||||
var mod module
|
||||
json.Unmarshal(out.Bytes(), &mod)
|
||||
|
||||
pkg := gogen.NewPackage("", mod.Name, nil)
|
||||
pkg.Import("unsafe").MarkForceUsed(pkg) // import _ "unsafe"
|
||||
py := pkg.Import("github.com/goplus/llgo/py") // import "github.com/goplus/llgo/py"
|
||||
|
||||
obj := py.Ref("Object").(*types.TypeName).Type().(*types.Named)
|
||||
objPtr := types.NewPointer(obj)
|
||||
ret := types.NewTuple(pkg.NewParam(0, "", objPtr))
|
||||
|
||||
ctx := &context{pkg, obj, objPtr, ret, py}
|
||||
for _, sym := range mod.Items {
|
||||
switch sym.Type {
|
||||
case "builtin_function_or_method", "function":
|
||||
ctx.genFunc(pkg, sym)
|
||||
case "str", "float", "bool", "type", "dict", "list", "module", "int", "set": // skip
|
||||
default:
|
||||
t := sym.Type
|
||||
if len(t) > 0 && (t[0] >= 'a' && t[0] <= 'z') {
|
||||
log.Panicln("unsupport type:", sym.Type)
|
||||
}
|
||||
}
|
||||
}
|
||||
pkg.WriteTo(os.Stdout)
|
||||
}
|
||||
|
||||
type context struct {
|
||||
pkg *gogen.Package
|
||||
obj *types.Named
|
||||
objPtr *types.Pointer
|
||||
ret *types.Tuple
|
||||
py gogen.PkgRef
|
||||
}
|
||||
|
||||
func (ctx *context) genFunc(pkg *gogen.Package, sym *symbol) {
|
||||
name := sym.Name
|
||||
if len(name) == 0 || name[0] == '_' {
|
||||
return
|
||||
}
|
||||
params, variadic, skip := ctx.genParams(pkg, sym.Sig)
|
||||
if skip {
|
||||
// TODO(xsw): don't skip any func
|
||||
log.Println("skip func:", name, sym.Sig)
|
||||
return
|
||||
}
|
||||
if c := name[0]; c >= 'a' && c <= 'z' {
|
||||
name = string(c+'A'-'a') + name[1:]
|
||||
}
|
||||
sig := types.NewSignatureType(nil, nil, nil, params, ctx.ret, variadic)
|
||||
fn := pkg.NewFuncDecl(token.NoPos, name, sig)
|
||||
list := ctx.genDoc(sym.Doc)
|
||||
list = append(list, emptyCommentLine)
|
||||
list = append(list, ctx.genLinkname(name, sym))
|
||||
fn.SetComments(pkg, &ast.CommentGroup{List: list})
|
||||
// fn.BodyStart(pkg).End()
|
||||
}
|
||||
|
||||
func (ctx *context) genParams(pkg *gogen.Package, sig string) (*types.Tuple, bool, bool) {
|
||||
if sig == "<NULL>" {
|
||||
return nil, false, true
|
||||
}
|
||||
sig = strings.TrimSuffix(strings.TrimPrefix(sig, "("), ")")
|
||||
parts := strings.Split(sig, ",")
|
||||
n := len(parts)
|
||||
if last := strings.TrimSpace(parts[n-1]); last == "/" {
|
||||
n--
|
||||
}
|
||||
objPtr := ctx.objPtr
|
||||
list := make([]*types.Var, n)
|
||||
for i := 0; i < n; i++ {
|
||||
part := strings.TrimSpace(parts[i])
|
||||
if strings.HasPrefix(part, "*") {
|
||||
if len(part) > 1 && part[1] == '*' || i != n-1 {
|
||||
return nil, false, true
|
||||
}
|
||||
list[i] = pkg.NewParam(0, part[1:], types.NewSlice(objPtr))
|
||||
return types.NewTuple(list...), true, false
|
||||
}
|
||||
list[i] = pkg.NewParam(0, part, objPtr)
|
||||
}
|
||||
return types.NewTuple(list...), false, false
|
||||
}
|
||||
|
||||
func (ctx *context) genLinkname(name string, sym *symbol) *ast.Comment {
|
||||
return &ast.Comment{Text: "//go:linkname " + name + " py." + sym.Name}
|
||||
}
|
||||
|
||||
func (ctx *context) genDoc(doc string) []*ast.Comment {
|
||||
lines := strings.Split(doc, "\n")
|
||||
list := make([]*ast.Comment, len(lines), len(lines)+2)
|
||||
for i, line := range lines {
|
||||
list[i] = &ast.Comment{Text: "// " + line}
|
||||
}
|
||||
return list
|
||||
}
|
||||
|
||||
var (
|
||||
emptyCommentLine = &ast.Comment{Text: "//"}
|
||||
)
|
||||
Binary file not shown.
13
py/module.go
13
py/module.go
@@ -25,6 +25,19 @@ import (
|
||||
// https://docs.python.org/3/c-api/import.html
|
||||
// https://docs.python.org/3/c-api/module.html
|
||||
|
||||
/*
|
||||
// llgo:type C
|
||||
type ModuleDefBase struct {
|
||||
Unused [8]byte // TODO(xsw)
|
||||
}
|
||||
|
||||
// llgo:type C
|
||||
type ModuleDef struct {
|
||||
Base ModuleDefBase
|
||||
// TODO(xsw)
|
||||
}
|
||||
*/
|
||||
|
||||
// Return the module object corresponding to a module name. The name argument
|
||||
// may be of the form package.module. First check the modules dictionary if
|
||||
// there’s one there, and if not, create a new one and insert it in the modules
|
||||
|
||||
17
py/object.go
17
py/object.go
@@ -22,6 +22,8 @@ import (
|
||||
"github.com/goplus/llgo/c"
|
||||
)
|
||||
|
||||
// https://docs.python.org/3/c-api/object.html
|
||||
|
||||
// Object represents a Python object.
|
||||
type Object struct {
|
||||
Unused [8]byte
|
||||
@@ -30,6 +32,9 @@ type Object struct {
|
||||
// llgo:link (*Object).DecRef C.Py_DecRef
|
||||
func (o *Object) DecRef() {}
|
||||
|
||||
// llgo:link (*Object).Type C.PyObject_Type
|
||||
func (o *Object) Type() *TypeObject { return nil }
|
||||
|
||||
// Compute a string representation of object o. Returns the string representation on
|
||||
// success, nil on failure. This is the equivalent of the Python expression str(o).
|
||||
// Called by the str() built-in function and, therefore, by the print() function.
|
||||
@@ -37,6 +42,18 @@ func (o *Object) DecRef() {}
|
||||
// llgo:link (*Object).Str C.PyObject_Str
|
||||
func (o *Object) Str() *Object { return nil }
|
||||
|
||||
// Returns 1 if the object o is considered to be true, and 0 otherwise. This is equivalent
|
||||
// to the Python expression not not o. On failure, return -1.
|
||||
//
|
||||
// llgo:link (*Object) IsTrue() C.PyObject_IsTrue
|
||||
func (o *Object) IsTrue() c.Int { return -1 }
|
||||
|
||||
// Returns 0 if the object o is considered to be true, and 1 otherwise. This is equivalent
|
||||
// to the Python expression not o. On failure, return -1.
|
||||
//
|
||||
// llgo:link (*Object) NotTrue() C.PyObject_Not
|
||||
func (o *Object) NotTrue() c.Int { return -1 }
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
|
||||
// Retrieve an attribute named attrName from object o. Returns the attribute value on success,
|
||||
|
||||
56
py/type.go
Normal file
56
py/type.go
Normal file
@@ -0,0 +1,56 @@
|
||||
/*
|
||||
* Copyright (c) 2024 The GoPlus Authors (goplus.org). All rights reserved.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package py
|
||||
|
||||
import (
|
||||
_ "unsafe"
|
||||
)
|
||||
|
||||
// https://docs.python.org/3/c-api/type.html
|
||||
|
||||
// TypeObject represents the Python type object.
|
||||
type TypeObject = Object
|
||||
|
||||
// Return the type’s name. Equivalent to getting the type’s __name__ attribute.
|
||||
//
|
||||
// llgo:link (*TypeObject).Name C.PyType_GetName
|
||||
func (t *TypeObject) Name() *Object { return nil }
|
||||
|
||||
// Return the tp_flags member of type. This function is primarily meant for use
|
||||
// with Py_LIMITED_API; the individual flag bits are guaranteed to be stable across
|
||||
// Python releases, but access to tp_flags itself is not part of the limited API.
|
||||
//
|
||||
// llgo:link (*TypeObject).Flags C.PyType_GetFlags
|
||||
func (t *TypeObject) Flags() uint32 { return 0 }
|
||||
|
||||
// Return the module object associated with the given type when the type was created
|
||||
// using PyType_FromModuleAndSpec().
|
||||
//
|
||||
// If no module is associated with the given type, sets TypeError and returns nil.
|
||||
//
|
||||
// This function is usually used to get the module in which a method is defined. Note
|
||||
// that in such a method, Py_TYPE(self).Module() may not return the intended result.
|
||||
// Py_TYPE(self) may be a subclass of the intended class, and subclasses are not
|
||||
// necessarily defined in the same module as their superclass. See PyCMethod to get
|
||||
// the class that defines the method. See ModuleByDef() for cases when PyCMethod
|
||||
// cannot be used.
|
||||
//
|
||||
// llgo:link (*TypeObject).Module C.PyType_GetModule
|
||||
func (t *TypeObject) Module() *Object { return nil }
|
||||
|
||||
// llgo:link (*TypeObject).ModuleByDef C.PyType_GetModuleByDef
|
||||
// func (t *TypeObject) ModuleByDef(def *ModuleDef) *Object { return nil }
|
||||
Reference in New Issue
Block a user