#import "../head.typ": *

#set page(margin: (top: 1.5cm, left: 2cm, right: 2cm), footer: context {align(center, counter(page).display("1"))})
#set text(size: 1.2em)
#set par(first-line-indent: 16pt)

#align(center, heading(depth: 1)[Архитектура и стиль
кода в Дарье (prototype1)])

#heading(depth: 2)[Структура репозитория]

Для компиляции используется только сборочная система make.
Генерировать makefile с помощью shell-скрипта разрешено, просто в данный момент это не
практикуется.
Другие сборочные системы, вроде Cmake, Meson, скрипты на питоне, и.т.д.
есть мерзость. _Ты можешь обнаружить в корне репозитория `CmakeLists.txt` - он не
обязателен для компиляции, он лишь для тех, чья среда разработки требует cmake._

Ни одна строка кода не должна быть написана на C++. Дарья не требует
для функционирования компилятор C++. То, что почти все зависимости Дарьи
требуют компилятор C++ - очень досадное обстоятельство, но не причина отказываться
от них, ибо аналогов у них нет. Мы молчаливо осуждаем тех, кто написал компилятор
glsl на C++. Допускается использовать python, rust, haskell
для написания скриптов, вспомогательных для разработки Дарьи, но не обязательных
для запуска Дарьи. Допускается написание самых высших уровней Дарьи на
haskell и rust. Самые высшие уровни Дарьи это те, что лишь используют мощь
моего игрового движка для исключительно творческих целей. Сам же движок Дарьи
пишется на чистом C99. Я не называю ни одну зависимость Дарьи святой.
Тем не менее аналогов им я не знаю. Как бы тебе не был противен C, прийдётся
уж им пользоваться, на нём основан linux, без линукса Дарья не запускается. Нижние
уровни Дарьи декларируют фреймворк, сглаживающий большинство недостатков C.

Во всех файлах на C используется `snake_case` для именования функций,
`UpperCamelCase` для именования типов. Имя пространства имён не имеет
такого правила наименования, поскольку если оно встречается в имени
функции, используется правило наименования для функции, если внутри имени типа,
используется правило для типов. Имя пространства имён дописывается перед
именем символа, внутреннего для пространства имён, без всякого разделителя.
Пространств имён у меня не много. В Дарье есть система инстанциации шаблонов
для C. К имени шаблона справа дописываются аргументы инстанциации (но есть исключения).
`VecU64`, `OptionVkFormat`, `ResultTextureDataR8OrSpanU8` значат буквально то,
что они значат.

Я не морочусь с тонной объектных файлов при компиляции, ибо пишу код
исключительно в `.h` файлах, где декларация объединена с определением.
Если я компилирую исполняемый бинарник, код с функцией `main` имеет расширение
`.c`, он вбирает все те заголовочные файлы, что ему нужны. В заголовочных файлах
используются "хедер-гуарды". При компиляции весь весь код со всех файлов,
нужных исполняемой программе какбы склеивается воедино. Поэтому нельзя одно и то же
имя дважды в двух разных заголовках, используемых одной программой, даже если чисто
логически они независимы.

В корне репозитория находится главный `Makefile`, плюс необязательны 
для сборки `shell.nix` для
людей нетрадиционной сексуальной ориентации, которые захотят воспользоваться
Дарьей. Весь остальной код лежит в папке `src` в обнимку с тестами. В процессе
компиляции дарья создаст папку `out`, куда будут помещены скомпилированные `cc`
исполняемые файлы и папку `gen`, куда будет помещён код на C, 
сгенерированный самой Дарьей для последующей компиляции. Поскольку в Дарье
присутствует кодген, весь исходный код (и генерируемый код тоже) разграничен на уровни.
Уровни обозначают порядок компиляции. На низших уровнях сгенерированно кода цель
компиляции только одна - сам этот код. На низших уровнях исходного кода
есть цель для генерации кода генерируемого соответсвующего себе уровня,
а так же тесты исходного кода этого уровня и любого кода с предыдущих уровней.
Да, уровни располагаются в одном порядке. В их именазаложена числовая нумерация.
Есть, правда, исключения из этого правила, для уровней, у которых
нет исходного (только генерируемый код) и генерируемый код генерируется не Дарьей,
а зависимостью Дарьи.

Вот какие уровни есть в данный момент:

`l_wl_protocls` (написан не мной, не нумеруется), `l1`, `l1_4`, `l1_5`, `l2`

Весь код хранится в папках `src/<имя уровня>` и `gen/<имя уровня>`.
Код с более высокого уровня может использовать код с более низкого уровня.
Сгенерированный код с какого-то уровня может использовать исходный код 
с этого же уровня, но исходный код не может использовать генерированный
код своего уровня. Тем не менее код из `src/lX`,
генерирующий другой код, может быть осведомлён о существовании и содердании
более высоких слоёв, но только если он находится в специальной папке
`src/lX/anne`. Цель (функция `main`), что генерирует код `gen/lX` находится в
c-файле `src/lX/anne/codegen.c`. Вместе с ним в `src/lX/anne` помещены
h-файлы, которые содержат 'под-процедуры' от `src/lX/anne/codegen.c`,
каждый файл использует доступные в `src/lX` методы для нужд своего более высокого
уровня. В `src/lX/codegen` содержатся исключительно методы для генерации кода,
которые используются в `src/lX/anne`, но сам `src/lX/anne` не
осведомлён о высших уровнях. Больше нигде код, нужный непосредственно для генерации
кода, не помещается.

Из этого правила есть ОДНО исключение: 
Файл `src/l1/core/VecU8_as_str.h` при компиляции цели `src/l1/anne/codegen.h`
использует, как ему и положено, только исходный код с первого уровня, но 
при компиляции любых другиц целей он инклюдит `gen/l1/VecAndSpan_U8.h`.
Казалось бы, это нарушение, ведь именно `src/l1` отвечает за генерацию `gen/l1`,
но это самый первый уровень, и если `gen/l1/VecAndSpan_U8.h` ещё не существует - значит
наше цель это и есть `src/l1/anne/codegen.c`. В этом случае вместо 
`gen/l1/VecAndSpan_U8.h` инклюдится `src/l1/core/chicken_VecU8.h`. 
Файл `src/l1/core/chicken_VecU8.h` содержит копию некоторых самых полезных методов из
`gen/l1/VecAndSpan_U8.h`, что позволяет писать и `l1` и все другие уровни с
одним и тем же определение строки. Это грязный трюк, но он сэкономил мне
сотни нервных клеток.

_Не спрашивай как я написал `src/l1/core/chicken_VecU8.h` без
`gen/l1/VecAndSpan_U8.h`_...

Разберём что делает каждый уровень, что есть в данный момент в Дарье:

- `l_wl_protocols` -- из-за странного способа дистрибуции wayland-lib мы должны сами
 генерировать код для неё.
- `l1` -- самый первый уровень.
- - Тут определены все утилиты, которые не
 потребовали кодгена.
- - Исходный код `l` определяет типы и функции,
 полезные при любой генерации кода.
- - В утилитах `l1` есть
 обёртки над базовыми обёртками над системными вызовами линукса.
- - Шаблоны: `Vec<T>`, `Option<T>`, `Span<T>`, `MutSpan<T>`, `Result<O>Or<E>`.
 Ну а раз на нём эти шаблоны определены,
 то в этом же уровне код из папки `src/l1/anne` инстанциирует их для
 ВСЕХ будущих целей.
- - `gen/l1/geom.h` -- файл со структурами
 векторов и матриц, их методами для операций из линейной алгебры.

- - В `gen/l1/pixel_masses.h` инстанциированы матрицы пикселей,
 или же проще - текстуры,
 хранящиеся в памяти максимально тривиальным способом.

#block(width: 100%, inset: 5pt, fill: luma(90%), radius: 4pt)[#par()[
    В `gen/l1` лежат
много много крутых заголовков, но `geom.h` и `pixel_masses.h` особенны тем,
что они не содержат в себе осведомление о высших уровнях, они пришли от самого `l1`,
а не просто зашли в `l1`, поскольку здесь впервые стали доступны методы для их
генерации.
]]

- `l1_4` -- Тут просто лежат тесты для шаблонов `l1`.

- `l1_5`
- - Инстанциация `Box`, `Ref`, `RefMut` для трейта (инстанциация
 'громадных' ссылок).
- - `gen/l1_5/marie/clipping.h` - дурацкий бесполезный файл для
пересечения треугольников. Даже не тестил его. Удалю его когда-нибудь.
- - Шаблоны `BuffRBTree_Set<T>`, `BuffRBTree_Map<K, V>`

- `l2`
- - Тесты для `l1_5`. 
- - `src/l2/liza` -- пространство имён для обёрток над `pipewire` и работы со звуком.
- - `src/l2/margaret/time_utils.h` -- утилиты для замерки времени с использованием
 системных часов.
- - `src/l2/margaret/vulkan_utils.h` -- утилиты для использования Vulkan.
- - `src/l2/marie/graphics_geom.h`, `src/l2/marie/shape_geom.h` -- больше
 алгебраических утилит, более специализированных.
- - `src/l2/marie/rasterization.h` -- Растеризация треугольников на процессоре.
- - `src/l2/marie/texture_processing.h` -- Утилиты для обработки текстур
 на процессоре. Как и код, куча текстур генерируется автоматически, для этих целей
 создан этот файл.
- - Тесты к `l1_5`
- - Особые тесты, названные `r` + `<число>`. Они не строгие их просто надо
запустить и проверить, что они запускаются.

Этот список не полный.

#heading(depth: 2)[Утилиты и классификация типов]

Весь код в Дарье сильно отличается от привычного кода на C из-за многочисленных
утилит, использующихся повсеместно. Тот, кто не знает всех утилит, определяемых в
`l1`, не сможет дальше понять ничего.

Нигде в Дарье я не принимаю во внимание случай Out of Memory. Когда `malloc`
возвращает `NULL` я немедленно завершаю программу. Поэтому я ввёл
функции `safe_malloc`, `safe_calloc`, `safe_realloc`. Они работают как и их
аналоги из стандартной библиотеки, но тебе не нужно беспокоиться о том что они вернут
ошибку. Хочешь понять код Дарьи - начни читать `src/l1/core/int_primitives.h`, там 
определены слиасы для имён числовых типов. Вместо `uint32_t` надо писать
`U32`, дабы уподобиться `Holy C`. Дальше читай `src/l1/core/util.h` чтобы понять
все утилиты ничего незнакомого. Не всё здесь уникально для Дарьи, например,
```c #define ARRAY_SIZE(arr) (sizeof(arr) / sizeof((arr)[0])) ```
здесь определён как и во многих других проектах на C.
Дальше логически идёт `src/l1/core/VecU8_as_str.h`. Но у этого файла есть одна
"движущаяся" зависимость - откуда он берёт `VecU8`. Первоначально он берёт
часть методов `VecU8` из `src/l1/core/chicken_VecU8.h`. Прочитай его дабы понять какие
методы будут у вектора. `src/l1/core/VecU8_as_str.h`
инклюдит `src/l1/core/chicken_VecU8.h` когда определён "флаг"
`PROTOTYPE1_L1_CODEGEN_BOOTSTRAP_USE_CHICKEN_VECU8`. Поти всегда, когда что-то будет
иметь дело строками, он будет инклюдить `VecU8_as_str.h`
Теперь можешь заглянуть в `Makfile` и убедиться, что его структура совпадает с той,
что я описал. Для некоторых тестов есть своя отдельная Makefile-цель `run_` +
`<имя теста>`.

Определяются следуюущие трейты для типов