### 6.7 Building macros with macros ¶

Since m4 is a macro language, it is possible to write macros that can build other macros. First on the list is a way to automate the creation of blind macros.

Composite: define_blind (name, [value]) ¶

  Defines name as a blind macro, such that name will expand to value only when given explicit arguments. value should not be the result of `defn` (see Renaming macros). This macro is only recognized with parameters, and results in an empty string.

Defining a macro to define another macro can be a bit tricky. We want to use a literal ‘`$#`’ in the argument to the nested `define`. However, if ‘`$`’ and ‘`#`’ are adjacent in the definition of `define_blind`, then it would be expanded as the number of arguments to `define_blind` rather than the intended number of arguments to name. The solution is to pass the difficult characters through extra arguments to a helper macro `_define_blind`. When composing macros, it is a common idiom to need a helper macro to concatenate text that forms parameters in the composed macro, rather than interpreting the text as a parameter of the composing macro.

As for the limitation against using `defn`, there are two reasons. If a macro was previously defined with `define_blind`, then it can safely be renamed to a new blind macro using plain `define`; using `define_blind` to rename it just adds another layer of `ifelse`, occupying memory and slowing down execution. And if a macro is a builtin, then it would result in an attempt to define a macro consisting of both text and a builtin token; this is not supported, and the builtin token is flattened to an empty string.

With that explanation, here’s the definition, and some sample usage. Notice that `define_blind` is itself a blind macro.

    $ m4 -d
    define(`define_blind', `ifelse(`$#', `0', ``$0'',
    `_$0(`$1', `$2', `$'`#', `$'`0')')')
    ⇒
    define(`_define_blind', `define(`$1',
    `ifelse(`$3', `0', ``$4'', `$2')')')
    ⇒
    define_blind
    ⇒define_blind
    define_blind(`foo', `arguments were $*')
    ⇒
    foo
    ⇒foo
    foo(`bar')
    ⇒arguments were bar
    define(`blah', defn(`foo'))
    ⇒
    blah
    ⇒blah
    blah(`a', `b')
    ⇒arguments were a,b
    defn(`blah')
    ⇒ifelse(`$#', `0', ``$0'', `arguments were $*')

Another interesting composition tactic is argument currying, or factoring a macro that takes multiple arguments for use in a context that provides exactly one argument.

Composite: curry (macro, …) ¶

  Expand to a macro call that takes exactly one argument, then appends that argument to the original arguments and invokes macro with the resulting list of arguments.

A demonstration of currying makes the intent of this macro a little more obvious. The macro `stack_foreach` mentioned earlier is an example of a context that provides exactly one argument to a macro name. But coupled with currying, we can invoke `reverse` with two arguments for each definition of a macro stack. This example uses the file `m4-1.4.19/examples/curry.m4` included in the distribution.

    $ m4 -I examples
    include(`curry.m4')include(`stack.m4')
    ⇒
    define(`reverse', `ifelse(`$#', `0', , `$#', `1', ``$1'',
                              `reverse(shift($@)), `$1'')')
    ⇒
    pushdef(`a', `1')pushdef(`a', `2')pushdef(`a', `3')
    ⇒
    stack_foreach(`a', `:curry(`reverse', `4')')
    ⇒:1, 4:2, 4:3, 4
    curry(`curry', `reverse', `1')(`2')(`3')
    ⇒3, 2, 1

Now for the implementation. Notice how `curry` leaves off with a macro name but no open parenthesis, while still in the middle of collecting arguments for ‘`$1`’. The macro `_curry` is the helper macro that takes one argument, then adds it to the list and finally supplies the closing parenthesis. The use of a comma inside the `shift` call allows currying to also work for a macro that takes one argument, although it often makes more sense to invoke that macro directly rather than going through `curry`.

    $ m4 -I examples
    undivert(`curry.m4')dnl
    ⇒divert(`-1')
    ⇒# curry(macro, args)
    ⇒# Expand to a macro call that takes one argument, then invoke
    ⇒# macro(args, extra).
    ⇒define(`curry', `$1(shift($@,)_$0')
    ⇒define(`_curry', ``$1')')
    ⇒divert`'dnl

Unfortunately, with M4 1.4.x, `curry` is unable to handle builtin tokens, which are silently flattened to the empty string when passed through another text macro. This limitation will be lifted in a future release of M4.

Putting the last few concepts together, it is possible to copy or rename an entire stack of macro definitions.

Composite: copy (source, dest) ¶
Composite: rename (source, dest) ¶

  Ensure that dest is undefined, then define it to the same stack of definitions currently in source. `copy` leaves source unchanged, while `rename` undefines source. There are only a few macros, such as `copy` or `defn`, which cannot be copied via this macro.

The implementation is relatively straightforward (although since it uses `curry`, it is unable to copy builtin macros, such as the second definition of `a` as a synonym for `divnum`. See if you can design a version that works around this limitation, or see Answers).

    $ m4 -I examples
    include(`curry.m4')include(`stack.m4')
    ⇒
    define(`rename', `copy($@)undefine(`$1')')dnl
    define(`copy', `ifdef(`$2', `errprint(`$2 already defined
    ')m4exit(`1')',
       `stack_foreach(`$1', `curry(`pushdef', `$2')')')')dnl
    pushdef(`a', `1')pushdef(`a', defn(`divnum'))pushdef(`a', `2')
    ⇒
    copy(`a', `b')
    ⇒
    rename(`b', `c')
    ⇒
    a b c
    ⇒2 b 2
    popdef(`a', `c')c a
    ⇒ 0
    popdef(`a', `c')a c
    ⇒1 1