@@ -645,7 +645,6 @@ func (g *codeGen) tryExpr(e *ast.TryExpr) (string, error) {
645645 }
646646
647647 // Build the handler body as Go source in a temporary buffer.
648- var handlerBuf strings.Builder
649648 handlerCode , cerr := g .captureOutput (func () error {
650649 g .pushScope ()
651650 g .declareVar (e .ErrVar )
@@ -680,24 +679,22 @@ func (g *codeGen) tryExpr(e *ast.TryExpr) (string, error) {
680679 return "" , cerr
681680 }
682681
683- // Build the IIFE
684- handlerBuf .WriteString ("func() (r interface{}) {\n " )
685- handlerBuf .WriteString ("\t \t defer func() {\n " )
686- handlerBuf .WriteString ("\t \t \t if e := recover(); e != nil {\n " )
687- handlerBuf .WriteString (fmt .Sprintf ("\t \t \t \t %s := fmt.Sprint(e)\n " , e .ErrVar ))
688- handlerBuf .WriteString (fmt .Sprintf ("\t \t \t \t _ = %s\n " , e .ErrVar ))
689- // Indent and write handler code
690- for _ , line := range strings .Split (handlerCode , "\n " ) {
691- if line != "" {
692- handlerBuf .WriteString ("\t \t \t \t " + strings .TrimLeft (line , "\t " ) + "\n " )
693- }
682+ // Build the IIFE using Go IR
683+ ir := goIIFE {
684+ ReturnType : "(r interface{})" ,
685+ Body : []goNode {
686+ goDefer {Body : []goNode {
687+ goIf {Cond : "e := recover(); e != nil" , Body : []goNode {
688+ goRaw {Code : fmt .Sprintf ("%s := fmt.Sprint(e)" , e .ErrVar )},
689+ goRaw {Code : fmt .Sprintf ("_ = %s" , e .ErrVar )},
690+ goUserCode {Code : handlerCode },
691+ }},
692+ }},
693+ },
694+ Return : exprStr ,
694695 }
695- handlerBuf .WriteString ("\t \t \t }\n " )
696- handlerBuf .WriteString ("\t \t }()\n " )
697- handlerBuf .WriteString (fmt .Sprintf ("\t \t return %s\n " , exprStr ))
698- handlerBuf .WriteString ("\t }()" )
699696
700- return handlerBuf . String ( ), nil
697+ return g . emitGoIR ( ir ), nil
701698}
702699
703700func (g * codeGen ) spawnExpr (e * ast.SpawnExpr ) (string , error ) {
@@ -732,27 +729,24 @@ func (g *codeGen) spawnExpr(e *ast.SpawnExpr) (string, error) {
732729 return "" , cerr
733730 }
734731
735- // Build the IIFE that creates a rugoTask and launches a goroutine
736- var buf strings.Builder
737- buf .WriteString ("func() interface{} {\n " )
738- buf .WriteString ("\t \t t := &rugoTask{done: make(chan struct{})}\n " )
739- buf .WriteString ("\t \t go func() {\n " )
740- buf .WriteString ("\t \t \t defer func() {\n " )
741- buf .WriteString ("\t \t \t \t if e := recover(); e != nil {\n " )
742- buf .WriteString ("\t \t \t \t \t t.err = fmt.Sprint(e)\n " )
743- buf .WriteString ("\t \t \t \t }\n " )
744- buf .WriteString ("\t \t \t \t close(t.done)\n " )
745- buf .WriteString ("\t \t \t }()\n " )
746- for _ , line := range strings .Split (bodyCode , "\n " ) {
747- if line != "" {
748- buf .WriteString ("\t \t \t " + strings .TrimLeft (line , "\t " ) + "\n " )
749- }
750- }
751- buf .WriteString ("\t \t }()\n " )
752- buf .WriteString ("\t \t return interface{}(t)\n " )
753- buf .WriteString ("\t }()" )
754-
755- return buf .String (), nil
732+ // Build the IIFE using Go IR
733+ ir := goIIFE {
734+ Body : []goNode {
735+ goRaw {Code : "t := &rugoTask{done: make(chan struct{})}" },
736+ goGoroutine {Body : []goNode {
737+ goDefer {Body : []goNode {
738+ goIf {Cond : "e := recover(); e != nil" , Body : []goNode {
739+ goRaw {Code : "t.err = fmt.Sprint(e)" },
740+ }},
741+ goRaw {Code : "close(t.done)" },
742+ }},
743+ goUserCode {Code : bodyCode },
744+ }},
745+ },
746+ Return : "interface{}(t)" ,
747+ }
748+
749+ return g .emitGoIR (ir ), nil
756750}
757751
758752func (g * codeGen ) fnExpr (e * ast.FnExpr ) (string , error ) {
@@ -895,42 +889,48 @@ func (g *codeGen) parallelExpr(e *ast.ParallelExpr) (string, error) {
895889 }
896890 }
897891
898- var buf strings.Builder
899- buf .WriteString ("func() interface{} {\n " )
900- buf .WriteString (fmt .Sprintf ("\t \t _results := make([]interface{}, %d)\n " , n ))
901- buf .WriteString ("\t \t var _wg sync.WaitGroup\n " )
902- buf .WriteString ("\t \t var _parErr string\n " )
903- buf .WriteString ("\t \t var _parOnce sync.Once\n " )
904- buf .WriteString (fmt .Sprintf ("\t \t _wg.Add(%d)\n " , n ))
905-
892+ // Build goroutine nodes for each parallel branch
893+ var goroutines []goNode
906894 for i , sc := range stmts {
907- buf .WriteString ("\t \t go func() {\n " )
908- buf .WriteString ("\t \t \t defer _wg.Done()\n " )
909- buf .WriteString ("\t \t \t defer func() {\n " )
910- buf .WriteString ("\t \t \t \t if e := recover(); e != nil {\n " )
911- buf .WriteString ("\t \t \t \t \t _parOnce.Do(func() { _parErr = fmt.Sprint(e) })\n " )
912- buf .WriteString ("\t \t \t \t }\n " )
913- buf .WriteString ("\t \t \t }()\n " )
895+ var bodyNode goNode
914896 if sc .isExpr {
915- buf . WriteString ( fmt .Sprintf ("\t \t \t _results [%d] = %s\n " , i , sc .code ))
897+ bodyNode = goRaw { Code : fmt .Sprintf ("_results [%d] = %s" , i , sc .code )}
916898 } else {
917- for _ , line := range strings .Split (sc .code , "\n " ) {
918- if line != "" {
919- buf .WriteString ("\t \t \t " + strings .TrimLeft (line , "\t " ) + "\n " )
920- }
921- }
922- }
923- buf .WriteString ("\t \t }()\n " )
924- }
925-
926- buf .WriteString ("\t \t _wg.Wait()\n " )
927- buf .WriteString ("\t \t if _parErr != \" \" {\n " )
928- buf .WriteString ("\t \t \t panic(_parErr)\n " )
929- buf .WriteString ("\t \t }\n " )
930- buf .WriteString ("\t \t out := make([]interface{}, len(_results))\n " )
931- buf .WriteString ("\t \t copy(out, _results)\n " )
932- buf .WriteString ("\t \t return interface{}(out)\n " )
933- buf .WriteString ("\t }()" )
934-
935- return buf .String (), nil
899+ bodyNode = goUserCode {Code : sc .code }
900+ }
901+ goroutines = append (goroutines , goGoroutine {Body : []goNode {
902+ goRaw {Code : "defer _wg.Done()" },
903+ goDefer {Body : []goNode {
904+ goIf {Cond : "e := recover(); e != nil" , Body : []goNode {
905+ goRaw {Code : `_parOnce.Do(func() { _parErr = fmt.Sprint(e) })` },
906+ }},
907+ }},
908+ bodyNode ,
909+ }})
910+ }
911+
912+ // Build the IIFE using Go IR
913+ body := []goNode {
914+ goRaw {Code : fmt .Sprintf ("_results := make([]interface{}, %d)" , n )},
915+ goRaw {Code : "var _wg sync.WaitGroup" },
916+ goRaw {Code : "var _parErr string" },
917+ goRaw {Code : "var _parOnce sync.Once" },
918+ goRaw {Code : fmt .Sprintf ("_wg.Add(%d)" , n )},
919+ }
920+ body = append (body , goroutines ... )
921+ body = append (body ,
922+ goRaw {Code : "_wg.Wait()" },
923+ goIf {Cond : `_parErr != ""` , Body : []goNode {
924+ goRaw {Code : "panic(_parErr)" },
925+ }},
926+ goRaw {Code : "out := make([]interface{}, len(_results))" },
927+ goRaw {Code : "copy(out, _results)" },
928+ )
929+
930+ ir := goIIFE {
931+ Body : body ,
932+ Return : "interface{}(out)" ,
933+ }
934+
935+ return g .emitGoIR (ir ), nil
936936}
0 commit comments