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-2021 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 
56 void Foam::functionEntries::ifeqEntry::readToken(token& t, Istream& is)
57 {
58  // Skip dummy tokens - avoids entry::getKeyword consuming #else, #endif
59  do
60  {
61  if (is.read(t).bad() || is.eof() || !t.good())
62  {
63  return;
64  }
65  }
66  while (t == token::END_STATEMENT);
67 }
68 
69 
70 Foam::token Foam::functionEntries::ifeqEntry::expandToken
71 (
72  const dictionary& dict,
73  const string& keyword,
74  const token& t
75 )
76 {
77  if (keyword[0] == '$')
78  {
79  const word varName(keyword.substr(1));
80 
81  // Lookup the variable name in the given dictionary
82  const entry* ePtr = dict.findScoped(varName, keyType::REGEX_RECURSIVE);
83  if (ePtr)
84  {
85  return token(ePtr->stream());
86  }
87  else
88  {
89  // String expansion. Allow unset variables
90  string expanded(keyword);
91  stringOps::inplaceExpand(expanded, dict, true, true);
92 
93  // Re-form as a string token so we can compare to string
94  return token(expanded, t.lineNumber());
95  }
96  }
97  else if (!t.isString())
98  {
99  // Re-form as a string token so we can compare to string
100  return token(keyword, t.lineNumber());
101  }
102 
103  return t;
104 }
105 
106 
107 Foam::token Foam::functionEntries::ifeqEntry::expandToken
108 (
109  const dictionary& dict,
110  const token& t
111 )
112 {
113  if (t.isWord())
114  {
115  return expandToken(dict, t.wordToken(), t);
116  }
117  else if (t.isVariable())
118  {
119  return expandToken(dict, t.stringToken(), t);
120  }
121  else if (t.isString())
122  {
123  return expandToken(dict, t.stringToken(), t);
124  }
125 
126  return t;
127 }
128 
129 
130 bool Foam::functionEntries::ifeqEntry::equalToken
131 (
132  const token& t1,
133  const token& t2
134 )
135 {
136  const bool eqType = (t1.type() == t2.type());
137 
138  switch (t1.type())
139  {
140  case token::UNDEFINED:
141  return eqType;
142 
143  case token::BOOL:
144  return (eqType && t1.boolToken() == t2.boolToken());
145 
146  case token::FLAG:
147  return (eqType && t1.flagToken() == t2.flagToken());
148 
149  case token::PUNCTUATION:
150  return (eqType && t1.pToken() == t2.pToken());
151 
152  case token::WORD:
153  case token::DIRECTIVE:
154  if (t2.isWord())
155  {
156  return t1.wordToken() == t2.wordToken();
157  }
158  else if (t2.isString())
159  {
160  const wordRe w2(t2.stringToken(), wordRe::DETECT);
161  return w2.match(t1.wordToken());
162  }
163  return false;
164 
165  case token::STRING:
166  if (eqType)
167  {
168  const wordRe w1(t1.stringToken(), wordRe::DETECT);
169  const wordRe w2(t2.stringToken(), wordRe::DETECT);
170  return w1.match(w2) || w2.match(w1);
171  }
172  else if (t2.isWord())
173  {
174  const wordRe w1(t1.stringToken(), wordRe::DETECT);
175  return w1.match(t2.wordToken());
176  }
177  return false;
178 
179  case token::VARIABLE:
180  case token::VERBATIM:
181  if (t2.isStringType())
182  {
183  return t1.stringToken() == t2.stringToken();
184  }
185  return false;
186 
187  case token::LABEL:
188  if (eqType)
189  {
190  return t1.labelToken() == t2.labelToken();
191  }
192  else if (t2.isScalar())
193  {
194  return t1.labelToken() == t2.scalarToken();
195  }
196  return false;
197 
198  case token::FLOAT:
199  if (eqType)
200  {
201  return equal(t1.floatToken(), t2.floatToken());
202  }
203  else if (t2.isLabel())
204  {
205  return t1.floatToken() == t2.labelToken();
206  }
207  else if (t2.isScalar())
208  {
209  return t1.scalarToken() == t2.scalarToken();
210  }
211  return false;
212 
213  case token::DOUBLE:
214  if (eqType)
215  {
216  return equal(t1.doubleToken(), t2.doubleToken());
217  }
218  else if (t2.isLabel())
219  {
220  return t1.doubleToken() == t2.labelToken();
221  }
222  else if (t2.isScalar())
223  {
224  return t1.scalarToken() == t2.scalarToken();
225  }
226  return false;
227 
228  case token::EXPRESSION:
229  return false;
230 
231  case token::COMPOUND:
232  return false;
233 
234  case token::ERROR:
235  return eqType;
236  }
237 
238  return false;
239 }
240 
241 
242 void Foam::functionEntries::ifeqEntry::skipUntil
243 (
244  DynamicList<filePos>& stack,
245  const dictionary& parentDict,
246  const word& endDirective,
247  Istream& is
248 )
249 {
250  while (!is.eof())
251  {
252  token t;
253  readToken(t, is);
254 
255  if (!t.isDirective())
256  {
257  continue;
258  }
259  else if (t.wordToken() == "#if" || t.wordToken() == "#ifeq")
260  {
261  stack.append(filePos(is.name(), is.lineNumber()));
262  skipUntil(stack, parentDict, "#endif", is);
263  stack.remove();
264  }
265  else if (t.wordToken() == endDirective)
266  {
267  return;
268  }
269  }
270 
271  FatalIOErrorInFunction(parentDict)
272  << "Did not find matching " << endDirective << nl
273  << exit(FatalIOError);
274 }
275 
276 
277 // * * * * * * * * * * * * Protected Member Functions * * * * * * * * * * * //
278 
280 (
281  const bool doIf,
282  DynamicList<filePos>& stack,
283  dictionary& parentDict,
284  Istream& is
285 )
286 {
287  while (!is.eof())
288  {
289  token t;
290  readToken(t, is);
291  bool pending = false;
292 
293  if (t.isDirective())
294  {
295  if (t.wordToken() == "#ifeq")
296  {
297  // Recurse to evaluate
298  execute(stack, parentDict, is);
299  }
300  else if (t.wordToken() == "#if")
301  {
302  // Recurse to evaluate
303  ifEntry::execute(stack, parentDict, is);
304  }
305  else if
306  (
307  doIf
308  && (t.wordToken() == "#else" || t.wordToken() == "#elif")
309  )
310  {
311  // Now skip until #endif
312  skipUntil(stack, parentDict, "#endif", is);
313  stack.remove();
314  break;
315  }
316  else if (t.wordToken() == "#endif")
317  {
318  stack.remove();
319  break;
320  }
321  else
322  {
323  pending = true;
324  }
325  }
326  else
327  {
328  pending = true;
329  }
330 
331  if (pending)
332  {
333  is.putBack(t);
334  bool ok = entry::New(parentDict, is);
335  if (!ok)
336  {
337  return false;
338  }
339  }
340  }
341  return true;
342 }
343 
344 
346 (
347  const bool doIf,
348  DynamicList<filePos>& stack,
349  dictionary& parentDict,
350  Istream& is
351 )
352 {
353  if (doIf)
354  {
355  evaluate(true, stack, parentDict, is);
356  }
357  else
358  {
359  // Fast-forward to #else
360  token t;
361  while (!is.eof())
362  {
363  readToken(t, is);
364 
365  // Only consider directives
366  if (!t.isDirective())
367  {
368  continue;
369  }
370 
371  if (t.wordToken() == "#if" || t.wordToken() == "#ifeq")
372  {
373  stack.append(filePos(is.name(), is.lineNumber()));
374  skipUntil(stack, parentDict, "#endif", is);
375  stack.remove();
376  }
377  else if (t.wordToken() == "#else")
378  {
379  break;
380  }
381  else if (t.wordToken() == "#elif")
382  {
383  // const label lineNo = is.lineNumber();
384 
385  // Read line
386  string line;
387  dynamic_cast<ISstream&>(is).getLine(line);
388  line += ';';
389  IStringStream lineStream(line);
390  const primitiveEntry e("ifEntry", parentDict, lineStream);
391 
392  if (ifEntry::isTrue(e.stream()))
393  {
394  // Info<< "Using #elif " << doIf << " - line " << lineNo
395  // << " in file " << is.relativeName() << endl;
396  break;
397  }
398  }
399  else if (t.wordToken() == "#endif")
400  {
401  stack.remove();
402  break;
403  }
404  }
405 
406  if (t.wordToken() == "#else")
407  {
408  // Evaluate until we hit #endif
409  evaluate(false, stack, parentDict, is);
410  }
411  else if (t.wordToken() == "#elif")
412  {
413  // Evaluate until we hit #else or #endif
414  evaluate(true, stack, parentDict, is);
415  }
416  }
417  return true;
418 }
419 
420 
422 (
423  DynamicList<filePos>& stack,
424  dictionary& parentDict,
425  Istream& is
426 )
427 {
428  const label nNested = stack.size();
429 
430  stack.append(filePos(is.name(), is.lineNumber()));
431 
432  // Read first token and expand any string
433  token cond1(is);
434  cond1 = expandToken(parentDict, cond1);
435 
436  // Read second token and expand any string
437  token cond2(is);
438  cond2 = expandToken(parentDict, cond2);
439 
440  const bool equal = equalToken(cond1, cond2);
441 
442  // Info<< "Using #" << typeName << " " << cond1
443  // << " == " << cond2
444  // << " at line " << stack.last().second()
445  // << " in file " << stack.last().first() << endl;
446 
447  bool ok = ifeqEntry::execute(equal, stack, parentDict, is);
448 
449  if (stack.size() != nNested)
450  {
451  FatalIOErrorInFunction(parentDict)
452  << "Did not find matching #endif for condition starting"
453  << " at line " << stack.last().second()
454  << " in file " << stack.last().first() << exit(FatalIOError);
455  }
456 
457  return ok;
458 }
459 
460 
461 // * * * * * * * * * * * * * * * Member Functions * * * * * * * * * * * * * //
462 
464 (
465  dictionary& parentDict,
466  Istream& is
467 )
468 {
469  DynamicList<filePos> stack(10);
470  return execute(stack, parentDict, is);
471 }
472 
473 
474 // ************************************************************************* //
Foam::functionEntries::ifeqEntry::execute
static bool execute(const bool equal, DynamicList< filePos > &stack, dictionary &parentDict, Istream &is)
Definition: ifeqEntry.C:346
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:105
Foam::token::DOUBLE
double (double-precision) type
Definition: token.H:87
Foam::primitiveEntry
A keyword and a list of tokens comprise a primitiveEntry. A primitiveEntry can be read,...
Definition: primitiveEntry.H:63
Foam::token::COMPOUND
Compound type such as List<label> etc.
Definition: token.H:92
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::LABEL
label (integer) type
Definition: token.H:85
Foam::functionEntries::defineTypeNameAndDebug
defineTypeNameAndDebug(codeStream, 0)
Foam::wordRe::DETECT
Detect if the string contains meta-characters.
Definition: wordRe.H:108
Foam::ISstream
Generic input stream using a standard (STL) stream.
Definition: ISstream.H:55
Foam::IOstream::lineNumber
label lineNumber() const noexcept
Const access to the current stream line number.
Definition: IOstream.H:318
Foam::FatalIOError
IOerror FatalIOError
Foam::token
A token holds an item read from Istream.
Definition: token.H:68
Foam::token::STRING
Foam::string (usually double-quoted)
Definition: token.H:91
Foam::token::DIRECTIVE
Definition: token.H:94
Foam::functionEntries::ifeqEntry::evaluate
static bool evaluate(const bool doIf, DynamicList< filePos > &stack, dictionary &parentDict, Istream &is)
Definition: ifeqEntry.C:280
Foam::token::EXPRESSION
Definition: token.H:96
Foam::token::ERROR
Token error encountered.
Definition: token.H:79
Foam::stringOps::inplaceExpand
void inplaceExpand(std::string &s, const HashTable< string > &mapping, const char sigil='$')
Definition: stringOps.C:731
Foam::token::PUNCTUATION
single character punctuation
Definition: token.H:83
Foam::Istream
An Istream is an abstract base class for all input systems (streams, files, token lists etc)....
Definition: Istream.H:61
Foam::DynamicList::append
DynamicList< T, SizeMin > & append(const T &val)
Append an element to the end of this list.
Definition: DynamicListI.H:511
Foam::IOstream::eof
bool eof() const noexcept
True if end of input seen.
Definition: IOstream.H:239
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:40
Foam::token::END_STATEMENT
End entry [isseparator].
Definition: token.H:154
ifeqEntry.H
dict
dictionary dict
Definition: searchingEngine.H:14
Foam::token::WORD
Foam::word.
Definition: token.H:90
Foam::dictionary
A list of keyword definitions, which are a keyword followed by a number of values (eg,...
Definition: dictionary.H:123
w2
#define w2
Definition: blockCreate.C:35
Foam::functionEntries::addNamedToMemberFunctionSelectionTable
addNamedToMemberFunctionSelectionTable(functionEntry, calcEntry, execute, dictionaryIstream, calc)
Foam::IStringStream
Input from string buffer, using a ISstream. Always UNCOMPRESSED.
Definition: StringStream.H:108
Foam
Namespace for OpenFOAM.
Definition: atmBoundaryLayer.C:33
Foam::token::wordToken
const word & wordToken() const
Return const reference to the word contents.
Definition: tokenI.H:631
Foam::token::isDirective
bool isDirective() const noexcept
Token is DIRECTIVE (word variant)
Definition: tokenI.H:625
Foam::exit
errorManipArg< error, int > exit(error &err, const int errNo=1)
Definition: errorManip.H:130
Foam::token::VARIABLE
Definition: token.H:98
Foam::token::UNDEFINED
An undefined token-type.
Definition: token.H:78
Foam::nl
constexpr char nl
Definition: Ostream.H:404
Foam::token::BOOL
boolean type
Definition: token.H:84
Foam::Istream::putBack
void putBack(const token &tok)
Put back a token. Only a single put back is permitted.
Definition: Istream.C:70
Foam::constant::electromagnetic::e
const dimensionedScalar e
Elementary charge.
Definition: createFields.H:11
Foam::token::FLAG
stream flag (1-byte bitmask)
Definition: token.H:82
Foam::DynamicList::remove
T remove()
Remove and return the last element. Fatal on an empty list.
Definition: DynamicListI.H:704
Foam::line
A line primitive.
Definition: line.H:53
Foam::token::FLOAT
float (single-precision) type
Definition: token.H:86
FatalIOErrorInFunction
#define FatalIOErrorInFunction(ios)
Report an error message using Foam::FatalIOError.
Definition: error.H:473
Foam::Tuple2
A 2-tuple for storing two objects of dissimilar types. The container is similar in purpose to std::pa...
Definition: stringOps.H:60
Foam::token::VERBATIM
Definition: token.H:100
stringOps.H
Foam::equal
bool equal(const T &s1, const T &s2)
Compare two values for equality.
Definition: doubleFloat.H:46
Foam::keyType::REGEX_RECURSIVE
Definition: keyType.H:87
Foam::stringOps::evaluate
string evaluate(label fieldWidth, const std::string &s, size_t pos=0, size_t len=std::string::npos)
String evaluation with specified (positive, non-zero) field width.
Definition: stringOpsEvaluate.C:37