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