+2008-10-29 Paolo Bonzini <bonzini@gnu.org>
+
+ Rewrite handling of diversion and expansion stack.
+ * NEWS: Document stricter requirement on m4_init.
+ * lib/m4sugar/m4sugar.m4 (m4_divert_stack): New, replacing
+ _m4_divert_n_stack.
+ (_m4_divert_stack_push): New.
+ (m4_divert): Use _m4_divert_stack_push and replace m4_define with
+ m4_popdef.
+ (m4_divert_push): Use _m4_divert_stack_push.
+ (m4_divert_pop): Use m4_divert_stack instead of _m4_divert_n_stack,
+ pop _m4_divert_stack instead of m4_divert_stack.
+ (m4_expansion_stack): New. Update comment above it.
+ (m4_expansion_stack_push, m4_expansion_stack_pop): Work on
+ _m4_expansion_stack instead of m4_expansion_stack.
+ (m4_expansion_stack_dump): Check presence of _m4_expansion_stack
+ instead of m4_expansion_stack. Use m4_expansion_stack's expansion
+ instead of the definition, and compensate for the trailing newline
+ in the expansion.
+ (m4_warn, _m4_defun_pro, _m4_defun_epi): Check presence of
+ _m4_expansion_stack instead of m4_expansion_stack.
+ (m4_newline): Expand first argument after the newline.
+ (m4_init): Use m4_divert_stack instead of _m4_divert_n_stack,
+ * tests/m4sugar.at (m4_append, m4_text_wrap): Invoke m4_init.
+ * tests/tools.at (whitespace in file names, the empty token): Likewise.
+
2008-10-28 Eric Blake <ebb9@byu.net>
Reduce forks while searching for better shell.
# Report a MESSAGE to the user if the CATEGORY of warnings is enabled.
m4_define([m4_warn],
[_m4_warn([$1], [$2],
-m4_ifdef([m4_expansion_stack],
- [_m4_defn([m4_expansion_stack])
-m4_location[: the top level]]))dnl
-])
+m4_ifdef([_m4_expansion_stack],
+ [m4_expansion_stack[]m4_location[: the top level]]))])
m4_define([_m4_divert()], 0)
-# _m4_divert_n_stack
+# m4_divert_stack
# ------------------
# Print m4_divert_stack with newline prepended, if it's nonempty.
-m4_define([_m4_divert_n_stack],
-[m4_ifdef([m4_divert_stack], [
-_m4_defn([m4_divert_stack])])])
+m4_define([m4_divert_stack],
+[m4_stack_foreach_lifo([_m4_divert_stack], [m4_newline])])
+
+
+# m4_divert_stack_push(LOCATION, MACRO-NAME, DIVERSION-NAME)
+# -----------------------------------------------------------
+# Form an entry of the diversion stack and push it.
+m4_define([m4_divert_stack_push],
+[m4_pushdef([_m4_divert_stack], [[$1: $2: $3]])])
# m4_divert(DIVERSION-NAME)
# -------------------------
# Change the diversion stream to DIVERSION-NAME.
m4_define([m4_divert],
-[m4_define([m4_divert_stack], m4_location[: $0: $1]_m4_divert_n_stack)]dnl
+[m4_popdef([_m4_divert_stack])]dnl
+[m4_divert_stack_push(m4_location, [$0], [$1])]dnl
[m4_builtin([divert], _m4_divert([$1]))])
# ------------------------------
# Change the diversion stream to DIVERSION-NAME, while stacking old values.
m4_define([m4_divert_push],
-[m4_pushdef([m4_divert_stack], m4_location[: $0: $1]_m4_divert_n_stack)]dnl
+[m4_divert_stack_push(m4_location, [$0], [$1])]dnl
[m4_pushdef([_m4_divert_diversion], [$1])]dnl
[m4_builtin([divert], _m4_divert([$1]))])
[m4_fatal([too many m4_divert_pop])])]dnl
[m4_if([$1], [], [],
[$1], _m4_defn([_m4_divert_diversion]), [],
- [m4_fatal([$0($1): diversion mismatch: ]_m4_divert_n_stack)])]dnl
-[_m4_popdef([m4_divert_stack], [_m4_divert_diversion])]dnl
+ [m4_fatal([$0($1): diversion mismatch: ]m4_divert_stack)])]dnl
+[_m4_popdef([_m4_divert_stack], [_m4_divert_diversion])]dnl
[m4_builtin([divert],
m4_ifdef([_m4_divert_diversion],
[_m4_divert(_m4_defn([_m4_divert_diversion]))],
# performance penalty this is implemented only for m4_defun'd macros,
# not for define'd macros.
#
-# The scheme is simplistic: each time we enter an m4_defun'd macros,
-# we prepend its name in m4_expansion_stack, and when we exit the
-# macro, we remove it (thanks to pushdef/popdef).
+# Each time we enter an m4_defun'd macros, we add a definition in
+# _m4_expansion_stack, and when we exit the macro, we remove it (thanks
+# to pushdef/popdef). m4_stack_foreach is used to print the expansion
+# stack in the rare cases when it's needed.
#
# In addition, we want to detect circular m4_require dependencies.
# Each time we expand a macro FOO we define _m4_expanding(FOO); and
# m4_require(BAR) simply checks whether _m4_expanding(BAR) is defined.
+# m4_expansion_stack
+# ------------------
+# Expands to the entire contents of the expansion stack, if not empty,
+# with a newline at its end.
+m4_define([m4_expansion_stack],
+[m4_ifdef([_m4_expansion_stack],
+ [m4_stack_foreach_lifo([_m4_expansion_stack], [m4_n])])])
+
# m4_expansion_stack_push(TEXT)
# -----------------------------
+# Form an entry of the expansion stack and push it.
m4_define([m4_expansion_stack_push],
-[m4_pushdef([m4_expansion_stack],
- [$1]m4_ifdef([m4_expansion_stack], [
-_m4_defn([m4_expansion_stack])]))])
+[m4_pushdef([_m4_expansion_stack], [[$1]])])
# m4_expansion_stack_pop
# ----------------------
+# Pop the topmost entry of the expansion stack.
m4_define([m4_expansion_stack_pop],
-[m4_popdef([m4_expansion_stack])])
+[m4_popdef([_m4_expansion_stack])])
# m4_expansion_stack_dump
# -----------------------
# Dump the expansion stack.
m4_define([m4_expansion_stack_dump],
-[m4_ifdef([m4_expansion_stack],
- [m4_errprintn(_m4_defn([m4_expansion_stack]))])dnl
+[m4_ifdef([_m4_expansion_stack],
+ [m4_errprint(m4_expansion_stack)])dnl
m4_errprintn(m4_location[: the top level])])
# This is called frequently, so minimize the number of macro invocations
# by avoiding dnl and m4_defn overhead.
m4_define([_m4_defun_pro],
-m4_do([[m4_ifdef([m4_expansion_stack], [], [_m4_defun_pro_outer[]])]],
+m4_do([[m4_ifdef([_m4_expansion_stack], [], [_m4_defun_pro_outer[]])]],
[[m4_expansion_stack_push(_m4_defn(
[m4_location($1)])[: $1 is expanded from...])]],
[[m4_pushdef([_m4_expanding($1)])]]))
m4_define([_m4_defun_epi],
m4_do([[_m4_popdef([_m4_expanding($1)])]],
[[m4_expansion_stack_pop()]],
- [[m4_ifdef([m4_expansion_stack], [], [_m4_defun_epi_outer[]])]],
+ [[m4_ifdef([_m4_expansion_stack], [], [_m4_defun_epi_outer[]])]],
[[m4_provide([$1])]]))
m4_define([_m4_defun_epi_outer],
# If NAME-TO-CHECK has never been expanded (actually, if it is not
# m4_provide'd), expand BODY-TO-EXPAND *before* the current macro
# expansion. Once expanded, emit it in _m4_divert_dump. Keep track
-# of the m4_require chain in m4_expansion_stack.
+# of the m4_require chain in _m4_expansion_stack.
#
# The normal cases are:
#
_m4_define_cr_not([symbols2])
-# m4_newline
-# ----------
-# Expands to a newline. Exists for formatting reasons.
+# m4_newline([STRING])
+# --------------------
+# Expands to a newline, possibly followed by STRING. Exists mostly for
+# formatting reasons.
m4_define([m4_newline], [
-])
+$1])
# m4_re_escape(STRING)
# Check the divert push/pop perfect balance.
m4_wrap([m4_divert_pop([])
m4_ifdef([_m4_divert_diversion],
- [m4_fatal([$0: unbalanced m4_divert_push:]_m4_divert_n_stack)])[]])
+ [m4_fatal([$0: unbalanced m4_divert_push:]m4_divert_stack)])[]])
])