* acgeneral.m4 (m4_case): Fixed a typo and a bug: one shift was

missing.
(m4_match): New macro.
* tests/atgeneral.m4 (AT_CASE): Fixed.
This commit is contained in:
Akim Demaille 2000-02-07 16:28:06 +00:00
parent db2e9d0892
commit 304ecacb35
5 changed files with 233 additions and 166 deletions

View File

@ -1,3 +1,10 @@
2000-02-07 Akim Demaille <akim@epita.fr>
* acgeneral.m4 (m4_case): Fixed a typo and a bug: one shift was
missing.
(m4_match): New macro.
* tests/atgeneral.m4 (AT_CASE): Fixed.
2000-02-07 Akim Demaille <akim@epita.fr> 2000-02-07 Akim Demaille <akim@epita.fr>
* acgeneral.m4: Formatting changes. * acgeneral.m4: Formatting changes.

View File

@ -314,93 +314,121 @@ dnl Returns EXP1 if non empty, otherwise EXP2.
define([m4_default], [ifval([$1], [$1], [$2])]) define([m4_default], [ifval([$1], [$1], [$2])])
dnl m4_case(SWITCH, VAL1, IF-VAL1, VAL2, IF-VAL2, ..., DEFAULT) # m4_case(SWITCH, VAL1, IF-VAL1, VAL2, IF-VAL2, ..., DEFAULT)
dnl ----------------------------------------------------------- # -----------------------------------------------------------
dnl m4 equivalent of # m4 equivalent of
dnl switch (SWITCH) # switch (SWITCH)
dnl { # {
dnl case VAL1: # case VAL1:
dnl IF-VAL1; # IF-VAL1;
dnl break; # break;
dnl case VAL2: # case VAL2:
dnl IF-VAL2; # IF-VAL2;
dnl break; # break;
dnl ... # ...
dnl default: # default:
dnl DEFAULT; # DEFAULT;
dnl break; # break;
dnl }. # }.
dnl All the values are optional, and the macro is robust to active # All the values are optional, and the macro is robust to active
dnl symbols properly quoted. # symbols properly quoted.
define(m4_case, define(m4_case,
[ifelse([$1], 1,, [ifelse([$#], 0, [],
[$#], 1, [],
[$#], 2, [$2], [$#], 2, [$2],
[$1], [$2], [$3], [$1], [$2], [$3],
[m4_case([$1], m4_shift(m4_shift($@)))])]) [m4_case([$1], m4_shift(m4_shift(m4_shift($@))))])])
dnl ### Implementing m4 loops # m4_match(SWITCH, RE1, VAL1, RE2, VAL2, ..., DEFAULT)
# ----------------------------------------------------
dnl Implementing loops (`foreach' loops) in m4 is much more tricky than it # m4 equivalent of
dnl may seem. Actually, the example of a `foreach' loop in the m4 #
dnl documentation is wrong: it does not quote the arguments properly, # if (SWITCH =~ RE1)
dnl which leads to undesired expansions. # VAL1;
dnl # elif (SWITCH =~ RE2)
dnl The example in the documentation is: # VAL2;
dnl # elif ...
dnl | # foreach(x, (item_1, item_2, ..., item_n), stmt) # ...
dnl | define(`foreach', # else
dnl | `pushdef(`$1', `')_foreach(`$1', `$2', `$3')popdef(`$1')') # DEFAULT
dnl | define(`_arg1', `$1') #
dnl | define(`_foreach', # All the values are optional, and the macro is robust to active symbols
dnl | `ifelse(`$2', `()', , # properly quoted.
dnl | `define(`$1', _arg1$2)$3`'_foreach(`$1', (shift$2), `$3')')') define(m4_match,
dnl [ifelse([$#], 0, [],
dnl But then if you run [$#], 1, [],
dnl [$#], 2, [$2],
dnl | define(a, 1) regexp([$1], [$2]), -1, [m4_match([$1],
dnl | define(b, 2) m4_shift(m4_shift(m4_shift($@))))],
dnl | define(c, 3) [$3])])
dnl | foreach(`f', `(`a', `(b', `c)')', `echo f
dnl | ')
dnl
dnl it gives
dnl
dnl => echo 1
dnl => echo (2,3)
dnl
dnl which is not what is expected.
dnl
dnl Once you understood this, you turn yourself into a quoting wizard,
dnl and come up with the following solution:
dnl
dnl | # foreach(x, (item_1, item_2, ..., item_n), stmt)
dnl | define(`foreach', `pushdef(`$1', `')_foreach($@)popdef(`$1')')
dnl | define(`_arg1', ``$1'')
dnl | define(`_foreach',
dnl | `ifelse($2, `()', ,
dnl | `define(`$1', `_arg1$2')$3`'_foreach(`$1', `(shift$2)', `$3')')')
dnl
dnl which this time answers
dnl
dnl => echo a
dnl => echo (b
dnl => echo c)
dnl
dnl Bingo!
dnl M4_FOREACH(VARIABLE, LIST, EXPRESSION) ## --------------------- ##
dnl -------------------------------------- ## Implementing m4 loops ##
dnl Expand EXPRESSION assigning to VARIABLE each value of the LIST ## --------------------- ##
dnl (LIST should have the form `[(item_1, item_2, ..., item_n)]'),
dnl i.e. the whole list should be *quoted*. Quote members too if
dnl you don't want them to be expanded. # Implementing loops (`foreach' loops) in m4 is much more tricky than it
dnl # may seem. Actually, the example of a `foreach' loop in the m4
dnl This macro is robust to active symbols: # documentation is wrong: it does not quote the arguments properly,
dnl define(active, ACTIVE) # which leads to undesired expansions.
dnl m4_foreach([Var], [([active], [b], [active])], [-Var-])end #
dnl => -active--b--active-end # The example in the documentation is:
#
# | # foreach(x, (item_1, item_2, ..., item_n), stmt)
# | define(`foreach',
# | `pushdef(`$1', `')_foreach(`$1', `$2', `$3')popdef(`$1')')
# | define(`_arg1', `$1')
# | define(`_foreach',
# | `ifelse(`$2', `()', ,
# | `define(`$1', _arg1$2)$3`'_foreach(`$1', (shift$2), `$3')')')
#
# But then if you run
#
# | define(a, 1)
# | define(b, 2)
# | define(c, 3)
# | foreach(`f', `(`a', `(b', `c)')', `echo f
# | ')
#
# it gives
#
# => echo 1
# => echo (2,3)
#
# which is not what is expected.
#
# Once you understood this, you turn yourself into a quoting wizard,
# and come up with the following solution:
#
# | # foreach(x, (item_1, item_2, ..., item_n), stmt)
# | define(`foreach', `pushdef(`$1', `')_foreach($@)popdef(`$1')')
# | define(`_arg1', ``$1'')
# | define(`_foreach',
# | `ifelse($2, `()', ,
# | `define(`$1', `_arg1$2')$3`'_foreach(`$1', `(shift$2)', `$3')')')
#
# which this time answers
#
# => echo a
# => echo (b
# => echo c)
#
# Bingo!
# m4_foreach(VARIABLE, LIST, EXPRESSION)
# --------------------------------------
# Expand EXPRESSION assigning to VARIABLE each value of the LIST
# (LIST should have the form `[(item_1, item_2, ..., item_n)]'),
# i.e. the whole list should be *quoted*. Quote members too if
# you don't want them to be expanded.
#
# This macro is robust to active symbols:
# define(active, ACTIVE)
# m4_foreach([Var], [([active], [b], [active])], [-Var-])end
# => -active--b--active-end
define(m4_foreach, define(m4_foreach,
[pushdef([$1], [])_m4_foreach($@)popdef([$1])]) [pushdef([$1], [])_m4_foreach($@)popdef([$1])])

View File

@ -314,93 +314,121 @@ dnl Returns EXP1 if non empty, otherwise EXP2.
define([m4_default], [ifval([$1], [$1], [$2])]) define([m4_default], [ifval([$1], [$1], [$2])])
dnl m4_case(SWITCH, VAL1, IF-VAL1, VAL2, IF-VAL2, ..., DEFAULT) # m4_case(SWITCH, VAL1, IF-VAL1, VAL2, IF-VAL2, ..., DEFAULT)
dnl ----------------------------------------------------------- # -----------------------------------------------------------
dnl m4 equivalent of # m4 equivalent of
dnl switch (SWITCH) # switch (SWITCH)
dnl { # {
dnl case VAL1: # case VAL1:
dnl IF-VAL1; # IF-VAL1;
dnl break; # break;
dnl case VAL2: # case VAL2:
dnl IF-VAL2; # IF-VAL2;
dnl break; # break;
dnl ... # ...
dnl default: # default:
dnl DEFAULT; # DEFAULT;
dnl break; # break;
dnl }. # }.
dnl All the values are optional, and the macro is robust to active # All the values are optional, and the macro is robust to active
dnl symbols properly quoted. # symbols properly quoted.
define(m4_case, define(m4_case,
[ifelse([$1], 1,, [ifelse([$#], 0, [],
[$#], 1, [],
[$#], 2, [$2], [$#], 2, [$2],
[$1], [$2], [$3], [$1], [$2], [$3],
[m4_case([$1], m4_shift(m4_shift($@)))])]) [m4_case([$1], m4_shift(m4_shift(m4_shift($@))))])])
dnl ### Implementing m4 loops # m4_match(SWITCH, RE1, VAL1, RE2, VAL2, ..., DEFAULT)
# ----------------------------------------------------
dnl Implementing loops (`foreach' loops) in m4 is much more tricky than it # m4 equivalent of
dnl may seem. Actually, the example of a `foreach' loop in the m4 #
dnl documentation is wrong: it does not quote the arguments properly, # if (SWITCH =~ RE1)
dnl which leads to undesired expansions. # VAL1;
dnl # elif (SWITCH =~ RE2)
dnl The example in the documentation is: # VAL2;
dnl # elif ...
dnl | # foreach(x, (item_1, item_2, ..., item_n), stmt) # ...
dnl | define(`foreach', # else
dnl | `pushdef(`$1', `')_foreach(`$1', `$2', `$3')popdef(`$1')') # DEFAULT
dnl | define(`_arg1', `$1') #
dnl | define(`_foreach', # All the values are optional, and the macro is robust to active symbols
dnl | `ifelse(`$2', `()', , # properly quoted.
dnl | `define(`$1', _arg1$2)$3`'_foreach(`$1', (shift$2), `$3')')') define(m4_match,
dnl [ifelse([$#], 0, [],
dnl But then if you run [$#], 1, [],
dnl [$#], 2, [$2],
dnl | define(a, 1) regexp([$1], [$2]), -1, [m4_match([$1],
dnl | define(b, 2) m4_shift(m4_shift(m4_shift($@))))],
dnl | define(c, 3) [$3])])
dnl | foreach(`f', `(`a', `(b', `c)')', `echo f
dnl | ')
dnl
dnl it gives
dnl
dnl => echo 1
dnl => echo (2,3)
dnl
dnl which is not what is expected.
dnl
dnl Once you understood this, you turn yourself into a quoting wizard,
dnl and come up with the following solution:
dnl
dnl | # foreach(x, (item_1, item_2, ..., item_n), stmt)
dnl | define(`foreach', `pushdef(`$1', `')_foreach($@)popdef(`$1')')
dnl | define(`_arg1', ``$1'')
dnl | define(`_foreach',
dnl | `ifelse($2, `()', ,
dnl | `define(`$1', `_arg1$2')$3`'_foreach(`$1', `(shift$2)', `$3')')')
dnl
dnl which this time answers
dnl
dnl => echo a
dnl => echo (b
dnl => echo c)
dnl
dnl Bingo!
dnl M4_FOREACH(VARIABLE, LIST, EXPRESSION) ## --------------------- ##
dnl -------------------------------------- ## Implementing m4 loops ##
dnl Expand EXPRESSION assigning to VARIABLE each value of the LIST ## --------------------- ##
dnl (LIST should have the form `[(item_1, item_2, ..., item_n)]'),
dnl i.e. the whole list should be *quoted*. Quote members too if
dnl you don't want them to be expanded. # Implementing loops (`foreach' loops) in m4 is much more tricky than it
dnl # may seem. Actually, the example of a `foreach' loop in the m4
dnl This macro is robust to active symbols: # documentation is wrong: it does not quote the arguments properly,
dnl define(active, ACTIVE) # which leads to undesired expansions.
dnl m4_foreach([Var], [([active], [b], [active])], [-Var-])end #
dnl => -active--b--active-end # The example in the documentation is:
#
# | # foreach(x, (item_1, item_2, ..., item_n), stmt)
# | define(`foreach',
# | `pushdef(`$1', `')_foreach(`$1', `$2', `$3')popdef(`$1')')
# | define(`_arg1', `$1')
# | define(`_foreach',
# | `ifelse(`$2', `()', ,
# | `define(`$1', _arg1$2)$3`'_foreach(`$1', (shift$2), `$3')')')
#
# But then if you run
#
# | define(a, 1)
# | define(b, 2)
# | define(c, 3)
# | foreach(`f', `(`a', `(b', `c)')', `echo f
# | ')
#
# it gives
#
# => echo 1
# => echo (2,3)
#
# which is not what is expected.
#
# Once you understood this, you turn yourself into a quoting wizard,
# and come up with the following solution:
#
# | # foreach(x, (item_1, item_2, ..., item_n), stmt)
# | define(`foreach', `pushdef(`$1', `')_foreach($@)popdef(`$1')')
# | define(`_arg1', ``$1'')
# | define(`_foreach',
# | `ifelse($2, `()', ,
# | `define(`$1', `_arg1$2')$3`'_foreach(`$1', `(shift$2)', `$3')')')
#
# which this time answers
#
# => echo a
# => echo (b
# => echo c)
#
# Bingo!
# m4_foreach(VARIABLE, LIST, EXPRESSION)
# --------------------------------------
# Expand EXPRESSION assigning to VARIABLE each value of the LIST
# (LIST should have the form `[(item_1, item_2, ..., item_n)]'),
# i.e. the whole list should be *quoted*. Quote members too if
# you don't want them to be expanded.
#
# This macro is robust to active symbols:
# define(active, ACTIVE)
# m4_foreach([Var], [([active], [b], [active])], [-Var-])end
# => -active--b--active-end
define(m4_foreach, define(m4_foreach,
[pushdef([$1], [])_m4_foreach($@)popdef([$1])]) [pushdef([$1], [])_m4_foreach($@)popdef([$1])])

View File

@ -80,10 +80,12 @@ undefine([undefine])
# All the values are optional, and the macro is robust to active # All the values are optional, and the macro is robust to active
# symbols properly quoted. # symbols properly quoted.
AT_DEFINE(AT_CASE, AT_DEFINE(AT_CASE,
[ifelse([$1], 1,, [ifelse([$#], 0, [],
[$#], 1, [],
[$#], 2, [$2], [$#], 2, [$2],
[$1], [$2], [$3], [$1], [$2], [$3],
[AT_CASE([$1], AT_SHIFT(AT_SHIFT($@)))])]) [AT_CASE([$1], AT_SHIFT(AT_SHIFT(AT_SHIFT($@))))])])
# Use of diversions: # Use of diversions:
# 0 - overall initialization; for each test group: skipping and cleanups; # 0 - overall initialization; for each test group: skipping and cleanups;
@ -371,4 +373,4 @@ fi
$at_traceon $at_traceon
]) ])
divert[]dnl divert(0)dnl

View File

@ -80,10 +80,12 @@ undefine([undefine])
# All the values are optional, and the macro is robust to active # All the values are optional, and the macro is robust to active
# symbols properly quoted. # symbols properly quoted.
AT_DEFINE(AT_CASE, AT_DEFINE(AT_CASE,
[ifelse([$1], 1,, [ifelse([$#], 0, [],
[$#], 1, [],
[$#], 2, [$2], [$#], 2, [$2],
[$1], [$2], [$3], [$1], [$2], [$3],
[AT_CASE([$1], AT_SHIFT(AT_SHIFT($@)))])]) [AT_CASE([$1], AT_SHIFT(AT_SHIFT(AT_SHIFT($@))))])])
# Use of diversions: # Use of diversions:
# 0 - overall initialization; for each test group: skipping and cleanups; # 0 - overall initialization; for each test group: skipping and cleanups;
@ -371,4 +373,4 @@ fi
$at_traceon $at_traceon
]) ])
divert[]dnl divert(0)dnl