TL; DR Ваш метод действия сработает, если ваш rule
создаст структуру данных, которую ожидает метод. Поэтому мы исправим rule
и оставим метод в покое.
Основная проблема
Давайте предположим, что правило EX1
вставлено в рабочую грамматику; строка была успешно проанализирована; подстрока ex2/ex2/ex2
соответствует правилу EX1
; и мы отобразили соответствующую часть дерева разбора (просто say
используя результаты .parse
с использованием грамматики):
EX1 => 「ex2/ex2/ex2」
EX2 => 「ex2」
0 => 「/ex2」
EX2 => 「ex2」
0 => 「/ex2」
EX2 => 「ex2」
Обратите внимание на посторонние 0 =>
снимки и то, как вторые и третьи EX2
смещены под ними и смещены относительно первого EX2
. Это неправильная структура вложений относительно предположений вашего метода.
Решение Брэда главной проблемы
Как отметил Брэд ++ в своем комментарии в ответ на первую версию этого ответа, вы можете просто переключиться с конструкции, которая группирует и захватывает ((...)
), на конструкцию, которая только группирует ([...]
).
rule EX1 { <EX2> [ '/' <EX2>]* }
Теперь соответствующий фрагмент дерева разбора для той же входной строки, как указано выше:
EX1 => 「ex2/ex2/ex2」
EX2 => 「ex2」
EX2 => 「ex2」
EX2 => 「ex2」
Захваты 0
исчезли, а EX2
теперь все братья и сестры. Для дальнейшего обсуждения того, когда и почему P6 вложений фиксирует то, как оно происходит, см. ответ jnthn на Почему / как ... захват групп? .
Ваш метод действия теперь должен работать - для некоторых входов ...
Решение Хокон другой вероятной проблемы
Если решение Брэда работает для некоторых входных данных, для которых вы ожидаете, что оно будет работать, но не для всех, вероятно, часть проблемы заключается в том, как ваш rule
соответствует между <EX2>
и символом /
.
Как отметил Хакон ++ в своем ответе, у вашего rule
есть интервалы, которые, вероятно, не соответствуют вашим ожиданиям.
Если вы не хотите, чтобы интервал в вашем шаблоне был значительным, не используйте rule
. В token
или regex
все пробелы в шаблоне (игнорирование внутри строки, например, ' '
) просто для того, чтобы сделать ваш шаблон более читабельным и не имеет смысла по отношению к любой входной строке, которая сопоставляется , В случае сомнений используйте token
(или regex
), а не rule
:
token EX1 { <EX2> ( '/' <EX2>)* }
? ? ? ? ? ?
Интервал, обозначенный ?
, не имеет значения. Вы можете опустить или расширить его, и это не будет иметь никакого значения для того, как правило соответствует вводу. Это только для удобства чтения.
Напротив, весь смысл конструкции rule
состоит в том, что пробел после каждого атома и каждого квантификатора в шаблоне значим . Такой интервал неявно применяет (переопределенное пользователем) правило сопоставления границ (по умолчанию правило, разрешающее пробелы и / или переход между символами «слово» и не «слово») после соответствующей подстроки во входных данных.
В вашем правиле EX1
, которое я повторяю ниже с преувеличенным интервалом для обеспечения ясности, некоторые интервалы не значимы, так же, как это не в token
или regex
:
rule EX1 { <EX2> ( '/' <EX2>)* }
? ? ?
Как и раньше, ?
указывает на несущественный интервал - вы можете его опустить или расширить, и это не будет иметь значения. Следует помнить, что пробелы в начале шаблона (или подшаблона) предназначены только для удобства чтения. (Опыт использования показал, что было бы намного лучше, если бы какой-либо интервал не считался значимым.)
Но интервал или отсутствие интервала после атома или квантификатора значим:
This spacing is significant: ⮟ ⮟ ⮟
rule EX1 { <EX2> ( '/' <EX2>)* }
This LACK of spacing is significant: ⮝⮝
Путем написания rule
, как вы сделали, вы указываете P6, что нужно сопоставлять ввод только с сопоставлением границ (которое по умолчанию допускает пропуски):
после первый <EX2>
(и, следовательно, до * первый /
);
между /
и последующими <EX2>
совпадениями;
после последнего последнего <EX2>
матча.
Итак, ваше правило говорит P6 разрешить пробелы между /
и <EX2>
совпадать с , когда они встречаются в таком порядке - /
, затем <EX2>
.
Ноон также указывает P6 не разрешать пробелы наоборот - между <EX2>
соответствием и /
совпадением в , что в порядке!За исключением самой первой пары <EX2> '/'
!P6 позволит вам объявлять шаблоны соответствия произвольной сложности, включая интервалы, но я сомневаюсь, что это то, что вы имели в виду или хотите.
Для полного перечисления того, что означает «после атома» (то есть, когда пробел в rule
s имеет значение) см. Когда пробелы действительно важны в грамматиках Perl6? .
Эта важная особенность интервалов:
Classic Perl DWIMery предназначен для облегчения жизни;
Идиоматический - используется в большинстве грамматик, потому что действительно действительно облегчает жизнь;
Единственная причина, по которой существует декларатор rule
(этот существенный аспект - только разница между rule
и token
);
Полностью необязательный, потому что вместо него можно использовать token
.
Если кто-то, читающий это, думает, что он предпочел бы не использовать эту важную функцию пространства, онвместо этого можно использовать token
s.(Это, в свою очередь, вероятно, заставит их понять, почему rule
существует как опция, а затем, или, возможно, позже, понять, почему он работает так, как работает, и заново оценить его DWIMery. :))
Встроенная конструкция для сопоставляемого вами шаблона
Наконец, вот идиоматический способ написать шаблон, который вы пытаетесь сопоставить:
rule EX1 { <EX2> + % '/' }
Это говорит P6 о соответствииодин или несколько <EX2>
с, разделенных /
символами.См. Модифицированный квантификатор: %
, %%
для объяснения этой хорошей конструкции.
Это все еще rule
, поэтому большая часть расстояния вэто остается значительным. Точные детали того, когда он есть и нет , по-видимому, наиболее вероятны для этой конструкции, потому что он имеет до трех значительных распорок, а одна - нет:
NOT significant: ⮟ ⮟
rule EX1 { <EX2> + % '/' }
Significant: ⮝ ⮝ ⮝
Включая интервалыи до и после +
с избыточностью:
rule EX1 { <EX2> + % '/' }
rule EX1 { <EX2> +% '/' } # same match result
rule EX1 { <EX2>+ % '/' } # same match result