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 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  if (eqType)
159  {
160  return t1.wordToken() == t2.wordToken();
161  }
162  else if (t2.isString())
163  {
165  return w2.match(t1.wordToken(), false);
166  }
167  return false;
168 
169  case token::STRING:
170  if (eqType)
171  {
172  const wordRe w1(t1.stringToken(), wordRe::DETECT);
173  const wordRe w2(t2.stringToken(), wordRe::DETECT);
174  return w1.match(w2, false) || w2.match(w1, false);
175  }
176  else if (t2.isWord())
177  {
178  const wordRe w1(t1.stringToken(), wordRe::DETECT);
179  return w1.match(t2.wordToken(), false);
180  }
181  return false;
182 
183  case token::VARIABLE:
185  if (eqType)
186  {
187  return t1.stringToken() == t2.stringToken();
188  }
189  else if (t2.isWord())
190  {
191  return t1.stringToken() == t2.wordToken();
192  }
193  return false;
194 
195  case token::LABEL:
196  if (eqType)
197  {
198  return t1.labelToken() == t2.labelToken();
199  }
200  else if (t2.isScalar())
201  {
202  return t1.labelToken() == t2.scalarToken();
203  }
204  return false;
205 
206  case token::FLOAT_SCALAR:
207  if (eqType)
208  {
209  return equal(t1.floatScalarToken(), t2.floatScalarToken());
210  }
211  else if (t2.isScalar())
212  {
213  return t1.scalarToken() == t2.scalarToken();
214  }
215  return false;
216 
218  if (eqType)
219  {
220  return equal(t1.doubleScalarToken(), t2.doubleScalarToken());
221  }
222  else if (t2.isScalar())
223  {
224  return t1.scalarToken() == t2.scalarToken();
225  }
226  return false;
227 
228  case token::COMPOUND:
229  return false;
230 
231  case token::ERROR:
232  return eqType;
233  }
234 
235  return false;
236 }
237 
238 
240 (
241  DynamicList<filePos>& stack,
242  const dictionary& parentDict,
243  const word& endWord,
244  Istream& is
245 )
246 {
247  while (!is.eof())
248  {
249  token t;
250  readToken(t, is);
251  if (t.isWord())
252  {
253  if (t.wordToken() == "#if" || t.wordToken() == "#ifeq")
254  {
255  stack.append(filePos(is.name(), is.lineNumber()));
256  skipUntil(stack, parentDict, "#endif", is);
257  stack.remove();
258  }
259  else if (t.wordToken() == endWord)
260  {
261  return;
262  }
263  }
264  }
265 
266  FatalIOErrorInFunction(parentDict)
267  << "Did not find matching " << endWord << nl
268  << exit(FatalIOError);
269 }
270 
271 
273 (
274  const bool doIf,
275  DynamicList<filePos>& stack,
276  dictionary& parentDict,
277  Istream& is
278 )
279 {
280  while (!is.eof())
281  {
282  token t;
283  readToken(t, is);
284 
285  if (t.isWord() && t.wordToken() == "#ifeq")
286  {
287  // Recurse to evaluate
288  execute(stack, parentDict, is);
289  }
290  else if (t.isWord() && t.wordToken() == "#if")
291  {
292  // Recurse to evaluate
293  ifEntry::execute(stack, parentDict, is);
294  }
295  else if
296  (
297  doIf
298  && t.isWord()
299  && (t.wordToken() == "#else" || t.wordToken() == "#elif")
300  )
301  {
302  // Now skip until #endif
303  skipUntil(stack, parentDict, "#endif", is);
304  stack.remove();
305  break;
306  }
307  else if (t.isWord() && t.wordToken() == "#endif")
308  {
309  stack.remove();
310  break;
311  }
312  else
313  {
314  is.putBack(t);
315  bool ok = entry::New(parentDict, is);
316  if (!ok)
317  {
318  return false;
319  }
320  }
321  }
322  return true;
323 }
324 
325 
327 (
328  const bool doIf,
329  DynamicList<filePos>& stack,
330  dictionary& parentDict,
331  Istream& is
332 )
333 {
334  if (doIf)
335  {
336  evaluate(true, stack, parentDict, is);
337  }
338  else
339  {
340  // Fast-forward to #else
341  token t;
342  while (!is.eof())
343  {
344  readToken(t, is);
345  if
346  (
347  t.isWord()
348  && (t.wordToken() == "#if" || t.wordToken() == "#ifeq")
349  )
350  {
351  stack.append(filePos(is.name(), is.lineNumber()));
352  skipUntil(stack, parentDict, "#endif", is);
353  stack.remove();
354  }
355  else if (t.isWord() && t.wordToken() == "#else")
356  {
357  break;
358  }
359  else if (t.isWord() && t.wordToken() == "#elif")
360  {
361  // const label lineNo = is.lineNumber();
362 
363  // Read line
364  string line;
365  dynamic_cast<ISstream&>(is).getLine(line);
366  line += ';';
367  IStringStream lineStream(line);
368  const primitiveEntry e("ifEntry", parentDict, lineStream);
369 
370  if (ifEntry::isTrue(e.stream()))
371  {
372  // Info<< "Using #elif " << doIf << " at line " << lineNo
373  // << " in file " << is.name() << endl;
374  break;
375  }
376  }
377  else if (t.isWord() && t.wordToken() == "#endif")
378  {
379  stack.remove();
380  break;
381  }
382  }
383 
384  if (t.wordToken() == "#else")
385  {
386  // Evaluate until we hit #endif
387  evaluate(false, stack, parentDict, is);
388  }
389  else if (t.wordToken() == "#elif")
390  {
391  // Evaluate until we hit #else or #endif
392  evaluate(true, stack, parentDict, is);
393  }
394  }
395  return true;
396 }
397 
398 
400 (
401  DynamicList<filePos>& stack,
402  dictionary& parentDict,
403  Istream& is
404 )
405 {
406  const label nNested = stack.size();
407 
408  stack.append(filePos(is.name(), is.lineNumber()));
409 
410  // Read first token and expand any string
411  token cond1(is);
412  cond1 = expand(parentDict, cond1);
413 
414  // Read second token and expand any string
415  token cond2(is);
416  cond2 = expand(parentDict, cond2);
417 
418  const bool equal = equalToken(cond1, cond2);
419 
420  // Info<< "Using #" << typeName << " " << cond1
421  // << " == " << cond2
422  // << " at line " << stack.last().second()
423  // << " in file " << stack.last().first() << endl;
424 
425  bool ok = ifeqEntry::execute(equal, stack, parentDict, is);
426 
427  if (stack.size() != nNested)
428  {
429  FatalIOErrorInFunction(parentDict)
430  << "Did not find matching #endif for condition starting"
431  << " at line " << stack.last().second()
432  << " in file " << stack.last().first() << exit(FatalIOError);
433  }
434 
435  return ok;
436 }
437 
438 
439 // * * * * * * * * * * * * * * * Member Functions * * * * * * * * * * * * * //
440 
442 (
443  dictionary& parentDict,
444  Istream& is
445 )
446 {
447  DynamicList<filePos> stack(10);
448  return execute(stack, parentDict, is);
449 }
450 
451 
452 // ************************************************************************* //
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:456
Foam::functionEntries::ifeqEntry::execute
static bool execute(const bool equal, DynamicList< filePos > &stack, dictionary &parentDict, Istream &is)
Definition: ifeqEntry.C:327
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::token::isScalar
bool isScalar() const
Token is FLOAT_SCALAR or DOUBLE_SCALAR.
Definition: tokenI.H:504
Foam::primitiveEntry
A keyword and a list of tokens comprise a primitiveEntry. A primitiveEntry can be read,...
Definition: primitiveEntry.H:62
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:57
Foam::token::stringToken
const string & stringToken() const
Return const reference to the string contents.
Definition: tokenI.H:599
Foam::IOstream::eof
bool eof() const
Return true if end of input seen.
Definition: IOstream.H:222
Foam::token::LABEL
label (integer) type
Definition: token.H:84
Foam::functionEntries::defineTypeNameAndDebug
defineTypeNameAndDebug(codeStream, 0)
Foam::token::isString
bool isString() const
Token is STRING, VARIABLE or VERBATIM string.
Definition: tokenI.H:570
Foam::wordRe::DETECT
Detect if the string contains meta-characters.
Definition: wordRe.H:100
Foam::ISstream
Generic input stream using standard (STL) streams.
Definition: ISstream.H:54
Foam::token::boolToken
bool boolToken() const
Return boolean token value.
Definition: tokenI.H:392
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:82
Foam::token
A token holds an item read from Istream.
Definition: token.H:69
Foam::token::ERROR
A token error encountered.
Definition: token.H:95
Foam::token::good
bool good() const
True if token is not UNDEFINED or ERROR.
Definition: tokenI.H:368
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::pToken
punctuationToken pToken() const
Return punctuation character.
Definition: tokenI.H:428
Foam::token::floatScalarToken
floatScalar floatScalarToken() const
Return float value.
Definition: tokenI.H:474
Foam::functionEntries::ifeqEntry::evaluate
static bool evaluate(const bool doIf, DynamicList< filePos > &stack, dictionary &parentDict, Istream &is)
Definition: ifeqEntry.C:273
Foam::token::FLOAT_SCALAR
float (single-precision) type
Definition: token.H:85
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:240
Foam::label
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:62
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:472
Foam::token::isVariable
bool isVariable() const
Token is VARIABLE.
Definition: tokenI.H:581
Foam::stringOps::inplaceExpand
void inplaceExpand(std::string &s, const HashTable< string, word, string::hash > &mapping, const char sigil='$')
Definition: stringOps.C:752
Foam::token::BOOL
boolean type
Definition: token.H:83
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:116
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::token::isWord
bool isWord() const
Token is WORD.
Definition: tokenI.H:552
Foam::IOstream::bad
bool bad() const
Return true if stream is corrupted.
Definition: IOstream.H:234
w2
#define w2
Definition: blockCreate.C:35
Foam::token::STRING
A string.
Definition: token.H:90
Foam::functionEntries::addNamedToMemberFunctionSelectionTable
addNamedToMemberFunctionSelectionTable(functionEntry, calcEntry, execute, dictionaryIstream, calc)
Foam::IStringStream
Input from string buffer, using a ISstream.
Definition: StringStream.H:112
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:558
Foam::exit
errorManipArg< error, int > exit(error &err, const int errNo=1)
Definition: errorManip.H:130
Foam::token::FLAG
stream flag (1-byte bitmask)
Definition: token.H:81
Foam::token::type
tokenType type() const
Return the token type.
Definition: tokenI.H:295
Foam::nl
constexpr char nl
Definition: Ostream.H:372
Foam::token::scalarToken
scalar scalarToken() const
Return float or double value.
Definition: tokenI.H:514
Foam::Istream::putBack
void putBack(const token &tok)
Put back token.
Definition: Istream.C:53
Foam::stringOps::expand
string expand(const std::string &str, const HashTable< string, word, string::hash > &mapping, const char sigil='$')
Definition: stringOps.C:739
Foam::constant::electromagnetic::e
const dimensionedScalar e
Elementary charge.
Definition: createFields.H:11
Foam::token::WORD
A Foam::word.
Definition: token.H:89
Foam::DynamicList::remove
T remove()
Remove and return the last element. Fatal on an empty list.
Definition: DynamicListI.H:651
Foam::line
A line primitive.
Definition: line.H:59
Foam::token::DOUBLE_SCALAR
double (double-precision) type
Definition: token.H:86
Foam::token::doubleScalarToken
doubleScalar doubleScalarToken() const
Return double value.
Definition: tokenI.H:492
Foam::IOstream::lineNumber
label lineNumber() const
Const access to the current stream line number.
Definition: IOstream.H:301
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:410
FatalIOErrorInFunction
#define FatalIOErrorInFunction(ios)
Report an error message using Foam::FatalIOError.
Definition: error.H:375
Foam::token::lineNumber
label lineNumber() const
The line number for the token.
Definition: tokenI.H:356
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:78
stringOps.H
Foam::equal
bool equal(const T &s1, const T &s2)
Compare two values for equality.
Definition: doubleFloat.H:46
Foam::token::VERBATIMSTRING
Verbatim string content.
Definition: token.H:92
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.