[Top][All Lists]
[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
Re: naming m4_transform
From: |
Eric Blake |
Subject: |
Re: naming m4_transform |
Date: |
Fri, 17 Oct 2008 16:36:50 -0600 |
User-agent: |
Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.8.1.17) Gecko/20080914 Thunderbird/2.0.0.17 Mnenhy/0.7.5.666 |
-----BEGIN PGP SIGNED MESSAGE-----
Hash: SHA1
According to Eric Blake on 10/14/2008 5:31 PM:
>
> I like it. Here's three preliminary patches along this front:
>
> aaee3a9 Document m4_map_args.
> 4cd6caa Add m4_set_map.
> 3bdb8d4 Improve suggested test filtering.
>
> But m4 doesn't make it easy to write anonymous functions. By making
> m4_map_args supply the ( and ) around a single argument, I no longer have a
> way
> to inject $2 and $3 into the mapping function, at least, not without some
> inefficiencies. I've thought about something like this (untested, and I'm
> not
> even sure I'm using the best naming convention):
>
> # m4_curry(MACRO, ARG...)
Here's what I'm committing for now. I still plan on optimizing the uses
of m4_foreach{,_w} within autoconf, but haven't yet timed whether m4_join
or m4_curry gives better results across m4 1.4.x and m4 1.6.
- --
Don't work too hard, make some time for fun as well!
Eric Blake address@hidden
-----BEGIN PGP SIGNATURE-----
Version: GnuPG v1.4.9 (Cygwin)
Comment: Public key at home.comcast.net/~ericblake/eblake.gpg
Comment: Using GnuPG with Mozilla - http://enigmail.mozdev.org
iEYEARECAAYFAkj5E4IACgkQ84KuGfSFAYD30QCglXMwHuI+K4YVY5aB/Bj7fYJ6
Dj0AoNEP19uoT5eitkg1RbhCsGLvC/7I
=ctHz
-----END PGP SIGNATURE-----
>From f4ace96990c107f028a496ebd45ff031d7302a7b Mon Sep 17 00:00:00 2001
From: Eric Blake <address@hidden>
Date: Mon, 13 Oct 2008 10:46:40 -0600
Subject: [PATCH] Document m4_map_args.
* lib/m4sugar/m4sugar.m4 (m4_transform, m4_transform_pair):
Rename...
(m4_map_args, m4_map_args_pair): ...to these names, and document.
(m4_version_unletter): Use the interface.
* lib/m4sugar/foreach.m4 (m4_map_args, m4_map_args_pair)
(_m4_map_args_, _m4_map_args_pair_, _m4_map_args_pair_end):
Perform same renames.
* lib/m4sugar/m4sh.m4 (AS_CASE, AS_IF): Adjust callers.
* tests/m4sugar.at (m4@&address@hidden): New test.
(recursion): Adjust caller.
* tests/m4sh.at (AS@&address@hidden and AS@&address@hidden): Likewise.
* doc/autoconf.texi (Looping constructs) <m4_map_args>: Document
this interface.
* NEWS: Mention the new macros.
Signed-off-by: Eric Blake <address@hidden>
---
ChangeLog | 18 ++++++++++++++++++
NEWS | 2 +-
doc/autoconf.texi | 35 +++++++++++++++++++++++++++++++++++
lib/m4sugar/foreach.m4 | 26 +++++++++++++-------------
lib/m4sugar/m4sh.m4 | 4 ++--
lib/m4sugar/m4sugar.m4 | 27 +++++++++++++--------------
tests/m4sh.at | 2 +-
tests/m4sugar.at | 44 +++++++++++++++++++++++++++++++++++++++++---
8 files changed, 124 insertions(+), 34 deletions(-)
diff --git a/ChangeLog b/ChangeLog
index 32bf23b..988018f 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,5 +1,23 @@
2008-10-17 Eric Blake <address@hidden>
+ Document m4_map_args.
+ * lib/m4sugar/m4sugar.m4 (m4_transform, m4_transform_pair):
+ Rename...
+ (m4_map_args, m4_map_args_pair): ...to these names, and document.
+ (m4_version_unletter): Use the interface.
+ * lib/m4sugar/foreach.m4 (m4_map_args, m4_map_args_pair)
+ (_m4_map_args_, _m4_map_args_pair_, _m4_map_args_pair_end):
+ Perform same renames.
+ * lib/m4sugar/m4sh.m4 (AS_CASE, AS_IF): Adjust callers.
+ * tests/m4sugar.at (m4@&address@hidden): New test.
+ (recursion): Adjust caller.
+ * tests/m4sh.at (AS@&address@hidden and AS@&address@hidden): Likewise.
+ * doc/autoconf.texi (Looping constructs) <m4_map_args>: Document
+ this interface.
+ * NEWS: Mention the new macros.
+
+2008-10-17 Eric Blake <address@hidden>
+
Reduce vertical whitespace in configure.
* lib/autoconf/general.m4 (AC_INIT): Silence newline output during
m4 side effect initializations.
diff --git a/NEWS b/NEWS
index 72eab50..664425c 100644
--- a/NEWS
+++ b/NEWS
@@ -13,7 +13,7 @@ GNU Autoconf NEWS - User visible changes.
** Configure scripts now use shell functions.
** The following m4sugar macros are new:
- m4_default_quoted
+ m4_default_quoted m4_map_args m4_map_args_pair
** The following documented m4sh macros are new:
AS_LINENO_PREPARE AS_ME_PREPARE AS_VAR_COPY
diff --git a/doc/autoconf.texi b/doc/autoconf.texi
index 67c1b42..9573034 100644
--- a/doc/autoconf.texi
+++ b/doc/autoconf.texi
@@ -10928,6 +10928,41 @@ Looping constructs
@end example
@end defmac
address@hidden m4_map_args (@var{macro}, @address@hidden)
address@hidden
+Repeatedly invoke @var{macro} with each successive @var{arg} as its
+argument. In the following example, three solutions are presented with
+the same expansion; the solution using @code{m4_map_args} is the most
+efficient.
address@hidden
+m4_define([active], [ACTIVE])dnl
+m4_foreach([var], [[plain], [active]], [ m4_echo(m4_defn([var]))])
address@hidden plain active
+m4_map([ m4_echo], [[[plain]], [[active]]])
address@hidden plain active
+m4_map_args([ m4_echo], [plain], [active])
address@hidden plain active
address@hidden example
address@hidden defmac
+
address@hidden m4_map_args_pair (@var{macro}, @dvar{macro-end, macro}, @
+ @address@hidden)
address@hidden
+For every pair of arguments @var{arg}, invoke @var{macro} with two
+arguments. If there is an odd number of arguments, invoke
address@hidden, which defaults to @var{macro}, with the remaining
+argument.
+
address@hidden
+m4_map_args_pair([, m4_reverse], [], [1], [2], [3])
address@hidden, 2, 1, 3
+m4_map_args_pair([, m4_reverse], [, m4_dquote], [1], [2], [3])
address@hidden, 2, 1, [3]
+m4_map_args_pair([, m4_reverse], [, m4_dquote], [1], [2], [3], [4])
address@hidden, 2, 1, 4, 3
address@hidden example
address@hidden defmac
+
@defmac m4_shiftn (@var{count}, @dots{})
@defmacx m4_shift2 (@dots{})
@defmacx m4_shift3 (@dots{})
diff --git a/lib/m4sugar/foreach.m4 b/lib/m4sugar/foreach.m4
index bfad301..9dc02e1 100644
--- a/lib/m4sugar/foreach.m4
+++ b/lib/m4sugar/foreach.m4
@@ -270,33 +270,33 @@ m4_define([_m4_map],
m4_define([_m4_map_],
[[$$1, [$$2])]])
-# m4_transform(EXPRESSION, ARG...)
-# --------------------------------
+# m4_map_args(EXPRESSION, ARG...)
+# -------------------------------
# Expand EXPRESSION([ARG]) for each argument. More efficient than
# m4_foreach([var], [ARG...], [EXPRESSION(m4_defn([var]))])
#
-# Invoke the temporary macro _m4_transform, defined as:
-# $1([$2])[]$1([$3])[]...$1([$m])[]_m4_popdef([_m4_transform])
-m4_define([m4_transform],
+# Invoke the temporary macro _m4_map_args, defined as:
+# $1([$2])[]$1([$3])[]...$1([$m])[]_m4_popdef([_m4_map_args])
+m4_define([m4_map_args],
[m4_if([$#], [0], [m4_fatal([$0: too few arguments: $#])],
[$#], [1], [],
[m4_define([_$0], m4_pushdef([_$0])_m4_for([_$0], [2], [$#], [1],
[_$0_([1], _$0)])[_m4_popdef([_$0])])_$0($@)])])
-m4_define([_m4_transform_],
+m4_define([_m4_map_args_],
[[$$1([$$2])[]]])
-# m4_transform_pair(EXPRESSION, [END-EXPR = EXPRESSION], ARG...)
-# --------------------------------------------------------------
+# m4_map_args_pair(EXPRESSION, [END-EXPR = EXPRESSION], ARG...)
+# -------------------------------------------------------------
# Perform a pairwise grouping of consecutive ARGs, by expanding
# EXPRESSION([ARG1], [ARG2]). If there are an odd number of ARGs, the
# final argument is expanded with END-EXPR([ARGn]).
#
-# Build the temporary macro _m4_transform_pair, with the $2([$m+1])
+# Build the temporary macro _m4_map_args_pair, with the $2([$m+1])
# only output if $# is odd:
# $1([$3], [$4])[]$1([$5], [$6])[]...$1([$m-1],
-# [$m])[]m4_default([$2], [$1])([$m+1])[]_m4_popdef([_m4_transform_pair])
-m4_define([m4_transform_pair],
+# [$m])[]m4_default([$2], [$1])([$m+1])[]_m4_popdef([_m4_map_args_pair])
+m4_define([m4_map_args_pair],
[m4_if([$#], [0], [m4_fatal([$0: too few arguments: $#])],
[$#], [1], [m4_fatal([$0: too few arguments: $#: $1])],
[$#], [2], [],
@@ -305,10 +305,10 @@ m4_define([m4_transform_pair],
m4_eval([$# / 2 * 2 - 1]), [2], [_$0_([1], _$0, m4_incr(_$0))])_$0_end(
[1], [2], [$#])[_m4_popdef([_$0])])_$0($@)])])
-m4_define([_m4_transform_pair_],
+m4_define([_m4_map_args_pair_],
[[$$1([$$2], [$$3])[]]])
-m4_define([_m4_transform_pair_end],
+m4_define([_m4_map_args_pair_end],
[m4_if(m4_eval([$3 & 1]), [1], [[m4_default([$$2], [$$1])([$$3])[]]])])
# m4_join(SEP, ARG1, ARG2...)
diff --git a/lib/m4sugar/m4sh.m4 b/lib/m4sugar/m4sh.m4
index 1feff8f..27ef262 100644
--- a/lib/m4sugar/m4sh.m4
+++ b/lib/m4sugar/m4sh.m4
@@ -490,7 +490,7 @@ m4_define([_AS_CASE_DEFAULT],
m4_defun([AS_CASE],
[m4_ifval([$2$3],
[case $1 in
-m4_transform_pair([_$0], [_$0_DEFAULT], m4_shift($@))dnl
+m4_map_args_pair([_$0], [_$0_DEFAULT], m4_shift($@))dnl
esac
])dnl
])# AS_CASE
@@ -535,7 +535,7 @@ m4_defun([AS_IF],
[m4_ifval([$2$3],
[if $1; then
m4_default([$2], [:])
-m4_transform_pair([_$0], [_$0_ELSE], m4_shift2($@))dnl
+m4_map_args_pair([_$0], [_$0_ELSE], m4_shift2($@))dnl
fi
])dnl
])# AS_IF
diff --git a/lib/m4sugar/m4sugar.m4 b/lib/m4sugar/m4sugar.m4
index 681f4b0..fa01ec6 100644
--- a/lib/m4sugar/m4sugar.m4
+++ b/lib/m4sugar/m4sugar.m4
@@ -1106,34 +1106,34 @@ m4_define([_m4_map],
[m4_if([$#], [2], [],
[$1, [$3])$0([$1], m4_shift2($@))])])
-# m4_transform(EXPRESSION, ARG...)
-# --------------------------------
+# m4_map_args(EXPRESSION, ARG...)
+# -------------------------------
# Expand EXPRESSION([ARG]) for each argument. More efficient than
# m4_foreach([var], [ARG...], [EXPRESSION(m4_defn([var]))])
#
# Please keep foreach.m4 in sync with any adjustments made here.
-m4_define([m4_transform],
+m4_define([m4_map_args],
[m4_if([$#], [0], [m4_fatal([$0: too few arguments: $#])],
[$#], [1], [],
[$#], [2], [$1([$2])[]],
[$1([$2])[]$0([$1], m4_shift2($@))])])
-# m4_transform_pair(EXPRESSION, [END-EXPR = EXPRESSION], ARG...)
-# --------------------------------------------------------------
+# m4_map_args_pair(EXPRESSION, [END-EXPR = EXPRESSION], ARG...)
+# -------------------------------------------------------------
# Perform a pairwise grouping of consecutive ARGs, by expanding
# EXPRESSION([ARG1], [ARG2]). If there are an odd number of ARGs, the
# final argument is expanded with END-EXPR([ARGn]).
#
# For example:
# m4_define([show], [($*)m4_newline])dnl
-# m4_transform_pair([show], [], [a], [b], [c], [d], [e])dnl
+# m4_map_args_pair([show], [], [a], [b], [c], [d], [e])dnl
# => (a,b)
# => (c,d)
# => (e)
#
# Please keep foreach.m4 in sync with any adjustments made here.
-m4_define([m4_transform_pair],
+m4_define([m4_map_args_pair],
[m4_if([$#], [0], [m4_fatal([$0: too few arguments: $#])],
[$#], [1], [m4_fatal([$0: too few arguments: $#: $1])],
[$#], [2], [],
@@ -2387,9 +2387,9 @@ m4_define([m4_sign],
# Nl -> (N+1).-1.(l#)
#
# for example:
-# [2.14a] -> [2.14+1.-1.[0r36:a]] -> 2.15.-1.10
-# [2.14b] -> [2.15+1.-1.[0r36:b]] -> 2.15.-1.11
-# [2.61aa.b] -> [2.61+1.-1.[0r36:aa],+1.-1.[0r36:b]] -> 2.62.-1.370.1.-1.11
+# [2.14a] -> [2,14+1,-1,[0r36:a]] -> 2.15.-1.10
+# [2.14b] -> [2,15+1,-1,[0r36:b]] -> 2.15.-1.11
+# [2.61aa.b] -> [2.61,1,-1,[0r36:aa],+1,-1,[0r36:b]] -> 2.62.-1.370.1.-1.11
#
# This macro expects reasonable version numbers, but can handle double
# letters and does not expand any macros. Original version strings can
@@ -2397,11 +2397,10 @@ m4_define([m4_sign],
#
# Inline constant expansions, to avoid m4_defn overhead.
# _m4_version_unletter is the real workhorse used by m4_version_compare,
-# but since [0r36:a] is less readable than 10, we provide a wrapper for
-# human use.
+# but since [0r36:a] and commas are less readable than 10 and dots, we
+# provide a wrapper for human use.
m4_define([m4_version_unletter],
-[m4_map_sep([m4_eval], [.],
- m4_dquote(m4_dquote_elt(m4_unquote(_$0([$1])))))])
+[m4_substr(m4_map_args([.m4_eval], m4_unquote(_$0([$1]))), [1])])
m4_define([_m4_version_unletter],
[m4_bpatsubst(m4_translit([[[$1]]], [.-], [,,]),]dnl
m4_dquote(m4_dquote(m4_defn([m4_cr_Letters])))[[+],
diff --git a/tests/m4sh.at b/tests/m4sh.at
index 5a5ebec..73438fb 100644
--- a/tests/m4sh.at
+++ b/tests/m4sh.at
@@ -724,7 +724,7 @@ AT_CLEANUP
## ------------------- ##
AT_SETUP([AS@&address@hidden and AS@&address@hidden)
-AT_KEYWORDS([m4sh m4@&address@hidden)
+AT_KEYWORDS([m4sh m4@&address@hidden)
AT_DATA_M4SH([script.as], [[dnl
AS_INIT
diff --git a/tests/m4sugar.at b/tests/m4sugar.at
index 89109c6..72b7843 100644
--- a/tests/m4sugar.at
+++ b/tests/m4sugar.at
@@ -866,6 +866,44 @@ hi
AT_CLEANUP
+## --------------------- ##
+## m4_map_args{,_pair}. ##
+## --------------------- ##
+
+AT_SETUP([m4@&address@hidden)
+AT_KEYWORDS([m4@&address@hidden m4@&address@hidden)
+
+AT_CHECK_M4SUGAR_TEXT([[m4_define([active], [ACTIVE])dnl
+m4_map_args([ m4_echo])
+m4_map_args([ m4_echo], [plain], [active])
+m4_map_args([m4_unquote], [plain], [active])
+m4_map_args_pair([, m4_reverse], [])
+m4_map_args_pair([, m4_reverse], [], [1])
+m4_map_args_pair([, m4_reverse], [], [1], [2])
+m4_map_args_pair([, m4_reverse], [], [1], [2], [3])
+m4_map_args_pair([, m4_reverse], [], [1], [2], [3], [4])
+m4_map_args_pair([, m4_reverse], [, m4_dquote], [1])
+m4_map_args_pair([, m4_reverse], [, m4_dquote], [1], [2])
+m4_map_args_pair([, m4_reverse], [, m4_dquote], [1], [2], [3])
+m4_map_args_pair([, m4_reverse], [, m4_dquote], [1], [2], [3], [4])
+]],
+[[
+ plain active
+plainACTIVE
+
+, 1
+, 2, 1
+, 2, 1, 3
+, 2, 1, 4, 3
+, [1]
+, 2, 1
+, 2, 1, [3]
+, 2, 1, 4, 3
+]])
+
+AT_CLEANUP
+
+
## ------------ ##
## m4_combine. ##
## ------------ ##
@@ -981,7 +1019,7 @@ AT_SETUP([recursion])
AT_KEYWORDS([m4@&address@hidden m4@&address@hidden m4@&address@hidden
m4@&address@hidden
m4@&address@hidden m4@&address@hidden m4@&address@hidden m4@&address@hidden
m4@&address@hidden
m4@&address@hidden m4@&address@hidden m4@&address@hidden m4@&address@hidden
m4@&address@hidden m4@&address@hidden
-m4@&address@hidden m4@&address@hidden m4@&address@hidden)
+m4@&address@hidden m4@&address@hidden m4@&address@hidden)
dnl This test completes in a reasonable time if m4_foreach is linear,
dnl but thrashes if it is quadratic. If we are testing with m4 1.4.x,
@@ -1009,7 +1047,7 @@ m4_bpatsubsts([a1]m4_for([i], [1], [10000], [], [,i]),
[a2], [A])
m4_bmatch([9997]m4_for([i], [1], [10000], [], [,^i$]))
m4_define([up], [m4_define([$1], m4_incr($1))$1])m4_define([j], 0)dnl
m4_cond(m4_for([i], [1], [10000], [], [[up([j])], [9990], i,]) [oops]) j
-m4_count(m4_transform_pair([,m4_quote], []m4_transform([,m4_echo]m4_for([i],
+m4_count(m4_map_args_pair([,m4_quote], []m4_map_args([,m4_echo]m4_for([i],
[1], [10000], [], [,i]))))
m4_divert_pop(0)
]])
@@ -1066,7 +1104,7 @@ m4_bpatsubsts([a1]m4_for([i], [1], [10000], [], [,i]),
[a2], [A])
m4_bmatch([9997]m4_for([i], [1], [10000], [], [,^i$]))
m4_define([up], [m4_define([$1], m4_incr($1))$1])m4_define([j], 0)dnl
m4_cond(m4_for([i], [1], [10000], [], [[up([j])], [9990], i,]) [oops]) j
-m4_count(m4_transform_pair([,m4_quote], []m4_transform([,m4_echo]m4_for([i],
+m4_count(m4_map_args_pair([,m4_quote], []m4_map_args([,m4_echo]m4_for([i],
[1], [10000], [], [,i]))))
m4_divert_pop(0)
]])
--
1.6.0.2
>From 92f34215fcf5e13206f7632ea832b48ce4dca702 Mon Sep 17 00:00:00 2001
From: Eric Blake <address@hidden>
Date: Mon, 13 Oct 2008 15:37:31 -0600
Subject: [PATCH] Add m4_set_map.
* lib/m4sugar/m4sugar.m4 (m4_set_foreach): New macro.
* tests/m4sugar.at (m4@&address@hidden): Enhance test.
* doc/autoconf.texi (Set manipulation Macros) <m4_set_map>:
Document it.
* NEWS: Likewise.
Signed-off-by: Eric Blake <address@hidden>
---
ChangeLog | 7 +++++++
NEWS | 2 +-
doc/autoconf.texi | 14 +++++++++++++-
lib/m4sugar/m4sugar.m4 | 15 ++++++++++++++-
tests/m4sugar.at | 12 ++++++++++--
5 files changed, 45 insertions(+), 5 deletions(-)
diff --git a/ChangeLog b/ChangeLog
index 988018f..45a0434 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,5 +1,12 @@
2008-10-17 Eric Blake <address@hidden>
+ Add m4_set_map.
+ * lib/m4sugar/m4sugar.m4 (m4_set_foreach): New macro.
+ * tests/m4sugar.at (m4@&address@hidden): Enhance test.
+ * doc/autoconf.texi (Set manipulation Macros) <m4_set_map>:
+ Document it.
+ * NEWS: Likewise.
+
Document m4_map_args.
* lib/m4sugar/m4sugar.m4 (m4_transform, m4_transform_pair):
Rename...
diff --git a/NEWS b/NEWS
index 664425c..1ba23cc 100644
--- a/NEWS
+++ b/NEWS
@@ -13,7 +13,7 @@ GNU Autoconf NEWS - User visible changes.
** Configure scripts now use shell functions.
** The following m4sugar macros are new:
- m4_default_quoted m4_map_args m4_map_args_pair
+ m4_default_quoted m4_map_args m4_map_args_pair m4_set_map
** The following documented m4sh macros are new:
AS_LINENO_PREPARE AS_ME_PREPARE AS_VAR_COPY
diff --git a/doc/autoconf.texi b/doc/autoconf.texi
index 9573034..d539329 100644
--- a/doc/autoconf.texi
+++ b/doc/autoconf.texi
@@ -11751,6 +11751,17 @@ Set manipulation Macros
@end example
@end defmac
address@hidden m4_set_map (@var{set}, @var{action})
address@hidden
+For each element in the set @var{set}, expand @var{action} with a single
+argument of the set element. Behavior is unspecified if @var{action}
+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 passed as an argument. This macro is faster than the
+corresponding
address@hidden(address@hidden(address@hidden))}.
address@hidden defmac
+
@defmac m4_set_remove (@var{set}, @var{value}, @ovar{if-present}, @
@ovar{if-absent})
@msindex{set_remove}
@@ -11758,7 +11769,8 @@ Set manipulation Macros
expand @var{if-present}. Otherwise expand @var{if-absent}. This macro
operates in constant time so that multiple removals will scale linearly
rather than quadratically; but when used outside of
address@hidden, it leaves memory occupied until the set is later
address@hidden or @code{m4_set_map}, it leaves memory occupied
+until the set is later
compacted by @code{m4_set_contents} or @code{m4_set_list}. Several
other set operations are then less efficient between the time of element
removal and subsequent memory compaction, but still maintain their
diff --git a/lib/m4sugar/m4sugar.m4 b/lib/m4sugar/m4sugar.m4
index fa01ec6..2d50230 100644
--- a/lib/m4sugar/m4sugar.m4
+++ b/lib/m4sugar/m4sugar.m4
@@ -2717,6 +2717,19 @@ m4_define([m4_set_listc],
[_m4_set_contents_1])([$1])_m4_set_contents_2([$1],
[,_m4_defn([_m4_set_($1)])])])
+# m4_set_map(SET, ACTION)
+# -----------------------
+# For each element of SET, expand ACTION with a single argument of the
+# current element. ACTION should not recursively list SET's contents,
+# add elements to SET, nor delete any element from SET except the one
+# passed as an argument. The order that the elements are visited in
+# is not guaranteed. This is faster than the corresponding
+# m4_map_args([ACTION]m4_set_listc([SET]))
+m4_define([m4_set_map],
+[m4_ifdef([_m4_set_cleanup($1)],
+ [_m4_set_contents_1c], [_m4_set_contents_1])([$1])_m4_set_contents_2([$1],
+ [$2(_m4_defn([_m4_set_($1)]))])])
+
# m4_set_remove(SET, VALUE, [IF-PRESENT], [IF-ABSENT])
# ----------------------------------------------------
# If VALUE is an element of SET, delete it and expand IF-PRESENT.
@@ -2726,7 +2739,7 @@ m4_define([m4_set_listc],
#
# Optimize if the element being removed is the most recently added,
# since defining _m4_set_cleanup($1) slows down so many other macros.
-# In particular, this plays well with m4_set_foreach.
+# In particular, this plays well with m4_set_foreach and m4_set_map.
m4_define([m4_set_remove],
[m4_set_contains([$1], [$2], [_m4_set_size([$1],
[m4_decr])m4_if(_m4_defn([_m4_set([$1])]), [$2],
diff --git a/tests/m4sugar.at b/tests/m4sugar.at
index 72b7843..d6f40a7 100644
--- a/tests/m4sugar.at
+++ b/tests/m4sugar.at
@@ -1136,7 +1136,8 @@ AT_SETUP([m4@&address@hidden)
AT_KEYWORDS([m4@&address@hidden m4@&address@hidden m4@&address@hidden
m4@&address@hidden m4@&address@hidden m4@&address@hidden m4@&address@hidden
m4@&address@hidden m4@&address@hidden m4@&address@hidden m4@&address@hidden
-m4@&address@hidden m4@&address@hidden m4@&address@hidden m4@&address@hidden)
+m4@&address@hidden m4@&address@hidden m4@&address@hidden m4@&address@hidden
+m4@&address@hidden)
# Simple tests
AT_CHECK_M4SUGAR_TEXT([[m4_set_contains([a], [1], [yes], [no])
@@ -1161,6 +1162,8 @@ m4_set_difference([a], [b])
m4_set_difference([b], [a])
m4_set_intersection([a], [b])
m4_set_union([a], [b])
+m4_define([printodd], [m4_if(m4_eval([$1 & 1]), [1], [:$1])])dnl
+m4_set_map([a], [printodd])
m4_set_foreach([a], [i], [m4_if(m4_eval(i & 1), [1], [m4_set_remove([a], i)])])
m4_set_list([a])
m4_set_add([a], [])
@@ -1196,6 +1199,7 @@ yes
,,4
,3
,1,2,3,,4
+:1:3
2
@@ -1259,11 +1263,15 @@ m4_len(m4_set_contents([a]))
m4_len(m4_set_foreach([b], [b], [m4_if(m4_eval(b & 1), [1],
[m4_set_remove([b], b, [-])])]))
m4_set_size([b])
+m4_define([prune3x], [m4_if(m4_eval([$1 % 3]), [0],
+ [m4_set_remove([a], [$1], [-])])])dnl
+m4_len(m4_set_map([a], [prune3x]))
m4_count(m4_shift(m4_set_intersection([a], [b])))
]], [[38894
5000
5000
-5000
+3333
+3334
]])
AT_CLEANUP
--
1.6.0.2
>From a00c4430bad94ff1062e3fcfc7358f5eb0bd81bd Mon Sep 17 00:00:00 2001
From: Eric Blake <address@hidden>
Date: Fri, 17 Oct 2008 16:12:17 -0600
Subject: [PATCH] Improve suggested test filtering.
* lib/m4sugar/m4sh.m4 (_AS_DETECT_SUGGESTED_PRUNE): New macro,
extracted from...
(_AS_DETECT_BETTER_SHELL): ...here, to use faster API. No need to
check for an empty required set.
Signed-off-by: Eric Blake <address@hidden>
---
ChangeLog | 6 ++++++
lib/m4sugar/m4sh.m4 | 27 +++++++++++++++------------
2 files changed, 21 insertions(+), 12 deletions(-)
diff --git a/ChangeLog b/ChangeLog
index 45a0434..4e4127d 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,5 +1,11 @@
2008-10-17 Eric Blake <address@hidden>
+ Improve suggested test filtering.
+ * lib/m4sugar/m4sh.m4 (_AS_DETECT_SUGGESTED_PRUNE): New macro,
+ extracted from...
+ (_AS_DETECT_BETTER_SHELL): ...here, to use faster API. No need to
+ check for an empty required set.
+
Add m4_set_map.
* lib/m4sugar/m4sugar.m4 (m4_set_foreach): New macro.
* tests/m4sugar.at (m4@&address@hidden): Enhance test.
diff --git a/lib/m4sugar/m4sh.m4 b/lib/m4sugar/m4sh.m4
index 27ef262..75b8d84 100644
--- a/lib/m4sugar/m4sh.m4
+++ b/lib/m4sugar/m4sh.m4
@@ -173,6 +173,14 @@ m4_defun([_AS_DETECT_SUGGESTED],
])])
+# _AS_DETECT_SUGGESTED_PRUNE(TEST)
+# --------------------------------
+# If TEST is also a required test, remove it from the set of suggested tests.
+m4_define([_AS_DETECT_SUGGESTED_PRUNE],
+[m4_set_contains([_AS_DETECT_REQUIRED_BODY], [$1],
+ [m4_set_remove([_AS_DETECT_SUGGESTED_BODY], [$1])])])
+
+
# _AS_DETECT_BETTER_SHELL
# -----------------------
# The real workhorse for detecting a shell with the correct
@@ -190,18 +198,13 @@ m4_defun([_AS_DETECT_SUGGESTED],
m4_defun([_AS_DETECT_BETTER_SHELL],
[if test "x$CONFIG_SHELL" = x; then
dnl Remove any tests from suggested that are also required
- m4_set_foreach([_AS_DETECT_SUGGESTED_BODY], [AS_snippet],
- [m4_set_contains([_AS_DETECT_REQUIRED_BODY],
- _m4_defn([AS_snippet]),
- [m4_set_remove([_AS_DETECT_SUGGESTED_BODY],
- _m4_defn([AS_snippet]))])])dnl
- m4_set_empty([_AS_DETECT_REQUIRED_BODY], [as_have_required=yes],
- [as_bourne_compatible="AS_ESCAPE(m4_expand([_AS_BOURNE_COMPATIBLE]))"
-
as_required="AS_ESCAPE(m4_expand(m4_set_contents([_AS_DETECT_REQUIRED_BODY])))"
-
as_suggested="AS_ESCAPE(m4_expand(m4_set_contents([_AS_DETECT_SUGGESTED_BODY])))"
- AS_IF([_AS_RUN(["$as_required"])],
- [as_have_required=yes],
- [as_have_required=no])])
+ m4_set_map([_AS_DETECT_SUGGESTED_BODY], [_AS_DETECT_SUGGESTED_PRUNE])dnl
+ as_bourne_compatible="AS_ESCAPE(m4_expand([_AS_BOURNE_COMPATIBLE]))"
+
as_required="AS_ESCAPE(m4_expand(m4_set_contents([_AS_DETECT_REQUIRED_BODY])))"
+
as_suggested="AS_ESCAPE(m4_expand(m4_set_contents([_AS_DETECT_SUGGESTED_BODY])))"
+ AS_IF([_AS_RUN(["$as_required"])],
+ [as_have_required=yes],
+ [as_have_required=no])
AS_IF([test x$as_have_required = xyes && _AS_RUN(["$as_suggested"])],
[],
[as_candidate_shells=
--
1.6.0.2
>From c6b172ee196b189c4074f5e623f22d9b47decb6f Mon Sep 17 00:00:00 2001
From: Eric Blake <address@hidden>
Date: Wed, 15 Oct 2008 11:55:45 -0600
Subject: [PATCH] Add m4_curry.
* lib/m4sugar/m4sugar.m4 (m4_curry, _m4_curry): New macros.
* tests/m4sugar.at (m4@&address@hidden): Rename...
(m4@&address@hidden and m4@&address@hidden): ...and add currying tests.
* doc/autoconf.texi (Looping constructs) <m4_map_args>: Document
currying as a way to add parameters.
(Evaluation Macros) <m4_curry>: Document the new macro.
* NEWS: Likewise.
Signed-off-by: Eric Blake <address@hidden>
---
ChangeLog | 9 ++++++++
NEWS | 3 +-
doc/autoconf.texi | 39 +++++++++++++++++++++++++++++++++++-
lib/m4sugar/m4sugar.m4 | 14 ++++++++++++
tests/m4sugar.at | 52 ++++++++++++++++++++++++++++++-----------------
5 files changed, 96 insertions(+), 21 deletions(-)
diff --git a/ChangeLog b/ChangeLog
index 4e4127d..79100bc 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,5 +1,14 @@
2008-10-17 Eric Blake <address@hidden>
+ Add m4_curry.
+ * lib/m4sugar/m4sugar.m4 (m4_curry, _m4_curry): New macros.
+ * tests/m4sugar.at (m4@&address@hidden): Rename...
+ (m4@&address@hidden and m4@&address@hidden): ...and add currying tests.
+ * doc/autoconf.texi (Looping constructs) <m4_map_args>: Document
+ currying as a way to add parameters.
+ (Evaluation Macros) <m4_curry>: Document the new macro.
+ * NEWS: Likewise.
+
Improve suggested test filtering.
* lib/m4sugar/m4sh.m4 (_AS_DETECT_SUGGESTED_PRUNE): New macro,
extracted from...
diff --git a/NEWS b/NEWS
index 1ba23cc..147639b 100644
--- a/NEWS
+++ b/NEWS
@@ -13,7 +13,8 @@ GNU Autoconf NEWS - User visible changes.
** Configure scripts now use shell functions.
** The following m4sugar macros are new:
- m4_default_quoted m4_map_args m4_map_args_pair m4_set_map
+ m4_curry m4_default_quoted m4_map_args m4_map_args_pair
+ m4_set_map
** The following documented m4sh macros are new:
AS_LINENO_PREPARE AS_ME_PREPARE AS_VAR_COPY
diff --git a/doc/autoconf.texi b/doc/autoconf.texi
index d539329..3078869 100644
--- a/doc/autoconf.texi
+++ b/doc/autoconf.texi
@@ -10930,7 +10930,7 @@ Looping constructs
@defmac m4_map_args (@var{macro}, @address@hidden)
@msindex{map_args}
-Repeatedly invoke @var{macro} with each successive @var{arg} as its
+Repeatedly invoke @var{macro} with each successive @var{arg} as its only
argument. In the following example, three solutions are presented with
the same expansion; the solution using @code{m4_map_args} is the most
efficient.
@@ -10943,6 +10943,30 @@ Looping constructs
m4_map_args([ m4_echo], [plain], [active])
@result{} plain active
@end example
+
+In cases where it is useful to operate on additional parameters besides
+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}.
+
address@hidden
+m4_define([list], [[1], [2], [3]])dnl
+m4_define([add], [m4_eval(([$1]) + ([$2]))])dnl
+dnl list_add_n(N, ARG...)
+dnl Output a list consisting of each ARG added to N
+m4_define([list_add_n],
+[m4_shift(m4_map_args([,m4_curry([add], [$1])], m4_shift($@@)))])dnl
+list_add_n([1], list)
address@hidden,3,4
+list_add_n([2], list)
address@hidden,4,5
+m4_define([list_add_x],
+[m4_shift(m4_foreach([var], m4_dquote(m4_shift($@@)),
+ [,add([$1],m4_defn([var]))]))])dnl
+list_add_x([1], list)
address@hidden,3,4
address@hidden example
@end defmac
@defmac m4_map_args_pair (@var{macro}, @dvar{macro-end, macro}, @
@@ -11010,6 +11034,19 @@ Evaluation Macros
passed.
@end defmac
address@hidden m4_curry (@var{macro}, @address@hidden)
address@hidden
+This macro performs argument currying. The expansion of this macro is
+another macro name that expects exactly one argument; that argument is
+then appended to the @var{arg} list, and then @var{macro} is expanded
+with the resulting argument list.
+
address@hidden
+m4_curry([m4_curry], [m4_reverse], [1])([2])([3])
address@hidden, 2, 1
address@hidden example
address@hidden defmac
+
@defmac m4_do (@var{arg}, @dots{})
@msindex{do}
This macro loops over its arguments and expands each @var{arg} in
diff --git a/lib/m4sugar/m4sugar.m4 b/lib/m4sugar/m4sugar.m4
index 2d50230..ee8ee63 100644
--- a/lib/m4sugar/m4sugar.m4
+++ b/lib/m4sugar/m4sugar.m4
@@ -726,6 +726,20 @@ m4_define([_m4_apply],
m4_define([m4_count], [$#])
+# m4_curry(MACRO, ARG...)
+# -----------------------
+# Perform argument currying. The expansion of this macro is another
+# macro that takes exactly one argument, appends it to the end of the
+# original ARG list, then invokes MACRO. For example:
+# m4_curry([m4_curry], [m4_reverse], [1])([2])([3]) => 3, 2, 1
+# Not quite as practical as m4_incr, but you could also do:
+# m4_define([add], [m4_eval(([$1]) + ([$2]))])
+# m4_define([add_one], [m4_curry([add], [1])])
+# add_one()([2]) => 3
+m4_define([m4_curry], [$1(m4_shift($@,)_$0])
+m4_define([_m4_curry], [[$1])])
+
+
# m4_do(STRING, ...)
# ------------------
# This macro invokes all its arguments (in sequence, of course). It is
diff --git a/tests/m4sugar.at b/tests/m4sugar.at
index d6f40a7..f34bca3 100644
--- a/tests/m4sugar.at
+++ b/tests/m4sugar.at
@@ -37,21 +37,6 @@ AT_CHECK_M4SUGAR([-o-],, [$2], [$3])
])# AT_CHECK_M4SUGAR_TEXT
-# Order of the tests:
-# - m4_warn
-#
-# - m4_require
-# uses warn/error code.
-#
-# - m4_split
-#
-# - m4_append
-#
-# - m4_join
-#
-# - m4_text_wrap
-# uses m4_split code.
-
## --------- ##
## m4_defn. ##
## --------- ##
@@ -866,13 +851,27 @@ hi
AT_CLEANUP
-## --------------------- ##
-## m4_map_args{,_pair}. ##
-## --------------------- ##
+## ---------------------------------- ##
+## m4_map_args{,_pair} and m4_curry. ##
+## ---------------------------------- ##
-AT_SETUP([m4@&address@hidden)
+AT_SETUP([m4@&address@hidden and m4@&address@hidden)
AT_KEYWORDS([m4@&address@hidden m4@&address@hidden)
+dnl First, make sure we can curry in isolation.
+AT_CHECK_M4SUGAR_TEXT(
+[[m4_curry([m4_echo])([1])
+m4_curry([m4_curry], [m4_reverse], [1])([2])([3])
+m4_define([add], [m4_eval(([$1]) + ([$2]))])dnl
+m4_define([add_one], [m4_curry([add], [1])])dnl
+add_one()([4])
+]],
+[[1
+3, 2, 1
+5
+]])
+
+dnl Now, check that we can map a list of arguments.
AT_CHECK_M4SUGAR_TEXT([[m4_define([active], [ACTIVE])dnl
m4_map_args([ m4_echo])
m4_map_args([ m4_echo], [plain], [active])
@@ -901,6 +900,21 @@ plainACTIVE
, 2, 1, 4, 3
]])
+dnl Finally, put the two concepts together, to show the real power of the API.
+AT_CHECK_M4SUGAR_TEXT(
+[[m4_define([add], [m4_eval(([$1]) + ([$2]))])dnl
+m4_define([list], [[-1], [0], [1]])dnl
+dnl list_add_n(value, arg...)
+dnl add VALUE to each ARG and output the resulting list
+m4_define([list_add_n],
+ [m4_shift(m4_map_args([,m4_curry([add], [$1])], m4_shift($@)))])
+list_add_n([1], list)
+list_add_n([2], list)
+]], [[
+0,1,2
+1,2,3
+]])
+
AT_CLEANUP
--
1.6.0.2