Home | History | Annotate | Line # | Download | only in unit-tests
cond-op.mk revision 1.12
      1  1.12  rillig # $NetBSD: cond-op.mk,v 1.12 2021/01/19 18:13:37 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.4  rillig .if "!word" == !word
     51   1.8  rillig .  error
     52   1.4  rillig .endif
     53   1.4  rillig 
     54   1.4  rillig # Surprisingly, the ampersand and pipe are allowed in bare strings.
     55   1.4  rillig # That's another opportunity for writing confusing code.
     56   1.5  rillig # See CondParser_String, which only has '!' in the list of stop characters.
     57   1.4  rillig .if "a&&b||c" != a&&b||c
     58   1.8  rillig .  error
     59   1.4  rillig .endif
     60   1.4  rillig 
     61   1.6  rillig # As soon as the parser sees the '$', it knows that the condition will
     62   1.6  rillig # be malformed.  Therefore there is no point in evaluating it.
     63   1.7  rillig #
     64   1.7  rillig # As of 2020-09-11, that part of the condition is evaluated nevertheless,
     65   1.7  rillig # since CondParser_Expr just requests the next token, without restricting
     66   1.7  rillig # the token to the expected tokens.  If the parser were to restrict the
     67   1.7  rillig # valid follow tokens for the token "0" to those that can actually produce
     68   1.7  rillig # a correct condition (which in this case would be comparison operators,
     69   1.7  rillig # TOK_AND, TOK_OR or TOK_RPAREN), the variable expression would not have
     70   1.7  rillig # to be evaluated.
     71   1.7  rillig #
     72   1.7  rillig # This would add a good deal of complexity to the code though, for almost
     73   1.7  rillig # no benefit, especially since most expressions and conditions are side
     74   1.7  rillig # effect free.
     75   1.6  rillig .if 0 ${ERR::=evaluated}
     76   1.6  rillig .  error
     77   1.6  rillig .endif
     78   1.6  rillig .if ${ERR:Uundefined} == evaluated
     79  1.10  rillig .  info After detecting a parse error, the rest is evaluated.
     80   1.6  rillig .endif
     81   1.6  rillig 
     82   1.4  rillig # Just in case that parsing should ever stop on the first error.
     83   1.4  rillig .info Parsing continues until here.
     84   1.4  rillig 
     85   1.9  rillig # Demonstration that '&&' has higher precedence than '||'.
     86   1.9  rillig .info A B C   =>   (A || B) && C   A || B && C   A || (B && C)
     87   1.9  rillig .for a in 0 1
     88   1.9  rillig .  for b in 0 1
     89   1.9  rillig .    for c in 0 1
     90   1.9  rillig .      for r1 in ${ ($a || $b) && $c :?1:0}
     91   1.9  rillig .        for r2 in ${ $a || $b && $c :?1:0}
     92   1.9  rillig .          for r3 in ${ $a || ($b && $c) :?1:0}
     93   1.9  rillig .            info $a $b $c   =>   ${r1}               ${r2}             ${r3}
     94   1.9  rillig .          endfor
     95   1.9  rillig .        endfor
     96   1.9  rillig .      endfor
     97   1.9  rillig .    endfor
     98   1.9  rillig .  endfor
     99   1.9  rillig .endfor
    100   1.9  rillig 
    101  1.11  rillig # This condition is obviously malformed.  It is properly detected and also
    102  1.11  rillig # was properly detected before 2021-01-19, but only because the left hand
    103  1.11  rillig # side of the '&&' evaluated to true.
    104  1.11  rillig .if 1 &&
    105  1.11  rillig .  error
    106  1.11  rillig .else
    107  1.11  rillig .  error
    108  1.11  rillig .endif
    109  1.11  rillig 
    110  1.12  rillig # This obviously malformed condition was not detected as such before cond.c
    111  1.12  rillig # 1.238 from 2021-01-19.
    112  1.11  rillig .if 0 &&
    113  1.11  rillig .  error
    114  1.11  rillig .else
    115  1.11  rillig .  error
    116  1.11  rillig .endif
    117  1.11  rillig 
    118  1.12  rillig # This obviously malformed condition was not detected as such before cond.c
    119  1.12  rillig # 1.238 from 2021-01-19.
    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.11  rillig # This condition is obviously malformed.  It is properly detected and also
    127  1.11  rillig # was properly detected before 2021-01-19, but only because the left hand
    128  1.11  rillig # side of the '||' evaluated to false.
    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.1  rillig all:
    136   1.1  rillig 	@:;
    137