← All programs · Grammars and match trees
Grammars and match trees #17
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.08 | Raku++ 4.0.1 | |
|---|---|---|
input "a a a b a " | ||
$/ kind | Match | Match |
$/ str | "a a a b a " | "a " ≠ |
$/ from | 0 | 0 |
$/ to | 10 | 2 ≠ |
$/ 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 " ≠ |
$/ made | Nil | Nil |
$/<k0> kind | Match | — ≠ |
$/<k0> str | "b " | — ≠ |
$/<k0> from | 6 | — ≠ |
$/<k0> to | 8 | — ≠ |
$/<k0> orig | "a a a b a " | — ≠ |
$/<k0> target | "a a a b a " | — ≠ |
$/<k0> pre | "a a a " | — ≠ |
$/<k0> post | "a " | — ≠ |
$/<k0> made | Nil | — ≠ |
$/<k0> caps | | — ≠ |
$/<k1> kind | List(3) | List(0) ≠ |
$/<k1>.0 kind | Match | — ≠ |
$/<k1>.0 str | "a " | — ≠ |
$/<k1>.0 from | 0 | — ≠ |
$/<k1>.0 to | 2 | — ≠ |
$/<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 made | Nil | — ≠ |
$/<k1>.0 caps | | — ≠ |
$/<k1>.1 kind | Match | — ≠ |
$/<k1>.1 str | "a " | — ≠ |
$/<k1>.1 from | 2 | — ≠ |
$/<k1>.1 to | 4 | — ≠ |
$/<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 made | Nil | — ≠ |
$/<k1>.1 caps | | — ≠ |
$/<k1>.2 kind | Match | — ≠ |
$/<k1>.2 str | "a " | — ≠ |
$/<k1>.2 from | 8 | — ≠ |
$/<k1>.2 to | 10 | — ≠ |
$/<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 made | Nil | — ≠ |
$/<k1>.2 caps | | — ≠ |
$/<r1> kind | Match | Match |
$/<r1> str | "b " | "a " ≠ |
$/<r1> from | 6 | 0 ≠ |
$/<r1> to | 8 | 2 ≠ |
$/<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> made | Nil | Nil |
$/<r1> caps | | |
$/<r2> kind | List(4) | — ≠ |
$/<r2>.0 kind | Match | — ≠ |
$/<r2>.0 str | "a " | — ≠ |
$/<r2>.0 from | 0 | — ≠ |
$/<r2>.0 to | 2 | — ≠ |
$/<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 made | Nil | — ≠ |
$/<r2>.0 caps | | — ≠ |
$/<r2>.1 kind | Match | — ≠ |
$/<r2>.1 str | "a " | — ≠ |
$/<r2>.1 from | 2 | — ≠ |
$/<r2>.1 to | 4 | — ≠ |
$/<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 made | Nil | — ≠ |
$/<r2>.1 caps | | — ≠ |
$/<r2>.2 kind | Match | — ≠ |
$/<r2>.2 str | "a " | — ≠ |
$/<r2>.2 from | 4 | — ≠ |
$/<r2>.2 to | 6 | — ≠ |
$/<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 made | Nil | — ≠ |
$/<r2>.2 caps | | — ≠ |
$/<r2>.3 kind | Match | — ≠ |
$/<r2>.3 str | "a " | — ≠ |
$/<r2>.3 from | 8 | — ≠ |
$/<r2>.3 to | 10 | — ≠ |
$/<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 made | Nil | — ≠ |
$/<r2>.3 caps | | — ≠ |
$/ caps | k1="a " r2="a " k1="a " r2="a " r2="a " k0="b " r1="b " k1="a " r2="a " | r1="a " ≠ |
input "a a c a " | ||
$/ kind | Match | Match |
$/ str | "a a c a " | "a " ≠ |
$/ from | 0 | 0 |
$/ to | 8 | 2 ≠ |
$/ orig | "a a c a " | "a a c a " |
$/ target | "a a c a " | "a a c a " |
$/ pre | "" | "" |
$/ post | "" | "a c a " ≠ |
$/ made | Nil | Nil |
$/<k0> kind | Match | — ≠ |
$/<k0> str | "c " | — ≠ |
$/<k0> from | 4 | — ≠ |
$/<k0> to | 6 | — ≠ |
$/<k0> orig | "a a c a " | — ≠ |
$/<k0> target | "a a c a " | — ≠ |
$/<k0> pre | "a a " | — ≠ |
$/<k0> post | "a " | — ≠ |
$/<k0> made | Nil | — ≠ |
$/<k0> caps | | — ≠ |
$/<k1> kind | List(2) | List(0) ≠ |
$/<k1>.0 kind | Match | — ≠ |
$/<k1>.0 str | "a " | — ≠ |
$/<k1>.0 from | 0 | — ≠ |
$/<k1>.0 to | 2 | — ≠ |
$/<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 made | Nil | — ≠ |
$/<k1>.0 caps | | — ≠ |
$/<k1>.1 kind | Match | — ≠ |
$/<k1>.1 str | "a " | — ≠ |
$/<k1>.1 from | 6 | — ≠ |
$/<k1>.1 to | 8 | — ≠ |
$/<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 made | Nil | — ≠ |
$/<k1>.1 caps | | — ≠ |
$/<r1> kind | Match | Match |
$/<r1> str | "c " | "a " ≠ |
$/<r1> from | 4 | 0 ≠ |
$/<r1> to | 6 | 2 ≠ |
$/<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> made | Nil | Nil |
$/<r1> caps | | |
$/<r2> kind | List(3) | — ≠ |
$/<r2>.0 kind | Match | — ≠ |
$/<r2>.0 str | "a " | — ≠ |
$/<r2>.0 from | 0 | — ≠ |
$/<r2>.0 to | 2 | — ≠ |
$/<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 made | Nil | — ≠ |
$/<r2>.0 caps | | — ≠ |
$/<r2>.1 kind | Match | — ≠ |
$/<r2>.1 str | "a " | — ≠ |
$/<r2>.1 from | 2 | — ≠ |
$/<r2>.1 to | 4 | — ≠ |
$/<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 made | Nil | — ≠ |
$/<r2>.1 caps | | — ≠ |
$/<r2>.2 kind | Match | — ≠ |
$/<r2>.2 str | "a " | — ≠ |
$/<r2>.2 from | 6 | — ≠ |
$/<r2>.2 to | 8 | — ≠ |
$/<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 made | Nil | — ≠ |
$/<r2>.2 caps | | — ≠ |
$/ caps | k1="a " r2="a " r2="a " k0="c " r1="c " k1="a " r2="a " | r1="a " ≠ |
input " c a " | ||
$/ kind | Match | Nil ≠ |
$/ str | "" | — ≠ |
$/ from | 0 | — ≠ |
$/ to | -3 | — ≠ |
$/ orig | " c a " | — ≠ |
$/ target | " c a " | — ≠ |
$/ pre | "" | — ≠ |
$/ post | " a " | — ≠ |
$/ made | Nil | — ≠ |
$/ caps | | — ≠ |
grammars-v1 · seed 1066 · recorded 2026-09-23 with Rakudo 2026.08 and Raku++ 4.0.1-132-g3e242220-modified · Source on GitHub ↗