Home | History | Annotate | Line # | Download | only in unit-tests
      1  1.20  rillig # $NetBSD: varmod-match-escape.mk,v 1.20 2025/06/28 22:39:29 rillig Exp $
      2   1.1  rillig #
      3   1.1  rillig # As of 2020-08-01, the :M and :N modifiers interpret backslashes differently,
      4  1.12  rillig # depending on whether there was an expression somewhere before the
      5  1.11  rillig # first backslash or not.  See ParseModifier_Match, "copy = true".
      6   1.1  rillig #
      7   1.1  rillig # Apart from the different and possibly confusing debug output, there is no
      8   1.1  rillig # difference in behavior.  When parsing the modifier text, only \{, \} and \:
      9   1.1  rillig # are unescaped, and in the pattern matching these have the same meaning as
     10   1.1  rillig # their plain variants '{', '}' and ':'.  In the pattern matching from
     11   1.1  rillig # Str_Match, only \*, \? or \[ would make a noticeable difference.
     12   1.4  rillig 
     13   1.4  rillig .MAKEFLAGS: -dcv
     14   1.4  rillig 
     15   1.1  rillig SPECIALS=	\: : \\ * \*
     16   1.1  rillig .if ${SPECIALS:M${:U}\:} != ${SPECIALS:M\:${:U}}
     17   1.2  rillig .  warning unexpected
     18   1.1  rillig .endif
     19   1.4  rillig 
     20   1.4  rillig # And now both cases combined: A single modifier with both an escaped ':'
     21  1.12  rillig # as well as an expression that expands to a ':'.
     22   1.4  rillig #
     23  1.12  rillig # XXX: As of 2020-11-01, when an escaped ':' occurs before the
     24   1.4  rillig # expression, the whole modifier text is subject to unescaping '\:' to ':',
     25  1.12  rillig # before the expression is expanded.  This means that the '\:' in
     26  1.12  rillig # the expression is expanded as well, turning ${:U\:} into a simple
     27   1.4  rillig # ${:U:}, which silently expands to an empty string, instead of generating
     28   1.4  rillig # an error message.
     29   1.4  rillig #
     30   1.4  rillig # XXX: As of 2020-11-01, the modifier on the right-hand side of the
     31  1.12  rillig # comparison is parsed differently though.  First, the expression
     32   1.7  rillig # is parsed, resulting in ':' and needSubst=true.  After that, the escaped
     33   1.7  rillig # ':' is seen, and this time, copy=true is not executed but stays copy=false.
     34   1.4  rillig # Therefore the escaped ':' is kept as-is, and the final pattern becomes
     35   1.4  rillig # ':\:'.
     36   1.4  rillig #
     37  1.11  rillig # If ParseModifier_Match had used the same parsing algorithm as Var_Subst,
     38   1.4  rillig # both patterns would end up as '::'.
     39   1.4  rillig #
     40   1.4  rillig VALUES=		: :: :\:
     41   1.4  rillig .if ${VALUES:M\:${:U\:}} != ${VALUES:M${:U\:}\:}
     42   1.8  rillig # expect+1: warning: XXX: Oops
     43   1.4  rillig .  warning XXX: Oops
     44   1.4  rillig .endif
     45   1.4  rillig 
     46   1.3  rillig .MAKEFLAGS: -d0
     47   1.1  rillig 
     48   1.5  rillig # XXX: As of 2020-11-01, unlike all other variable modifiers, a '$' in the
     49   1.5  rillig # :M and :N modifiers is written as '$$', not as '\$'.  This is confusing,
     50   1.5  rillig # undocumented and hopefully not used in practice.
     51   1.5  rillig .if ${:U\$:M$$} != "\$"
     52   1.5  rillig .  error
     53   1.5  rillig .endif
     54   1.5  rillig 
     55   1.5  rillig # XXX: As of 2020-11-01, unlike all other variable modifiers, '\$' is not
     56  1.11  rillig # parsed as an escaped '$'.  Instead, ParseModifier_Match first scans for
     57   1.5  rillig # the ':' at the end of the modifier, which results in the pattern '\$'.
     58   1.5  rillig # No unescaping takes place since the pattern neither contained '\:' nor
     59   1.5  rillig # '\{' nor '\}'.  But the text is expanded, and a lonely '$' at the end
     60   1.5  rillig # is silently discarded.  The resulting expanded pattern is thus '\', that
     61   1.5  rillig # is a single backslash.
     62  1.20  rillig # expect+1: Unfinished backslash at the end in pattern "\" of modifier ":M"
     63   1.5  rillig .if ${:U\$:M\$} != ""
     64   1.5  rillig .  error
     65   1.5  rillig .endif
     66   1.5  rillig 
     67   1.5  rillig # In lint mode, the case of a lonely '$' is covered with an error message.
     68   1.5  rillig .MAKEFLAGS: -dL
     69  1.19  rillig # expect+2: Dollar followed by nothing
     70  1.20  rillig # expect+1: Unfinished backslash at the end in pattern "\" of modifier ":M"
     71   1.5  rillig .if ${:U\$:M\$} != ""
     72   1.5  rillig .  error
     73   1.5  rillig .endif
     74   1.5  rillig 
     75   1.6  rillig # The control flow of the pattern parser depends on the actual string that
     76   1.6  rillig # is being matched.  There needs to be either a test that shows a difference
     77   1.6  rillig # in behavior, or a proof that the behavior does not depend on the actual
     78   1.6  rillig # string.
     79   1.6  rillig #
     80   1.6  rillig # TODO: Str_Match("a-z]", "[a-z]")
     81   1.6  rillig # TODO: Str_Match("012", "[0-]]")
     82   1.6  rillig # TODO: Str_Match("[", "[[]")
     83   1.6  rillig # TODO: Str_Match("]", "[]")
     84   1.6  rillig # TODO: Str_Match("]", "[[-]]")
     85   1.6  rillig 
     86   1.9  rillig # Demonstrate an inconsistency between positive and negative character lists
     87   1.9  rillig # when the range ends with the character ']'.
     88   1.9  rillig #
     89   1.9  rillig # 'A' begins the range, 'B' is in the middle of the range, ']' ends the range,
     90   1.9  rillig # 'a' is outside the range.
     91   1.9  rillig WORDS=		A A] A]] B B] B]] ] ]] ]]] a a] a]]
     92   1.9  rillig # The ']' is part of the character range and at the same time ends the
     93   1.9  rillig # character list.
     94   1.9  rillig EXP.[A-]=	A B ]
     95   1.9  rillig # The first ']' is part of the character range and at the same time ends the
     96   1.9  rillig # character list.
     97   1.9  rillig EXP.[A-]]=	A] B] ]]
     98   1.9  rillig # The first ']' is part of the character range and at the same time ends the
     99   1.9  rillig # character list.
    100   1.9  rillig EXP.[A-]]]=	A]] B]] ]]]
    101   1.9  rillig # For negative character lists, the ']' ends the character range but does not
    102   1.9  rillig # end the character list.
    103   1.9  rillig # XXX: This is unnecessarily inconsistent but irrelevant in practice as there
    104   1.9  rillig # is no practical need for a character range that ends at ']'.
    105   1.9  rillig EXP.[^A-]=	a
    106   1.9  rillig EXP.[^A-]]=	a
    107   1.9  rillig EXP.[^A-]]]=	a]
    108   1.9  rillig 
    109   1.9  rillig .for pattern in [A-] [A-]] [A-]]] [^A-] [^A-]] [^A-]]]
    110  1.20  rillig # expect+2: Unfinished character list in pattern "[A-]" of modifier ":M"
    111  1.20  rillig # expect+1: Unfinished character list in pattern "[^A-]" of modifier ":M"
    112   1.9  rillig .  if ${WORDS:M${pattern}} != ${EXP.${pattern}}
    113   1.9  rillig .    warning ${pattern}: ${WORDS:M${pattern}} != ${EXP.${pattern}}
    114   1.9  rillig .  endif
    115   1.9  rillig .endfor
    116   1.9  rillig 
    117   1.6  rillig # In brackets, the backslash is just an ordinary character.
    118   1.6  rillig # Outside brackets, it is an escape character for a few special characters.
    119   1.6  rillig # TODO: Str_Match("\\", "[\\-]]")
    120   1.6  rillig # TODO: Str_Match("-]", "[\\-]]")
    121   1.6  rillig 
    122   1.1  rillig all:
    123   1.1  rillig 	@:;
    124