refal-5-lambda
refal-5-lambda copied to clipboard
Псевдокомментарии в духе Рефала-05
Эта задача — подзадача #185. Процитирую параграф оттуда.
Рефал-05 не поддерживает символы-слова, вместо них используются символы-функции. Пустые функции определяются при помощи ключевого слова
$ENUM
. При этом Рефал-05 совместим с Рефалом-5. Противоречие разрешается благодаря псевдокомментариям — комментариям вида*$ENUM True, False
которые эквивалентны
$ENUM True, False;
Если однострочный комментарий начинается с
*$
, то знак*
в начале заменяется на пробел, в конец дописывается;
и полученная строка считается обычной строчкой программы.Есть мысль использовать такие же псевдокомментарии для описания встраиваемых или специализируемых функций — сохранится совместимость и с Рефалом-5, если это нужно, и появится возможность для оптимизации. Для записи многострочных псевдокомментариев предлагается использовать такой синтаксис:
*$INLINE Foo, Bar, Baz *$ Oof, Rab, Zab
Если следующая строка после псевдокомментария начинается на
*$
(звёздочка, доллар, пробел), то она считается продолжением псевдокомментария.Вообще, псевдокомментарии в языке частично есть —
*$CLASSIC
и$EXTENDED
— значит, имеющуюся функцию нужно расширить и углубить.
Можно добавить только, что псевдокомментарии могут быть доступны не для всех ключевых слов, и даже наоборот, не все ключевые слова могут быть доступны без псевдокомментариев. Например, следующая конструкция бессмысленна, ибо глупа:
*$ENTRY Go { = <Prout 'Hello, World!'> }
Но её поддерживает Рефал-05 ради минималистичности и компактности исходников.
Сейчас компилятор Рефала-5λ поддерживает директиву $LABEL
(199c8e24401ec06999eb17ab015ada8024ad9cc5), что есть костыль. Разумно подобные вещи допускать только в псевдокомментариях:
*$PRAGMA-NATIVE-IDENTS CURRENT, BEGIN, END
FSeek {
%%
...
Когда закрыть заявку?
- [x] https://github.com/bmstu-iu9/refal-5-lambda/issues/314#issuecomment-734850619 — реализованы псевдокомментарии управления оптимизацией.
- [ ] Удалён псевдокомментарий
*$EXTENDED
. - [ ] Семантика псевдокомментария
*$CLASSIC
упрощена.
Не сформулирована цель у псевдокомментариев
В постановке задачи говорится только о том, что надо сделать, как в Рефале-05. Но отношение между Рефалом-05 и классическим Рефалом-5 отличается от отношения между классическим и Рефалом-5λ.
Рефал-05 декларируется как совместимый с Рефалом-5 минималистичный, эффективный и компилирующийся в Си (https://github.com/Mazdaywik/Refal-05/issues/33). Точное вложение одного языка в другой не требуется — требуется только совместимость — наличие возможности писать программы, одинаково работающие в обоих языках. Псевдокомментарии используются для определения пустых функций, которые необходимы Рефалу-05 и не нужны Рефалу-5.
Рефал-5λ позиционируется как точное надмножество, т.е. любая корректная программа на классическом Рефале-5 будет корректной для Рефала-5 и будет работать точно также. (На данный момент, однако, есть оговорка о метафункциях — Up
, Dn
и Ev-met
временно не поддерживаются, но это вопрос времени и реализации.)
А в Рефале-5λ какая цель может быть у псевдокомментариев?
Цели у псевдокомментариев
Цели можно выделить две:
- Подсказки компилятору с сохранением совместимости с классическим Рефалом-5.
- Прагмы.
Подсказки, невидимые классическому Рефалу-5
Рефал-5λ декларируется как точное надмножество классического Рефала-5 (далее мы будем опускать определение «классический») — любая программа на Рефале-5 является корректной программой на Рефале-5λ, имеющей ту же семантику. Рефал-5 игнорирует все псевдокомментарии. Следовательно:
- удаление всех псевдокомментариев в корректной программе на Рефале-5 не должно менять её семантику при компиляции для Рефала-5λ,
- корректная программа на Рефале-5 должна быть корректной программой на Рефале-5λ независимо от содержимого комментариев.
Таким образом, компилятор не может сообщать о синтаксических ошибках в псевдокомментариях как об ошибках — они должны быть предупреждениями. Также псевдокомментарии не должны изменять семантику программы. Они могут, например, влиять на оптимизацию программы (вроде *$DRIVE
).
Прагмы
Мотивация здесь в том, что для каких-то второстепенных средств не вводится специальный синтаксис «верхнего» уровня. Вроде того, что вместо $LABEL
в постановке задачи предлагается *$PRAGMA-NATIVE-IDENTS
— с точки зрения языка вещь второстепенная. Такие средства можно с сохранением обратной совместимости добавлять и удалять в разных версиях языка — если они не поддерживаются, они будут игнорироваться как игнорируются комментарии.
Псевдокомментариями можно, например, подавлять предупреждения. Тоже вещь второстепенная.
Возможные псевдокомментарии и подходы к реализации
-
*$DRIVE
,*$INLINE
,*$SPEC
— подсказки для оптимизатора, эквивалентны соответствующим ключевым словам. Сложность их реализации в том, что в псевдокомментариях ошибки в них должны стать предупреждениями. Т.е., например, имя неопределённой функции в*$DRIVE
не будет приводить к остановке компиляции. А значит, последующие проходы должны быть к этому готовы — игнорировать неопределённые функции и перепроверять шаблоны для*$SPEC
. -
*$WARNING PUSH "-Wno-govnocode"
— управление предупреждениями. -
*$INCLUDE
— сложность с синтаксической корректностью. В идеале программу с этой директивой нужно компилировать дважды — с игнорированием этого комментария и с его заменой на$INCLUDE
и выводить объединение синтаксических ошибок. Да и вообще-то сам$INCLUDE
не нужен в свете #255. - Уже поддерживаемые
*$CLASSIC
и*$EXTENDED
используются для тестирования режимов компилятора.
Минимальная реализация
Можно гарантировать соответствие семантики Рефала-5λ классическому Рефалу-5 только в режиме --classic
— в нём игнорировать все псевдокомментарии. Правильно игнорировать также и *$EXTENDED
. но он используется для тестирования, поэтому его придётся оставить.
Такой подход позволит быстро реализовать *$DRIVE
и *$SPEC
: в обычном режиме при синтаксических ошибках в них компилятор будет выдавать ошибки и останавливать компиляцию, в классическом — просто игнорировать.
*$CLASSIC
и *$EXTENDED
Эти псевдокомментарии компилятор поддерживает давно. Когда-то они были добавлены в язык для удобства тестирования на совместимость к классической версией языка.
*$CLASSIC
переключает компилятор в режим совместимости. *$EXTENDED
возвращает его обратно, был добавлен для симметрии с *$CLASSIC
.
Так вот — *$EXTENDED
не нужен. Я не смог придумать сценария, где он может быть полезен. Тем более, он нарушает совместимость — после *$EXTENDED
будут снова интерпретироваться *$DRIVE
и др., ошибки в них станут ошибками компиляции. А значит, появятся программы, которые в режиме --classic
не будут транслироваться.
Единственное его применение в компиляторе — это .refi
-файл со встроенными функциями refal5-builtins.refi
. Действительно, этот файл подключается к любым программам и содержит расширения языка (вроде $META Mu;
). В режиме совместимости он по-прежнему должен компилироваться.
Но $INCLUDE
— это уже расширение языка. Поэтому любые подключаемые файлы всегда можно парсить в расширенном режиме.
Подытоживая
Ключевые слова оптимизатора
Цитата из топика:
Есть мысль использовать такие же псевдокомментарии для описания встраиваемых или специализируемых функций — сохранится совместимость и с Рефалом-5, если это нужно, и появится возможность для оптимизации.
В заявке #314, а именно в https://github.com/bmstu-iu9/refal-5-lambda/issues/314#issuecomment-734850619 предлагается сделать то же самое, причём в комментарии написано больше и подробнее.
*$CLASSIC
и *$EXTENDED
Псевдокомментарий *$EXTENDED
противоречит сути классического режима (--classic
). В классическом режиме должна отвергаться любая программа, которая отвергается Рефалом-5. Но с *$EXTENDED
можно написать программу с расширениями.
В .refi
-файлах *$EXTENDED
не нужен, т.к. эти файлы сами являются расширениями и должны парситься в расширенном режиме.
Псевдокомментарии *$CLASSIC
и *$EXTENDED
могут использоваться для включения и отключения расширений на участке кода, первый отключает, а второй для последующего текста включает расширения.. Но эта функциональность бесполезная: не вижу сценариев, когда нужно на некотором участке кода отключать или включать расширения.
Таким образом, псевдокомментарий *$EXTENDED
не нужен.
Поскольку комментария *$EXTENDED
не будет, семантику *$CLASSIC
можно упростить: файл компилируется в классическом режиме, если в нём в произвольном месте есть хотя бы один комментарий *$CLASSIC
.
Перекрёстная ссылка. Эти псевдокомментарии внесены в рамках заявки #144 без какой-либо мотивации. Требуемое поведение просто постулировалось.
Когда заявку закрыть?
Закрыть, когда будут реализованы псевдокомментарии для управления оптимизацией согласно https://github.com/bmstu-iu9/refal-5-lambda/issues/314#issuecomment-734850619, когда будет удалён *$EXTENDED
и упрощена семантика *$CLASSIC
.
Обновляю топик, внося в него чек-лист.
Местоположение псевдокомментариев
Где располагать псевдокомментарии? В произвольном месте программы или только вне определений?
На псевдокомментарии в Рефале-5λ вдохновил Рефал-05. В нём псевдокомментарий, т.е. строчка вида *$KEYWORD …
комментарием не считается, если KEYWORD
— допустимое ключевое слово. Соответственно, наличие псевдокомментария, например, посреди функции будет ошибкой. Для Рефала-05 это допустимо, т.к. не требуется полной совместимости с Рефалом-5 — он поддерживает лишь синтаксическое подмножество (с некоторыми отличиями в семантике).
В Рефале-5λ ситуация иная. Любая корректная программа на Рефале-5 должна быть корректной программой на Рефале-5λ, в том числе, с любыми комментариями. Сейчас эта цель достигается частично — в классическом режиме псевдокомментарии *$INLINE
, *$DRIVE
и *$SPEC
игнорируются, в расширенном — ошибки в них являются синтаксическими ошибками. Т.е. цель полной совместимости достигается только в классическом режиме. А должно быть в обоих.
Опыт других проектов:
- Во фреймворке https://github.com/Mazdaywik/refal-5-framework псевдокомментарии поддерживаются, но они допустимы только на верхнем уровне. В других местах они считаются синтаксической ошибкой. Это ошибка.
- В SCP4 псевдокомментарии допустимы везде, но интерпретируются только на верхнем уровне. В суперкомпиляторе лексический анализ не отделён от синтаксического, поэтому строки программы в разных местах можно интерпретировать по-разному.
В постановке задачи https://github.com/bmstu-iu9/refal-5-lambda/issues/314#issuecomment-734850619 предлагается выдавать только предупреждения на проблемы с псевдокомментариями, что соответствует цели совместимости.
Так где же допускать псевдокомментарии?
Если их разрешать только на верхнем уровне, то во всех остальных местах их нужно будет учитывать и обрабатывать (игнорировать, возможно, выдавая предупреждение), как это сейчас делается с *$CLASSIC
и *$EXTENDED
. Преимущества и недостатки подхода:
- ✔Можно допускать контекстно-зависимые псевдокомментарии. Например, комментарий
*$OPT
без списка имён перед определением функции будет естественно распространяться на последующую функцию. В дальнейшем можно будет реализовать и другие контекстно-зависимые комментарии. - ❌Заметно усложняется синтаксический анализ.
Если разрешать их везде, то возможна другая реализация: отдельная обработка псевдокомментариев и отдельный синтаксический анализ обычных токенов.
- ✔Заметно простая реализация.
- ❌Псевдокомментарии теряют контекст. Однако, на данный момент это проблемой не является. Единственные контекстно-зависимые комментарии — это
*$CLASSIC
и*$EXTENDED
, но (а) они уже обрабатываются особым образом и (б) в комментарии выше предлагается*$EXTENDEN
удалить, а*$CLASSIC
сделать бесконтекстным.
Вывод
Предлагается отдельным проходом сначала обработать все псевдокомментарии, а затем все остальные токены.