xref: /freebsd/contrib/bmake/unit-tests/cond-op.mk (revision a8c56be47166295d37600ff81fc1857db87b3a9b)
1*a8c56be4SSimon J. Gerraty# $NetBSD: cond-op.mk,v 1.18 2025/06/28 22:39:28 rillig Exp $
22c3632d1SSimon J. Gerraty#
32c3632d1SSimon J. Gerraty# Tests for operators like &&, ||, ! in .if conditions.
42c3632d1SSimon J. Gerraty#
52c3632d1SSimon J. Gerraty# See also:
62c3632d1SSimon J. Gerraty#	cond-op-and.mk
72c3632d1SSimon J. Gerraty#	cond-op-not.mk
82c3632d1SSimon J. Gerraty#	cond-op-or.mk
92c3632d1SSimon J. Gerraty#	cond-op-parentheses.mk
102c3632d1SSimon J. Gerraty
112c3632d1SSimon J. Gerraty# In make, && binds more tightly than ||, like in C.
12e2eeea75SSimon J. Gerraty# If make had the same precedence for both && and ||, like in the shell,
13e2eeea75SSimon J. Gerraty# the result would be different.
142c3632d1SSimon J. Gerraty# If || were to bind more tightly than &&, the result would be different
152c3632d1SSimon J. Gerraty# as well.
162c3632d1SSimon J. Gerraty.if !(1 || 1 && 0)
172c3632d1SSimon J. Gerraty.  error
182c3632d1SSimon J. Gerraty.endif
192c3632d1SSimon J. Gerraty
202c3632d1SSimon J. Gerraty# If make were to interpret the && and || operators like the shell, the
21e2eeea75SSimon J. Gerraty# previous condition would be interpreted as:
222c3632d1SSimon J. Gerraty.if (1 || 1) && 0
232c3632d1SSimon J. Gerraty.  error
242c3632d1SSimon J. Gerraty.endif
252c3632d1SSimon J. Gerraty
262c3632d1SSimon J. Gerraty# The precedence of the ! operator is different from C though. It has a
27e2eeea75SSimon J. Gerraty# lower precedence than the comparison operators.  Negating a condition
28e2eeea75SSimon J. Gerraty# does not need parentheses.
29e2eeea75SSimon J. Gerraty#
30e2eeea75SSimon J. Gerraty# This kind of condition looks so unfamiliar that it doesn't occur in
31e2eeea75SSimon J. Gerraty# practice.
322c3632d1SSimon J. Gerraty.if !"word" == "word"
332c3632d1SSimon J. Gerraty.  error
342c3632d1SSimon J. Gerraty.endif
352c3632d1SSimon J. Gerraty
362c3632d1SSimon J. Gerraty# This is how the above condition is actually interpreted.
372c3632d1SSimon J. Gerraty.if !("word" == "word")
382c3632d1SSimon J. Gerraty.  error
392c3632d1SSimon J. Gerraty.endif
402c3632d1SSimon J. Gerraty
412c3632d1SSimon J. Gerraty# TODO: Demonstrate that the precedence of the ! and == operators actually
422c3632d1SSimon J. Gerraty# makes a difference.  There is a simple example for sure, I just cannot
43e2eeea75SSimon J. Gerraty# wrap my head around it right now.  See the truth table generator below
44e2eeea75SSimon J. Gerraty# for an example that doesn't require much thought.
452c3632d1SSimon J. Gerraty
462c3632d1SSimon J. Gerraty# This condition is malformed because the '!' on the right-hand side must not
472c3632d1SSimon J. Gerraty# appear unquoted.  If any, it must be enclosed in quotes.
482c3632d1SSimon J. Gerraty# In any case, it is not interpreted as a negation of an unquoted string.
49956e45f6SSimon J. Gerraty# See CondParser_String.
50*a8c56be4SSimon J. Gerraty# expect+1: Malformed conditional ""!word" == !word"
512c3632d1SSimon J. Gerraty.if "!word" == !word
522c3632d1SSimon J. Gerraty.  error
532c3632d1SSimon J. Gerraty.endif
542c3632d1SSimon J. Gerraty
552c3632d1SSimon J. Gerraty# Surprisingly, the ampersand and pipe are allowed in bare strings.
562c3632d1SSimon J. Gerraty# That's another opportunity for writing confusing code.
57956e45f6SSimon J. Gerraty# See CondParser_String, which only has '!' in the list of stop characters.
582c3632d1SSimon J. Gerraty.if "a&&b||c" != a&&b||c
592c3632d1SSimon J. Gerraty.  error
602c3632d1SSimon J. Gerraty.endif
612c3632d1SSimon J. Gerraty
6212904384SSimon J. Gerraty# In the following malformed conditions, as soon as the parser sees the '$'
6312904384SSimon J. Gerraty# after the '0' or the '1', it knows that the condition will be malformed.
6412904384SSimon J. Gerraty# Therefore there is no point in evaluating the misplaced expression.
65956e45f6SSimon J. Gerraty#
6612904384SSimon J. Gerraty# Before cond.c 1.286 from 2021-12-10, the extra expression was evaluated
6712904384SSimon J. Gerraty# nevertheless, since CondParser_Or and CondParser_And asked for the expanded
6812904384SSimon J. Gerraty# next token, even though in this position of the condition, only comparison
6912904384SSimon J. Gerraty# operators, TOK_AND, TOK_OR or TOK_RPAREN are allowed.
7012904384SSimon J. Gerraty.undef ERR
71*a8c56be4SSimon J. Gerraty# expect+1: Malformed conditional "0 ${ERR::=evaluated}"
72956e45f6SSimon J. Gerraty.if 0 ${ERR::=evaluated}
73956e45f6SSimon J. Gerraty.  error
74956e45f6SSimon J. Gerraty.endif
7512904384SSimon J. Gerraty.if ${ERR:Uundefined} == undefined
76148ee845SSimon J. Gerraty# expect+1: A misplaced expression after 0 is not evaluated.
7712904384SSimon J. Gerraty.  info A misplaced expression after 0 is not evaluated.
7812904384SSimon J. Gerraty.endif
7912904384SSimon J. Gerraty
8012904384SSimon J. Gerraty.undef ERR
81*a8c56be4SSimon J. Gerraty# expect+1: Malformed conditional "1 ${ERR::=evaluated}"
8212904384SSimon J. Gerraty.if 1 ${ERR::=evaluated}
8312904384SSimon J. Gerraty.  error
8412904384SSimon J. Gerraty.endif
8512904384SSimon J. Gerraty.if ${ERR:Uundefined} == undefined
86148ee845SSimon J. Gerraty# expect+1: A misplaced expression after 1 is not evaluated.
8712904384SSimon J. Gerraty.  info A misplaced expression after 1 is not evaluated.
88956e45f6SSimon J. Gerraty.endif
89956e45f6SSimon J. Gerraty
902c3632d1SSimon J. Gerraty
91e2eeea75SSimon J. Gerraty# Demonstration that '&&' has higher precedence than '||'.
92148ee845SSimon J. Gerraty# expect+1: A B C   =>   (A || B) && C   A || B && C   A || (B && C)
93e2eeea75SSimon J. Gerraty.info A B C   =>   (A || B) && C   A || B && C   A || (B && C)
94e2eeea75SSimon J. Gerraty.for a in 0 1
95e2eeea75SSimon J. Gerraty.  for b in 0 1
96e2eeea75SSimon J. Gerraty.    for c in 0 1
97e2eeea75SSimon J. Gerraty.      for r1 in ${ ($a || $b) && $c :?1:0}
98e2eeea75SSimon J. Gerraty.        for r2 in ${ $a || $b && $c :?1:0}
99e2eeea75SSimon J. Gerraty.          for r3 in ${ $a || ($b && $c) :?1:0}
100148ee845SSimon J. Gerraty# expect+8: 0 0 0   =>   0               0             0
101148ee845SSimon J. Gerraty# expect+7: 0 0 1   =>   0               0             0
102148ee845SSimon J. Gerraty# expect+6: 0 1 0   =>   0               0             0
103148ee845SSimon J. Gerraty# expect+5: 0 1 1   =>   1               1             1
104148ee845SSimon J. Gerraty# expect+4: 1 0 0   =>   0               1             1
105148ee845SSimon J. Gerraty# expect+3: 1 0 1   =>   1               1             1
106148ee845SSimon J. Gerraty# expect+2: 1 1 0   =>   0               1             1
107148ee845SSimon J. Gerraty# expect+1: 1 1 1   =>   1               1             1
108e2eeea75SSimon J. Gerraty.            info $a $b $c   =>   ${r1}               ${r2}             ${r3}
109e2eeea75SSimon J. Gerraty.          endfor
110e2eeea75SSimon J. Gerraty.        endfor
111e2eeea75SSimon J. Gerraty.      endfor
112e2eeea75SSimon J. Gerraty.    endfor
113e2eeea75SSimon J. Gerraty.  endfor
114e2eeea75SSimon J. Gerraty.endfor
115e2eeea75SSimon J. Gerraty
116dba7b0efSSimon J. Gerraty# This condition is obviously malformed.  It is properly detected and also
117dba7b0efSSimon J. Gerraty# was properly detected before 2021-01-19, but only because the left hand
118dba7b0efSSimon J. Gerraty# side of the '&&' evaluated to true.
119*a8c56be4SSimon J. Gerraty# expect+1: Malformed conditional "1 &&"
120dba7b0efSSimon J. Gerraty.if 1 &&
121dba7b0efSSimon J. Gerraty.  error
122dba7b0efSSimon J. Gerraty.else
123dba7b0efSSimon J. Gerraty.  error
124dba7b0efSSimon J. Gerraty.endif
125dba7b0efSSimon J. Gerraty
126dba7b0efSSimon J. Gerraty# This obviously malformed condition was not detected as such before cond.c
127dba7b0efSSimon J. Gerraty# 1.238 from 2021-01-19.
128*a8c56be4SSimon J. Gerraty# expect+1: Malformed conditional "0 &&"
129dba7b0efSSimon J. Gerraty.if 0 &&
130dba7b0efSSimon J. Gerraty.  error
131dba7b0efSSimon J. Gerraty.else
132dba7b0efSSimon J. Gerraty.  error
133dba7b0efSSimon J. Gerraty.endif
134dba7b0efSSimon J. Gerraty
135dba7b0efSSimon J. Gerraty# This obviously malformed condition was not detected as such before cond.c
136dba7b0efSSimon J. Gerraty# 1.238 from 2021-01-19.
137*a8c56be4SSimon J. Gerraty# expect+1: Malformed conditional "1 ||"
138dba7b0efSSimon J. Gerraty.if 1 ||
139dba7b0efSSimon J. Gerraty.  error
140dba7b0efSSimon J. Gerraty.else
141dba7b0efSSimon J. Gerraty.  error
142dba7b0efSSimon J. Gerraty.endif
143dba7b0efSSimon J. Gerraty
144dba7b0efSSimon J. Gerraty# This condition is obviously malformed.  It is properly detected and also
145dba7b0efSSimon J. Gerraty# was properly detected before 2021-01-19, but only because the left hand
146dba7b0efSSimon J. Gerraty# side of the '||' evaluated to false.
147*a8c56be4SSimon J. Gerraty# expect+1: Malformed conditional "0 ||"
148dba7b0efSSimon J. Gerraty.if 0 ||
149dba7b0efSSimon J. Gerraty.  error
150dba7b0efSSimon J. Gerraty.else
151dba7b0efSSimon J. Gerraty.  error
152dba7b0efSSimon J. Gerraty.endif
153dba7b0efSSimon J. Gerraty
1542c3632d1SSimon J. Gerratyall:
1552c3632d1SSimon J. Gerraty	@:;
156