another regression test

Eric Blake <[email protected]>
Newsgroups gmane.comp.gnu.m4.patches
Message-ID <[email protected]>
-----BEGIN PGP SIGNED MESSAGE-----
Hash: SHA1

While working on porting stage 16 to head, I noticed that I wasn't really
exercising recursive code with multi-character quoting.  Ultimately, the
speedup for linear speed on recursion only applies to single-character
quoting (because with multi-character quoting, the parser can't bypass
checking arguments, in case characters are concatenated together to form a
quote delimiter), but I at least wanted to ensure it doesn't break with
all the optimizations being added for single-character quotes.  And in the
process of adding that test, I had a hard time using the
examples/forloop2.m4 file as is once I translated it to use different
quoting, so I adjusted the example and added some documentation why.  This
patch applies to both the branch and head.

- --
Don't work too hard, make some time for fun as well!

Eric Blake             [email protected]
-----BEGIN PGP SIGNATURE-----
Version: GnuPG v1.4.5 (Cygwin)
Comment: Public key at home.comcast.net/~ericblake/eblake.gpg
Comment: Using GnuPG with Mozilla - http://enigmail.mozdev.org

iD8DBQFHt2Nt84KuGfSFAYARAsYPAKDAzuba1VfMq9gwyIB3Yllft0A+mQCeLagz
rkGq4h8kfnJ79IPgS9Mu3DA=
=NKMJ
-----END PGP SIGNATURE-----

_______________________________________________
M4-patches mailing list
[email protected]
http://lists.gnu.org/mailman/listinfo/m4-patches
m4.patch319 (text/plain, 7.7 KB)
From 702a3fe3e8a61c0d4c6da09221559deeff43fabb Mon Sep 17 00:00:00 2001
From: Eric Blake <[email protected]>
Date: Sat, 16 Feb 2008 14:39:41 -0700
Subject: [PATCH] Add regression test for multi-character quote recursion.

* examples/foreach2.m4: Use $0 rather than spelling out name.
* examples/foreachq2.m4: Likewise.
* examples/forloop2.m4: Likewise.
* examples/hanoi.m4: Likewise.
* examples/trace.m4: Likewise.
* doc/m4.texinfo (Improved forloop): Document advantage of $0.
(Improved foreach): Adjust dump from file.

Signed-off-by: Eric Blake <[email protected]>
---
 ChangeLog             |    9 +++++++++
 doc/m4.texinfo        |   48 +++++++++++++++++++++++++++++++++++++++++++++---
 examples/foreach2.m4  |    2 +-
 examples/foreachq2.m4 |    2 +-
 examples/forloop2.m4  |    2 +-
 examples/hanoi.m4     |    4 ++--
 examples/trace.m4     |    4 ++--
 7 files changed, 61 insertions(+), 10 deletions(-)

diff --git a/ChangeLog b/ChangeLog
index 0baa3c1..76fcac3 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,5 +1,14 @@
 2008-02-16  Eric Blake  <[email protected]>
 
+	Add regression test for multi-character quote recursion.
+	* examples/foreach2.m4: Use $0 rather than spelling out name.
+	* examples/foreachq2.m4: Likewise.
+	* examples/forloop2.m4: Likewise.
+	* examples/hanoi.m4: Likewise.
+	* examples/trace.m4: Likewise.
+	* doc/m4.texinfo (Improved forloop): Document advantage of $0.
+	(Improved foreach): Adjust dump from file.
+
 	Stage 15: return argv refs back to collect_arguments.
 	Collect an entire $@ reference at once rather than one argument at
 	a time, outside of quotes (but inside quotes, $@ is still
diff --git a/doc/m4.texinfo b/doc/m4.texinfo
index 32cb0a9..6172277 100644
--- a/doc/m4.texinfo
+++ b/doc/m4.texinfo
@@ -6987,7 +6987,7 @@ undivert(`forloop2.m4')dnl
 @result{}#   performs sanity check that FROM is larger than TO
 @result{}#   allows complex numerical expressions in TO and FROM
 @result{}define(`forloop', `ifelse(eval(`($3) >= ($2)'), `1',
-@result{}  `pushdef(`$1', eval(`$2'))_forloop(`$1',
+@result{}  `pushdef(`$1', eval(`$2'))_$0(`$1',
 @result{}    eval(`$3'), `$4')popdef(`$1')')')
 @result{}define(`_forloop',
 @result{}  `$3`'ifelse(indir(`$1'), `$2', `',
@@ -7006,6 +7006,48 @@ forloop(`i', `a', `b', `non-numeric bounds')
 @result{}
 @end example
 
+One other change to notice is that the improved version used @samp{_$0}
+rather than @samp{_foreach} to invoke the helper routine.  In general,
+this is a good practice to follow, because then the set of macros can be
+uniformly transformed.  The following example shows a transformation
+that doubles the current quoting and appends a suffix @samp{2} to each
+transformed macro.  If @code{foreach} refers to the literal
+@samp{_foreach}, then @code{foreach2} invokes @code{_foreach} instead of
+the intended @code{_foreach2}, and the mixing of quoting paradigms leads
+to an infinite recursion loop in this example.
+
+@comment options: -L9
+@comment status: 1
+@comment examples
+@example
+$ @kbd{m4 -d -L 9 -I examples}
+define(`arg1', `$1')include(`forloop2.m4')include(`quote.m4')
+@result{}
+define(`double', `define(`$1'`2',
+  arg1(patsubst(dquote(defn(`$1')), `[`']', `\&\&')))')
+@result{}
+double(`forloop')double(`_forloop')defn(`forloop2')
+@result{}ifelse(eval(``($3) >= ($2)''), ``1'',
+@result{}  ``pushdef(``$1'', eval(``$2''))_$0(``$1'',
+@result{}    eval(``$3''), ``$4'')popdef(``$1'')'')
+forloop(i, 1, 5, `ifelse(')forloop(i, 1, 5, `)')
+@result{}
+changequote(`[', `]')changequote([``], [''])
+@result{}
+forloop2(i, 1, 5, ``ifelse('')forloop2(i, 1, 5, ``)'')
+@result{}
+changequote`'include(`forloop.m4')
+@result{}
+double(`forloop')double(`_forloop')defn(`forloop2')
+@result{}pushdef(``$1'', ``$2'')_forloop($@@)popdef(``$1'')
+forloop(i, 1, 5, `ifelse(')forloop(i, 1, 5, `)')
+@result{}
+changequote(`[', `]')changequote([``], [''])
+@result{}
+forloop2(i, 1, 5, ``ifelse('')forloop2(i, 1, 5, ``)'')
+@error{}m4:stdin:12: recursion limit of 9 exceeded, use -L<N> to change it
+@end example
+
 Of course, it is possible to make even more improvements, such as
 adding an optional step argument, or allowing iteration through
 descending sequences.  @acronym{GNU} Autoconf provides some of these
@@ -7068,7 +7110,7 @@ undivert(`foreachq2.m4')dnl
 @result{}divert(`-1')
 @result{}# foreachq(x, `item_1, item_2, ..., item_n', stmt)
 @result{}#   quoted list, improved version
-@result{}define(`foreachq', `pushdef(`$1')_foreachq($@@)popdef(`$1')')
+@result{}define(`foreachq', `pushdef(`$1')_$0($@@)popdef(`$1')')
 @result{}define(`_arg1q', ``$1'')
 @result{}define(`_rest', `ifelse(`$#', `1', `', `dquote(shift($@@))')')
 @result{}define(`_foreachq', `ifelse(`$2', `', `',
@@ -7163,7 +7205,7 @@ undivert(`foreach2.m4')dnl
 @result{}divert(`-1')
 @result{}# foreach(x, (item_1, item_2, ..., item_n), stmt)
 @result{}#   parenthesized list, improved version
-@result{}define(`foreach', `pushdef(`$1')_foreach(`$1',
+@result{}define(`foreach', `pushdef(`$1')_$0(`$1',
 @result{}  (dquote(dquote_elt$2)), `$3')popdef(`$1')')
 @result{}define(`_arg1', `$1')
 @result{}define(`_foreach', `ifelse(`$2', `(`')', `',
diff --git a/examples/foreach2.m4 b/examples/foreach2.m4
index 4acf0c2..74d00fb 100644
--- a/examples/foreach2.m4
+++ b/examples/foreach2.m4
@@ -2,7 +2,7 @@ include(`quote.m4')dnl
 divert(`-1')
 # foreach(x, (item_1, item_2, ..., item_n), stmt)
 #   parenthesized list, improved version
-define(`foreach', `pushdef(`$1')_foreach(`$1',
+define(`foreach', `pushdef(`$1')_$0(`$1',
   (dquote(dquote_elt$2)), `$3')popdef(`$1')')
 define(`_arg1', `$1')
 define(`_foreach', `ifelse(`$2', `(`')', `',
diff --git a/examples/foreachq2.m4 b/examples/foreachq2.m4
index 345ddfe..f57d3ed 100644
--- a/examples/foreachq2.m4
+++ b/examples/foreachq2.m4
@@ -2,7 +2,7 @@ include(`quote.m4')dnl
 divert(`-1')
 # foreachq(x, `item_1, item_2, ..., item_n', stmt)
 #   quoted list, improved version
-define(`foreachq', `pushdef(`$1')_foreachq($@)popdef(`$1')')
+define(`foreachq', `pushdef(`$1')_$0($@)popdef(`$1')')
 define(`_arg1q', ``$1'')
 define(`_rest', `ifelse(`$#', `1', `', `dquote(shift($@))')')
 define(`_foreachq', `ifelse(`$2', `', `',
diff --git a/examples/forloop2.m4 b/examples/forloop2.m4
index f1bdf0e..41e0e16 100644
--- a/examples/forloop2.m4
+++ b/examples/forloop2.m4
@@ -4,7 +4,7 @@ divert(`-1')
 #   performs sanity check that FROM is larger than TO
 #   allows complex numerical expressions in TO and FROM
 define(`forloop', `ifelse(eval(`($3) >= ($2)'), `1',
-  `pushdef(`$1', eval(`$2'))_forloop(`$1',
+  `pushdef(`$1', eval(`$2'))_$0(`$1',
     eval(`$3'), `$4')popdef(`$1')')')
 define(`_forloop',
   `$3`'ifelse(indir(`$1'), `$2', `',
diff --git a/examples/hanoi.m4 b/examples/hanoi.m4
index c4a80fc..d290866 100644
--- a/examples/hanoi.m4
+++ b/examples/hanoi.m4
@@ -6,10 +6,10 @@ define(`move', `Move one disk from `$1' to `$2'.
 
 # _hanoi (cnt, from, to, aux)
 define(`_hanoi', `ifelse(eval(`$1'<=1), 1, `move($2, $3)',
-`_hanoi(decr($1), $2, $4, $3)move($2, $3)_hanoi(decr($1), $4, $3, $2)')')
+`$0(decr($1), $2, $4, $3)move($2, $3)$0(decr($1), $4, $3, $2)')')
 
 # hanoi (cnt)
-define(`hanoi', `_hanoi(`$1', source, destination, auxilliary)')
+define(`hanoi', `_$0(`$1', source, destination, auxilliary)')
 
 # traceon(`move', `_hanoi', `decr')
 divert`'dnl
diff --git a/examples/trace.m4 b/examples/trace.m4
index a79dbcd..92ce981 100644
--- a/examples/trace.m4
+++ b/examples/trace.m4
@@ -6,10 +6,10 @@ define(`move', `Move one disk from `$1' to `$2'.
 
 # _hanoi (cnt, from, to, aux)
 define(`_hanoi', `ifelse(eval(`$1'<=1), 1, `move($2, $3)',
-`_hanoi(decr($1), $2, $4, $3)move($2, $3)_hanoi(decr($1), $4, $3, $2)')')
+`$0(decr($1), $2, $4, $3)move($2, $3)$0(decr($1), $4, $3, $2)')')
 
 # hanoi (cnt)
-define(`hanoi', `_hanoi(`$1', source, destination, auxilliary)')
+define(`hanoi', `_$0(`$1', source, destination, auxilliary)')
 divert`'dnl
 
 # Debugmode t
-- 
1.5.4
lmpx.com only provides a reader for public news (NNTP) servers. It is not affiliated with the servers or forums shown here and is not responsible for the content of articles, which is written by their respective authors.