Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How do I write a perl6 macro to enquote text?

Tags:

macros

raku

I'm looking to create a macro in P6 which converts its argument to a string. Here's my macro:

macro tfilter($expr) {
        quasi {
                my $str = Q ({{{$expr}}});
                filter-sub $str;   
        };
}

And here is how I call it:

my @some = tfilter(age < 50);

However, when I run the program, I obtain the error:

Unable to parse expression in quote words; couldn't find final '>'

How do I fix this?

like image 875
blippy Avatar asked Apr 22 '17 16:04

blippy


1 Answers

Your use case, converting some code to a string via a macro, is very reasonable. There isn't an established API for this yet (even in my head), although I have come across and thought about the same use case. It would be nice in cases such as:

assert a ** 2 + b ** 2 == c ** 2;

This assert statement macro could evaluate its expression, and if it fails, it could print it out. Printing it out requires stringifying it. (In fact, in this case, having file-and-line information would be a nice touch also.)

(Edit: 007 is a language laboratory to flesh out macros in Perl 6.)

Right now in 007 if you stringify a Q object (an AST), you get a condensed object representation of the AST itself, not the code it represents:

$ bin/007 -e='say(~quasi { 2 + 2 })'
Q::Infix::Addition {
    identifier: Q::Identifier "infix:+",
    lhs: Q::Literal::Int 2,
    rhs: Q::Literal::Int 2
}

This is potentially more meaningful and immediate than outputting source code. Consider also the fact that it's possible to build ASTs that were never source code in the first place. (And people are expected to do this. And to mix such "synthetic Qtrees" with natural ones from programs.)

So maybe what we're looking at is a property on Q nodes called .source or something. Then we'd be able to do this:

$ bin/007 -e='say((quasi { 2 + 2 }).source)'
 2 + 2 

(Note: doesn't work yet.)

It's an interesting question what .source ought to output for synthetic Qtrees. Should it throw an exception? Or just output <black box source>? Or do a best-effort attempt to turn itself into stringified source?

Coming back to your original code, this line fascinates me:

my $str = Q ({{{$expr}}});

It's actually a really cogent attempt to express what you want to do (turn an AST into its string representation). But I doubt it'll ever work as-is. In the end, it's still kind of based on a source-code-as-strings kind of thinking à la C. The fundamental issue with it is that the place where you put your {{{$expr}}} (inside of a string quote environment) is not a place where an expression AST is able to go. From an AST node type perspective, it doesn't typecheck because expressions are not a subtype of quote environments.

Hope that helps!

(PS: Taking a step back, I think you're doing yourself a disservice by making filter-sub accept a string argument. What will you do with the string inside of this function? Parse it for information? In that case you'd be better off analyzing the AST, not the string.)

(PPS: Moritz++ on #perl6 points out that there's an unrelated syntax error in age < 50 that needs to be addressed. Perl 6 is picky about things being defined before they are used; macros do not change this equation much. Therefore, the Perl 6 parser is going to assume that age is a function you haven't declared yet. Then it's going to consider the < an opening quote character. Eventually it'll be disappointed that there's no >. Again, macros don't rescue you from needing to declare your variables up-front. (Though see #159 for further discussion.))

like image 100
Carl Mäsak Avatar answered Oct 22 '22 06:10

Carl Mäsak