Files
forth_bootslop/CONVENTIONS.md
2026-02-20 21:03:37 -05:00

4.8 KiB

C DSL Conventions (duffle)

This document outlines the strict C style and architectural conventions expected in this workspace. It is based on the duffle.amd64.win32.h header, the user's fortish-study samples, and iterative feedback.

1. Type Conventions (Byte-Width Fundamentals)

  • Never use standard C types (e.g., int, long, unsigned, short, float, double) directly in application code.
  • Always use the byte-width typedefs:
    • Unsigned: U1, U2, U4, U8
    • Signed: S1, S2, S4, S8
    • Float: F4, F8
    • Boolean: B1, B2, B4, B8 (use true/false primitives)
    • Strings/Chars: UTF8 (for characters), Str8 (for string slices)
  • WinAPI Structs: Only use MS_ prefixed fundamental types (e.g., MS_LONG, MS_DWORD) inside WinAPI struct definitions (MS_WNDCLASSA, etc.) to maintain FFI compatibility. Do not use them in general application logic.

2. Declaration Wrappers & X-Macros

  • Structs and Enums: Always use the macro wrappers for defining compound types to enforce clean namespacing.
    • typedef Struct_(Name) { ... };
    • typedef Enum_(UnderlyingType, Name) { ... };
  • X-Macros: Use X-Macros to tightly couple Enums with their corresponding string representations or metadata.
    #define My_Tag_Entries() 
            X(Define, "Define") 
            X(Call,   "Call")
    

3. Function & Symbol Naming

  • Case: Strictly use lower_snake_case for all functions and variables.
  • Types: Use PascalCase for type names (FArena, SWord_Tag).
  • WinAPI Symbols: When declaring foreign Win32 symbols, prefix the C function name with ms_ (using lower_snake_case) and use the asm("SymbolName") attribute to link it to the actual DLL export.
    • Correct: WinAPI U2 ms_register_class_a(MS_WNDCLASSA const* lpWndClass) asm("RegisterClassA");
    • Incorrect: WinAPI U2 RegisterClassA(...);

4. Formatting & Layout

  • Vertical Alignment: Align related variable declarations, struct fields, and function prototypes into columns to create a "sheet-like" layout. This improves visual parsing.
    • Example Struct:
      typedef struct MS_WNDCLASSA {
          U4          style;
          S8          (*lpfnWndProc)(void*, U4, U8, S8);
          S4          cbClsExtra;
          // ...
          char const* lpszClassName;
      } MS_WNDCLASSA;
      
  • Multi-line Argument Alignment: For long function signatures, place one argument per line with a single 4-space indent.
    • Example:
      WinAPI B4 ms_read_console(
          MS_Handle handle, 
          UTF8*r    buffer, 
          U4        to_read, 
          U4*r      num_read, 
          U8        reserved_input_control
      ) asm("ReadConsoleA");
      
  • WinAPI Grouping: Group foreign procedure declarations by their originating OS library (e.g., Kernel32, User32, GDI32) using comment headers.
  • Brace Style: Use Allman style (braces on a new line) for function bodies or control blocks (if, for, switch, etc.) that are large or complex. Smaller blocks may use K&R style.
  • Conditionals: Always place else if and else statements on a new line, un-nested from the previous closing brace.

5. Memory Management

  • Standard Library: The C standard library is linked, but headers like <stdlib.h> or <string.h> should not be included directly. Required functions should be declared manually if needed, or accessed via compiler builtins.
  • Arenas over Malloc: Use FArena and its associated macros (farena_push, farena_push_type, farena_reset) for all dynamic memory allocations. Do not use raw pointers with manual arithmetic when an arena can handle it.
  • Memory Ops: Use mem_fill and mem_copy instead of standard memset/memcpy within the application logic.

6. Type Qualifiers

  • const Placement: The const keyword must always be placed to the right of the type it modifies. This maintains a consistent right-to-left reading of type declarations.
    • Correct: char const* my_ptr; (Pointer to a constant character)
    • Correct: U4 const* const my_ptr; (Constant pointer to a constant U4)
    • Incorrect: const char* my_ptr;

7. Metadata Coupling (X-Macros)

  • Metadata Enums: Use X-Macros to define Enums that are tightly coupled with static metadata (colors, prefixes, names).
    • Example:
      #define Tag_Entries() \
              X(Define,  "Define",  0x0018AEFF, ":") \
              X(Call,    "Call",    0x00D6A454, "~")
      
  • Naming Conventions: When using X-Macros for Tags, entry names should be PascalCase, and the Enum symbols should be prefixed with the Enum type name (e.g., tmpl(STag, Define) -> STag_Define).