Разрыв в поведении грамматики между 6.c и 6.d? - PullRequest
10 голосов
/ 19 мая 2019

У меня есть грамматика, которая отлично работает в 6.c (2018.01) - я не могу получить стабильный вывод в 6.d (2019.03.01).

Когда я включаю грамматику ::Tracer (приятно!), Шаблон выглядит согласованным.

Но с тем же вводом 'm / s' мой вывод случайным образом бродит по диапазону результатов для примера ... * m / s = m.True * m / s = True.m * m / s = s-1.True * m / s = ms-1 (это тот, который я хочу, мне плевать на порядок)

Я с подозрением отношусь к unam =>Object s 」「 / 」「 m 」содержимое объекта сопоставления (см. Код отладки) - Tracer показывает только одно совпадение для unam в каждой ветви.

Все советы приветствуются!

#!/usr/bin/env perl6

sub get-dime( $dime-str ) { 
        use Grammar::Tracer;

        my $unit-names = '|m|s';

        grammar UnitGrammar {
            token TOP     { <dim> <divi> <den> }
            token divi    { \/ }
            token dim     { <unam> }
            token den     { <unam> }
            token unam    { <$unit-names> }
        }    
        class UnitActions {
            method TOP($/)     { make $/.values.[0].made~'.'~$/.values.[1].made }
            method dim($/)     { make ~$<unam> }
            method den($/)     { make ~$<unam>~'-1' }
            method divi($/)    { make True }
        }    

        my $match = UnitGrammar.parse($dime-str, :actions(UnitActions));

        #[[ verbose for debug (also uncomment #use Grammar::Tracer)
        say "$match=", $match.made;
        say "--------------------";
        say $match.values;
        say $match.values.[0].made;
        say $match.values.[1].made;
        #]]  

        return $match.made if $match.so;
}
say $*PERL.compiler.version;
say get-dime( 'm/s' );

бан enter image description here

Ответы [ 2 ]

10 голосов
/ 19 мая 2019

@ Хакон назвал игру.Вы отправляетесь на посадку на трассе.Я получил нас рядом с зеленым, но в грубой.@ugexe заметил мяч.@ Хакон пропустил эту дыру, перешел к следующей тройке и спрятался в одну.Так что я думаю, что мне осталось написать об окончании игры.


Это не 6.c против 6.d.

Основная проблема заключается в том, что хеши указываются дляих пары ключ / значение перечислены в случайном порядке.В более ранних компиляторах реализация хэш-списка возвращала пары ключ / значение в фиксированном порядке.Затем samcv реализовал хэш-рандомизацию для MoarVM в прошлом году .Он нарушает код, который неправильно полагается на порядок хеширования.

Таким образом, следующий код - на Rakudo / MoarVM с 2018.05 - случайным образом отображает либо (a b), либо (b a):

say .values given { apple => 'a', bananas => 'b' }

Ваш код вызывал .values для Match объекта.

Вызов этого метода обычно сводится к чему-то похожему на:

say .values given ( apple => 'a', bananas => 'b', 0, 1, 2 ) .Capture

, который будет отображать список, начинающийся с0 1 2 (они позиционные, поэтому они отображаются сначала в правильном порядке), а затем либо a b или b a (они называются так, что отображаются последними в случайном порядке).

Это, в свою очередь, объясняется тем, что Match является подклассом Capture и наследует свой метод .values от этого класса.Как его документ говорит:

Возвращает Seq, содержащий все позиционные значения, за которыми следуют все именованные значения аргументов.

В вашем коде былонет позиционных захватов.Итак, все, что вам нужно было увидеть, это значения именованных захватов.Но, конечно, они находятся в списке, поэтому появляются под индексами .[0], .[1] и т. Д., Которые предположительно заставили вас думать, что они были заказаны (в сочетании с тем фактом, что в ранних Rakudos их предположительно случайный порядок былв действительности исправлено).

.caps улучшает это, поскольку упорядочивает свои значения в соответствии с их позициями совпадения на входе.Это обеспечит стабильное упорядочение списка значений именованных захватов - при условии, что ни один из захватов не разделяет совпадающую позицию:

say .caps given 'foo' ~~ / $<alias>=<ident> /

будет случайным образом отображать либо (alias => 「foo」 ident => 「foo」), либо (ident => 「foo」 alias => 「foo」).

Мой первый ответ

Для протокола, вот первая версия этого ответа:

Здесь игра в гольф настолько низка, насколько я думаю:

grammar {
  token TOP { <one> <two> }
  token one { 1 }
  token two { 2 }
}.parse('12').values.say;

В v2018.04, текущей версии, запущенной на tio.run, она достоверно отображает (「1」 「2」).В v2018.12 это текущая версия, работающая на glot.io, которая выдает либо (「1」 「2」), либо (「2」 「1」), случайным образом варьируясь между ними.

Я не знаю, является ли это ошибкой.Расследование продолжается, но я решил опубликовать это как первоначальный ответ.

6 голосов
/ 19 мая 2019

Я не уверен, какой заказ $/.values должен вернуть (я получаю случайный порядок, как вы описываете), но вместо использования $/.values:

method TOP($/)     {
     make $<divi> ?? $/.values.[0].made~'.'~$/.values.[1].made
                  !! $/.values.[0].made
}

Вы можете использовать try $/.caps:

method TOP($/)     {
    make $<divi> ?? $/.caps.[0].value.made~'.'~$/.caps.[2].value.made
                 !! $/.caps.[0].value.made
}

по крайней мере, это работает для меня.

...