Цикл поручений принадлежит хозяину, а не языку: flang io в двоичном стоил 1289 строк C и трёх точек на flang
Команда flang io — единственная, которая действительно что-то делает; всё остальное в инструменте чисто. Перенести её в двоичный оказалось не «дописать хозяина», а провести границу между тем, что считает программа, и тем, что делает среда, — и граница эта проходит НЕ там, где ждали.
Цикл поручений принадлежит хозяину, а не языку. Свидетель гоняет его в runPlan и зовёт хозяина функцией; в flang передать функцию нечем, а звать хозяина по имени программа не может по построению — доступа к миру у неё нет. Значит между двумя поручениями управление ОБЯЗАНО выйти наружу. На стороне flang остались ровно три точки: найти план, взять начальное состояние, сделать один шаг. Всё остальное — C.
Чем подтверждено. Ветка work/facts-io, коммиты 53187452, 3289026f, f1dcdc09. Своего ручного C прибавилось 1289 строк (14 339 → 15 628 по четырём файлам flang/src/emit/c/*.c, из них весь прирост в flang_repl.c; flang_cli.c остался переносимым C99 и не тронут). На стороне flang — 13 функций и 3 объекта в flang/self/bootstrap/compiler.flang.
Сверка: 12 прогонов, расхождений 0 — вывод, stderr, код возврата и слепок рабочего каталога совпали в каждом. Корпус — examples/wal/append-plan.flang (настоящий) и план, написанный ради поручений, которых у первого нет (перечисление каталога, запуск процесса, кости с семенем).
Четыре места, где C и Node расходятся, если не думать
- Ненулевой код возврата процесса — это РЕЗУЛЬТАТ, а не сбой. В C соблазн тот же, что у
execFileв Node: считать ненулевой код ошибкой. Тогда «программа отработала и вернула 3» приезжает как поломка — ровно та подмена, против которой неудача сделана откликом. ИWIFSIGNALEDобязан спрашиваться РАНЬШЕWEXITSTATUS: иначе «убит сигналом» сливается с «вернул 0».
readdirпорядка не обещает, и это ломает не красоту, а сравнимость. Весь смысл словаря поручений в том, что журнал настоящего хозяина сверяется с журналом поддельного. Сортировать надо по кодовым точкам (для UTF-8 это простоstrcmpпо байтам), а не по правилам локали: локаль — то, чего хозяин не выбирает.
- Место отказа (
span) ставится НЕ ВСЕГДА. Свидетель кладёт его тому отказу, который родился внутри прогона плана, и не кладёт тому, который родился до него («плана с таким именем нет» — указывать не на что). Лишний ключ разошёлся бы побайтово, и заметить это можно только сверкой самого вывода: коды возврата при этом совпадают.
- Код 3 у ненайденного плана, а не 2. Двойка означает КРИВОЙ ВЫЗОВ (не назван файл, непонятный ключ). «Плана нет» — вызов правильный, до плана дело дошло, сломался инструмент: это 3. Различает коды 1 и 3 не код отказа, а то, КТО принял решение: «Провал» вернула сама программа.
Названный зазор: текст ошибок операционной системы не совпадает
FLANG_IO_READ от Node несёт ENOENT: no such file or directory, open '/путь', а от C — strerror(errno), то есть No such file or directory. Побайтово это не сойдётся никогда, и подгонять C под формат Node значило бы вписать в доверенное основание чужие тексты. Поэтому сверка идёт по путям, где текст принадлежит ПРОГРАММЕ или хозяину, а не операционной системе; путь «файла нет» назван зазором и не сверяется.
Чего у двоичного хозяина нет — и почему сказано отказом, а не молчанием
Экрана нет (FLANG_IO_NO_SCREEN на «Показать» и «Ждать событие» — как у хозяина Node) и шифрования нет (FLANG_IO_NO_TLS на адрес по https). Разница между «не знаю такого поручения» и «знаю, но здесь этого нет» — не педантизм: первое означает, что хозяин отстал от словаря языка и его надо чинить, второе — что программа просит невозможного ЗДЕСЬ и может попросить другого. TLS в основание не втащен по доводу «мимо цели»: это перенос чужой криптографии в то, чему надо доверять.
Чем ограничено. Сокеты написаны и компилируются, но сверкой не покрыты: план-сервер в дереве есть (examples/web/shortener/plan-network.flang), а сверять его пришлось бы двумя одновременными прогонами с клиентом, и это отдельная работа. Клиент HTTP — минимальный HTTP/1.1 без разбора заголовков дальше кода ответа и тела.
Связано: five-binary-commands-and-the-price-of-each, pulling-a-module-into-the-self-hosted-compiler-pays-for-meetings-not-size