The change to NQP-rx is causing all kinds of problems. Some of them are voluntary: I'm moving to attribute based classes, and I'm taking advantage of a bunch of features of the new -rx engine. But some of them are involuntary, like climbing the learning curve for how optable parsing works.
I put up a wiki page about that over on the Parrot.org trac site, but even after writing out a bunch of stuff, it's still not totally obvious to me how some parts work. That's part of the learning process, I guess.
One thing I'm doing somewhat differently now is testing. Before, I was writing tests for the compiler. Now I'm writing tests of the compiler.
I've got this much of the TDD approach figured out: find out what needs to be done, write some code to do it, and then bury it in tests.
In theory, this is a bad idea because it leads to "test sclerosis," a condition where the system becomes unmodifiable because of the cost of updating the test cases. That's not an issue for me (yet) because I'm testing parsing rules. First, if things get a little sclerotic I don't think I'll mind, because the testing has been working - in the sense that it is finding places where my code doesn't do what I think it does. (Switching to a new language that uses the same syntax makes this a particularly acute problem.)
Second, although it's still early in the process, I'm testing stuff that I don't expect to change much. Recognizing this or that token should produce pretty much exactly the same PAST output. As I get higher in the grammar, this may not be true any more - maybe when I'm up high, I'll want to quickly change the grammar and the tests will be a drag.
But for now, it's smooth sailing. The Kakapo library has a little bit of syntactic sugar added just for this purpose: the Matcher::PctNode class and its friend Matcher::PAST::Node. Here's what a testcase looks like:
method test_binary() {In fact, there are so many test cases that the processing is more scripted than this. But this represents what one test would look like. The sugar I've built is in the "my $matcher := " line - that expression is generating a matcher.
my $matcher := val( :value(1) );
my $code := "0b01";
my $slam := Slam::Compiler.new;
my $past := $slam.compile: $code,
:rule<EXPR>,
:target<past>,
;
assert_match($past, $matcher,
'Failed to parse {' ~ $code ~ '} as expected');
}
Anyway, this next stage is going to be mostly me migrating the grammar over to -rx, and building test scaffolding around it. I've started working on a private branch, instead of trunk, so there won't be so many bogus commits.
Good information. You are doing good work. I will be following you for more. Please keep us posted. Thanks.
ReplyDelete