flang компилятор доказывает, что программа не зациклится 0.7.29 GitHub English

Справочник команд

У двоичного flang команды перечислены в его собственной справке (она вставлена в конце страницы из flang --help). Для каждой здесь сказано, когда её запускать, как вызывать, какие у неё ключи, что она печатает и с каким кодом возврата выходит. Всё это сверяется с flang --help и flang <команда> --help; каждый вывод ниже снят с нынешнего двоичного.

Шпаргалка

КомандаКогда запускатьТипичный вызов
checkпосле каждой правки: разбор, типы, завершаемость, prover, unit-тестыflang check привет.flang
testчтобы прогнать только unit-тесты (пример)flang test привет.flang
runчтобы вычислить одну функцию и напечатать значениеflang run привет.flang --function «Удвоить» --args '{"н":21}'
emitчтобы сгенерировать код на одном из десяти целевых языковflang emit привет.flang --target js --file привет.js
astчтобы увидеть разобранную программу деревом JSONflang ast привет.flang --pretty
tokensчтобы увидеть, чем лексер счёл каждое словоflang tokens привет.flang
lintчтобы строки не были слишком длинными, а ветвления — слишком глубокими, по пределам из .flangrcflang lint scripts/
factsчтобы проверить утверждения на данных из JSON-файлаflang facts привет.flang --facts факты.json --claims '["…"]'
ioчтобы запустить программу, которая читает файлы, запускает процессы или ходит в сетьflang io план.flang --pretty
lockчтобы записать lock-файл, в котором лежат сами зависимостиflang lock привет.flang > flang.lock
packageчтобы собрать пакет: lock плюс имя, версия и список доказанногоflang package привет.flang > привет.flang-package
newчтобы начать новый пакетflang new проба
run-scriptчтобы запустить короткую команду проекта из .flangrcflang run-script site:build
replчтобы пробовать выражения интерактивноflang repl привет.flang
lspзапускает редактор: языковой серверflang lsp --stdio

Ещё: flang --help, flang --version, flang <команда> --help; flang --machine [<файл>] печатает, насколько быстра эта машина (шагов вычисления в секунду); flang --mcp-mode — сервер для ИИ-помощника по стандартному вводу и выводу (flang --mcp-mode --help — как его подключить).

Три ключа годятся при любой команде и ограничивают сам двоичный на этот прогон:

КлючЧто задаёт
--depth-limit N (--предел-глубины)предел глубины вызовов
--step-limit N (--предел-шагов)предел шагов; исчерпание — FLANG_RECURSION_LIMIT с числом
--memory-limit N (--предел-памяти)предел памяти, байтами или с буквой K, M, G, T; 0 — без предела. У check, test и run по умолчанию три четверти памяти машины. На пределе прогон останавливается с кодом 5 и называет функцию и число шагов

Долгие прогоны печатают в поток ошибок строку хода шагов N из M ….

Примеры ниже идут на этом файле, docs/examples/cli/double.flang:

module «Hello»

total function «Удвоить»
  accepts н: number
  returns number
  example «Двадцать один»
    given н equals 21
    expected 42
  н plus н

Коды возврата

Коды значат одно и то же во всех командах.

КодЧто значит
0сделано, замечаний нет
1программа не прошла проверку; у facts и io — программа сама ответила «нет»
2кривой вызов: неизвестный ключ, неверное значение, нет такого файла
3сделано, но проверено не всё, и вывод называет, что именно. А ещё: run и io отказываются запускать программу, гарантии которой не доказаны
4часть проверок не запускалась вовсе (check --fast)
5прогон остановлен на пределе памяти

В скрипте сборки различайте 1 и 3: 1 — работа не сделана, 3 — сделана, но поручиться за неё целиком нельзя.

Входной файл: четыре расширения

Файл программы может кончаться на .flang, .fp, .фп или .фланг; все четыре равноправны. .flang — основное; .fp избавляет от переключения раскладки; .фп и .фланг позволяют русскому имени файла остаться в одном алфавите. Команды берут файл по пути, так что годится и любое другое имя.

flang test различает один файл и набор файлов по доводу, см. test. Файл с любым из четырёх расширений берётся как один файл:

$ flang test привет.фп
привет.фп: примеров 1, прошло 1, не прошло 0

check

Проверяет программу: разбор, связывание имён, типы, завершаемость, prover и unit-тесты. Запускайте после каждой правки.

flang check <файл.flang> [--proof [--json] [--strict] [--record <файл>]]
                          [--fast] [--step-limit N] [--depth-limit N]

У каждого ключа есть и кириллическое написание, оно в скобках.

КлючЧто делает
--proofпечатает отчёт о доказательствах: у каждой функции — чем доказано завершение, у каждого постусловия — доказано ли оно, проверено только на примерах или не доказано. Постусловие без доказательства и без примеров даёт код 3
--jsonвместе с --proof: тот же отчёт в JSON
--strict (--строго)вместе с --proof: код 0 только когда доказана каждая гарантия. Для CI. Подробно ниже
--record <файл> (--записать)вместе с --proof: записать само доказательство в файл, чтобы его перепроверила независимая программа flang/proof/checker/checker.c
--fast (--быстро)только имена, типы, полнота pattern matching и завершаемость. Prover и unit-тесты не запускаются, вывод говорит об этом, код возврата 4. Вместе с --proof нельзя
--step-limit N (--предел-шагов)поднять предел шагов на этот прогон. Нужен для --proof --json на очень больших файлах. Ключа --max-steps у check нет: это кривой вызов, код 2
--depth-limit N (--предел-глубины)поднять предел глубины вызовов на этот прогон. Не путать с --max-depth у emit: тот записывается в сгенерированную программу
--memory-limit N (--предел-памяти)предел памяти, см. выше; на пределе код 5

Коды: 0 — замечаний нет; 1 — программа не прошла либо с --proof гарантия нарушена; 2 — в программе есть объявления, которые двоичный не проверяет вовсе (категорные объявления, процессы, надзор), и он их называет; 3 — с --proof гарантия не доказана, в том числе проверенная только на примерах (сетка N), закон, посчитанный только на сетке, гарантия, доказанная при недоказанной посылке, и файл без ввоза, запись доказательства которого независимый сверщик не принял (НЕ СОШЛОСЬ СО СВЕРЩИКОМ); с --strict — ещё и файл без единой гарантии; 4 — с --fast. Строка сверщика идёт перед строкой приговора. Файлу с ввозом сверщик не получает записей ввезённых модулей; его несогласие там названо НЕЗАВИСИМО НЕ ПРОВЕРЕНО и код не меняет (ADR-0115).

$ flang check docs/examples/cli/double.flang
модуль «Hello»: функций 1, из них с доказанным завершением 1; типов 0
docs/examples/cli/double.flang: проверено — разбор, типы, завершаемость, ядро и примеры; замечаний нет

Первая строка считает функции и сколько из них с доказанным завершением. Вторая говорит, что прошли все проверки: разбор, типы, завершаемость, prover («ядро») и unit-тесты.

Когда проверка не прошла, вывод называет код ошибки, строку и столбец. Здесь docs/examples/cli/bad.flang объявляет returns string, а тело даёт число:

$ flang check docs/examples/cli/bad.flang
модуль «Bad»: функций 1, из них с доказанным завершением 1; типов 0
FLANG_TYPE в файле docs/examples/cli/bad.flang, строка 6, столбец 5: функция «Удвоить» объявлена как строка, а тело даёт число
docs/examples/cli/bad.flang: не проверено — замечаний 1
$ echo $?
1

Каждый код FLANG_… и как его чинить — в Справочнике отказов.

$ flang check docs/examples/cli/double.flang --fast
модуль «Hello»: функций 1, из них с доказанным завершением 1; типов 0
ПРОВЕРЕНО: связывание имён и повторы объявлений, типы, исчерпываемость разбора,
           завершаемость (в том числе взаимная рекурсия по компонентам), процессы, планы.
НЕ СМОТРЕЛИ НА ЭТОМ ПРОГОНЕ: ядро доказательств — обязательств 0, теорем 0;
           законы категории на сетке; прогон примеров — примеров 1.
           И это не «нарушений нет»: про них не сказано ничего — ни хорошего, ни плохого.
           «Не смотрели» — не то же, что «объявлено, доказательства нет»: второе
           значит «смотрели и не смогли», а здесь вопроса не задавали вовсе.
           Спросить всё — та же команда без «--быстро».
docs/examples/cli/double.flang: часть проверок НЕ ЗАПУСКАЛАСЬ — код возврата 4, а не 0
$ echo $?
4

--strict: свой код возврата на каждый итог

Без --strict команда check --proof выходит с 0 и когда доказано всё, и когда часть гарантий проверена только на ваших примерах. Слова в выводе разные, но скрипт сборки читает код возврата. С --strict у каждого итога свой код:

ИтогКодКогда
ДОКАЗАНО0гарантия есть хотя бы одна, и доказана каждая
ОПРОВЕРГНУТО1найден контрпример
НЕ УДАЛОСЬ ДОКАЗАТЬ3контрпримера нет, но доказано не всё; вывод называет, что
НЕ ПОДДЕРЖИВАЕТСЯ2программа объявляет то, что двоичный не проверяет, и вывод это называет

У кода 3 три причины, их различают слова после него: ОПОРА НЕ СУДИЛАСЬ — гарантия проверена только на примерах; ОБЪЯВЛЕНО, НЕ ДОКАЗАНО — у гарантии нет ни доказательства, ни примеров; ПРОВЕРЕНО ВПУСТУЮ — гарантий нет вовсе. Когда причин несколько, называется самая серьёзная: контрпример важнее отсутствия доказательства, а отсутствие доказательства важнее «только примеров».

Файл без гарантий по умолчанию проходит, а под --strict — нет, потому что «доказывать нечего» — не доказательство:

$ flang check привет.flang --proof --strict | tail -2
привет.flang: НЕ УДАЛОСЬ ДОКАЗАТЬ — ПРОВЕРЕНО ВПУСТУЮ, ОБЯЗАТЕЛЬСТВ НЕТ ВОВСЕ — утверждений 0: доказано 0, условно 0, сетка 0, объявлено, не доказано 0, отвергнуто 0, нарушено 0; законов на сетке 0, на веру 0 — код возврата 3
  ничего: ни одно утверждение не назвало ни правила, ни шага

Прошедшие примеры — не доказательство. Здесь постусловие ложно, а два примера случайно проходят:

модуль «Grid»

тотальная функция «Удвоить»
  принимает н: неотрицательное
  возвращает число
  обеспечивает «не больше ста» результат не больше 100
  пример «один»
    дано н равно 1
    ожидается 2
  пример «десять»
    дано н равно 10
    ожидается 20
  н плюс н

flang check docs/examples/cli/grid.flang выходит с 0: доказательств он не судит. flang check docs/examples/cli/grid.flang --proof выходит с 3: отчёт пишет сетка 1 — одна гарантия проверена только на примерах — и НЕ ДОКАЗАНО — ОПОРА НЕ СУДИЛАСЬ. С --strict код тоже 3. flang run такую программу считать отказывается (см. run), а с --trust при н = 100 нарушает постусловие:

$ flang run docs/examples/cli/grid.flang --function «Удвоить» --args '{"н":100}' --trust
на веру: доказанность не считалась — запуск по ключу --trust
FLANG_PROPERTY: нарушено свойство «не больше ста» функции «Удвоить»
$ echo $?
1

--strict делает строгим только компилятор. Независимая программа проверки flang/proof/checker/checker.c на записи доказательства, где не доказано ничего, отвечает НЕ ПРОВЕРЕНО — ВПУСТУЮ с кодом 3 и без ключа.

--strict без --proof — кривой вызов, код 2. Пробные программы на все итоги лежат в flang/proof/probes/strict/; прогон — bootstrap/flang io flang/proof/probes/strict/run.fscript --plan Binary.

test

Прогоняет unit-тесты (пример), объявленные внутри функций. Сначала делает те же проверки, что check: прошедший тест в программе с ошибкой типов ничего не значит.

flang test <файл.flang | каталог | маска> [--no-check] [--json] [--ledger]
                                          [--max-steps N] [--max-depth N]
КлючЧто делает
--no-checkне проверять, только прогнать примеры — пока программа ещё в правке
--jsonитог одной строкой JSON
--ledgerпо строке на файл через табуляцию — чтобы сравнивать прогоны через diff
--max-steps Nпредел шагов вычислителя
--max-depth Nпредел глубины
--memory-limit Nпредел памяти; на пределе код 5

Довод, который не кончается ни на одно из четырёх расширений или содержит * или ?, — это набор файлов:

flang test flang/stdlib/                весь каталог, вглубь
flang test 'docs/examples/**/*.flang'  по маске (кавычки — от оболочки)

Коды: 0 — взяты все файлы и прошли все примеры; 1 — пример не прошёл или файл не взят; 2 — кривой вызов.

Блок прогон описывает сценарий над процессами. flang test исполняет его планировщиком flang/self/conc.flang и сверяет ожидания; блок считается одним примером, поэтому блок с ложным ожиданием валит файл кодом 1:

$ flang test flang/concurrency/examples/counter.flang
flang/concurrency/examples/counter.flang: примеров 4, прошло 4, не прошло 0
$ flang test docs/examples/cli/double.flang
docs/examples/cli/double.flang: примеров 1, прошло 1, не прошло 0

Для не прошедшего примера печатаются обе стороны: ожидалось и получено. Длинное значение обрезается на 200 знаках, и полная длина называется числом.

run

Вычисляет одну функцию и печатает значение. Считает сам двоичный: ни компилятор C, ни Node не нужны.

flang run <файл.flang> --function «Имя» [--args '{"н":10}'] [--max-steps N]
                       [--max-depth N] [--trust] [--unproven refuse|warn|allow]
                       [--cost]
КлючЧто делает
--function «Имя»какую функцию вычислить. Обязателен
--args '{…}'аргументы плоским JSON-объектом из скаляров. Списки и вложенные объекты не принимаются
--max-steps Nпредел шагов вычислителя
--max-depth Nпредел глубины вычисляемой программы (свой предел двоичного — --depth-limit)
--memory-limit Nпредел памяти; на пределе код 5
--cost (--цена)после значения строкой в поток ошибок: шагов вычислителя, пик памяти процесса в байтах и секунды прогона — цена прогона: шагов 6, пик памяти 13443072 байт, секунд 0.005997
--trust (--на-веру)запустить, даже если гарантии не доказаны; доказательства не проверяются вовсе, и об этом говорит отдельная строка
--unproven СЛОВО (--недоказанное)что делать, когда гарантии не доказаны: refuse — не запускать (по умолчанию), warn — сказать и запустить, allow — то же, что --trust. По-русски: отказ, предупреждение, разрешение

Аргументы сначала сверяются с объявленными типами: «Факториал» от −3 отвергается с FLANG_TYPE, а не вычисляется.

run не запускает недоказанную программу. Перед вычислением он проверяет доказательства всего, что программа использует (а не только этого файла), и печатает одну строку в поток ошибок: доказано: утверждений N (N гарантий, все доказаны) либо не доказано: … — и тогда не вычисляется ничего, код 3.

$ flang run docs/examples/cli/double.flang --function «Удвоить» --args '{"н":21}'
доказано: утверждений 0
42

Чтобы разрешить недоказанные программы раз и навсегда, задайте ключ unproven в .flangrc (Настройки): unproven = warn. Ключ командной строки старше переменной среды FLANG_UNPROVEN, она старше .flangrc, а он — умолчания refuse. Строка перед значением называет, что разрешило запуск: ключ или настройку и путь к её файлу. Неизвестное значение — код 2 с объяснением.

emit

Генерирует код на целевом языке. Все десять целей встроены в двоичный. Каталог из --out заводится сам, вместе с подкаталогами, которых требует цель.

flang emit <файл.flang> --target c|cpp|go|rust|java|js|ts|elixir|python|csharp
                        [--out каталог | --file имя] [--cli|--no-cli] [--repl]
                        [--runtime каталог] [--index-base 0|1]
                        [--max-steps N] [--max-depth N] [--no-check]
                        [--no-postconditions]
КлючЧто делает
--target <цель>c, cpp, go, rust, java, js, ts, elixir, python, csharp. Обязателен
--out каталогзаписать все файлы в каталог
--file имяодин файл на стандартный вывод
--cli, --no-cliгенерировать ли запускалку командной строки
--replсгенерировать ещё и интерактивный вход. Только цель c
--protocol файл (--протокол)только цель c: записать ещё журнал перевода — во что перешла каждая конструкция и по какому правилу; его перепроверяет flang/translation/matcher.c
--runtime каталоггде лежат исходники рантайма цели
`--index-base 0\1`объявить базу индексов программы
--max-steps Nпредел шагов, записываемый в сгенерированный код
--max-depth Nпредел глубины, записываемый в сгенерированный код
--no-checkне запускать prover. Разбор, типы и завершаемость проверяются всё равно
--no-postconditionsне генерировать проверки постусловий во время работы. Доказываются они по-прежнему: ключ меняет только сгенерированный код, и его шапка об этом говорит. Предусловия, проверки завершения и пределы шагов и глубины остаются. Замеры — в flang emit --help

Генерируется только проверенная программа. Перед генерацией emit делает те же проверки, что flang check; при ошибке не пишется ни одного файла, код 1.

--no-check убирает prover и больше ничего

С --no-check разбор, имена, типы и завершаемость проверяются, и программа, не прошедшая их, всё так же не генерируется. Что меняется:

Сколько времени ключ экономит, зависит от файла: на одних файлах — в разы, на других весь круг с ключом идёт дольше, потому что лишние проверки обходятся сборке C дороже, чем prover обходится emit. Числа — в flang emit --help. На двух самых больших модулях компилятора, flang/self/distributed.flang и flang/self/bounded.flang, prover выбирает весь предел шагов, и сгенерировать их можно только с этим ключом.

Коды emit:

КодЧто значит
0сгенерировано, проверено всё
1не прошло проверку; не записано ничего
2кривой вызов: нет такой цели, нет файла, неверное значение ключа
3сгенерировано, но проверено не всё: двоичный не проверяет категорные объявления и процессы и называет, что пропустил

emit не прогоняет unit-тесты и говорит об этом; прогоните их flang test.

$ flang emit привет.flang --target c --out вывод
напечатано файлов 6, байт …, в вывод
проверено перед печатью — разбор, типы, завершаемость и ядро доказательств.
ПРИМЕРЫ НЕ ПРОГНАНЫ: их считает вычислитель на самом языке, и на самых больших
программах он в предел шагов этого бинарника не укладывается — свяжи с ними
печать, и компилятор перестал бы печатать сам себя. Прогоните их отдельно:
flang test <файл>

$ ls вывод
Makefile  flang_cli.c  flang_runtime.c  flang_runtime.h  privet.c  privet.h

Вывод говорит: записано 6 файлов; программа проверена перед генерацией; unit-тесты не прогнаны. Сгенерированная запускалка сверяет аргументы с объявленными типами так же, как flang run: на −3 для параметра неотрицательное она отвечает FLANG_TYPE. Имена файлов — имя модуля латиницей («Привет» → privet.c).

Неизвестная цель — код 2 и список целей:

$ flang emit docs/examples/cli/double.flang --target нету
flang emit: цели «нету» у этой сборки flang нет — целей здесь ДЕСЯТЬ — «c», «cpp», «go», «rust», «java», «js», «ts», «elixir», «python», «csharp».
Невтащенных целей больше нет: все десять живут в замыкании этой сборки, и
печатает их она сама, без Node.
$ echo $?
2

ast

Печатает разобранную программу с подключёнными импортами деревом JSON — ровно то, что получает генератор кода.

flang ast <файл.flang> [--pretty]
КлючЧто делает
--prettyотступ в два пробела

Типы и завершаемость здесь не проверяются: дерево показывает, что прочитано, а не что верно. Команда отказывает только на ошибках разбора и неподключённых импортах.

$ flang ast привет.flang --pretty | head -8
{
  "flang": 1,
  "module": "Привет",
  "types": [],
  "functions": [
    {
      "name": "Удвоить",
      "total": true,

tokens

Печатает поток токенов: что прочитал лексер, до разбора. Нужна, чтобы узнать, чем станет слово, если его написать. grep на это не ответит: слово в комментарии, внутри строкового литерала или внутри имени в ёлочках ключевым словом не становится никогда.

flang tokens <файл.flang> [--json] [--pretty]
flang tokens --keyword «фраза»
КлючЧто делает
--jsonJSON с теми же ключами, что у flang ast: kind, value, text, quoted и span со строкой и столбцом
--prettyJSON с отступами; включает --json сам
--keyword «фраза»ключевое ли это слово. Фраза из нескольких слов проверяется как одна фраза. Файл с этим ключом не называют

Отказывает там же, где лексер, — незакрытый литерал, рваный отступ — с кодом 1; JSON при этом печатается всё равно, с пустым tokens и заполненным diagnostics.

$ flang tokens привет.flang | head -4
1:1	слово module
1:8	ёлочка Привет
1:16	/
3:1	слово total

$ flang tokens --keyword 'элемент или беда'
«элемент или беда» — не ключевое слово языка: одним ключевым токеном лексер это не отдаёт

$ flang tokens --keyword 'код символа'
«код символа» — ключевое слово, конструкция «charCode»

Каждая строка — строка:столбец, вид токена (слово, ёлочка — имя в ёлочках) и его текст.

lint

flang lint меряет исходники flang двумя мерами и сверяет их с пределами, записанными в .flangrc:

Оба предела живут в файле настроек рядом с остальными ключами:

max-line-length = 120
max-conditional-depth = 2
lint = refuse

Ключа нет — предела нет: у проекта без этих строк находок не бывает вовсе.

Вызов

flang lint [<путь>…] [--max-line-length N] [--max-conditional-depth N]
           [--warn | --refuse] [--tsv]

Путь — файл или каталог. Каталог обходится целиком, кроме имён, начинающихся с точки; берутся файлы с пятью расширениями исходников: .flang, .fscript, .fp, .фп, .фланг. Названный файл, который не исходник flang, пропускается, и об этом сказано. Без пути обходится рабочий каталог.

Ключ командной строки старше .flangrc проекта, а файл проекта старше .flangrc в домашнем каталоге.

$ flang lint docs/examples/guide/ladder-before.flang docs/examples/guide/walk-tree.flang
docs/examples/guide/ladder-before.flang:17: глубина ветвлений 3 > 2 в «Цена доставки» (max-conditional-depth)
docs/examples/guide/walk-tree.flang:15: длина строки 206 > 120 (max-line-length)
flang lint: файлов 2; max-line-length 120: 1; max-conditional-depth 2: 1; не разобрано 0

Находка называет файл, строку, измеренное значение, предел и ключ. Последняя строка уходит в поток ошибок и считает файлы и находки.

КодЧто значит
0ничего сверх пределов, или lint = warn
1находки есть, и lint = refuse
2плохой вызов: незнакомый ключ, несуществующий путь, негодное значение в .flangrc
3сверх пределов ничего, но часть файлов не разобралась, и глубина в них не измерена

--tsv печатает по находке на строку, поля через табуляцию, без итоговой строки:

length	<путь>	<строка>	<длина>	<предел>
depth	<путь>	<строка>	<глубина>	<предел>	<функция>	<первая строка>	<последняя строка>
unparsed	<путь>
skipped	<путь>

Что считается

Длина считается в знаках, а не в байтах: «Сумма» — семь знаков. Перевод строки не считается, табуляция — один знак. Длинный строковый литерал — тоже длинная строка.

Глубина меряется по дереву разбора тела функции, а не по отступам. Каждое если и каждый разбор на пути от тела до узла прибавляет уровень, где бы он ни стоял: в условии, в ветви, в доводе вызова, в значении пусть. Глубина функции — самый глубокий такой путь, и находка указывает на строку самого глубокого ветвления.

если а
  то 1
  иначе если б
    то 2
    иначе 3

Это глубина 2: если в ветви иначе другого если стоит уровнем глубже. Лестница из пяти таких ветвей — глубина 5. Мелким код остаётся от списка правил и одного разбор, а не от лестницы.

или и и притом для линтера не ветвления, хотя дерево разбора пишет их как если. Примеры, обеспечивает, требует и теоремы не меряются: только тело.

Где грамматика даёт перенести строку

Строка переносится только там, где грамматика позволяет продолжить:

Запись, вариант с полями и цепочка вызовов не переносятся: перевод строки внутри них заканчивает выражение. Такую строку укорачивают, назвав её часть через пусть или маленькой функцией.

facts

Проверяет утверждения на данных. Утверждение имеет вид «слева оператор справа»; слева — факт, поле факта или функция от фактов, справа — то же или литерал.

flang facts <файл.flang> --claims '["…"]' [--facts факты.json] [--steps N] [--pretty]
КлючЧто делает
--claims '[…]'что проверять, JSON-массивом строк. Обязателен
--facts файлфакты JSON-объектом. Без ключа фактов нет
--steps Nпредел шагов. По умолчанию 10000
--prettyJSON с отступами

Коды: 0 — подтверждено; 1 — опровергнуто (результат всё равно уходит на стандартный вывод, а код нужен, чтобы упал CI); 2 — кривой вызов: нет файла, не разобран JSON, не подключились импорты.

В утверждении можно вызывать только функции с доказанным завершением; любая другая отвергается до вычисления.

$ cat факты.json
{"н": 21}

$ flang facts привет.flang --facts факты.json --claims '["«Удвоить» от н равно 42"]' --pretty | head -7
{
  "ok": true,
  "results": [
    {
      "claim": "«Удвоить» от н равно 42",
      "holds": true,
      "why": "«Удвоить» от факта «н» = 42; требование «равно 42» выполнено",

io

Запускает план: единственный способ, которым программа на flang работает с файлами, процессами, сетью или терминалом. Сама программа этого не делает: каждый шаг возвращает команду как данные («запиши этот файл»), рантайм её выполняет и вызывает программу снова с ответом. Поэтому все функции плана остаются чистыми и тотальными, а их unit-тестам не нужны ни файлы, ни сеть.

flang io <файл.flang> [--plan 'Имя'] [--max-orders N] [--seed N] [--in-dir]
                      [--max-steps N] [--timeout N] [--pretty] [--trust]
                      [--unproven refuse|warn|allow] [-- довод…]
КлючЧто делает
--plan 'Имя'какой план запустить, если их в файле несколько
--max-orders Nпредел команд за прогон. По умолчанию 10000
--max-steps Nпредел шагов на один шаг плана
--timeout Nсколько процесс, запущенный «Запустить процесс», может молчать, в миллисекундах, от его последнего байта в stdout или stderr. По умолчанию 30000. Дольше — рантайм его убивает и отвечает «Сбой» с FLANG_IO_TIMEOUT. 0 или не число — кривой вызов, код 2
--seed Nзерно случайности: прогон становится повторимым
--in-dirзапретить пути за пределами каталога входного файла
--prettyJSON с отступами
--trust (--на-веру)запустить план с недоказанными гарантиями; доказательства не проверяются, и об этом говорит отдельная строка
--unproven СЛОВО (--недоказанное)refuse (по умолчанию), warn, allow; раз и навсегда — ключ unproven в .flangrc
--всё после него уходит плану, а не flang io. План получает эти доводы командой «Прочитать доводы» — списком строк, по порядку

Как и run, io сначала проверяет доказательства и печатает одну строку в поток ошибок; план с недоказанными гарантиями не запускается, код 3.

Имя плана пишется без ёлочек, а имя с пробелом — в кавычках оболочки. В исходнике имена пишутся в ёлочках, но --plan берёт имя ровно как набрано, вместе с ёлочками:

$ flang io scripts/shortcut-collector.fscript --plan «Целость»
доказано: утверждений 9
{"error":"не найден план ««Целость»»","diagnostics":[{"code":"FLANG_UNKNOWN_PLAN","message":"не найден план ««Целость»»","severity":"error"}]}
$ echo $?
3
$ flang io scripts/shortcut-collector.fscript --plan Целость
доказано: утверждений 9
{"plan":"Целость","result":"коротких команд 217; …
$ echo $?
0

Без кавычек оболочки имя из двух слов оболочка разбивает на два довода:

$ flang io flang/scripts/kernel-forgeries.fscript --plan «Аксиом ноль»
flang io: непонятный ключ «ноль»»
$ echo $?
2
$ flang io flang/scripts/kernel-forgeries.fscript --plan 'Аксиом ноль' --trust
на веру: доказанность не считалась — запуск по ключу --trust
{"plan":"Аксиом ноль","result":"подделки отвергнуты: 36 файлов каталога … аксиом ноль, нарушений 0", …
$ echo $?
0

Сама справка flang io --help пишет --plan «Имя»; там ёлочки только показывают, куда ставить имя.

Права отнимаются по одному: --no-read, --no-write, --no-net, --no-clock, --no-random, --no-spawn, --no-env, --no-args, --no-screen. По умолчанию можно всё: запуская программу через flang io, вы соглашаетесь с тем, что она делает.

Ключа --args у io нет: план начинается со своей функции начинает с, а не с аргументов. Данные передавайте после --.

$ flang io docs/examples/crypto/revocation.flang --args '{}'
flang io: непонятный ключ «--args»
$ echo $?
2

Коды: 0 — план дошёл до конца; 1 — программа сдалась сама («Провал»): нашла проблему и назвала её; 2 — кривой вызов; 3 — сломался инструмент, или программа ответила «Не проверено» (проверить то, о чём просили, ей было нечем), или план не доказан, а ни --trust, ни настройка unproven его не разрешили.

Пример плана, план.flang, записывает один файл:

модуль «План»

тип «Ход»
  вариант «Пишем»
  вариант «Ждём запись»

план «Записать привет»
  состояние «Ход»
  начинает с «Начало»
  обрабатывает «Дальше»

тотальная функция «Начало»
  возвращает «Ход»
  пример «план начинается с записи»
    ожидается вариант «Пишем»
  вариант «Пишем»

тотальная функция «После записи»
  принимает отклик: «Отклик»
  возвращает «Продолжение»
  пример «записано шесть байт»
    дано отклик равно вариант «Записано» с сколько равным 6
    ожидается вариант «Конец работы» с значение равным 6
  разбор отклик
    случай вариант «Записано» с сколько как сколько
      то вариант «Конец работы» с значение равным сколько
    случай любое
      то вариант «Провал» с код равным "FLANG_IO_ORDER" и сообщение равным "ждали подтверждение записи"

тотальная функция «Дальше»
  принимает ход: «Ход», отклик: «Отклик»
  возвращает «Продолжение»
  пример «первым делом пишется файл»
    дано ход равно вариант «Пишем»
    дано отклик равно вариант «Пока ничего»
    ожидается вариант «Сделать» с поручение равным (вариант «Записать файл» с путь равным "привет.txt" и содержимое равным "привет") и потом равным (вариант «Ждём запись»)
  разбор ход
    случай вариант «Пишем»
      то вариант «Сделать» с поручение равным (вариант «Записать файл» с путь равным "привет.txt" и содержимое равным "привет") и потом равным (вариант «Ждём запись»)
    случай вариант «Ждём запись»
      то «После записи» от отклик

Вывод — результат плана и журнал: каждая команда («поручение») с ответом рантайма («отклик»):

$ flang io план.flang --pretty
доказано: утверждений 0
{
  "plan": "Записать привет",
  "result": 6,
  "orders": 1,
  "log": [
    {
      "поручение": {
        "variant": "Записать файл",
        "fields": {
          "путь": "привет.txt",
          "содержимое": "привет"
        }
      },
      "отклик": {
        "variant": "Записано",
        "fields": {
          "сколько": 6
        }
      }
    }
  ]
}

Отнимите право — и план получит отказ как ответ и сдастся с кодом 1:

$ flang io план.flang --no-write
доказано: утверждений 0
{"error":"ждали подтверждение записи","diagnostics":[{"code":"FLANG_IO_ORDER","message":"ждали подтверждение записи","severity":"error","span":{"line":7,"column":1}}]}
$ echo $?
1

Терминал. Экран — управляющий терминал (/dev/tty), и место у него одно, «экран»; любое другое имя — FLANG_IO_PLACE. «Показать» рисует кадр целиком (очистка, потом текст) в терминале, а не в stdout — в stdout идёт результат плана. На первом «Показать» рантайм переходит на запасной экран терминала и прячет курсор, а по окончании прогона возвращает оба. «Ждать событие» ждёт клавишу не дольше «срока» миллисекунд (0 или без срока — без предела): клавиша даёт «Случилось» с «откуда» равным «клавиатура», истёкший срок — «Срок вышел». Имена клавиш: ввод, пробел, таб, возврат, выход, вверх, вниз, влево, вправо; прочие приходят самим знаком. Ctrl-C по-прежнему останавливает программу. «Размер экрана» отдаёт ширину и высоту в знаках. Без терминала (вывод в трубу, CI, nohup) эти команды отвечают FLANG_IO_NO_SCREEN; с --no-screen — FLANG_IO_DENIED.

HTTPS. Команда «Запросить» поддерживает https. В исходниках рантайма её исполняет клиент TLS 1.3 на языке (flang/stdlib/tls-client.flang), напечатанный в C и собранный в двоичный; двоичный, напечатанный до этой правки, ходит через внешний curl и без него отвечает FLANG_IO_NO_TLS (ADR-0101). Клиент проверяет цепочку до корня, срок, имя узла и подпись узла; беда сертификата — FLANG_IO_TLS_CERT, прочая — FLANG_IO_TLS. Корни — --trust-roots <файл PEM> или системная связка. Отзыв сертификата (OCSP, CRL) не проверяется. «Открыть соединение» — голый TCP.

Датаграммы. «Отправить датаграмму» и «Принять датаграмму» — UDP поверх IPv4, октеты списком чисел; ответ — «Записано», «Датаграмма» или «Срок вышел».

lock

Печатает lock-файл программы: JSON, в котором лежат сами зависимости, а не ссылки на них. Для каждого подключённого модуля записан весь его исходник, и адрес ему — sha256 этого исходника. Реестра нет и скачивать нечего: всё уже в lock-файле.

flang lock <файл.flang> [--pretty]
КлючЧто делает
--prettyотступ в два пробела

Если рядом с входным файлом лежит flang.lock, все команды берут импорты из него и исходников зависимостей не читают. Испорченный lock-файл отвергается с FLANG_LOCK.

$ flang lock docs/examples/cli/double.flang
{"схема":2,"вход":"./double.flang","модули":[],"печать":"dcf9b0c54a6a814573047949d66a78d7e4706c67ae8873e637823fa799609779"}

double.flang ничего не подключает, поэтому список модулей («модули») пуст.

package

Печатает пакет: то же содержимое, что у lock-файла, плюс имя, версия, источник и список доказанного.

flang package <файл.flang> [--pretty]
КлючЧто делает
--prettyотступ в два пробела

Имя и версия берутся из файла flang.package рядом с входным файлом, а не из ключей. Без него команда отказывает с кодом 1:

$ flang package привет.flang
FLANG_PACKAGE: рядом с привет.flang нет объявления flang.package: пакету нужны имя и версия, и берутся они оттуда, а не из вызова
$ echo $?
1

С flang.package рядом пакет собирается:

$ cat flang.package
{"имя": "Привет", "версия": "1.0.0"}

$ flang package привет.flang | head -c 400
{"схема":2,"имя":"Привет","версия":"1.0.0","вход":"./привет.flang","модули":[{"имя":"Привет","путь":"./привет.flang","функций":1,"адрес":"2bc2186046bc075d03953d3ff11c333835b8561a724dc526bb95c91730fe0699","исходник":"module «Привет»\n\ntotal function «Удвоить»\n  accepts н: number\n  returns number\n  examp

Пакет собирается только из проверенной программы. Как им пользоваться — Как писать пакеты.

new

Заводит каталог с готовым пакетом: модуль с одной тотальной функцией и unit-тестом, каталог fspec/ с одной доказанной спекой и программой проверки guard.flang, манифест flang.package и README.

flang new <имя> [--force]
КлючЧто делает
--force (--силой)переписать каталог, если он уже есть
$ flang new проба-cli
flang new: пакет «проба-cli» создан в …/проба-cli
  cd проба-cli && flang check проба-cli.flang
  flang io fspec/guard.flang
$ ls проба-cli
README.md  flang.package  fspec  проба-cli.flang

Существующий каталог без --force — код 1; имя с пробелом, косой чертой, кавычками или ёлочками либо занятое слово (имя команды, flang, fspec) — код 2, и не создаётся ни одного файла.

run-script

flang run-script [<имя> [доводы…]]

Короткая команда проекта — имя для строки оболочки. Записывается в файле настроек .flangrc как script.<имя> = <команда>, как scripts в package.json:

script.site:build = node docs/site/build.mjs

Без имени flang run-script перечисляет короткие команды проекта; с именем — запускает эту, и всё после имени уходит команде. В каталоге, где .flangrc состоит из двух показанных строк:

$ cat .flangrc
script.hello = echo hello
script.fail = exit 7

$ flang run-script hello
hello
$ echo $?
0

$ flang run-script fail
$ echo $?
7

$ flang run-script missing
flang run-script: короткой команды «missing» в «…/.flangrc» нет. Вот какие есть:

  hello                              echo hello
  fail                               exit 7
$ echo $?
2

Файл — ближайший .flangrc от текущего каталога вверх; файл в домашнем каталоге коротких команд не задаёт. Строка исполняется /bin/sh -c в каталоге этого файла, и код возврата — её собственный. Если имя записано дважды, берётся последняя строка. В строке из нескольких команд через && доводы достаются последней.

Код возвратаКогда
собственный код командыкоманда запустилась
2такого имени нет, или нет .flangrc
3файл не прочитался, или не запустился /bin/sh

Ключи самого двоичного --depth-limit и --step-limit двоичный забирает до имени, и команде они не достаются.

repl

Интерактивная оболочка — то же, что голый flang в терминале. Объявления накапливаются за сессию, выражения вычисляются сразу, .помощь показывает команды оболочки. Файл в доводе загружается при запуске.

flang repl [<файл.flang>] [--max-steps N] [--max-depth N]
КлючЧто делает
--max-steps Nпредел шагов вычислителя
--max-depth Nпредел глубины

Выражение вычисляется так: для сессии генерируется C (как у flang emit), собирается системным компилятором C и запускается:

$ echo '«Удвоить» от 21' | flang repl привет.flang
объявлено: тотальная функция «Удвоить» — завершение доказано
загружено из привет.flang
42

Без компилятора C оболочка работает всё равно: проверяет разбор, типы и завершаемость и вместо значения отвечает «проверено», о чём говорит при запуске:

$ echo '«Удвоить» от 21' | FLANG_CC=/nonexistent/cc flang repl привет.flang
вычислять нечем: компилятора C нет (ни $FLANG_CC, ни cc, ни gcc, ни clang в PATH).
Разбор, типы и завершаемость проверяются по-прежнему; выражение отвечает «проверено».
объявлено: тотальная функция «Удвоить» — завершение доказано
загружено из привет.flang
проверено

Компилятор C и его файлы ищутся через FLANG_CC, FLANG_INCLUDE_DIR и FLANG_LIB_DIR.

lsp

Языковой сервер flang по стандартному вводу и выводу (рамки Content-Length с телом JSON, как требует спецификация LSP). Его запускает редактор; запущенный вручную, он молча ждёт сообщений.

flang lsp [--stdio]
КлючЧто делает
--stdioобщаться через стандартный ввод и вывод

Умеет: диагностику (те же проверки, что flang check: разбор, имена, типы, завершаемость), дополнение, подсказку с сигнатурой при наведении и переход к объявлению. На стандартный вывод идут только сообщения протокола, всё прочее — в поток ошибок.

Проверить, что сервер работает, — послать ему одно сообщение:

$ printf 'Content-Length: 107\r\n\r\n{"jsonrpc":"2.0","id":1,"method":"initialize","params":{"processId":null,"rootUri":null,"capabilities":{}}}' | flang lsp --stdio
Content-Length: 311

{"jsonrpc":"2.0","id":1,"result":{"capabilities":{"positionEncoding":"utf-16","textDocumentSync":{"openClose":true,"change":1,"save":{"includeText":false}},"completionProvider":{"triggerCharacters":["«","."]},"hoverProvider":true,"definitionProvider":true},"serverInfo":{"name":"flang-lsp","version":"0.1.0"}}}

Известное ограничение: в программе с использует (импорт) ошибка в подключённом модуле уходит в журнал редактора, а не подчёркивается в буфере этого модуля.

Справка двоичного целиком

Ниже — то, что печатает сам двоичный: flang --help и flang <команда> --help по каждой команде. Текст вставлен из вывода при сборке страницы и сверяется с ним на каждой проверке, поэтому расходиться с двоичным не может. Двоичный говорит по-русски.

$ flang --help
flang 0.7.29 — язык, проверяемый до запуска: типы и доказанное завершение.

  flang                              оболочка: объявляй и считай сразу
  flang check <файл>                 разбор, типы, завершаемость, доказательства
  flang test <файл|каталог>          прогон примеров: один файл или целый каталог
  flang run <файл> --function «Имя»  вычислить одну функцию и напечатать значение
  flang emit <файл> --target «цель»  напечатать программу: c|cpp|go|rust|java|js|ts|elixir|python|csharp
  flang ast <файл>                   разобранная программа деревом в JSON
  flang tokens <файл>                поток токенов: чем каждое слово стало у лексера
  flang lint [<путь>…]               длина строк и глубина ветвлений против «.flangrc»
  flang facts <файл> --claims '[…]'  проверить утверждения на фактах
  flang io <файл>                    исполнить план: файлы, каталоги, процессы, сеть
  flang lock <файл>                  замок: сами зависимости, а не ссылки на них
  flang package <файл>               пакет: замок с именем, версией и ведомостью
  flang new <имя>                    новый пакет с нуля: модуль, fspec/, манифест
  flang run-script <имя>             короткая команда проекта из «.flangrc»
  flang repl [файл]                  та же оболочка, названная по имени
  flang lsp [--stdio]                языковой сервер для редактора (LSP)
  flang --mcp-mode                   служба для ИИ-помощника (MCP по стандартным потокам)

  flang --help                       эта справка
  flang --version                    версия
  flang --machine [<файл>]           постоянная этой машины: витков в секунду
  flang <команда> --help             все ключи команды

  --depth-limit N                    предел глубины вызовов САМОГО бинарника
                                     на этот прогон; годится при любой команде
                                     и поднимает заодно стек. Кириллицей:
                                     --предел-глубины
  --step-limit N                     предел ШАГОВ самого бинарника на этот
                                     прогон; годится при любой команде, печать
                                     включая. НЕ путать с «--max-steps N» у
                                     «emit»: тот впечатывается в вывод и своему
                                     прогону не говорит ничего. Кириллицей:
                                     --предел-шагов
  --memory-limit N                   предел ПАМЯТИ самого бинарника на этот
                                     прогон, байтами или с буквой K, M, G, T;
                                     0 — без предела. У check, test и run по
                                     умолчанию три четверти памяти машины. На
                                     пределе — остановка кодом 5 с именем
                                     функции и числом шагов. Кириллицей:
                                     --предел-памяти

Без доводов и без терминала на входе (конвейер, «--json») бинарник остаётся
прогонщиком: JSON на входе, JSON на выходе, по запросу на строку.

Здесь все 15 команд, и «flang lsp» среди них; отдельная команда «flang-lsp» —
тот же языковой сервер, который кладёт на «PATH» пакет npm.
Служба для ИИ-помощника отвечает НЕ «ок»: три вердикта — «доказано», «сетка N»
и «объявлено, не доказано» — уходят порознь. «flang --mcp-mode --help» — как её
прописать помощнику.
Чего бинарник не судит — ЗАКОНЫ КАТЕГОРИИ бинарник СЧИТАЕТ САМ — на сетке, с названным числом
значений: что объявленное равенство есть эквивалентность, что композиция
его уважает, что она ассоциативна и что квадрат естественного
преобразования коммутирует. Это счёт, а не доказательство, и отчёт говорит
об этом словами.

ЧЕГО НЕТ — УСТРОЙСТВО тех же объявлений: что категория замкнута под
композицией, что у каждого объекта есть единица, что концы у композиции
сходятся, что морфизм и преобразование объявлены как надо. Целиком нет
этих: связь модулей, бифунктор, изоморфизм, моноид, монада, множества,
объявленные свойства, требования, процесс, надзор, прогон.
Программу с такими объявлениями «flang check» НЕ пропускает молча: он
называет, чего не проверил, и отвечает кодом 2.

Подробности: man flang

flang check --help

$ flang check --help
flang check <файл.flang> [--proof [--json] [--strict] [--record <файл>]]
                          [--fast] [--step-limit N] [--depth-limit N]

Разбор, типы, завершаемость, ядро доказательства. Замечания с кодом и местом,
код возврата 1, если программа не прошла.

  --fast             только связывание, типы, исчерпываемость и
                     завершаемость. Ядро доказательств, законы категории и
                     прогон примеров НЕ ЗАПУСКАЮТСЯ, и об этом говорится
                     вслух: что пропущено, сколько обязательств и сколько
                     примеров не смотрели. Код возврата 4 — «часть проверок
                     не запускалась»; ноль остаётся за «спрошено всё».
                     Рядом с «--proof» не имеет смысла и отвергается:
                     ведомость — это ответ ядра. Кириллицей: --быстро
  --proof            ведомость: чем несётся обещание «тотальная» у каждой
                     функции и чем — каждое высказанное утверждение
  --json             вместе с --proof: ведомость машинным видом
  --strict           вместе с --proof: четыре исхода разъезжаются кодами.
                     0 — ДОКАЗАНО: утверждений хотя бы одно и у КАЖДОГО
                     вердикт «доказано»; 1 — ОПРОВЕРГНУТО; 3 — НЕ УДАЛОСЬ
                     ДОКАЗАТЬ (опора на сетку значений автора, на
                     недоказанную посылку или «объявлено, не доказано»);
                     2 — НЕ ПОДДЕРЖИВАЕТСЯ. Код 4 остаётся за «--fast».
                     Без ключа опора остаётся нулём и называется строкой.
                     Кириллицей: --строго
  --record <файл>    вместе с --proof: положить САМО доказательство в файл
                     строками, которые читает и человек, и сверщик
                     (flang/proof/checker.flang). Ключ пишется и кириллицей:
                     --записать
  --step-limit N     ключ САМОГО бинарника (стоит где угодно в строке) —
                     поднять предел шагов ПРОВЕРЯЮЩЕГО на этот прогон.
                     Умолчание вшито при сборке (scripts/bootstrap-reprint.sh) и
                     ловит зацикливание; ключ поднимает его осознанно и
                     только там, где сказано. Исчерпание остаётся внятным:
                     FLANG_RECURSION_LIMIT с числом. Кириллицей: --предел-шагов
  --depth-limit N    поднять предел ГЛУБИНЫ вызовов на этот прогон. Ключ
                     общий у всех команд бинарника и поднимает заодно стек,
                     которым глубина и несётся. Не путать с «--max-depth» у
                     «emit»: тот кладёт число в НАПЕЧАТАННУЮ программу, а
                     этот — в текущий прогон. Кириллицей: --предел-глубины
  --memory-limit N   предел памяти прогона (умолчание — три четверти памяти
                     машины); на пределе — код 5 с именем функции и числом
                     шагов. Кириллицей: --предел-памяти

ПУСТАЯ ВЕДОМОСТЬ ПОД «--strict» — НЕ УСПЕХ. Ноль под ключом требует хотя бы
одного обязательства: у программы без единого утверждения и закона прибор не
проверил ничего, и ответ ей — ПРОВЕРЕНО ВПУСТУЮ, код 3. «Доказано ноль из
нуля» — тишина, а не доказательство, и код 0 значил бы «ничего не нашли».
Умолчание тут не тронуто: без ключа такая программа по-прежнему ноль.

Категорной поверхности и процессов бинарник НЕ СУДИТ ВОВСЕ — ни доказуемых
правил (концы стрелок, замкнутость категории, полнота связи), ни законов на
сетке (моноид, монада, изоморфизм, равенство морфизмов, множества, квадрат
связи, пять объявленных свойств), ни процессов, надзора и прогонов. Слоёв,
которые это делают, в бинарнике нет. Поэтому программа с такими объявлениями
получает отказ с названным пробелом и код 2 — и у check, и у --proof:
«замечаний нет» и пустой раздел ведомости читались бы как «проверено», а это
неправда. Поиск нарушений по примерам тоже не переехал: ведомость говорит «не
искали», а не «не найдено». Печать такую программу ПЕЧАТАЕТ, но называет тот же
пробел и уходит кодом 3: файлы есть, ручаться за них целиком нельзя.

ДВА ЗАЗОРА, которые бинарник не умеет даже НАЗВАТЬ, и потому названы здесь.
Уточнённые числовые типы («сотых», «вес») стоят типом в подписи, а не
отдельной строкой: программу с ними от обычной по объявлениям не отличить, и
check на ней отвечает «замечаний нет». Мост из FTS («.fts»-модели, законы
поверх них) бинарник не принимает вовсе.

Полный список правил, которых здесь нет, — не в этой справке, а в проверке:
flang/scripts/binary-rules-guard.mjs сверяет СОСТАВ ПРАВИЛ двух реализаций в
обе стороны, и правило, дописанное одной из них, красит её само.

flang test --help

$ flang test --help
flang test <файл.flang | каталог | маска> [--no-check] [--json]
                                          [--max-steps N] [--max-depth N]

Прогон примеров, объявленных внутри функций. Сначала проверяет программу теми
же проверками, что и check: «пример сошёлся» на программе с ошибкой типов не
значит ничего.

Довод, не кончающийся на «.flang», и всякий довод со звездой или вопросом —
это НАБОР файлов, а не один файл:

  flang test flang/stdlib/                весь каталог, вглубь
  flang test 'examples/**/*.flang'  по маске (кавычки — от оболочки)

У набора печатается каждый не прошедший пример и каждый не взятый файл, а
прошедшие — числом. Код возврата 0 — взяты все файлы и сошлись все примеры;
1 — что-то не сошлось или файл не взят; 2 — кривой вызов.

  --no-check      не проверять — смотреть на поведение примеров, пока
                  программа ещё в правке
  --json          машиночитаемый итог одной строкой
  --ledger        ведомость: по строке на файл, для сверки диффом
  --max-steps N   предел шагов вычислителя
  --max-depth N   предел глубины
  --memory-limit N  предел памяти прогона (умолчание — три четверти памяти
                  машины); на пределе — код 5 с именем функции и числом шагов.
                  Кириллицей: --предел-памяти

У не сошедшегося примера называются ОБЕ стороны: ожидалось и получено.
Длинное значение обрезается на 200 знаках, и длина полного сказана числом.

Примеры, объявленные при морфизмах теорката, здесь не прогоняются: их считает
версия для Node. На таких программах счёт «примеров N» окажется меньше её.

flang run --help

$ flang run --help
flang run <файл.flang> --function «Имя» [--args '{"н":10}'] [--max-steps N]
                       [--max-depth N] [--trust] [--unproven refuse|warn|allow]
                       [--cost]

Вычисляет ОДНУ функцию и печатает значение. Считает сам flang — ни Node, ни
«cc» для этого не нужны.

Аргументы сверяются объявленным типам ДО вычисления: «Факториал» от −3
отвергается FLANG_TYPE, а не считается.

ПЕРЕД ВЫЧИСЛЕНИЕМ СЧИТАЕТСЯ ВЕРДИКТ и одной строкой уходит в поток ошибок:
«доказано: утверждений N» либо «не доказано: …». Судится ЗАМЫКАНИЕ — всё,
что связано, а не один файл. Недоказанная программа не считается вовсе:
код 3 (ADR-0045). Запустить её всё же — «--trust» на один прогон либо ключ
«unproven» в «.flangrc» — раз и навсегда.

  --function «Имя»   что вычислять
  --args '{…}'       аргументы: ПЛОСКИЙ объект скаляров, вроде '{"н":10}'.
                     Списка или вложенного объекта здесь не принимают —
                     их считает версия для Node
  --max-steps N      предел шагов вычислителя
  --max-depth N      предел глубины ВЫЧИСЛЯЕМОЙ программы. Предел самого
                     бинарника — другой счётчик и другой ключ:
                     «--depth-limit N»
  --memory-limit N   предел памяти прогона (умолчание — три четверти памяти
                     машины); на пределе — код 5 с именем функции и числом
                     шагов. Кириллицей: --предел-памяти
  --cost             после значения одной строкой в поток ошибок: шагов
                     вычислителя (тот же счётчик, что у «--max-steps»), пик
                     памяти процесса в байтах и секунды всего прогона.
                     Кириллицей — «--цена»
  --trust            считать недоказанную: вердикт не считается вовсе, и об
                     этом говорится своей строкой. Кириллицей — «--на-веру»
  --unproven СЛОВО   что делать с недоказанной, все три исхода сразу:
                     refuse — не запускать (умолчание), warn — сказать и
                     запустить, allow — запустить, вердикта не считая (то же,
                     что «--trust»). Кириллицей — «--недоказанное отказ |
                     предупреждение | разрешение»

ТО ЖЕ РАЗ И НАВСЕГДА — ключ «unproven» в «.flangrc»
(docs/guide/settings.ru.md): «unproven = warn». Старшинство: ключ команды
старше переменной среды FLANG_UNPROVEN, та старше «.flangrc», а он —
умолчания «refuse». Значения, которого нет, файл молча не проглатывает:
отказ словами и код 2. Запись до 0.7.22, «недоказанное = отказ», читается
по-прежнему, и одной строкой сказано, какой английской её заменить.

flang emit --help

$ flang emit --help
flang emit <файл.flang> --target c|cpp|go|rust|java|js|ts|elixir|python|csharp
                        [--out каталог | --file имя] [--cli|--no-cli] [--repl]
                        [--runtime каталог] [--index-base 0|1]
                        [--max-steps N] [--max-depth N] [--no-check]
                        [--no-postconditions]

Печатает программу без Node — во все десять целей. Каталог из «--out»
заводится сам, вместе с промежуточными и с подкаталогами, которых просит цель
(у Go путь файла — это имя пакета).

  --out каталог     записать все файлы в каталог
  --protocol файл   рядом с C напечатать протокол перевода (только у цели «c»,
                    ADR-0030): что во что перешло и по какому правилу; его
                    переигрывает flang/translation/matcher.c. Кириллицей —
                    --протокол
  --file имя        один файл на стандартный вывод
  --cli | --no-cli  печатать ли прогонщик
  --repl            напечатать ещё и человеческий вход (только цель «c»)
  --runtime каталог где лежат исходники рантайма цели
  --max-steps N     предел шагов, ВПЕЧАТЫВАЕМЫЙ в напечатанную программу
                    («#define FL_MAX_STEPS»). Своему прогону печати он не
                    говорит ничего — для него «--step-limit N»
  --max-depth N     предел глубины, ВПЕЧАТЫВАЕМЫЙ в напечатанную программу
                    («#define FL_MAX_DEPTH»). Своему прогону печати он не
                    говорит ничего — для него «--depth-limit N»
  --no-check        не гонять ядро доказательств. Насколько быстрее —
                    зависит от модуля, и РАЗНИЦА ОГРОМНА: числа ниже.
                    Напечатанное толще. ЧТО ЭТИМ НЕЛЬЗЯ — ниже, отдельным
                    абзацем: в ствол напечатанное так НЕ ГОДИТСЯ
  --no-postconditions  не печатать сторожей постусловий В КОД. Судятся они
                    по-прежнему: это ключ печати, а не проверки. Напечатанное
                    заметно быстрее и говорит о ключе своей шапкой — числа и
                    условия ниже, отдельным абзацем


ПЕЧАТАЕТСЯ ТОЛЬКО ПРОВЕРЕННОЕ. Перед печатью программа судится той же дорогой,
что и «flang check»: разбор, связывание, типы, завершаемость и ядро
доказательств. Замечание — печать отменена и код 1, ни файла не записано.
ЧЕГО ЭТА СБОРКА НЕ СУДИТ, она называет. Категорную поверхность и процессы с
надзором она не судит вовсе. Такая программа ПЕЧАТАЕТСЯ — иначе эту часть языка
нечем было бы собрать без Node, — но несуждённое зовётся поимённо, а код 3.
Коды: 0 напечатано и пробелов нет, 1 не прошло проверку, 2 неверен вызов,
3 напечатано, но проверено не всё.
ПРИМЕРЫ не прогоняются, и это названо, а не умолчано: их считает вычислитель на
самом языке, и на самых больших программах дерева он в предел шагов этой сборки
не укладывается — свяжи с ними печать, и компилятор перестал бы печатать сам
себя, то есть сломалась бы раскрутка. Прогоняются они «flang test <файл>».
«--no-check» СНИМАЕТ РОВНО ЯДРО ДОКАЗАТЕЛЬСТВ, и больше ничего. Разбор,
связывание, типы и завершаемость судятся и с ним, и печать при замечании
по-прежнему отменяется кодом 1. Имя ключа шире его дела: написание занято у
«flang test» и у версии для Node, и второе заводить не стали — потому дело и
названо здесь, а не оставлено на догадку.
СКОЛЬКО ОН ЭКОНОМИТ — ЧИСЛО НЕ ОДНО, и разброс больше самой экономии;
«вдвое» неправда в обе стороны. Замер 30 августа 2026 на этом дереве, круг
«печать + сборка», по два прогона:
  flang/self/builtins.flang   148,8 → 18,9 с   в 7,9 раза быстрее
  flang/self/cli.flang         13,1 →  7,5 с   в 1,8 раза
  flang/self/lexer.flang        6,5 →  6,9 с   КЛЮЧ ВРЕДИТ
Цена ядра растёт с числом ДОКАЗЫВАЕМЫХ постусловий, а не с размером файла:
у lexer.flang ядро стоит 4 % печати, у builtins.flang — 95 %. А сборка с
ключом идёт ДОЛЬШЕ, потому что сторожей в напечатанном больше. Где ядро
дёшево, ключ проигрывает — не берите его по привычке, померьте.
ОТДЕЛЬНЫЙ СЛУЧАЙ — где ядру не хватает миллиарда шагов: distributed.flang и
bounded.flang без ключа не печатаются ВОВСЕ («ядро доказательства
прекращено» через 110 с), с ключом печатаются за 4,4 с.
ЧЕГО ОН НЕ ДАЁТ — а это важнее того, что даёт:
  * НАПЕЧАТАННОЕ ЭТИМ КЛЮЧОМ НЕ ГОДИТСЯ В СТВОЛ. Отпечаток семени не сойдётся
    («scripts/seed-fingerprint»), а собранный из такого семени двоичный толще
    и поведёт СЛЕДУЮЩУЮ печать медленнее — то есть беда переезжает дальше
    самого семени. Перепечатка семени идёт БЕЗ этого ключа, всегда;
  * доказательств никто не проверял. Ложное доказательство ядро ловит, а без
    ядра оно проходит молча — прогоните «flang check», прежде чем верить;
  * быстрее становится ПЕЧАТЬ, а не напечатанное. Постусловия уезжают в код
    все до одного, включая доказанные, которые печать с ядром снимает: список
    снимаемых считает то самое ядро. Напечатанное толще и на работе медленнее
    (замер: сторожей на «flang/stdlib/lists.flang» 67 против 29), но не
    слабее — лишний сторож стережёт то, что и так верно.
Это средство разработчика, а не замена перепечатке. Двоичный говорит всё то же
самое ВСЛУХ после каждой печати с ключом, чтобы ключ, уехавший в скопированный
рецепт, не стал привычкой за день.

«--no-postconditions» СНИМАЕТ СТОРОЖЕЙ В НАПЕЧАТАННОМ КОДЕ, А НЕ ПРОВЕРКУ.
Постусловие остаётся в исходнике, остаётся обещанием и судится этой же
командой: разбор, типы, завершаемость и ядро доказательств идут как обычно, и
замечание по-прежнему отменяет печать кодом 1. «flang check» и «flang test»
ключа не знают вовсе — они считают постусловия ВСЕГДА.
ЗАЧЕМ. Постусловие пересчитывается на КАЖДОМ возврате. Замер 2 сентября 2026,
раскладка терминального экрана (19 функций, 25 обещаний, цель go, кадр целиком,
«go test -benchtime 200x -count 5», медиана пяти, AMD EPYC 7742):
  кадр  80×24     42,6 мс со сторожами →  6,00 мс без них   в 7,1 раза
  кадр 200×50    100,0 мс              → 14,6 мс            в 6,9 раза
  выделений на кадре 200×50: 151 226 → 29 354
  напечатанного кода на Go: 1862 строки → 1303, сторожей rt.Post 23 → 0
Кадр перерисовывается не только по такту, но и на каждое нажатие клавиши и на
каждый SIGWINCH; 15 мс не видно, 100 мс видно. На программе, которую зовут раз
в час, ключ не нужен — померьте, прежде чем брать.
СВЕРЕНО, ЧТО СНЯТИЕ НЕ МЕНЯЕТ ЗНАЧЕНИЙ: 1119 входов на трёх функциях той же
раскладки, печать с ключом против печати без него — расхождений нет. И то, что
печатает ключ, совпало БАЙТ В БАЙТ с печатью исходника, из которого строки
«обеспечивает» вырезаны руками.
ВСЕ ВОСЕМЬ ЦЕЛЕЙ ВЕДУТ СЕБЯ ОДИНАКОВО: постусловия снимаются с разобранной
программы до того места, где цели расходятся, — печатнику про ключ знать
нечего.
НАПЕЧАТАННОЕ ГОВОРИТ О КЛЮЧЕ САМО. В шапку каждого файла кладётся заметка:
ключ, число снятых сторожей и то, что обещания проверяются на воротах, а не
здесь. Молча отдать облегчённый код нельзя — тот, кто взял его в руки, обязан
узнать об этом из него. Без заметки остаются два файла, где её негде
поставить: «go.mod» (шапки нет вовсе) и «flang.csproj» (XML-комментарий не
терпит двух дефисов подряд, а имя ключа их содержит).
ЧЕГО КЛЮЧ НЕ СНИМАЕТ: предусловия, сторожа убывания у тотальных функций,
пределы шагов и глубины, разбор отказов надзора.
ПЕРЕПЕЧАТКОЙ СЕМЕНИ ЭТО НЕ ПОЛЬЗУЮТСЯ: компилятор собирают со сторожами,
довод тот же, что у «--no-check».

РАНТАЙМ ЦЕЛИ уезжает в вывод ДОСЛОВНО, поэтому читается с диска: от двух
файлов у go, rust, js и python до шести у java и csharp, у cpp четыре (три
из них рантайм «c»). Ищутся они в
«--runtime», затем в $FLANG_RUNTIME_DIR, затем рядом с установленным flang
(share/flang/<цель>); в дереве исходников это flang/src/emit/<цель>. Полный
перечень имён — man flang.

СВЕРХУ УЖЕ СКАЗАНО, ЧТО ПЕЧАТАЕТСЯ ТОЛЬКО ПРОВЕРЕННОЕ, и это правда: типы и
завершаемость печать судит и при замечании отменяется. Проверено прогоном
25 августа 2026: функция, объявленная как «число», с телом-строкой даёт
FLANG_TYPE, «печать отменена», код 1 и ни одного файла.

ЧЕМ ЭТА ПЕЧАТЬ ОТЛИЧАЕТСЯ ОТ ПЕЧАТИ ПОЛНОГО ИНСТРУМЕНТАРИЯ:
  c            недостижимое НЕ отбрасывается, доказанное не метится
               («markProven»); напечатанного просто больше, работает так же;
  все прочие   недостижимое отбрасывается, как у свидетеля.

У ВСЕХ ДЕВЯТИ ПУСТА ГРАНИЦА ВХОДА: таблицу объявленных типов строит слой
типов свидетеля, которого на flang нет ни строки. Напечатанное собирается и
работает, но аргументы прогонщика объявленным типам не сверяются, и об этом
сказано словами после печати.

Невтащенных целей больше нет: все десять живут в замыкании этой сборки, и
печатает их она сама, без Node.

flang ast --help

$ flang ast --help
flang ast <файл.flang> [--pretty]

Печатает разобранную и СВЯЗАННУЮ программу деревом в JSON — то же самое, что
видит печать в целевой язык. Связывание здесь не украшение: без него у
программы с «использует … из "…"» дерево вышло бы неполным, и первым признаком
стала бы не ошибка команды, а несобирающийся напечатанный код.

  --pretty   с отступами в два пробела

Проверок типов и завершаемости здесь нет НАМЕРЕННО: дерево — это то, что
прочитано, а не то, что признано годным. Отказывает команда только на том, из
чего дерева не выходит вовсе, — на разборе и на связывании.

flang tokens --help

$ flang tokens --help
flang tokens <файл.flang> [--json] [--pretty]
flang tokens --keyword «фраза»

Печатает поток токенов — то, что прочитал ЛЕКСЕР, до разбора и до связывания.
Вопрос, ради которого команда есть, один: чем станет это слово, если его
написать. Грепом он не решается — ломает программу не текст, а токен: слово в
комментарии, слово внутри строкового литерала и имя в ёлочках ключевым словом
не становятся никогда.

  --json      машинный вид: те же ключи, что у «flang ast» — kind, value, text,
              quoted и span со строкой и столбцом
  --pretty    с отступами в два пробела; машинный вид включает сам
  --keyword «фраза»   ключевое ли это слово: имя конструкции или отказ. Фраза
              из нескольких слов проверяется как фраза — «код символа» лексер
              отдаёт ОДНИМ токеном, а «элемент или беда» тремя, и формой языка
              вторая не является

Связывания здесь нет, в отличие от «flang ast»: токены файла от подключений не
зависят вовсе. Отказ бывает там же, где отказал сам лексер, — незакрытый
литерал, рваный отступ; тогда код 1, а машинный вид всё равно печатается, с
пустым tokens и заполненным diagnostics.

flang lint --help

$ flang lint --help
flang lint [<путь>…] [--max-line-length N] [--max-conditional-depth N]
                     [--warn | --refuse] [--tsv]

Меряет исходники и планы flang двумя мерами: длину строки в знаках и
глубину ветвлений в теле функции. Каталог обходится целиком, кроме имён с
точкой в начале; без путей — рабочий каталог. Файл не исходник — пропущен.

  --max-line-length N        предел длины строки в знаках
  --max-conditional-depth N  предел глубины: сколько «если» и «разбор»
                             вложено друг в друга в теле функции
  --warn                     назвать нарушения и ответить нулём
  --refuse                   назвать нарушения и ответить единицей
  --tsv                      машинный вид: строка на находку, поля через
                             табуляцию, без итоговой строки

Те же пределы — ключи «.flangrc»: max-line-length, max-conditional-depth и
lint = refuse|warn. Ключ команды старше файла проекта, файл проекта старше
файла дома. Предела нет нигде — мера не применяется.

Коды: 0 — нарушений нет или сказано «warn»; 1 — нарушения есть; 2 — плохой
вызов, нет пути или негодное значение в «.flangrc»; 3 — нарушений нет, но
часть файлов не разобралась, и глубина в них не измерена.

flang facts --help

$ flang facts --help
flang facts <файл.flang> --claims '["…"]' [--facts факты.json] [--steps N] [--pretty]

Проверяет утверждения на фактах — то, ради чего язык написан. Утверждение
имеет вид «<что-то> <оператор> <что-то>»; слева бывает факт, поле факта или
вызов функции от фактов, справа — то же самое или литерал.

  --facts файл    факты JSON-объектом (без ключа — фактов нет)
  --claims '[…]'  что проверять, JSON-массивом строк
  --steps N       предел шагов вычисления (по умолчанию 10000)
  --pretty        JSON с отступами

КОД 1 ЗДЕСЬ ЗНАЧИТ «ОПРОВЕРГНУТО», а не «сломалось»: вердикт всё равно уходит
в stdout, и код нужен, чтобы на нём падал CI. Код 2 — отказ вызова: не назван
файл, не разобран JSON, не связалась программа.

Вызов зовётся ТОЛЬКО у функции, чьё завершение доказано: нетотальная даёт
отказ до всякого вычисления. Упирание в предел шагов — тоже ответ, «не
досчитали за отведённый бюджет», а не сбой инструмента.

flang io --help

$ flang io --help
flang io <файл.flang> [--plan «Имя»] [--max-orders N] [--seed N] [--in-dir] [--pretty]
                      [--timeout МС] [--trust] [--unproven refuse|warn|allow] [-- довод…]

Исполняет ПЛАН — единственное место языка, где программа встречается с миром.
Встречается не сама: каждый шаг возвращает ОПИСАНИЕ действия, а делает его
хозяин. Поэтому все функции плана остаются тотальными и проверяются обычными
примерами — без файлов и без сети.

  --plan «Имя»    какой план исполнять, если их несколько
  --max-orders N  предел поручений за прогон (по умолчанию 10000)
  --seed N        семя случайности: прогон становится повторимым.
                  «Случайное число» без семени берёт /dev/urandom;
                  «Случайные октеты» берут его всегда, а под семенем
                  отказывают кодом FLANG_IO_ENTROPY
  --in-dir        запретить пути за пределы каталога входного файла
  --trust-roots Ф связка корней PEM для «https»; без ключа — системная
  --max-steps N   предел шагов вычисления на один виток
  --timeout МС    срок ТИШИНЫ процесса из «Запустить процесс», миллисекундами
                  (по умолчанию 30000): отсчёт от последнего байта в stdout
                  или stderr, а не от запуска. Молчит дольше — хозяин убивает
                  его и отвечает «Сбой» с кодом FLANG_IO_TIMEOUT. Свой срок
                  плана (поручение «Запустить процесс с пределом»)
                  этого срока НЕ отменяет: ждут оба, бьёт тот, что раньше
  --pretty        JSON с отступами
  --trust         исполнить недоказанный план: вердикт не считается вовсе, и
                  об этом говорится своей строкой. Кириллицей — «--на-веру»
  --unproven СЛОВО  что делать с недоказанным: refuse — не исполнять
                  (умолчание), warn — сказать и исполнить, allow — то же, что
                  «--trust». Кириллицей — «--недоказанное отказ |
                  предупреждение | разрешение». Раз и навсегда — ключ
                  «unproven» в «.flangrc» (docs/guide/settings.ru.md)
  --              ГРАНИЦА: всё, что стоит после этого отдельного довода, —
                  доводы ПЛАНА, а не ключи команды. Их отдаёт поручение
                  «Прочитать доводы» списком строк, в том же порядке и без
                  разбора. Ключи самого «flang io» в этот список не попадают
                  никогда, имени программы и имени файла плана в нём нет.
                  Нет «--» в строке — список пуст

Полномочия сужаются по одному: --no-read, --no-write, --no-net, --no-clock,
--no-random, --no-spawn, --no-env, --no-args, --no-screen. Умолчание —
«можно всё»: запуск программы этой командой и есть согласие на её действия.

КОДЫ ВОЗВРАТА — контракт. 0 — план дошёл до конца; 1 — ПРОГРАММА СДАЛАСЬ
САМА («Провал»), то есть нашла беду и назвала её; 2 — кривой вызов; 3 —
сломался инструмент ЛИБО программа сказала «Не проверено», то есть смотреть
ей было нечем. Первое и второе различает не код отказа, а то, КТО принял
решение; второе и третье — то, ЧТО решено: «нашёл беду» против «не смог
посмотреть». Тройкой же отвечает и ОТКАЗ ЗАПУСКА недоказанного плана: перед
работой считается вердикт о замыкании и одной строкой уходит в поток ошибок
(ADR-0045); «--trust» («--на-веру») его пропускает, «--unproven warn»
предупреждает и работает, а сказать это раз и навсегда можно ключом
«unproven» в «.flangrc». Негодное значение там — код 2, а не тишина.

Среду и доводы хозяин читает сам: «Прочитать переменную среды» отдаёт РОВНО
названную переменную («Значение среды»), а незаданную — отдельным откликом
«Переменной среды нет», а не пустой строкой; пустое имя — отказ FLANG_IO_ENV.
Среды целиком не отдаётся: вместе с ней уехали бы ключи и пароли, которых
план не спрашивал. Запрет — --no-env и --no-args, отказом FLANG_IO_DENIED.

ЭКРАН ДВОИЧНОГО — УПРАВЛЯЮЩИЙ ТЕРМИНАЛ (/dev/tty), и место у него ОДНО, оно
зовётся «экран»; всякое другое имя — отказ FLANG_IO_PLACE. «Показать» кладёт
«текст» целым кадром: очистка, потом текст. Пишется кадр в терминал, а НЕ в
stdout — там вердикт плана, и смешивать их нельзя. На первом «Показать»
хозяин уходит на запасной экран терминала и прячет курсор, а при завершении
прогона — удачном ли, по отказу ли — возвращает как было.

«Ждать событие» переводит терминал в посимвольный режим и ждёт нажатия не
дольше «срока» миллисекунд; срок 0 или неназванный — без предела. Пришла
клавиша — «Случилось» с «откуда» равным «клавиатура»; вышел срок — «Срок
вышел». Имена клавиш: ввод, пробел, таб, возврат, выход, вверх, вниз, влево,
вправо; прочее приходит самим знаком. CTRL-C ПРОДОЛЖАЕТ УБИВАТЬ ПРОГРАММУ и
в ожидании тоже: выход человеку программа не отнимает.

«Размер экрана» отдаёт «Экран» с «ширина» и «высота» — знаков в строке и
строк на экране. Нулевой или нечитаемый размер — отказ, а не 80×24: кадр по
выдуманной ширине рисуется молча и неверно.

Терминала нет — вывод уведён в трубу или в файл, CI, nohup — и все три
поручения отвечают FLANG_IO_NO_SCREEN, ровно как отвечали всегда.

«https» у «Запросить» исполняет САМ ДВОИЧНЫЙ: клиент TLS 1.3 на языке
(flang/stdlib/tls-client.flang), напечатанный в C и собранный в него; curl
не нужен. Беда сертификата — FLANG_IO_TLS_CERT, прочая — FLANG_IO_TLS, код
клиента первым словом. Корни — --trust-roots <PEM>, иначе системная связка.
ОТЗЫВ СЕРТИФИКАТА НЕ ПРОВЕРЯЕТСЯ. «Открыть соединение» — голый TCP.
UDP (IPv4): «Отправить датаграмму» и «Принять датаграмму» (ADR-0101).

flang lock --help

$ flang lock --help
flang lock <файл.flang> [--pretty]

Печатает ЗАМОК программы — JSON, в котором лежат САМИ зависимости, а не ссылки
на них: у каждого импортированного модуля записан его исходник целиком, а
адресом ему служит sha256 по этому исходнику. Склада нет вовсе — скачивать
неоткуда, потому что всё уже в замке; сжатия в формате нет тоже.

  flang lock программа.flang > flang.lock

Если рядом с входным файлом лежит flang.lock, все команды берут импорты ИЗ НЕГО
и исходников зависимостей не читают вовсе — их может не быть на диске. Замок
самозаверен печатью: испорченный замок — отказ FLANG_LOCK, а не тихая сборка из
чего попало. Обновляется замок целиком: в нём лежит код, а не хеш.

  --pretty   с отступами в два пробела

Входного модуля в грузе нет: замок отвечает на вопрос «из чего собрана эта
программа», а сама программа лежит рядом с ним.

flang package --help

$ flang package --help
flang package <файл.flang> [--pretty]

Печатает ПАКЕТ — тот же груз, что в замке, плюс имя, версия, источник и
ведомость доказанного. Имя и версию команда берёт из объявления flang.package
рядом со входным файлом, а не из ключей вызова: ключ живёт в истории оболочки,
а объявление живёт в репозитории и попадает в «git diff».

  flang package strings.flang > strings.flang-package

Подключается пакет одной строкой и без новых слов в языке:

  использует «Строки» из "strings.flang-package"

Исходников зависимостей при этом на диске нет, склада нет, сети не надо: код уже
в файле. Испорченный пакет — отказ FLANG_PACKAGE. Двух версий одной библиотеки в
программе по-прежнему не бывает; два пакета, привезшие один путь с разным
содержимым, — тоже FLANG_PACKAGE, а не молчаливый выбор первого.

  --pretty   с отступами в два пробела

Пакет собирается ТОЛЬКО ИЗ ПРОВЕРЕННОГО: пакет — это обещание, а обещать за
непроверенное нельзя.

flang new --help

$ flang new --help
flang new <имя> [--force]

Создаёт каталог <имя>/ с готовой структурой пакета одной командой: базовый
модуль с тотальной функцией и примером, каталог fspec/ с одной доказанной
спекой и стражем guard.flang, манифест flang.package и README.

  flang new проба
  cd проба
  flang check проба.flang
  flang io fspec/guard.flang

Имя пакета — без пробела, косой черты, обратной косой черты, кавычек и
гильемет, вне списка зарезервированных слов (имена команд бинарника,
«flang», «fspec») и не «.»/«..». Недопустимое имя — отказ FLANG_NEW,
код 2, и ни один файл не создаётся.

  --force   переписать каталог, если он уже существует. Кириллицей: --силой.
            Без ключа существующий каталог — отказ
            FLANG_NEW, код 1: команда не переписывает чужую работу молча.

Образец fspec/ команда берёт рядом с собой (<каталог двоичного>/../fspec)
или из FLANG_FSPEC_TEMPLATE_DIR; не нашла ни того ни другого — отказ
FLANG_NEW, код 1, и каталог не заводится вовсе.

flang run-script --help

$ flang run-script --help
flang run-script [<имя> [доводы…]]

Короткая команда проекта: имя, за которым стоит строка оболочки. Записана она
в файле настроек «.flangrc» строкой «script.<имя> = <команда>»:

  script.site:build = node docs/site/build.mjs

  flang run-script                   перечень: имя и команда каждой
  flang run-script site:build        исполнить
  flang run-script version 0.7.23    доводы после имени уезжают команде

Файл — ближайший «.flangrc» от рабочего каталога вверх, по правилу остальных
настроек; файл дома коротких команд не даёт. Команду исполняет «/bin/sh -c» в
каталоге этого файла, и код возврата — её собственный. Одноимённых строк две —
берётся последняя. У строки из нескольких команд через «&&» доводы достаются
последней.

Имени в файле нет — код 2 и перечень; файла нет — код 2; оболочка не
запустилась — код 3.

flang repl --help

$ flang repl --help
flang repl [<файл.flang>] [--max-steps N] [--max-depth N]

Интерактивная оболочка — то же самое, что голая команда «flang» на терминале.
Объявления накапливаются в сессии, выражения вычисляются сразу, «.помощь»
показывает команды. Файл в аргументе загружается в сессию при запуске.

Выражение считается так: сессия печатается в C тем же способом, что у
«flang emit», собирается системным «cc» против lib/libcompiler_flang.a и
запускается. Нет «cc» — оболочка не выключается, а проверяет разбор, типы и
завершаемость и говорит об этом при запуске.
Где искать: FLANG_CC, FLANG_INCLUDE_DIR, FLANG_LIB_DIR.

flang lsp --help

$ flang lsp --help
flang lsp [--stdio]

Языковой сервер flang по стандартному вводу-выводу: рамки Content-Length, тело
JSON, как требует спецификация LSP. Запускается редактором, а не человеком —
вручную он будет молча ждать сообщений.

Умеет то же, что «flang-lsp» из инструментария на Node, и ТЕМ ЖЕ СЛОЕМ
(«flang/self/lsp.flang»): диагностику той же дорогой, что «flang check» —
разбор, связывание, типы, завершаемость, — дополнение, наведение с подписью и
переход к объявлению.

Расхождение со свидетелем одно, и оно названо: у программы с «использует» беда
импортированного модуля уходит в журнал редактора, а не подчёркивается в его
буфере. «Место» (self/types.flang) поля файла не имеет, поэтому файл беды
называется тогда и только тогда, когда исходник один.

Печатать в stdout что-либо, кроме сообщений протокола, нельзя: редактор читает
оттуда рамки. Всё человеческое уходит в stderr.

Переменные окружения

ПеременнаяЧто задаёт
FLANG_RUNTIME_DIRгде emit ищет исходники рантайма цели, если не задан --runtime
FLANG_CCкакой компилятор C зовёт repl
FLANG_INCLUDE_DIR, FLANG_LIB_DIRгде repl ищет заголовки и библиотеку
FLANG_UNPROVENчто run и io делают с недоказанными программами: refuse, warn, allow

FLANG_RECURSION_LIMIT — не переменная, а код ошибки: кончился предел шагов или глубины.

Дальше