mirror of
git://git.sv.gnu.org/autoconf
synced 2025-02-11 13:51:04 +08:00
Fix m4_map regression from 2007-10-16.
* lib/m4sugar/m4sugar.m4 (_m4_apply): New macro. (m4_map): Ignore empty sublists. For a list consisting of only an empty sublist, this restores 2.61 behavior of being a no-op. (m4_map_sep): Likewise, and expand separator. (m4_mapall, m4_mapall_sep): New macros, to regain 2.62 behavior. (_m4_map): Rewrite, to be common base for all four variants. * lib/m4sugar/foreach.m4 (_m4_map): Adjust to new prototype. * tests/m4sugar.at (m4@&t@_map): Add tests. * doc/autoconf.texi (Looping constructs) <m4_map>: Document new macros, and mention ramifications of expanded separator. * NEWS: Mention the change. Signed-off-by: Eric Blake <ebb9@byu.net>
This commit is contained in:
parent
903b58ef95
commit
aeff96ce94
15
ChangeLog
15
ChangeLog
@ -1,3 +1,18 @@
|
||||
2008-08-15 Eric Blake <ebb9@byu.net>
|
||||
|
||||
Fix m4_map regression from 2007-10-16.
|
||||
* lib/m4sugar/m4sugar.m4 (_m4_apply): New macro.
|
||||
(m4_map): Ignore empty sublists. For a list consisting of only an
|
||||
empty sublist, this restores 2.61 behavior of being a no-op.
|
||||
(m4_map_sep): Likewise, and expand separator.
|
||||
(m4_mapall, m4_mapall_sep): New macros, to regain 2.62 behavior.
|
||||
(_m4_map): Rewrite, to be common base for all four variants.
|
||||
* lib/m4sugar/foreach.m4 (_m4_map): Adjust to new prototype.
|
||||
* tests/m4sugar.at (m4@&t@_map): Add tests.
|
||||
* doc/autoconf.texi (Looping constructs) <m4_map>: Document new
|
||||
macros, and mention ramifications of expanded separator.
|
||||
* NEWS: Mention the change.
|
||||
|
||||
2008-08-14 Eric Blake <ebb9@byu.net>
|
||||
|
||||
Implement m4_transform_pair, to speed up AS_IF.
|
||||
|
17
NEWS
17
NEWS
@ -19,6 +19,14 @@ GNU Autoconf NEWS - User visible changes.
|
||||
|
||||
AC_TYPE_SIGNAL
|
||||
|
||||
** The macros m4_map and m4_map_sep now ignore any list elements
|
||||
consisting of just empty quotes, and m4_map_sep now expands its
|
||||
separator. This fixes a regression in 2.62 when these macros were
|
||||
first documented, for the sake of clients expecting the semantics
|
||||
that these macros had prior to that time. The new macros m4_mapall
|
||||
and m4_mapall_sep, along with extra quoting of the separator, can
|
||||
be used to get the semantics that m4_map_sep had in 2.62.
|
||||
|
||||
** Clients of m4_expand, such as AS_HELP_STRING and AT_SETUP, can now
|
||||
handle properly quoted but otherwise unbalanced parentheses (for
|
||||
some macros, this fixes a regression in 2.62).
|
||||
@ -27,10 +35,11 @@ GNU Autoconf NEWS - User visible changes.
|
||||
allowing the output of unbalanced parantheses in more contexts.
|
||||
|
||||
** The following m4sugar macros are new:
|
||||
m4_joinall m4_reverse m4_set_add m4_set_add_all m4_set_contains
|
||||
m4_set_contents m4_set_delete m4_set_difference m4_set_dump
|
||||
m4_set_empty m4_set_foreach m4_set_intersection m4_set_list
|
||||
m4_set_listc m4_set_remove m4_set_size m4_set_union
|
||||
m4_joinall m4_mapall m4_mapall_sep m4_reverse m4_set_add
|
||||
m4_set_add_all m4_set_contains m4_set_contents m4_set_delete
|
||||
m4_set_difference m4_set_dump m4_set_empty m4_set_foreach
|
||||
m4_set_intersection m4_set_list m4_set_listc m4_set_remove
|
||||
m4_set_size m4_set_union
|
||||
|
||||
** The following m4sugar macros now accept multiple arguments, as is the
|
||||
case with underlying m4:
|
||||
|
@ -10822,24 +10822,49 @@ The deprecated macro @code{AC_FOREACH} is an alias of
|
||||
@end defmac
|
||||
|
||||
@defmac m4_map (@var{macro}, @var{list})
|
||||
@defmacx m4_mapall (@var{macro}, @var{list})
|
||||
@defmacx m4_map_sep (@var{macro}, @var{separator}, @var{list})
|
||||
@defmacx m4_mapall_sep (@var{macro}, @var{separator}, @var{list})
|
||||
@msindex{map}
|
||||
@msindex{mapall}
|
||||
@msindex{map_sep}
|
||||
@msindex{mapall_sep}
|
||||
Loop over the comma separated quoted list of argument descriptions in
|
||||
@var{list}, and invoke @var{macro} with the arguments. An argument
|
||||
description is in turn a comma-separated quoted list of quoted elements,
|
||||
suitable for @code{m4_apply}, making it possible to invoke @var{macro}
|
||||
without arguments if an argument description is empty.
|
||||
@code{m4_map_sep} additionally outputs @var{separator} between macro
|
||||
invocations, with no additional expansion of the separator.
|
||||
suitable for @code{m4_apply}. The macros @code{m4_map} and
|
||||
@code{m4_map_sep} ignore empty argument descriptions, while
|
||||
@code{m4_mapall} and @code{m4_mapall_sep} invoke @var{macro} with no
|
||||
arguments. The macros @code{m4_map_sep} and @code{m4_mapall_sep}
|
||||
additionally expand @var{separator} between invocations of @var{macro}.
|
||||
|
||||
Note that @var{separator} is expanded, unlike in @code{m4_join}. When
|
||||
separating output with commas, this means that the map result can be
|
||||
used as a series of arguments, by using a single-quoted comma as
|
||||
@var{separator}, or as a single string, by using a double-quoted comma.
|
||||
|
||||
@example
|
||||
m4_map([m4_count], [])
|
||||
@result{}
|
||||
m4_map([ m4_count], [[],
|
||||
[[1]],
|
||||
[[1], [2]]])
|
||||
@result{} 1 2
|
||||
m4_mapall([ m4_count], [[],
|
||||
[[1]],
|
||||
[[1], [2]]])
|
||||
@result{} 0 1 2
|
||||
m4_map_sep([m4_eval], [,], [[[1+2]],
|
||||
[[10], [16]]])
|
||||
@result{}3,a
|
||||
m4_map_sep([m4_echo], [,], [[[a]], [[b]]])
|
||||
@result{}a,b
|
||||
m4_count(m4_map_sep([m4_echo], [,], [[[a]], [[b]]]))
|
||||
@result{}2
|
||||
m4_map_sep([m4_echo], [[,]], [[[a]], [[b]]])
|
||||
@result{}a,b
|
||||
m4_count(m4_map_sep([m4_echo], [[,]], [[[a]], [[b]]]))
|
||||
@result{}1
|
||||
@end example
|
||||
@end defmac
|
||||
|
||||
|
@ -257,11 +257,16 @@ m4_define([m4_reverse],
|
||||
# of LIST. $1, $2... must in turn be lists, appropriate for m4_apply.
|
||||
#
|
||||
# m4_map/m4_map_sep only execute once; the speedup comes in fixing
|
||||
# _m4_map. m4_foreach to the rescue.
|
||||
# _m4_map. The mismatch in () is intentional, since $1 supplies the
|
||||
# opening `(' (but it sure looks odd!). Build the temporary _m4_m:
|
||||
# $1, [$3])$1, [$4])...$1, [$m])_m4_popdef([_m4_m])
|
||||
m4_define([_m4_map],
|
||||
[m4_if([$#], [2], [],
|
||||
[m4_foreach([_m4_elt], [m4_shift2($@)],
|
||||
[m4_apply([$1], m4_defn([_m4_elt]))])])])
|
||||
[m4_define([_m4_m], m4_pushdef([_m4_m])_m4_for([_m4_m], [3], [$#], [1],
|
||||
[$0_([1], _m4_m)])[_m4_popdef([_m4_m])])_m4_m($@)])])
|
||||
|
||||
m4_define([_m4_map_],
|
||||
[[$$1, [$$2])]])
|
||||
|
||||
# m4_transform(EXPRESSION, ARG...)
|
||||
# --------------------------------
|
||||
|
@ -684,10 +684,17 @@ m4_define([m4_wrap_lifo],
|
||||
# ---------------------
|
||||
# Invoke MACRO, with arguments provided from the quoted list of
|
||||
# comma-separated quoted arguments. If LIST is empty, invoke MACRO
|
||||
# without arguments.
|
||||
# without arguments. The expansion will not be concatenated with
|
||||
# subsequent text.
|
||||
m4_define([m4_apply],
|
||||
[m4_if([$2], [], [$1], [$1($2)])[]])
|
||||
|
||||
# _m4_apply(MACRO, LIST)
|
||||
# ----------------------
|
||||
# Like m4_apply, except do nothing if LIST is empty.
|
||||
m4_define([_m4_apply],
|
||||
[m4_if([$2], [], [], [$1($2)[]])])
|
||||
|
||||
|
||||
# m4_count(ARGS)
|
||||
# --------------
|
||||
@ -803,7 +810,7 @@ m4_define([m4_quote], [[$*]])
|
||||
# ---------------
|
||||
# Like m4_quote, except that when there are no arguments, there is no
|
||||
# output. For conditional scenarios (such as passing _m4_quote as the
|
||||
# macro name in m4_map), this feature can be used to distinguish between
|
||||
# macro name in m4_mapall), this feature can be used to distinguish between
|
||||
# one argument of the empty string vs. no arguments. However, in the
|
||||
# normal case with arguments present, this is less efficient than m4_quote.
|
||||
m4_define([_m4_quote],
|
||||
@ -1002,31 +1009,63 @@ m4_define([m4_foreach_w],
|
||||
|
||||
|
||||
# m4_map(MACRO, LIST)
|
||||
# -------------------
|
||||
# Invoke MACRO($1), MACRO($2) etc. where $1, $2... are the elements
|
||||
# of LIST. $1, $2... must in turn be lists, appropriate for m4_apply.
|
||||
# m4_mapall(MACRO, LIST)
|
||||
# ----------------------
|
||||
# Invoke MACRO($1), MACRO($2) etc. where $1, $2... are the elements of
|
||||
# LIST. $1, $2... must in turn be lists, appropriate for m4_apply.
|
||||
# If LIST contains an empty sublist, m4_map skips the expansion of
|
||||
# MACRO, while m4_mapall expands MACRO with no arguments.
|
||||
#
|
||||
# Since LIST may be quite large, we want to minimize how often it appears
|
||||
# in the expansion. Rather than use m4_car/m4_cdr iteration, we unbox the
|
||||
# list, ignore the second argument, and use m4_shift2 to detect the end of
|
||||
# recursion.
|
||||
# Since LIST may be quite large, we want to minimize how often it
|
||||
# appears in the expansion. Rather than use m4_car/m4_cdr iteration,
|
||||
# we unbox the list, ignore the second argument, and use m4_shift2 to
|
||||
# detect the end of recursion. The mismatch in () is intentional; see
|
||||
# _m4_map. For m4_map, an empty list behaves like an empty sublist
|
||||
# and gets ignored; for m4_mapall, we must special-case the empty
|
||||
# list.
|
||||
m4_define([m4_map],
|
||||
[_m4_map([_m4_apply([$1]], [], $2)])
|
||||
|
||||
m4_define([m4_mapall],
|
||||
[m4_if([$2], [], [],
|
||||
[_$0([$1], [], $2)])])
|
||||
m4_define([_m4_map],
|
||||
[m4_if([$#], [2], [],
|
||||
[m4_apply([$1], [$3])$0([$1], m4_shift2($@))])])
|
||||
[_m4_map([m4_apply([$1]], [], $2)])])
|
||||
|
||||
|
||||
# m4_map_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 not further expanded.
|
||||
# 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
|
||||
# of a list of arguments by using a single-quoted comma as the
|
||||
# separator. For each empty sublist, m4_map_sep skips the expansion
|
||||
# of MACRO and SEPARATOR, while m4_mapall_sep expands MACRO with no
|
||||
# arguments.
|
||||
#
|
||||
# For m4_mapall_sep, merely expand the first iteration without the
|
||||
# separator, then include separator as part of subsequent recursion.
|
||||
# For m4_map_sep, things are trickier - we don't know if the first
|
||||
# list element is an empty sublist, so we must define a self-modifying
|
||||
# helper macro and use that as the separator instead.
|
||||
m4_define([m4_map_sep],
|
||||
[m4_if([$3], [], [],
|
||||
[m4_apply([$1], m4_car($3))_m4_map([[$2]$1], $3)])])
|
||||
[m4_pushdef([m4_Sep], [m4_define([m4_Sep], _m4_defn([m4_unquote]))])]dnl
|
||||
[_m4_map([_m4_apply([m4_Sep([$2])[]$1]], [], $3)m4_popdef([m4_Sep])])
|
||||
|
||||
m4_define([m4_mapall_sep],
|
||||
[m4_if([$3], [], [],
|
||||
[m4_apply([$1], m4_car($3))_m4_map([m4_apply([$2[]$1]], $3)])])
|
||||
|
||||
# _m4_map(PREFIX, IGNORED, SUBLIST, ...)
|
||||
# --------------------------------------
|
||||
# Common implementation for all four m4_map variants. The mismatch in
|
||||
# the number of () is intentional. PREFIX must supply a form of
|
||||
# m4_apply, the open `(', and the MACRO to be applied. Each iteration
|
||||
# then appends `,', the current SUBLIST and the closing `)', then
|
||||
# recurses to the next SUBLIST. IGNORED is an aid to ending recursion
|
||||
# efficiently.
|
||||
m4_define([_m4_map],
|
||||
[m4_if([$#], [2], [],
|
||||
[$1, [$3])$0([$1], m4_shift2($@))])])
|
||||
|
||||
# m4_transform(EXPRESSION, ARG...)
|
||||
# --------------------------------
|
||||
|
@ -757,12 +757,12 @@ autom4te: m4 failed with exit status: 1
|
||||
AT_CLEANUP
|
||||
|
||||
|
||||
## --------------- ##
|
||||
## m4_map{,_sep}. ##
|
||||
## --------------- ##
|
||||
## --------------------- ##
|
||||
## m4_map{,all}{,_sep}. ##
|
||||
## --------------------- ##
|
||||
|
||||
AT_SETUP([m4@&t@_map])
|
||||
AT_KEYWORDS([m4@&t@_apply])
|
||||
AT_KEYWORDS([m4@&t@_apply m4@&t@_map_sep m4@&t@_mapall m4@&t@_mapall_sep])
|
||||
AT_KEYWORDS([m4@&t@_count])
|
||||
|
||||
AT_CHECK_M4SUGAR_TEXT([[dnl
|
||||
@ -770,8 +770,21 @@ m4_map([m4_count], [])
|
||||
m4_map([ m4_count], [[],
|
||||
[[1]],
|
||||
[[1], [2]]])
|
||||
m4_mapall([ m4_count], [[],
|
||||
[[1]],
|
||||
[[1], [2]]])
|
||||
m4_map_sep([m4_eval], [,], [[[1+2]],
|
||||
[[10], [16]]])
|
||||
m4_count(m4_map_sep([m4_echo], [,], [[], [[1]], [[2]]]))
|
||||
m4_count(m4_mapall_sep([m4_echo], [,], [[], [[1]], [[2]]]))
|
||||
m4_map_sep([m4_eval], [[,]], [[[1+2]],
|
||||
[[10], [16]]])
|
||||
m4_count(m4_map_sep([m4_echo], [[,]], [[], [[1]], [[2]]]))
|
||||
m4_count(m4_mapall_sep([m4_echo], [[,]], [[], [[1]], [[2]]]))
|
||||
m4_map([-], [[]])
|
||||
m4_mapall([-], [[]])
|
||||
m4_map_sep([-], [:], [[]])
|
||||
m4_mapall_sep([-], [:], [[]])
|
||||
m4_define([a], [m4_if([$#], [0], [oops], [$1], [a], [pass], [oops])])dnl
|
||||
m4_define([a1], [oops])dnl
|
||||
m4_define([pass1], [oops])dnl
|
||||
@ -779,8 +792,18 @@ m4_map([a], [[[a]]])1
|
||||
m4_map([m4_unquote([a])], [m4_dquote([a])])
|
||||
]],
|
||||
[[
|
||||
1 2
|
||||
0 1 2
|
||||
3,a
|
||||
2
|
||||
3
|
||||
3,a
|
||||
1
|
||||
1
|
||||
|
||||
-
|
||||
|
||||
-
|
||||
pass1
|
||||
pass
|
||||
]], [])
|
||||
|
Loading…
Reference in New Issue
Block a user