1# $NetBSD: cond-op.mk,v 1.16 2023/06/01 20:56:35 rillig Exp $ 2# 3# Tests for operators like &&, ||, ! in .if conditions. 4# 5# See also: 6# cond-op-and.mk 7# cond-op-not.mk 8# cond-op-or.mk 9# cond-op-parentheses.mk 10 11# In make, && binds more tightly than ||, like in C. 12# If make had the same precedence for both && and ||, like in the shell, 13# the result would be different. 14# If || were to bind more tightly than &&, the result would be different 15# as well. 16.if !(1 || 1 && 0) 17. error 18.endif 19 20# If make were to interpret the && and || operators like the shell, the 21# previous condition would be interpreted as: 22.if (1 || 1) && 0 23. error 24.endif 25 26# The precedence of the ! operator is different from C though. It has a 27# lower precedence than the comparison operators. Negating a condition 28# does not need parentheses. 29# 30# This kind of condition looks so unfamiliar that it doesn't occur in 31# practice. 32.if !"word" == "word" 33. error 34.endif 35 36# This is how the above condition is actually interpreted. 37.if !("word" == "word") 38. error 39.endif 40 41# TODO: Demonstrate that the precedence of the ! and == operators actually 42# makes a difference. There is a simple example for sure, I just cannot 43# wrap my head around it right now. See the truth table generator below 44# for an example that doesn't require much thought. 45 46# This condition is malformed because the '!' on the right-hand side must not 47# appear unquoted. If any, it must be enclosed in quotes. 48# In any case, it is not interpreted as a negation of an unquoted string. 49# See CondParser_String. 50# expect+1: Malformed conditional ("!word" == !word) 51.if "!word" == !word 52. error 53.endif 54 55# Surprisingly, the ampersand and pipe are allowed in bare strings. 56# That's another opportunity for writing confusing code. 57# See CondParser_String, which only has '!' in the list of stop characters. 58.if "a&&b||c" != a&&b||c 59. error 60.endif 61 62# In the following malformed conditions, as soon as the parser sees the '$' 63# after the '0' or the '1', it knows that the condition will be malformed. 64# Therefore there is no point in evaluating the misplaced expression. 65# 66# Before cond.c 1.286 from 2021-12-10, the extra expression was evaluated 67# nevertheless, since CondParser_Or and CondParser_And asked for the expanded 68# next token, even though in this position of the condition, only comparison 69# operators, TOK_AND, TOK_OR or TOK_RPAREN are allowed. 70.undef ERR 71# expect+1: Malformed conditional (0 ${ERR::=evaluated}) 72.if 0 ${ERR::=evaluated} 73. error 74.endif 75.if ${ERR:Uundefined} == undefined 76# expect+1: A misplaced expression after 0 is not evaluated. 77. info A misplaced expression after 0 is not evaluated. 78.endif 79 80.undef ERR 81# expect+1: Malformed conditional (1 ${ERR::=evaluated}) 82.if 1 ${ERR::=evaluated} 83. error 84.endif 85.if ${ERR:Uundefined} == undefined 86# expect+1: A misplaced expression after 1 is not evaluated. 87. info A misplaced expression after 1 is not evaluated. 88.endif 89 90 91# Demonstration that '&&' has higher precedence than '||'. 92# expect+1: A B C => (A || B) && C A || B && C A || (B && C) 93.info A B C => (A || B) && C A || B && C A || (B && C) 94.for a in 0 1 95. for b in 0 1 96. for c in 0 1 97. for r1 in ${ ($a || $b) && $c :?1:0} 98. for r2 in ${ $a || $b && $c :?1:0} 99. for r3 in ${ $a || ($b && $c) :?1:0} 100# expect+8: 0 0 0 => 0 0 0 101# expect+7: 0 0 1 => 0 0 0 102# expect+6: 0 1 0 => 0 0 0 103# expect+5: 0 1 1 => 1 1 1 104# expect+4: 1 0 0 => 0 1 1 105# expect+3: 1 0 1 => 1 1 1 106# expect+2: 1 1 0 => 0 1 1 107# expect+1: 1 1 1 => 1 1 1 108. info $a $b $c => ${r1} ${r2} ${r3} 109. endfor 110. endfor 111. endfor 112. endfor 113. endfor 114.endfor 115 116# This condition is obviously malformed. It is properly detected and also 117# was properly detected before 2021-01-19, but only because the left hand 118# side of the '&&' evaluated to true. 119# expect+1: Malformed conditional (1 &&) 120.if 1 && 121. error 122.else 123. error 124.endif 125 126# This obviously malformed condition was not detected as such before cond.c 127# 1.238 from 2021-01-19. 128# expect+1: Malformed conditional (0 &&) 129.if 0 && 130. error 131.else 132. error 133.endif 134 135# This obviously malformed condition was not detected as such before cond.c 136# 1.238 from 2021-01-19. 137# expect+1: Malformed conditional (1 ||) 138.if 1 || 139. error 140.else 141. error 142.endif 143 144# This condition is obviously malformed. It is properly detected and also 145# was properly detected before 2021-01-19, but only because the left hand 146# side of the '||' evaluated to false. 147# expect+1: Malformed conditional (0 ||) 148.if 0 || 149. error 150.else 151. error 152.endif 153 154all: 155 @:; 156