1# $NetBSD: parse-var.mk,v 1.8 2023/02/18 11:16:09 rillig Exp $ 2# 3# Tests for parsing variable 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# eval 24# eval-undeferr 25# eval-keep-dollar 26# eval-keep-undef 27# eval-keep-dollar-undef 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 variable 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