ENH: adjust token in preparation for separate expression tokenization

- minor simplification of #if/#endif handling

ENH: improve input robustness with negative-prefixed expansions (#2095)

- especially in blockMeshDict it is useful to negate an value directly.
  Eg,
  ```
     xmax  100;
     xmin  -$xmax;
  ```
  However, this fails since the dictionary expansion is a two-step
  process of tokenization followed by expansion. After the expansion
  the given input would now be the following:
  ```
     xmax  100;
     xmin  - 100;
  ```
  and retrieving a scalar value for 'xmin' fails.

  Counteract this by being more generous on tokenized input when
  attempting to retrieve a label or scalar value.
  If a '-' is found where a number is expected, use it to negate the
  subsequent value.

  The previous solution was to invoke an 'eval':
  ```
     xmax  100;
     xmin  #eval{-$xmax};
  ```
  which adds additional clutter.
This commit is contained in:
Mark Olesen
2021-05-17 16:50:15 +02:00
parent 739c1c1d61
commit efd1ac4b5f
28 changed files with 507 additions and 166 deletions

View File

@ -10,7 +10,7 @@ FoamFile
version 2.0; version 2.0;
format ascii; format ascii;
class dictionary; class dictionary;
object testDict; object dictionary;
} }
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * // // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //

View File

@ -10,7 +10,7 @@ FoamFile
version 2.0; version 2.0;
format ascii; format ascii;
class dictionary; class dictionary;
object testDict; object dictionary;
} }
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * // // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //

View File

@ -10,7 +10,7 @@ FoamFile
version 2.0; version 2.0;
format ascii; format ascii;
class dictionary; class dictionary;
object testDict; object dictionary;
} }
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * // // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //

View File

@ -10,7 +10,7 @@ FoamFile
version 2.0; version 2.0;
format ascii; format ascii;
class dictionary; class dictionary;
object testDictCalc1; object dictionary;
} }
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * // // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //

View File

@ -10,7 +10,7 @@ FoamFile
version 2.0; version 2.0;
format ascii; format ascii;
class dictionary; class dictionary;
object testDictEval1; object dictionary;
} }
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * // // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //

View File

@ -10,7 +10,7 @@ FoamFile
version 2.0; version 2.0;
format ascii; format ascii;
class dictionary; class dictionary;
object testDictEval1; object dictionary;
} }
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * // // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //

View File

@ -10,7 +10,7 @@ FoamFile
version 2.0; version 2.0;
format ascii; format ascii;
class dictionary; class dictionary;
object testDictEval1; object dictionary;
} }
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * // // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //

View File

@ -0,0 +1,121 @@
/*--------------------------------*- C++ -*----------------------------------*\
| ========= | |
| \\ / F ield | OpenFOAM: The Open Source CFD Toolbox |
| \\ / O peration | Version: v2012 |
| \\ / A nd | Website: www.openfoam.com |
| \\/ M anipulation | |
\*---------------------------------------------------------------------------*/
FoamFile
{
version 2.0;
format ascii;
class dictionary;
object dictionary;
}
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
// Test expansion with negative signs
value 0.5;
radius 3;
negValue -$value;
select1 10;
sqrt05 #eval{ sqrt(0.5) };
vector ( -10 ${{-$sqrt05}} $value );
corner ( ${{ -$radius*sqrt(0.5) }} 1 0 );
corner2 ${{
vector(-${radius}*sqrt(0.5), ${radius}*sqrt(0.5), 2)
}};
// Just a future idea (2021-05-14) - does not yet work!
#if 0
corner3 #eval #{
variables ( "outer = $radius*sqrt(0.5)" );
vector(-outer, outer, 2)
#};
#endif
// The brace-bracket #eval with multi-lines failed for v2012 and earlier
corner2b #eval
{
vector(-${radius}*sqrt(0.5), $radius*sqrt(0.5), 2)
};
corner2c #eval
${{
vector(-${radius}*sqrt(0.5), $radius*sqrt(0.5), 2)
}};
longSlurp #eval
{
// This is actually a very simple expression
1 + 2
// With a long comment that is stripped out
// during reading anyhow.
};
longVariable
${{
// This is actually a very simple expression in variable syntax
1 + 2
/*
// With a long comment that is stripped out
// during reading anyhow.
*/
}};
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
// Geometric parameters
rxo 2;
ryo 3;
rzo 4;
// Geometric parameters
outerRadius 1;
innerRatio 0.75;
geometry
{
sphere
{
type sphere;
origin (0 0 0);
radius ($rxo $ryo $rzo);
}
innerSphere
{
$sphere
// Different solutions to the same problem
radius_v1
(
${{ $innerRatio*$rxo }}
${{ $innerRatio*$ryo }}
${{ $innerRatio*$rzo }}
);
radius_v2 #eval{ $innerRatio*vector($rxo, $ryo, $rzo) };
radius_v3 ${{ $innerRatio*$[(vector) ../sphere/radius] }};
// Inplace overwrite the same value
radius ${{ $innerRatio*$[(vector) radius] }};
}
}
// ************************************************************************* //

View File

@ -10,7 +10,7 @@ FoamFile
version 2.0; version 2.0;
format ascii; format ascii;
class dictionary; class dictionary;
object testDict; object dictionary;
} }
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * // // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
// Test some parsing // Test some parsing

View File

@ -10,7 +10,7 @@ FoamFile
version 2.0; version 2.0;
format ascii; format ascii;
class dictionary; class dictionary;
object testDictRegex; object dictionary;
} }
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * // // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
#inputMode merge #inputMode merge

View File

@ -10,7 +10,7 @@ FoamFile
version 2.0; version 2.0;
format ascii; format ascii;
class dictionary; class dictionary;
object testDict; object dictionary;
} }
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * // // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //

View File

@ -10,7 +10,7 @@ FoamFile
version 2.0; version 2.0;
format ascii; format ascii;
class dictionary; class dictionary;
object testDict; object dictionary;
note "test with foamDictionary -expand"; note "test with foamDictionary -expand";
} }
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * // // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //

View File

@ -0,0 +1,3 @@
Test-dictionary3.C
EXE = $(FOAM_USER_APPBIN)/Test-dictionary3

View File

@ -0,0 +1,2 @@
/* EXE_INC = */
/* EXE_LIBS = */

View File

@ -0,0 +1,78 @@
/*---------------------------------------------------------------------------*\
========= |
\\ / F ield | OpenFOAM: The Open Source CFD Toolbox
\\ / O peration |
\\ / A nd | www.openfoam.com
\\/ M anipulation |
-------------------------------------------------------------------------------
Copyright (C) 2021 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 <http://www.gnu.org/licenses/>.
Application
Test-dictionary3
Description
Test expressions and re-expansions
\*---------------------------------------------------------------------------*/
#include "argList.H"
#include "IOstreams.H"
#include "dictionary.H"
#include "vector.H"
#include "StringStream.H"
using namespace Foam;
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
// Main program:
int main(int argc, char *argv[])
{
argList::noParallel();
{
IStringStream is
(
"value 10;"
"scalar1 $value;"
"scalar2 -$value;"
// Use #eval expansion entirely
"vector1 ${{vector($value, -$value, $value)}};"
"vector2 ($value -$value $value);"
);
dictionary dict(is);
Info<< "input dictionary:" << dict << nl;
Info<< "value: " << dict.get<scalar>("value") << nl;
Info<< "scalar1: " << dict.get<scalar>("scalar1") << nl;
Info<< "scalar2: " << dict.get<scalar>("scalar2") << nl;
Info<< "vector1: " << dict.get<vector>("vector1") << nl;
Info<< "vector2: " << dict.get<vector>("vector2") << nl;
}
return 0;
}
// ************************************************************************* //

View File

@ -218,8 +218,8 @@ Foam::Istream& Foam::UIPstream::read(token& t)
case token::COLON : case token::COLON :
case token::COMMA : case token::COMMA :
case token::ASSIGN : case token::ASSIGN :
case token::ADD : case token::PLUS :
case token::SUBTRACT : case token::MINUS :
case token::MULTIPLY : case token::MULTIPLY :
case token::DIVIDE : case token::DIVIDE :
{ {
@ -227,12 +227,12 @@ Foam::Istream& Foam::UIPstream::read(token& t)
return *this; return *this;
} }
// Word/directive // The word-variants
case token::tokenType::WORD : case token::tokenType::WORD :
case token::tokenType::DIRECTIVE : case token::tokenType::DIRECTIVE :
{ {
word val; word val;
if (read(val)) if (readStringFromBuffer(val))
{ {
if (token::compound::isCompound(val)) if (token::compound::isCompound(val))
{ {
@ -251,13 +251,14 @@ Foam::Istream& Foam::UIPstream::read(token& t)
return *this; return *this;
} }
// String types // The string-variants
case token::tokenType::STRING : case token::tokenType::STRING :
case token::tokenType::EXPRESSION :
case token::tokenType::VARIABLE : case token::tokenType::VARIABLE :
case token::tokenType::VERBATIM : case token::tokenType::VERBATIM :
{ {
string val; string val;
if (read(val)) if (readStringFromBuffer(val))
{ {
t = std::move(val); t = std::move(val);
t.setType(token::tokenType(c)); t.setType(token::tokenType(c));

View File

@ -202,14 +202,19 @@ bool Foam::UOPstream::write(const token& tok)
return true; return true;
} }
// The word-variants
case token::tokenType::WORD :
case token::tokenType::DIRECTIVE : case token::tokenType::DIRECTIVE :
{ {
writeToBuffer(char(token::tokenType::DIRECTIVE)); writeToBuffer(char(tok.type()));
writeStringToBuffer(tok.wordToken()); writeStringToBuffer(tok.wordToken());
return true; return true;
} }
// The string-variants
case token::tokenType::STRING :
case token::tokenType::EXPRESSION :
case token::tokenType::VARIABLE : case token::tokenType::VARIABLE :
case token::tokenType::VERBATIM : case token::tokenType::VERBATIM :
{ {

View File

@ -199,8 +199,8 @@ Foam::Istream& Foam::ISstream::read(token& t)
case token::COLON : case token::COLON :
case token::COMMA : case token::COMMA :
case token::ASSIGN : case token::ASSIGN :
case token::ADD : case token::PLUS :
// NB: token::SUBTRACT handled later as the possible start of a Number // NB: token::MINUS handled later as the possible start of a Number
case token::MULTIPLY : case token::MULTIPLY :
case token::DIVIDE : case token::DIVIDE :
{ {
@ -368,7 +368,7 @@ Foam::Istream& Foam::ISstream::read(token& t)
if (nChar == 1 && buf[0] == '-') if (nChar == 1 && buf[0] == '-')
{ {
// A single '-' is punctuation // A single '-' is punctuation
t = token::punctuationToken(token::SUBTRACT); t = token::punctuationToken(token::MINUS);
} }
else if (labelVal && Foam::read(buf, labelVal)) else if (labelVal && Foam::read(buf, labelVal))
{ {

View File

@ -6,7 +6,7 @@
\\/ M anipulation | \\/ M anipulation |
------------------------------------------------------------------------------- -------------------------------------------------------------------------------
Copyright (C) 2011-2016 OpenFOAM Foundation Copyright (C) 2011-2016 OpenFOAM Foundation
Copyright (C) 2017-2020 OpenCFD Ltd. Copyright (C) 2017-2021 OpenCFD Ltd.
------------------------------------------------------------------------------- -------------------------------------------------------------------------------
License License
This file is part of OpenFOAM. This file is part of OpenFOAM.
@ -47,27 +47,33 @@ bool Foam::OSstream::write(const token& tok)
case token::tokenType::DIRECTIVE : case token::tokenType::DIRECTIVE :
{ {
// The '#' sigil is already part of the wordToken // Token stored with leading '#' sigil - output directly
write(tok.wordToken()); write(tok.wordToken());
return true; return true;
} }
case token::tokenType::VERBATIM : case token::tokenType::EXPRESSION :
{ {
// Surrounding '#{ .. #}' to be recognized as verbatim // Token stored with surrounding '${{ .. }}' - output directly
write(char(token::HASH));
write(char(token::BEGIN_BLOCK));
writeQuoted(tok.stringToken(), false); writeQuoted(tok.stringToken(), false);
write(char(token::HASH));
write(char(token::END_BLOCK));
return true; return true;
} }
case token::tokenType::VARIABLE : case token::tokenType::VARIABLE :
{ {
// Token stored with leading '$' sigil - output directly
writeQuoted(tok.stringToken(), false); writeQuoted(tok.stringToken(), false);
return true;
}
case token::tokenType::VERBATIM :
{
// Token stored without surrounding '#{ .. #}'. Add on output
write(char(token::HASH));
write(char(token::BEGIN_BLOCK));
writeQuoted(tok.stringToken(), false);
write(char(token::HASH));
write(char(token::END_BLOCK));
return true; return true;
} }

View File

@ -71,11 +71,13 @@ class token
public: public:
//- Enumeration defining the types of token. //- Enumeration defining the types of token.
// Since these values are also used to tag content in Pstream, // Since the enumeration is used to tag content in Pstream, it is of
// the maximum number of types is limited to 30. // type \c char and shall have values that do not overlap with regular
enum tokenType // punctuation characters.
enum tokenType : char
{ {
UNDEFINED = 0, //!< An undefined token-type UNDEFINED = '\0', //!< An undefined token-type
ERROR = '\x80', //!< Token error encountered
// Fundamental types // Fundamental types
FLAG, //!< stream flag (1-byte bitmask) FLAG, //!< stream flag (1-byte bitmask)
@ -86,14 +88,18 @@ public:
DOUBLE, //!< double (double-precision) type DOUBLE, //!< double (double-precision) type
// Pointer types // Pointer types
WORD, //!< A Foam::word WORD, //!< Foam::word
STRING, //!< A string (usually double-quoted) STRING, //!< Foam::string (usually double-quoted)
DIRECTIVE, //!< A dictionary \c \#directive (word variant)
VARIABLE, //!< A dictionary \c \$variable (string variant)
VERBATIM, //!< Verbatim string content
COMPOUND, //!< Compound type such as \c List\<label\> etc. COMPOUND, //!< Compound type such as \c List\<label\> etc.
ERROR, //!< A token error encountered DIRECTIVE, //!< Word-variant: dictionary \c \#directive
//!< stored with sigil
EXPRESSION, //!< String-variant: math expression for evaluation
//!< stored with delimiters
VARIABLE, //!< String-variant: dictionary \c \$variable
//!< stored with sigil
VERBATIM, //!< String-variant: verbatim string content
//!< stored without delimiters
// Aliases // Aliases
FLOAT_SCALAR = FLOAT, FLOAT_SCALAR = FLOAT,
@ -122,16 +128,16 @@ public:
COLON = ':', //!< Colon [#isseparator] COLON = ':', //!< Colon [#isseparator]
SEMICOLON = ';', //!< Semicolon [#isseparator] SEMICOLON = ';', //!< Semicolon [#isseparator]
COMMA = ',', //!< Comma [#isseparator] COMMA = ',', //!< Comma [#isseparator]
HASH = '#', //!< Hash - directive or verbatim string HASH = '#', //!< Hash - directive or start verbatim string
DOLLAR = '$', //!< Dollar - start variable DOLLAR = '$', //!< Dollar - start variable or expression
QUESTION = '?', //!< Question mark (eg, ternary) QUESTION = '?', //!< Question mark (eg, ternary)
ATSYM = '@', //!< The 'at' symbol ATSYM = '@', //!< The 'at' symbol
SQUOTE = '\'', //!< Single quote SQUOTE = '\'', //!< Single quote
DQUOTE = '"', //!< Double quote DQUOTE = '"', //!< Double quote
ASSIGN = '=', //!< Assignment/equals [#isseparator] ASSIGN = '=', //!< Assignment/equals [#isseparator]
ADD = '+', //!< Addition [#isseparator] PLUS = '+', //!< Addition [#isseparator]
SUBTRACT = '-', //!< Subtract or start of negative number MINUS = '-', //!< Subtract or start of negative number
MULTIPLY = '*', //!< Multiply [#isseparator] MULTIPLY = '*', //!< Multiply [#isseparator]
DIVIDE = '/', //!< Divide [#isseparator] DIVIDE = '/', //!< Divide [#isseparator]
@ -144,6 +150,8 @@ public:
// With semantically meaning // With semantically meaning
ADD = PLUS, //!< Addition [#isseparator]
SUBTRACT = MINUS, //!< Subtract or start of negative number
END_STATEMENT = SEMICOLON, //!< End entry [#isseparator] END_STATEMENT = SEMICOLON, //!< End entry [#isseparator]
BEGIN_LIST = LPAREN, //!< Begin list [#isseparator] BEGIN_LIST = LPAREN, //!< Begin list [#isseparator]
END_LIST = RPAREN, //!< End list [#isseparator] END_LIST = RPAREN, //!< End list [#isseparator]
@ -471,10 +479,10 @@ public:
//- Token is LABEL, FLOAT or DOUBLE //- Token is LABEL, FLOAT or DOUBLE
inline bool isNumber() const noexcept; inline bool isNumber() const noexcept;
//- Token is WORD or DIRECTIVE word //- Token is word-variant (WORD, DIRECTIVE)
inline bool isWord() const noexcept; inline bool isWord() const noexcept;
//- Token is WORD or DIRECTIVE word and equal to parameter //- Token is word-variant and equal to parameter
inline bool isWord(const std::string& s) const; inline bool isWord(const std::string& s) const;
//- Token is DIRECTIVE (word variant) //- Token is DIRECTIVE (word variant)
@ -483,16 +491,20 @@ public:
//- Token is (quoted) STRING (string variant) //- Token is (quoted) STRING (string variant)
inline bool isQuotedString() const noexcept; inline bool isQuotedString() const noexcept;
//- Token is STRING, VARIABLE or VERBATIM (string variant) //- Token is string-variant (STRING, EXPRESSION, VARIABLE, VERBATIM)
inline bool isString() const noexcept; inline bool isString() const noexcept;
//- Token is EXPRESSION (string variant)
inline bool isExpression() const noexcept;
//- Token is VARIABLE (string variant) //- Token is VARIABLE (string variant)
inline bool isVariable() const noexcept; inline bool isVariable() const noexcept;
//- Token is VERBATIM string (string variant) //- Token is VERBATIM string (string variant)
inline bool isVerbatim() const noexcept; inline bool isVerbatim() const noexcept;
//- Token is WORD, DIRECTIVE, STRING, VARIABLE or VERBATIM //- Token is word-variant or string-variant
//- (WORD, DIRECTIVE, STRING, EXPRESSION, VARIABLE, VERBATIM)
inline bool isStringType() const noexcept; inline bool isStringType() const noexcept;
//- Token is COMPOUND //- Token is COMPOUND
@ -542,7 +554,8 @@ public:
//- Return const reference to the string contents. //- Return const reference to the string contents.
// Report FatalIOError and return \b "" if token is not a // Report FatalIOError and return \b "" if token is not a
// STRING, VARIABLE, VERBATIM or an upcast WORD or DIRECTIVE // STRING, EXPRESSION, VARIABLE, VERBATIM
// or an upcast WORD or DIRECTIVE
inline const string& stringToken() const; inline const string& stringToken() const;
//- Read access for compound token //- Read access for compound token
@ -599,16 +612,16 @@ public:
//- Copy assign from double //- Copy assign from double
inline void operator=(const doubleScalar val); inline void operator=(const doubleScalar val);
//- Copy assign from word //- Copy assign from word content
inline void operator=(const word& w); inline void operator=(const word& w);
//- Copy assign from string //- Copy assign from string content
inline void operator=(const string& str); inline void operator=(const string& str);
//- Move assign from word //- Move assign from word content
inline void operator=(word&& w); inline void operator=(word&& w);
//- Move assign from string //- Move assign from string content
inline void operator=(string&& str); inline void operator=(string&& str);
//- Assign compound with reference counting to token //- Assign compound with reference counting to token

View File

@ -66,8 +66,8 @@ inline bool Foam::token::isseparator(int c) noexcept
case token::COLON : case token::COLON :
case token::COMMA : case token::COMMA :
case token::ASSIGN : case token::ASSIGN :
case token::ADD : case token::PLUS :
// Excluded token::SUBTRACT since it could start a number // Excluded token::MINUS since it could start a number
case token::MULTIPLY : case token::MULTIPLY :
case token::DIVIDE : case token::DIVIDE :
{ {
@ -121,6 +121,7 @@ inline Foam::token::token(const token& tok)
} }
case tokenType::STRING: case tokenType::STRING:
case tokenType::EXPRESSION:
case tokenType::VARIABLE: case tokenType::VARIABLE:
case tokenType::VERBATIM: case tokenType::VERBATIM:
{ {
@ -265,6 +266,7 @@ inline void Foam::token::reset()
} }
case tokenType::STRING: case tokenType::STRING:
case tokenType::EXPRESSION:
case tokenType::VARIABLE: case tokenType::VARIABLE:
case tokenType::VERBATIM: case tokenType::VERBATIM:
{ {
@ -357,6 +359,7 @@ inline bool Foam::token::setType(token::tokenType tokType) noexcept
break; break;
case tokenType::STRING: case tokenType::STRING:
case tokenType::EXPRESSION:
case tokenType::VARIABLE: case tokenType::VARIABLE:
case tokenType::VERBATIM: case tokenType::VERBATIM:
{ {
@ -364,6 +367,7 @@ inline bool Foam::token::setType(token::tokenType tokType) noexcept
{ {
// could also go from WORD to STRING etc - to be decided // could also go from WORD to STRING etc - to be decided
case tokenType::STRING: case tokenType::STRING:
case tokenType::EXPRESSION:
case tokenType::VARIABLE: case tokenType::VARIABLE:
case tokenType::VERBATIM: case tokenType::VERBATIM:
type_ = tokType; type_ = tokType;
@ -651,12 +655,19 @@ inline bool Foam::token::isString() const noexcept
return return
( (
type_ == tokenType::STRING type_ == tokenType::STRING
|| type_ == tokenType::EXPRESSION
|| type_ == tokenType::VARIABLE || type_ == tokenType::VARIABLE
|| type_ == tokenType::VERBATIM || type_ == tokenType::VERBATIM
); );
} }
inline bool Foam::token::isExpression() const noexcept
{
return (type_ == tokenType::EXPRESSION);
}
inline bool Foam::token::isVariable() const noexcept inline bool Foam::token::isVariable() const noexcept
{ {
return (type_ == tokenType::VARIABLE); return (type_ == tokenType::VARIABLE);
@ -680,6 +691,7 @@ inline const Foam::string& Foam::token::stringToken() const
if if
( (
type_ == tokenType::STRING type_ == tokenType::STRING
|| type_ == tokenType::EXPRESSION
|| type_ == tokenType::VARIABLE || type_ == tokenType::VARIABLE
|| type_ == tokenType::VERBATIM || type_ == tokenType::VERBATIM
) )
@ -754,6 +766,7 @@ inline void Foam::token::operator=(const token& tok)
break; break;
case tokenType::STRING: case tokenType::STRING:
case tokenType::EXPRESSION:
case tokenType::VARIABLE: case tokenType::VARIABLE:
case tokenType::VERBATIM: case tokenType::VERBATIM:
{ {
@ -903,6 +916,7 @@ inline bool Foam::token::operator==(const token& tok) const
return *data_.wordPtr == *tok.data_.wordPtr; return *data_.wordPtr == *tok.data_.wordPtr;
case tokenType::STRING: case tokenType::STRING:
case tokenType::EXPRESSION:
case tokenType::VARIABLE: case tokenType::VARIABLE:
case tokenType::VERBATIM: case tokenType::VERBATIM:
return *data_.stringPtr == *tok.data_.stringPtr; return *data_.stringPtr == *tok.data_.stringPtr;

View File

@ -6,7 +6,7 @@
\\/ M anipulation | \\/ M anipulation |
------------------------------------------------------------------------------- -------------------------------------------------------------------------------
Copyright (C) 2011-2015 OpenFOAM Foundation Copyright (C) 2011-2015 OpenFOAM Foundation
Copyright (C) 2017-2020 OpenCFD Ltd. Copyright (C) 2017-2021 OpenCFD Ltd.
------------------------------------------------------------------------------- -------------------------------------------------------------------------------
License License
This file is part of OpenFOAM. This file is part of OpenFOAM.
@ -82,6 +82,10 @@ static OS& printTokenInfo(OS& os, const token& tok)
os << "string " << tok.stringToken(); os << "string " << tok.stringToken();
break; break;
case token::tokenType::EXPRESSION:
os << "expression " << tok.stringToken();
break;
case token::tokenType::VARIABLE: case token::tokenType::VARIABLE:
os << "variable " << tok.stringToken(); os << "variable " << tok.stringToken();
break; break;
@ -141,6 +145,7 @@ Foam::word Foam::token::name() const
case token::tokenType::WORD: return "word"; case token::tokenType::WORD: return "word";
case token::tokenType::DIRECTIVE: return "directive"; case token::tokenType::DIRECTIVE: return "directive";
case token::tokenType::STRING: return "string"; case token::tokenType::STRING: return "string";
case token::tokenType::EXPRESSION: return "expression";
case token::tokenType::VERBATIM: return "verbatim"; case token::tokenType::VERBATIM: return "verbatim";
case token::tokenType::VARIABLE: return "variable"; case token::tokenType::VARIABLE: return "variable";
case token::tokenType::COMPOUND: return "compound"; case token::tokenType::COMPOUND: return "compound";
@ -194,8 +199,10 @@ Foam::Ostream& Foam::operator<<(Ostream& os, const token& tok)
os << tok.data_.doubleVal; os << tok.data_.doubleVal;
break; break;
// Different behaviour for (serial/parallel) streams: preserve types // Possibly different behaviour for serial/parallel streams:
// preserve types
case token::tokenType::DIRECTIVE: case token::tokenType::DIRECTIVE:
case token::tokenType::EXPRESSION:
case token::tokenType::VARIABLE: case token::tokenType::VARIABLE:
case token::tokenType::VERBATIMSTRING: case token::tokenType::VERBATIMSTRING:
os.write(tok); os.write(tok);

View File

@ -90,7 +90,8 @@ bool Foam::functionEntry::execute
if (!executedictionaryIstreamMemberFunctionTablePtr_) if (!executedictionaryIstreamMemberFunctionTablePtr_)
{ {
cerr<< FUNCTION_NAME << nl std::cerr
<< FUNCTION_NAME << nl
<< "Not yet initialized, function = " << "Not yet initialized, function = "
<< functionName.c_str() << std::endl; << functionName.c_str() << std::endl;
@ -128,7 +129,8 @@ bool Foam::functionEntry::execute
if (!executeprimitiveEntryIstreamMemberFunctionTablePtr_) if (!executeprimitiveEntryIstreamMemberFunctionTablePtr_)
{ {
cerr<< FUNCTION_NAME << nl std::cerr
<< FUNCTION_NAME << nl
<< "Not yet initialized, function = " << "Not yet initialized, function = "
<< functionName.c_str() << std::endl; << functionName.c_str() << std::endl;

View File

@ -58,12 +58,7 @@ void Foam::functionEntries::ifeqEntry::readToken(token& t, Istream& is)
// Skip dummy tokens - avoids entry::getKeyword consuming #else, #endif // Skip dummy tokens - avoids entry::getKeyword consuming #else, #endif
do do
{ {
if if (is.read(t).bad() || is.eof() || !t.good())
(
is.read(t).bad()
|| is.eof()
|| !t.good()
)
{ {
return; return;
} }
@ -72,7 +67,7 @@ void Foam::functionEntries::ifeqEntry::readToken(token& t, Istream& is)
} }
Foam::token Foam::functionEntries::ifeqEntry::expand Foam::token Foam::functionEntries::ifeqEntry::expandToken
( (
const dictionary& dict, const dictionary& dict,
const string& keyword, const string& keyword,
@ -109,7 +104,7 @@ Foam::token Foam::functionEntries::ifeqEntry::expand
} }
Foam::token Foam::functionEntries::ifeqEntry::expand Foam::token Foam::functionEntries::ifeqEntry::expandToken
( (
const dictionary& dict, const dictionary& dict,
const token& t const token& t
@ -117,15 +112,15 @@ Foam::token Foam::functionEntries::ifeqEntry::expand
{ {
if (t.isWord()) if (t.isWord())
{ {
return expand(dict, t.wordToken(), t); return expandToken(dict, t.wordToken(), t);
} }
else if (t.isVariable()) else if (t.isVariable())
{ {
return expand(dict, t.stringToken(), t); return expandToken(dict, t.stringToken(), t);
} }
else if (t.isString()) else if (t.isString())
{ {
return expand(dict, t.stringToken(), t); return expandToken(dict, t.stringToken(), t);
} }
return t; return t;
@ -230,6 +225,9 @@ bool Foam::functionEntries::ifeqEntry::equalToken
} }
return false; return false;
case token::EXPRESSION:
return false;
case token::COMPOUND: case token::COMPOUND:
return false; return false;
@ -245,7 +243,7 @@ void Foam::functionEntries::ifeqEntry::skipUntil
( (
DynamicList<filePos>& stack, DynamicList<filePos>& stack,
const dictionary& parentDict, const dictionary& parentDict,
const word& endWord, const word& endDirective,
Istream& is Istream& is
) )
{ {
@ -258,28 +256,26 @@ void Foam::functionEntries::ifeqEntry::skipUntil
{ {
continue; continue;
} }
else if else if (t.wordToken() == "#if" || t.wordToken() == "#ifeq")
(
t.wordToken() == "#if"
|| t.wordToken() == "#ifeq"
)
{ {
stack.append(filePos(is.name(), is.lineNumber())); stack.append(filePos(is.name(), is.lineNumber()));
skipUntil(stack, parentDict, "#endif", is); skipUntil(stack, parentDict, "#endif", is);
stack.remove(); stack.remove();
} }
else if (t.wordToken() == endWord) else if (t.wordToken() == endDirective)
{ {
return; return;
} }
} }
FatalIOErrorInFunction(parentDict) FatalIOErrorInFunction(parentDict)
<< "Did not find matching " << endWord << nl << "Did not find matching " << endDirective << nl
<< exit(FatalIOError); << exit(FatalIOError);
} }
// * * * * * * * * * * * * Protected Member Functions * * * * * * * * * * * //
bool Foam::functionEntries::ifeqEntry::evaluate bool Foam::functionEntries::ifeqEntry::evaluate
( (
const bool doIf, const bool doIf,
@ -292,35 +288,47 @@ bool Foam::functionEntries::ifeqEntry::evaluate
{ {
token t; token t;
readToken(t, is); readToken(t, is);
bool pending = false;
if (t.isWord() && t.wordToken() == "#ifeq") if (t.isDirective())
{ {
// Recurse to evaluate if (t.wordToken() == "#ifeq")
execute(stack, parentDict, is); {
} // Recurse to evaluate
else if (t.isWord() && t.wordToken() == "#if") execute(stack, parentDict, is);
{ }
// Recurse to evaluate else if (t.wordToken() == "#if")
ifEntry::execute(stack, parentDict, is); {
} // Recurse to evaluate
else if ifEntry::execute(stack, parentDict, is);
( }
doIf else if
&& t.isWord() (
&& (t.wordToken() == "#else" || t.wordToken() == "#elif") doIf
) && (t.wordToken() == "#else" || t.wordToken() == "#elif")
{ )
// Now skip until #endif {
skipUntil(stack, parentDict, "#endif", is); // Now skip until #endif
stack.remove(); skipUntil(stack, parentDict, "#endif", is);
break; stack.remove();
} break;
else if (t.isWord() && t.wordToken() == "#endif") }
{ else if (t.wordToken() == "#endif")
stack.remove(); {
break; stack.remove();
break;
}
else
{
pending = true;
}
} }
else else
{
pending = true;
}
if (pending)
{ {
is.putBack(t); is.putBack(t);
bool ok = entry::New(parentDict, is); bool ok = entry::New(parentDict, is);
@ -354,21 +362,23 @@ bool Foam::functionEntries::ifeqEntry::execute
{ {
readToken(t, is); readToken(t, is);
if // Only consider directives
( if (!t.isDirective())
t.isWord() {
&& (t.wordToken() == "#if" || t.wordToken() == "#ifeq") continue;
) }
if (t.wordToken() == "#if" || t.wordToken() == "#ifeq")
{ {
stack.append(filePos(is.name(), is.lineNumber())); stack.append(filePos(is.name(), is.lineNumber()));
skipUntil(stack, parentDict, "#endif", is); skipUntil(stack, parentDict, "#endif", is);
stack.remove(); stack.remove();
} }
else if (t.isWord() && t.wordToken() == "#else") else if (t.wordToken() == "#else")
{ {
break; break;
} }
else if (t.isWord() && t.wordToken() == "#elif") else if (t.wordToken() == "#elif")
{ {
// const label lineNo = is.lineNumber(); // const label lineNo = is.lineNumber();
@ -386,7 +396,7 @@ bool Foam::functionEntries::ifeqEntry::execute
break; break;
} }
} }
else if (t.isWord() && t.wordToken() == "#endif") else if (t.wordToken() == "#endif")
{ {
stack.remove(); stack.remove();
break; break;
@ -421,11 +431,11 @@ bool Foam::functionEntries::ifeqEntry::execute
// Read first token and expand any string // Read first token and expand any string
token cond1(is); token cond1(is);
cond1 = expand(parentDict, cond1); cond1 = expandToken(parentDict, cond1);
// Read second token and expand any string // Read second token and expand any string
token cond2(is); token cond2(is);
cond2 = expand(parentDict, cond2); cond2 = expandToken(parentDict, cond2);
const bool equal = equalToken(cond1, cond2); const bool equal = equalToken(cond1, cond2);

View File

@ -6,6 +6,7 @@
\\/ M anipulation | \\/ M anipulation |
------------------------------------------------------------------------------- -------------------------------------------------------------------------------
Copyright (C) 2018 OpenFOAM Foundation Copyright (C) 2018 OpenFOAM Foundation
Copyright (C) 2021 OpenCFD Ltd.
------------------------------------------------------------------------------- -------------------------------------------------------------------------------
License License
This file is part of OpenFOAM. This file is part of OpenFOAM.
@ -31,7 +32,7 @@ Description
E.g. E.g.
\verbatim \verbatim
a #calc "0.123"; a #eval "0.123";
b 1.23e-1; b 1.23e-1;
#ifeq $a $b #ifeq $a $b
@ -90,46 +91,15 @@ class ifeqEntry
: :
public functionEntry public functionEntry
{ {
protected: protected:
// Data Types
typedef Tuple2<fileName, label> filePos; typedef Tuple2<fileName, label> filePos;
// Protected Member Functions // Protected Member Functions
//- Read tokens. Skip dummy tokens
static void readToken(token& t, Istream& is);
//- Expand a variable (string/word/var starting with '$')
static token expand
(
const dictionary& dict,
const string& keyword,
const token& t
);
//- Expand a string/word/var token
static token expand
(
const dictionary& dict,
const token& t
);
static bool equalToken
(
const token& t1,
const token& t2
);
//- Consume tokens until reached a specific word
static void skipUntil
(
DynamicList<filePos>& stack,
const dictionary& parentDict,
const word& endWord,
Istream& is
);
static bool evaluate static bool evaluate
( (
const bool doIf, const bool doIf,
@ -158,6 +128,41 @@ protected:
); );
private:
// Private Member Functions
//- Read tokens. Skip dummy tokens
static void readToken(token& t, Istream& is);
//- Expand a variable (string/word/var starting with '$')
static token expandToken
(
const dictionary& dict,
const string& keyword,
const token& t
);
//- Expand a string/word/var token
static token expandToken
(
const dictionary& dict,
const token& t
);
//- Test for equality
static bool equalToken(const token& t1, const token& t2);
//- Consume tokens until reached a specific directive
static void skipUntil
(
DynamicList<filePos>& stack,
const dictionary& parentDict,
const word& endDirective, //!< end directive (without '#')
Istream& is
);
public: public:
//- Runtime type information //- Runtime type information

View File

@ -6,7 +6,7 @@
\\/ M anipulation | \\/ M anipulation |
------------------------------------------------------------------------------- -------------------------------------------------------------------------------
Copyright (C) 2011-2016 OpenFOAM Foundation Copyright (C) 2011-2016 OpenFOAM Foundation
Copyright (C) 2016-2019 OpenCFD Ltd. Copyright (C) 2016-2021 OpenCFD Ltd.
------------------------------------------------------------------------------- -------------------------------------------------------------------------------
License License
This file is part of OpenFOAM. This file is part of OpenFOAM.
@ -145,16 +145,37 @@ Istream& operator>>(Istream& is, Scalar& val)
return is; return is;
} }
// Accept separated '-' (or '+') while expecting a number.
// This can arise during dictionary expansions (Eg, -$value)
char prefix = 0;
if (t.isPunctuation())
{
prefix = t.pToken();
if (prefix == token::PLUS || prefix == token::MINUS)
{
is >> t;
}
}
if (t.isNumber()) if (t.isNumber())
{ {
val = t.number(); val =
(
(prefix == token::MINUS)
? (0 - t.number())
: t.number()
);
} }
else else
{ {
FatalIOErrorInFunction(is) FatalIOErrorInFunction(is)
<< "Wrong token type - expected scalar value, found " << "Wrong token type - expected scalar value, found ";
<< t.info() if (prefix == token::PLUS || prefix == token::MINUS)
<< exit(FatalIOError); {
FatalIOError << '\'' << prefix << "' followed by ";
}
FatalIOError << t.info() << exit(FatalIOError);
is.setBad(); is.setBad();
return is; return is;
} }

View File

@ -6,7 +6,7 @@
\\/ M anipulation | \\/ M anipulation |
------------------------------------------------------------------------------- -------------------------------------------------------------------------------
Copyright (C) 2014-2016 OpenFOAM Foundation Copyright (C) 2014-2016 OpenFOAM Foundation
Copyright (C) 2016-2020 OpenCFD Ltd. Copyright (C) 2016-2021 OpenCFD Ltd.
------------------------------------------------------------------------------- -------------------------------------------------------------------------------
License License
This file is part of OpenFOAM. This file is part of OpenFOAM.
@ -100,13 +100,36 @@ Foam::Istream& Foam::operator>>(Istream& is, int32_t& val)
return is; return is;
} }
// Accept separated '-' (or '+') while expecting a number.
// This can arise during dictionary expansions (Eg, -$value)
char prefix = 0;
if (t.isPunctuation())
{
prefix = t.pToken();
if (prefix == token::PLUS || prefix == token::MINUS)
{
is >> t;
}
}
if (t.isLabel()) if (t.isLabel())
{ {
val = int32_t(t.labelToken()); val = int32_t
(
(prefix == token::MINUS)
? (0 - t.labelToken())
: t.labelToken()
);
} }
else if (t.isScalar()) else if (t.isScalar())
{ {
const scalar sval(t.scalarToken()); const scalar sval
(
(prefix == token::MINUS)
? (0 - t.scalarToken())
: t.scalarToken()
);
const intmax_t parsed = intmax_t(std::round(sval)); const intmax_t parsed = intmax_t(std::round(sval));
val = 0 + int32_t(parsed); val = 0 + int32_t(parsed);
@ -135,9 +158,12 @@ Foam::Istream& Foam::operator>>(Istream& is, int32_t& val)
else else
{ {
FatalIOErrorInFunction(is) FatalIOErrorInFunction(is)
<< "Wrong token type - expected label (int32), found " << "Wrong token type - expected label (int32), found ";
<< t.info() if (prefix == token::PLUS || prefix == token::MINUS)
<< exit(FatalIOError); {
FatalIOError << '\'' << prefix << "' followed by ";
}
FatalIOError << t.info() << exit(FatalIOError);
is.setBad(); is.setBad();
return is; return is;
} }

View File

@ -6,7 +6,7 @@
\\/ M anipulation | \\/ M anipulation |
------------------------------------------------------------------------------- -------------------------------------------------------------------------------
Copyright (C) 2014-2016 OpenFOAM Foundation Copyright (C) 2014-2016 OpenFOAM Foundation
Copyright (C) 2017-2020 OpenCFD Ltd. Copyright (C) 2017-2021 OpenCFD Ltd.
------------------------------------------------------------------------------- -------------------------------------------------------------------------------
License License
This file is part of OpenFOAM. This file is part of OpenFOAM.
@ -100,13 +100,37 @@ Foam::Istream& Foam::operator>>(Istream& is, int64_t& val)
return is; return is;
} }
// Accept separated '-' (or '+') while expecting a number.
// This can arise during dictionary expansions (Eg, -$value)
char prefix = 0;
if (t.isPunctuation())
{
prefix = t.pToken();
if (prefix == token::PLUS || prefix == token::MINUS)
{
is >> t;
}
}
if (t.isLabel()) if (t.isLabel())
{ {
val = int64_t(t.labelToken()); val = int64_t
(
(prefix == token::MINUS)
? (0 - t.labelToken())
: t.labelToken()
);
} }
else if (t.isScalar()) else if (t.isScalar())
{ {
const scalar sval(t.scalarToken()); const scalar sval
(
(prefix == token::MINUS)
? (0 - t.scalarToken())
: t.scalarToken()
);
const intmax_t parsed = intmax_t(std::round(sval)); const intmax_t parsed = intmax_t(std::round(sval));
val = 0 + int64_t(parsed); val = 0 + int64_t(parsed);
@ -135,9 +159,12 @@ Foam::Istream& Foam::operator>>(Istream& is, int64_t& val)
else else
{ {
FatalIOErrorInFunction(is) FatalIOErrorInFunction(is)
<< "Wrong token type - expected label (int64), found " << "Wrong token type - expected label (int64), found ";
<< t.info() if (prefix == token::PLUS || prefix == token::MINUS)
<< exit(FatalIOError); {
FatalIOError << '\'' << prefix << "' followed by ";
}
FatalIOError << t.info() << exit(FatalIOError);
is.setBad(); is.setBad();
return is; return is;
} }