| @@ -1,211 +1,230 @@ | | | @@ -1,211 +1,230 @@ |
1 | # $NetBSD: varmod-sysv.mk,v 1.9 2020/10/31 11:06:24 rillig Exp $ | | 1 | # $NetBSD: varmod-sysv.mk,v 1.10 2020/11/01 22:10:57 rillig Exp $ |
2 | # | | 2 | # |
3 | # Tests for the ${VAR:from=to} variable modifier, which replaces the suffix | | 3 | # Tests for the ${VAR:from=to} variable modifier, which replaces the suffix |
4 | # "from" with "to". It can also use '%' as a wildcard. | | 4 | # "from" with "to". It can also use '%' as a wildcard. |
5 | # | | 5 | # |
6 | # This modifier is applied when the other modifiers don't match exactly. | | 6 | # This modifier is applied when the other modifiers don't match exactly. |
7 | # | | 7 | # |
8 | # See ApplyModifier_SysV. | | 8 | # See ApplyModifier_SysV. |
9 | | | 9 | |
10 | # A typical use case for the :from=to modifier is conversion of filename | | 10 | # A typical use case for the :from=to modifier is conversion of filename |
11 | # extensions. | | 11 | # extensions. |
12 | .if ${src.c:L:.c=.o} != "src.o" | | 12 | .if ${src.c:L:.c=.o} != "src.o" |
13 | . error | | 13 | . error |
14 | .endif | | 14 | .endif |
15 | | | 15 | |
16 | # The modifier applies to each word on its own. | | 16 | # The modifier applies to each word on its own. |
17 | .if ${one.c two.c three.c:L:.c=.o} != "one.o two.o three.o" | | 17 | .if ${one.c two.c three.c:L:.c=.o} != "one.o two.o three.o" |
18 | . error | | 18 | . error |
19 | .endif | | 19 | .endif |
20 | | | 20 | |
21 | # Words that don't match the pattern are passed unmodified. | | 21 | # Words that don't match the pattern are passed unmodified. |
22 | .if ${src.c src.h:L:.c=.o} != "src.o src.h" | | 22 | .if ${src.c src.h:L:.c=.o} != "src.o src.h" |
23 | . error | | 23 | . error |
24 | .endif | | 24 | .endif |
25 | | | 25 | |
26 | # The :from=to modifier is therefore often combined with the :M modifier. | | 26 | # The :from=to modifier is therefore often combined with the :M modifier. |
27 | .if ${src.c src.h:L:M*.c:.c=.o} != "src.o" | | 27 | .if ${src.c src.h:L:M*.c:.c=.o} != "src.o" |
28 | . error | | 28 | . error |
29 | .endif | | 29 | .endif |
30 | | | 30 | |
31 | # Another use case for the :from=to modifier is to append a suffix to each | | 31 | # Another use case for the :from=to modifier is to append a suffix to each |
32 | # word. In this case, the "from" string is empty, therefore it always | | 32 | # word. In this case, the "from" string is empty, therefore it always |
33 | # matches. The same effect can be achieved with the :S,$,teen, modifier. | | 33 | # matches. The same effect can be achieved with the :S,$,teen, modifier. |
34 | .if ${four six seven nine:L:=teen} != "fourteen sixteen seventeen nineteen" | | 34 | .if ${four six seven nine:L:=teen} != "fourteen sixteen seventeen nineteen" |
35 | . error | | 35 | . error |
36 | .endif | | 36 | .endif |
37 | | | 37 | |
38 | # The :from=to modifier can also be used to surround each word by strings. | | 38 | # The :from=to modifier can also be used to surround each word by strings. |
39 | # It might be tempting to use this for enclosing a string in quotes for the | | 39 | # It might be tempting to use this for enclosing a string in quotes for the |
40 | # shell, but that's the job of the :Q modifier. | | 40 | # shell, but that's the job of the :Q modifier. |
41 | .if ${one two three:L:%=(%)} != "(one) (two) (three)" | | 41 | .if ${one two three:L:%=(%)} != "(one) (two) (three)" |
42 | . error | | 42 | . error |
43 | .endif | | 43 | .endif |
44 | | | 44 | |
45 | # When the :from=to modifier is parsed, it lasts until the closing brace | | 45 | # When the :from=to modifier is parsed, it lasts until the closing brace |
46 | # or parenthesis. The :Q in the below expression may look like a modifier | | 46 | # or parenthesis. The :Q in the below expression may look like a modifier |
47 | # but isn't. It is part of the replacement string. | | 47 | # but isn't. It is part of the replacement string. |
48 | .if ${a b c d e:L:%a=x:Q} != "x:Q b c d e" | | 48 | .if ${a b c d e:L:%a=x:Q} != "x:Q b c d e" |
49 | . error | | 49 | . error |
50 | .endif | | 50 | .endif |
51 | | | 51 | |
52 | # In the :from=to modifier, both parts can contain variable expressions. | | 52 | # In the :from=to modifier, both parts can contain variable expressions. |
53 | .if ${one two:L:${:Uone}=${:U1}} != "1 two" | | 53 | .if ${one two:L:${:Uone}=${:U1}} != "1 two" |
54 | . error | | 54 | . error |
55 | .endif | | 55 | .endif |
56 | | | 56 | |
57 | # In the :from=to modifier, the "from" part is expanded exactly once. | | 57 | # In the :from=to modifier, the "from" part is expanded exactly once. |
58 | .if ${:U\$ \$\$ \$\$\$\$:${:U\$\$\$\$}=4} != "\$ \$\$ 4" | | 58 | .if ${:U\$ \$\$ \$\$\$\$:${:U\$\$\$\$}=4} != "\$ \$\$ 4" |
59 | . error | | 59 | . error |
60 | .endif | | 60 | .endif |
61 | | | 61 | |
62 | # In the :from=to modifier, the "to" part is expanded exactly twice. | | 62 | # In the :from=to modifier, the "to" part is expanded exactly twice. |
63 | # XXX: The right-hand side should be expanded only once. | | 63 | # XXX: The right-hand side should be expanded only once. |
64 | # XXX: It's hard to get the escaping correct here, and to read that. | | 64 | # XXX: It's hard to get the escaping correct here, and to read that. |
65 | # XXX: It's not intuitive why the closing brace must be escaped but not | | 65 | # XXX: It's not intuitive why the closing brace must be escaped but not |
66 | # the opening brace. | | 66 | # the opening brace. |
67 | .if ${:U1 2 4:4=${:Uonce\${\:Utwice\}}} != "1 2 oncetwice" | | 67 | .if ${:U1 2 4:4=${:Uonce\${\:Utwice\}}} != "1 2 oncetwice" |
68 | . error | | 68 | . error |
69 | .endif | | 69 | .endif |
70 | | | 70 | |
71 | # The replacement string can contain spaces, thereby changing the number | | 71 | # The replacement string can contain spaces, thereby changing the number |
72 | # of words in the variable expression. | | 72 | # of words in the variable expression. |
73 | .if ${In:L:%=% ${:Uthe Sun}} != "In the Sun" | | 73 | .if ${In:L:%=% ${:Uthe Sun}} != "In the Sun" |
74 | . error | | 74 | . error |
75 | .endif | | 75 | .endif |
76 | | | 76 | |
77 | # If the variable is empty, it is debatable whether it consists of a single | | 77 | # If the variable is empty, it is debatable whether it consists of a single |
78 | # empty word, or no word at all. The :from=to modifier treats it as no | | 78 | # empty word, or no word at all. The :from=to modifier treats it as no |
79 | # word at all. | | 79 | # word at all. |
80 | .if ${:L:=suffix} != "" | | 80 | .if ${:L:=suffix} != "" |
81 | . error | | 81 | . error |
82 | .endif | | 82 | .endif |
83 | | | 83 | |
84 | # Before 2020-07-19, an ampersand could be used in the replacement part | | 84 | # Before 2020-07-19, an ampersand could be used in the replacement part |
85 | # of a SysV substitution modifier, and it was replaced with the whole match, | | 85 | # of a SysV substitution modifier, and it was replaced with the whole match, |
86 | # just like in the :S modifier. | | 86 | # just like in the :S modifier. |
87 | # | | 87 | # |
88 | # This was probably a copy-and-paste mistake since the code for the SysV | | 88 | # This was probably a copy-and-paste mistake since the code for the SysV |
89 | # modifier looked a lot like the code for the :S and :C modifiers. | | 89 | # modifier looked a lot like the code for the :S and :C modifiers. |
90 | # The ampersand is not mentioned in the manual page. | | 90 | # The ampersand is not mentioned in the manual page. |
91 | .if ${a.bcd.e:L:a.%=%} != "bcd.e" | | 91 | .if ${a.bcd.e:L:a.%=%} != "bcd.e" |
92 | . error | | 92 | . error |
93 | .endif | | 93 | .endif |
94 | # Before 2020-07-19, the result of the expression was "a.bcd.e". | | 94 | # Before 2020-07-19, the result of the expression was "a.bcd.e". |
95 | .if ${a.bcd.e:L:a.%=&} != "&" | | 95 | .if ${a.bcd.e:L:a.%=&} != "&" |
96 | . error | | 96 | . error |
97 | .endif | | 97 | .endif |
98 | | | 98 | |
99 | # Before 2020-07-20, when a SysV modifier was parsed, a single dollar | | 99 | # Before 2020-07-20, when a SysV modifier was parsed, a single dollar |
100 | # before the '=' was parsed (but not interpreted) as an anchor. | | 100 | # before the '=' was parsed (but not interpreted) as an anchor. |
101 | # Parsing something without then evaluating it accordingly doesn't make | | 101 | # Parsing something without then evaluating it accordingly doesn't make |
102 | # sense. | | 102 | # sense. |
103 | .if ${value:L:e$=x} != "value" | | 103 | .if ${value:L:e$=x} != "value" |
104 | . error | | 104 | . error |
105 | .endif | | 105 | .endif |
106 | # Before 2020-07-20, the modifier ":e$=x" was parsed as having a left-hand | | 106 | # Before 2020-07-20, the modifier ":e$=x" was parsed as having a left-hand |
107 | # side "e" and a right-hand side "x". The dollar was parsed (but not | | 107 | # side "e" and a right-hand side "x". The dollar was parsed (but not |
108 | # interpreted) as 'anchor at the end'. Therefore the modifier was equivalent | | 108 | # interpreted) as 'anchor at the end'. Therefore the modifier was equivalent |
109 | # to ":e=x", which doesn't match the string "value$". Therefore the whole | | 109 | # to ":e=x", which doesn't match the string "value$". Therefore the whole |
110 | # expression evaluated to "value$". | | 110 | # expression evaluated to "value$". |
111 | .if ${${:Uvalue\$}:L:e$=x} != "valux" | | 111 | .if ${${:Uvalue\$}:L:e$=x} != "valux" |
112 | . error | | 112 | . error |
113 | .endif | | 113 | .endif |
114 | .if ${value:L:e=x} != "valux" | | 114 | .if ${value:L:e=x} != "valux" |
115 | . error | | 115 | . error |
116 | .endif | | 116 | .endif |
117 | | | 117 | |
118 | # Words that don't match are copied unmodified. | | 118 | # Words that don't match are copied unmodified. |
119 | .if ${:Ufile.c file.h:%.c=%.cpp} != "file.cpp file.h" | | 119 | .if ${:Ufile.c file.h:%.c=%.cpp} != "file.cpp file.h" |
120 | . error | | 120 | . error |
121 | .endif | | 121 | .endif |
122 | | | 122 | |
123 | # The % placeholder can be anywhere in the string, it doesn't have to be at | | 123 | # The % placeholder can be anywhere in the string, it doesn't have to be at |
124 | # the beginning of the pattern. | | 124 | # the beginning of the pattern. |
125 | .if ${:Ufile.c other.c:file.%=renamed.%} != "renamed.c other.c" | | 125 | .if ${:Ufile.c other.c:file.%=renamed.%} != "renamed.c other.c" |
126 | . error | | 126 | . error |
127 | .endif | | 127 | .endif |
128 | | | 128 | |
129 | # It's also possible to modify each word by replacing the prefix and adding | | 129 | # It's also possible to modify each word by replacing the prefix and adding |
130 | # a suffix. | | 130 | # a suffix. |
131 | .if ${one two:L:o%=a%w} != "anew two" | | 131 | .if ${one two:L:o%=a%w} != "anew two" |
132 | . error | | 132 | . error |
133 | .endif | | 133 | .endif |
134 | | | 134 | |
135 | # Each word gets the suffix "X" appended. | | 135 | # Each word gets the suffix "X" appended. |
136 | .if ${one two:L:=X} != "oneX twoX" | | 136 | .if ${one two:L:=X} != "oneX twoX" |
137 | . error | | 137 | . error |
138 | .endif | | 138 | .endif |
139 | | | 139 | |
140 | # The suffix "o" is replaced with "X". | | 140 | # The suffix "o" is replaced with "X". |
141 | .if ${one two:L:o=X} != "one twX" | | 141 | .if ${one two:L:o=X} != "one twX" |
142 | . error | | 142 | . error |
143 | .endif | | 143 | .endif |
144 | | | 144 | |
145 | # The suffix "o" is replaced with nothing. | | 145 | # The suffix "o" is replaced with nothing. |
146 | .if ${one two:L:o=} != "one tw" | | 146 | .if ${one two:L:o=} != "one tw" |
147 | . error | | 147 | . error |
148 | .endif | | 148 | .endif |
149 | | | 149 | |
150 | # The suffix "o" is replaced with a literal percent. The percent is only | | 150 | # The suffix "o" is replaced with a literal percent. The percent is only |
151 | # a wildcard when it appears on the left-hand side. | | 151 | # a wildcard when it appears on the left-hand side. |
152 | .if ${one two:L:o=%} != "one tw%" | | 152 | .if ${one two:L:o=%} != "one tw%" |
153 | . error | | 153 | . error |
154 | .endif | | 154 | .endif |
155 | | | 155 | |
156 | # Each word with the suffix "o" is replaced with "X". The percent is a | | 156 | # Each word with the suffix "o" is replaced with "X". The percent is a |
157 | # wildcard even though the right-hand side does not contain another percent. | | 157 | # wildcard even though the right-hand side does not contain another percent. |
158 | .if ${one two:L:%o=X} != "one X" | | 158 | .if ${one two:L:%o=X} != "one X" |
159 | . error | | 159 | . error |
160 | .endif | | 160 | .endif |
161 | | | 161 | |
162 | # Each word with the prefix "o" is replaced with "X". The percent is a | | 162 | # Each word with the prefix "o" is replaced with "X". The percent is a |
163 | # wildcard even though the right-hand side does not contain another percent. | | 163 | # wildcard even though the right-hand side does not contain another percent. |
164 | .if ${one two:L:o%=X} != "X two" | | 164 | .if ${one two:L:o%=X} != "X two" |
165 | . error | | 165 | . error |
166 | .endif | | 166 | .endif |
167 | | | 167 | |
168 | # For each word with the prefix "o" and the suffix "e", the whole word is | | 168 | # For each word with the prefix "o" and the suffix "e", the whole word is |
169 | # replaced with "X". | | 169 | # replaced with "X". |
170 | .if ${one two oe oxen:L:o%e=X} != "X two X oxen" | | 170 | .if ${one two oe oxen:L:o%e=X} != "X two X oxen" |
171 | . error | | 171 | . error |
172 | .endif | | 172 | .endif |
173 | | | 173 | |
174 | # Only the first '%' is the wildcard. | | 174 | # Only the first '%' is the wildcard. |
175 | .if ${one two o%e other%e:L:o%%e=X} != "one two X X" | | 175 | .if ${one two o%e other%e:L:o%%e=X} != "one two X X" |
176 | . error | | 176 | . error |
177 | .endif | | 177 | .endif |
178 | | | 178 | |
179 | # In the replacement, only the first '%' is the placeholder, all others | | 179 | # In the replacement, only the first '%' is the placeholder, all others |
180 | # are literal percent characters. | | 180 | # are literal percent characters. |
181 | .if ${one two:L:%=%%} != "one% two%" | | 181 | .if ${one two:L:%=%%} != "one% two%" |
182 | . error | | 182 | . error |
183 | .endif | | 183 | .endif |
184 | | | 184 | |
185 | # In the word "one", only a prefix of the pattern suffix "nes" matches, | | 185 | # In the word "one", only a prefix of the pattern suffix "nes" matches, |
186 | # the whole word is too short. Therefore it doesn't match. | | 186 | # the whole word is too short. Therefore it doesn't match. |
187 | .if ${one two:L:%nes=%xxx} != "one two" | | 187 | .if ${one two:L:%nes=%xxx} != "one two" |
188 | . error | | 188 | . error |
189 | .endif | | 189 | .endif |
190 | | | 190 | |
191 | # The :from=to modifier can be used to replace both the prefix and a suffix | | 191 | # The :from=to modifier can be used to replace both the prefix and a suffix |
192 | # of a word with other strings. This is not possible with a single :S | | 192 | # of a word with other strings. This is not possible with a single :S |
193 | # modifier, and using a :C modifier for the same task looks more complicated | | 193 | # modifier, and using a :C modifier for the same task looks more complicated |
194 | # in many cases. | | 194 | # in many cases. |
195 | .if ${prefix-middle-suffix:L:prefix-%-suffix=p-%-s} != "p-middle-s" | | 195 | .if ${prefix-middle-suffix:L:prefix-%-suffix=p-%-s} != "p-middle-s" |
196 | . error | | 196 | . error |
197 | .endif | | 197 | .endif |
198 | | | 198 | |
| | | 199 | # This is not a SysV modifier since the nested variable expression expands |
| | | 200 | # to an empty string. The '=' in it should be irrelevant during parsing. |
| | | 201 | # As of 2020-11-01, this seemingly correct modifier leads to a parse error. |
| | | 202 | # XXX |
| | | 203 | .if ${word203:L:from${:D=}to} |
| | | 204 | . error |
| | | 205 | .endif |
| | | 206 | |
| | | 207 | # XXX: This specially constructed case demonstrates that the SysV modifier |
| | | 208 | # lasts longer than expected. The whole expression initially has the value |
| | | 209 | # "fromto}...". The next modifier is a SysV modifier. ApplyModifier_SysV |
| | | 210 | # parses the modifier as "from${:D=}to", ending at the '}'. Next, the two |
| | | 211 | # parts of the modifier are parsed using ParseModifierPart, which scans |
| | | 212 | # differently, properly handling nested variable expressions. The two parts |
| | | 213 | # are now "fromto}..." and "replaced". |
| | | 214 | .if "${:Ufromto\}...:from${:D=}to}...=replaced}" != "replaced" |
| | | 215 | . error |
| | | 216 | .endif |
| | | 217 | |
199 | # As of 2020-10-06, the right-hand side of the SysV modifier is expanded | | 218 | # As of 2020-10-06, the right-hand side of the SysV modifier is expanded |
200 | # twice. The first expansion happens in ApplyModifier_SysV, where the | | 219 | # twice. The first expansion happens in ApplyModifier_SysV, where the |
201 | # modifier is split into its two parts. The second expansion happens | | 220 | # modifier is split into its two parts. The second expansion happens |
202 | # when each word is replaced in ModifyWord_SYSVSubst. | | 221 | # when each word is replaced in ModifyWord_SYSVSubst. |
203 | # XXX: This is unexpected. Add more test case to demonstrate the effects | | 222 | # XXX: This is unexpected. Add more test case to demonstrate the effects |
204 | # of removing one of the expansions. | | 223 | # of removing one of the expansions. |
205 | VALUE= value | | 224 | VALUE= value |
206 | INDIRECT= 1:${VALUE} 2:$${VALUE} 4:$$$${VALUE} | | 225 | INDIRECT= 1:${VALUE} 2:$${VALUE} 4:$$$${VALUE} |
207 | .if ${x:L:x=${INDIRECT}} != "1:value 2:value 4:\${VALUE}" | | 226 | .if ${x:L:x=${INDIRECT}} != "1:value 2:value 4:\${VALUE}" |
208 | . error | | 227 | . error |
209 | .endif | | 228 | .endif |
210 | | | 229 | |
211 | all: | | 230 | all: |