+2008-08-14 Eric Blake <ebb9@byu.net>
+
+ Implement m4_transform_pair, to speed up AS_IF.
+ * lib/m4sugar/m4sugar.m4 (m4_transform, m4_transform_pair): New
+ macros, undocumented for now.
+ * lib/m4sugar/foreach.m4 (m4_transform, m4_transform_pair): Also
+ the m4 1.4.x counterparts.
+ * lib/m4sugar/m4sh.m4 (AS_IF, AS_CASE): Use it.
+ * tests/m4sh.at (AS@&t@_IF and AS@&t@_CASE): Test it.
+
2008-08-14 Ralf Wildenhues <Ralf.Wildenhues@gmx.de>
* lib/autoconf/programs.m4 (AC_PATH_TARGET_TOOL)
[m4_foreach([_m4_elt], [m4_shift2($@)],
[m4_apply([$1], m4_defn([_m4_elt]))])])])
+# m4_transform(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],
+[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_],
+[[$$1([$$2])[]]])
+
+# m4_transform_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])
+# 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],
+[m4_if([$#], [0], [m4_fatal([$0: too few arguments: $#])],
+ [$#], [1], [m4_fatal([$0: too few arguments: $#: $1])],
+ [$#], [2], [],
+ [$#], [3], [m4_default([$2], [$1])([$3])[]],
+ [m4_define([_$0], m4_pushdef([_$0])_m4_for([_$0], [3],
+ 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_],
+[[$$1([$$2], [$$3])[]]])
+
+m4_define([_m4_transform_pair_end],
+[m4_if(m4_eval([$3 & 1]), [1], [[m4_default([$$2], [$$1])([$$3])[]]])])
+
# m4_join(SEP, ARG1, ARG2...)
# ---------------------------
# Produce ARG1SEPARG2...SEPARGn. Avoid back-to-back SEP when a given ARG
# | *) DEFAULT ;;
# | esac
m4_define([_AS_CASE],
-[m4_if([$#], 0, [m4_fatal([$0: too few arguments: $#])],
- [$#], 1, [ *) $1 ;;],
- [$#], 2, [ $1) m4_default([$2], [:]) ;;],
- [ $1) m4_default([$2], [:]) ;;
-$0(m4_shift2($@))])dnl
+[ $1[)] m4_default([$2], [:]) ;;
+])
+m4_define([_AS_CASE_DEFAULT],
+[ *[)] $1 ;;
])
m4_defun([AS_CASE],
[m4_ifval([$2$3],
[case $1 in
-_AS_CASE(m4_shift($@))
+m4_transform_pair([_$0], [_$0_DEFAULT], m4_shift($@))dnl
esac
])dnl
])# AS_CASE
# with simplifications if IF-TRUE1 and/or IF-FALSE is empty.
#
m4_define([_AS_IF],
-[m4_ifval([$2$3],
[elif $1; then
m4_default([$2], [:])
-m4_ifval([$3], [$0(m4_shift2($@))])],
+])
+m4_define([_AS_IF_ELSE],
[m4_ifvaln([$1],
[else
- $1])dnl
-])dnl
-])# _AS_IF
+ $1])])
m4_defun([AS_IF],
[m4_ifval([$2$3],
[if $1; then
m4_default([$2], [:])
-m4_ifval([$3], [_$0(m4_shift2($@))])[]dnl
+m4_transform_pair([_$0], [_$0_ELSE], m4_shift2($@))dnl
fi
])dnl
])# AS_IF
[m4_apply([$1], m4_car($3))_m4_map([[$2]$1], $3)])])
+# m4_transform(EXPRESSION, ARG...)
+# --------------------------------
+# Expand EXPRESSION([ARG]) for each argument. More efficient than
+# m4_foreach([var], [ARG...], [EXPRESSION(m4_defn([var]))])
+m4_define([m4_transform],
+[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...)
+# --------------------------------------------------------------
+# 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
+# => (a,b)
+# => (c,d)
+# => (e)
+m4_define([m4_transform_pair],
+[m4_if([$#], [0], [m4_fatal([$0: too few arguments: $#])],
+ [$#], [1], [m4_fatal([$0: too few arguments: $#: $1])],
+ [$#], [2], [],
+ [$#], [3], [m4_default([$2], [$1])([$3])[]],
+ [$#], [4], [$1([$3], [$4])[]],
+ [$1([$3], [$4])[]$0([$1], [$2], m4_shift(m4_shift3($@)))])])
+
+
## --------------------------- ##
## 9. More diversion support. ##
## --------------------------- ##
AT_SETUP([AS@&t@_IF and AS@&t@_CASE])
+AT_KEYWORDS([m4@&t@_foreach_pair])
+
AT_DATA_M4SH([script.as], [[dnl
AS_INIT
# Syntax checks: cope with empty arguments.
foo9=9 bar9=9
]])
+dnl stress test for large number of conditionals
+AT_DATA_M4SH([script.as], [[dnl
+AS_INIT
+AS_IF(m4_shift(m4_for([i], [1], [1000], [], [, test $[1] = i, echo i])))
+AS_IF(m4_shift(m4_for([i], [1], [1000], [], [, test $[1] = i, echo i])),
+ [echo default])
+AS_CASE([$[1]]m4_for([i], [1], [1000], [], [, i, echo i]))
+AS_CASE([$[1]]m4_for([i], [1], [1000], [], [, i, echo i]), [echo default])
+]])
+
+AT_CHECK_M4SH
+AT_CHECK([./script 1], [0], [[1
+1
+1
+1
+]])
+AT_CHECK([./script 1000], [0], [[1000
+1000
+1000
+1000
+]])
+AT_CHECK([./script default], [0], [[default
+default
+]])
+
AT_CLEANUP