make(1): add tests for the :D and :U modifiers This prepares a refactoring for ApplyModifier_Defined.diff -r1.3 -r1.4 src/usr.bin/make/unit-tests/varmod-defined.mk
(rillig)
--- 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 | |||
6 | DEF= defined | 6 | DEF= 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 | ||||
27 | all: | 66 | all: | |
28 | @:; | 67 | @:; |
--- 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 | ||||
54 | all: | 64 | all: | |
55 | @:; | 65 | @:; |