Re: Каковы границы расширения синтаксиса в Н1
От: VladD2 Российская Империя www.nemerle.org
Дата: 20.03.12 22:08
Оценка:
Здравствуйте, m.e., Вы писали:

ME>вот, кстати, хотел задать вопрос — каковы границы расширения синтаксиса в Н1 (т.е. что можно, а что уже нельзя)?


1. Н1 использует лексер, препроцессор и препарсер. Изменить их из макросов нельзя.
Лексер определяет то как Н1 разбирает лексемы (режет текст на токены). Например, последовтаельность символов "+=+" буде распознана как один оператор (например, в C# она может быть распознана как операторы "+=" и "+".
Препроцессор аналогичен оном в C# и никак не изменяем.
Препарсер отвечает за:
* Подгрузку и выгрузку синтаксических расширения.
* Свертку токенов по группам (на основе скобок).
* Абстрагирование от типа синтаксиса (скобочного или на базе отступов).

Все эти решения являются компромисными и в той или иной степени снижают расширяемость.
Так при свертке по скобкам производится обработка знаков разделителей (запятых, точек с запятых и т.п.). Это приводт к тому, что казалось бы простой синтаксис вроде:
select a, b

не может быть разобран.

Для сравнения в Н2 используется безлексерный генерируемый расширяемый парсер который не имеет подобных проблем.

2. Макросы Н1 позволяют расширять только предопределенные создателями места в грамматике: набор выражений, заголовок типа (новый тип определить нельзя), член типа, заголовок метода или эксессора свойства/события, параметр.

3. Макросы могут быть лексическими (так называемые raw-макросы) и синтаксическими. Первые позволяют разбирать более сложные грамматики (любые удовлетворяющие правилам лексера и препарсера). Вторые позволяют разбирать набор ключевых слов, скобок и выражений.

Здесь надо обратить особое внимание на слово "выражение". Заметьте, не произвольная грамматика, а только выражение.

Например, нельзя определить макрос:
macro ForEach(pattern, collectoin, body)
  syntax ("foreach", "(", pattern, "in", collectoin, ")", body)
{
  ...
}

так как в первый это выражение, а в немерле есть бинарный оператор "in".
Если определить описанный выше синтаксис, то при разборе будет всегда выдаваться сообщение об ошибке, так как в параметр pattern будет помещаться выражение in, а далее парсер не сможет найти ключевое слово in.
Это вынуждает прибегать к хитрости. У реального макроса ForEach есть только два параметра:
  macro @foreach (inexpr, body)
  syntax ("foreach", "(", inexpr, ")", body)
  {

а выражения pattern и collectoin добываются позже с помощью паттерн-матчинга.
Причем этот трюк работает не всегда, так как не всегда грамматика оператора совпадает с требуемой грамматикой.

О гибкости конструкций верхнего уровня уже и речи быть не может.

Лексерные макросы лишены подобных ограничений, но в них обязанности разбора (парсинга) выражения ложатся на создателя макроса. Это сильно усложняет его работу. Примером лексерного макроса является PegGrammar.

В отличии от этого подхода в Н2 всегда задается произвольная грамматика. В Н2 даже не будет выделенного понятия приоритет. Вместо этого в нем будет возможность создавать правила использующие силу связывания (похожий механизм используется в операторах Н1).

Фактически изменение синтаксиса любого языка созданного на базе Н2 (подчеркиваю, не только Н2 как языка, но и, например, C#) ограничено только согласованностью грамматики языка и соответствию правилам контекстно-свободной грамматики (точнее правилам нашего генератора парсеров, так как они несколько отличаются от КСГ).

Точкой расширения в грамматиках Н2 задаются авторами этих грамматик. Макрос сможет создавать новые точки расширения. Для этого достаточно просто объявить правило без тела.

4. В Н1 макросы типизируются после раскрытия (точнее макросы раскрываются в процессе типизации). Макрос по сути нетипизирован. Чтобы получить выгоду от знания и управления типами он должен вмешаться в процесс типизации и произвести ручную типизацию подвыражений (или сгенерированного кода). Это не позволяет перегружать синтаксические расширения. Например, не может быть два foreach-а с одинаковым синтаксисом, но разными реализациями (в зависимости от типов аргументов). Это вынуждает разработчика макроса реализовывать всю логику внутри одного макроса (используя ручную типизацию). А это уменьшает возможности расширения, так как нельзя создать альтернативую реализацию макроса (точнее такую реализацию нельзя будет использовать параллельно с основной в одной области видимости).

ME>этот вопрос стоит задать в отдельном треде, или ты прямо тут расскажешь это, и покажешь, почему пришлось синтаксис вынести в строку?


Вынес в отдельную тему.

ME>понятно, что "расширение синтаксиса, завернутое в строку" позволяет сделать все что угодно — так что имеются в виду граници расширения синтаксиса другими способами


В Н2 как раз ограниченя будут практически сняты. Если ее учитывать крутость самого парсера (предикаты, откаты, ...), то возможности по расширению синтаксиса становятся просто беспредельными.

Именно это позволит нам реализовать не один язык, а любое их кличество.
Есть логика намерений и логика обстоятельств, последняя всегда сильнее.
 
Подождите ...
Wait...
Пока на собственное сообщение не было ответов, его можно удалить.