@@ -1142,18 +1142,23 @@ ${this.ctx.pre}else ${alternate}`;
11421142 if ( statement [ 0 ] === NODE . for ) {
11431143 const [ _ , init , condition , update , body ] = statement ;
11441144
1145- const [ initStatement , conditionExpr , updateStatement ] = this . ctx
1146- . withResetIndentLevel ( ( ) => [
1147- init ? this . statement ( init ) : undefined ,
1148- condition ? this . typedExpression ( condition , bool ) : undefined ,
1149- update ? this . statement ( update ) : undefined ,
1150- ] ) ;
1151-
1152- const initStr = initStatement ? initStatement . slice ( 0 , - 1 ) : '' ;
1153- const updateStr = updateStatement ? updateStatement . slice ( 0 , - 1 ) : '' ;
1154-
1155- const bodyStr = this . block ( blockifySingleStatement ( body ) ) ;
1156- return stitch `${ this . ctx . pre } for (${ initStr } ; ${ conditionExpr } ; ${ updateStr } ) ${ bodyStr } ` ;
1145+ try {
1146+ this . ctx . pushBlockScope ( ) ;
1147+ const [ initStatement , conditionExpr , updateStatement ] = this . ctx
1148+ . withResetIndentLevel ( ( ) => [
1149+ init ? this . statement ( init ) : undefined ,
1150+ condition ? this . typedExpression ( condition , bool ) : undefined ,
1151+ update ? this . statement ( update ) : undefined ,
1152+ ] ) ;
1153+
1154+ const initStr = initStatement ? initStatement . slice ( 0 , - 1 ) : '' ;
1155+ const updateStr = updateStatement ? updateStatement . slice ( 0 , - 1 ) : '' ;
1156+
1157+ const bodyStr = this . block ( blockifySingleStatement ( body ) ) ;
1158+ return stitch `${ this . ctx . pre } for (${ initStr } ; ${ conditionExpr } ; ${ updateStr } ) ${ bodyStr } ` ;
1159+ } finally {
1160+ this . ctx . popBlockScope ( ) ;
1161+ }
11571162 }
11581163
11591164 if ( statement [ 0 ] === NODE . while ) {
@@ -1174,120 +1179,122 @@ ${this.ctx.pre}else ${alternate}`;
11741179 '`for ... of ...` loops only support iterables stored in variables' ,
11751180 ) ;
11761181 }
1182+ try {
1183+ this . ctx . pushBlockScope ( ) ;
11771184
1178- // Our index name will be some element from infinite sequence (i, ii, iii, ...).
1179- // If user defines `i` and `ii` before `for ... of ...` loop, then our index name will be `iii`.
1180- // If user defines `i` inside `for ... of ...` then it will be scoped to a new block,
1181- // so we can safely use `i`.
1182- let index = 'i' ; // it will be valid name, no need to call this.ctx.makeNameValid
1183- while ( this . ctx . getById ( index ) !== null ) {
1184- index += 'i' ;
1185- }
1185+ const index = this . ctx . makeNameValid ( 'i' ) ;
11861186
1187- const elementSnippet = accessIndex (
1188- iterableSnippet ,
1189- snip ( index , u32 , 'runtime' ) ,
1190- ) ;
1191- if ( ! elementSnippet ) {
1192- throw new WgslTypeError (
1193- '`for ... of ...` loops only support array or vector iterables' ,
1187+ const elementSnippet = accessIndex (
1188+ iterableSnippet ,
1189+ snip ( index , u32 , 'runtime' ) ,
11941190 ) ;
1195- }
1191+ if ( ! elementSnippet ) {
1192+ throw new WgslTypeError (
1193+ '`for ... of ...` loops only support array or vector iterables' ,
1194+ ) ;
1195+ }
11961196
1197- const iterableDataType = iterableSnippet . dataType ;
1198- let elementCountSnippet : Snippet ;
1199- let elementType = elementSnippet . dataType ;
1197+ const iterableDataType = iterableSnippet . dataType ;
1198+ let elementCountSnippet : Snippet ;
1199+ let elementType = elementSnippet . dataType ;
12001200
1201- if ( elementType === UnknownData ) {
1202- throw new WgslTypeError (
1203- stitch `The elements in iterable ${ iterableSnippet } are of unknown type` ,
1204- ) ;
1205- }
1201+ if ( elementType === UnknownData ) {
1202+ throw new WgslTypeError (
1203+ stitch `The elements in iterable ${ iterableSnippet } are of unknown type` ,
1204+ ) ;
1205+ }
12061206
1207- if ( wgsl . isWgslArray ( iterableDataType ) ) {
1208- elementCountSnippet = iterableDataType . elementCount > 0
1209- ? snip (
1210- `${ iterableDataType . elementCount } ` ,
1207+ if ( wgsl . isWgslArray ( iterableDataType ) ) {
1208+ elementCountSnippet = iterableDataType . elementCount > 0
1209+ ? snip (
1210+ `${ iterableDataType . elementCount } ` ,
1211+ u32 ,
1212+ 'constant' ,
1213+ )
1214+ : arrayLength [ $gpuCallable ] . call ( this . ctx , [ iterableSnippet ] ) ;
1215+ } else if ( wgsl . isVec ( iterableDataType ) ) {
1216+ elementCountSnippet = snip (
1217+ `${ Number ( iterableDataType . type . match ( / \d / ) ) } ` ,
12111218 u32 ,
12121219 'constant' ,
1213- )
1214- : arrayLength [ $gpuCallable ] . call ( this . ctx , [ iterableSnippet ] ) ;
1215- } else if ( wgsl . isVec ( iterableDataType ) ) {
1216- elementCountSnippet = snip (
1217- `${ Number ( iterableDataType . type . match ( / \d / ) ) } ` ,
1218- u32 ,
1219- 'constant' ,
1220- ) ;
1221- } else {
1222- throw new WgslTypeError (
1223- '`for ... of ...` loops only support array or vector iterables' ,
1224- ) ;
1225- }
1220+ ) ;
1221+ } else {
1222+ throw new WgslTypeError (
1223+ '`for ... of ...` loops only support array or vector iterables' ,
1224+ ) ;
1225+ }
12261226
1227- if ( loopVar [ 0 ] !== NODE . const ) {
1228- throw new WgslTypeError (
1229- 'Only `for (const ... of ... )` loops are supported' ,
1230- ) ;
1231- }
1227+ if ( loopVar [ 0 ] !== NODE . const ) {
1228+ throw new WgslTypeError (
1229+ 'Only `for (const ... of ... )` loops are supported' ,
1230+ ) ;
1231+ }
12321232
1233- // If it's ephemeral, it's a value that cannot change. If it's a reference, we take
1234- // an implicit pointer to it
1235- let loopVarKind = 'let' ;
1236- const loopVarName = this . ctx . makeNameValid ( loopVar [ 1 ] ) ;
1233+ // If it's ephemeral, it's a value that cannot change. If it's a reference, we take
1234+ // an implicit pointer to it
1235+ let loopVarKind = 'let' ;
1236+ const loopVarName = this . ctx . makeNameValid ( loopVar [ 1 ] ) ;
1237+
1238+ if ( ! isEphemeralSnippet ( elementSnippet ) ) {
1239+ if ( elementSnippet . origin === 'constant-tgpu-const-ref' ) {
1240+ loopVarKind = 'const' ;
1241+ } else if ( elementSnippet . origin === 'runtime-tgpu-const-ref' ) {
1242+ loopVarKind = 'let' ;
1243+ } else {
1244+ loopVarKind = 'let' ;
1245+ if ( ! wgsl . isPtr ( elementType ) ) {
1246+ const ptrType = createPtrFromOrigin (
1247+ elementSnippet . origin ,
1248+ concretize (
1249+ elementType as wgsl . AnyWgslData ,
1250+ ) as wgsl . StorableData ,
1251+ ) ;
1252+ invariant (
1253+ ptrType !== undefined ,
1254+ `Creating pointer type from origin ${ elementSnippet . origin } ` ,
1255+ ) ;
1256+ elementType = ptrType ;
1257+ }
12371258
1238- if ( ! isEphemeralSnippet ( elementSnippet ) ) {
1239- if ( elementSnippet . origin === 'constant-tgpu-const-ref' ) {
1240- loopVarKind = 'const' ;
1241- } else if ( elementSnippet . origin === 'runtime-tgpu-const-ref' ) {
1242- loopVarKind = 'let' ;
1243- } else {
1244- loopVarKind = 'let' ;
1245- if ( ! wgsl . isPtr ( elementType ) ) {
1246- const ptrType = createPtrFromOrigin (
1247- elementSnippet . origin ,
1248- concretize ( elementType as wgsl . AnyWgslData ) as wgsl . StorableData ,
1249- ) ;
1250- invariant (
1251- ptrType !== undefined ,
1252- `Creating pointer type from origin ${ elementSnippet . origin } ` ,
1253- ) ;
1254- elementType = ptrType ;
1259+ elementType = implicitFrom ( elementType as wgsl . Ptr ) ;
12551260 }
1256-
1257- elementType = implicitFrom ( elementType as wgsl . Ptr ) ;
12581261 }
1259- }
12601262
1261- const loopVarSnippet = snip (
1262- loopVarName ,
1263- elementType ,
1264- elementSnippet . origin ,
1265- ) ;
1266- this . ctx . defineVariable ( loopVarName , loopVarSnippet ) ;
1263+ const loopVarSnippet = snip (
1264+ loopVarName ,
1265+ elementType ,
1266+ elementSnippet . origin ,
1267+ ) ;
12671268
1268- const forStr = stitch `${ this . ctx . pre } for (var ${ index } = 0u; ${ index } < ${
1269- tryConvertSnippet ( this . ctx , elementCountSnippet , u32 , false )
1270- } ; ${ index } ++) {`;
1269+ this . ctx . defineVariable ( loopVar [ 1 ] , loopVarSnippet ) ;
12711270
1272- this . ctx . indent ( ) ;
1271+ const forStr =
1272+ stitch `${ this . ctx . pre } for (var ${ index } = 0u; ${ index } < ${
1273+ tryConvertSnippet ( this . ctx , elementCountSnippet , u32 , false )
1274+ } ; ${ index } ++) {`;
12731275
1274- const loopVarDeclStr =
1275- stitch `${ this . ctx . pre } ${ loopVarKind } ${ loopVarName } = ${
1276- tryConvertSnippet (
1277- this . ctx ,
1278- elementSnippet ,
1279- elementType ,
1280- false ,
1281- )
1282- } ;`;
1276+ this . ctx . indent ( ) ;
12831277
1284- const bodyStr = `${ this . ctx . pre } ${
1285- this . block ( blockifySingleStatement ( body ) )
1286- } `;
1278+ const loopVarDeclStr =
1279+ stitch `${ this . ctx . pre } ${ loopVarKind } ${ loopVarName } = ${
1280+ tryConvertSnippet (
1281+ this . ctx ,
1282+ elementSnippet ,
1283+ elementType ,
1284+ false ,
1285+ )
1286+ } ;`;
12871287
1288- this . ctx . dedent ( ) ;
1288+ const bodyStr = `${ this . ctx . pre } ${
1289+ this . block ( blockifySingleStatement ( body ) )
1290+ } `;
1291+
1292+ this . ctx . dedent ( ) ;
12891293
1290- return stitch `${ forStr } \n${ loopVarDeclStr } \n${ bodyStr } \n${ this . ctx . pre } }` ;
1294+ return stitch `${ forStr } \n${ loopVarDeclStr } \n${ bodyStr } \n${ this . ctx . pre } }` ;
1295+ } finally {
1296+ this . ctx . popBlockScope ( ) ;
1297+ }
12911298 }
12921299
12931300 if ( statement [ 0 ] === NODE . continue ) {
0 commit comments