autoconf-patches
[Top][All Lists]
Advanced

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

Re: document m4_foreach*/AC_FOREACH


From: Ralf Wildenhues
Subject: Re: document m4_foreach*/AC_FOREACH
Date: Fri, 17 Feb 2006 18:02:15 +0100
User-agent: Mutt/1.5.11

Hi Eric,

* Eric Blake wrote on Thu, Feb 16, 2006 at 10:08:12PM CET:
> According to Ralf Wildenhues on 2/16/2006 1:58 PM:
> >>m4_for([myvar], 1, 1, 0, [ myvar])
> > 
> > Yes, good idea.  Below is an additional patchlet for the first and third
> > case.  The second isn't m4_assert'ed at the moment: the body is expanded
> > once, with myvar set to 1.

> Either way, the
> testsuite needs to explicitly test the chosen behavior, so that we cannot
> accidentally regress in the future (even though we never anticipate a user
> coding up m4_for([myval], 1, 1, 0, [ myval]), we can't be too careful).

Good idea.

Below is an updated patch, which combines the previous version and
tests all three of your cases, and also makes sure that it works
with arguments that themselves are arithmetic expressions (as opposed
to plain integers).  I also changed it so that it does not incur
integer overflow any more.

Who would've thought a simple for-loop was so involved?  Guess for
each simple programming concept there is a language in which it is
difficult to realize.  ;-)

OK to apply?

Side note: m4_cmp and m4_sign need similar fixes, if they are to be
used more widely.

Cheers,
Ralf

        * doc/autoconf.texi (Looping constructs): New node, to
        document m4_for, m4_foreach, m4_foreach_w, and mention
        obsolete AC_FOREACH.
        (Obsolete Macros): Document AC_FOREACH.
        * lib/m4sugar/m4sugar.m4 (_m4_for): Fix declaration comment.
        (m4_for): Fix to never loop (almost) endlessly, work correctly
        with arithmetic expressions in arguments, a step of zero or
        non-integer multiple of the interval, and avoid integer
        overflow.
        * tests/m4sugar.at: New test for m4_for, m4_foreach, and
        m4_foreach_w.

Index: doc/autoconf.texi
===================================================================
RCS file: /cvsroot/autoconf/autoconf/doc/autoconf.texi,v
retrieving revision 1.949
diff -u -r1.949 autoconf.texi
--- doc/autoconf.texi   15 Feb 2006 07:00:29 -0000      1.949
+++ doc/autoconf.texi   17 Feb 2006 16:42:17 -0000
@@ -437,6 +437,7 @@
 Programming in M4sugar
 
 * Redefined M4 Macros::         M4 builtins changed in M4sugar
+* Looping constructs::          Iteration in M4
 * Evaluation Macros::           More quotation and evaluation control
 * Forbidden Patterns::          Catching unexpanded macros
 
@@ -8781,6 +8782,7 @@
 
 @menu
 * Redefined M4 Macros::         M4 builtins changed in M4sugar
+* Looping constructs::          Iteration in M4
 * Evaluation Macros::           More quotation and evaluation control
 * Forbidden Patterns::          Catching unexpanded macros
 @end menu
@@ -8897,6 +8899,48 @@
 to recover the behavior of the builtin.
 @end defmac
 
+
+
address@hidden Looping constructs
address@hidden Looping constructs
+
+The following macros implement loops in M4.
+
address@hidden m4_for (@var{var}, @var{first}, @var{last}, @ovar{step}, 
@var{expression})
address@hidden
+Loop over the numeric values between @var{first} and @var{last}
+including bounds by increments of @var{step}.  For each iteration,
+expand @var{expression} with the numeric value assigned to @var{var}.
+If @var{step} is omitted, it defaults to @samp{1} or @samp{-1} depending
+on the order of the limits.  If given, @var{step} has to match this
+order.
address@hidden defmac
+
address@hidden m4_foreach (@var{var}, @var{list}, @var{expression})
address@hidden
+Loop over the comma-separated m4 list @var{list}, assigning each value
+to @var{var}, and expand @var{expression}.  The following example will
+output two lines:
+
address@hidden
+m4_foreach([myvar], [[foo], [bar, baz]],
+           [echo myvar
+])
+
address@hidden example
address@hidden defmac
+
address@hidden m4_foreach_w (@var{var}, @var{list}, @var{expression})
address@hidden
+Loop over the whitespace-separated list @var{list}, assigning each value
+to @var{var}, and expand @var{expression}.
+
+The deprecated macro @code{AC_FOREACH} is an alias of
address@hidden
address@hidden defmac
+
+
+
 @node Evaluation Macros
 @subsection Evaluation Macros
 
@@ -14735,6 +14779,11 @@
 @code{AC_PATH_XTRA}
 @end defmac
 
address@hidden AC_FOREACH
address@hidden
address@hidden
address@hidden defmac
+
 @defmac AC_FUNC_CHECK
 @acindex{FUNC_CHECK}
 @code{AC_CHECK_FUNC}
@@ -15955,7 +16004,7 @@
 this scheme helps supporting more languages than plain C and C++.
 @end itemize
 
-In addition to the change of syntax, the philosphy has changed too:
+In addition to the change of syntax, the philosophy has changed too:
 while emphasis was put on speed at the expense of accuracy, today's
 Autoconf promotes accuracy of the testing framework at, address@hidden, the
 expense of speed.
Index: lib/m4sugar/m4sugar.m4
===================================================================
RCS file: /cvsroot/autoconf/autoconf/lib/m4sugar/m4sugar.m4,v
retrieving revision 2.96
diff -u -r2.96 m4sugar.m4
--- lib/m4sugar/m4sugar.m4      11 Jan 2006 08:05:55 -0000      2.96
+++ lib/m4sugar/m4sugar.m4      17 Feb 2006 16:42:17 -0000
@@ -571,19 +571,24 @@
 # Expand EXPRESSION defining VARIABLE to FROM, FROM + 1, ..., TO.
 # Both limits are included, and bounds are checked for consistency.
 m4_define([m4_for],
-[m4_case(m4_sign(m4_eval($3 - $2)),
-        1, [m4_assert(m4_sign(m4_default($4, 1)) == 1)],
-       -1, [m4_assert(m4_sign(m4_default($4, -1)) == -1)])dnl
-m4_pushdef([$1], [$2])dnl
-m4_if(m4_eval([$3 > $2]), 1,
-      [_m4_for([$1], [$3], m4_default([$4], 1), [$5])],
-      [_m4_for([$1], [$3], m4_default([$4], -1), [$5])])dnl
+[m4_pushdef([$1], m4_eval([$2]))dnl
+m4_if(m4_eval(([$3]) > $1), 1,
+[m4_pushdef([_m4_step], m4_eval(m4_default([$4], 1)))dnl
+m4_assert(_m4_step > 0)dnl
+_m4_for([$1], m4_eval((([$3]) - $1) / _m4_step * _m4_step + $1), _m4_step, 
[$5])],
+      m4_eval(([$3]) < $1), 1,
+[m4_pushdef([_m4_step], m4_eval(m4_default([$4], -1)))dnl
+m4_assert(_m4_step < 0)dnl
+_m4_for([$1], m4_eval(($1 - ([$3])) / -(_m4_step) * _m4_step + $1), _m4_step, 
[$5])],
+      [m4_pushdef(_m4_step,[])dnl
+$5])[]dnl
+m4_popdef([_m4_step])dnl
 m4_popdef([$1])])
 
 
-# _m4_for(VARIABLE, FIRST, LAST, STEP, EXPRESSION)
-# ------------------------------------------------
-# Core of the loop, no consistency checks.
+# _m4_for(VARIABLE, LAST, STEP, EXPRESSION)
+# -----------------------------------------
+# Core of the loop, no consistency checks, all arguments are plain numbers.
 m4_define([_m4_for],
 [$4[]dnl
 m4_if($1, [$2], [],
Index: tests/m4sugar.at
===================================================================
RCS file: /cvsroot/autoconf/autoconf/tests/m4sugar.at,v
retrieving revision 1.28
diff -u -r1.28 m4sugar.at
--- tests/m4sugar.at    14 May 2005 07:00:40 -0000      1.28
+++ tests/m4sugar.at    17 Feb 2006 16:42:17 -0000
@@ -2,7 +2,7 @@
 
 AT_BANNER([M4sugar.])
 
-# Copyright (C) 2000, 2001, 2002, 2005 Free Software Foundation, Inc.
+# Copyright (C) 2000, 2001, 2002, 2005, 2006 Free Software Foundation, Inc.
 #
 # This program is free software; you can redistribute it and/or modify
 # it under the terms of the GNU General Public License as published by
@@ -20,8 +20,8 @@
 # 02110-1301, USA.
 
 
-# AT_CHECK_M4SUGAR_TEXT(CODE, STDOUT, STDER)
-# ------------------------------------------
+# AT_CHECK_M4SUGAR_TEXT(CODE, STDOUT, STDERR)
+# -------------------------------------------
 # Check that m4sugar CODE expands to STDOUT and emits STDERR.
 m4_define([AT_CHECK_M4SUGAR_TEXT],
 [
@@ -204,3 +204,117 @@
 AT_CHECK_M4RE([m4_re_string], address@hidden)
 
 AT_CLEANUP
+
+## ---------- ##
+## M4 Loops.  ##
+## ---------- ##
+
+AT_SETUP([M4 loops])
+
+AT_CHECK_M4SUGAR_TEXT([[dnl
+m4_define([myvar], [outer value])dnl
+m4_for([myvar], 1, 3, 1, [ myvar])
+m4_for([myvar], 1, 3,  , [ myvar])
+m4_for([myvar], 3, 1,-1, [ myvar])
+m4_for([myvar], 3, 1,  , [ myvar])
+m4_for([myvar], 1, 3, 2, [ myvar])
+m4_for([myvar], 3, 1,-2, [ myvar])
+m4_for([myvar],-1,-3,-2, [ myvar])
+m4_for([myvar],-3,-1, 2, [ myvar])
+dnl Make sure we recalculate the bounds correctly:
+m4_for([myvar], 1, 3, 3, [ myvar])
+m4_for([myvar], 1, 6, 3, [ myvar])
+m4_for([myvar],22,-7,-5, [ myvar])
+m4_for([myvar],-2,-7,-4, [ myvar])
+m4_for([myvar],-7,-2, 4, [ myvar])
+dnl Make sure we are not exposed to division truncation:
+m4_for([myvar], 2, 5, 2, [ myvar])
+m4_for([myvar],-5,-2, 2, [ myvar])
+m4_for([myvar], 5, 2,-2, [ myvar])
+m4_for([myvar],-2,-5,-2, [ myvar])
+dnl Make sure we do not divide by zero:
+m4_for([myvar], 1, 1,  , [ myvar])
+m4_for([myvar], 1, 1,+2, [ myvar])
+m4_for([myvar], 1, 1,-2, [ myvar])
+dnl Make sure we do not loop endlessly
+m4_for([myval], 1, 1, 0, [ myval])
+dnl Make sure to properly parenthesize
+m4_for([myvar], 3-5, -2+8, , [ myvar])
+m4_for([myvar], -2+8, 3-5, , [ myvar])
+m4_for([myvar], 8, 16, 3 * 2, [ myvar])
+m4_for([myvar], 8, 16, -3 * -2, [ myvar])
+m4_for([myvar], [2<<2], [2<<3], [-3 * (-2)], [ myvar])
+m4_foreach([myvar], [[a], [b, c], [d], [e
+],[f]], [ myvar|])
+m4_foreach_w([myvar], [a  b c, d,e f
+g], [ myvar|])
+myvar
+]],
+[[ 1 2 3
+ 1 2 3
+ 3 2 1
+ 3 2 1
+ 1 3
+ 3 1
+ -1 -3
+ -3 -1
+ 1
+ 1 4
+ 22 17 12 7 2 -3
+ -2 -6
+ -7 -3
+ 2 4
+ -5 -3
+ 5 3
+ -2 -4
+ 1
+ 1
+ 1
+ 1
+ -2 -1 0 1 2 3 4 5 6
+ 6 5 4 3 2 1 0 -1 -2
+ 8 14
+ 8 14
+ 8 14
+ a| b, c| d| e
+| f|
+ a| b| c,| d,e| f| g|
+outer value
+]], [])
+
+AT_DATA_M4SUGAR([script.4s],
+[[m4_init
+m4_divert_push([0])m4_wrap([m4_divert_pop([0])[]])dnl
+m4_for([myvar], 1, 3,-1, [ myvar])
+]])
+
+AT_CHECK_M4SUGAR([], 1, [],
+[[script.4s:3: error: assert failed: -1 > 0
+script.4s:3: the top level
+autom4te: m4 failed with exit status: 1
+]])
+
+AT_DATA_M4SUGAR([script.4s],
+[[m4_init
+m4_divert_push([0])m4_wrap([m4_divert_pop([0])[]])dnl
+m4_for([myvar], 1, 2, 0, [ myvar])
+]])
+
+AT_CHECK_M4SUGAR([], 1, [],
+[[script.4s:3: error: assert failed: 0 > 0
+script.4s:3: the top level
+autom4te: m4 failed with exit status: 1
+]])
+
+AT_DATA_M4SUGAR([script.4s],
+[[m4_init
+m4_divert_push([0])m4_wrap([m4_divert_pop([0])[]])dnl
+m4_for([myvar], 2, 1, 0, [ myvar])
+]])
+
+AT_CHECK_M4SUGAR([], 1, [],
+[[script.4s:3: error: assert failed: 0 < 0
+script.4s:3: the top level
+autom4te: m4 failed with exit status: 1
+]])
+AT_CLEANUP




reply via email to

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