freebsd-dev/contrib/bmake/unit-tests/parse-var.mk
Simon J. Gerraty 8c973ee23d Merge bmake-20230414
Merge commit '51d8a8b4ac1dd7265e891149e470a803906de2a7'
2023-04-24 16:50:16 -07:00

130 lines
4.4 KiB
Makefile

# $NetBSD: parse-var.mk,v 1.8 2023/02/18 11:16:09 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 (return value)?
# 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
# Since var.c 1.323 from 2020-07-26 18:11 and until var.c 1.1047 from
# 2023-02-18, the exact way of parsing an expression with subexpressions
# 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.
#.MAKEFLAGS: -dcpv
# Keep these braces outside the conditions below, to keep them simple to
# understand. If the expression ${BRACE_PAIR:...} had been replaced with the
# literal ${: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 below conditions will replace the '{{}' in the middle
# with the string '<lbraces>'.
BRACE_GROUP= {{{{}}}}
# The inner ':S' modifier turns the word '{}' into '{{}'.
# The outer ':S' modifier then replaces '{{}' with '<lbraces>'.
# Due to the always-true condition '1', the outer expression is relevant and
# is parsed correctly.
.if 1 && ${BRACE_GROUP:S,${BRACE_PAIR:S,{,{{,},<lbraces>,}
.endif
# Due to the always-false condition '0', the outer expression is irrelevant.
# In this case, in the parts of the outer ':S' modifier, the expression parser
# 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.1047 from 2023-02-18.
.if 0 && ${BRACE_GROUP:S,${BRACE_PAIR:S,{,{{,},<lbraces>,}
.endif
#.MAKEFLAGS: -d0
all: .PHONY