Odin-типы для Language Server Protocol, сгенерированные из официальной
машиночитаемой спецификации (metaModel.json,
версия 3.17.0).
generate.py читает metaModel.json и пишет generated/lsp_types.odin —
структуры, перечисления, алиасы типов и таблицу методов запрос/уведомление,
готовые для сериализации через core:encoding/json.
python3 generate.py
odin check generated -vet -no-entry-point # или odin build generated -build-mode:objmetaModel.json уже лежит в репозитории. При выходе новой версии спеки —
перекачать файл и перезапустить generate.py; скрипт детерминирован,
результат воспроизводим.
Из metaModel.json:
| Секция спеки | Во что превращается |
|---|---|
structures |
Odin struct с `json:"…"` тегами |
enumerations |
enum (int/uint) или distinct string + константы (string) |
typeAliases |
Name :: <тип> |
requests/notifications |
Method enum + method_string/message_info таблицы |
| LSP kind | Odin |
|---|---|
base |
string/bool/i32/u32/f64, DocumentUri/URI (distinct string) |
reference |
имя типа как есть |
array |
[]T |
map |
map[K]V |
tuple |
[N]T (если все элементы одного типа) либо именованный struct |
literal (анонимная структура) |
именованный struct, имя = контекст объявления (Родитель + Поле) |
or |
union {A, B, …}; если в списке был null — поле дополнительно оборачивается |
and |
struct с using-полями на каждый входящий тип (structural intersection) |
stringLiteral |
string (Odin не умеет типы-литералы, значение не проверяется компилятором) |
Опциональные поля (optional: true в спеке, либо or с null-веткой):
- если тип — ссылка на структуру:
^T(указатель,nil= отсутствует); - иначе:
Maybe(T).
Указатель для optional-структур — не стилевой выбор, а необходимость:
Maybe(T) — это union($T){T} без индирекции, и такие LSP-типы, как
SelectionRange.parent: SelectionRange? (ссылка сама на себя), через
Maybe дают бесконечный размер типа. Через ^T — нет проблемы, nil
корректно кодируется как отсутствие поля при JSON-сериализации.
Message_Info :: struct {
method: string,
is_notification: bool,
params_type: typeid,
result_type: typeid,
}
message_info: [Method]Message_Info
method_string: [Method]stringКаждый метод спеки (textDocument/definition, $/cancelRequest, …) —
один член Method. $/-методы получают префикс Dollar_ (Odin
идентификатор не может начинаться с $), остальные — Namespace_MethodName
(/ → _, PascalCase). params_type/result_type — настоящий typeid
через typeid_of(...), nil если у метода нет параметров/результата
(у notification результата никогда нет). Даёт диспетчеру таблицу
"строка метода → тип" без ручного switch на 93 case.
stringLiteral-типы (теговые поля вродеCreateFile.kind == "create") вырождаются в обычныйstring— Odin не проверяет конкретное значение на этапе компиляции.LSPAnyне оборачивается вMaybe, хотя в спеке допускаетnull:LSPAny ↔ LSPObject ↔ LSPArray— взаимно рекурентный цикл, аMaybe($T)требует полностью резолвнутый размер$Tуже на объявлении алиаса — компилятор не тянет такой цикл через generic-инстанцирование. Zero-value union'а используется как суррогат "нет значения". Единственный такой случай в спеке 3.17.0.registrationOptions/partialResult/errorDataполей запросов не генерируются — толькоmethod/params/result.- Диспетчер JSON-RPC (чтение
methodиз входящего сообщения,json.unmarshalв конкретныйparams_type, вызов хендлера) не реализован — этот репозиторий даёт только типы и таблицу методов, connection/transport слой — отдельная задача.