Skip to content

Commit 3de1044

Browse files
fix(minifier): lookup idents in type-space scopes
1 parent 66df85e commit 3de1044

File tree

2 files changed

+77
-69
lines changed

2 files changed

+77
-69
lines changed

src/minifier.ts

Lines changed: 76 additions & 68 deletions
Original file line numberDiff line numberDiff line change
@@ -156,21 +156,19 @@ export function minify(
156156
return null
157157
}
158158

159-
const prefixes: (string | null)[] = []
160-
161-
function getPrefix(): string | null {
162-
if (prefixes.length > 0 && prefixes.at(-1)) {
163-
return prefixes.join('.')
164-
}
165-
166-
return null
167-
}
159+
const typeScopes = new Map<string, Scope>()
160+
const types: (string | null)[] = []
168161

169162
function getScopedName(name: string): string | null {
170163
if (mangleMap.has(name)) {
171164
return mangleMap.get(name)!
172165
}
173166

167+
if (types[0] != null && typeScopes.has(types[0])) {
168+
const renamed = typeScopes.get(types[0])!.values.get(name)
169+
if (renamed) return renamed
170+
}
171+
174172
for (let i = scopes.length - 1; i >= 0; i--) {
175173
const renamed = scopes[i].values.get(name)
176174
if (renamed) return renamed
@@ -200,7 +198,10 @@ export function minify(
200198
}
201199

202200
scopes.at(-1)!.values.set(name, renamed)
203-
if (isExternal) mangleMap.set(name, renamed)
201+
if (isExternal) {
202+
if (types[0] != null) mangleMap.set(types[0] + '.' + name, renamed)
203+
else mangleMap.set(name, renamed)
204+
}
204205

205206
return renamed
206207
}
@@ -264,76 +265,85 @@ export function minify(
264265
popScope()
265266
},
266267
},
267-
StructDeclaration(node) {
268-
const isExternal = externalTypes.has(node.id.name)
269-
if (!isExternal || mangleExternals) {
270-
mangleName(node.id.name, isExternal)
271-
272-
// pushScope()
273-
for (const member of node.members) {
274-
if (member.type !== 'VariableDeclaration') continue
275-
for (const decl of member.declarations) {
276-
mangleName(node.id.name + '.' + decl.id.name, isExternal)
277-
}
268+
StructDeclaration: {
269+
enter(node) {
270+
const isExternal = externalTypes.has(node.id.name)
271+
if (!isExternal || mangleExternals) {
272+
mangleName(node.id.name, isExternal)
278273
}
279-
// popScope()
280-
}
274+
275+
pushScope()
276+
typeScopes.set(node.id.name, scopes.at(-1)!)
277+
types.push(node.id.name)
278+
},
279+
exit() {
280+
types.length -= 1
281+
popScope()
282+
},
281283
},
282-
StructuredBufferDeclaration(node) {
283-
if (node.typeSpecifier.type !== 'Identifier') return
284+
StructuredBufferDeclaration: {
285+
enter(node) {
286+
if (node.typeSpecifier.type !== 'Identifier') return
284287

285-
// When an instance name is not defined, the type specifier can be used as an external reference
286-
if (node.id || mangleExternals) {
287-
mangleName(node.typeSpecifier.name, false)
288-
}
288+
// When an instance name is not defined, the type specifier can be used as an external reference
289+
if (node.id || mangleExternals) {
290+
mangleName(node.typeSpecifier.name, false)
291+
}
289292

290-
if (!node.id) return
293+
if (!node.id) return
291294

292-
const isExternal = externalTypes.has(node.typeSpecifier.name)
293-
if (!isExternal || mangleExternals) {
294-
mangleName(node.id.name, isExternal)
295+
const isExternal = externalTypes.has(node.typeSpecifier.name)
296+
if (!isExternal || mangleExternals) {
297+
mangleName(node.id.name, isExternal)
298+
}
295299

296300
const scope = scopes.at(-1)!
297301
if (node.typeSpecifier.type === 'Identifier') {
298302
scope.references.set(node.id.name, node.typeSpecifier.name)
303+
types.push(node.typeSpecifier.name)
299304
} else if ((node.typeSpecifier as ArraySpecifier).type === 'ArraySpecifier') {
300305
scope.references.set(node.id.name, (node.typeSpecifier as ArraySpecifier).typeSpecifier.name)
306+
types.push((node.typeSpecifier as ArraySpecifier).typeSpecifier.name)
301307
}
302308

303-
// pushScope()
304-
for (const member of node.members) {
305-
if (member.type !== 'VariableDeclaration') continue
306-
for (const decl of member.declarations) {
307-
mangleName(node.typeSpecifier.name + '.' + decl.id.name, isExternal)
308-
}
309+
pushScope()
310+
typeScopes.set(node.id.name, scopes.at(-1)!)
311+
},
312+
exit(node) {
313+
if (node.id) {
314+
types.length -= 1
315+
popScope()
309316
}
310-
// popScope()
311-
}
317+
},
312318
},
313-
VariableDeclarator(node, ancestors) {
319+
VariableDeclaration(node, ancestors) {
314320
// TODO: ensure uniform decl lists work
315-
const containerNode = ancestors.at(-2) // Container -> VariableDecl
316-
const isExternal =
317-
node.qualifiers.some(isStorage) ||
318-
containerNode?.type === 'StructDeclaration' ||
319-
(containerNode?.type === 'StructuredBufferDeclaration' && containerNode.qualifiers.some(isStorage))
320-
321-
if (!isExternal || mangleExternals) {
322-
let name: string = ''
323-
if (node.id.type === 'Identifier') {
324-
name = node.id.name
325-
mangleName(name, isExternal)
326-
} else if (node.id.type === 'ArraySpecifier') {
327-
name = (node.id as unknown as ArraySpecifier).typeSpecifier.name
328-
}
321+
const parent = ancestors.at(-1) // Container -> VariableDecl
322+
const isParentExternal =
323+
parent?.type === 'StructDeclaration' ||
324+
(parent?.type === 'StructuredBufferDeclaration' && parent.qualifiers.some(isStorage))
325+
326+
for (const decl of node.declarations) {
327+
// Skip preprocessor
328+
if (decl.type !== 'VariableDeclarator') continue
329+
330+
const isExternal = isParentExternal || decl.qualifiers.some(isStorage)
331+
if (!isExternal || mangleExternals) {
332+
let name: string = ''
333+
if (decl.id.type === 'Identifier') {
334+
name = decl.id.name
335+
} else if (decl.id.type === 'ArraySpecifier') {
336+
name = (decl.id as unknown as ArraySpecifier).typeSpecifier.name
337+
}
329338

330-
mangleName(name, isExternal)
339+
mangleName(name, isExternal)
331340

332-
const scope = scopes.at(-1)!
333-
if (node.typeSpecifier.type === 'Identifier') {
334-
scope.references.set(name, node.typeSpecifier.name)
335-
} else if (node.typeSpecifier.type === 'ArraySpecifier') {
336-
scope.references.set(name, node.typeSpecifier.typeSpecifier.name)
341+
const scope = scopes.at(-1)!
342+
if (decl.typeSpecifier.type === 'Identifier') {
343+
scope.references.set(name, decl.typeSpecifier.name)
344+
} else if (decl.typeSpecifier.type === 'ArraySpecifier') {
345+
scope.references.set(name, decl.typeSpecifier.typeSpecifier.name)
346+
}
337347
}
338348
}
339349
},
@@ -352,7 +362,7 @@ export function minify(
352362
},
353363
MemberExpression: {
354364
enter(node) {
355-
let type: string | null = null
365+
let type: string | null = ''
356366

357367
if (node.object.type === 'CallExpression' && node.object.callee.type === 'Identifier') {
358368
// TODO: length() should be mangled whereas array.length() should not
@@ -368,16 +378,14 @@ export function minify(
368378
if (renamed !== null) node.object.name = renamed
369379
}
370380

371-
prefixes.push(type)
381+
types.push(type)
372382
},
373383
exit() {
374-
prefixes.length -= 1
384+
types.length -= 1
375385
},
376386
},
377387
Identifier(node) {
378-
// TODO: can this wrongly scope objects inside of member expr?
379-
const prefix = getPrefix()
380-
const renamed = getScopedName(prefix ? prefix + '.' + node.name : node.name)
388+
const renamed = getScopedName(node.name)
381389
if (renamed !== null) node.name = renamed
382390
},
383391
})

tests/shaders/glslang.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -46,7 +46,7 @@ if (!fs.existsSync(dstBinPath)) {
4646

4747
export function glslang(...args: string[]): void {
4848
try {
49-
execFileSync(dstBinPath, args.length === 0 ? ['--version'] : args, { encoding: 'utf-8' })
49+
execFileSync(dstBinPath, args, { encoding: 'utf-8' })
5050
} catch (error: any) {
5151
throw new Error(error.stdout)
5252
}

0 commit comments

Comments
 (0)