# definition.
#
# Some macros simply can't be renamed with this method: namely, anything
-# involved in the implementation of m4_stack_foreach and m4_curry.
+# involved in the implementation of m4_stack_foreach_sep.
m4_define([m4_copy],
[m4_ifdef([$2], [m4_fatal([$0: won't overwrite defined macro: $2])],
- [m4_stack_foreach([$1], [m4_curry([m4_pushdef], [$2])])])]dnl
+ [m4_stack_foreach_sep([$1], [m4_pushdef([$2],], [)])])]dnl
[m4_ifdef([m4_location($1)], [m4_define([m4_location($2)], m4_location)])])
# the active definition of MACRO (it will not be the topmost, and may not
# be the one passed to FUNC either).
#
-# The recursive worker _m4_stack_reverse destructively swaps the order of a
-# stack. We use a temporary stack, and swap directions twice. Some macros
-# simply can't be examined with this method: namely, anything involved
-# in the implementation of _m4_stack_reverse.
-m4_define([_m4_stack_reverse],
-[m4_ifdef([$1], [m4_pushdef([$2], _m4_defn([$1]))$3[]_m4_popdef([$1])$0($@)])])
-
+# Some macros simply can't be examined with this method: namely,
+# anything involved in the implementation of _m4_stack_reverse.
m4_define([m4_stack_foreach],
[_m4_stack_reverse([$1], [m4_tmp-$1])]dnl
[_m4_stack_reverse([m4_tmp-$1], [$1], [$2(_m4_defn([m4_tmp-$1]))])])
[_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)
+# ------------------------------------------------
+# 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
+# expands the concatenation of PRE[]definition[]POST, and expands SEP
+# between consecutive expansions. Note that m4_stack_foreach([a], [b])
+# is equivalent to m4_stack_foreach_sep([a], [b(], [)]).
+m4_define([m4_stack_foreach_sep],
+[_m4_stack_reverse([$1], [m4_tmp-$1])]dnl
+[_m4_stack_reverse([m4_tmp-$1], [$1], [$2[]_m4_defn([m4_tmp-$1])$3], [$4])])
+
+m4_define([m4_stack_foreach_sep_lifo],
+[_m4_stack_reverse([$1], [m4_tmp-$1], [$2[]_m4_defn([m4_tmp-$1])$3], [$4])]dnl
+[_m4_stack_reverse([m4_tmp-$1], [$1])])
+
+
+# _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
+# of ACTION. The current definition is examined after the NEW has
+# been pushed but before OLD has been popped; this order is important,
+# as ACTION is permitted to operate on either _m4_defn([OLD]) or
+# _m4_defn([NEW]). Since the operation is destructive, this macro is
+# generally used twice, with a temporary macro name holding the
+# swapped copy.
+m4_define([_m4_stack_reverse],
+[m4_ifdef([$1], [m4_pushdef([$2],
+ _m4_defn([$1]))$3[]_m4_popdef([$1])$0([$1], [$2], [$4$3])])])
+
+
## --------------------------- ##
## 9. More diversion support. ##
## m4_stack_foreach. ##
## ------------------ ##
-AT_SETUP([m4@&t@_stack_foreach])
+AT_SETUP([m4@&t@_stack])
-AT_KEYWORDS([m4@&t@_stack_foreach_lifo m4@&t@_copy m4@&t@_n])
+AT_KEYWORDS([m4@&t@_stack_foreach m4@&t@_stack_foreach_lifo])
+AT_KEYWORDS([m4@&t@_stack_foreach_sep m4@&t@_stack_foreach_sep_lifo])
+AT_KEYWORDS([m4@&t@_copy m4@&t@_n])
# Test the semantics of macros to walk stacked macro definitions.
AT_CHECK_M4SUGAR_TEXT([[dnl
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_stack_foreach_sep_lifo([abc], [<], [>], [:])
m4_pushdef([xyz], [123])dnl
m4_pushdef([xyz], [456])dnl
-m4_define([doit], [[$1](m4_shift(m4_stack_foreach([xyz], [,m4_echo])))
+m4_define([doit], [[$1](m4_stack_foreach_sep([xyz], [m4_dquote(], [)], [,]))
])dnl
m4_stack_foreach([abc], [doit])]],
[[def
ghi
def
-def(123,456)
-ghi(123,456)
-jkl(123,456)
+ 3 6 9
+<jkl>:<ghi>:<def>
+def([123],[456])
+ghi([123],[456])
+jkl([123],[456])
]])
AT_CLEANUP