ifeqEntry.C
Go to the documentation of this file.
1 /*---------------------------------------------------------------------------*\
2  ========= |
3  \\ / F ield | OpenFOAM: The Open Source CFD Toolbox
4  \\ / O peration |
5  \\ / A nd | www.openfoam.com
6  \\/ M anipulation |
7 -------------------------------------------------------------------------------
8  Copyright (C) 2018 OpenFOAM Foundation
9  Copyright (C) 2019-2020 OpenCFD Ltd.
10 -------------------------------------------------------------------------------
11 License
12  This file is part of OpenFOAM.
13 
14  OpenFOAM is free software: you can redistribute it and/or modify it
15  under the terms of the GNU General Public License as published by
16  the Free Software Foundation, either version 3 of the License, or
17  (at your option) any later version.
18 
19  OpenFOAM is distributed in the hope that it will be useful, but WITHOUT
20  ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
21  FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
22  for more details.
23 
24  You should have received a copy of the GNU General Public License
25  along with OpenFOAM. If not, see <http://www.gnu.org/licenses/>.
26 
27 \*---------------------------------------------------------------------------*/
28 
29 #include "ifeqEntry.H"
30 #include "ifEntry.H"
31 #include "stringOps.H"
33 
34 // * * * * * * * * * * * * * * Static Data Members * * * * * * * * * * * * * //
35 
36 namespace Foam
37 {
38 namespace functionEntries
39 {
40  defineTypeNameAndDebug(ifeqEntry, 0);
41 
43  (
44  functionEntry,
45  ifeqEntry,
46  execute,
47  dictionaryIstream,
48  ifeq
49  );
50 } // End namespace functionEntries
51 } // End namespace Foam
52 
53 
54 // * * * * * * * * * * * * * Private Member Functions * * * * * * * * * * * //
55 
57 {
58  // Skip dummy tokens - avoids entry::getKeyword consuming #else, #endif
59  do
60  {
61  if
62  (
63  is.read(t).bad()
64  || is.eof()
65  || !t.good()
66  )
67  {
68  return;
69  }
70  }
71  while (t == token::END_STATEMENT);
72 }
73 
74 
76 (
77  const dictionary& dict,
78  const string& keyword,
79  const token& t
80 )
81 {
82  if (keyword[0] == '$')
83  {
84  const word varName(keyword.substr(1));
85 
86  // Lookup the variable name in the given dictionary
87  const entry* ePtr = dict.findScoped(varName, keyType::REGEX_RECURSIVE);
88  if (ePtr)
89  {
90  return token(ePtr->stream());
91  }
92  else
93  {
94  // String expansion. Allow unset variables
95  string expanded(keyword);
96  stringOps::inplaceExpand(expanded, dict, true, true);
97 
98  // Re-form as a string token so we can compare to string
99  return token(expanded, t.lineNumber());
100  }
101  }
102  else if (!t.isString())
103  {
104  // Re-form as a string token so we can compare to string
105  return token(keyword, t.lineNumber());
106  }
107 
108  return t;
109 }
110 
111 
113 (
114  const dictionary& dict,
115  const token& t
116 )
117 {
118  if (t.isWord())
119  {
120  return expand(dict, t.wordToken(), t);
121  }
122  else if (t.isVariable())
123  {
124  return expand(dict, t.stringToken(), t);
125  }
126  else if (t.isString())
127  {
128  return expand(dict, t.stringToken(), t);
129  }
130 
131  return t;
132 }
133 
134 
136 (
137  const token& t1,
138  const token& t2
139 )
140 {
141  const bool eqType = (t1.type() == t2.type());
142 
143  switch (t1.type())
144  {
145  case token::UNDEFINED:
146  return eqType;
147 
148  case token::BOOL:
149  return (eqType && t1.boolToken() == t2.boolToken());
150 
151  case token::FLAG:
152  return (eqType && t1.flagToken() == t2.flagToken());
153 
154  case token::PUNCTUATION:
155  return (eqType && t1.pToken() == t2.pToken());
156 
157  case token::WORD:
158  case token::DIRECTIVE:
159  if (t2.isWord())
160  {
161  return t1.wordToken() == t2.wordToken();
162  }
163  else if (t2.isString())
164  {
165  const wordRe w2(t2.stringToken(), wordRe::DETECT);
166  return w2.match(t1.wordToken());
167  }
168  return false;
169 
170  case token::STRING:
171  if (eqType)
172  {
173  const wordRe w1(t1.stringToken(), wordRe::DETECT);
174  const wordRe w2(t2.stringToken(), wordRe::DETECT);
175  return w1.match(w2) || w2.match(w1);
176  }
177  else if (t2.isWord())
178  {
179  const wordRe w1(t1.stringToken(), wordRe::DETECT);
180  return w1.match(t2.wordToken());
181  }
182  return false;
183 
184  case token::VARIABLE:
185  case token::VERBATIM:
186  if (t2.isStringType())
187  {
188  return t1.stringToken() == t2.stringToken();
189  }
190  return false;
191 
192  case token::LABEL:
193  if (eqType)
194  {
195  return t1.labelToken() == t2.labelToken();
196  }
197  else if (t2.isScalar())
198  {
199  return t1.labelToken() == t2.scalarToken();
200  }
201  return false;
202 
203  case token::FLOAT:
204  if (eqType)
205  {
206  return equal(t1.floatToken(), t2.floatToken());
207  }
208  else if (t2.isScalar())
209  {
210  return t1.scalarToken() == t2.scalarToken();
211  }
212  return false;
213 
214  case token::DOUBLE:
215  if (eqType)
216  {
217  return equal(t1.doubleToken(), t2.doubleToken());
218  }
219  else if (t2.isScalar())
220  {
221  return t1.scalarToken() == t2.scalarToken();
222  }
223  return false;
224 
225  case token::COMPOUND:
226  return false;
227 
228  case token::ERROR:
229  return eqType;
230  }
231 
232  return false;
233 }
234 
235 
237 (
238  DynamicList<filePos>& stack,
239  const dictionary& parentDict,
240  const word& endWord,
241  Istream& is
242 )
243 {
244  while (!is.eof())
245  {
246  token t;
247  readToken(t, is);
248 
249  if (!t.isDirective())
250  {
251  continue;
252  }
253  else if
254  (
255  t.wordToken() == "#if"
256  || t.wordToken() == "#ifeq"
257  )
258  {
259  stack.append(filePos(is.name(), is.lineNumber()));
260  skipUntil(stack, parentDict, "#endif", is);
261  stack.remove();
262  }
263  else if (t.wordToken() == endWord)
264  {
265  return;
266  }
267  }
268 
269  FatalIOErrorInFunction(parentDict)
270  << "Did not find matching " << endWord << nl
271  << exit(FatalIOError);
272 }
273 
274 
276 (
277  const bool doIf,
278  DynamicList<filePos>& stack,
279  dictionary& parentDict,
280  Istream& is
281 )
282 {
283  while (!is.eof())
284  {
285  token t;
286  readToken(t, is);
287 
288  if (t.isWord() && t.wordToken() == "#ifeq")
289  {
290  // Recurse to evaluate
291  execute(stack, parentDict, is);
292  }
293  else if (t.isWord() && t.wordToken() == "#if")
294  {
295  // Recurse to evaluate
296  ifEntry::execute(stack, parentDict, is);
297  }
298  else if
299  (
300  doIf
301  && t.isWord()
302  && (t.wordToken() == "#else" || t.wordToken() == "#elif")
303  )
304  {
305  // Now skip until #endif
306  skipUntil(stack, parentDict, "#endif", is);
307  stack.remove();
308  break;
309  }
310  else if (t.isWord() && t.wordToken() == "#endif")
311  {
312  stack.remove();
313  break;
314  }
315  else
316  {
317  is.putBack(t);
318  bool ok = entry::New(parentDict, is);
319  if (!ok)
320  {
321  return false;
322  }
323  }
324  }
325  return true;
326 }
327 
328 
330 (
331  const bool doIf,
332  DynamicList<filePos>& stack,
333  dictionary& parentDict,
334  Istream& is
335 )
336 {
337  if (doIf)
338  {
339  evaluate(true, stack, parentDict, is);
340  }
341  else
342  {
343  // Fast-forward to #else
344  token t;
345  while (!is.eof())
346  {
347  readToken(t, is);
348 
349  if
350  (
351  t.isWord()
352  && (t.wordToken() == "#if" || t.wordToken() == "#ifeq")
353  )
354  {
355  stack.append(filePos(is.name(), is.lineNumber()));
356  skipUntil(stack, parentDict, "#endif", is);
357  stack.remove();
358  }
359  else if (t.isWord() && t.wordToken() == "#else")
360  {
361  break;
362  }
363  else if (t.isWord() && t.wordToken() == "#elif")
364  {
365  // const label lineNo = is.lineNumber();
366 
367  // Read line
368  string line;
369  dynamic_cast<ISstream&>(is).getLine(line);
370  line += ';';
371  IStringStream lineStream(line);
372  const primitiveEntry e("ifEntry", parentDict, lineStream);
373 
374  if (ifEntry::isTrue(e.stream()))
375  {
376  // Info<< "Using #elif " << doIf << " at line " << lineNo
377  // << " in file " << is.name() << endl;
378  break;
379  }
380  }
381  else if (t.isWord() && t.wordToken() == "#endif")
382  {
383  stack.remove();
384  break;
385  }
386  }
387 
388  if (t.wordToken() == "#else")
389  {
390  // Evaluate until we hit #endif
391  evaluate(false, stack, parentDict, is);
392  }
393  else if (t.wordToken() == "#elif")
394  {
395  // Evaluate until we hit #else or #endif
396  evaluate(true, stack, parentDict, is);
397  }
398  }
399  return true;
400 }
401 
402 
404 (
405  DynamicList<filePos>& stack,
406  dictionary& parentDict,
407  Istream& is
408 )
409 {
410  const label nNested = stack.size();
411 
412  stack.append(filePos(is.name(), is.lineNumber()));
413 
414  // Read first token and expand any string
415  token cond1(is);
416  cond1 = expand(parentDict, cond1);
417 
418  // Read second token and expand any string
419  token cond2(is);
420  cond2 = expand(parentDict, cond2);
421 
422  const bool equal = equalToken(cond1, cond2);
423 
424  // Info<< "Using #" << typeName << " " << cond1
425  // << " == " << cond2
426  // << " at line " << stack.last().second()
427  // << " in file " << stack.last().first() << endl;
428 
429  bool ok = ifeqEntry::execute(equal, stack, parentDict, is);
430 
431  if (stack.size() != nNested)
432  {
433  FatalIOErrorInFunction(parentDict)
434  << "Did not find matching #endif for condition starting"
435  << " at line " << stack.last().second()
436  << " in file " << stack.last().first() << exit(FatalIOError);
437  }
438 
439  return ok;
440 }
441 
442 
443 // * * * * * * * * * * * * * * * Member Functions * * * * * * * * * * * * * //
444 
446 (
447  dictionary& parentDict,
448  Istream& is
449 )
450 {
451  DynamicList<filePos> stack(10);
452  return execute(stack, parentDict, is);
453 }
454 
455 
456 // ************************************************************************* //
Foam::entry
A keyword and a list of tokens is an 'entry'.
Definition: entry.H:67
Foam::token::labelToken
label labelToken() const
Return label value.
Definition: tokenI.H:487
Foam::functionEntries::ifeqEntry::execute
static bool execute(const bool equal, DynamicList< filePos > &stack, dictionary &parentDict, Istream &is)
Definition: ifeqEntry.C:330
Foam::entry::New
static bool New(dictionary &parentDict, Istream &is, const inputMode inpMode=inputMode::GLOBAL, const int endChar=0)
Construct from an Istream and insert into the dictionary.
Definition: entryIO.C:104
Foam::primitiveEntry
A keyword and a list of tokens comprise a primitiveEntry. A primitiveEntry can be read,...
Definition: primitiveEntry.H:63
Foam::word
A class for handling words, derived from Foam::string.
Definition: word.H:62
ifEntry.H
w1
#define w1
Definition: blockCreate.C:34
Foam::DynamicList
A 1D vector of objects of type <T> that resizes itself as necessary to accept the new objects.
Definition: DynamicList.H:55
Foam::token::lineNumber
label lineNumber() const noexcept
The line number for the token.
Definition: tokenI.H:387
Foam::token::stringToken
const string & stringToken() const
Return const reference to the string contents.
Definition: tokenI.H:644
Foam::IOstream::eof
bool eof() const
Return true if end of input seen.
Definition: IOstream.H:230
Foam::token::LABEL
label (integer) type
Definition: token.H:83
Foam::functionEntries::defineTypeNameAndDebug
defineTypeNameAndDebug(codeStream, 0)
Foam::token::isStringType
bool isStringType() const noexcept
Token is WORD, DIRECTIVE, STRING, VARIABLE or VERBATIM.
Definition: tokenI.H:638
Foam::wordRe::DETECT
Detect if the string contains meta-characters.
Definition: wordRe.H:100
Foam::ISstream
Generic input stream using a standard (STL) stream.
Definition: ISstream.H:55
Foam::token::boolToken
bool boolToken() const
Return boolean token value.
Definition: tokenI.H:423
Foam::token::DIRECTIVE
A dictionary #directive (word variant)
Definition: token.H:90
Foam::FatalIOError
IOerror FatalIOError
Foam::functionEntries::ifeqEntry::readToken
static void readToken(token &t, Istream &is)
Read tokens. Skip dummy tokens.
Definition: ifeqEntry.C:56
Foam::token::PUNCTUATION
single character punctuation
Definition: token.H:81
Foam::token
A token holds an item read from Istream.
Definition: token.H:68
Foam::token::ERROR
A token error encountered.
Definition: token.H:95
Foam::functionEntries::ifeqEntry::expand
static token expand(const dictionary &dict, const string &keyword, const token &t)
Expand a variable (string/word/var starting with '$')
Definition: ifeqEntry.C:76
Foam::wordRe
A wordRe is a Foam::word, but can contain a regular expression for matching words or strings.
Definition: wordRe.H:72
Foam::token::VERBATIM
Verbatim string content.
Definition: token.H:92
Foam::token::pToken
punctuationToken pToken() const
Return punctuation character.
Definition: tokenI.H:459
Foam::token::isVariable
bool isVariable() const noexcept
Token is VARIABLE (string variant)
Definition: tokenI.H:626
Foam::token::isWord
bool isWord() const noexcept
Token is WORD or DIRECTIVE word.
Definition: tokenI.H:583
Foam::stringOps::expand
string expand(const std::string &s, const HashTable< string, word, string::hash > &mapping, const char sigil='$')
Definition: stringOps.C:720
Foam::functionEntries::ifeqEntry::evaluate
static bool evaluate(const bool doIf, DynamicList< filePos > &stack, dictionary &parentDict, Istream &is)
Definition: ifeqEntry.C:276
Foam::functionEntries::ifeqEntry::skipUntil
static void skipUntil(DynamicList< filePos > &stack, const dictionary &parentDict, const word &endWord, Istream &is)
Consume tokens until reached a specific word.
Definition: ifeqEntry.C:237
Foam::Istream
An Istream is an abstract base class for all input systems (streams, files, token lists etc)....
Definition: Istream.H:61
Foam::token::VARIABLE
A dictionary $variable (string variant)
Definition: token.H:91
Foam::DynamicList::append
DynamicList< T, SizeMin > & append(const T &val)
Append an element to the end of this list.
Definition: DynamicListI.H:474
Foam::stringOps::inplaceExpand
void inplaceExpand(std::string &s, const HashTable< string, word, string::hash > &mapping, const char sigil='$')
Definition: stringOps.C:733
Foam::token::BOOL
boolean type
Definition: token.H:82
addToMemberFunctionSelectionTable.H
Macros for easy insertion into member function selection tables.
Foam::IOstream::name
virtual const fileName & name() const
Return the name of the stream.
Definition: IOstream.C:39
Foam::token::END_STATEMENT
End entry [isseparator].
Definition: token.H:121
ifeqEntry.H
dict
dictionary dict
Definition: searchingEngine.H:14
Foam::token::COMPOUND
Compound type such as List<label> etc.
Definition: token.H:93
Foam::dictionary
A list of keyword definitions, which are a keyword followed by a number of values (eg,...
Definition: dictionary.H:121
Foam::IOstream::bad
bool bad() const
Return true if stream is corrupted.
Definition: IOstream.H:242
w2
#define w2
Definition: blockCreate.C:35
Foam::token::STRING
A string.
Definition: token.H:89
Foam::functionEntries::addNamedToMemberFunctionSelectionTable
addNamedToMemberFunctionSelectionTable(functionEntry, calcEntry, execute, dictionaryIstream, calc)
Foam::IStringStream
Input from string buffer, using a ISstream.
Definition: StringStream.H:111
Foam
Namespace for OpenFOAM.
Definition: atmBoundaryLayer.C:33
Foam::token::isScalar
bool isScalar() const noexcept
Token is FLOAT or DOUBLE.
Definition: tokenI.H:535
Foam::token::floatToken
floatScalar floatToken() const
Return float value.
Definition: tokenI.H:505
Foam::token::doubleToken
doubleScalar doubleToken() const
Return double value.
Definition: tokenI.H:523
Foam::token::wordToken
const word & wordToken() const
Return const reference to the word contents.
Definition: tokenI.H:599
Foam::token::isDirective
bool isDirective() const noexcept
Token is DIRECTIVE (word variant)
Definition: tokenI.H:593
Foam::exit
errorManipArg< error, int > exit(error &err, const int errNo=1)
Definition: errorManip.H:130
Foam::token::good
bool good() const noexcept
True if token is not UNDEFINED or ERROR.
Definition: tokenI.H:399
Foam::token::type
tokenType type() const noexcept
Return the token type.
Definition: tokenI.H:309
Foam::token::FLAG
stream flag (1-byte bitmask)
Definition: token.H:80
Foam::token::FLOAT
float (single-precision) type
Definition: token.H:84
Foam::nl
constexpr char nl
Definition: Ostream.H:385
Foam::token::scalarToken
scalar scalarToken() const
Return float or double value.
Definition: tokenI.H:545
Foam::Istream::putBack
void putBack(const token &tok)
Put back token.
Definition: Istream.C:53
Foam::constant::electromagnetic::e
const dimensionedScalar e
Elementary charge.
Definition: createFields.H:11
Foam::token::WORD
A Foam::word.
Definition: token.H:88
Foam::token::isString
bool isString() const noexcept
Token is STRING, VARIABLE or VERBATIM string.
Definition: tokenI.H:615
Foam::DynamicList::remove
T remove()
Remove and return the last element. Fatal on an empty list.
Definition: DynamicListI.H:653
Foam::line
A line primitive.
Definition: line.H:59
Foam::IOstream::lineNumber
label lineNumber() const
Const access to the current stream line number.
Definition: IOstream.H:309
Foam::functionEntries::ifeqEntry::equalToken
static bool equalToken(const token &t1, const token &t2)
Definition: ifeqEntry.C:136
Foam::token::flagToken
int flagToken() const
Return flag bitmask value.
Definition: tokenI.H:441
FatalIOErrorInFunction
#define FatalIOErrorInFunction(ios)
Report an error message using Foam::FatalIOError.
Definition: error.H:401
Foam::Tuple2
A 2-tuple for storing two objects of dissimilar types. The container is similar in purpose to std::pa...
Definition: Tuple2.H:57
Foam::token::UNDEFINED
An undefined token-type.
Definition: token.H:77
stringOps.H
Foam::equal
bool equal(const T &s1, const T &s2)
Compare two values for equality.
Definition: doubleFloat.H:46
Foam::token::DOUBLE
double (double-precision) type
Definition: token.H:85
Foam::stringOps::evaluate
string evaluate(const std::string &s, size_t pos=0, size_t len=std::string::npos)
Definition: stringOpsEvaluate.C:37
Foam::keyType::REGEX_RECURSIVE
Definition: keyType.H:79
Foam::Istream::read
virtual Istream & read(token &)=0
Return next token from stream.