cond-token-plain.mk revision 1.14 1 1.14 rillig # $NetBSD: cond-token-plain.mk,v 1.14 2021/12/12 09:36:00 rillig Exp $
2 1.1 rillig #
3 1.2 rillig # Tests for plain tokens (that is, string literals without quotes)
4 1.14 rillig # in .if conditions. These are also called bare words.
5 1.1 rillig
6 1.3 rillig .MAKEFLAGS: -dc
7 1.3 rillig
8 1.14 rillig # The word 'value' after the '!=' is a bare word.
9 1.3 rillig .if ${:Uvalue} != value
10 1.3 rillig . error
11 1.3 rillig .endif
12 1.3 rillig
13 1.14 rillig # Using a '#' in a string literal in a condition leads to a malformed
14 1.14 rillig # condition since comment parsing is done in an early phase and removes the
15 1.14 rillig # '#' and everything after it long before the condition parser gets to see it.
16 1.3 rillig #
17 1.3 rillig # XXX: The error message is missing for this malformed condition.
18 1.6 rillig # The right-hand side of the comparison is just a '"', before unescaping.
19 1.3 rillig .if ${:U} != "#hash"
20 1.3 rillig . error
21 1.3 rillig .endif
22 1.3 rillig
23 1.3 rillig # To get a '#' into a condition, it has to be escaped using a backslash.
24 1.3 rillig # This prevents the comment parser from removing it, and in turn, it becomes
25 1.3 rillig # visible to CondParser_String.
26 1.3 rillig .if ${:U\#hash} != "\#hash"
27 1.3 rillig . error
28 1.3 rillig .endif
29 1.3 rillig
30 1.3 rillig # Since 2002-12-30, and still as of 2020-09-11, CondParser_Token handles
31 1.3 rillig # the '#' specially, even though at this point, there should be no need for
32 1.3 rillig # comment handling anymore. The comments are supposed to be stripped off
33 1.3 rillig # in a very early parsing phase.
34 1.3 rillig #
35 1.5 rillig # See https://gnats.netbsd.org/19596 for example makefiles demonstrating the
36 1.14 rillig # original problems. At that time, the parser didn't recognize the comment in
37 1.14 rillig # the line '.else # comment3'. This workaround is not needed anymore since
38 1.14 rillig # comments are stripped in an earlier phase. See "case '#'" in
39 1.14 rillig # CondParser_Token.
40 1.5 rillig #
41 1.3 rillig # XXX: Missing error message for the malformed condition. The right-hand
42 1.6 rillig # side before unescaping is double-quotes, backslash, backslash.
43 1.3 rillig .if ${:U\\} != "\\#hash"
44 1.3 rillig . error
45 1.3 rillig .endif
46 1.3 rillig
47 1.3 rillig # The right-hand side of a comparison is not parsed as a token, therefore
48 1.3 rillig # the code from CondParser_Token does not apply to it.
49 1.6 rillig # TODO: Explain the consequences.
50 1.6 rillig # TODO: Does this mean that more syntactic variants are allowed here?
51 1.3 rillig .if ${:U\#hash} != \#hash
52 1.3 rillig . error
53 1.3 rillig .endif
54 1.3 rillig
55 1.3 rillig # XXX: What is the purpose of treating an escaped '#' in the following
56 1.3 rillig # condition as a comment? And why only at the beginning of a token,
57 1.3 rillig # just as in the shell?
58 1.3 rillig .if 0 \# This is treated as a comment, but why?
59 1.3 rillig . error
60 1.3 rillig .endif
61 1.3 rillig
62 1.3 rillig # Ah, ok, this can be used to add an end-of-condition comment. But does
63 1.3 rillig # anybody really use this? This is neither documented nor obvious since
64 1.3 rillig # the '#' is escaped. It's much clearer to write a comment in the line
65 1.3 rillig # above the condition.
66 1.3 rillig .if ${0 \# comment :?yes:no} != no
67 1.3 rillig . error
68 1.3 rillig .endif
69 1.3 rillig .if ${1 \# comment :?yes:no} != yes
70 1.3 rillig . error
71 1.3 rillig .endif
72 1.1 rillig
73 1.4 rillig # Usually there is whitespace around the comparison operator, but this is
74 1.4 rillig # not required.
75 1.4 rillig .if ${UNDEF:Uundefined}!=undefined
76 1.4 rillig . error
77 1.4 rillig .endif
78 1.4 rillig .if ${UNDEF:U12345}>12345
79 1.4 rillig . error
80 1.4 rillig .endif
81 1.4 rillig .if ${UNDEF:U12345}<12345
82 1.4 rillig . error
83 1.4 rillig .endif
84 1.4 rillig .if (${UNDEF:U0})||0
85 1.4 rillig . error
86 1.4 rillig .endif
87 1.4 rillig
88 1.4 rillig # Only the comparison operator terminates the comparison operand, and it's
89 1.4 rillig # a coincidence that the '!' is both used in the '!=' comparison operator
90 1.4 rillig # as well as for negating a comparison result.
91 1.4 rillig #
92 1.4 rillig # The boolean operators '&' and '|' don't terminate a comparison operand.
93 1.4 rillig .if ${:Uvar}&&name != "var&&name"
94 1.4 rillig . error
95 1.4 rillig .endif
96 1.4 rillig .if ${:Uvar}||name != "var||name"
97 1.4 rillig . error
98 1.4 rillig .endif
99 1.4 rillig
100 1.7 rillig # A bare word may appear alone in a condition, without any comparison
101 1.7 rillig # operator. It is implicitly converted into defined(bare).
102 1.7 rillig .if bare
103 1.7 rillig . error
104 1.7 rillig .else
105 1.7 rillig . info A bare word is treated like defined(...), and the variable $\
106 1.7 rillig 'bare' is not defined.
107 1.7 rillig .endif
108 1.7 rillig
109 1.7 rillig VAR= defined
110 1.7 rillig .if VAR
111 1.7 rillig . info A bare word is treated like defined(...).
112 1.7 rillig .else
113 1.7 rillig . error
114 1.7 rillig .endif
115 1.7 rillig
116 1.7 rillig # Bare words may be intermixed with variable expressions.
117 1.7 rillig .if V${:UA}R
118 1.7 rillig . info ok
119 1.7 rillig .else
120 1.7 rillig . error
121 1.7 rillig .endif
122 1.7 rillig
123 1.7 rillig # In bare words, even undefined variables are allowed. Without the bare
124 1.7 rillig # words, undefined variables are not allowed. That feels inconsistent.
125 1.7 rillig .if V${UNDEF}AR
126 1.7 rillig . info Undefined variables in bare words expand to an empty string.
127 1.7 rillig .else
128 1.7 rillig . error
129 1.7 rillig .endif
130 1.7 rillig
131 1.7 rillig .if 0${:Ux00}
132 1.7 rillig . error
133 1.7 rillig .else
134 1.7 rillig . info Numbers can be composed from literals and variable expressions.
135 1.7 rillig .endif
136 1.7 rillig
137 1.7 rillig .if 0${:Ux01}
138 1.7 rillig . info Numbers can be composed from literals and variable expressions.
139 1.7 rillig .else
140 1.7 rillig . error
141 1.7 rillig .endif
142 1.7 rillig
143 1.8 rillig # If the right-hand side is missing, it's a parse error.
144 1.8 rillig .if "" ==
145 1.8 rillig . error
146 1.8 rillig .else
147 1.8 rillig . error
148 1.8 rillig .endif
149 1.8 rillig
150 1.8 rillig # If the left-hand side is missing, it's a parse error as well, but without
151 1.8 rillig # a specific error message.
152 1.8 rillig .if == ""
153 1.8 rillig . error
154 1.8 rillig .else
155 1.8 rillig . error
156 1.8 rillig .endif
157 1.8 rillig
158 1.8 rillig # The '\\' is not a line continuation. Neither is it an unquoted string
159 1.13 rillig # literal. Instead, it is parsed as a bare word (ParseWord),
160 1.8 rillig # and in that context, the backslash is just an ordinary character. The
161 1.8 rillig # function argument thus stays '\\' (2 backslashes). This string is passed
162 1.8 rillig # to FuncDefined, and since there is no variable named '\\', the condition
163 1.8 rillig # evaluates to false.
164 1.8 rillig .if \\
165 1.8 rillig . error
166 1.8 rillig .else
167 1.8 rillig . info The variable '\\' is not defined.
168 1.8 rillig .endif
169 1.8 rillig
170 1.8 rillig ${:U\\\\}= backslash
171 1.8 rillig .if \\
172 1.8 rillig . info Now the variable '\\' is defined.
173 1.8 rillig .else
174 1.8 rillig . error
175 1.8 rillig .endif
176 1.8 rillig
177 1.9 rillig # Anything that doesn't start with a double quote is considered a "bare word".
178 1.9 rillig # Strangely, a bare word may contain double quotes inside. Nobody should ever
179 1.9 rillig # depend on this since it may well be unintended. See CondParser_String.
180 1.9 rillig .if "unquoted\"quoted" != unquoted"quoted
181 1.9 rillig . error
182 1.9 rillig .endif
183 1.9 rillig
184 1.10 rillig # FIXME: In CondParser_String, Var_Parse returns var_Error without a
185 1.10 rillig # corresponding error message.
186 1.10 rillig .if $$$$$$$$ != ""
187 1.10 rillig . error
188 1.10 rillig .else
189 1.10 rillig . error
190 1.10 rillig .endif
191 1.10 rillig
192 1.11 rillig # In a condition in an .if directive, the left-hand side must not be an
193 1.11 rillig # unquoted string literal.
194 1.11 rillig # expect+1: Malformed conditional (left == right)
195 1.11 rillig .if left == right
196 1.11 rillig .endif
197 1.11 rillig # Before cond.c 1.276 from 2021-09-21, a variable expression containing the
198 1.11 rillig # modifier ':?:' allowed unquoted string literals for the rest of the
199 1.11 rillig # condition. This was an unintended implementation mistake.
200 1.12 rillig # expect+1: Malformed conditional (${0:?:} || left == right)
201 1.11 rillig .if ${0:?:} || left == right
202 1.11 rillig .endif
203 1.11 rillig # This affected only the comparisons after the expression, so the following
204 1.11 rillig # was still a syntax error.
205 1.11 rillig # expect+1: Malformed conditional (left == right || ${0:?:})
206 1.11 rillig .if left == right || ${0:?:}
207 1.11 rillig .endif
208 1.11 rillig
209 1.7 rillig # See cond-token-string.mk for similar tests where the condition is enclosed
210 1.7 rillig # in "quotes".
211 1.7 rillig
212 1.1 rillig all:
213 1.1 rillig @:;
214