autoconf-patches
[Top][All Lists]
Advanced

[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


reply via email to

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