@@ -32,8 +32,9 @@ import (
3232
3333// varScope represents a variable allocation scope
3434type varScope struct {
35- nextNum int
36- names map [string ]string // maps Clojure names to Go variable names
35+ nextNum int
36+ names map [string ]string // maps Clojure names to Go variable names
37+ localAtoms map [string ]bool // local atoms proven not to escape
3738}
3839
3940// recurContext represents the context for a loop/recur form
@@ -1669,6 +1670,9 @@ func (g *Generator) generateVarDeref(node *ast.Node) string {
16691670// generateInvoke generates code for an Invoke node
16701671func (g * Generator ) generateInvoke (node * ast.Node ) string {
16711672 invokeNode := node .Sub .(* ast.InvokeNode )
1673+ if result , ok := g .generateLocalAtomInvoke (invokeNode ); ok {
1674+ return result
1675+ }
16721676 if plan := analyzeReducePipeline (invokeNode ); plan != nil {
16731677 return g .generateAOTReducePipeline (invokeNode , plan )
16741678 }
@@ -2031,7 +2035,7 @@ func (g *Generator) generateLet(node *ast.Node, isLoop bool) string {
20312035 }
20322036
20332037 // Emit bindings directly to g.w
2034- for _ , binding := range letNode .Bindings {
2038+ for bindingIndex , binding := range letNode .Bindings {
20352039 bindingNode := binding .Sub .(* ast.BindingNode )
20362040 name := bindingNode .Name .Name ()
20372041 init := bindingNode .Init
@@ -2040,9 +2044,25 @@ func (g *Generator) generateLet(node *ast.Node, isLoop bool) string {
20402044 g .writef ("// let binding \" %s\" \n " , name )
20412045
20422046 // Generate initialization code
2043- initCode := g .generateASTNode (init )
2047+ var localAtomInit * ast.Node
2048+ if ! isLoop {
2049+ localAtomInit = scalarReplaceableAtomInit (
2050+ bindingNode ,
2051+ letNode .Bindings [bindingIndex + 1 :],
2052+ letNode .Body ,
2053+ )
2054+ }
2055+ initCode := ""
2056+ if localAtomInit != nil {
2057+ initCode = g .generateASTNode (localAtomInit )
2058+ } else {
2059+ initCode = g .generateASTNode (init )
2060+ }
20442061 varName := g .allocateLocal (name )
20452062 g .writef ("var %s any = %s\n " , varName , initCode )
2063+ if localAtomInit != nil {
2064+ g .markLocalAtom (name )
2065+ }
20462066 g .writeAssign ("_" , varName ) // Prevent unused variable warning
20472067
20482068 // Collect binding variables for loop
@@ -2754,8 +2774,9 @@ func (g *Generator) pushVarScope() {
27542774
27552775 // Push new scope onto the stack
27562776 g .varScopes = append (g .varScopes , varScope {
2757- nextNum : nextNum ,
2758- names : make (map [string ]string ),
2777+ nextNum : nextNum ,
2778+ names : make (map [string ]string ),
2779+ localAtoms : make (map [string ]bool ),
27592780 })
27602781}
27612782
@@ -2866,6 +2887,20 @@ func (g *Generator) getLocal(name string) string {
28662887 panic (fmt .Sprintf ("variable %s not found in any scope" , name ))
28672888}
28682889
2890+ func (g * Generator ) markLocalAtom (name string ) {
2891+ g .varScopes [len (g .varScopes )- 1 ].localAtoms [name ] = true
2892+ }
2893+
2894+ func (g * Generator ) getLocalAtom (name string ) (string , bool ) {
2895+ for i := len (g .varScopes ) - 1 ; i >= 0 ; i -- {
2896+ scope := & g .varScopes [i ]
2897+ if varName , ok := scope .names [name ]; ok {
2898+ return varName , scope .localAtoms [name ]
2899+ }
2900+ }
2901+ return "" , false
2902+ }
2903+
28692904// allocateTempVar allocates a fresh temporary variable without name tracking
28702905func (g * Generator ) allocateTempVar () string {
28712906 if len (g .varScopes ) == 0 {
0 commit comments