/*---------------------------------------------------------------------------*\
========= |
\\ / 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 .
\*---------------------------------------------------------------------------*/
#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::New
(
const word& name
)
{
auto cstrIter = emptyConstructorTablePtr_->cfind(name);
if (!cstrIter.found())
{
FatalErrorInLookup
(
"expressionEntry",
name,
*emptyConstructorTablePtr_
) << exit(FatalError);
}
return autoPtr(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;
}
// ************************************************************************* //