1# $NetBSD: varmod-loop.mk,v 1.5 2020/10/31 12:34:03 rillig Exp $ 2# 3# Tests for the :@var@...${var}...@ variable modifier. 4 5all: mod-loop-varname 6all: mod-loop-resolve 7all: mod-loop-varname-dollar 8all: mod-loop-dollar 9 10# In the :@ modifier, the name of the loop variable can even be generated 11# dynamically. There's no practical use-case for this, and hopefully nobody 12# will ever depend on this, but technically it's possible. 13# Therefore, in -dL mode, this is forbidden, see lint.mk. 14mod-loop-varname: 15 @echo :${:Uone two three:@${:Ubar:S,b,v,}@+${var}+@:Q}: 16 17 # ":::" is a very creative variable name, unlikely in practice. 18 # The expression ${\:\:\:} would not work since backslashes can only 19 # be escaped in the modifiers, but not in the variable name. 20 @echo :${:U1 2 3:@:::@x${${:U\:\:\:}}y@}: 21 22 # "@@" is another creative variable name. 23 @echo :${:U1 2 3:@\@\@@x${@@}y@}: 24 25 # Even "@" works as a variable name since the variable is installed 26 # in the "current" scope, which in this case is the one from the 27 # target. 28 @echo :$@: :${:U1 2 3:@\@@x${@}y@}: :$@: 29 30 # In extreme cases, even the backslash can be used as variable name. 31 # It needs to be doubled though. 32 @echo :${:U1 2 3:@\\@x${${:Ux:S,x,\\,}}y@}: 33 34 # The variable name can technically be empty, and in this situation 35 # the variable value cannot be accessed since the empty variable is 36 # protected to always return an empty string. 37 @echo empty: :${:U1 2 3:@@x${}y@}: 38 39# The :@ modifier resolves the variables a little more often than expected. 40# In particular, it resolves _all_ variables from the context, and not only 41# the loop variable (in this case v). 42# 43# The d means direct reference, the i means indirect reference. 44RESOLVE= ${RES1} $${RES1} 45RES1= 1d${RES2} 1i$${RES2} 46RES2= 2d${RES3} 2i$${RES3} 47RES3= 3 48 49mod-loop-resolve: 50 @echo $@:${RESOLVE:@v@w${v}w@:Q}: 51 52# Until 2020-07-20, the variable name of the :@ modifier could end with one 53# or two dollar signs, which were silently ignored. 54# There's no point in allowing a dollar sign in that position. 55mod-loop-varname-dollar: 56 @echo $@:${1 2 3:L:@v$@($v)@:Q}. 57 @echo $@:${1 2 3:L:@v$$@($v)@:Q}. 58 @echo $@:${1 2 3:L:@v$$$@($v)@:Q}. 59 60# Demonstrate that it is possible to generate dollar characters using the 61# :@ modifier. 62# 63# These are edge cases that could have resulted in a parse error as well 64# since the $@ at the end could have been interpreted as a variable, which 65# would mean a missing closing @ delimiter. 66mod-loop-dollar: 67 @echo $@:${:U1:@word@${word}$@:Q}: 68 @echo $@:${:U2:@word@$${word}$$@:Q}: 69 @echo $@:${:U3:@word@$$${word}$$$@:Q}: 70 @echo $@:${:U4:@word@$$$${word}$$$$@:Q}: 71 @echo $@:${:U5:@word@$$$$${word}$$$$$@:Q}: 72 @echo $@:${:U6:@word@$$$$$${word}$$$$$$@:Q}: 73 74# It may happen that there are nested :@ modifiers that use the same name for 75# for the loop variable. These modifiers influence each other. 76# 77# As of 2020-10-18, the :@ modifier is implemented by actually setting a 78# variable in the context of the expression and deleting it again after the 79# loop. This is different from the .for loops, which substitute the variable 80# expression with ${:Uvalue}, leading to different unwanted side effects. 81# 82# To make the behavior more predictable, the :@ modifier should restore the 83# loop variable to the value it had before the loop. This would result in 84# the string "1a b c1 2a b c2 3a b c3", making the two loops independent. 85.if ${:U1 2 3:@i@$i${:Ua b c:@i@$i@}${i:Uu}@} != "1a b cu 2a b cu 3a b cu" 86. error 87.endif 88 89# During the loop, the variable is actually defined and nonempty. 90# If the loop were implemented in the same way as the .for loop, the variable 91# would be neither defined nor nonempty since all expressions of the form 92# ${var} would have been replaced with ${:Uword} before evaluating them. 93.if defined(var) 94. error 95.endif 96.if ${:Uword:@var@${defined(var):?def:undef} ${empty(var):?empty:nonempty}@} \ 97 != "def nonempty" 98. error 99.endif 100.if defined(var) 101. error 102.endif 103