@@ -65,8 +65,8 @@ The `_demo` directory contains our demos (it start with `_` to prevent the `go`
|
|||||||
And the `py/_demo` directory contains python related demos:
|
And the `py/_demo` directory contains python related demos:
|
||||||
|
|
||||||
* [hellopy](py/_demo/hellopy/hello.go): link Python to Go and say `Hello world`
|
* [hellopy](py/_demo/hellopy/hello.go): link Python to Go and say `Hello world`
|
||||||
* [clpy](py/_demo/clpy/cleval.go): compile Python code and eval.
|
* [clpy](py/_demo/clpy/cleval.go): compile Python code and eval
|
||||||
* [callpy](py/_demo/callpy/call.go): call Python standard library function `math.sqrt`.
|
* [callpy](py/_demo/callpy/call.go): call Python standard library function `math.sqrt`
|
||||||
|
|
||||||
### How to run demos
|
### How to run demos
|
||||||
|
|
||||||
|
|||||||
@@ -8,5 +8,5 @@ import (
|
|||||||
|
|
||||||
func main() {
|
func main() {
|
||||||
x := math.Sqrt(py.Float(2))
|
x := math.Sqrt(py.Float(2))
|
||||||
c.Printf(c.Str("sqrt(2) = %f\n"), x.FloatAsDouble())
|
c.Printf(c.Str("sqrt(2) = %f\n"), x.Float64())
|
||||||
}
|
}
|
||||||
|
|||||||
15
cl/_testpy/callpy/in.go
Normal file
15
cl/_testpy/callpy/in.go
Normal file
@@ -0,0 +1,15 @@
|
|||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"github.com/goplus/llgo/c"
|
||||||
|
"github.com/goplus/llgo/py"
|
||||||
|
"github.com/goplus/llgo/py/math"
|
||||||
|
"github.com/goplus/llgo/py/os"
|
||||||
|
)
|
||||||
|
|
||||||
|
func main() {
|
||||||
|
x := math.Sqrt(py.Float(2))
|
||||||
|
wd := os.Getcwd()
|
||||||
|
c.Printf(c.Str("sqrt(2) = %f\n"), x.Float64())
|
||||||
|
c.Printf(c.Str("cwd = %s\n"), wd.CStr())
|
||||||
|
}
|
||||||
59
cl/_testpy/callpy/out.ll
Normal file
59
cl/_testpy/callpy/out.ll
Normal file
@@ -0,0 +1,59 @@
|
|||||||
|
; ModuleID = 'main'
|
||||||
|
source_filename = "main"
|
||||||
|
|
||||||
|
@"main.init$guard" = global ptr null
|
||||||
|
@__llgo_argc = global ptr null
|
||||||
|
@__llgo_argv = global ptr null
|
||||||
|
@sqrt = external global ptr
|
||||||
|
@getcwd = external global ptr
|
||||||
|
@0 = private unnamed_addr constant [14 x i8] c"sqrt(2) = %f\0A\00", align 1
|
||||||
|
@1 = private unnamed_addr constant [10 x i8] c"cwd = %s\0A\00", align 1
|
||||||
|
|
||||||
|
define void @main.init() {
|
||||||
|
_llgo_0:
|
||||||
|
%0 = load i1, ptr @"main.init$guard", align 1
|
||||||
|
br i1 %0, label %_llgo_2, label %_llgo_1
|
||||||
|
|
||||||
|
_llgo_1: ; preds = %_llgo_0
|
||||||
|
store i1 true, ptr @"main.init$guard", align 1
|
||||||
|
call void @"github.com/goplus/llgo/py/math.init"()
|
||||||
|
call void @"github.com/goplus/llgo/py/os.init"()
|
||||||
|
br label %_llgo_2
|
||||||
|
|
||||||
|
_llgo_2: ; preds = %_llgo_1, %_llgo_0
|
||||||
|
ret void
|
||||||
|
}
|
||||||
|
|
||||||
|
define void @main(i32 %0, ptr %1) {
|
||||||
|
_llgo_0:
|
||||||
|
store i32 %0, ptr @__llgo_argc, align 4
|
||||||
|
store ptr %1, ptr @__llgo_argv, align 8
|
||||||
|
call void @"github.com/goplus/llgo/internal/runtime.init"()
|
||||||
|
call void @main.init()
|
||||||
|
%2 = call ptr @PyFloat_FromDouble(double 2.000000e+00)
|
||||||
|
%3 = call ptr @PyObject_CallOneArg(ptr @sqrt, ptr %2)
|
||||||
|
%4 = call ptr @PyObject_CallNoArg(ptr @getcwd)
|
||||||
|
%5 = call double @PyFloat_AsDouble()
|
||||||
|
%6 = call i32 (ptr, ...) @printf(ptr @0, double %5)
|
||||||
|
%7 = call ptr @PyBytes_AsString()
|
||||||
|
%8 = call i32 (ptr, ...) @printf(ptr @1, ptr %7)
|
||||||
|
ret void
|
||||||
|
}
|
||||||
|
|
||||||
|
declare void @"github.com/goplus/llgo/py/math.init"()
|
||||||
|
|
||||||
|
declare void @"github.com/goplus/llgo/py/os.init"()
|
||||||
|
|
||||||
|
declare void @"github.com/goplus/llgo/internal/runtime.init"()
|
||||||
|
|
||||||
|
declare ptr @PyFloat_FromDouble(double)
|
||||||
|
|
||||||
|
declare ptr @PyObject_CallOneArg(ptr, ptr)
|
||||||
|
|
||||||
|
declare ptr @PyObject_CallNoArg(ptr)
|
||||||
|
|
||||||
|
declare double @PyFloat_AsDouble()
|
||||||
|
|
||||||
|
declare i32 @printf(ptr, ...)
|
||||||
|
|
||||||
|
declare ptr @PyBytes_AsString()
|
||||||
14
cl/_testpy/math/in.go
Normal file
14
cl/_testpy/math/in.go
Normal file
@@ -0,0 +1,14 @@
|
|||||||
|
package math
|
||||||
|
|
||||||
|
import (
|
||||||
|
_ "unsafe"
|
||||||
|
|
||||||
|
"github.com/goplus/llgo/py"
|
||||||
|
)
|
||||||
|
|
||||||
|
const (
|
||||||
|
LLGoPackage = "py.math"
|
||||||
|
)
|
||||||
|
|
||||||
|
//go:linkname Sqrt py.sqrt
|
||||||
|
func Sqrt(x *py.Object) *py.Object
|
||||||
29
cl/_testpy/math/out.ll
Normal file
29
cl/_testpy/math/out.ll
Normal file
@@ -0,0 +1,29 @@
|
|||||||
|
; ModuleID = 'math'
|
||||||
|
source_filename = "math"
|
||||||
|
|
||||||
|
@__llgo_py.math.sqrt = external global ptr
|
||||||
|
@"math.init$guard" = global ptr null
|
||||||
|
@__llgo_py.math = linkonce global ptr null
|
||||||
|
@0 = private unnamed_addr constant [5 x i8] c"math\00", align 1
|
||||||
|
|
||||||
|
define void @math.init() {
|
||||||
|
_llgo_0:
|
||||||
|
%0 = load i1, ptr @"math.init$guard", align 1
|
||||||
|
br i1 %0, label %_llgo_2, label %_llgo_1
|
||||||
|
|
||||||
|
_llgo_1: ; preds = %_llgo_0
|
||||||
|
store i1 true, ptr @"math.init$guard", align 1
|
||||||
|
%1 = load ptr, ptr @__llgo_py.math, align 8
|
||||||
|
%2 = icmp ne ptr %1, null
|
||||||
|
br i1 %2, label %_llgo_2, label %_llgo_3
|
||||||
|
|
||||||
|
_llgo_2: ; preds = %_llgo_3, %_llgo_1, %_llgo_0
|
||||||
|
ret void
|
||||||
|
|
||||||
|
_llgo_3: ; preds = %_llgo_1
|
||||||
|
%3 = call ptr @PyImport_ImportModule(ptr @0)
|
||||||
|
store ptr %3, ptr @__llgo_py.math, align 8
|
||||||
|
br label %_llgo_2
|
||||||
|
}
|
||||||
|
|
||||||
|
declare ptr @PyImport_ImportModule(ptr)
|
||||||
@@ -147,6 +147,13 @@ func TestCompileEx(t *testing.T, src any, fname, expected string) {
|
|||||||
}
|
}
|
||||||
return rt
|
return rt
|
||||||
})
|
})
|
||||||
|
prog.SetPython(func() *types.Package {
|
||||||
|
rt, err := imp.Import(llssa.PkgPython)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal("load python failed:", err)
|
||||||
|
}
|
||||||
|
return rt
|
||||||
|
})
|
||||||
|
|
||||||
ret, err := cl.NewPackage(prog, foo, files)
|
ret, err := cl.NewPackage(prog, foo, files)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
|||||||
122
cl/compile.go
122
cl/compile.go
@@ -143,6 +143,7 @@ type context struct {
|
|||||||
goProg *ssa.Program
|
goProg *ssa.Program
|
||||||
goTyps *types.Package
|
goTyps *types.Package
|
||||||
goPkg *ssa.Package
|
goPkg *ssa.Package
|
||||||
|
pyMod string
|
||||||
link map[string]string // pkgPath.nameInPkg => linkname
|
link map[string]string // pkgPath.nameInPkg => linkname
|
||||||
loaded map[*types.Package]*pkgInfo // loaded packages
|
loaded map[*types.Package]*pkgInfo // loaded packages
|
||||||
bvals map[ssa.Value]llssa.Expr // block values
|
bvals map[ssa.Value]llssa.Expr // block values
|
||||||
@@ -210,14 +211,19 @@ var (
|
|||||||
argvTy = types.NewPointer(types.NewPointer(types.Typ[types.Int8]))
|
argvTy = types.NewPointer(types.NewPointer(types.Typ[types.Int8]))
|
||||||
)
|
)
|
||||||
|
|
||||||
func (p *context) compileFuncDecl(pkg llssa.Package, f *ssa.Function) llssa.Function {
|
func (p *context) compileFuncDecl(pkg llssa.Package, f *ssa.Function) (llssa.Function, llssa.PyFunction, int) {
|
||||||
pkgTypes, name, ftype := p.funcName(f, true)
|
pkgTypes, name, ftype := p.funcName(f, true)
|
||||||
if ftype != goFunc {
|
if ftype != goFunc {
|
||||||
return nil
|
if ftype == pyFunc {
|
||||||
|
// TODO(xsw): pyMod == ""
|
||||||
|
fnName := pysymPrefix + p.pyMod + "." + name
|
||||||
|
return nil, pkg.NewPyFunc(fnName, f.Signature), pyFunc
|
||||||
|
}
|
||||||
|
return nil, nil, ignoredFunc
|
||||||
}
|
}
|
||||||
fn := pkg.FuncOf(name)
|
fn := pkg.FuncOf(name)
|
||||||
if fn != nil && fn.HasBody() {
|
if fn != nil && fn.HasBody() {
|
||||||
return fn
|
return fn, nil, goFunc
|
||||||
}
|
}
|
||||||
|
|
||||||
var sig = f.Signature
|
var sig = f.Signature
|
||||||
@@ -244,6 +250,7 @@ func (p *context) compileFuncDecl(pkg llssa.Package, f *ssa.Function) llssa.Func
|
|||||||
}
|
}
|
||||||
if nblk := len(f.Blocks); nblk > 0 {
|
if nblk := len(f.Blocks); nblk > 0 {
|
||||||
fn.MakeBlocks(nblk) // to set fn.HasBody() = true
|
fn.MakeBlocks(nblk) // to set fn.HasBody() = true
|
||||||
|
isPyMod := p.pyMod != ""
|
||||||
p.inits = append(p.inits, func() {
|
p.inits = append(p.inits, func() {
|
||||||
p.fn = fn
|
p.fn = fn
|
||||||
defer func() {
|
defer func() {
|
||||||
@@ -263,21 +270,29 @@ func (p *context) compileFuncDecl(pkg llssa.Package, f *ssa.Function) llssa.Func
|
|||||||
off[i] = p.compilePhis(b, block)
|
off[i] = p.compilePhis(b, block)
|
||||||
}
|
}
|
||||||
for i, block := range f.Blocks {
|
for i, block := range f.Blocks {
|
||||||
p.compileBlock(b, block, off[i], i == 0 && name == "main")
|
doInit := (i == 0 && name == "main")
|
||||||
|
doPyModInit := (isPyMod && i == 1 && f.Name() == "init" && sig.Recv() == nil)
|
||||||
|
p.compileBlock(b, block, off[i], doInit, doPyModInit)
|
||||||
}
|
}
|
||||||
for _, phi := range p.phis {
|
for _, phi := range p.phis {
|
||||||
phi()
|
phi()
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
return fn
|
return fn, nil, goFunc
|
||||||
}
|
}
|
||||||
|
|
||||||
// funcOf returns a function by name and set ftype = goFunc, cFunc, etc.
|
// funcOf returns a function by name and set ftype = goFunc, cFunc, etc.
|
||||||
// or returns nil and set ftype = llgoCstr, llgoAlloca, llgoUnreachable, etc.
|
// or returns nil and set ftype = llgoCstr, llgoAlloca, llgoUnreachable, etc.
|
||||||
func (p *context) funcOf(fn *ssa.Function) (ret llssa.Function, ftype int) {
|
func (p *context) funcOf(fn *ssa.Function) (aFn llssa.Function, pyFn llssa.PyFunction, ftype int) {
|
||||||
_, name, ftype := p.funcName(fn, false)
|
_, name, ftype := p.funcName(fn, false)
|
||||||
if ftype == llgoInstr {
|
switch ftype {
|
||||||
|
case pyFunc:
|
||||||
|
pkg := p.pkg
|
||||||
|
if pyFn = pkg.PyFuncOf(name); pyFn == nil {
|
||||||
|
pyFn = pkg.NewPyFunc(name, fn.Signature)
|
||||||
|
}
|
||||||
|
case llgoInstr:
|
||||||
switch name {
|
switch name {
|
||||||
case "cstr":
|
case "cstr":
|
||||||
ftype = llgoCstr
|
ftype = llgoCstr
|
||||||
@@ -294,35 +309,60 @@ func (p *context) funcOf(fn *ssa.Function) (ret llssa.Function, ftype int) {
|
|||||||
default:
|
default:
|
||||||
panic("unknown llgo instruction: " + name)
|
panic("unknown llgo instruction: " + name)
|
||||||
}
|
}
|
||||||
} else {
|
default:
|
||||||
pkg := p.pkg
|
pkg := p.pkg
|
||||||
if ret = pkg.FuncOf(name); ret == nil && len(fn.FreeVars) == 0 {
|
if aFn = pkg.FuncOf(name); aFn == nil {
|
||||||
|
if len(fn.FreeVars) > 0 {
|
||||||
|
return nil, nil, ignoredFunc
|
||||||
|
}
|
||||||
sig := fn.Signature
|
sig := fn.Signature
|
||||||
ret = pkg.NewFuncEx(name, sig, llssa.Background(ftype), false)
|
aFn = pkg.NewFuncEx(name, sig, llssa.Background(ftype), false)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
func (p *context) compileBlock(b llssa.Builder, block *ssa.BasicBlock, n int, doInit bool) llssa.BasicBlock {
|
func (p *context) compileBlock(b llssa.Builder, block *ssa.BasicBlock, n int, doInit, pyModInit bool) llssa.BasicBlock {
|
||||||
ret := p.fn.Block(block.Index)
|
var last int
|
||||||
|
var instrs []ssa.Instruction
|
||||||
|
var ret = p.fn.Block(block.Index)
|
||||||
b.SetBlock(ret)
|
b.SetBlock(ret)
|
||||||
if doInit {
|
if pyModInit {
|
||||||
prog := p.prog
|
last = len(block.Instrs) - 1
|
||||||
pkg := p.pkg
|
instrs = block.Instrs[n:last]
|
||||||
fn := p.fn
|
} else {
|
||||||
argc := pkg.NewVar("__llgo_argc", types.NewPointer(types.Typ[types.Int32]), llssa.InC)
|
instrs = block.Instrs[n:]
|
||||||
argv := pkg.NewVar("__llgo_argv", types.NewPointer(argvTy), llssa.InC)
|
if doInit {
|
||||||
argc.Init(prog.Null(argc.Type))
|
prog := p.prog
|
||||||
argv.Init(prog.Null(argv.Type))
|
pkg := p.pkg
|
||||||
b.Store(argc.Expr, fn.Param(0))
|
fn := p.fn
|
||||||
b.Store(argv.Expr, fn.Param(1))
|
argc := pkg.NewVar("__llgo_argc", types.NewPointer(types.Typ[types.Int32]), llssa.InC)
|
||||||
callRuntimeInit(b, pkg)
|
argv := pkg.NewVar("__llgo_argv", types.NewPointer(argvTy), llssa.InC)
|
||||||
b.Call(pkg.FuncOf("main.init").Expr)
|
argc.Init(prog.Null(argc.Type))
|
||||||
|
argv.Init(prog.Null(argv.Type))
|
||||||
|
b.Store(argc.Expr, fn.Param(0))
|
||||||
|
b.Store(argv.Expr, fn.Param(1))
|
||||||
|
callRuntimeInit(b, pkg)
|
||||||
|
b.Call(pkg.FuncOf("main.init").Expr)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
for _, instr := range block.Instrs[n:] {
|
for _, instr := range instrs {
|
||||||
p.compileInstr(b, instr)
|
p.compileInstr(b, instr)
|
||||||
}
|
}
|
||||||
|
if pyModInit {
|
||||||
|
jump := block.Instrs[last].(*ssa.Jump)
|
||||||
|
jumpTo := p.jumpTo(jump)
|
||||||
|
modPath := p.pyMod
|
||||||
|
modName := pysymPrefix + modPath
|
||||||
|
modPtr := p.pkg.NewPyModVar(modName).Expr
|
||||||
|
mod := b.Load(modPtr)
|
||||||
|
cond := b.BinOp(token.NEQ, mod, b.Prog.Null(mod.Type))
|
||||||
|
newBlk := p.fn.MakeBlock()
|
||||||
|
b.If(cond, jumpTo, newBlk)
|
||||||
|
b.SetBlock(newBlk)
|
||||||
|
b.Store(modPtr, b.ImportPyMod(modPath))
|
||||||
|
b.Jump(jumpTo)
|
||||||
|
}
|
||||||
return ret
|
return ret
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -507,11 +547,14 @@ func (p *context) compileInstrOrValue(b llssa.Builder, iv instrOrValue, asValue
|
|||||||
ret = b.BuiltinCall(fn, args...)
|
ret = b.BuiltinCall(fn, args...)
|
||||||
}
|
}
|
||||||
case *ssa.Function:
|
case *ssa.Function:
|
||||||
fn, ftype := p.compileFunction(cv)
|
aFn, pyFn, ftype := p.compileFunction(cv)
|
||||||
switch ftype {
|
switch ftype {
|
||||||
case goFunc, cFunc:
|
case goFunc, cFunc:
|
||||||
args := p.compileValues(b, args, kind)
|
args := p.compileValues(b, args, kind)
|
||||||
ret = b.Call(fn.Expr, args...)
|
ret = b.Call(aFn.Expr, args...)
|
||||||
|
case pyFunc:
|
||||||
|
args := p.compileValues(b, args, kind)
|
||||||
|
ret = b.Call(pyFn.Expr, args...)
|
||||||
case llgoCstr:
|
case llgoCstr:
|
||||||
ret = cstr(b, args)
|
ret = cstr(b, args)
|
||||||
case llgoAdvance:
|
case llgoAdvance:
|
||||||
@@ -643,6 +686,12 @@ func (p *context) compileInstrOrValue(b llssa.Builder, iv instrOrValue, asValue
|
|||||||
return ret
|
return ret
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (p *context) jumpTo(v *ssa.Jump) llssa.BasicBlock {
|
||||||
|
fn := p.fn
|
||||||
|
succs := v.Block().Succs
|
||||||
|
return fn.Block(succs[0].Index)
|
||||||
|
}
|
||||||
|
|
||||||
func (p *context) compileInstr(b llssa.Builder, instr ssa.Instruction) {
|
func (p *context) compileInstr(b llssa.Builder, instr ssa.Instruction) {
|
||||||
if iv, ok := instr.(instrOrValue); ok {
|
if iv, ok := instr.(instrOrValue); ok {
|
||||||
p.compileInstrOrValue(b, iv, false)
|
p.compileInstrOrValue(b, iv, false)
|
||||||
@@ -666,9 +715,7 @@ func (p *context) compileInstr(b llssa.Builder, instr ssa.Instruction) {
|
|||||||
val := p.compileValue(b, v.Val)
|
val := p.compileValue(b, v.Val)
|
||||||
b.Store(ptr, val)
|
b.Store(ptr, val)
|
||||||
case *ssa.Jump:
|
case *ssa.Jump:
|
||||||
fn := p.fn
|
jmpb := p.jumpTo(v)
|
||||||
succs := v.Block().Succs
|
|
||||||
jmpb := fn.Block(succs[0].Index)
|
|
||||||
b.Jump(jmpb)
|
b.Jump(jmpb)
|
||||||
case *ssa.Return:
|
case *ssa.Return:
|
||||||
var results []llssa.Expr
|
var results []llssa.Expr
|
||||||
@@ -699,12 +746,13 @@ func (p *context) compileInstr(b llssa.Builder, instr ssa.Instruction) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (p *context) compileFunction(v *ssa.Function) (llssa.Function, int) {
|
func (p *context) compileFunction(v *ssa.Function) (goFn llssa.Function, pyFn llssa.PyFunction, kind int) {
|
||||||
// v.Pkg == nil: means auto generated function?
|
// v.Pkg == nil: means auto generated function?
|
||||||
if v.Pkg == p.goPkg || v.Pkg == nil {
|
if v.Pkg == p.goPkg || v.Pkg == nil {
|
||||||
// function in this package
|
// function in this package
|
||||||
if fn := p.compileFuncDecl(p.pkg, v); fn != nil {
|
goFn, pyFn, kind = p.compileFuncDecl(p.pkg, v)
|
||||||
return fn, goFunc
|
if kind != ignoredFunc {
|
||||||
|
return
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return p.funcOf(v)
|
return p.funcOf(v)
|
||||||
@@ -723,8 +771,11 @@ func (p *context) compileValue(b llssa.Builder, v ssa.Value) llssa.Expr {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
case *ssa.Function:
|
case *ssa.Function:
|
||||||
fn, _ := p.compileFunction(v)
|
aFn, pyFn, _ := p.compileFunction(v)
|
||||||
return fn.Expr
|
if aFn != nil {
|
||||||
|
return aFn.Expr
|
||||||
|
}
|
||||||
|
return pyFn.Expr
|
||||||
case *ssa.Global:
|
case *ssa.Global:
|
||||||
g := p.varOf(v)
|
g := p.varOf(v)
|
||||||
return g.Expr
|
return g.Expr
|
||||||
@@ -807,6 +858,7 @@ func NewPackage(prog llssa.Program, pkg *ssa.Package, files []*ast.File) (ret ll
|
|||||||
types.Unsafe: {kind: PkgDeclOnly}, // TODO(xsw): PkgNoInit or PkgDeclOnly?
|
types.Unsafe: {kind: PkgDeclOnly}, // TODO(xsw): PkgNoInit or PkgDeclOnly?
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
ctx.initPyModule()
|
||||||
ctx.initFiles(pkgPath, files)
|
ctx.initFiles(pkgPath, files)
|
||||||
for _, m := range members {
|
for _, m := range members {
|
||||||
member := m.val
|
member := m.val
|
||||||
|
|||||||
@@ -28,6 +28,10 @@ func testCompile(t *testing.T, src, expected string) {
|
|||||||
cltest.TestCompileEx(t, src, "foo.go", expected)
|
cltest.TestCompileEx(t, src, "foo.go", expected)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestFromTestpy(t *testing.T) {
|
||||||
|
cltest.FromDir(t, "", "./_testpy", false)
|
||||||
|
}
|
||||||
|
|
||||||
func TestFromTestlibc(t *testing.T) {
|
func TestFromTestlibc(t *testing.T) {
|
||||||
cltest.FromDir(t, "", "./_testlibc", false)
|
cltest.FromDir(t, "", "./_testlibc", false)
|
||||||
}
|
}
|
||||||
|
|||||||
20
cl/import.go
20
cl/import.go
@@ -30,6 +30,8 @@ import (
|
|||||||
"golang.org/x/tools/go/ssa"
|
"golang.org/x/tools/go/ssa"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
// -----------------------------------------------------------------------------
|
||||||
|
|
||||||
type symInfo struct {
|
type symInfo struct {
|
||||||
file string
|
file string
|
||||||
fullName string
|
fullName string
|
||||||
@@ -305,6 +307,7 @@ const (
|
|||||||
ignoredFunc = iota
|
ignoredFunc = iota
|
||||||
goFunc = int(llssa.InGo)
|
goFunc = int(llssa.InGo)
|
||||||
cFunc = int(llssa.InC)
|
cFunc = int(llssa.InC)
|
||||||
|
pyFunc = int(llssa.InPython)
|
||||||
llgoInstr = -1
|
llgoInstr = -1
|
||||||
|
|
||||||
llgoInstrBase = 0x80
|
llgoInstrBase = 0x80
|
||||||
@@ -339,6 +342,9 @@ func (p *context) funcName(fn *ssa.Function, ignore bool) (*types.Package, strin
|
|||||||
if strings.HasPrefix(v, "C.") {
|
if strings.HasPrefix(v, "C.") {
|
||||||
return nil, v[2:], cFunc
|
return nil, v[2:], cFunc
|
||||||
}
|
}
|
||||||
|
if strings.HasPrefix(v, "py.") {
|
||||||
|
return pkg, v[3:], pyFunc
|
||||||
|
}
|
||||||
if strings.HasPrefix(v, "llgo.") {
|
if strings.HasPrefix(v, "llgo.") {
|
||||||
return nil, v[5:], llgoInstr
|
return nil, v[5:], llgoInstr
|
||||||
}
|
}
|
||||||
@@ -391,3 +397,17 @@ func pkgKindByPath(pkgPath string) int {
|
|||||||
}
|
}
|
||||||
return PkgNormal
|
return PkgNormal
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// -----------------------------------------------------------------------------
|
||||||
|
|
||||||
|
const (
|
||||||
|
pysymPrefix = "__llgo_py."
|
||||||
|
)
|
||||||
|
|
||||||
|
func (p *context) initPyModule() {
|
||||||
|
if kind, mod := pkgKindByScope(p.goTyps.Scope()); kind == PkgPyModule {
|
||||||
|
p.pyMod = mod
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// -----------------------------------------------------------------------------
|
||||||
|
|||||||
@@ -120,18 +120,31 @@ func Do(args []string, conf *Config) {
|
|||||||
cl.SetDebug(cl.DbgFlagAll)
|
cl.SetDebug(cl.DbgFlagAll)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
var needRt bool
|
||||||
var rt []*packages.Package
|
var rt []*packages.Package
|
||||||
prog := llssa.NewProgram(nil)
|
prog := llssa.NewProgram(nil)
|
||||||
|
load := func() []*packages.Package {
|
||||||
|
if rt == nil {
|
||||||
|
var err error
|
||||||
|
rt, err = packages.Load(cfg, llssa.PkgRuntime, llssa.PkgPython)
|
||||||
|
check(err)
|
||||||
|
}
|
||||||
|
return rt
|
||||||
|
}
|
||||||
prog.SetRuntime(func() *types.Package {
|
prog.SetRuntime(func() *types.Package {
|
||||||
rt, err = packages.Load(cfg, llssa.PkgRuntime)
|
needRt = true
|
||||||
check(err)
|
rt := load()
|
||||||
return rt[0].Types
|
return rt[0].Types
|
||||||
})
|
})
|
||||||
|
prog.SetPython(func() *types.Package {
|
||||||
|
rt := load()
|
||||||
|
return rt[1].Types
|
||||||
|
})
|
||||||
|
|
||||||
pkgs := buildAllPkgs(prog, initial, mode, verbose)
|
pkgs := buildAllPkgs(prog, initial, mode, verbose)
|
||||||
|
|
||||||
var runtimeFiles []string
|
var runtimeFiles []string
|
||||||
if rt != nil {
|
if needRt {
|
||||||
runtimeFiles = allLinkFiles(rt)
|
runtimeFiles = allLinkFiles(rt)
|
||||||
}
|
}
|
||||||
if mode != ModeBuild {
|
if mode != ModeBuild {
|
||||||
|
|||||||
@@ -30,6 +30,7 @@ import (
|
|||||||
"golang.org/x/tools/go/ssa/ssautil"
|
"golang.org/x/tools/go/ssa/ssautil"
|
||||||
|
|
||||||
llssa "github.com/goplus/llgo/ssa"
|
llssa "github.com/goplus/llgo/ssa"
|
||||||
|
cpackages "golang.org/x/tools/go/packages"
|
||||||
)
|
)
|
||||||
|
|
||||||
func Init() {
|
func Init() {
|
||||||
@@ -71,11 +72,10 @@ func Gen(pkgPath, inFile string, src any) string {
|
|||||||
}
|
}
|
||||||
|
|
||||||
prog := llssa.NewProgram(nil)
|
prog := llssa.NewProgram(nil)
|
||||||
prog.SetRuntime(func() *types.Package {
|
initRtAndPy(prog, &cpackages.Config{
|
||||||
rt, err := imp.Import(llssa.PkgRuntime)
|
Mode: loadSyntax | cpackages.NeedDeps,
|
||||||
check(err)
|
|
||||||
return rt
|
|
||||||
})
|
})
|
||||||
|
|
||||||
ret, err := cl.NewPackage(prog, ssaPkg, files)
|
ret, err := cl.NewPackage(prog, ssaPkg, files)
|
||||||
check(err)
|
check(err)
|
||||||
|
|
||||||
|
|||||||
@@ -38,6 +38,27 @@ const (
|
|||||||
loadSyntax = loadTypes | packages.NeedSyntax | packages.NeedTypesInfo
|
loadSyntax = loadTypes | packages.NeedSyntax | packages.NeedTypesInfo
|
||||||
)
|
)
|
||||||
|
|
||||||
|
func initRtAndPy(prog llssa.Program, cfg *packages.Config) {
|
||||||
|
var pkgRtAndPy []*packages.Package
|
||||||
|
load := func() []*packages.Package {
|
||||||
|
if pkgRtAndPy == nil {
|
||||||
|
var err error
|
||||||
|
pkgRtAndPy, err = packages.Load(cfg, llssa.PkgRuntime, llssa.PkgPython)
|
||||||
|
check(err)
|
||||||
|
}
|
||||||
|
return pkgRtAndPy
|
||||||
|
}
|
||||||
|
|
||||||
|
prog.SetRuntime(func() *types.Package {
|
||||||
|
rt := load()
|
||||||
|
return rt[0].Types
|
||||||
|
})
|
||||||
|
prog.SetPython(func() *types.Package {
|
||||||
|
rt := load()
|
||||||
|
return rt[1].Types
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
func GenFrom(fileOrPkg string) string {
|
func GenFrom(fileOrPkg string) string {
|
||||||
cfg := &packages.Config{
|
cfg := &packages.Config{
|
||||||
Mode: loadSyntax | packages.NeedDeps,
|
Mode: loadSyntax | packages.NeedDeps,
|
||||||
@@ -52,11 +73,7 @@ func GenFrom(fileOrPkg string) string {
|
|||||||
ssaPkg.Build()
|
ssaPkg.Build()
|
||||||
|
|
||||||
prog := llssa.NewProgram(nil)
|
prog := llssa.NewProgram(nil)
|
||||||
prog.SetRuntime(func() *types.Package {
|
initRtAndPy(prog, cfg)
|
||||||
rt, err := packages.Load(cfg, llssa.PkgRuntime)
|
|
||||||
check(err)
|
|
||||||
return rt[0].Types
|
|
||||||
})
|
|
||||||
|
|
||||||
if Verbose {
|
if Verbose {
|
||||||
ssaPkg.WriteTo(os.Stderr)
|
ssaPkg.WriteTo(os.Stderr)
|
||||||
|
|||||||
Binary file not shown.
@@ -23,10 +23,16 @@ import (
|
|||||||
"github.com/goplus/llgo/py"
|
"github.com/goplus/llgo/py"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
const (
|
||||||
|
LLGoPackage = "decl"
|
||||||
|
)
|
||||||
|
|
||||||
|
/*
|
||||||
func init() {
|
func init() {
|
||||||
py.Initialize()
|
py.Initialize()
|
||||||
py.SetProgramName(*c.Argv)
|
py.SetProgramName(*c.Argv)
|
||||||
}
|
}
|
||||||
|
*/
|
||||||
|
|
||||||
//go:linkname Module C.PyImport_ImportModule
|
//go:linkname Module C.PyImport_ImportModule
|
||||||
func Module(name *c.Char) *py.Module
|
func Module(name *c.Char) *py.Module
|
||||||
|
|||||||
@@ -11,7 +11,7 @@ func main() {
|
|||||||
math := py.ImportModule(c.Str("math"))
|
math := py.ImportModule(c.Str("math"))
|
||||||
sqrt := math.GetAttrString(c.Str("sqrt"))
|
sqrt := math.GetAttrString(c.Str("sqrt"))
|
||||||
sqrt2 := sqrt.CallOneArg(py.Float(2))
|
sqrt2 := sqrt.CallOneArg(py.Float(2))
|
||||||
c.Printf(c.Str("sqrt(2) = %f\n"), sqrt2.FloatAsDouble())
|
c.Printf(c.Str("sqrt(2) = %f\n"), sqrt2.Float64())
|
||||||
sqrt2.DecRef()
|
sqrt2.DecRef()
|
||||||
sqrt.DecRef()
|
sqrt.DecRef()
|
||||||
math.DecRef()
|
math.DecRef()
|
||||||
|
|||||||
46
py/bytes.go
Normal file
46
py/bytes.go
Normal file
@@ -0,0 +1,46 @@
|
|||||||
|
/*
|
||||||
|
* 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"
|
||||||
|
|
||||||
|
"github.com/goplus/llgo/c"
|
||||||
|
)
|
||||||
|
|
||||||
|
// https://docs.python.org/3/c-api/bytes.html
|
||||||
|
|
||||||
|
// String returns a new bytes object from a C string.
|
||||||
|
//
|
||||||
|
//go:linkname StringFrom C.PyBytes_FromString
|
||||||
|
func StringFrom(s *c.Char) *Object
|
||||||
|
|
||||||
|
//go:linkname stringFromStringAndSize C.PyBytes_FromStringAndSize
|
||||||
|
func stringFromStringAndSize(s *c.Char, size uintptr) *Object
|
||||||
|
|
||||||
|
// String returns a new bytes object from a Go string.
|
||||||
|
func String(s string) *Object {
|
||||||
|
return stringFromStringAndSize(c.GoStringData(s), uintptr(len(s)))
|
||||||
|
}
|
||||||
|
|
||||||
|
// CStr returns the content of a bytes object as a C string.
|
||||||
|
//
|
||||||
|
// llgo:link (*Object).CStr C.PyBytes_AsString
|
||||||
|
func (o *Object) CStr() *c.Char { return nil }
|
||||||
|
|
||||||
|
// llgo:link (*Object).Strlen C.PyBytes_Size
|
||||||
|
func (o *Object) Strlen() uintptr { return 0 }
|
||||||
@@ -28,5 +28,5 @@ func Float(v float64) *Object
|
|||||||
//go:linkname FloatFromSring C.PyFloat_FromString
|
//go:linkname FloatFromSring C.PyFloat_FromString
|
||||||
func FloatFromSring(v *Object) *Object
|
func FloatFromSring(v *Object) *Object
|
||||||
|
|
||||||
// llgo:link (*Object).FloatAsDouble C.PyFloat_AsDouble
|
// llgo:link (*Object).Float64 C.PyFloat_AsDouble
|
||||||
func (o *Object) FloatAsDouble() float64 { panic("unreachable") }
|
func (o *Object) Float64() float64 { return 0 }
|
||||||
|
|||||||
@@ -53,6 +53,6 @@ func Import(name *Object) *Module
|
|||||||
// manipulate a module’s __dict__.
|
// manipulate a module’s __dict__.
|
||||||
//
|
//
|
||||||
// llgo:link (*Module).GetDict C.PyModule_GetDict
|
// llgo:link (*Module).GetDict C.PyModule_GetDict
|
||||||
func (m *Module) GetDict() *Object { panic("unreachable") }
|
func (m *Module) GetDict() *Object { return nil }
|
||||||
|
|
||||||
// -----------------------------------------------------------------------------
|
// -----------------------------------------------------------------------------
|
||||||
|
|||||||
32
py/object.go
32
py/object.go
@@ -36,7 +36,7 @@ type Object struct {
|
|||||||
func BuildValue(format *c.Char, __llgo_va_list ...any) *Object
|
func BuildValue(format *c.Char, __llgo_va_list ...any) *Object
|
||||||
|
|
||||||
// llgo:link (*Object).DecRef C.Py_DecRef
|
// llgo:link (*Object).DecRef C.Py_DecRef
|
||||||
func (o *Object) DecRef() { panic("unreachable") }
|
func (o *Object) DecRef() {}
|
||||||
|
|
||||||
// -----------------------------------------------------------------------------
|
// -----------------------------------------------------------------------------
|
||||||
|
|
||||||
@@ -44,10 +44,10 @@ func (o *Object) DecRef() { panic("unreachable") }
|
|||||||
// or nil on failure. This is the equivalent of the Python expression o.attrName.
|
// or nil on failure. This is the equivalent of the Python expression o.attrName.
|
||||||
//
|
//
|
||||||
// llgo:link (*Object).GetAttr C.PyObject_GetAttr
|
// llgo:link (*Object).GetAttr C.PyObject_GetAttr
|
||||||
func (o *Object) GetAttr(attrName *Object) *Object { panic("unreachable") }
|
func (o *Object) GetAttr(attrName *Object) *Object { return nil }
|
||||||
|
|
||||||
// llgo:link (*Object).GetAttrString C.PyObject_GetAttrString
|
// llgo:link (*Object).GetAttrString C.PyObject_GetAttrString
|
||||||
func (o *Object) GetAttrString(attrName *c.Char) *Object { panic("unreachable") }
|
func (o *Object) GetAttrString(attrName *c.Char) *Object { return nil }
|
||||||
|
|
||||||
// -----------------------------------------------------------------------------
|
// -----------------------------------------------------------------------------
|
||||||
|
|
||||||
@@ -55,7 +55,7 @@ func (o *Object) GetAttrString(attrName *c.Char) *Object { panic("unreachable")
|
|||||||
// 0 otherwise. This function always succeeds.
|
// 0 otherwise. This function always succeeds.
|
||||||
//
|
//
|
||||||
// llgo:link (*Object).Callable C.PyCallable_Check
|
// llgo:link (*Object).Callable C.PyCallable_Check
|
||||||
func (o *Object) Callable() int { panic("unreachable") }
|
func (o *Object) Callable() c.Int { return 0 }
|
||||||
|
|
||||||
// Call a callable Python object o, with arguments given by the tuple args, and
|
// Call a callable Python object o, with arguments given by the tuple args, and
|
||||||
// named arguments given by the dictionary kwargs.
|
// named arguments given by the dictionary kwargs.
|
||||||
@@ -69,7 +69,7 @@ func (o *Object) Callable() int { panic("unreachable") }
|
|||||||
// This is the equivalent of the Python expression: o(*args, **kwargs).
|
// This is the equivalent of the Python expression: o(*args, **kwargs).
|
||||||
//
|
//
|
||||||
// llgo:link (*Object).Call C.PyObject_Call
|
// llgo:link (*Object).Call C.PyObject_Call
|
||||||
func (o *Object) Call(args, kwargs *Object) *Object { panic("unreachable") }
|
func (o *Object) Call(args, kwargs *Object) *Object { return nil }
|
||||||
|
|
||||||
// Call a callable Python object callable without any arguments. It is the most
|
// Call a callable Python object callable without any arguments. It is the most
|
||||||
// efficient way to call a callable Python object without any argument.
|
// efficient way to call a callable Python object without any argument.
|
||||||
@@ -78,7 +78,7 @@ func (o *Object) Call(args, kwargs *Object) *Object { panic("unreachable") }
|
|||||||
// on failure.
|
// on failure.
|
||||||
//
|
//
|
||||||
// llgo:link (*Object).CallNoArgs C.PyObject_CallNoArgs
|
// llgo:link (*Object).CallNoArgs C.PyObject_CallNoArgs
|
||||||
func (o *Object) CallNoArgs() *Object { panic("unreachable") }
|
func (o *Object) CallNoArgs() *Object { return nil }
|
||||||
|
|
||||||
// Call a callable Python object callable with exactly 1 positional argument arg
|
// Call a callable Python object callable with exactly 1 positional argument arg
|
||||||
// and no keyword arguments.
|
// and no keyword arguments.
|
||||||
@@ -87,7 +87,7 @@ func (o *Object) CallNoArgs() *Object { panic("unreachable") }
|
|||||||
// on failure.
|
// on failure.
|
||||||
//
|
//
|
||||||
// llgo:link (*Object).CallOneArg C.PyObject_CallOneArg
|
// llgo:link (*Object).CallOneArg C.PyObject_CallOneArg
|
||||||
func (o *Object) CallOneArg(arg *Object) *Object { panic("unreachable") }
|
func (o *Object) CallOneArg(arg *Object) *Object { return nil }
|
||||||
|
|
||||||
// Call a callable Python object o, with arguments given by the tuple args. If no
|
// Call a callable Python object o, with arguments given by the tuple args. If no
|
||||||
// arguments are needed, then args can be nil.
|
// arguments are needed, then args can be nil.
|
||||||
@@ -98,7 +98,7 @@ func (o *Object) CallOneArg(arg *Object) *Object { panic("unreachable") }
|
|||||||
// This is the equivalent of the Python expression: o(*args).
|
// This is the equivalent of the Python expression: o(*args).
|
||||||
//
|
//
|
||||||
// llgo:link (*Object).CallObject C.PyObject_CallObject
|
// llgo:link (*Object).CallObject C.PyObject_CallObject
|
||||||
func (o *Object) CallObject(callable, args *Object) *Object { panic("unreachable") }
|
func (o *Object) CallObject(callable, args *Object) *Object { return nil }
|
||||||
|
|
||||||
// Call a callable Python object o, with a variable number of C arguments. The C
|
// Call a callable Python object o, with a variable number of C arguments. The C
|
||||||
// arguments are described using a py.BuildValue style format string. The format
|
// arguments are described using a py.BuildValue style format string. The format
|
||||||
@@ -113,7 +113,7 @@ func (o *Object) CallObject(callable, args *Object) *Object { panic("unreachable
|
|||||||
// faster alternative.
|
// faster alternative.
|
||||||
//
|
//
|
||||||
// llgo:link (*Object).CallFunction C.PyObject_CallFunction
|
// llgo:link (*Object).CallFunction C.PyObject_CallFunction
|
||||||
func (o *Object) CallFunction(format *c.Char, __llgo_va_list ...any) *Object { panic("unreachable") }
|
func (o *Object) CallFunction(format *c.Char, __llgo_va_list ...any) *Object { return nil }
|
||||||
|
|
||||||
// Call a callable Python object o, with a variable number of PyObject* arguments.
|
// Call a callable Python object o, with a variable number of PyObject* arguments.
|
||||||
// The arguments are provided as a variable number of parameters followed by nil.
|
// The arguments are provided as a variable number of parameters followed by nil.
|
||||||
@@ -124,7 +124,7 @@ func (o *Object) CallFunction(format *c.Char, __llgo_va_list ...any) *Object { p
|
|||||||
// This is the equivalent of the Python expression: o(arg1, arg2, ...).
|
// This is the equivalent of the Python expression: o(arg1, arg2, ...).
|
||||||
//
|
//
|
||||||
// llgo:link (*Object).CallFunctionObjArgs C.PyObject_CallFunctionObjArgs
|
// llgo:link (*Object).CallFunctionObjArgs C.PyObject_CallFunctionObjArgs
|
||||||
func (o *Object) CallFunctionObjArgs(__llgo_va_list ...any) *Object { panic("unreachable") }
|
func (o *Object) CallFunctionObjArgs(__llgo_va_list ...any) *Object { return nil }
|
||||||
|
|
||||||
// llgo:link (*Object).CallMethod C.PyObject_CallMethod
|
// llgo:link (*Object).CallMethod C.PyObject_CallMethod
|
||||||
func (o *Object) CallMethod(name *c.Char, format *c.Char, __llgo_va_list ...any) *Object {
|
func (o *Object) CallMethod(name *c.Char, format *c.Char, __llgo_va_list ...any) *Object {
|
||||||
@@ -132,27 +132,27 @@ func (o *Object) CallMethod(name *c.Char, format *c.Char, __llgo_va_list ...any)
|
|||||||
}
|
}
|
||||||
|
|
||||||
// llgo:link (*Object).CallMethodObjArgs C.PyObject_CallMethodObjArgs
|
// llgo:link (*Object).CallMethodObjArgs C.PyObject_CallMethodObjArgs
|
||||||
func (o *Object) CallMethodObjArgs(name *Object, __llgo_va_list ...any) *Object { panic("unreachable") }
|
func (o *Object) CallMethodObjArgs(name *Object, __llgo_va_list ...any) *Object { return nil }
|
||||||
|
|
||||||
// llgo:link (*Object).CallMethodNoArgs C.PyObject_CallMethodNoArgs
|
// llgo:link (*Object).CallMethodNoArgs C.PyObject_CallMethodNoArgs
|
||||||
func (o *Object) CallMethodNoArgs(name *Object) *Object { panic("unreachable") }
|
func (o *Object) CallMethodNoArgs(name *Object) *Object { return nil }
|
||||||
|
|
||||||
// llgo:link (*Object).CallMethodOneArg C.PyObject_CallMethodOneArg
|
// llgo:link (*Object).CallMethodOneArg C.PyObject_CallMethodOneArg
|
||||||
func (o *Object) CallMethodOneArg(name, arg *Object) *Object { panic("unreachable") }
|
func (o *Object) CallMethodOneArg(name, arg *Object) *Object { return nil }
|
||||||
|
|
||||||
// llgo:link (*Object).Vectorcall C.PyObject_Vectorcall
|
// llgo:link (*Object).Vectorcall C.PyObject_Vectorcall
|
||||||
func (o *Object) Vectorcall(args **Object, nargs uintptr, kwnames *Object) *Object {
|
func (o *Object) Vectorcall(args **Object, nargs uintptr, kwnames *Object) *Object {
|
||||||
panic("unreachable")
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// llgo:link (*Object).VectorcallDict C.PyObject_VectorcallDict
|
// llgo:link (*Object).VectorcallDict C.PyObject_VectorcallDict
|
||||||
func (o *Object) VectorcallDict(args **Object, nargs uintptr, kwdict *Object) *Object {
|
func (o *Object) VectorcallDict(args **Object, nargs uintptr, kwdict *Object) *Object {
|
||||||
panic("unreachable")
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// llgo:link (*Object).VectorcallMethod C.PyObject_VectorcallMethod
|
// llgo:link (*Object).VectorcallMethod C.PyObject_VectorcallMethod
|
||||||
func (o *Object) VectorcallMethod(name *Object, args **Object, nargs uintptr, kwnames *Object) *Object {
|
func (o *Object) VectorcallMethod(name *Object, args **Object, nargs uintptr, kwnames *Object) *Object {
|
||||||
panic("unreachable")
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// -----------------------------------------------------------------------------
|
// -----------------------------------------------------------------------------
|
||||||
|
|||||||
30
py/os/os.go
Normal file
30
py/os/os.go
Normal file
@@ -0,0 +1,30 @@
|
|||||||
|
/*
|
||||||
|
* 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 os
|
||||||
|
|
||||||
|
import (
|
||||||
|
_ "unsafe"
|
||||||
|
|
||||||
|
"github.com/goplus/llgo/py"
|
||||||
|
)
|
||||||
|
|
||||||
|
const (
|
||||||
|
LLGoPackage = "py.os"
|
||||||
|
)
|
||||||
|
|
||||||
|
//go:linkname Getcwd py.getcwd
|
||||||
|
func Getcwd() *py.Object
|
||||||
@@ -22,6 +22,10 @@ import (
|
|||||||
"github.com/goplus/llgo/cl/cltest"
|
"github.com/goplus/llgo/cl/cltest"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
func TestFromTestpy(t *testing.T) {
|
||||||
|
cltest.FromDir(t, "", "../cl/_testpy", false)
|
||||||
|
}
|
||||||
|
|
||||||
func TestFromTestrt(t *testing.T) {
|
func TestFromTestrt(t *testing.T) {
|
||||||
cltest.FromDir(t, "", "../cl/_testrt", true)
|
cltest.FromDir(t, "", "../cl/_testrt", true)
|
||||||
}
|
}
|
||||||
|
|||||||
93
ssa/decl.go
93
ssa/decl.go
@@ -18,6 +18,7 @@ package ssa
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"go/types"
|
"go/types"
|
||||||
|
"log"
|
||||||
"strconv"
|
"strconv"
|
||||||
|
|
||||||
"github.com/goplus/llvm"
|
"github.com/goplus/llvm"
|
||||||
@@ -68,6 +69,23 @@ type aGlobal struct {
|
|||||||
// variable.
|
// variable.
|
||||||
type Global = *aGlobal
|
type Global = *aGlobal
|
||||||
|
|
||||||
|
// NewVar creates a new global variable.
|
||||||
|
func (p Package) NewVar(name string, typ types.Type, bg Background) Global {
|
||||||
|
if v, ok := p.vars[name]; ok {
|
||||||
|
return v
|
||||||
|
}
|
||||||
|
t := p.Prog.Type(typ, bg)
|
||||||
|
gbl := llvm.AddGlobal(p.mod, t.ll, name)
|
||||||
|
ret := &aGlobal{Expr{gbl, t}}
|
||||||
|
p.vars[name] = ret
|
||||||
|
return ret
|
||||||
|
}
|
||||||
|
|
||||||
|
// VarOf returns a global variable by name.
|
||||||
|
func (p Package) VarOf(name string) Global {
|
||||||
|
return p.vars[name]
|
||||||
|
}
|
||||||
|
|
||||||
// Init initializes the global variable with the given value.
|
// Init initializes the global variable with the given value.
|
||||||
func (g Global) Init(v Expr) {
|
func (g Global) Init(v Expr) {
|
||||||
g.impl.SetInitializer(v.impl)
|
g.impl.SetInitializer(v.impl)
|
||||||
@@ -140,6 +158,31 @@ type aFunction struct {
|
|||||||
// Function represents a function or method.
|
// Function represents a function or method.
|
||||||
type Function = *aFunction
|
type Function = *aFunction
|
||||||
|
|
||||||
|
// NewFunc creates a new function.
|
||||||
|
func (p Package) NewFunc(name string, sig *types.Signature, bg Background) Function {
|
||||||
|
return p.NewFuncEx(name, sig, bg, false)
|
||||||
|
}
|
||||||
|
|
||||||
|
// NewFuncEx creates a new function.
|
||||||
|
func (p Package) NewFuncEx(name string, sig *types.Signature, bg Background, hasFreeVars bool) Function {
|
||||||
|
if v, ok := p.fns[name]; ok {
|
||||||
|
return v
|
||||||
|
}
|
||||||
|
t := p.Prog.FuncDecl(sig, bg)
|
||||||
|
if debugInstr {
|
||||||
|
log.Println("NewFunc", name, t.raw.Type, "hasFreeVars:", hasFreeVars)
|
||||||
|
}
|
||||||
|
fn := llvm.AddFunction(p.mod, name, t.ll)
|
||||||
|
ret := newFunction(fn, t, p, p.Prog, hasFreeVars)
|
||||||
|
p.fns[name] = ret
|
||||||
|
return ret
|
||||||
|
}
|
||||||
|
|
||||||
|
// FuncOf returns a function by name.
|
||||||
|
func (p Package) FuncOf(name string) Function {
|
||||||
|
return p.fns[name]
|
||||||
|
}
|
||||||
|
|
||||||
func newFunction(fn llvm.Value, t Type, pkg Package, prog Program, hasFreeVars bool) Function {
|
func newFunction(fn llvm.Value, t Type, pkg Package, prog Program, hasFreeVars bool) Function {
|
||||||
params, hasVArg := newParams(t, prog)
|
params, hasVArg := newParams(t, prog)
|
||||||
base := 0
|
base := 0
|
||||||
@@ -212,22 +255,60 @@ func (p Function) MakeBody(nblk int) Builder {
|
|||||||
|
|
||||||
// MakeBlocks creates nblk basic blocks for the function.
|
// MakeBlocks creates nblk basic blocks for the function.
|
||||||
func (p Function) MakeBlocks(nblk int) []BasicBlock {
|
func (p Function) MakeBlocks(nblk int) []BasicBlock {
|
||||||
if p.blks == nil {
|
n := len(p.blks)
|
||||||
|
if n == 0 {
|
||||||
p.blks = make([]BasicBlock, 0, nblk)
|
p.blks = make([]BasicBlock, 0, nblk)
|
||||||
}
|
}
|
||||||
n := len(p.blks)
|
|
||||||
f := p.impl
|
|
||||||
for i := 0; i < nblk; i++ {
|
for i := 0; i < nblk; i++ {
|
||||||
label := "_llgo_" + strconv.Itoa(i)
|
p.addBlock(n + i)
|
||||||
blk := llvm.AddBasicBlock(f, label)
|
|
||||||
p.blks = append(p.blks, &aBasicBlock{blk, p, n + i})
|
|
||||||
}
|
}
|
||||||
return p.blks[n:]
|
return p.blks[n:]
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (p Function) addBlock(idx int) BasicBlock {
|
||||||
|
label := "_llgo_" + strconv.Itoa(idx)
|
||||||
|
blk := llvm.AddBasicBlock(p.impl, label)
|
||||||
|
ret := &aBasicBlock{blk, p, idx}
|
||||||
|
p.blks = append(p.blks, ret)
|
||||||
|
return ret
|
||||||
|
}
|
||||||
|
|
||||||
|
// MakeBlock creates a new basic block for the function.
|
||||||
|
func (p Function) MakeBlock() BasicBlock {
|
||||||
|
return p.addBlock(len(p.blks))
|
||||||
|
}
|
||||||
|
|
||||||
// Block returns the ith basic block of the function.
|
// Block returns the ith basic block of the function.
|
||||||
func (p Function) Block(idx int) BasicBlock {
|
func (p Function) Block(idx int) BasicBlock {
|
||||||
return p.blks[idx]
|
return p.blks[idx]
|
||||||
}
|
}
|
||||||
|
|
||||||
// -----------------------------------------------------------------------------
|
// -----------------------------------------------------------------------------
|
||||||
|
|
||||||
|
type aPyFunction struct {
|
||||||
|
Expr
|
||||||
|
Obj Global
|
||||||
|
}
|
||||||
|
|
||||||
|
// PyFunction represents a python function.
|
||||||
|
type PyFunction = *aPyFunction
|
||||||
|
|
||||||
|
// NewPyFunc creates a new python function.
|
||||||
|
func (p Package) NewPyFunc(name string, sig *types.Signature) PyFunction {
|
||||||
|
if v, ok := p.pyfns[name]; ok {
|
||||||
|
return v
|
||||||
|
}
|
||||||
|
obj := p.NewVar(name, p.Prog.PyObjectPtrPtr().RawType(), InC)
|
||||||
|
ty := &aType{obj.ll, rawType{sig}, vkPyFunc}
|
||||||
|
expr := Expr{obj.impl, ty}
|
||||||
|
ret := &aPyFunction{expr, obj}
|
||||||
|
p.pyfns[name] = ret
|
||||||
|
return ret
|
||||||
|
}
|
||||||
|
|
||||||
|
// PyFuncOf returns a function by name.
|
||||||
|
func (p Package) PyFuncOf(name string) PyFunction {
|
||||||
|
return p.pyfns[name]
|
||||||
|
}
|
||||||
|
|
||||||
|
// -----------------------------------------------------------------------------
|
||||||
|
|||||||
@@ -1204,7 +1204,6 @@ func (b Builder) InlineCall(fn Expr, args ...Expr) (ret Expr) {
|
|||||||
// t4 = t3()
|
// t4 = t3()
|
||||||
// t7 = invoke t5.Println(...t6)
|
// t7 = invoke t5.Println(...t6)
|
||||||
func (b Builder) Call(fn Expr, args ...Expr) (ret Expr) {
|
func (b Builder) Call(fn Expr, args ...Expr) (ret Expr) {
|
||||||
prog := b.Prog
|
|
||||||
if debugInstr {
|
if debugInstr {
|
||||||
var b bytes.Buffer
|
var b bytes.Buffer
|
||||||
name := fn.impl.Name()
|
name := fn.impl.Name()
|
||||||
@@ -1219,11 +1218,16 @@ func (b Builder) Call(fn Expr, args ...Expr) (ret Expr) {
|
|||||||
}
|
}
|
||||||
log.Println(b.String())
|
log.Println(b.String())
|
||||||
}
|
}
|
||||||
|
var kind = fn.kind
|
||||||
|
if kind == vkPyFunc {
|
||||||
|
return b.pyCall(fn, args)
|
||||||
|
}
|
||||||
var ll llvm.Type
|
var ll llvm.Type
|
||||||
var data Expr
|
var data Expr
|
||||||
var sig *types.Signature
|
var sig *types.Signature
|
||||||
|
var prog = b.Prog
|
||||||
var raw = fn.raw.Type
|
var raw = fn.raw.Type
|
||||||
switch fn.kind {
|
switch kind {
|
||||||
case vkClosure:
|
case vkClosure:
|
||||||
data = b.Field(fn, 1)
|
data = b.Field(fn, 1)
|
||||||
fn = b.Field(fn, 0)
|
fn = b.Field(fn, 0)
|
||||||
|
|||||||
171
ssa/package.go
171
ssa/package.go
@@ -19,13 +19,13 @@ package ssa
|
|||||||
import (
|
import (
|
||||||
"go/token"
|
"go/token"
|
||||||
"go/types"
|
"go/types"
|
||||||
"log"
|
|
||||||
|
|
||||||
"github.com/goplus/llvm"
|
"github.com/goplus/llvm"
|
||||||
"golang.org/x/tools/go/types/typeutil"
|
"golang.org/x/tools/go/types/typeutil"
|
||||||
)
|
)
|
||||||
|
|
||||||
const (
|
const (
|
||||||
|
PkgPython = "github.com/goplus/llgo/py"
|
||||||
PkgRuntime = "github.com/goplus/llgo/internal/runtime"
|
PkgRuntime = "github.com/goplus/llgo/internal/runtime"
|
||||||
)
|
)
|
||||||
|
|
||||||
@@ -103,6 +103,9 @@ type aProgram struct {
|
|||||||
rt *types.Package
|
rt *types.Package
|
||||||
rtget func() *types.Package
|
rtget func() *types.Package
|
||||||
|
|
||||||
|
py *types.Package
|
||||||
|
pyget func() *types.Package
|
||||||
|
|
||||||
target *Target
|
target *Target
|
||||||
td llvm.TargetData
|
td llvm.TargetData
|
||||||
// tm llvm.TargetMachine
|
// tm llvm.TargetMachine
|
||||||
@@ -131,8 +134,15 @@ type aProgram struct {
|
|||||||
uintptrTy Type
|
uintptrTy Type
|
||||||
intTy Type
|
intTy Type
|
||||||
f64Ty Type
|
f64Ty Type
|
||||||
|
pyObjPtr Type
|
||||||
|
pyObjPPtr Type
|
||||||
|
|
||||||
|
pyImpTy *types.Signature
|
||||||
|
callNoArg *types.Signature
|
||||||
|
callOneArg *types.Signature
|
||||||
|
|
||||||
needRuntime bool
|
needRuntime bool
|
||||||
|
needPyInit bool
|
||||||
}
|
}
|
||||||
|
|
||||||
// A Program presents a program.
|
// A Program presents a program.
|
||||||
@@ -158,6 +168,17 @@ func NewProgram(target *Target) Program {
|
|||||||
return &aProgram{ctx: ctx, gocvt: newGoTypes(), target: target, td: td, named: make(map[string]llvm.Type)}
|
return &aProgram{ctx: ctx, gocvt: newGoTypes(), target: target, td: td, named: make(map[string]llvm.Type)}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// SetPython sets the Python package.
|
||||||
|
// Its type can be *types.Package or func() *types.Package.
|
||||||
|
func (p Program) SetPython(py any) {
|
||||||
|
switch v := py.(type) {
|
||||||
|
case *types.Package:
|
||||||
|
p.py = v
|
||||||
|
case func() *types.Package:
|
||||||
|
p.pyget = v
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// SetRuntime sets the runtime.
|
// SetRuntime sets the runtime.
|
||||||
// Its type can be *types.Package or func() *types.Package.
|
// Its type can be *types.Package or func() *types.Package.
|
||||||
func (p Program) SetRuntime(runtime any) {
|
func (p Program) SetRuntime(runtime any) {
|
||||||
@@ -182,12 +203,25 @@ func (p Program) runtime() *types.Package {
|
|||||||
return p.rt
|
return p.rt
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (p Program) python() *types.Package {
|
||||||
|
if p.py == nil {
|
||||||
|
p.py = p.pyget()
|
||||||
|
}
|
||||||
|
return p.py
|
||||||
|
}
|
||||||
|
|
||||||
func (p Program) rtNamed(name string) *types.Named {
|
func (p Program) rtNamed(name string) *types.Named {
|
||||||
t := p.runtime().Scope().Lookup(name).Type().(*types.Named)
|
t := p.runtime().Scope().Lookup(name).Type().(*types.Named)
|
||||||
t, _ = p.gocvt.cvtNamed(t)
|
t, _ = p.gocvt.cvtNamed(t)
|
||||||
return t
|
return t
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (p Program) pyNamed(name string) *types.Named {
|
||||||
|
// TODO(xsw): does python type need to convert?
|
||||||
|
t := p.python().Scope().Lookup(name).Type().(*types.Named)
|
||||||
|
return t
|
||||||
|
}
|
||||||
|
|
||||||
func (p Program) rtType(name string) Type {
|
func (p Program) rtType(name string) Type {
|
||||||
return p.rawType(p.rtNamed(name))
|
return p.rawType(p.rtNamed(name))
|
||||||
}
|
}
|
||||||
@@ -228,8 +262,26 @@ func (p Program) NewPackage(name, pkgPath string) Package {
|
|||||||
gbls := make(map[string]Global)
|
gbls := make(map[string]Global)
|
||||||
fns := make(map[string]Function)
|
fns := make(map[string]Function)
|
||||||
stubs := make(map[string]Function)
|
stubs := make(map[string]Function)
|
||||||
|
pyfns := make(map[string]PyFunction)
|
||||||
p.needRuntime = false
|
p.needRuntime = false
|
||||||
return &aPackage{mod, gbls, fns, stubs, p}
|
return &aPackage{mod, gbls, fns, stubs, pyfns, p}
|
||||||
|
}
|
||||||
|
|
||||||
|
// PyObjectPtrPtr returns the **py.Object type.
|
||||||
|
func (p Program) PyObjectPtrPtr() Type {
|
||||||
|
if p.pyObjPPtr == nil {
|
||||||
|
p.pyObjPPtr = p.Pointer(p.PyObjectPtr())
|
||||||
|
}
|
||||||
|
return p.pyObjPPtr
|
||||||
|
}
|
||||||
|
|
||||||
|
// PyObjectPtr returns the *py.Object type.
|
||||||
|
func (p Program) PyObjectPtr() Type {
|
||||||
|
if p.pyObjPtr == nil {
|
||||||
|
objPtr := types.NewPointer(p.pyNamed("Object"))
|
||||||
|
p.pyObjPtr = p.rawType(objPtr)
|
||||||
|
}
|
||||||
|
return p.pyObjPtr
|
||||||
}
|
}
|
||||||
|
|
||||||
// Void returns void type.
|
// Void returns void type.
|
||||||
@@ -316,6 +368,7 @@ type aPackage struct {
|
|||||||
vars map[string]Global
|
vars map[string]Global
|
||||||
fns map[string]Function
|
fns map[string]Function
|
||||||
stubs map[string]Function
|
stubs map[string]Function
|
||||||
|
pyfns map[string]PyFunction
|
||||||
Prog Program
|
Prog Program
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -328,40 +381,6 @@ func (p Package) NewConst(name string, val constant.Value) NamedConst {
|
|||||||
}
|
}
|
||||||
*/
|
*/
|
||||||
|
|
||||||
// NewVar creates a new global variable.
|
|
||||||
func (p Package) NewVar(name string, typ types.Type, bg Background) Global {
|
|
||||||
t := p.Prog.Type(typ, bg)
|
|
||||||
gbl := llvm.AddGlobal(p.mod, t.ll, name)
|
|
||||||
ret := &aGlobal{Expr{gbl, t}}
|
|
||||||
p.vars[name] = ret
|
|
||||||
return ret
|
|
||||||
}
|
|
||||||
|
|
||||||
// VarOf returns a global variable by name.
|
|
||||||
func (p Package) VarOf(name string) Global {
|
|
||||||
return p.vars[name]
|
|
||||||
}
|
|
||||||
|
|
||||||
// NewFunc creates a new function.
|
|
||||||
func (p Package) NewFunc(name string, sig *types.Signature, bg Background) Function {
|
|
||||||
return p.NewFuncEx(name, sig, bg, false)
|
|
||||||
}
|
|
||||||
|
|
||||||
// NewFuncEx creates a new function.
|
|
||||||
func (p Package) NewFuncEx(name string, sig *types.Signature, bg Background, hasFreeVars bool) Function {
|
|
||||||
if v, ok := p.fns[name]; ok {
|
|
||||||
return v
|
|
||||||
}
|
|
||||||
t := p.Prog.FuncDecl(sig, bg)
|
|
||||||
if debugInstr {
|
|
||||||
log.Println("NewFunc", name, t.raw.Type, "hasFreeVars:", hasFreeVars)
|
|
||||||
}
|
|
||||||
fn := llvm.AddFunction(p.mod, name, t.ll)
|
|
||||||
ret := newFunction(fn, t, p, p.Prog, hasFreeVars)
|
|
||||||
p.fns[name] = ret
|
|
||||||
return ret
|
|
||||||
}
|
|
||||||
|
|
||||||
func (p Package) rtFunc(fnName string) Expr {
|
func (p Package) rtFunc(fnName string) Expr {
|
||||||
fn := p.Prog.runtime().Scope().Lookup(fnName).(*types.Func)
|
fn := p.Prog.runtime().Scope().Lookup(fnName).(*types.Func)
|
||||||
name := FullName(fn.Pkg(), fnName)
|
name := FullName(fn.Pkg(), fnName)
|
||||||
@@ -369,6 +388,11 @@ func (p Package) rtFunc(fnName string) Expr {
|
|||||||
return p.NewFunc(name, sig, InGo).Expr
|
return p.NewFunc(name, sig, InGo).Expr
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (p Package) pyFunc(fullName string, sig *types.Signature) Expr {
|
||||||
|
p.Prog.needPyInit = true
|
||||||
|
return p.NewFunc(fullName, sig, InC).Expr
|
||||||
|
}
|
||||||
|
|
||||||
func (p Package) closureStub(b Builder, t *types.Struct, v Expr) Expr {
|
func (p Package) closureStub(b Builder, t *types.Struct, v Expr) Expr {
|
||||||
name := v.impl.Name()
|
name := v.impl.Name()
|
||||||
prog := b.Prog
|
prog := b.Prog
|
||||||
@@ -402,11 +426,6 @@ func (p Package) closureStub(b Builder, t *types.Struct, v Expr) Expr {
|
|||||||
return b.aggregateValue(prog.rawType(t), v.impl, nilVal)
|
return b.aggregateValue(prog.rawType(t), v.impl, nilVal)
|
||||||
}
|
}
|
||||||
|
|
||||||
// FuncOf returns a function by name.
|
|
||||||
func (p Package) FuncOf(name string) Function {
|
|
||||||
return p.fns[name]
|
|
||||||
}
|
|
||||||
|
|
||||||
// -----------------------------------------------------------------------------
|
// -----------------------------------------------------------------------------
|
||||||
|
|
||||||
// String returns a string representation of the package.
|
// String returns a string representation of the package.
|
||||||
@@ -455,3 +474,73 @@ func (p *Package) WriteFile(file string) (err error) {
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
// -----------------------------------------------------------------------------
|
// -----------------------------------------------------------------------------
|
||||||
|
|
||||||
|
func (p Program) tyImportPyModule() *types.Signature {
|
||||||
|
if p.pyImpTy == nil {
|
||||||
|
charPtr := types.NewPointer(types.Typ[types.Int8])
|
||||||
|
objPtr := p.PyObjectPtr().raw.Type
|
||||||
|
params := types.NewTuple(types.NewParam(token.NoPos, nil, "", charPtr))
|
||||||
|
results := types.NewTuple(types.NewParam(token.NoPos, nil, "", objPtr))
|
||||||
|
p.pyImpTy = types.NewSignatureType(nil, nil, nil, params, results, false)
|
||||||
|
}
|
||||||
|
return p.pyImpTy
|
||||||
|
}
|
||||||
|
|
||||||
|
func (p Program) tyCallNoArg() *types.Signature {
|
||||||
|
if p.callNoArg == nil {
|
||||||
|
objPtr := p.PyObjectPtr().raw.Type
|
||||||
|
paramObjPtr := types.NewParam(token.NoPos, nil, "", objPtr)
|
||||||
|
params := types.NewTuple(paramObjPtr)
|
||||||
|
p.callNoArg = types.NewSignatureType(nil, nil, nil, params, params, false)
|
||||||
|
}
|
||||||
|
return p.callNoArg
|
||||||
|
}
|
||||||
|
|
||||||
|
func (p Program) tyCallOneArg() *types.Signature {
|
||||||
|
if p.callOneArg == nil {
|
||||||
|
objPtr := p.PyObjectPtr().raw.Type
|
||||||
|
paramObjPtr := types.NewParam(token.NoPos, nil, "", objPtr)
|
||||||
|
params := types.NewTuple(paramObjPtr, paramObjPtr)
|
||||||
|
results := types.NewTuple(paramObjPtr)
|
||||||
|
p.callOneArg = types.NewSignatureType(nil, nil, nil, params, results, false)
|
||||||
|
}
|
||||||
|
return p.callOneArg
|
||||||
|
}
|
||||||
|
|
||||||
|
// ImportPyMod imports a Python module.
|
||||||
|
func (b Builder) ImportPyMod(path string) Expr {
|
||||||
|
pkg := b.Func.Pkg
|
||||||
|
fnImp := pkg.pyFunc("PyImport_ImportModule", b.Prog.tyImportPyModule())
|
||||||
|
return b.Call(fnImp, b.CStr(path))
|
||||||
|
}
|
||||||
|
|
||||||
|
// NewPyModVar creates a new global variable for a Python module.
|
||||||
|
func (p Package) NewPyModVar(name string) Global {
|
||||||
|
prog := p.Prog
|
||||||
|
objPtr := prog.PyObjectPtrPtr().raw.Type
|
||||||
|
g := p.NewVar(name, objPtr, InC)
|
||||||
|
g.Init(prog.Null(g.Type))
|
||||||
|
g.impl.SetLinkage(llvm.LinkOnceAnyLinkage)
|
||||||
|
return g
|
||||||
|
}
|
||||||
|
|
||||||
|
func (b Builder) pyCall(fn Expr, args []Expr) (ret Expr) {
|
||||||
|
prog := b.Prog
|
||||||
|
pkg := b.Func.Pkg
|
||||||
|
sig := fn.raw.Type.(*types.Signature)
|
||||||
|
params := sig.Params()
|
||||||
|
n := params.Len()
|
||||||
|
switch n {
|
||||||
|
case 0:
|
||||||
|
call := pkg.pyFunc("PyObject_CallNoArg", prog.tyCallNoArg())
|
||||||
|
ret = b.Call(call, fn)
|
||||||
|
case 1:
|
||||||
|
call := pkg.pyFunc("PyObject_CallOneArg", prog.tyCallOneArg())
|
||||||
|
ret = b.Call(call, fn, args[0])
|
||||||
|
default:
|
||||||
|
panic("todo")
|
||||||
|
}
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// -----------------------------------------------------------------------------
|
||||||
|
|||||||
@@ -25,6 +25,12 @@ import (
|
|||||||
"github.com/goplus/llvm"
|
"github.com/goplus/llvm"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
func TestSetPython(t *testing.T) {
|
||||||
|
prog := NewProgram(nil)
|
||||||
|
typ := types.NewPackage("foo", "foo")
|
||||||
|
prog.SetPython(typ)
|
||||||
|
}
|
||||||
|
|
||||||
func TestClosureCtx(t *testing.T) {
|
func TestClosureCtx(t *testing.T) {
|
||||||
defer func() {
|
defer func() {
|
||||||
if r := recover(); r == nil {
|
if r := recover(); r == nil {
|
||||||
@@ -106,10 +112,28 @@ func assertPkg(t *testing.T, p Package, expected string) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestPyFunc(t *testing.T) {
|
||||||
|
prog := NewProgram(nil)
|
||||||
|
py := types.NewPackage("foo", "foo")
|
||||||
|
o := types.NewTypeName(0, py, "Object", nil)
|
||||||
|
types.NewNamed(o, types.Typ[types.Int], nil)
|
||||||
|
py.Scope().Insert(o)
|
||||||
|
prog.SetPython(py)
|
||||||
|
pkg := prog.NewPackage("bar", "foo/bar")
|
||||||
|
sig := types.NewSignatureType(nil, nil, nil, nil, nil, false)
|
||||||
|
a := pkg.NewPyFunc("a", sig)
|
||||||
|
if pkg.NewPyFunc("a", sig) != a {
|
||||||
|
t.Fatal("NewPyFunc(a) failed")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
func TestVar(t *testing.T) {
|
func TestVar(t *testing.T) {
|
||||||
prog := NewProgram(nil)
|
prog := NewProgram(nil)
|
||||||
pkg := prog.NewPackage("bar", "foo/bar")
|
pkg := prog.NewPackage("bar", "foo/bar")
|
||||||
a := pkg.NewVar("a", types.Typ[types.Int], InGo)
|
a := pkg.NewVar("a", types.Typ[types.Int], InGo)
|
||||||
|
if pkg.NewVar("a", types.Typ[types.Int], InGo) != a {
|
||||||
|
t.Fatal("NewVar(a) failed")
|
||||||
|
}
|
||||||
a.Init(prog.Val(100))
|
a.Init(prog.Val(100))
|
||||||
b := pkg.NewVar("b", types.Typ[types.Int], InGo)
|
b := pkg.NewVar("b", types.Typ[types.Int], InGo)
|
||||||
b.Init(a.Expr)
|
b.Init(a.Expr)
|
||||||
|
|||||||
@@ -43,6 +43,7 @@ const (
|
|||||||
vkFuncDecl
|
vkFuncDecl
|
||||||
vkFuncPtr
|
vkFuncPtr
|
||||||
vkClosure
|
vkClosure
|
||||||
|
vkPyFunc
|
||||||
vkTuple
|
vkTuple
|
||||||
vkPhisExpr = -1
|
vkPhisExpr = -1
|
||||||
)
|
)
|
||||||
|
|||||||
@@ -42,6 +42,7 @@ const (
|
|||||||
inUnknown Background = iota
|
inUnknown Background = iota
|
||||||
InGo
|
InGo
|
||||||
InC
|
InC
|
||||||
|
InPython
|
||||||
)
|
)
|
||||||
|
|
||||||
// Type convert a Go/C type into raw type.
|
// Type convert a Go/C type into raw type.
|
||||||
|
|||||||
Reference in New Issue
Block a user