mirror of
https://develop.openfoam.com/Development/openfoam.git
synced 2025-11-28 03:28:01 +00:00
- follows the principle of least surprise if the expansion behaviour for #eval and expressions (eg, exprFixedValue) are the same. This is possible now that we harness the regular stringOps::expand() within exprString::expand()
297 lines
7.7 KiB
C
297 lines
7.7 KiB
C
/*---------------------------------------------------------------------------*\
|
|
========= |
|
|
\\ / F ield | OpenFOAM: The Open Source CFD Toolbox
|
|
\\ / O peration |
|
|
\\ / A nd | www.openfoam.com
|
|
\\/ M anipulation |
|
|
-------------------------------------------------------------------------------
|
|
Original code Copyright (C) 2014-2018 Bernhard Gschaider
|
|
Copyright (C) 2019 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 "expressionEntry.H"
|
|
#include "stringOps.H"
|
|
#include "runTimeSelectionTables.H"
|
|
#include "addToRunTimeSelectionTable.H"
|
|
|
|
// * * * * * * * * * * * * * * Static Data Members * * * * * * * * * * * * * //
|
|
|
|
namespace Foam
|
|
{
|
|
namespace exprTools
|
|
{
|
|
|
|
defineTypeName(expressionEntry);
|
|
defineRunTimeSelectionTable(expressionEntry, empty);
|
|
|
|
// Various types can be used directly without any changes
|
|
|
|
addNamedToRunTimeSelectionTable
|
|
(
|
|
expressionEntry,
|
|
expressionEntry,
|
|
empty,
|
|
direct
|
|
);
|
|
|
|
addNamedToRunTimeSelectionTable
|
|
(
|
|
expressionEntry,
|
|
expressionEntry,
|
|
empty,
|
|
label
|
|
);
|
|
|
|
addNamedToRunTimeSelectionTable
|
|
(
|
|
expressionEntry,
|
|
expressionEntry,
|
|
empty,
|
|
scalar
|
|
);
|
|
|
|
addNamedToRunTimeSelectionTable
|
|
(
|
|
expressionEntry,
|
|
expressionEntry,
|
|
empty,
|
|
word
|
|
);
|
|
|
|
} // End namespace exprTools
|
|
} // End namespace Foam
|
|
|
|
|
|
// * * * * * * * * * * * * * * * Local Functions * * * * * * * * * * * * * * //
|
|
|
|
namespace Foam
|
|
{
|
|
inline static const entry* getVariableOrDie
|
|
(
|
|
const word& name,
|
|
const dictionary& dict
|
|
)
|
|
{
|
|
const entry* eptr = dict.findScoped(name, keyType::LITERAL_RECURSIVE);
|
|
|
|
if (!eptr)
|
|
{
|
|
FatalIOErrorInFunction(dict)
|
|
<< "No dictionary entry " << name << nl
|
|
<< exit(FatalIOError);
|
|
}
|
|
|
|
if (eptr->isDict())
|
|
{
|
|
FatalIOErrorInFunction(dict)
|
|
<< "Found dictionary " << name << " instead of entry" << nl
|
|
<< exit(FatalIOError);
|
|
}
|
|
|
|
return eptr;
|
|
}
|
|
|
|
} // End namespace Foam
|
|
|
|
|
|
// * * * * * * * * * * * * * * * * Selectors * * * * * * * * * * * * * * * * //
|
|
|
|
Foam::autoPtr<Foam::exprTools::expressionEntry>
|
|
Foam::exprTools::expressionEntry::New
|
|
(
|
|
const word& name
|
|
)
|
|
{
|
|
auto cstrIter = emptyConstructorTablePtr_->cfind(name);
|
|
|
|
if (!cstrIter.found())
|
|
{
|
|
FatalErrorInLookup
|
|
(
|
|
"expressionEntry",
|
|
name,
|
|
*emptyConstructorTablePtr_
|
|
) << exit(FatalError);
|
|
}
|
|
|
|
return autoPtr<expressionEntry>(cstrIter()());
|
|
}
|
|
|
|
|
|
// * * * * * * * * * * * * * * * Member Functions * * * * * * * * * * * * * //
|
|
|
|
void Foam::exprTools::expressionEntry::inplaceExpand
|
|
(
|
|
std::string& s,
|
|
const dictionary& dict
|
|
)
|
|
{
|
|
// This is much like stringOps::inplaceExpand
|
|
constexpr const char sigil = '$';
|
|
|
|
// Step 1:
|
|
// Handle $[] special expansions first
|
|
|
|
std::string::size_type varBeg = 0;
|
|
|
|
while
|
|
(
|
|
(varBeg = s.find(sigil, varBeg)) != std::string::npos
|
|
&& varBeg < s.size()-1
|
|
)
|
|
{
|
|
if (varBeg && s[varBeg-1] == '\\')
|
|
{
|
|
// Escaped character - pass through
|
|
++varBeg;
|
|
continue;
|
|
}
|
|
|
|
if (s[varBeg+1] == '[')
|
|
{
|
|
// An expression pattern with $[...]
|
|
|
|
std::string::size_type varEnd = s.find(']', varBeg);
|
|
std::string::size_type delim = 1;
|
|
|
|
if (varEnd == std::string::npos)
|
|
{
|
|
// Parsed '$[...' without closing ']' - error
|
|
FatalErrorInFunction
|
|
<< "No correct terminating ']' found in " << s << nl
|
|
<< exit(FatalError);
|
|
break;
|
|
}
|
|
|
|
// Look for embedded (type) cast
|
|
word castTo, varName;
|
|
|
|
const auto lparen = varBeg+2;
|
|
if (lparen < s.size() && s[lparen] == '(')
|
|
{
|
|
const auto rparen = s.find(')', lparen);
|
|
|
|
if (rparen > varEnd)
|
|
{
|
|
// Handles both "$[( ...]" and "$[( ...])" cases
|
|
|
|
auto& err = FatalErrorInFunction;
|
|
|
|
if (rparen == std::string::npos)
|
|
{
|
|
err << "No closing ')' found in ";
|
|
}
|
|
else
|
|
{
|
|
err << "Closing ')' found outside of";
|
|
}
|
|
|
|
err << " substring "
|
|
<< s.substr(varBeg, varEnd-varBeg) << nl
|
|
<< exit(FatalError);
|
|
}
|
|
|
|
castTo.assign(s.substr(lparen+1, rparen - lparen - 1));
|
|
varName.assign(s.substr(rparen+1, varEnd - rparen - 1));
|
|
}
|
|
else
|
|
{
|
|
varName.assign
|
|
(
|
|
s.substr(varBeg + 1 + delim, varEnd - varBeg - 2*delim)
|
|
);
|
|
}
|
|
|
|
// Likely no spaces there, but for extra safety...
|
|
stringOps::inplaceTrim(varName);
|
|
|
|
// Allow recursive plain expansion for the *variable* name.
|
|
// 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;
|
|
|
|
if (castTo.empty())
|
|
{
|
|
// Serialized with spaces
|
|
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
|
|
{
|
|
varValue = expressionEntry::New(castTo)->toExpr(*eptr);
|
|
}
|
|
|
|
s.std::string::replace(varBeg, replaceLen, varValue);
|
|
varBeg += varValue.size();
|
|
}
|
|
else
|
|
{
|
|
++varBeg;
|
|
}
|
|
}
|
|
|
|
|
|
// Step 2:
|
|
// Handle all ${}, $var and ${{ ... }} expansions.
|
|
// - this is done second such that $[(vector) xyz] entries will have
|
|
// been properly expanded by this stage
|
|
|
|
// Expand with env=true, empty=true, subDict=false
|
|
stringOps::inplaceExpand(s, dict, true, true, false);
|
|
}
|
|
|
|
|
|
Foam::expressions::exprString
|
|
Foam::exprTools::expressionEntry::expand
|
|
(
|
|
const std::string& orig,
|
|
const dictionary& dict
|
|
)
|
|
{
|
|
// Copy without validation (use assign)
|
|
expressions::exprString s;
|
|
s.assign(orig);
|
|
|
|
inplaceExpand(s, dict);
|
|
|
|
return s;
|
|
}
|
|
|
|
|
|
// ************************************************************************* //
|