diff --git a/applications/test/dictionary/testDictEval2 b/applications/test/dictionary/testDictEval2
index 5f53157740..d965c935d0 100644
--- a/applications/test/dictionary/testDictEval2
+++ b/applications/test/dictionary/testDictEval2
@@ -47,10 +47,10 @@ eval6b #eval " pi() * 2 * ${{ ${unknown:-0} * ${{ 15 * 3 }} }} + 5";
eval6c #eval " pi() * 2 * ${{ -${unknown:-0} * ${{ 15 * 3 }} }} + 5";
// Even this work
-eval7a #eval " pi() * 1 * ${factor${{2*5}}:-100}";
+eval7a #eval " pi() * 1 * ${factor${{2*5}}:-100}";
// Even this work
-eval7b #eval " pi() * 1 * ${factorXYZ${{2*5}}:-100}";
+eval7b #eval " pi() * 1 * ${factorXYZ${{2*5}}:-100}";
index 10;
@@ -58,7 +58,40 @@ eval8a #eval " pi() * 2 * ${{ ${factor$index} + ${factor10} }}";
eval8b #eval " pi() * 2 * $factor * ${{ 100 }}";
-eval10a #eval "vector(1,2,3) * 5";
+eval10a #eval "vector(1,2,3) * 5";
+// Slightly stranger ideas:
+
+axis1 (1 0 0);
+axis2 (0 1 0);
+axis3 (0 0 1);
+index 100;
+
+location #eval #{
+ 400 *
+
+ // Numerator: use the index to get relevant suffix [1,2,3]
+ // to form the lookup of axis1,axis2,...
+ // Treat the lookup as a vector within the expression evaluation
+
+ $[(vector) axis${{
+ ($index % 3) + 1 /* Evaluates: 1,2,3 from index */ }}
+ ]
+
+ // Denominator: divide by index with zero-division protection
+ / ${{max(1, $index)}}
+
+ // Same thing, but using expressions-syntax for variable lookup
+ / ${{max(1, $[index])}}
+#};
+
+
+// This is still a rather clunky syntax
+length #eval{ cbrt(mag($[(vector) location])) };
+
+
+// Remove evidence of some variables
+#remove ("axis[0-9]*" index)
+
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
diff --git a/src/OpenFOAM/db/IOstreams/Tstreams/ITstream.C b/src/OpenFOAM/db/IOstreams/Tstreams/ITstream.C
index be9998a0e8..f61de4c53b 100644
--- a/src/OpenFOAM/db/IOstreams/Tstreams/ITstream.C
+++ b/src/OpenFOAM/db/IOstreams/Tstreams/ITstream.C
@@ -231,6 +231,9 @@ std::string Foam::ITstream::toString() const
label len = tokens.size();
+ // NOTE: may wish to have special handling if there is a single token
+ // and it is already a string or word
+
for (const token& tok : tokens)
{
buf << tok;
diff --git a/src/OpenFOAM/db/dictionary/functionEntries/evalEntry/evalEntry.C b/src/OpenFOAM/db/dictionary/functionEntries/evalEntry/evalEntry.C
index 9fbb48b394..b1a40df9a6 100644
--- a/src/OpenFOAM/db/dictionary/functionEntries/evalEntry/evalEntry.C
+++ b/src/OpenFOAM/db/dictionary/functionEntries/evalEntry/evalEntry.C
@@ -105,10 +105,10 @@ Foam::tokenList Foam::functionEntries::evalEntry::evaluate
<< "input: " << s << endl;
#endif
- // Expanding with env-variables, with empty
-
- stringOps::inplaceRemoveComments(s);
- stringOps::inplaceExpand(s, parentDict, true, true);
+ // Expand with env=true, empty=true, subDict=false
+ // with comments stripped.
+ // Special handling of $[...] syntax enabled.
+ expressions::exprString::inplaceExpand(s, parentDict, true);
stringOps::inplaceTrim(s);
// An extraneous trailing ';' is a common input error, catch it now.
diff --git a/src/OpenFOAM/expressions/exprEntry/expressionEntry.C b/src/OpenFOAM/expressions/exprEntry/expressionEntry.C
index a350c3ed18..6e83f0b738 100644
--- a/src/OpenFOAM/expressions/exprEntry/expressionEntry.C
+++ b/src/OpenFOAM/expressions/exprEntry/expressionEntry.C
@@ -223,12 +223,15 @@ void Foam::exprTools::expressionEntry::inplaceExpand
stringOps::inplaceTrim(varName);
// Allow recursive plain expansion for the *variable* name.
- // This means "$[(vector) var${index] ]" should work
- stringOps::inplaceExpand(varName, dict);
+ // This means "$[(vector) var${index} ]" should work
+
+ // Expand with env=true, empty=true, subDict=false
+ stringOps::inplaceExpand(varName, dict, true, true, false);
// Length of original text to replace (incl. decorators)
const auto replaceLen = (varEnd - varBeg + 1);
+ // Get primitiveEntry with env=false, subDict=false
const entry* eptr = getVariableOrDie(varName, dict);
std::string varValue;
@@ -236,7 +239,17 @@ void Foam::exprTools::expressionEntry::inplaceExpand
if (castTo.empty())
{
// Serialized with spaces
- varValue = eptr->stream().toString();
+ ITstream& its = eptr->stream();
+
+ if (its.size() == 1 && its[0].isStringType())
+ {
+ // Already a string-type (WORD, STRING, ...). Just copy.
+ varValue = its[0].stringToken();
+ }
+ else
+ {
+ varValue = its.toString();
+ }
}
else
{
@@ -258,7 +271,8 @@ void Foam::exprTools::expressionEntry::inplaceExpand
// - this is done second such that $[(vector) xyz] entries will have
// been properly expanded by this stage
- stringOps::inplaceExpand(s, dict);
+ // Expand with env=true, empty=true, subDict=false
+ stringOps::inplaceExpand(s, dict, true, true, false);
}
diff --git a/src/OpenFOAM/expressions/exprEntry/expressionEntry.H b/src/OpenFOAM/expressions/exprEntry/expressionEntry.H
index b42c8efd94..7c1f983928 100644
--- a/src/OpenFOAM/expressions/exprEntry/expressionEntry.H
+++ b/src/OpenFOAM/expressions/exprEntry/expressionEntry.H
@@ -134,7 +134,14 @@ public:
//- Generic concatenate tokens to space-separated string.
inline static string evaluate(const entry& e);
- //- Inplace expand expression with dictionary entries
+ //- Inplace expand expression with dictionary variables/entries
+ //
+ // \par Expansion behaviour
+ // - alternatives = True
+ // - environment = True
+ // - allow empty = True
+ // - subDict = False
+ // .
static void inplaceExpand
(
std::string& s,
diff --git a/src/OpenFOAM/expressions/exprString/exprString.H b/src/OpenFOAM/expressions/exprString/exprString.H
index 612022d0fe..a7aa13f577 100644
--- a/src/OpenFOAM/expressions/exprString/exprString.H
+++ b/src/OpenFOAM/expressions/exprString/exprString.H
@@ -118,7 +118,14 @@ public:
// Static Member Functions
//- Inplace expansion with dictionary variables,
- //- and strip C/C++ comments from the input
+ //- and strip C/C++ comments from the input.
+ //
+ // \par Expansion behaviour
+ // - alternatives = True
+ // - environment = True
+ // - allow empty = True
+ // - subDict = False
+ // .
static void inplaceExpand
(
std::string& str,
@@ -127,7 +134,9 @@ public:
);
//- Get and expand expression with dictionary entries,
- //- optionally strip C/C++ comments from the input
+ //- optionally strip C/C++ comments from the input.
+ //
+ // Expansion behaviour as per inplaceExpand
static exprString getExpression
(
const word& name,
diff --git a/src/OpenFOAM/primitives/strings/stringOps/stringOps.C b/src/OpenFOAM/primitives/strings/stringOps/stringOps.C
index f0823bad14..dc3a12d84b 100644
--- a/src/OpenFOAM/primitives/strings/stringOps/stringOps.C
+++ b/src/OpenFOAM/primitives/strings/stringOps/stringOps.C
@@ -252,7 +252,7 @@ static inline std::string entryToString
if (pe.size() == 1 && pe[0].isStringType())
{
- // Already a string-type. Just copy.
+ // Already a string-type (WORD, STRING, ...). Just copy.
str = pe[0].stringToken();
}
else
diff --git a/src/OpenFOAM/primitives/strings/stringOps/stringOps.H b/src/OpenFOAM/primitives/strings/stringOps/stringOps.H
index 9b12511191..51d3a4e37d 100644
--- a/src/OpenFOAM/primitives/strings/stringOps/stringOps.H
+++ b/src/OpenFOAM/primitives/strings/stringOps/stringOps.H
@@ -28,8 +28,7 @@ Namespace
Foam::stringOps
Description
- Collection of static functions to do various simple string-related
- operations
+ Collection of static functions for various string-related operations
SourceFiles
stringOps.C
@@ -93,34 +92,37 @@ namespace stringOps
//- Does \b not use environment values.
//
// Expansion includes:
- // -# variables
+ // -# Variables
// - \c $VAR
// - \c ${VAR}
- // - \c ${VAR:-defValue}
- // - \c ${VAR:+altValue}
//
- // Default and alternative values as per the POSIX shell:
- // \code
- // 1. ${parameter:-defValue}
- // 2. ${parameter:+altValue}
- // \endcode
- // -# If parameter is unset or null, the \c defValue is substituted.
- // Otherwise, the value of parameter is substituted.
- // -# If parameter is unset or null, nothing is substituted.
- // Otherwise the \c altValue is substituted.
+ // -# Default and alternative values as per the POSIX shell:
+ // - \c ${parameter:-defValue}
+ // If parameter is unset or null, the \c defValue is substituted.
+ // Otherwise, the value of parameter is substituted.
+ // - \c ${parameter:+altValue}
+ // If parameter is unset or null, nothing is substituted.
+ // Otherwise the \c altValue is substituted.
// .
//
// General behaviour:
// - Unknown entries are removed silently.
- // - Malformed entries (eg, brace mismatch, sigil followed by bad chars)
- // are left as is.
- //
- // Currently only used by dynamicCode.
+ // - Malformed entries (eg, brace mismatch, sigil followed by unknown
+ // characters) are left as is.
//
// \param[in,out] s The string to modify inplace.
// \param mapping The lookup table
// \param sigil The leading sigil. Can be changed to avoid conflict
// with other string expansions. (default: '$')
+ //
+ // \par Expansion behaviour
+ // - alternatives = True
+ // - environment = False
+ // - allow empty = True
+ // - subDict = Not applicable
+ // .
+ //
+ // \note Currently only used by Foam::dynamicCode.
void inplaceExpand
(
std::string& s,
@@ -133,17 +135,17 @@ namespace stringOps
//- and (optionally) environment variables.
//
// Expansion includes:
- // -# dictionary variables and (optionally) environment variables
+ // -# Dictionary variables and (optionally) environment variables
// - \c $VAR
// - \c ${VAR}
// - \c ${VAR:-defValue}
// - \c ${VAR:+altValue}
- // -# mathematical evaluation using stringOps::evaluate
+ // -# Mathematical evaluation using stringOps::evaluate
// - \c ${{EXPR}}
- // -# current directory
+ // -# Current directory
// - leading "./"
// : the current directory - Foam::cwd()
- // -# leading tag expansion for commonly used directories
+ // -# Leading tag expansion for commonly used directories
// - \/
// : user/group/other OpenFOAM etc directory
// - \[ugoa]+)\>/
@@ -154,24 +156,21 @@ namespace stringOps
// : The \c $FOAM_CASE/constant directory
// - \/
// : The \c $FOAM_CASE/system directory
- // -# tilde expansion
+ // -# Tilde expansion
// - leading "~/" : home directory
// - leading "~user" : home directory for specified user
- //
- // Default and alternative values as per the POSIX shell:
- // \code
- // 1. ${parameter:-defValue}
- // 2. ${parameter:+altValue}
- // \endcode
- // -# If parameter is unset or null, the \c defValue is substituted.
- // Otherwise, the value of parameter is substituted.
- // -# If parameter is unset or null, nothing is substituted.
- // Otherwise the \c altValue is substituted.
+ // -# Default and alternative values as per the POSIX shell:
+ // - \c ${parameter:-defValue}
+ // If parameter is unset or null, the \c defValue is substituted.
+ // Otherwise, the value of parameter is substituted.
+ // - \c ${parameter:+altValue}
+ // If parameter is unset or null, nothing is substituted.
+ // Otherwise the \c altValue is substituted.
// .
//
// General behaviour:
- // - Malformed entries (eg, brace mismatch, sigil followed by bad chars)
- // are left as is.
+ // - Malformed entries (eg, brace mismatch, sigil followed by unknown
+ // characters) are left as is.
// - Supports recursive variable expansions.
// For example, "${var${num}}" and "${{100 + ${var}}}"
//
@@ -186,7 +185,14 @@ namespace stringOps
//
// \sa Foam::findEtcEntry(), Foam::findEtcEntries(), stringOps::evaluate()
//
- // \note this function has too many parameters and should generally
+ // \par Expansion behaviour
+ // - alternatives = True
+ // - environment = Given by parameter
+ // - allow empty = Given by parameter
+ // - subDict = Given by parameter (default: False)
+ // .
+ //
+ // \note This function has too many parameters and should generally
// be avoided in user coding.
void inplaceExpand
(
@@ -217,7 +223,16 @@ namespace stringOps
// Empty expansions are allowed.
// Serialization of subDict entries is permitted.
//
- // \sa stringOps::inplaceExpand(std::string&, const dictionary&, bool, bool, bool, char)
+ // \sa
+ // stringOps::inplaceExpand
+ // (std::string&, const dictionary&, bool, bool, bool, char)
+ //
+ // \par Expansion behaviour
+ // - alternatives = True
+ // - environment = True
+ // - allow empty = True
+ // - subDict = True
+ // .
void inplaceExpand
(
std::string& s,
@@ -242,9 +257,17 @@ namespace stringOps
//- variables
//
// The expansion behaviour is identical to
- // stringOps::inplaceExpand(std::string&, const dictionary&, bool, bool, bool, char)
+ // stringOps::inplaceExpand
+ // (std::string&, const dictionary&, bool, bool, bool, char)
// except that there is no dictionary and the environment variables
// are always enabled.
+ //
+ // \par Expansion behaviour
+ // - alternatives = True
+ // - environment = True
+ // - allow empty = Given by parameter (default: False)
+ // - subDict = Not applicable
+ // .
void inplaceExpand
(
std::string& s,