Home | History | Annotate | Line # | Download | only in unit-tests
var-op-sunsh.mk revision 1.10
      1 # $NetBSD: var-op-sunsh.mk,v 1.10 2022/02/09 21:09:24 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'.
     11 VAR: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.
     18 VAR :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 to the variable named
     28 # 'VAR:shell', using the '=' assignment operator.
     29 VAR:shell=	echo colon-shell
     30 # The variable name needs to be generated using a ${:U...} expression because
     31 # it is not possible to express the ':' as part of a literal variable name,
     32 # see ParseVarname.
     33 .if ${${:UVAR\:shell}} != "echo colon-shell"
     34 .  error
     35 .endif
     36 
     37 # Several colons can syntactically appear in a variable name.
     38 # Until 2020-10-04, the last of them was interpreted as the ':sh'
     39 # assignment operator.
     40 #
     41 # Since 2020-10-04, the colons are part of the variable name.
     42 VAR:shoe:shore=	echo two-colons
     43 .if ${${:UVAR\:shoe\:shore}} != "echo two-colons"
     44 .  error
     45 .endif
     46 
     47 # Until 2020-10-04, the following expression was wrongly marked as
     48 # a parse error.  This was because the parser for variable assignments
     49 # just looked for the previous ":sh", without taking any contextual
     50 # information into account.
     51 #
     52 # There are two different syntactical elements that look exactly the same:
     53 # The variable modifier ':sh' and the assignment operator modifier ':sh'.
     54 # Intuitively this variable name contains the variable modifier, but until
     55 # 2020-10-04, the parser regarded it as an assignment operator modifier, in
     56 # Parse_Var.
     57 VAR.${:Uecho 123:sh}=	ok-123
     58 .if ${VAR.123} != "ok-123"
     59 .  error
     60 .endif
     61 
     62 # Same pattern here. Until 2020-10-04, the ':sh' inside the nested expression
     63 # was taken for the :sh assignment operator modifier, even though it was
     64 # escaped by a backslash.
     65 VAR.${:U echo\:shell}=	ok-shell
     66 .if ${VAR.${:U echo\:shell}} != "ok-shell"
     67 .  error
     68 .endif
     69 
     70 # Until 2020-10-04, the word 'shift' was also affected since it starts with
     71 # ':sh'.
     72 VAR.key:shift=		Shift
     73 .if ${${:UVAR.key\:shift}} != "Shift"
     74 .  error
     75 .endif
     76 
     77 # Just for fun: The code in Parse_IsVar allows for multiple appearances of
     78 # the ':sh' assignment operator modifier.  Let's see what happens ...
     79 #
     80 # Well, the end result is correct but the way until there is rather
     81 # adventurous.  This only works because the parser replaces each and every
     82 # whitespace character that is not nested with '\0' (see Parse_Var).
     83 # The variable name therefore ends before the first ':sh', and the last
     84 # ':sh' turns the assignment operator into the shell command evaluation.
     85 # Parse_Var completely trusts Parse_IsVar to properly verify the syntax.
     86 #
     87 # The ':sh' is the only word that may occur between the variable name and
     88 # the assignment operator at nesting level 0.  All other words would lead
     89 # to a parse error since the left-hand side of an assignment must be
     90 # exactly one word.
     91 VAR :sh :sh :sh :sh=	echo multiple
     92 .if ${VAR} != "multiple"
     93 .  error
     94 .endif
     95 
     96 # The word ':sh' is not the only thing that can occur after a variable name.
     97 # Since the parser just counts braces and parentheses instead of properly
     98 # expanding nested expressions, the token ' :sh' can be used to add arbitrary
     99 # text between the variable name and the assignment operator, it just has to
    100 # be enclosed in braces or parentheses.
    101 #
    102 # Since the text to the left of the assignment operator '=' does not end with
    103 # ':sh', the effective assignment operator becomes '=', not '!='.
    104 VAR :sh(Put a comment here)=	comment in parentheses
    105 .if ${VAR} != "comment in parentheses"
    106 .  error
    107 .endif
    108 
    109 # The unintended comment can include multiple levels of nested braces and
    110 # parentheses.  Braces and parentheses are interchangeable, that is, a '(' can
    111 # be closed by either ')' or '}'.  These braces and parentheses are only
    112 # counted by Parse_IsVar, in particular Parse_Var doesn't see them.
    113 VAR :sh{Put}((((a}{comment}}}}{here}=	comment in braces
    114 .if ${VAR} != "comment in braces"
    115 .  error
    116 .endif
    117 
    118 # The assignment modifier ':sh' can be combined with the assignment operator
    119 # '+='.  In such a case the ':sh' is silently ignored, and the effective
    120 # assignment operator is '+='.
    121 #
    122 # XXX: This combination should not be allowed at all, as it is confusing.
    123 VAR=		one
    124 VAR :sh +=	echo two
    125 .if ${VAR} != "one echo two"
    126 .  error ${VAR}
    127 .endif
    128 
    129 # The assignment modifier ':sh' can be combined with the assignment operator
    130 # '!='.  In such a case the ':sh' is silently ignored, and the effective
    131 # assignment operator is '!=', just like with '+=' or the other compound
    132 # assignment operators.
    133 #
    134 # XXX: This combination should not be allowed at all, as it is confusing.
    135 VAR :sh !=	echo echo echo echo spaces-around
    136 .if ${VAR} != "echo echo echo spaces-around"
    137 .  error ${VAR}
    138 .endif
    139 
    140 # If there is no space between the variable name and the assignment modifier
    141 # ':sh', the ':sh' becomes part of the variable name, as the parser only
    142 # expects a single assignment modifier to the left of the '=', which in this
    143 # case is the '!'.
    144 VAR:sh !=	echo echo echo echo space-after
    145 .if ${${:UVAR\:sh}} != "echo echo echo space-after"
    146 .  error ${${:UVAR\:sh}}
    147 .endif
    148 
    149 all: .PHONY
    150