aboutsummaryrefslogblamecommitdiff
path: root/contrib/bmake/unit-tests/cond-op.mk
blob: 6371e4db0594ddf8b058581035981c12f5c4e4d5 (plain) (tree)
1
2
3
4
5
6
7
8
9
10
11
                                                             









                                                       

                                                                        


                                                                        
        


                                                                       
                                             
                 
        


                                                                       




                                                                       
                     
        



                                                          
        



                                                                          

                                                                        



                                                                             
                        
                                                    
                    
        



                                                                   
                                                                           
                        


        


                                                                           
 



                                                                             
          
                                                        


                        
                                  
                                                            



                                                        
                                                        



                                  
                                                            
                                                        

      
 
                                                          
                                                                    






                                                              







                                                        







                                                                             


                                                                          
                                        







                                                                           
                                        







                                                                           
                                        








                                                                          
                                        





        

           
# $NetBSD: cond-op.mk,v 1.16 2023/06/01 20:56:35 rillig Exp $
#
# Tests for operators like &&, ||, ! in .if conditions.
#
# See also:
#	cond-op-and.mk
#	cond-op-not.mk
#	cond-op-or.mk
#	cond-op-parentheses.mk

# In make, && binds more tightly than ||, like in C.
# If make had the same precedence for both && and ||, like in the shell,
# the result would be different.
# If || were to bind more tightly than &&, the result would be different
# as well.
.if !(1 || 1 && 0)
.  error
.endif

# If make were to interpret the && and || operators like the shell, the
# previous condition would be interpreted as:
.if (1 || 1) && 0
.  error
.endif

# The precedence of the ! operator is different from C though. It has a
# lower precedence than the comparison operators.  Negating a condition
# does not need parentheses.
#
# This kind of condition looks so unfamiliar that it doesn't occur in
# practice.
.if !"word" == "word"
.  error
.endif

# This is how the above condition is actually interpreted.
.if !("word" == "word")
.  error
.endif

# TODO: Demonstrate that the precedence of the ! and == operators actually
# makes a difference.  There is a simple example for sure, I just cannot
# wrap my head around it right now.  See the truth table generator below
# for an example that doesn't require much thought.

# This condition is malformed because the '!' on the right-hand side must not
# appear unquoted.  If any, it must be enclosed in quotes.
# In any case, it is not interpreted as a negation of an unquoted string.
# See CondParser_String.
# expect+1: Malformed conditional ("!word" == !word)
.if "!word" == !word
.  error
.endif

# Surprisingly, the ampersand and pipe are allowed in bare strings.
# That's another opportunity for writing confusing code.
# See CondParser_String, which only has '!' in the list of stop characters.
.if "a&&b||c" != a&&b||c
.  error
.endif

# In the following malformed conditions, as soon as the parser sees the '$'
# after the '0' or the '1', it knows that the condition will be malformed.
# Therefore there is no point in evaluating the misplaced expression.
#
# Before cond.c 1.286 from 2021-12-10, the extra expression was evaluated
# nevertheless, since CondParser_Or and CondParser_And asked for the expanded
# next token, even though in this position of the condition, only comparison
# operators, TOK_AND, TOK_OR or TOK_RPAREN are allowed.
.undef ERR
# expect+1: Malformed conditional (0 ${ERR::=evaluated})
.if 0 ${ERR::=evaluated}
.  error
.endif
.if ${ERR:Uundefined} == undefined
# expect+1: A misplaced expression after 0 is not evaluated.
.  info A misplaced expression after 0 is not evaluated.
.endif

.undef ERR
# expect+1: Malformed conditional (1 ${ERR::=evaluated})
.if 1 ${ERR::=evaluated}
.  error
.endif
.if ${ERR:Uundefined} == undefined
# expect+1: A misplaced expression after 1 is not evaluated.
.  info A misplaced expression after 1 is not evaluated.
.endif


# Demonstration that '&&' has higher precedence than '||'.
# expect+1: A B C   =>   (A || B) && C   A || B && C   A || (B && C)
.info A B C   =>   (A || B) && C   A || B && C   A || (B && C)
.for a in 0 1
.  for b in 0 1
.    for c in 0 1
.      for r1 in ${ ($a || $b) && $c :?1:0}
.        for r2 in ${ $a || $b && $c :?1:0}
.          for r3 in ${ $a || ($b && $c) :?1:0}
# expect+8: 0 0 0   =>   0               0             0
# expect+7: 0 0 1   =>   0               0             0
# expect+6: 0 1 0   =>   0               0             0
# expect+5: 0 1 1   =>   1               1             1
# expect+4: 1 0 0   =>   0               1             1
# expect+3: 1 0 1   =>   1               1             1
# expect+2: 1 1 0   =>   0               1             1
# expect+1: 1 1 1   =>   1               1             1
.            info $a $b $c   =>   ${r1}               ${r2}             ${r3}
.          endfor
.        endfor
.      endfor
.    endfor
.  endfor
.endfor

# This condition is obviously malformed.  It is properly detected and also
# was properly detected before 2021-01-19, but only because the left hand
# side of the '&&' evaluated to true.
# expect+1: Malformed conditional (1 &&)
.if 1 &&
.  error
.else
.  error
.endif

# This obviously malformed condition was not detected as such before cond.c
# 1.238 from 2021-01-19.
# expect+1: Malformed conditional (0 &&)
.if 0 &&
.  error
.else
.  error
.endif

# This obviously malformed condition was not detected as such before cond.c
# 1.238 from 2021-01-19.
# expect+1: Malformed conditional (1 ||)
.if 1 ||
.  error
.else
.  error
.endif

# This condition is obviously malformed.  It is properly detected and also
# was properly detected before 2021-01-19, but only because the left hand
# side of the '||' evaluated to false.
# expect+1: Malformed conditional (0 ||)
.if 0 ||
.  error
.else
.  error
.endif

all:
	@:;