1# $NetBSD: var-op-sunsh.mk,v 1.6 2020/11/15 20:20:58 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_DoVar.
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 an every
79# whitespace character that is not nested with '\0' (see Parse_DoVar).
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_DoVar 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_DoVar.
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