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 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  ifeq
47  );
48 }
49 }
50 
51 
52 // * * * * * * * * * * * * * Private Member Functions * * * * * * * * * * * //
53 
55 {
56  // Skip dummy tokens - avoids entry::getKeyword consuming #else, #endif
57  do
58  {
59  if
60  (
61  is.read(t).bad()
62  || is.eof()
63  || !t.good()
64  )
65  {
66  return;
67  }
68  }
69  while (t == token::END_STATEMENT);
70 }
71 
72 
74 (
75  const dictionary& dict,
76  const string& keyword,
77  const token& t
78 )
79 {
80  if (keyword[0] == '$')
81  {
82  word varName = keyword(1, keyword.size()-1);
83 
84  // lookup the variable name in the given dictionary
85  const entry* ePtr = dict.lookupScopedEntryPtr
86  (
87  varName,
88  true,
89  true
90  );
91  if (ePtr)
92  {
93  return token(ePtr->stream());
94  }
95  else
96  {
97  // String expansion. Allow unset variables
98  string expanded(keyword);
99  stringOps::inplaceExpand(expanded, dict, true, true);
100 
101  // Re-form as a string token so we can compare to string
102  return token(expanded, t.lineNumber());
103  }
104  }
105  else if (!t.isString())
106  {
107  // Re-form as a string token so we can compare to string
108  return token(keyword, t.lineNumber());
109  }
110  else
111  {
112  return t;
113  }
114 }
115 
116 
118 (
119  const dictionary& dict,
120  const token& t
121 )
122 {
123  if (t.isWord())
124  {
125  return expand(dict, t.wordToken(), t);
126  }
127  else if (t.isVariable())
128  {
129  return expand(dict, t.stringToken(), t);
130  }
131  else if (t.isString())
132  {
133  return expand(dict, t.stringToken(), t);
134  }
135  else
136  {
137  return t;
138  }
139 }
140 
141 
143 (
144  const token& t1,
145  const token& t2
146 )
147 {
148  const bool eqType = (t1.type() == t2.type());
149 
150  switch (t1.type())
151  {
152  case token::UNDEFINED:
153  return eqType;
154 
155  case token::PUNCTUATION:
156  return (eqType && t1.pToken() == t2.pToken());
157 
158  case token::WORD:
159  if (eqType)
160  {
161  return t1.wordToken() == t2.wordToken();
162  }
163  else if (t2.isString())
164  {
165  return t1.wordToken() == t2.stringToken();
166  }
167  else
168  {
169  return false;
170  }
171 
172  case token::STRING:
173  case token::VARIABLE:
175  if (eqType)
176  {
177  return t1.stringToken() == t2.stringToken();
178  }
179  else if (t2.isWord())
180  {
181  return t1.stringToken() == t2.wordToken();
182  }
183  else
184  {
185  return false;
186  }
187 
188  case token::LABEL:
189  if (eqType)
190  {
191  return t1.labelToken() == t2.labelToken();
192  }
193  else if (t2.isScalar())
194  {
195  return t1.labelToken() == t2.scalarToken();
196  }
197  else
198  {
199  return false;
200  }
201 
202  case token::FLOAT_SCALAR:
203  if (eqType)
204  {
205  return equal(t1.floatScalarToken(), t2.floatScalarToken());
206  }
207  else if (t2.isScalar())
208  {
209  return t1.scalarToken() == t2.scalarToken();
210  }
211  else
212  {
213  return false;
214  }
215 
217  if (eqType)
218  {
219  return equal(t1.doubleScalarToken(), t2.doubleScalarToken());
220  }
221  else if (t2.isScalar())
222  {
223  return t1.scalarToken() == t2.scalarToken();
224  }
225  else
226  {
227  return false;
228  }
229 
231  if (eqType)
232  {
233  return equal
234  (
237  );
238  }
239  else if (t2.isScalar())
240  {
241  return t1.scalarToken() == t2.scalarToken();
242  }
243  else
244  {
245  return false;
246  }
247 
248  case token::COMPOUND:
249  return false;
250 
251  case token::ERROR:
252  return eqType;
253  }
254  return false;
255 }
256 
257 
259 (
260  DynamicList<filePos>& stack,
261  const dictionary& parentDict,
262  const word& endWord,
263  Istream& is
264 )
265 {
266  while (!is.eof())
267  {
268  token t;
269  readToken(t, is);
270  if (t.isWord())
271  {
272  if (t.wordToken() == "#if" || t.wordToken() == "#ifeq")
273  {
274  stack.append(filePos(is.name(), is.lineNumber()));
275  skipUntil(stack, parentDict, "#endif", is);
276  stack.remove();
277  }
278  else if (t.wordToken() == endWord)
279  {
280  return;
281  }
282  }
283  }
284 
285  FatalIOErrorInFunction(parentDict)
286  << "Did not find matching " << endWord << exit(FatalIOError);
287 }
288 
289 
291 (
292  const bool doIf,
293  DynamicList<filePos>& stack,
294  dictionary& parentDict,
295  Istream& is
296 )
297 {
298  while (!is.eof())
299  {
300  token t;
301  readToken(t, is);
302 
303  if (t.isWord() && t.wordToken() == "#ifeq")
304  {
305  // Recurse to evaluate
306  execute(stack, parentDict, is);
307  }
308  else if (t.isWord() && t.wordToken() == "#if")
309  {
310  // Recurse to evaluate
311  ifEntry::execute(stack, parentDict, is);
312  }
313  else if
314  (
315  doIf
316  && t.isWord()
317  && (t.wordToken() == "#else" || t.wordToken() == "#elif")
318  )
319  {
320  // Now skip until #endif
321  skipUntil(stack, parentDict, "#endif", is);
322  stack.remove();
323  break;
324  }
325  else if (t.isWord() && t.wordToken() == "#endif")
326  {
327  stack.remove();
328  break;
329  }
330  else
331  {
332  is.putBack(t);
333  bool ok = entry::New(parentDict, is);
334  if (!ok)
335  {
336  return false;
337  }
338  }
339  }
340  return true;
341 }
342 
343 
345 (
346  const bool doIf,
347  DynamicList<filePos>& stack,
348  dictionary& parentDict,
349  Istream& is
350 )
351 {
352  if (doIf)
353  {
354  evaluate(true, stack, parentDict, is);
355  }
356  else
357  {
358  // Fast-forward to #else
359  token t;
360  while (!is.eof())
361  {
362  readToken(t, is);
363  if
364  (
365  t.isWord()
366  && (t.wordToken() == "#if" || t.wordToken() == "#ifeq")
367  )
368  {
369  stack.append(filePos(is.name(), is.lineNumber()));
370  skipUntil(stack, parentDict, "#endif", is);
371  stack.remove();
372  }
373  else if (t.isWord() && t.wordToken() == "#else")
374  {
375  break;
376  }
377  else if (t.isWord() && t.wordToken() == "#elif")
378  {
379  // const label lineNo = is.lineNumber();
380 
381  // Read line
382  string line;
383  dynamic_cast<ISstream&>(is).getLine(line);
384  line += ';';
385  IStringStream lineStream(line);
386  const primitiveEntry e("ifEntry", parentDict, lineStream);
387  const Switch doIf(e.stream());
388 
389  if (doIf)
390  {
391  // Info<< "Using #elif " << doIf << " at line " << lineNo
392  // << " in file " << is.name() << endl;
393  break;
394  }
395  }
396  else if (t.isWord() && t.wordToken() == "#endif")
397  {
398  stack.remove();
399  break;
400  }
401  }
402 
403  if (t.wordToken() == "#else")
404  {
405  // Evaluate until we hit #endif
406  evaluate(false, stack, parentDict, is);
407  }
408  else if (t.wordToken() == "#elif")
409  {
410  // Evaluate until we hit #else or #endif
411  evaluate(true, stack, parentDict, is);
412  }
413  }
414  return true;
415 }
416 
417 
419 (
420  DynamicList<filePos>& stack,
421  dictionary& parentDict,
422  Istream& is
423 )
424 {
425  const label nNested = stack.size();
426 
427  stack.append(filePos(is.name(), is.lineNumber()));
428 
429  // Read first token and expand any string
430  token cond1(is);
431  cond1 = expand(parentDict, cond1);
432 
433  // Read second token and expand any string
434  token cond2(is);
435  cond2 = expand(parentDict, cond2);
436 
437  const bool equal = equalToken(cond1, cond2);
438 
439  // Info<< "Using #" << typeName << " " << cond1
440  // << " == " << cond2
441  // << " at line " << stack.last().second()
442  // << " in file " << stack.last().first() << endl;
443 
444  bool ok = ifeqEntry::execute(equal, stack, parentDict, is);
445 
446  if (stack.size() != nNested)
447  {
448  FatalIOErrorInFunction(parentDict)
449  << "Did not find matching #endif for condition starting"
450  << " at line " << stack.last().second()
451  << " in file " << stack.last().first() << exit(FatalIOError);
452  }
453 
454  return ok;
455 }
456 
457 
458 // * * * * * * * * * * * * * * * Member Functions * * * * * * * * * * * * * //
459 
461 (
462  dictionary& parentDict,
463  Istream& is
464 )
465 {
466  DynamicList<filePos> stack(10);
467  return execute(stack, parentDict, is);
468 }
469 
470 
471 // ************************************************************************* //
bool isWord() const
Definition: tokenI.H:230
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:75
punctuationToken pToken() const
Definition: tokenI.H:217
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
bool bad() const
Return true if stream is corrupted.
Definition: IOstream.H:351
A list of keyword definitions, which are a keyword followed by any number of values (e...
Definition: dictionary.H:158
A 2-tuple for storing two objects of different types.
Definition: HashTable.H:65
static bool equalToken(const token &t1, const token &t2)
Definition: ifeqEntry.C:143
const word & wordToken() const
Definition: tokenI.H:235
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:163
A token holds items read from Istream.
Definition: token.H:69
static bool New(dictionary &parentDict, Istream &)
Construct from Istream and insert into dictionary.
Definition: entryIO.C:107
void putBack(const token &)
Put back token.
Definition: Istream.C:30
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
scalar scalarToken() const
Definition: tokenI.H:356
static void skipUntil(DynamicList< filePos > &stack, const dictionary &parentDict, const word &endWord, Istream &is)
Consume tokens until reached a specific word.
Definition: ifeqEntry.C:259
const entry * lookupScopedEntryPtr(const word &, bool recursive, bool patternMatch) const
Find and return an entry data stream pointer if present.
Definition: dictionary.C:594
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.
floatScalar floatScalarToken() const
Definition: tokenI.H:294
virtual Istream & read(token &)=0
Return next token from stream.
A 1D vector of objects of type <T> that resizes itself as necessary to accept the new objects...
Definition: DynamicList.H:56
A class for handling words, derived from string.
Definition: word.H:59
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
bool good() const
Definition: tokenI.H:197
bool isScalar() const
Definition: tokenI.H:346
label lineNumber() const
Definition: tokenI.H:418
static token expand(const dictionary &dict, const string &keyword, const token &t)
Expand a variable (string/word/var starting with &#39;$&#39;)
Definition: ifeqEntry.C:74
addNamedToMemberFunctionSelectionTable(functionEntry, ifEntry, execute, dictionaryIstream, if)
bool isVariable() const
Definition: tokenI.H:248
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
const string & stringToken() const
Definition: tokenI.H:258
longDoubleScalar longDoubleScalarToken() const
Definition: tokenI.H:332
bool isString() const
Definition: tokenI.H:253
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:87
#define FatalIOErrorInFunction(ios)
Report an error message using Foam::FatalIOError.
Definition: error.H:331
tokenType type() const
Definition: tokenI.H:187
Input from memory buffer stream.
Definition: IStringStream.H:49
static bool evaluate(const bool doIf, DynamicList< filePos > &stack, dictionary &parentDict, Istream &is)
Definition: ifeqEntry.C:291
label labelToken() const
Definition: tokenI.H:276
Macros for easy insertion into member function selection tables.
const doubleScalar e
Elementary charge.
Definition: doubleScalar.H:98
T & last()
Return the last element of the list.
Definition: UListI.H:128
doubleScalar doubleScalarToken() const
Definition: tokenI.H:313
static void readToken(token &t, Istream &is)
Read tokens. Skip dummy tokens.
Definition: ifeqEntry.C:54
static bool execute(const bool equal, DynamicList< filePos > &stack, dictionary &parentDict, Istream &is)
Main driver: depending on &#39;equal&#39; starts evaluating or.
Definition: ifeqEntry.C:345
defineTypeNameAndDebug(calcEntry, 0)
Namespace for OpenFOAM.
A keyword and a list of tokens is an &#39;entry&#39;.
Definition: entry.H:65
IOerror FatalIOError