/*---------------------------------------------------------------------------*\ ========= | \\ / 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; } // ************************************************************************* //