-
Notifications
You must be signed in to change notification settings - Fork 35
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Удаление устаревших элементов языка и компилятора #318
Comments
В заявке #337 предложена следующая стратегия удаления устаревших элементов:
|
Ранее древенсая оптимизация в lexgen’е подавлялась при помощи объявления функций как $SPEC State (e.acc) e.text; До реализации #251 «Специализация без шаблона» эта строчка подавляла специализацию функции-состояния в режиме -OA+. Сейчас эта строчка наоборот, форсирует специализацию этой функции даже в режиме -OA-. Избыточная прогонка подавлена при помощи организации автомата так, чтобы авторазметка (#251) рассматривала некоторые «опасные» функции как базисные, см. 0cda99e2d. В текущей версии 3.3 реализована поддержка функции обобщения gen_e__ (#331), которая предназначена для подавления специализации. Теперь все аккумуляторы принудительно обобщаются при помощи gen_e__. Прогонка подавляется за счёт того, что в актуальной версии не реализована прогонка функций с активным аргументом (#230). Потеря быстродействия не страшна, т.к. Простой Рефал уже deprecated (#318, DSL, который растворяется во время компиляции (#50). Потеря быстродей
В заявке #195 предлагалось заменить $LABEL на *$PRAGMA-NATIVE-IDENTS, но было выбрано слово $IDENT. Во-первых, вещь второстепенная и с удалением нативных вставок (см. #318) она будет удалена, во-вторых, имеющийся код легко расширить новым ключевым словом, если оно совпадает с точностью до регистра с узлом дерева. А директива $LABEL отображается на узел дерева (Ident t.Pos e.Name).
Классический режим как режимОбзорКомпилятор поддерживает возможность компиляции как в режиме «расширенного» Рефала-5λ, так и в «классическом подмножестве». В «расширенном режиме» доступны все средства языка, в «классическом» — только те синтаксические конструкции, которые поддерживают Предложение было внесено в #144 без какой-либо мотивации. В комментарии #195 (comment) предлагается отказаться от псевдокомментария Из-за того, что в актуальной реализации используется переключение режимов псевдокомментариями, по всему исходнику парсера приходится таскать флаг текущего режима (который может меняться). При изменении семантики Как переделатьКогда включен «классический» режим, компилятор считает некоторые синтаксические конструкции ошибками. Когда он выключен, не считает. В компиляторе уже есть другой механизм, способный в зависимости от настроек или считать, или не считать некоторые синтаксические/семантические конструкции ошибками, прерывающими компиляцию. Предлагается «классический» режим реализовать через него. Речь идёт о предупреждениях и режиме При условии реализации #195 (comment) (т.е. удалении
Опция |
Мотивация
Проект развивается давно и эволюционно. А любое эволюционное развитие подразумевает накопление рудиментов и атавизмов вплоть до возвратно-гортанного нерва жирафа.
Но в отличие от живых существ, развитие которых осуществляется путём мутаций и отбора (генетическое программирование пока фантастика), программу можно пересмотреть и коренным образом переделать.
Поэтому предлагается пересмотреть язык и компилятор и удалить неадекватные его элементы.
Другой мотивацией может служить, как обычно, ускорение. Ускорение работы самого компилятора + ускорение сборки компилятора. С ускорением работы пока не очевидно, а сборка может ускориться из-за уменьшения объёма исходников.
Перечень устаревших элементов
Ниже будут перечислены возможности, которые предлагается удалить. Или, как минимум, обдумать их удаление.
$DRIVE
,$INLINE
,$SPEC
,-OD
,-OI
,-OS
—замена на
$OPT
и-OT
(#314)Предлагается под капотом объединить различные виды древесных оптимизаций, как описано в #314. Да, для этого уже создана отдельная задача, здесь упомянуто, поскольку в тему.
$INCLUDE
А вот это уже интереснее! Казалось бы, полезная фича языка и зачем её удалять. Но, рассмотрим её преимущества и недостатки.
LibraryEx
не нужно явно импортировать используемые функции. В большинстве случаев, этоMap
,MapAccum
иReduce
.-OG
. Собственно, именно возможность оптимизации была основной мотивацией внедрения$INCLUDE
(Реализовать включение файлов (ключевое слово $INCLUDE) #92).Но преимущество раздельной компиляции с древесной оптимизацией не очевидно. При разработке компилятор собирается без оптимизаций для ускорения цикла самоприменения. Дистрибутив собирается редко, при выпуске новой версии, и со всеми оптимизациями — можно и подождать.
$INCLUDE
. Реализация довольно простая и красивая. Без механизма подключаемых файлов, вероятно, было бы немного сложнее.Map
и др, по логу профилировщика можно понять, вызовMap
в каком файле требует много времени.Преимущество несущественное.
Map
и др. теперь определены черезMu
. Поэтому теперь можно в Рефале-5λ писать<Map Func e.Items>
, гдеFunc
— локальная функция. ЕслиMap
будет располагаться в другой единице трансляции (как в Рефале-05 + фреймворк), то косвенные функции придётся определять как entry.Преимущество несущественное.
Для совместимости с фреймворком такие функции всё равно нужно определять как entry. А если почему-то хочется косвенную функцию разрешать по имени (например, для вызова
<Map s.Func …>
, гдеs.Func
приходит извне), то можно использовать конструкцию(&Mu s.Func)
.$INCLUDE "LibraryEx";
, приходится заново сканировать и разбирать определения одних и тех же функций.$INCLUDE
, уже решается опцией-OG
. Более того, решаемая проблема эта сугубо второстепенная и техническая (ускорение конкретной реализации), но решалась она внесением нового средства в язык.$INCLUDE
для оптимизации вызовов требует синтаксиса оторванных$ENTRY
(см. далее).LibraryEx
располагались в префиксе, префикс можно было собрать один раз с максимальной оптимизацией, после чего разработка компилятора незначительно ускорялась. Функции типаMap
вызываются повсеместно, поэтому их сборка с-OPR
заметно ускоряла работу. С переходом на$INCLUDE "LibraryEx";
это перестало работать.$INCLUDE
также несколько усложняет SRMake, в частности, в нём приходится анализировать escape-последовательности.Таким образом, средство хоть и удобное, но избыточное, его удаление только упростит язык.
Синтаксис оторванных
$ENTRY
(detached$ENTRY
)Эта конструкция была добавлена в язык в сочетании с предыдущей — ради оптимизации некоторых функций библиотеки с сохранением возможности их вызова через обычный
$EXTERN
. Подробнее смотри в #159.$ENTRY
можно добавить синтаксис «пришитых»$DRIVE
,$INLINE
и, в перспективе,$OPT
. Про это даже задача есть — Синтаксис атрибутов функций #250.Единственная причина, заставляющая этот синтаксис существовать в компиляторе — возможность оптимизировать map-подобные функции с раздельной компиляцией.
$SCOPEID
(#284)Устаревшая конструкция языка. Подробнее — в задаче на удаление #284. Дублировать или конспектировать содержимое #284 я не буду.
Нативные вставки
Нативные вставки, они же вставки кода на С++, позволяют в исходном коде на Рефале-5λ описывать функции, тело которых реализовано на C++. По своему замыслу они являются аналогом ассемблерных вставок уже в самом C++ (или в расширениях некоторых компиляторов Си). В компилятор были добавлены в рамках задачи #11.
Мотивация их добавления была в возможности смешивать в одном файле код на Рефале и код на C++. В частности, так сделано для того, чтобы в одном файле
Library.sref
иметь некоторые функции, написанные на Рефале, и некоторые функции, написанные на C++.Рассмотрим их преимущества и недостатки.
refal-5-lambda/src/lib/Library.ref
Lines 510 to 515 in b40f74f
Но вот недостаток у перемешивания кода Рефала и C++ есть. Со смешанным файлом нельзя работать инструментами, ориентированными на C++, например, IDE с автодополнением.
Подытоживая. Нативные вставки — не самый лучший способ осуществления FFI. При этом они требуют заметного усложнения архитектуры компилятора. Так что нужно продумывать хороший FFI и нативные вставки удалять из языка.
Директива
$LABEL
Она нужна только в рамках актуального FFI — с нативными вставками. При использовании другого FFI она становится избыточной.
Простой Рефал (#327)
А вообще, зачем нужна поддержка этого front-end’а? Единственный эксплуатируемый код на Простом Рефале — это его самоприменимый front-end. Потому что если бы я перевёл front-end на Рефал-5λ, то никакой пользы от Простого Рефала уже не было бы.
Помимо front-end’а на Простом Рефале написана куча автоматизированных тестов. Небольшая часть тестов проверяют front-end Простого Рефала, остальные более глубокую логику. При удалении Простого Рефала первую часть тестов логично удалить, а вторую переписать на Рефал-5λ — нет никаких причин продолжать использовать Простой Рефал.
Есть задача по унификации парсеров Рефала-5λ и Простого Рефала — #201. Поскольку их синтаксисы похожи и различаются они по сути только идентификаторами и указателями на функции, можно обойтись одним парсером со внутренним флагом режима. В парсере Рефала-5λ уже есть флаг режима, его можно расширить. Но, если эту задачу реализовать, то объём эксплуатируемого кода на Простом Рефале уполовинится — останется только лексер.
Модульный Рефал поддерживает компиляцию себя в Простой Рефал. Но это не существенно, т.к. переделать кодогенератор на Рефал-5λ нет никакой сложности.
LexGen
Это генератор лексических анализаторов в виде конечного автомата. Также к нему частично написан front-end в виде синтаксиса регулярных выражений (#50).
На данный момент он используется только во front-end’е Простого Рефала. Если последний будет удалён, то генератор станет не нужен.
При разработке лексера Рефала-5λ LexGen не использовался по двум причинам. Во-первых, уже был готовый лексер Рефала-5 из тогда ещё будущего фреймворка. Во-вторых, написать хороший эффективный лексер не сложнее, чем написать автомат и постобработку.
В своём текущем виде генератор мало полезен. Написание автомата с его помощью не на много проще написания генератора лексических анализаторов вручную. Поэтому либо его надо дорабатывать, чтобы он наоборот облегчал разработку, либо выбрасывать.
Генерируемый код тоже не слишком эффективен. Вопросы вызывает эффективность построенных функций, порой содержащих десятки предложений. Не исключено, что вызов функции
Type
и анализ её возвращаемого значения будет быстрее.На доработку front-end’а уже давно есть задача #50. На оптимизацию генерируемого кода задача пока не ставилась.
Рассахаривание условий (
-OC-
)Режим рассахаривания условий существует в компиляторе по историческим причинам. Когда-то был Простой Рефал, в котором условий не было. Потом независимо я создал проект по конвертации Рефала-5 с условиями и блоками в его базисное подмножество.
Затем я решил внедрить условия в компилятор. На первом этапе я решил адаптировать конвертор, чтобы во входном языке были доступны условия, но при этом не требовалось менять back-end и рантайм.
Затем были реализованы условия (@Anastasya34, #17, #161), но режим рассахаривания условий остался. Режим нативной поддержки условий был оформлен как оптимизация
-OC
(по умолчанию устанавливается скриптамиrlc
иrlmake
), т.е. при использовании этого ключа рассахаривание условий отключается. Забавно, что это единственный режим оптимизации, включение которого ускоряет работу компилятора.Рассахаривание условий был оставлено по двум причинам. Во-первых, оно позволило @Anastasya34 сделать сравнительные замеры производительности между нативной поддержкой условий и рассахариванием. Во-вторых, жалко было удалять.
Сейчас рассахаривание условий интересно тем, что в этом режиме возможны и прогонки условий (#248) и прогонки вызовов в условиях (#283). Это может быть актуально для классического Рефала-5 и некоторых стилей программирования. В частности, с рассахариванием условий и пометкой одной из функций как
$DRIVE
можно ускорить MSCP-A (версия от января 2020) в два раза (там есть специфическое узкое место и оно в условии).Но концептуально этот режим уже не нужен.
Избыточные
^
(#337)Стоит запретить знак
^
, записанный после ранее не встречавшейся переменной.Формально это не удаление синтаксического средства. Но, поскольку это сужение входного языка, то здесь оно вполне уместно.
Выводы
Перечислено несколько устаревших средств. Их нужно или удалить (те, которые удалить надо), или аргументированно оставить (те, с которыми всё неоднозначно).
$DRIVE
,$INLINE
,$SPEC
,-OD
,-OI
,-OS
— замена на$OPT
и-OT
(Универсальная древесная оптимизация $OPT #314)$INCLUDE
$ENTRY
(detached$ENTRY
)$SCOPEID
(Удалить $SCOPEID #284)$LABEL
-OC-
) — обдумать удаление (написать в комментариях).^
(Избыточные ^ сделать ошибкой #337)*$EXTENDED
, старое поведение*$CLASSIC
(Псевдокомментарии в духе Рефала-05 #195).-Wclassic
(Удаление устаревших элементов языка и компилятора #318 (comment))The text was updated successfully, but these errors were encountered: