1# $NetBSD: parse-var.mk,v 1.10 2024/06/02 15:31:26 rillig Exp $
2#
3# Tests for parsing expressions.
4#
5# TODO: Add systematic tests for all of the below combinations.
6#
7# Written form:
8#         short form
9#         long form with braces                   endc == '}'
10#         long form with parentheses    endc == ')'
11#         indirect modifiers            endc == '\0'
12#
13# Based on:
14#         undefined variable
15#         global variable
16#         command-line variable
17#         environment variable
18#         target-local variable
19#         legacy variable '@F'
20#
21# VarEvalMode:
22#         parse
23#         parse-balanced
24#         eval
25#         eval-defined
26#         eval-keep-undefined
27#         eval-keep-dollar-and-undefined
28#
29# Global mode:
30#         without -dL
31#         with -dL
32#
33# Modifiers:
34#         no
35#         yes, stay undefined
36#         convert to defined
37#         indirect modifiers, involving changes to VarEvalMode
38#
39# Error conditions:
40#         for the short form, EOF after the '$'
41#         for the short form, each character
42#         for the long forms, EOF right after '${'
43#         for the long forms, EOF after the variable name
44#         for the long forms, EOF after the ':'
45#         for the long forms, EOF after parsing a modifier
46#         for the long forms, ':}'
47#         for each modifier: syntactic error
48#         for each modifier: evaluation error
49#
50# Context:
51#         in a condition, only operand, unquoted
52#         in a condition, only operand, quoted
53#         in a condition, left-hand side, unquoted
54#         in a condition, left-hand side, quoted
55#         in a condition, right-hand side, unquoted
56#         in a condition, right-hand side, quoted
57#         left-hand side of a variable assignment
58#         right-hand side of a ':=' variable assignment
59#         right-hand side of a '!=' variable assignment
60#         shell command in a target
61#         .info directive
62#         dependency line
63#         items in a .for loop
64#         everywhere else Var_Parse is called
65#
66# Further influences:
67#         multi-level evaluations like 'other=${OTHER}' with OTHER='$$ ${THIRD}'
68#
69# Effects:
70#         How much does the parsing position advance (pp)?
71#         What's the value of the expression (return value)?
72#         What error messages are printed (Parse_Error)?
73#         What no-effect error messages are printed (Error)?
74#         What error messages should be printed but aren't?
75#         What other side effects are there?
76
77.MAKEFLAGS: -dL
78
79# In variable assignments, there may be spaces in the middle of the left-hand
80# side of the assignment, but only if they occur inside expressions.
81# Leading spaces (but not tabs) are possible but unusual.
82# Trailing spaces are common in some coding styles, others omit them.
83VAR.${:U param }=   value
84.if ${VAR.${:U param }} != "value"
85.  error
86.endif
87
88# Since var.c 1.323 from 2020-07-26 18:11 and until var.c 1.1047 from
89# 2023-02-18, the exact way of parsing an expression with subexpressions
90# depended on whether the expression was actually evaluated or merely parsed.
91#
92# If it was evaluated, nested expressions were parsed correctly, parsing each
93# modifier according to its exact definition (see varmod.mk).
94#
95# If the expression was merely parsed but not evaluated (for example, because
96# its value would not influence the outcome of the condition, or during the
97# first pass of the ':@var@body@' modifier), and the expression contained a
98# modifier, and that modifier contained a nested expression, the nested
99# expression was not parsed correctly.  Instead, make only counted the opening
100# and closing delimiters, which failed for nested modifiers with unbalanced
101# braces.
102
103#.MAKEFLAGS: -dcpv
104# Keep these braces outside the conditions below, to keep them simple to
105# understand.  If the expression ${BRACE_PAIR:...} had been replaced with the
106# literal ${:U{}}, the '}' would have to be escaped, but not the '{'.  This
107# asymmetry would have made the example even more complicated to understand.
108BRACE_PAIR=         {}
109# In this test word, the below conditions will replace the '{{}' in the middle
110# with the string '<lbraces>'.
111BRACE_GROUP=        {{{{}}}}
112
113# The inner ':S' modifier turns the word '{}' into '{{}'.
114# The outer ':S' modifier then replaces '{{}' with '<lbraces>'.
115# Due to the always-true condition '1', the outer expression is relevant and
116# is parsed correctly.
117.if 1 && ${BRACE_GROUP:S,${BRACE_PAIR:S,{,{{,},<lbraces>,}
118.endif
119# Due to the always-false condition '0', the outer expression is irrelevant.
120# In this case, in the parts of the outer ':S' modifier, the expression parser
121# only counted the braces, and since the inner expression '${BRACE_PAIR:...}'
122# contains more '{' than '}', parsing failed with the error message 'Unfinished
123# modifier for "BRACE_GROUP"'.  Fixed in var.c 1.1047 from 2023-02-18.
124.if 0 && ${BRACE_GROUP:S,${BRACE_PAIR:S,{,{{,},<lbraces>,}
125.endif
126#.MAKEFLAGS: -d0
127
128
129all: .PHONY
130