Библиотеки на языке
Три библиотеки, написанные на flang. Все три выросли из настоящих программ
портала. Экран и чтение окружения digitdisk были написаны на
Go; их переписали на flang, сверили с оригиналом на общем наборе входов, и
вышли flang-tui и flang-env. Арифметику ленты окон перенесли из
digitwm тем же способом. Там C не убрали, а заменили: десять
функций ribbon.c теперь вызывают код, который flang выводит из
flang-ribbon (подключён в digitwm подмодулем ribbon-flang/).
| Репозиторий | Что умеет | Строк кода библиотеки | Всего строк на flang | Переводится в |
|---|---|---|---|---|
| flang-tui | раскладка терминального экрана: полосы, обрезка, укладка, вкладки, прокрутка | 3838 | 6360 | Go, C |
| flang-ribbon | арифметика ленты окон: смещения, ширина колонки, высота окна, вставка, панели | 1727 | 2571 | C, Go |
| flang-env | разбор значений окружения: глубина цвета, язык, NO_COLOR |
807 | 1210 | Go, C |
Откуда числа. Замер 18–19 октября 2026, компилятор — готовая сборка
flang 0.7.29 для Linux x86_64. Деревья: flang-tui на 7c04e31 (13 сентября),
flang-ribbon на d59225b (5 сентября), flang-env на 37120d0 (2 сентября).
«Строк кода библиотеки» — модули в flang/; «всего» — все файлы *.flang
дерева: git ls-files -z '*.flang' | xargs -0 wc -l. В «всего» входят общая
для трёх деревьев проверка лицензий tools/licensing.flang (303 строки), список
команд ярлыки.flang, у flang-tui — спецификации в fspec/, у flang-ribbon —
программы сверки в tools/. Функции, утверждения и примеры посчитаны
flang check --proof --json и flang test по каждому модулю.
Кроме flang, в деревьях есть только короткий запускатель ярлык на sh и у
flang-ribbon три скрипта сверки на sh. Ни Go, ни JavaScript, ни Makefile.
flang-tui — экран терминала
Что умеет. Шесть модулей, и граница у всех одна: данные плюс ширина и высота → готовые строки. Ни чтения, ни записи, ни запросов к среде.
| Модуль | Файл | Что делает |
|---|---|---|
| «Screen» | flang/screen/screen.flang |
полоса заполнения, обрезка по видимым ячейкам, укладка раздела в высоту, кадр целиком |
| «Format» | flang/format/format.flang |
размеры, доли, проценты, длительности, счётчики разрядами, прочерк, выравнивание |
| «Colour» | flang/colour/colour.flang |
истинный цвет, куб xterm-256, шестнадцать базовых |
| «History» | flang/history/history.flang |
история бегущего графика и строка его знаков |
| «Scroll» | flang/scroll/scroll.flang |
прокрутка: положение, высота окна, длина содержимого, нажатие → положение |
| «Tabs» | flang/tabs/tabs.flang |
вкладки: состояние плюс нажатие → состояние |
Сырой режим терминала, чтение клавиш, буфер вывода и SIGWINCH остаются у
программы, которая библиотеку зовёт. Здесь лежат только чистые тотальные
функции, и поэтому их можно перевести в другой язык и проверить там же.
Как подключается. Двумя путями.
- Переводом в Go или C:
./ярлык печатькладёт каждый модуль вout-go/<имя>иout-c/<имя>и собирает обе версии (gofmt,go vet,go build,cc -Werror). Результат встраивается в чужую программу без рантайма flang. Единственная правка выведенного кода — имя пакета Go: у всех модулей оно одно (flangprogram), иsedпереписывает его наflang<имя>, чтобы шесть модулей не столкнулись в одной сборке. На 0.7.29 всё собирается, код возврата 0. - Пакетом flang:
./ярлык пакетысобирает шесть файлов.flang-package(у каждого модуля свой манифестflang.package). Подключается строкойиспользует «Screen» из "flang-tui/flang/screen/screen.flang-package"; обещания модуля едут вместе с кодом и доказываются у того, кто подключил.
Чем проверяется. ./ярлык проверка — flang check и flang test по
каждому модулю. На 0.7.29:
| Функций | Тотальных | Утверждений | доказано | на сетке значений | Примеров | |
|---|---|---|---|---|---|---|
| Шесть модулей | 102 | 102 | 71 | 23 | 48 | 613 из 613 |
«Доказано» — для всех входов. «На сетке значений» — постусловие посчитано на значениях из примеров; это не доказательство, и отчёт так и пишет.
Что на 0.7.29 краснеет. Два ярлыка библиотеки написаны под прежний компилятор и на 0.7.29 падают:
./ярлык ведомостьвыходит кодом 1: начиная с 0.7.29flang check --proofотвечает кодом 3, если часть утверждений держится только на сетке, а здесь таких 48;./ярлык спекивыходит кодом 3: с 0.7.21flang ioне запускает план, у которого не всё доказано, без ключа--на-веру(125 утверждений: 75 доказано, 50 на сетке).
Сам код библиотеки от этого не меняется: проверка и примеры проходят.
Сверка с оригиналом. Её делали дважды, 2 и 3 сентября 2026, на flang 0.6.2: 494 467 входов против digitdisk 0.5.0 и 1 944 268 входов против digitdisk 0.8.0, расхождений 0. Программа сверки на Go после этого удалена из дерева, а ответы оригинала на граничных входах перенесены в модули примерами — это те же 613 примеров, которые проходят на 0.7.29. Если поменяется digitdisk, примеры этого не заметят.
flang-ribbon — лента окон
Что умеет. Пять модулей. Четыре — арифметика: данные плюс размеры экрана → куда что встаёт. Пятый, «Ribbon», описывает саму ленту как значение и обещания о том, как она меняется при вставке окна.
| Модуль | Файл | Что решает |
|---|---|---|
| «Viewport» | flang/viewport.flang |
смещение по ленте и вниз по стопке; поправка смещения после смены размера экрана |
| «Geometry» | flang/geometry.flang |
ширина колонки от доли и от пресета, высота окна в стопке, деление нацело по правилам C99 |
| «Placement» | flang/placement.flang |
куда встаёт новое окно, кто получает фокус после закрытия |
| «Strut» | flang/strut.flang |
пересекаются ли панель и область, сколько панель забирает от края, что остаётся двум панелям напротив друг друга |
| «Ribbon» | flang/ribbon.flang |
лента как значение: колонки, фокус, два смещения; вставка окна как функция «лента → лента» |
Оригинал — ribbon.c из digitwm, десять функций
ribbon_policy_* на закреплённом коммите bfd5d85. Строк C из digitwm в
дереве нет: арифметика записана на flang заново.
Как подключается. Переводом: flang emit flang/geometry.flang --target c --out out-c/geometry, так же в Go. В digitwm это уже работает: в ribbon.c
десять функций ribbon_policy_* — тонкие обёртки над выведенным C из
подмодуля ribbon-flang/ (он закреплён на 66d3493, на два коммита раньше
main библиотеки). Таблицу долей ширины, которую оригинал читал из
глобальной Conf, функция получает аргументом.
Чем проверяется. На 0.7.29:
| Функций | Тотальных | Утверждений | доказано | на сетке значений | Примеров | |
|---|---|---|---|---|---|---|
| Пять модулей | 60 | 60 | 31 | 6 | 25 | 199 из 199 |
./ярлык проверка и ./ярлык сетка (оба обещания ленты пересчитаны на 896
лентах) проходят. ./ярлык ведомость на 0.7.29 выходит кодом 1 по той же
причине, что у flang-tui: 25 утверждений держатся на сетке.
Сверка с оригиналом — команда, и она повторена на 0.7.29. ./ярлык сверка
(tools/compare.sh) клонирует digitwm на закреплённом коммите и сверяет
sha256 ribbon.c, вырезает десять функций в отдельный объектный файл (у него
ровно одно неопределённое имя — Conf), выводит четыре модуля в C и в Go и
гоняет все три реализации на 526 871 входе. Прогон 19 октября 2026:
$ ./ярлык сверка
…
сверено входов: 526871
расхождений: 0
теорема пары («Пара вместе», счётчика в эталоне нет): проверена на 4536 входах, не сработала 0 раз
потоки ответов совпали побайтно: строк 526871, байт 14458160 (cmp)
…
напечатанное в Go совпало с эталоном побайтно: строк 526871 (cmp)
Ответы оригинала C, выведенного C и выведенного Go совпали байт в байт.
У одной функции пары в оригинале нет: «Пара вместе» складывает обе доли двух панелей и обещает, что вместе они не займут больше, чем есть в области. Доказательства у этого обещания нет; в выведенном коде оно проверяется при работе, и сверка считает, сколько раз оно сработало.
Отрицательный контроль. ./ярлык наоборот портит копию дерева и требует,
чтобы каждая проверка покраснела: подменённый ответ примера, строка вместо
числа, ложное постусловие, сломанный модуль (для check --proof и для
emit), подложенные чужая лицензия, чужой язык и рукописный C, перевранная
арифметика для сверки. На 0.7.29 все эти порчи ловятся. Не сработал один
контроль: ужесточённое обещание ленты краснеет, но не тем постусловием,
которого ждёт скрипт, и он выходит кодом 1. Сверку вставки против живого
cwm не запускали: для неё нужен собранный оконный менеджер.
Находка при переносе. Первый прогон сверки дал 606 расхождений из
526 871, все на ширине колонки. Ошибалась не арифметика, а постусловие: в
flang, как в IEEE-754, есть +0 и −0, и (0 − 0) × −20 даёт −0.
Постусловие «частное и остаток восстанавливают делимое» без нормализации
отвечало отказом там, где оригинал возвращал ноль. Исправляет плюс 0 (приём
из flang/stdlib/numbers.flang); случай записан примером в «Ширине колонки».
Что осталось в C. ribbon.c на текущем digitwm (b8e5d1b) — 1640 строк.
Кроме десяти обёрток там обход списков и память (TAILQ_*, malloc, free)
и вызовы оконной системы. Этого в библиотеке нет и не будет: библиотека,
которая знает про client_show, становится половиной оконного менеджера.
flang-env — окружение
Что умеет. Два слоя.
Слой 1 — модуль «Env», flang/env.flang: чистые тотальные функции. Программа
передаёт строки, библиотека решает: сколько цвета терпит терминал
(NO_COLOR, TERM, COLORTERM), годен ли он под экран, на каком языке
говорить, какими знаками писать числа. Переводится в Go и C и встраивается в
чужую программу.
Слой 2 — план «Прочитать окружение», flang/read-env.flang: читает шесть
переменных сам (через printenv) и отдаёт ответ слоя 1. Исполняет его
flang io.
Переменная — это вариант, а не строка: вариант «Задано» с значение равным … против вариант «Не задано». Пустая строка и отсутствие переменной —
разные вещи, и тип это различает. Так сделано ради NO_COLOR, который
действует самим своим наличием.
Как подключается. Слой 1 — переводом в Go или C. Слой 2 на 0.7.29
переводится во все цели (go, c, rust, js — код 0), но выведенная
программа план не исполняет:
$ flang emit flang/read-env.flang --target c --out env-c && make -C env-c
$ ./env-c/flang_cli --plan 'Прочитать окружение'
{"error":"… исполните план двоичным: flang io <файл.flang>: Запустить процесс","code":"FLANG_IO_NOT_WIRED"}
Поэтому путей два: кому нужно, чтобы окружение читала сама библиотека, зовёт
flang io; кому нужно, чтобы разбор жил внутри его программы, берёт
переведённый модуль «Env» и передаёт строки сам.
С 0.7.21 flang io не запускает план, у которого не все утверждения
доказаны: у read-env одно из двух держится на сетке, и запуск идёт по ключу
--на-веру:
$ flang io flang/read-env.flang --на-веру
на веру: доказанность не считалась — запуск по ключу --на-веру
{"plan":"Прочитать окружение","result":"цвет: 256; язык: ru; область: RU; дробный: «,»; разрядный: « »", …}
Чем проверяется. На 0.7.29:
| Функций | Тотальных | Утверждений | доказано | на сетке значений | Примеров | |
|---|---|---|---|---|---|---|
| «Env», слой 1 | 25 | 25 | 9 | 4 | 5 | 103 из 103 |
| «ReadEnv», слой 2 | 7 | 7 | 2 | 1 | 1 | 117 из 117 |
Четыре ярлыка библиотеки написаны под прежний компилятор и на 0.7.29 падают — каждый потому, что язык изменился, а не код библиотеки:
./ярлык ведомость— код 3: часть утверждений держится на сетке;./ярлык отказждёт, что для плана отчёт о доказательствах не печатается (код 2), а 0.7.29 его печатает (код 3);./ярлык границаждёт, что Go, C и Rust откажутся переводить план, а 0.7.29 переводит (код 0);./ярлык план—flang ioбез--на-веруотказывается запускать план.
./ярлык проверка и ./ярлык лицензии проходят.
Сверка с digitdisk — 402 входа, 0 расхождений — была разовой (2 сентября, flang 0.6.2); 41 из 103 примеров слоя 1 — ответы оригинала на закреплённом коммите.
Цена flang io. Медиана десяти запусков, та же машина:
| Что | Время |
|---|---|
flang io flang/read-env.flang --на-веру |
0,97 с |
flang check flang/read-env.flang |
1,16 с |
printenv TERM |
3 мс |
Почти всё время уходит на проверку программы перед запуском, а не на чтение
переменных. Поэтому flang io годится для старта, установки и CI, но не для
горячего цикла; там место переведённому слою 1.
Общее у всех трёх: make нет
Точка входа — ./ярлык, короткий скрипт на sh. Списка команд в нём нет:
он спрашивает строку команды у программы ярлыки.flang и запускает её.
Сам список — программа на flang: с типами, примерами и обещанием о числе
команд. Список модулей нигде не записан — команды берут flang/*.flang,
поэтому новый модуль не может молча выпасть из проверки.
Все три — под BSD-2-Clause, написаны с нуля. Поведение сверено с оригиналами по их открытому исходнику: flang-tui и flang-env — с digitdisk, flang-ribbon — с digitwm.
См. также
- Описание языка — что за язык, два класса программ, перевод в другие языки
- Справочник конструкций — карточка с примером на каждую форму
- Практикум — восемь ступеней, вердикт выносит исполнение
- digitdisk — программа, из которой выросли flang-tui и flang-env
- digitwm — программа, из которой перенесена арифметика flang-ribbon