refal-5-lambda icon indicating copy to clipboard operation
refal-5-lambda copied to clipboard

Псевдокомментарии в духе Рефала-05

Open Mazdaywik opened this issue 6 years ago • 5 comments

Эта задача — подзадача #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 упрощена.

Mazdaywik avatar Feb 27 '19 11:02 Mazdaywik

Не сформулирована цель у псевдокомментариев

В постановке задачи говорится только о том, что надо сделать, как в Рефале-05. Но отношение между Рефалом-05 и классическим Рефалом-5 отличается от отношения между классическим и Рефалом-5λ.

Рефал-05 декларируется как совместимый с Рефалом-5 минималистичный, эффективный и компилирующийся в Си (https://github.com/Mazdaywik/Refal-05/issues/33). Точное вложение одного языка в другой не требуется — требуется только совместимость — наличие возможности писать программы, одинаково работающие в обоих языках. Псевдокомментарии используются для определения пустых функций, которые необходимы Рефалу-05 и не нужны Рефалу-5.

Рефал-5λ позиционируется как точное надмножество, т.е. любая корректная программа на классическом Рефале-5 будет корректной для Рефала-5 и будет работать точно также. (На данный момент, однако, есть оговорка о метафункциях — Up, Dn и Ev-met временно не поддерживаются, но это вопрос времени и реализации.)

А в Рефале-5λ какая цель может быть у псевдокомментариев?

Mazdaywik avatar May 14 '20 14:05 Mazdaywik

Цели у псевдокомментариев

Цели можно выделить две:

  • Подсказки компилятору с сохранением совместимости с классическим Рефалом-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: в обычном режиме при синтаксических ошибках в них компилятор будет выдавать ошибки и останавливать компиляцию, в классическом — просто игнорировать.

Mazdaywik avatar May 14 '20 16:05 Mazdaywik

*$CLASSIC и *$EXTENDED

Эти псевдокомментарии компилятор поддерживает давно. Когда-то они были добавлены в язык для удобства тестирования на совместимость к классической версией языка.

*$CLASSIC переключает компилятор в режим совместимости. *$EXTENDED возвращает его обратно, был добавлен для симметрии с *$CLASSIC.

Так вот — *$EXTENDED не нужен. Я не смог придумать сценария, где он может быть полезен. Тем более, он нарушает совместимость — после *$EXTENDED будут снова интерпретироваться *$DRIVE и др., ошибки в них станут ошибками компиляции. А значит, появятся программы, которые в режиме --classic не будут транслироваться.

Единственное его применение в компиляторе — это .refi-файл со встроенными функциями refal5-builtins.refi. Действительно, этот файл подключается к любым программам и содержит расширения языка (вроде $META Mu;). В режиме совместимости он по-прежнему должен компилироваться.

Но $INCLUDE — это уже расширение языка. Поэтому любые подключаемые файлы всегда можно парсить в расширенном режиме.

Mazdaywik avatar May 16 '20 20:05 Mazdaywik

Подытоживая

Ключевые слова оптимизатора

Цитата из топика:

Есть мысль использовать такие же псевдокомментарии для описания встраиваемых или специализируемых функций — сохранится совместимость и с Рефалом-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.

Обновляю топик, внося в него чек-лист.

Mazdaywik avatar Aug 02 '21 09:08 Mazdaywik

Местоположение псевдокомментариев

Где располагать псевдокомментарии? В произвольном месте программы или только вне определений?

На псевдокомментарии в Рефале-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 сделать бесконтекстным.

Вывод

Предлагается отдельным проходом сначала обработать все псевдокомментарии, а затем все остальные токены.

Mazdaywik avatar Aug 22 '21 12:08 Mazdaywik