Every compiler has that moment where it just stops being a token re-arranger and starts becoming a real compiler. For DotC it was when I realized that the next thing I wanted to add was everything. I was secretly asking myself in this process: “How big is this thing?”
So before any of that, I built one function to answer that question, and I made the whole compiler route through it. Struct layout asks it. Array sizing asks it. sizeof asks it. It felt overkill at the time. It turned out to be the best decision in the project because every feature since has been a variation on how does this change the answer.
Structs
Structs were interesting. Structs look pretty straightforward and simple – I know famous last words – until you have this: struct Node* next;. To parse the pointer to Node, you need Node to exist, but Node only becomes complete after you parse it’s own body. It’s a classic problem of Chicken and egg.
Now how did I fix this? Well what I did was register the name as an empty shell the instant you see it, fill it in later. So in this case lies are a good thing.
Layout was the moment I felt like crying. One pass computes every field offset and the total size, shared by both “where’s this field” and “how big it is”, so they can never disagree. Bit-fields just gew that same pass to pack bits into shared storage. And unions just used structs infra.
Arrays
Arrays were quite boring honestly. int grid[3][4] is just an array of arrays. The nightmare was decay. In an expression, an array name stops being an array and becomes a ptr right. I got that wrong in type inference once, and it made me want to cry. A fresh address is 64 bits, and if anything decided it was 32-bit, the upper half just went away. And it was a pain to debug.
The Std
For now I only have a stddef.h with NULL, size_t, ptrdiff_t, include guards. Nothing crazy. Then I got to the part that needed a bit of… “work”. offsetof which cannot be written in portable C. Everyone cheats and so will I and I’m not hiding that.
Builtins
I cheated. Now everyone in their mother knows what an intrinsic is. So what intrinsics are supported? Well…: __builtin_unreachable, __builtin_expect, byte-swaps, and – of course – __builtin_offsetof.
Experimental
Added a little bit of an experimental CMake support, but it’s nothing stable or safe yet.