As promised, here is my documentation patch that makes the m4_stack* and various m4_*_sep macros public, because of the efficiency that they offer. I've hammered these macros pretty well in autoconf, so I think the API is pretty much settled now, except for the fact that this patch had to add an argument to m4_map_args_w for consistency with the rest.
From: Eric Blake <[email protected]> Date: Fri, 19 Dec 2008 14:06:46 -0700 Subject: [PATCH] Document some recently added macros. * lib/m4sugar/m4sugar.m4 (m4_map_args_w): Add optional sep parameter. * doc/autoconf.texi (Looping constructs) <m4_map_args_sep> <m4_map_args_w, m4_stack_foreach, m4_stack_foreach_sep>: Document new macros. (Set manipulation Macros) <m4_set_map_sep>: Likewise. * tests/m4sugar.at (m4@&t...@_stack, M4 loops): Enhance tests. * NEWS: Document new macros. Signed-off-by: Eric Blake <[email protected]> --- ChangeLog | 12 ++++++ NEWS | 4 ++- doc/autoconf.texi | 89 ++++++++++++++++++++++++++++++++++++++++++++++-- lib/m4sugar/m4sugar.m4 | 45 ++++++++++++------------ tests/m4sugar.at | 9 +++-- 5 files changed, 129 insertions(+), 30 deletions(-) diff --git a/ChangeLog b/ChangeLog index 369433c..e12309f 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,15 @@ +2008-12-19 Eric Blake <[email protected]> + + Document some recently added macros. + * lib/m4sugar/m4sugar.m4 (m4_map_args_w): Add optional sep + parameter. + * doc/autoconf.texi (Looping constructs) <m4_map_args_sep> + <m4_map_args_w, m4_stack_foreach, m4_stack_foreach_sep>: Document + new macros. + (Set manipulation Macros) <m4_set_map_sep>: Likewise. + * tests/m4sugar.at (m4@&t...@_stack, M4 loops): Enhance tests. + * NEWS: Document new macros. + 2008-12-18 Eric Blake <[email protected]> Fix separator in m4_stack_foreach_sep. diff --git a/NEWS b/NEWS index 30ac715..7eff140 100644 --- a/NEWS +++ b/NEWS @@ -27,7 +27,9 @@ GNU Autoconf NEWS - User visible changes. ** The following documented m4sugar macros are new: m4_chomp m4_curry m4_default_quoted m4_esyscmd_s m4_map_args - m4_map_args_pair m4_set_map + m4_map_args_pair m4_map_args_sep m4_map_args_w m4_set_map + m4_set_map_sep m4_stack_foreach m4_stack_foreach_lifo + m4_stack_foreach_sep m4_stack_foreach_sep_lifo ** The following m4sugar macros are documented now, but in some cases with slightly different semantics than what the previous diff --git a/doc/autoconf.texi b/doc/autoconf.texi index 1e211a1..2a2d4c7 100644 --- a/doc/autoconf.texi +++ b/doc/autoconf.texi @@ -11106,7 +11106,9 @@ Looping constructs @defmac m4_foreach_w (@var{var}, @var{list}, @var{expression}) @msindex{foreach_w} Loop over the white-space-separated list @var{list}, assigning each value -to @var{var}, and expand @var{expression}. +to @var{var}, and expand @var{expression}. If @var{var} is only +referenced once in @var{expression}, it is more efficient to use +...@code{m4_map_args_w}. The deprecated macro @code{AC_FOREACH} is an alias of @code{m4_foreach_w}. @@ -11179,7 +11181,8 @@ Looping constructs the list elements, the macro @code{m4_curry} can be used in @var{macro} to supply the argument currying necessary to generate the desired argument list. In the following example, @code{list_add_n} is more -efficient than @code{list_add_x}. +efficient than @code{list_add_x}. On the other hand, using +...@code{m4_map_args_sep} can be even more efficient. @example m4_define([list], [[1], [2], [3]])dnl @@ -11218,6 +11221,30 @@ Looping constructs @end example @end defmac +...@defmac m4_map_args_sep (@ovar{pre}, @ovar{post}, @ovar{sep}, @var{a...@dots{}) +...@msindex{map_args_sep} +Expand the sequence @co...@var{pre}[@var{ar...@var{post}} for each +argument, additionally expanding @var{sep} between arguments. One +common use of this macro is constructing a macro call, where the opening +and closing parentheses are split between @var{pre} and @var{post}; in +particular, @code{m4_map_args([...@var{macro}], [...@var{arg}])} is equivalent +to @code{m4_map_args_sep([...@var{macro}(], [)], [], [...@var{arg}])}. This +macro provides the most efficient means for iterating over an arbitrary +list of arguments, particularly when repeatedly constructing a macro +call with more arguments than @var{arg}. +...@end defmac + +...@defmac m4_map_args_w (@var{string}, @ovar{pre}, @ovar{post}, @ovar{sep}) +...@msindex{map_args_w} +Expand the sequence @co...@var{pre}[word]@var{post}} for each word in +the whitespace-separated @var{string}, additionally expanding @var{sep} +between words. This macro provides the most efficient means for +iterating over a whitespace-separated string. In particular, +...@code{m4_map_args_w([...@var{string}], [...@var{action}(], [)])} is more +efficient than @code{m4_foreach_w([var], [...@var{string}], +...@var{action}(m4_defn([var]))])}. +...@end defmac + @defmac m4_shiftn (@var{count}, @dots{}) @defmacx m4_shift2 (@dots{}) @defmacx m4_shift3 (@dots{}) @@ -11232,6 +11259,47 @@ Looping constructs for two and three shifts, respectively. @end defmac +...@defmac m4_stack_foreach (@var{macro}, @var{action}) +...@defmacx m4_stack_foreach_lifo (@var{macro}, @var{action}) +...@msindex{stack_foreach} +...@msindex{stack_foreach_lifo} +For each of the @code{m4_pushdef} definitions of @var{macro}, expand +...@var{action} with the single argument of a definition of @var{macro}. +...@code{m4_stack_foreach} starts with the oldest definition, while +...@code{m4_stack_foreach_lifo} starts with the current definition. +...@var{action} should not push or pop definitions of @var{macro}, nor is +there any guarantee that the current definition of @var{macro} matches +the argument that was passed to @var{action}. The macro @code{m4_curry} +can be used if @var{action} needs more than one argument, although in +that case it is more efficient to use @var{m4_stack_foreach_sep}. + +Due to technical limitations, there are a few low-level m4sugar +functions, such as @code{m4_pushdef}, that cannot be used as the +...@var{macro} argument. + +...@example +m4_pushdef([a], [1])m4_pushdef([a], [2])dnl +m4_stack_foreach([a], [ m4_incr]) +...@result{} 2 3 +m4_stack_foreach_lifo([a], [ m4_curry([m4_substr], [abcd])]) +...@result{} cd bcd +...@end example +...@end defmac + +...@defmac m4_stack_foreach_sep (@var{macro}, @ovar{pre}, @ovar{post}, @ovar{sep}) +...@defmacx m4_stack_foreach_sep_lifo (@var{macro}, @ovar{pre}, @ovar{post}, @ + @ovar{sep}) +...@msindex{stack_foreach_sep} +...@msindex{stack_foreach_sep_lifo} +Expand the sequence @co...@var{pre}[definition]@var{post}} for each +...@code{m4_pushdef} definition of @var{macro}, additionally expanding +...@var{sep} between definitions. @code{m4_stack_foreach_sep} visits the +oldest definition first, while @code{m4_stack_foreach_sep_lifo} visits +the current definition first. This macro provides the most efficient +means for iterating over a pushdef stack. In particular, +...@code{m4_stack_foreach([...@var{macro}], [...@var{action}])} is short for +...@code{m4_stack_foreach_sep([...@var{macro}], [...@var{action}(], [)])}. +...@end defmac @node Evaluation Macros @subsection Evaluation Macros @@ -12071,7 +12139,22 @@ Set manipulation Macros corresponding counterpart of @code{m4_map_args([...@var{action}]m4_set_listc([...@var{set}]))} or @code{m4_set_foreach([...@var{set}], [var], -...@var{action}(m4_defn([var]))])}. +...@var{action}(m4_defn([var]))])}. It is possible to use @code{m4_curry} +if more than one argument is needed for @var{action}, although it is +more efficient to use @code{m4_set_map_sep} in that case. +...@end defmac + +...@defmac m4_set_map_sep (@var{set}, @ovar{pre}, @ovar{post}, @ovar{sep}) +...@msindex{set_map_sep} +For each element in the set @var{set}, expand +...@code{@var{pre}[eleme...@var{post}}, additionally expanding @var{sep} +between elements. Behavior is unspecified if the expansion recursively +lists the contents of @var{set} (although listing other sets +is acceptable), or if it modifies the set in any way other than removing +the element visited by the expansion. This macro provides the most +efficient means for non-destructively visiting the elements of a set; in +particular, @code(m4_set_map([...@var{set}], [...@var{action}]) is equivalent +to @code{m4_set_map_sep([...@var{set}], [...@var{action}(], [)])}. @end defmac @defmac m4_set_remove (@var{set}, @var{value}, @ovar{if-present}, @ diff --git a/lib/m4sugar/m4sugar.m4 b/lib/m4sugar/m4sugar.m4 index 6ca825f..05e357a 100644 --- a/lib/m4sugar/m4sugar.m4 +++ b/lib/m4sugar/m4sugar.m4 @@ -1145,9 +1145,9 @@ m4_define([m4_mapall], [_m4_foreach([m4_apply([$1],], [)], [], $2)])]) -# m4_map_sep(MACRO, SEPARATOR, LIST) -# m4_mapall_sep(MACRO, SEPARATOR, LIST) -# ------------------------------------- +# m4_map_sep(MACRO, [SEPARATOR], LIST) +# m4_mapall_sep(MACRO, [SEPARATOR], LIST) +# --------------------------------------- # Invoke MACRO($1), SEPARATOR, MACRO($2), ..., MACRO($N) where $1, # $2... $N are the elements of LIST, and are in turn lists appropriate # for m4_apply. SEPARATOR is expanded, in order to allow the creation @@ -1207,8 +1207,8 @@ m4_define([m4_map_args_pair], [$1([$3], [$4])[]$0([$1], [$2], m4_shift(m4_shift3($@)))])]) -# m4_map_args_sep(PRE, POST, SEP, ARG...) -# --------------------------------------- +# m4_map_args_sep([PRE], [POST], [SEP], ARG...) +# --------------------------------------------- # Expand PRE[ARG]POST for each argument, with SEP between arguments. m4_define([m4_map_args_sep], [m4_if([$#], [0], [m4_fatal([$0: too few arguments: $#])], @@ -1219,11 +1219,12 @@ m4_define([m4_map_args_sep], [$1[$4]$2[]_m4_foreach([$3[]$1], [$2], m4_shift3($@))])]) -# m4_map_args_w(STRING, [PRE], [POST]) -# ------------------------------------ +# m4_map_args_w(STRING, [PRE], [POST], [SEP]) +# ------------------------------------------- # Perform the expansion of PRE[word]POST[] for each word in STRING # separated by whitespace. More efficient than: # m4_foreach_w([var], [STRING], [PRE[]m4_defn([var])POST]) +# Additionally, expand SEP between words. # # As long as we have to use m4_bpatsubst to split the string, we might # as well make it also apply PRE and POST; this avoids iteration @@ -1234,9 +1235,9 @@ m4_define([m4_map_args_sep], # empty elements and remove the extra layer of quoting. m4_define([m4_map_args_w], [_$0(_m4_split([ ]m4_flatten([$1])[ ], [[ ]+], - m4_if(m4_index([$2$3], [\]), [-1], [[$3[]$2]], - [m4_bpatsubst([[$3[]$2]], [\\], [\\\\])])), - m4_len([[]$3]), m4_len([$2[]]))]) + m4_if(m4_index([$2$3$4], [\]), [-1], [[$3[]$4[]$2]], + [m4_bpatsubst([[$3[]$4[]$2]], [\\], [\\\\])])), + m4_len([[]$3[]$4]), m4_len([$4[]$2[]]))]) m4_define([_m4_map_args_w], [m4_substr([$1], [$2], m4_eval(m4_len([$1]) - [$2] - [$3]))]) @@ -1262,9 +1263,9 @@ m4_define([m4_stack_foreach_lifo], [_m4_stack_reverse([$1], [m4_tmp-$1], [$2(_m4_defn([m4_tmp-$1]))])]dnl [_m4_stack_reverse([m4_tmp-$1], [$1])]) -# m4_stack_foreach_sep(MACRO, PRE, POST, SEP) -# m4_stack_foreach_sep_lifo(MACRO, PRE, POST, SEP) -# ------------------------------------------------ +# m4_stack_foreach_sep(MACRO, [PRE], [POST], [SEP]) +# m4_stack_foreach_sep_lifo(MACRO, [PRE], [POST], [SEP]) +# ------------------------------------------------------ # Similar to m4_stack_foreach and m4_stack_foreach_lifo, in that every # definition of a pushdef stack will be visited. But rather than # passing the definition as a single argument to a macro, this variant @@ -1280,8 +1281,8 @@ m4_define([m4_stack_foreach_sep_lifo], [_m4_stack_reverse([m4_tmp-$1], [$1])]) -# _m4_stack_reverse(OLD, NEW, ACTION, SEP) -# ---------------------------------------- +# _m4_stack_reverse(OLD, NEW, [ACTION], [SEP]) +# -------------------------------------------- # A recursive worker for pushdef stack manipulation. Destructively # copy the OLD stack into the NEW, and expanding ACTION for each # iteration. After the first iteration, SEP is promoted to the front @@ -2793,8 +2794,8 @@ m4_define([m4_set_contents], # _m4_set_contents_1(SET) # _m4_set_contents_1c(SET) -# _m4_set_contents_2(SET, PRE, POST, SEP) -# --------------------------------------- +# _m4_set_contents_2(SET, [PRE], [POST], [SEP]) +# --------------------------------------------- # Expand to a list of quoted elements currently in the set, each # surrounded by PRE and POST, and moving SEP in front of PRE on # recursion. To avoid nesting limit restrictions, the algorithm must @@ -2868,9 +2869,9 @@ m4_define([m4_set_dump], [_m4_popdef([_m4_set_size($1)])])m4_ifdef([_m4_set_cleanup($1)], [_$0_check], [_$0])([$1], [], [$2])]) -# _m4_set_dump(SET, SEP, PREP) -# _m4_set_dump_check(SET, SEP, PREP) -# ---------------------------------- +# _m4_set_dump(SET, [SEP], [PREP]) +# _m4_set_dump_check(SET, [SEP], [PREP]) +# -------------------------------------- # Print SEP and the current element, then delete the element and # recurse with empty SEP changed to PREP. The check variant checks # whether the element has been previously removed. Use _m4_defn and @@ -2951,8 +2952,8 @@ m4_define([m4_set_listc], m4_define([m4_set_map], [m4_set_map_sep([$1], [$2(], [)])]) -# m4_set_map_sep(SET, PRE, POST, SEP) -# ----------------------------------- +# m4_set_map_sep(SET, [PRE], [POST], [SEP]) +# ----------------------------------------- # For each element of SET, expand PRE[value]POST[], and expand SEP # between elements. m4_define([m4_set_map_sep], diff --git a/tests/m4sugar.at b/tests/m4sugar.at index a876588..4938027 100644 --- a/tests/m4sugar.at +++ b/tests/m4sugar.at @@ -60,8 +60,8 @@ m4_copy([abc], [foo])dnl m4_stack_foreach([foo], [m4_n]) m4_stack_foreach_lifo([foo], [m4_n]) m4_stack_foreach_sep([abc], [ m4_index([abcdefghijkl],], [)]) -m4_define([colon], [:])dnl -m4_stack_foreach_sep_lifo([abc], [<], [>], [colon]) +m4_define([colon], [:])m4_define([lt], [<])m4_define([gt], [>])dnl +m4_stack_foreach_sep_lifo([abc], [lt], [gt], [colon]) m4_pushdef([xyz], [123])dnl m4_pushdef([xyz], [456])dnl m4_define([doit], [[$1](m4_stack_foreach_sep([xyz], [m4_dquote(], [)], [,])) @@ -1029,7 +1029,8 @@ myvar m4_map_args_w([a b c, d,e f g], [ ], [|]) m4_map_args_w([a b], [\1], [/]) -m4_map_args_w([a b], [/], [\1]) +m4_define([dashes], [--])dnl +m4_map_args_w([a b c], [/], [\1], [dashes]) dnl only one side effect expansion, prior to visiting list elements m4_foreach([i], [[1], [2], [3]m4_errprintn([hi])], [m4_errprintn(i)])dnl dnl shifting forms an important part of loops @@ -1070,7 +1071,7 @@ m4_shiftn(3,1,2,3):m4_shiftn(3,1,2,3,4) outer value a| b| c,| d,e| f| g| \1a/\1b/ -/a\1/b\1 +/a\1--/b\1--/c\1 ::4 :4 ]], [[hi -- 1.6.0.4
