Thu Sep 3 18:52:37 2020 UTC ()
make(1): add tests for the :D and :U modifiers

This prepares a refactoring for ApplyModifier_Defined.


(rillig)
diff -r1.3 -r1.4 src/usr.bin/make/unit-tests/varmod-defined.mk
diff -r1.3 -r1.4 src/usr.bin/make/unit-tests/varmod-undefined.mk

cvs diff -r1.3 -r1.4 src/usr.bin/make/unit-tests/varmod-defined.mk (expand / switch to unified diff)

--- src/usr.bin/make/unit-tests/varmod-defined.mk 2020/08/25 21:58:08 1.3
+++ src/usr.bin/make/unit-tests/varmod-defined.mk 2020/09/03 18:52:36 1.4
@@ -1,28 +1,67 @@ @@ -1,28 +1,67 @@
1# $NetBSD: varmod-defined.mk,v 1.3 2020/08/25 21:58:08 rillig Exp $ 1# $NetBSD: varmod-defined.mk,v 1.4 2020/09/03 18:52:36 rillig Exp $
2# 2#
3# Tests for the :D variable modifier, which returns the given string 3# Tests for the :D variable modifier, which returns the given string
4# if the variable is defined. It is closely related to the :U modifier. 4# if the variable is defined. It is closely related to the :U modifier.
5 5
6DEF= defined 6DEF= defined
7.undef UNDEF 7.undef UNDEF
8 8
9# Since DEF is defined, the value of the expression is "value", not 9# Since DEF is defined, the value of the expression is "value", not
10# "defined". 10# "defined".
11# 11#
12.if ${DEF:Dvalue} != "value" 12.if ${DEF:Dvalue} != "value"
13.error 13.error
14.endif 14.endif
15 15
16# Since UNDEF is not defined, the "value" is ignored. Instead of leaving the 16# Since UNDEF is not defined, the "value" is ignored. Instead of leaving the
17# expression undefined, it is set to "", exactly to allow the expression to 17# expression undefined, it is set to "", exactly to allow the expression to
18# be used in .if conditions. In this place, other undefined expressions 18# be used in .if conditions. In this place, other undefined expressions
19# would generate an error message. 19# would generate an error message.
20# XXX: Ideally the error message would be "undefined variable", but as of 20# XXX: Ideally the error message would be "undefined variable", but as of
21# 2020-08-25 it is "Malformed conditional". 21# 2020-08-25 it is "Malformed conditional".
22# 22#
23.if ${UNDEF:Dvalue} != "" 23.if ${UNDEF:Dvalue} != ""
24.error 24.error
25.endif 25.endif
26 26
 27# The modifier text may contain plain text as well as expressions.
 28#
 29.if ${DEF:D<${DEF}>} != "<defined>"
 30. error
 31.endif
 32
 33# Special characters that would be interpreted differently can be escaped.
 34# These are '}' (the closing character of the expression), ':', '$' and '\'.
 35# Any other backslash sequences are preserved.
 36#
 37# The escaping rules for string literals in conditions are completely
 38# different though. There, any character may be escaped using a backslash.
 39#
 40.if ${DEF:D \} \: \$ \\ \) \n } != " } : \$ \\ \\) \\n "
 41. error
 42.endif
 43
 44# Like in several other places in variable expressions, when
 45# ApplyModifier_Defined calls Var_Parse, double dollars lead to a parse
 46# error that is silently ignored. This makes all dollar signs disappear,
 47# except for the last, which is a well-formed variable expression.
 48#
 49.if ${DEF:D$$$$$${DEF}} != "defined"
 50. error
 51.endif
 52
 53# Any other text is written without any further escaping. In contrast
 54# to the :M modifier, parentheses and braces do not need to be nested.
 55# Instead, the :D modifier is implemented sanely by parsing nested
 56# expressions as such, without trying any shortcuts. See ApplyModifier_Match
 57# for an inferior variant.
 58#
 59.if ${DEF:D!&((((} != "!&(((("
 60. error
 61.endif
 62
 63# TODO: Add more tests for parsing the plain text part, to cover each branch
 64# of ApplyModifier_Defined.
 65
27all: 66all:
28 @:; 67 @:;

cvs diff -r1.3 -r1.4 src/usr.bin/make/unit-tests/varmod-undefined.mk (expand / switch to unified diff)

--- src/usr.bin/make/unit-tests/varmod-undefined.mk 2020/08/23 20:49:33 1.3
+++ src/usr.bin/make/unit-tests/varmod-undefined.mk 2020/09/03 18:52:36 1.4
@@ -1,14 +1,14 @@ @@ -1,14 +1,14 @@
1# $NetBSD: varmod-undefined.mk,v 1.3 2020/08/23 20:49:33 rillig Exp $ 1# $NetBSD: varmod-undefined.mk,v 1.4 2020/09/03 18:52:36 rillig Exp $
2# 2#
3# Tests for the :U variable modifier, which returns the given string 3# Tests for the :U variable modifier, which returns the given string
4# if the variable is undefined. 4# if the variable is undefined.
5# 5#
6# The pattern ${:Uword} is heavily used when expanding .for loops. 6# The pattern ${:Uword} is heavily used when expanding .for loops.
7 7
8# This is how an expanded .for loop looks like. 8# This is how an expanded .for loop looks like.
9# .for word in one 9# .for word in one
10# . if ${word} != one 10# . if ${word} != one
11# . error ${word} 11# . error ${word}
12# . endif 12# . endif
13# .endfor 13# .endfor
14 14
@@ -36,20 +36,30 @@ @@ -36,20 +36,30 @@
36# The escaping rules for the :U modifier (left-hand side) and condition 36# The escaping rules for the :U modifier (left-hand side) and condition
37# string literals (right-hand side) are completely different. 37# string literals (right-hand side) are completely different.
38# 38#
39# In the :U modifier, the backslash only escapes very few characters, all 39# In the :U modifier, the backslash only escapes very few characters, all
40# other backslashes are retained. 40# other backslashes are retained.
41# 41#
42# In condition string literals, the backslash always escapes the following 42# In condition string literals, the backslash always escapes the following
43# character, no matter whether it would be necessary or not. 43# character, no matter whether it would be necessary or not.
44# 44#
45# In both contexts, \n is an escaped letter n, not a newline; that's what 45# In both contexts, \n is an escaped letter n, not a newline; that's what
46# the .newline variable is for. 46# the .newline variable is for.
47# 47#
48# Whitespace at the edges is preserved, on both sides of the comparison. 48# Whitespace at the edges is preserved, on both sides of the comparison.
49 49#
50.if ${:U \: \} \$ \\ \a \b \n } != " : } \$ \\ \\a \\b \\n " 50.if ${:U \: \} \$ \\ \a \b \n } != " : } \$ \\ \\a \\b \\n "
51.error 51.error
52.endif 52.endif
53 53
 54# Even after the :U modifier has been applied, the expression still remembers
 55# that it originated from an undefined variable, and the :U modifier can
 56# be used to overwrite the value of the expression.
 57#
 58.if ${UNDEF:Uvalue:S,a,X,} != "vXlue"
 59. error
 60.elif ${UNDEF:Uvalue:S,a,X,:Uwas undefined} != "was undefined"
 61. error
 62.endif
 63
54all: 64all:
55 @:; 65 @:;