[Top][All Lists]
[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
[PATCH] Rewrite handling of diversion and expansion stacks
From: |
Paolo Bonzini |
Subject: |
[PATCH] Rewrite handling of diversion and expansion stacks |
Date: |
Tue, 28 Oct 2008 12:58:55 +0100 |
This patch rewrites the handling of diversion and expansion stacks,
pushing only single entries to the stack and putting them together
using m4_stack_foreach in the rare case a warning or error message
needs them.
The speedup is only 3-5% because quadratic behavior is not apparent
on the configure.ac files I tested, but better than nothing. It
would also make m4_defun_init'd macros faster if they were to push/pop
the location to the stack.
While doing this, I also rationalized a little the names of the macros for
the two stacks: the macro m4_XXX_stack expands the stack (unfortunately
the two macros place newlines in slightly different ways; this can be
cleaned up later); _m4_XXX_stack hosts the entries, and can be tested
with m4_ifdef.
Another possible cleanup left for later is to synthesize the proper format
of the expansion stack message in m4_expansion_stack_push, as is done
for m4_divert_stack_push.
The new definition of m4_divert, unfortunately, introduces a small
backwards incompatibility: all users that use the diversion stack should
now use m4_init to push the KILL diversion; this is good practice anyway,
and does not break Bison. It does break a couple of tests in Autoconf's
own testsuite, which this patch fixes.
Okay?
Paolo
2008-10-28 Paolo Bonzini <address@hidden>
* 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.
---
NEWS | 3 ++
lib/m4sugar/m4sugar.m4 | 73 +++++++++++++++++++++++++++++-------------------
tests/m4sugar.at | 7 ++--
3 files changed, 51 insertions(+), 32 deletions(-)
diff --git a/NEWS b/NEWS
index 5bdff48..999880b 100644
--- a/NEWS
+++ b/NEWS
@@ -12,6 +12,9 @@ GNU Autoconf NEWS - User visible changes.
** Configure scripts now use shell functions.
+** m4sugar requires m4_init in order to use m4_divert, m4_divert_push
+ and m4_divert_pop.
+
** The following documented m4sugar macros are new:
m4_curry m4_default_quoted m4_map_args m4_map_args_pair
m4_set_map
diff --git a/lib/m4sugar/m4sugar.m4 b/lib/m4sugar/m4sugar.m4
index 8d0a772..0888092 100644
--- a/lib/m4sugar/m4sugar.m4
+++ b/lib/m4sugar/m4sugar.m4
@@ -259,10 +259,8 @@ m4_define([_m4_warn], [])
# 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]]))])
@@ -1225,19 +1223,26 @@ m4_define([_m4_divert(KILL)], -1)
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]))])
@@ -1245,7 +1250,7 @@ m4_define([m4_divert],
# ------------------------------
# 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]))])
@@ -1260,8 +1265,8 @@ m4_define([m4_divert_pop],
[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]))],
@@ -1562,35 +1567,44 @@ m4_define([m4_undivert],
# 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])])
@@ -1620,7 +1634,7 @@ m4_define([_m4_divert(GROW)], 10000)
# 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)])]]))
@@ -1639,7 +1653,7 @@ m4_define([_m4_defun_pro_outer],
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],
@@ -1747,7 +1761,7 @@ m4_define([m4_before],
# 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:
#
@@ -1931,11 +1945,12 @@ _m4_define_cr_not([symbols1])
_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)
@@ -2929,5 +2944,5 @@ m4_divert_push([KILL])
# 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)])[]])
])
diff --git a/tests/m4sugar.at b/tests/m4sugar.at
index 32f07dd..fcbf64d 100644
--- a/tests/m4sugar.at
+++ b/tests/m4sugar.at
@@ -468,14 +468,15 @@ one, two, three
]])
AT_DATA_M4SUGAR([script.4s],
-[[m4_append_uniq([str], [a], [ ])
+[[m4_init[]dnl
+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@&address@hidden: `a b' contains ` '
+]], [[script.4s:3: warning: m4@&address@hidden: `a b' contains ` '
]])
AT_CLEANUP
@@ -543,7 +544,7 @@ AT_SETUP([m4@&address@hidden)
# m4-listification.
AT_DATA_M4SUGAR([script.4s],
-[[m4_divert([0])dnl
+[[m4_init[]m4_divert([0])dnl
m4_text_wrap([Short string */], [ ], [/* ], 20)
m4_text_wrap([Much longer string */], [ ], [/* ], 20)
--
1.5.5
- [PATCH] Rewrite handling of diversion and expansion stacks,
Paolo Bonzini <=