autoconf/tests/m4sugar.at
Eric Blake c6b172ee19 Add m4_curry.
* lib/m4sugar/m4sugar.m4 (m4_curry, _m4_curry): New macros.
* tests/m4sugar.at (m4@&t@_map_args): Rename...
(m4@&t@_map_args and m4@&t@_curry): ...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 <ebb9@byu.net>
2008-10-17 16:32:27 -06:00

1292 lines
27 KiB
Plaintext

# -*- Autotest -*-
AT_BANNER([M4sugar.])
# Copyright (C) 2000, 2001, 2002, 2005, 2006, 2007, 2008 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
# the Free Software Foundation; either version 2, or (at your option)
# any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
# 02110-1301, USA.
# AT_CHECK_M4SUGAR_TEXT(CODE, STDOUT, STDERR)
# -------------------------------------------
# Check that m4sugar CODE expands to STDOUT and emits STDERR.
m4_define([AT_CHECK_M4SUGAR_TEXT],
[
AT_DATA_M4SUGAR([script.4s],
[[m4_init
m4_divert_push(0)[]dnl
]$1[[]dnl
m4_divert_pop(0)
]])
AT_CHECK_M4SUGAR([-o-],, [$2], [$3])
])# AT_CHECK_M4SUGAR_TEXT
## --------- ##
## m4_defn. ##
## --------- ##
AT_SETUP([m4@&t@_defn])
AT_KEYWORDS([m4@&t@_popdef m4@&t@_undefine])
# Ensure that m4sugar dies when dereferencing undefined macros, whether
# this is provided by m4 natively or faked by wrappers in m4sugar.
AT_DATA_M4SUGAR([script.4s],
[[m4_define([good])
m4_defn([good], [oops])
]])
AT_CHECK_M4SUGAR([-o-], 1, [], [stderr])
AT_CHECK([grep good stderr], [1])
AT_CHECK([grep 'm4@&t@_defn: undefined.*oops' stderr], [0], [ignore])
AT_DATA_M4SUGAR([script.4s],
[[m4_define([good])
m4_popdef([good], [oops])
]])
AT_CHECK_M4SUGAR([-o-], 1, [], [stderr])
AT_CHECK([grep good stderr], [1])
AT_CHECK([grep 'm4@&t@_popdef: undefined.*oops' stderr], [0], [ignore])
AT_DATA_M4SUGAR([script.4s],
[[m4_define([good])
m4_undefine([good], [oops])
]])
AT_CHECK_M4SUGAR([-o-], 1, [], [stderr])
AT_CHECK([grep good stderr], [1])
AT_CHECK([grep 'm4@&t@_undefine: undefined.*oops' stderr], [0], [ignore])
AT_CLEANUP
## --------- ##
## m4_warn. ##
## --------- ##
AT_SETUP([m4@&t@_warn])
# m4_text_wrap is used to display the help strings. Also, check that
# commas are not swallowed. This can easily happen because of
# m4-listification.
# FIXME: For the time being we use -f to make sure we do issue the
# warnings. But maybe autom4te should handle that by itself?
AT_DATA_M4SUGAR([script.4s],
[[m4_init
m4_defun([cross_warning], [m4_warn([cross], [cross])])
m4_divert([0])dnl
m4_warn([obsolete], [obsolete])dnl
cross_warning[]dnl
m4_warn([syntax], [syntax])dnl
]])
AT_CHECK_M4SUGAR([-o-], 0, [],
[script.4s:7: warning: syntax
])
AT_CHECK_M4SUGAR([-o- -Wall -f], 0, [],
[script.4s:5: warning: obsolete
script.4s:6: warning: cross
script.4s:2: cross_warning is expanded from...
script.4s:6: the top level
script.4s:7: warning: syntax
])
AT_CHECK_M4SUGAR([-o- -Wnone,cross -f], 0, [],
[script.4s:6: warning: cross
script.4s:2: cross_warning is expanded from...
script.4s:6: the top level
])
AT_CHECK_M4SUGAR([-o- -Wnone,cross,error -f], 1, [],
[[script.4s:6: warning: cross
script.4s:2: cross_warning is expanded from...
script.4s:6: the top level
]])
AT_CLEANUP
## --------------------------- ##
## m4_require: error message. ##
## --------------------------- ##
AT_SETUP([m4@&t@_require: error message])
AT_DATA_M4SUGAR([script.4s],
[[m4_defun([foo], [FOO])
m4_require([foo])
]])
AT_CHECK_M4SUGAR([], 1, [],
[[script.4s:2: error: m4@&t@_require(foo): cannot be used outside of an m4_defun'd macro
script.4s:2: the top level
autom4te: m4 failed with exit status: 1
]])
AT_CLEANUP
## ----------------------------------- ##
## m4_require: circular dependencies. ##
## ----------------------------------- ##
AT_SETUP([m4@&t@_require: circular dependencies])
AT_DATA_M4SUGAR([script.4s],
[[m4_defun([foo], [m4_require([bar])])
m4_defun([bar], [m4_require([foo])])
m4_defun([baz], [m4_require([foo])])
m4_init
m4_divert([0])dnl
baz
]])
AT_CHECK_M4SUGAR([], 1, [],
[[script.4s:9: error: m4@&t@_require: circular dependency of foo
script.4s:3: bar is expanded from...
script.4s:1: foo is expanded from...
script.4s:5: baz is expanded from...
script.4s:9: the top level
autom4te: m4 failed with exit status: 1
]])
AT_CLEANUP
## --------- ##
## m4_cond. ##
## --------- ##
AT_SETUP([m4@&t@_cond])
AT_CHECK_M4SUGAR_TEXT([[m4_define([side], [m4_errprintn([$1])$1])
m4_cond([side(1)], [1], [a],
[side(1)], [1], [b],
[side(1)], [2], [c])
m4_cond([side(2)], [1], [a],
[side(2)], [1], [b],
[side(2)], [2], [c],
[side(2)])
m4_cond([side(3)], [1], [a],
[side(3)], [1], [b],
[side(3)], [2], [c],
[side(3)])
m4_cond([a,a], [a,a], [yes], [no])
m4_cond([[a,a]], [a,a], [yes])
m4_cond([a,a], [a,b], [yes], [no])
m4_cond([a,a], [a,b], [yes])
m4_cond([m4_eval([0xa])])
m4_define([ab], [AB])dnl
m4_cond([a])b
m4_cond([1], [1], [a])b
m4_cond([1], [2], [3], [a])b
]], [[
a
c
3
yes
yes
no
10
AB
AB
AB
]], [[1
2
2
2
3
3
3
3
]])
AT_CLEANUP
## ---------- ##
## m4_split. ##
## ---------- ##
AT_SETUP([m4@&t@_split])
AT_CHECK_M4SUGAR_TEXT(
[[m4_define([active], [ACT, IVE])m4_define([bd], [oops])
m4_split
m4_split([[]])
m4_split([ ])
m4_split([active])
m4_split([ active active ])end
m4_split([ ], [ ])
m4_split([active], [ ])
m4_split([ active active ], [ ])end
m4_split([abcde], [bd])
m4_split([abcde], [[bd]])
m4_split([foo=`` bar=''])
m4_split([foo='' bar=``])
dnl these next two are from the manual; keep this in sync if the internal
dnl quoting strings in m4_split are changed
m4_define([a], [A])m4_define([b], [B])m4_define([c], [C])dnl
m4_split([a )}>=- b -=<{( c])
m4_split([a )}@&t@>=- b -=<@&t@{( c])
]],
[[
[[]]
[], []
[active]
[], [active], [active], []end
[], []
[active]
[], [active active], []end
[abcde]
[a], [c], [e]
[foo=``], [bar='']
[foo=''], [bar=``]
[a], [], [B], [], [c]
[a], [)}>=-], [b], [-=<{(], [c]
]])
AT_CLEANUP
## ------- ##
## m4_do. ##
## ------- ##
AT_SETUP([m4@&t@_do])
AT_CHECK_M4SUGAR_TEXT(
[[m4_define([ab], [1])m4_define([bc], [2])m4_define([abc], [3])dnl
m4_define([AB], [4])m4_define([BC], [5])m4_define([ABC], [6])dnl
m4_do
m4_do([a])
m4_do([a], [b])c
m4_unquote(m4_join([], [a], [b]))c
m4_define([a], [A])m4_define([b], [B])m4_define([c], [C])dnl
m4_do([a], [b])c
m4_unquote(m4_join([], [a], [b]))c
]],
[[
a
abc
3
ABC
3
]])
AT_CLEANUP
## ----------- ##
## m4_append. ##
## ----------- ##
AT_SETUP([m4@&t@_append])
AT_CHECK_M4SUGAR_TEXT(
[[m4_define([active], [ACTIVE])dnl
m4_append([sentence], [This is an])dnl
m4_append([sentence], [ active ])dnl
m4_append([sentence], [symbol.])dnl
sentence
m4_undefine([active])dnl
sentence
m4_define([active], [ACTIVE])dnl
m4_append([hooks], [m4_define([act1], [act2])])dnl
m4_append([hooks], [m4_define([act2], [active])])dnl
m4_undefine([active])dnl
act1
hooks
act1
dnl Test for bug fixed in 2.62 when separator is active.
m4_define([a], [A])dnl
m4_append_uniq([foo], [-], [a])dnl
m4_append_uniq([foo], [-], [a])dnl
m4_append_uniq([bar], [-], [a])dnl
m4_append_uniq([bar], [~], [a])dnl
m4_append_uniq([bar], [-], [a])dnl
m4_defn([foo])
m4_defn([bar])
foo
bar
m4_append_uniq([blah], [one], [, ], [new], [existing])
m4_append_uniq([blah], [two], [, ], [new], [existing])
m4_append_uniq([blah], [two], [, ], [new], [existing])
m4_append_uniq([blah], [three], [, ], [new], [existing])
m4_append([blah], [two], [, ])dnl
blah
m4_dquote(blah)
m4_append([list], [one], [[, ]])dnl
m4_append([list], [two], [[, ]])dnl
m4_append([list], [three], [[, ]])dnl
list
m4_dquote(list)
m4_append_uniq_w([numbers], [1 1 2])dnl
m4_append_uniq_w([numbers], [ 2 3 ])dnl
numbers
]],
[[This is an ACTIVE symbol.
This is an active symbol.
act1
active
-
-a~
-
-A~
new
new
existing
new
one, two, three, two
[one],[two],[three],[two]
one, two, three
[one, two, three]
1 2 3
]])
AT_DATA_M4SUGAR([script.4s],
[[m4_append_uniq([str], [a], [ ])
m4_append_uniq([str], [a b], [ ])
m4_divert([0])dnl
str
]])
AT_CHECK_M4SUGAR([-o-], 0, [[a a b
]], [[script.4s:2: warning: m4@&t@_append_uniq: `a b' contains ` '
]])
AT_CLEANUP
## --------- ##
## m4_join. ##
## --------- ##
AT_SETUP([m4@&t@_join])
AT_KEYWORDS([m4@&t@_joinall])
AT_CHECK_M4SUGAR_TEXT(
[[m4_define([active], [ACTIVE])
m4_join
m4_join([|])
m4_join([, ], [one], [two])
m4_dquote(m4_join([, ], [one], [two]))
m4_join([|], [active], [active])
m4_join([|], ,,,[one])
m4_join([|], [one],,,)
m4_join([], ,,,[two])
m4_join([], [two],,,)
m4_join([ active ], [one], , [two])
m4_join([], [one], [two])
m4_joinall([-], [one], [], [two])
m4_joinall([-], [], [], [three], [], [])
m4_joinall([], [one], [], [two])
m4_joinall
m4_joinall([-])
m4_joinall([-], [one])
]],
[[
one, two
[one, two]
active|active
one
one
two
two
one active two
onetwo
one--two
--three--
onetwo
one
]])
AT_CLEANUP
## -------------- ##
## m4_text_wrap. ##
## -------------- ##
AT_SETUP([m4@&t@_text_wrap])
# m4_text_wrap is used to display the help strings. Also, check that
# commas and $ are not swallowed. This can easily happen because of
# m4-listification.
AT_DATA_M4SUGAR([script.4s],
[[m4_divert([0])dnl
m4_text_wrap([Short string */], [ ], [/* ], 20)
m4_text_wrap([Much longer string */], [ ], [/* ], 20)
m4_text_wrap([Short doc.], [ ], [ --short ], 30)
m4_text_wrap([Short doc.], [ ], [ --too-wide], 30)
m4_text_wrap([Super long documentation.], [ ], [ --too-wide], 30)
m4_text_wrap([First, second , third, [,quoted]])
m4_define([xfff], [oops])
m4_text_wrap([Some $1 $2 $3 $4 embedded dollars.], [ $* ], [ $@ ], [0xfff & 20])
]])
AT_DATA([expout],
[[/* Short string */
/* Much longer
string */
--short Short doc.
--too-wide
Short doc.
--too-wide
Super long
documentation.
First, second , third, [,quoted]
$@ Some $1 $2 $3
$* $4 embedded
$* dollars.
]])
AT_CHECK_M4SUGAR([-o-], 0, [expout])
AT_CLEANUP
## -------------------- ##
## m4_version_compare. ##
## -------------------- ##
AT_SETUP([m4@&t@_version_compare])
AT_KEYWORDS([m4@&t@_list_cmp])
AT_CHECK_M4SUGAR_TEXT(
[[m4_version_compare([1.1], [2.0])
m4_version_compare([2.0b], [2.0a])
m4_version_compare([2.0z], [2.0y])
m4_version_compare([1.1.1], [1.1.1a])
m4_version_compare([1.2], [1.1.1a])
m4_version_compare([1.0], [1])
m4_version_compare([1.0a], [1.0a])
m4_version_compare([1.1a], [1.1a.1])
m4_version_compare([1.10], [1.1a])
m4_version_compare([1-1a], [1,1A])
m4_define([a], [oops])dnl
m4_version_compare([1.1a], [1.1A])
m4_version_compare([1z], [1aa])
m4_version_compare([2.61a], [2.61a-248-dc51])
m4_version_compare([2.61b], [2.61a-248-dc51])
dnl Test that side effects to m4_list_cmp occur exactly once
m4_list_cmp([[0], [0], [0]m4_errprintn([hi])],
[[0], [0], [0]m4_errprintn([hi])])
m4_list_cmp([[0], [0], [0]m4_errprintn([hi])],
[[0], [0], [0]m4_errprintn([bye])])
]],
[[-1
1
1
-1
1
0
0
-1
1
0
0
-1
-1
1
0
0
]], [[hi
hi
hi
bye
]])
AT_CLEANUP
## ------------------------------ ##
## Standard regular expressions. ##
## ------------------------------ ##
AT_SETUP([Standard regular expressions])
# AT_CHECK_M4RE(RE-NAME, TEXT, INTENT = `ok' | `')
# ------------------------------------------------
# Check whether RE-NAME (a macro whose definition is a regular expression)
# matches TEXT. INTENT = `ok' if the match should succeed or else empty.
m4_define([AT_CHECK_M4RE],
[AT_CHECK_M4SUGAR_TEXT(
[[m4_bregexp([$2], ^m4_defn([$1])$, [ok])
]], [$3
])])
AT_CHECK_M4RE([m4_re_word], [ab9_c], [ok])
AT_CHECK_M4RE([m4_re_word], [_9abc], [ok])
AT_CHECK_M4RE([m4_re_word], [9ab_c])
AT_CHECK_M4RE([m4_re_string], [ab9_c], [ok])
AT_CHECK_M4RE([m4_re_string], [_9abc], [ok])
AT_CHECK_M4RE([m4_re_string], [9ab_c], [ok])
AT_CHECK_M4RE([m4_re_string], [9a@_c])
AT_CLEANUP
## ----------- ##
## m4_bmatch. ##
## ----------- ##
AT_SETUP([m4@&t@_bmatch])
AT_CHECK_M4SUGAR_TEXT(
[[m4_bmatch([abc], [default\])
m4_bmatch([abc], [^a], [yes])
m4_bmatch([abc], [^a], [yes], [no])
m4_bmatch([abc], [^.a], [yes])
m4_bmatch([abc], [^.a], [yes], [no\])
m4_bmatch([abc], [a], [1], [b], [2])
m4_bmatch([abc], [A], [1], [b], [2])
m4_define([ab], [AB])dnl
m4_bmatch([$*], [a])b
m4_bmatch([$*], [\*], [a])b
m4_bmatch([$*], [1], [2], [a])b
]], [[default\
yes
yes
no\
1
2
AB
AB
AB
]])
AT_CLEANUP
## --------------- ##
## m4_bpatsubsts. ##
## --------------- ##
AT_SETUP([m4@&t@_bpatsubsts])
AT_CHECK_M4SUGAR_TEXT(
[[m4_bpatsubsts([11], [^..$])
m4_bpatsubsts([11], [\(.\)1], [\12])
m4_bpatsubsts([11], [^..$], [], [1], [2])
m4_bpatsubsts([11], [\(.\)1], [\12], [1], [3])
m4_define([a], [oops])m4_define([c], [oops])dnl
m4_define([AB], [good])m4_define([bc], [good])dnl
m4_bpatsubsts([abc], [a], [A], [b], [B], [c])
m4_bpatsubsts([ab], [a])c
m4_bpatsubsts([ab], [c], [C], [a])c
m4_bpatsubsts([$1$*$@], [\$\*], [$#])
]], [[11
21
22
23
good
good
good
$1$#$@
]])
AT_CLEANUP
## ---------- ##
## M4 Loops. ##
## ---------- ##
AT_SETUP([M4 loops])
AT_KEYWORDS([m4@&t@_for m4@&t@_foreach m4@&t@_foreach_w])
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])
dnl Modifying var does not affect the number of iterations
m4_for([myvar], 1, 5, , [ myvar[]m4_define([myvar], 5)])
dnl Make sure we can do nameless iteration
m4_for(, 1, 10, , -)
dnl foreach tests
m4_foreach([myvar], [[a], [b, c], [d], [e
],[f]], [ myvar|])
m4_foreach_w([myvar], [a b c, d,e f
g], [ myvar|])
myvar
dnl only one side effect expansion, prior to visiting list elements
m4_foreach([i], [[1], [2], [3]m4_errprintn([hi])], [m4_errprintn(i)])dnl
dnl shifting forms an important part of loops
m4_shift3:m4_shift3(1,2,3):m4_shift3(1,2,3,4)
m4_shiftn(3,1,2,3):m4_shiftn(3,1,2,3,4)
]],
[[ 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
1 2 3 4 5
----------
a| b, c| d| e
| f|
a| b| c,| d,e| f| g|
outer value
::4
:4
]], [[hi
1
2
3
]])
dnl bounds checking in m4_for
AT_DATA_M4SUGAR([script.4s],
[[m4_init
m4_divert([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([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([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
]])
dnl m4_shiftn also does bounds checking
AT_DATA_M4SUGAR([script.4s],
[[m4_init
m4_divert([0])dnl
m4_shiftn(3,1,2)
]])
AT_CHECK_M4SUGAR([], 1, [],
[[script.4s:3: error: assert failed: 0 < 3 && 3 < 3
script.4s:3: the top level
autom4te: m4 failed with exit status: 1
]])
AT_CLEANUP
## --------------------- ##
## m4_map{,all}{,_sep}. ##
## --------------------- ##
AT_SETUP([m4@&t@_map])
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
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
m4_map([a], [[[a]]])1
m4_map([m4_unquote([a])], [m4_dquote([a])])
dnl only one side effect expansion, prior to visiting list elements
m4_map([m4_errprintn], [[[1]], [[2]], [[3]]m4_errprintn([hi])])dnl
m4_map_sep([m4_errprintn], [], [[[1]], [[2]], [[3]]m4_errprintn([hi])])dnl
m4_mapall([m4_errprintn], [[[1]], [[2]], [[3]]m4_errprintn([hi])])dnl
m4_mapall_sep([m4_errprintn], [], [[[1]], [[2]], [[3]]m4_errprintn([hi])])dnl
]],
[[
1 2
0 1 2
3,a
2
3
3,a
1
1
-
-
pass1
pass
]], [[hi
1
2
3
hi
1
2
3
hi
1
2
3
hi
1
2
3
]])
AT_CLEANUP
## ---------------------------------- ##
## m4_map_args{,_pair} and m4_curry. ##
## ---------------------------------- ##
AT_SETUP([m4@&t@_map_args and m4@&t@_curry])
AT_KEYWORDS([m4@&t@_map_args_pair m4@&t@_reverse])
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])
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
]])
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
## ------------ ##
## m4_combine. ##
## ------------ ##
AT_SETUP([m4@&t@_combine])
AT_CHECK_M4SUGAR_TEXT([[m4_define([a], [oops])dnl
m4_combine([, ], [[a], [b], [c]], [-], [1], [2], [3])
m4_combine([, ], [[a], [b]], [-])
m4_combine([, ], [[a], [b]], [-], [])
m4_combine([, ], [], [-], [a], [b])
m4_combine([, ], [[]], [-], [a], [b])
m4_combine([ a ], [[-], [+]], [a], [-], [+])
m4_combine([$* ], [[$1], [$2]], [$#], [$@])
]],
[[a-1, a-2, a-3, b-1, b-2, b-3, c-1, c-2, c-3
a-, b-
-a, -b
-a- a -a+ a +a- a +a+
$1$#$@$* $2$#$@
]], [])
AT_CLEANUP
## -------------- ##
## m4_{max,min}. ##
## -------------- ##
AT_SETUP([m4@&t@_max and m4@&t@_min])
AT_DATA_M4SUGAR([script.4s],
[[m4_max
]])
AT_CHECK_M4SUGAR([], 1, [],
[[script.4s:1: error: too few arguments to m4@&t@_max
script.4s:1: the top level
autom4te: m4 failed with exit status: 1
]])
AT_DATA_M4SUGAR([script.4s],
[[m4_min
]])
AT_CHECK_M4SUGAR([], 1, [],
[[script.4s:1: error: too few arguments to m4@&t@_min
script.4s:1: the top level
autom4te: m4 failed with exit status: 1
]])
AT_CHECK_M4SUGAR_TEXT([[dnl
m4_min(0)
m4_min(0xa)
m4_min(0, 0)
m4_min(0, 1)
m4_min(1, 0)
m4_min(0+1, 1+1)
m4_min(0+1, 1+0)
m4_min(0, 1, 2)
m4_min(2, 1, 0)
m4_min(1m4_for([i], 2, 100, , [,i]))
m4_min(m4_for([i], 100, 2, , [i,])1)
----
m4_max(0)
m4_max(0xa)
m4_max(0, 0)
m4_max(0, 1)
m4_max(1, 0)
m4_max(1+0, 1+1)
m4_max(1+0, 1+0)
m4_max(0, 1, 2)
m4_max(2, 1, 0)
m4_max(1m4_for([i], 2, 100, , [,i]))
m4_max(m4_for([i], 100, 2, , [i,])1)
]],
[[0
10
0
0
0
1
1
0
0
1
1
----
0
10
0
1
1
2
1
2
2
100
100
]], [])
AT_CLEANUP
## ----------- ##
## Recursion. ##
## ----------- ##
AT_SETUP([recursion])
AT_KEYWORDS([m4@&t@_foreach m4@&t@_foreach_w m4@&t@_case m4@&t@_cond
m4@&t@_bpatsubsts m4@&t@_shiftn m4@&t@_do m4@&t@_dquote_elt m4@&t@_reverse
m4@&t@_map m4@&t@_join m4@&t@_joinall m4@&t@_list_cmp m4@&t@_max m4@&t@_min
m4@&t@_bmatch m4@&t@_map_args m4@&t@_map_args_pair])
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,
dnl only the slower foreach.m4 implementation will work. But if we
dnl are testing with m4 1.6, we can rerun the test with __m4_version__
dnl undefined to exercise the alternate code path.
AT_DATA_M4SUGAR([script.4s],
[[m4_init
m4_divert_push(0)[]dnl
m4_len(m4_foreach_w([j], m4_do(m4_for([i], [1], [10000], [], [,i ])), [j ]))
m4_shiftn(9998m4_for([i], [1], [10000], [], [,i]))
m4_len(m4_join([--],, m4_dquote_elt(m4_for([i], [1], [10000], [], [,i])),))
m4_len(m4_joinall([--], m4_map([, m4_echo],
m4_dquote([1]m4_for([i], [2], [10000], [], [,i])))))
m4_max(m4_min([1]m4_for([i], [2], [10000], [],
[,i]))m4_for([i], [2], [10000], [], [,i]))
m4_case([10000]m4_for([i], [1], [10000], [], [,i]),[end])
m4_list_cmp(m4_dquote(1m4_for([i], [2], [10000], [], [,i])),
m4_dquote(m4_reverse(10000m4_for([i], [9999], [1], [], [,i])), [0]))
m4_list_cmp([0], [0m4_for([i], [1], [10000], [], [,0])])
m4_list_cmp([0m4_for([i], [1], [10000], [], [,0])], [0])
m4_for([i], [1], [10000], [], [m4_define(i)])dnl
m4_undefine(1m4_for([i], [2], [10000], [], [,i]))dnl
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_map_args_pair([,m4_quote], []m4_map_args([,m4_echo]m4_for([i],
[1], [10000], [], [,i]))))
m4_divert_pop(0)
]])
AT_CHECK_M4SUGAR([-o-], [0], [[48894
9999,10000
78896
58894
10000
end
0
0
0
A
^9998$
9990 9990
5001
]])
AT_DATA_M4SUGAR([script.4s],
[[m4_ifdef([__m4_version__],
[m4_undefine([__m4_version__])],
[m4_divert_push(0)48894
9999,10000
78896
58894
10000
end
0
0
0
A
^9998$
9990 9990
5001
m4_exit([0])])
m4_init
m4_divert_push(0)[]dnl
m4_len(m4_foreach_w([j], m4_do(m4_for([i], [1], [10000], [], [,i ])), [j ]))
m4_shiftn(9998m4_for([i], [1], [10000], [], [,i]))
m4_len(m4_join([--],, m4_dquote_elt(m4_for([i], [1], [10000], [], [,i])),))
m4_len(m4_joinall([--], m4_map([, m4_echo],
m4_dquote([1]m4_for([i], [2], [10000], [], [,i])))))
m4_max(m4_min([1]m4_for([i], [2], [10000], [],
[,i]))m4_for([i], [2], [10000], [], [,i]))
m4_case([10000]m4_for([i], [1], [10000], [], [,i]),[end])
m4_list_cmp(m4_dquote(1m4_for([i], [2], [10000], [], [,i])),
m4_dquote(m4_reverse(10000m4_for([i], [9999], [1], [], [,i])), [0]))
m4_list_cmp([0], [0m4_for([i], [1], [10000], [], [,0])])
m4_list_cmp([0m4_for([i], [1], [10000], [], [,0])], [0])
m4_for([i], [1], [10000], [], [m4_define(i)])dnl
m4_undefine(1m4_for([i], [2], [10000], [], [,i]))dnl
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_map_args_pair([,m4_quote], []m4_map_args([,m4_echo]m4_for([i],
[1], [10000], [], [,i]))))
m4_divert_pop(0)
]])
AT_CHECK_M4SUGAR([-o-], [0], [[48894
9999,10000
78896
58894
10000
end
0
0
0
A
^9998$
9990 9990
5001
]])
AT_CLEANUP
## ---------- ##
## m4_set_*. ##
## ---------- ##
AT_SETUP([m4@&t@_set])
AT_KEYWORDS([m4@&t@_set_add m4@&t@_set_add_all m4@&t@_set_contains
m4@&t@_set_contents m4@&t@_set_delete m4@&t@_set_difference m4@&t@_set_dump
m4@&t@_set_empty m4@&t@_set_foreach m4@&t@_set_intersection m4@&t@_set_list
m4@&t@_set_listc m4@&t@_set_map m4@&t@_set_remove m4@&t@_set_size
m4@&t@_set_union])
# Simple tests
AT_CHECK_M4SUGAR_TEXT([[m4_set_contains([a], [1], [yes], [no])
m4_set_add([a], [1], [added], [dup])
m4_set_contains([a], [1], [yes], [no])
m4_set_add([a], [1], [added], [dup])
m4_set_contents([a])
m4_set_remove([a], [1], [removed], [missing])
m4_set_contains([a], [1], [yes], [no])
m4_set_remove([a], [1], [removed], [missing])
m4_set_add([a], [2], [added], [dup])
m4_set_empty([a], [yes], [no])
m4_set_delete([a])
m4_set_empty([a], [yes], [no])
m4_set_add_all([c], [1], [2], [3])
m4_set_add_all([a]m4_set_listc([c]))
m4_set_contents([c], [-])
m4_set_dump([a], [-])
m4_set_contents([a])
m4_set_add_all([a], [1], [2], [3])m4_set_add_all([b], [3], [], [4])
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], [])
m4_set_list([a])
m4_set_remove([a], [2])
m4_dquote(m4_set_list([a]))
m4_set_listc([a])
m4_set_size([a])
m4_set_delete([a])
m4_dquote(m4_set_list([a]))
m4_indir([m4_dquote]m4_set_listc([a]))
m4_set_listc([a])
m4_set_size([a])
]], [[no
added
yes
dup
1
removed
no
missing
added
no
yes
1-2-3
3-2-1
,1,2
,,4
,3
,1,2,3,,4
:1:3
2
2,
[]
,
1
[]
0
]])
# Stress tests - check for unusual names/values
AT_CHECK_M4SUGAR_TEXT([[m4_define([a], [oops])dnl
m4_set_add([a], [a])dnl
m4_set_remove([a], [oops], [yes], [no])
m4_set_add([a,b], [c])dnl
m4_set_add([a,b], [$*[]])dnl
m4_set_add_all([a], [b,c])dnl
m4_set_size([a])
m4_count(m4_set_contents([a], [,]))
m4_count(m4_set_list([a], [,]))
m4_set_dump([a], [,])
m4_set_contents([a,b], [,])
m4_set_list([a,b])
m4_set_foreach([$*[]], [$*[]], [oops])
m4_set_add([$*[]], [])dnl
m4_set_remove([$*[]], [a], [yes], [no])
m4_set_add([$*[]], [a])dnl
m4_set_foreach([$*[]], [$*[]], [-m4_defn([$*[]])m4_indir([$*[]])-])
m4_set_remove([$*[]], [], [yes], [no])
m4_set_add([c], [,])dnl
m4_set_foreach([a,b], [set], [:m4_set_listc(_m4_defn([set])):])
]],[[no
2
1
2
b,c,a
c,$*[]
c,$*[]
no
---aoops-
yes
:,,::,a:
]])
# Stress tests - check for linear scaling (won't necessarily fail if
# quadratic, but hopefully users will complain if it appears to hang)
AT_CHECK_M4SUGAR_TEXT([[dnl
m4_for([i], [1], [10000], [], [m4_set_add([a], i)])dnl
m4_set_add_all([b]m4_for([i], [1], [10000], [], [,i]))dnl
m4_set_remove([a], [1])dnl
m4_set_remove([b], [10000])dnl
m4_set_add_all([a]m4_for([i], [1], [10000], [], [,i]))dnl
m4_for([i], [1], [10000], [], [m4_set_add([b], i)])dnl
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
3333
3334
]])
AT_CLEANUP