// Copyright 2026 International Digital Economy Academy
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
///|
priv struct WgslIrFinalNamePlan {
names : Map[String, String]
}
///|
fn WgslIrFinalNamePlan::empty() -> WgslIrFinalNamePlan {
{ names: Map([]) }
}
///|
priv struct WgslIrWriterNamer {
unique : Map[String, Int]
}
///|
priv enum WgslIrEmitFunctionOrigin {
UserFunction(Int)
EntryPointFunction(Int)
}
///|
fn WgslIrWriterNamer::WgslIrWriterNamer() -> WgslIrWriterNamer {
{ unique: Map([]) }
}
///|
fn WgslIrWriterNamer::call(self : WgslIrWriterNamer, raw : String) -> String {
self.call_with_builtin_policy(raw, true)
}
///|
fn WgslIrWriterNamer::member_call(
self : WgslIrWriterNamer,
raw : String,
) -> String {
let name = self.call_with_builtin_policy(raw, false)
if wgsl_ir_identifier_ends_with_digit(name) {
"\{name}_"
} else {
name
}
}
///|
fn WgslIrWriterNamer::call_with_builtin_policy(
self : WgslIrWriterNamer,
raw : String,
reserve_builtin_functions : Bool,
) -> String {
let base = sanitize_wgsl_ir_writer_identifier_base(raw)
match self.unique.get(base) {
Some(count) => {
let next = count + 1
self.unique.set(base, next)
"\{base}_\{next}"
}
None => {
self.unique.set(base, 0)
if (
!wgsl_ir_identifier_is_expression_temporary(base) &&
wgsl_ir_identifier_ends_with_digit(base)
) ||
self.should_reserve_identifier(base, reserve_builtin_functions) ||
(
reserve_builtin_functions &&
wgsl_ir_identifier_is_builtin_function(base)
) {
"\{base}_"
} else {
base
}
}
}
}
///|
fn WgslIrWriterNamer::call_preserving_trailing_digit(
self : WgslIrWriterNamer,
raw : String,
) -> String {
let base = sanitize_wgsl_ir_writer_identifier_base(raw)
match self.unique.get(base) {
Some(count) => {
let next = count + 1
self.unique.set(base, next)
"\{base}_\{next}"
}
None => {
self.unique.set(base, 0)
if self.should_reserve_identifier(base, true) ||
wgsl_ir_identifier_is_builtin_function(base) {
"\{base}_"
} else {
base
}
}
}
}
///|
fn WgslIrWriterNamer::should_reserve_identifier(
self : WgslIrWriterNamer,
base : String,
reserve_builtin_functions : Bool,
) -> Bool {
ignore(self)
if !wgsl_ir_identifier_is_reserved(base) {
return false
}
reserve_builtin_functions || !wgsl_ir_identifier_is_builtin_function(base)
}
///|
fn WgslIrWriterNamer::call_or(
self : WgslIrWriterNamer,
name : String?,
fallback : String,
) -> String {
match name {
Some(value) => self.call(value)
None => self.call(fallback)
}
}
///|
fn sanitize_wgsl_ir_writer_identifier_base(raw : String) -> String {
let mut out = raw.trim().to_owned()
while out.length() > 0 && wgsl_ir_ascii_is_digit(out.code_unit_at(0).to_int()) {
out = out[1:].to_owned()
}
while out.has_suffix("_") {
out = out[:out.length() - 1].to_owned()
}
while out.contains("__") {
out = out.replace(old="__", new="_")
}
if out == "" {
out = "unnamed"
}
if out.has_prefix("_naga") || out.has_prefix("__") {
out = "gen_\{out}"
}
out
}
///|
fn wgsl_ir_ascii_is_digit(code : Int) -> Bool {
code >= 48 && code <= 57
}
///|
fn wgsl_ir_identifier_is_expression_temporary(name : String) -> Bool {
guard name.length() > 2 && name[0:2] == "_e" else { return false }
for i in 2.. String {
let base = sanitize_wgsl_ir_writer_identifier_base(raw)
if wgsl_ir_identifier_is_expression_temporary(base) {
temp_namer.call(base)
} else {
self.call(raw)
}
}
///|
fn WgslIrWriterNamer::local_call_or(
self : WgslIrWriterNamer,
temp_namer : WgslIrWriterNamer,
name : String?,
fallback : String,
) -> String {
match name {
Some(value) => self.local_call(temp_namer, value)
None => self.local_call(temp_namer, fallback)
}
}
///|
fn wgsl_ir_emit_name_key(kind : String, index : Int) -> String {
"\{kind}:\{index}"
}
///|
fn wgsl_ir_emit_name_key2(kind : String, a : Int, b : Int) -> String {
"\{kind}:\{a}:\{b}"
}
///|
fn WgslIrFinalNamePlan::get(
self : WgslIrFinalNamePlan,
key : String,
) -> String? {
self.names.get(key)
}
///|
fn WgslIrEmitter::required_emit_name(
self : WgslIrEmitter,
key : String,
) -> String raise WgslIrEmitError {
match self.names.get(key) {
Some(value) => value
None => raise MissingName("emitter name key \{key}")
}
}
///|
fn WgslIrEmitter::with_function_origin(
self : WgslIrEmitter,
origin : WgslIrEmitFunctionOrigin,
) -> WgslIrEmitter {
{
shader_module: self.shader_module,
options: self.options,
writer_module: self.writer_module,
names: self.names,
current_function_origin: Some(origin),
compat_negative_zero_seen: self.compat_negative_zero_seen,
emitted_function_named_expressions: Set([]),
emitted_function_materialized_expressions: Set([]),
}
}