1# $NetBSD: var-op-sunsh.mk,v 1.8 2021/04/04 10:13:09 rillig Exp $ 2# 3# Tests for the :sh= variable assignment operator, which runs its right-hand 4# side through the shell. It is a seldom-used alternative to the != 5# assignment operator, adopted from Sun make. 6 7.MAKEFLAGS: -dL # Enable sane error messages 8 9# This is the idiomatic form of the Sun shell assignment operator. 10# The assignment operator is directly preceded by the ':sh'. 11VAR:sh= echo colon-sh 12.if ${VAR} != "colon-sh" 13. error 14.endif 15 16# It is also possible to have whitespace around the :sh assignment 17# operator modifier. 18VAR :sh = echo colon-sh-spaced 19.if ${VAR} != "colon-sh-spaced" 20. error 21.endif 22 23# Until 2020-10-04, the ':sh' could even be followed by other characters. 24# This was neither documented by NetBSD make nor by Solaris make and was 25# an implementation error. 26# 27# Since 2020-10-04, this is a normal variable assignment using the '=' 28# assignment operator. 29VAR:shell= echo colon-shell 30.if ${${:UVAR\:shell}} != "echo colon-shell" 31. error 32.endif 33 34# Several colons can syntactically appear in a variable name. 35# Until 2020-10-04, the last of them was interpreted as the ':sh' 36# assignment operator. 37# 38# Since 2020-10-04, the colons are part of the variable name. 39VAR:shoe:shore= echo two-colons 40.if ${${:UVAR\:shoe\:shore}} != "echo two-colons" 41. error 42.endif 43 44# Until 2020-10-04, the following expression was wrongly marked as 45# a parse error. This was because the parser for variable assignments 46# just looked for the previous ":sh", without taking any contextual 47# information into account. 48# 49# There are two different syntactical elements that look exactly the same: 50# The variable modifier ':sh' and the assignment operator modifier ':sh'. 51# Intuitively this variable name contains the variable modifier, but until 52# 2020-10-04, the parser regarded it as an assignment operator modifier, in 53# Parse_Var. 54VAR.${:Uecho 123:sh}= ok-123 55.if ${VAR.123} != "ok-123" 56. error 57.endif 58 59# Same pattern here. Until 2020-10-04, the ':sh' inside the nested expression 60# was taken for the :sh assignment operator modifier, even though it was 61# escaped by a backslash. 62VAR.${:U echo\:shell}= ok-shell 63.if ${VAR.${:U echo\:shell}} != "ok-shell" 64. error 65.endif 66 67# Until 2020-10-04, the word 'shift' was also affected since it starts with 68# ':sh'. 69VAR.key:shift= Shift 70.if ${${:UVAR.key\:shift}} != "Shift" 71. error 72.endif 73 74# Just for fun: The code in Parse_IsVar allows for multiple appearances of 75# the ':sh' assignment operator modifier. Let's see what happens ... 76# 77# Well, the end result is correct but the way until there is rather 78# adventurous. This only works because the parser replaces each and every 79# whitespace character that is not nested with '\0' (see Parse_Var). 80# The variable name therefore ends before the first ':sh', and the last 81# ':sh' turns the assignment operator into the shell command evaluation. 82# Parse_Var completely trusts Parse_IsVar to properly verify the syntax. 83# 84# The ':sh' is the only word that may occur between the variable name and 85# the assignment operator at nesting level 0. All other words would lead 86# to a parse error since the left-hand side of an assignment must be 87# exactly one word. 88VAR :sh :sh :sh :sh= echo multiple 89.if ${VAR} != "multiple" 90. error 91.endif 92 93# The word ':sh' is not the only thing that can occur after a variable name. 94# Since the parser just counts braces and parentheses instead of properly 95# expanding nested expressions, the token ' :sh' can be used to add arbitrary 96# text between the variable name and the assignment operator, it just has to 97# be enclosed in braces or parentheses. 98VAR :sh(Put a comment here)= comment in parentheses 99.if ${VAR} != "comment in parentheses" 100. error 101.endif 102 103# The unintended comment can include multiple levels of nested braces and 104# parentheses, they don't even need to be balanced since they are only 105# counted by Parse_IsVar and ignored by Parse_Var. 106VAR :sh{Put}((((a}{comment}}}}{here}= comment in braces 107.if ${VAR} != "comment in braces" 108. error 109.endif 110 111# Syntactically, the ':sh' modifier can be combined with the '+=' assignment 112# operator. In such a case the ':sh' modifier is silently ignored. 113# 114# XXX: This combination should not be allowed at all. 115VAR= one 116VAR :sh += echo two 117.if ${VAR} != "one echo two" 118. error ${VAR} 119.endif 120 121# TODO: test VAR:sh!=command 122 123all: 124 @:; 125