in reply to {Perl6} Macros and native compilation

Since I was just into A6 when I read your question, I wanted to write up a nice tutorial on Perl 6 macros for you. But I ended up just repeating the original text, so I decided to copy-paste here the relevant parts instead:

A macro is a function that is called immediately upon completion of the parsing of its arguments. Macros must be defined before they are used--there are no forward declarations of macros, and while a macro's name may be installed in either a package or a lexical scope, its syntactic effect can only be lexical, from the point of declaration (or importation) to the end of the current lexical scope.

Every macro is associated (implicitly or explicitly) with a particular grammar rule that parses and reduces the arguments to the macro. The formal parameters of a macro are special in that they must be derived somehow from the results of that associated grammar rule. We treat macros as if they were methods on the parse object returned by the grammar rule, so the first argument is passed as if it were an invocant, and it is always bound to the current parse tree object, known as $0 in Apocalypse 5. (A macro is not a true method of that class, however, because its name is in your scope, not the class's.)

Update: That's now the $/ object. $0 has been "demoted" to being the entire matched string.


A macro can do anything it likes with the parse tree, but the return value is treated specially by the parser. You can return one of several kinds of values:

A macro by default parses any subsequent text using whatever macro rule is currently in effect. Generally this will be the standard Perl::macro rule, which parses subsequent arguments as a list operator would--that is, as a comma-separated list with the same policy on using or omitting parentheses as any other list operator. This default may be overridden with the "is parsed" trait.


If there is no signature at all, macro defaults to using the null rule, meaning it looks for no argument at all. You can use it for simple word substitutions where no argument processing is needed. Instead of the long-winded:

my macro this () is parsed(/<null>/) { "self" }
you can just quietly turn your program into C++:
my macro this { "self" }
A lot of Perl is fun, and macros are fun, but in general, you should never use a macro just for the fun of it. It's far too easy to poke someone's eye out with a macro.

Now, it's up to you to decide, how this compares to LISP et co.


Replies are listed 'Best First'.
Re^2: {Perl6} Macros and native compilation
by spurperl (Priest) on Apr 11, 2005 at 11:37 UTC
    It sounds really good, just one thing is unclear...

    When the macro body is a string that is "shoved back into the input and reparsed", can I ask which variables to evaluate and which not ? I.e.

    my macro this {"self{$foo}"}

    Will $foo be interpolated/evaluated at compile-time, when the macro is expanded, or at runtime, in the context of the macro's usage ? In Lisp, using special syntax you can have both, which is very, *very* powerful.

      In my understanding, you absolutely can do this with Perl 6 macros. If you want $foo to be avaluated at compile time, you just return a string as you did. Contrariwise, if you return a closure (maybe using the simple my macro this { self{$foo} } syntax?), you get "a generic routine that is to be immediately inlined, treating the closure as a template", such that "any variable not referring back to a parameter is left alone, so that your template can declare its own lexical variables, or refer to a package variable". This way, $foo will be evaluated at runtime...

      But, as always with Perl 6, don't take my words for granted...:-)


      I'd say you'd have to use single quotes, e.g.:

      my macro this { 'self{$foo}' }

      I don't think rg0now's idea will work, because $foo would refer to some outer $foo. If my understanding is correct, you can do things like the following:

      my $compilation_time = BEGIN { time }; macro uptime { time - $compilation_time } # And then... say "$*PROGRAM_NAME has been running for {uptime} seconds.";

      (Update: Doing s/macro/sub/ here would work just fine, too.)

      But, as rg0now said, that may be wrong, of course.