Skip to content

Commit 0b0ca36

Browse files
Marat Zimnurovclaude
andcommitted
Слои самоприменения перестали ходить по строке позицией — лексер стал тотальным целиком
Форма `разложить … на символы` появилась и уже закрыла долги прикладного кода, а сами слои компилятора по-прежнему шли по строке позицией: `подстрока линия с позиция по позиция`, а убывала разность «размер минус позиция». Это число, а не значение, и анализ завершаемости числа частью значения не считает — отсюда в «Долгах» стояли 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_01P6ehGNnEcrkCK1V5iMHNYi
1 parent 2f110f4 commit 0b0ca36

6 files changed

Lines changed: 724 additions & 485 deletions

File tree

flang/self/SPEC.md

Lines changed: 99 additions & 43 deletions
Large diffs are not rendered by default.

flang/self/bootstrap/compiler.flang

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@
1616
// `self-types.test.mjs` и `self-totality.test.mjs` судят КАЖДЫЙ `.flang` в
1717
// `flang/self`, предварительно связав его, — и лимиты шагов там взяты с
1818
// двукратным запасом от самой дорогой программы репозитория
19-
// (`core/parser.flang`, 280 функций). Связанный компилятор — это 1271 функция,
19+
// (`core/parser.flang`, 280 функций). Связанный компилятор — это 1269 функций,
2020
// вчетверо больше; он упирается в лимит анализа тотальности за две секунды и
2121
// в лимит проверки типов заведомо, потому что та квадратична по числу
2222
// объявлений. Лимиты там стерегут сложность слоёв, и поднимать их ради файла,
@@ -292,7 +292,7 @@
292292
// такого имени ещё не было. Повтор из ДРУГОГО файла — беда; повтор из того же
293293
// файла (файл попал в обход дважды) молча пропускается, как и у эталона.
294294

295-
функция «Слить тип»
295+
тотальная функция «Слить тип»
296296
принимает «связка»: «Связывание», «узел»: «Значение», «файл»: строка, «видимость»: «Видимость»
297297
возвращает «Связывание»
298298
пусть «имя» равно («Строка поля» от «узел» и "name")
@@ -302,15 +302,15 @@
302302
то «Повтор типа» от «связка» и «узел» и «имя» и «файл»
303303
иначе «С типом» от «связка» и «узел» и «имя» и «файл»
304304

305-
функция «Повтор типа»
305+
тотальная функция «Повтор типа»
306306
принимает «связка»: «Связывание», «узел»: «Значение», «имя»: строка, «файл»: строка
307307
возвращает «Связывание»
308308
пусть «прежний» равно («Значение по ключу» от («связка».«откуда типов») и «имя»)
309309
если «прежний» равен «файл»
310310
то «связка»
311311
иначе «Добавить беду» от «связка» и («Беда узла» от "FLANG_DUPLICATE_NAME" и (соединить ["тип «", «имя», "» объявлен в двух модулях: ", «прежний», " и ", «файл»] по "") и «узел»)
312312

313-
функция «Слить функцию»
313+
тотальная функция «Слить функцию»
314314
принимает «связка»: «Связывание», «узел»: «Значение», «файл»: строка, «видимость»: «Видимость»
315315
возвращает «Связывание»
316316
пусть «имя» равно («Строка поля» от «узел» и "name")
@@ -320,15 +320,15 @@
320320
то «Повтор функции» от «связка» и «узел» и «имя» и «файл»
321321
иначе «С функцией» от «связка» и «узел» и «имя» и «файл»
322322

323-
функция «Повтор функции»
323+
тотальная функция «Повтор функции»
324324
принимает «связка»: «Связывание», «узел»: «Значение», «имя»: строка, «файл»: строка
325325
возвращает «Связывание»
326326
пусть «прежний» равно («Значение по ключу» от («связка».«откуда функций») и «имя»)
327327
если «прежний» равен «файл»
328328
то «связка»
329329
иначе «Добавить беду» от «связка» и («Беда узла» от "FLANG_DUPLICATE_NAME" и (соединить ["функция «", «имя», "» объявлена в двух модулях: ", «прежний», " и ", «файл»] по "") и «узел»)
330330

331-
функция «Слить программу»
331+
тотальная функция «Слить программу»
332332
принимает «связка»: «Связывание», «программа»: «Значение», «файл»: строка, «видимость»: «Видимость»
333333
возвращает «Связывание»
334334
пусть «после типов» равно (свёртка («Элементы поля» от «программа» и "types") начиная с «связка» как «акк» и «узел» → «Слить тип» от «акк» и «узел» и «файл» и «видимость»)
@@ -432,7 +432,7 @@
432432
пусть «шаг» равно («Загрузить» от «спрошено» и «таблица» и «цель» и («Значение по ключу» от «таблица» и «цель») и нет)
433433
«Сверить имя модуля» от («шаг».«связка») и («шаг».«программа») и («Строка поля» от «импорт» и "category") и «цель»
434434

435-
функция «Сверить имя модуля»
435+
тотальная функция «Сверить имя модуля»
436436
принимает «связка»: «Связывание», «программа»: «Может быть узел», «категория»: строка, «цель»: строка
437437
возвращает «Связывание»
438438
разбор «программа»

0 commit comments

Comments
 (0)