1# $NetBSD: varmod-match.mk,v 1.8 2022/03/27 18:39:01 rillig Exp $ 2# 3# Tests for the :M variable modifier, which filters words that match the 4# given pattern. 5# 6# See ApplyModifier_Match and ModifyWord_Match for the implementation. 7 8.MAKEFLAGS: -dc 9 10NUMBERS= One Two Three Four five six seven 11 12# Only keep words that start with an uppercase letter. 13.if ${NUMBERS:M[A-Z]*} != "One Two Three Four" 14. error 15.endif 16 17# Only keep words that start with a character other than an uppercase letter. 18.if ${NUMBERS:M[^A-Z]*} != "five six seven" 19. error 20.endif 21 22# Only keep words that don't start with s and at the same time end with 23# either of [ex]. 24# 25# This test case ensures that the negation from the first character class 26# does not propagate to the second character class. 27.if ${NUMBERS:M[^s]*[ex]} != "One Three five" 28. error 29.endif 30 31# Before 2020-06-13, this expression took quite a long time in Str_Match, 32# calling itself 601080390 times for 16 asterisks. 33.if ${:U****************:M****************b} 34.endif 35 36# To match a dollar sign in a word, double it. 37# 38# This is different from the :S and :C variable modifiers, where a '$' 39# has to be escaped as '\$'. 40.if ${:Ua \$ sign:M*$$*} != "\$" 41. error 42.endif 43 44# In the :M modifier, '\$' does not escape a dollar. Instead it is 45# interpreted as a backslash followed by whatever expression the 46# '$' starts. 47# 48# This differs from the :S, :C and several other variable modifiers. 49${:U*}= asterisk 50.if ${:Ua \$ sign any-asterisk:M*\$*} != "any-asterisk" 51. error 52.endif 53 54# TODO: ${VAR:M(((}}}} 55# TODO: ${VAR:M{{{)))} 56# TODO: ${VAR:M${UNBALANCED}} 57# TODO: ${VAR:M${:U(((\}\}\}}} 58 59.MAKEFLAGS: -d0 60 61# Special characters: 62# * matches 0 or more arbitrary characters 63# ? matches a single arbitrary character 64# \ starts an escape sequence, only outside ranges 65# [ starts a set for matching a single character 66# ] ends a set for matching a single character 67# - in a set, forms a range of characters 68# ^ as the first character in a set, negates the set 69# ( during parsing of the pattern, starts a nesting level 70# ) during parsing of the pattern, ends a nesting level 71# { during parsing of the pattern, starts a nesting level 72# } during parsing of the pattern, ends a nesting level 73# : during parsing of the pattern, finishes the pattern 74# $ during parsing of the pattern, starts a nested expression 75# # in a line except a shell command, starts a comment 76# 77# Pattern parts: 78# * matches 0 or more arbitrary characters 79# ? matches exactly 1 arbitrary character 80# \x matches exactly the character 'x' 81# [...] matches exactly 1 character from the set 82# [^...] matches exactly 1 character outside the set 83# [a-z] matches exactly 1 character from the range 'a' to 'z' 84# 85 86# [] matches never 87.if ${ ab a[]b a[b a b :L:M[]} != "" 88. error 89.endif 90 91# a[]b matches never 92.if ${ ab a[]b a[b a b [ ] :L:Ma[]b} != "" 93. error 94.endif 95 96# [^] matches exactly 1 arbitrary character 97.if ${ ab a[]b a[b a b [ ] :L:M[^]} != "a b [ ]" 98. error 99.endif 100 101# a[^]b matches 'a', then exactly 1 arbitrary character, then 'b' 102.if ${ ab a[]b a[b a b :L:Ma[^]b} != "a[b" 103. error 104.endif 105 106# [Nn0] matches exactly 1 character from the set 'N', 'n', '0' 107.if ${ a b N n 0 Nn0 [ ] :L:M[Nn0]} != "N n 0" 108. error 109.endif 110 111# [a-c] matches exactly 1 character from the range 'a' to 'c' 112.if ${ A B C a b c d [a-c] [a] :L:M[a-c]} != "a b c" 113. error 114.endif 115 116# [c-a] matches the same as [a-c] 117.if ${ A B C a b c d [a-c] [a] :L:M[c-a]} != "a b c" 118. error 119.endif 120 121# [^a-c67] 122# matches a single character, except for 'a', 'b', 'c', '6' or 123# '7' 124.if ${ A B C a b c d 5 6 7 8 [a-c] [a] :L:M[^a-c67]} != "A B C d 5 8" 125. error 126.endif 127 128# : terminates the pattern 129.if ${ A * :L:M:} != "" 130. error 131.endif 132 133# \: matches a colon 134.if ${ ${:U\: \:\:} :L:M\:} != ":" 135. error 136.endif 137 138# ${:U\:} matches a colon 139.if ${ ${:U\:} ${:U\:\:} :L:M${:U\:}} != ":" 140. error 141.endif 142 143# [:] matches never since the ':' starts the next modifier 144# expect+2: Unknown modifier "]" 145# expect+1: Malformed conditional (${ ${:U\:} ${:U\:\:} :L:M[:]} != ":") 146.if ${ ${:U\:} ${:U\:\:} :L:M[:]} != ":" 147. error 148.else 149. error 150.endif 151 152# [\] matches exactly a backslash; no escaping takes place in 153# character ranges 154# Without the 'a' in the below expressions, the backslash would end a word and 155# thus influence how the string is split into words. 156.if ${ ${:U\\a} ${:U\\\\a} :L:M[\]a} != "\\a" 157. error 158.endif 159 160#.MAKEFLAGS: -dcv 161# 162# Incomplete patterns: 163# [ matches TODO 164# [x matches TODO 165# [^ matches TODO 166# [- matches TODO 167# [xy matches TODO 168# [^x matches TODO 169# [\ matches TODO 170# 171# [x- matches exactly 'x', doesn't match 'x-' 172# [^x- matches TODO 173# \ matches never 174 175 176# The modifier ':tW' prevents splitting at whitespace. Even leading and 177# trailing whitespace is preserved. 178.if ${ plain string :L:tW:M*} != " plain string " 179. error 180.endif 181 182# Without the modifier ':tW', the string is split into words. All whitespace 183# around and between the words is normalized to a single space. 184.if ${ plain string :L:M*} != "plain string" 185. error 186.endif 187