Home | History | Annotate | Line # | Download | only in unit-tests
cond-func-empty.mk revision 1.28
      1 # $NetBSD: cond-func-empty.mk,v 1.28 2025/01/11 20:54:45 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
     11 EMPTY=	# empty
     12 SPACE=	${:U }
     13 ZERO=	0
     14 WORD=	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 allows
    109 # subexpressions to be based on undefined variables, the value of the
    110 # undefined variable "" 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+1: Unclosed variable "WORD"
    167 .if empty(WORD
    168 .  error
    169 .else
    170 .  error
    171 .endif
    172 
    173 # Since cond.c 1.76 from 2020-06-28 and before var.c 1.226 from 2020-07-02,
    174 # the following example generated a wrong error message "Variable VARNAME is
    175 # recursive".
    176 #
    177 # Since at least 1993, the manual page claimed that irrelevant parts of
    178 # conditions were not evaluated, but that was wrong for a long time.  The
    179 # expressions in irrelevant parts of the condition were actually evaluated,
    180 # they just allowed undefined variables to be used in the conditions.  These
    181 # unnecessary evaluations were fixed in several commits, starting with var.c
    182 # 1.226 from 2020-07-02.
    183 #
    184 # In this example, the variable "VARNAME2" is not defined, so evaluation of
    185 # the condition should have stopped at this point, and the rest of the
    186 # condition should have been processed in parse-only mode.  The right-hand
    187 # side containing the '!empty' was evaluated though, as it had always been.
    188 #
    189 # When evaluating the !empty condition, the variable name was parsed as
    190 # "VARNAME${:U2}", but without expanding any nested expression, in
    191 # this case the ${:U2}.  The expression '${:U2}' was replaced with an empty
    192 # string, the resulting variable name was thus "VARNAME".  This conceptually
    193 # wrong variable name should have been discarded quickly after parsing it, to
    194 # prevent it from doing any harm.
    195 #
    196 # The expression was evaluated, and this was wrong.  The evaluation was done
    197 # without VARE_EVAL (called VARF_WANTRES back then) though.  This had the
    198 # effect that the ${:U1} from the value of VARNAME evaluated to an empty
    199 # string.  This in turn created the seemingly recursive definition
    200 # VARNAME=${VARNAME}, and that definition was evaluated even though it was
    201 # never meant to be evaluated.
    202 #
    203 # This was fixed by evaluating nested expressions in the variable name only
    204 # when the whole expression was evaluated as well.
    205 VARNAME=	${VARNAME${:U1}}
    206 .if defined(VARNAME${:U2}) && !empty(VARNAME${:U2})
    207 .endif
    208 
    209 # Expressions in the argument of a function call don't have to be defined.
    210 .if !empty(${UNDEF})
    211 .  error
    212 .endif
    213 
    214 # If the word 'empty' is not followed by '(', it is not a function call but an
    215 # ordinary bare word.  This bare word is interpreted as 'defined(empty)', and
    216 # since there is no variable named 'empty', the condition evaluates to false.
    217 .if empty
    218 .  error
    219 .endif
    220 
    221 empty=		# defined but empty
    222 .if empty
    223 .else
    224 .  error
    225 .endif
    226