← All programs · Grammars and match trees

Grammars and match trees #17

≠
Raku++ 5.0.0-g312cde8e 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.

grammar G {
    rule TOP { <r1> | <k1=r2>* <r2> <k0=r1> <k1=r2> $ }
    token r0 { \d }
    rule r1 { <[a..c]> }
    rule r2 { [ [ 'a' ] ] }
}
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 = "a a a b a ", "a a c a ", "  c a ";
for @inputs.kv -> $i, $in {
    say "#$i input {$in.raku}";
    rm-dump(G.subparse($in), '@' ~ $i);
}

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++ 5.0.0-g312cde8e
input "a a a b a "
$/ kindMatchMatch
$/ str"a a a b a ""a " ≠
$/ from00
$/ to102 ≠
$/ orig"a a a b a ""a a a b a "
$/ target"a a a b a ""a a a b a "
$/ pre""""
$/ post"""a a b a " ≠
$/ madeNilNil
$/<k0> kindMatch— ≠
$/<k0> str"b "— ≠
$/<k0> from6— ≠
$/<k0> to8— ≠
$/<k0> orig"a a a b a "— ≠
$/<k0> target"a a a b a "— ≠
$/<k0> pre"a a a "— ≠
$/<k0> post"a "— ≠
$/<k0> madeNil— ≠
$/<k0> caps— ≠
$/<k1> kindList(3)List(0) ≠
$/<k1>.0 kindMatch— ≠
$/<k1>.0 str"a "— ≠
$/<k1>.0 from0— ≠
$/<k1>.0 to2— ≠
$/<k1>.0 orig"a a a b a "— ≠
$/<k1>.0 target"a a a b a "— ≠
$/<k1>.0 pre""— ≠
$/<k1>.0 post"a a b a "— ≠
$/<k1>.0 madeNil— ≠
$/<k1>.0 caps— ≠
$/<k1>.1 kindMatch— ≠
$/<k1>.1 str"a "— ≠
$/<k1>.1 from2— ≠
$/<k1>.1 to4— ≠
$/<k1>.1 orig"a a a b a "— ≠
$/<k1>.1 target"a a a b a "— ≠
$/<k1>.1 pre"a "— ≠
$/<k1>.1 post"a b a "— ≠
$/<k1>.1 madeNil— ≠
$/<k1>.1 caps— ≠
$/<k1>.2 kindMatch— ≠
$/<k1>.2 str"a "— ≠
$/<k1>.2 from8— ≠
$/<k1>.2 to10— ≠
$/<k1>.2 orig"a a a b a "— ≠
$/<k1>.2 target"a a a b a "— ≠
$/<k1>.2 pre"a a a b "— ≠
$/<k1>.2 post""— ≠
$/<k1>.2 madeNil— ≠
$/<k1>.2 caps— ≠
$/<r1> kindMatchMatch
$/<r1> str"b ""a " ≠
$/<r1> from60 ≠
$/<r1> to82 ≠
$/<r1> orig"a a a b a ""a a a b a "
$/<r1> target"a a a b a ""a a a b a "
$/<r1> pre"a a a """ ≠
$/<r1> post"a ""a a b a " ≠
$/<r1> madeNilNil
$/<r1> caps
$/<r2> kindList(4)List(0) ≠
$/<r2>.0 kindMatch— ≠
$/<r2>.0 str"a "— ≠
$/<r2>.0 from0— ≠
$/<r2>.0 to2— ≠
$/<r2>.0 orig"a a a b a "— ≠
$/<r2>.0 target"a a a b a "— ≠
$/<r2>.0 pre""— ≠
$/<r2>.0 post"a a b a "— ≠
$/<r2>.0 madeNil— ≠
$/<r2>.0 caps— ≠
$/<r2>.1 kindMatch— ≠
$/<r2>.1 str"a "— ≠
$/<r2>.1 from2— ≠
$/<r2>.1 to4— ≠
$/<r2>.1 orig"a a a b a "— ≠
$/<r2>.1 target"a a a b a "— ≠
$/<r2>.1 pre"a "— ≠
$/<r2>.1 post"a b a "— ≠
$/<r2>.1 madeNil— ≠
$/<r2>.1 caps— ≠
$/<r2>.2 kindMatch— ≠
$/<r2>.2 str"a "— ≠
$/<r2>.2 from4— ≠
$/<r2>.2 to6— ≠
$/<r2>.2 orig"a a a b a "— ≠
$/<r2>.2 target"a a a b a "— ≠
$/<r2>.2 pre"a a "— ≠
$/<r2>.2 post"b a "— ≠
$/<r2>.2 madeNil— ≠
$/<r2>.2 caps— ≠
$/<r2>.3 kindMatch— ≠
$/<r2>.3 str"a "— ≠
$/<r2>.3 from8— ≠
$/<r2>.3 to10— ≠
$/<r2>.3 orig"a a a b a "— ≠
$/<r2>.3 target"a a a b a "— ≠
$/<r2>.3 pre"a a a b "— ≠
$/<r2>.3 post""— ≠
$/<r2>.3 madeNil— ≠
$/<r2>.3 caps— ≠
$/ capsk1="a " r2="a " k1="a " r2="a " r2="a " k0="b " r1="b " k1="a " r2="a "r1="a " ≠
input "a a c a "
$/ kindMatchMatch
$/ str"a a c a ""a " ≠
$/ from00
$/ to82 ≠
$/ orig"a a c a ""a a c a "
$/ target"a a c a ""a a c a "
$/ pre""""
$/ post"""a c a " ≠
$/ madeNilNil
$/<k0> kindMatch— ≠
$/<k0> str"c "— ≠
$/<k0> from4— ≠
$/<k0> to6— ≠
$/<k0> orig"a a c a "— ≠
$/<k0> target"a a c a "— ≠
$/<k0> pre"a a "— ≠
$/<k0> post"a "— ≠
$/<k0> madeNil— ≠
$/<k0> caps— ≠
$/<k1> kindList(2)List(0) ≠
$/<k1>.0 kindMatch— ≠
$/<k1>.0 str"a "— ≠
$/<k1>.0 from0— ≠
$/<k1>.0 to2— ≠
$/<k1>.0 orig"a a c a "— ≠
$/<k1>.0 target"a a c a "— ≠
$/<k1>.0 pre""— ≠
$/<k1>.0 post"a c a "— ≠
$/<k1>.0 madeNil— ≠
$/<k1>.0 caps— ≠
$/<k1>.1 kindMatch— ≠
$/<k1>.1 str"a "— ≠
$/<k1>.1 from6— ≠
$/<k1>.1 to8— ≠
$/<k1>.1 orig"a a c a "— ≠
$/<k1>.1 target"a a c a "— ≠
$/<k1>.1 pre"a a c "— ≠
$/<k1>.1 post""— ≠
$/<k1>.1 madeNil— ≠
$/<k1>.1 caps— ≠
$/<r1> kindMatchMatch
$/<r1> str"c ""a " ≠
$/<r1> from40 ≠
$/<r1> to62 ≠
$/<r1> orig"a a c a ""a a c a "
$/<r1> target"a a c a ""a a c a "
$/<r1> pre"a a """ ≠
$/<r1> post"a ""a c a " ≠
$/<r1> madeNilNil
$/<r1> caps
$/<r2> kindList(3)List(0) ≠
$/<r2>.0 kindMatch— ≠
$/<r2>.0 str"a "— ≠
$/<r2>.0 from0— ≠
$/<r2>.0 to2— ≠
$/<r2>.0 orig"a a c a "— ≠
$/<r2>.0 target"a a c a "— ≠
$/<r2>.0 pre""— ≠
$/<r2>.0 post"a c a "— ≠
$/<r2>.0 madeNil— ≠
$/<r2>.0 caps— ≠
$/<r2>.1 kindMatch— ≠
$/<r2>.1 str"a "— ≠
$/<r2>.1 from2— ≠
$/<r2>.1 to4— ≠
$/<r2>.1 orig"a a c a "— ≠
$/<r2>.1 target"a a c a "— ≠
$/<r2>.1 pre"a "— ≠
$/<r2>.1 post"c a "— ≠
$/<r2>.1 madeNil— ≠
$/<r2>.1 caps— ≠
$/<r2>.2 kindMatch— ≠
$/<r2>.2 str"a "— ≠
$/<r2>.2 from6— ≠
$/<r2>.2 to8— ≠
$/<r2>.2 orig"a a c a "— ≠
$/<r2>.2 target"a a c a "— ≠
$/<r2>.2 pre"a a c "— ≠
$/<r2>.2 post""— ≠
$/<r2>.2 madeNil— ≠
$/<r2>.2 caps— ≠
$/ capsk1="a " r2="a " r2="a " k0="c " r1="c " k1="a " r2="a "r1="a " ≠
input " c a "
$/ kindMatchNil ≠
$/ str""— ≠
$/ from0— ≠
$/ to-3— ≠
$/ orig" c a "— ≠
$/ target" c a "— ≠
$/ pre""— ≠
$/ post" a "— ≠
$/ madeNil— ≠
$/ caps— ≠