Module Name: src
Committed By: rillig
Date: Sun Aug 16 12:30:45 UTC 2020
Modified Files:
src/usr.bin/make/unit-tests: Makefile modmisc.exp modmisc.mk
varmod-loop.exp varmod-loop.mk varmod-subst-regex.exp
varmod-subst-regex.mk varmod-subst.exp varmod-subst.mk
Log Message:
make(1): move tests for :S, :C, :@ from modmisc to their separate tests
To generate a diff of this commit:
cvs rdiff -u -r1.93 -r1.94 src/usr.bin/make/unit-tests/Makefile
cvs rdiff -u -r1.41 -r1.42 src/usr.bin/make/unit-tests/modmisc.exp \
src/usr.bin/make/unit-tests/modmisc.mk
cvs rdiff -u -r1.1 -r1.2 src/usr.bin/make/unit-tests/varmod-loop.exp \
src/usr.bin/make/unit-tests/varmod-loop.mk \
src/usr.bin/make/unit-tests/varmod-subst-regex.exp \
src/usr.bin/make/unit-tests/varmod-subst-regex.mk \
src/usr.bin/make/unit-tests/varmod-subst.exp \
src/usr.bin/make/unit-tests/varmod-subst.mk
Please note that diffs are not public domain; they are subject to the
copyright notices on the relevant files.
Modified files:
Index: src/usr.bin/make/unit-tests/Makefile
diff -u src/usr.bin/make/unit-tests/Makefile:1.93 src/usr.bin/make/unit-tests/Makefile:1.94
--- src/usr.bin/make/unit-tests/Makefile:1.93 Sun Aug 16 12:07:51 2020
+++ src/usr.bin/make/unit-tests/Makefile Sun Aug 16 12:30:45 2020
@@ -1,4 +1,4 @@
-# $NetBSD: Makefile,v 1.93 2020/08/16 12:07:51 rillig Exp $
+# $NetBSD: Makefile,v 1.94 2020/08/16 12:30:45 rillig Exp $
#
# Unit tests for make(1)
#
@@ -320,8 +320,8 @@ FLAGS.recursive= -dL -r
FLAGS.vardebug= -k -dv FROM_CMDLINE=
# Some tests need extra post-processing.
-SED_CMDS.moderrs+= -e 's,\(Regex compilation error:\).*,\1 (details omitted),'
-SED_CMDS.modmisc+= -e 's,\(Regex compilation error:\).*,\1 (details omitted),'
+SED_CMDS.varmod-subst-regex+= \
+ -e 's,\(Regex compilation error:\).*,\1 (details omitted),'
SED_CMDS.varmod-edge+= -e 's, line [0-9]*:, line omitted:,'
SED_CMDS.varshell+= -e 's,^[a-z]*sh: ,,'
SED_CMDS.varshell+= -e '/command/s,No such.*,not found,'
@@ -440,7 +440,7 @@ sync-mi:
cvs diff "$$mi" || true
.if exists(${TEST_MAKE})
-${TESTS:=.rawout}: ${TEST_MAKE}
+${TESTS:=.rawout}: ${TEST_MAKE} ${.PARSEDIR}/Makefile
.endif
.-include <bsd.obj.mk>
Index: src/usr.bin/make/unit-tests/modmisc.exp
diff -u src/usr.bin/make/unit-tests/modmisc.exp:1.41 src/usr.bin/make/unit-tests/modmisc.exp:1.42
--- src/usr.bin/make/unit-tests/modmisc.exp:1.41 Sun Aug 9 08:03:31 2020
+++ src/usr.bin/make/unit-tests/modmisc.exp Sun Aug 16 12:30:45 2020
@@ -18,100 +18,6 @@ C:
S:empty
C:empty
@:
-mod-subst:
-:a b b c:
-:a b b c:
-: b c:
-:a c:
-:x__ 3 x__ 3:
-12345
-mod-subst-delimiter:
-1 two 3 horizontal tabulator
-1 two 3 space
-1 two 3 exclamation mark
-1 two 3 double quotes
-1 two 3 hash
-1 two 3 dollar
-1 two 3 percent
-1 two 3 apostrophe
-1 two 3 opening parenthesis
-1 two 3 closing parenthesis
-1 two 3 digit
-1 two 3 colon
-1 two 3 less than sign
-1 two 3 equal sign
-1 two 3 greater than sign
-1 two 3 question mark
-1 two 3 at
-1 two 3 letter
-1 two 3 opening bracket
-1 two 3 backslash
-1 two 3 closing bracket
-1 two 3 caret
-1 two 3 opening brace
-1 two 3 vertical line
-1 two 3 closing brace
-1 two 3 tilde
-mod-subst-chain:
-A B c.
-make: Unknown modifier 'i'
-.
-mod-regex:
-:a b b c:
-:a b b c:
-: b c:
-make: Regex compilation error: (details omitted)
-:C,word,____,:Q}:
-:a c:
-:x__ 3 x__ 3:
-:+one+ +two+ +three+:
-:x1y x2y x3y:
-:x1y x2y x3y:
-:mod-loop-varname: :x1y x2y x3y: ::
-:x1y x2y x3y:
-mod-loop-resolve:w1d2d3w w2i3w w1i2d3 2i${RES3}w w1d2d3 2i${RES3} 1i${RES2}w:
-mod-loop-varname-dollar:(1) (2) (3).
-mod-loop-varname-dollar:() () ().
-mod-loop-varname-dollar:() () ().
-mod-subst-dollar:$1:
-mod-subst-dollar:$2:
-mod-subst-dollar:$3:
-mod-subst-dollar:$4:
-mod-subst-dollar:$5:
-mod-subst-dollar:$6:
-mod-subst-dollar:$7:
-mod-subst-dollar:$8:
-mod-subst-dollar:$40:
-mod-subst-dollar:U8:
-mod-subst-dollar:$$$$:
-mod-subst-dollar:$$$good3
-mod-loop-dollar:1:
-mod-loop-dollar:${word}$:
-mod-loop-dollar:$3$:
-mod-loop-dollar:$${word}$$:
-mod-loop-dollar:$$5$$:
-mod-loop-dollar:$$${word}$$$:
-mod-regex-limits:00-ok:1 2323 45456
-make: No subexpression \1
-make: No subexpression \1
-make: No subexpression \1
-make: No subexpression \1
-mod-regex-limits:11-missing:1 6
-mod-regex-limits:11-ok:1 22 446
-make: No subexpression \2
-make: No subexpression \2
-make: No subexpression \2
-make: No subexpression \2
-mod-regex-limits:22-missing:1 6
-make: No subexpression \2
-make: No subexpression \2
-make: No subexpression \2
-make: No subexpression \2
-mod-regex-limits:22-missing:1 6
-mod-regex-limits:22-ok:1 33 556
-mod-regex-limits:capture:ihgfedcbaabcdefghijABCDEFGHIJa0a1a2rest
-make: Regex compilation error: (details omitted)
-mod-regex-errors:
mod-assign: first=1.
mod-assign: last=3.
mod-assign: appended=1 2 3.
Index: src/usr.bin/make/unit-tests/modmisc.mk
diff -u src/usr.bin/make/unit-tests/modmisc.mk:1.41 src/usr.bin/make/unit-tests/modmisc.mk:1.42
--- src/usr.bin/make/unit-tests/modmisc.mk:1.41 Sun Aug 9 09:32:04 2020
+++ src/usr.bin/make/unit-tests/modmisc.mk Sun Aug 16 12:30:45 2020
@@ -1,4 +1,4 @@
-# $Id: modmisc.mk,v 1.41 2020/08/09 09:32:04 rillig Exp $
+# $Id: modmisc.mk,v 1.42 2020/08/16 12:30:45 rillig Exp $
#
# miscellaneous modifier tests
@@ -16,14 +16,6 @@ MOD_OPT=@d@$${exists($$d):?$$d:$${d:S,/u
MOD_SEP=S,:, ,g
all: modvar modvarloop modsysv mod-HTE emptyvar undefvar
-all: mod-subst
-all: mod-subst-delimiter
-all: mod-subst-chain
-all: mod-regex
-all: mod-loop-varname mod-loop-resolve mod-loop-varname-dollar
-all: mod-subst-dollar mod-loop-dollar
-all: mod-regex-limits
-all: mod-regex-errors
all: mod-assign
all: mod-assign-nested
all: mod-tu-space
@@ -80,225 +72,6 @@ undefvar:
@echo C:${:U:C,^$,empty,}
@echo @:${:U:@var@empty@}
-WORDS= sequences of letters
-.if ${WORDS:S,,,} != ${WORDS}
-.warning The empty pattern matches something.
-.endif
-.if ${WORDS:S,e,*,1} != "s*quences of letters"
-.warning The :S modifier flag '1' is not applied exactly once.
-.endif
-.if ${WORDS:S,e,*,} != "s*quences of l*tters"
-.warning The :S modifier does not replace every first match per word.
-.endif
-.if ${WORDS:S,e,*,g} != "s*qu*nc*s of l*tt*rs"
-.warning The :S modifier flag 'g' does not replace every occurrence.
-.endif
-.if ${WORDS:S,^sequ,occurr,} != "occurrences of letters"
-.warning The :S modifier fails for a short match anchored at the start.
-.endif
-.if ${WORDS:S,^of,with,} != "sequences with letters"
-.warning The :S modifier fails for an exact match anchored at the start.
-.endif
-.if ${WORDS:S,^office,does not match,} != ${WORDS}
-.warning The :S modifier matches a too long pattern anchored at the start.
-.endif
-.if ${WORDS:S,f$,r,} != "sequences or letters"
-.warning The :S modifier fails for a short match anchored at the end.
-.endif
-.if ${WORDS:S,s$,,} != "sequence of letter"
-.warning The :S modifier fails to replace one occurrence per word.
-.endif
-.if ${WORDS:S,of$,,} != "sequences letters"
-.warning The :S modifier fails for an exact match anchored at the end.
-.endif
-.if ${WORDS:S,eof$,,} != ${WORDS}
-.warning The :S modifier matches a too long pattern anchored at the end.
-.endif
-.if ${WORDS:S,^of$,,} != "sequences letters"
-.warning The :S modifier does not match a word anchored at both ends.
-.endif
-.if ${WORDS:S,^o$,,} != ${WORDS}
-.warning The :S modifier matches a prefix anchored at both ends.
-.endif
-.if ${WORDS:S,^f$,,} != ${WORDS}
-.warning The :S modifier matches a suffix anchored at both ends.
-.endif
-.if ${WORDS:S,^eof$,,} != ${WORDS}
-.warning The :S modifier matches a too long prefix anchored at both ends.
-.endif
-.if ${WORDS:S,^office$,,} != ${WORDS}
-.warning The :S modifier matches a too long suffix anchored at both ends.
-.endif
-
-mod-subst:
- @echo $@:
- @echo :${:Ua b b c:S,a b,,:Q}:
- @echo :${:Ua b b c:S,a b,,1:Q}:
- @echo :${:Ua b b c:S,a b,,W:Q}:
- @echo :${:Ua b b c:S,b,,g:Q}:
- @echo :${:U1 2 3 1 2 3:S,1 2,___,Wg:S,_,x,:Q}:
- @echo ${:U12345:S,,sep,g:Q}
-
-# The :S and :C modifiers accept an arbitrary character as the delimiter,
-# including characters that are otherwise used as escape characters or
-# interpreted in a special way. This can be used to confuse humans.
-mod-subst-delimiter:
- @echo $@:
- @echo ${:U1 2 3:S 2 two :Q} horizontal tabulator
- @echo ${:U1 2 3:S 2 two :Q} space
- @echo ${:U1 2 3:S!2!two!:Q} exclamation mark
- @echo ${:U1 2 3:S"2"two":Q} double quotes
- # In shell command lines, the hash does not need to be escaped.
- # It needs to be escaped in variable assignment lines though.
- @echo ${:U1 2 3:S#2#two#:Q} hash
- @echo ${:U1 2 3:S$2$two$:Q} dollar
- @echo ${:U1 2 3:S%2%two%:Q} percent
- @echo ${:U1 2 3:S'2'two':Q} apostrophe
- @echo ${:U1 2 3:S(2(two(:Q} opening parenthesis
- @echo ${:U1 2 3:S)2)two):Q} closing parenthesis
- @echo ${:U1 2 3:S121two1:Q} digit
- @echo ${:U1 2 3:S:2:two::Q} colon
- @echo ${:U1 2 3:S<2<two<:Q} less than sign
- @echo ${:U1 2 3:S=2=two=:Q} equal sign
- @echo ${:U1 2 3:S>2>two>:Q} greater than sign
- @echo ${:U1 2 3:S?2?two?:Q} question mark
- @echo ${:U1 2 3:S@2@two@:Q} at
- @echo ${:U1 2 3:Sa2atwoa:Q} letter
- @echo ${:U1 2 3:S[2[two[:Q} opening bracket
- @echo ${:U1 2 3:S\2\two\:Q} backslash
- @echo ${:U1 2 3:S]2]two]:Q} closing bracket
- @echo ${:U1 2 3:S^2^two^:Q} caret
- @echo ${:U1 2 3:S{2{two{:Q} opening brace
- @echo ${:U1 2 3:S|2|two|:Q} vertical line
- @echo ${:U1 2 3:S}2}two}:Q} closing brace
- @echo ${:U1 2 3:S~2~two~:Q} tilde
-
-# The :S and :C modifiers can be chained without a separating ':'.
-# This is not documented in the manual page.
-# It works because ApplyModifier_Subst scans for the known modifiers g1W
-# and then just returns to ApplyModifiers. There, the colon is optionally
-# skipped (see the *st.next == ':' at the end of the loop).
-#
-# Most other modifiers cannot be chained since their parsers skip until
-# the next ':' or '}' or ')'.
-mod-subst-chain:
- @echo $@:
- @echo ${:Ua b c:S,a,A,S,b,B,}.
- # There is no 'i' modifier for the :S or :C modifiers.
- # The error message is "make: Unknown modifier 'i'", which is
- # kind of correct, although it is mixing the terms for variable
- # modifiers with the matching modifiers.
- @echo ${:Uvalue:S,a,x,i}.
-
-mod-regex:
- @echo $@:
- @echo :${:Ua b b c:C,a b,,:Q}:
- @echo :${:Ua b b c:C,a b,,1:Q}:
- @echo :${:Ua b b c:C,a b,,W:Q}:
- @echo :${:Uword1 word2:C,****,____,g:C,word,____,:Q}:
- @echo :${:Ua b b c:C,b,,g:Q}:
- @echo :${:U1 2 3 1 2 3:C,1 2,___,Wg:C,_,x,:Q}:
-
-# In the :@ modifier, the name of the loop variable can even be generated
-# dynamically. There's no practical use-case for this, and hopefully nobody
-# will ever depend on this, but technically it's possible.
-# Therefore, in -dL mode, this is forbidden, see lint.mk.
-mod-loop-varname:
- @echo :${:Uone two three:@${:Ubar:S,b,v,}@+${var}+@:Q}:
- # ":::" is a very creative variable name, unlikely in practice
- # The expression ${\:\:\:} would not work since backslashes can only
- # be escaped in the modifiers, but not in the variable name.
- @echo :${:U1 2 3:@:::@x${${:U\:\:\:}}y@}:
- # "@@" is another creative variable name.
- @echo :${:U1 2 3:@\@\@@x${@@}y@}:
- # Even "@" works as a variable name since the variable is installed
- # in the "current" scope, which in this case is the one from the
- # target.
- @echo :$@: :${:U1 2 3:@\@@x${@}y@}: :$@:
- # In extreme cases, even the backslash can be used as variable name.
- # It needs to be doubled though.
- @echo :${:U1 2 3:@\\@x${${:Ux:S,x,\\,}}y@}:
-
-# The :@ modifier resolves the variables a little more often than expected.
-# In particular, it resolves _all_ variables from the context, and not only
-# the loop variable (in this case v).
-#
-# The d means direct reference, the i means indirect reference.
-RESOLVE= ${RES1} $${RES1}
-RES1= 1d${RES2} 1i$${RES2}
-RES2= 2d${RES3} 2i$${RES3}
-RES3= 3
-
-mod-loop-resolve:
- @echo $@:${RESOLVE:@v@w${v}w@:Q}:
-
-# Until 2020-07-20, the variable name of the :@ modifier could end with one
-# or two dollar signs, which were silently ignored.
-# There's no point in allowing a dollar sign in that position.
-mod-loop-varname-dollar:
- @echo $@:${1 2 3:L:@v$@($v)@:Q}.
- @echo $@:${1 2 3:L:@v$$@($v)@:Q}.
- @echo $@:${1 2 3:L:@v$$$@($v)@:Q}.
-
-# No matter how many dollar characters there are, they all get merged
-# into a single dollar by the :S modifier.
-#
-# As of 2020-08-09, this is because ParseModifierPart sees a '$' and
-# calls Var_Parse to expand the variable. In all other places, the "$$"
-# is handled outside of Var_Parse. Var_Parse therefore considers "$$"
-# one of the "really stupid names", skips the first dollar, and parsing
-# continues with the next character. This repeats for the other dollar
-# signs, except the one before the delimiter. That one is handled by
-# the code that optionally interprets the '$' as the end-anchor in the
-# first part of the :S modifier. That code doesn't call Var_Parse but
-# simply copies the dollar to the result.
-mod-subst-dollar:
- @echo $@:${:U1:S,^,$,:Q}:
- @echo $@:${:U2:S,^,$$,:Q}:
- @echo $@:${:U3:S,^,$$$,:Q}:
- @echo $@:${:U4:S,^,$$$$,:Q}:
- @echo $@:${:U5:S,^,$$$$$,:Q}:
- @echo $@:${:U6:S,^,$$$$$$,:Q}:
- @echo $@:${:U7:S,^,$$$$$$$,:Q}:
- @echo $@:${:U8:S,^,$$$$$$$$,:Q}:
- @echo $@:${:U40:S,^,$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$,:Q}:
-# This generates no dollar at all:
- @echo $@:${:UU8:S,^,${:U$$$$$$$$},:Q}:
-# Here is an alternative way to generate dollar characters.
-# It's unexpectedly complicated though.
- @echo $@:${:U:range=5:ts\x24:C,[0-9],,g:Q}:
-# In modifiers, dollars are escaped using the backslash, not using another
-# dollar sign. Therefore, creating a dollar sign is pretty simple:
- @echo $@:${:Ugood3:S,^,\$\$\$,:Q}
-
-# Demonstrate that it is possible to generate dollar characters using the
-# :@ modifier.
-#
-# These are edge cases that could have resulted in a parse error as well
-# since the $@ at the end could have been interpreted as a variable, which
-# would mean a missing closing @ delimiter.
-mod-loop-dollar:
- @echo $@:${:U1:@word@${word}$@:Q}:
- @echo $@:${:U2:@word@$${word}$$@:Q}:
- @echo $@:${:U3:@word@$$${word}$$$@:Q}:
- @echo $@:${:U4:@word@$$$${word}$$$$@:Q}:
- @echo $@:${:U5:@word@$$$$${word}$$$$$@:Q}:
- @echo $@:${:U6:@word@$$$$$${word}$$$$$$@:Q}:
-
-mod-regex-limits:
- @echo $@:00-ok:${:U1 23 456:C,..,\0\0,:Q}
- @echo $@:11-missing:${:U1 23 456:C,..,\1\1,:Q}
- @echo $@:11-ok:${:U1 23 456:C,(.).,\1\1,:Q}
- @echo $@:22-missing:${:U1 23 456:C,..,\2\2,:Q}
- @echo $@:22-missing:${:U1 23 456:C,(.).,\2\2,:Q}
- @echo $@:22-ok:${:U1 23 456:C,(.)(.),\2\2,:Q}
- # The :C modifier only handles single-digit capturing groups,
- # which is more than enough for daily use.
- @echo $@:capture:${:UabcdefghijABCDEFGHIJrest:C,(.)(.)(.)(.)(.)(.)(.)(.)(.)(.)(.)(.)(.)(.)(.)(.)(.)(.)(.)(.),\9\8\7\6\5\4\3\2\1\0\10\11\12,}
-
-mod-regex-errors:
- @echo $@: ${UNDEF:Uvalue:C,[,,}
-
# Just a bit of basic code coverage for the obscure ::= assignment modifiers.
mod-assign:
@echo $@: ${1 2 3:L:@i@${FIRST::?=$i}@} first=${FIRST}.
Index: src/usr.bin/make/unit-tests/varmod-loop.exp
diff -u src/usr.bin/make/unit-tests/varmod-loop.exp:1.1 src/usr.bin/make/unit-tests/varmod-loop.exp:1.2
--- src/usr.bin/make/unit-tests/varmod-loop.exp:1.1 Sun Aug 16 12:07:51 2020
+++ src/usr.bin/make/unit-tests/varmod-loop.exp Sun Aug 16 12:30:45 2020
@@ -1 +1,16 @@
+:+one+ +two+ +three+:
+:x1y x2y x3y:
+:x1y x2y x3y:
+:mod-loop-varname: :x1y x2y x3y: ::
+:x1y x2y x3y:
+mod-loop-resolve:w1d2d3w w2i3w w1i2d3 2i${RES3}w w1d2d3 2i${RES3} 1i${RES2}w:
+mod-loop-varname-dollar:(1) (2) (3).
+mod-loop-varname-dollar:() () ().
+mod-loop-varname-dollar:() () ().
+mod-loop-dollar:1:
+mod-loop-dollar:${word}$:
+mod-loop-dollar:$3$:
+mod-loop-dollar:$${word}$$:
+mod-loop-dollar:$$5$$:
+mod-loop-dollar:$$${word}$$$:
exit status 0
Index: src/usr.bin/make/unit-tests/varmod-loop.mk
diff -u src/usr.bin/make/unit-tests/varmod-loop.mk:1.1 src/usr.bin/make/unit-tests/varmod-loop.mk:1.2
--- src/usr.bin/make/unit-tests/varmod-loop.mk:1.1 Sun Aug 16 12:07:51 2020
+++ src/usr.bin/make/unit-tests/varmod-loop.mk Sun Aug 16 12:30:45 2020
@@ -1,8 +1,63 @@
-# $NetBSD: varmod-loop.mk,v 1.1 2020/08/16 12:07:51 rillig Exp $
+# $NetBSD: varmod-loop.mk,v 1.2 2020/08/16 12:30:45 rillig Exp $
#
-# TODO: Description
+# Tests for the :@var@...${var}...@ variable modifier.
-# TODO: Implementation
+all: mod-loop-varname
+all: mod-loop-resolve
+all: mod-loop-varname-dollar
+all: mod-loop-dollar
-all:
- @:;
+# In the :@ modifier, the name of the loop variable can even be generated
+# dynamically. There's no practical use-case for this, and hopefully nobody
+# will ever depend on this, but technically it's possible.
+# Therefore, in -dL mode, this is forbidden, see lint.mk.
+mod-loop-varname:
+ @echo :${:Uone two three:@${:Ubar:S,b,v,}@+${var}+@:Q}:
+ # ":::" is a very creative variable name, unlikely in practice
+ # The expression ${\:\:\:} would not work since backslashes can only
+ # be escaped in the modifiers, but not in the variable name.
+ @echo :${:U1 2 3:@:::@x${${:U\:\:\:}}y@}:
+ # "@@" is another creative variable name.
+ @echo :${:U1 2 3:@\@\@@x${@@}y@}:
+ # Even "@" works as a variable name since the variable is installed
+ # in the "current" scope, which in this case is the one from the
+ # target.
+ @echo :$@: :${:U1 2 3:@\@@x${@}y@}: :$@:
+ # In extreme cases, even the backslash can be used as variable name.
+ # It needs to be doubled though.
+ @echo :${:U1 2 3:@\\@x${${:Ux:S,x,\\,}}y@}:
+
+# The :@ modifier resolves the variables a little more often than expected.
+# In particular, it resolves _all_ variables from the context, and not only
+# the loop variable (in this case v).
+#
+# The d means direct reference, the i means indirect reference.
+RESOLVE= ${RES1} $${RES1}
+RES1= 1d${RES2} 1i$${RES2}
+RES2= 2d${RES3} 2i$${RES3}
+RES3= 3
+
+mod-loop-resolve:
+ @echo $@:${RESOLVE:@v@w${v}w@:Q}:
+
+# Until 2020-07-20, the variable name of the :@ modifier could end with one
+# or two dollar signs, which were silently ignored.
+# There's no point in allowing a dollar sign in that position.
+mod-loop-varname-dollar:
+ @echo $@:${1 2 3:L:@v$@($v)@:Q}.
+ @echo $@:${1 2 3:L:@v$$@($v)@:Q}.
+ @echo $@:${1 2 3:L:@v$$$@($v)@:Q}.
+
+# Demonstrate that it is possible to generate dollar characters using the
+# :@ modifier.
+#
+# These are edge cases that could have resulted in a parse error as well
+# since the $@ at the end could have been interpreted as a variable, which
+# would mean a missing closing @ delimiter.
+mod-loop-dollar:
+ @echo $@:${:U1:@word@${word}$@:Q}:
+ @echo $@:${:U2:@word@$${word}$$@:Q}:
+ @echo $@:${:U3:@word@$$${word}$$$@:Q}:
+ @echo $@:${:U4:@word@$$$${word}$$$$@:Q}:
+ @echo $@:${:U5:@word@$$$$${word}$$$$$@:Q}:
+ @echo $@:${:U6:@word@$$$$$${word}$$$$$$@:Q}:
Index: src/usr.bin/make/unit-tests/varmod-subst-regex.exp
diff -u src/usr.bin/make/unit-tests/varmod-subst-regex.exp:1.1 src/usr.bin/make/unit-tests/varmod-subst-regex.exp:1.2
--- src/usr.bin/make/unit-tests/varmod-subst-regex.exp:1.1 Sun Aug 16 12:07:51 2020
+++ src/usr.bin/make/unit-tests/varmod-subst-regex.exp Sun Aug 16 12:30:45 2020
@@ -1 +1,30 @@
+mod-regex:
+:a b b c:
+:a b b c:
+: b c:
+make: Regex compilation error: (details omitted)
+:C,word,____,:Q}:
+:a c:
+:x__ 3 x__ 3:
+mod-regex-limits:00-ok:1 2323 45456
+make: No subexpression \1
+make: No subexpression \1
+make: No subexpression \1
+make: No subexpression \1
+mod-regex-limits:11-missing:1 6
+mod-regex-limits:11-ok:1 22 446
+make: No subexpression \2
+make: No subexpression \2
+make: No subexpression \2
+make: No subexpression \2
+mod-regex-limits:22-missing:1 6
+make: No subexpression \2
+make: No subexpression \2
+make: No subexpression \2
+make: No subexpression \2
+mod-regex-limits:22-missing:1 6
+mod-regex-limits:22-ok:1 33 556
+mod-regex-limits:capture:ihgfedcbaabcdefghijABCDEFGHIJa0a1a2rest
+make: Regex compilation error: (details omitted)
+mod-regex-errors:
exit status 0
Index: src/usr.bin/make/unit-tests/varmod-subst-regex.mk
diff -u src/usr.bin/make/unit-tests/varmod-subst-regex.mk:1.1 src/usr.bin/make/unit-tests/varmod-subst-regex.mk:1.2
--- src/usr.bin/make/unit-tests/varmod-subst-regex.mk:1.1 Sun Aug 16 12:07:51 2020
+++ src/usr.bin/make/unit-tests/varmod-subst-regex.mk Sun Aug 16 12:30:45 2020
@@ -1,8 +1,30 @@
-# $NetBSD: varmod-subst-regex.mk,v 1.1 2020/08/16 12:07:51 rillig Exp $
+# $NetBSD: varmod-subst-regex.mk,v 1.2 2020/08/16 12:30:45 rillig Exp $
#
-# TODO: Description
+# Tests for the :C,from,to, variable modifier.
-# TODO: Implementation
+all: mod-regex
+all: mod-regex-limits
+all: mod-regex-errors
-all:
- @:;
+mod-regex:
+ @echo $@:
+ @echo :${:Ua b b c:C,a b,,:Q}:
+ @echo :${:Ua b b c:C,a b,,1:Q}:
+ @echo :${:Ua b b c:C,a b,,W:Q}:
+ @echo :${:Uword1 word2:C,****,____,g:C,word,____,:Q}:
+ @echo :${:Ua b b c:C,b,,g:Q}:
+ @echo :${:U1 2 3 1 2 3:C,1 2,___,Wg:C,_,x,:Q}:
+
+mod-regex-limits:
+ @echo $@:00-ok:${:U1 23 456:C,..,\0\0,:Q}
+ @echo $@:11-missing:${:U1 23 456:C,..,\1\1,:Q}
+ @echo $@:11-ok:${:U1 23 456:C,(.).,\1\1,:Q}
+ @echo $@:22-missing:${:U1 23 456:C,..,\2\2,:Q}
+ @echo $@:22-missing:${:U1 23 456:C,(.).,\2\2,:Q}
+ @echo $@:22-ok:${:U1 23 456:C,(.)(.),\2\2,:Q}
+ # The :C modifier only handles single-digit capturing groups,
+ # which is more than enough for daily use.
+ @echo $@:capture:${:UabcdefghijABCDEFGHIJrest:C,(.)(.)(.)(.)(.)(.)(.)(.)(.)(.)(.)(.)(.)(.)(.)(.)(.)(.)(.)(.),\9\8\7\6\5\4\3\2\1\0\10\11\12,}
+
+mod-regex-errors:
+ @echo $@: ${UNDEF:Uvalue:C,[,,}
Index: src/usr.bin/make/unit-tests/varmod-subst.exp
diff -u src/usr.bin/make/unit-tests/varmod-subst.exp:1.1 src/usr.bin/make/unit-tests/varmod-subst.exp:1.2
--- src/usr.bin/make/unit-tests/varmod-subst.exp:1.1 Sun Aug 16 12:07:51 2020
+++ src/usr.bin/make/unit-tests/varmod-subst.exp Sun Aug 16 12:30:45 2020
@@ -1 +1,51 @@
+mod-subst:
+:a b b c:
+:a b b c:
+: b c:
+:a c:
+:x__ 3 x__ 3:
+12345
+mod-subst-delimiter:
+1 two 3 horizontal tabulator
+1 two 3 space
+1 two 3 exclamation mark
+1 two 3 double quotes
+1 two 3 hash
+1 two 3 dollar
+1 two 3 percent
+1 two 3 apostrophe
+1 two 3 opening parenthesis
+1 two 3 closing parenthesis
+1 two 3 digit
+1 two 3 colon
+1 two 3 less than sign
+1 two 3 equal sign
+1 two 3 greater than sign
+1 two 3 question mark
+1 two 3 at
+1 two 3 letter
+1 two 3 opening bracket
+1 two 3 backslash
+1 two 3 closing bracket
+1 two 3 caret
+1 two 3 opening brace
+1 two 3 vertical line
+1 two 3 closing brace
+1 two 3 tilde
+mod-subst-chain:
+A B c.
+make: Unknown modifier 'i'
+.
+mod-subst-dollar:$1:
+mod-subst-dollar:$2:
+mod-subst-dollar:$3:
+mod-subst-dollar:$4:
+mod-subst-dollar:$5:
+mod-subst-dollar:$6:
+mod-subst-dollar:$7:
+mod-subst-dollar:$8:
+mod-subst-dollar:$40:
+mod-subst-dollar:U8:
+mod-subst-dollar:$$$$:
+mod-subst-dollar:$$$good3
exit status 0
Index: src/usr.bin/make/unit-tests/varmod-subst.mk
diff -u src/usr.bin/make/unit-tests/varmod-subst.mk:1.1 src/usr.bin/make/unit-tests/varmod-subst.mk:1.2
--- src/usr.bin/make/unit-tests/varmod-subst.mk:1.1 Sun Aug 16 12:07:51 2020
+++ src/usr.bin/make/unit-tests/varmod-subst.mk Sun Aug 16 12:30:45 2020
@@ -1,8 +1,149 @@
-# $NetBSD: varmod-subst.mk,v 1.1 2020/08/16 12:07:51 rillig Exp $
+# $NetBSD: varmod-subst.mk,v 1.2 2020/08/16 12:30:45 rillig Exp $
#
-# TODO: Description
+# Tests for the :S,from,to, variable modifier.
-# TODO: Implementation
+all: mod-subst
+all: mod-subst-delimiter
+all: mod-subst-chain
+all: mod-subst-dollar
-all:
- @:;
+WORDS= sequences of letters
+.if ${WORDS:S,,,} != ${WORDS}
+.warning The empty pattern matches something.
+.endif
+.if ${WORDS:S,e,*,1} != "s*quences of letters"
+.warning The :S modifier flag '1' is not applied exactly once.
+.endif
+.if ${WORDS:S,e,*,} != "s*quences of l*tters"
+.warning The :S modifier does not replace every first match per word.
+.endif
+.if ${WORDS:S,e,*,g} != "s*qu*nc*s of l*tt*rs"
+.warning The :S modifier flag 'g' does not replace every occurrence.
+.endif
+.if ${WORDS:S,^sequ,occurr,} != "occurrences of letters"
+.warning The :S modifier fails for a short match anchored at the start.
+.endif
+.if ${WORDS:S,^of,with,} != "sequences with letters"
+.warning The :S modifier fails for an exact match anchored at the start.
+.endif
+.if ${WORDS:S,^office,does not match,} != ${WORDS}
+.warning The :S modifier matches a too long pattern anchored at the start.
+.endif
+.if ${WORDS:S,f$,r,} != "sequences or letters"
+.warning The :S modifier fails for a short match anchored at the end.
+.endif
+.if ${WORDS:S,s$,,} != "sequence of letter"
+.warning The :S modifier fails to replace one occurrence per word.
+.endif
+.if ${WORDS:S,of$,,} != "sequences letters"
+.warning The :S modifier fails for an exact match anchored at the end.
+.endif
+.if ${WORDS:S,eof$,,} != ${WORDS}
+.warning The :S modifier matches a too long pattern anchored at the end.
+.endif
+.if ${WORDS:S,^of$,,} != "sequences letters"
+.warning The :S modifier does not match a word anchored at both ends.
+.endif
+.if ${WORDS:S,^o$,,} != ${WORDS}
+.warning The :S modifier matches a prefix anchored at both ends.
+.endif
+.if ${WORDS:S,^f$,,} != ${WORDS}
+.warning The :S modifier matches a suffix anchored at both ends.
+.endif
+.if ${WORDS:S,^eof$,,} != ${WORDS}
+.warning The :S modifier matches a too long prefix anchored at both ends.
+.endif
+.if ${WORDS:S,^office$,,} != ${WORDS}
+.warning The :S modifier matches a too long suffix anchored at both ends.
+.endif
+
+mod-subst:
+ @echo $@:
+ @echo :${:Ua b b c:S,a b,,:Q}:
+ @echo :${:Ua b b c:S,a b,,1:Q}:
+ @echo :${:Ua b b c:S,a b,,W:Q}:
+ @echo :${:Ua b b c:S,b,,g:Q}:
+ @echo :${:U1 2 3 1 2 3:S,1 2,___,Wg:S,_,x,:Q}:
+ @echo ${:U12345:S,,sep,g:Q}
+
+# The :S and :C modifiers accept an arbitrary character as the delimiter,
+# including characters that are otherwise used as escape characters or
+# interpreted in a special way. This can be used to confuse humans.
+mod-subst-delimiter:
+ @echo $@:
+ @echo ${:U1 2 3:S 2 two :Q} horizontal tabulator
+ @echo ${:U1 2 3:S 2 two :Q} space
+ @echo ${:U1 2 3:S!2!two!:Q} exclamation mark
+ @echo ${:U1 2 3:S"2"two":Q} double quotes
+ # In shell command lines, the hash does not need to be escaped.
+ # It needs to be escaped in variable assignment lines though.
+ @echo ${:U1 2 3:S#2#two#:Q} hash
+ @echo ${:U1 2 3:S$2$two$:Q} dollar
+ @echo ${:U1 2 3:S%2%two%:Q} percent
+ @echo ${:U1 2 3:S'2'two':Q} apostrophe
+ @echo ${:U1 2 3:S(2(two(:Q} opening parenthesis
+ @echo ${:U1 2 3:S)2)two):Q} closing parenthesis
+ @echo ${:U1 2 3:S121two1:Q} digit
+ @echo ${:U1 2 3:S:2:two::Q} colon
+ @echo ${:U1 2 3:S<2<two<:Q} less than sign
+ @echo ${:U1 2 3:S=2=two=:Q} equal sign
+ @echo ${:U1 2 3:S>2>two>:Q} greater than sign
+ @echo ${:U1 2 3:S?2?two?:Q} question mark
+ @echo ${:U1 2 3:S@2@two@:Q} at
+ @echo ${:U1 2 3:Sa2atwoa:Q} letter
+ @echo ${:U1 2 3:S[2[two[:Q} opening bracket
+ @echo ${:U1 2 3:S\2\two\:Q} backslash
+ @echo ${:U1 2 3:S]2]two]:Q} closing bracket
+ @echo ${:U1 2 3:S^2^two^:Q} caret
+ @echo ${:U1 2 3:S{2{two{:Q} opening brace
+ @echo ${:U1 2 3:S|2|two|:Q} vertical line
+ @echo ${:U1 2 3:S}2}two}:Q} closing brace
+ @echo ${:U1 2 3:S~2~two~:Q} tilde
+
+# The :S and :C modifiers can be chained without a separating ':'.
+# This is not documented in the manual page.
+# It works because ApplyModifier_Subst scans for the known modifiers g1W
+# and then just returns to ApplyModifiers. There, the colon is optionally
+# skipped (see the *st.next == ':' at the end of the loop).
+#
+# Most other modifiers cannot be chained since their parsers skip until
+# the next ':' or '}' or ')'.
+mod-subst-chain:
+ @echo $@:
+ @echo ${:Ua b c:S,a,A,S,b,B,}.
+ # There is no 'i' modifier for the :S or :C modifiers.
+ # The error message is "make: Unknown modifier 'i'", which is
+ # kind of correct, although it is mixing the terms for variable
+ # modifiers with the matching modifiers.
+ @echo ${:Uvalue:S,a,x,i}.
+
+# No matter how many dollar characters there are, they all get merged
+# into a single dollar by the :S modifier.
+#
+# As of 2020-08-09, this is because ParseModifierPart sees a '$' and
+# calls Var_Parse to expand the variable. In all other places, the "$$"
+# is handled outside of Var_Parse. Var_Parse therefore considers "$$"
+# one of the "really stupid names", skips the first dollar, and parsing
+# continues with the next character. This repeats for the other dollar
+# signs, except the one before the delimiter. That one is handled by
+# the code that optionally interprets the '$' as the end-anchor in the
+# first part of the :S modifier. That code doesn't call Var_Parse but
+# simply copies the dollar to the result.
+mod-subst-dollar:
+ @echo $@:${:U1:S,^,$,:Q}:
+ @echo $@:${:U2:S,^,$$,:Q}:
+ @echo $@:${:U3:S,^,$$$,:Q}:
+ @echo $@:${:U4:S,^,$$$$,:Q}:
+ @echo $@:${:U5:S,^,$$$$$,:Q}:
+ @echo $@:${:U6:S,^,$$$$$$,:Q}:
+ @echo $@:${:U7:S,^,$$$$$$$,:Q}:
+ @echo $@:${:U8:S,^,$$$$$$$$,:Q}:
+ @echo $@:${:U40:S,^,$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$,:Q}:
+# This generates no dollar at all:
+ @echo $@:${:UU8:S,^,${:U$$$$$$$$},:Q}:
+# Here is an alternative way to generate dollar characters.
+# It's unexpectedly complicated though.
+ @echo $@:${:U:range=5:ts\x24:C,[0-9],,g:Q}:
+# In modifiers, dollars are escaped using the backslash, not using another
+# dollar sign. Therefore, creating a dollar sign is pretty simple:
+ @echo $@:${:Ugood3:S,^,\$\$\$,:Q}