Merge branch 'main' of https://github.com/goplus/llgo into main_return_0

This commit is contained in:
tsingbx
2024-05-16 15:35:05 +08:00
85 changed files with 15965 additions and 499 deletions

1
.gitignore vendored
View File

@@ -13,6 +13,7 @@ llgo_autogen.ll
stories*.bin stories*.bin
.DS_Store .DS_Store
err.log err.log
numpy.txt
_go/ _go/
_runtime/ _runtime/

3
.gitmodules vendored
View File

@@ -1,6 +1,3 @@
[submodule "x/llama2/llama2.c"] [submodule "x/llama2/llama2.c"]
path = x/llama2/llama2.c path = x/llama2/llama2.c
url = https://github.com/karpathy/llama2.c.git url = https://github.com/karpathy/llama2.c.git
[submodule "x/sqlite/sqlite"]
path = x/sqlite/sqlite
url = https://github.com/sqlite/sqlite.git

188
README.md
View File

@@ -8,7 +8,8 @@ llgo - A Go compiler based on LLVM
[![GoDoc](https://pkg.go.dev/badge/github.com/goplus/llgo.svg)](https://pkg.go.dev/github.com/goplus/llgo) [![GoDoc](https://pkg.go.dev/badge/github.com/goplus/llgo.svg)](https://pkg.go.dev/github.com/goplus/llgo)
[![Language](https://img.shields.io/badge/language-Go+-blue.svg)](https://github.com/goplus/gop) [![Language](https://img.shields.io/badge/language-Go+-blue.svg)](https://github.com/goplus/gop)
This is a Go compiler based on LLVM in order to better integrate Go with the C ecosystem including Python. It's a subproject of [the Go+ project](https://github.com/goplus/gop). LLGo is a Go compiler based on LLVM in order to better integrate Go with the C ecosystem including Python. It's a subproject of [the Go+ project](https://github.com/goplus/gop).
## C standard libary support ## C standard libary support
@@ -22,14 +23,40 @@ func main() {
} }
``` ```
This is a simple example of calling the C `printf` function to print `Hello world`. Here, `c.Str` is not a function for converting a Go string to a C string, but a built-in instruction supported by llgo for generating a C string constant. This is a simple example of calling the C `printf` function to print `Hello world`. Here, `c.Str` is not a function for converting a Go string to a C string, but a built-in instruction supported by `llgo` for generating a C string constant.
The `_demo` directory contains some C standard libary related demos (it start with `_` to prevent the `go` command from compiling it):
* [hello](_demo/hello/hello.go): call C `printf` to print `Hello world`
* [concat](_demo/concat/concat.go): call C `fprintf` with `stderr`
* [qsort](_demo/qsort/qsort.go): call C function with a callback (eg. `qsort`)
To run these demos (If you haven't installed `llgo` yet, please refer to [How to install](#how-to-install)):
```sh
export LLGOROOT=`pwd`
cd <demo-directory> # eg. cd _demo/hello
llgo run .
```
See [github.com/goplus/llgo/c](https://pkg.go.dev/github.com/goplus/llgo/c) for more detials. See [github.com/goplus/llgo/c](https://pkg.go.dev/github.com/goplus/llgo/c) for more detials.
## Python support ## Python support
You can import a Python library in llgo! For example: You can import a Python library in LLGo!
And you can import any Python library into `llgo` through a program called `llpyg` (See [Development tools](#development-tools)). The currently imported libraries include:
* [sys](https://pkg.go.dev/github.com/goplus/llgo/py/sys)
* [os](https://pkg.go.dev/github.com/goplus/llgo/py/os)
* [math](https://pkg.go.dev/github.com/goplus/llgo/py/math)
* [json](https://pkg.go.dev/github.com/goplus/llgo/py/json)
* [inspect](https://pkg.go.dev/github.com/goplus/llgo/py/inspect)
* [statistics](https://pkg.go.dev/github.com/goplus/llgo/py/statistics)
* [numpy](https://pkg.go.dev/github.com/goplus/llgo/py/numpy)
Here is an example using the Python `math` library:
```go ```go
package main package main
@@ -48,12 +75,117 @@ func main() {
Here, We call `py.Float(2)` to create a Python number 2, and pass it to Pythons `math.sqrt` to get `x`. Then use `x.Float64()` to convert x to Go's `float64` type, and print the value through the C `printf` function. Here, We call `py.Float(2)` to create a Python number 2, and pass it to Pythons `math.sqrt` to get `x`. Then use `x.Float64()` to convert x to Go's `float64` type, and print the value through the C `printf` function.
Let's look at a slightly more complex example. For example, we use `numpy` to calculate:
```go
package main
import (
"github.com/goplus/llgo/c"
"github.com/goplus/llgo/py"
"github.com/goplus/llgo/py/numpy"
)
func main() {
a := py.List(
py.List(1.0, 2.0, 3.0),
py.List(4.0, 5.0, 6.0),
py.List(7.0, 8.0, 9.0),
)
b := py.List(
py.List(9.0, 8.0, 7.0),
py.List(6.0, 5.0, 4.0),
py.List(3.0, 2.0, 1.0),
)
x := numpy.Add(a, b)
c.Printf(c.Str("a+b = %s\n"), x.Str().CStr())
}
```
Here we define two 3x3 matrices a and b, add them to get x, and then print the result.
The `_pydemo` directory contains some python related demos:
* [callpy](_pydemo/callpy/callpy.go): call Python standard library function `math.sqrt`
* [pi](_pydemo/pi/pi.go): print python constants `math.pi`
* [statistics](_pydemo/statistics/statistics.go): define a python list and call `statistics.mean` to get the mean
* [matrix](_pydemo/matrix/matrix.go): a basic `numpy` demo
To run these demos, you need to set the `LLGO_LIB_PYTHON` environment variable first.
If Python is in the search path for `clang` linking, then `LLGO_LIB_PYTHON` only needs to be set to the name of the Python library. For example:
```sh
export LLGO_LIB_PYTHON=python3.12
```
You can also specify the path to tell `llgo` where the Python library is located:
```sh
export LLGO_LIB_PYTHON=/foo/bar/python3.12
```
For example, `/opt/homebrew/Frameworks/Python.framework/Versions/3.12/libpython3.12.dylib` is a typical python library location under macOS. So we should set it like this:
```sh
export LLGO_LIB_PYTHON=/opt/homebrew/Frameworks/Python.framework/Versions/3.12/python3.12
```
Note that the file name must be written in a platform-independent format, using `python3.12` instead of `libpython3.12.dylib`.
Then you can run the demos:
```sh
export LLGOROOT=`pwd`
cd <demo-directory> # eg. cd _pydemo/callpy
llgo run .
```
See [github.com/goplus/llgo/py](https://pkg.go.dev/github.com/goplus/llgo/py) for more detials. See [github.com/goplus/llgo/py](https://pkg.go.dev/github.com/goplus/llgo/py) for more detials.
## Other frequently used libraries ## Other frequently used libraries
TODO LLGo can easily import any libraries from the C ecosystem. Currently, this import process is still manual, but in the future, it will be automated similar to Python library imports.
The currently imported libraries include:
* [llama2.c](https://pkg.go.dev/github.com/goplus/llgo/x/llama2)
* [cjson](https://pkg.go.dev/github.com/goplus/llgo/x/cjson)
* [sqlite](https://pkg.go.dev/github.com/goplus/llgo/x/sqlite)
Here are some examples related to them:
* [llama2-c](_demo/llama2-c): inference Llama 2 (It's the first llgo AI example)
* [mkjson](x/cjson/_demo/mkjson/mkjson.go): create a json object and print it
* [sqlitedemo](x/sqlite/_demo/sqlitedemo/demo.go): a basic sqlite demo
## Go syntax support
The priority of `llgo` feature iteration is:
* Popular C/Python libraries
* Full Go syntax
* Go standard libraries
* Popular Go packages
Common Go syntax is already supported. Except for the following, which needs to be improved:
* interface (Limited support)
* map (Very limited support)
* panic (Limited support)
* recover (Not supported yet)
* defer (Not supported yet)
* gc (Not supported yet)
* chan (Not supported yet)
* goroutine (Not supported yet)
* generics (Not supported yet)
Here are some examples related to Go syntax:
* [concat](_demo/concat/concat.go): define a variadic function
* [genints](_demo/genints/genints.go): various forms of closure usage (including C function, recv.method and anonymous function)
## How to install ## How to install
@@ -83,45 +215,25 @@ go install -v ./...
TODO TODO
## Demo ## Development tools
The `_demo` directory contains our demos (it start with `_` to prevent the `go` command from compiling it): * [pydump](chore/_xtool/pydump): It's the first program compiled by `llgo` (NOT `go`) in a production environment. It outputs symbol information (functions, variables, and constants) from a Python library in JSON format, preparing for the generation of corresponding packages in `llgo`.
* [llpyg](chore/llpyg): It is used to automatically convert Python libraries into Go packages that `llgo` can import. It depends on `pydump` to accomplish the task.
* [llgen](chore/llgen): It is used to compile Go packages into LLVM IR files (*.ll).
* [ssadump](chore/ssadump): It is a Go SSA builder and interpreter.
* [hello](_demo/hello/hello.go): call C printf to print `Hello world` How do I generate these tools?
* [concat](_demo/concat/concat.go): call C fprintf with stderr, and Go variadic function
* [qsort](_demo/qsort/qsort.go): call C function with a callback (eg. qsort)
* [genints](_demo/genints/genints.go): various forms of closure usage (including C function, recv.method and anonymous function)
* [llama2-c](_demo/llama2-c): inference Llama 2 (It's the first llgo AI example)
And the `_pydemo` directory contains python related demos:
* [callpy](_pydemo/callpy/callpy.go): call Python standard library function `math.sqrt`
### How to run demos
To run the demos in directory `_demo`:
```sh ```sh
cd <demo-directory> # eg. cd _demo/genints go install -v ./... # compile all tools except pydump
llgo run . cd chore/_xtool
llgo install ./... # compile pydump
``` ```
To run the demos in directory `_pydemo`, you need to set the `LLGO_LIB_PYTHON` environment variable first. Assuming you use Python 3.12, and the `libpython3.12.so` (or `libpython3.12.dylib` or `python3.12.lib`) file is in the /foo/bar directory, then you need to set `LLGO_LIB_PYTHON` to: ## Key modules
```sh Below are the key modules for understanding the implementation principles of `llgo`:
export LLGO_LIB_PYTHON=/foo/bar/python3.12
```
For example, `/opt/homebrew/Frameworks/Python.framework/Versions/3.12/libpython3.12.dylib` is a typical python lib location under macOS. So we should set it like this: * [llgo/ssa](https://pkg.go.dev/github.com/goplus/llgo/ssa): It generates LLVM IR files (LLVM SSA) using the semantics (interfaces) of Go SSA. Although `LLVM SSA` and `Go SSA` are both IR languages, they work at completely different levels. `LLVM SSA` is closer to machine code, which abstracts different instruction sets. While `Go SSA` is closer to a high-level language. We can think of it as the instruction set of the `Go computer`. `llgo/ssa` is not just limited to the `llgo` compiler. If we view it as the high-level expressive power of `LLVM`, you'll find it very useful. Prior to `llgo/ssa`, you had to operate `LLVM` using machine code semantics. But now, with the advanced SSA form (in the semantics of Go SSA), you can conveniently utilize `LLVM`.
* [llgo/cl](https://pkg.go.dev/github.com/goplus/llgo/cl): It is the core of the llgo compiler. It converts a Go package into LLVM IR files. It depends on `llgo/ssa`.
```sh * [llgo/internal/build](https://pkg.go.dev/github.com/goplus/llgo/internal/build): It strings together the entire compilation process of `llgo`. It depends on `llgo/ssa` and `llgo/cl`.
export LLGO_LIB_PYTHON=/opt/homebrew/Frameworks/Python.framework/Versions/3.12/python3.12
```
Then you can run the demos in directory `_pydemo`:
```sh
cd <demo-directory> # eg. cd _pydemo/callpy
llgo run .
```

22
_pydemo/matrix/matrix.go Normal file
View File

@@ -0,0 +1,22 @@
package main
import (
"github.com/goplus/llgo/c"
"github.com/goplus/llgo/py"
"github.com/goplus/llgo/py/numpy"
)
func main() {
a := py.List(
py.List(1.0, 2.0, 3.0),
py.List(4.0, 5.0, 6.0),
py.List(7.0, 8.0, 9.0),
)
b := py.List(
py.List(9.0, 8.0, 7.0),
py.List(6.0, 5.0, 4.0),
py.List(3.0, 2.0, 1.0),
)
x := numpy.Add(a, b)
c.Printf(c.Str("a+b = %s\n"), x.Str().CStr())
}

10
_pydemo/pi/pi.go Normal file
View File

@@ -0,0 +1,10 @@
package main
import (
"github.com/goplus/llgo/c"
"github.com/goplus/llgo/py/math"
)
func main() {
c.Printf(c.Str("pi = %f\n"), math.Pi.Float64())
}

View File

@@ -0,0 +1,13 @@
package main
import (
"github.com/goplus/llgo/c"
"github.com/goplus/llgo/py"
"github.com/goplus/llgo/py/statistics"
)
func main() {
list := py.List(1.0, 2.0, 3.0, 4.0, 4.0)
mean := statistics.Mean(list)
c.Printf(c.Str("mean(1, 2, 3, 4, 4) = %f\n"), mean.Float64())
}

4
c/c.go
View File

@@ -28,6 +28,10 @@ type (
Char = int8 Char = int8
Int = C.int Int = C.int
Uint = C.uint Uint = C.uint
Long = int32
Ulong = uint32
LongLong = int64
UlongLong = uint64
Float = float32 Float = float32
Pointer = unsafe.Pointer Pointer = unsafe.Pointer
FilePtr = unsafe.Pointer FilePtr = unsafe.Pointer

View File

@@ -20,32 +20,41 @@ import (
"github.com/goplus/llgo/c" "github.com/goplus/llgo/c"
"github.com/goplus/llgo/py" "github.com/goplus/llgo/py"
"github.com/goplus/llgo/py/inspect" "github.com/goplus/llgo/py/inspect"
"github.com/goplus/llgo/x/cjson"
) )
func main() { func main() {
if c.Argc < 2 { if c.Argc < 2 {
c.Fprintf(c.Stderr, c.Str("Usage: llpyg <pythonLibPath> [<destDir>]\n")) c.Fprintf(c.Stderr, c.Str("Usage: pydump <pythonLibPath>\n"))
return return
} }
pyLib := c.Index(c.Argv, 1) pyLib := c.Index(c.Argv, 1)
destDir := c.Str(".")
if c.Argc > 2 {
destDir = c.Index(c.Argv, 2)
}
c.Fprintf(c.Stderr, c.Str("pyLib: %s, destDir: %s\n"), pyLib, destDir)
py.Initialize() py.Initialize()
root := cjson.Object()
root.SetItem(c.Str("name"), cjson.String(pyLib))
items := cjson.Array()
mod := py.ImportModule(pyLib) mod := py.ImportModule(pyLib)
dict := mod.ModuleGetDict() keys := mod.ModuleGetDict().DictKeys()
items := dict.DictItems() for i, n := uintptr(0), keys.ListLen(); i < n; i++ {
for i, n := uintptr(0), items.ListLen(); i < n; i++ { key := keys.ListItem(i)
item := items.ListItem(i) val := mod.GetAttr(key)
key := item.TupleItem(0) doc := val.GetAttrString(c.Str("__doc__"))
val := item.TupleItem(1) sym := cjson.Object()
sym.SetItem(c.Str("type"), cjson.String(val.Type().TypeName().CStr()))
sym.SetItem(c.Str("name"), cjson.String(key.CStr()))
if doc != nil {
sym.SetItem(c.Str("doc"), cjson.String(doc.CStr()))
}
if val.Callable() != 0 { if val.Callable() != 0 {
sig := inspect.Signature(val) sig := inspect.Signature(val)
c.Fprintf(c.Stderr, c.Str("%s: %s\n"), key.CStr(), sig.Str().CStr()) sym.SetItem(c.Str("sig"), cjson.String(sig.Str().CStr()))
} }
items.AddItem(sym)
} }
root.SetItem(c.Str("items"), items)
c.Printf(c.Str("%s\n"), root.CStr())
} }

200
chore/llpyg/llpyg.go Normal file
View File

@@ -0,0 +1,200 @@
/*
* 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"
"github.com/goplus/llgo/ssa"
)
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)
modName := mod.Name
if modName == "" {
log.Printf("import module %s failed\n", pyLib)
os.Exit(1)
}
pkg := gogen.NewPackage("", modName, nil)
pkg.Import("unsafe").MarkForceUsed(pkg) // import _ "unsafe"
py := pkg.Import("github.com/goplus/llgo/py") // import "github.com/goplus/llgo/py"
f := func(cb *gogen.CodeBuilder) int {
cb.Val("py." + modName)
return 1
}
defs := pkg.NewConstDefs(pkg.Types.Scope())
defs.New(f, 0, 0, nil, "LLGoPackage")
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", "ufunc", "method-wrapper":
ctx.genFunc(pkg, sym)
case "str", "float", "bool", "type", "dict", "tuple", "list", "object",
"module", "int", "set", "frozenset", "flags", "bool_": // skip
default:
t := sym.Type
if len(t) > 0 && (t[0] >= 'a' && t[0] <= 'z') && !strings.HasSuffix(t, "_info") {
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, symSig := sym.Name, sym.Sig
if len(name) == 0 || name[0] == '_' {
return
}
params, variadic, skip := ctx.genParams(pkg, symSig)
if skip {
// TODO(xsw): don't skip any func
log.Println("skip func:", name, symSig)
return
}
name = genName(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, "("), ")")
if sig == "" { // empty params
return nil, false, false
}
parts := strings.Split(sig, ",")
n := len(parts)
objPtr := ctx.objPtr
list := make([]*types.Var, 0, n)
for i := 0; i < n; i++ {
part := strings.TrimSpace(parts[i])
if part == "/" {
continue
}
if part == "*" {
break
}
if strings.HasPrefix(part, "*") {
if part[1] != '*' {
list = append(list, ssa.VArg())
return types.NewTuple(list...), true, false
}
return types.NewTuple(list...), false, false
}
pos := strings.IndexByte(part, '=')
if pos >= 0 {
if strings.HasPrefix(part[pos+1:], "<") { // skip complex default value
return nil, false, true
}
part = part[:pos]
}
list = append(list, pkg.NewParam(0, genName(part, 0), objPtr))
}
return types.NewTuple(list...), false, false
}
func genName(name string, idxDontTitle int) string {
parts := strings.Split(name, "_")
for i, part := range parts {
if i != idxDontTitle && part != "" {
if c := part[0]; c >= 'a' && c <= 'z' {
part = string(c+'A'-'a') + part[1:]
}
parts[i] = part
}
}
name = strings.Join(parts, "")
switch name {
case "default", "func", "":
name += "_"
}
return name
}
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: "//"}
)

View File

@@ -51,7 +51,7 @@ _llgo_0:
define void @main.gwrite(%"github.com/goplus/llgo/internal/runtime.Slice" %0) { define void @main.gwrite(%"github.com/goplus/llgo/internal/runtime.Slice" %0) {
_llgo_0: _llgo_0:
%1 = call i64 @"github.com/goplus/llgo/internal/runtime.SliceLen"(%"github.com/goplus/llgo/internal/runtime.Slice" %0) %1 = extractvalue %"github.com/goplus/llgo/internal/runtime.Slice" %0, 1
%2 = icmp eq i64 %1, 0 %2 = icmp eq i64 %1, 0
br i1 %2, label %_llgo_1, label %_llgo_2 br i1 %2, label %_llgo_1, label %_llgo_2
@@ -680,7 +680,7 @@ _llgo_2: ; preds = %_llgo_1, %_llgo_0
define void @main.println(%"github.com/goplus/llgo/internal/runtime.Slice" %0) { define void @main.println(%"github.com/goplus/llgo/internal/runtime.Slice" %0) {
_llgo_0: _llgo_0:
%1 = call i64 @"github.com/goplus/llgo/internal/runtime.SliceLen"(%"github.com/goplus/llgo/internal/runtime.Slice" %0) %1 = extractvalue %"github.com/goplus/llgo/internal/runtime.Slice" %0, 1
br label %_llgo_1 br label %_llgo_1
_llgo_1: ; preds = %_llgo_5, %_llgo_0 _llgo_1: ; preds = %_llgo_5, %_llgo_0
@@ -690,7 +690,7 @@ _llgo_1: ; preds = %_llgo_5, %_llgo_0
br i1 %4, label %_llgo_2, label %_llgo_3 br i1 %4, label %_llgo_2, label %_llgo_3
_llgo_2: ; preds = %_llgo_1 _llgo_2: ; preds = %_llgo_1
%5 = call ptr @"github.com/goplus/llgo/internal/runtime.SliceData"(%"github.com/goplus/llgo/internal/runtime.Slice" %0) %5 = extractvalue %"github.com/goplus/llgo/internal/runtime.Slice" %0, 0
%6 = getelementptr inbounds %"github.com/goplus/llgo/internal/runtime.iface", ptr %5, i64 %3 %6 = getelementptr inbounds %"github.com/goplus/llgo/internal/runtime.iface", ptr %5, i64 %3
%7 = load %"github.com/goplus/llgo/internal/runtime.iface", ptr %6, align 8 %7 = load %"github.com/goplus/llgo/internal/runtime.iface", ptr %6, align 8
%8 = icmp ne i64 %3, 0 %8 = icmp ne i64 %3, 0
@@ -783,8 +783,6 @@ _llgo_0:
declare ptr @"github.com/goplus/llgo/internal/runtime.AllocZ"(i64) declare ptr @"github.com/goplus/llgo/internal/runtime.AllocZ"(i64)
declare i64 @"github.com/goplus/llgo/internal/runtime.SliceLen"(%"github.com/goplus/llgo/internal/runtime.Slice")
declare i32 @printf(ptr, ...) declare i32 @printf(ptr, ...)
declare void @"github.com/goplus/llgo/internal/runtime.init"() declare void @"github.com/goplus/llgo/internal/runtime.init"()
@@ -802,5 +800,3 @@ declare %"github.com/goplus/llgo/internal/runtime.Slice" @"github.com/goplus/llg
declare { i64, i1 } @"github.com/goplus/llgo/internal/runtime.CheckI2Int"(%"github.com/goplus/llgo/internal/runtime.iface", ptr) declare { i64, i1 } @"github.com/goplus/llgo/internal/runtime.CheckI2Int"(%"github.com/goplus/llgo/internal/runtime.iface", ptr)
declare { %"github.com/goplus/llgo/internal/runtime.String", i1 } @"github.com/goplus/llgo/internal/runtime.CheckI2String"(%"github.com/goplus/llgo/internal/runtime.iface", ptr) declare { %"github.com/goplus/llgo/internal/runtime.String", i1 } @"github.com/goplus/llgo/internal/runtime.CheckI2String"(%"github.com/goplus/llgo/internal/runtime.iface", ptr)
declare ptr @"github.com/goplus/llgo/internal/runtime.SliceData"(%"github.com/goplus/llgo/internal/runtime.Slice")

View File

@@ -48,7 +48,7 @@ _llgo_0:
define void @main.test(%"github.com/goplus/llgo/internal/runtime.Slice" %0) { define void @main.test(%"github.com/goplus/llgo/internal/runtime.Slice" %0) {
_llgo_0: _llgo_0:
%1 = call i64 @"github.com/goplus/llgo/internal/runtime.SliceLen"(%"github.com/goplus/llgo/internal/runtime.Slice" %0) %1 = extractvalue %"github.com/goplus/llgo/internal/runtime.Slice" %0, 1
br label %_llgo_1 br label %_llgo_1
_llgo_1: ; preds = %_llgo_2, %_llgo_0 _llgo_1: ; preds = %_llgo_2, %_llgo_0
@@ -58,7 +58,7 @@ _llgo_1: ; preds = %_llgo_2, %_llgo_0
br i1 %4, label %_llgo_2, label %_llgo_3 br i1 %4, label %_llgo_2, label %_llgo_3
_llgo_2: ; preds = %_llgo_1 _llgo_2: ; preds = %_llgo_1
%5 = call ptr @"github.com/goplus/llgo/internal/runtime.SliceData"(%"github.com/goplus/llgo/internal/runtime.Slice" %0) %5 = extractvalue %"github.com/goplus/llgo/internal/runtime.Slice" %0, 0
%6 = getelementptr inbounds %"github.com/goplus/llgo/internal/runtime.iface", ptr %5, i64 %3 %6 = getelementptr inbounds %"github.com/goplus/llgo/internal/runtime.iface", ptr %5, i64 %3
%7 = load %"github.com/goplus/llgo/internal/runtime.iface", ptr %6, align 8 %7 = load %"github.com/goplus/llgo/internal/runtime.iface", ptr %6, align 8
%8 = call ptr @"github.com/goplus/llgo/internal/runtime.Basic"(i64 2) %8 = call ptr @"github.com/goplus/llgo/internal/runtime.Basic"(i64 2)
@@ -80,10 +80,6 @@ declare %"github.com/goplus/llgo/internal/runtime.iface" @"github.com/goplus/llg
declare %"github.com/goplus/llgo/internal/runtime.Slice" @"github.com/goplus/llgo/internal/runtime.NewSlice3"(ptr, i64, i64, i64, i64, i64) declare %"github.com/goplus/llgo/internal/runtime.Slice" @"github.com/goplus/llgo/internal/runtime.NewSlice3"(ptr, i64, i64, i64, i64, i64)
declare i64 @"github.com/goplus/llgo/internal/runtime.SliceLen"(%"github.com/goplus/llgo/internal/runtime.Slice")
declare ptr @"github.com/goplus/llgo/internal/runtime.SliceData"(%"github.com/goplus/llgo/internal/runtime.Slice")
declare i64 @"github.com/goplus/llgo/internal/runtime.I2Int"(%"github.com/goplus/llgo/internal/runtime.iface", ptr) declare i64 @"github.com/goplus/llgo/internal/runtime.I2Int"(%"github.com/goplus/llgo/internal/runtime.iface", ptr)
declare i32 @printf(ptr, ...) declare i32 @printf(ptr, ...)

12
cl/_testpy/gcd/in.go Normal file
View File

@@ -0,0 +1,12 @@
package main
import (
"github.com/goplus/llgo/c"
"github.com/goplus/llgo/py"
"github.com/goplus/llgo/py/math"
)
func main() {
x := math.Gcd(py.Long(60), py.Long(20), py.Long(25))
c.Printf(c.Str("gcd(60, 20, 25) = %d\n"), x.Long())
}

59
cl/_testpy/gcd/out.ll Normal file
View 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
@__llgo_py.math.gcd = linkonce global ptr null
@0 = private unnamed_addr constant [22 x i8] c"gcd(60, 20, 25) = %d\0A\00", align 1
@__llgo_py.math = external global ptr
@1 = private unnamed_addr constant [4 x i8] c"gcd\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"()
%1 = load ptr, ptr @__llgo_py.math, align 8
call void (ptr, ...) @llgoLoadPyModSyms(ptr %1, ptr @1, ptr @__llgo_py.math.gcd, ptr null)
br label %_llgo_2
_llgo_2: ; preds = %_llgo_1, %_llgo_0
ret void
}
define void @main(i32 %0, ptr %1) {
_llgo_0:
call void @Py_Initialize()
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 @PyLong_FromLong(i32 60)
%3 = call ptr @PyLong_FromLong(i32 20)
%4 = call ptr @PyLong_FromLong(i32 25)
%5 = load ptr, ptr @__llgo_py.math.gcd, align 8
%6 = call ptr (ptr, ...) @PyObject_CallFunctionObjArgs(ptr %5, ptr %2, ptr %3, ptr %4, ptr null)
%7 = call i32 @PyLong_AsLong(ptr %6)
%8 = call i32 (ptr, ...) @printf(ptr @0, i32 %7)
ret void
}
declare void @"github.com/goplus/llgo/py/math.init"()
declare void @"github.com/goplus/llgo/internal/runtime.init"()
declare ptr @PyLong_FromLong(i32)
declare ptr @PyObject_CallFunctionObjArgs(ptr, ...)
declare i32 @PyLong_AsLong(ptr)
declare i32 @printf(ptr, ...)
declare void @llgoLoadPyModSyms(ptr, ...)
declare void @Py_Initialize()

View File

@@ -1,7 +1,6 @@
; ModuleID = 'math' ; ModuleID = 'math'
source_filename = "math" source_filename = "math"
@__llgo_py.math.sqrt = external global ptr
@"math.init$guard" = global ptr null @"math.init$guard" = global ptr null
@__llgo_py.math = linkonce global ptr null @__llgo_py.math = linkonce global ptr null
@0 = private unnamed_addr constant [5 x i8] c"math\00", align 1 @0 = private unnamed_addr constant [5 x i8] c"math\00", align 1

24
cl/_testpy/matrix/in.go Normal file
View File

@@ -0,0 +1,24 @@
package main
import (
"github.com/goplus/llgo/c"
"github.com/goplus/llgo/py"
"github.com/goplus/llgo/py/numpy"
)
func main() {
a := py.List(
py.List(1.0, 2.0, 3.0),
py.List(4.0, 5.0, 6.0),
py.List(7.0, 8.0, 9.0),
)
b := py.List(
py.List(9.0, 8.0, 7.0),
py.List(6.0, 5.0, 4.0),
py.List(3.0, 2.0, 1.0),
)
x := numpy.Add(a, b)
c.Printf(c.Str("a = %s\n"), a.Str().CStr())
c.Printf(c.Str("a = %s\n"), b.Str().CStr())
c.Printf(c.Str("a+b = %s\n"), x.Str().CStr())
}

121
cl/_testpy/matrix/out.ll Normal file
View File

@@ -0,0 +1,121 @@
; ModuleID = 'main'
source_filename = "main"
@"main.init$guard" = global ptr null
@__llgo_argc = global ptr null
@__llgo_argv = global ptr null
@__llgo_py.numpy.add = linkonce global ptr null
@0 = private unnamed_addr constant [8 x i8] c"a = %s\0A\00", align 1
@1 = private unnamed_addr constant [8 x i8] c"a = %s\0A\00", align 1
@2 = private unnamed_addr constant [10 x i8] c"a+b = %s\0A\00", align 1
@__llgo_py.numpy = external global ptr
@3 = private unnamed_addr constant [4 x i8] c"add\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/numpy.init"()
%1 = load ptr, ptr @__llgo_py.numpy, align 8
call void (ptr, ...) @llgoLoadPyModSyms(ptr %1, ptr @3, ptr @__llgo_py.numpy.add, ptr null)
br label %_llgo_2
_llgo_2: ; preds = %_llgo_1, %_llgo_0
ret void
}
define void @main(i32 %0, ptr %1) {
_llgo_0:
call void @Py_Initialize()
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 @PyList_New(i64 3)
%3 = call ptr @PyFloat_FromDouble(double 1.000000e+00)
%4 = call i32 @PyList_SetItem(ptr %2, i64 0, ptr %3)
%5 = call ptr @PyFloat_FromDouble(double 2.000000e+00)
%6 = call i32 @PyList_SetItem(ptr %2, i64 1, ptr %5)
%7 = call ptr @PyFloat_FromDouble(double 3.000000e+00)
%8 = call i32 @PyList_SetItem(ptr %2, i64 2, ptr %7)
%9 = call ptr @PyList_New(i64 3)
%10 = call ptr @PyFloat_FromDouble(double 4.000000e+00)
%11 = call i32 @PyList_SetItem(ptr %9, i64 0, ptr %10)
%12 = call ptr @PyFloat_FromDouble(double 5.000000e+00)
%13 = call i32 @PyList_SetItem(ptr %9, i64 1, ptr %12)
%14 = call ptr @PyFloat_FromDouble(double 6.000000e+00)
%15 = call i32 @PyList_SetItem(ptr %9, i64 2, ptr %14)
%16 = call ptr @PyList_New(i64 3)
%17 = call ptr @PyFloat_FromDouble(double 7.000000e+00)
%18 = call i32 @PyList_SetItem(ptr %16, i64 0, ptr %17)
%19 = call ptr @PyFloat_FromDouble(double 8.000000e+00)
%20 = call i32 @PyList_SetItem(ptr %16, i64 1, ptr %19)
%21 = call ptr @PyFloat_FromDouble(double 9.000000e+00)
%22 = call i32 @PyList_SetItem(ptr %16, i64 2, ptr %21)
%23 = call ptr @PyList_New(i64 3)
%24 = call i32 @PyList_SetItem(ptr %23, i64 0, ptr %2)
%25 = call i32 @PyList_SetItem(ptr %23, i64 1, ptr %9)
%26 = call i32 @PyList_SetItem(ptr %23, i64 2, ptr %16)
%27 = call ptr @PyList_New(i64 3)
%28 = call ptr @PyFloat_FromDouble(double 9.000000e+00)
%29 = call i32 @PyList_SetItem(ptr %27, i64 0, ptr %28)
%30 = call ptr @PyFloat_FromDouble(double 8.000000e+00)
%31 = call i32 @PyList_SetItem(ptr %27, i64 1, ptr %30)
%32 = call ptr @PyFloat_FromDouble(double 7.000000e+00)
%33 = call i32 @PyList_SetItem(ptr %27, i64 2, ptr %32)
%34 = call ptr @PyList_New(i64 3)
%35 = call ptr @PyFloat_FromDouble(double 6.000000e+00)
%36 = call i32 @PyList_SetItem(ptr %34, i64 0, ptr %35)
%37 = call ptr @PyFloat_FromDouble(double 5.000000e+00)
%38 = call i32 @PyList_SetItem(ptr %34, i64 1, ptr %37)
%39 = call ptr @PyFloat_FromDouble(double 4.000000e+00)
%40 = call i32 @PyList_SetItem(ptr %34, i64 2, ptr %39)
%41 = call ptr @PyList_New(i64 3)
%42 = call ptr @PyFloat_FromDouble(double 3.000000e+00)
%43 = call i32 @PyList_SetItem(ptr %41, i64 0, ptr %42)
%44 = call ptr @PyFloat_FromDouble(double 2.000000e+00)
%45 = call i32 @PyList_SetItem(ptr %41, i64 1, ptr %44)
%46 = call ptr @PyFloat_FromDouble(double 1.000000e+00)
%47 = call i32 @PyList_SetItem(ptr %41, i64 2, ptr %46)
%48 = call ptr @PyList_New(i64 3)
%49 = call i32 @PyList_SetItem(ptr %48, i64 0, ptr %27)
%50 = call i32 @PyList_SetItem(ptr %48, i64 1, ptr %34)
%51 = call i32 @PyList_SetItem(ptr %48, i64 2, ptr %41)
%52 = load ptr, ptr @__llgo_py.numpy.add, align 8
%53 = call ptr (ptr, ...) @PyObject_CallFunctionObjArgs(ptr %52, ptr %23, ptr %48, ptr null)
%54 = call ptr @PyObject_Str(ptr %23)
%55 = call ptr @PyUnicode_AsUTF8(ptr %54)
%56 = call i32 (ptr, ...) @printf(ptr @0, ptr %55)
%57 = call ptr @PyObject_Str(ptr %48)
%58 = call ptr @PyUnicode_AsUTF8(ptr %57)
%59 = call i32 (ptr, ...) @printf(ptr @1, ptr %58)
%60 = call ptr @PyObject_Str(ptr %53)
%61 = call ptr @PyUnicode_AsUTF8(ptr %60)
%62 = call i32 (ptr, ...) @printf(ptr @2, ptr %61)
ret void
}
declare void @"github.com/goplus/llgo/py/numpy.init"()
declare void @"github.com/goplus/llgo/internal/runtime.init"()
declare ptr @PyList_New(i64)
declare ptr @PyFloat_FromDouble(double)
declare i32 @PyList_SetItem(ptr, i64, ptr)
declare ptr @PyObject_CallFunctionObjArgs(ptr, ...)
declare ptr @PyObject_Str(ptr)
declare ptr @PyUnicode_AsUTF8(ptr)
declare i32 @printf(ptr, ...)
declare void @llgoLoadPyModSyms(ptr, ...)
declare void @Py_Initialize()

10
cl/_testpy/pi/in.go Normal file
View File

@@ -0,0 +1,10 @@
package main
import (
"github.com/goplus/llgo/c"
"github.com/goplus/llgo/py/math"
)
func main() {
c.Printf(c.Str("pi = %f\n"), math.Pi.Float64())
}

49
cl/_testpy/pi/out.ll Normal file
View File

@@ -0,0 +1,49 @@
; ModuleID = 'main'
source_filename = "main"
@"main.init$guard" = global ptr null
@__llgo_argc = global ptr null
@__llgo_argv = global ptr null
@0 = private unnamed_addr constant [9 x i8] c"pi = %f\0A\00", align 1
@__llgo_py.math = external global ptr
@1 = private unnamed_addr constant [3 x i8] c"pi\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"()
br label %_llgo_2
_llgo_2: ; preds = %_llgo_1, %_llgo_0
ret void
}
define void @main(i32 %0, ptr %1) {
_llgo_0:
call void @Py_Initialize()
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 = load ptr, ptr @__llgo_py.math, align 8
%3 = call ptr @PyObject_GetAttrString(ptr %2, ptr @1)
%4 = call double @PyFloat_AsDouble(ptr %3)
%5 = call i32 (ptr, ...) @printf(ptr @0, double %4)
ret void
}
declare void @"github.com/goplus/llgo/py/math.init"()
declare void @"github.com/goplus/llgo/internal/runtime.init"()
declare ptr @PyObject_GetAttrString(ptr, ptr)
declare double @PyFloat_AsDouble(ptr)
declare i32 @printf(ptr, ...)
declare void @Py_Initialize()

12
cl/_testpy/pow/in.go Normal file
View File

@@ -0,0 +1,12 @@
package main
import (
"github.com/goplus/llgo/c"
"github.com/goplus/llgo/py"
"github.com/goplus/llgo/py/math"
)
func main() {
x := math.Pow(py.Float(2), py.Float(3))
c.Printf(c.Str("pow(2, 3) = %f\n"), x.Float64())
}

58
cl/_testpy/pow/out.ll Normal file
View File

@@ -0,0 +1,58 @@
; ModuleID = 'main'
source_filename = "main"
@"main.init$guard" = global ptr null
@__llgo_argc = global ptr null
@__llgo_argv = global ptr null
@__llgo_py.math.pow = linkonce global ptr null
@0 = private unnamed_addr constant [16 x i8] c"pow(2, 3) = %f\0A\00", align 1
@__llgo_py.math = external global ptr
@1 = private unnamed_addr constant [4 x i8] c"pow\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"()
%1 = load ptr, ptr @__llgo_py.math, align 8
call void (ptr, ...) @llgoLoadPyModSyms(ptr %1, ptr @1, ptr @__llgo_py.math.pow, ptr null)
br label %_llgo_2
_llgo_2: ; preds = %_llgo_1, %_llgo_0
ret void
}
define void @main(i32 %0, ptr %1) {
_llgo_0:
call void @Py_Initialize()
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 @PyFloat_FromDouble(double 3.000000e+00)
%4 = load ptr, ptr @__llgo_py.math.pow, align 8
%5 = call ptr (ptr, ...) @PyObject_CallFunctionObjArgs(ptr %4, ptr %2, ptr %3, ptr null)
%6 = call double @PyFloat_AsDouble(ptr %5)
%7 = call i32 (ptr, ...) @printf(ptr @0, double %6)
ret void
}
declare void @"github.com/goplus/llgo/py/math.init"()
declare void @"github.com/goplus/llgo/internal/runtime.init"()
declare ptr @PyFloat_FromDouble(double)
declare ptr @PyObject_CallFunctionObjArgs(ptr, ...)
declare double @PyFloat_AsDouble(ptr)
declare i32 @printf(ptr, ...)
declare void @llgoLoadPyModSyms(ptr, ...)
declare void @Py_Initialize()

View File

@@ -1,7 +1,7 @@
package main package main
import ( import (
"github.com/goplus/llgo/internal/runtime/c" "unsafe"
) )
var a int64 = 1<<63 - 1 var a int64 = 1<<63 - 1
@@ -11,41 +11,19 @@ var n uint64 = 1<<64 - 1
func main() { func main() {
var s = []int{1, 2, 3, 4} var s = []int{1, 2, 3, 4}
var a = [...]int{1, 2, 3, 4} var a = [...]int{1, 2, 3, 4}
d := make([]byte, 4, 10)
println(s, len(s), cap(s))
println(d, len(d), cap(d))
println(len(a), cap(a), cap(&a), len(&a))
println(len([]int{1, 2, 3, 4}), len([4]int{1, 2, 3, 4}))
println(len(s[1:]), cap(s[1:]), len(s[1:2]), cap(s[1:2]), len(s[1:2:2]), cap(s[1:2:2]))
println(len(a[1:]), cap(a[1:]), len(a[1:2]), cap(a[1:2]), len(a[1:2:2]), cap(a[1:2:2]))
out(len(s)) println("hello", "hello"[1:], "hello"[1:2], len("hello"[5:]))
out(len([]int{1, 2, 3, 4})) println(append(s, 5, 6, 7, 8))
out(len(a)) data := []byte{'a', 'b', 'c'}
out(len(&a)) data = append(data, "def"...)
out(len([4]int{1, 2, 3, 4})) println(data)
var i any = 100
out(cap(s)) println(true, 100, -100, uint(100), int32(-100), 100.5, i, &i, uintptr(unsafe.Pointer(&i)))
out(cap(a))
out(cap(&a))
out(len(s[1:]))
out(cap(s[1:]))
out(len(s[1:2]))
out(cap(s[1:2]))
out(len(s[1:2:2]))
out(cap(s[1:2:2]))
out(len(a[1:]))
out(cap(a[1:]))
out(len(a[1:2]))
out(cap(a[1:2]))
out(len(a[1:2:2]))
out(cap(a[1:2:2]))
string_len("hello")
string_len("hello"[1:])
string_len("hello"[1:2])
string_len("hello"[5:])
}
func string_len(s string) {
out(len(s))
}
func out(n int) {
c.Printf(c.Str("%d\n"), n)
} }

View File

@@ -3,6 +3,7 @@ source_filename = "main"
%"github.com/goplus/llgo/internal/runtime.Slice" = type { ptr, i64, i64 } %"github.com/goplus/llgo/internal/runtime.Slice" = type { ptr, i64, i64 }
%"github.com/goplus/llgo/internal/runtime.String" = type { ptr, i64 } %"github.com/goplus/llgo/internal/runtime.String" = type { ptr, i64 }
%"github.com/goplus/llgo/internal/runtime.iface" = type { ptr, ptr }
@main.a = global ptr null @main.a = global ptr null
@main.b = global ptr null @main.b = global ptr null
@@ -10,11 +11,50 @@ source_filename = "main"
@main.n = global ptr null @main.n = global ptr null
@__llgo_argc = global ptr null @__llgo_argc = global ptr null
@__llgo_argv = global ptr null @__llgo_argv = global ptr null
@0 = private unnamed_addr constant [6 x i8] c"hello\00", align 1 @0 = private unnamed_addr constant [2 x i8] c" \00", align 1
@1 = private unnamed_addr constant [6 x i8] c"hello\00", align 1 @1 = private unnamed_addr constant [2 x i8] c" \00", align 1
@2 = private unnamed_addr constant [6 x i8] c"hello\00", align 1 @2 = private unnamed_addr constant [2 x i8] c"\0A\00", align 1
@3 = private unnamed_addr constant [6 x i8] c"hello\00", align 1 @3 = private unnamed_addr constant [2 x i8] c" \00", align 1
@4 = private unnamed_addr constant [4 x i8] c"%d\0A\00", align 1 @4 = private unnamed_addr constant [2 x i8] c" \00", align 1
@5 = private unnamed_addr constant [2 x i8] c"\0A\00", align 1
@6 = private unnamed_addr constant [2 x i8] c" \00", align 1
@7 = private unnamed_addr constant [2 x i8] c" \00", align 1
@8 = private unnamed_addr constant [2 x i8] c" \00", align 1
@9 = private unnamed_addr constant [2 x i8] c"\0A\00", align 1
@10 = private unnamed_addr constant [2 x i8] c" \00", align 1
@11 = private unnamed_addr constant [2 x i8] c"\0A\00", align 1
@12 = private unnamed_addr constant [2 x i8] c" \00", align 1
@13 = private unnamed_addr constant [2 x i8] c" \00", align 1
@14 = private unnamed_addr constant [2 x i8] c" \00", align 1
@15 = private unnamed_addr constant [2 x i8] c" \00", align 1
@16 = private unnamed_addr constant [2 x i8] c" \00", align 1
@17 = private unnamed_addr constant [2 x i8] c"\0A\00", align 1
@18 = private unnamed_addr constant [2 x i8] c" \00", align 1
@19 = private unnamed_addr constant [2 x i8] c" \00", align 1
@20 = private unnamed_addr constant [2 x i8] c" \00", align 1
@21 = private unnamed_addr constant [2 x i8] c" \00", align 1
@22 = private unnamed_addr constant [2 x i8] c" \00", align 1
@23 = private unnamed_addr constant [2 x i8] c"\0A\00", align 1
@24 = private unnamed_addr constant [6 x i8] c"hello\00", align 1
@25 = private unnamed_addr constant [6 x i8] c"hello\00", align 1
@26 = private unnamed_addr constant [6 x i8] c"hello\00", align 1
@27 = private unnamed_addr constant [6 x i8] c"hello\00", align 1
@28 = private unnamed_addr constant [2 x i8] c" \00", align 1
@29 = private unnamed_addr constant [2 x i8] c" \00", align 1
@30 = private unnamed_addr constant [2 x i8] c" \00", align 1
@31 = private unnamed_addr constant [2 x i8] c"\0A\00", align 1
@32 = private unnamed_addr constant [2 x i8] c"\0A\00", align 1
@33 = private unnamed_addr constant [4 x i8] c"def\00", align 1
@34 = private unnamed_addr constant [2 x i8] c"\0A\00", align 1
@35 = private unnamed_addr constant [2 x i8] c" \00", align 1
@36 = private unnamed_addr constant [2 x i8] c" \00", align 1
@37 = private unnamed_addr constant [2 x i8] c" \00", align 1
@38 = private unnamed_addr constant [2 x i8] c" \00", align 1
@39 = private unnamed_addr constant [2 x i8] c" \00", align 1
@40 = private unnamed_addr constant [2 x i8] c" \00", align 1
@41 = private unnamed_addr constant [2 x i8] c" \00", align 1
@42 = private unnamed_addr constant [2 x i8] c" \00", align 1
@43 = private unnamed_addr constant [2 x i8] c"\0A\00", align 1
define void @main.init() { define void @main.init() {
_llgo_0: _llgo_0:
@@ -57,103 +97,219 @@ _llgo_0:
store i64 2, ptr %10, align 4 store i64 2, ptr %10, align 4
store i64 3, ptr %11, align 4 store i64 3, ptr %11, align 4
store i64 4, ptr %12, align 4 store i64 4, ptr %12, align 4
%13 = call i64 @"github.com/goplus/llgo/internal/runtime.SliceLen"(%"github.com/goplus/llgo/internal/runtime.Slice" %7) %13 = call ptr @"github.com/goplus/llgo/internal/runtime.AllocZ"(i64 10)
call void @main.out(i64 %13) %14 = call %"github.com/goplus/llgo/internal/runtime.Slice" @"github.com/goplus/llgo/internal/runtime.NewSlice3"(ptr %13, i64 1, i64 10, i64 0, i64 4, i64 10)
%14 = call ptr @"github.com/goplus/llgo/internal/runtime.AllocZ"(i64 32) %15 = extractvalue %"github.com/goplus/llgo/internal/runtime.Slice" %7, 1
%15 = getelementptr inbounds i64, ptr %14, i64 0 %16 = extractvalue %"github.com/goplus/llgo/internal/runtime.Slice" %7, 2
store i64 1, ptr %15, align 4 call void @"github.com/goplus/llgo/internal/runtime.PrintSlice"(%"github.com/goplus/llgo/internal/runtime.Slice" %7)
%16 = getelementptr inbounds i64, ptr %14, i64 1 %17 = call %"github.com/goplus/llgo/internal/runtime.String" @"github.com/goplus/llgo/internal/runtime.NewString"(ptr @0, i64 1)
store i64 2, ptr %16, align 4 call void @"github.com/goplus/llgo/internal/runtime.PrintString"(%"github.com/goplus/llgo/internal/runtime.String" %17)
%17 = getelementptr inbounds i64, ptr %14, i64 2 call void @"github.com/goplus/llgo/internal/runtime.PrintInt"(i64 %15)
store i64 3, ptr %17, align 4 %18 = call %"github.com/goplus/llgo/internal/runtime.String" @"github.com/goplus/llgo/internal/runtime.NewString"(ptr @1, i64 1)
%18 = getelementptr inbounds i64, ptr %14, i64 3 call void @"github.com/goplus/llgo/internal/runtime.PrintString"(%"github.com/goplus/llgo/internal/runtime.String" %18)
store i64 4, ptr %18, align 4 call void @"github.com/goplus/llgo/internal/runtime.PrintInt"(i64 %16)
%19 = call %"github.com/goplus/llgo/internal/runtime.Slice" @"github.com/goplus/llgo/internal/runtime.NewSlice3"(ptr %14, i64 8, i64 4, i64 0, i64 4, i64 4) %19 = call %"github.com/goplus/llgo/internal/runtime.String" @"github.com/goplus/llgo/internal/runtime.NewString"(ptr @2, i64 1)
%20 = call i64 @"github.com/goplus/llgo/internal/runtime.SliceLen"(%"github.com/goplus/llgo/internal/runtime.Slice" %19) call void @"github.com/goplus/llgo/internal/runtime.PrintString"(%"github.com/goplus/llgo/internal/runtime.String" %19)
call void @main.out(i64 %20) %20 = extractvalue %"github.com/goplus/llgo/internal/runtime.Slice" %14, 1
call void @main.out(i64 4) %21 = extractvalue %"github.com/goplus/llgo/internal/runtime.Slice" %14, 2
call void @main.out(i64 4) call void @"github.com/goplus/llgo/internal/runtime.PrintSlice"(%"github.com/goplus/llgo/internal/runtime.Slice" %14)
call void @main.out(i64 4) %22 = call %"github.com/goplus/llgo/internal/runtime.String" @"github.com/goplus/llgo/internal/runtime.NewString"(ptr @3, i64 1)
%21 = call i64 @"github.com/goplus/llgo/internal/runtime.SliceCap"(%"github.com/goplus/llgo/internal/runtime.Slice" %7) call void @"github.com/goplus/llgo/internal/runtime.PrintString"(%"github.com/goplus/llgo/internal/runtime.String" %22)
call void @main.out(i64 %21) call void @"github.com/goplus/llgo/internal/runtime.PrintInt"(i64 %20)
call void @main.out(i64 4) %23 = call %"github.com/goplus/llgo/internal/runtime.String" @"github.com/goplus/llgo/internal/runtime.NewString"(ptr @4, i64 1)
call void @main.out(i64 4) call void @"github.com/goplus/llgo/internal/runtime.PrintString"(%"github.com/goplus/llgo/internal/runtime.String" %23)
%22 = call i64 @"github.com/goplus/llgo/internal/runtime.SliceCap"(%"github.com/goplus/llgo/internal/runtime.Slice" %7) call void @"github.com/goplus/llgo/internal/runtime.PrintInt"(i64 %21)
%23 = call i64 @"github.com/goplus/llgo/internal/runtime.SliceLen"(%"github.com/goplus/llgo/internal/runtime.Slice" %7) %24 = call %"github.com/goplus/llgo/internal/runtime.String" @"github.com/goplus/llgo/internal/runtime.NewString"(ptr @5, i64 1)
%24 = call ptr @"github.com/goplus/llgo/internal/runtime.SliceData"(%"github.com/goplus/llgo/internal/runtime.Slice" %7) call void @"github.com/goplus/llgo/internal/runtime.PrintString"(%"github.com/goplus/llgo/internal/runtime.String" %24)
%25 = call %"github.com/goplus/llgo/internal/runtime.Slice" @"github.com/goplus/llgo/internal/runtime.NewSlice3"(ptr %24, i64 8, i64 %22, i64 1, i64 %23, i64 %22) call void @"github.com/goplus/llgo/internal/runtime.PrintInt"(i64 4)
%26 = call i64 @"github.com/goplus/llgo/internal/runtime.SliceLen"(%"github.com/goplus/llgo/internal/runtime.Slice" %25) %25 = call %"github.com/goplus/llgo/internal/runtime.String" @"github.com/goplus/llgo/internal/runtime.NewString"(ptr @6, i64 1)
call void @main.out(i64 %26) call void @"github.com/goplus/llgo/internal/runtime.PrintString"(%"github.com/goplus/llgo/internal/runtime.String" %25)
%27 = call i64 @"github.com/goplus/llgo/internal/runtime.SliceCap"(%"github.com/goplus/llgo/internal/runtime.Slice" %7) call void @"github.com/goplus/llgo/internal/runtime.PrintInt"(i64 4)
%28 = call i64 @"github.com/goplus/llgo/internal/runtime.SliceLen"(%"github.com/goplus/llgo/internal/runtime.Slice" %7) %26 = call %"github.com/goplus/llgo/internal/runtime.String" @"github.com/goplus/llgo/internal/runtime.NewString"(ptr @7, i64 1)
%29 = call ptr @"github.com/goplus/llgo/internal/runtime.SliceData"(%"github.com/goplus/llgo/internal/runtime.Slice" %7) call void @"github.com/goplus/llgo/internal/runtime.PrintString"(%"github.com/goplus/llgo/internal/runtime.String" %26)
%30 = call %"github.com/goplus/llgo/internal/runtime.Slice" @"github.com/goplus/llgo/internal/runtime.NewSlice3"(ptr %29, i64 8, i64 %27, i64 1, i64 %28, i64 %27) call void @"github.com/goplus/llgo/internal/runtime.PrintInt"(i64 4)
%31 = call i64 @"github.com/goplus/llgo/internal/runtime.SliceCap"(%"github.com/goplus/llgo/internal/runtime.Slice" %30) %27 = call %"github.com/goplus/llgo/internal/runtime.String" @"github.com/goplus/llgo/internal/runtime.NewString"(ptr @8, i64 1)
call void @main.out(i64 %31) call void @"github.com/goplus/llgo/internal/runtime.PrintString"(%"github.com/goplus/llgo/internal/runtime.String" %27)
%32 = call i64 @"github.com/goplus/llgo/internal/runtime.SliceCap"(%"github.com/goplus/llgo/internal/runtime.Slice" %7) call void @"github.com/goplus/llgo/internal/runtime.PrintInt"(i64 4)
%33 = call ptr @"github.com/goplus/llgo/internal/runtime.SliceData"(%"github.com/goplus/llgo/internal/runtime.Slice" %7) %28 = call %"github.com/goplus/llgo/internal/runtime.String" @"github.com/goplus/llgo/internal/runtime.NewString"(ptr @9, i64 1)
%34 = call %"github.com/goplus/llgo/internal/runtime.Slice" @"github.com/goplus/llgo/internal/runtime.NewSlice3"(ptr %33, i64 8, i64 %32, i64 1, i64 2, i64 %32) call void @"github.com/goplus/llgo/internal/runtime.PrintString"(%"github.com/goplus/llgo/internal/runtime.String" %28)
%35 = call i64 @"github.com/goplus/llgo/internal/runtime.SliceLen"(%"github.com/goplus/llgo/internal/runtime.Slice" %34) %29 = call ptr @"github.com/goplus/llgo/internal/runtime.AllocZ"(i64 32)
call void @main.out(i64 %35) %30 = getelementptr inbounds i64, ptr %29, i64 0
%36 = call i64 @"github.com/goplus/llgo/internal/runtime.SliceCap"(%"github.com/goplus/llgo/internal/runtime.Slice" %7) store i64 1, ptr %30, align 4
%37 = call ptr @"github.com/goplus/llgo/internal/runtime.SliceData"(%"github.com/goplus/llgo/internal/runtime.Slice" %7) %31 = getelementptr inbounds i64, ptr %29, i64 1
%38 = call %"github.com/goplus/llgo/internal/runtime.Slice" @"github.com/goplus/llgo/internal/runtime.NewSlice3"(ptr %37, i64 8, i64 %36, i64 1, i64 2, i64 %36) store i64 2, ptr %31, align 4
%39 = call i64 @"github.com/goplus/llgo/internal/runtime.SliceCap"(%"github.com/goplus/llgo/internal/runtime.Slice" %38) %32 = getelementptr inbounds i64, ptr %29, i64 2
call void @main.out(i64 %39) store i64 3, ptr %32, align 4
%40 = call i64 @"github.com/goplus/llgo/internal/runtime.SliceCap"(%"github.com/goplus/llgo/internal/runtime.Slice" %7) %33 = getelementptr inbounds i64, ptr %29, i64 3
%41 = call ptr @"github.com/goplus/llgo/internal/runtime.SliceData"(%"github.com/goplus/llgo/internal/runtime.Slice" %7) store i64 4, ptr %33, align 4
%42 = call %"github.com/goplus/llgo/internal/runtime.Slice" @"github.com/goplus/llgo/internal/runtime.NewSlice3"(ptr %41, i64 8, i64 %40, i64 1, i64 2, i64 2) %34 = call %"github.com/goplus/llgo/internal/runtime.Slice" @"github.com/goplus/llgo/internal/runtime.NewSlice3"(ptr %29, i64 8, i64 4, i64 0, i64 4, i64 4)
%43 = call i64 @"github.com/goplus/llgo/internal/runtime.SliceLen"(%"github.com/goplus/llgo/internal/runtime.Slice" %42) %35 = extractvalue %"github.com/goplus/llgo/internal/runtime.Slice" %34, 1
call void @main.out(i64 %43) call void @"github.com/goplus/llgo/internal/runtime.PrintInt"(i64 %35)
%44 = call i64 @"github.com/goplus/llgo/internal/runtime.SliceCap"(%"github.com/goplus/llgo/internal/runtime.Slice" %7) %36 = call %"github.com/goplus/llgo/internal/runtime.String" @"github.com/goplus/llgo/internal/runtime.NewString"(ptr @10, i64 1)
%45 = call ptr @"github.com/goplus/llgo/internal/runtime.SliceData"(%"github.com/goplus/llgo/internal/runtime.Slice" %7) call void @"github.com/goplus/llgo/internal/runtime.PrintString"(%"github.com/goplus/llgo/internal/runtime.String" %36)
%46 = call %"github.com/goplus/llgo/internal/runtime.Slice" @"github.com/goplus/llgo/internal/runtime.NewSlice3"(ptr %45, i64 8, i64 %44, i64 1, i64 2, i64 2) call void @"github.com/goplus/llgo/internal/runtime.PrintInt"(i64 4)
%47 = call i64 @"github.com/goplus/llgo/internal/runtime.SliceCap"(%"github.com/goplus/llgo/internal/runtime.Slice" %46) %37 = call %"github.com/goplus/llgo/internal/runtime.String" @"github.com/goplus/llgo/internal/runtime.NewString"(ptr @11, i64 1)
call void @main.out(i64 %47) call void @"github.com/goplus/llgo/internal/runtime.PrintString"(%"github.com/goplus/llgo/internal/runtime.String" %37)
%48 = call %"github.com/goplus/llgo/internal/runtime.Slice" @"github.com/goplus/llgo/internal/runtime.NewSlice3"(ptr %8, i64 8, i64 4, i64 1, i64 4, i64 4) %38 = extractvalue %"github.com/goplus/llgo/internal/runtime.Slice" %7, 2
%49 = call i64 @"github.com/goplus/llgo/internal/runtime.SliceLen"(%"github.com/goplus/llgo/internal/runtime.Slice" %48) %39 = extractvalue %"github.com/goplus/llgo/internal/runtime.Slice" %7, 2
call void @main.out(i64 %49) %40 = extractvalue %"github.com/goplus/llgo/internal/runtime.Slice" %7, 0
%50 = call %"github.com/goplus/llgo/internal/runtime.Slice" @"github.com/goplus/llgo/internal/runtime.NewSlice3"(ptr %8, i64 8, i64 4, i64 1, i64 4, i64 4) %41 = call %"github.com/goplus/llgo/internal/runtime.Slice" @"github.com/goplus/llgo/internal/runtime.NewSlice3"(ptr %40, i64 8, i64 %38, i64 1, i64 %39, i64 %38)
%51 = call i64 @"github.com/goplus/llgo/internal/runtime.SliceCap"(%"github.com/goplus/llgo/internal/runtime.Slice" %50) %42 = extractvalue %"github.com/goplus/llgo/internal/runtime.Slice" %41, 1
call void @main.out(i64 %51) %43 = extractvalue %"github.com/goplus/llgo/internal/runtime.Slice" %7, 2
%52 = call %"github.com/goplus/llgo/internal/runtime.Slice" @"github.com/goplus/llgo/internal/runtime.NewSlice3"(ptr %8, i64 8, i64 4, i64 1, i64 2, i64 4) %44 = extractvalue %"github.com/goplus/llgo/internal/runtime.Slice" %7, 2
%53 = call i64 @"github.com/goplus/llgo/internal/runtime.SliceLen"(%"github.com/goplus/llgo/internal/runtime.Slice" %52) %45 = extractvalue %"github.com/goplus/llgo/internal/runtime.Slice" %7, 0
call void @main.out(i64 %53) %46 = call %"github.com/goplus/llgo/internal/runtime.Slice" @"github.com/goplus/llgo/internal/runtime.NewSlice3"(ptr %45, i64 8, i64 %43, i64 1, i64 %44, i64 %43)
%54 = call %"github.com/goplus/llgo/internal/runtime.Slice" @"github.com/goplus/llgo/internal/runtime.NewSlice3"(ptr %8, i64 8, i64 4, i64 1, i64 2, i64 4) %47 = extractvalue %"github.com/goplus/llgo/internal/runtime.Slice" %46, 2
%55 = call i64 @"github.com/goplus/llgo/internal/runtime.SliceCap"(%"github.com/goplus/llgo/internal/runtime.Slice" %54) %48 = extractvalue %"github.com/goplus/llgo/internal/runtime.Slice" %7, 2
call void @main.out(i64 %55) %49 = extractvalue %"github.com/goplus/llgo/internal/runtime.Slice" %7, 0
%56 = call %"github.com/goplus/llgo/internal/runtime.Slice" @"github.com/goplus/llgo/internal/runtime.NewSlice3"(ptr %8, i64 8, i64 4, i64 1, i64 2, i64 2) %50 = call %"github.com/goplus/llgo/internal/runtime.Slice" @"github.com/goplus/llgo/internal/runtime.NewSlice3"(ptr %49, i64 8, i64 %48, i64 1, i64 2, i64 %48)
%57 = call i64 @"github.com/goplus/llgo/internal/runtime.SliceLen"(%"github.com/goplus/llgo/internal/runtime.Slice" %56) %51 = extractvalue %"github.com/goplus/llgo/internal/runtime.Slice" %50, 1
call void @main.out(i64 %57) %52 = extractvalue %"github.com/goplus/llgo/internal/runtime.Slice" %7, 2
%58 = call %"github.com/goplus/llgo/internal/runtime.Slice" @"github.com/goplus/llgo/internal/runtime.NewSlice3"(ptr %8, i64 8, i64 4, i64 1, i64 2, i64 2) %53 = extractvalue %"github.com/goplus/llgo/internal/runtime.Slice" %7, 0
%59 = call i64 @"github.com/goplus/llgo/internal/runtime.SliceCap"(%"github.com/goplus/llgo/internal/runtime.Slice" %58) %54 = call %"github.com/goplus/llgo/internal/runtime.Slice" @"github.com/goplus/llgo/internal/runtime.NewSlice3"(ptr %53, i64 8, i64 %52, i64 1, i64 2, i64 %52)
call void @main.out(i64 %59) %55 = extractvalue %"github.com/goplus/llgo/internal/runtime.Slice" %54, 2
%60 = call %"github.com/goplus/llgo/internal/runtime.String" @"github.com/goplus/llgo/internal/runtime.NewString"(ptr @0, i64 5) %56 = extractvalue %"github.com/goplus/llgo/internal/runtime.Slice" %7, 2
call void @main.string_len(%"github.com/goplus/llgo/internal/runtime.String" %60) %57 = extractvalue %"github.com/goplus/llgo/internal/runtime.Slice" %7, 0
%61 = call %"github.com/goplus/llgo/internal/runtime.String" @"github.com/goplus/llgo/internal/runtime.NewString"(ptr @1, i64 5) %58 = call %"github.com/goplus/llgo/internal/runtime.Slice" @"github.com/goplus/llgo/internal/runtime.NewSlice3"(ptr %57, i64 8, i64 %56, i64 1, i64 2, i64 2)
%62 = extractvalue %"github.com/goplus/llgo/internal/runtime.String" %61, 1 %59 = extractvalue %"github.com/goplus/llgo/internal/runtime.Slice" %58, 1
%63 = call %"github.com/goplus/llgo/internal/runtime.String" @"github.com/goplus/llgo/internal/runtime.NewStringSlice"(%"github.com/goplus/llgo/internal/runtime.String" %61, i64 1, i64 %62) %60 = extractvalue %"github.com/goplus/llgo/internal/runtime.Slice" %7, 2
call void @main.string_len(%"github.com/goplus/llgo/internal/runtime.String" %63) %61 = extractvalue %"github.com/goplus/llgo/internal/runtime.Slice" %7, 0
%64 = call %"github.com/goplus/llgo/internal/runtime.String" @"github.com/goplus/llgo/internal/runtime.NewString"(ptr @2, i64 5) %62 = call %"github.com/goplus/llgo/internal/runtime.Slice" @"github.com/goplus/llgo/internal/runtime.NewSlice3"(ptr %61, i64 8, i64 %60, i64 1, i64 2, i64 2)
%65 = call %"github.com/goplus/llgo/internal/runtime.String" @"github.com/goplus/llgo/internal/runtime.NewStringSlice"(%"github.com/goplus/llgo/internal/runtime.String" %64, i64 1, i64 2) %63 = extractvalue %"github.com/goplus/llgo/internal/runtime.Slice" %62, 2
call void @main.string_len(%"github.com/goplus/llgo/internal/runtime.String" %65) call void @"github.com/goplus/llgo/internal/runtime.PrintInt"(i64 %42)
%66 = call %"github.com/goplus/llgo/internal/runtime.String" @"github.com/goplus/llgo/internal/runtime.NewString"(ptr @3, i64 5) %64 = call %"github.com/goplus/llgo/internal/runtime.String" @"github.com/goplus/llgo/internal/runtime.NewString"(ptr @12, i64 1)
%67 = extractvalue %"github.com/goplus/llgo/internal/runtime.String" %66, 1 call void @"github.com/goplus/llgo/internal/runtime.PrintString"(%"github.com/goplus/llgo/internal/runtime.String" %64)
%68 = call %"github.com/goplus/llgo/internal/runtime.String" @"github.com/goplus/llgo/internal/runtime.NewStringSlice"(%"github.com/goplus/llgo/internal/runtime.String" %66, i64 5, i64 %67) call void @"github.com/goplus/llgo/internal/runtime.PrintInt"(i64 %47)
call void @main.string_len(%"github.com/goplus/llgo/internal/runtime.String" %68) %65 = call %"github.com/goplus/llgo/internal/runtime.String" @"github.com/goplus/llgo/internal/runtime.NewString"(ptr @13, i64 1)
ret void call void @"github.com/goplus/llgo/internal/runtime.PrintString"(%"github.com/goplus/llgo/internal/runtime.String" %65)
} call void @"github.com/goplus/llgo/internal/runtime.PrintInt"(i64 %51)
%66 = call %"github.com/goplus/llgo/internal/runtime.String" @"github.com/goplus/llgo/internal/runtime.NewString"(ptr @14, i64 1)
define void @main.out(i64 %0) { call void @"github.com/goplus/llgo/internal/runtime.PrintString"(%"github.com/goplus/llgo/internal/runtime.String" %66)
_llgo_0: call void @"github.com/goplus/llgo/internal/runtime.PrintInt"(i64 %55)
%1 = call i32 (ptr, ...) @printf(ptr @4, i64 %0) %67 = call %"github.com/goplus/llgo/internal/runtime.String" @"github.com/goplus/llgo/internal/runtime.NewString"(ptr @15, i64 1)
ret void call void @"github.com/goplus/llgo/internal/runtime.PrintString"(%"github.com/goplus/llgo/internal/runtime.String" %67)
} call void @"github.com/goplus/llgo/internal/runtime.PrintInt"(i64 %59)
%68 = call %"github.com/goplus/llgo/internal/runtime.String" @"github.com/goplus/llgo/internal/runtime.NewString"(ptr @16, i64 1)
define void @main.string_len(%"github.com/goplus/llgo/internal/runtime.String" %0) { call void @"github.com/goplus/llgo/internal/runtime.PrintString"(%"github.com/goplus/llgo/internal/runtime.String" %68)
_llgo_0: call void @"github.com/goplus/llgo/internal/runtime.PrintInt"(i64 %63)
%1 = extractvalue %"github.com/goplus/llgo/internal/runtime.String" %0, 1 %69 = call %"github.com/goplus/llgo/internal/runtime.String" @"github.com/goplus/llgo/internal/runtime.NewString"(ptr @17, i64 1)
call void @main.out(i64 %1) call void @"github.com/goplus/llgo/internal/runtime.PrintString"(%"github.com/goplus/llgo/internal/runtime.String" %69)
%70 = call %"github.com/goplus/llgo/internal/runtime.Slice" @"github.com/goplus/llgo/internal/runtime.NewSlice3"(ptr %8, i64 8, i64 4, i64 1, i64 4, i64 4)
%71 = extractvalue %"github.com/goplus/llgo/internal/runtime.Slice" %70, 1
%72 = call %"github.com/goplus/llgo/internal/runtime.Slice" @"github.com/goplus/llgo/internal/runtime.NewSlice3"(ptr %8, i64 8, i64 4, i64 1, i64 4, i64 4)
%73 = extractvalue %"github.com/goplus/llgo/internal/runtime.Slice" %72, 2
%74 = call %"github.com/goplus/llgo/internal/runtime.Slice" @"github.com/goplus/llgo/internal/runtime.NewSlice3"(ptr %8, i64 8, i64 4, i64 1, i64 2, i64 4)
%75 = extractvalue %"github.com/goplus/llgo/internal/runtime.Slice" %74, 1
%76 = call %"github.com/goplus/llgo/internal/runtime.Slice" @"github.com/goplus/llgo/internal/runtime.NewSlice3"(ptr %8, i64 8, i64 4, i64 1, i64 2, i64 4)
%77 = extractvalue %"github.com/goplus/llgo/internal/runtime.Slice" %76, 2
%78 = call %"github.com/goplus/llgo/internal/runtime.Slice" @"github.com/goplus/llgo/internal/runtime.NewSlice3"(ptr %8, i64 8, i64 4, i64 1, i64 2, i64 2)
%79 = extractvalue %"github.com/goplus/llgo/internal/runtime.Slice" %78, 1
%80 = call %"github.com/goplus/llgo/internal/runtime.Slice" @"github.com/goplus/llgo/internal/runtime.NewSlice3"(ptr %8, i64 8, i64 4, i64 1, i64 2, i64 2)
%81 = extractvalue %"github.com/goplus/llgo/internal/runtime.Slice" %80, 2
call void @"github.com/goplus/llgo/internal/runtime.PrintInt"(i64 %71)
%82 = call %"github.com/goplus/llgo/internal/runtime.String" @"github.com/goplus/llgo/internal/runtime.NewString"(ptr @18, i64 1)
call void @"github.com/goplus/llgo/internal/runtime.PrintString"(%"github.com/goplus/llgo/internal/runtime.String" %82)
call void @"github.com/goplus/llgo/internal/runtime.PrintInt"(i64 %73)
%83 = call %"github.com/goplus/llgo/internal/runtime.String" @"github.com/goplus/llgo/internal/runtime.NewString"(ptr @19, i64 1)
call void @"github.com/goplus/llgo/internal/runtime.PrintString"(%"github.com/goplus/llgo/internal/runtime.String" %83)
call void @"github.com/goplus/llgo/internal/runtime.PrintInt"(i64 %75)
%84 = call %"github.com/goplus/llgo/internal/runtime.String" @"github.com/goplus/llgo/internal/runtime.NewString"(ptr @20, i64 1)
call void @"github.com/goplus/llgo/internal/runtime.PrintString"(%"github.com/goplus/llgo/internal/runtime.String" %84)
call void @"github.com/goplus/llgo/internal/runtime.PrintInt"(i64 %77)
%85 = call %"github.com/goplus/llgo/internal/runtime.String" @"github.com/goplus/llgo/internal/runtime.NewString"(ptr @21, i64 1)
call void @"github.com/goplus/llgo/internal/runtime.PrintString"(%"github.com/goplus/llgo/internal/runtime.String" %85)
call void @"github.com/goplus/llgo/internal/runtime.PrintInt"(i64 %79)
%86 = call %"github.com/goplus/llgo/internal/runtime.String" @"github.com/goplus/llgo/internal/runtime.NewString"(ptr @22, i64 1)
call void @"github.com/goplus/llgo/internal/runtime.PrintString"(%"github.com/goplus/llgo/internal/runtime.String" %86)
call void @"github.com/goplus/llgo/internal/runtime.PrintInt"(i64 %81)
%87 = call %"github.com/goplus/llgo/internal/runtime.String" @"github.com/goplus/llgo/internal/runtime.NewString"(ptr @23, i64 1)
call void @"github.com/goplus/llgo/internal/runtime.PrintString"(%"github.com/goplus/llgo/internal/runtime.String" %87)
%88 = call %"github.com/goplus/llgo/internal/runtime.String" @"github.com/goplus/llgo/internal/runtime.NewString"(ptr @24, i64 5)
%89 = extractvalue %"github.com/goplus/llgo/internal/runtime.String" %88, 1
%90 = call %"github.com/goplus/llgo/internal/runtime.String" @"github.com/goplus/llgo/internal/runtime.NewStringSlice"(%"github.com/goplus/llgo/internal/runtime.String" %88, i64 1, i64 %89)
%91 = call %"github.com/goplus/llgo/internal/runtime.String" @"github.com/goplus/llgo/internal/runtime.NewString"(ptr @25, i64 5)
%92 = call %"github.com/goplus/llgo/internal/runtime.String" @"github.com/goplus/llgo/internal/runtime.NewStringSlice"(%"github.com/goplus/llgo/internal/runtime.String" %91, i64 1, i64 2)
%93 = call %"github.com/goplus/llgo/internal/runtime.String" @"github.com/goplus/llgo/internal/runtime.NewString"(ptr @26, i64 5)
%94 = extractvalue %"github.com/goplus/llgo/internal/runtime.String" %93, 1
%95 = call %"github.com/goplus/llgo/internal/runtime.String" @"github.com/goplus/llgo/internal/runtime.NewStringSlice"(%"github.com/goplus/llgo/internal/runtime.String" %93, i64 5, i64 %94)
%96 = extractvalue %"github.com/goplus/llgo/internal/runtime.String" %95, 1
%97 = call %"github.com/goplus/llgo/internal/runtime.String" @"github.com/goplus/llgo/internal/runtime.NewString"(ptr @27, i64 5)
call void @"github.com/goplus/llgo/internal/runtime.PrintString"(%"github.com/goplus/llgo/internal/runtime.String" %97)
%98 = call %"github.com/goplus/llgo/internal/runtime.String" @"github.com/goplus/llgo/internal/runtime.NewString"(ptr @28, i64 1)
call void @"github.com/goplus/llgo/internal/runtime.PrintString"(%"github.com/goplus/llgo/internal/runtime.String" %98)
call void @"github.com/goplus/llgo/internal/runtime.PrintString"(%"github.com/goplus/llgo/internal/runtime.String" %90)
%99 = call %"github.com/goplus/llgo/internal/runtime.String" @"github.com/goplus/llgo/internal/runtime.NewString"(ptr @29, i64 1)
call void @"github.com/goplus/llgo/internal/runtime.PrintString"(%"github.com/goplus/llgo/internal/runtime.String" %99)
call void @"github.com/goplus/llgo/internal/runtime.PrintString"(%"github.com/goplus/llgo/internal/runtime.String" %92)
%100 = call %"github.com/goplus/llgo/internal/runtime.String" @"github.com/goplus/llgo/internal/runtime.NewString"(ptr @30, i64 1)
call void @"github.com/goplus/llgo/internal/runtime.PrintString"(%"github.com/goplus/llgo/internal/runtime.String" %100)
call void @"github.com/goplus/llgo/internal/runtime.PrintInt"(i64 %96)
%101 = call %"github.com/goplus/llgo/internal/runtime.String" @"github.com/goplus/llgo/internal/runtime.NewString"(ptr @31, i64 1)
call void @"github.com/goplus/llgo/internal/runtime.PrintString"(%"github.com/goplus/llgo/internal/runtime.String" %101)
%102 = call ptr @"github.com/goplus/llgo/internal/runtime.AllocZ"(i64 32)
%103 = getelementptr inbounds i64, ptr %102, i64 0
store i64 5, ptr %103, align 4
%104 = getelementptr inbounds i64, ptr %102, i64 1
store i64 6, ptr %104, align 4
%105 = getelementptr inbounds i64, ptr %102, i64 2
store i64 7, ptr %105, align 4
%106 = getelementptr inbounds i64, ptr %102, i64 3
store i64 8, ptr %106, align 4
%107 = call %"github.com/goplus/llgo/internal/runtime.Slice" @"github.com/goplus/llgo/internal/runtime.NewSlice3"(ptr %102, i64 8, i64 4, i64 0, i64 4, i64 4)
%108 = extractvalue %"github.com/goplus/llgo/internal/runtime.Slice" %107, 0
%109 = extractvalue %"github.com/goplus/llgo/internal/runtime.Slice" %107, 1
%110 = call %"github.com/goplus/llgo/internal/runtime.Slice" @"github.com/goplus/llgo/internal/runtime.SliceAppend"(%"github.com/goplus/llgo/internal/runtime.Slice" %7, ptr %108, i64 %109, i64 8)
call void @"github.com/goplus/llgo/internal/runtime.PrintSlice"(%"github.com/goplus/llgo/internal/runtime.Slice" %110)
%111 = call %"github.com/goplus/llgo/internal/runtime.String" @"github.com/goplus/llgo/internal/runtime.NewString"(ptr @32, i64 1)
call void @"github.com/goplus/llgo/internal/runtime.PrintString"(%"github.com/goplus/llgo/internal/runtime.String" %111)
%112 = call ptr @"github.com/goplus/llgo/internal/runtime.AllocZ"(i64 3)
%113 = getelementptr inbounds i8, ptr %112, i64 0
store i8 97, ptr %113, align 1
%114 = getelementptr inbounds i8, ptr %112, i64 1
store i8 98, ptr %114, align 1
%115 = getelementptr inbounds i8, ptr %112, i64 2
store i8 99, ptr %115, align 1
%116 = call %"github.com/goplus/llgo/internal/runtime.Slice" @"github.com/goplus/llgo/internal/runtime.NewSlice3"(ptr %112, i64 1, i64 3, i64 0, i64 3, i64 3)
%117 = call %"github.com/goplus/llgo/internal/runtime.String" @"github.com/goplus/llgo/internal/runtime.NewString"(ptr @33, i64 3)
%118 = extractvalue %"github.com/goplus/llgo/internal/runtime.String" %117, 0
%119 = extractvalue %"github.com/goplus/llgo/internal/runtime.String" %117, 1
%120 = call %"github.com/goplus/llgo/internal/runtime.Slice" @"github.com/goplus/llgo/internal/runtime.SliceAppend"(%"github.com/goplus/llgo/internal/runtime.Slice" %116, ptr %118, i64 %119, i64 1)
call void @"github.com/goplus/llgo/internal/runtime.PrintSlice"(%"github.com/goplus/llgo/internal/runtime.Slice" %120)
%121 = call %"github.com/goplus/llgo/internal/runtime.String" @"github.com/goplus/llgo/internal/runtime.NewString"(ptr @34, i64 1)
call void @"github.com/goplus/llgo/internal/runtime.PrintString"(%"github.com/goplus/llgo/internal/runtime.String" %121)
%122 = call ptr @"github.com/goplus/llgo/internal/runtime.AllocZ"(i64 16)
%123 = call ptr @"github.com/goplus/llgo/internal/runtime.Basic"(i64 2)
%124 = call %"github.com/goplus/llgo/internal/runtime.iface" @"github.com/goplus/llgo/internal/runtime.MakeAnyInt"(ptr %123, i64 100)
store %"github.com/goplus/llgo/internal/runtime.iface" %124, ptr %122, align 8
%125 = load %"github.com/goplus/llgo/internal/runtime.iface", ptr %122, align 8
%126 = ptrtoint ptr %122 to i64
call void @"github.com/goplus/llgo/internal/runtime.PrintBool"(i1 true)
%127 = call %"github.com/goplus/llgo/internal/runtime.String" @"github.com/goplus/llgo/internal/runtime.NewString"(ptr @35, i64 1)
call void @"github.com/goplus/llgo/internal/runtime.PrintString"(%"github.com/goplus/llgo/internal/runtime.String" %127)
call void @"github.com/goplus/llgo/internal/runtime.PrintInt"(i64 100)
%128 = call %"github.com/goplus/llgo/internal/runtime.String" @"github.com/goplus/llgo/internal/runtime.NewString"(ptr @36, i64 1)
call void @"github.com/goplus/llgo/internal/runtime.PrintString"(%"github.com/goplus/llgo/internal/runtime.String" %128)
call void @"github.com/goplus/llgo/internal/runtime.PrintInt"(i64 -100)
%129 = call %"github.com/goplus/llgo/internal/runtime.String" @"github.com/goplus/llgo/internal/runtime.NewString"(ptr @37, i64 1)
call void @"github.com/goplus/llgo/internal/runtime.PrintString"(%"github.com/goplus/llgo/internal/runtime.String" %129)
call void @"github.com/goplus/llgo/internal/runtime.PrintUint"(i64 100)
%130 = call %"github.com/goplus/llgo/internal/runtime.String" @"github.com/goplus/llgo/internal/runtime.NewString"(ptr @38, i64 1)
call void @"github.com/goplus/llgo/internal/runtime.PrintString"(%"github.com/goplus/llgo/internal/runtime.String" %130)
call void @"github.com/goplus/llgo/internal/runtime.PrintInt"(i64 -100)
%131 = call %"github.com/goplus/llgo/internal/runtime.String" @"github.com/goplus/llgo/internal/runtime.NewString"(ptr @39, i64 1)
call void @"github.com/goplus/llgo/internal/runtime.PrintString"(%"github.com/goplus/llgo/internal/runtime.String" %131)
call void @"github.com/goplus/llgo/internal/runtime.PrintFloat"(double 1.005000e+02)
%132 = call %"github.com/goplus/llgo/internal/runtime.String" @"github.com/goplus/llgo/internal/runtime.NewString"(ptr @40, i64 1)
call void @"github.com/goplus/llgo/internal/runtime.PrintString"(%"github.com/goplus/llgo/internal/runtime.String" %132)
call void @"github.com/goplus/llgo/internal/runtime.PrintIface"(%"github.com/goplus/llgo/internal/runtime.iface" %125)
%133 = call %"github.com/goplus/llgo/internal/runtime.String" @"github.com/goplus/llgo/internal/runtime.NewString"(ptr @41, i64 1)
call void @"github.com/goplus/llgo/internal/runtime.PrintString"(%"github.com/goplus/llgo/internal/runtime.String" %133)
call void @"github.com/goplus/llgo/internal/runtime.PrintPointer"(ptr %122)
%134 = call %"github.com/goplus/llgo/internal/runtime.String" @"github.com/goplus/llgo/internal/runtime.NewString"(ptr @42, i64 1)
call void @"github.com/goplus/llgo/internal/runtime.PrintString"(%"github.com/goplus/llgo/internal/runtime.String" %134)
call void @"github.com/goplus/llgo/internal/runtime.PrintUint"(i64 %126)
%135 = call %"github.com/goplus/llgo/internal/runtime.String" @"github.com/goplus/llgo/internal/runtime.NewString"(ptr @43, i64 1)
call void @"github.com/goplus/llgo/internal/runtime.PrintString"(%"github.com/goplus/llgo/internal/runtime.String" %135)
ret void ret void
} }
@@ -163,14 +319,28 @@ declare ptr @"github.com/goplus/llgo/internal/runtime.AllocZ"(i64)
declare %"github.com/goplus/llgo/internal/runtime.Slice" @"github.com/goplus/llgo/internal/runtime.NewSlice3"(ptr, i64, i64, i64, i64, i64) declare %"github.com/goplus/llgo/internal/runtime.Slice" @"github.com/goplus/llgo/internal/runtime.NewSlice3"(ptr, i64, i64, i64, i64, i64)
declare i64 @"github.com/goplus/llgo/internal/runtime.SliceLen"(%"github.com/goplus/llgo/internal/runtime.Slice") declare void @"github.com/goplus/llgo/internal/runtime.PrintSlice"(%"github.com/goplus/llgo/internal/runtime.Slice")
declare i64 @"github.com/goplus/llgo/internal/runtime.SliceCap"(%"github.com/goplus/llgo/internal/runtime.Slice") declare void @"github.com/goplus/llgo/internal/runtime.PrintString"(%"github.com/goplus/llgo/internal/runtime.String")
declare ptr @"github.com/goplus/llgo/internal/runtime.SliceData"(%"github.com/goplus/llgo/internal/runtime.Slice")
declare %"github.com/goplus/llgo/internal/runtime.String" @"github.com/goplus/llgo/internal/runtime.NewString"(ptr, i64) declare %"github.com/goplus/llgo/internal/runtime.String" @"github.com/goplus/llgo/internal/runtime.NewString"(ptr, i64)
declare void @"github.com/goplus/llgo/internal/runtime.PrintInt"(i64)
declare %"github.com/goplus/llgo/internal/runtime.String" @"github.com/goplus/llgo/internal/runtime.NewStringSlice"(%"github.com/goplus/llgo/internal/runtime.String", i64, i64) declare %"github.com/goplus/llgo/internal/runtime.String" @"github.com/goplus/llgo/internal/runtime.NewStringSlice"(%"github.com/goplus/llgo/internal/runtime.String", i64, i64)
declare i32 @printf(ptr, ...) declare %"github.com/goplus/llgo/internal/runtime.Slice" @"github.com/goplus/llgo/internal/runtime.SliceAppend"(%"github.com/goplus/llgo/internal/runtime.Slice", ptr, i64, i64)
declare ptr @"github.com/goplus/llgo/internal/runtime.Basic"(i64)
declare %"github.com/goplus/llgo/internal/runtime.iface" @"github.com/goplus/llgo/internal/runtime.MakeAnyInt"(ptr, i64)
declare void @"github.com/goplus/llgo/internal/runtime.PrintBool"(i1)
declare void @"github.com/goplus/llgo/internal/runtime.PrintUint"(i64)
declare void @"github.com/goplus/llgo/internal/runtime.PrintFloat"(double)
declare void @"github.com/goplus/llgo/internal/runtime.PrintIface"(%"github.com/goplus/llgo/internal/runtime.iface")
declare void @"github.com/goplus/llgo/internal/runtime.PrintPointer"(ptr)

View File

@@ -11,6 +11,10 @@ func concat(args ...string) (ret string) {
return return
} }
func info(s string) string {
return "" + s + "..."
}
func main() { func main() {
result := concat("Hello", " ", "World") result := concat("Hello", " ", "World")
c.Fprintf(c.Stderr, c.Str("Hi, %s\n"), c.AllocaCStr(result)) c.Fprintf(c.Stderr, c.Str("Hi, %s\n"), c.AllocaCStr(result))

View File

@@ -6,17 +6,19 @@ source_filename = "main"
@"main.init$guard" = global ptr null @"main.init$guard" = global ptr null
@0 = private unnamed_addr constant [1 x i8] zeroinitializer, align 1 @0 = private unnamed_addr constant [1 x i8] zeroinitializer, align 1
@1 = private unnamed_addr constant [1 x i8] zeroinitializer, align 1
@2 = private unnamed_addr constant [4 x i8] c"...\00", align 1
@__llgo_argc = global ptr null @__llgo_argc = global ptr null
@__llgo_argv = global ptr null @__llgo_argv = global ptr null
@1 = private unnamed_addr constant [6 x i8] c"Hello\00", align 1 @3 = private unnamed_addr constant [6 x i8] c"Hello\00", align 1
@2 = private unnamed_addr constant [2 x i8] c" \00", align 1 @4 = private unnamed_addr constant [2 x i8] c" \00", align 1
@3 = private unnamed_addr constant [6 x i8] c"World\00", align 1 @5 = private unnamed_addr constant [6 x i8] c"World\00", align 1
@__stderrp = external global ptr @__stderrp = external global ptr
@4 = private unnamed_addr constant [8 x i8] c"Hi, %s\0A\00", align 1 @6 = private unnamed_addr constant [8 x i8] c"Hi, %s\0A\00", align 1
define %"github.com/goplus/llgo/internal/runtime.String" @main.concat(%"github.com/goplus/llgo/internal/runtime.Slice" %0) { define %"github.com/goplus/llgo/internal/runtime.String" @main.concat(%"github.com/goplus/llgo/internal/runtime.Slice" %0) {
_llgo_0: _llgo_0:
%1 = call i64 @"github.com/goplus/llgo/internal/runtime.SliceLen"(%"github.com/goplus/llgo/internal/runtime.Slice" %0) %1 = extractvalue %"github.com/goplus/llgo/internal/runtime.Slice" %0, 1
%2 = call %"github.com/goplus/llgo/internal/runtime.String" @"github.com/goplus/llgo/internal/runtime.NewString"(ptr @0, i64 0) %2 = call %"github.com/goplus/llgo/internal/runtime.String" @"github.com/goplus/llgo/internal/runtime.NewString"(ptr @0, i64 0)
%3 = extractvalue %"github.com/goplus/llgo/internal/runtime.String" %2, 0 %3 = extractvalue %"github.com/goplus/llgo/internal/runtime.String" %2, 0
%4 = extractvalue %"github.com/goplus/llgo/internal/runtime.String" %2, 1 %4 = extractvalue %"github.com/goplus/llgo/internal/runtime.String" %2, 1
@@ -37,7 +39,7 @@ _llgo_1: ; preds = %_llgo_2, %_llgo_0
br i1 %13, label %_llgo_2, label %_llgo_3 br i1 %13, label %_llgo_2, label %_llgo_3
_llgo_2: ; preds = %_llgo_1 _llgo_2: ; preds = %_llgo_1
%14 = call ptr @"github.com/goplus/llgo/internal/runtime.SliceData"(%"github.com/goplus/llgo/internal/runtime.Slice" %0) %14 = extractvalue %"github.com/goplus/llgo/internal/runtime.Slice" %0, 0
%15 = getelementptr inbounds %"github.com/goplus/llgo/internal/runtime.String", ptr %14, i64 %12 %15 = getelementptr inbounds %"github.com/goplus/llgo/internal/runtime.String", ptr %14, i64 %12
%16 = load %"github.com/goplus/llgo/internal/runtime.String", ptr %15, align 8 %16 = load %"github.com/goplus/llgo/internal/runtime.String", ptr %15, align 8
%17 = call %"github.com/goplus/llgo/internal/runtime.String" @"github.com/goplus/llgo/internal/runtime.StringCat"(%"github.com/goplus/llgo/internal/runtime.String" %11, %"github.com/goplus/llgo/internal/runtime.String" %16) %17 = call %"github.com/goplus/llgo/internal/runtime.String" @"github.com/goplus/llgo/internal/runtime.StringCat"(%"github.com/goplus/llgo/internal/runtime.String" %11, %"github.com/goplus/llgo/internal/runtime.String" %16)
@@ -49,6 +51,15 @@ _llgo_3: ; preds = %_llgo_1
ret %"github.com/goplus/llgo/internal/runtime.String" %11 ret %"github.com/goplus/llgo/internal/runtime.String" %11
} }
define %"github.com/goplus/llgo/internal/runtime.String" @main.info(%"github.com/goplus/llgo/internal/runtime.String" %0) {
_llgo_0:
%1 = call %"github.com/goplus/llgo/internal/runtime.String" @"github.com/goplus/llgo/internal/runtime.NewString"(ptr @1, i64 0)
%2 = call %"github.com/goplus/llgo/internal/runtime.String" @"github.com/goplus/llgo/internal/runtime.StringCat"(%"github.com/goplus/llgo/internal/runtime.String" %1, %"github.com/goplus/llgo/internal/runtime.String" %0)
%3 = call %"github.com/goplus/llgo/internal/runtime.String" @"github.com/goplus/llgo/internal/runtime.NewString"(ptr @2, i64 3)
%4 = call %"github.com/goplus/llgo/internal/runtime.String" @"github.com/goplus/llgo/internal/runtime.StringCat"(%"github.com/goplus/llgo/internal/runtime.String" %2, %"github.com/goplus/llgo/internal/runtime.String" %3)
ret %"github.com/goplus/llgo/internal/runtime.String" %4
}
define void @main.init() { define void @main.init() {
_llgo_0: _llgo_0:
%0 = load i1, ptr @"main.init$guard", align 1 %0 = load i1, ptr @"main.init$guard", align 1
@@ -70,13 +81,13 @@ _llgo_0:
call void @main.init() call void @main.init()
%2 = call ptr @"github.com/goplus/llgo/internal/runtime.AllocZ"(i64 48) %2 = call ptr @"github.com/goplus/llgo/internal/runtime.AllocZ"(i64 48)
%3 = getelementptr inbounds %"github.com/goplus/llgo/internal/runtime.String", ptr %2, i64 0 %3 = getelementptr inbounds %"github.com/goplus/llgo/internal/runtime.String", ptr %2, i64 0
%4 = call %"github.com/goplus/llgo/internal/runtime.String" @"github.com/goplus/llgo/internal/runtime.NewString"(ptr @1, i64 5) %4 = call %"github.com/goplus/llgo/internal/runtime.String" @"github.com/goplus/llgo/internal/runtime.NewString"(ptr @3, i64 5)
store %"github.com/goplus/llgo/internal/runtime.String" %4, ptr %3, align 8 store %"github.com/goplus/llgo/internal/runtime.String" %4, ptr %3, align 8
%5 = getelementptr inbounds %"github.com/goplus/llgo/internal/runtime.String", ptr %2, i64 1 %5 = getelementptr inbounds %"github.com/goplus/llgo/internal/runtime.String", ptr %2, i64 1
%6 = call %"github.com/goplus/llgo/internal/runtime.String" @"github.com/goplus/llgo/internal/runtime.NewString"(ptr @2, i64 1) %6 = call %"github.com/goplus/llgo/internal/runtime.String" @"github.com/goplus/llgo/internal/runtime.NewString"(ptr @4, i64 1)
store %"github.com/goplus/llgo/internal/runtime.String" %6, ptr %5, align 8 store %"github.com/goplus/llgo/internal/runtime.String" %6, ptr %5, align 8
%7 = getelementptr inbounds %"github.com/goplus/llgo/internal/runtime.String", ptr %2, i64 2 %7 = getelementptr inbounds %"github.com/goplus/llgo/internal/runtime.String", ptr %2, i64 2
%8 = call %"github.com/goplus/llgo/internal/runtime.String" @"github.com/goplus/llgo/internal/runtime.NewString"(ptr @3, i64 5) %8 = call %"github.com/goplus/llgo/internal/runtime.String" @"github.com/goplus/llgo/internal/runtime.NewString"(ptr @5, i64 5)
store %"github.com/goplus/llgo/internal/runtime.String" %8, ptr %7, align 8 store %"github.com/goplus/llgo/internal/runtime.String" %8, ptr %7, align 8
%9 = call %"github.com/goplus/llgo/internal/runtime.Slice" @"github.com/goplus/llgo/internal/runtime.NewSlice3"(ptr %2, i64 16, i64 3, i64 0, i64 3, i64 3) %9 = call %"github.com/goplus/llgo/internal/runtime.Slice" @"github.com/goplus/llgo/internal/runtime.NewSlice3"(ptr %2, i64 16, i64 3, i64 0, i64 3, i64 3)
%10 = call %"github.com/goplus/llgo/internal/runtime.String" @main.concat(%"github.com/goplus/llgo/internal/runtime.Slice" %9) %10 = call %"github.com/goplus/llgo/internal/runtime.String" @main.concat(%"github.com/goplus/llgo/internal/runtime.Slice" %9)
@@ -85,14 +96,10 @@ _llgo_0:
%13 = add i64 %12, 1 %13 = add i64 %12, 1
%14 = alloca i8, i64 %13, align 1 %14 = alloca i8, i64 %13, align 1
%15 = call ptr @"github.com/goplus/llgo/internal/runtime.CStrCopy"(ptr %14, %"github.com/goplus/llgo/internal/runtime.String" %10) %15 = call ptr @"github.com/goplus/llgo/internal/runtime.CStrCopy"(ptr %14, %"github.com/goplus/llgo/internal/runtime.String" %10)
%16 = call i32 (ptr, ptr, ...) @fprintf(ptr %11, ptr @4, ptr %15) %16 = call i32 (ptr, ptr, ...) @fprintf(ptr %11, ptr @6, ptr %15)
ret void ret void
} }
declare i64 @"github.com/goplus/llgo/internal/runtime.SliceLen"(%"github.com/goplus/llgo/internal/runtime.Slice")
declare ptr @"github.com/goplus/llgo/internal/runtime.SliceData"(%"github.com/goplus/llgo/internal/runtime.Slice")
declare %"github.com/goplus/llgo/internal/runtime.String" @"github.com/goplus/llgo/internal/runtime.StringCat"(%"github.com/goplus/llgo/internal/runtime.String", %"github.com/goplus/llgo/internal/runtime.String") declare %"github.com/goplus/llgo/internal/runtime.String" @"github.com/goplus/llgo/internal/runtime.StringCat"(%"github.com/goplus/llgo/internal/runtime.String", %"github.com/goplus/llgo/internal/runtime.String")
declare %"github.com/goplus/llgo/internal/runtime.String" @"github.com/goplus/llgo/internal/runtime.NewString"(ptr, i64) declare %"github.com/goplus/llgo/internal/runtime.String" @"github.com/goplus/llgo/internal/runtime.NewString"(ptr, i64)

View File

@@ -16,7 +16,7 @@ _llgo_0:
%2 = mul i64 %0, 4 %2 = mul i64 %0, 4
%3 = call ptr @"github.com/goplus/llgo/internal/runtime.AllocZ"(i64 %2) %3 = call ptr @"github.com/goplus/llgo/internal/runtime.AllocZ"(i64 %2)
%4 = call %"github.com/goplus/llgo/internal/runtime.Slice" @"github.com/goplus/llgo/internal/runtime.NewSlice"(ptr %3, i64 %0, i64 %0) %4 = call %"github.com/goplus/llgo/internal/runtime.Slice" @"github.com/goplus/llgo/internal/runtime.NewSlice"(ptr %3, i64 %0, i64 %0)
%5 = call i64 @"github.com/goplus/llgo/internal/runtime.SliceLen"(%"github.com/goplus/llgo/internal/runtime.Slice" %4) %5 = extractvalue %"github.com/goplus/llgo/internal/runtime.Slice" %4, 1
br label %_llgo_1 br label %_llgo_1
_llgo_1: ; preds = %_llgo_2, %_llgo_0 _llgo_1: ; preds = %_llgo_2, %_llgo_0
@@ -29,7 +29,7 @@ _llgo_2: ; preds = %_llgo_1
%9 = extractvalue { ptr, ptr } %1, 1 %9 = extractvalue { ptr, ptr } %1, 1
%10 = extractvalue { ptr, ptr } %1, 0 %10 = extractvalue { ptr, ptr } %1, 0
%11 = call i32 %10(ptr %9) %11 = call i32 %10(ptr %9)
%12 = call ptr @"github.com/goplus/llgo/internal/runtime.SliceData"(%"github.com/goplus/llgo/internal/runtime.Slice" %4) %12 = extractvalue %"github.com/goplus/llgo/internal/runtime.Slice" %4, 0
%13 = getelementptr inbounds i32, ptr %12, i64 %7 %13 = getelementptr inbounds i32, ptr %12, i64 %7
store i32 %11, ptr %13, align 4 store i32 %11, ptr %13, align 4
br label %_llgo_1 br label %_llgo_1
@@ -76,7 +76,7 @@ _llgo_0:
store ptr null, ptr %4, align 8 store ptr null, ptr %4, align 8
%5 = load { ptr, ptr }, ptr %2, align 8 %5 = load { ptr, ptr }, ptr %2, align 8
%6 = call %"github.com/goplus/llgo/internal/runtime.Slice" @main.genInts(i64 5, { ptr, ptr } %5) %6 = call %"github.com/goplus/llgo/internal/runtime.Slice" @main.genInts(i64 5, { ptr, ptr } %5)
%7 = call i64 @"github.com/goplus/llgo/internal/runtime.SliceLen"(%"github.com/goplus/llgo/internal/runtime.Slice" %6) %7 = extractvalue %"github.com/goplus/llgo/internal/runtime.Slice" %6, 1
br label %_llgo_1 br label %_llgo_1
_llgo_1: ; preds = %_llgo_2, %_llgo_0 _llgo_1: ; preds = %_llgo_2, %_llgo_0
@@ -86,7 +86,7 @@ _llgo_1: ; preds = %_llgo_2, %_llgo_0
br i1 %10, label %_llgo_2, label %_llgo_3 br i1 %10, label %_llgo_2, label %_llgo_3
_llgo_2: ; preds = %_llgo_1 _llgo_2: ; preds = %_llgo_1
%11 = call ptr @"github.com/goplus/llgo/internal/runtime.SliceData"(%"github.com/goplus/llgo/internal/runtime.Slice" %6) %11 = extractvalue %"github.com/goplus/llgo/internal/runtime.Slice" %6, 0
%12 = getelementptr inbounds i32, ptr %11, i64 %9 %12 = getelementptr inbounds i32, ptr %11, i64 %9
%13 = load i32, ptr %12, align 4 %13 = load i32, ptr %12, align 4
%14 = call i32 (ptr, ...) @printf(ptr @0, i32 %13) %14 = call i32 (ptr, ...) @printf(ptr @0, i32 %13)
@@ -105,7 +105,7 @@ _llgo_3: ; preds = %_llgo_1
store ptr %16, ptr %20, align 8 store ptr %16, ptr %20, align 8
%21 = load { ptr, ptr }, ptr %18, align 8 %21 = load { ptr, ptr }, ptr %18, align 8
%22 = call %"github.com/goplus/llgo/internal/runtime.Slice" @main.genInts(i64 5, { ptr, ptr } %21) %22 = call %"github.com/goplus/llgo/internal/runtime.Slice" @main.genInts(i64 5, { ptr, ptr } %21)
%23 = call i64 @"github.com/goplus/llgo/internal/runtime.SliceLen"(%"github.com/goplus/llgo/internal/runtime.Slice" %22) %23 = extractvalue %"github.com/goplus/llgo/internal/runtime.Slice" %22, 1
br label %_llgo_4 br label %_llgo_4
_llgo_4: ; preds = %_llgo_5, %_llgo_3 _llgo_4: ; preds = %_llgo_5, %_llgo_3
@@ -115,7 +115,7 @@ _llgo_4: ; preds = %_llgo_5, %_llgo_3
br i1 %26, label %_llgo_5, label %_llgo_6 br i1 %26, label %_llgo_5, label %_llgo_6
_llgo_5: ; preds = %_llgo_4 _llgo_5: ; preds = %_llgo_4
%27 = call ptr @"github.com/goplus/llgo/internal/runtime.SliceData"(%"github.com/goplus/llgo/internal/runtime.Slice" %22) %27 = extractvalue %"github.com/goplus/llgo/internal/runtime.Slice" %22, 0
%28 = getelementptr inbounds i32, ptr %27, i64 %25 %28 = getelementptr inbounds i32, ptr %27, i64 %25
%29 = load i32, ptr %28, align 4 %29 = load i32, ptr %28, align 4
%30 = call i32 (ptr, ...) @printf(ptr @1, i32 %29) %30 = call i32 (ptr, ...) @printf(ptr @1, i32 %29)
@@ -135,7 +135,7 @@ _llgo_6: ; preds = %_llgo_4
store ptr %33, ptr %37, align 8 store ptr %33, ptr %37, align 8
%38 = load { ptr, ptr }, ptr %35, align 8 %38 = load { ptr, ptr }, ptr %35, align 8
%39 = call %"github.com/goplus/llgo/internal/runtime.Slice" @main.genInts(i64 5, { ptr, ptr } %38) %39 = call %"github.com/goplus/llgo/internal/runtime.Slice" @main.genInts(i64 5, { ptr, ptr } %38)
%40 = call i64 @"github.com/goplus/llgo/internal/runtime.SliceLen"(%"github.com/goplus/llgo/internal/runtime.Slice" %39) %40 = extractvalue %"github.com/goplus/llgo/internal/runtime.Slice" %39, 1
br label %_llgo_7 br label %_llgo_7
_llgo_7: ; preds = %_llgo_8, %_llgo_6 _llgo_7: ; preds = %_llgo_8, %_llgo_6
@@ -145,7 +145,7 @@ _llgo_7: ; preds = %_llgo_8, %_llgo_6
br i1 %43, label %_llgo_8, label %_llgo_9 br i1 %43, label %_llgo_8, label %_llgo_9
_llgo_8: ; preds = %_llgo_7 _llgo_8: ; preds = %_llgo_7
%44 = call ptr @"github.com/goplus/llgo/internal/runtime.SliceData"(%"github.com/goplus/llgo/internal/runtime.Slice" %39) %44 = extractvalue %"github.com/goplus/llgo/internal/runtime.Slice" %39, 0
%45 = getelementptr inbounds i32, ptr %44, i64 %42 %45 = getelementptr inbounds i32, ptr %44, i64 %42
%46 = load i32, ptr %45, align 4 %46 = load i32, ptr %45, align 4
%47 = call i32 (ptr, ...) @printf(ptr @2, i32 %46) %47 = call i32 (ptr, ...) @printf(ptr @2, i32 %46)
@@ -159,10 +159,6 @@ declare ptr @"github.com/goplus/llgo/internal/runtime.AllocZ"(i64)
declare %"github.com/goplus/llgo/internal/runtime.Slice" @"github.com/goplus/llgo/internal/runtime.NewSlice"(ptr, i64, i64) declare %"github.com/goplus/llgo/internal/runtime.Slice" @"github.com/goplus/llgo/internal/runtime.NewSlice"(ptr, i64, i64)
declare i64 @"github.com/goplus/llgo/internal/runtime.SliceLen"(%"github.com/goplus/llgo/internal/runtime.Slice")
declare ptr @"github.com/goplus/llgo/internal/runtime.SliceData"(%"github.com/goplus/llgo/internal/runtime.Slice")
declare void @"github.com/goplus/llgo/internal/runtime.init"() declare void @"github.com/goplus/llgo/internal/runtime.init"()
declare i32 @rand() declare i32 @rand()

8
cl/_testrt/mask/in.go Normal file
View File

@@ -0,0 +1,8 @@
package main
func main() {
println(mask(1))
}
func mask(x int8) int32 {
return int32(x) << 31 >> 31
}

52
cl/_testrt/mask/out.ll Normal file
View File

@@ -0,0 +1,52 @@
; ModuleID = 'main'
source_filename = "main"
%"github.com/goplus/llgo/internal/runtime.String" = type { ptr, i64 }
@"main.init$guard" = global ptr null
@__llgo_argc = global ptr null
@__llgo_argv = global ptr null
@0 = private unnamed_addr constant [2 x i8] c"\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
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 i32 @main.mask(i8 1)
%3 = sext i32 %2 to i64
call void @"github.com/goplus/llgo/internal/runtime.PrintInt"(i64 %3)
%4 = call %"github.com/goplus/llgo/internal/runtime.String" @"github.com/goplus/llgo/internal/runtime.NewString"(ptr @0, i64 1)
call void @"github.com/goplus/llgo/internal/runtime.PrintString"(%"github.com/goplus/llgo/internal/runtime.String" %4)
ret void
}
define i32 @main.mask(i8 %0) {
_llgo_0:
%1 = sext i8 %0 to i32
%2 = shl i32 %1, 31
%3 = ashr i32 %2, 31
ret i32 %3
}
declare void @"github.com/goplus/llgo/internal/runtime.init"()
declare void @"github.com/goplus/llgo/internal/runtime.PrintInt"(i64)
declare void @"github.com/goplus/llgo/internal/runtime.PrintString"(%"github.com/goplus/llgo/internal/runtime.String")
declare %"github.com/goplus/llgo/internal/runtime.String" @"github.com/goplus/llgo/internal/runtime.NewString"(ptr, i64)

View File

@@ -44,7 +44,7 @@ _llgo_0:
define i64 @main.sum(%"github.com/goplus/llgo/internal/runtime.Slice" %0) { define i64 @main.sum(%"github.com/goplus/llgo/internal/runtime.Slice" %0) {
_llgo_0: _llgo_0:
%1 = call i64 @"github.com/goplus/llgo/internal/runtime.SliceLen"(%"github.com/goplus/llgo/internal/runtime.Slice" %0) %1 = extractvalue %"github.com/goplus/llgo/internal/runtime.Slice" %0, 1
br label %_llgo_1 br label %_llgo_1
_llgo_1: ; preds = %_llgo_2, %_llgo_0 _llgo_1: ; preds = %_llgo_2, %_llgo_0
@@ -55,7 +55,7 @@ _llgo_1: ; preds = %_llgo_2, %_llgo_0
br i1 %5, label %_llgo_2, label %_llgo_3 br i1 %5, label %_llgo_2, label %_llgo_3
_llgo_2: ; preds = %_llgo_1 _llgo_2: ; preds = %_llgo_1
%6 = call ptr @"github.com/goplus/llgo/internal/runtime.SliceData"(%"github.com/goplus/llgo/internal/runtime.Slice" %0) %6 = extractvalue %"github.com/goplus/llgo/internal/runtime.Slice" %0, 0
%7 = getelementptr inbounds i64, ptr %6, i64 %4 %7 = getelementptr inbounds i64, ptr %6, i64 %4
%8 = load i64, ptr %7, align 4 %8 = load i64, ptr %7, align 4
%9 = add i64 %2, %8 %9 = add i64 %2, %8
@@ -72,7 +72,3 @@ declare ptr @"github.com/goplus/llgo/internal/runtime.AllocZ"(i64)
declare %"github.com/goplus/llgo/internal/runtime.Slice" @"github.com/goplus/llgo/internal/runtime.NewSlice3"(ptr, i64, i64, i64, i64, i64) declare %"github.com/goplus/llgo/internal/runtime.Slice" @"github.com/goplus/llgo/internal/runtime.NewSlice3"(ptr, i64, i64, i64, i64, i64)
declare i32 @printf(ptr, ...) declare i32 @printf(ptr, ...)
declare i64 @"github.com/goplus/llgo/internal/runtime.SliceLen"(%"github.com/goplus/llgo/internal/runtime.Slice")
declare ptr @"github.com/goplus/llgo/internal/runtime.SliceData"(%"github.com/goplus/llgo/internal/runtime.Slice")

View File

@@ -226,5 +226,5 @@ func TestErrVarOf(t *testing.T) {
} }
ssaPkg := &ssa.Package{Pkg: pkgTypes} ssaPkg := &ssa.Package{Pkg: pkgTypes}
g := &ssa.Global{Pkg: ssaPkg} g := &ssa.Global{Pkg: ssaPkg}
ctx.varOf(g) ctx.varOf(nil, g)
} }

View File

@@ -180,7 +180,7 @@ func (p *context) compileMethods(pkg llssa.Package, typ types.Type) {
for i, n := 0, mthds.Len(); i < n; i++ { for i, n := 0, mthds.Len(); i < n; i++ {
mthd := mthds.At(i) mthd := mthds.At(i)
if ssaMthd := prog.MethodValue(mthd); ssaMthd != nil { if ssaMthd := prog.MethodValue(mthd); ssaMthd != nil {
p.compileFuncDecl(pkg, ssaMthd, false) p.compileFuncDecl(pkg, ssaMthd)
} }
} }
} }
@@ -189,7 +189,7 @@ func (p *context) compileMethods(pkg llssa.Package, typ types.Type) {
func (p *context) compileGlobal(pkg llssa.Package, gbl *ssa.Global) { func (p *context) compileGlobal(pkg llssa.Package, gbl *ssa.Global) {
typ := gbl.Type() typ := gbl.Type()
name, vtype := p.varName(gbl.Pkg.Pkg, gbl) name, vtype := p.varName(gbl.Pkg.Pkg, gbl)
if ignoreName(name) || checkCgo(gbl.Name()) { if vtype == pyVar || ignoreName(name) || checkCgo(gbl.Name()) {
return return
} }
if debugInstr { if debugInstr {
@@ -215,14 +215,16 @@ 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, call bool) (llssa.Function, llssa.PyObjRef, int) { func (p *context) compileFuncDecl(pkg llssa.Package, f *ssa.Function) (llssa.Function, llssa.PyObjRef, int) {
pkgTypes, name, ftype := p.funcName(f, true) pkgTypes, name, ftype := p.funcName(f, true)
if ftype != goFunc { if ftype != goFunc {
/*
if ftype == pyFunc { if ftype == pyFunc {
// TODO(xsw): pyMod == "" // TODO(xsw): pyMod == ""
fnName := pysymPrefix + p.pyMod + "." + name fnName := pysymPrefix + p.pyMod + "." + name
return nil, pkg.NewPyFunc(fnName, f.Signature, call), pyFunc return nil, pkg.NewPyFunc(fnName, f.Signature, call), pyFunc
} }
*/
return nil, nil, ignoredFunc return nil, nil, ignoredFunc
} }
fn := pkg.FuncOf(name) fn := pkg.FuncOf(name)
@@ -239,8 +241,8 @@ func (p *context) compileFuncDecl(pkg llssa.Package, f *ssa.Function, call bool)
ctx := makeClosureCtx(pkgTypes, f.FreeVars) ctx := makeClosureCtx(pkgTypes, f.FreeVars)
sig = llssa.FuncAddCtx(ctx, sig) sig = llssa.FuncAddCtx(ctx, sig)
} else { } else {
if debugInstr && sig != nil && sig.Recv() != nil { if debugInstr {
log.Println("==> NewFunc", name, "type:", sig.Recv(), sig) log.Println("==> NewFunc", name, "type:", sig.Recv(), sig, "ftype:", ftype)
} }
} }
if fn == nil { if fn == nil {
@@ -298,7 +300,7 @@ func (p *context) funcOf(fn *ssa.Function) (aFn llssa.Function, pyFn llssa.PyObj
pkg := p.pkg pkg := p.pkg
fnName := pysymPrefix + mod + "." + name fnName := pysymPrefix + mod + "." + name
if pyFn = pkg.PyObjOf(fnName); pyFn == nil { if pyFn = pkg.PyObjOf(fnName); pyFn == nil {
pyFn = pkg.NewPyFunc(fnName, fn.Signature, true) pyFn = pkg.PyNewFunc(fnName, fn.Signature, true)
return return
} }
} }
@@ -317,6 +319,8 @@ func (p *context) funcOf(fn *ssa.Function) (aFn llssa.Function, pyFn llssa.PyObj
ftype = llgoAllocaCStr ftype = llgoAllocaCStr
case "stringData": case "stringData":
ftype = llgoStringData ftype = llgoStringData
case "pyList":
ftype = llgoPyList
case "unreachable": case "unreachable":
ftype = llgoUnreachable ftype = llgoUnreachable
default: default:
@@ -374,7 +378,7 @@ func (p *context) compileBlock(b llssa.Builder, block *ssa.BasicBlock, n int, do
b.SetBlockEx(ret, llssa.AfterInit) b.SetBlockEx(ret, llssa.AfterInit)
for _, modName := range modNames { for _, modName := range modNames {
objs := mods[modName] objs := mods[modName]
b.LoadPyModSyms(modName, objs...) b.PyLoadModSyms(modName, objs...)
} }
} }
}) })
@@ -398,13 +402,13 @@ func (p *context) compileBlock(b llssa.Builder, block *ssa.BasicBlock, n int, do
jumpTo := p.jumpTo(jump) jumpTo := p.jumpTo(jump)
modPath := p.pyMod modPath := p.pyMod
modName := pysymPrefix + modPath modName := pysymPrefix + modPath
modPtr := pkg.NewPyModVar(modName, true).Expr modPtr := pkg.PyNewModVar(modName, true).Expr
mod := b.Load(modPtr) mod := b.Load(modPtr)
cond := b.BinOp(token.NEQ, mod, prog.Null(mod.Type)) cond := b.BinOp(token.NEQ, mod, prog.Null(mod.Type))
newBlk := p.fn.MakeBlock() newBlk := p.fn.MakeBlock()
b.If(cond, jumpTo, newBlk) b.If(cond, jumpTo, newBlk)
b.SetBlock(newBlk) b.SetBlock(newBlk)
b.Store(modPtr, b.ImportPyMod(modPath)) b.Store(modPtr, b.PyImportMod(modPath))
b.Jump(jumpTo) b.Jump(jumpTo)
} }
return ret return ret
@@ -607,6 +611,9 @@ func (p *context) compileInstrOrValue(b llssa.Builder, iv instrOrValue, asValue
case pyFunc: case pyFunc:
args := p.compileValues(b, args, kind) args := p.compileValues(b, args, kind)
ret = b.Call(pyFn.Expr, args...) ret = b.Call(pyFn.Expr, args...)
case llgoPyList:
args := p.compileValues(b, args, fnHasVArg)
ret = b.PyList(args...)
case llgoCstr: case llgoCstr:
ret = cstr(b, args) ret = cstr(b, args)
case llgoAdvance: case llgoAdvance:
@@ -808,7 +815,7 @@ func (p *context) compileFunction(v *ssa.Function) (goFn llssa.Function, pyFn ll
// 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
goFn, pyFn, kind = p.compileFuncDecl(p.pkg, v, true) goFn, pyFn, kind = p.compileFuncDecl(p.pkg, v)
if kind != ignoredFunc { if kind != ignoredFunc {
return return
} }
@@ -835,8 +842,7 @@ func (p *context) compileValue(b llssa.Builder, v ssa.Value) llssa.Expr {
} }
return pyFn.Expr return pyFn.Expr
case *ssa.Global: case *ssa.Global:
g := p.varOf(v) return p.varOf(b, v)
return g.Expr
case *ssa.Const: case *ssa.Const:
t := types.Default(v.Type()) t := types.Default(v.Type())
return b.Const(v.Value, p.prog.Type(t, llssa.InGo)) return b.Const(v.Value, p.prog.Type(t, llssa.InGo))
@@ -927,7 +933,7 @@ func NewPackage(prog llssa.Program, pkg *ssa.Package, files []*ast.File) (ret ll
// Do not try to build generic (non-instantiated) functions. // Do not try to build generic (non-instantiated) functions.
continue continue
} }
ctx.compileFuncDecl(ret, member, false) ctx.compileFuncDecl(ret, member)
case *ssa.Type: case *ssa.Type:
ctx.compileType(ret, member) ctx.compileType(ret, member)
case *ssa.Global: case *ssa.Global:

View File

@@ -45,7 +45,7 @@ func TestFromTestdata(t *testing.T) {
} }
func TestSqlite(t *testing.T) { func TestSqlite(t *testing.T) {
cltest.Pkg(t, "github.com/goplus/llgo/x/sqlite", "../x/sqlite/sqlite.ll") cltest.Pkg(t, "github.com/goplus/llgo/x/sqlite", "../x/sqlite/llgo_autogen.ll")
} }
func TestFromTestpymath(t *testing.T) { func TestFromTestpymath(t *testing.T) {

View File

@@ -318,6 +318,7 @@ const (
llgoAdvance = llgoInstrBase + 4 llgoAdvance = llgoInstrBase + 4
llgoIndex = llgoInstrBase + 5 llgoIndex = llgoInstrBase + 5
llgoStringData = llgoInstrBase + 6 llgoStringData = llgoInstrBase + 6
llgoPyList = llgoInstrBase + 7
) )
func (p *context) funcName(fn *ssa.Function, ignore bool) (*types.Package, string, int) { func (p *context) funcName(fn *ssa.Function, ignore bool) (*types.Package, string, int) {
@@ -358,24 +359,35 @@ const (
ignoredVar = iota ignoredVar = iota
goVar = int(llssa.InGo) goVar = int(llssa.InGo)
cVar = int(llssa.InC) cVar = int(llssa.InC)
pyVar = int(llssa.InPython)
) )
func (p *context) varName(pkg *types.Package, v *ssa.Global) (vName string, vtype int) { func (p *context) varName(pkg *types.Package, v *ssa.Global) (vName string, vtype int) {
name := llssa.FullName(pkg, v.Name()) name := llssa.FullName(pkg, v.Name())
if v, ok := p.link[name]; ok { if v, ok := p.link[name]; ok {
if strings.HasPrefix(v, "py.") {
return v[3:], pyVar
}
return v, cVar return v, cVar
} }
return name, goVar return name, goVar
} }
func (p *context) varOf(v *ssa.Global) (ret llssa.Global) { func (p *context) varOf(b llssa.Builder, v *ssa.Global) llssa.Expr {
pkgTypes := p.ensureLoaded(v.Pkg.Pkg) pkgTypes := p.ensureLoaded(v.Pkg.Pkg)
pkg := p.pkg pkg := p.pkg
name, vtype := p.varName(pkgTypes, v) name, vtype := p.varName(pkgTypes, v)
if ret = pkg.VarOf(name); ret == nil { if vtype == pyVar {
if kind, mod := pkgKindByScope(pkgTypes.Scope()); kind == PkgPyModule {
return b.PyNewVar(pysymPrefix+mod, name).Expr
}
panic("unreachable")
}
ret := pkg.VarOf(name)
if ret == nil {
ret = pkg.NewVar(name, v.Type(), llssa.Background(vtype)) ret = pkg.NewVar(name, v.Type(), llssa.Background(vtype))
} }
return return ret.Expr
} }
func (p *context) ensureLoaded(pkgTypes *types.Package) *types.Package { func (p *context) ensureLoaded(pkgTypes *types.Package) *types.Package {

View File

@@ -200,7 +200,9 @@ func buildAllPkgs(prog llssa.Program, initial []*packages.Package, mode Mode, ve
if isPkgInLLGo(pkgPath) { if isPkgInLLGo(pkgPath) {
pkg.ExportFile = concatPkgLinkFiles(pkgPath) pkg.ExportFile = concatPkgLinkFiles(pkgPath)
} else { } else {
panic("todo") // panic("todo")
// TODO(xsw): support packages out of llgo
pkg.ExportFile = ""
} }
if kind == cl.PkgLinkExtern { // need to be linked with external library if kind == cl.PkgLinkExtern { // need to be linked with external library
linkFile := os.ExpandEnv(strings.TrimSpace(param)) linkFile := os.ExpandEnv(strings.TrimSpace(param))
@@ -209,10 +211,10 @@ func buildAllPkgs(prog llssa.Program, initial []*packages.Package, mode Mode, ve
if dir != "" { if dir != "" {
command += " -L " + dir command += " -L " + dir
} }
if isMultiLinkFiles(pkg.ExportFile) { if isSingleLinkFile(pkg.ExportFile) {
pkg.ExportFile = command + pkg.ExportFile
} else {
pkg.ExportFile = command + " " + pkg.ExportFile pkg.ExportFile = command + " " + pkg.ExportFile
} else {
pkg.ExportFile = command + pkg.ExportFile
} }
} }
default: default:
@@ -454,14 +456,14 @@ func llgoRoot() string {
} }
func appendLinkFiles(args []string, file string) []string { func appendLinkFiles(args []string, file string) []string {
if isMultiLinkFiles(file) { if isSingleLinkFile(file) {
return append(args, strings.Split(file[1:], " ")...)
}
return append(args, file) return append(args, file)
} }
return append(args, strings.Split(file[1:], " ")...)
}
func isMultiLinkFiles(ret string) bool { func isSingleLinkFile(ret string) bool {
return len(ret) > 0 && ret[0] == ' ' return len(ret) > 0 && ret[0] != ' '
} }
func concatPkgLinkFiles(pkgPath string) string { func concatPkgLinkFiles(pkgPath string) string {

View File

@@ -103,8 +103,6 @@ func SmartDoFile(inFile string, pkgPath ...string) {
fname := autgenFile fname := autgenFile
if inCompilerDir(absDir) { if inCompilerDir(absDir) {
fname = "out.ll" fname = "out.ll"
} else if inSqlite(absDir) {
fname = "sqlite.ll"
} }
outFile := dir + fname outFile := dir + fname
@@ -129,7 +127,3 @@ func genZip(dir string, outFile, inFile string) {
func inCompilerDir(dir string) bool { func inCompilerDir(dir string) bool {
return strings.Contains(dir, "/llgo/cl/") return strings.Contains(dir, "/llgo/cl/")
} }
func inSqlite(dir string) bool {
return strings.HasSuffix(dir, "/llgo/x/sqlite")
}

Binary file not shown.

172
internal/runtime/print.go Normal file
View File

@@ -0,0 +1,172 @@
// Copyright 2009 The Go 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 runtime
import (
"unsafe"
"github.com/goplus/llgo/c"
)
// The compiler knows that a print of a value of this type
// should use printhex instead of printuint (decimal).
func bytes(s string) (ret []byte) {
rp := (*Slice)(unsafe.Pointer(&ret))
sp := (*String)(unsafe.Pointer(&s))
rp.data = sp.data
rp.len = sp.len
rp.cap = sp.len
return
}
func gwrite(b []byte) {
if len(b) == 0 {
return
}
for _, v := range b {
c.Fprintf(c.Stderr, c.Str("%c"), v)
}
}
func PrintBool(v bool) {
if v {
PrintString("true")
} else {
PrintString("false")
}
}
func PrintFloat(v float64) {
switch {
case v != v:
PrintString("NaN")
return
case v+v == v && v > 0:
PrintString("+Inf")
return
case v+v == v && v < 0:
PrintString("-Inf")
return
}
const n = 7 // digits printed
var buf [n + 7]byte
buf[0] = '+'
e := 0 // exp
if v == 0 {
if 1/v < 0 {
buf[0] = '-'
}
} else {
if v < 0 {
v = -v
buf[0] = '-'
}
// normalize
for v >= 10 {
e++
v /= 10
}
for v < 1 {
e--
v *= 10
}
// round
h := 5.0
for i := 0; i < n; i++ {
h /= 10
}
v += h
if v >= 10 {
e++
v /= 10
}
}
// format +d.dddd+edd
for i := 0; i < n; i++ {
s := int(v)
buf[i+2] = byte(s + '0')
v -= float64(s)
v *= 10
}
buf[1] = buf[2]
buf[2] = '.'
buf[n+2] = 'e'
buf[n+3] = '+'
if e < 0 {
e = -e
buf[n+3] = '-'
}
buf[n+4] = byte(e/100) + '0'
buf[n+5] = byte(e/10)%10 + '0'
buf[n+6] = byte(e%10) + '0'
gwrite(buf[:])
}
// func PrintComplex(c complex128) {
// print("(", real(c), imag(c), "i)")
// }
func PrintUint(v uint64) {
var buf [100]byte
i := len(buf)
for i--; i > 0; i-- {
buf[i] = byte(v%10 + '0')
if v < 10 {
break
}
v /= 10
}
gwrite(buf[i:])
}
func PrintInt(v int64) {
if v < 0 {
PrintString("-")
v = -v
}
PrintUint(uint64(v))
}
func PrintHex(v uint64) {
const dig = "0123456789abcdef"
var buf [100]byte
i := len(buf)
for i--; i > 0; i-- {
buf[i] = dig[v%16]
if v < 16 && len(buf)-i >= 0 {
break
}
v /= 16
}
i--
buf[i] = 'x'
i--
buf[i] = '0'
gwrite(buf[i:])
}
func PrintPointer(p unsafe.Pointer) {
PrintHex(uint64(uintptr(p)))
}
func PrintString(s string) {
gwrite(bytes(s))
}
func PrintSlice(s Slice) {
sp := (*Slice)(unsafe.Pointer(&s))
print("[", s.len, "/", s.cap, "]")
PrintPointer(sp.data)
}
func PrintIface(i iface) {
print("(", i.tab, ",", i.data, ")")
}

40
internal/runtime/slice.go Normal file
View File

@@ -0,0 +1,40 @@
// Copyright 2009 The Go 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 runtime
// nextslicecap computes the next appropriate slice length.
func nextslicecap(newLen, oldCap int) int {
newcap := oldCap
doublecap := newcap + newcap
if newLen > doublecap {
return newLen
}
const threshold = 256
if oldCap < threshold {
return doublecap
}
for {
// Transition from growing 2x for small slices
// to growing 1.25x for large slices. This formula
// gives a smooth-ish transition between the two.
newcap += (newcap + 3*threshold) >> 2
// We need to check `newcap >= newLen` and whether `newcap` overflowed.
// newLen is guaranteed to be larger than zero, hence
// when newcap overflows then `uint(newcap) > uint(newLen)`.
// This allows to check for both with the same comparison.
if uint(newcap) >= uint(newLen) {
break
}
}
// Set newcap to the requested cap when
// the newcap calculation overflowed.
if newcap <= 0 {
return newLen
}
return newcap
}

View File

@@ -70,4 +70,25 @@ func SliceData(s Slice) unsafe.Pointer {
return s.data return s.data
} }
// SliceAppend append elem data and returns a slice.
func SliceAppend(src Slice, data unsafe.Pointer, num, etSize int) Slice {
if etSize == 0 {
return src
}
oldLen := src.len
newLen := src.len + num
if newLen > src.cap {
newCap := nextslicecap(newLen, src.cap)
p := AllocZ(uintptr(newCap * etSize))
if oldLen != 0 {
c.Memcpy(p, src.data, uintptr(oldLen*etSize))
}
src.data = p
src.cap = newCap
}
src.len = newLen
c.Memcpy(c.Advance(src.data, oldLen*etSize), data, uintptr(num*etSize))
return src
}
// ----------------------------------------------------------------------------- // -----------------------------------------------------------------------------

49
py/_pyg/llpyg/llpyg.c Normal file
View File

@@ -0,0 +1,49 @@
#include <stdlib.h>
#include <stdio.h>
typedef struct PyObject PyObject;
void Py_Initialize();
PyObject* PyImport_ImportModule(const char* modName);
PyObject* PyModule_GetDict(PyObject* mod);
PyObject* PyObject_Str(PyObject* obj);
PyObject* PyDict_Keys(PyObject* dict);
PyObject* PyList_GetItem(PyObject* list, size_t index);
PyObject* PyTuple_GetItem(PyObject* tuple, size_t index);
PyObject* PyObject_GetAttr(PyObject* mod, PyObject* attrName);
PyObject* PyObject_GetAttrString(PyObject* mod, const char* attrName);
PyObject* PyObject_CallOneArg(PyObject* fn, PyObject* arg);
const char* PyUnicode_AsUTF8(PyObject* str);
size_t PyList_Size(PyObject* list);
int PyCallable_Check(PyObject*);
int main() {
Py_Initialize();
PyObject* inspect = PyImport_ImportModule("inspect");
PyObject* signature = PyObject_GetAttrString(inspect, "signature");
PyObject* mod = PyImport_ImportModule("numpy");
PyObject* dict = PyModule_GetDict(mod);
PyObject* keys = PyDict_Keys(dict);
size_t i, n;
n = PyList_Size(keys);
for (i = 0; i < n; i++) {
PyObject* key = PyList_GetItem(keys, i);
PyObject* val = PyObject_GetAttr(mod, key);
if (PyCallable_Check(val) != 0) {
PyObject* doc = PyObject_GetAttrString(val, "__doc__");
PyObject* sig = PyObject_CallOneArg(signature, val);
printf("-----------------------------------\n");
printf("sig: %p\n", sig);
printf("%s: %s\n", PyUnicode_AsUTF8(key), PyUnicode_AsUTF8(PyObject_Str(sig)));
printf("%s\n", PyUnicode_AsUTF8(key));
if (doc != NULL) {
printf("%s\n", PyUnicode_AsUTF8(doc));
}
}
}
return 0;
}

View File

@@ -1,5 +1,6 @@
#include <stdlib.h> #include <stdlib.h>
#include <stdarg.h> #include <stdarg.h>
#include <stdio.h>
// example: // example:
// llgoLoadPyModSyms(mod, "name1", &func1, "name2", &func2, NULL) // llgoLoadPyModSyms(mod, "name1", &func1, "name2", &func2, NULL)
@@ -23,3 +24,30 @@ void llgoLoadPyModSyms(PyObject* mod, ...) {
} }
va_end(ap); va_end(ap);
} }
/*
wchar_t* toWcs(const char* str) {
size_t len = mbstowcs(NULL, str, 0);
wchar_t* wstr = (wchar_t*)malloc((len + 1) * sizeof(wchar_t));
mbstowcs(wstr, str, len + 1);
return wstr;
}
char* toMbs(const wchar_t* str) {
size_t len = wcstombs(NULL, str, 0);
char* mstr = (char*)malloc(len + 1);
wcstombs(mstr, str, len + 1);
return mstr;
}
wchar_t *Py_GetPath();
void Py_SetPath(const wchar_t* path);
void Py_Initialize();
void llgoPyInitialize() {
setenv("PYTHONPATH", "/opt/homebrew/lib/python3.12/site-packages", 1);
Py_Initialize();
printf("sys.path = %s\n", toMbs(Py_GetPath()));
}
*/

61
py/builtins/builtins.go Normal file
View File

@@ -0,0 +1,61 @@
/*
* 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 builtins
import (
_ "unsafe"
"github.com/goplus/llgo/py"
)
const (
LLGoPackage = "py.inspect"
)
// https://docs.python.org/3/library/functions.html
// https://docs.python.org/3/library/constants.html
// print(*objects, sep=' ', end='\n', file=None, flush=False)
//
// Print objects to the text stream file, separated by sep and followed by
// end. sep, end, file, and flush, if present, must be given as keyword
// arguments.
//
// All non-keyword arguments are converted to strings like str() does and
// written to the stream, separated by sep and followed by end. Both sep
// and end must be strings; they can also be None, which means to use the
// default values. If no objects are given, print() will just write end.
//
//go:linkname Print py.print
func Print(objects ...*py.Object)
//go:linkname PrintEx py.print
func PrintEx(__llgo_kwargs *py.Object, objects ...*py.Object)
// Invoke the built-in help system. (This function is intended for interactive
// use.) If no argument is given, the interactive help system starts on the
// interpreter console. If the argument is a string, then the string is looked
// up as the name of a module, function, class, method, keyword, or documentation
// topic, and a help page is printed on the console. If the argument is any other
// kind of object, a help page on the object is generated.
//
// Note that if a slash(/) appears in the parameter list of a function when invoking
// help(), it means that the parameters prior to the slash are positional-only. For
// more info, see the FAQ entry on positional-only parameters.
//
//go:linkname Help py.help
func Help(object *py.Object)

Binary file not shown.

View File

@@ -71,7 +71,7 @@ func (o *Object) CallOneArg(arg *Object) *Object { return nil }
// 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 { return nil } func (o *Object) CallObject(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

View File

@@ -14,29 +14,19 @@
* limitations under the License. * limitations under the License.
*/ */
package inspect package py
import ( import (
_ "unsafe" _ "unsafe"
"github.com/goplus/llgo/py"
) )
const ( // https://docs.python.org/3/c-api/exceptions.html
LLGoPackage = "py.inspect"
)
// https://docs.python.org/3/library/inspect.html // Clear the error indicator. If the error indicator is not set, there is
// no effect.
//
//go:linkname ErrClear C.PyErr_Clear
func ErrClear()
// Return a signature object for the given callable. //go:linkname ErrPrint C.PyErr_Print
// func ErrPrint()
//go:linkname Signature py.signature
func Signature(callable *py.Object) *py.Object
// Get the names and default values of a Python functions parameters. A named
// tuple is returned:
//
// FullArgSpec(args, varargs, varkw, defaults, kwonlyargs, kwonlydefaults, annotations)
//
//go:linkname Getfullargspec py.getfullargspec
func Getfullargspec(f *py.Object) *py.Object

14
py/inspect/doc.txt Normal file
View File

@@ -0,0 +1,14 @@
// https://docs.python.org/3/library/inspect.html
// Return a signature object for the given callable.
//
//go:linkname Signature py.signature
func Signature(callable *py.Object) *py.Object
// Get the names and default values of a Python functions parameters. A named
// tuple is returned:
//
// FullArgSpec(args, varargs, varkw, defaults, kwonlyargs, kwonlydefaults, annotations)
//
//go:linkname Getfullargspec py.getfullargspec
func Getfullargspec(f *py.Object) *py.Object

617
py/inspect/gen.go Normal file
View File

@@ -0,0 +1,617 @@
package inspect
import (
_ "unsafe"
"github.com/goplus/llgo/py"
)
const LLGoPackage = "py.inspect"
// Compute the annotations dict for an object.
//
// obj may be a callable, class, or module.
// Passing in an object of any other type raises TypeError.
//
// Returns a dict. get_annotations() returns a new dict every time
// it's called; calling it twice on the same object will return two
// different but equivalent dicts.
//
// This function handles several details for you:
//
// * If eval_str is true, values of type str will
// be un-stringized using eval(). This is intended
// for use with stringized annotations
// ("from __future__ import annotations").
// * If obj doesn't have an annotations dict, returns an
// empty dict. (Functions and methods always have an
// annotations dict; classes, modules, and other types of
// callables may not.)
// * Ignores inherited annotations on classes. If a class
// doesn't have its own annotations dict, returns an empty dict.
// * All accesses to object members and dict values are done
// using getattr() and dict.get() for safety.
// * Always, always, always returns a freshly-created dict.
//
// eval_str controls whether or not values of type str are replaced
// with the result of calling eval() on those values:
//
// * If eval_str is true, eval() is called on values of type str.
// * If eval_str is false (the default), values of type str are unchanged.
//
// globals and locals are passed in to eval(); see the documentation
// for eval() for more information. If either globals or locals is
// None, this function may replace that value with a context-specific
// default, contingent on type(obj):
//
// * If obj is a module, globals defaults to obj.__dict__.
// * If obj is a class, globals defaults to
// sys.modules[obj.__module__].__dict__ and locals
// defaults to the obj class namespace.
// * If obj is a callable, globals defaults to obj.__globals__,
// although if obj is a wrapped function (using
// functools.update_wrapper()) it is first unwrapped.
//
//go:linkname GetAnnotations py.get_annotations
func GetAnnotations(obj *py.Object) *py.Object
// Return true if the object is a module.
//
//go:linkname Ismodule py.ismodule
func Ismodule(object *py.Object) *py.Object
// Return true if the object is a class.
//
//go:linkname Isclass py.isclass
func Isclass(object *py.Object) *py.Object
// Return true if the object is an instance method.
//
//go:linkname Ismethod py.ismethod
func Ismethod(object *py.Object) *py.Object
// Return true if the object is a method descriptor.
//
// But not if ismethod() or isclass() or isfunction() are true.
//
// This is new in Python 2.2, and, for example, is true of int.__add__.
// An object passing this test has a __get__ attribute but not a __set__
// attribute, but beyond that the set of attributes varies. __name__ is
// usually sensible, and __doc__ often is.
//
// Methods implemented via descriptors that also pass one of the other
// tests return false from the ismethoddescriptor() test, simply because
// the other tests promise more -- you can, e.g., count on having the
// __func__ attribute (etc) when an object passes ismethod().
//
//go:linkname Ismethoddescriptor py.ismethoddescriptor
func Ismethoddescriptor(object *py.Object) *py.Object
// Return true if the object is a data descriptor.
//
// Data descriptors have a __set__ or a __delete__ attribute. Examples are
// properties (defined in Python) and getsets and members (defined in C).
// Typically, data descriptors will also have __name__ and __doc__ attributes
// (properties, getsets, and members have both of these attributes), but this
// is not guaranteed.
//
//go:linkname Isdatadescriptor py.isdatadescriptor
func Isdatadescriptor(object *py.Object) *py.Object
// Return true if the object is a member descriptor.
//
// Member descriptors are specialized descriptors defined in extension
// modules.
//
//go:linkname Ismemberdescriptor py.ismemberdescriptor
func Ismemberdescriptor(object *py.Object) *py.Object
// Return true if the object is a getset descriptor.
//
// getset descriptors are specialized descriptors defined in extension
// modules.
//
//go:linkname Isgetsetdescriptor py.isgetsetdescriptor
func Isgetsetdescriptor(object *py.Object) *py.Object
// Return true if the object is a user-defined function.
//
// Function objects provide these attributes:
// __doc__ documentation string
// __name__ name with which this function was defined
// __code__ code object containing compiled function bytecode
// __defaults__ tuple of any default values for arguments
// __globals__ global namespace in which this function was defined
// __annotations__ dict of parameter annotations
// __kwdefaults__ dict of keyword only parameters with defaults
//
//go:linkname Isfunction py.isfunction
func Isfunction(object *py.Object) *py.Object
// Return true if the object is a user-defined generator function.
//
// Generator function objects provide the same attributes as functions.
// See help(isfunction) for a list of attributes.
//
//go:linkname Isgeneratorfunction py.isgeneratorfunction
func Isgeneratorfunction(obj *py.Object) *py.Object
// Decorator to ensure callable is recognised as a coroutine function.
//
//go:linkname Markcoroutinefunction py.markcoroutinefunction
func Markcoroutinefunction(func_ *py.Object) *py.Object
// Return true if the object is a coroutine function.
//
// Coroutine functions are normally defined with "async def" syntax, but may
// be marked via markcoroutinefunction.
//
//go:linkname Iscoroutinefunction py.iscoroutinefunction
func Iscoroutinefunction(obj *py.Object) *py.Object
// Return true if the object is an asynchronous generator function.
//
// Asynchronous generator functions are defined with "async def"
// syntax and have "yield" expressions in their body.
//
//go:linkname Isasyncgenfunction py.isasyncgenfunction
func Isasyncgenfunction(obj *py.Object) *py.Object
// Return true if the object is an asynchronous generator.
//
//go:linkname Isasyncgen py.isasyncgen
func Isasyncgen(object *py.Object) *py.Object
// Return true if the object is a generator.
//
// Generator objects provide these attributes:
// __iter__ defined to support iteration over container
// close raises a new GeneratorExit exception inside the
// generator to terminate the iteration
// gi_code code object
// gi_frame frame object or possibly None once the generator has
// been exhausted
// gi_running set to 1 when generator is executing, 0 otherwise
// next return the next item from the container
// send resumes the generator and "sends" a value that becomes
// the result of the current yield-expression
// throw used to raise an exception inside the generator
//
//go:linkname Isgenerator py.isgenerator
func Isgenerator(object *py.Object) *py.Object
// Return true if the object is a coroutine.
//
//go:linkname Iscoroutine py.iscoroutine
func Iscoroutine(object *py.Object) *py.Object
// Return true if object can be passed to an “await“ expression.
//
//go:linkname Isawaitable py.isawaitable
func Isawaitable(object *py.Object) *py.Object
// Return true if the object is a traceback.
//
// Traceback objects provide these attributes:
// tb_frame frame object at this level
// tb_lasti index of last attempted instruction in bytecode
// tb_lineno current line number in Python source code
// tb_next next inner traceback object (called by this level)
//
//go:linkname Istraceback py.istraceback
func Istraceback(object *py.Object) *py.Object
// Return true if the object is a frame object.
//
// Frame objects provide these attributes:
// f_back next outer frame object (this frame's caller)
// f_builtins built-in namespace seen by this frame
// f_code code object being executed in this frame
// f_globals global namespace seen by this frame
// f_lasti index of last attempted instruction in bytecode
// f_lineno current line number in Python source code
// f_locals local namespace seen by this frame
// f_trace tracing function for this frame, or None
//
//go:linkname Isframe py.isframe
func Isframe(object *py.Object) *py.Object
// Return true if the object is a code object.
//
// Code objects provide these attributes:
// co_argcount number of arguments (not including *, ** args
// or keyword only arguments)
// co_code string of raw compiled bytecode
// co_cellvars tuple of names of cell variables
// co_consts tuple of constants used in the bytecode
// co_filename name of file in which this code object was created
// co_firstlineno number of first line in Python source code
// co_flags bitmap: 1=optimized | 2=newlocals | 4=*arg | 8=**arg
// | 16=nested | 32=generator | 64=nofree | 128=coroutine
// | 256=iterable_coroutine | 512=async_generator
// co_freevars tuple of names of free variables
// co_posonlyargcount number of positional only arguments
// co_kwonlyargcount number of keyword only arguments (not including ** arg)
// co_lnotab encoded mapping of line numbers to bytecode indices
// co_name name with which this code object was defined
// co_names tuple of names other than arguments and function locals
// co_nlocals number of local variables
// co_stacksize virtual machine stack space required
// co_varnames tuple of names of arguments and local variables
//
//go:linkname Iscode py.iscode
func Iscode(object *py.Object) *py.Object
// Return true if the object is a built-in function or method.
//
// Built-in functions and methods provide these attributes:
// __doc__ documentation string
// __name__ original name of this function or method
// __self__ instance to which a method is bound, or None
//
//go:linkname Isbuiltin py.isbuiltin
func Isbuiltin(object *py.Object) *py.Object
// Return true if the object is a method wrapper.
//
//go:linkname Ismethodwrapper py.ismethodwrapper
func Ismethodwrapper(object *py.Object) *py.Object
// Return true if the object is any kind of function or method.
//
//go:linkname Isroutine py.isroutine
func Isroutine(object *py.Object) *py.Object
// Return true if the object is an abstract base class (ABC).
//
//go:linkname Isabstract py.isabstract
func Isabstract(object *py.Object) *py.Object
// Return all members of an object as (name, value) pairs sorted by name.
//
// Optionally, only return members that satisfy a given predicate.
//
//go:linkname Getmembers py.getmembers
func Getmembers(object *py.Object, predicate *py.Object) *py.Object
// Return all members of an object as (name, value) pairs sorted by name
//
// without triggering dynamic lookup via the descriptor protocol,
// __getattr__ or __getattribute__. Optionally, only return members that
// satisfy a given predicate.
//
// Note: this function may not be able to retrieve all members
// that getmembers can fetch (like dynamically created attributes)
// and may find members that getmembers can't (like descriptors
// that raise AttributeError). It can also return descriptor objects
// instead of instance members in some cases.
//
//go:linkname GetmembersStatic py.getmembers_static
func GetmembersStatic(object *py.Object, predicate *py.Object) *py.Object
// Return list of attribute-descriptor tuples.
//
// For each name in dir(cls), the return list contains a 4-tuple
// with these elements:
//
// 0. The name (a string).
//
// 1. The kind of attribute this is, one of these strings:
// 'class method' created via classmethod()
// 'static method' created via staticmethod()
// 'property' created via property()
// 'method' any other flavor of method or descriptor
// 'data' not a method
//
// 2. The class which defined this attribute (a class).
//
// 3. The object as obtained by calling getattr; if this fails, or if the
// resulting object does not live anywhere in the class' mro (including
// metaclasses) then the object is looked up in the defining class's
// dict (found by walking the mro).
//
// If one of the items in dir(cls) is stored in the metaclass it will now
// be discovered and not have None be listed as the class in which it was
// defined. Any items whose home class cannot be discovered are skipped.
//
//go:linkname ClassifyClassAttrs py.classify_class_attrs
func ClassifyClassAttrs(cls *py.Object) *py.Object
// Return tuple of base classes (including cls) in method resolution order.
//
//go:linkname Getmro py.getmro
func Getmro(cls *py.Object) *py.Object
// Get the object wrapped by *func*.
//
// Follows the chain of :attr:`__wrapped__` attributes returning the last
// object in the chain.
//
// *stop* is an optional callback accepting an object in the wrapper chain
// as its sole argument that allows the unwrapping to be terminated early if
// the callback returns a true value. If the callback never returns a true
// value, the last object in the chain is returned as usual. For example,
// :func:`signature` uses this to stop unwrapping if any object in the
// chain has a ``__signature__`` attribute defined.
//
// :exc:`ValueError` is raised if a cycle is encountered.
//
//go:linkname Unwrap py.unwrap
func Unwrap(func_ *py.Object) *py.Object
// Return the indent size, in spaces, at the start of a line of text.
//
//go:linkname Indentsize py.indentsize
func Indentsize(line *py.Object) *py.Object
// Get the documentation string for an object.
//
// All tabs are expanded to spaces. To clean up docstrings that are
// indented to line up with blocks of code, any whitespace than can be
// uniformly removed from the second line onwards is removed.
//
//go:linkname Getdoc py.getdoc
func Getdoc(object *py.Object) *py.Object
// Clean up indentation from docstrings.
//
// Any whitespace that can be uniformly removed from the second line
// onwards is removed.
//
//go:linkname Cleandoc py.cleandoc
func Cleandoc(doc *py.Object) *py.Object
// Work out which source or compiled file an object was defined in.
//
//go:linkname Getfile py.getfile
func Getfile(object *py.Object) *py.Object
// Return the module name for a given file, or None.
//
//go:linkname Getmodulename py.getmodulename
func Getmodulename(path *py.Object) *py.Object
// Return the filename that can be used to locate an object's source.
//
// Return None if no way can be identified to get the source.
//
//go:linkname Getsourcefile py.getsourcefile
func Getsourcefile(object *py.Object) *py.Object
// Return an absolute path to the source or compiled file for an object.
//
// The idea is for each object to have a unique origin, so this routine
// normalizes the result as much as possible.
//
//go:linkname Getabsfile py.getabsfile
func Getabsfile(object *py.Object, Filename *py.Object) *py.Object
// Return the module an object was defined in, or None if not found.
//
//go:linkname Getmodule py.getmodule
func Getmodule(object *py.Object, Filename *py.Object) *py.Object
// Return the entire source file and starting line number for an object.
//
// The argument may be a module, class, method, function, traceback, frame,
// or code object. The source code is returned as a list of all the lines
// in the file and the line number indexes a line in that list. An OSError
// is raised if the source code cannot be retrieved.
//
//go:linkname Findsource py.findsource
func Findsource(object *py.Object) *py.Object
// Get lines of comments immediately preceding an object's source code.
//
// Returns None when source can't be found.
//
//go:linkname Getcomments py.getcomments
func Getcomments(object *py.Object) *py.Object
// Extract the block of code at the top of the given list of lines.
//
//go:linkname Getblock py.getblock
func Getblock(lines *py.Object) *py.Object
// Return a list of source lines and starting line number for an object.
//
// The argument may be a module, class, method, function, traceback, frame,
// or code object. The source code is returned as a list of the lines
// corresponding to the object and the line number indicates where in the
// original source file the first line of code was found. An OSError is
// raised if the source code cannot be retrieved.
//
//go:linkname Getsourcelines py.getsourcelines
func Getsourcelines(object *py.Object) *py.Object
// Return the text of the source code for an object.
//
// The argument may be a module, class, method, function, traceback, frame,
// or code object. The source code is returned as a single string. An
// OSError is raised if the source code cannot be retrieved.
//
//go:linkname Getsource py.getsource
func Getsource(object *py.Object) *py.Object
// Recursive helper function for getclasstree().
//
//go:linkname Walktree py.walktree
func Walktree(classes *py.Object, children *py.Object, parent *py.Object) *py.Object
// Arrange the given list of classes into a hierarchy of nested lists.
//
// Where a nested list appears, it contains classes derived from the class
// whose entry immediately precedes the list. Each entry is a 2-tuple
// containing a class and a tuple of its base classes. If the 'unique'
// argument is true, exactly one entry appears in the returned structure
// for each class in the given list. Otherwise, classes using multiple
// inheritance and their descendants will appear multiple times.
//
//go:linkname Getclasstree py.getclasstree
func Getclasstree(classes *py.Object, unique *py.Object) *py.Object
// Get information about the arguments accepted by a code object.
//
// Three things are returned: (args, varargs, varkw), where
// 'args' is the list of argument names. Keyword-only arguments are
// appended. 'varargs' and 'varkw' are the names of the * and **
// arguments or None.
//
//go:linkname Getargs py.getargs
func Getargs(co *py.Object) *py.Object
// Get the names and default values of a callable object's parameters.
//
// A tuple of seven things is returned:
// (args, varargs, varkw, defaults, kwonlyargs, kwonlydefaults, annotations).
// 'args' is a list of the parameter names.
// 'varargs' and 'varkw' are the names of the * and ** parameters or None.
// 'defaults' is an n-tuple of the default values of the last n parameters.
// 'kwonlyargs' is a list of keyword-only parameter names.
// 'kwonlydefaults' is a dictionary mapping names from kwonlyargs to defaults.
// 'annotations' is a dictionary mapping parameter names to annotations.
//
// Notable differences from inspect.signature():
// - the "self" parameter is always reported, even for bound methods
// - wrapper chains defined by __wrapped__ *not* unwrapped automatically
//
//go:linkname Getfullargspec py.getfullargspec
func Getfullargspec(func_ *py.Object) *py.Object
// Get information about arguments passed into a particular frame.
//
// A tuple of four things is returned: (args, varargs, varkw, locals).
// 'args' is a list of the argument names.
// 'varargs' and 'varkw' are the names of the * and ** arguments or None.
// 'locals' is the locals dictionary of the given frame.
//
//go:linkname Getargvalues py.getargvalues
func Getargvalues(frame *py.Object) *py.Object
// Get the mapping of arguments to values.
//
// A dict is returned, with keys the function argument names (including the
// names of the * and ** arguments, if any), and values the respective bound
// values from 'positional' and 'named'.
//
//go:linkname Getcallargs py.getcallargs
func Getcallargs(func_ *py.Object, __llgo_va_list ...interface{}) *py.Object
// Get the mapping of free variables to their current values.
//
// Returns a named tuple of dicts mapping the current nonlocal, global
// and builtin references as seen by the body of the function. A final
// set of unbound names that could not be resolved is also provided.
//
//go:linkname Getclosurevars py.getclosurevars
func Getclosurevars(func_ *py.Object) *py.Object
// Get information about a frame or traceback object.
//
// A tuple of five things is returned: the filename, the line number of
// the current line, the function name, a list of lines of context from
// the source code, and the index of the current line within that list.
// The optional second argument specifies the number of lines of context
// to return, which are centered around the current line.
//
//go:linkname Getframeinfo py.getframeinfo
func Getframeinfo(frame *py.Object, context *py.Object) *py.Object
// Get the line number from a frame object, allowing for optimization.
//
//go:linkname Getlineno py.getlineno
func Getlineno(frame *py.Object) *py.Object
// Get a list of records for a frame and all higher (calling) frames.
//
// Each record contains a frame object, filename, line number, function
// name, a list of lines of context, and index within the context.
//
//go:linkname Getouterframes py.getouterframes
func Getouterframes(frame *py.Object, context *py.Object) *py.Object
// Get a list of records for a traceback's frame and all lower frames.
//
// Each record contains a frame object, filename, line number, function
// name, a list of lines of context, and index within the context.
//
//go:linkname Getinnerframes py.getinnerframes
func Getinnerframes(tb *py.Object, context *py.Object) *py.Object
// Return the frame of the caller or None if this is not possible.
//
//go:linkname Currentframe py.currentframe
func Currentframe() *py.Object
// Return a list of records for the stack above the caller's frame.
//
//go:linkname Stack py.stack
func Stack(context *py.Object) *py.Object
// Return a list of records for the stack below the current exception.
//
//go:linkname Trace py.trace
func Trace(context *py.Object) *py.Object
// Get current state of a generator-iterator.
//
// Possible states are:
// GEN_CREATED: Waiting to start execution.
// GEN_RUNNING: Currently being executed by the interpreter.
// GEN_SUSPENDED: Currently suspended at a yield expression.
// GEN_CLOSED: Execution has completed.
//
//go:linkname Getgeneratorstate py.getgeneratorstate
func Getgeneratorstate(generator *py.Object) *py.Object
// Get the mapping of generator local variables to their current values.
//
// A dict is returned, with the keys the local variable names and values the
// bound values.
//
//go:linkname Getgeneratorlocals py.getgeneratorlocals
func Getgeneratorlocals(generator *py.Object) *py.Object
// Get current state of a coroutine object.
//
// Possible states are:
// CORO_CREATED: Waiting to start execution.
// CORO_RUNNING: Currently being executed by the interpreter.
// CORO_SUSPENDED: Currently suspended at an await expression.
// CORO_CLOSED: Execution has completed.
//
//go:linkname Getcoroutinestate py.getcoroutinestate
func Getcoroutinestate(coroutine *py.Object) *py.Object
// Get the mapping of coroutine local variables to their current values.
//
// A dict is returned, with the keys the local variable names and values the
// bound values.
//
//go:linkname Getcoroutinelocals py.getcoroutinelocals
func Getcoroutinelocals(coroutine *py.Object) *py.Object
// Get current state of an asynchronous generator object.
//
// Possible states are:
// AGEN_CREATED: Waiting to start execution.
// AGEN_RUNNING: Currently being executed by the interpreter.
// AGEN_SUSPENDED: Currently suspended at a yield expression.
// AGEN_CLOSED: Execution has completed.
//
//go:linkname Getasyncgenstate py.getasyncgenstate
func Getasyncgenstate(agen *py.Object) *py.Object
// Get the mapping of asynchronous generator local variables to their current
// values.
//
// A dict is returned, with the keys the local variable names and values the
// bound values.
//
//go:linkname Getasyncgenlocals py.getasyncgenlocals
func Getasyncgenlocals(agen *py.Object) *py.Object
// Get a signature object for the passed callable.
//
//go:linkname Signature py.signature
func Signature(obj *py.Object) *py.Object

152
py/json/gen.go Normal file
View File

@@ -0,0 +1,152 @@
package json
import (
_ "unsafe"
"github.com/goplus/llgo/py"
)
const LLGoPackage = "py.json"
// Serialize “obj“ as a JSON formatted stream to “fp“ (a
//
// ``.write()``-supporting file-like object).
//
// If ``skipkeys`` is true then ``dict`` keys that are not basic types
// (``str``, ``int``, ``float``, ``bool``, ``None``) will be skipped
// instead of raising a ``TypeError``.
//
// If ``ensure_ascii`` is false, then the strings written to ``fp`` can
// contain non-ASCII characters if they appear in strings contained in
// ``obj``. Otherwise, all such characters are escaped in JSON strings.
//
// If ``check_circular`` is false, then the circular reference check
// for container types will be skipped and a circular reference will
// result in an ``RecursionError`` (or worse).
//
// If ``allow_nan`` is false, then it will be a ``ValueError`` to
// serialize out of range ``float`` values (``nan``, ``inf``, ``-inf``)
// in strict compliance of the JSON specification, instead of using the
// JavaScript equivalents (``NaN``, ``Infinity``, ``-Infinity``).
//
// If ``indent`` is a non-negative integer, then JSON array elements and
// object members will be pretty-printed with that indent level. An indent
// level of 0 will only insert newlines. ``None`` is the most compact
// representation.
//
// If specified, ``separators`` should be an ``(item_separator, key_separator)``
// tuple. The default is ``(', ', ': ')`` if *indent* is ``None`` and
// ``(',', ': ')`` otherwise. To get the most compact JSON representation,
// you should specify ``(',', ':')`` to eliminate whitespace.
//
// ``default(obj)`` is a function that should return a serializable version
// of obj or raise TypeError. The default simply raises TypeError.
//
// If *sort_keys* is true (default: ``False``), then the output of
// dictionaries will be sorted by key.
//
// To use a custom ``JSONEncoder`` subclass (e.g. one that overrides the
// ``.default()`` method to serialize additional types), specify it with
// the ``cls`` kwarg; otherwise ``JSONEncoder`` is used.
//
//go:linkname Dump py.dump
func Dump(obj *py.Object, fp *py.Object) *py.Object
// Serialize “obj“ to a JSON formatted “str“.
//
// If ``skipkeys`` is true then ``dict`` keys that are not basic types
// (``str``, ``int``, ``float``, ``bool``, ``None``) will be skipped
// instead of raising a ``TypeError``.
//
// If ``ensure_ascii`` is false, then the return value can contain non-ASCII
// characters if they appear in strings contained in ``obj``. Otherwise, all
// such characters are escaped in JSON strings.
//
// If ``check_circular`` is false, then the circular reference check
// for container types will be skipped and a circular reference will
// result in an ``RecursionError`` (or worse).
//
// If ``allow_nan`` is false, then it will be a ``ValueError`` to
// serialize out of range ``float`` values (``nan``, ``inf``, ``-inf``) in
// strict compliance of the JSON specification, instead of using the
// JavaScript equivalents (``NaN``, ``Infinity``, ``-Infinity``).
//
// If ``indent`` is a non-negative integer, then JSON array elements and
// object members will be pretty-printed with that indent level. An indent
// level of 0 will only insert newlines. ``None`` is the most compact
// representation.
//
// If specified, ``separators`` should be an ``(item_separator, key_separator)``
// tuple. The default is ``(', ', ': ')`` if *indent* is ``None`` and
// ``(',', ': ')`` otherwise. To get the most compact JSON representation,
// you should specify ``(',', ':')`` to eliminate whitespace.
//
// ``default(obj)`` is a function that should return a serializable version
// of obj or raise TypeError. The default simply raises TypeError.
//
// If *sort_keys* is true (default: ``False``), then the output of
// dictionaries will be sorted by key.
//
// To use a custom ``JSONEncoder`` subclass (e.g. one that overrides the
// ``.default()`` method to serialize additional types), specify it with
// the ``cls`` kwarg; otherwise ``JSONEncoder`` is used.
//
//go:linkname Dumps py.dumps
func Dumps(obj *py.Object) *py.Object
// Deserialize “fp“ (a “.read()“-supporting file-like object containing
//
// a JSON document) to a Python object.
//
// ``object_hook`` is an optional function that will be called with the
// result of any object literal decode (a ``dict``). The return value of
// ``object_hook`` will be used instead of the ``dict``. This feature
// can be used to implement custom decoders (e.g. JSON-RPC class hinting).
//
// ``object_pairs_hook`` is an optional function that will be called with the
// result of any object literal decoded with an ordered list of pairs. The
// return value of ``object_pairs_hook`` will be used instead of the ``dict``.
// This feature can be used to implement custom decoders. If ``object_hook``
// is also defined, the ``object_pairs_hook`` takes priority.
//
// To use a custom ``JSONDecoder`` subclass, specify it with the ``cls``
// kwarg; otherwise ``JSONDecoder`` is used.
//
//go:linkname Load py.load
func Load(fp *py.Object) *py.Object
// Deserialize “s“ (a “str“, “bytes“ or “bytearray“ instance
//
// containing a JSON document) to a Python object.
//
// ``object_hook`` is an optional function that will be called with the
// result of any object literal decode (a ``dict``). The return value of
// ``object_hook`` will be used instead of the ``dict``. This feature
// can be used to implement custom decoders (e.g. JSON-RPC class hinting).
//
// ``object_pairs_hook`` is an optional function that will be called with the
// result of any object literal decoded with an ordered list of pairs. The
// return value of ``object_pairs_hook`` will be used instead of the ``dict``.
// This feature can be used to implement custom decoders. If ``object_hook``
// is also defined, the ``object_pairs_hook`` takes priority.
//
// ``parse_float``, if specified, will be called with the string
// of every JSON float to be decoded. By default this is equivalent to
// float(num_str). This can be used to use another datatype or parser
// for JSON floats (e.g. decimal.Decimal).
//
// ``parse_int``, if specified, will be called with the string
// of every JSON int to be decoded. By default this is equivalent to
// int(num_str). This can be used to use another datatype or parser
// for JSON integers (e.g. float).
//
// ``parse_constant``, if specified, will be called with one of the
// following strings: -Infinity, Infinity, NaN.
// This can be used to raise an exception if invalid JSON numbers
// are encountered.
//
// To use a custom ``JSONDecoder`` subclass, specify it with the ``cls``
// kwarg; otherwise ``JSONDecoder`` is used.
//
//go:linkname Loads py.loads
func Loads(s *py.Object) *py.Object

BIN
py/json/llgo_autogen.lla Normal file

Binary file not shown.

View File

@@ -18,10 +18,15 @@ package py
import ( import (
_ "unsafe" _ "unsafe"
"github.com/goplus/llgo/c"
) )
// https://docs.python.org/3/c-api/list.html // https://docs.python.org/3/c-api/list.html
//go:linkname List llgo.pyList
func List(__llgo_va_list ...any) *Object
// Return a new list of length len on success, or nil on failure. // Return a new list of length len on success, or nil on failure.
// //
//go:linkname NewList C.PyList_New //go:linkname NewList C.PyList_New
@@ -39,3 +44,53 @@ func (l *Object) ListLen() uintptr { return 0 }
// //
// llgo:link (*Object).ListItem C.PyList_GetItem // llgo:link (*Object).ListItem C.PyList_GetItem
func (l *Object) ListItem(index uintptr) *Object { return nil } func (l *Object) ListItem(index uintptr) *Object { return nil }
// Set the item at index index in list to item. Return 0 on success. If index is out
// of bounds, return -1 and set an IndexError exception.
//
// llgo:link (*Object).ListSetItem C.PyList_SetItem
func (l *Object) ListSetItem(index uintptr, item *Object) c.Int { return 0 }
// Insert the item item into list list in front of index index. Return 0 if successful;
// return -1 and set an exception if unsuccessful. Analogous to list.insert(index, item).
//
// llgo:link (*Object).ListInsert C.PyList_Insert
func (l *Object) ListInsert(index uintptr, item *Object) c.Int { return 0 }
// Append the object item at the end of list list. Return 0 if successful; return -1
// and set an exception if unsuccessful. Analogous to list.append(item).
//
// llgo:link (*Object).ListAppend C.PyList_Append
func (l *Object) ListAppend(item *Object) c.Int { return 0 }
// Return a list of the objects in list containing the objects between low and high.
// Return nil and set an exception if unsuccessful. Analogous to list[low:high].
// Indexing from the end of the list is not supported.
//
// llgo:link (*Object).ListSlice C.PyList_GetSlice
func (l *Object) ListSlice(low, high uintptr) *Object { return nil }
// Set the slice of list between low and high to the contents of itemlist. Analogous
// to list[low:high] = itemlist. The itemlist may be NULL, indicating the assignment
// of an empty list (slice deletion). Return 0 on success, -1 on failure. Indexing
// from the end of the list is not supported.
//
// llgo:link (*Object).ListSetSlice C.PyList_SetSlice
func (l *Object) ListSetSlice(low, high uintptr, itemlist *Object) c.Int { return 0 }
// Sort the items of list in place. Return 0 on success, -1 on failure. This is equivalent
// to list.sort().
//
// llgo:link (*Object).ListSort C.PyList_Sort
func (l *Object) ListSort() c.Int { return 0 }
// Reverse the items of list in place. Return 0 on success, -1 on failure. This is the
// equivalent of list.reverse().
//
// llgo:link (*Object).ListReverse C.PyList_Reverse
func (l *Object) ListReverse() c.Int { return 0 }
// Return a new tuple object containing the contents of list; equivalent to tuple(list).
//
// llgo:link (*Object).ListAsTuple C.PyList_AsTuple
func (l *Object) ListAsTuple() *Object { return nil }

Binary file not shown.

73
py/long.go Normal file
View File

@@ -0,0 +1,73 @@
/*
* 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/long.html
//go:linkname Long C.PyLong_FromLong
func Long(v c.Long) *Object
//go:linkname LongLong C.PyLong_FromLongLong
func LongLong(v c.LongLong) *Object
//go:linkname Ulong C.PyLong_FromUnsignedLong
func Ulong(v c.Ulong) *Object
//go:linkname UlongLong C.PyLong_FromUnsignedLongLong
func UlongLong(v c.UlongLong) *Object
//go:linkname Uintptr C.PyLong_FromSize_t
func Uintptr(v uintptr) *Object
//go:linkname LongFromFloat64 C.PyLong_FromDouble
func LongFromFloat64(v float64) *Object
//go:linkname LongFromVoidPtr C.PyLong_FromVoidPtr
func LongFromVoidPtr(v c.Pointer) *Object
//go:linkname LongFromCStr C.PyLong_FromString
func LongFromCStr(v *c.Char, pend **c.Char, base c.Int) *Object
//go:linkname LongFromUnicode C.PyLong_FromUnicodeObject
func LongFromUnicode(v *Object, base c.Int) *Object
// llgo:link (*Object).Long C.PyLong_AsLong
func (l *Object) Long() c.Long { return 0 }
// llgo:link (*Object).LongLong C.PyLong_AsLongLong
func (l *Object) LongLong() c.LongLong { return 0 }
// llgo:link (*Object).Ulong C.PyLong_AsUnsignedLong
func (l *Object) Ulong() c.Ulong { return 0 }
// llgo:link (*Object).UlongLong C.PyLong_AsUnsignedLongLong
func (l *Object) UlongLong() c.UlongLong { return 0 }
// llgo:link (*Object).Uintptr C.PyLong_AsSize_t
func (l *Object) Uintptr() uintptr { return 0 }
// llgo:link (*Object).LongAsFloat64 C.PyLong_AsDouble
func (l *Object) LongAsFloat64() float64 { return 0 }
// llgo:link (*Object).LongAsVoidPtr C.PyLong_AsVoidPtr
func (l *Object) LongAsVoidPtr() c.Pointer { return nil }

31
py/math/doc.txt Normal file
View File

@@ -0,0 +1,31 @@
// Unlike the built-in ** operator, math.pow() converts both its arguments to type
// float. Use ** or the built-in pow() function for computing exact integer powers.
//
//go:linkname Pow py.pow
func Pow(x, y *py.Object) *py.Object
// Return the sine of x radians.
//
//go:linkname Sin py.sin
func Sin(x *py.Object) *py.Object
// Return the hyperbolic sine of x.
//
//go:linkname Sinh py.sinh
func Sinh(x *py.Object) *py.Object
// Return the base-2 logarithm of x. This is usually more accurate than log(x, 2).
//
//go:linkname Log2 py.log2
func Log2(x *py.Object) *py.Object
// Return the base-10 logarithm of x. This is usually more accurate than log(x, 10).
//
//go:linkname Log10 py.log10
func Log10(x *py.Object) *py.Object
// Return the fractional and integer parts of x. Both results carry the sign of
// x and are floats.
//
//go:linkname Modf py.modf
func Modf(x *py.Object) *py.Object

349
py/math/gen.go Normal file
View File

@@ -0,0 +1,349 @@
package math
import (
_ "unsafe"
"github.com/goplus/llgo/py"
)
const LLGoPackage = "py.math"
// Return the arc cosine (measured in radians) of x.
//
// The result is between 0 and pi.
//
//go:linkname Acos py.acos
func Acos(x *py.Object) *py.Object
// Return the inverse hyperbolic cosine of x.
//
//go:linkname Acosh py.acosh
func Acosh(x *py.Object) *py.Object
// Return the arc sine (measured in radians) of x.
//
// The result is between -pi/2 and pi/2.
//
//go:linkname Asin py.asin
func Asin(x *py.Object) *py.Object
// Return the inverse hyperbolic sine of x.
//
//go:linkname Asinh py.asinh
func Asinh(x *py.Object) *py.Object
// Return the arc tangent (measured in radians) of x.
//
// The result is between -pi/2 and pi/2.
//
//go:linkname Atan py.atan
func Atan(x *py.Object) *py.Object
// Return the arc tangent (measured in radians) of y/x.
//
// Unlike atan(y/x), the signs of both x and y are considered.
//
//go:linkname Atan2 py.atan2
func Atan2(y *py.Object, x *py.Object) *py.Object
// Return the inverse hyperbolic tangent of x.
//
//go:linkname Atanh py.atanh
func Atanh(x *py.Object) *py.Object
// Return the cube root of x.
//
//go:linkname Cbrt py.cbrt
func Cbrt(x *py.Object) *py.Object
// Return the ceiling of x as an Integral.
//
// This is the smallest integer >= x.
//
//go:linkname Ceil py.ceil
func Ceil(x *py.Object) *py.Object
// Return a float with the magnitude (absolute value) of x but the sign of y.
//
// On platforms that support signed zeros, copysign(1.0, -0.0)
// returns -1.0.
//
//go:linkname Copysign py.copysign
func Copysign(x *py.Object, y *py.Object) *py.Object
// Return the cosine of x (measured in radians).
//
//go:linkname Cos py.cos
func Cos(x *py.Object) *py.Object
// Return the hyperbolic cosine of x.
//
//go:linkname Cosh py.cosh
func Cosh(x *py.Object) *py.Object
// Convert angle x from radians to degrees.
//
//go:linkname Degrees py.degrees
func Degrees(x *py.Object) *py.Object
// Return the Euclidean distance between two points p and q.
//
// The points should be specified as sequences (or iterables) of
// coordinates. Both inputs must have the same dimension.
//
// Roughly equivalent to:
//
// sqrt(sum((px - qx) ** 2.0 for px, qx in zip(p, q)))
//
//go:linkname Dist py.dist
func Dist(p *py.Object, q *py.Object) *py.Object
// Error function at x.
//
//go:linkname Erf py.erf
func Erf(x *py.Object) *py.Object
// Complementary error function at x.
//
//go:linkname Erfc py.erfc
func Erfc(x *py.Object) *py.Object
// Return e raised to the power of x.
//
//go:linkname Exp py.exp
func Exp(x *py.Object) *py.Object
// Return 2 raised to the power of x.
//
//go:linkname Exp2 py.exp2
func Exp2(x *py.Object) *py.Object
// Return exp(x)-1.
//
// This function avoids the loss of precision involved in the direct evaluation of exp(x)-1 for small x.
//
//go:linkname Expm1 py.expm1
func Expm1(x *py.Object) *py.Object
// Return the absolute value of the float x.
//
//go:linkname Fabs py.fabs
func Fabs(x *py.Object) *py.Object
// Find n!.
//
// Raise a ValueError if x is negative or non-integral.
//
//go:linkname Factorial py.factorial
func Factorial(n *py.Object) *py.Object
// Return the floor of x as an Integral.
//
// This is the largest integer <= x.
//
//go:linkname Floor py.floor
func Floor(x *py.Object) *py.Object
// Return fmod(x, y), according to platform C.
//
// x % y may differ.
//
//go:linkname Fmod py.fmod
func Fmod(x *py.Object, y *py.Object) *py.Object
// Return the mantissa and exponent of x, as pair (m, e).
//
// m is a float and e is an int, such that x = m * 2.**e.
// If x is 0, m and e are both 0. Else 0.5 <= abs(m) < 1.0.
//
//go:linkname Frexp py.frexp
func Frexp(x *py.Object) *py.Object
// Return an accurate floating point sum of values in the iterable seq.
//
// Assumes IEEE-754 floating point arithmetic.
//
//go:linkname Fsum py.fsum
func Fsum(seq *py.Object) *py.Object
// Gamma function at x.
//
//go:linkname Gamma py.gamma
func Gamma(x *py.Object) *py.Object
// Greatest Common Divisor.
//
//go:linkname Gcd py.gcd
func Gcd(__llgo_va_list ...interface{}) *py.Object
// Return True if x is neither an infinity nor a NaN, and False otherwise.
//
//go:linkname Isfinite py.isfinite
func Isfinite(x *py.Object) *py.Object
// Return True if x is a positive or negative infinity, and False otherwise.
//
//go:linkname Isinf py.isinf
func Isinf(x *py.Object) *py.Object
// Return True if x is a NaN (not a number), and False otherwise.
//
//go:linkname Isnan py.isnan
func Isnan(x *py.Object) *py.Object
// Return the integer part of the square root of the input.
//
//go:linkname Isqrt py.isqrt
func Isqrt(n *py.Object) *py.Object
// Least Common Multiple.
//
//go:linkname Lcm py.lcm
func Lcm(__llgo_va_list ...interface{}) *py.Object
// Return x * (2**i).
//
// This is essentially the inverse of frexp().
//
//go:linkname Ldexp py.ldexp
func Ldexp(x *py.Object, i *py.Object) *py.Object
// Natural logarithm of absolute value of Gamma function at x.
//
//go:linkname Lgamma py.lgamma
func Lgamma(x *py.Object) *py.Object
// Return the base 10 logarithm of x.
//
//go:linkname Log10 py.log10
func Log10(x *py.Object) *py.Object
// Return the base 2 logarithm of x.
//
//go:linkname Log2 py.log2
func Log2(x *py.Object) *py.Object
// Return the fractional and integer parts of x.
//
// Both results carry the sign of x and are floats.
//
//go:linkname Modf py.modf
func Modf(x *py.Object) *py.Object
// Return x**y (x to the power of y).
//
//go:linkname Pow py.pow
func Pow(x *py.Object, y *py.Object) *py.Object
// Convert angle x from degrees to radians.
//
//go:linkname Radians py.radians
func Radians(x *py.Object) *py.Object
// Difference between x and the closest integer multiple of y.
//
// Return x - n*y where n*y is the closest integer multiple of y.
// In the case where x is exactly halfway between two multiples of
// y, the nearest even value of n is used. The result is always exact.
//
//go:linkname Remainder py.remainder
func Remainder(x *py.Object, y *py.Object) *py.Object
// Return the sine of x (measured in radians).
//
//go:linkname Sin py.sin
func Sin(x *py.Object) *py.Object
// Return the hyperbolic sine of x.
//
//go:linkname Sinh py.sinh
func Sinh(x *py.Object) *py.Object
// Return the square root of x.
//
//go:linkname Sqrt py.sqrt
func Sqrt(x *py.Object) *py.Object
// Return the tangent of x (measured in radians).
//
//go:linkname Tan py.tan
func Tan(x *py.Object) *py.Object
// Return the hyperbolic tangent of x.
//
//go:linkname Tanh py.tanh
func Tanh(x *py.Object) *py.Object
// Return the sum of products of values from two iterables p and q.
//
// Roughly equivalent to:
//
// sum(itertools.starmap(operator.mul, zip(p, q, strict=True)))
//
// For float and mixed int/float inputs, the intermediate products
// and sums are computed with extended precision.
//
//go:linkname Sumprod py.sumprod
func Sumprod(p *py.Object, q *py.Object) *py.Object
// Truncates the Real x to the nearest Integral toward 0.
//
// Uses the __trunc__ magic method.
//
//go:linkname Trunc py.trunc
func Trunc(x *py.Object) *py.Object
// Calculate the product of all the elements in the input iterable.
//
// The default start value for the product is 1.
//
// When the iterable is empty, return the start value. This function is
// intended specifically for use with numeric values and may reject
// non-numeric types.
//
//go:linkname Prod py.prod
func Prod(iterable *py.Object) *py.Object
// Number of ways to choose k items from n items without repetition and with order.
//
// Evaluates to n! / (n - k)! when k <= n and evaluates
// to zero when k > n.
//
// If k is not specified or is None, then k defaults to n
// and the function returns n!.
//
// Raises TypeError if either of the arguments are not integers.
// Raises ValueError if either of the arguments are negative.
//
//go:linkname Perm py.perm
func Perm(n *py.Object, k *py.Object) *py.Object
// Number of ways to choose k items from n items without repetition and without order.
//
// Evaluates to n! / (k! * (n - k)!) when k <= n and evaluates
// to zero when k > n.
//
// Also called the binomial coefficient because it is equivalent
// to the coefficient of k-th term in polynomial expansion of the
// expression (1 + x)**n.
//
// Raises TypeError if either of the arguments are not integers.
// Raises ValueError if either of the arguments are negative.
//
//go:linkname Comb py.comb
func Comb(n *py.Object, k *py.Object) *py.Object
// Return the floating-point value the given number of steps after x towards y.
//
// If steps is not specified or is None, it defaults to 1.
//
// Raises a TypeError, if x or y is not a double, or if steps is not an integer.
// Raises ValueError if steps is negative.
//
//go:linkname Nextafter py.nextafter
func Nextafter(x *py.Object, y *py.Object) *py.Object
// Return the value of the least significant bit of the float x.
//
//go:linkname Ulp py.ulp
func Ulp(x *py.Object) *py.Object

Binary file not shown.

View File

@@ -22,9 +22,30 @@ import (
"github.com/goplus/llgo/py" "github.com/goplus/llgo/py"
) )
const ( // https://docs.python.org/3/library/math.html
LLGoPackage = "py.math"
)
//go:linkname Sqrt py.sqrt //go:linkname Pi py.pi
func Sqrt(x *py.Object) *py.Object var Pi *py.Object
// With one argument, return the natural logarithm of x (to base e).
//
//go:linkname Log py.log
func Log(x *py.Object) *py.Object
// With two arguments, return the logarithm of x to the given base, calculated
// as log(x)/log(base).
//
//go:linkname LogOf py.log
func LogOf(x, base *py.Object) *py.Object
// Return the natural logarithm of 1+x (base e). The result is calculated in
// a way which is accurate for x near zero.
//
//go:linkname Log1p py.log1p
func Log1p(x *py.Object) *py.Object
// Return the Euclidean norm, sqrt(sum(x**2 for x in coordinates)). This is the
// length of the vector from the origin to the point given by the coordinates.
//
//go:linkname Hypot py.hypot
func Hypot(coordinates ...*py.Object) *py.Object

View File

@@ -22,8 +22,30 @@ import (
"github.com/goplus/llgo/c" "github.com/goplus/llgo/c"
) )
// https://docs.python.org/3/c-api/import.html
// https://docs.python.org/3/c-api/module.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
// theres one there, and if not, create a new one and insert it in the modules
// dictionary. Return nil with an exception set on failure.
//
//go:linkname AddModule C.PyImport_AddModule
func AddModule(name *c.Char) *Object
// This is a wrapper around py.Import which takes a const char* as an argument // This is a wrapper around py.Import which takes a const char* as an argument
// instead of an Object. // instead of an Object.
// //

10195
py/numpy/gen.go Normal file

File diff suppressed because it is too large Load Diff

BIN
py/numpy/llgo_autogen.lla Normal file

Binary file not shown.

79
py/numpy/numpy.go Normal file
View File

@@ -0,0 +1,79 @@
/*
* 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 numpy
import (
_ "unsafe"
"github.com/goplus/llgo/py"
)
// https://numpy.org/doc/stable/reference/index.html#reference
// Return evenly spaced values within a given interval.
//
// numpy.arange([start, ]stop, [step, ]dtype=None, *, like=None)
//
// See https://numpy.org/doc/stable/reference/generated/numpy.arange.html#numpy-arange
//
//go:linkname Arange py.arange
func Arange(start, stop, step, dtype *py.Object) *py.Object
// Return a new array of given shape and type, without initializing entries.
//
// numpy.empty(shape, dtype=float, order='C', *, like=None)
//
// See https://numpy.org/doc/stable/reference/generated/numpy.empty.html#numpy-empty
//
//go:linkname Empty py.empty
func Empty(shape, dtype, order *py.Object) *py.Object
// Return a 2-D array with ones on the diagonal and zeros elsewhere.
//
// numpy.eye(N, M=None, k=0, dtype=<class 'float'>, order='C', *, like=None)
//
// See https://numpy.org/doc/stable/reference/generated/numpy.eye.html#numpy-eye
//
//go:linkname Eye py.eye
func Eye(N, M, k, dtype, order *py.Object) *py.Object
// Return a new array of given shape and type, filled with zeros.
//
// numpy.zeros(shape, dtype=float, order='C', *, like=None)
//
// See https://numpy.org/doc/stable/reference/generated/numpy.zeros.html#numpy-zeros
//
//go:linkname Zeros py.zeros
func Zeros(shape, dtype, order *py.Object) *py.Object
// Create an array.
//
// numpy.array(object, dtype=None, *, copy=True, order='K', subok=False, ndmin=0, like=None)
//
// See https://numpy.org/doc/stable/reference/generated/numpy.array.html#numpy-array
//
//go:linkname Array py.array
func Array(object, dtype *py.Object) *py.Object
// Convert the input to an array.
//
// numpy.asarray(a, dtype=None, order=None, *, like=None)
//
// See https://numpy.org/doc/stable/reference/generated/numpy.asarray.html#numpy-asarray
//
//go:linkname AsArray py.asarray
func AsArray(a, dtype, order *py.Object) *py.Object

View File

@@ -22,6 +22,8 @@ import (
"github.com/goplus/llgo/c" "github.com/goplus/llgo/c"
) )
// https://docs.python.org/3/c-api/object.html
// Object represents a Python object. // Object represents a Python object.
type Object struct { type Object struct {
Unused [8]byte Unused [8]byte
@@ -30,6 +32,9 @@ type Object struct {
// llgo:link (*Object).DecRef C.Py_DecRef // llgo:link (*Object).DecRef C.Py_DecRef
func (o *Object) DecRef() {} func (o *Object) DecRef() {}
// llgo:link (*Object).Type C.PyObject_Type
func (o *Object) Type() *Object { return nil }
// Compute a string representation of object o. Returns the string representation on // 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). // 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. // 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 // llgo:link (*Object).Str C.PyObject_Str
func (o *Object) Str() *Object { return nil } 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, // Retrieve an attribute named attrName from object o. Returns the attribute value on success,

1429
py/os/gen.go Normal file

File diff suppressed because it is too large Load Diff

Binary file not shown.

View File

@@ -22,9 +22,21 @@ import (
"github.com/goplus/llgo/py" "github.com/goplus/llgo/py"
) )
const ( // https://docs.python.org/3/library/os.html
LLGoPackage = "py.os"
)
//go:linkname Getcwd py.getcwd // Rename the file or directory src to dst. If dst exists, the operation will
func Getcwd() *py.Object // fail with an OSError subclass in a number of cases:
//
// On Windows, if dst exists a FileExistsError is always raised. The operation
// may fail if src and dst are on different filesystems. Use shutil.move() to
// support moves to a different filesystem.
//
// On Unix, if src is a file and dst is a directory or vice-versa, an IsADirectoryError
// or a NotADirectoryError will be raised respectively. If both are directories and dst
// is empty, dst will be silently replaced. If dst is a non-empty directory, an OSError
// is raised. If both are files, dst will be replaced silently if the user has permission.
// The operation may fail on some Unix flavors if src and dst are on different filesystems.
// If successful, the renaming will be an atomic operation (this is a POSIX requirement).
//
//go:linkname Rename py.rename
func Rename(src, dst *py.Object) *py.Object

401
py/statistics/gen.go Normal file
View File

@@ -0,0 +1,401 @@
package statistics
import (
_ "unsafe"
"github.com/goplus/llgo/py"
)
const LLGoPackage = "py.statistics"
// Error function at x.
//
//go:linkname Erf py.erf
func Erf(x *py.Object) *py.Object
// Return the sample arithmetic mean of data.
//
// >>> mean([1, 2, 3, 4, 4])
// 2.8
//
// >>> from fractions import Fraction as F
// >>> mean([F(3, 7), F(1, 21), F(5, 3), F(1, 3)])
// Fraction(13, 21)
//
// >>> from decimal import Decimal as D
// >>> mean([D("0.5"), D("0.75"), D("0.625"), D("0.375")])
// Decimal('0.5625')
//
// If ``data`` is empty, StatisticsError will be raised.
//
//go:linkname Mean py.mean
func Mean(data *py.Object) *py.Object
// Convert data to floats and compute the arithmetic mean.
//
// This runs faster than the mean() function and it always returns a float.
// If the input dataset is empty, it raises a StatisticsError.
//
// >>> fmean([3.5, 4.0, 5.25])
// 4.25
//
//go:linkname Fmean py.fmean
func Fmean(data *py.Object, weights *py.Object) *py.Object
// Convert data to floats and compute the geometric mean.
//
// Raises a StatisticsError if the input dataset is empty,
// if it contains a zero, or if it contains a negative value.
//
// No special efforts are made to achieve exact results.
// (However, this may change in the future.)
//
// >>> round(geometric_mean([54, 24, 36]), 9)
// 36.0
//
//go:linkname GeometricMean py.geometric_mean
func GeometricMean(data *py.Object) *py.Object
// Return the harmonic mean of data.
//
// The harmonic mean is the reciprocal of the arithmetic mean of the
// reciprocals of the data. It can be used for averaging ratios or
// rates, for example speeds.
//
// Suppose a car travels 40 km/hr for 5 km and then speeds-up to
// 60 km/hr for another 5 km. What is the average speed?
//
// >>> harmonic_mean([40, 60])
// 48.0
//
// Suppose a car travels 40 km/hr for 5 km, and when traffic clears,
// speeds-up to 60 km/hr for the remaining 30 km of the journey. What
// is the average speed?
//
// >>> harmonic_mean([40, 60], weights=[5, 30])
// 56.0
//
// If ``data`` is empty, or any element is less than zero,
// ``harmonic_mean`` will raise ``StatisticsError``.
//
//go:linkname HarmonicMean py.harmonic_mean
func HarmonicMean(data *py.Object, weights *py.Object) *py.Object
// Return the median (middle value) of numeric data.
//
// When the number of data points is odd, return the middle data point.
// When the number of data points is even, the median is interpolated by
// taking the average of the two middle values:
//
// >>> median([1, 3, 5])
// 3
// >>> median([1, 3, 5, 7])
// 4.0
//
//go:linkname Median py.median
func Median(data *py.Object) *py.Object
// Return the low median of numeric data.
//
// When the number of data points is odd, the middle value is returned.
// When it is even, the smaller of the two middle values is returned.
//
// >>> median_low([1, 3, 5])
// 3
// >>> median_low([1, 3, 5, 7])
// 3
//
//go:linkname MedianLow py.median_low
func MedianLow(data *py.Object) *py.Object
// Return the high median of data.
//
// When the number of data points is odd, the middle value is returned.
// When it is even, the larger of the two middle values is returned.
//
// >>> median_high([1, 3, 5])
// 3
// >>> median_high([1, 3, 5, 7])
// 5
//
//go:linkname MedianHigh py.median_high
func MedianHigh(data *py.Object) *py.Object
// Estimates the median for numeric data binned around the midpoints
//
// of consecutive, fixed-width intervals.
//
// The *data* can be any iterable of numeric data with each value being
// exactly the midpoint of a bin. At least one value must be present.
//
// The *interval* is width of each bin.
//
// For example, demographic information may have been summarized into
// consecutive ten-year age groups with each group being represented
// by the 5-year midpoints of the intervals:
//
// >>> demographics = Counter({
// ... 25: 172, # 20 to 30 years old
// ... 35: 484, # 30 to 40 years old
// ... 45: 387, # 40 to 50 years old
// ... 55: 22, # 50 to 60 years old
// ... 65: 6, # 60 to 70 years old
// ... })
//
// The 50th percentile (median) is the 536th person out of the 1071
// member cohort. That person is in the 30 to 40 year old age group.
//
// The regular median() function would assume that everyone in the
// tricenarian age group was exactly 35 years old. A more tenable
// assumption is that the 484 members of that age group are evenly
// distributed between 30 and 40. For that, we use median_grouped().
//
// >>> data = list(demographics.elements())
// >>> median(data)
// 35
// >>> round(median_grouped(data, interval=10), 1)
// 37.5
//
// The caller is responsible for making sure the data points are separated
// by exact multiples of *interval*. This is essential for getting a
// correct result. The function does not check this precondition.
//
// Inputs may be any numeric type that can be coerced to a float during
// the interpolation step.
//
//go:linkname MedianGrouped py.median_grouped
func MedianGrouped(data *py.Object, interval *py.Object) *py.Object
// Return the most common data point from discrete or nominal data.
//
// ``mode`` assumes discrete data, and returns a single value. This is the
// standard treatment of the mode as commonly taught in schools:
//
// >>> mode([1, 1, 2, 3, 3, 3, 3, 4])
// 3
//
// This also works with nominal (non-numeric) data:
//
// >>> mode(["red", "blue", "blue", "red", "green", "red", "red"])
// 'red'
//
// If there are multiple modes with same frequency, return the first one
// encountered:
//
// >>> mode(['red', 'red', 'green', 'blue', 'blue'])
// 'red'
//
// If *data* is empty, ``mode``, raises StatisticsError.
//
//go:linkname Mode py.mode
func Mode(data *py.Object) *py.Object
// Return a list of the most frequently occurring values.
//
// Will return more than one result if there are multiple modes
// or an empty list if *data* is empty.
//
// >>> multimode('aabbbbbbbbcc')
// ['b']
// >>> multimode('aabbbbccddddeeffffgg')
// ['b', 'd', 'f']
// >>> multimode('')
// []
//
//go:linkname Multimode py.multimode
func Multimode(data *py.Object) *py.Object
// Divide *data* into *n* continuous intervals with equal probability.
//
// Returns a list of (n - 1) cut points separating the intervals.
//
// Set *n* to 4 for quartiles (the default). Set *n* to 10 for deciles.
// Set *n* to 100 for percentiles which gives the 99 cuts points that
// separate *data* in to 100 equal sized groups.
//
// The *data* can be any iterable containing sample.
// The cut points are linearly interpolated between data points.
//
// If *method* is set to *inclusive*, *data* is treated as population
// data. The minimum value is treated as the 0th percentile and the
// maximum value is treated as the 100th percentile.
//
//go:linkname Quantiles py.quantiles
func Quantiles(data *py.Object) *py.Object
// Return the sample variance of data.
//
// data should be an iterable of Real-valued numbers, with at least two
// values. The optional argument xbar, if given, should be the mean of
// the data. If it is missing or None, the mean is automatically calculated.
//
// Use this function when your data is a sample from a population. To
// calculate the variance from the entire population, see ``pvariance``.
//
// Examples:
//
// >>> data = [2.75, 1.75, 1.25, 0.25, 0.5, 1.25, 3.5]
// >>> variance(data)
// 1.3720238095238095
//
// If you have already calculated the mean of your data, you can pass it as
// the optional second argument ``xbar`` to avoid recalculating it:
//
// >>> m = mean(data)
// >>> variance(data, m)
// 1.3720238095238095
//
// This function does not check that ``xbar`` is actually the mean of
// ``data``. Giving arbitrary values for ``xbar`` may lead to invalid or
// impossible results.
//
// Decimals and Fractions are supported:
//
// >>> from decimal import Decimal as D
// >>> variance([D("27.5"), D("30.25"), D("30.25"), D("34.5"), D("41.75")])
// Decimal('31.01875')
//
// >>> from fractions import Fraction as F
// >>> variance([F(1, 6), F(1, 2), F(5, 3)])
// Fraction(67, 108)
//
//go:linkname Variance py.variance
func Variance(data *py.Object, xbar *py.Object) *py.Object
// Return the population variance of “data“.
//
// data should be a sequence or iterable of Real-valued numbers, with at least one
// value. The optional argument mu, if given, should be the mean of
// the data. If it is missing or None, the mean is automatically calculated.
//
// Use this function to calculate the variance from the entire population.
// To estimate the variance from a sample, the ``variance`` function is
// usually a better choice.
//
// Examples:
//
// >>> data = [0.0, 0.25, 0.25, 1.25, 1.5, 1.75, 2.75, 3.25]
// >>> pvariance(data)
// 1.25
//
// If you have already calculated the mean of the data, you can pass it as
// the optional second argument to avoid recalculating it:
//
// >>> mu = mean(data)
// >>> pvariance(data, mu)
// 1.25
//
// Decimals and Fractions are supported:
//
// >>> from decimal import Decimal as D
// >>> pvariance([D("27.5"), D("30.25"), D("30.25"), D("34.5"), D("41.75")])
// Decimal('24.815')
//
// >>> from fractions import Fraction as F
// >>> pvariance([F(1, 4), F(5, 4), F(1, 2)])
// Fraction(13, 72)
//
//go:linkname Pvariance py.pvariance
func Pvariance(data *py.Object, mu *py.Object) *py.Object
// Return the square root of the sample variance.
//
// See ``variance`` for arguments and other details.
//
// >>> stdev([1.5, 2.5, 2.5, 2.75, 3.25, 4.75])
// 1.0810874155219827
//
//go:linkname Stdev py.stdev
func Stdev(data *py.Object, xbar *py.Object) *py.Object
// Return the square root of the population variance.
//
// See ``pvariance`` for arguments and other details.
//
// >>> pstdev([1.5, 2.5, 2.5, 2.75, 3.25, 4.75])
// 0.986893273527251
//
//go:linkname Pstdev py.pstdev
func Pstdev(data *py.Object, mu *py.Object) *py.Object
// Covariance
//
// Return the sample covariance of two inputs *x* and *y*. Covariance
// is a measure of the joint variability of two inputs.
//
// >>> x = [1, 2, 3, 4, 5, 6, 7, 8, 9]
// >>> y = [1, 2, 3, 1, 2, 3, 1, 2, 3]
// >>> covariance(x, y)
// 0.75
// >>> z = [9, 8, 7, 6, 5, 4, 3, 2, 1]
// >>> covariance(x, z)
// -7.5
// >>> covariance(z, x)
// -7.5
//
//go:linkname Covariance py.covariance
func Covariance(x *py.Object, y *py.Object) *py.Object
// Pearson's correlation coefficient
//
// Return the Pearson's correlation coefficient for two inputs. Pearson's
// correlation coefficient *r* takes values between -1 and +1. It measures
// the strength and direction of a linear relationship.
//
// >>> x = [1, 2, 3, 4, 5, 6, 7, 8, 9]
// >>> y = [9, 8, 7, 6, 5, 4, 3, 2, 1]
// >>> correlation(x, x)
// 1.0
// >>> correlation(x, y)
// -1.0
//
// If *method* is "ranked", computes Spearman's rank correlation coefficient
// for two inputs. The data is replaced by ranks. Ties are averaged
// so that equal values receive the same rank. The resulting coefficient
// measures the strength of a monotonic relationship.
//
// Spearman's rank correlation coefficient is appropriate for ordinal
// data or for continuous data that doesn't meet the linear proportion
// requirement for Pearson's correlation coefficient.
//
//go:linkname Correlation py.correlation
func Correlation(x *py.Object, y *py.Object) *py.Object
// Slope and intercept for simple linear regression.
//
// Return the slope and intercept of simple linear regression
// parameters estimated using ordinary least squares. Simple linear
// regression describes relationship between an independent variable
// *x* and a dependent variable *y* in terms of a linear function:
//
// y = slope * x + intercept + noise
//
// where *slope* and *intercept* are the regression parameters that are
// estimated, and noise represents the variability of the data that was
// not explained by the linear regression (it is equal to the
// difference between predicted and actual values of the dependent
// variable).
//
// The parameters are returned as a named tuple.
//
// >>> x = [1, 2, 3, 4, 5]
// >>> noise = NormalDist().samples(5, seed=42)
// >>> y = [3 * x[i] + 2 + noise[i] for i in range(5)]
// >>> linear_regression(x, y) #doctest: +ELLIPSIS
// LinearRegression(slope=3.09078914170..., intercept=1.75684970486...)
//
// If *proportional* is true, the independent variable *x* and the
// dependent variable *y* are assumed to be directly proportional.
// The data is fit to a line passing through the origin.
//
// Since the *intercept* will always be 0.0, the underlying linear
// function simplifies to:
//
// y = slope * x + noise
//
// >>> y = [3 * x[i] + noise[i] for i in range(5)]
// >>> linear_regression(x, y, proportional=True) #doctest: +ELLIPSIS
// LinearRegression(slope=3.02447542484..., intercept=0.0)
//
//go:linkname LinearRegression py.linear_regression
func LinearRegression(x *py.Object, y *py.Object) *py.Object

Binary file not shown.

220
py/sys/gen.go Normal file
View File

@@ -0,0 +1,220 @@
package sys
import (
_ "unsafe"
"github.com/goplus/llgo/py"
)
const LLGoPackage = "py.sys"
// Adds a new audit hook callback.
//
//go:linkname Addaudithook py.addaudithook
func Addaudithook(hook *py.Object) *py.Object
// Print an object to sys.stdout and also save it in builtins._
//
//go:linkname Displayhook py.displayhook
func Displayhook(object *py.Object) *py.Object
// Return the current exception.
//
// Return the most recent exception caught by an except clause
// in the current stack frame or in an older stack frame, or None
// if no such exception exists.
//
//go:linkname Exception py.exception
func Exception() *py.Object
// Return current exception information: (type, value, traceback).
//
// Return information about the most recent exception caught by an except
// clause in the current stack frame or in an older stack frame.
//
//go:linkname ExcInfo py.exc_info
func ExcInfo() *py.Object
// Handle an exception by displaying it with a traceback on sys.stderr.
//
//go:linkname Excepthook py.excepthook
func Excepthook(exctype *py.Object, value *py.Object, traceback *py.Object) *py.Object
// Exit the interpreter by raising SystemExit(status).
//
// If the status is omitted or None, it defaults to zero (i.e., success).
// If the status is an integer, it will be used as the system exit status.
// If it is another kind of object, it will be printed and the system
// exit status will be one (i.e., failure).
//
//go:linkname Exit py.exit
func Exit(status *py.Object) *py.Object
// Return the current default encoding used by the Unicode implementation.
//
//go:linkname Getdefaultencoding py.getdefaultencoding
func Getdefaultencoding() *py.Object
// Return the current value of the flags that are used for dlopen calls.
//
// The flag constants are defined in the os module.
//
//go:linkname Getdlopenflags py.getdlopenflags
func Getdlopenflags() *py.Object
// Return the number of memory blocks currently allocated.
//
//go:linkname Getallocatedblocks py.getallocatedblocks
func Getallocatedblocks() *py.Object
// Return the number of elements of the unicode interned dictionary
//
//go:linkname Getunicodeinternedsize py.getunicodeinternedsize
func Getunicodeinternedsize() *py.Object
// Return the encoding used to convert Unicode filenames to OS filenames.
//
//go:linkname Getfilesystemencoding py.getfilesystemencoding
func Getfilesystemencoding() *py.Object
// Return the error mode used Unicode to OS filename conversion.
//
//go:linkname Getfilesystemencodeerrors py.getfilesystemencodeerrors
func Getfilesystemencodeerrors() *py.Object
// Return the reference count of object.
//
// The count returned is generally one higher than you might expect,
// because it includes the (temporary) reference as an argument to
// getrefcount().
//
//go:linkname Getrefcount py.getrefcount
func Getrefcount(object *py.Object) *py.Object
// Return the current value of the recursion limit.
//
// The recursion limit is the maximum depth of the Python interpreter
// stack. This limit prevents infinite recursion from causing an overflow
// of the C stack and crashing Python.
//
//go:linkname Getrecursionlimit py.getrecursionlimit
func Getrecursionlimit() *py.Object
// “Intern” the given string.
//
// This enters the string in the (global) table of interned strings whose
// purpose is to speed up dictionary lookups. Return the string itself or
// the previously interned string object with the same value.
//
//go:linkname Intern py.intern
func Intern(string *py.Object) *py.Object
// Return True if Python is exiting.
//
//go:linkname IsFinalizing py.is_finalizing
func IsFinalizing() *py.Object
// Set the ideal thread switching delay inside the Python interpreter.
//
// The actual frequency of switching threads can be lower if the
// interpreter executes long sequences of uninterruptible code
// (this is implementation-specific and workload-dependent).
//
// The parameter must represent the desired switching delay in seconds
// A typical value is 0.005 (5 milliseconds).
//
//go:linkname Setswitchinterval py.setswitchinterval
func Setswitchinterval(interval *py.Object) *py.Object
// Return the current thread switch interval; see sys.setswitchinterval().
//
//go:linkname Getswitchinterval py.getswitchinterval
func Getswitchinterval() *py.Object
// Set the flags used by the interpreter for dlopen calls.
//
// This is used, for example, when the interpreter loads extension
// modules. Among other things, this will enable a lazy resolving of
// symbols when importing a module, if called as sys.setdlopenflags(0).
// To share symbols across extension modules, call as
// sys.setdlopenflags(os.RTLD_GLOBAL). Symbolic names for the flag
// modules can be found in the os module (RTLD_xxx constants, e.g.
// os.RTLD_LAZY).
//
//go:linkname Setdlopenflags py.setdlopenflags
func Setdlopenflags(flags *py.Object) *py.Object
// Set the maximum depth of the Python interpreter stack to n.
//
// This limit prevents infinite recursion from causing an overflow of the C
// stack and crashing Python. The highest possible limit is platform-
// dependent.
//
//go:linkname Setrecursionlimit py.setrecursionlimit
func Setrecursionlimit(limit *py.Object) *py.Object
// Return the global debug tracing function set with sys.settrace.
//
// See the debugger chapter in the library manual.
//
//go:linkname Gettrace py.gettrace
func Gettrace() *py.Object
// Call func(*args), while tracing is enabled.
//
// The tracing state is saved, and restored afterwards. This is intended
// to be called from a debugger from a checkpoint, to recursively debug
// some other code.
//
//go:linkname CallTracing py.call_tracing
func CallTracing(func_ *py.Object, args *py.Object) *py.Object
// Enable or disable origin tracking for coroutine objects in this thread.
//
// Coroutine objects will track 'depth' frames of traceback information
// about where they came from, available in their cr_origin attribute.
//
// Set a depth of 0 to disable.
//
//go:linkname SetCoroutineOriginTrackingDepth py.set_coroutine_origin_tracking_depth
func SetCoroutineOriginTrackingDepth(depth *py.Object) *py.Object
// Check status of origin tracking for coroutine objects in this thread.
//
//go:linkname GetCoroutineOriginTrackingDepth py.get_coroutine_origin_tracking_depth
func GetCoroutineOriginTrackingDepth() *py.Object
// Deactivate the current stack profiler trampoline backend.
//
// If no stack profiler is activated, this function has no effect.
//
//go:linkname DeactivateStackTrampoline py.deactivate_stack_trampoline
func DeactivateStackTrampoline() *py.Object
// Return *True* if a stack profiler trampoline is active.
//
//go:linkname IsStackTrampolineActive py.is_stack_trampoline_active
func IsStackTrampolineActive() *py.Object
// Handle an unraisable exception.
//
// The unraisable argument has the following attributes:
//
// * exc_type: Exception type.
// * exc_value: Exception value, can be None.
// * exc_traceback: Exception traceback, can be None.
// * err_msg: Error message, can be None.
// * object: Object causing the exception, can be None.
//
//go:linkname Unraisablehook py.unraisablehook
func Unraisablehook(unraisable *py.Object) *py.Object
// Return the maximum string digits limit for non-binary int<->str conversions.
//
//go:linkname GetIntMaxStrDigits py.get_int_max_str_digits
func GetIntMaxStrDigits() *py.Object
// Set the maximum string digits limit for non-binary int<->str conversions.
//
//go:linkname SetIntMaxStrDigits py.set_int_max_str_digits
func SetIntMaxStrDigits(maxdigits *py.Object) *py.Object

BIN
py/sys/llgo_autogen.lla Normal file

Binary file not shown.

53
py/type.go Normal file
View File

@@ -0,0 +1,53 @@
/*
* 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
// Return the types name. Equivalent to getting the types __name__ attribute.
//
// llgo:link (*Object).TypeName C.PyType_GetName
func (t *Object) TypeName() *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 (*Object).TypeFlags C.PyType_GetFlags
func (t *Object) TypeFlags() 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 (*Object).TypeModule C.PyType_GetModule
func (t *Object) TypeModule() *Object { return nil }
// llgo:link (*Object).TypeModuleByDef C.PyType_GetModuleByDef
// func (t *Object) TypeModuleByDef(def *ModuleDef) *Object { return nil }

View File

@@ -29,19 +29,16 @@ import (
const ( const (
ClosureCtx = "__llgo_ctx" ClosureCtx = "__llgo_ctx"
ClosureStub = "__llgo_stub." ClosureStub = "__llgo_stub."
)
// -----------------------------------------------------------------------------
const (
NameValist = "__llgo_va_list" NameValist = "__llgo_va_list"
) )
func VArg() *types.Var { func VArg() *types.Var {
return types.NewParam(0, nil, NameValist, types.Typ[types.Invalid]) return types.NewParam(0, nil, NameValist, types.NewSlice(tyAny))
}
func IsVArg(arg *types.Var) bool {
return arg.Name() == NameValist
}
func HasVArg(t *types.Tuple, n int) bool {
return n > 0 && IsVArg(t.At(n-1))
} }
// ----------------------------------------------------------------------------- // -----------------------------------------------------------------------------
@@ -196,7 +193,7 @@ func newParams(fn Type, prog Program) (params []Type, hasVArg bool) {
sig := fn.raw.Type.(*types.Signature) sig := fn.raw.Type.(*types.Signature)
in := sig.Params() in := sig.Params()
if n := in.Len(); n > 0 { if n := in.Len(); n > 0 {
if hasVArg = HasVArg(in, n); hasVArg { if hasVArg = sig.Variadic(); hasVArg {
n-- n--
} }
params = make([]Type, n) params = make([]Type, n)
@@ -285,6 +282,29 @@ func (p Function) Block(idx int) BasicBlock {
// ----------------------------------------------------------------------------- // -----------------------------------------------------------------------------
type aPyGlobal struct {
Expr
}
type PyGlobal = *aPyGlobal
// PyNewVar creates a Python variable.
func (b Builder) PyNewVar(modName, name string) PyGlobal {
pkg := b.Func.Pkg
modPtr := pkg.PyNewModVar(modName, false).Expr
mod := b.Load(modPtr)
return &aPyGlobal{pyVarExpr(mod, name)}
}
func (b Builder) pyLoad(ptr Expr) Expr {
pkg := b.Func.Pkg
t := ptr.raw.Type.(*pyVarTy)
fn := pkg.pyFunc("PyObject_GetAttrString", b.Prog.tyGetAttrString())
return b.Call(fn, t.mod, b.CStr(t.name))
}
// -----------------------------------------------------------------------------
type aPyObjRef struct { type aPyObjRef struct {
Expr Expr
Obj Global Obj Global
@@ -293,8 +313,8 @@ type aPyObjRef struct {
// PyObjRef represents a python object reference. // PyObjRef represents a python object reference.
type PyObjRef = *aPyObjRef type PyObjRef = *aPyObjRef
// NewPyFunc creates a new python function. // PyNewFunc creates a new python function.
func (p Package) NewPyFunc(name string, sig *types.Signature, doInit bool) PyObjRef { func (p Package) PyNewFunc(name string, sig *types.Signature, doInit bool) PyObjRef {
if v, ok := p.pyobjs[name]; ok { if v, ok := p.pyobjs[name]; ok {
return v return v
} }

View File

@@ -54,6 +54,26 @@ func (v Expr) Do(b Builder) Expr {
// ----------------------------------------------------------------------------- // -----------------------------------------------------------------------------
type pyVarTy struct {
mod Expr
name string
}
func (p pyVarTy) Underlying() types.Type {
panic("don't call")
}
func (p pyVarTy) String() string {
return "pyVar"
}
func pyVarExpr(mod Expr, name string) Expr {
tvar := &aType{raw: rawType{&pyVarTy{mod, name}}, kind: vkPyVarRef}
return Expr{Type: tvar}
}
// -----------------------------------------------------------------------------
type phisExprTy struct { type phisExprTy struct {
phis []llvm.Value phis []llvm.Value
Type Type
@@ -68,7 +88,8 @@ func (p phisExprTy) String() string {
} }
func phisExpr(t Type, phis []llvm.Value) Expr { func phisExpr(t Type, phis []llvm.Value) Expr {
return Expr{Type: &aType{raw: rawType{&phisExprTy{phis, t}}, kind: vkPhisExpr}} tphi := &aType{raw: rawType{&phisExprTy{phis, t}}, kind: vkPhisExpr}
return Expr{Type: tphi}
} }
// ----------------------------------------------------------------------------- // -----------------------------------------------------------------------------
@@ -78,6 +99,11 @@ func (p Program) Null(t Type) Expr {
return Expr{llvm.ConstNull(t.ll), t} return Expr{llvm.ConstNull(t.ll), t}
} }
// PyNull returns a null *PyObject constant expression.
func (p Program) PyNull() Expr {
return p.Null(p.PyObjectPtr())
}
// BoolVal returns a boolean constant expression. // BoolVal returns a boolean constant expression.
func (p Program) BoolVal(v bool) Expr { func (p Program) BoolVal(v bool) Expr {
t := p.Bool() t := p.Bool()
@@ -284,7 +310,7 @@ func (b Builder) BinOp(op token.Token, x, y Expr) Expr {
case vkString: case vkString:
if op == token.ADD { if op == token.ADD {
pkg := b.Func.Pkg pkg := b.Func.Pkg
return b.InlineCall(pkg.rtFunc("StringCat"), x, y) return Expr{b.InlineCall(pkg.rtFunc("StringCat"), x, y).impl, x.Type}
} }
case vkComplex: case vkComplex:
default: default:
@@ -302,6 +328,11 @@ func (b Builder) BinOp(op token.Token, x, y Expr) Expr {
if op == token.SHR && kind == vkUnsigned { if op == token.SHR && kind == vkUnsigned {
llop = llvm.LShr // Logical Shift Right llop = llvm.LShr // Logical Shift Right
} }
if op == token.SHL || op == token.SHR {
if b.Prog.SizeOf(x.Type) != b.Prog.SizeOf(y.Type) {
y = b.Convert(x.Type, y)
}
}
return Expr{llvm.CreateBinOp(b.impl, llop, x.impl, y.impl), x.Type} return Expr{llvm.CreateBinOp(b.impl, llop, x.impl, y.impl), x.Type}
case isPredOp(op): // op: == != < <= < >= case isPredOp(op): // op: == != < <= < >=
tret := b.Prog.Bool() tret := b.Prog.Bool()
@@ -508,6 +539,9 @@ func (b Builder) Load(ptr Expr) Expr {
if debugInstr { if debugInstr {
log.Printf("Load %v\n", ptr.impl) log.Printf("Load %v\n", ptr.impl)
} }
if ptr.kind == vkPyVarRef {
return b.pyLoad(ptr)
}
telem := b.Prog.Elem(ptr.Type) telem := b.Prog.Elem(ptr.Type)
return Expr{llvm.CreateLoad(b.impl, telem.ll, ptr.impl), telem} return Expr{llvm.CreateLoad(b.impl, telem.ll, ptr.impl), telem}
} }
@@ -627,6 +661,36 @@ func (b Builder) StringLen(x Expr) Expr {
return Expr{ptr, prog.Int()} return Expr{ptr, prog.Int()}
} }
// SliceData returns the data pointer of a slice.
func (b Builder) SliceData(x Expr) Expr {
if debugInstr {
log.Printf("SliceData %v\n", x.impl)
}
prog := b.Prog
ptr := llvm.CreateExtractValue(b.impl, x.impl, 0)
return Expr{ptr, prog.CStr()}
}
// SliceLen returns the length of a slice.
func (b Builder) SliceLen(x Expr) Expr {
if debugInstr {
log.Printf("SliceLen %v\n", x.impl)
}
prog := b.Prog
ptr := llvm.CreateExtractValue(b.impl, x.impl, 1)
return Expr{ptr, prog.Int()}
}
// SliceCap returns the length of a slice cap.
func (b Builder) SliceCap(x Expr) Expr {
if debugInstr {
log.Printf("SliceCap %v\n", x.impl)
}
prog := b.Prog
ptr := llvm.CreateExtractValue(b.impl, x.impl, 2)
return Expr{ptr, prog.Int()}
}
// The IndexAddr instruction yields the address of the element at // The IndexAddr instruction yields the address of the element at
// index `idx` of collection `x`. `idx` is an integer expression. // index `idx` of collection `x`. `idx` is an integer expression.
// //
@@ -648,8 +712,7 @@ func (b Builder) IndexAddr(x, idx Expr) Expr {
pt := prog.Pointer(telem) pt := prog.Pointer(telem)
switch x.raw.Type.Underlying().(type) { switch x.raw.Type.Underlying().(type) {
case *types.Slice: case *types.Slice:
pkg := b.Func.Pkg ptr := b.SliceData(x)
ptr := b.InlineCall(pkg.rtFunc("SliceData"), x)
indices := []llvm.Value{idx.impl} indices := []llvm.Value{idx.impl}
return Expr{llvm.CreateInBoundsGEP(b.impl, telem.ll, ptr.impl, indices), pt} return Expr{llvm.CreateInBoundsGEP(b.impl, telem.ll, ptr.impl, indices), pt}
} }
@@ -752,12 +815,12 @@ func (b Builder) Slice(x, low, high, max Expr) (ret Expr) {
return return
case *types.Slice: case *types.Slice:
nEltSize = b.SizeOf(prog.Index(x.Type)) nEltSize = b.SizeOf(prog.Index(x.Type))
nCap = b.InlineCall(pkg.rtFunc("SliceCap"), x) nCap = b.SliceCap(x)
if high.IsNil() { if high.IsNil() {
high = b.InlineCall(pkg.rtFunc("SliceLen"), x) high = b.SliceCap(x)
} }
ret.Type = x.Type ret.Type = x.Type
base = b.InlineCall(pkg.rtFunc("SliceData"), x) base = b.SliceData(x)
case *types.Pointer: case *types.Pointer:
telem := t.Elem() telem := t.Elem()
switch te := telem.Underlying().(type) { switch te := telem.Underlying().(type) {
@@ -1292,23 +1355,86 @@ func (b Builder) BuiltinCall(fn string, args ...Expr) (ret Expr) {
case "len": case "len":
if len(args) == 1 { if len(args) == 1 {
arg := args[0] arg := args[0]
switch t := arg.raw.Type.Underlying().(type) { switch arg.kind {
case *types.Slice: case vkSlice:
return b.InlineCall(b.Func.Pkg.rtFunc("SliceLen"), arg) return b.SliceLen(arg)
case *types.Basic: case vkString:
if t.Kind() == types.String {
return b.StringLen(arg) return b.StringLen(arg)
} }
} }
}
case "cap": case "cap":
if len(args) == 1 { if len(args) == 1 {
arg := args[0] arg := args[0]
switch arg.raw.Type.Underlying().(type) { switch arg.kind {
case *types.Slice: case vkSlice:
return b.InlineCall(b.Func.Pkg.rtFunc("SliceCap"), arg) return b.SliceCap(arg)
} }
} }
case "append":
if len(args) == 2 {
src := args[0]
if src.kind == vkSlice {
elem := args[1]
switch elem.kind {
case vkSlice:
etSize := b.Prog.SizeOf(b.Prog.Elem(elem.Type))
ret.Type = src.Type
ret.impl = b.InlineCall(b.Func.Pkg.rtFunc("SliceAppend"),
src, b.SliceData(elem), b.SliceLen(elem), b.Prog.Val(int(etSize))).impl
return
case vkString:
etSize := b.Prog.SizeOf(b.Prog.Type(types.Typ[types.Byte], InGo))
ret.Type = src.Type
ret.impl = b.InlineCall(b.Func.Pkg.rtFunc("SliceAppend"),
src, b.StringData(elem), b.StringLen(elem), b.Prog.Val(int(etSize))).impl
return
}
}
}
case "print", "println":
ln := fn == "println"
ret.Type = b.Prog.Void()
for i, arg := range args {
if ln && i > 0 {
b.InlineCall(b.Func.Pkg.rtFunc("PrintString"), b.Str(" "))
}
var fn string
var typ types.Type
switch arg.kind {
case vkBool:
fn = "PrintBool"
case vkSigned:
fn = "PrintInt"
typ = types.Typ[types.Int64]
case vkUnsigned:
fn = "PrintUint"
typ = types.Typ[types.Uint64]
case vkFloat:
fn = "PrintFloat"
typ = types.Typ[types.Float64]
case vkSlice:
fn = "PrintSlice"
case vkPtr, vkFuncPtr, vkFuncDecl, vkClosure, vkPyVarRef, vkPyFuncRef:
fn = "PrintPointer"
typ = types.Typ[types.UnsafePointer]
case vkString:
fn = "PrintString"
case vkInterface:
fn = "PrintIface"
// case vkComplex:
// fn = "PrintComplex"
default:
panic(fmt.Errorf("illegal types for operand: print %v", arg.RawType()))
}
if typ != nil && typ != arg.raw.Type {
arg = b.Convert(b.Prog.Type(typ, InGo), arg)
}
b.InlineCall(b.Func.Pkg.rtFunc(fn), arg)
}
if ln {
b.InlineCall(b.Func.Pkg.rtFunc("PrintString"), b.Str("\n"))
}
return
} }
panic("todo") panic("todo")
} }

View File

@@ -130,6 +130,7 @@ type aProgram struct {
voidPtr Type voidPtr Type
boolTy Type boolTy Type
cstrTy Type cstrTy Type
cintTy Type
stringTy Type stringTy Type
uintptrTy Type uintptrTy Type
intTy Type intTy Type
@@ -138,9 +139,16 @@ type aProgram struct {
pyObjPPtr Type pyObjPPtr Type
pyImpTy *types.Signature pyImpTy *types.Signature
pyNewList *types.Signature
pyListSetI *types.Signature
callArgs *types.Signature
callNoArgs *types.Signature callNoArgs *types.Signature
callOneArg *types.Signature callOneArg *types.Signature
callFOArgs *types.Signature
loadPyModS *types.Signature loadPyModS *types.Signature
getAttrStr *types.Signature
paramObjPtr_ *types.Var
NeedRuntime bool NeedRuntime bool
NeedPyInit bool NeedPyInit bool
@@ -328,6 +336,13 @@ func (p Program) Any() Type {
return p.anyTy return p.anyTy
} }
func (p Program) CInt() Type {
if p.cintTy == nil { // C.int
p.cintTy = p.rawType(types.Typ[types.Int32]) // TODO(xsw): support 64-bit
}
return p.cintTy
}
// Int returns int type. // Int returns int type.
func (p Program) Int() Type { func (p Program) Int() Type {
if p.intTy == nil { if p.intTy == nil {
@@ -475,31 +490,38 @@ func (p *Package) WriteFile(file string) (err error) {
// ----------------------------------------------------------------------------- // -----------------------------------------------------------------------------
func (p Program) paramObjPtr() *types.Var {
if p.paramObjPtr_ == nil {
objPtr := p.PyObjectPtr().raw.Type
p.paramObjPtr_ = types.NewParam(token.NoPos, nil, "", objPtr)
}
return p.paramObjPtr_
}
// func(*char) *Object
func (p Program) tyImportPyModule() *types.Signature { func (p Program) tyImportPyModule() *types.Signature {
if p.pyImpTy == nil { if p.pyImpTy == nil {
charPtr := types.NewPointer(types.Typ[types.Int8]) charPtr := types.NewPointer(types.Typ[types.Int8])
objPtr := p.PyObjectPtr().raw.Type
params := types.NewTuple(types.NewParam(token.NoPos, nil, "", charPtr)) params := types.NewTuple(types.NewParam(token.NoPos, nil, "", charPtr))
results := types.NewTuple(types.NewParam(token.NoPos, nil, "", objPtr)) results := types.NewTuple(p.paramObjPtr())
p.pyImpTy = types.NewSignatureType(nil, nil, nil, params, results, false) p.pyImpTy = types.NewSignatureType(nil, nil, nil, params, results, false)
} }
return p.pyImpTy return p.pyImpTy
} }
// func(*Object) *Object
func (p Program) tyCallNoArgs() *types.Signature { func (p Program) tyCallNoArgs() *types.Signature {
if p.callNoArgs == nil { if p.callNoArgs == nil {
objPtr := p.PyObjectPtr().raw.Type params := types.NewTuple(p.paramObjPtr())
paramObjPtr := types.NewParam(token.NoPos, nil, "", objPtr)
params := types.NewTuple(paramObjPtr)
p.callNoArgs = types.NewSignatureType(nil, nil, nil, params, params, false) p.callNoArgs = types.NewSignatureType(nil, nil, nil, params, params, false)
} }
return p.callNoArgs return p.callNoArgs
} }
// func(*Object, *Object) *Object
func (p Program) tyCallOneArg() *types.Signature { func (p Program) tyCallOneArg() *types.Signature {
if p.callOneArg == nil { if p.callOneArg == nil {
objPtr := p.PyObjectPtr().raw.Type paramObjPtr := p.paramObjPtr()
paramObjPtr := types.NewParam(token.NoPos, nil, "", objPtr)
params := types.NewTuple(paramObjPtr, paramObjPtr) params := types.NewTuple(paramObjPtr, paramObjPtr)
results := types.NewTuple(paramObjPtr) results := types.NewTuple(paramObjPtr)
p.callOneArg = types.NewSignatureType(nil, nil, nil, params, results, false) p.callOneArg = types.NewSignatureType(nil, nil, nil, params, results, false)
@@ -507,29 +529,101 @@ func (p Program) tyCallOneArg() *types.Signature {
return p.callOneArg return p.callOneArg
} }
// func(*Object, ...) *Object
func (p Program) tyCallFunctionObjArgs() *types.Signature {
if p.callFOArgs == nil {
paramObjPtr := p.paramObjPtr()
params := types.NewTuple(paramObjPtr, VArg())
results := types.NewTuple(paramObjPtr)
p.callFOArgs = types.NewSignatureType(nil, nil, nil, params, results, true)
}
return p.callFOArgs
}
/*
// func(*Object, *Object, *Object) *Object
func (p Program) tyCall() *types.Signature {
if p.callArgs == nil {
paramObjPtr := p.paramObjPtr()
params := types.NewTuple(paramObjPtr, paramObjPtr, paramObjPtr)
results := types.NewTuple(paramObjPtr)
p.callArgs = types.NewSignatureType(nil, nil, nil, params, results, false)
}
return p.callArgs
}
*/
// func(*Object, uintptr, *Object) cint
func (p Program) tyListSetItem() *types.Signature {
if p.pyListSetI == nil {
paramUintptr := types.NewParam(token.NoPos, nil, "", p.Uintptr().raw.Type)
paramCInt := types.NewParam(token.NoPos, nil, "", p.CInt().raw.Type)
paramObjPtr := p.paramObjPtr()
params := types.NewTuple(paramObjPtr, paramUintptr, paramObjPtr)
results := types.NewTuple(paramCInt)
p.pyListSetI = types.NewSignatureType(nil, nil, nil, params, results, false)
}
return p.pyListSetI
}
// func(uintptr) *Object
func (p Program) tyNewList() *types.Signature {
if p.pyNewList == nil {
paramUintptr := types.NewParam(token.NoPos, nil, "", p.Uintptr().raw.Type)
params := types.NewTuple(paramUintptr)
results := types.NewTuple(p.paramObjPtr())
p.pyNewList = types.NewSignatureType(nil, nil, nil, params, results, false)
}
return p.pyNewList
}
// func(float64) *Object
func (p Program) tyFloatFromDouble() *types.Signature {
if p.callArgs == nil {
paramObjPtr := p.paramObjPtr()
paramFloat := types.NewParam(token.NoPos, nil, "", p.Float64().raw.Type)
params := types.NewTuple(paramFloat)
results := types.NewTuple(paramObjPtr)
p.callArgs = types.NewSignatureType(nil, nil, nil, params, results, false)
}
return p.callArgs
}
// func(*Object, ...)
func (p Program) tyLoadPyModSyms() *types.Signature { func (p Program) tyLoadPyModSyms() *types.Signature {
if p.loadPyModS == nil { if p.loadPyModS == nil {
objPtr := p.PyObjectPtr().raw.Type paramObjPtr := p.paramObjPtr()
paramObjPtr := types.NewParam(token.NoPos, nil, "mod", objPtr)
params := types.NewTuple(paramObjPtr, VArg()) params := types.NewTuple(paramObjPtr, VArg())
p.loadPyModS = types.NewSignatureType(nil, nil, nil, params, nil, false) p.loadPyModS = types.NewSignatureType(nil, nil, nil, params, nil, true)
} }
return p.loadPyModS return p.loadPyModS
} }
// func(*Objecg, *char) *Object
func (p Program) tyGetAttrString() *types.Signature {
if p.getAttrStr == nil {
charPtr := types.NewPointer(types.Typ[types.Int8])
paramObjPtr := p.paramObjPtr()
params := types.NewTuple(paramObjPtr, types.NewParam(token.NoPos, nil, "", charPtr))
results := types.NewTuple(paramObjPtr)
p.getAttrStr = types.NewSignatureType(nil, nil, nil, params, results, false)
}
return p.getAttrStr
}
// PyInit initializes Python for a main package. // PyInit initializes Python for a main package.
func (p Package) PyInit() bool { func (p Package) PyInit() bool {
if fn := p.FuncOf("main"); fn != nil { if fn := p.FuncOf("main"); fn != nil {
b := fn.NewBuilder() b := fn.NewBuilder()
b.SetBlockEx(fn.Block(0), AtStart).CallPyInit() b.SetBlockEx(fn.Block(0), AtStart).callPyInit()
b.Dispose() b.Dispose()
return true return true
} }
return false return false
} }
// NewPyModVar creates a new global variable for a Python module. // PyNewModVar creates a new global variable for a Python module.
func (p Package) NewPyModVar(name string, doInit bool) Global { func (p Package) PyNewModVar(name string, doInit bool) Global {
if v, ok := p.pymods[name]; ok { if v, ok := p.pymods[name]; ok {
return v return v
} }
@@ -544,18 +638,18 @@ func (p Package) NewPyModVar(name string, doInit bool) Global {
return g return g
} }
// ImportPyMod imports a Python module. // PyImportMod imports a Python module.
func (b Builder) ImportPyMod(path string) Expr { func (b Builder) PyImportMod(path string) Expr {
pkg := b.Func.Pkg pkg := b.Func.Pkg
fnImp := pkg.pyFunc("PyImport_ImportModule", b.Prog.tyImportPyModule()) fnImp := pkg.pyFunc("PyImport_ImportModule", b.Prog.tyImportPyModule())
return b.Call(fnImp, b.CStr(path)) return b.Call(fnImp, b.CStr(path))
} }
// LoadPyModSyms loads python objects from specified module. // PyLoadModSyms loads python objects from specified module.
func (b Builder) LoadPyModSyms(modName string, objs ...PyObjRef) Expr { func (b Builder) PyLoadModSyms(modName string, objs ...PyObjRef) Expr {
pkg := b.Func.Pkg pkg := b.Func.Pkg
fnLoad := pkg.pyFunc("llgoLoadPyModSyms", b.Prog.tyLoadPyModSyms()) fnLoad := pkg.pyFunc("llgoLoadPyModSyms", b.Prog.tyLoadPyModSyms())
modPtr := pkg.NewPyModVar(modName, false).Expr modPtr := pkg.PyNewModVar(modName, false).Expr
mod := b.Load(modPtr) mod := b.Load(modPtr)
args := make([]Expr, 1, len(objs)*2+2) args := make([]Expr, 1, len(objs)*2+2)
args[0] = mod args[0] = mod
@@ -583,16 +677,76 @@ func (b Builder) pyCall(fn Expr, args []Expr) (ret Expr) {
call := pkg.pyFunc("PyObject_CallNoArgs", prog.tyCallNoArgs()) call := pkg.pyFunc("PyObject_CallNoArgs", prog.tyCallNoArgs())
ret = b.Call(call, fn) ret = b.Call(call, fn)
case 1: case 1:
if !sig.Variadic() {
call := pkg.pyFunc("PyObject_CallOneArg", prog.tyCallOneArg()) call := pkg.pyFunc("PyObject_CallOneArg", prog.tyCallOneArg())
ret = b.Call(call, fn, args[0]) return b.Call(call, fn, args[0])
}
fallthrough
default: default:
panic("todo") call := pkg.pyFunc("PyObject_CallFunctionObjArgs", prog.tyCallFunctionObjArgs())
n = len(args)
callargs := make([]Expr, n+2)
callargs[0] = fn
copy(callargs[1:], args)
callargs[n+1] = prog.PyNull()
ret = b.Call(call, callargs...)
} }
return return
} }
// CallPyInit calls Py_Initialize. // PyNewList(n uintptr) *Object
func (b Builder) CallPyInit() (ret Expr) { func (b Builder) PyNewList(n Expr) (ret Expr) {
prog := b.Prog
pkg := b.Func.Pkg
fn := pkg.pyFunc("PyList_New", prog.tyNewList())
return b.Call(fn, n)
}
// PyListSetItem(list *Object, index uintptr, item *Object) c.Int
func (b Builder) PyListSetItem(list, index, item Expr) (ret Expr) {
prog := b.Prog
pkg := b.Func.Pkg
fn := pkg.pyFunc("PyList_SetItem", prog.tyListSetItem())
return b.Call(fn, list, index, item)
}
// PyList(args ...Expr) *Object
func (b Builder) PyList(args ...Expr) (ret Expr) {
prog := b.Prog
n := len(args)
uintPtr := prog.Uintptr()
list := b.PyNewList(prog.IntVal(uint64(n), uintPtr))
for i, arg := range args {
b.PyListSetItem(list, prog.IntVal(uint64(i), uintPtr), b.PyVal(arg))
}
return list
}
// PyVal(v any) *Object
func (b Builder) PyVal(v Expr) (ret Expr) {
switch t := v.raw.Type.(type) {
case *types.Basic:
switch t.Kind() {
case types.Float64:
return b.PyFloat(v)
default:
panic("PyVal: todo")
}
default:
return v
}
}
// PyFloat(fltVal float64) *Object
func (b Builder) PyFloat(fltVal Expr) (ret Expr) {
prog := b.Prog
pkg := b.Func.Pkg
fn := pkg.pyFunc("PyFloat_FromDouble", prog.tyFloatFromDouble())
return b.Call(fn, fltVal)
}
// callPyInit calls Py_Initialize.
func (b Builder) callPyInit() (ret Expr) {
fn := b.Func.Pkg.pyFunc("Py_Initialize", NoArgsNoRet) fn := b.Func.Pkg.pyFunc("Py_Initialize", NoArgsNoRet)
return b.Call(fn) return b.Call(fn)
} }

View File

@@ -102,7 +102,9 @@ func TestCvtType(t *testing.T) {
func TestUserdefExpr(t *testing.T) { func TestUserdefExpr(t *testing.T) {
b := &phisExprTy{} b := &phisExprTy{}
c := &pyVarTy{}
_ = b.String() _ = b.String()
_ = c.String()
test := func(a types.Type) { test := func(a types.Type) {
defer func() { defer func() {
if r := recover(); r == nil { if r := recover(); r == nil {
@@ -112,6 +114,7 @@ func TestUserdefExpr(t *testing.T) {
a.Underlying() a.Underlying()
} }
test(b) test(b)
test(c)
} }
func TestAny(t *testing.T) { func TestAny(t *testing.T) {
@@ -143,12 +146,12 @@ func TestPyFunc(t *testing.T) {
prog.SetPython(py) prog.SetPython(py)
pkg := prog.NewPackage("bar", "foo/bar") pkg := prog.NewPackage("bar", "foo/bar")
sig := types.NewSignatureType(nil, nil, nil, nil, nil, false) sig := types.NewSignatureType(nil, nil, nil, nil, nil, false)
a := pkg.NewPyFunc("a", sig, false) a := pkg.PyNewFunc("a", sig, false)
if pkg.NewPyFunc("a", sig, false) != a { if pkg.PyNewFunc("a", sig, false) != a {
t.Fatal("NewPyFunc(a) failed") t.Fatal("NewPyFunc(a) failed")
} }
foo := pkg.NewPyModVar("foo", false) foo := pkg.PyNewModVar("foo", false)
if pkg.NewPyModVar("foo", false) != foo { if pkg.PyNewModVar("foo", false) != foo {
t.Fatal("NewPyModVar(foo) failed") t.Fatal("NewPyModVar(foo) failed")
} }
} }
@@ -399,8 +402,8 @@ func TestPrintf(t *testing.T) {
pchar := types.NewPointer(types.Typ[types.Int8]) pchar := types.NewPointer(types.Typ[types.Int8])
params := types.NewTuple(types.NewVar(0, nil, "format", pchar), VArg()) params := types.NewTuple(types.NewVar(0, nil, "format", pchar), VArg())
rets := types.NewTuple(types.NewVar(0, nil, "", types.Typ[types.Int32])) rets := types.NewTuple(types.NewVar(0, nil, "", types.Typ[types.Int32]))
sig := types.NewSignatureType(nil, nil, nil, params, rets, false) sig := types.NewSignatureType(nil, nil, nil, params, rets, true)
pkg.NewFunc("printf", sig, InGo) pkg.NewFunc("printf", sig, InC)
assertPkg(t, pkg, `; ModuleID = 'foo/bar' assertPkg(t, pkg, `; ModuleID = 'foo/bar'
source_filename = "foo/bar" source_filename = "foo/bar"

View File

@@ -44,7 +44,12 @@ const (
vkFuncPtr vkFuncPtr
vkClosure vkClosure
vkPyFuncRef vkPyFuncRef
vkPyVarRef
vkTuple vkTuple
vkSlice
vkArray
vkMap
vkInterface
vkPhisExpr = -1 vkPhisExpr = -1
) )
@@ -103,7 +108,10 @@ func (p Program) Pointer(typ Type) Type {
} }
func (p Program) Elem(typ Type) Type { func (p Program) Elem(typ Type) Type {
elem := typ.raw.Type.(*types.Pointer).Elem() elem := typ.raw.Type.(interface {
types.Type
Elem() types.Type
}).Elem()
return p.rawType(elem) return p.rawType(elem)
} }
@@ -235,11 +243,11 @@ func (p Program) toType(raw types.Type) Type {
elem := p.rawType(t.Elem()) elem := p.rawType(t.Elem())
return &aType{llvm.PointerType(elem.ll, 0), typ, vkPtr} return &aType{llvm.PointerType(elem.ll, 0), typ, vkPtr}
case *types.Interface: case *types.Interface:
return &aType{p.rtIface(), typ, vkInvalid} return &aType{p.rtIface(), typ, vkInterface}
case *types.Slice: case *types.Slice:
return &aType{p.rtSlice(), typ, vkInvalid} return &aType{p.rtSlice(), typ, vkSlice}
case *types.Map: case *types.Map:
return &aType{p.rtMap(), typ, vkInvalid} return &aType{p.rtMap(), typ, vkMap}
case *types.Struct: case *types.Struct:
ll, kind := p.toLLVMStruct(t) ll, kind := p.toLLVMStruct(t)
return &aType{ll, typ, kind} return &aType{ll, typ, kind}
@@ -249,7 +257,7 @@ func (p Program) toType(raw types.Type) Type {
return &aType{p.toLLVMFuncPtr(t), typ, vkFuncPtr} return &aType{p.toLLVMFuncPtr(t), typ, vkFuncPtr}
case *types.Array: case *types.Array:
elem := p.rawType(t.Elem()) elem := p.rawType(t.Elem())
return &aType{llvm.ArrayType(elem.ll, int(t.Len())), typ, vkInvalid} return &aType{llvm.ArrayType(elem.ll, int(t.Len())), typ, vkArray}
case *types.Chan: case *types.Chan:
} }
panic(fmt.Sprintf("toLLVMType: todo - %T\n", typ)) panic(fmt.Sprintf("toLLVMType: todo - %T\n", typ))
@@ -313,7 +321,7 @@ func (p Program) toLLVMTypes(t *types.Tuple, n int) (ret []llvm.Type) {
func (p Program) toLLVMFunc(sig *types.Signature) llvm.Type { func (p Program) toLLVMFunc(sig *types.Signature) llvm.Type {
tParams := sig.Params() tParams := sig.Params()
n := tParams.Len() n := tParams.Len()
hasVArg := HasVArg(tParams, n) hasVArg := sig.Variadic()
if hasVArg { if hasVArg {
n-- n--
} }

View File

@@ -66,6 +66,27 @@ func (p Program) FuncDecl(sig *types.Signature, bg Background) Type {
return &aType{p.toLLVMFunc(sig), rawType{sig}, vkFuncDecl} return &aType{p.toLLVMFunc(sig), rawType{sig}, vkFuncDecl}
} }
/*
// cvtCxFunc converts a C extended function type into raw type.
func cvtCxFunc(sig *types.Signature, recv *types.Var) *types.Signature {
if sig.Variadic() {
// convert printf-like function type
tParams := sig.Params()
n := tParams.Len()
params := make([]*types.Var, n)
n--
for i := 0; i < n; i++ {
params[i] = tParams.At(i)
}
params[n] = VArg()
sig = types.NewSignatureType(nil, nil, nil, types.NewTuple(params...), sig.Results(), true)
panic("todo")
}
sig = FuncAddCtx(recv, sig)
return sig
}
*/
// Closure creates a closture type for a function. // Closure creates a closture type for a function.
func (p Program) Closure(fn Type) Type { func (p Program) Closure(fn Type) Type {
sig := fn.raw.Type.(*types.Signature) sig := fn.raw.Type.(*types.Signature)
@@ -151,8 +172,9 @@ func (p goTypes) cvtFunc(sig *types.Signature, recv *types.Var) (raw *types.Sign
} }
params, cvt1 := p.cvtTuple(sig.Params()) params, cvt1 := p.cvtTuple(sig.Params())
results, cvt2 := p.cvtTuple(sig.Results()) results, cvt2 := p.cvtTuple(sig.Results())
if cvt1 || cvt2 { if cvt1 || cvt2 || sig.Variadic() {
return types.NewSignatureType(nil, nil, nil, params, results, sig.Variadic()) // variadic always is false in raw type for Go function
return types.NewSignatureType(nil, nil, nil, params, results, false)
} }
return sig return sig
} }

35
x/cjson/README.md Normal file
View File

@@ -0,0 +1,35 @@
LLGo wrapper of DaveGamble/cJSON
=====
[![Build Status](https://github.com/goplus/cjson/actions/workflows/go.yml/badge.svg)](https://github.com/goplus/cjson/actions/workflows/go.yml)
[![GitHub release](https://img.shields.io/github/v/tag/goplus/cjson.svg?label=release)](https://github.com/goplus/cjson/releases)
[![GoDoc](https://pkg.go.dev/badge/github.com/goplus/cjson.svg)](https://pkg.go.dev/github.com/goplus/cjson)
[![Compiler](https://img.shields.io/badge/compiler-llgo-darkgreen.svg)](https://github.com/goplus/llgo)
[![Language](https://img.shields.io/badge/language-Go+-blue.svg)](https://github.com/goplus/gop)
## How to install
```sh
git clone https://github.com/goplus/cjson.git
cd cjson
git submodule init
git submodule update
mkdir build.dir
cd build.dir
cmake ../cJSON
sudo make install
```
## Demos
The `_demo` directory contains our demos (it start with `_` to prevent the `go` command from compiling it):
* [mkjson](_demo/mkjson/mkjson.go): create a json object and print it
### How to run demos
To run the demos in directory `_demo`:
```sh
cd <demo-directory> # eg. cd _demo/mkjson
llgo run .
```

View File

@@ -0,0 +1,27 @@
package main
import (
"github.com/goplus/llgo/c"
"github.com/goplus/llgo/x/cjson"
)
func main() {
mod := cjson.Object()
mod.SetItem(c.Str("name"), cjson.String(c.Str("math")))
syms := cjson.Array()
fn := cjson.Object()
fn.SetItem(c.Str("name"), cjson.String(c.Str("sqrt")))
fn.SetItem(c.Str("sig"), cjson.String(c.Str("(x, /)")))
syms.AddItem(fn)
v := cjson.Object()
v.SetItem(c.Str("name"), cjson.String(c.Str("pi")))
syms.AddItem(v)
mod.SetItem(c.Str("items"), syms)
c.Printf(c.Str("%s\n"), mod.CStr())
mod.Delete()
}

116
x/cjson/cjson.go Normal file
View File

@@ -0,0 +1,116 @@
/*
* 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 cjson
import (
_ "unsafe"
"github.com/goplus/llgo/c"
)
const (
LLGoPackage = "link: cjson"
)
// llgo:type C
type JSON struct {
Unused [0]byte
}
//go:linkname Null C.cJSON_CreateNull
func Null() *JSON
//go:linkname True C.cJSON_CreateTrue
func True() *JSON
//go:linkname False C.cJSON_CreateFalse
func False() *JSON
//go:linkname Bool C.cJSON_CreateBool
func Bool(boolean c.Int) *JSON
//go:linkname Number C.cJSON_CreateNumber
func Number(num float64) *JSON
//go:linkname String C.cJSON_CreateString
func String(str *c.Char) *JSON
//go:linkname Array C.cJSON_CreateArray
func Array() *JSON
//go:linkname Object C.cJSON_CreateObject
func Object() *JSON
// raw json
//
//go:linkname Raw C.cJSON_CreateRaw
func Raw(raw *c.Char) *JSON
// Create a string where valuestring references a string so
// it will not be freed by Delete
//
//go:linkname StringRef C.cJSON_CreateStringReference
func StringRef(str *c.Char) *JSON
// Create an object that only references it's elements so
// they will not be freed by Delete
//
//go:linkname ObjectRef C.cJSON_CreateObjectReference
func ObjectRef(child *JSON) *JSON
// Create an array that only references it's elements so
// they will not be freed by Delete
//
//go:linkname ArrayRef C.cJSON_CreateArrayReference
func ArrayRef(child *JSON) *JSON
// Delete a JSON entity and all subentities.
//
// llgo:link (*JSON).Delete C.cJSON_Delete
func (o *JSON) Delete() {}
// Append item to the specified array.
//
// llgo:link (*JSON).AddItem C.cJSON_AddItemToArray
func (o *JSON) AddItem(item *JSON) c.Int { return 0 }
// Append item to the specified object.
//
// llgo:link (*JSON).SetItem C.cJSON_AddItemToObject
func (o *JSON) SetItem(key *c.Char, item *JSON) c.Int { return 0 }
// llgo:link (*JSON).CStr C.cJSON_PrintUnformatted
func (o *JSON) CStr() *c.Char { return nil }
// Render a JSON entity to text for transfer/storage.
//
// llgo:link (*JSON).Print C.cJSON_Print
func (o *JSON) Print() *c.Char { return nil }
// Render a JSON entity to text for transfer/storage without any formatting.
//
// llgo:link (*JSON).PrintUnformatted C.cJSON_PrintUnformatted
func (o *JSON) PrintUnformatted() *c.Char { return nil }
// Render a JSON entity to text using a buffered strategy.
//
// prebuffer is a guess at the final size. guessing well reduces reallocation.
//
// fmt=0 gives unformatted, =1 gives formatted.
//
// llgo:link (*JSON).PrintBuffered C.cJSON_PrintBuffered
func (o *JSON) PrintBuffered(prebuffer c.Int, fmt c.Int) *c.Char { return nil }

BIN
x/cjson/llgo_autogen.lla Normal file

Binary file not shown.

35
x/sqlite/README.md Normal file
View File

@@ -0,0 +1,35 @@
LLGo wrapper of sqlite
=====
[![Build Status](https://github.com/goplus/sqlite/actions/workflows/go.yml/badge.svg)](https://github.com/goplus/sqlite/actions/workflows/go.yml)
[![GitHub release](https://img.shields.io/github/v/tag/goplus/sqlite.svg?label=release)](https://github.com/goplus/sqlite/releases)
[![GoDoc](https://pkg.go.dev/badge/github.com/goplus/sqlite.svg)](https://pkg.go.dev/github.com/goplus/sqlite)
[![Compiler](https://img.shields.io/badge/compiler-llgo-darkgreen.svg)](https://github.com/goplus/llgo)
[![Language](https://img.shields.io/badge/language-Go+-blue.svg)](https://github.com/goplus/gop)
## How to install
```sh
git clone https://github.com/goplus/sqlite.git
cd sqlite
git submodule init
git submodule update
mkdir build.dir
cd build.dir
../sqlite/configure --enable-shared
sudo make install
```
## Demos
The `_demo` directory contains our demos (it start with `_` to prevent the `go` command from compiling it):
* [sqlitedemo](_demo/sqlitedemo/demo.go): a basic sqlite demo
### How to run demos
To run the demos in directory `_demo`:
```sh
cd <demo-directory> # eg. cd _demo/sqlitedemo
llgo run .
```

View File

@@ -1,12 +0,0 @@
{
"cl": [
"mkdir build.dir",
"cd build.dir",
"../sqlite/configure",
"make",
"clang -emit-llvm -S -o ../llgo_autogen.ll -c sqlite3.c",
"cd ..",
"llgen .",
"rm llgo_autogen.lla; zip llgo_autogen.lla llgo_autogen.ll sqlite.ll",
]
}

Binary file not shown.

Submodule x/sqlite/sqlite deleted from b74eb00e2c

View File

@@ -29,15 +29,17 @@ type (
) )
const ( const (
LLGoPackage = "link" LLGoPackage = "link: sqlite3"
) )
// llgo:type C // llgo:type C
type Sqlite3 struct { type Sqlite3 struct {
Unused [8]byte
} }
// llgo:type C // llgo:type C
type Stmt struct { type Stmt struct {
Unused [8]byte
} }
// ----------------------------------------------------------------------------- // -----------------------------------------------------------------------------

View File

@@ -1,99 +0,0 @@
; ModuleID = 'github.com/goplus/llgo/x/sqlite'
source_filename = "github.com/goplus/llgo/x/sqlite"
%"github.com/goplus/llgo/internal/runtime.String" = type { ptr, i64 }
@"github.com/goplus/llgo/x/sqlite.init$guard" = global ptr null
define ptr @"(*github.com/goplus/llgo/x/sqlite.Errno).Errstr"(ptr %0) {
_llgo_0:
%1 = load i32, ptr %0, align 4
%2 = call ptr @sqlite3_errstr(i32 %1)
ret ptr %2
}
define { ptr, i32 } @"github.com/goplus/llgo/x/sqlite.Open"(ptr %0) {
_llgo_0:
%1 = call ptr @"github.com/goplus/llgo/internal/runtime.AllocZ"(i64 8)
%2 = call i32 @sqlite3_open(ptr %0, ptr %1)
%3 = load ptr, ptr %1, align 8
%mrv = insertvalue { ptr, i32 } poison, ptr %3, 0
%mrv1 = insertvalue { ptr, i32 } %mrv, i32 %2, 1
ret { ptr, i32 } %mrv1
}
define { ptr, i32 } @"github.com/goplus/llgo/x/sqlite.OpenV2"(ptr %0, i32 %1, ptr %2) {
_llgo_0:
%3 = call ptr @"github.com/goplus/llgo/internal/runtime.AllocZ"(i64 8)
%4 = call i32 @sqlite3_open_v2(ptr %0, ptr %3, i32 %1, ptr %2)
%5 = load ptr, ptr %3, align 8
%mrv = insertvalue { ptr, i32 } poison, ptr %5, 0
%mrv1 = insertvalue { ptr, i32 } %mrv, i32 %4, 1
ret { ptr, i32 } %mrv1
}
define { ptr, i32 } @"(*github.com/goplus/llgo/x/sqlite.Sqlite3).Prepare"(ptr %0, %"github.com/goplus/llgo/internal/runtime.String" %1, ptr %2) {
_llgo_0:
%3 = call ptr @"github.com/goplus/llgo/internal/runtime.AllocZ"(i64 8)
%4 = extractvalue %"github.com/goplus/llgo/internal/runtime.String" %1, 0
%5 = extractvalue %"github.com/goplus/llgo/internal/runtime.String" %1, 1
%6 = trunc i64 %5 to i32
%7 = call i32 @sqlite3_prepare(ptr %0, ptr %4, i32 %6, ptr %3, ptr %2)
%8 = load ptr, ptr %3, align 8
%mrv = insertvalue { ptr, i32 } poison, ptr %8, 0
%mrv1 = insertvalue { ptr, i32 } %mrv, i32 %7, 1
ret { ptr, i32 } %mrv1
}
define { ptr, i32 } @"(*github.com/goplus/llgo/x/sqlite.Sqlite3).PrepareV2"(ptr %0, %"github.com/goplus/llgo/internal/runtime.String" %1, ptr %2) {
_llgo_0:
%3 = call ptr @"github.com/goplus/llgo/internal/runtime.AllocZ"(i64 8)
%4 = extractvalue %"github.com/goplus/llgo/internal/runtime.String" %1, 0
%5 = extractvalue %"github.com/goplus/llgo/internal/runtime.String" %1, 1
%6 = trunc i64 %5 to i32
%7 = call i32 @sqlite3_prepare_v2(ptr %0, ptr %4, i32 %6, ptr %3, ptr %2)
%8 = load ptr, ptr %3, align 8
%mrv = insertvalue { ptr, i32 } poison, ptr %8, 0
%mrv1 = insertvalue { ptr, i32 } %mrv, i32 %7, 1
ret { ptr, i32 } %mrv1
}
define { ptr, i32 } @"(*github.com/goplus/llgo/x/sqlite.Sqlite3).PrepareV3"(ptr %0, %"github.com/goplus/llgo/internal/runtime.String" %1, i32 %2, ptr %3) {
_llgo_0:
%4 = call ptr @"github.com/goplus/llgo/internal/runtime.AllocZ"(i64 8)
%5 = extractvalue %"github.com/goplus/llgo/internal/runtime.String" %1, 0
%6 = extractvalue %"github.com/goplus/llgo/internal/runtime.String" %1, 1
%7 = trunc i64 %6 to i32
%8 = call i32 @sqlite3_prepare_v3(ptr %0, ptr %5, i32 %7, i32 %2, ptr %4, ptr %3)
%9 = load ptr, ptr %4, align 8
%mrv = insertvalue { ptr, i32 } poison, ptr %9, 0
%mrv1 = insertvalue { ptr, i32 } %mrv, i32 %8, 1
ret { ptr, i32 } %mrv1
}
define void @"github.com/goplus/llgo/x/sqlite.init"() {
_llgo_0:
%0 = load i1, ptr @"github.com/goplus/llgo/x/sqlite.init$guard", align 1
br i1 %0, label %_llgo_2, label %_llgo_1
_llgo_1: ; preds = %_llgo_0
store i1 true, ptr @"github.com/goplus/llgo/x/sqlite.init$guard", align 1
br label %_llgo_2
_llgo_2: ; preds = %_llgo_1, %_llgo_0
ret void
}
declare ptr @sqlite3_errstr(i32)
declare ptr @"github.com/goplus/llgo/internal/runtime.AllocZ"(i64)
declare i32 @sqlite3_open(ptr, ptr)
declare i32 @sqlite3_open_v2(ptr, ptr, i32, ptr)
declare i32 @sqlite3_prepare(ptr, ptr, i32, ptr, ptr)
declare i32 @sqlite3_prepare_v2(ptr, ptr, i32, ptr, ptr)
declare i32 @sqlite3_prepare_v3(ptr, ptr, i32, i32, ptr, ptr)