reorganize: consolidate demo directories

- Consolidate _demo, _pydemo, _embdemo into single _demo directory structure
- Organize demos by language: _demo/{go,py,c,embed}/
- Categorize demos based on imports:
- Python library demos (py imports) → _demo/py/
- C/C++ library demos (c/cpp imports) → _demo/c/
- Go-specific demos → _demo/go/
- Embedded demos → _demo/embed/
- Move C-related demos (asm*, cabi*, cgo*, linkname, targetsbuild) from go/ to c/
- Update all path references in README.md and GitHub workflows
- Improve demo organization and navigation as requested in #1256

🤖 Generated with [Claude Code](https://claude.ai/code)

Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
Li Jie
2025-09-09 15:06:55 +08:00
parent 849b23079b
commit 64df39b3c5
96 changed files with 61 additions and 52 deletions

View File

@@ -0,0 +1,31 @@
package async
import (
_ "unsafe"
)
type Void = [0]byte
type Future[T any] interface {
Then(cb func(T))
}
type future[T any] struct {
cb func(func(T))
}
func (f *future[T]) Then(cb func(T)) {
f.cb(cb)
}
func Async[T any](fn func(func(T))) Future[T] {
return &future[T]{fn}
}
func Run[T any](future Future[T]) T {
var ret T
future.Then(func(v T) {
ret = v
})
return ret
}

23
_demo/go/async/main.go Normal file
View File

@@ -0,0 +1,23 @@
package main
import (
"time"
"github.com/goplus/llgo/_demo/go/async/async"
"github.com/goplus/llgo/_demo/go/async/timeout"
)
func Sleep(i int, d time.Duration) async.Future[int] {
return async.Async(func(resolve func(int)) {
timeout.Timeout(d).Then(func(async.Void) {
resolve(i)
})
})
}
func main() {
async.Run(async.Async(func(resolve func(async.Void)) {
println("read file")
defer resolve(async.Void{})
}))
}

View File

@@ -0,0 +1,16 @@
package timeout
import (
"time"
"github.com/goplus/llgo/_demo/go/async/async"
)
func Timeout(d time.Duration) async.Future[async.Void] {
return async.Async(func(resolve func(async.Void)) {
go func() {
time.Sleep(d)
resolve(async.Void{})
}()
})
}

View File

@@ -0,0 +1,28 @@
package main
import (
"fmt"
"os"
"path/filepath"
)
func main() {
tempDir := os.TempDir()
noexist := filepath.Join(tempDir, "noexist.txt")
if _, err := os.Stat(noexist); err != nil {
if os.IsNotExist(err) {
fmt.Println("noexist:", err.Error())
} else {
fmt.Println("exist,other err:", err.Error())
}
}
if _, err := os.Open(noexist); err != nil {
if os.IsNotExist(err) {
fmt.Println("noexist:", err.Error())
} else {
fmt.Println("exist,other err:", err.Error())
}
}
}

View File

@@ -0,0 +1,20 @@
package main
import (
"bytes"
"os/exec"
"path/filepath"
)
func main() {
var data bytes.Buffer
cmd := exec.Command("echo", "hello llgo")
cmd.Dir = filepath.Dir("./")
cmd.Stdout = &data
err := cmd.Run()
if err != nil {
panic(err)
}
println("len:", len(data.Bytes()))
println("data:", data.String())
}

View File

@@ -0,0 +1,9 @@
package main
import (
"math/cmplx"
)
func main() {
println("abs(3+4i):", cmplx.Abs(3+4i))
}

18
_demo/go/defer/main.go Normal file
View File

@@ -0,0 +1,18 @@
package main
func main() {
var a int = 5
defer println(a)
defer func() {
println(a)
}()
defer func() {
println(recover().(string))
}()
a = 10
panic("error")
//Output:
// error
// 10
// 5
}

View File

@@ -0,0 +1,42 @@
package main
import (
"fmt"
)
type MyStruct[T any] struct {
value T
}
func (m *MyStruct[T]) Method() {
fmt.Println("In generic method")
genericFunc[T](m.value)
}
func genericFunc[T any](v T) {
fmt.Println("In generic function")
normalFunc()
}
func normalFunc() {
fmt.Println("In normal function")
panic("panic occurs here")
}
func main() {
m := &MyStruct[string]{value: "hello"}
m.Method()
}
//Expected:
// In generic method
// In generic function
// In normal function
// panic: panic occurs here
// [0x00C6D310 github.com/goplus/llgo/internal/runtime.Rethrow+0x2f, SP = 0x60]
// [0x00C6CF44 github.com/goplus/llgo/internal/runtime.Panic+0x2d, SP = 0x50]
// [0x00C69420 main.normalFunc+0xf, SP = 0xa8]
// [0x00C69564 main.genericFunc[string]+0x18, SP = 0x74]
// [0x00C694A8 main.(*MyStruct[string]).Method+0x1f, SP = 0x84]
// [0x00C6936C main+0x4, SP = 0x40]

3
_demo/go/go.mod Normal file
View File

@@ -0,0 +1,3 @@
module github.com/goplus/llgo/_demo/go
go 1.20

0
_demo/go/go.sum Normal file
View File

View File

@@ -0,0 +1,12 @@
package main
func main() {
done := false
go func() {
println("Hello, goroutine")
done = true
}()
for !done {
print(".")
}
}

7
_demo/go/gotime/time.go Normal file
View File

@@ -0,0 +1,7 @@
package main
import "time"
func main() {
println(time.Now().String())
}

View File

@@ -0,0 +1,85 @@
package main
// Tests of interface conversions and type assertions.
type I0 interface {
}
type I1 interface {
f()
}
type I2 interface {
f()
g()
}
type C0 struct{}
type C1 struct{}
func (C1) f() {}
type C2 struct{}
func (C2) f() {}
func (C2) g() {}
func main() {
var i0 I0
var i1 I1
var i2 I2
// Nil always causes a type assertion to fail, even to the
// same type.
if _, ok := i0.(I0); ok {
panic("nil i0.(I0) succeeded")
}
if _, ok := i1.(I1); ok {
panic("nil i1.(I1) succeeded")
}
if _, ok := i2.(I2); ok {
panic("nil i2.(I2) succeeded")
}
// Conversions can't fail, even with nil.
_ = I0(i0)
_ = I0(i1)
_ = I1(i1)
_ = I0(i2)
_ = I1(i2)
_ = I2(i2)
// Non-nil type assertions pass or fail based on the concrete type.
i1 = C1{}
if _, ok := i1.(I0); !ok {
panic("C1 i1.(I0) failed")
}
if _, ok := i1.(I1); !ok {
panic("C1 i1.(I1) failed")
}
if _, ok := i1.(I2); ok {
panic("C1 i1.(I2) succeeded")
}
i1 = C2{}
if _, ok := i1.(I0); !ok {
panic("C2 i1.(I0) failed")
}
if _, ok := i1.(I1); !ok {
panic("C2 i1.(I1) failed")
}
if _, ok := i1.(I2); !ok {
panic("C2 i1.(I2) failed")
}
// Conversions can't fail.
i1 = C1{}
if I0(i1) == nil {
panic("C1 I0(i1) was nil")
}
if I1(i1) == nil {
panic("C1 I1(i1) was nil")
}
println("pass")
}

9
_demo/go/logdemo/log.go Normal file
View File

@@ -0,0 +1,9 @@
package main
import (
"log"
)
func main() {
log.Println("Hello")
}

11
_demo/go/math/math.go Normal file
View File

@@ -0,0 +1,11 @@
package main
import (
"math"
)
func main() {
println(math.Sqrt(2))
println(math.Abs(-1.2))
println(math.Ldexp(1.2, 3))
}

View File

@@ -0,0 +1,13 @@
package main
import "net/textproto"
func main() {
h := make(textproto.MIMEHeader)
h.Set("host", "www.example.com")
println(h.Get("Host"))
}
/* Expected output:
www.example.com
*/

View File

@@ -0,0 +1,34 @@
package main
import (
"fmt"
"os"
"path/filepath"
)
func main() {
tempDir, err := os.MkdirTemp("", "example*")
if err != nil {
fmt.Println("Failed to create temp directory:", err)
return
}
defer os.Remove(tempDir)
fmt.Println("Temp directory:", tempDir)
tempFile, err := os.CreateTemp("", "example*.txt")
if err != nil {
fmt.Println("Failed to create temp file:", err)
return
}
defer tempFile.Close()
defer os.Remove(tempFile.Name())
fmt.Println("Temp file:", tempFile.Name())
nestedDir := filepath.Join("nested", "directory")
err = os.MkdirAll(nestedDir, 0755)
if err != nil {
fmt.Println("Failed to create nested directory:", err)
return
}
fmt.Println("Nest directory:", nestedDir)
}

View File

@@ -0,0 +1,19 @@
package main
import (
"fmt"
"os/exec"
"runtime"
)
func main() {
ls := "ls"
if runtime.GOOS == "windows" {
ls = "dir"
}
lspath, _ := exec.LookPath(ls)
if lspath != "" {
ls = lspath
}
fmt.Println(ls)
}

View File

@@ -0,0 +1,18 @@
package main
import (
"crypto/rand"
"fmt"
)
func main() {
c := 10
b := make([]byte, c)
_, err := rand.Read(b)
if err != nil {
fmt.Println("error:", err)
return
}
// The slice should now contain random bytes instead of only zeroes.
fmt.Printf("%x\n", b)
}

12
_demo/go/randdemo/rand.go Normal file
View File

@@ -0,0 +1,12 @@
package main
import (
"fmt"
"math/rand"
)
func main() {
fmt.Println(rand.Intn(100))
fmt.Println(rand.Intn(100))
fmt.Println(rand.Intn(100))
}

29
_demo/go/readdir/main.go Normal file
View File

@@ -0,0 +1,29 @@
package main
import (
"fmt"
"os"
)
func main() {
entries, err := os.ReadDir("../")
if err != nil {
panic(err)
}
if len(entries) == 0 {
panic("No files found")
}
var check int
for _, e := range entries {
fmt.Printf("%s isDir[%t]\n", e.Name(), e.IsDir())
if !e.IsDir() {
switch e.Name() {
case "go.sum", "go.mod":
check++
}
}
}
if check != 2 {
panic("Bad readdir entries go.mod/go.sum")
}
}

View File

@@ -0,0 +1,42 @@
package main
import (
"fmt"
"reflect"
)
func add(a, b int) int {
return a + b
}
func main() {
fn := func(a, b int) int {
return a + b
}
var i int
fn1 := func() {
i++
}
fn2 := func() func() {
return func() {
println("closure", i)
}
}
fns := []any{add, fn, fn1, fn2}
for _, fn := range fns {
v := reflect.ValueOf(fn)
fmt.Println(v.Type())
fmt.Println(v.Kind())
if v.Kind() != reflect.Func {
panic(fmt.Sprintf("not func: %T", fn))
}
t := v.Type()
fmt.Println(t)
fmt.Println(t.Kind())
if t.Kind() != reflect.Func {
panic(fmt.Sprintf("not func: %T", fn))
}
}
}

112
_demo/go/sync/sync.go Normal file
View File

@@ -0,0 +1,112 @@
package main
import (
"fmt"
"sync"
"sync/atomic"
"time"
)
// Counter represents a thread-safe counter
type Counter struct {
mu sync.Mutex
value int64
}
// Increment increases the counter value by 1
func (c *Counter) Increment() {
c.mu.Lock()
defer c.mu.Unlock()
c.value++
}
// GetValue returns the current value of the counter
func (c *Counter) GetValue() int64 {
c.mu.Lock()
defer c.mu.Unlock()
return c.value
}
// Constant values for the test
const (
numGoroutines = 64
numIterations = 10000
expectedTotal = numGoroutines * numIterations
)
func main() {
// Create a new counter instance
counter := &Counter{}
// Create a wait group to wait for all goroutines to finish
var wg sync.WaitGroup
// Track active goroutines for monitoring
var activeGoroutines int32
// Start time
startTime := time.Now()
// Launch goroutines
for i := 0; i < numGoroutines; i++ {
wg.Add(1)
atomic.AddInt32(&activeGoroutines, 1)
go func(id int) {
defer func() {
wg.Done()
atomic.AddInt32(&activeGoroutines, -1)
}()
// Each goroutine increments the counter numIterations times
for j := 0; j < numIterations; j++ {
counter.Increment()
// Simulate varying workload with random sleeps
if j%100 == 0 {
time.Sleep(time.Microsecond)
}
}
fmt.Printf("Goroutine %d finished\n", id)
}(i)
}
// Monitor progress in a separate goroutine
go func() {
for {
active := atomic.LoadInt32(&activeGoroutines)
if active == 0 {
break
}
fmt.Printf("Active goroutines: %d\n", active)
time.Sleep(time.Second)
}
}()
// Wait for all goroutines to complete
wg.Wait()
// Calculate execution time
duration := time.Since(startTime)
// Get and verify the final result
finalValue := counter.GetValue()
fmt.Printf("\nExecution completed in: %v\n", duration)
fmt.Printf("Final counter value: %d\n", finalValue)
fmt.Printf("Expected value: %d\n", expectedTotal)
// Assert the result
if finalValue != expectedTotal {
panic(fmt.Sprintf("ERROR: Counter value mismatch! Expected %d, got %d\n",
expectedTotal, finalValue))
} else {
fmt.Printf("SUCCESS: Counter value matches expected total\n")
}
// Print some statistics
opsPerSecond := float64(expectedTotal) / duration.Seconds()
fmt.Printf("\nStatistics:\n")
fmt.Printf("Operations per second: %.2f\n", opsPerSecond)
fmt.Printf("Average time per operation: %.2f ns\n",
float64(duration.Nanoseconds())/float64(expectedTotal))
}

26
_demo/go/sysexec/exec.go Normal file
View File

@@ -0,0 +1,26 @@
package main
import (
"fmt"
"os/exec"
"runtime"
"syscall"
)
func main() {
ls := "ls"
args := []string{ls, "-l"}
if runtime.GOOS == "windows" {
ls = "dir"
args = []string{ls}
}
lspath, _ := exec.LookPath(ls)
if lspath != "" {
ls = lspath
}
err := syscall.Exec(ls, args, nil)
if err != nil {
fmt.Println("syscall.Exec error:", err)
return
}
}

View File

@@ -0,0 +1,11 @@
package main
import (
"fmt"
"time"
)
func main() {
t := time.Now().Add(time.Second * 5)
fmt.Println(time.Until(t))
}