@@ -288,6 +288,79 @@ function transformBinaryOrLogical(node, state, ancestors) {
288288 node . arguments = [ node . right ] ;
289289}
290290
291+ // Shared helper used by both IfStatement and ForStatement handlers.
292+ // Adds temp variable copies, replaces references, and appends a return
293+ // statement to a branch/loop function body.
294+ // sourcePrefix: the root identifier to read from ('vars' for loops,
295+ // null for if-branches where we read directly from the outer variable).
296+ function addCopyingAndReturn ( functionBody , varsToReturn , sourcePrefix = null ) {
297+ if ( functionBody . type !== 'BlockStatement' ) return ;
298+
299+ const tempVarMap = new Map ( ) ;
300+ const copyStatements = [ ] ;
301+
302+ for ( const varPath of varsToReturn ) {
303+ const parts = varPath . split ( '.' ) ;
304+ const tempName = `__copy_${ parts . join ( '_' ) } _${ blockVarCounter ++ } ` ;
305+ tempVarMap . set ( varPath , tempName ) ;
306+
307+ // If sourcePrefix is set (loop case), read from vars.x.y
308+ // Otherwise (if-branch case), read directly from x.y
309+ let sourceExpr = sourcePrefix
310+ ? { type : 'Identifier' , name : sourcePrefix }
311+ : { type : 'Identifier' , name : parts [ 0 ] } ;
312+
313+ const pathParts = sourcePrefix ? parts : parts . slice ( 1 ) ;
314+ for ( const part of pathParts ) {
315+ sourceExpr = {
316+ type : 'MemberExpression' ,
317+ object : sourceExpr ,
318+ property : { type : 'Identifier' , name : part } ,
319+ computed : false
320+ } ;
321+ }
322+
323+ copyStatements . push ( {
324+ type : 'VariableDeclaration' ,
325+ declarations : [ {
326+ type : 'VariableDeclarator' ,
327+ id : { type : 'Identifier' , name : tempName } ,
328+ init : {
329+ type : 'CallExpression' ,
330+ callee : {
331+ type : 'MemberExpression' ,
332+ object : sourceExpr ,
333+ property : { type : 'Identifier' , name : 'copy' } ,
334+ computed : false
335+ } ,
336+ arguments : [ ]
337+ }
338+ } ] ,
339+ kind : 'let'
340+ } ) ;
341+ }
342+
343+ functionBody . body . forEach ( node => replaceReferences ( node , tempVarMap ) ) ;
344+ functionBody . body . unshift ( ...copyStatements ) ;
345+
346+ const returnObj = {
347+ type : 'ObjectExpression' ,
348+ properties : Array . from ( varsToReturn ) . map ( varPath => ( {
349+ type : 'Property' ,
350+ key : { type : 'Literal' , value : varPath } ,
351+ value : { type : 'Identifier' , name : tempVarMap . get ( varPath ) } ,
352+ kind : 'init' ,
353+ computed : false ,
354+ shorthand : false
355+ } ) )
356+ } ;
357+
358+ functionBody . body . push ( {
359+ type : 'ReturnStatement' ,
360+ argument : returnObj
361+ } ) ;
362+ }
363+
291364const ASTCallbacks = {
292365 UnaryExpression ( node , state , ancestors ) {
293366 if ( ancestors . some ( a => nodeIsUniform ( a ) || nodeIsUniformCallbackFn ( a , state . uniformCallbackNames ) ) ) {
@@ -689,70 +762,6 @@ const ASTCallbacks = {
689762 analyzeBranch ( thenFunction . body ) ;
690763 analyzeBranch ( elseFunction . body ) ;
691764 if ( assignedVars . size > 0 ) {
692- // Add copying, reference replacement, and return statements to branch functions
693- const addCopyingAndReturn = ( functionBody , varsToReturn ) => {
694- if ( functionBody . type === 'BlockStatement' ) {
695- // Create temporary variables and copy statements
696- const tempVarMap = new Map ( ) ; // property path -> temp name
697- const copyStatements = [ ] ;
698- for ( const varPath of varsToReturn ) {
699- const parts = varPath . split ( '.' ) ;
700- const tempName = `__copy_${ parts . join ( '_' ) } _${ blockVarCounter ++ } ` ;
701- tempVarMap . set ( varPath , tempName ) ;
702-
703- // Build the member expression for the property path
704- let sourceExpr = { type : 'Identifier' , name : parts [ 0 ] } ;
705- for ( let i = 1 ; i < parts . length ; i ++ ) {
706- sourceExpr = {
707- type : 'MemberExpression' ,
708- object : sourceExpr ,
709- property : { type : 'Identifier' , name : parts [ i ] } ,
710- computed : false
711- } ;
712- }
713-
714- // let tempName = propertyPath.copy()
715- copyStatements . push ( {
716- type : 'VariableDeclaration' ,
717- declarations : [ {
718- type : 'VariableDeclarator' ,
719- id : { type : 'Identifier' , name : tempName } ,
720- init : {
721- type : 'CallExpression' ,
722- callee : {
723- type : 'MemberExpression' ,
724- object : sourceExpr ,
725- property : { type : 'Identifier' , name : 'copy' } ,
726- computed : false
727- } ,
728- arguments : [ ]
729- }
730- } ] ,
731- kind : 'let'
732- } ) ;
733- }
734- // Apply reference replacement to all statements
735- functionBody . body . forEach ( node => replaceReferences ( node , tempVarMap ) ) ;
736- // Insert copy statements at the beginning
737- functionBody . body . unshift ( ...copyStatements ) ;
738- // Add return statement with flat object using property paths as keys
739- const returnObj = {
740- type : 'ObjectExpression' ,
741- properties : Array . from ( varsToReturn ) . map ( varPath => ( {
742- type : 'Property' ,
743- key : { type : 'Literal' , value : varPath } ,
744- value : { type : 'Identifier' , name : tempVarMap . get ( varPath ) } ,
745- kind : 'init' ,
746- computed : false ,
747- shorthand : false
748- } ) )
749- } ;
750- functionBody . body . push ( {
751- type : 'ReturnStatement' ,
752- argument : returnObj
753- } ) ;
754- }
755- } ;
756765 addCopyingAndReturn ( thenFunction . body , assignedVars ) ;
757766 addCopyingAndReturn ( elseFunction . body , assignedVars ) ;
758767 // Create a block variable to capture the return value
@@ -1057,73 +1066,8 @@ const ASTCallbacks = {
10571066 } ) ;
10581067
10591068 if ( assignedVars . size > 0 ) {
1060- // Add copying, reference replacement, and return statements similar to if statements
1061- const addCopyingAndReturn = ( functionBody , varsToReturn ) => {
1062- if ( functionBody . type === 'BlockStatement' ) {
1063- const tempVarMap = new Map ( ) ;
1064- const copyStatements = [ ] ;
1065-
1066- for ( const varPath of varsToReturn ) {
1067- const parts = varPath . split ( '.' ) ;
1068- const tempName = `__copy_${ parts . join ( '_' ) } _${ blockVarCounter ++ } ` ;
1069- tempVarMap . set ( varPath , tempName ) ;
1070-
1071- // Build the member expression for vars.propertyPath
1072- // e.g., vars.inputs.color or vars.x
1073- let sourceExpr = { type : 'Identifier' , name : 'vars' } ;
1074- for ( const part of parts ) {
1075- sourceExpr = {
1076- type : 'MemberExpression' ,
1077- object : sourceExpr ,
1078- property : { type : 'Identifier' , name : part } ,
1079- computed : false
1080- } ;
1081- }
1082-
1083- copyStatements . push ( {
1084- type : 'VariableDeclaration' ,
1085- declarations : [ {
1086- type : 'VariableDeclarator' ,
1087- id : { type : 'Identifier' , name : tempName } ,
1088- init : {
1089- type : 'CallExpression' ,
1090- callee : {
1091- type : 'MemberExpression' ,
1092- object : sourceExpr ,
1093- property : { type : 'Identifier' , name : 'copy' } ,
1094- computed : false
1095- } ,
1096- arguments : [ ]
1097- }
1098- } ] ,
1099- kind : 'let'
1100- } ) ;
1101- }
1102-
1103- functionBody . body . forEach ( node => replaceReferences ( node , tempVarMap ) ) ;
1104- functionBody . body . unshift ( ...copyStatements ) ;
1105-
1106- // Add return statement with flat object using property paths as keys
1107- const returnObj = {
1108- type : 'ObjectExpression' ,
1109- properties : Array . from ( varsToReturn ) . map ( varPath => ( {
1110- type : 'Property' ,
1111- key : { type : 'Literal' , value : varPath } ,
1112- value : { type : 'Identifier' , name : tempVarMap . get ( varPath ) } ,
1113- kind : 'init' ,
1114- computed : false ,
1115- shorthand : false
1116- } ) )
1117- } ;
1118-
1119- functionBody . body . push ( {
1120- type : 'ReturnStatement' ,
1121- argument : returnObj
1122- } ) ;
1123- }
1124- } ;
11251069
1126- addCopyingAndReturn ( bodyFunction . body , assignedVars ) ;
1070+ addCopyingAndReturn ( bodyFunction . body , assignedVars , 'vars' ) ;
11271071
11281072 // Create block variable and assignments similar to if statements
11291073 const blockVar = `__block_${ blockVarCounter ++ } ` ;
0 commit comments