[Top][All Lists]

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

document recent iteration functions

From: Eric Blake
Subject: document recent iteration functions
Date: Fri, 19 Dec 2008 21:16:08 +0000 (UTC)
User-agent: Loom/3.14 (

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 <address@hidden>
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
* 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/ (m4@&address@hidden, M4 loops): Enhance tests.
* NEWS: Document new macros.

Signed-off-by: Eric Blake <address@hidden>
 ChangeLog              |   12 ++++++
 NEWS                   |    4 ++-
 doc/autoconf.texi      |   89 ++++++++++++++++++++++++++++++++++++++++++++++--
 lib/m4sugar/m4sugar.m4 |   45 ++++++++++++------------
 tests/       |    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  <address@hidden>
+       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/ (m4@&address@hidden, M4 loops): Enhance tests.
+       * NEWS: Document new macros.
 2008-12-18  Eric Blake  <address@hidden>
        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})
 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
 The deprecated macro @code{AC_FOREACH} is an alias of
@@ -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
address@hidden can be even more efficient.
 m4_define([list], [[1], [2], [3]])dnl
@@ -11218,6 +11221,30 @@ Looping constructs
 @end example
 @end defmac
address@hidden m4_map_args_sep (@ovar{pre}, @ovar{post}, @ovar{sep}, 
+Expand the sequence @address@hidden@address@hidden 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(address@hidden, address@hidden)} is equivalent
+to @code{m4_map_args_sep(address@hidden(], [)], [], address@hidden)}.  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}.
address@hidden defmac
address@hidden m4_map_args_w (@var{string}, @ovar{pre}, @ovar{post}, @ovar{sep})
+Expand the sequence @address@hidden@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,
address@hidden(address@hidden, address@hidden(], [)])} is more
+efficient than @code{m4_foreach_w([var], address@hidden,
address@hidden 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
address@hidden m4_stack_foreach (@var{macro}, @var{action})
address@hidden m4_stack_foreach_lifo (@var{macro}, @var{action})
+For each of the @code{m4_pushdef} definitions of @var{macro}, expand
address@hidden with the single argument of a definition of @var{macro}.
address@hidden starts with the oldest definition, while
address@hidden starts with the current definition.
address@hidden 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
address@hidden argument.
+m4_pushdef([a], [1])m4_pushdef([a], [2])dnl
+m4_stack_foreach([a], [ m4_incr])
address@hidden 2 3
+m4_stack_foreach_lifo([a], [ m4_curry([m4_substr], [abcd])])
address@hidden cd bcd
address@hidden example
address@hidden defmac
address@hidden m4_stack_foreach_sep (@var{macro}, @ovar{pre}, @ovar{post}, 
address@hidden m4_stack_foreach_sep_lifo (@var{macro}, @ovar{pre}, @ovar{post}, 
+  @ovar{sep})
+Expand the sequence @address@hidden@var{post}} for each
address@hidden definition of @var{macro}, additionally expanding
address@hidden 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,
address@hidden(address@hidden, address@hidden)} is short for
address@hidden(address@hidden, address@hidden(], [)])}.
address@hidden defmac
 @node Evaluation Macros
 @subsection Evaluation Macros
@@ -12071,7 +12139,22 @@ Set manipulation Macros
 corresponding counterpart of
 @code{m4_map_args(address@hidden(address@hidden))} or
 @code{m4_set_foreach(address@hidden, [var],
address@hidden(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.
address@hidden defmac
address@hidden m4_set_map_sep (@var{set}, @ovar{pre}, @ovar{post}, @ovar{sep})
+For each element in the set @var{set}, expand
address@hidden@address@hidden, 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(address@hidden, address@hidden) is equivalent
+to @code{m4_set_map_sep(address@hidden, address@hidden(], [)])}.
 @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_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.
 [_$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_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],
     [_$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_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.
diff --git a/tests/ b/tests/
index a876588..4938027 100644
--- a/tests/
+++ b/tests/
@@ -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|
 ]], [[hi

reply via email to

[Prev in Thread] Current Thread [Next in Thread]