# Naming Conventions This document explains how the SDL3 Parser converts C naming conventions to idiomatic Zig code. ## Overview The parser applies systematic rules to transform SDL3's C naming patterns into Zig-friendly identifiers while preserving semantic meaning and avoiding invalid identifiers. ## Core Principle: The "First Underscore Rule" The fundamental naming algorithm is the **first underscore rule**, which prevents invalid identifiers and preserves type semantics. ### Algorithm For enum values like `SDL_GPU_PRIMITIVETYPE_TRIANGLELIST`: 1. **Strip SDL prefix**: `PRIMITIVETYPE_TRIANGLELIST` 2. **Find first underscore**: Position 13 (after `PRIMITIVETYPE`) 3. **Split into parts**: - Type part: `PRIMITIVETYPE` - Value part: `TRIANGLELIST` 4. **Convert casing**: - Type → lowercase: `primitivetype` - Value → TitleCase: `Trianglelist` 5. **Concatenate**: `primitivetypeTrianglelist` ### Why First Underscore? **Problem with Last Underscore**: ``` SDL_GPU_TEXTURETYPE_2D_ARRAY Split at LAST underscore: TEXTURETYPE_2D + ARRAY Result: texturetype2dArray ✗ Wrong semantics ``` **First Underscore Solution**: ``` SDL_GPU_TEXTURETYPE_2D_ARRAY Split at FIRST underscore: TEXTURETYPE + 2D_ARRAY Result: texturetype2dArray ✓ Correct! ``` **Prevents Invalid Identifiers**: ``` SDL_GPU_INDEXELEMENTSIZE_16BIT Split at FIRST underscore: INDEXELEMENTSIZE + 16BIT Result: indexelementsize16bit ✓ Valid (starts with letter) If we stripped too much: Result: 16bit ✗ Invalid Zig identifier (starts with number) ``` ## Type Name Conversion ### Opaque Types, Enums, Structs, Flags **Pattern**: Strip `SDL_` prefix, keep GPU prefix | C Name | Zig Name | |--------|----------| | `SDL_GPUDevice` | `GPUDevice` | | `SDL_GPUBuffer` | `GPUBuffer` | | `SDL_GPUTextureUsageFlags` | `GPUTextureUsageFlags` | | `SDL_Window` | `Window` | **Rule**: ```zig // Strip SDL_ or SDL_GPU_ prefix typeNameToZig("SDL_GPUDevice") → "GPUDevice" typeNameToZig("SDL_Window") → "Window" ``` ## Enum Value Conversion ### Standard Pattern **C Enum**: ```c typedef enum SDL_GPUPrimitiveType { SDL_GPU_PRIMITIVETYPE_TRIANGLELIST, SDL_GPU_PRIMITIVETYPE_TRIANGLESTRIP, } SDL_GPUPrimitiveType; ``` **Zig Enum**: ```zig pub const GPUPrimitiveType = enum(c_int) { primitivetypeTrianglelist, primitivetypeTrianglestrip, }; ``` ### Numeric Suffixes **C Enum**: ```c typedef enum SDL_GPUSampleCount { SDL_GPU_SAMPLECOUNT_1, SDL_GPU_SAMPLECOUNT_2, SDL_GPU_SAMPLECOUNT_4, } SDL_GPUSampleCount; ``` **Zig Enum**: ```zig pub const GPUSampleCount = enum(c_int) { samplecount1, samplecount2, samplecount4, }; ``` **Note**: The type prefix (`samplecount`) prevents the invalid identifier `1`, `2`, `4`. ### Multi-Word Values **C Enum**: ```c typedef enum SDL_GPUTextureType { SDL_GPU_TEXTURETYPE_2D, SDL_GPU_TEXTURETYPE_2D_ARRAY, SDL_GPU_TEXTURETYPE_3D, } SDL_GPUTextureType; ``` **Zig Enum**: ```zig pub const GPUTextureType = enum(c_int) { texturetype2d, texturetype2dArray, texturetype3d, }; ``` **Algorithm Applied**: - `SDL_GPU_TEXTURETYPE_2D_ARRAY` - Strip prefix: `TEXTURETYPE_2D_ARRAY` - First underscore at position 11 - Type: `TEXTURETYPE` → `texturetype` - Value: `2D_ARRAY` → `2dArray` - Result: `texturetype2dArray` ## Flag Field Conversion ### C Flags Definition ```c typedef Uint32 SDL_GPUTextureUsageFlags; #define SDL_GPU_TEXTUREUSAGE_SAMPLER (1u << 0) #define SDL_GPU_TEXTUREUSAGE_COLOR_TARGET (1u << 1) #define SDL_GPU_TEXTUREUSAGE_DEPTH_STENCIL_TARGET (1u << 2) ``` ### Zig Packed Struct ```zig pub const GPUTextureUsageFlags = packed struct(u32) { textureusageSampler: bool = false, textureusageColorTarget: bool = false, textureusageDepthStencilTarget: bool = false, pad0: u29 = 0, }; ``` **Field Name Pattern**: - Strip `SDL_GPU_` prefix: `TEXTUREUSAGE_SAMPLER` - Apply first underscore rule: `textureusage` + `Sampler` - Result: `textureusageSampler` ## Function Name Conversion ### Pattern: Lowercase Leading Acronyms **C Function**: ```c extern SDL_DECLSPEC SDL_GPUDevice* SDLCALL SDL_CreateGPUDevice(bool debug_mode); ``` **Zig Function**: ```zig pub inline fn createGPUDevice(debug_mode: bool) ?*GPUDevice { return @ptrCast(c.SDL_CreateGPUDevice(debug_mode)); } ``` **Rule**: - Strip `SDL_` prefix: `CreateGPUDevice` - Lowercase first character: `createGPUDevice` - Preserve internal acronyms: GPU stays uppercase ### More Examples | C Function | Zig Function | |------------|--------------| | `SDL_CreateGPUDevice` | `createGPUDevice` | | `SDL_DestroyGPUDevice` | `destroyGPUDevice` | | `SDL_CreateWindow` | `createWindow` | | `SDL_GetGPUSwapchainTextureFormat` | `getGPUSwapchainTextureFormat` | ## Prefix Detection ### Common Prefix Algorithm **Goal**: Detect `SDL_GPU_` vs `SDL_` prefix ```zig detectCommonPrefix(["SDL_GPU_PRIMITIVETYPE_TRIANGLELIST", "SDL_GPU_PRIMITIVETYPE_TRIANGLESTRIP"]) → "SDL_GPU_" detectCommonPrefix(["SDL_WINDOW_FULLSCREEN", "SDL_WINDOW_RESIZABLE"]) → "SDL_" ``` **Implementation**: 1. Check if first name starts with `SDL_GPU_` → return `"SDL_GPU_"` 2. Otherwise check if it starts with `SDL_` → return `"SDL_"` 3. Otherwise return empty string **Critical**: The prefix is ONLY the SDL part, NOT the type name part. ## Edge Cases ### Single Word (No Underscore) **C Enum**: ```c SDL_GPU_INVALID ``` **Zig**: ```zig invalid // No underscore, so just lowercase entire word ``` ### Numbers at Start (After Strip) **Prevented by Type Prefix**: ``` SDL_GPU_INDEXELEMENTSIZE_16BIT → indexelementsize16bit ✓ Starts with letter Without type prefix (WRONG): → 16bit ✗ Invalid identifier ``` ### Consecutive Underscores **C**: ```c SDL_GPU_SOME__VALUE // Double underscore ``` **Zig**: ```zig someValue // Underscores treated as word separators ``` ## Casing Helpers ### screaminToLowerCamel Converts `SCREAMING_SNAKE_CASE` to `lowerCamelCase`: ```zig screaminToLowerCamel("TRIANGLE_LIST") → "triangleList" screaminToLowerCamel("INVALID") → "invalid" ``` **Algorithm**: 1. First word: all lowercase 2. Subsequent words: capitalize first letter 3. Underscores removed ### screaminToTitleCamel Converts `SCREAMING_SNAKE_CASE` to `TitleCamelCase`: ```zig screaminToTitleCamel("TRIANGLE_LIST") → "TriangleList" screaminToTitleCamel("2D_ARRAY") → "2dArray" ``` **Algorithm**: 1. Every word: capitalize first letter, lowercase rest 2. Underscores removed 3. Numbers preserved ## Testing Strategy The naming.zig module includes comprehensive tests for: 1. **Prefix detection**: Verify `SDL_GPU_` vs `SDL_` detection 2. **Enum value conversion**: Test first underscore rule 3. **Numeric prefixes**: Ensure no invalid identifiers 4. **Multi-word values**: Test underscore handling 5. **Type name conversion**: Verify SDL prefix stripping 6. **Function name conversion**: Test lowercase leading character See naming.zig for 10+ unit tests validating these rules. ## Design Rationale ### Why Keep Type Prefix in Enum Values? **Benefit 1: Prevents Invalid Identifiers** ```zig // With type prefix indexelementsize16bit ✓ Valid // Without type prefix 16bit ✗ Invalid ``` **Benefit 2: Namespace Clarity** ```zig // With type prefix - clear which type primitivetypeTrianglelist texturetypeTrianglelist // Without - ambiguous trianglelist // Which type? ``` **Benefit 3: Consistent Pattern** ```zig // All enum values follow same pattern primitivetypeTrianglelist primitivetypeTrianglestrip primitivetypeLineList // Type prefix always present ``` ### Why Inline Functions Instead of Direct Imports? **Type Safety**: ```zig // Inline function with proper types pub inline fn createGPUDevice(debug_mode: bool) ?*GPUDevice { return @ptrCast(c.SDL_CreateGPUDevice(debug_mode)); } // vs direct C import c.SDL_CreateGPUDevice(debug_mode) // Returns opaque C type ``` **Zero Overhead**: - `inline` keyword ensures no runtime cost - Compiler optimizes away the wrapper - Identical performance to direct C call **Better Error Messages**: - Zig type names in errors - Clear parameter names - Type checking at call site ## Summary The SDL3 Parser naming system: 1. Uses **first underscore rule** for enum values 2. Strips **SDL prefix** from type names (keeps GPU) 3. **Lowercases first character** of function names 4. Converts **SCREAMING_SNAKE** to **camelCase** 5. **Preserves type prefixes** in enum values for safety 6. **Prevents invalid identifiers** starting with numbers All conversions are deterministic, tested, and generate valid Zig code.