Home | History | Annotate | Line # | Download | only in unit-tests
var-op-sunsh.mk revision 1.6
      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'.
     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 using the '='
     28 # assignment operator.
     29 VAR: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.
     39 VAR: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.
     54 VAR.${: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.
     62 VAR.${: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'.
     69 VAR.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.
     88 VAR :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.
     98 VAR :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.
    106 VAR :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.
    115 VAR=		one
    116 VAR :sh +=	echo two
    117 .if ${VAR} != "one echo two"
    118 .  error ${VAR}
    119 .endif
    120 
    121 # TODO: test VAR:sh!=command
    122 
    123 all:
    124 	@:;
    125