← All programs · Grammars and match trees

Grammars and match trees #18

≠
Raku++ 4.0.1 prints something different from Rakudo 2026.08

Rakudo 2026.08 runs this program cleanly; the lines marked ≠ below are where the answers part. A difference is a lead, not a verdict: sometimes both are valid Raku, and sometimes Rakudo is the one that is wrong. This difference is preserved as a Rakumap finding ↗

The program

The grammar and its inputs come first. rm-dump, the same in every program of this topic, prints one line for every field of every node of the resulting Match — its text, position, .orig, .prematch, .made, its captures — so a difference in the shape of the match shows as a difference in output.

my token r0 { \w }
my token r1 { $<k0>=[ \w ] <&r0> }
my rule r2 { <r0> }
sub rm-q($v) { $v.defined ?? $v.raku !! 'Nil' }
sub rm-dump($m, Str $p) {
    unless $m.defined { say "$p kind Nil"; return }
    if $m ~~ Match {
        say "$p kind Match";
        say "$p str {$m.Str.raku}";
        say "$p from {$m.from}";
        say "$p to {$m.to}";
        say "$p orig {rm-q($m.orig)}";
        say "$p target {rm-q($m.target)}";
        say "$p pre {rm-q($m.prematch)}";
        say "$p post {rm-q($m.postmatch)}";
        say "$p made {rm-q($m.made)}";
        for $m.list.kv -> $i, $c { rm-dump($c, $p ~ '[' ~ $i ~ ']') }
        for $m.hash.keys.sort -> $k { rm-dump($m.hash{$k}, $p ~ '<' ~ $k ~ '>') }
        # Captures that start at the same position have no specified order
        # (rakupp's varies from run to run), so ties are ordered by name.
        say "$p caps {$m.caps.sort({ .value.from, ~.key }).map({ .key ~ '=' ~ .value.Str.raku }).join(' ')}";
    }
    elsif $m ~~ Positional {
        say "$p kind List({$m.elems})";
        for $m.list.kv -> $i, $c { rm-dump($c, $p ~ '.' ~ $i) }
    }
    else { say "$p kind {$m.^name}" }
}
my @inputs = "0", "1_", "";
for @inputs.kv -> $i, $in {
    say "#$i input {$in.raku}";
    if $in ~~ / :ratchet ( ( $<k0>=[ <k1=&r2> ] ) ) / { rm-dump($/, '@' ~ $i) }
    else { say '@' ~ $i ~ ' kind Nil' }
}

Run executes the program in your browser, with the Raku++ build this site ships. Edit it and try variations.

What each compiler printed

Rakudo 2026.08Raku++ 4.0.1
input "0"
$/ kindMatchMatch
$/ str"0""0"
$/ from00
$/ to11
$/ orig"0""0"
$/ target"0""0"
$/ pre""""
$/ post""""
$/ madeNilNil
$/[0] kindMatchMatch
$/[0] str"0""0"
$/[0] from00
$/[0] to11
$/[0] orig"0""0"
$/[0] target"0""0"
$/[0] pre""""
$/[0] post""""
$/[0] madeNilNil
$/[0][0] kindMatchMatch
$/[0][0] str"0""0"
$/[0][0] from00
$/[0][0] to11
$/[0][0] orig"0""0"
$/[0][0] target"0""0"
$/[0][0] pre""""
$/[0][0] post""""
$/[0][0] madeNilNil
$/[0][0]<k0> kindMatchMatch
$/[0][0]<k0> str"0""0"
$/[0][0]<k0> from00
$/[0][0]<k0> to11
$/[0][0]<k0> orig"0""0"
$/[0][0]<k0> target"0""0"
$/[0][0]<k0> pre""""
$/[0][0]<k0> post""""
$/[0][0]<k0> madeNilNil
$/[0][0]<k0> capsr0="0" ≠
$/[0][0]<k1> kindMatchMatch
$/[0][0]<k1> str"0""0"
$/[0][0]<k1> from00
$/[0][0]<k1> to11
$/[0][0]<k1> orig"0""0"
$/[0][0]<k1> target"0""0"
$/[0][0]<k1> pre""""
$/[0][0]<k1> post""""
$/[0][0]<k1> madeNilNil
$/[0][0]<k1><r0> kindMatchMatch
$/[0][0]<k1><r0> str"0""0"
$/[0][0]<k1><r0> from00
$/[0][0]<k1><r0> to11
$/[0][0]<k1><r0> orig"0""0"
$/[0][0]<k1><r0> target"0""0"
$/[0][0]<k1><r0> pre""""
$/[0][0]<k1><r0> post""""
$/[0][0]<k1><r0> madeNilNil
$/[0][0]<k1><r0> caps
$/[0][0]<k1> capsr0="0"r0="0"
$/[0][0] capsk0="0" k1="0"k0="0" k1="0"
$/[0] caps0="0"0="0"
$/ caps0="0"0="0"
input "1_"
$/ kindMatchMatch
$/ str"_""_"
$/ from11
$/ to22
$/ orig"1_""1_"
$/ target"1_""1_"
$/ pre"1""1"
$/ post""""
$/ madeNilNil
$/[0] kindMatchMatch
$/[0] str"_""_"
$/[0] from11
$/[0] to22
$/[0] orig"1_""1_"
$/[0] target"1_""1_"
$/[0] pre"1""1"
$/[0] post""""
$/[0] madeNilNil
$/[0][0] kindMatchMatch
$/[0][0] str"_""_"
$/[0][0] from11
$/[0][0] to22
$/[0][0] orig"1_""1_"
$/[0][0] target"1_""1_"
$/[0][0] pre"1""1"
$/[0][0] post""""
$/[0][0] madeNilNil
$/[0][0]<k0> kindMatchMatch
$/[0][0]<k0> str"_""_"
$/[0][0]<k0> from11
$/[0][0]<k0> to22
$/[0][0]<k0> orig"1_""1_"
$/[0][0]<k0> target"1_""1_"
$/[0][0]<k0> pre"1""1"
$/[0][0]<k0> post""""
$/[0][0]<k0> madeNilNil
$/[0][0]<k0> capsr0="_" ≠
$/[0][0]<k1> kindMatchMatch
$/[0][0]<k1> str"_""_"
$/[0][0]<k1> from11
$/[0][0]<k1> to22
$/[0][0]<k1> orig"1_""1_"
$/[0][0]<k1> target"1_""1_"
$/[0][0]<k1> pre"1""1"
$/[0][0]<k1> post""""
$/[0][0]<k1> madeNilNil
$/[0][0]<k1><r0> kindMatchMatch
$/[0][0]<k1><r0> str"_""_"
$/[0][0]<k1><r0> from11
$/[0][0]<k1><r0> to22
$/[0][0]<k1><r0> orig"1_""1_"
$/[0][0]<k1><r0> target"1_""1_"
$/[0][0]<k1><r0> pre"1""1"
$/[0][0]<k1><r0> post""""
$/[0][0]<k1><r0> madeNilNil
$/[0][0]<k1><r0> caps
$/[0][0]<k1> capsr0="_"r0="_"
$/[0][0] capsk0="_" k1="_"k0="_" k1="_"
$/[0] caps0="_"0="_"
$/ caps0="_"0="_"
input ""
$/ kindNilNil
$/[0][0]<k0><r0> kind—Match ≠
$/[0][0]<k0><r0> str—"0" ≠
$/[0][0]<k0><r0> from—0 ≠
$/[0][0]<k0><r0> to—1 ≠
$/[0][0]<k0><r0> orig—"0" ≠
$/[0][0]<k0><r0> target—"0" ≠
$/[0][0]<k0><r0> pre—"" ≠
$/[0][0]<k0><r0> post—"" ≠
$/[0][0]<k0><r0> made—Nil ≠
$/[0][0]<k0><r0> caps— ≠
$/[0][0]<k0><r0> kind—Match ≠
$/[0][0]<k0><r0> str—"_" ≠
$/[0][0]<k0><r0> from—1 ≠
$/[0][0]<k0><r0> to—2 ≠
$/[0][0]<k0><r0> orig—"1_" ≠
$/[0][0]<k0><r0> target—"1_" ≠
$/[0][0]<k0><r0> pre—"1" ≠
$/[0][0]<k0><r0> post—"" ≠
$/[0][0]<k0><r0> made—Nil ≠
$/[0][0]<k0><r0> caps— ≠