@@ -679,46 +679,71 @@ const ASTCallbacks = {
679679
680680 // Analyze which outer scope variables are assigned in the loop body
681681 const assignedVars = new Set ( ) ;
682- const analyzeBlock = ( body , parentLocalVars = new Set ( ) ) => {
683- if ( body . type !== 'BlockStatement' ) return ;
684682
685- // First pass: collect variable declarations within this block
686- const localVars = new Set ( [ ...parentLocalVars ] ) ;
687- for ( const stmt of body . body ) {
683+ // Helper function to check if a block contains strands control flow calls as immediate children
684+ const blockContainsStrandsControlFlow = ( node ) => {
685+ if ( node . type !== 'BlockStatement' ) return false ;
686+ return node . body . some ( stmt => {
687+ // Check for variable declarations with strands control flow init
688688 if ( stmt . type === 'VariableDeclaration' ) {
689- for ( const decl of stmt . declarations ) {
690- if ( decl . id . type === 'Identifier' ) {
691- localVars . add ( decl . id . name ) ;
692- }
693- }
689+ const match = stmt . declarations . some ( decl =>
690+ decl . init ?. type === 'CallExpression' &&
691+ (
692+ (
693+ decl . init ?. callee ?. type === 'MemberExpression' &&
694+ decl . init ?. callee ?. object ?. type === 'Identifier' &&
695+ decl . init ?. callee ?. object ?. name === '__p5' &&
696+ ( decl . init ?. callee ?. property ?. name === 'strandsFor' ||
697+ decl . init ?. callee ?. property ?. name === 'strandsIf' )
698+ ) ||
699+ (
700+ decl . init ?. callee ?. type === 'Identifier' &&
701+ ( decl . init ?. callee ?. name === '__p5.strandsFor' ||
702+ decl . init ?. callee ?. name === '__p5.strandsIf' )
703+ )
704+ )
705+ ) ;
706+ return match
707+ }
708+ return false ;
709+ } ) ;
710+ } ;
711+
712+ // First pass: collect all variable declarations in the body
713+ const localVars = new Set ( ) ;
714+ ancestor ( bodyFunction . body , {
715+ VariableDeclarator ( node , ancestors ) {
716+ // Skip if we're inside a block that contains strands control flow
717+ if ( ancestors . some ( blockContainsStrandsControlFlow ) ) return ;
718+ if ( node . id . type === 'Identifier' ) {
719+ localVars . add ( node . id . name ) ;
694720 }
695721 }
722+ } ) ;
723+
724+ // Second pass: find assignments to non-local variables using acorn-walk
725+ ancestor ( bodyFunction . body , {
726+ AssignmentExpression ( node , ancestors ) {
727+ // Skip if we're inside a block that contains strands control flow
728+ if ( ancestors . some ( blockContainsStrandsControlFlow ) ) {
729+ return
730+ }
696731
697- // Second pass: find assignments to non-local variables
698- for ( const stmt of body . body ) {
699- if ( stmt . type === 'ExpressionStatement' &&
700- stmt . expression . type === 'AssignmentExpression' ) {
701- const left = stmt . expression . left ;
702- if ( left . type === 'Identifier' ) {
703- // Direct variable assignment: x = value
704- if ( ! localVars . has ( left . name ) ) {
705- assignedVars . add ( left . name ) ;
706- }
707- } else if ( left . type === 'MemberExpression' &&
708- left . object . type === 'Identifier' ) {
709- // Property assignment: obj.prop = value (includes swizzles)
710- if ( ! localVars . has ( left . object . name ) ) {
711- assignedVars . add ( left . object . name ) ;
712- }
732+ const left = node . left ;
733+ if ( left . type === 'Identifier' ) {
734+ // Direct variable assignment: x = value
735+ if ( ! localVars . has ( left . name ) ) {
736+ assignedVars . add ( left . name ) ;
737+ }
738+ } else if ( left . type === 'MemberExpression' &&
739+ left . object . type === 'Identifier' ) {
740+ // Property assignment: obj.prop = value (includes swizzles)
741+ if ( ! localVars . has ( left . object . name ) ) {
742+ assignedVars . add ( left . object . name ) ;
713743 }
714- } else if ( stmt . type === 'BlockStatement' ) {
715- // Recursively analyze nested block statements, passing down local vars
716- analyzeBlock ( stmt , localVars ) ;
717744 }
718745 }
719- } ;
720-
721- analyzeBlock ( bodyFunction . body ) ;
746+ } ) ;
722747
723748 if ( assignedVars . size > 0 ) {
724749 // Add copying, reference replacement, and return statements similar to if statements
0 commit comments