ENH: additional #word and #message dictionary directives (#2276)

- use `#word` to concatenate, expand content with the resulting string
  being treated as a word token. Can be used in dictionary or
  primitive context.

  In dictionary context, it fills the gap for constructing dictionary
  names on-the-fly. For example,

  ```
  #word "some_prefix_solverInfo_${application}"
  {
      type    solverInfo;
      libs    (utilityFunctionObjects);
      ...
  }
  ```

  The '#word' directive will automatically squeeze out non-word
  characters. In the block content form, it will also strip out
  comments. This means that this type of content should also work:

  ```
  #word {
     some_prefix_solverInfo
     /* Appended with application name (if defined) */
     ${application:+_}  // Use '_' separator
     ${application}     // The application
  }
  {
      type    solverInfo;
      libs    (utilityFunctionObjects);
      ...
  }
  ```
  This is admittedly quite ugly, but illustrates its capabilities.

- use `#message` to report expanded string content to stderr.
  For example,

  ```
  T
  {
     solver          PBiCG;
     preconditioner  DILU;
     tolerance       1e-10;
     relTol          0;
     #message "using solver: $solver"
  }
  ```
  Only reports on the master node.
This commit is contained in:
Mark Olesen 2021-11-23 21:03:21 +01:00
parent 55af2fc2c6
commit 1804d3fed5
25 changed files with 837 additions and 134 deletions

View File

@ -18,6 +18,8 @@ FoamFile
#sinclude "$FOAM_CASE/someUnknownFile"
#includeIfPresent "$FOAM_CASE/someUnknownFile-$FOAM_CASENAME"
zeroVelocity uniform (0 0 0);
internalField uniform 1;
// supply defaults
@ -48,7 +50,7 @@ x 5;
varName x;
//Indirection for keys
// Indirection for keys
key inlet_9;
@ -67,13 +69,17 @@ boundaryField
inlet_5 { $inactive }
inlet_6a { $...inactive } // Relative scoping - fairly horrible to use
inlet_6b { $^inactive } // Absolute scoping
inlet_6c { key ${/key}; } // Absolute scoping
inlet_7 { ${inactive}} // Test variable expansion
inlet_8 { $inactive }
// Variable expansion for a keyword
${key} { $inactive }
#include "testDictInc"
outlet
outletBase
{
type inletOutlet;
inletValue $internalField;
@ -83,16 +89,36 @@ boundaryField
y 6;
}
// this should have no effect
outlet
{
$outletBase
}
Default_Boundary_Region
{
valueOut $zeroVelocity;
}
// this should have no effect (not in scope)
#remove inactive
inlet_7 { ${${varType}}} // Test indirection/recursive expansion
inlet_8 { $active }
// But this should work to remove things in different scopes
#remove "/zeroVelocity"
inlet_7 { ${inactive} } // Test variable expansion
inlet_8 { $inactive }
inlet_7a { ${${varType}} } // Test indirection/recursive expansion
inlet_7b { ${${varType}} } // Test indirection/recursive expansion
#overwrite inlet_8 { type none; }
}
// No patterns with scoped removal
// #remove "/boundaryField/outletB.*"
#remove "/boundaryField/outletBase"
#include "testDict2"
verbatim #{
@ -123,10 +149,25 @@ baz
$active
}
// this should work
#remove active
// This should work
#remove x
// this should work too
// This should work too
#remove ( bar baz )
// Remove a sub-dictionary entry
#remove "/anynumber.*/value"
// Removal does not auto-vivify
#remove "/nonExistentDict/value"
// Add into existing dictionary
"/anynumber.*/someValue" 100;
// Auto-vivify
// - but currently cannot auto-vivify entries with dictionary patterns
"/abd/someValue" 100;
"/def/'someValue.*" 100;
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //

View File

@ -303,13 +303,15 @@ $(functionEntries)/calcEntry/calcEntry.C
$(functionEntries)/codeStream/codeStream.C
$(functionEntries)/evalEntry/evalEntry.C
$(functionEntries)/functionEntry/functionEntry.C
$(functionEntries)/ifEntry/ifEntry.C
$(functionEntries)/ifeqEntry/ifeqEntry.C
$(functionEntries)/includeEntry/includeEntry.C
$(functionEntries)/includeEtcEntry/includeEtcEntry.C
$(functionEntries)/includeFuncEntry/includeFuncEntry.C
$(functionEntries)/inputMode/inputMode.C
$(functionEntries)/message/messageDirective.C
$(functionEntries)/removeEntry/removeEntry.C
$(functionEntries)/ifeqEntry/ifeqEntry.C
$(functionEntries)/ifEntry/ifEntry.C
$(functionEntries)/word/wordDirective.C
IOdictionary = db/IOobjects/IOdictionary
$(IOdictionary)/baseIOdictionary.C

View File

@ -37,6 +37,7 @@ License
// Truncate error message for readability
static constexpr const unsigned errLen = 80;
// * * * * * * * * * * * * * * * Local Functions * * * * * * * * * * * * * * //
namespace
@ -55,6 +56,21 @@ inline bool validVariableChar(char c)
return (Foam::word::valid(c) || c == '/');
}
inline void inplaceTrimRight(std::string& s)
{
auto end = s.length();
if (end)
{
while (end && Foam::isspace(s[end-1]))
{
--end;
}
s.erase(end);
}
}
} // End anonymous namespace
@ -123,7 +139,7 @@ char Foam::ISstream::nextValid()
// C-style comment: discard through to "*/" ending
if (!seekCommentEnd_Cstyle())
{
return 0;
return 0; // Premature end of stream
}
}
else
@ -390,17 +406,133 @@ static token::tokenType readVariable
return token::tokenType::ERROR;
}
// Raw, low-level get into a string.
// Continues reading after an initial opening delimiter (eg, '{')
// until it finds the matching closing delimiter (eg, '}')
static bool readUntilBalancedDelimiter
(
ISstream& is,
std::string& str,
const bool stripComments,
const char delimOpen,
const char delimClose
)
{
constexpr const unsigned bufLen = 1024;
static char buf[bufLen];
unsigned nChar = 0;
unsigned depth = 1; // Initial '{' already seen by caller
char c = 0;
str.clear();
while (is.get(c))
{
if ((str.empty() && !nChar) && isspace(c))
{
continue; // Ignore leading whitespace
}
buf[nChar++] = c;
// Note: no '\' escape handling needed at the moment
if (c == delimOpen)
{
++depth;
}
else if (c == delimClose)
{
--depth;
if (!depth)
{
// Closing character - do not include in output
--nChar;
str.append(buf, nChar);
inplaceTrimRight(str); // Remove trailing whitespace
return true;
}
}
else if (stripComments && c == '/')
{
// Strip C/C++ comments from expressions
// Note: could also peek instead of get/putback
if (!is.get(c))
{
break; // Premature end of stream
}
else if (c == '/')
{
--nChar; // Remove initial '/' from buffer
// C++ comment: discard through newline
(void) is.getLine(nullptr, '\n');
}
else if (c == '*')
{
--nChar; // Remove initial '/' from buffer
// C-style comment: discard through to "*/" ending
if (!is.seekCommentEnd_Cstyle())
{
break; // Premature end of stream
}
}
else
{
// Reanalyze the char
is.putback(c);
}
}
if (nChar == bufLen)
{
str.append(buf, nChar); // Flush full buffer
nChar = 0;
}
}
// Abnormal exit of the loop
str.append(buf, nChar); // Finalize pending content
inplaceTrimRight(str); // Remove trailing whitespace
// Exhausted stream without finding closing sequence
return false;
}
} // End namespace Foam
// * * * * * * * * * * * * * * Member Functions * * * * * * * * * * * * * * //
bool Foam::ISstream::continueReadUntilRightBrace
(
std::string& str,
const bool stripComments
)
{
return
readUntilBalancedDelimiter
(
*this,
str,
stripComments,
token::BEGIN_BLOCK,
token::END_BLOCK
);
}
Foam::Istream& Foam::ISstream::read(token& t)
{
constexpr const unsigned bufLen = 128; // Max length for labels/scalars
static char buf[bufLen];
// Return the put back token if it exists
// Return the putback token if it exists
if (Istream::getBack(t))
{
return *this;

View File

@ -66,7 +66,8 @@ class ISstream
// Private Member Functions
//- Get the next valid character
//- Get the next valid (non-whitespace) character,
//- after skipping any C/C++ comments.
char nextValid();
//- No copy assignment
@ -131,6 +132,18 @@ public:
// \return False if stream exhausted before finding the comment end
bool seekCommentEnd_Cstyle();
//- Raw, low-level get into a string.
//- Continues reading \b after an initial left-brace until it finds
//- the matching closing right-brace.
// Tracks balanced pairs, trims out leading/trailing whitespace.
//
// \return False if stream exhausted before finding closing brace
bool continueReadUntilRightBrace
(
std::string& str,
const bool stripComments = true
);
// Read Functions

View File

@ -6,23 +6,32 @@
#overwrite | dict | entry introducer
#warn | dict | entry introducer
#error | dict | entry introducer
| |
#remove | dict | keyType or List<keyType>
| |
#include | dict/primitive | string
#sinclude | dict/primitive | string
#includeIfPresent | dict/primitive | string
#includeEtc | dict/primitive | string
#sincludeEtc | dict/primitive | string
#includeFunc | dict | word
| |
#message | dict/primitive | string or braced content
#word | dict/primitive | string or braced content
#eval | primitive | string or braced content
| |
#calc | dict/primitive | string
#codeStream | dict/primitive | dictionary
#if | dict | string
#ifeq | dict | entry entry
Pending future extensions
Deprecated
| directive | comments |
|-------------------|---------------------------------------|
#includeIfPresent | same as #sinclude |
Pending future extensions (considered reserved)
| directive | context | content | line oriented?
|-------------------|-------------------|-------------------|-----------------
@ -31,4 +40,4 @@ Pending future extensions
#undef | dict | keyType or List<keyType>
2019-08-21
2021-11-24

View File

@ -51,8 +51,8 @@ SourceFiles
\*---------------------------------------------------------------------------*/
#ifndef calcEntry_H
#define calcEntry_H
#ifndef functionEntries_calcEntry_H
#define functionEntries_calcEntry_H
#include "codeStream.H"

View File

@ -92,8 +92,8 @@ SourceFiles
\*---------------------------------------------------------------------------*/
#ifndef codeStream_H
#define codeStream_H
#ifndef functionEntries_codeStream_H
#define functionEntries_codeStream_H
#include "functionEntry.H"

View File

@ -56,96 +56,6 @@ namespace functionEntries
} // End namespace Foam
// * * * * * * * * * * * * * * * Local Functions * * * * * * * * * * * * * * //
namespace Foam
{
// Slurp a string until a closing '}' is found.
// Track balanced bracket/brace pairs, with max stack depth of 60.
static bool slurpUntilBalancedBrace(ISstream& is, std::string& str)
{
constexpr const unsigned bufLen = 1024;
static char buf[bufLen];
is.fatalCheck(FUNCTION_NAME);
unsigned nChar = 0;
unsigned depth = 1; // Initial '{' already seen by caller
char c;
str.clear();
while (is.get(c))
{
buf[nChar++] = c;
if (c == token::BEGIN_BLOCK)
{
++depth;
}
else if (c == token::END_BLOCK)
{
--depth;
if (!depth)
{
// Closing '}' character - do not include in output
--nChar;
str.append(buf, nChar);
return true;
}
}
else if (c == '/')
{
// Strip C/C++ comments from expressions
// Note: could also peek instead of get/putback
if (!is.get(c))
{
break; // Premature end of stream
}
else if (c == '/')
{
--nChar; // Remove initial '/' from buffer
// C++ comment: discard through newline
(void) is.getLine(nullptr, '\n');
}
else if (c == '*')
{
--nChar; // Remove initial '/' from buffer
// C-style comment: discard through to "*/" ending
if (!is.seekCommentEnd_Cstyle())
{
break; // Premature end of stream
}
}
else
{
// Reanalyze the char
is.putback(c);
}
}
if (nChar == bufLen)
{
str.append(buf, nChar); // Flush full buffer
nChar = 0;
}
}
// Abnormal exit of the loop
str.append(buf, nChar); // Finalize pending content
is.fatalCheck(FUNCTION_NAME);
return false;
}
} // End namespace Foam
// * * * * * * * * * * * * * Static Member Functions * * * * * * * * * * * * //
Foam::tokenList Foam::functionEntries::evalEntry::evaluate
@ -292,8 +202,11 @@ Foam::tokenList Foam::functionEntries::evalEntry::evaluate
is >> tok;
}
string str; // The string to evaluate
if (tok.isString())
// The string to evaluate
string str;
if (tok.isStringType()) // Also accepts a single bare word
{
// - #eval "expr"
// - #eval #{ expr #}
@ -303,12 +216,13 @@ Foam::tokenList Foam::functionEntries::evalEntry::evaluate
else if (tok.isPunctuation(token::BEGIN_BLOCK))
{
// - #eval { expr }
if (!slurpUntilBalancedBrace(dynamic_cast<ISstream&>(is), str))
// strip comments
if (!continueReadUntilRightBrace(is, str, true))
{
reportReadWarning
(
is,
"Premature end while reading expression - missing '}'?"
"Premature end while reading #eval - missing '}'?"
);
}
}

View File

@ -65,8 +65,8 @@ SourceFiles
\*---------------------------------------------------------------------------*/
#ifndef evalEntry_H
#define evalEntry_H
#ifndef functionEntries_evalEntry_H
#define functionEntries_evalEntry_H
#include "functionEntry.H"
@ -98,6 +98,7 @@ class evalEntry
//- Evaluate and return a token list
static tokenList evaluate(const dictionary& parentDict, Istream& is);
public:
//- Execute in a primitiveEntry context, extracts token or line

View File

@ -47,6 +47,7 @@ namespace Foam
execute,
primitiveEntryIstream
);
} // End namespace Foam
@ -61,6 +62,19 @@ Foam::token Foam::functionEntry::readLine(const word& key, Istream& is)
}
bool Foam::functionEntry::continueReadUntilRightBrace
(
Istream& is,
std::string& str,
const bool stripComments
)
{
return
dynamic_cast<ISstream&>(is)
.continueReadUntilRightBrace(str, stripComments);
}
// * * * * * * * * * * * * * * * * Constructors * * * * * * * * * * * * * * //
Foam::functionEntry::functionEntry

View File

@ -80,6 +80,15 @@ protected:
template<class StringType>
static List<StringType> readStringList(Istream& is);
//- Slurp a string until a closing '}' is found.
// Track balanced bracket/brace pairs, with max stack depth of 60.
static bool continueReadUntilRightBrace
(
Istream& is,
std::string& str,
const bool stripComments = true
);
//- No copy construct
functionEntry(const functionEntry&) = delete;

View File

@ -50,13 +50,13 @@ namespace functionEntries
} // End namespace Foam
// * * * * * * * * * * * * * Private Member Functions * * * * * * * * * * * //
// * * * * * * * * * * * * * Static Member Functions * * * * * * * * * * * * //
bool Foam::functionEntries::ifEntry::isTrue(ITstream& its)
{
Switch logic;
if (its.size() && its.first().isScalar())
if (its.peekFirst().isScalar())
{
// Use default rounding tolerance
logic = Switch(its.first().scalarToken());
@ -70,6 +70,8 @@ bool Foam::functionEntries::ifEntry::isTrue(ITstream& its)
}
// * * * * * * * * * * * * * Private Member Functions * * * * * * * * * * * //
bool Foam::functionEntries::ifEntry::execute
(
DynamicList<filePos>& stack,

View File

@ -54,8 +54,8 @@ SourceFiles
\*---------------------------------------------------------------------------*/
#ifndef ifEntry_H
#define ifEntry_H
#ifndef functionEntries_ifEntry_H
#define functionEntries_ifEntry_H
#include "ifeqEntry.H"

View File

@ -69,8 +69,8 @@ SourceFiles
\*---------------------------------------------------------------------------*/
#ifndef ifeqEntry_H
#define ifeqEntry_H
#ifndef functionEntries_ifeqEntry_H
#define functionEntries_ifeqEntry_H
#include "functionEntry.H"
#include "DynamicList.H"

View File

@ -53,8 +53,8 @@ SourceFiles
\*---------------------------------------------------------------------------*/
#ifndef includeEntry_H
#define includeEntry_H
#ifndef functionEntries_includeEntry_H
#define functionEntries_includeEntry_H
#include "functionEntry.H"

View File

@ -50,8 +50,8 @@ SourceFiles
\*---------------------------------------------------------------------------*/
#ifndef includeEtcEntry_H
#define includeEtcEntry_H
#ifndef functionEntries_includeEtcEntry_H
#define functionEntries_includeEtcEntry_H
#include "functionEntry.H"

View File

@ -64,8 +64,8 @@ SourceFiles
\*---------------------------------------------------------------------------*/
#ifndef includeFuncEntry_H
#define includeFuncEntry_H
#ifndef functionEntries_includeFuncEntry_H
#define functionEntries_includeFuncEntry_H
#include "functionEntry.H"

View File

@ -55,8 +55,8 @@ SourceFiles
\*---------------------------------------------------------------------------*/
#ifndef inputMode_H
#define inputMode_H
#ifndef functionEntries_inputMode_H
#define functionEntries_inputMode_H
#include "entry.H"
#include "functionEntry.H"

View File

@ -0,0 +1,145 @@
/*---------------------------------------------------------------------------*\
========= |
\\ / F ield | OpenFOAM: The Open Source CFD Toolbox
\\ / O peration |
\\ / A nd | www.openfoam.com
\\/ M anipulation |
-------------------------------------------------------------------------------
Copyright (C) 2021 OpenCFD Ltd.
-------------------------------------------------------------------------------
License
This file is part of OpenFOAM.
OpenFOAM is free software: you can redistribute it and/or modify it
under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
OpenFOAM is distributed in the hope that it will be useful, but WITHOUT
ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
for more details.
You should have received a copy of the GNU General Public License
along with OpenFOAM. If not, see <http://www.gnu.org/licenses/>.
\*---------------------------------------------------------------------------*/
#include "messageDirective.H"
#include "dictionary.H"
#include "stringOps.H"
#include "addToMemberFunctionSelectionTable.H"
// * * * * * * * * * * * * * * Static Data Members * * * * * * * * * * * * * //
namespace Foam
{
namespace functionEntries
{
addNamedToMemberFunctionSelectionTable
(
functionEntry,
messageDirective,
execute,
dictionaryIstream,
message
);
addNamedToMemberFunctionSelectionTable
(
functionEntry,
messageDirective,
execute,
primitiveEntryIstream,
message
);
} // End namespace functionEntry
} // End namespace Foam
// * * * * * * * * * * * * * Static Member Functions * * * * * * * * * * * * //
bool Foam::functionEntries::messageDirective::evaluate
(
const dictionary& parentDict,
Istream& is
)
{
token tok(is);
// The string to evaluate
string str;
if (tok.isStringType()) // Also accepts a single bare word
{
// - #message expr
// - #message "expr"
// - #message #{ expr #}
str = tok.stringToken();
}
else if (tok.isPunctuation(token::BEGIN_BLOCK))
{
// - #message { expr }
// strip comments
if (!continueReadUntilRightBrace(is, str, true))
{
reportReadWarning
(
is,
"Premature end while reading #message - missing '}'?"
);
}
}
else
{
FatalIOErrorInFunction(is)
<< "Invalid input for #message."
" Expecting a string or block to expand, but found" << nl
<< tok.info() << endl
<< exit(FatalIOError);
}
stringOps::inplaceExpand(str, parentDict);
stringOps::inplaceTrim(str);
if (!str.empty() && error::master())
{
// Use stderr directly, in case message should be part of startup
std::cerr
<< str << " (file: \""
<< parentDict.relativeName() << "\" line: "
<< tok.lineNumber() << ")\n" << std::flush;
}
return true;
}
// * * * * * * * * * * * * * * * Member Functions * * * * * * * * * * * * * //
bool Foam::functionEntries::messageDirective::execute
(
dictionary& parentDict,
Istream& is
)
{
evaluate(parentDict, is);
return true;
}
bool Foam::functionEntries::messageDirective::execute
(
const dictionary& parentDict,
primitiveEntry& entry,
Istream& is
)
{
evaluate(parentDict, is);
return true;
}
// ************************************************************************* //

View File

@ -0,0 +1,101 @@
/*---------------------------------------------------------------------------*\
========= |
\\ / F ield | OpenFOAM: The Open Source CFD Toolbox
\\ / O peration |
\\ / A nd | www.openfoam.com
\\/ M anipulation |
-------------------------------------------------------------------------------
Copyright (C) 2021 OpenCFD Ltd.
-------------------------------------------------------------------------------
License
This file is part of OpenFOAM.
OpenFOAM is free software: you can redistribute it and/or modify it
under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
OpenFOAM is distributed in the hope that it will be useful, but WITHOUT
ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
for more details.
You should have received a copy of the GNU General Public License
along with OpenFOAM. If not, see <http://www.gnu.org/licenses/>.
Class
Foam::functionEntries::messageDirective
Description
Expands string content and reports as a message on stderr.
For example,
\verbatim
T
{
solver PBiCG;
preconditioner DILU;
tolerance 1e-10;
relTol 0;
#message "using solver: $solver"
}
\endverbatim
SourceFiles
messageDirective.C
\*---------------------------------------------------------------------------*/
#ifndef functionEntries_messageDirective_H
#define functionEntries_messageDirective_H
#include "functionEntry.H"
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
namespace Foam
{
namespace functionEntries
{
/*---------------------------------------------------------------------------*\
Class messageDirective Declaration
\*---------------------------------------------------------------------------*/
class messageDirective
:
public functionEntry
{
// Private Member Functions
//- Evaluate
static bool evaluate(const dictionary& parentDict, Istream& is);
public:
//- Execute in a primitiveEntry context.
// Reports message string (after expansion) - does not alter entry.
static bool execute
(
const dictionary& parentDict,
primitiveEntry& entry,
Istream& is
);
//- Execute in a sub-dict context.
// Reports message string (after expansion) - does not alter dictionary.
static bool execute(dictionary& parentDict, Istream& is);
};
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
} // End namespace functionEntries
} // End namespace Foam
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
#endif
// ************************************************************************* //

View File

@ -52,8 +52,8 @@ SourceFiles
\*---------------------------------------------------------------------------*/
#ifndef removeEntry_H
#define removeEntry_H
#ifndef functionEntries_removeEntry_H
#define functionEntries_removeEntry_H
#include "functionEntry.H"

View File

@ -0,0 +1,157 @@
/*---------------------------------------------------------------------------*\
========= |
\\ / F ield | OpenFOAM: The Open Source CFD Toolbox
\\ / O peration |
\\ / A nd | www.openfoam.com
\\/ M anipulation |
-------------------------------------------------------------------------------
Copyright (C) 2021 OpenCFD Ltd.
-------------------------------------------------------------------------------
License
This file is part of OpenFOAM.
OpenFOAM is free software: you can redistribute it and/or modify it
under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
OpenFOAM is distributed in the hope that it will be useful, but WITHOUT
ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
for more details.
You should have received a copy of the GNU General Public License
along with OpenFOAM. If not, see <http://www.gnu.org/licenses/>.
\*---------------------------------------------------------------------------*/
#include "wordDirective.H"
#include "dictionary.H"
#include "stringOps.H"
#include "addToMemberFunctionSelectionTable.H"
// * * * * * * * * * * * * * * Static Data Members * * * * * * * * * * * * * //
namespace Foam
{
namespace functionEntries
{
addNamedToMemberFunctionSelectionTable
(
functionEntry,
wordDirective,
execute,
dictionaryIstream,
word
);
addNamedToMemberFunctionSelectionTable
(
functionEntry,
wordDirective,
execute,
primitiveEntryIstream,
word
);
} // End namespace functionEntries
} // End namespace Foam
// * * * * * * * * * * * * * Private Member Functions * * * * * * * * * * * //
Foam::token Foam::functionEntries::wordDirective::evaluate
(
const dictionary& parentDict,
Istream& is
)
{
token tok(is);
// The string to evaluate
string str;
if (tok.isStringType()) // Also accepts a single bare word
{
// - #word expr
// - #word "expr"
// - #word #{ expr #}
str = tok.stringToken();
}
else if (tok.isPunctuation(token::BEGIN_BLOCK))
{
// - #word { expr }
// strip comments
if (!continueReadUntilRightBrace(is, str, true))
{
reportReadWarning
(
is,
"Premature end while reading #word - missing '}'?"
);
}
}
else
{
FatalIOErrorInFunction(is)
<< "Invalid input for #word."
" Expecting a string or block to expand, but found" << nl
<< tok.info() << endl
<< exit(FatalIOError);
}
stringOps::inplaceExpand(str, parentDict);
word result(word::validate(str)); // Includes trimming etc.
if (!result.empty())
{
tok = std::move(result);
return tok;
}
// Expanded to nothing - treat as a no-op
return token::undefinedToken;
}
// * * * * * * * * * * * * * * * Member Functions * * * * * * * * * * * * * //
bool Foam::functionEntries::wordDirective::execute
(
const dictionary& parentDict,
primitiveEntry& entry,
Istream& is
)
{
token tok(evaluate(parentDict, is));
if (tok.good())
{
// Can add evaluated value directly into primitiveEntry
entry.append(std::move(tok), true); // Lazy resizing
}
return true;
}
bool Foam::functionEntries::wordDirective::execute
(
dictionary& parentDict,
Istream& is
)
{
token tok(evaluate(parentDict, is));
if (tok.good())
{
// Using putBack to insert evaluated value into stream
is.putBack(tok);
}
return true;
}
// ************************************************************************* //

View File

@ -0,0 +1,100 @@
/*---------------------------------------------------------------------------*\
========= |
\\ / F ield | OpenFOAM: The Open Source CFD Toolbox
\\ / O peration |
\\ / A nd | www.openfoam.com
\\/ M anipulation |
-------------------------------------------------------------------------------
Copyright (C) 2021 OpenCFD Ltd.
-------------------------------------------------------------------------------
License
This file is part of OpenFOAM.
OpenFOAM is free software: you can redistribute it and/or modify it
under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
OpenFOAM is distributed in the hope that it will be useful, but WITHOUT
ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
for more details.
You should have received a copy of the GNU General Public License
along with OpenFOAM. If not, see <http://www.gnu.org/licenses/>.
Class
Foam::functionEntries::wordDirective
Description
Converts/expands string content to a word.
This can be useful for composition of names.
For example,
\verbatim
#word "some_prefix_solverInfo_${application}_${{10 * 5}}"
{
type solverInfo;
libs (utilityFunctionObjects);
fields (".*");
returnName #word solver$type;
}
\endverbatim
SourceFiles
wordDirective.C
\*---------------------------------------------------------------------------*/
#ifndef functionEntries_wordDirective_H
#define functionEntries_wordDirective_H
#include "functionEntry.H"
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
namespace Foam
{
namespace functionEntries
{
/*---------------------------------------------------------------------------*\
Class wordDirective Declaration
\*---------------------------------------------------------------------------*/
class wordDirective
:
public functionEntry
{
// Private Member Functions
//- Evaluate
static token evaluate(const dictionary& parentDict, Istream& is);
public:
//- Execute in a primitiveEntry context
static bool execute
(
const dictionary& parentDict,
primitiveEntry& entry,
Istream& is
);
//- Execute in a sub-dict context.
static bool execute(dictionary& parentDict, Istream& is);
};
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
} // End namespace functionEntries
} // End namespace Foam
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
#endif
// ************************************************************************* //

View File

@ -0,0 +1,61 @@
/*--------------------------------*- C++ -*----------------------------------*\
| ========= | |
| \\ / F ield | OpenFOAM: The Open Source CFD Toolbox |
| \\ / O peration | Version: v2112 |
| \\ / A nd | Website: www.openfoam.com |
| \\/ M anipulation | |
\*---------------------------------------------------------------------------*/
FoamFile
{
version 2.0;
format ascii;
class dictionary;
object dictionary;
}
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
// message from a word
#message message-word
// message from a string
#message "message string [] from ${FOAM_API:-unset}"
// message from a braced-block string
#message { message block string from ${FOAM_API:-unset} }
// word in primitive entry
foamApi using #word "_ ${FOAM_API:-unset}" version;
// word as dictionary entry (string syntax)
#word "dict1entry_ ${FOAM_API:-unset}"
{
value1 10;
}
// word as dictionary entry (braced-block string)
#word { dict2entry_ ${FOAM_API:-unset} }
{
value1 20;
}
#word
{
dict3entry
${FOAM_API:+_} // Use '_' separator
${FOAM_API} // The value (if any)
}
{
// This is a funny corner-case for #eval.
// It also accepts a single word ... not that many make sense though
value1 #eval pi();
}
// ************************************************************************* //

View File

@ -1,7 +1,7 @@
/*--------------------------------*- C++ -*----------------------------------*\
| ========= | |
| \\ / F ield | OpenFOAM: The Open Source CFD Toolbox |
| \\ / O peration | Version: v2106 |
| \\ / O peration | Version: v2112 |
| \\ / A nd | Website: www.openfoam.com |
| \\/ M anipulation | |
\*---------------------------------------------------------------------------*/
@ -16,6 +16,8 @@ FoamFile
mergeType points; // Wedge geometry - Merge points instead of topology
#message "Using mergeType: ${mergeType:-default}"
scale 0.001;
vertices