xref: /freebsd/contrib/bmake/unit-tests/cond-func-empty.mk (revision af23369a6deaaeb612ab266eb88b8bb8d560c322)
1# $NetBSD: cond-func-empty.mk,v 1.17 2021/12/28 22:13:56 rillig Exp $
2#
3# Tests for the empty() function in .if conditions, which tests a variable
4# expression for emptiness.
5#
6# Note that the argument in the parentheses is a variable name, not a variable
7# expression, optionally followed by variable modifiers.
8#
9
10.undef UNDEF
11EMPTY=	# empty
12SPACE=	${:U }
13WORD=	word
14
15# An undefined variable is empty.
16.if !empty(UNDEF)
17.  error
18.endif
19
20# An undefined variable has the empty string as the value, and the :M
21# variable modifier does not change that.
22#
23.if !empty(UNDEF:M*)
24.  error
25.endif
26
27# The :S modifier replaces the empty value with an actual word.  The
28# expression is now no longer empty, but it is still based on an undefined
29# variable (DEF_UNDEF).  There are a few variable modifiers that turn an
30# undefined expression into a defined expression, among them :U and :D, but
31# not :S.
32#
33# XXX: This is hard to explain to someone who doesn't know these
34# implementation details.
35#
36.if !empty(UNDEF:S,^$,value,W)
37.  error
38.endif
39
40# The :U modifier changes the state of a previously undefined expression from
41# DEF_UNDEF to DEF_DEFINED.  This marks the expression as "being interesting
42# enough to be further processed".
43#
44.if empty(UNDEF:S,^$,value,W:Ufallback)
45.  error
46.endif
47
48# And now to the surprising part.  Applying the following :S modifier to the
49# undefined expression makes it non-empty, but the expression is still in
50# state DEF_UNDEF.  The :U modifier that follows only looks at the state
51# DEF_UNDEF to decide whether the variable is defined or not.  This kind of
52# makes sense since the :U modifier tests the _variable_, not the
53# _expression_.
54#
55# But since the variable was undefined to begin with, the fallback value from
56# the :U modifier is used in this expression.
57#
58.if ${UNDEF:S,^$,value,W:Ufallback} != "fallback"
59.  error
60.endif
61
62# The variable EMPTY is completely empty (0 characters).
63.if !empty(EMPTY)
64.  error
65.endif
66
67# The variable SPACE has a single space, which counts as being empty.
68.if !empty(SPACE)
69.  error
70.endif
71
72# The variable .newline has a single newline, which counts as being empty.
73.if !empty(.newline)
74.  error
75.endif
76
77# The following example constructs an expression with the variable name ""
78# and the value " ".  This expression counts as empty since the value contains
79# only whitespace.
80#
81# Contrary to the other functions in conditionals, the trailing space is not
82# stripped off, as can be seen in the -dv debug log.  If the space had been
83# stripped, it wouldn't make a difference in this case, but in other cases.
84#
85.if !empty(:U )
86.  error
87.endif
88
89# Now the variable named " " gets a non-empty value, which demonstrates that
90# neither leading nor trailing spaces are trimmed in the argument of the
91# function.  If the spaces were trimmed, the variable name would be "" and
92# that variable is indeed undefined.  Since CondParser_FuncCallEmpty calls
93# Var_Parse without VARE_UNDEFERR, the value of the undefined variable is
94# returned as an empty string.
95${:U }=	space
96.if empty( )
97.  error
98.endif
99
100# The value of the following expression is " word", which is not empty.
101.if empty(:U word)
102.  error
103.endif
104
105# The :L modifier creates a variable expression that has the same value as
106# its name, which both are "VAR" in this case.  The value is therefore not
107# empty.
108.if empty(VAR:L)
109.  error
110.endif
111
112# The variable WORD has the value "word", which does not count as empty.
113.if empty(WORD)
114.  error
115.endif
116
117# The expression ${} for a variable with the empty name always evaluates
118# to an empty string (see Var_Parse, varUndefined).
119.if !empty()
120.  error
121.endif
122
123# Ensure that variable expressions that appear as part of the argument are
124# properly parsed.  Typical use cases for this are .for loops, which are
125# expanded to exactly these ${:U} expressions.
126#
127# If everything goes well, the argument expands to "WORD", and that variable
128# is defined at the beginning of this file.  The surrounding 'W' and 'D'
129# ensure that CondParser_FuncCallEmpty keeps track of the parsing position,
130# both before and after the call to Var_Parse.
131.if empty(W${:UOR}D)
132.  error
133.endif
134
135# There may be spaces at the outside of the parentheses.
136# Spaces inside the parentheses are interpreted as part of the variable name.
137.if ! empty ( WORD )
138.  error
139.endif
140
141${:U WORD }=	variable name with spaces
142
143# Now there is a variable named " WORD ", and it is not empty.
144.if empty ( WORD )
145.  error
146.endif
147
148# Parse error: missing closing parenthesis.
149.if empty(WORD
150.  error
151.else
152.  error
153.endif
154
155# Since cond.c 1.76 from 2020-06-28 and before var.c 1.226 from 2020-07-02,
156# the following example generated a wrong error message "Variable VARNAME is
157# recursive".
158#
159# Since at least 1993, the manual page claimed that irrelevant parts of
160# conditions were not evaluated, but that was wrong for a long time.  The
161# expressions in irrelevant parts of the condition were actually evaluated,
162# they just allowed undefined variables to be used in the conditions, and the
163# result of evaluating them was not used further.  These unnecessary
164# evaluations were fixed in several commits, starting with var.c 1.226 from
165# 2020-07-02.
166#
167# In this example, the variable "VARNAME2" is not defined, so evaluation of
168# the condition should have stopped at this point, and the rest of the
169# condition should have been processed in parse-only mode.  The right-hand
170# side containing the '!empty' was evaluated though, as it had always been.
171#
172# When evaluating the !empty condition, the variable name was parsed as
173# "VARNAME${:U2}", but without expanding any nested variable expression, in
174# this case the ${:U2}.  The expression '${:U2}' was replaced with an empty
175# string, the resulting variable name was thus "VARNAME".  This conceptually
176# wrong variable name should have been discarded quickly after parsing it, to
177# prevent it from doing any harm.
178#
179# The variable expression was expanded though, and this was wrong.  The
180# expansion was done without VARE_WANTRES (called VARF_WANTRES back
181# then) though.  This had the effect that the ${:U1} from the value of VARNAME
182# expanded to an empty string.  This in turn created the seemingly recursive
183# definition VARNAME=${VARNAME}, and that definition was never meant to be
184# expanded.
185#
186# This was fixed by expanding nested variable expressions in the variable name
187# only if the flag VARE_WANTRES is given.
188VARNAME=	${VARNAME${:U1}}
189.if defined(VARNAME${:U2}) && !empty(VARNAME${:U2})
190.endif
191
192
193# If the word 'empty' is not followed by '(', it is not a function call but an
194# ordinary bare word.  This bare word is interpreted as 'defined(empty)', and
195# since there is no variable named 'empty', the condition evaluates to false.
196.if empty
197.  error
198.endif
199
200empty=		# defined but empty
201.if empty
202.else
203.  error
204.endif
205