ifeqEntry.C
Go to the documentation of this file.
1 /*---------------------------------------------------------------------------*\
2  ========= |
3  \\ / F ield | OpenFOAM: The Open Source CFD Toolbox
4  \\ / O peration | Website: https://openfoam.org
5  \\ / A nd | Copyright (C) 2018-2024 OpenFOAM Foundation
6  \\/ M anipulation |
7 -------------------------------------------------------------------------------
8 License
9  This file is part of OpenFOAM.
10 
11  OpenFOAM is free software: you can redistribute it and/or modify it
12  under the terms of the GNU General Public License as published by
13  the Free Software Foundation, either version 3 of the License, or
14  (at your option) any later version.
15 
16  OpenFOAM is distributed in the hope that it will be useful, but WITHOUT
17  ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
18  FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
19  for more details.
20 
21  You should have received a copy of the GNU General Public License
22  along with OpenFOAM. If not, see <http://www.gnu.org/licenses/>.
23 
24 \*---------------------------------------------------------------------------*/
25 
26 #include "ifeqEntry.H"
27 #include "stringOps.H"
28 #include "ifEntry.H"
29 #include "Switch.H"
31 
32 // * * * * * * * * * * * * * * Static Data Members * * * * * * * * * * * * * //
33 
34 namespace Foam
35 {
36 namespace functionEntries
37 {
39 
41  (
43  ifeqEntry,
44  execute,
45  dictionaryIstream
46  );
47 }
48 }
49 
55 
56 // * * * * * * * * * * * * * Private Member Functions * * * * * * * * * * * //
57 
58 void Foam::functionEntries::ifeqEntry::readToken(token& t, Istream& is)
59 {
60  // Skip dummy tokens - avoids entry::getKeyword consuming #else, #endif
61  do
62  {
63  if
64  (
65  is.read(t).bad()
66  || is.eof()
67  || !t.good()
68  )
69  {
70  return;
71  }
72  }
73  while (t == token::END_STATEMENT);
74 }
75 
76 
77 Foam::token Foam::functionEntries::ifeqEntry::expand
78 (
79  const dictionary& dict,
80  const token& t
81 )
82 {
83  if (t.isVariable())
84  {
85  const variable& var = t.variableToken();
86 
87  word varName = var(1, var.size() - 1);
88 
89  // Lookup the variable name in the given dictionary
90  const entry* ePtr = dict.lookupScopedEntryPtr
91  (
92  varName,
93  true,
94  true
95  );
96 
97  if (ePtr)
98  {
99  return token(ePtr->stream());
100  }
101  else
102  {
103  // String expansion. Allow unset variables
104  string expanded(var);
105  stringOps::inplaceExpandEntry(expanded, dict, true, true);
106 
107  // Re-form as a string token so we can compare to string
108  return token(expanded, t.lineNumber());
109  }
110  }
111  else
112  {
113  return t;
114  }
115 }
116 
117 
118 bool Foam::functionEntries::ifeqEntry::equalToken
119 (
120  const token& t1,
121  const token& t2
122 )
123 {
124  const bool eqType = (t1.type() == t2.type());
125 
126  switch (t1.type())
127  {
128  case token::UNDEFINED:
129  return eqType;
130 
131  case token::PUNCTUATION:
132  return (eqType && t1.pToken() == t2.pToken());
133 
134  case token::WORD:
135  case token::FUNCTIONNAME:
136  case token::STRING:
138  if (t2.isAnyString())
139  {
140  return t1.anyStringToken() == t2.anyStringToken();
141  }
142  else
143  {
144  return false;
145  }
146 
147  case token::VARIABLE:
149  << "Attempt to compare an un-expanded variable"
150  << InfoProxy<token>(t1)
151  << exit(FatalIOError);
152  return false;
153 
154  case token::INTEGER_32:
155  if (eqType)
156  {
157  return t1.integer32Token() == t2.integer32Token();
158  }
159  else if (t2.isLabel())
160  {
161  return t1.labelToken() == t2.labelToken();
162  }
163  else if (t2.isScalar())
164  {
165  return t1.labelToken() == t2.scalarToken();
166  }
167  else
168  {
169  return false;
170  }
171 
172  case token::INTEGER_64:
173  if (eqType)
174  {
175  return t1.integer64Token() == t2.integer64Token();
176  }
177  else if (t2.isLabel())
178  {
179  return t1.labelToken() == t2.labelToken();
180  }
181  else if (t2.isScalar())
182  {
183  return t1.labelToken() == t2.scalarToken();
184  }
185  else
186  {
187  return false;
188  }
189 
191  if (eqType)
192  {
193  return
194  t1.unsignedInteger32Token() == t2.unsignedInteger32Token();
195  }
196  else if (t2.isLabel())
197  {
198  return t1.labelToken() == t2.labelToken();
199  }
200  else if (t2.isScalar())
201  {
202  return t1.labelToken() == t2.scalarToken();
203  }
204  else
205  {
206  return false;
207  }
208 
210  if (eqType)
211  {
212  return
213  t1.unsignedInteger64Token() == t2.unsignedInteger64Token();
214  }
215  else if (t2.isLabel())
216  {
217  return t1.labelToken() == t2.labelToken();
218  }
219  else if (t2.isScalar())
220  {
221  return t1.labelToken() == t2.scalarToken();
222  }
223  else
224  {
225  return false;
226  }
227 
228  case token::FLOAT_SCALAR:
229  if (eqType)
230  {
231  return equal(t1.floatScalarToken(), t2.floatScalarToken());
232  }
233  else if (t2.isScalar())
234  {
235  return t1.scalarToken() == t2.scalarToken();
236  }
237  else
238  {
239  return false;
240  }
241 
243  if (eqType)
244  {
245  return equal(t1.doubleScalarToken(), t2.doubleScalarToken());
246  }
247  else if (t2.isScalar())
248  {
249  return t1.scalarToken() == t2.scalarToken();
250  }
251  else
252  {
253  return false;
254  }
255 
257  if (eqType)
258  {
259  return equal
260  (
261  t1.longDoubleScalarToken(),
262  t2.longDoubleScalarToken()
263  );
264  }
265  else if (t2.isScalar())
266  {
267  return t1.scalarToken() == t2.scalarToken();
268  }
269  else
270  {
271  return false;
272  }
273 
274  case token::COMPOUND:
275  return false;
276 
277  case token::ERROR:
278  return eqType;
279  }
280 
281  return false;
282 }
283 
284 
285 void Foam::functionEntries::ifeqEntry::skipUntil
286 (
287  DynamicList<filePos>& stack,
288  const dictionary& parentDict,
289  const functionName& endWord,
290  Istream& is
291 )
292 {
293  while (!is.eof())
294  {
295  token t;
296  readToken(t, is);
297  if (t.isFunctionName())
298  {
299  if
300  (
301  t.functionNameToken() == ifName
302  || t.functionNameToken() == ifeqName
303  )
304  {
305  stack.append(filePos(is.name(), is.lineNumber()));
306  skipUntil(stack, parentDict, endifName, is);
307  stack.remove();
308  }
309  else if (t.functionNameToken() == endWord)
310  {
311  return;
312  }
313  }
314  }
315 
316  FatalIOErrorInFunction(parentDict)
317  << "Did not find matching " << endWord << exit(FatalIOError);
318 }
319 
320 
321 bool Foam::functionEntries::ifeqEntry::evaluate
322 (
323  const bool doIf,
324  DynamicList<filePos>& stack,
325  dictionary& parentDict,
326  Istream& is
327 )
328 {
329  while (!is.eof())
330  {
331  token t;
332  readToken(t, is);
333 
334  if (t.isFunctionName() && t.functionNameToken() == ifeqName)
335  {
336  // Recurse to evaluate
337  execute(stack, parentDict, is);
338  }
339  else if (t.isFunctionName() && t.functionNameToken() == ifName)
340  {
341  // Recurse to evaluate
342  ifEntry::execute(stack, parentDict, is);
343  }
344  else if
345  (
346  doIf
347  && t.isFunctionName()
348  && (
349  t.functionNameToken() == elseName
350  || t.functionNameToken() == elifName
351  )
352  )
353  {
354  // Now skip until #endif
355  skipUntil(stack, parentDict, endifName, is);
356  stack.remove();
357  break;
358  }
359  else if (t.isFunctionName() && t.functionNameToken() == endifName)
360  {
361  stack.remove();
362  break;
363  }
364  else
365  {
366  is.putBack(t);
367  bool ok = entry::New(parentDict, is);
368  if (!ok)
369  {
370  return false;
371  }
372  }
373  }
374  return true;
375 }
376 
377 
378 bool Foam::functionEntries::ifeqEntry::execute
379 (
380  const bool doIf,
381  DynamicList<filePos>& stack,
382  dictionary& parentDict,
383  Istream& is
384 )
385 {
386  if (doIf)
387  {
388  evaluate(true, stack, parentDict, is);
389  }
390  else
391  {
392  // Fast-forward to #else
393  token t;
394  while (!is.eof())
395  {
396  readToken(t, is);
397 
398  if (t.isFunctionName())
399  {
400  if
401  (
402  t.functionNameToken() == ifName
403  || t.functionNameToken() == ifeqName
404  )
405  {
406  stack.append(filePos(is.name(), is.lineNumber()));
407  skipUntil(stack, parentDict, endifName, is);
408  stack.remove();
409  }
410  else if (t.functionNameToken() == elseName)
411  {
412  break;
413  }
414  else if (t.functionNameToken() == elifName)
415  {
416  // Read line
417  string line;
418  dynamic_cast<ISstream&>(is).getLine(line);
419  line += ';';
420  IStringStream lineStream(line);
421  const primitiveEntry e("ifEntry", parentDict, lineStream);
422  const Switch doIf(e.stream());
423 
424  if (doIf)
425  {
426  // Info<< "Using #elif " << doIf
427  // << " at line " << lineNo
428  // << " in file " << is.name() << endl;
429  break;
430  }
431  }
432  else if (t.functionNameToken() == endifName)
433  {
434  stack.remove();
435  break;
436  }
437  }
438  }
439 
440  if (t.functionNameToken() == elseName)
441  {
442  // Evaluate until we hit #endif
443  evaluate(false, stack, parentDict, is);
444  }
445  else if (t.functionNameToken() == elifName)
446  {
447  // Evaluate until we hit #else or #endif
448  evaluate(true, stack, parentDict, is);
449  }
450  }
451  return true;
452 }
453 
454 
455 bool Foam::functionEntries::ifeqEntry::execute
456 (
457  DynamicList<filePos>& stack,
458  dictionary& parentDict,
459  Istream& is
460 )
461 {
462  const label nNested = stack.size();
463 
464  stack.append(filePos(is.name(), is.lineNumber()));
465 
466  // Read first token and expand if a variable
467  token cond1(is);
468  cond1 = expand(parentDict, cond1);
469 
470  // Read second token and expand if a variable
471  token cond2(is);
472  cond2 = expand(parentDict, cond2);
473 
474  const bool equal = equalToken(cond1, cond2);
475 
476  // Info<< "Using #" << typeName << " " << cond1
477  // << " == " << cond2
478  // << " at line " << stack.last().second()
479  // << " in file " << stack.last().first() << endl;
480 
481  bool ok = ifeqEntry::execute(equal, stack, parentDict, is);
482 
483  if (stack.size() != nNested)
484  {
485  FatalIOErrorInFunction(parentDict)
486  << "Did not find matching #endif for condition starting"
487  << " at line " << stack.last().second()
488  << " in file " << stack.last().first() << exit(FatalIOError);
489  }
490 
491  return ok;
492 }
493 
494 
495 // * * * * * * * * * * * * * * * Member Functions * * * * * * * * * * * * * //
496 
497 bool Foam::functionEntries::ifeqEntry::execute
498 (
499  dictionary& parentDict,
500  Istream& is
501 )
502 {
503  DynamicList<filePos> stack(10);
504  return execute(stack, parentDict, is);
505 }
506 
507 
508 // ************************************************************************* //
Macros for easy insertion into member function selection tables.
A 1D vector of objects of type <T> that resizes itself as necessary to accept the new objects.
Definition: DynamicList.H:78
T remove()
Remove and return the top element.
Definition: DynamicListI.H:351
DynamicList< T, SizeInc, SizeMult, SizeDiv > & append(const T &)
Append an element at the end of the list.
Definition: DynamicListI.H:296
label lineNumber() const
Return current stream line number.
Definition: IOstream.H:435
virtual const fileName & name() const
Return the name of the stream.
Definition: IOstream.H:294
bool eof() const
Return true if end of input seen.
Definition: IOstream.H:336
Generic input stream.
Definition: ISstream.H:55
Input from memory buffer stream.
Definition: IStringStream.H:52
An Istream is an abstract base class for all input systems (streams, files, token lists etc)....
Definition: Istream.H:60
void size(const label)
Override size to be inconsistent with allocated storage.
Definition: ListI.H:164
A simple wrapper around bool so that it can be read as a word: true/false, on/off,...
Definition: Switch.H:61
A 2-tuple for storing two objects of different types.
Definition: Tuple2.H:66
T & last()
Return the last element of the list.
Definition: UListI.H:128
A list of keyword definitions, which are a keyword followed by any number of values (e....
Definition: dictionary.H:162
static bool New(dictionary &parentDict, Istream &)
Construct from Istream and insert into dictionary.
Definition: entryIO.C:91
Conditional parsing of dictionary entries.
Definition: ifeqEntry.H:88
static const functionName ifeqName
Definition: ifeqEntry.H:155
static const functionName ifName
Definition: ifeqEntry.H:154
static const functionName endifName
Definition: ifeqEntry.H:158
static const functionName elseName
Definition: ifeqEntry.H:157
static const functionName elifName
Definition: ifeqEntry.H:156
A functionEntry causes entries to be added/manipulated on the specified dictionary given an input str...
Definition: functionEntry.H:66
A functionName is a word starting with '#'.
Definition: functionName.H:60
A line primitive.
Definition: line.H:71
A keyword and a list of tokens is a 'primitiveEntry'. An primitiveEntry can be read,...
A token holds items read from Istream.
Definition: token.H:73
const variable & variableToken() const
Definition: tokenI.H:339
@ ERROR
Definition: token.H:97
@ VARIABLE
Definition: token.H:85
@ WORD
Definition: token.H:83
@ UNSIGNED_INTEGER_32
Definition: token.H:90
@ UNDEFINED
Definition: token.H:80
@ COMPOUND
Definition: token.H:95
@ FLOAT_SCALAR
Definition: token.H:92
@ INTEGER_64
Definition: token.H:89
@ DOUBLE_SCALAR
Definition: token.H:93
@ LONG_DOUBLE_SCALAR
Definition: token.H:94
@ VERBATIMSTRING
Definition: token.H:87
@ FUNCTIONNAME
Definition: token.H:84
@ UNSIGNED_INTEGER_64
Definition: token.H:91
@ INTEGER_32
Definition: token.H:88
@ STRING
Definition: token.H:86
@ PUNCTUATION
Definition: token.H:82
const functionName & functionNameToken() const
Definition: tokenI.H:321
@ END_STATEMENT
Definition: token.H:108
bool isFunctionName() const
Definition: tokenI.H:316
#define FatalIOErrorInFunction(ios)
Report an error message using Foam::FatalIOError.
Definition: error.H:346
#define FatalErrorInFunction
Report an error message using Foam::FatalError.
Definition: error.H:334
defineTypeNameAndDebug(includeFvConstraintEntry, 0)
addToMemberFunctionSelectionTable(functionEntry, includeFvConstraintEntry, execute, dictionaryIstream)
string & inplaceExpandEntry(string &s, const dictionary &dict, const bool allowEnvVars, const bool allowEmpty, const char sigil='$')
Inplace expand occurrences of variables according to the dictionary.
Definition: stringOps.C:760
Namespace for OpenFOAM.
errorManipArg< error, int > exit(error &err, const int errNo=1)
Definition: errorManip.H:124
bool equal(const T &s1, const T &s2)
Definition: doubleFloat.H:62
const doubleScalar e
Definition: doubleScalar.H:106
intWM_LABEL_SIZE_t label
A label is an int32_t or int64_t as specified by the pre-processor macro WM_LABEL_SIZE.
Definition: label.H:59
IOerror FatalIOError
void evaluate(GeometricField< Type, PatchField, GeoMesh > &result, const Function1< Type > &func, const GeometricField< Type, PatchField, GeoMesh > &x)
string expand(const string &s, string::size_type &index, const dictionary &dict, const bool allowEnvVars, const bool allowEmpty)
Definition: stringOps.C:146
dictionary dict