1# $NetBSD: varmod-indirect.mk,v 1.5 2020/12/27 17:32:25 rillig Exp $ 2# 3# Tests for indirect variable modifiers, such as in ${VAR:${M_modifiers}}. 4# These can be used for very basic purposes like converting a string to either 5# uppercase or lowercase, as well as for fairly advanced modifiers that first 6# look like line noise and are hard to decipher. 7# 8# TODO: Since when are indirect modifiers supported? 9 10 11# To apply a modifier indirectly via another variable, the whole 12# modifier must be put into a single variable expression. 13.if ${value:L:${:US}${:U,value,replacement,}} != "S,value,replacement,}" 14. warning unexpected 15.endif 16 17 18# Adding another level of indirection (the 2 nested :U expressions) helps. 19.if ${value:L:${:U${:US}${:U,value,replacement,}}} != "replacement" 20. warning unexpected 21.endif 22 23 24# Multiple indirect modifiers can be applied one after another as long as 25# they are separated with colons. 26.if ${value:L:${:US,a,A,}:${:US,e,E,}} != "vAluE" 27. warning unexpected 28.endif 29 30 31# An indirect variable that evaluates to the empty string is allowed though. 32# This makes it possible to define conditional modifiers, like this: 33# 34# M.little-endian= S,1234,4321, 35# M.big-endian= # none 36.if ${value:L:${:Dempty}S,a,A,} != "vAlue" 37. warning unexpected 38.endif 39 40 41# The nested variable expression expands to "tu", and this is interpreted as 42# a variable modifier for the value "Upper", resulting in "UPPER". 43.if ${Upper:L:${:Utu}} != "UPPER" 44. error 45.endif 46 47# The nested variable expression expands to "tl", and this is interpreted as 48# a variable modifier for the value "Lower", resulting in "lower". 49.if ${Lower:L:${:Utl}} != "lower" 50. error 51.endif 52 53 54# The nested variable expression is ${1 != 1:?Z:tl}, consisting of the 55# condition "1 != 1", the then-branch "Z" and the else-branch "tl". Since 56# the condition evaluates to false, the then-branch is ignored (it would 57# have been an unknown modifier anyway) and the ":tl" modifier is applied. 58.if ${Mixed:L:${1 != 1:?Z:tl}} != "mixed" 59. error 60.endif 61 62 63# The indirect modifier can also replace an ':L' modifier, which allows for 64# brain twisters since by reading the expression alone, it is not possible 65# to say whether the variable name will be evaluated as a variable name or 66# as the immediate value of the expression. 67VAR= value 68M_ExpandVar= # an empty modifier 69M_VarAsValue= L 70# 71.if ${VAR:${M_ExpandVar}} != "value" 72. error 73.endif 74.if ${VAR:${M_VarAsValue}} != "VAR" 75. error 76.endif 77 78# The indirect modifier M_ListToSkip, when applied to a list of patterns, 79# expands to a sequence of ':N' modifiers, each of which filters one of the 80# patterns. This list of patterns can then be applied to another variable 81# to actually filter that variable. 82# 83M_ListToSkip= @pat@N$${pat}@:ts: 84# 85# The dollar signs need to be doubled in the above modifier expression, 86# otherwise they would be expanded too early, that is, when parsing the 87# modifier itself. 88# 89# In the following example, M_NoPrimes expands to 'N2:N3:N5:N7:N1[1379]'. 90# The 'N' comes from the expression 'N${pat}', the separating colons come 91# from the modifier ':ts:'. 92# 93#.MAKEFLAGS: -dcv # Uncomment this line to see the details 94# 95PRIMES= 2 3 5 7 1[1379] 96M_NoPrimes= ${PRIMES:${M_ListToSkip}} 97.if ${:U:range=20:${M_NoPrimes}} != "1 4 6 8 9 10 12 14 15 16 18 20" 98. error 99.endif 100.MAKEFLAGS: -d0 101 102 103# In contrast to the .if conditions, the .for loop allows undefined variable 104# expressions. These expressions expand to empty strings. 105 106# An undefined expression without any modifiers expands to an empty string. 107.for var in before ${UNDEF} after 108. info ${var} 109.endfor 110 111# An undefined expression with only modifiers that keep the expression 112# undefined expands to an empty string. 113.for var in before ${UNDEF:${:US,a,a,}} after 114. info ${var} 115.endfor 116 117# Even in an indirect modifier based on an undefined variable, the value of 118# the expression in Var_Parse is a simple empty string. 119.for var in before ${UNDEF:${:U}} after 120. info ${var} 121.endfor 122 123# An error in an indirect modifier. 124.for var in before ${UNDEF:${:UZ}} after 125. info ${var} 126.endfor 127 128 129# Another slightly different evaluation context is the right-hand side of 130# a variable assignment using ':='. 131.MAKEFLAGS: -dpv 132 133# The undefined variable expression is kept as-is. 134_:= before ${UNDEF} after 135 136# The undefined variable expression is kept as-is. 137_:= before ${UNDEF:${:US,a,a,}} after 138 139# XXX: The subexpression ${:U} is fully defined, therefore it is expanded. 140# This results in ${UNDEF:}, which can lead to tricky parse errors later, 141# when the variable '_' is expanded further. 142# 143# XXX: What should be the correct strategy here? One possibility is to 144# expand the defined subexpression and replace it with ${:U...}, just like 145# in .for loops. This would preserve the structure of the expression while 146# at the same time expanding the expression as far as possible. 147_:= before ${UNDEF:${:U}} after 148 149# XXX: This expands to ${UNDEF:Z}, which will behave differently if the 150# variable '_' is used in a context where the variable expression ${_} is 151# parsed but not evaluated. 152_:= before ${UNDEF:${:UZ}} after 153 154.MAKEFLAGS: -d0 155.undef _ 156 157all: 158