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