@@ -57,36 +57,44 @@ function walkImplementation<T extends { nodes?: T[] }>(
5757 enter : ( node : T , ctx : VisitContext < T > ) => EnterResult < T > | void = ( ) => WalkAction . Continue ,
5858 exit : ( node : T , ctx : VisitContext < T > ) => ExitResult < T > | void = ( ) => WalkAction . Continue ,
5959) {
60- let stack : [ nodes : T [ ] , offset : number , parent : Parent < T > | null ] [ ] = [ [ ast , 0 , null ] ]
60+ let surrogate = { nodes : ast } as Parent < T >
61+
62+ // Reduce memory usage by tracking 2 different objects instead of a single
63+ // stack data structure. We could use 2 arrays, but objects are faster in Bun.
64+ // In Node.js the 2 arrays or 2 objects have similar performance.
65+ //
66+ // Used indexing to prevent `push()` / `pop()` overhead.
67+ let offsets : Record < number , number > = { 0 : 0 }
68+ let parents : Record < number , Parent < T > > = { 0 : surrogate }
69+
70+ let depth = 0
71+
6172 let ctx : VisitContext < T > = {
6273 parent : null ,
6374 depth : 0 ,
6475 path ( ) {
6576 let path : T [ ] = [ ]
6677
67- for ( let i = 1 ; i < stack . length ; i ++ ) {
68- let parent = stack [ i ] [ 2 ]
69- if ( parent ) path . push ( parent )
78+ for ( let i = 1 ; i <= depth ; i ++ ) {
79+ path . push ( parents [ i ] )
7080 }
7181
7282 return path
7383 } ,
7484 }
7585
76- while ( stack . length > 0 ) {
77- let depth = stack . length - 1
78- let frame = stack [ depth ]
79- let nodes = frame [ 0 ]
80- let offset = frame [ 1 ]
81- let parent = frame [ 2 ]
86+ while ( depth >= 0 ) {
87+ let offset = offsets [ depth ]
88+ let parent = parents [ depth ]
89+ let nodes = parent . nodes
8290
8391 // Done with this level
8492 if ( offset >= nodes . length ) {
85- stack . pop ( )
93+ depth --
8694 continue
8795 }
8896
89- ctx . parent = parent
97+ ctx . parent = depth === 0 ? null : parent
9098 ctx . depth = depth
9199
92100 // Enter phase (offsets are positive)
@@ -96,19 +104,21 @@ function walkImplementation<T extends { nodes?: T[] }>(
96104
97105 switch ( result . kind ) {
98106 case WalkKind . Continue : {
107+ offsets [ depth ] = ~ offset // Prepare for exit phase, same offset
108+
99109 if ( node . nodes && node . nodes . length > 0 ) {
100- stack . push ( [ node . nodes , 0 , node as Parent < T > ] )
110+ depth ++
111+ offsets [ depth ] = 0
112+ parents [ depth ] = node as Parent < T >
101113 }
102-
103- frame [ 1 ] = ~ offset // Prepare for exit phase, same offset
104114 continue
105115 }
106116
107117 case WalkKind . Stop :
108118 return // Stop immediately
109119
110120 case WalkKind . Skip : {
111- frame [ 1 ] = ~ offset // Prepare for exit phase, same offset
121+ offsets [ depth ] = ~ offset // Prepare for exit phase, same offset
112122 continue
113123 }
114124
@@ -124,7 +134,7 @@ function walkImplementation<T extends { nodes?: T[] }>(
124134
125135 case WalkKind . ReplaceSkip : {
126136 nodes . splice ( offset , 1 , ...result . nodes )
127- frame [ 1 ] += result . nodes . length // Advance to next sibling past replacements
137+ offsets [ depth ] += result . nodes . length // Advance to next sibling past replacements
128138 continue
129139 }
130140
@@ -146,15 +156,15 @@ function walkImplementation<T extends { nodes?: T[] }>(
146156
147157 switch ( result . kind ) {
148158 case WalkKind . Continue :
149- frame [ 1 ] = index + 1 // Advance to next sibling
159+ offsets [ depth ] = index + 1 // Advance to next sibling
150160 continue
151161
152162 case WalkKind . Stop :
153163 return // Stop immediately
154164
155165 case WalkKind . Replace : {
156166 nodes . splice ( index , 1 , ...result . nodes )
157- frame [ 1 ] = index + result . nodes . length // Advance to next sibling past replacements
167+ offsets [ depth ] = index + result . nodes . length // Advance to next sibling past replacements
158168 continue
159169 }
160170
@@ -165,7 +175,7 @@ function walkImplementation<T extends { nodes?: T[] }>(
165175
166176 case WalkKind . ReplaceSkip : {
167177 nodes . splice ( index , 1 , ...result . nodes )
168- frame [ 1 ] = index + result . nodes . length // Advance to next sibling past replacements
178+ offsets [ depth ] = index + result . nodes . length // Advance to next sibling past replacements
169179 continue
170180 }
171181
0 commit comments