xref: /freebsd/contrib/bmake/unit-tests/varname.mk (revision a8c56be47166295d37600ff81fc1857db87b3a9b)
1# $NetBSD: varname.mk,v 1.18 2025/06/28 22:39:29 rillig Exp $
2#
3# Tests for variable names.
4
5.MAKEFLAGS: -dv
6
7# In a variable assignment, braces are allowed in the variable name, but they
8# must be balanced.  Parentheses and braces may be mixed.
9VAR{{{}}}=	3 braces
10.if "${VAR{{{}}}}" != "3 braces"
11.  error
12.endif
13
14# In expressions, the parser works differently.  It doesn't treat
15# braces and parentheses equally, therefore the first closing brace already
16# marks the end of the variable name.
17VARNAME=	VAR(((
18${VARNAME}=	3 open parentheses
19.if "${VAR(((}}}}" != "3 open parentheses}}}"
20.  error
21.endif
22
23# In the above test, the variable name is constructed indirectly.  Neither
24# of the following expressions produces the intended effect.
25#
26# This is not a variable assignment since the parentheses and braces are not
27# balanced.  At the end of the line, there are still 3 levels open, which
28# means the variable name is not finished.
29# expect+2: Missing ")" in archive specification
30# expect+1: Error in archive specification: "VAR"
31${:UVAR(((}=	try1
32# On the left-hand side of a variable assignments, the backslash is not parsed
33# as an escape character, therefore the parentheses still count to the nesting
34# level, which at the end of the line is still 3.  Therefore this is not a
35# variable assignment as well.
36# expect+1: Invalid line "${:UVAR\(\(\(}=	try2", expanded to "VAR\(\(\(=	try2"
37${:UVAR\(\(\(}=	try2
38# To assign to a variable with an arbitrary name, the variable name has to
39# come from an external source, not the text that is parsed in the assignment
40# itself.  This is exactly the reason why further above, the indirect
41# ${VARNAME} works, while all other attempts fail.
42${VARNAME}=	try3
43
44.MAKEFLAGS: -d0
45
46# All variable names of a scope are stored in the same hash table, using a
47# simple hash function.  Ensure that HashTable_Find handles collisions
48# correctly and that the correct variable is looked up.  The strings "0x" and
49# "1Y" have the same hash code, as 31 * '0' + 'x' == 31 * '1' + 'Y'.
50V.0x=	0x
51V.1Y=	1Y
52.if ${V.0x} != "0x" || ${V.1Y} != "1Y"
53.  error
54.endif
55
56# The string "ASDZguv", when used as a prefix of a variable name, keeps the
57# hash code unchanged, its own hash code is 0.
58ASDZguvV.0x=	0x
59ASDZguvV.1Y=	1Y
60.if ${ASDZguvV.0x} != "0x"
61.  error
62.elif ${ASDZguvV.1Y} != "1Y"
63.  error
64.endif
65
66# Ensure that variables with the same hash code whose name is a prefix of the
67# other can be accessed.  In this case, the shorter variable name is defined
68# first to make it appear later in the bucket of the hash table.
69ASDZguv=	once
70ASDZguvASDZguv=	twice
71.if ${ASDZguv} != "once"
72.  error
73.elif ${ASDZguvASDZguv} != "twice"
74.  error
75.endif
76
77# Ensure that variables with the same hash code whose name is a prefix of the
78# other can be accessed.  In this case, the longer variable name is defined
79# first to make it appear later in the bucket of the hash table.
80ASDZguvASDZguv.param=	twice
81ASDZguv.param=		once
82.if ${ASDZguv.param} != "once"
83.  error
84.elif ${ASDZguvASDZguv.param} != "twice"
85.  error
86.endif
87
88
89# Warn about expressions in the style of GNU make, as these would silently
90# expand to an empty string instead.
91#
92# https://pubs.opengroup.org/onlinepubs/9799919799/utilities/make.html says:
93#	a macro name shall not contain an <equals-sign>, <blank>, or control
94#	character.
95#
96GNU_MAKE_IF=	$(if ${HAVE_STRLEN},yes,no)
97# expect+1: warning: Invalid character " " in variable name "if ,yes,no"
98.if ${GNU_MAKE_IF} != ""
99.  error
100.endif
101#
102# This requirement needs to be ignored for expressions with a ":L" or ":?:"
103# modifier, as these modifiers rely on arbitrary characters in the expression
104# name.
105.if ${"left" == "right":?equal:unequal} != "unequal"
106.  error
107.endif
108#
109# In fact, this requirement is ignored for any expression that has a modifier.
110# In this indirect case, though, the expression with the space in the name is
111# a nested expression, so the ":U" modifier doesn't affect the warning.
112# expect+1: warning: Invalid character " " in variable name "if ,yes,no"
113.if ${GNU_MAKE_IF:Ufallback} != ""
114.  error
115.endif
116#
117# A modifier in a nested expression does not affect the warning.
118GNU_MAKE_IF_EXPR=	$(if ${HAVE_STRLEN},${HEADERS:.h=.c},)
119# expect+1: warning: Invalid character " " in variable name "if ,,"
120.if ${GNU_MAKE_IF_EXPR} != ""
121.  error
122.endif
123#
124# When the GNU make expression contains a colon, chances are good that the
125# colon is interpreted as an unknown modifier.
126GNU_MAKE_IF_MODIFIER=	$(if ${HAVE_STRLEN},answer:yes,answer:no)
127# expect+1: Unknown modifier ":yes,answer"
128.if ${GNU_MAKE_IF_MODIFIER} != "no)"
129.  error
130.endif
131#
132# If the variable name contains a non-printable character, the warning
133# contains the numeric character value instead, to prevent control sequences
134# in the output.
135CONTROL_CHARACTER=	${:U a b:ts\t}
136# expect+2: warning: Invalid character "\x09" in variable name "a	b"
137# expect+1: Variable "a	b" is undefined
138.if ${${CONTROL_CHARACTER}} != ""
139.endif
140#
141# For now, only whitespace generates a warning, non-ASCII characters don't.
142UMLAUT=		ÄÖÜ
143# expect+1: Variable "ÄÖÜ" is undefined
144.if ${${UMLAUT}} != ""
145.endif
146