mirror of
https://github.com/goplus/llgo.git
synced 2025-09-27 03:56:05 +08:00
675 lines
16 KiB
Go
675 lines
16 KiB
Go
package main
|
|
|
|
import (
|
|
"unsafe"
|
|
|
|
C "github.com/goplus/llgo/_demo/go/export/c"
|
|
)
|
|
|
|
// assert helper function for testing
|
|
func assert[T comparable](got, expected T, message string) {
|
|
if got != expected {
|
|
println("ASSERTION FAILED:", message)
|
|
println(" Expected:", expected)
|
|
println(" Got: ", got)
|
|
panic("assertion failed: " + message)
|
|
}
|
|
println("✓", message)
|
|
}
|
|
|
|
// Small struct
|
|
type SmallStruct struct {
|
|
ID int8 `json:"id"`
|
|
Flag bool `json:"flag"`
|
|
}
|
|
|
|
// Large struct
|
|
type LargeStruct struct {
|
|
ID int64 `json:"id"`
|
|
Name string `json:"name"`
|
|
Values [10]float64 `json:"values"`
|
|
Metadata map[string]int `json:"metadata"`
|
|
Children []SmallStruct `json:"children"`
|
|
Extra1 int32 `json:"extra1"`
|
|
Extra2 uint64 `json:"extra2"`
|
|
Extra3 float32 `json:"extra3"`
|
|
Extra4 bool `json:"extra4"`
|
|
Extra5 uintptr `json:"extra5"`
|
|
}
|
|
|
|
// Self-referential struct
|
|
type Node struct {
|
|
Data int `json:"data"`
|
|
Next *Node `json:"next"`
|
|
}
|
|
|
|
// Named types
|
|
type MyInt int
|
|
type MyString string
|
|
|
|
// Function types for callbacks
|
|
//
|
|
//llgo:type C
|
|
type IntCallback func(int) int
|
|
|
|
//llgo:type C
|
|
type StringCallback func(string) string
|
|
|
|
//llgo:type C
|
|
type VoidCallback func()
|
|
|
|
// Complex struct with mixed arrays and slices
|
|
type ComplexData struct {
|
|
Matrix [3][4]int32 `json:"matrix"` // 2D array
|
|
Slices [][]string `json:"slices"` // slice of slices - commented out
|
|
IntArray [5]int `json:"int_array"` // 1D array
|
|
DataList []float64 `json:"data_list"` // slice - commented out
|
|
}
|
|
|
|
//export HelloWorld
|
|
func HelloWorld() {
|
|
println("Hello, World!")
|
|
}
|
|
|
|
// Functions with small struct parameters and return values
|
|
|
|
//export CreateSmallStruct
|
|
func CreateSmallStruct(id int8, flag bool) SmallStruct {
|
|
return SmallStruct{ID: id, Flag: flag}
|
|
}
|
|
|
|
//export ProcessSmallStruct
|
|
func ProcessSmallStruct(s SmallStruct) SmallStruct {
|
|
s.ID += 1
|
|
s.Flag = !s.Flag
|
|
return s
|
|
}
|
|
|
|
//export ProcessSmallStructPtr
|
|
func ProcessSmallStructPtr(s *SmallStruct) *SmallStruct {
|
|
if s != nil {
|
|
s.ID *= 2
|
|
s.Flag = !s.Flag
|
|
}
|
|
return s
|
|
}
|
|
|
|
// Functions with large struct parameters and return values
|
|
|
|
//export CreateLargeStruct
|
|
func CreateLargeStruct(id int64, name string) LargeStruct {
|
|
return LargeStruct{
|
|
ID: id,
|
|
Name: name,
|
|
Values: [10]float64{1.1, 2.2, 3.3, 4.4, 5.5, 6.6, 7.7, 8.8, 9.9, 10.0},
|
|
Metadata: map[string]int{"count": 42, "size": 100},
|
|
Children: []SmallStruct{{ID: 1, Flag: true}, {ID: 2, Flag: false}},
|
|
Extra1: 12345,
|
|
Extra2: 67890,
|
|
Extra3: 3.14,
|
|
Extra4: true,
|
|
Extra5: 0x1000,
|
|
}
|
|
}
|
|
|
|
//export ProcessLargeStruct
|
|
func ProcessLargeStruct(ls LargeStruct) int64 {
|
|
total := ls.ID + int64(len(ls.Name))
|
|
for _, v := range ls.Values {
|
|
total += int64(v)
|
|
}
|
|
total += int64(len(ls.Children))
|
|
total += int64(ls.Extra1) + int64(ls.Extra2) + int64(ls.Extra3)
|
|
if ls.Extra4 {
|
|
total += 1000
|
|
}
|
|
total += int64(ls.Extra5)
|
|
return total
|
|
}
|
|
|
|
//export ProcessLargeStructPtr
|
|
func ProcessLargeStructPtr(ls *LargeStruct) *LargeStruct {
|
|
if ls != nil {
|
|
ls.ID += 100
|
|
ls.Name = "processed_" + ls.Name
|
|
ls.Extra1 *= 2
|
|
ls.Extra4 = !ls.Extra4
|
|
}
|
|
return ls
|
|
}
|
|
|
|
// Functions with self-referential struct
|
|
|
|
//export CreateNode
|
|
func CreateNode(data int) *Node {
|
|
return &Node{Data: data, Next: nil}
|
|
}
|
|
|
|
//export LinkNodes
|
|
func LinkNodes(first, second *Node) int {
|
|
if first != nil && second != nil {
|
|
first.Next = second
|
|
return first.Data + second.Data // Return sum for verification
|
|
}
|
|
if first != nil {
|
|
return first.Data + 1000 // Return data + offset if only first exists
|
|
}
|
|
return 2000 // Return fixed value if both are nil
|
|
}
|
|
|
|
//export TraverseNodes
|
|
func TraverseNodes(head *Node) int {
|
|
count := 0
|
|
current := head
|
|
for current != nil {
|
|
count++
|
|
current = current.Next
|
|
if count > 100 { // Safety check
|
|
break
|
|
}
|
|
}
|
|
return count
|
|
}
|
|
|
|
// Functions covering all basic types
|
|
|
|
//export ProcessBool
|
|
func ProcessBool(b bool) bool {
|
|
return !b
|
|
}
|
|
|
|
//export ProcessInt8
|
|
func ProcessInt8(x int8) int8 {
|
|
return x + 1
|
|
}
|
|
|
|
//export ProcessUint8
|
|
func ProcessUint8(x uint8) uint8 {
|
|
return x + 1
|
|
}
|
|
|
|
//export ProcessInt16
|
|
func ProcessInt16(x int16) int16 {
|
|
return x * 2
|
|
}
|
|
|
|
//export ProcessUint16
|
|
func ProcessUint16(x uint16) uint16 {
|
|
return x * 2
|
|
}
|
|
|
|
//export ProcessInt32
|
|
func ProcessInt32(x int32) int32 {
|
|
return x * 3
|
|
}
|
|
|
|
//export ProcessUint32
|
|
func ProcessUint32(x uint32) uint32 {
|
|
return x * 3
|
|
}
|
|
|
|
//export ProcessInt64
|
|
func ProcessInt64(x int64) int64 {
|
|
return x * 4
|
|
}
|
|
|
|
//export ProcessUint64
|
|
func ProcessUint64(x uint64) uint64 {
|
|
return x * 4
|
|
}
|
|
|
|
//export ProcessInt
|
|
func ProcessInt(x int) int {
|
|
return x * 11
|
|
}
|
|
|
|
//export ProcessUint
|
|
func ProcessUint(x uint) uint {
|
|
return x * 21
|
|
}
|
|
|
|
//export ProcessUintptr
|
|
func ProcessUintptr(x uintptr) uintptr {
|
|
return x + 300
|
|
}
|
|
|
|
//export ProcessFloat32
|
|
func ProcessFloat32(x float32) float32 {
|
|
return x * 1.5
|
|
}
|
|
|
|
//export ProcessFloat64
|
|
func ProcessFloat64(x float64) float64 {
|
|
return x * 2.5
|
|
}
|
|
|
|
//export ProcessString
|
|
func ProcessString(s string) string {
|
|
return "processed_" + s
|
|
}
|
|
|
|
//export ProcessUnsafePointer
|
|
func ProcessUnsafePointer(p unsafe.Pointer) unsafe.Pointer {
|
|
return p
|
|
}
|
|
|
|
// Functions with named types
|
|
|
|
//export ProcessMyInt
|
|
func ProcessMyInt(x MyInt) MyInt {
|
|
return x * 10
|
|
}
|
|
|
|
//export ProcessMyString
|
|
func ProcessMyString(s MyString) MyString {
|
|
return MyString("modified_" + string(s))
|
|
}
|
|
|
|
// Functions with arrays, slices, maps, channels
|
|
|
|
//export ProcessIntArray
|
|
func ProcessIntArray(arr [5]int) int {
|
|
total := 0
|
|
for _, v := range arr {
|
|
total += v
|
|
}
|
|
return total
|
|
}
|
|
|
|
//export CreateComplexData
|
|
func CreateComplexData() ComplexData {
|
|
return ComplexData{
|
|
Matrix: [3][4]int32{{1, 2, 3, 4}, {5, 6, 7, 8}, {9, 10, 11, 12}},
|
|
Slices: [][]string{{"helo"}},
|
|
IntArray: [5]int{10, 20, 30, 40, 50},
|
|
DataList: []float64{1.0},
|
|
}
|
|
}
|
|
|
|
//export ProcessComplexData
|
|
func ProcessComplexData(data ComplexData) int32 {
|
|
// Sum all matrix elements
|
|
var sum int32
|
|
for i := 0; i < 3; i++ {
|
|
for j := 0; j < 4; j++ {
|
|
sum += data.Matrix[i][j]
|
|
}
|
|
}
|
|
return sum
|
|
}
|
|
|
|
// Functions with multidimensional arrays as parameters and return values
|
|
|
|
//export ProcessMatrix2D
|
|
func ProcessMatrix2D(matrix [3][4]int32) int32 {
|
|
var sum int32
|
|
for i := 0; i < 3; i++ {
|
|
for j := 0; j < 4; j++ {
|
|
sum += matrix[i][j]
|
|
}
|
|
}
|
|
return sum
|
|
}
|
|
|
|
//export CreateMatrix1D
|
|
func CreateMatrix1D() [4]int32 {
|
|
return [4]int32{1, 2, 3, 4}
|
|
}
|
|
|
|
//export CreateMatrix2D
|
|
func CreateMatrix2D() [3][4]int32 {
|
|
return [3][4]int32{{1, 2, 3, 4}, {5, 6, 7, 8}, {9, 10, 11, 12}}
|
|
}
|
|
|
|
//export ProcessMatrix3D
|
|
func ProcessMatrix3D(cube [2][3][4]uint8) uint32 {
|
|
var sum uint32
|
|
for i := 0; i < 2; i++ {
|
|
for j := 0; j < 3; j++ {
|
|
for k := 0; k < 4; k++ {
|
|
sum += uint32(cube[i][j][k])
|
|
}
|
|
}
|
|
}
|
|
return sum
|
|
}
|
|
|
|
//export CreateMatrix3D
|
|
func CreateMatrix3D() [2][3][4]uint8 {
|
|
var cube [2][3][4]uint8
|
|
val := uint8(1)
|
|
for i := 0; i < 2; i++ {
|
|
for j := 0; j < 3; j++ {
|
|
for k := 0; k < 4; k++ {
|
|
cube[i][j][k] = val
|
|
val++
|
|
}
|
|
}
|
|
}
|
|
return cube
|
|
}
|
|
|
|
//export ProcessGrid5x4
|
|
func ProcessGrid5x4(grid [5][4]float64) float64 {
|
|
var sum float64
|
|
for i := 0; i < 5; i++ {
|
|
for j := 0; j < 4; j++ {
|
|
sum += grid[i][j]
|
|
}
|
|
}
|
|
return sum
|
|
}
|
|
|
|
//export CreateGrid5x4
|
|
func CreateGrid5x4() [5][4]float64 {
|
|
var grid [5][4]float64
|
|
val := 1.0
|
|
for i := 0; i < 5; i++ {
|
|
for j := 0; j < 4; j++ {
|
|
grid[i][j] = val
|
|
val += 0.5
|
|
}
|
|
}
|
|
return grid
|
|
}
|
|
|
|
//export ProcessIntSlice
|
|
func ProcessIntSlice(slice []int) int {
|
|
total := 0
|
|
for _, v := range slice {
|
|
total += v
|
|
}
|
|
return total
|
|
}
|
|
|
|
//export ProcessStringMap
|
|
func ProcessStringMap(m map[string]int) int {
|
|
total := 0
|
|
for _, v := range m {
|
|
total += v
|
|
}
|
|
return total
|
|
}
|
|
|
|
//export ProcessIntChannel
|
|
func ProcessIntChannel(ch chan int) int {
|
|
select {
|
|
case val := <-ch:
|
|
return val
|
|
default:
|
|
return -1
|
|
}
|
|
}
|
|
|
|
// Functions with function callbacks
|
|
|
|
//export ProcessWithIntCallback
|
|
func ProcessWithIntCallback(x int, callback IntCallback) int {
|
|
if callback != nil {
|
|
return callback(x)
|
|
}
|
|
return x
|
|
}
|
|
|
|
//export ProcessWithStringCallback
|
|
func ProcessWithStringCallback(s string, callback StringCallback) string {
|
|
if callback != nil {
|
|
return callback(s)
|
|
}
|
|
return s
|
|
}
|
|
|
|
//export ProcessWithVoidCallback
|
|
func ProcessWithVoidCallback(callback VoidCallback) int {
|
|
if callback != nil {
|
|
callback()
|
|
return 123 // Return non-zero to indicate callback was called
|
|
}
|
|
return 456 // Return different value if callback is nil
|
|
}
|
|
|
|
//export ProcessThreeUnnamedParams
|
|
func ProcessThreeUnnamedParams(a int, s string, b bool) float64 {
|
|
result := float64(a) + float64(len(s))
|
|
if b {
|
|
result *= 1.5
|
|
}
|
|
return result
|
|
}
|
|
|
|
// Functions with interface
|
|
|
|
//export ProcessInterface
|
|
func ProcessInterface(i interface{}) int {
|
|
switch v := i.(type) {
|
|
case int:
|
|
return v + 100
|
|
case string:
|
|
return len(v) * 10
|
|
default:
|
|
return 999 // Non-zero default to avoid false positives
|
|
}
|
|
}
|
|
|
|
// Functions with various parameter counts
|
|
|
|
//export NoParams
|
|
func NoParams() int {
|
|
return 42
|
|
}
|
|
|
|
//export OneParam
|
|
func OneParam(x int) int {
|
|
return x * 2
|
|
}
|
|
|
|
//export TwoParams
|
|
func TwoParams(a int, b string) string {
|
|
return string(rune(a)) + b
|
|
}
|
|
|
|
//export ThreeParams
|
|
func ThreeParams(a int32, b float64, c bool) float64 {
|
|
result := float64(a) + b
|
|
if c {
|
|
result *= 2
|
|
}
|
|
return result
|
|
}
|
|
|
|
//export MultipleParams
|
|
func MultipleParams(a int8, b uint16, c int32, d uint64, e float32, f float64, g string, h bool) string {
|
|
result := g + "_" + string(rune('A'+a)) + string(rune('0'+b%10)) + string(rune('0'+c%10))
|
|
if h {
|
|
result += "_true"
|
|
}
|
|
return result + "_" + string(rune('0'+int(d%10))) + "_" + string(rune('0'+int(e)%10)) + "_" + string(rune('0'+int(f)%10))
|
|
}
|
|
|
|
//export NoParamNames
|
|
func NoParamNames(int8, int16, bool) int32 {
|
|
return 789 // Return non-zero value for testing, params are unnamed by design
|
|
}
|
|
|
|
// Functions returning no value
|
|
|
|
//export NoReturn
|
|
func NoReturn(message string) {
|
|
println("Message:", message)
|
|
}
|
|
|
|
// Functions using XType from c package
|
|
|
|
//export CreateXType
|
|
func CreateXType(id int32, name string, value float64, flag bool) C.XType {
|
|
return C.XType{
|
|
ID: id,
|
|
Name: name,
|
|
Value: value,
|
|
Flag: flag,
|
|
}
|
|
}
|
|
|
|
//export ProcessXType
|
|
func ProcessXType(x C.XType) C.XType {
|
|
x.ID += 100
|
|
x.Name = "processed_" + x.Name
|
|
x.Value *= 2.0
|
|
x.Flag = !x.Flag
|
|
return x
|
|
}
|
|
|
|
//export ProcessXTypePtr
|
|
func ProcessXTypePtr(x *C.XType) *C.XType {
|
|
if x != nil {
|
|
x.ID *= 2
|
|
x.Name = "ptr_" + x.Name
|
|
x.Value += 10.0
|
|
x.Flag = !x.Flag
|
|
}
|
|
return x
|
|
}
|
|
|
|
func main() {
|
|
println("=== Export Demo ===")
|
|
|
|
// Test small struct
|
|
small := CreateSmallStruct(5, true)
|
|
assert(small.ID, int8(5), "CreateSmallStruct ID should be 5")
|
|
assert(small.Flag, true, "CreateSmallStruct Flag should be true")
|
|
println("Small struct:", small.ID, small.Flag)
|
|
|
|
processed := ProcessSmallStruct(small)
|
|
assert(processed.ID, int8(6), "ProcessSmallStruct should increment ID to 6")
|
|
assert(processed.Flag, false, "ProcessSmallStruct should flip Flag to false")
|
|
println("Processed small:", processed.ID, processed.Flag)
|
|
|
|
// Test large struct
|
|
large := CreateLargeStruct(12345, "test")
|
|
assert(large.ID, int64(12345), "CreateLargeStruct ID should be 12345")
|
|
assert(large.Name, "test", "CreateLargeStruct Name should be 'test'")
|
|
println("Large struct ID:", large.ID, "Name:", large.Name)
|
|
|
|
total := ProcessLargeStruct(large)
|
|
// Expected calculation:
|
|
// ID: 12345, Name len: 4, Values: 1+2+3+4+5+6+7+8+9+10=55, Children len: 2
|
|
// Extra1: 12345, Extra2: 67890, Extra3: 3, Extra4: +1000, Extra5: 4096
|
|
expectedTotal := int64(12345 + 4 + 55 + 2 + 12345 + 67890 + 3 + 1000 + 4096)
|
|
assert(total, expectedTotal, "ProcessLargeStruct total should match expected calculation")
|
|
println("Large struct total:", total)
|
|
|
|
// Test self-referential struct
|
|
node1 := CreateNode(100)
|
|
node2 := CreateNode(200)
|
|
linkResult := LinkNodes(node1, node2)
|
|
assert(linkResult, 300, "LinkNodes should return sum of node data (100 + 200)")
|
|
|
|
count := TraverseNodes(node1)
|
|
assert(count, 2, "TraverseNodes should count 2 linked nodes")
|
|
println("Node count:", count)
|
|
|
|
// Test basic types with assertions
|
|
assert(ProcessBool(true), false, "ProcessBool(true) should return false")
|
|
assert(ProcessInt8(10), int8(11), "ProcessInt8(10) should return 11")
|
|
f32Result := ProcessFloat32(3.14)
|
|
// Float comparison with tolerance
|
|
if f32Result < 4.7 || f32Result > 4.72 {
|
|
println("ASSERTION FAILED: ProcessFloat32(3.14) should return ~4.71, got:", f32Result)
|
|
panic("float assertion failed")
|
|
}
|
|
println("✓ ProcessFloat32(3.14) returns ~4.71")
|
|
|
|
assert(ProcessString("hello"), "processed_hello", "ProcessString should prepend 'processed_'")
|
|
|
|
println("Bool:", ProcessBool(true))
|
|
println("Int8:", ProcessInt8(10))
|
|
println("Float32:", ProcessFloat32(3.14))
|
|
println("String:", ProcessString("hello"))
|
|
|
|
// Test named types
|
|
myInt := ProcessMyInt(MyInt(42))
|
|
assert(myInt, MyInt(420), "ProcessMyInt(42) should return 420")
|
|
println("MyInt:", int(myInt))
|
|
|
|
myStr := ProcessMyString(MyString("world"))
|
|
assert(myStr, MyString("modified_world"), "ProcessMyString should prepend 'modified_'")
|
|
println("MyString:", string(myStr))
|
|
|
|
// Test collections
|
|
arr := [5]int{1, 2, 3, 4, 5}
|
|
arrSum := ProcessIntArray(arr)
|
|
assert(arrSum, 15, "ProcessIntArray([1,2,3,4,5]) should return 15")
|
|
println("Array sum:", arrSum)
|
|
|
|
slice := []int{10, 20, 30}
|
|
sliceSum := ProcessIntSlice(slice)
|
|
assert(sliceSum, 60, "ProcessIntSlice([10,20,30]) should return 60")
|
|
println("Slice sum:", sliceSum)
|
|
|
|
m := make(map[string]int)
|
|
m["a"] = 100
|
|
m["b"] = 200
|
|
mapSum := ProcessStringMap(m)
|
|
assert(mapSum, 300, "ProcessStringMap({'a':100,'b':200}) should return 300")
|
|
println("Map sum:", mapSum)
|
|
|
|
// Test multidimensional arrays
|
|
matrix2d := CreateMatrix2D()
|
|
matrix2dSum := ProcessMatrix2D(matrix2d)
|
|
assert(matrix2dSum, int32(78), "ProcessMatrix2D should return 78 (sum of 1+2+...+12)")
|
|
println("Matrix2D sum:", matrix2dSum)
|
|
|
|
matrix3d := CreateMatrix3D()
|
|
matrix3dSum := ProcessMatrix3D(matrix3d)
|
|
assert(matrix3dSum, uint32(300), "ProcessMatrix3D should return 300")
|
|
println("Matrix3D sum:", matrix3dSum)
|
|
|
|
grid5x4 := CreateGrid5x4()
|
|
gridSum := ProcessGrid5x4(grid5x4)
|
|
assert(gridSum, 115.0, "ProcessGrid5x4 should return 115.0")
|
|
println("Grid5x4 sum:", gridSum)
|
|
|
|
// Test complex data with multidimensional arrays
|
|
complexData := CreateComplexData()
|
|
complexSum := ProcessComplexData(complexData)
|
|
assert(complexSum, int32(78), "ProcessComplexData should return 78")
|
|
println("ComplexData matrix sum:", complexSum)
|
|
|
|
// Test various parameter counts
|
|
assert(NoParams(), 42, "NoParams should return 42")
|
|
assert(OneParam(5), 10, "OneParam(5) should return 10")
|
|
assert(TwoParams(65, "_test"), "A_test", "TwoParams should return 'A_test'")
|
|
assert(ThreeParams(10, 2.5, true), 25.0, "ThreeParams should return 25.0")
|
|
assert(NoParamNames(1, 2, false), int32(789), "NoParamNames should return 789")
|
|
|
|
println("NoParams:", NoParams())
|
|
println("OneParam:", OneParam(5))
|
|
println("TwoParams:", TwoParams(65, "_test"))
|
|
println("ThreeParams:", ThreeParams(10, 2.5, true))
|
|
println("MultipleParams:", MultipleParams(1, 2, 3, 4, 5.0, 6.0, "result", true))
|
|
println("NoParamNames:", NoParamNames(1, 2, false))
|
|
|
|
// Test XType from c package
|
|
xtype := CreateXType(42, "test", 3.14, true)
|
|
println("XType:", xtype.ID, xtype.Name, xtype.Value, xtype.Flag)
|
|
|
|
processedX := ProcessXType(xtype)
|
|
println("Processed XType:", processedX.ID, processedX.Name, processedX.Value, processedX.Flag)
|
|
|
|
ptrX := ProcessXTypePtr(&xtype)
|
|
if ptrX != nil {
|
|
println("Ptr XType:", ptrX.ID, ptrX.Name, ptrX.Value, ptrX.Flag)
|
|
}
|
|
|
|
// Test callback functions
|
|
intResult := ProcessWithIntCallback(10, func(x int) int { return x * 3 })
|
|
println("IntCallback result:", intResult)
|
|
|
|
stringResult := ProcessWithStringCallback("hello", func(s string) string { return s + "_callback" })
|
|
println("StringCallback result:", stringResult)
|
|
|
|
ProcessWithVoidCallback(func() { println("VoidCallback executed") })
|
|
|
|
NoReturn("demo completed")
|
|
}
|