К README · Указатель документации
Две реализации и неподвижная точка
Реализации две, и обе поддерживаются намеренно. Эталонная написана на TypeScript и JavaScript и служит определением поведения языка. Самоприменяющаяся написана на самом flang.
Ядро FTS, написанное на flang
[flang/core/](../../flang/core) — это ядро FTS (лексер, парсер, вычислитель, печать JSON), переписанное на flang: 300 функций, каждая помечена тотальная и доказана. fts check тоже не имеет права зависнуть.
Критерий правильности здесь не «свои тесты проходят». Он дифференциальный и записан в [flang/core/SPEC.md](../../flang/core/SPEC.md): прогнать всю цепочку — текст → лексер на flang → парсер на flang → печать JSON на flang — и потребовать, чтобы выданная строка побайтово совпала с JSON.stringify(compile(текст)) ядра на TypeScript. Прогон идёт по каждой модели .fts репозитория — на чистом клоне их 50, на обеих поверхностях (47 отступных и 3 скобочных) — с нулём расхождений. Если на машине есть внешний каталог моделей, его модели попадают в тот же прогон, и число у вас окажется больше; обещание касается корпуса, а не числа. Диагностики сверяются отдельно — на 34 намеренно сломанных отступных моделях и 13 скобочных, причём и код, и текст сообщения.
Компилятор, написанный на flang, и неподвижная точка
[flang/self/](../../flang/self) — это компилятор flang, написанный на flang. Пять слоёв, и у каждого свой эталон на JavaScript, с которым он сверяется точно — не «в целом так же», а до последней составляющей результата:
| Слой | Функций | Эталон | Что обязано совпасть |
|---|---|---|---|
self/lexer.flang | 88 | src/lexer.mjs | поток токенов: вид, значение, закавыченность, строка и столбец |
self/parser.flang | 372 | src/parser.mjs | AST — побайтово после сериализации |
self/types.flang | 276 | src/types.mjs | диагностики (код, текст, строка и столбец) и таблица сигнатур |
self/totality.flang | 124 | src/totality.mjs | вердикт: список доказанных функций в том же порядке, диагностики, признак ok |
self/emit-c.flang | 328 | src/emit/c.mjs | напечатанный C — побайтово, и он собирается без предупреждений |
Готовность определяется не тем, что «собралось», а классической неподвижной точкой:
1. компилятор на JS печатает self/*.flang → C → сборка → flang₁
2. flang₁ печатает те же self/*.flang → C → сборка → flang₂
3. C, напечатанный flang₁, и C, напечатанный flang₂, совпадают побайтово
Неподвижная точка сошлась. Эталон, flang₁ и flang₂ печатают компилятор одинаково — все семь напечатанных файлов C, — то есть компилятор понимает язык так же, как эталон, и никакой набор тестов этого не заменяет. Проверка — flang/test/self-bootstrap.test.mjs, и она печатает результат:
✔ шаги 2 и 3: flang₁ печатает сам себя, flang₂ печатает то же самое
ℹ неподвижная точка сошлась: 7 файлов совпали побайтово у эталона, flang₁ и flang₂
Именно отсюда берётся релиз: C в релизном архиве напечатан из этих исходников. Эталонную реализацию при этом не удаляют и не удалят — относительно неё и проверяется схождение, а её удаление сделало бы проверку невозможной.