autoconf-patches
[Top][All Lists]
Advanced

[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





reply via email to

[Prev in Thread] Current Thread [Next in Thread]