Очень часто требуется возвращать значение из одного из нетерминалов в правиле или внутри субправила в скобках. Например:
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! :улыбка:
Обожаю эту идею! ^
тоже очень интуитивно понятен.
Это может работать и с невложенными правилами:
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, которое ссылается на эту проблему.