aboutsummaryrefslogtreecommitdiff
path: root/contrib/bmake/unit-tests/varmod-defined.mk
blob: a44b9f99314687ea2d3a7f6be08bce6ff8eea2df (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
# $NetBSD: varmod-defined.mk,v 1.11 2021/04/11 13:35:56 rillig Exp $
#
# Tests for the :D variable modifier, which returns the given string
# if the variable is defined.  It is closely related to the :U modifier.

.MAKE.SAVE_DOLLARS=	yes

DEF=	defined
.undef UNDEF

# Since DEF is defined, the value of the expression is "value", not
# "defined".
#
.if ${DEF:Dvalue} != "value"
.  error
.endif

# Since UNDEF is not defined, the "value" is ignored.  Instead of leaving the
# expression undefined, it is set to "", exactly to allow the expression to
# be used in .if conditions.  In this place, other undefined expressions
# would generate an error message.
# XXX: Ideally the error message would be "undefined variable", but as of
# 2020-08-25 it is "Malformed conditional".
#
.if ${UNDEF:Dvalue} != ""
.  error
.endif

# The modifier text may contain plain text as well as expressions.
#
.if ${DEF:D<${DEF}>} != "<defined>"
.  error
.endif

# Special characters that would be interpreted differently can be escaped.
# These are '}' (the closing character of the expression), ':', '$' and '\'.
# Any other backslash sequences are preserved.
#
# The escaping rules for string literals in conditions are completely
# different though. There, any character may be escaped using a backslash.
#
.if ${DEF:D \} \: \$ \\ \) \n } != " } : \$ \\ \\) \\n "
.  error
.endif

# Like in several other places in variable expressions, when
# ApplyModifier_Defined calls Var_Parse, double dollars lead to a parse
# error that is silently ignored.  This makes all dollar signs disappear,
# except for the last, which is a well-formed variable expression.
#
.if ${DEF:D$$$$$${DEF}} != "defined"
.  error
.endif

# Any other text is written without any further escaping.  In contrast
# to the :M modifier, parentheses and braces do not need to be nested.
# Instead, the :D modifier is implemented sanely by parsing nested
# expressions as such, without trying any shortcuts. See ApplyModifier_Match
# for an inferior variant.
#
.if ${DEF:D!&((((} != "!&(((("
.  error
.endif

# The :D modifier is often used in combination with the :U modifier.
# It does not matter in which order the :D and :U modifiers appear.
.if ${UNDEF:Dyes:Uno} != no
.  error
.endif
.if ${UNDEF:Uno:Dyes} != no
.  error
.endif
.if ${DEF:Dyes:Uno} != yes
.  error
.endif
.if ${DEF:Uno:Dyes} != yes
.  error
.endif

# Since the variable with the empty name is never defined, the :D modifier
# can be used to add comments in the middle of an expression.  That
# expression always evaluates to an empty string.
.if ${:D This is a comment. } != ""
.  error
.endif

# TODO: Add more tests for parsing the plain text part, to cover each branch
# of ApplyModifier_Defined.

# The :D and :U modifiers behave differently from the :@var@ modifier in
# that they preserve dollars in a ':=' assignment.  This is because
# ApplyModifier_Defined passes the emode unmodified to Var_Parse, unlike
# ApplyModifier_Loop, which uses ParseModifierPart, which in turn removes
# the keepDollar flag from emode.
#
# XXX: This inconsistency is documented nowhere.
.MAKEFLAGS: -dv
8_DOLLARS=	$$$$$$$$
VAR:=		${8_DOLLARS}
VAR:=		${VAR:D${8_DOLLARS}}
VAR:=		${VAR:@var@${8_DOLLARS}@}
.MAKEFLAGS: -d0

all:
	@:;