[Nitra] Параметризованные правила
От: VladD2 Российская Империя www.nemerle.org
Дата: 03.11.14 16:39
Оценка: 18 (1)
Мы тут продумываем дизайн параметризованных правил. В двух словах параметризованные правила — это правила которые имеют нечто вроде параметра типов, но вместо типа в него подставляется другое правило. Получается что-то вроде обобщенных правил.

Вот пример (из реальной грамматики JSON) демонстрирующий проблему решаемую параметризованными правилами:
regex HexDigit = ['0'..'9', 'a'..'f', 'A'..'F'];
regex EscChar  = '\\' | '/' | 'b' | 'f' | 'n' | 'r'| 't' | 'u' HexDigit{4,4}
 
[SpanClass(String)]
token StringLiteral1 = Quote StringPart* Quote
{
  regex Quote   = '\"';
  regex Esc     = '\\' (Quote | EscChar);
  regex Escs    = Esc+;
  regex NotEscs = ~(Any* (Quote | '\\') Any*) - "";
 
  token StringPart
  {
    | Escs;
    | NotEscs;
  }
}
 
[SpanClass(String)]
token StringLiteral2 = Quote StringPart* Quote
{
  regex Quote   = '\'';
  token StringPart
  {
    regex Esc = '\\' (Quote | EscChar);
    | Escs    { regex Escs    = Esc+; }
    | NotEscs { regex NotEscs = ~(Any* (Quote | '\\') Any*) - ""; }
  }
}
 
syntax Value
{
  | Identifier
  | StringLiteral1
  | StringLiteral2
  ...


Выделенное жирным правило StringLiteral2 практически дублирует правило StringLiteral1. Разница заключается только в типе кавычки заданной в подправиле Quote.

Бывают случае когда такое дублирование принимает угрожающие размеры. Например, в грамматике нового форматера РСДН таких мест довольно много Paragraph.nitra, Content.nitra. Правило Part, в каждом своем вхождении, дублирует один и тот же код.

Так вот возникла идея ввести параметризованные правила, чтобы избавиться от этого дублирования.
Вот пример приведенной выше грамматики литералов JSON-а переписанный с гипотетическими параметризованными правилами:

regex HexDigit = ['0'..'9', 'a'..'f', 'A'..'F'];
regex EscChar  = '\\' | '/' | 'b' | 'f' | 'n' | 'r'| 't' | 'u' HexDigit{4,4}
 
[SpanClass(String)]
token StringLiteral<Quote> = Quote StringPart* Quote
{
  regex Esc     = '\\' (Quote | EscChar);
  regex Escs    = Esc+;
  regex NotEscs = ~(Any* (Quote | '\\') Any*) - "";
 
  token StringPart
  {
    | Escs;
    | NotEscs;
  }
}
 
syntax Value
{
  | Identifier
  | StringLiteral1 = StringLiteral<'\"'>
  | StringLiteral2 = StringLiteral<'\''>
  ...


Думаю все очевидно.

Теперь, собственно, вопрос!

Так как Нитра является статически типизируемым языком, на параметры правил налагаются определенные ограничения. В приведенном примере в качестве параметра Quote можно подставить исключительно regex-правило, так как оно применяется в теле другого regex-правила. Могут быть следующие ограничения:
1. Параметр может быть исключительно regex-правилом.
2. Параметр может быть regex-правилом или token-правилом.
3. Параметр может быть любым правилом (т.е. regex, token или syntax).

В приведенном примере тип параметра выводится из использования, т.е. при компиляции компилятор узнает тип Quote только после того как проведет анализ всех (или части) подправил. Так как параметры правил это часть публичного интерфейса, то резонно возникают сомнения относительно целесообразности его вывода.

Альтернативой выводу типа параметров может быть явная его задание при объявлении параметра.
Например, так:
[SpanClass(String)]
token StringLiteral<regex Quote> = Quote StringPart* Quote
...


Собственно вопрос в том насколько интуитивным являются следующие соглашения
* regex — означает что правило может быть только regex-ом.
* token — правило может быть token-правилом или regex-ом.
* syntax — правило может быть syntax-правилом, token-правилом или regex-ом.

Не введет ли это пользователей в заблуждение?

Если это плохое решение, то предлагайте свои варианты, которые кажутся вам более интуитивными.

ЗЫ

Еще, возможно, будет разумно различать аннотации для расширяемых правил (или-правила) и для обычных. Тут уже совсем не ясно как это описать синтаксически. Если есть идеи, милости просим.
Есть логика намерений и логика обстоятельств, последняя всегда сильнее.
Re: [Nitra] Параметризованные правила
От: btn1  
Дата: 03.11.14 18:50
Оценка:
Здравствуйте, VladD2, Вы писали:

VD>3. Параметр может быть любым правилом (т.е. regex, token или syntax).


С этого момента непонятно PEG — он же вроде однородный, описал правило — получи соответствие! Зачем нужны типы для правил?
Re: [Nitra] Параметризованные правила
От: s22  
Дата: 03.11.14 19:41
Оценка:
Здравствуйте, VladD2, Вы писали:


Почему тогда не сделать параметризацией и константами?
[SpanClass(String)]
token StringLiteral<Count> = Strings
{
  regex Strings= Digit(Count,Count);
}
Re[2]: [Nitra] Параметризованные правила
От: VladD2 Российская Империя www.nemerle.org
Дата: 03.11.14 20:05
Оценка:
Здравствуйте, btn1, Вы писали:

B>С этого момента непонятно PEG — он же вроде однородный, описал правило — получи соответствие! Зачем нужны типы для правил?


В Найтре давно не совсем PEG. На нижнем уровне используются классические регулярные выражения. Они быстрее и экономичнее по памяти.
Так же делается разделение на обычные правила и токены. Токены — это по сути обычные правила (в них доступна рекурсия), но в них не производится подстановка пробельных правил и они иначе интерпретируются при восстановлении и в IDE.
Есть логика намерений и логика обстоятельств, последняя всегда сильнее.
Re[2]: [Nitra] Параметризованные правила
От: VladD2 Российская Империя www.nemerle.org
Дата: 03.11.14 20:06
Оценка:
Здравствуйте, s22, Вы писали:

s22>Почему тогда не сделать параметризацией и константами?


Зачем?
Есть логика намерений и логика обстоятельств, последняя всегда сильнее.
Re[3]: [Nitra] Параметризованные правила
От: WolfHound  
Дата: 03.11.14 21:18
Оценка:
Здравствуйте, VladD2, Вы писали:

s22>>Почему тогда не сделать параметризацией и константами?

VD>Зачем?
За тем, что у нас вот такая хрень есть.
    | UpperBound = "{" sm        "," sm Number sm "}" { override Bounds = (0,               Some(Number.Value()));  }
    | LowerBound = "{" sm Number ","           sm "}" { override Bounds = (Number.Value(),  None());                }
    | FullBounds = "{" sm Number "," sm Number sm "}" { override Bounds = (Number1.Value(), Some(Number2.Value())); }
    | Exact      = "{" sm Number               sm "}" { override Bounds { def x = Number.Value(); (x, Some(x)); }   }
... << RSDN@Home 1.2.0 alpha 5 rev. 62>>
Пусть это будет просто:
просто, как только можно,
но не проще.
(C) А. Эйнштейн
Re[4]: [Nitra] Параметризованные правила
От: VladD2 Российская Империя www.nemerle.org
Дата: 03.11.14 22:35
Оценка:
Здравствуйте, WolfHound, Вы писали:

WH>За тем, что у нас вот такая хрень есть.


Не думаю, что в этом есть особый смысл.

В прочем, можно и числа поддержать.
Есть логика намерений и логика обстоятельств, последняя всегда сильнее.
Re[5]: [Nitra] Параметризованные правила
От: WolfHound  
Дата: 03.11.14 23:42
Оценка:
Здравствуйте, VladD2, Вы писали:

WH>>За тем, что у нас вот такая хрень есть.

VD>Не думаю, что в этом есть особый смысл.
VD>В прочем, можно и числа поддержать.
Нам это почти ничего не стоит.
... << RSDN@Home 1.2.0 alpha 5 rev. 62>>
Пусть это будет просто:
просто, как только можно,
но не проще.
(C) А. Эйнштейн
Re[6]: [Nitra] Параметризованные правила
От: s22  
Дата: 04.11.14 10:04
Оценка:
Здравствуйте, WolfHound, Вы писали:

WH>Нам это почти ничего не стоит.


А пробрасывать функции? (в методы обработки)
Re[7]: [Nitra] Параметризованные правила
От: WolfHound  
Дата: 04.11.14 11:46
Оценка:
Здравствуйте, s22, Вы писали:

WH>>Нам это почти ничего не стоит.

s22>А пробрасывать функции? (в методы обработки)
Не понял.
... << RSDN@Home 1.2.0 alpha 5 rev. 62>>
Пусть это будет просто:
просто, как только можно,
но не проще.
(C) А. Эйнштейн
Re: [Nitra] Параметризованные правила
От: WolfHound  
Дата: 04.11.14 11:50
Оценка:
Здравствуйте, VladD2, Вы писали:

VD>В приведенном примере тип параметра выводится из использования, т.е. при компиляции компилятор узнает тип Quote только после того как проведет анализ всех (или части) подправил. Так как параметры правил это часть публичного интерфейса, то резонно возникают сомнения относительно целесообразности его вывода.

Моё мнение задавать тип параметра правила нужно явно.
Ибо это публичный контракт правила.
Даже в языках, где вывод типов суров и глобален, правилом хорошего тона является явное задание типов функций, которые экспортируются из модуля.
... << RSDN@Home 1.2.0 alpha 5 rev. 62>>
Пусть это будет просто:
просто, как только можно,
но не проще.
(C) А. Эйнштейн
Re[2]: [Nitra] Параметризованные правила
От: s22  
Дата: 04.11.14 11:54
Оценка:
Здравствуйте, WolfHound, Вы писали:

WH>Здравствуйте, VladD2, Вы писали:


VD>>В приведенном примере тип параметра выводится из использования, т.е. при компиляции компилятор узнает тип Quote только после того как проведет анализ всех (или части) подправил. Так как параметры правил это часть публичного интерфейса, то резонно возникают сомнения относительно целесообразности его вывода.

WH>Моё мнение задавать тип параметра правила нужно явно.
WH>Ибо это публичный контракт правила.
WH>Даже в языках, где вывод типов суров и глобален, правилом хорошего тона является явное задание типов функций, которые экспортируются из модуля.

Согласен.
Но как быть с тем, что синтаксис, токен и регексп не являются наследниками друг друга?
А есл метод может включать снтаксис то может включать регексп
Единственное сделать что то типа иерархии.
Re[8]: [Nitra] Параметризованные правила
От: s22  
Дата: 04.11.14 11:58
Оценка:
Здравствуйте, WolfHound, Вы писали:

WH>Здравствуйте, s22, Вы писали:


WH>>>Нам это почти ничего не стоит.

s22>>А пробрасывать функции? (в методы обработки)
WH>Не понял.
[SpanClass(String)]
token StringLiteral<Count, Digit, F> = Strings1
{
  regex Strings= Digit(Count,Count);
  syntax Strings =  (s:Strings sm) { F(s)}
}

Нечто вроде, как я понимаю там все равно работают макросы, так что много переделывать не потредуется
Re[2]: [Nitra] Параметризованные правила
От: VladD2 Российская Империя www.nemerle.org
Дата: 04.11.14 13:41
Оценка:
Здравствуйте, WolfHound, Вы писали:

WH>Моё мнение задавать тип параметра правила нужно явно.


Да я же не против. Цель этой темы придумать внятный синтаксис или подтвердить, что люди понимают предложенный. Пока что (судя по отсутствию осмысленных ответов) люди его не очень понимают. Даже наличие 3 сущностей кое-кого смущает. А уж указание token за regex явно будет смущать.

Народ! Высказывайтесь, плиз.
Есть логика намерений и логика обстоятельств, последняя всегда сильнее.
Re[3]: [Nitra] Параметризованные правила
От: WolfHound  
Дата: 04.11.14 15:13
Оценка:
Здравствуйте, VladD2, Вы писали:

VD>Да я же не против. Цель этой темы придумать внятный синтаксис или подтвердить, что люди понимают предложенный. Пока что (судя по отсутствию осмысленных ответов) люди его не очень понимают. Даже наличие 3 сущностей кое-кого смущает. А уж указание token за regex явно будет смущать.

У тебя будут ровно эти же сущности. Только они будут выводиться.
... << RSDN@Home 1.2.0 alpha 5 rev. 62>>
Пусть это будет просто:
просто, как только можно,
но не проще.
(C) А. Эйнштейн
Re[3]: [Nitra] Параметризованные правила
От: CodingUnit Россия  
Дата: 05.11.14 12:19
Оценка:
Здравствуйте, VladD2, Вы писали:

VD>Здравствуйте, WolfHound, Вы писали:


WH>>Моё мнение задавать тип параметра правила нужно явно.


VD>Да я же не против. Цель этой темы придумать внятный синтаксис или подтвердить, что люди понимают предложенный. Пока что (судя по отсутствию осмысленных ответов) люди его не очень понимают. Даже наличие 3 сущностей кое-кого смущает. А уж указание token за regex явно будет смущать.


VD>Народ! Высказывайтесь, плиз.


Параметризированные правила хорошая вещь, но мое мнение, параметры типов не надо указывать, притом что это не параметры типов, они не говорят о конкретном правиле или типе, поэтому о типизации здесь речь не идет, сравнивая с обычными языками где есть контракт интерфейса на входные типы, существует всего три варианта подстановки и неужели эту работу выбрать токен, режекс или синтакс не может сделать компилятор за пользователя, которому эти лишние сложности, ключевые слова и ограничения не нужны, он просто пишет быстро грамматику, в наиболее короткой форме, компилятор все остальное делает сам. Параметры правил больше похожи на обобщенные типы где T в большинстве не описывается как определенная сущность, часто там может быть что угодно и при связывании уже метод вызывается со своим T, ограничения на T where T : class и тп делается редко и далеко не всегда, чаще используется обычный <T>. Можно сделать два синтаксиса как и есть в Н и C#, обобщенный <T> которому подставляется что угодно и компилятор найтры смотрит сопоставления при компиляции правила, также можно указать явно токен, режекс или синтакс правило которое может подставляться туда, и можно как публичный интерфейс задавать ограничения на правило, но для обычных проектов где краткость кода и удобство использования языка на главном месте, никакие лишние ключевые слова не нужны, в любом случае если правило переопределяется или используется из внешней библиотеки оно может проверяться при компиляции на соответствие также, как аналогично и с С# и остальными языками с обобщенными типами.
Re: [Nitra] Параметризованные правила
От: kaa_t Россия  
Дата: 05.11.14 14:42
Оценка:
Здравствуйте, VladD2, Вы писали:

VD>Мы тут продумываем дизайн параметризованных правил. В двух словах параметризованные правила — это правила которые имеют нечто вроде параметра типов, но вместо типа в него подставляется другое правило. Получается что-то вроде обобщенных правил.


VD>Собственно вопрос в том насколько интуитивным являются следующие соглашения

VD>* regex — означает что правило может быть только regex-ом.
VD>* token — правило может быть token-правилом или regex-ом.
VD>* syntax — правило может быть syntax-правилом, token-правилом или regex-ом.

Мне кажется, это будет сбивать с толку. Лучше ввести другие ключевые слова.

Еще мне не очень нравятся угловые скобки. Лучше обычные. Оно как то логичнее на мой взгляд, получится.

token StringLiteral ( Quote : token ) = Quote StringPart* Quote



А вообще с введением параметров, напрашиваются управляющие конструкции обрабатывающие входные параметры, что то типа :

syntax Value(Param)
{
    | Identifier
 
 #if Param == 1
    | StringLiteral = StringLiteral('\"');
 #else if Param == 2
    | StringLiteral = StringLiteral('\'');
 #else
    | StringLiteral1 = StringLiteral('\"');
    | StringLiteral2 = StringLiteral('\'');
 #endif
Re[2]: [Nitra] Параметризованные правила
От: VladD2 Российская Империя www.nemerle.org
Дата: 05.11.14 15:34
Оценка:
Здравствуйте, kaa_t, Вы писали:

_>Мне кажется, это будет сбивать с толку. Лучше ввести другие ключевые слова.


Дык, какие?

_>Еще мне не очень нравятся угловые скобки. Лучше обычные. Оно как то логичнее на мой взгляд, получится.


_>
_>token StringLiteral ( Quote : token ) = Quote StringPart* Quote
_>


Угловые скобки банально привычнее для людей. Плюс круглые скобки уж используются в грамматике (внутри правил), так что будет конфликт.

_>А вообще с введением параметров, напрашиваются управляющие конструкции обрабатывающие входные параметры, что то типа :


Эти параметры не препроцессорные символы. Скорее их можно сравнить со ссылками на функции. Параметризованные правила (скорее всего) будут доступны в бинарном виде из внешних сборок (как дженерики или функции).

Так что управлять генерацией кода в них будет нельзя.

Зато у нас и так есть средства расширения — extend.

Список правил можно даже в рантайме изменять. Как минимум мы хотим воспроивести поведение Немерла в котором можно расширять грамматику с помощью using-а (импорта).

Параметризованные же правила — это некий вариант обобщений. Но они будут не шаблонного (шаблонов С++) плана, а скорее более похожими на дженерики дотнета или даже на функции высшего порядка. По сути правила — это функции. Так что для того чтобы передать правилу ссылку на другое правило, нужно просто передать ему ссылку на функцию или некий интерфейс.
Есть логика намерений и логика обстоятельств, последняя всегда сильнее.
Re: [Nitra] Параметризованные правила
От: Рамиль Вахитов  
Дата: 10.11.14 19:01
Оценка:
Если я правильно понял, тип параметра определяется описанием правила, а не объявлением параметра. Для меня важным является описание правила. И если объявление типа конфликтует с описанием правила, тогда я не хочу заморачиваться с объявлением типа.
Re[2]: [Nitra] Параметризованные правила
От: WolfHound  
Дата: 10.11.14 23:42
Оценка:
Здравствуйте, Рамиль Вахитов, Вы писали:

РВ>Если я правильно понял, тип параметра определяется описанием правила, а не объявлением параметра. Для меня важным является описание правила. И если объявление типа конфликтует с описанием правила, тогда я не хочу заморачиваться с объявлением типа.

Не правильно.
Тип у параметра будет и так и так.
Вопрос в том указывать явно или выводить.
... << RSDN@Home 1.2.0 alpha 5 rev. 62>>
Пусть это будет просто:
просто, как только можно,
но не проще.
(C) А. Эйнштейн
Подождите ...
Wait...
Пока на собственное сообщение не было ответов, его можно удалить.