Add expression functions with context boundaries

This commit is contained in:
pavel 2026-08-27 23:05:49 +02:00
commit 773c34f3f4
18 changed files with 391 additions and 52 deletions

View file

@ -5,17 +5,17 @@ import (
"strings"
)
var coroutineBuiltins = map[string]bool{"runBlocking": true, "coroutineScope": true, "launch": true, "async": true, "delay": true, "withTimeout": true, "isActive": true, "coroutineContext": true}
var coroutineBuiltins = map[string]bool{"runBlocking": true, "withContext": true, "coroutineScope": true, "launch": true, "async": true, "delay": true, "withTimeout": true, "isActive": true, "coroutineContext": true}
func programUsesCoroutines(program *Program) bool {
for _, fn := range program.Functions {
if statementsUseCoroutines(fn.Body) {
if statementsUseCoroutines(fn.Body) || (fn.ExpressionBody != nil && expressionUsesCoroutines(fn.ExpressionBody)) {
return true
}
}
for _, class := range program.Classes {
for _, fn := range class.Methods {
if statementsUseCoroutines(fn.Body) {
if statementsUseCoroutines(fn.Body) || (fn.ExpressionBody != nil && expressionUsesCoroutines(fn.ExpressionBody)) {
return true
}
}
@ -96,7 +96,9 @@ func (g *goGenerator) emitCoroutineSupport() {
g.line("func (scope *GotlinCoroutineScope) IsActive() bool { return scope.ctx.Err()==nil }")
g.line("func (scope *GotlinCoroutineScope) Context() context.Context { return scope.ctx }")
g.line("func (scope *GotlinCoroutineScope) WithTimeout(ms int, block func(*GotlinCoroutineScope)) { ctx,cancel:=context.WithTimeout(scope.ctx,time.Duration(ms)*time.Millisecond); defer cancel(); child:=gotlinNewCoroutineScope(ctx); defer child.cancel(); block(child); child.wait() }")
g.line("func (scope *GotlinCoroutineScope) WithContext(ctx context.Context, block func(*GotlinCoroutineScope)) { merged,cancel:=context.WithCancel(ctx); stop:=context.AfterFunc(scope.ctx,cancel); defer stop(); defer cancel(); child:=gotlinNewCoroutineScope(merged); defer child.cancel(); block(child); child.wait() }")
g.line("func gotlinRunBlocking(block func(*GotlinCoroutineScope)) { scope:=gotlinNewCoroutineScope(context.Background()); defer scope.cancel(); defer func(){if value:=recover();value!=nil{scope.cancel();scope.workers.Wait();panic(value)}}(); block(scope); scope.wait() }")
g.line("func gotlinRunWithContext(ctx context.Context, block func(*GotlinCoroutineScope)) { scope:=gotlinNewCoroutineScope(ctx); defer scope.cancel(); defer func(){if value:=recover();value!=nil{scope.cancel();scope.workers.Wait();panic(value)}}(); block(scope); scope.wait() }")
g.line("type GotlinDeferred[T any] struct { done chan struct{}; value T; failure any }")
g.line("func gotlinAsync[T any](scope *GotlinCoroutineScope, block func(*GotlinCoroutineScope) T) *GotlinDeferred[T] { deferred:=&GotlinDeferred[T]{done:make(chan struct{})}; scope.Launch(func(child *GotlinCoroutineScope){defer close(deferred.done);defer func(){if value:=recover();value!=nil{deferred.failure=value;scope.fail(value)}}();deferred.value=block(child)}); return deferred }")
g.line("func (deferred *GotlinDeferred[T]) await() T { <-deferred.done; if deferred.failure!=nil{panic(deferred.failure)}; return deferred.value }")