Своя поверхность: как написать тот же язык по-французски
Обычный язык программирования пишут по-английски, и это не решение, а привычка.
if, while, return — английские слова, и человек, для которого английский
не родной, каждый день читает код на языке, на котором не думает.
В flang слова языка живут в таблице, а не в грамматике. Таблица знает четыре набора слов — русский, английский, эсперанто и китайский. Компилятор не спрашивает, на каком языке написан файл: он узнаёт слова. Такой набор слов называется поверхностью.
Одна программа, четыре записи, одно дерево
В репозитории языка лежит факториал, записанный четырежды:
docs/examples/rosetta/factorial.flang, factorial-english.flang рядом с ним,
docs/examples/surfaces/factorial.eo.flang и factorial.zh.flang. Вот одна и та
же функция на русской, эсперантской и китайской поверхностях:
тотальная функция «Произведение»
принимает элементы: список числа
возвращает число
пример «Произведение четырёх»
дано элементы равно [1, 2, 3, 4]
ожидается 24
свёртка элементы начиная с 1 как акк и эл → акк умножить на эл
totala funkcio «Produto»
akceptas eroj: listo de nombro
redonas nombro
ekzemplo «Produto de kvar»
donite eroj egalas [1, 2, 3, 4]
atendata 24
faldo eroj komencante per 1 kiel akumulo kaj elem → akumulo fojoj elem
完全 函数 «乘积»
接受 诸项:列表 数字
返回 数字
示例 «四数之积»
给定 诸项 等于 [1,2,3,4]
期望 24
折叠 诸项 起始于 1 作为 累加 和 当项 → 累加 乘以 当项
Проверяется это командами, которые можно повторить в клоне репозитория:
$ flang check docs/examples/rosetta/factorial.flang
docs/examples/rosetta/factorial.flang: проверено — разбор, типы, завершаемость, ядро и примеры; замечаний нет
$ flang check docs/examples/surfaces/factorial.eo.flang
docs/examples/surfaces/factorial.eo.flang: проверено — разбор, типы, завершаемость, ядро и примеры; замечаний нет
$ flang check docs/examples/surfaces/factorial.zh.flang
docs/examples/surfaces/factorial.zh.flang: проверено — разбор, типы, завершаемость, ядро и примеры; замечаний нет
flang ast показывает, почему так: деревья разбора совпадают по форме. Мы
сравнили вывод flang ast всех четырёх файлов на 0.7.29, убрав позиции в тексте
и заменив строки заглушкой: пять функций, одинаковые узлы, типы и примеры.
Различаются только имена, которые написал автор, — элементы, items, eroj,
诸项.
Поверхность кончается на лексере: она не влияет ни на типы, ни на доказательство завершения.
Где живут слова
Таблица — в flang/self/lexer.flang, в самом компиляторе, написанном на flang.
У неё две формы, обе строками:
|тотальная:total| totala:total| 完全:total|
|total@ru:тотальная|total@en:total|total@eo:totala|total@zh:完全|
Первая отвечает на вопрос «какое понятие стоит за этим словом» — ею пользуется разбор. Вторая — обратная: «каким словом назвать понятие на такой-то поверхности», ею пользуется диагностика.
Понятий в таблице на 0.7.29 — 159 (счёт пар понятие@поверхность в
flang/self/lexer.flang):
| поверхность | понятий |
|---|---|
| русская | 159 |
| английская | 158 |
| китайская | 143 |
| эсперанто | 138 |
На всех четырёх открыто 137 понятий. У 22 слова где-то нет, и это решение, а не недоделка.
Поверхность не обязана быть полной
Пример — эсперанто и слово «модуль». На эсперанто напрашивается modulo, но это
слово уже занято: английская поверхность называет им остаток от деления
(opMod@en:modulo). Одно слово не вправе называть две конструкции, поэтому
эсперантская поверхность здесь молчит, и factorial.eo.flang начинается
английским словом:
module «Faktorialo»
Вот все 22 понятия, у которых на какой-то поверхности слова нет:
| понятие | по-русски | нет на |
|---|---|---|
alias |
это |
en, eo, zh |
ensures, requires |
обеспечивает, требует |
eo, zh |
claim, qed |
утверждаем, следовательно доказано |
eo, zh |
forall, exists, suchThat, namely |
для всех, есть такой, таких что, а именно |
eo, zh |
induction, follows |
индукция по, следует |
eo, zh |
byExample, byHypothesis, byProperty |
по примеру, по предположению, по свойству |
eo, zh |
decreases |
убывает |
eo, zh |
module, not, nested, embedding, supervision, hash256 |
модуль, не, вложен объект, вложение, надзор, хеш256 |
eo |
opPercent |
процентов |
zh |
Закономерность видна: на эсперанто и китайском не открыт словарь
доказательств. Причина записана в docs/surfaces.md репозитория: у этих
понятий нет устоявшегося слова ни в эсперанто, ни в китайском, а придуманное
слово хуже отсутствующего.
Недостающее понятие можно написать словом другой поверхности — смешивать слова в одном файле разрешено, потому что понятие одно. Китайская функция с русским постусловием проверяется и доказывается:
模块 «混合»
完全 函数 «放在前面»
接受 首项:数字,诸项:列表 数字
返回 列表 数字
обеспечивает «на один длиннее» (长度 结果) 等于 ((长度 诸项) 加 1)
示例 «放入空列表»
给定 首项 等于 1
给定 诸项 等于 空列表
期望 [1]
前置 首项 到 诸项
$ flang check --proof mix.zh.flang
…
постусловие «на один длиннее» функции «放在前面» — доказано сведением цели с телом функции …
mix.zh.flang: ПРОВЕРЕНО САМОСТОЯТЕЛЬНО — утверждений 1: доказано 1, …
Одна граница всё же есть, и она не в словах, а в генерации кода. Китайская программа
переводится в python, java, csharp и elixir, а c, go, rust и другие
цели отказываются: иероглифические имена схлопываются в один идентификатор, и
flang emit честно называет столкновение («имена «乘积» и «前置» дают один
идентификатор»).
Сообщения компилятора по-английски
Поверхность меняет слова программы, а язык сообщений задаётся отдельно:
переменной FLANG_LANG=en или строкой language = en в .flangrc. Переводы
лежат в таблице flang/messages/catalog.tsv. На 0.7.29 у этого две оговорки,
обе проверены запуском:
- переведены рамка и итог (
FLANG_NOT_TOTAL in file …, line 10, column 19,not verified — problems found: 2), а текст большинства отказов остаётся русским — английский шаблон есть у 13 кодов из 144 (docs/guide/settings.ru.md); - в готовой сборке v0.7.29 таблицы переводов нет, и бинарник отвечает
по-русски с предупреждением
no message catalog was found. Работает, если указать таблицу из клона:FLANG_MESSAGE_DIR=<клон>/flang/messages.
Что придётся решить, а не перевести
Поверхность — не словарь, и главная работа в ней не переводческая.
Слово должно быть одно на понятие. История с modulo — типичный случай: в
любом языке найдётся слово, которое хочет назвать две вещи. Решает это автор
языка, и решение записывается в таблицу вместе с причиной.
Слово должно быть отделимо. В китайском пробелов внутри фразы нет, поэтому
между ключевыми словами китайской поверхности пробел обязателен — ровно как
между тотальная и функция. Полноширинные : , ( ) делят поток
наравне с обычными.
Буквы должны быть известны лексеру. Надстрочные буквы эсперанто (Ĉ Ĝ Ĥ Ĵ Ŝ Ŭ) стоят в таблице заглавных букв flang/self/lexer.flang отдельными парами:
без них Se в начале строки не свелось бы к se. Для французского то же
касается É È Ê À Ç Ô Û.
Как добавить французскую поверхность
1. Выбрать слова. 159 понятий, из них хотя бы 137 — те, что открыты на всех
поверхностях. Для каждого нужно французское слово, не занятое другим понятием
ни на одной поверхности: fonction, accepte, retourne, exemple, étant donné, attendu, si, alors, sinon. Слова из нескольких слов допустимы.
2. Дописать таблицу. Обе формы в flang/self/lexer.flang: прямую
(fonction:function) и обратную (function@fr:fonction). Компилятор написан на
flang, поэтому правка — это правка программы на flang, и она проходит те же
проверки. После неё компилятор нужно пересобрать (глава
«Компилятор, написанный на самом себе»).
3. Добавить буквы. Диакритику — в таблицу заглавных, рядом с эсперантской.
4. Написать пример и сравнить деревья. factorial.fr.flang, слово в слово с
русским оригиналом:
$ flang check docs/examples/surfaces/factorial.fr.flang
$ flang ast docs/examples/surfaces/factorial.fr.flang > fr.json
$ flang ast docs/examples/rosetta/factorial.flang > ru.json
# деревья обязаны совпасть по форме: те же функции, узлы, типы и примеры
Если форма разошлась, какое-то слово попало не на то понятие, и это видно сразу.
Чего поверхность не даёт
Поверхность меняет слова языка, а не имена в вашей программе: «Рассчитать скидку» останется тем, что вы написали. Она не переводит стандартную
библиотеку и не делает правило понятнее: запутанное правило будет запутанным на
любом наборе слов.