dictionary: Added experimental "slash" syntax

A new optional "slash" scoping syntax is now provided which is more intuitive
than the current "dot" syntax as it corresponds to the common directory/file
access syntax used in UNIX, and avoids limitations of the "dot" (see below)
e.g.

internalField 3.4;

active
{
    type            fixedValue;
    value.air       $internalField;
}

inactive
{
    type            anotherFixedValue;

    value           $../active/value.air;
    anotherValue    $:active/value.air;

    sub
    {
        value           $../../active/value.air;
        anotherValue    $:active/value.air;
    }
}

"U.*"
{
    solver GAMG;
}

e.air
{
    // This does expand
    $U.air;
}

"#inputSyntax slash;" selects the new "slash" syntax.
"../" refers to the parent directory.
":" refers to the top-level directory.

The corresponding dictionary using the current "dot" syntax is

internalField 3.4;

active
{
    type            fixedValue;
    value.air       $internalField;
}

inactive
{
    type            anotherFixedValue;

    value           $..active.value.air;
    anotherValue    $:active.value.air;

    sub
    {
        value           $...active.value.air;
        anotherValue    $:active.value.air;
    }
}

"U.*"
{
    solver GAMG;
}

e.air
{
    // This doesn't expand
    $U.air;
}

Note that the "$U.air" expansion does not work in this case due to the
interference between the use of '.' for scoping and phase-name.
This is a fundamental problem which prompted the development of the new more
intuitive and flexible "slash" syntax.

The new syntax also allows a for planned future development to access entries
in directories in other files, e.g.

active
{
    type            fixedValue;
    value.air       $FOAM_CASE/internalFieldValues/value.air;
}

or

active
{
    type            fixedValue;
    value.air       :../internalFieldValues/value.air;
}
This commit is contained in:
Henry Weller
2019-07-09 16:45:07 +01:00
parent 481f643aec
commit a7b8425690
13 changed files with 575 additions and 29 deletions

View File

@ -0,0 +1,52 @@
/*--------------------------------*- C++ -*----------------------------------*\
========= |
\\ / F ield | OpenFOAM: The Open Source CFD Toolbox
\\ / O peration | Website: https://openfoam.org
\\ / A nd | Version: dev
\\/ M anipulation |
\*---------------------------------------------------------------------------*/
FoamFile
{
version 2.0;
format ascii;
class dictionary;
object testSlashDict;
}
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
#inputSyntax dot;
internalField 3.4;
active
{
type fixedValue;
value.air $internalField;
}
inactive
{
type anotherFixedValue;
value $..active.value.air;
anotherValue $:active.value.air;
sub
{
value $...active.value.air;
anotherValue $:active.value.air;
}
}
"U.*"
{
solver GAMG;
}
e.air
{
// This doesn't expand
$U.air;
}
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //

View File

@ -0,0 +1,52 @@
/*--------------------------------*- C++ -*----------------------------------*\
========= |
\\ / F ield | OpenFOAM: The Open Source CFD Toolbox
\\ / O peration | Website: https://openfoam.org
\\ / A nd | Version: dev
\\/ M anipulation |
\*---------------------------------------------------------------------------*/
FoamFile
{
version 2.0;
format ascii;
class dictionary;
object testSlashDict;
}
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
#inputSyntax slash;
internalField 3.4;
active
{
type fixedValue;
value.air $internalField;
}
inactive
{
type anotherFixedValue;
value $../active/value.air;
anotherValue $:active/value.air;
sub
{
value $../../active/value.air;
anotherValue $:active/value.air;
}
}
"U.*"
{
solver GAMG;
}
e.air
{
// This does expand
$U.air;
}
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //

View File

@ -79,6 +79,9 @@ OptimisationSwitches
// Force dumping (at next timestep) upon signal (-1 to disable) and exit
stopAtWriteNowSignal -1;
// Default dictionary scoping syntax
inputSyntax dot;
}

View File

@ -218,6 +218,7 @@ $(functionEntries)/includeEntry/includeEntry.C
$(functionEntries)/includeEtcEntry/includeEtcEntry.C
$(functionEntries)/includeFuncEntry/includeFuncEntry.C
$(functionEntries)/includeIfPresentEntry/includeIfPresentEntry.C
$(functionEntries)/inputSyntaxEntry/inputSyntaxEntry.C
$(functionEntries)/inputModeEntry/inputModeEntry.C
$(functionEntries)/removeEntry/removeEntry.C
$(functionEntries)/ifeqEntry/ifeqEntry.C

View File

@ -29,6 +29,8 @@ License
#include "regExp.H"
#include "OSHA1stream.H"
#include "DynamicList.H"
#include "inputSyntaxEntry.H"
/* * * * * * * * * * * * * * * Static Member Data * * * * * * * * * * * * * */
@ -46,7 +48,7 @@ namespace Foam
// * * * * * * * * * * * * * Private Member Functions * * * * * * * * * * * //
const Foam::entry* Foam::dictionary::lookupScopedSubEntryPtr
const Foam::entry* Foam::dictionary::lookupDotScopedSubEntryPtr
(
const word& keyword,
bool recursive,
@ -84,7 +86,7 @@ const Foam::entry* Foam::dictionary::lookupScopedSubEntryPtr
*this
) << "No parent of current dictionary"
<< " when searching for "
<< keyword.substr(begVar, keyword.size()-begVar)
<< keyword.substr(begVar, keyword.size() - begVar)
<< exit(FatalIOError);
}
dictPtr = &dictPtr->parent_;
@ -102,7 +104,7 @@ const Foam::entry* Foam::dictionary::lookupScopedSubEntryPtr
// Extract the first word
word firstWord = keyword.substr(0, dotPos);
const entry* entPtr = lookupScopedSubEntryPtr
const entry* entPtr = lookupDotScopedSubEntryPtr
(
firstWord,
false, // recursive
@ -118,7 +120,7 @@ const Foam::entry* Foam::dictionary::lookupScopedSubEntryPtr
string::size_type nextDotPos = keyword.find
(
'.',
dotPos+1
dotPos + 1
);
while (true)
@ -137,19 +139,148 @@ const Foam::entry* Foam::dictionary::lookupScopedSubEntryPtr
if (subEntPtr && subEntPtr->isDict())
{
return subEntPtr->dict().lookupScopedSubEntryPtr
return subEntPtr->dict().lookupDotScopedSubEntryPtr
(
keyword.substr
(
nextDotPos,
keyword.size()-nextDotPos
keyword.size() - nextDotPos
),
false,
patternMatch
);
}
nextDotPos = keyword.find('.', nextDotPos+1);
nextDotPos = keyword.find('.', nextDotPos + 1);
}
}
if (entPtr->isDict())
{
return entPtr->dict().lookupDotScopedSubEntryPtr
(
keyword.substr(dotPos, keyword.size() - dotPos),
false,
patternMatch
);
}
else
{
return nullptr;
}
}
}
}
const Foam::entry* Foam::dictionary::lookupScopedSubEntryPtr
(
const word& keyword,
bool recursive,
bool patternMatch
) const
{
if (functionEntries::inputSyntaxEntry::dot())
{
return lookupDotScopedSubEntryPtr(keyword, recursive, patternMatch);
}
string::size_type slashPos = keyword.find('/');
if (slashPos == string::npos)
{
// Non-scoped lookup
return lookupEntryPtr(keyword, recursive, patternMatch);
}
else
{
// Extract the first word
word firstWord = keyword.substr(0, slashPos);
slashPos++;
if (firstWord == ".")
{
return lookupScopedSubEntryPtr
(
keyword.substr(slashPos),
false,
patternMatch
);
}
else if (firstWord == "..")
{
// Go to parent
if (&parent_ == &dictionary::null)
{
FatalIOErrorInFunction
(
*this
) << "No parent of current dictionary"
<< " when searching for "
<< keyword.substr(slashPos, keyword.size() - slashPos)
<< exit(FatalIOError);
}
return parent_.lookupScopedSubEntryPtr
(
keyword.substr(slashPos),
false,
patternMatch
);
}
else
{
const entry* entPtr = lookupScopedSubEntryPtr
(
firstWord,
false, // recursive
patternMatch
);
if (!entPtr)
{
// Fall back to finding key with '/' so e.g. if keyword is
// a/b/c/d it would try
// a/b, a/b/c, a/b/c/d
string::size_type nextSlashPos = keyword.find
(
'/',
slashPos
);
while (true)
{
const entry* subEntPtr = lookupEntryPtr
(
keyword.substr(0, nextSlashPos),
false, // recursive,
patternMatch
);
if (nextSlashPos == string::npos)
{
// Parsed the whole word. Return entry or null.
return subEntPtr;
}
nextSlashPos++;
if (subEntPtr && subEntPtr->isDict())
{
return subEntPtr->dict().lookupScopedSubEntryPtr
(
keyword.substr
(
nextSlashPos,
keyword.size() - nextSlashPos
),
false,
patternMatch
);
}
nextSlashPos = keyword.find('/', nextSlashPos);
}
}
@ -157,7 +288,7 @@ const Foam::entry* Foam::dictionary::lookupScopedSubEntryPtr
{
return entPtr->dict().lookupScopedSubEntryPtr
(
keyword.substr(dotPos, keyword.size()-dotPos),
keyword.substr(slashPos, keyword.size() - slashPos),
false,
patternMatch
);
@ -340,7 +471,7 @@ Foam::dictionary::dictionary
patternEntries_(move(dict.patternEntries_)),
patternRegexps_(move(dict.patternRegexps_))
{
name() = parentDict.name() + '.' + name();
name() = parentDict.name() + '/' + name();
}
@ -609,7 +740,7 @@ const Foam::entry* Foam::dictionary::lookupScopedEntryPtr
// At top. Recurse to find entries
return dictPtr->lookupScopedSubEntryPtr
(
keyword.substr(1, keyword.size()-1),
keyword.substr(1, keyword.size() - 1),
false,
patternMatch
);
@ -628,7 +759,7 @@ const Foam::entry* Foam::dictionary::lookupScopedEntryPtr
bool Foam::dictionary::substituteScopedKeyword(const word& keyword)
{
word varName = keyword(1, keyword.size()-1);
word varName = keyword(1, keyword.size() - 1);
// Lookup the variable name in the given dictionary
const entry* ePtr = lookupScopedEntryPtr(varName, true, true);
@ -752,7 +883,7 @@ Foam::dictionary Foam::dictionary::subOrEmptyDict
}
else
{
return dictionary(*this, dictionary(name() + '.' + keyword));
return dictionary(*this, dictionary(name() + '/' + keyword));
}
}
else
@ -844,7 +975,7 @@ bool Foam::dictionary::add(entry* entryPtr, bool mergeEntry)
if (hashedEntries_.insert(entryPtr->keyword(), entryPtr))
{
entryPtr->name() = name() + '.' + entryPtr->keyword();
entryPtr->name() = name() + '/' + entryPtr->keyword();
if (entryPtr->keyword().isPattern())
{
@ -872,7 +1003,7 @@ bool Foam::dictionary::add(entry* entryPtr, bool mergeEntry)
if (hashedEntries_.insert(entryPtr->keyword(), entryPtr))
{
entryPtr->name() = name() + '.' + entryPtr->keyword();
entryPtr->name() = name() + '/' + entryPtr->keyword();
IDLList<entry>::append(entryPtr);
if (entryPtr->keyword().isPattern())
@ -1077,7 +1208,7 @@ bool Foam::dictionary::changeKeyword
// Change name and HashTable, but leave DL-List untouched
iter()->keyword() = newKeyword;
iter()->name() = name() + '.' + newKeyword;
iter()->name() = name() + '/' + newKeyword;
hashedEntries_.erase(oldKeyword);
hashedEntries_.insert(newKeyword, iter());

View File

@ -125,7 +125,7 @@ public:
{
const word scopedName = name_.name();
string::size_type i = scopedName.rfind('.');
string::size_type i = scopedName.rfind('/');
if (i == scopedName.npos)
{
@ -183,7 +183,16 @@ class dictionary
// Private Member Functions
//- Find and return an entry data stream pointer if present
// otherwise return nullptr. Allows scoping using '.'
// otherwise return nullptr. Supports scoping using '.'
const entry* lookupDotScopedSubEntryPtr
(
const word&,
bool recursive,
bool patternMatch
) const;
//- Find and return an entry data stream pointer if present
// otherwise return nullptr. Supports scoping using '/'
const entry* lookupScopedSubEntryPtr
(
const word&,
@ -413,8 +422,9 @@ public:
) const;
//- Find and return an entry data stream pointer if present
// otherwise return nullptr. Allows scoping using '.'.
// Special handling for ':' at start of keyword and '..'.
// otherwise return nullptr. Allows scoping using '/'.
// Special handling for ':' at start of keyword and
// '..'.
const entry* lookupScopedEntryPtr
(
const word&,

View File

@ -24,6 +24,7 @@ License
\*---------------------------------------------------------------------------*/
#include "dictionary.H"
#include "inputSyntaxEntry.H"
#include "inputModeEntry.H"
#include "regExp.H"
@ -36,7 +37,7 @@ Foam::dictionary::dictionary
Istream& is
)
:
dictionaryName(parentDict.name() + '.' + name),
dictionaryName(parentDict.name() + '/' + name),
parent_(parentDict)
{
read(is);
@ -48,6 +49,9 @@ Foam::dictionary::dictionary(Istream& is)
dictionaryName(is.name()),
parent_(dictionary::null)
{
// Reset input syntax as this is a "top-level" dictionary
functionEntries::inputSyntaxEntry::clear();
// Reset input mode as this is a "top-level" dictionary
functionEntries::inputModeEntry::clear();
@ -60,6 +64,9 @@ Foam::dictionary::dictionary(Istream& is, const bool keepHeader)
dictionaryName(is.name()),
parent_(dictionary::null)
{
// Reset input syntax as this is a "top-level" dictionary
functionEntries::inputSyntaxEntry::clear();
// Reset input mode as this is a "top-level" dictionary
functionEntries::inputModeEntry::clear();
@ -164,6 +171,9 @@ void Foam::writeEntry(Ostream& os, const dictionary& value)
Foam::Istream& Foam::operator>>(Istream& is, dictionary& dict)
{
// Reset input syntax as this is a "top-level" dictionary
functionEntries::inputSyntaxEntry::clear();
// Reset input mode assuming this is a "top-level" dictionary
functionEntries::inputModeEntry::clear();

View File

@ -0,0 +1,129 @@
/*---------------------------------------------------------------------------*\
========= |
\\ / F ield | OpenFOAM: The Open Source CFD Toolbox
\\ / O peration | Website: https://openfoam.org
\\ / A nd | Copyright (C) 2019 OpenFOAM Foundation
\\/ M anipulation |
-------------------------------------------------------------------------------
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 "inputSyntaxEntry.H"
#include "addToMemberFunctionSelectionTable.H"
// * * * * * * * * * * * * * * Static Data Members * * * * * * * * * * * * * //
const Foam::word Foam::functionEntries::inputSyntaxEntry::typeName
(
Foam::functionEntries::inputSyntaxEntry::typeName_()
);
// Don't lookup the debug switch here as the debug switch dictionary
// might include inputSyntax entries
int Foam::functionEntries::inputSyntaxEntry::debug(0);
Foam::functionEntries::inputSyntaxEntry::inputSyntax
Foam::functionEntries::inputSyntaxEntry::syntax_
(
Foam::debug::optimisationSwitches().found("inputSyntax")
? Foam::functionEntries::inputSyntaxEntry::syntax
(
Foam::debug::optimisationSwitches().lookup
(
"inputSyntax"
)
)
: DOT
);
namespace Foam
{
namespace functionEntries
{
addToMemberFunctionSelectionTable
(
functionEntry,
inputSyntaxEntry,
execute,
dictionaryIstream
);
}
}
// * * * * * * * * * * * * * Private Member Functions * * * * * * * * * * * //
Foam::functionEntries::inputSyntaxEntry::inputSyntax
Foam::functionEntries::inputSyntaxEntry::syntax
(
Istream& is
)
{
word syntax(is);
if (syntax == "slash" || syntax == "default")
{
return SLASH;
}
else if (syntax == "dot")
{
return DOT;
}
else
{
WarningInFunction
<< "unsupported input syntax'" << syntax
<< "' ... defaulting to 'dot'"
<< endl;
return DOT;
}
}
// * * * * * * * * * * * * * * * Member Functions * * * * * * * * * * * * * //
bool Foam::functionEntries::inputSyntaxEntry::execute
(
dictionary& parentDict,
Istream& is
)
{
syntax_ = syntax(is);
return true;
}
void Foam::functionEntries::inputSyntaxEntry::clear()
{
syntax_ = DOT;
}
bool Foam::functionEntries::inputSyntaxEntry::slash()
{
return syntax_ == SLASH;
}
bool Foam::functionEntries::inputSyntaxEntry::dot()
{
return syntax_ == DOT;
}
// ************************************************************************* //

View File

@ -0,0 +1,139 @@
/*---------------------------------------------------------------------------*\
========= |
\\ / F ield | OpenFOAM: The Open Source CFD Toolbox
\\ / O peration | Website: https://openfoam.org
\\ / A nd | Copyright (C) 2019 OpenFOAM Foundation
\\/ M anipulation |
-------------------------------------------------------------------------------
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::inputSyntaxEntry
Description
Specify the dictionary scoping syntax, expects a single word to follow.
An example of \c \#inputSyntax directive:
\verbatim
#inputSyntax dot
\endverbatim
The possible input syntax:
- \par slash use '/' as the scope operator
and '../' to go to the parent dictionary
- \par dot use '.' as the scope operator
and '..' to go to the parent dictionary
- \par default currently identical to dot
The default dictionary syntax is \c dot but changed to \c slash in
etc/controlDict
\verbatim
OptimisationSwitches
{
.
.
.
inputSyntax slash;
}
\endverbatim
SourceFiles
inputSyntaxEntry.C
\*---------------------------------------------------------------------------*/
#ifndef inputSyntaxEntry_H
#define inputSyntaxEntry_H
#include "functionEntry.H"
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
namespace Foam
{
namespace functionEntries
{
/*---------------------------------------------------------------------------*\
Class inputSyntaxEntry Declaration
\*---------------------------------------------------------------------------*/
class inputSyntaxEntry
:
public functionEntry
{
//- The input syntax options
enum inputSyntax
{
SLASH,
DOT
};
//- The current input syntax
static inputSyntax syntax_;
// Private Member Functions
//- Read the syntax as a word and return the corresponding enum
static inputSyntax syntax(Istream&);
public:
//- Runtime type information
ClassName("inputSyntax");
// Constructors
//- Disallow default bitwise copy construction
inputSyntaxEntry(const inputSyntaxEntry&) = delete;
// Member Functions
//- Execute the functionEntry in a sub-dict context
static bool execute(dictionary& parentDict, Istream&);
//- Reset the inputSyntax to %default (ie, %merge)
static void clear();
//- Return true if the inputSyntax is %slash
static bool slash();
//- Return true if the inputSyntax is %dot
static bool dot();
// Member Operators
//- Disallow default bitwise assignment
void operator=(const inputSyntaxEntry&) = delete;
};
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
} // End namespace functionEntries
} // End namespace Foam
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
#endif
// ************************************************************************* //

View File

@ -111,7 +111,7 @@ Foam::primitiveEntry::primitiveEntry(const keyType& key, const ITstream& is)
entry(key),
ITstream(is)
{
name() += '.' + keyword();
name() += '/' + keyword();
}

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-2018 OpenFOAM Foundation
\\ / A nd | Copyright (C) 2011-2019 OpenFOAM Foundation
\\/ M anipulation |
-------------------------------------------------------------------------------
License
@ -203,7 +203,7 @@ Foam::primitiveEntry::primitiveEntry
entry(key),
ITstream
(
is.name() + '.' + key,
is.name() + '/' + key,
tokenList(10),
is.format(),
is.version()
@ -218,7 +218,7 @@ Foam::primitiveEntry::primitiveEntry(const keyType& key, Istream& is)
entry(key),
ITstream
(
is.name() + '.' + key,
is.name() + '/' + key,
tokenList(10),
is.format(),
is.version()

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-2018 OpenFOAM Foundation
\\ / A nd | Copyright (C) 2011-2019 OpenFOAM Foundation
\\/ M anipulation |
-------------------------------------------------------------------------------
License
@ -119,7 +119,6 @@ inline bool Foam::word::valid(char c)
!isspace(c)
&& c != '"' // string quote
&& c != '\'' // string quote
&& c != '/' // path separator
&& c != ';' // end statement
&& c != '{' // beg subdict
&& c != '}' // end subdict

View File

@ -71,11 +71,31 @@ Foam::string foamSpecieString(const char* YYText)
return specieString;
}
class foamSpecieName
{
public:
//- Is this character valid for a foamSpecieName
inline static bool valid(char c)
{
return
(
!isspace(c)
&& c != '"' // string quote
&& c != '\'' // string quote
&& c != '/' // slash
&& c != ';' // end statement
&& c != '{' // beg subdict
&& c != '}' // end subdict
);
}
};
Foam::word foamName(const char* YYText)
{
Foam::string fn(YYText);
Foam::string::stripInvalid<Foam::word>(fn);
Foam::string::stripInvalid<foamSpecieName>(fn);
return fn;
}
@ -83,7 +103,7 @@ Foam::word foamName(const char* YYText)
Foam::word foamName(const Foam::string& s)
{
Foam::string fn(s);
Foam::string::stripInvalid<Foam::word>(fn);
Foam::string::stripInvalid<foamSpecieName>(fn);
return fn;
}
@ -121,7 +141,7 @@ startIsotopeMolW {space}"/"{space}
isotopeMolW {space}{floatNum}{space}"/"{space}
specieName {space}[A-Za-z](([A-Za-z0-9)*+-])|("("[^+]))*{space}
Y {space}{floatNum}{space}
Y {space}{floatNum}{space}
thermoTemp .{10}