pub(crate) fn lift_user_functions(src: &mut String) -> StringExpand description
Find HLSL-shaped function definitions (<TYPE> <name>(...) { ... })
at depth 0 in the translated body, rewrite each signature to WGSL
shape (fn name(arg: TYPE, …) -> TYPE { ... }), and remove them from
src in place. The lifted functions are returned as a single string
concatenated in source order — wrap_user_comp_shader_with_plan
places it before fs_main.
Preset pattern this unblocks (real example from
Geiss - Explosion 3 nz+ enscarpment via lateral hosations.milk):
vec2<f32> gradBlur1(vec2<f32> domain, vec2<f32> d, vec3<f32> filter) {
vec3<f32> dx = (2*GetBlur1(domain + vec2<f32>(1,0)*d) - 2*GetBlur1(domain - vec2<f32>(1,0)*d));
...
return 0.5 * vec2<f32>(...);
}
shader_body { ret += gradBlur1(uv, vec2<f32>(0.5)/aspect.xy, vec3<f32>(0.5,0.5,0.5)); }After lifting:
fn gradBlur1(domain: vec2<f32>, d: vec2<f32>, filter: vec3<f32>) -> vec2<f32> {
var dx: vec3<f32> = (2*GetBlur1(domain + vec2<f32>(1,0)*d) - 2*GetBlur1(domain - vec2<f32>(1,0)*d));
...
return 0.5 * vec2<f32>(...);
}Functions that reference fs_main locals (texsize, q1, …) will fail
to validate after lifting since those locals don’t exist at module
scope — we accept that limitation here; a future pass may pass them
explicitly.