xref: /freebsd/contrib/bmake/unit-tests/varmod-ifelse.mk (revision 8d5c8e21c690b35d0a9a604d6b886fba222cd2fe)
1*8d5c8e21SSimon J. Gerraty# $NetBSD: varmod-ifelse.mk,v 1.29 2024/06/02 15:31:26 rillig Exp $
22c3632d1SSimon J. Gerraty#
32c3632d1SSimon J. Gerraty# Tests for the ${cond:?then:else} variable modifier, which evaluates either
42c3632d1SSimon J. Gerraty# the then-expression or the else-expression, depending on the condition.
5956e45f6SSimon J. Gerraty#
6956e45f6SSimon J. Gerraty# The modifier was added on 1998-04-01.
7956e45f6SSimon J. Gerraty#
8956e45f6SSimon J. Gerraty# Until 2015-10-11, the modifier always evaluated both the "then" and the
9956e45f6SSimon J. Gerraty# "else" expressions.
102c3632d1SSimon J. Gerraty
112c3632d1SSimon J. Gerraty# TODO: Implementation
122c3632d1SSimon J. Gerraty
13956e45f6SSimon J. Gerraty# The variable name of the expression is expanded and then taken as the
149f45a3c8SSimon J. Gerraty# condition.  In the below example it becomes:
15956e45f6SSimon J. Gerraty#
16d5e0a182SSimon J. Gerraty#	bare words == "literal"
17956e45f6SSimon J. Gerraty#
18956e45f6SSimon J. Gerraty# This confuses the parser, which expects an operator instead of the bare
19956e45f6SSimon J. Gerraty# word "expression".  If the name were expanded lazily, everything would be
20956e45f6SSimon J. Gerraty# fine since the condition would be:
21956e45f6SSimon J. Gerraty#
22d5e0a182SSimon J. Gerraty#	${:Ubare words} == "literal"
23956e45f6SSimon J. Gerraty#
24956e45f6SSimon J. Gerraty# Evaluating the variable name lazily would require additional code in
25956e45f6SSimon J. Gerraty# Var_Parse and ParseVarname, it would be more useful and predictable
26956e45f6SSimon J. Gerraty# though.
27d5e0a182SSimon J. Gerraty# expect+1: Malformed conditional (${${:Ubare words} == "literal":?bad:bad})
28d5e0a182SSimon J. Gerraty.if ${${:Ubare words} == "literal":?bad:bad}
29956e45f6SSimon J. Gerraty.  error
30956e45f6SSimon J. Gerraty.else
31956e45f6SSimon J. Gerraty.  error
32956e45f6SSimon J. Gerraty.endif
33956e45f6SSimon J. Gerraty
34956e45f6SSimon J. Gerraty# In a variable assignment, undefined variables are not an error.
35956e45f6SSimon J. Gerraty# Because of the early expansion, the whole condition evaluates to
36956e45f6SSimon J. Gerraty# ' == ""' though, which cannot be parsed because the left-hand side looks
37956e45f6SSimon J. Gerraty# empty.
38956e45f6SSimon J. GerratyCOND:=	${${UNDEF} == "":?bad-assign:bad-assign}
39956e45f6SSimon J. Gerraty
40956e45f6SSimon J. Gerraty# In a condition, undefined variables generate a "Malformed conditional"
41956e45f6SSimon J. Gerraty# error.  That error message is wrong though.  In lint mode, the correct
42956e45f6SSimon J. Gerraty# "Undefined variable" error message is generated.
43956e45f6SSimon J. Gerraty# The difference to the ':=' variable assignment is the additional
44956e45f6SSimon J. Gerraty# "Malformed conditional" error message.
45148ee845SSimon J. Gerraty# expect+1: Malformed conditional (${${UNDEF} == "":?bad-cond:bad-cond})
46956e45f6SSimon J. Gerraty.if ${${UNDEF} == "":?bad-cond:bad-cond}
47956e45f6SSimon J. Gerraty.  error
48956e45f6SSimon J. Gerraty.else
49956e45f6SSimon J. Gerraty.  error
50956e45f6SSimon J. Gerraty.endif
51956e45f6SSimon J. Gerraty
52956e45f6SSimon J. Gerraty# When the :? is parsed, it is greedy.  The else branch spans all the
53956e45f6SSimon J. Gerraty# text, up until the closing character '}', even if the text looks like
54956e45f6SSimon J. Gerraty# another modifier.
55956e45f6SSimon J. Gerraty.if ${1:?then:else:Q} != "then"
56956e45f6SSimon J. Gerraty.  error
57956e45f6SSimon J. Gerraty.endif
58956e45f6SSimon J. Gerraty.if ${0:?then:else:Q} != "else:Q"
59956e45f6SSimon J. Gerraty.  error
60956e45f6SSimon J. Gerraty.endif
61956e45f6SSimon J. Gerraty
62e2eeea75SSimon J. Gerraty# This line generates 2 error messages.  The first comes from evaluating the
63e2eeea75SSimon J. Gerraty# malformed conditional "1 == == 2", which is reported as "Bad conditional
64d5e0a182SSimon J. Gerraty# expression" by ApplyModifier_IfElse.  The expression containing that
65e2eeea75SSimon J. Gerraty# conditional therefore returns a parse error from Var_Parse, and this parse
66e2eeea75SSimon J. Gerraty# error propagates to CondEvalExpression, where the "Malformed conditional"
67e2eeea75SSimon J. Gerraty# comes from.
68148ee845SSimon J. Gerraty# expect+1: Malformed conditional (${1 == == 2:?yes:no} != "")
69e2eeea75SSimon J. Gerraty.if ${1 == == 2:?yes:no} != ""
70e2eeea75SSimon J. Gerraty.  error
71e2eeea75SSimon J. Gerraty.else
72e2eeea75SSimon J. Gerraty.  error
73e2eeea75SSimon J. Gerraty.endif
74e2eeea75SSimon J. Gerraty
75e2eeea75SSimon J. Gerraty# If the "Bad conditional expression" appears in a quoted string literal, the
76e2eeea75SSimon J. Gerraty# error message "Malformed conditional" is not printed, leaving only the "Bad
77e2eeea75SSimon J. Gerraty# conditional expression".
78e2eeea75SSimon J. Gerraty#
79e2eeea75SSimon J. Gerraty# XXX: The left-hand side is enclosed in quotes.  This results in Var_Parse
80*8d5c8e21SSimon J. Gerraty# being called without VARE_EVAL_DEFINED.  When ApplyModifier_IfElse
81e2eeea75SSimon J. Gerraty# returns AMR_CLEANUP as result, Var_Parse returns varUndefined since the
82d5e0a182SSimon J. Gerraty# value of the expression is still undefined.  CondParser_String is
83e2eeea75SSimon J. Gerraty# then supposed to do proper error handling, but since varUndefined is local
84e2eeea75SSimon J. Gerraty# to var.c, it cannot distinguish this return value from an ordinary empty
85e2eeea75SSimon J. Gerraty# string.  The left-hand side of the comparison is therefore just an empty
86e2eeea75SSimon J. Gerraty# string, which is obviously equal to the empty string on the right-hand side.
87e2eeea75SSimon J. Gerraty#
88e2eeea75SSimon J. Gerraty# XXX: The debug log for -dc shows a comparison between 1.0 and 0.0.  The
89e2eeea75SSimon J. Gerraty# condition should be detected as being malformed before any comparison is
90e2eeea75SSimon J. Gerraty# done since there is no well-formed comparison in the condition at all.
91e2eeea75SSimon J. Gerraty.MAKEFLAGS: -dc
92e2eeea75SSimon J. Gerraty.if "${1 == == 2:?yes:no}" != ""
93e2eeea75SSimon J. Gerraty.  error
94e2eeea75SSimon J. Gerraty.else
95148ee845SSimon J. Gerraty# expect+1: warning: Oops, the parse error should have been propagated.
96e2eeea75SSimon J. Gerraty.  warning Oops, the parse error should have been propagated.
97e2eeea75SSimon J. Gerraty.endif
98e2eeea75SSimon J. Gerraty.MAKEFLAGS: -d0
99e2eeea75SSimon J. Gerraty
10098875883SSimon J. Gerraty# As of 2020-12-10, the variable "VAR" is first expanded, and the result of
101d5e0a182SSimon J. Gerraty# this expansion is then taken as the condition.  To force the
10206b9b3e0SSimon J. Gerraty# expression in the condition to be evaluated at exactly the right point,
10306b9b3e0SSimon J. Gerraty# the '$' of the intended '${VAR}' escapes from the parser in form of the
10498875883SSimon J. Gerraty# expression ${:U\$}.  Because of this escaping, the variable "VAR" and thus
10506b9b3e0SSimon J. Gerraty# the condition ends up as "${VAR} == value", just as intended.
10606b9b3e0SSimon J. Gerraty#
10706b9b3e0SSimon J. Gerraty# This hack does not work for variables from .for loops since these are
10806b9b3e0SSimon J. Gerraty# expanded at parse time to their corresponding ${:Uvalue} expressions.
10906b9b3e0SSimon J. Gerraty# Making the '$' of the '${VAR}' expression indirect hides this expression
110dba7b0efSSimon J. Gerraty# from the parser of the .for loop body.  See ForLoop_SubstVarLong.
11106b9b3e0SSimon J. Gerraty.MAKEFLAGS: -dc
11206b9b3e0SSimon J. GerratyVAR=	value
11306b9b3e0SSimon J. Gerraty.if ${ ${:U\$}{VAR} == value:?ok:bad} != "ok"
11406b9b3e0SSimon J. Gerraty.  error
11506b9b3e0SSimon J. Gerraty.endif
11606b9b3e0SSimon J. Gerraty.MAKEFLAGS: -d0
11706b9b3e0SSimon J. Gerraty
118b0c40a00SSimon J. Gerraty# On 2021-04-19, when building external/bsd/tmux with HAVE_LLVM=yes and
119b0c40a00SSimon J. Gerraty# HAVE_GCC=no, the following conditional generated this error message:
120b0c40a00SSimon J. Gerraty#
121b0c40a00SSimon J. Gerraty#	make: Bad conditional expression 'string == "literal" && no >= 10'
122b0c40a00SSimon J. Gerraty#	    in 'string == "literal" && no >= 10?yes:no'
123b0c40a00SSimon J. Gerraty#
124b0c40a00SSimon J. Gerraty# Despite the error message (which was not clearly marked with "error:"),
125b0c40a00SSimon J. Gerraty# the build continued, for historical reasons, see main_Exit.
126b0c40a00SSimon J. Gerraty#
127b0c40a00SSimon J. Gerraty# The tricky detail here is that the condition that looks so obvious in the
128b0c40a00SSimon J. Gerraty# form written in the makefile becomes tricky when it is actually evaluated.
129b0c40a00SSimon J. Gerraty# This is because the condition is written in the place of the variable name
130b0c40a00SSimon J. Gerraty# of the expression, and in an expression, the variable name is always
131b0c40a00SSimon J. Gerraty# expanded first, before even looking at the modifiers.  This happens for the
132b0c40a00SSimon J. Gerraty# modifier ':?' as well, so when CondEvalExpression gets to see the
133b0c40a00SSimon J. Gerraty# expression, it already looks like this:
134b0c40a00SSimon J. Gerraty#
135b0c40a00SSimon J. Gerraty#	string == "literal" && no >= 10
136b0c40a00SSimon J. Gerraty#
137b0c40a00SSimon J. Gerraty# When parsing such an expression, the parser used to be strict.  It first
138b0c40a00SSimon J. Gerraty# evaluated the left-hand side of the operator '&&' and then started parsing
139b0c40a00SSimon J. Gerraty# the right-hand side 'no >= 10'.  The word 'no' is obviously a string
140954401e6SSimon J. Gerraty# literal, not enclosed in quotes, which is OK, even on the left-hand side of
141b0c40a00SSimon J. Gerraty# the comparison operator, but only because this is a condition in the
142b0c40a00SSimon J. Gerraty# modifier ':?'.  In an ordinary directive '.if', this would be a parse error.
143b0c40a00SSimon J. Gerraty# For strings, only the comparison operators '==' and '!=' are defined,
144b0c40a00SSimon J. Gerraty# therefore parsing stopped at the '>', producing the 'Bad conditional
145b0c40a00SSimon J. Gerraty# expression'.
146b0c40a00SSimon J. Gerraty#
147b0c40a00SSimon J. Gerraty# Ideally, the conditional expression would not be expanded before parsing
148b0c40a00SSimon J. Gerraty# it.  This would allow to write the conditions exactly as seen below.  That
149b0c40a00SSimon J. Gerraty# change has a high chance of breaking _some_ existing code and would need
150b0c40a00SSimon J. Gerraty# to be thoroughly tested.
151b0c40a00SSimon J. Gerraty#
152b0c40a00SSimon J. Gerraty# Since cond.c 1.262 from 2021-04-20, make reports a more specific error
153b0c40a00SSimon J. Gerraty# message in situations like these, pointing directly to the specific problem
154b0c40a00SSimon J. Gerraty# instead of just saying that the whole condition is bad.
155b0c40a00SSimon J. GerratySTRING=		string
156b0c40a00SSimon J. GerratyNUMBER=		no		# not really a number
157148ee845SSimon J. Gerraty# expect+1: no.
158b0c40a00SSimon J. Gerraty.info ${${STRING} == "literal" && ${NUMBER} >= 10:?yes:no}.
159548bfc56SSimon J. Gerraty# expect+3: while evaluating variable "string == "literal" || no >= 10": Comparison with '>=' requires both operands 'no' and '10' to be numeric
160d5e0a182SSimon J. Gerraty# expect: make: Bad conditional expression 'string == "literal" || no >= 10' before '?yes:no'
16198875883SSimon J. Gerraty# expect+1: .
162b0c40a00SSimon J. Gerraty.info ${${STRING} == "literal" || ${NUMBER} >= 10:?yes:no}.
163b0c40a00SSimon J. Gerraty
164b0c40a00SSimon J. Gerraty# The following situation occasionally occurs with MKINET6 or similar
165b0c40a00SSimon J. Gerraty# variables.
166b0c40a00SSimon J. GerratyNUMBER=		# empty, not really a number either
167d5e0a182SSimon J. Gerraty# expect: make: Bad conditional expression 'string == "literal" &&  >= 10' before '?yes:no'
168148ee845SSimon J. Gerraty# expect+1: .
169b0c40a00SSimon J. Gerraty.info ${${STRING} == "literal" && ${NUMBER} >= 10:?yes:no}.
170d5e0a182SSimon J. Gerraty# expect: make: Bad conditional expression 'string == "literal" ||  >= 10' before '?yes:no'
171148ee845SSimon J. Gerraty# expect+1: .
172b0c40a00SSimon J. Gerraty.info ${${STRING} == "literal" || ${NUMBER} >= 10:?yes:no}.
173b0c40a00SSimon J. Gerraty
174b0c40a00SSimon J. Gerraty# CondParser_LeafToken handles [0-9-+] specially, treating them as a number.
175b0c40a00SSimon J. GerratyPLUS=		+
176b0c40a00SSimon J. GerratyASTERISK=	*
177b0c40a00SSimon J. GerratyEMPTY=		# empty
178b0c40a00SSimon J. Gerraty# "true" since "+" is not the empty string.
17998875883SSimon J. Gerraty# expect+1: <true>
18098875883SSimon J. Gerraty.info <${${PLUS}		:?true:false}>
181b0c40a00SSimon J. Gerraty# "false" since the variable named "*" is not defined.
18298875883SSimon J. Gerraty# expect+1: <false>
18398875883SSimon J. Gerraty.info <${${ASTERISK}	:?true:false}>
184b0c40a00SSimon J. Gerraty# syntax error since the condition is completely blank.
18598875883SSimon J. Gerraty# expect+1: <>
18698875883SSimon J. Gerraty.info <${${EMPTY}	:?true:false}>
187954401e6SSimon J. Gerraty
188954401e6SSimon J. Gerraty
189954401e6SSimon J. Gerraty# Since the condition of the '?:' modifier is expanded before being parsed and
190954401e6SSimon J. Gerraty# evaluated, it is common practice to enclose expressions in quotes, to avoid
191954401e6SSimon J. Gerraty# producing syntactically invalid conditions such as ' == value'.  This only
192954401e6SSimon J. Gerraty# works if the expanded values neither contain quotes nor backslashes.  For
193954401e6SSimon J. Gerraty# strings containing quotes or backslashes, the '?:' modifier should not be
194954401e6SSimon J. Gerraty# used.
195954401e6SSimon J. GerratyPRIMES=	2 3 5 7 11
196954401e6SSimon J. Gerraty.if ${1 2 3 4 5:L:@n@$n:${ ("${PRIMES:M$n}" != "") :?prime:not_prime}@} != \
197954401e6SSimon J. Gerraty  "1:not_prime 2:prime 3:prime 4:not_prime 5:prime"
198954401e6SSimon J. Gerraty.  error
199954401e6SSimon J. Gerraty.endif
2008c973ee2SSimon J. Gerraty
2018c973ee2SSimon J. Gerraty# When parsing the modifier ':?', there are 3 possible cases:
2028c973ee2SSimon J. Gerraty#
2038c973ee2SSimon J. Gerraty#	1. The whole expression is only parsed.
2048c973ee2SSimon J. Gerraty#	2. The expression is parsed and the 'then' branch is evaluated.
2058c973ee2SSimon J. Gerraty#	3. The expression is parsed and the 'else' branch is evaluated.
2068c973ee2SSimon J. Gerraty#
2078c973ee2SSimon J. Gerraty# In all of these cases, the expression must be parsed in the same way,
2088c973ee2SSimon J. Gerraty# especially when one of the branches contains unbalanced '{}' braces.
2098c973ee2SSimon J. Gerraty#
2108c973ee2SSimon J. Gerraty# At 2020-01-01, the expressions from the 'then' and 'else' branches were
2118c973ee2SSimon J. Gerraty# parsed differently, depending on whether the branch was taken or not.  When
2128c973ee2SSimon J. Gerraty# the branch was taken, the parser recognized that in the modifier ':S,}},,',
2138c973ee2SSimon J. Gerraty# the '}}' were ordinary characters.  When the branch was not taken, the
2148c973ee2SSimon J. Gerraty# parser only counted balanced '{' and '}', ignoring any escaping or other
2158c973ee2SSimon J. Gerraty# changes in the interpretation.
2168c973ee2SSimon J. Gerraty#
2178c973ee2SSimon J. Gerraty# In var.c 1.285 from 2020-07-20, the parsing of the expressions changed so
2188c973ee2SSimon J. Gerraty# that in both cases the expression is parsed in the same way, taking the
2198c973ee2SSimon J. Gerraty# unbalanced braces in the ':S' modifiers into account.  This change was not
2208c973ee2SSimon J. Gerraty# on purpose, the commit message mentioned 'has the same effect', which was a
2218c973ee2SSimon J. Gerraty# wrong assumption.
2228c973ee2SSimon J. Gerraty#
2238c973ee2SSimon J. Gerraty# In var.c 1.323 from 2020-07-26, the unintended fix from var.c 1.285 was
2248c973ee2SSimon J. Gerraty# reverted, still not knowing about the difference between regular parsing and
2258c973ee2SSimon J. Gerraty# balanced-mode parsing.
2268c973ee2SSimon J. Gerraty#
2278c973ee2SSimon J. Gerraty# In var.c 1.1028 from 2022-08-08, there was another attempt at fixing this
2288c973ee2SSimon J. Gerraty# inconsistency in parsing, but since that broke parsing of the modifier ':@',
2298c973ee2SSimon J. Gerraty# it was reverted in var.c 1.1029 from 2022-08-23.
2308c973ee2SSimon J. Gerraty#
2318c973ee2SSimon J. Gerraty# In var.c 1.1047 from 2023-02-18, the inconsistency in parsing was finally
2328c973ee2SSimon J. Gerraty# fixed.  The modifier ':@' now parses the body in balanced mode, while
2338c973ee2SSimon J. Gerraty# everywhere else the modifier parts have their subexpressions parsed in the
2348c973ee2SSimon J. Gerraty# same way, no matter whether they are evaluated or not.
2358c973ee2SSimon J. Gerraty#
2368c973ee2SSimon J. Gerraty# The modifiers ':@' and ':?' are similar in that they conceptually contain
2378c973ee2SSimon J. Gerraty# text to be evaluated later or conditionally, still they parse that text
2388c973ee2SSimon J. Gerraty# differently.  The crucial difference is that the body of the modifier ':@'
2398c973ee2SSimon J. Gerraty# is always parsed using balanced mode.  The modifier ':?', on the other hand,
2408c973ee2SSimon J. Gerraty# must parse both of its branches in the same way, no matter whether they are
2418c973ee2SSimon J. Gerraty# evaluated or not.  Since balanced mode and standard mode are incompatible,
2428c973ee2SSimon J. Gerraty# it's impossible to use balanced mode in the modifier ':?'.
2438c973ee2SSimon J. Gerraty.MAKEFLAGS: -dc
2448c973ee2SSimon J. Gerraty.if 0 && ${1:?${:Uthen0:S,}},,}:${:Uelse0:S,}},,}} != "not evaluated"
2458c973ee2SSimon J. Gerraty# At 2020-01-07, the expression evaluated to 'then0,,}}', even though it was
2468c973ee2SSimon J. Gerraty# irrelevant as the '0' had already been evaluated to 'false'.
2478c973ee2SSimon J. Gerraty.  error
2488c973ee2SSimon J. Gerraty.endif
2498c973ee2SSimon J. Gerraty.if 1 && ${0:?${:Uthen1:S,}},,}:${:Uelse1:S,}},,}} != "else1"
2508c973ee2SSimon J. Gerraty.  error
2518c973ee2SSimon J. Gerraty.endif
2528c973ee2SSimon J. Gerraty.if 2 && ${1:?${:Uthen2:S,}},,}:${:Uelse2:S,}},,}} != "then2"
2538c973ee2SSimon J. Gerraty# At 2020-01-07, the whole expression evaluated to 'then2,,}}' instead of the
2548c973ee2SSimon J. Gerraty# expected 'then2'.  The 'then' branch of the ':?' modifier was parsed
2558c973ee2SSimon J. Gerraty# normally, parsing and evaluating the ':S' modifier, thereby treating the
2568c973ee2SSimon J. Gerraty# '}}' as ordinary characters and resulting in 'then2'.  The 'else' branch was
2578c973ee2SSimon J. Gerraty# parsed in balanced mode, ignoring that the inner '}}' were ordinary
2588c973ee2SSimon J. Gerraty# characters.  The '}}' were thus interpreted as the end of the 'else' branch
2598c973ee2SSimon J. Gerraty# and the whole expression.  This left the trailing ',,}}', which together
2608c973ee2SSimon J. Gerraty# with the 'then2' formed the result 'then2,,}}'.
2618c973ee2SSimon J. Gerraty.  error
2628c973ee2SSimon J. Gerraty.endif
26398875883SSimon J. Gerraty
26498875883SSimon J. Gerraty
26598875883SSimon J. Gerraty# Since the condition is taken from the variable name of the expression, not
26698875883SSimon J. Gerraty# from its value, it is evaluated early.  It is possible though to construct
26798875883SSimon J. Gerraty# conditions that are evaluated lazily, at exactly the right point.  There is
26898875883SSimon J. Gerraty# no way to escape a '$' directly in the variable name, but there are
26998875883SSimon J. Gerraty# alternative ways to bring a '$' into the condition.
27098875883SSimon J. Gerraty#
27198875883SSimon J. Gerraty#	In an indirect condition using the ':U' modifier, each '$', ':' and
27298875883SSimon J. Gerraty#	'}' must be escaped as '\$', '\:' and '\}', respectively, but '{' must
27398875883SSimon J. Gerraty#	not be escaped.
27498875883SSimon J. Gerraty#
27598875883SSimon J. Gerraty#	In an indirect condition using a separate variable, each '$' must be
27698875883SSimon J. Gerraty#	escaped as '$$'.
27798875883SSimon J. Gerraty#
27898875883SSimon J. Gerraty# These two forms allow the variables to contain arbitrary characters, as the
27998875883SSimon J. Gerraty# condition parser does not see them.
28098875883SSimon J. GerratyDELAYED=	two
28198875883SSimon J. Gerraty# expect+1: no
28298875883SSimon J. Gerraty.info ${ ${:U \${DELAYED\} == "one"}:?yes:no}
28398875883SSimon J. Gerraty# expect+1: yes
28498875883SSimon J. Gerraty.info ${ ${:U \${DELAYED\} == "two"}:?yes:no}
28598875883SSimon J. GerratyINDIRECT_COND1=	$${DELAYED} == "one"
28698875883SSimon J. Gerraty# expect+1: no
28798875883SSimon J. Gerraty.info ${ ${INDIRECT_COND1}:?yes:no}
28898875883SSimon J. GerratyINDIRECT_COND2=	$${DELAYED} == "two"
28998875883SSimon J. Gerraty# expect+1: yes
29098875883SSimon J. Gerraty.info ${ ${INDIRECT_COND2}:?yes:no}
29198875883SSimon J. Gerraty
29298875883SSimon J. Gerraty
2938c973ee2SSimon J. Gerraty.MAKEFLAGS: -d0
294d5e0a182SSimon J. Gerraty
295d5e0a182SSimon J. Gerraty
296d5e0a182SSimon J. Gerraty# In the modifier parts for the 'then' and 'else' branches, subexpressions are
297548bfc56SSimon J. Gerraty# parsed by inspecting the actual modifiers.  In 2008, 2015, 2020, 2022 and
298d5e0a182SSimon J. Gerraty# 2023, the exact parsing algorithm switched a few times, counting balanced
299d5e0a182SSimon J. Gerraty# braces instead of proper subexpressions, which meant that unbalanced braces
300d5e0a182SSimon J. Gerraty# were parsed differently, depending on whether the branch was active or not.
301d5e0a182SSimon J. GerratyBRACES=	}}}
302d5e0a182SSimon J. GerratyNO=	${0:?${BRACES:S,}}},yes,}:${BRACES:S,}}},no,}}
303d5e0a182SSimon J. GerratyYES=	${1:?${BRACES:S,}}},yes,}:${BRACES:S,}}},no,}}
304d5e0a182SSimon J. GerratyBOTH=	<${YES}> <${NO}>
305d5e0a182SSimon J. Gerraty.if ${BOTH} != "<yes> <no>"
306d5e0a182SSimon J. Gerraty.  error
307d5e0a182SSimon J. Gerraty.endif
308