Backlog/lib/sdl3/parser/docs/naming.md

370 lines
8.4 KiB
Markdown

# 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.