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