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