freebsd-nq/contrib/bmake/unit-tests/parse-var.mk
2023-01-27 16:33:01 -08:00

136 lines
4.7 KiB
Makefile

# $NetBSD: parse-var.mk,v 1.6 2022/09/25 21:26:23 rillig Exp $
#
# Tests for parsing variable expressions.
#
# TODO: Add systematic tests for all of the below combinations.
#
# Written form:
# short form
# long form with braces endc == '}'
# long form with parentheses endc == ')'
# indirect modifiers endc == '\0'
#
# Based on:
# undefined variable
# global variable
# command-line variable
# environment variable
# target-local variable
# legacy variable '@F'
#
# VarEvalMode:
# parse
# eval
# eval-undeferr
# eval-keep-dollar
# eval-keep-undef
# eval-keep-dollar-undef
#
# Global mode:
# without -dL
# with -dL
#
# Modifiers:
# no
# yes, stay undefined
# convert to defined
# indirect modifiers, involving changes to VarEvalMode
#
# Error conditions:
# for the short form, EOF after the '$'
# for the short form, each character
# for the long forms, EOF right after '${'
# for the long forms, EOF after the variable name
# for the long forms, EOF after the ':'
# for the long forms, EOF after parsing a modifier
# for the long forms, ':}'
# for each modifier: syntactic error
# for each modifier: evaluation error
#
# Context:
# in a condition, only operand, unquoted
# in a condition, only operand, quoted
# in a condition, left-hand side, unquoted
# in a condition, left-hand side, quoted
# in a condition, right-hand side, unquoted
# in a condition, right-hand side, quoted
# left-hand side of a variable assignment
# right-hand side of a ':=' variable assignment
# right-hand side of a '!=' variable assignment
# shell command in a target
# .info directive
# dependency line
# items in a .for loop
# everywhere else Var_Parse is called
#
# Further influences:
# multi-level evaluations like 'other=${OTHER}' with OTHER='$$ ${THIRD}'
#
# Effects:
# How much does the parsing position advance (pp)?
# What's the value of the expression (out_val)?
# What's the status after parsing the expression (VarParseResult)?
# What error messages are printed (Parse_Error)?
# What no-effect error messages are printed (Error)?
# What error messages should be printed but aren't?
# What other side effects are there?
.MAKEFLAGS: -dL
# In variable assignments, there may be spaces in the middle of the left-hand
# side of the assignment, but only if they occur inside variable expressions.
# Leading spaces (but not tabs) are possible but unusual.
# Trailing spaces are common in some coding styles, others omit them.
VAR.${:U param }= value
.if ${VAR.${:U param }} != "value"
. error
.endif
# XXX: The following paragraph already uses past tense, in the hope that the
# parsing behavior can be cleaned up soon.
# Since var.c 1.323 from 2020-07-26 18:11 and except for var.c 1.1028 from
# 2022-08-08, the exact way of parsing an expression depended on whether the
# expression was actually evaluated or merely parsed.
#
# If it was evaluated, nested expressions were parsed correctly, parsing each
# modifier according to its exact definition (see varmod.mk).
#
# If the expression was merely parsed but not evaluated (for example, because
# its value would not influence the outcome of the condition, or during the
# first pass of the ':@var@body@' modifier), and the expression contained a
# modifier, and that modifier contained a nested expression, the nested
# expression was not parsed correctly. Instead, make only counted the opening
# and closing delimiters, which failed for nested modifiers with unbalanced
# braces.
#
# This naive brace counting was implemented in ParseModifierPartDollar. As of
# var.c 1.1029, there are still several other places that merely count braces
# instead of properly parsing subexpressions.
#.MAKEFLAGS: -dcpv
# Keep these braces outside the conditions below, to keep them simple to
# understand. If the BRACE_PAIR had been replaced with ':U{}', the '}' would
# have to be escaped, but not the '{'. This asymmetry would have made the
# example even more complicated to understand.
BRACE_PAIR= {}
# In this test word, the '{{}' in the middle will be replaced.
BRACE_GROUP= {{{{}}}}
# The inner ':S' modifier turns the word '{}' into '{{}'.
# The outer ':S' modifier then replaces '{{}' with '<lbraces>'.
# In the first case, the outer expression is relevant and is parsed correctly.
.if 1 && ${BRACE_GROUP:S,${BRACE_PAIR:S,{,{{,},<lbraces>,}
.endif
# In the second case, the outer expression was irrelevant. In this case, in
# the parts of the outer ':S' modifier, make only counted the braces, and since
# the inner expression '${BRACE_PAIR:...}' contains more '{' than '}', parsing
# failed with the error message 'Unfinished modifier for "BRACE_GROUP"'. Fixed
# in var.c 1.1028 from 2022-08-08, reverted in var.c 1.1029 from 2022-08-23.
.if 0 && ${BRACE_GROUP:S,${BRACE_PAIR:S,{,{{,},<lbraces>,}
.endif
#.MAKEFLAGS: -d0
all: .PHONY