= NQP-rx Tricks = Here are some tricks for parsing with NQP-rx: == Global Variables == A bunch of stuff in -rx is still done with globals. This will all move to contextuals, or to attributes of a common object, or something. Eventually. === HLL::Grammar::%!MARKHASH === The MARKED/MARKER special rules, which are used by default in the rule, tracks mark info in a global hash. In order to parse a different source, you need to reset this hash. {{{ Q:PIR { $P0 = null set_hll_global ['HLL';'Grammar'], '%!MARKHASH', $P0 }; }}} I use this to enable test cases for the grammar. The code below (built with the Kakapo library) runs the parser over and over again: {{{ method code_test(%code_matchers) { my $slam := Slam::Compiler.new; my $past; for %code_matchers -> $pair { my $code := $pair.key; say("Code: $code"); Q:PIR { $P0 = null set_hll_global ['HLL';'Grammar'], '%!MARKHASH', $P0 }; $past := $slam.compile: $code, :rule, :target; #, :parsetrace; #_dumper($past); my $matcher := $pair.value; assert_match($past, $matcher, 'Failed to parse {' ~ $code ~ '} as expected'); } } method test_postcircumfix_array_index() { my %code_matchers; %code_matchers := var( :scope, var( :name ), val( :value<0> )); %code_matchers := var( :scope, var( :name ), val( :value<1> )); %code_matchers := var( :scope, var( :name ), val( :value<2> )); %code_matchers := var( :scope, var( :name ), var( :name )); self.code_test: %code_matchers; } }}} The `var(...)` functions are syntactic sugar that generate a special Matcher for validating PCT trees. == HLL::Compiler == === Debugging === The Regex code supports debugging with a `!cursor_debug` call. To enable this, the topmost regex (your grammar) has to be called with the `'rxtrace'` flag. The default compiler doesn't appear to support this, so I overrode the `parse` method: {{{ class Slam::Compiler; method parse($source, *%adverbs) { unless %adverbs { %adverbs := %adverbs eq 'parse' ?? pir::null__P() !! self.parseactions; } my %options_map := hash( actions => 'actions', parsetrace => 'rxtrace', rule => 'rule', ); my %parse_flags; for %options_map -> $map { %parse_flags{$map.value} := %adverbs{$map.key} if %adverbs.contains: $map.key; } my $match := self.parsegrammar.parse($source, :p(0), |%parse_flags); self.panic('Failed to parse source') unless $match; $match; } }}}