Commit 0b0ca36
Слои самоприменения перестали ходить по строке позицией — лексер стал тотальным целиком
Форма `разложить … на символы` появилась и уже закрыла долги прикладного кода, а
сами слои компилятора по-прежнему шли по строке позицией: `подстрока линия с
позиция по позиция`, а убывала разность «размер минус позиция». Это число, а не
значение, и анализ завершаемости числа частью значения не считает — отсюда в
«Долгах» стояли 34 нетотальные функции лексера и 138 печати в C.
Теперь строка раскладывается в список, и тот же проход становится рекурсией по
хвосту. Лексер: 88 функций и 54 доказанные → 84 функции, доказаны все 84,
долгов по завершаемости не осталось ни одного. Печать в C: 329/191 → 326/223.
Парсер: 373/147 → 374/188 — там доказалась «Основа имени» и всё связывание имён,
которое её звало. Обёртка bootstrap: 68/46 → 68/52.
ТРИ МЕСТА СТОИЛИ ОТДЕЛЬНОГО РЕШЕНИЯ, И ВСЕ ТРИ ЗАПИСАНЫ В «ДОЛГАХ».
«Съесть токен целиком». Проход то съедает один символ, то сразу весь токен, а
«перейти вперёд на k символов» списком не выражается: k считается по ходу, и
прыжок через k хвостов частью значения не является. Длину токена считает
отдельная ТОТАЛЬНАЯ функция заглядывания, рекурсивная по хвосту («Запись
числа», «Читать имя», «Читать в кавычках», «Длина до закрытия»), а сам проход
всегда делает ровно один шаг и несёт счётчик `осталось`: этот символ уже отдан
выданному токену. Убывает список, а не счётчик.
«Дочитать и вернуться к тому же символу». Функция-читатель, остановившаяся на
символе, ей не принадлежащем, обязана этот символ кому-то отдать — а отдать его
можно только тем же списком, то есть без убывания. Ровно поэтому разбор косой
черты, минуса и равенства не вынесен в спутники «Сканировать», а стоит в ней
самой, и «Косая в начале» слилась с «Открыть строку».
Склейка ключевых слов. «Искать фразу» убывала по длине фразы (4 → 1), «Склеить»
— по суффиксу от «Отбросить токены». Ключевых фраз длиннее четырёх слов в языке
нет, поэтому перебор идёт по готовому списку `[4, 3, 2, 1]`, а снятие найденной
фразы выписано хвостами: один, два, три или четыре — случаи перечислимы.
ЧТО НЕ ПОДДАЛОСЬ И ОСТАЛОСЬ ОБЫЧНЫМ, С ПРИЧИНОЙ. «Пробелы» печати в C убывает
по числу, и список тут не помогает: отступ шириной n — не проход по значению, а
построение его из ничего; была бы встроенная «повторить строку», функция стала
бы тотальной вместе со всеми. «Повторная замена» парсера убывает по длине
строки: заменяется подстрока, а не символ, и переписывать её обходом значило бы
писать второй `replace`. Тарьян, обход обобщённого AST и рекурсивный спуск —
прежние долги, к символам отношения не имеющие.
ПОБАЙТОВОСТЬ СОХРАНЕНА, И ЭТО ЕДИНСТВЕННЫЙ КРИТЕРИЙ. Поток токенов совпадает с
`src/lexer.mjs` на 37 файлах репозитория, 78 краевых случаях и 300 склейках;
напечатанный C — с `src/emit/c.mjs`; AST — с `src/parser.mjs`; неподвижная
точка сходится: семь файлов совпали побайтово у эталона, flang₁ и flang₂.
Цена измерена, а не угадана: `хвост` в интерпретаторе на JavaScript копирует
(`list.slice(1)`), и сверка потоков идёт примерно в 1.35 раза дольше. Половину
надбавки сняло одно наблюдение — заглядывание на символ вперёд стоит той же
копии, что и шаг, поэтому оно не считается на каждый символ строки, а живёт
внутри трёх ветвей, которым нужно. В рантайме на C всё наоборот: `хвост` там
указатель внутрь того же массива, а `подстрока` резала строку по кодовым
точкам. Лимит шагов и предел памяти не двигались.
Тест `self-totality.test.mjs` обновлён вместе с «Долгами»: список поимённых
долгов лексера снят, а вместо него стоит проверка сильнее — у лексера тотальны
все функции до одной. Иначе откат легко не заметить: одна `подстрока` вместо
хвоста снимает пометку с половины слоя, а поток токенов остаётся тем же и
сверка с образцом молчит.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01P6ehGNnEcrkCK1V5iMHNYi1 parent 2f110f4 commit 0b0ca36
6 files changed
Lines changed: 724 additions & 485 deletions
File tree
- flang
- self
- bootstrap
- test
Large diffs are not rendered by default.
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
16 | 16 | | |
17 | 17 | | |
18 | 18 | | |
19 | | - | |
| 19 | + | |
20 | 20 | | |
21 | 21 | | |
22 | 22 | | |
| |||
292 | 292 | | |
293 | 293 | | |
294 | 294 | | |
295 | | - | |
| 295 | + | |
296 | 296 | | |
297 | 297 | | |
298 | 298 | | |
| |||
302 | 302 | | |
303 | 303 | | |
304 | 304 | | |
305 | | - | |
| 305 | + | |
306 | 306 | | |
307 | 307 | | |
308 | 308 | | |
309 | 309 | | |
310 | 310 | | |
311 | 311 | | |
312 | 312 | | |
313 | | - | |
| 313 | + | |
314 | 314 | | |
315 | 315 | | |
316 | 316 | | |
| |||
320 | 320 | | |
321 | 321 | | |
322 | 322 | | |
323 | | - | |
| 323 | + | |
324 | 324 | | |
325 | 325 | | |
326 | 326 | | |
327 | 327 | | |
328 | 328 | | |
329 | 329 | | |
330 | 330 | | |
331 | | - | |
| 331 | + | |
332 | 332 | | |
333 | 333 | | |
334 | 334 | | |
| |||
432 | 432 | | |
433 | 433 | | |
434 | 434 | | |
435 | | - | |
| 435 | + | |
436 | 436 | | |
437 | 437 | | |
438 | 438 | | |
| |||
0 commit comments