Pegjs: Разрешить возвращать результат совпадения определенного выражения в правиле без действия

Созданный на 23 мая 2016  ·  10Комментарии  ·  Источник: pegjs/pegjs

Очень часто требуется возвращать значение из одного из нетерминалов в правиле или внутри субправила в скобках. Например:

varDecl = type:type id:ID init:( EQ e:expr {return e} )?
                { return scopedAST('VARDECL', {type, id, init}) }

В этом случае мне нужен expr помеченный как e внутри уровня скобок init для необязательной фразы на языке. Мне не нужно было "шумовое слово" EQ как часть возвращаемого значения.

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

Чтобы переписать мой пример выше:

varDecl = type:type id:ID init:( EQ ^expr )?
                { return scopedAST('VARDECL', {type, id, init}) }

Обратите внимание на использование ^ для обозначения значения expr внутри необязательного подправила фраз в скобках init для обозначения того, что связано с init . Это упрощает многие ситуации как с заключенным в скобки подправилом, так и без него, показанным в этом примере.

Спасибо за создание такого удивительно простого, элегантного и мощного инструмента. Я люблю PEGjs! :улыбка:

Все 10 Комментарий

Обожаю эту идею! ^ тоже очень интуитивно понятен.

Это может работать и с невложенными правилами:

WhiteSpacedIdentifier = WhiteSpace? identifier:Identifier WhiteSpace {return identifier;}
// becomes
WhiteSpacedIdentifier = WhiteSpace? ^Identifier WhiteSpace?

Очень читабельно! Предположительно, использование нескольких ^ также будет работать, например:

a = ^b  c  ^d  e

Вернет [b, d] ? Кажется, имеет смысл.

Аналогичным образом, кажется логичным, что при смешивании с именованными захватами правила ^ игнорируются, поэтому

x = a ^b foo:c { return foo; }

Вернул бы только гр.

О, эта идея с мультипликаторами великолепна. Смешивание с именованными захватами должно быть
ошибка.

Вт, 5 июля 2016 г., 01:07 Грэм Уэйкфилд [email protected]
написал:

Очень читабельно! Предположительно, использование нескольких ^ также будет работать, например:

а = ^ bc ^ де

Вернется ли [b, d]? Кажется, имеет смысл.

Точно так же, кажется, имеет смысл, что если смешать с именованными захватами, ^
правила игнорируются:

x = a ^ b foo: c {return foo; }

-
Вы получаете это, потому что вы являетесь автором темы.

Ответьте на это письмо напрямую, просмотрите его на GitHub
https://github.com/pegjs/pegjs/issues/427#issuecomment -230413015 или отключить звук
нить
https://github.com/notifications/unsubscribe/ABC26k8v0DIzuWUlkoDZGm2ep10Y5bcMks5qShDAgaJpZM4IkuA9
.

Я полностью согласен, что описанный паттерн довольно распространен. Имеет смысл иметь способ выразить это без действия.

В чем я не так уверен насчет предлагаемого решения (оператор ^ ). Использование специального символа, значение которого не сразу становится очевидным, всегда проблематично и усложняет процесс обучения. Также возможно, что персонажа лучше использовать для других целей. И последнее, но не менее важное: мне не нравится идея помещать в выражения вещи, которые напрямую не влияют на синтаксический анализ. Можно утверждать, что уже есть один пример этого - оператор $ - и я согласен. Но я не уверен, было ли добавление $ (маленькой) ошибкой. Если так, я бы не хотел повторять это снова.

Я подумаю об этом более глубоко после 1.0.0.

Еще немного пищи для размышлений: поскольку ^ и помеченные выражения как бы конфликтуют ( ^ ), как насчет того, чтобы вместо того, чтобы отмечать результат, можно было бы отметить выражения _ignored_, например (предложение синтаксиса!), указав пустую метку:

WhiteSpacedIdentifier = WhiteSpace? identifier:Identifier WhiteSpace {return identifier;}
// becomes
WhiteSpacedIdentifier = :WhiteSpace? Identifier :WhiteSpace?

Там нет нового синтаксиса (у нас уже есть : ), только небольшое расширение семантики:

  • разрешить пустые метки (назовите эти «анонимные» выражения?)
  • если существует только один неанонимный захват, не генерировать массив совпадений выражений, вместо этого возвращать единственное совпадение

В таком случае более последовательный будет помечать пустыми «метками» те выражения, которые нужно будет вернуть в результате. Это, кстати, не для того, чтобы нарушать существующую семантику: метка существует, но не имеет имени; поскольку метки вводятся для доступа к результату, вполне логично, что безымянные метки автоматически становятся результатом. Одновременное наличие автоматических и конкретных этикеток запрещено. Если существует только одна автоматическая метка, то должен быть возвращен единственный результат, но не массив с одним элементом, поскольку такое поведение более востребовано.

@Mingun

Почему бы просто не вернуть этикетку?
start = "{" :expr "}" // return expr
start = "{" label:expr "}" // return label
Я думаю, имеет смысл, что если вы "маркируете" что-то, вы хотите что-то с этим сделать (например, вернуть).

С другой стороны, почему правила вроде start = ex:expr :expr должны вызывать ошибку?
Может быть, он должен делать что-то похожее на переменную аргументов функций javascript? Например, start = ex:expr :expr должен вернуть [ex, expr] . Когда у вас есть действие, должны быть помечены & arguments переменные ( start = ex:expr :expr { return [ex, arguments[0], ex] } )

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

Почему бы просто не вернуть этикетку?

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

К сожалению, необходимо признать, что автоматические метки в том виде, в каком они предлагаются @opatut , невозможно реализовать, поскольку это создает двусмысленность в грамматике. Простейший пример:

start = a :b;// `a` - it is rule reference or label?
a = .;
b = .;

Итак, для этого нужно выбрать другого персонажа. На данный момент есть выбор из: ~ , (backslash) , @ , # , % , ^ , - , | , \ и , .


Другое решение - ввести несколько псевдодействий - ярлыки для создания простых функций для возврата, например, {=>[]} может означать _ "собрать помеченные результаты из последовательности и вернуть их в массив" _ , а {=>{}} - то же самое, но для возврата объекта, с ключами, равными именам меток. Но реализация этого поведения не требует расширения грамматики и вполне может быть реализована с помощью плагинов. Я бы даже сказал, что предпочтительнее иметь такую ​​реализацию плагинами:

start1 = a:'a' b c d:. {=>[]};// returns ['a', <d value>]
start2 = a:'a' b c d:. {=>{}};// returns { a: 'a', d: <d value> }

@Mingun

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

Да, имя важно => Я хочу его использовать => Я хочу вернуть.
В чем проблема с нетривиальными выражениями?

К сожалению, необходимо признать, что автоматические метки в том виде, в каком они предлагаются @opatut , невозможно реализовать, поскольку это создает двусмысленность в грамматике. Простейший пример:

да.
Думаю, ::expression тоже сбивает с толку? @dmajda

Закрыто как дубликат № 235

Изменить: добавлено примечание к комментарию OP к # 235, которое ссылается на эту проблему.

Была ли эта страница полезной?
0 / 5 - 0 рейтинги