Add expression functions with context boundaries
This commit is contained in:
parent
5085ae51aa
commit
773c34f3f4
18 changed files with 391 additions and 52 deletions
|
|
@ -84,7 +84,7 @@ func (g *goGenerator) program(program *Program, packageOverride string) error {
|
|||
g.line("")
|
||||
|
||||
for _, fn := range program.Functions {
|
||||
if usesPrintln(fn.Body) {
|
||||
if usesPrintln(fn.Body) || (fn.ExpressionBody != nil && exprUsesPrintln(fn.ExpressionBody)) {
|
||||
g.needsFmt = true
|
||||
break
|
||||
}
|
||||
|
|
@ -92,7 +92,7 @@ func (g *goGenerator) program(program *Program, packageOverride string) error {
|
|||
if !g.needsFmt {
|
||||
for _, class := range program.Classes {
|
||||
for _, method := range class.Methods {
|
||||
if usesPrintln(method.Body) {
|
||||
if usesPrintln(method.Body) || (method.ExpressionBody != nil && exprUsesPrintln(method.ExpressionBody)) {
|
||||
g.needsFmt = true
|
||||
break
|
||||
}
|
||||
|
|
@ -104,7 +104,7 @@ func (g *goGenerator) program(program *Program, packageOverride string) error {
|
|||
}
|
||||
if !g.needsRunCatch {
|
||||
for _, fn := range program.Functions {
|
||||
if usesRunCatching(fn.Body) {
|
||||
if usesRunCatching(fn.Body) || (fn.ExpressionBody != nil && exprUsesRunCatching(fn.ExpressionBody)) {
|
||||
g.needsRunCatch = true
|
||||
break
|
||||
}
|
||||
|
|
@ -112,7 +112,7 @@ func (g *goGenerator) program(program *Program, packageOverride string) error {
|
|||
}
|
||||
if !g.needsGoUnwrap {
|
||||
for _, fn := range program.Functions {
|
||||
if usesGoUnwrap(fn.Body) {
|
||||
if usesGoUnwrap(fn.Body) || fn.ExpressionBody != nil {
|
||||
g.needsGoUnwrap = true
|
||||
break
|
||||
}
|
||||
|
|
@ -121,7 +121,7 @@ func (g *goGenerator) program(program *Program, packageOverride string) error {
|
|||
if !g.needsGoUnwrap {
|
||||
for _, class := range program.Classes {
|
||||
for _, method := range class.Methods {
|
||||
if usesGoUnwrap(method.Body) {
|
||||
if usesGoUnwrap(method.Body) || method.ExpressionBody != nil {
|
||||
g.needsGoUnwrap = true
|
||||
break
|
||||
}
|
||||
|
|
@ -134,7 +134,7 @@ func (g *goGenerator) program(program *Program, packageOverride string) error {
|
|||
if !g.needsRunCatch {
|
||||
for _, class := range program.Classes {
|
||||
for _, method := range class.Methods {
|
||||
if usesRunCatching(method.Body) {
|
||||
if usesRunCatching(method.Body) || (method.ExpressionBody != nil && exprUsesRunCatching(method.ExpressionBody)) {
|
||||
g.needsRunCatch = true
|
||||
break
|
||||
}
|
||||
|
|
@ -277,13 +277,24 @@ func (g *goGenerator) function(fn FunctionDecl) error {
|
|||
g.write(fn.Name)
|
||||
g.write(renderGoTypeParameters(fn.TypeParams))
|
||||
g.write(g.renderGoFunctionParams(fn))
|
||||
if ret := g.goReturnType(fn.ReturnType); ret != "" {
|
||||
returnType := g.functionReturnType(fn)
|
||||
if ret := g.goReturnType(returnType); ret != "" {
|
||||
g.write(" ")
|
||||
g.write(ret)
|
||||
}
|
||||
g.write(" {\n")
|
||||
g.indentLevel++
|
||||
if err := g.block(fn.Body); err != nil {
|
||||
if fn.ExpressionBody != nil {
|
||||
value, err := g.expr(fn.ExpressionBody, returnType)
|
||||
if err != nil {
|
||||
return fmt.Errorf("function %s: %w", fn.Name, err)
|
||||
}
|
||||
if g.goReturnType(returnType) == "" {
|
||||
g.line(value)
|
||||
} else {
|
||||
g.line("return " + value)
|
||||
}
|
||||
} else if err := g.block(fn.Body); err != nil {
|
||||
return fmt.Errorf("function %s: %w", fn.Name, err)
|
||||
}
|
||||
g.indentLevel--
|
||||
|
|
@ -443,13 +454,24 @@ func (g *goGenerator) method(class ClassDecl, fn FunctionDecl) error {
|
|||
g.write(") ")
|
||||
g.write(fn.Name)
|
||||
g.write(g.renderGoFunctionParams(fn))
|
||||
if ret := g.goReturnType(fn.ReturnType); ret != "" {
|
||||
returnType := g.functionReturnType(fn)
|
||||
if ret := g.goReturnType(returnType); ret != "" {
|
||||
g.write(" ")
|
||||
g.write(ret)
|
||||
}
|
||||
g.write(" {\n")
|
||||
g.indentLevel++
|
||||
if err := g.block(fn.Body); err != nil {
|
||||
if fn.ExpressionBody != nil {
|
||||
value, err := g.expr(fn.ExpressionBody, returnType)
|
||||
if err != nil {
|
||||
return fmt.Errorf("method %s.%s: %w", class.Name, fn.Name, err)
|
||||
}
|
||||
if g.goReturnType(returnType) == "" {
|
||||
g.line(value)
|
||||
} else {
|
||||
g.line("return " + value)
|
||||
}
|
||||
} else if err := g.block(fn.Body); err != nil {
|
||||
return fmt.Errorf("method %s.%s: %w", class.Name, fn.Name, err)
|
||||
}
|
||||
g.indentLevel--
|
||||
|
|
@ -898,6 +920,26 @@ func (g *goGenerator) expr(expr Expr, expectedType string) (string, error) {
|
|||
return "", err
|
||||
}
|
||||
return "gotlinRunBlocking(" + block + ")", nil
|
||||
case "withContext":
|
||||
if len(e.Args) != 2 {
|
||||
return "", fmt.Errorf("withContext expects a Go context and a lambda")
|
||||
}
|
||||
ctx, err := g.expr(e.Args[0], "context.Context")
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
lambda, ok := e.Args[1].(LambdaExpr)
|
||||
if !ok {
|
||||
return "", fmt.Errorf("withContext expects a lambda")
|
||||
}
|
||||
block, err := g.coroutineLambda(lambda, "Unit")
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
if g.currentCoroutineScope == "" {
|
||||
return "gotlinRunWithContext(" + ctx + ", " + block + ")", nil
|
||||
}
|
||||
return g.currentCoroutineScope + ".WithContext(" + ctx + ", " + block + ")", nil
|
||||
case "coroutineScope", "launch":
|
||||
if g.currentCoroutineScope == "" {
|
||||
return "", fmt.Errorf("%s requires a coroutine scope", ident.Name)
|
||||
|
|
@ -2521,6 +2563,24 @@ func (g *goGenerator) hasCoroutineEffect(function FunctionDecl) bool {
|
|||
return g.semantic.FunctionEffects[key].Has(CoroutineEffect)
|
||||
}
|
||||
|
||||
func (g *goGenerator) functionReturnType(function FunctionDecl) string {
|
||||
if !function.InferReturn {
|
||||
return function.ReturnType
|
||||
}
|
||||
var symbol *Symbol
|
||||
if g.currentClass != nil {
|
||||
symbol = g.semantic.ClassInfo[g.currentClass.Name].Method(function.Name)
|
||||
} else {
|
||||
symbol, _ = g.semantic.Global.Lookup(function.Name)
|
||||
}
|
||||
if symbol != nil {
|
||||
if signature, ok := symbol.Type.(FunctionType); ok {
|
||||
return signature.Result.String()
|
||||
}
|
||||
}
|
||||
return function.ReturnType
|
||||
}
|
||||
|
||||
func renderGoTypeParameters(params []string) string {
|
||||
if len(params) == 0 {
|
||||
return ""
|
||||
|
|
@ -2855,6 +2915,9 @@ func usedImportAliases(program *Program) map[string]bool {
|
|||
markType(param.Type)
|
||||
}
|
||||
markType(method.ReturnType)
|
||||
if method.ExpressionBody != nil {
|
||||
walkExpr(method.ExpressionBody)
|
||||
}
|
||||
for _, stmt := range method.Body {
|
||||
walkStmt(stmt)
|
||||
}
|
||||
|
|
@ -2865,6 +2928,9 @@ func usedImportAliases(program *Program) map[string]bool {
|
|||
markType(param.Type)
|
||||
}
|
||||
markType(fn.ReturnType)
|
||||
if fn.ExpressionBody != nil {
|
||||
walkExpr(fn.ExpressionBody)
|
||||
}
|
||||
for _, stmt := range fn.Body {
|
||||
walkStmt(stmt)
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue