Commit 511b3562 authored by Mark Olesen's avatar Mark Olesen
Browse files

ENH: improve infrastructure for detecting excess tokens (issue #762)

- Always used for optional dictionary entries, since these are individual
  values, and not meant to be embedded in a larger stream of tokens.

  Methods:
     - lookupOrDefault, lookupOrAddDefault, lookupOrDefaultCompat
     - readIfPresent, readIfPresentCompat

- Handling mandatory dictionary entries is slightly more complex,
  since these may be part of larger stream of tokens, and are often
  used in a constructor context. For example,

      word modelType(dict.lookup("type"));

  Or they are used without a definite context. For example,

      dict.lookup("format") >> outputFormat;

  Newly introduced methods for mandatory dictionary entries:
     - get, getCompat
     - read, readCompat

  In a constructor or assignment context:

      word modelType(dict.get<word>("type"));
      outputFormat = dict.lookup("format");

  without copy/move (similar to readIfPresent):

      dict.read("format", outputFormat);
parent a6f524b1
......@@ -138,7 +138,7 @@ const T* Foam::DictionaryBase<IDLListType, T>::lookup(const word& keyword) const
if (iter == hashedTs_.end())
{
FatalErrorInFunction
<< keyword << " is undefined"
<< "'" << keyword << "' not found"
<< exit(FatalError);
}
......@@ -154,7 +154,7 @@ T* Foam::DictionaryBase<IDLListType, T>::lookup(const word& keyword)
if (iter == hashedTs_.end())
{
FatalErrorInFunction
<< keyword << " is undefined"
<< "'" << keyword << "' not found"
<< exit(FatalError);
}
......
......@@ -3,7 +3,7 @@
\\ / F ield | OpenFOAM: The Open Source CFD Toolbox
\\ / O peration |
\\ / A nd | Copyright (C) 2011-2017 OpenFOAM Foundation
\\/ M anipulation | Copyright (C) 2015-2017 OpenCFD Ltd.
\\/ M anipulation | Copyright (C) 2015-2018 OpenCFD Ltd.
-------------------------------------------------------------------------------
License
This file is part of OpenFOAM.
......@@ -24,6 +24,8 @@ License
\*---------------------------------------------------------------------------*/
#include "dictionary.H"
#include "error.H"
#include "JobInfo.H"
#include "primitiveEntry.H"
#include "dictionaryEntry.H"
#include "regExp.H"
......@@ -48,7 +50,6 @@ bool Foam::dictionary::writeOptionalEntries
void Foam::dictionary::excessTokens
(
OSstream& msg,
const word& keyword,
const ITstream& is
) const
......@@ -60,12 +61,44 @@ void Foam::dictionary::excessTokens
return;
}
msg << "entry '" << keyword << "' has "
<< nExcess << " excess tokens, near line: " << is.lineNumber() << nl
<< "dictionary: " << name() << nl
<< "stream: ";
is.writeList(msg, 0);
msg << nl;
// Similar to SafeFatalIOError
if (JobInfo::constructed)
{
OSstream& err =
FatalIOError
(
"", // functionName
"", // sourceFileName
0, // sourceFileLineNumber
this->name(), // ioFileName
is.lineNumber() // ioStartLineNumber
);
err << "'" << keyword << "' has "
<< nExcess << " excess tokens in stream" << nl << nl
<< " ";
is.writeList(err, 0);
err << exit(FatalIOError);
}
else
{
std::cerr
<< nl
<< "--> FOAM FATAL IO ERROR:" << nl;
std::cerr
<< "'" << keyword << "' has "
<< nExcess << " excess tokens in stream" << nl << nl;
std::cerr
<< "file: " << this->name()
<< " at line " << is.lineNumber() << '.' << nl
<< std::endl;
::exit(1);
}
}
......@@ -296,10 +329,8 @@ const Foam::entry& Foam::dictionary::lookupEntry
if (!finder.found())
{
FatalIOErrorInFunction
(
*this
) << "keyword " << keyword << " is undefined in dictionary "
FatalIOErrorInFunction(*this)
<< "'" << keyword << "' not found in dictionary "
<< name()
<< exit(FatalIOError);
}
......@@ -422,10 +453,8 @@ const Foam::dictionary& Foam::dictionary::subDict(const word& keyword) const
if (!finder.found())
{
FatalIOErrorInFunction
(
*this
) << "keyword " << keyword << " is undefined in dictionary "
FatalIOErrorInFunction(*this)
<< "'" << keyword << "' not found in dictionary "
<< name()
<< exit(FatalIOError);
}
......@@ -441,10 +470,8 @@ Foam::dictionary& Foam::dictionary::subDict(const word& keyword)
if (!finder.found())
{
FatalIOErrorInFunction
(
*this
) << "keyword " << keyword << " is undefined in dictionary "
FatalIOErrorInFunction(*this)
<< "'" << keyword << "' not found in dictionary "
<< name()
<< exit(FatalIOError);
}
......@@ -470,20 +497,18 @@ Foam::dictionary Foam::dictionary::subOrEmptyDict
if (mustRead)
{
FatalIOErrorInFunction
(
*this
) << "keyword " << keyword
<< " is not a sub-dictionary in dictionary "
FatalIOErrorInFunction(*this)
<< "'" << keyword
<< "' is not a sub-dictionary in dictionary "
<< name()
<< exit(FatalIOError);
}
if (finder.found())
{
IOWarningInFunction((*this))
<< "keyword " << keyword
<< " found but not a sub-dictionary in dictionary "
IOWarningInFunction(*this)
<< "'" << keyword
<< "' found but not a sub-dictionary in dictionary "
<< name() << endl;
}
......@@ -506,9 +531,9 @@ const Foam::dictionary& Foam::dictionary::optionalSubDict
if (finder.found())
{
IOWarningInFunction((*this))
<< "keyword " << keyword
<< " found but not a sub-dictionary in dictionary "
IOWarningInFunction(*this)
<< "'" << keyword
<< "' found but not a sub-dictionary in dictionary "
<< name() << endl;
}
......@@ -597,7 +622,7 @@ Foam::entry* Foam::dictionary::add(entry* entryPtr, bool mergeEntry)
}
IOWarningInFunction((*this))
IOWarningInFunction(*this)
<< "problem replacing entry "<< entryPtr->keyword()
<< " in dictionary " << name() << endl;
......@@ -626,7 +651,7 @@ Foam::entry* Foam::dictionary::add(entry* entryPtr, bool mergeEntry)
}
IOWarningInFunction((*this))
IOWarningInFunction(*this)
<< "attempt to add entry " << entryPtr->keyword()
<< " which already exists in dictionary " << name()
<< endl;
......
......@@ -3,7 +3,7 @@
\\ / F ield | OpenFOAM: The Open Source CFD Toolbox
\\ / O peration |
\\ / A nd | Copyright (C) 2011-2017 OpenFOAM Foundation
\\/ M anipulation | Copyright (C) 2016-2017 OpenCFD Ltd.
\\/ M anipulation | Copyright (C) 2016-2018 OpenCFD Ltd.
-------------------------------------------------------------------------------
License
This file is part of OpenFOAM.
......@@ -143,18 +143,18 @@ public:
return name_;
}
//- Return the dictionary name
//- Return the dictionary name for modification (use with caution).
fileName& name()
{
return name_;
}
//- Return the local dictionary name (final part of scoped name)
const word dictName() const
word dictName() const
{
const word scopedName = name_.name();
const auto i = scopedName.rfind('.');
word scopedName(name_.name());
const auto i = scopedName.rfind('.');
if (i == std::string::npos)
{
return scopedName;
......@@ -383,13 +383,8 @@ private:
) const;
//- Add report of excess tokens to the messageStream
void excessTokens
(
OSstream& msg,
const word& keyword,
const ITstream& is
) const;
//- Emit FatalIOError if excess tokens exist
void excessTokens(const word& keyword, const ITstream& is) const;
public:
......@@ -505,7 +500,7 @@ public:
) const;
//- Find and return an entry pointer for manipulation if present,
// or return a nullptr.
//- or return a nullptr.
//
// \param recursive search parent dictionaries
// \param patternMatch use regular expressions
......@@ -516,7 +511,7 @@ public:
bool patternMatch
);
//- Find and return an entry if present otherwise error.
//- Find and return an entry if present, otherwise FatalIOError.
//
// \param recursive search parent dictionaries
// \param patternMatch use regular expressions
......@@ -528,7 +523,7 @@ public:
) const;
//- Find and return a T.
//- FatalError if not found, or if there are excess tokens.
//- FatalIOError if not found, or if there are excess tokens.
// Default search: non-recursive with patterns.
//
// \param recursive search parent dictionaries
......@@ -554,13 +549,13 @@ public:
) const;
//- Find and return a T.
//- FatalError if not found, or if there are excess tokens.
//- FatalIOError if not found, or if there are excess tokens.
// Default search: non-recursive with patterns.
//
// \param recursive search parent dictionaries
// \param patternMatch use regular expressions
//
// \note same as get()
// \deprecated - same as the get() method
template<class T>
T lookupType
(
......@@ -570,7 +565,7 @@ public:
) const;
//- Find and return a T, or return the given default value
//- FatalError if it is found and there are excess tokens.
//- FatalIOError if it is found and there are excess tokens.
// Default search: non-recursive with patterns.
//
// \param recursive search parent dictionaries
......@@ -586,7 +581,7 @@ public:
//- Find and return a T, or return the given default value
//- and add it to dictionary.
//- FatalError if it is found and there are excess tokens.
//- FatalIOError if it is found and there are excess tokens.
// Default search: non-recursive with patterns.
//
// \param recursive search parent dictionaries
......@@ -600,8 +595,26 @@ public:
bool patternMatch = true
);
//- Find entry and assign to T val.
//- FatalIOError if it is found and there are excess tokens.
// Default search: non-recursive with patterns.
//
// \param recursive search parent dictionaries
// \param patternMatch use regular expressions
//
// \return true if the entry was found.
template<class T>
bool read
(
const word& keyword,
T& val,
bool recursive = false,
bool patternMatch = true,
bool mandatory = true
) const;
//- Find an entry if present, and assign to T val.
//- FatalError if it is found and there are excess tokens.
//- FatalIOError if it is found and there are excess tokens.
// Default search: non-recursive with patterns.
//
// \param val the value to read
......@@ -662,7 +675,7 @@ public:
dictionary& subDict(const word& keyword);
//- Find and return a sub-dictionary as a copy, otherwise return
// an empty dictionary.
//- an empty dictionary.
// Warn if the entry exists but is not a sub-dictionary.
//
// Search type: non-recursive with patterns.
......@@ -984,7 +997,7 @@ public:
bool patternMatch
) const;
//- Find and return an entry if present otherwise error,
//- Find and return an entry if present, otherwise FatalIOError,
//- using any compatibility names if needed.
//
// \param compat list of old compatibility keywords and the last
......@@ -999,6 +1012,24 @@ public:
bool patternMatch
) const;
//- Find and return a T
//- using any compatibility names if needed.
//- FatalIOError if not found, or if there are excess tokens.
// Default search: non-recursive with patterns.
//
// \param compat list of old compatibility keywords and the last
// OpenFOAM version for which they were used.
// \param recursive search parent dictionaries
// \param patternMatch use regular expressions
template<class T>
T getCompat
(
const word& keyword,
std::initializer_list<std::pair<const char*,int>> compat,
bool recursive = false,
bool patternMatch = true
) const;
//- Find and return an entry data stream,
//- using any compatibility names if needed.
// Default search: non-recursive with patterns.
......@@ -1033,8 +1064,32 @@ public:
bool patternMatch = true
) const;
//- Find entry and assign to T val
//- using any compatibility names if needed.
//- FatalIOError if there are excess tokens.
// Default search: non-recursive with patterns.
//
// \param compat list of old compatibility keywords and the last
// OpenFOAM version for which they were used.
// \param val the value to read
// \param recursive search parent dictionaries
// \param patternMatch use regular expressions
//
// \return true if the entry was found.
template<class T>
bool readCompat
(
const word& keyword,
std::initializer_list<std::pair<const char*,int>> compat,
T& val,
bool recursive = false,
bool patternMatch = true,
bool mandatory = true
) const;
//- Find an entry if present, and assign to T val
//- using any compatibility names if needed.
//- FatalIOError if it is found and there are excess tokens.
// Default search: non-recursive with patterns.
//
// \param compat list of old compatibility keywords and the last
......
......@@ -52,7 +52,7 @@ Foam::dictionary::const_searcher Foam::dictionary::csearchCompat
bool patternMatch
) const
{
const_searcher finder(csearch(keyword, recursive,patternMatch));
const_searcher finder(csearch(keyword, recursive, patternMatch));
if (finder.found())
{
......@@ -61,7 +61,7 @@ Foam::dictionary::const_searcher Foam::dictionary::csearchCompat
for (const std::pair<const char*,int>& iter : compat)
{
finder = csearch(word::validate(iter.first), recursive,patternMatch);
finder = csearch(word::validate(iter.first), recursive, patternMatch);
if (finder.found())
{
......@@ -95,7 +95,7 @@ bool Foam::dictionary::foundCompat
bool patternMatch
) const
{
return csearchCompat(keyword, compat, recursive,patternMatch).found();
return csearchCompat(keyword, compat, recursive, patternMatch).found();
}
......@@ -107,7 +107,7 @@ const Foam::entry* Foam::dictionary::lookupEntryPtrCompat
bool patternMatch
) const
{
return csearchCompat(keyword, compat, recursive,patternMatch).ptr();
return csearchCompat(keyword, compat, recursive, patternMatch).ptr();
}
......@@ -120,14 +120,12 @@ const Foam::entry& Foam::dictionary::lookupEntryCompat
) const
{
const const_searcher
finder(csearchCompat(keyword, compat, recursive,patternMatch));
finder(csearchCompat(keyword, compat, recursive, patternMatch));
if (!finder.found())
{
FatalIOErrorInFunction
(
*this
) << "keyword " << keyword << " is undefined in dictionary "
FatalIOErrorInFunction(*this)
<< "'" << keyword << "' not found in dictionary "
<< name()
<< exit(FatalIOError);
}
......@@ -144,7 +142,8 @@ Foam::ITstream& Foam::dictionary::lookupCompat
bool patternMatch
) const
{
return lookupEntryCompat(keyword, compat, recursive,patternMatch).stream();
return
lookupEntryCompat(keyword, compat, recursive, patternMatch).stream();
}
......
......@@ -27,18 +27,17 @@ License
#include "dictionaryEntry.H"
#include "stringOps.H"
/* * * * * * * * * * * * * * * Static Member Data * * * * * * * * * * * * * */
// * * * * * * * * * * * * * * * Local Functions * * * * * * * * * * * * * * //
namespace Foam
namespace
{
// file-scope
//- Walk lists of patterns and regexps for an exact match
// or regular expression match
// Walk lists of patterns and regexps for an exact match
// or a regular expression match
template<class WcIterator, class ReIterator>
static bool findInPatterns
(
const bool patternMatch,
const word& keyword,
const Foam::word& keyword,
WcIterator& wcIter,
ReIterator& reIter
)
......@@ -61,7 +60,8 @@ namespace Foam
return false;
}
}
} // End anonymous namespace
// * * * * * * * * * * * * * Private Member Functions * * * * * * * * * * * //
......@@ -73,7 +73,7 @@ Foam::dictionary::const_searcher Foam::dictionary::csearchDotScoped
bool patternMatch
) const
{
std::string::size_type scopePos = keyword.find('.');
auto scopePos = keyword.find('.');
if (scopePos == string::npos)
{
......@@ -101,10 +101,8 @@ Foam::dictionary::const_searcher Foam::dictionary::csearchDotScoped
}
else
{
FatalIOErrorInFunction
(
*this
) << "No parent of current dictionary when searching for "
FatalIOErrorInFunction(*this)
<< "No parent of current dictionary when searching for "
<< keyword.substr(1)
<< exit(FatalIOError);
......@@ -210,10 +208,8 @@ Foam::dictionary::const_searcher Foam::dictionary::csearchSlashScoped
}
else
{
FatalIOErrorInFunction
(
*dictPtr
) << "No parent of current dictionary when searching for "
FatalIOErrorInFunction(*dictPtr)
<< "No parent of current dictionary when searching for "
<< keyword << " at " << cmpt
<< exit(FatalIOError);
break;
......@@ -424,10 +420,8 @@ const Foam::dictionary* Foam::dictionary::cfindScopedDictPtr
}
else
{
FatalIOErrorInFunction
(
*dictPtr
) << "No parent for dictionary while searching "
FatalIOErrorInFunction(*dictPtr)
<< "No parent for dictionary while searching "
<< path
<< exit(FatalIOError);
......@@ -451,10 +445,8 @@ const Foam::dictionary* Foam::dictionary::cfindScopedDictPtr
}
else
{
FatalIOErrorInFunction
(
*dictPtr
) << "Found entry '" << cmpt
FatalIOErrorInFunction(*dictPtr)
<< "Found entry '" << cmpt
<< "' but not a dictionary, while searching scoped"
<< nl
<< " " << path
......@@ -533,10 +525,8 @@ Foam::dictionary* Foam::dictionary::makeScopedDictPtr(const fileName& dictPath)
}
else
{
FatalIOErrorInFunction
(
*dictPtr
) << "No parent for dictionary while searching "
FatalIOErrorInFunction(*dictPtr)
<< "No parent for dictionary while searching "
<< path
<< exit(FatalIOError);
......@@ -561,10 +551,8 @@ Foam::dictionary* Foam::dictionary::makeScopedDictPtr(const fileName& dictPath)
}
else
{
FatalIOErrorInFunction
(
*dictPtr
) << "Cannot create sub-dictionary entry '" << cmptName
FatalIOErrorInFunction(*dictPtr)
<< "Cannot create sub-dictionary entry '" << cmptName
<< "' - a non-dictionary entry is in the way"
<< nl << "Encountered in scope" << nl
<< " " << path
......@@ -621,10 +609,8 @@ bool Foam::dictionary::remove(const word& keyword)
return true;
}
else
{
return false;
}
return false;
}
......@@ -651,10 +637,8 @@ bool Foam::dictionary::changeKeyword
if (iter()->keyword().isPattern())
{
FatalIOErrorInFunction
(
*this
) << "Old keyword "<< oldKeyword
FatalIOErrorInFunction(*this)
<< "Old keyword "<< oldKeyword
<< " is a pattern."
<< "Pattern replacement not yet implemented."
<< exit(FatalIOError);
......@@ -688,10 +672,8 @@ bool Foam::dictionary::changeKeyword
}
else
{
IOWarningInFunction
(
*this
) << "cannot rename keyword "<< oldKeyword
IOWarningInFunction(*this)
<< "cannot rename keyword "<< oldKeyword
<< " to existing keyword " << newKeyword
<< " in dictionary " << name() << endl;
return false;
......
......@@ -57,31 +57,63 @@ T Foam::dictionary::get
bool patternMatch
) const
{
const const_searcher finder(csearch(keyword, recursive, patternMatch));
T val;
read<T>(keyword, val, recursive, patternMatch);
return val;
}
if (!finder.found())
{
FatalIOErrorInFunction(*this)
<< "keyword " << keyword << " is undefined in dictionary "
<< name()
<< exit(FatalIOError);
}
template<class T>
T Foam::dictionary::getCompat
(