Module rewrite

Module rewrite 

Source
Expand description

AST-driven HLSL→HLSL rewrites.

Operates on the HLSL source before the regex pipeline in crate::translate_shader. Each pass parses the source with crate::parse::parse_hlsl, walks the AST to spot a specific HLSL idiom that the downstream regex passes can’t recover from, and emits a list of TextEdits applied back to the source.

Falls back silently when the parser can’t consume the input — the original source is returned unchanged so the regex pipeline still has a chance. The corpus parse rate is 100 % on test-presets-200/, so the fallback is exercised only by malformed test inputs in practice.

Each pass lives in its own submodule and is composed in order by apply_all. The shared WalkCtx and type-inference helpers live here in mod.rs; private items in this file are accessible to the pass submodules under Rust’s descendant-visibility rules.

Modules§

array_lower 🔒
Pass: HLSL array → WGSL array<T, N> lowering (globals + locals).
bare_expr 🔒
Pass: bare expression statements → _ = <expr>;
binop_vec 🔒
Pass: binary operator vec-size mismatch fix-up.
bool_arith 🔒
Pass: bool RHS in f32 context → select(0.0, 1.0, cond).
brace_init 🔒
Pass: lower T x = { … }; brace-init local declarations to T x = T(…); constructor calls.
chained_init 🔒
Pass: lower chained assignment in local-decl init position.
comma_paren 🔒
Pass: lower C-style comma operator inside parenthesised expressions.
embedded_assign 🔒
Pass: lift assignment-as-expression out of mid-statement positions.
for_init 🔒
Pass: for (int i = ...) init type rewrite (lowering).
modf_arity 🔒
Pass: lower HLSL two-arg modf(x, &out) to WGSL’s one-arg struct form.
qa_stub 🔒
Pass: _qa..._qh stub injection.
scalar_swizzle 🔒
Pass: scalar .xxx swizzle broadcast → vec constructor.
swizzle_assign 🔒
Pass: lower multi-component swizzle assignments to per-component writes.
ternary 🔒
Pass: ternary cond ? a : b → WGSL select(b, a, cond).
texture_uv 🔒
Pass: texture-sampling UV coercion (tex2D / GetPixel / GetBlur*).
user_fn 🔒
Pass: user-defined function call-site arg coercion.
vec_cmp 🔒
Pass: broadcast scalar operand of vec/scalar comparisons.

Structs§

TextEdit 🔒
One textual replacement on the original source. start..end are byte offsets; replacement is the new text.
WalkCtx 🔒
AST walker state: a small stacked symbol table plus a sink for text edits. Each walk_* consults and updates the table; walk_expr returns the inferred type of the expression so callers can decide whether to emit a fix-up edit.

Functions§

apply_all
Apply every AST-driven rewrite pass in series. Returns the rewritten source. If parsing fails at any step, returns the source unchanged from that step onward — the pipeline is best-effort.
apply_edits 🔒
Apply a list of non-overlapping edits in order. Sorts by start position descending so each application doesn’t invalidate the remaining offsets. Edits that overlap are dropped silently — the AST walker is responsible for ensuring non-overlap by emitting one edit per syntactic position.
apply_lowerings 🔒
Collect every “WGSL-output” lowering edit against a single parse of src, then apply them in one pass. Splitting these across separate pipeline steps would corrupt the second step: once the first emits var name: array<…> (or var i: i32), the source is no longer valid HLSL and a fresh parse_hlsl call returns Err, silently skipping the later passes. The for-int init rewrite once turned that latent hazard into a real regression on the Stahlregen + suksma dotes pair (the for-int rewrite ran first, then lower_array_globals couldn’t re-parse). The combined pass below avoids the order trap.
balanced 🔒
builtin_return 🔒
constructor_return 🔒
infer_type 🔒
Type-only version of walk_expr — doesn’t emit edits. Used by builtin-return inference where we want the type of an arg without double-walking it.
infer_type_static 🔒
Stand-alone type inference that doesn’t emit edits — used by the bool pass to peek at an Assign’s LHS type before deciding whether to wrap.
is_ident_chain 🔒
needs_parens_for_swizzle 🔒
type_from_typeref 🔒
widen_type 🔒