dynamicCodeContext: Lookup variables from the context dictionary

codeStream (#calc etc.) creates a local sub-dictionary in which to expand the
code so variable lookup needs to be checked with respect to the context
dictionary rather than with respect to the code sub-dictionary.  With this
change the following test/dictionary/testCalc #calc example now works:

    a   1.1;

    d
    {
        b   4.8;
    }

    // Access to higher-level sub-entries using the "../" operators, e.g.
    f
    {
        g #calc "$a / $../d/b";
    }
This commit is contained in:
Henry Weller
2024-07-26 11:15:56 +01:00
parent 44bfb5ac43
commit 6ebeb96563
5 changed files with 75 additions and 40 deletions

View File

@ -85,13 +85,14 @@ bool Foam::functionEntries::codeStream::masterOnlyRead
Foam::functionEntries::codeStream::streamingFunctionType
Foam::functionEntries::codeStream::getFunction
(
const dictionary& parentDict,
const dictionary& contextDict,
const dictionary& codeDict
)
{
// Get code, codeInclude, ...
const dynamicCodeContext context
(
contextDict,
codeDict,
{"code", "codeInclude", "localCode"},
{"dict", word::null, word::null}
@ -162,7 +163,7 @@ Foam::functionEntries::codeStream::getFunction
{
FatalIOErrorInFunction
(
parentDict
contextDict
) << "Failed writing files for" << nl
<< dynCode.libRelPath() << nl
<< exit(FatalIOError);
@ -173,7 +174,7 @@ Foam::functionEntries::codeStream::getFunction
{
FatalIOErrorInFunction
(
parentDict
contextDict
) << "Failed wmake " << dynCode.libRelPath() << nl
<< exit(FatalIOError);
}
@ -182,7 +183,7 @@ Foam::functionEntries::codeStream::getFunction
// Only block if not master only reading of a global dictionary
if
(
!masterOnlyRead(parentDict)
!masterOnlyRead(contextDict)
&& regIOobject::fileModificationSkew > 0
)
{
@ -224,7 +225,7 @@ Foam::functionEntries::codeStream::getFunction
{
FatalIOErrorInFunction
(
parentDict
contextDict
) << "Cannot read (NFS mounted) library " << nl
<< libPath << nl
<< "on processor " << Pstream::myProcNo()
@ -272,7 +273,7 @@ Foam::functionEntries::codeStream::getFunction
{
FatalIOErrorInFunction
(
parentDict
contextDict
) << "Failed loading library " << libPath << nl
<< "Did you add all libraries to the 'libs' entry"
<< " in system/controlDict?"
@ -280,7 +281,7 @@ Foam::functionEntries::codeStream::getFunction
}
bool haveLib = lib;
if (!masterOnlyRead(parentDict))
if (!masterOnlyRead(contextDict))
{
reduce(haveLib, andOp<bool>());
}
@ -289,7 +290,7 @@ Foam::functionEntries::codeStream::getFunction
{
FatalIOErrorInFunction
(
parentDict
contextDict
) << "Failed loading library " << libPath
<< " on some processors."
<< exit(FatalIOError);
@ -308,7 +309,7 @@ Foam::functionEntries::codeStream::getFunction
{
FatalIOErrorInFunction
(
parentDict
contextDict
) << "Failed looking up symbol " << dynCode.codeName()
<< " in library " << lib << exit(FatalIOError);
}
@ -319,31 +320,31 @@ Foam::functionEntries::codeStream::getFunction
Foam::string Foam::functionEntries::codeStream::run
(
const dictionary& parentDict,
const dictionary& contextDict,
Istream& is
)
{
if (debug)
{
Info<< "Using #codeStream at line " << is.lineNumber()
<< " in file " << parentDict.name() << endl;
<< " in file " << contextDict.name() << endl;
}
dynamicCode::checkSecurity
(
"functionEntries::codeStream::execute(..)",
parentDict
contextDict
);
// Construct codeDict for codeStream
// Parent dictionary provided for string expansion and variable substitution
const dictionary codeDict("#codeStream", parentDict, is);
const dictionary codeDict("#codeStream", contextDict, is);
const streamingFunctionType function = getFunction(parentDict, codeDict);
const streamingFunctionType function = getFunction(contextDict, codeDict);
// Use function to write stream
OStringStream os(is.format());
(*function)(os, parentDict);
(*function)(os, contextDict);
// Return the string containing the results of the code execution
return os.str();
@ -354,22 +355,22 @@ Foam::string Foam::functionEntries::codeStream::run
bool Foam::functionEntries::codeStream::execute
(
dictionary& parentDict,
dictionary& contextDict,
Istream& is
)
{
return insert(parentDict, run(parentDict, is));
return insert(contextDict, run(contextDict, is));
}
bool Foam::functionEntries::codeStream::execute
(
const dictionary& parentDict,
const dictionary& contextDict,
primitiveEntry& thisEntry,
Istream& is
)
{
return insert(parentDict, thisEntry, run(parentDict, is));
return insert(contextDict, thisEntry, run(contextDict, is));
}

View File

@ -2,7 +2,7 @@
========= |
\\ / F ield | OpenFOAM: The Open Source CFD Toolbox
\\ / O peration | Website: https://openfoam.org
\\ / A nd | Copyright (C) 2011-2023 OpenFOAM Foundation
\\ / A nd | Copyright (C) 2011-2024 OpenFOAM Foundation
\\/ M anipulation |
-------------------------------------------------------------------------------
License
@ -222,14 +222,14 @@ class codeStream
//- Construct, compile, load and return streaming function
static streamingFunctionType getFunction
(
const dictionary& parentDict,
const dictionary& contextDict,
const dictionary& codeDict
);
//- Compile and execute the code and return the resulting string
static string run
(
const dictionary& parentDict,
const dictionary& contextDict,
Istream& is
);
@ -260,12 +260,12 @@ public:
// Member Functions
//- Execute the functionEntry in a sub-dict context
static bool execute(dictionary& parentDict, Istream&);
static bool execute(dictionary& contextDict, Istream&);
//- Execute the functionEntry in a primitiveEntry context
static bool execute
(
const dictionary& parentDict,
const dictionary& contextDict,
primitiveEntry&,
Istream&
);

View File

@ -44,12 +44,13 @@ void Foam::dynamicCodeContext::addLineDirective
Foam::dynamicCodeContext::dynamicCodeContext
(
const dictionary& dict,
const dictionary& contextDict,
const dictionary& codeDict,
const wordList& codeKeys,
const wordList& codeDictVars
)
:
dict_(dict),
contextDict_(contextDict),
code_(),
options_(),
libs_()
@ -61,11 +62,16 @@ Foam::dynamicCodeContext::dynamicCodeContext
forAll(codeKeys, i)
{
const word& key = codeKeys[i];
codePtrs[i] = dict.lookupEntryPtr(key, false, false);
codePtrs[i] = codeDict.lookupEntryPtr(key, false, false);
if (codePtrs[i])
{
string s(stringOps::trim(verbatimString(codePtrs[i]->stream())));
stringOps::inplaceExpandCodeString(s, dict, codeDictVars[i]);
stringOps::inplaceExpandCodeString
(
s,
contextDict, // Lookup variables from the context dictionary
codeDictVars[i]
);
code_.insert(key, s);
}
else
@ -75,19 +81,20 @@ Foam::dynamicCodeContext::dynamicCodeContext
}
// Options
const entry* optionsPtr = dict.lookupEntryPtr("codeOptions", false, false);
const entry* optionsPtr =
codeDict.lookupEntryPtr("codeOptions", false, false);
if (optionsPtr)
{
options_ = stringOps::trim(verbatimString(optionsPtr->stream()));
stringOps::inplaceExpandCodeString(options_, dict, word::null);
stringOps::inplaceExpandCodeString(options_, contextDict, word::null);
}
// Libs
const entry* libsPtr = dict.lookupEntryPtr("codeLibs", false, false);
const entry* libsPtr = codeDict.lookupEntryPtr("codeLibs", false, false);
if (libsPtr)
{
libs_ = stringOps::trim(verbatimString(libsPtr->stream()));
stringOps::inplaceExpandCodeString(libs_, dict, word::null);
stringOps::inplaceExpandCodeString(libs_, contextDict, word::null);
}
// Calculate SHA1 digest from all entries
@ -110,11 +117,22 @@ Foam::dynamicCodeContext::dynamicCodeContext
(
code_[key],
codePtrs[i]->startLineNumber(),
dict.name()
codeDict.name()
);
}
}
}
Foam::dynamicCodeContext::dynamicCodeContext
(
const dictionary& contextDict,
const wordList& codeKeys,
const wordList& codeDictVars
)
:
dynamicCodeContext(contextDict, contextDict, codeKeys, codeDictVars)
{}
// ************************************************************************* //

View File

@ -52,8 +52,8 @@ class dynamicCodeContext
{
// Private Data
//- The parent dictionary context
const dictionary& dict_;
//- The context dictionary
const dictionary& contextDict_;
//- Code entries
HashTable<string> code_;
@ -84,11 +84,21 @@ public:
// Constructors
//- Construct from a dictionary and lists of which entries correspond
// to code
//- Construct from the context and code dictionaries
// and lists of which entries correspond to code
dynamicCodeContext
(
const dictionary& dict,
const dictionary& contextDict,
const dictionary& codeDict,
const wordList& codeKeys,
const wordList& codeDictVars
);
//- Construct from the context dictionary also containing the code
// and lists of which entries correspond
dynamicCodeContext
(
const dictionary& contextDict,
const wordList& codeKeys,
const wordList& codeDictVars
);
@ -96,10 +106,10 @@ public:
// Member Functions
//- Return the parent dictionary context
//- Return the context dictionary
const dictionary& dict() const
{
return dict_;
return contextDict_;
}
//- Return the code table

View File

@ -36,6 +36,12 @@ d
}
e #calc "$a / $d/b";
// Access to higher-level sub-entries using the "../" operators, e.g.
f
{
g #calc "$a / $../d/b";
}
s "field";
fieldName #calc "$<string>s + \"Name\"";