varmod-match-escape.mk revision 1.9 1 1.9 rillig # $NetBSD: varmod-match-escape.mk,v 1.9 2023/06/22 20:36:24 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.1 rillig # depending on whether there was a variable expression somewhere before the
5 1.7 rillig # first backslash or not. See ApplyModifier_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.4 rillig # as well as a variable expression that expands to a ':'.
22 1.4 rillig #
23 1.4 rillig # XXX: As of 2020-11-01, when an escaped ':' occurs before the variable
24 1.4 rillig # expression, the whole modifier text is subject to unescaping '\:' to ':',
25 1.4 rillig # before the variable expression is expanded. This means that the '\:' in
26 1.4 rillig # the variable 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.4 rillig # comparison is parsed differently though. First, the variable 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.4 rillig # If ApplyModifier_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.5 rillig # parsed as an escaped '$'. Instead, ApplyModifier_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.5 rillig .if ${:U\$:M\$} != ""
63 1.5 rillig . error
64 1.5 rillig .endif
65 1.5 rillig
66 1.5 rillig # In lint mode, the case of a lonely '$' is covered with an error message.
67 1.5 rillig .MAKEFLAGS: -dL
68 1.8 rillig # expect+1: Dollar followed by nothing
69 1.5 rillig .if ${:U\$:M\$} != ""
70 1.5 rillig . error
71 1.5 rillig .endif
72 1.5 rillig
73 1.6 rillig # The control flow of the pattern parser depends on the actual string that
74 1.6 rillig # is being matched. There needs to be either a test that shows a difference
75 1.6 rillig # in behavior, or a proof that the behavior does not depend on the actual
76 1.6 rillig # string.
77 1.6 rillig #
78 1.6 rillig # TODO: Str_Match("a-z]", "[a-z]")
79 1.6 rillig # TODO: Str_Match("012", "[0-]]")
80 1.6 rillig # TODO: Str_Match("[", "[[]")
81 1.6 rillig # TODO: Str_Match("]", "[]")
82 1.6 rillig # TODO: Str_Match("]", "[[-]]")
83 1.6 rillig
84 1.9 rillig # Demonstrate an inconsistency between positive and negative character lists
85 1.9 rillig # when the range ends with the character ']'.
86 1.9 rillig #
87 1.9 rillig # 'A' begins the range, 'B' is in the middle of the range, ']' ends the range,
88 1.9 rillig # 'a' is outside the range.
89 1.9 rillig WORDS= A A] A]] B B] B]] ] ]] ]]] a a] a]]
90 1.9 rillig # The ']' is part of the character range and at the same time ends the
91 1.9 rillig # character list.
92 1.9 rillig EXP.[A-]= A B ]
93 1.9 rillig # The first ']' is part of the character range and at the same time ends the
94 1.9 rillig # character list.
95 1.9 rillig EXP.[A-]]= A] B] ]]
96 1.9 rillig # The first ']' is part of the character range and at the same time ends the
97 1.9 rillig # character list.
98 1.9 rillig EXP.[A-]]]= A]] B]] ]]]
99 1.9 rillig # For negative character lists, the ']' ends the character range but does not
100 1.9 rillig # end the character list.
101 1.9 rillig # XXX: This is unnecessarily inconsistent but irrelevant in practice as there
102 1.9 rillig # is no practical need for a character range that ends at ']'.
103 1.9 rillig EXP.[^A-]= a
104 1.9 rillig EXP.[^A-]]= a
105 1.9 rillig EXP.[^A-]]]= a]
106 1.9 rillig
107 1.9 rillig .for pattern in [A-] [A-]] [A-]]] [^A-] [^A-]] [^A-]]]
108 1.9 rillig . if ${WORDS:M${pattern}} != ${EXP.${pattern}}
109 1.9 rillig . warning ${pattern}: ${WORDS:M${pattern}} != ${EXP.${pattern}}
110 1.9 rillig . endif
111 1.9 rillig .endfor
112 1.9 rillig
113 1.6 rillig # In brackets, the backslash is just an ordinary character.
114 1.6 rillig # Outside brackets, it is an escape character for a few special characters.
115 1.6 rillig # TODO: Str_Match("\\", "[\\-]]")
116 1.6 rillig # TODO: Str_Match("-]", "[\\-]]")
117 1.6 rillig
118 1.1 rillig all:
119 1.1 rillig @:;
120