NAME

Macrame - filter-time recursive macro framework providing the feature preventing Perl from being "a Lisp."

VERSION

This document describes version 0.09 of Macrame, released April 24, 2009. Both of Slaven Rezic's reported bugs have been addressed.

Minor changes towards new strictures at PAUSE have been made for version 0.13.

The next step towards getting Macrame to be everything it could become appears to be fixing Filter::Simple, by either fixing Filter::Simple so it works better, or by replacing it entirely with a more complex tokenizer, perhaps Filter::PPI.

Haven't touched this in almost a decade. Wow.

SYNOPSIS

macro curry OP A1 A2 { (OP A1), curry OP A2 }
macro curry OP A { (OP A) }

exactly three macros are always provided, macro, EXPAND, and NOMACROS. These are intended as stones sufficiently sturdy to build any cathedral.

Additionally, a set of PUNCTUATION macros are defined which may be modified to provide macros which will survive a NOMACROS invocation.

ABOUT THIS PERLDOC

this perldoc is interspersed through the relevant code implementing each feature, to minimize disconnection between documentation and implementation.

Cookbook kinds of things may appear at the bottom.

DESCRIPTION

tokenizing

at this version we ignore all whitespace in input and place whitespace in output only between barewords. Lexical blocks are treated as single tokens for signature matching purposes, as are expressions that indicate variables, such as %foo::bar.

the sigil contents eater needs some love before it follows the same rules as perl's double quoted variable interpolation engine concerning parsing things like $foo::bar-{baz}{blarf}>.

move the following elsewhere:

At this version we use the core-provided Filter::Simple FILTER_ONLY features to extract quotelikes, which is not quite as robust as Perl's parsing. The quotelike parser in Filter::Simple tends to treat slashes as quoting operators. When this is a problem, a workaround is to define a macro to provide the slash, and then use that instead.

macro divided_by { EXPAND '/' }
macro F2C F { ( (F) -32 * 5 divided_by 9 ) } 
macro C2F C { ( (C) divided_by 5 * 9 + 32 ) } 

We are also ignoring line numbers.

lexcial blocking

Curly, round and square brackets are all recognized, for macro visibility purposes, as lexical blocks. Inner macros hide outer macros.

macro signatures

macros are polymorphic based on syntactic signatures. More features of signature match syntax will appear in future releases of Macrame. The first, in inner to outer blocking and then document order, macro that matches the signature for any macro name, will operate during Macrame transformation. see "SIGNATURE SYNTAX" for what is currently allowed in macro signatures.

signature matching procedure

when a bareword is identified as a macro, signature matches are attempted against the untransformed token tree that follows it. In the event that no match is found, the token tree following the macro name is transformed, and matching is attempted again. That failing too is a fatal error.

where to find examples

See the t/Macrame.t file included with this distribution for examples, also there may be a cookbook section in this document. The examples in the test file are more certain to work.

@Macrame::Definitions array

localization of macros is provided by unshifting a new definitions frame onto the beginning of @Definitions whenever Macrame descends into a lexical block. Definitions frames are hash references.

SIGNATURE SYNTAX

The signature is the part of a macro definition between the name of the macro and the first opening curly bracket at the same lexical level as the name.

The signature provides two functions. Firstly, by matching or not matching, it selects which macro with a given name to use. Secondly, while deciding if it matched or not, the names to lexemes array is loaded with the replacement lexemes for the placeholder names.

The signature is optional, and when absent, the definition will always match.

macro define NAME = VALUE { macro NAME { VALUE } }
define pi = 3.14159  # a constant
define pie_predicate = ( $slices_remaining > 0 ) # an inlined sub()

bareword matching

Barewords appearing in macro signatures are placeholders and whatever lexeme appears in that place, be it a bareword, a sigil expression, a bracketed block, or a quoted expression, will be saved in the names to lexemes table for insertion.

syntax matching

Everything else (except quoted stuff -- see below) is syntax. syntax must be present to allow match. Bracketed blocks appearing in signatures get descended.

# this is obviously very powerful; would someone please
# do something with it and send an example to put here?

quoted expressions in signatures

It is expected that the room to shoehorn all kinds of fancy things into the signature matching language -- it could become every bit as complex as pcre -- is in quotelike lexemes.

At this time, the only quotelikes allowed in signatures use apostrophes, also known as single quotes. The single quotes may surround a bareword, which indicates that that word is part of the syntax of the macro and must appear in the input tree as a bareword. The bareword may be surrounded by brackets which means that a block bounded by the same kind of bracket must appear at that point, and that block will go into the names to lexemes table under the name of the bracketed bareword.

{
  macro search '(list)' 'for' regex {(NOMACROS  grep { regex } list )}
  macro search '{pairs}' 'for' '/regex/' {(NOMACROS do {
     my $pair_ref = pairs;
     grep { $pair_ref->{$_} =~ regex } keys %$pair_ref 
  })}
  my @bb = search (qw/foo bar baz/) for /a/;
  my @bc = search {qw/a foo b bar c baz/} for /a/;
  is("@bb","bar baz", "'(syntax)'");
  is("@bc","b c", "'{syntax}'");
}

how much gets matched by a macro signature

a matching signature will identify the part of the candidate filter input that is going to match the signature, and that is the part that gets replaced by the macro body after argument interpolation. A way to declare things like "this names to lexemes table entry represents everything until the next keyword" -- in short, regular expression syntax -- would be totally cool but at this point constitutes paralyzing featuritis.

%Macrame::PUNCTUATION_MACROS

by default, Q, QQ, SLASH, LPAREN, RPAREN, LSQUARE, RSQUARE, LCURLY and RCURLY appear as well as macro, EXPAND and NOMACROS when the macro set is reset, such as by invoking NOMACROS. This list is in a modifiable data structure, so if you really need Q to mean something other than an apostrophe that will sneak by the Filter::Simple quotelike parser you could do something like

EXPAND delete $Macrame::PUNCTUATION_MACROS{Q};

or

use Macrame();
BEGIN { delete $Macrame::PUNCTUATION_MACROS{Q} }
use Macrame;
my $Qobj = new Qobj;
macro CombineJQZ X { (X->J . X->Q . X->Z) }
printf "By default a new Qobj has JQZ of %s\n", CombineJQZ $Qobj;

EXPAND ... ;

the predefined EXPAND macro takes all tokens up to the next semicolon and executes them, inserting the result of the expression in the token stream. The execution takes place in the Macrame::_Expand_ package space.

NOMACROS macro

NOMACROS disables all except the initial core macros to the end of its visibility.

notes on Macrame lexing process

At this version, Macrame uses a trivial lexer that is not capable of splitting non-word tokens. It does not know one operator from another. It does however respect whitespace, and commas, as separators. This means that it does not know that C <<!! >> or C <<~~ >> are two separate tokens, while C <<++ >> is one token, in Perl.

KNOWN BUGS

slashes don't work well as punctuation because Text::Balanced, from Filter::Simple, tends to interpret them as match operators instead of divisions.

similarly, quotes in comments can wreck your day. Apostrophes are quotes.

Internals

@Macrame::Definitions

Definitions is an array of hash references, one for each level of bracketing encountered in the source code. The hashes are keyed by macro name and their values are ordered list of signature, replace pairs. The signature is a Macrame Regular Expression and the replace is a reference to code, which takes the current treeified source code position as argument and returns a replacement.

line numbers (broken)

When repaired, ...

line numbers are tracked by inserting L <<#line directives|perlsyn >> in a prepass, then converting them to a __Macrame_LINE(line,file) item during the lexing, so please don't call anything __Macrame_LINE. \W characters in file names are escaped.

gory internals

I'm afraid you're going to have to look at the source code. Suffice it to say that this module reserves all tokens matching /^__Macrame_[A-Z]+/ for internal use.

HISTORY

Copyright and License

Copyright 2007 David Nicol <<davidnico@cpan.org >>

released under same terms as Perl 5