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-2019 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 {
38  defineTypeNameAndDebug(ifeqEntry, 0);
39 
41  (
42  functionEntry,
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::inplaceExpand(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::LABEL:
155  if (eqType)
156  {
157  return t1.labelToken() == t2.labelToken();
158  }
159  else if (t2.isScalar())
160  {
161  return t1.labelToken() == t2.scalarToken();
162  }
163  else
164  {
165  return false;
166  }
167 
168  case token::FLOAT_SCALAR:
169  if (eqType)
170  {
171  return equal(t1.floatScalarToken(), t2.floatScalarToken());
172  }
173  else if (t2.isScalar())
174  {
175  return t1.scalarToken() == t2.scalarToken();
176  }
177  else
178  {
179  return false;
180  }
181 
183  if (eqType)
184  {
185  return equal(t1.doubleScalarToken(), t2.doubleScalarToken());
186  }
187  else if (t2.isScalar())
188  {
189  return t1.scalarToken() == t2.scalarToken();
190  }
191  else
192  {
193  return false;
194  }
195 
197  if (eqType)
198  {
199  return equal
200  (
201  t1.longDoubleScalarToken(),
202  t2.longDoubleScalarToken()
203  );
204  }
205  else if (t2.isScalar())
206  {
207  return t1.scalarToken() == t2.scalarToken();
208  }
209  else
210  {
211  return false;
212  }
213 
214  case token::COMPOUND:
215  return false;
216 
217  case token::ERROR:
218  return eqType;
219  }
220 
221  return false;
222 }
223 
224 
225 void Foam::functionEntries::ifeqEntry::skipUntil
226 (
227  DynamicList<filePos>& stack,
228  const dictionary& parentDict,
229  const functionName& endWord,
230  Istream& is
231 )
232 {
233  while (!is.eof())
234  {
235  token t;
236  readToken(t, is);
237  if (t.isFunctionName())
238  {
239  if
240  (
241  t.functionNameToken() == ifName
242  || t.functionNameToken() == ifeqName
243  )
244  {
245  stack.append(filePos(is.name(), is.lineNumber()));
246  skipUntil(stack, parentDict, endifName, is);
247  stack.remove();
248  }
249  else if (t.functionNameToken() == endWord)
250  {
251  return;
252  }
253  }
254  }
255 
256  FatalIOErrorInFunction(parentDict)
257  << "Did not find matching " << endWord << exit(FatalIOError);
258 }
259 
260 
261 bool Foam::functionEntries::ifeqEntry::evaluate
262 (
263  const bool doIf,
264  DynamicList<filePos>& stack,
265  dictionary& parentDict,
266  Istream& is
267 )
268 {
269  while (!is.eof())
270  {
271  token t;
272  readToken(t, is);
273 
274  if (t.isFunctionName() && t.functionNameToken() == ifeqName)
275  {
276  // Recurse to evaluate
277  execute(stack, parentDict, is);
278  }
279  else if (t.isFunctionName() && t.functionNameToken() == ifName)
280  {
281  // Recurse to evaluate
282  ifEntry::execute(stack, parentDict, is);
283  }
284  else if
285  (
286  doIf
287  && t.isFunctionName()
288  && (
289  t.functionNameToken() == elseName
290  || t.functionNameToken() == elifName
291  )
292  )
293  {
294  // Now skip until #endif
295  skipUntil(stack, parentDict, endifName, is);
296  stack.remove();
297  break;
298  }
299  else if (t.isFunctionName() && t.functionNameToken() == endifName)
300  {
301  stack.remove();
302  break;
303  }
304  else
305  {
306  is.putBack(t);
307  bool ok = entry::New(parentDict, is);
308  if (!ok)
309  {
310  return false;
311  }
312  }
313  }
314  return true;
315 }
316 
317 
318 bool Foam::functionEntries::ifeqEntry::execute
319 (
320  const bool doIf,
321  DynamicList<filePos>& stack,
322  dictionary& parentDict,
323  Istream& is
324 )
325 {
326  if (doIf)
327  {
328  evaluate(true, stack, parentDict, is);
329  }
330  else
331  {
332  // Fast-forward to #else
333  token t;
334  while (!is.eof())
335  {
336  readToken(t, is);
337 
338  if (t.isFunctionName())
339  {
340  if
341  (
342  t.functionNameToken() == ifName
343  || t.functionNameToken() == ifeqName
344  )
345  {
346  stack.append(filePos(is.name(), is.lineNumber()));
347  skipUntil(stack, parentDict, endifName, is);
348  stack.remove();
349  }
350  else if (t.functionNameToken() == elseName)
351  {
352  break;
353  }
354  else if (t.functionNameToken() == elifName)
355  {
356  // Read line
357  string line;
358  dynamic_cast<ISstream&>(is).getLine(line);
359  line += ';';
360  IStringStream lineStream(line);
361  const primitiveEntry e("ifEntry", parentDict, lineStream);
362  const Switch doIf(e.stream());
363 
364  if (doIf)
365  {
366  // Info<< "Using #elif " << doIf
367  // << " at line " << lineNo
368  // << " in file " << is.name() << endl;
369  break;
370  }
371  }
372  else if (t.functionNameToken() == endifName)
373  {
374  stack.remove();
375  break;
376  }
377  }
378  }
379 
380  if (t.functionNameToken() == elseName)
381  {
382  // Evaluate until we hit #endif
383  evaluate(false, stack, parentDict, is);
384  }
385  else if (t.functionNameToken() == elifName)
386  {
387  // Evaluate until we hit #else or #endif
388  evaluate(true, stack, parentDict, is);
389  }
390  }
391  return true;
392 }
393 
394 
395 bool Foam::functionEntries::ifeqEntry::execute
396 (
397  DynamicList<filePos>& stack,
398  dictionary& parentDict,
399  Istream& is
400 )
401 {
402  const label nNested = stack.size();
403 
404  stack.append(filePos(is.name(), is.lineNumber()));
405 
406  // Read first token and expand if a variable
407  token cond1(is);
408  cond1 = expand(parentDict, cond1);
409 
410  // Read second token and expand if a variable
411  token cond2(is);
412  cond2 = expand(parentDict, cond2);
413 
414  const bool equal = equalToken(cond1, cond2);
415 
416  // Info<< "Using #" << typeName << " " << cond1
417  // << " == " << cond2
418  // << " at line " << stack.last().second()
419  // << " in file " << stack.last().first() << endl;
420 
421  bool ok = ifeqEntry::execute(equal, stack, parentDict, is);
422 
423  if (stack.size() != nNested)
424  {
425  FatalIOErrorInFunction(parentDict)
426  << "Did not find matching #endif for condition starting"
427  << " at line " << stack.last().second()
428  << " in file " << stack.last().first() << exit(FatalIOError);
429  }
430 
431  return ok;
432 }
433 
434 
435 // * * * * * * * * * * * * * * * Member Functions * * * * * * * * * * * * * //
436 
437 bool Foam::functionEntries::ifeqEntry::execute
438 (
439  dictionary& parentDict,
440  Istream& is
441 )
442 {
443  DynamicList<filePos> stack(10);
444  return execute(stack, parentDict, is);
445 }
446 
447 
448 // ************************************************************************* //
const variable & variableToken() const
Definition: tokenI.H:302
const functionName & functionNameToken() const
Definition: tokenI.H:284
string expand(const string &, const HashTable< string, word, string::hash > &mapping, const char sigil='$')
Expand occurrences of variables according to the mapping.
Definition: stringOps.C:69
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
A line primitive.
Definition: line.H:56
errorManipArg< error, int > exit(error &err, const int errNo=1)
Definition: errorManip.H:124
A list of keyword definitions, which are a keyword followed by any number of values (e...
Definition: dictionary.H:158
#define FatalErrorInFunction
Report an error message using Foam::FatalError.
Definition: error.H:319
A 2-tuple for storing two objects of different types.
Definition: HashTable.H:65
An Istream is an abstract base class for all input systems (streams, files, token lists etc)...
Definition: Istream.H:57
void size(const label)
Override size to be inconsistent with allocated storage.
Definition: ListI.H:164
A token holds items read from Istream.
Definition: token.H:72
static bool New(dictionary &parentDict, Istream &)
Construct from Istream and insert into dictionary.
Definition: entryIO.C:94
A simple wrapper around bool so that it can be read as a word: true/false, on/off, yes/no, y/n, t/f, or none/any.
Definition: Switch.H:60
label lineNumber() const
Return current stream line number.
Definition: IOstream.H:438
addToMemberFunctionSelectionTable(functionEntry, calcEntry, execute, dictionaryIstream)
A keyword and a list of tokens is a &#39;primitiveEntry&#39;. An primitiveEntry can be read, written and printed, and the types and values of its tokens analysed.
A 1D vector of objects of type <T> that resizes itself as necessary to accept the new objects...
Definition: DynamicList.H:56
A functionName is a word starting with &#39;#&#39;.
Definition: functionName.H:57
static const functionName endifName
Definition: ifeqEntry.H:158
virtual const fileName & name() const
Return the name of the stream.
Definition: IOstream.H:297
DynamicList< T, SizeInc, SizeMult, SizeDiv > & append(const T &)
Append an element at the end of the list.
Definition: DynamicListI.H:296
static const functionName ifName
Definition: ifeqEntry.H:154
static const functionName ifeqName
Definition: ifeqEntry.H:155
ITstream & stream() const
Return token stream if this entry is a primitive entry.
bool eof() const
Return true if end of input seen.
Definition: IOstream.H:339
static const functionName elifName
Definition: ifeqEntry.H:156
T remove()
Remove and return the top element.
Definition: DynamicListI.H:351
bool equal(const T &s1, const T &s2)
Definition: doubleFloat.H:62
Generic input stream.
Definition: ISstream.H:51
string & inplaceExpand(string &, const HashTable< string, word, string::hash > &mapping, const char sigil='$')
Inplace expand occurrences of variables according to the mapping.
Definition: stringOps.C:81
#define FatalIOErrorInFunction(ios)
Report an error message using Foam::FatalIOError.
Definition: error.H:331
Input from memory buffer stream.
Definition: IStringStream.H:49
Macros for easy insertion into member function selection tables.
bool isFunctionName() const
Definition: tokenI.H:279
const doubleScalar e
Elementary charge.
Definition: doubleScalar.H:105
static const functionName elseName
Definition: ifeqEntry.H:157
T & last()
Return the last element of the list.
Definition: UListI.H:128
defineTypeNameAndDebug(calcEntry, 0)
Namespace for OpenFOAM.
IOerror FatalIOError