Loading...
Searching...
No Matches
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,2024 OpenFOAM Foundation
9 Copyright (C) 2019-2023 OpenCFD Ltd.
10-------------------------------------------------------------------------------
11License
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"
34// * * * * * * * * * * * * * * Static Data Members * * * * * * * * * * * * * //
36namespace Foam
37{
38namespace functionEntries
39{
41
43 (
46 execute,
47 dictionaryIstream,
48 ifeq
49 );
50} // End namespace functionEntries
51} // End namespace Foam
52
53
54// * * * * * * * * * * * * * Private Member Functions * * * * * * * * * * * //
55
56void 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
70Foam::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
107Foam::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
130bool 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
150 return (eqType && t1.pToken() == t2.pToken());
151
152 case token::WORD:
153 case token::DIRECTIVE:
154 {
155 if (t2.isWord())
156 {
157 return t1.wordToken() == t2.wordToken();
158 }
159 else if (t2.isString())
160 {
161 const wordRe w2(t2.stringToken(), wordRe::DETECT);
162 return w2.match(t1.wordToken());
163 }
164 return false;
165 }
166
167 case token::STRING:
168 {
169 if (eqType)
170 {
171 const wordRe w1(t1.stringToken(), wordRe::DETECT);
172 const wordRe w2(t2.stringToken(), wordRe::DETECT);
173 return w1.match(w2) || w2.match(w1);
174 }
175 else if (t2.isWord())
176 {
177 const wordRe w1(t1.stringToken(), wordRe::DETECT);
178 return w1.match(t2.wordToken());
179 }
180 return false;
181 }
182
183 case token::VARIABLE:
184 case token::VERBATIM:
185 case token::CHAR_DATA:
186 {
187 if (t2.isStringType())
188 {
189 return t1.stringToken() == t2.stringToken();
190 }
191 return false;
192 }
193
194 case token::INTEGER_32 :
195 {
196 if (eqType)
197 {
198 return t1.int32Token() == t2.int32Token();
199 }
200 else if (t2.isLabel())
201 {
202 return t1.labelToken() == t2.labelToken();
203 }
204 else if (t2.isScalar())
205 {
206 return t1.labelToken() == t2.scalarToken();
207 }
208 return false;
209 }
210
211 case token::INTEGER_64 :
212 {
213 if (eqType)
214 {
215 return t1.int64Token() == t2.int64Token();
216 }
217 else if (t2.isLabel())
218 {
219 return t1.labelToken() == t2.labelToken();
220 }
221 else if (t2.isScalar())
222 {
223 return t1.labelToken() == t2.scalarToken();
224 }
225 return false;
226 }
227
229 {
230 if (eqType)
231 {
232 return t1.uint32Token() == t2.uint32Token();
233 }
234 else if (t2.isLabel())
235 {
236 return t1.labelToken() == t2.labelToken();
237 }
238 else if (t2.isScalar())
239 {
240 return t1.labelToken() == t2.scalarToken();
241 }
242 return false;
243 }
244
246 {
247 if (eqType)
248 {
249 return t1.uint64Token() == t2.uint64Token();
250 }
251 else if (t2.isLabel())
252 {
253 return t1.labelToken() == t2.labelToken();
254 }
255 else if (t2.isScalar())
256 {
257 return t1.labelToken() == t2.scalarToken();
258 }
259 return false;
260 }
261
262 case token::FLOAT:
263 {
264 if (eqType)
265 {
266 return equal(t1.floatToken(), t2.floatToken());
267 }
268 else if (t2.isLabel())
269 {
270 return t1.floatToken() == t2.labelToken();
271 }
272 else if (t2.isScalar())
273 {
274 return t1.scalarToken() == t2.scalarToken();
275 }
276 return false;
277 }
278
279 case token::DOUBLE:
280 {
281 if (eqType)
282 {
283 return equal(t1.doubleToken(), t2.doubleToken());
284 }
285 else if (t2.isLabel())
286 {
287 return t1.doubleToken() == t2.labelToken();
288 }
289 else if (t2.isScalar())
290 {
291 return t1.scalarToken() == t2.scalarToken();
292 }
293 return false;
294 }
295
297 return false;
298
299 case token::COMPOUND:
300 return false;
301
302 case token::ERROR:
303 return eqType;
304 }
305
306 return false;
307}
308
309
310void Foam::functionEntries::ifeqEntry::skipUntil
311(
312 DynamicList<filePos>& stack,
313 const dictionary& parentDict,
314 const word& endDirective,
315 Istream& is
316)
317{
318 while (!is.eof())
319 {
320 token t;
321 readToken(t, is);
322
323 if (!t.isDirective())
324 {
325 continue;
326 }
327 else if (t.wordToken() == "#if" || t.wordToken() == "#ifeq")
328 {
329 stack.push_back(filePos(is.name(), is.lineNumber()));
330 skipUntil(stack, parentDict, "#endif", is);
331 stack.pop_back();
332 }
333 else if (t.wordToken() == endDirective)
334 {
335 return;
336 }
337 }
338
339 FatalIOErrorInFunction(parentDict)
340 << "Did not find matching " << endDirective << nl
341 << exit(FatalIOError);
342}
343
344
345// * * * * * * * * * * * * Protected Member Functions * * * * * * * * * * * //
346
348(
349 const bool doIf,
351 dictionary& parentDict,
352 Istream& is
353)
354{
355 while (!is.eof())
356 {
357 token t;
358 readToken(t, is);
359 bool pending = false;
360
361 if (t.isDirective())
362 {
363 if (t.wordToken() == "#ifeq")
364 {
365 // Recurse to evaluate
366 execute(stack, parentDict, is);
367 }
368 else if (t.wordToken() == "#if")
369 {
370 // Recurse to evaluate
371 ifEntry::execute(stack, parentDict, is);
372 }
373 else if
374 (
375 doIf
376 && (t.wordToken() == "#else" || t.wordToken() == "#elif")
377 )
378 {
379 // Now skip until #endif
380 skipUntil(stack, parentDict, "#endif", is);
381 stack.pop_back();
382 break;
383 }
384 else if (t.wordToken() == "#endif")
385 {
386 stack.pop_back();
387 break;
388 }
389 else
390 {
391 pending = true;
392 }
393 }
394 else
395 {
396 pending = true;
397 }
398
399 if (pending)
400 {
401 is.putBack(t);
402 bool ok = entry::New(parentDict, is);
403 if (!ok)
404 {
405 return false;
407 }
408 }
409 return true;
410}
411
412
414(
415 const bool doIf,
416 DynamicList<filePos>& stack,
417 dictionary& parentDict,
418 Istream& is
419)
420{
421 if (doIf)
422 {
423 evaluate(true, stack, parentDict, is);
424 }
425 else
426 {
427 // Fast-forward to #else
428 token t;
429 while (!is.eof())
430 {
431 readToken(t, is);
432
433 // Only consider directives
434 if (!t.isDirective())
435 {
436 continue;
437 }
438
439 if (t.wordToken() == "#if" || t.wordToken() == "#ifeq")
440 {
441 stack.push_back(filePos(is.name(), is.lineNumber()));
442 skipUntil(stack, parentDict, "#endif", is);
443 stack.pop_back();
444 }
445 else if (t.wordToken() == "#else")
446 {
447 break;
448 }
449 else if (t.wordToken() == "#elif")
450 {
451 // const label lineNo = is.lineNumber();
452
453 // Read line
454 string line;
455 dynamic_cast<ISstream&>(is).getLine(line);
456 line += ';';
457 IStringStream lineStream(line);
458 const primitiveEntry e("ifEntry", parentDict, lineStream);
459
460 if (ifEntry::isTrue(e.stream()))
461 {
462 // Info<< "Using #elif " << doIf << " - line " << lineNo
463 // << " in file " << is.relativeName() << endl;
464 break;
465 }
466 }
467 else if (t.wordToken() == "#endif")
468 {
469 stack.pop_back();
470 break;
471 }
472 }
473
474 if (t.wordToken() == "#else")
475 {
476 // Evaluate until we hit #endif
477 evaluate(false, stack, parentDict, is);
478 }
479 else if (t.wordToken() == "#elif")
480 {
481 // Evaluate until we hit #else or #endif
482 evaluate(true, stack, parentDict, is);
483 }
484 }
485 return true;
486}
487
488
490(
491 DynamicList<filePos>& stack,
492 dictionary& parentDict,
493 Istream& is
494)
495{
496 const label nNested = stack.size();
497
498 stack.push_back(filePos(is.name(), is.lineNumber()));
499
500 // Read first token and expand any string
501 token cond1(is);
502 cond1 = expandToken(parentDict, cond1);
503
504 // Read second token and expand any string
505 token cond2(is);
506 cond2 = expandToken(parentDict, cond2);
507
508 const bool equal = equalToken(cond1, cond2);
509
510 // Info<< "Using #" << typeName << " " << cond1
511 // << " == " << cond2
512 // << " at line " << stack.back().second()
513 // << " in file " << stack.back().first() << endl;
514
515 bool ok = ifeqEntry::execute(equal, stack, parentDict, is);
516
517 if (stack.size() != nNested)
518 {
519 FatalIOErrorInFunction(parentDict)
520 << "Did not find matching #endif for condition starting"
521 << " at line " << stack.back().second()
522 << " in file " << stack.back().first() << exit(FatalIOError);
523 }
525 return ok;
526}
527
528
529// * * * * * * * * * * * * * * * Member Functions * * * * * * * * * * * * * //
530
532(
533 dictionary& parentDict,
534 Istream& is
535)
536{
537 DynamicList<filePos> stack(10);
538 return execute(stack, parentDict, is);
539}
540
541
542// ************************************************************************* //
Macros for easy insertion into member function selection tables.
#define addNamedToMemberFunctionSelectionTable(baseType, thisType, funcName, argNames, lookupName)
Add to hash-table of functions with 'lookupName' as the key.
#define w2
Definition blockCreate.C:28
#define w1
Definition blockCreate.C:27
A 1D vector of objects of type <T> that resizes itself as necessary to accept the new objects.
Definition DynamicList.H:68
void pop_back(label n=1)
Reduce size by 1 or more elements. Can be called on an empty list.
void push_back(const T &val)
Copy append an element to the end of this list.
label lineNumber() const noexcept
Const access to the current stream line number.
Definition IOstream.H:409
bool bad() const noexcept
True if stream is corrupted.
Definition IOstream.H:305
virtual const fileName & name() const
The name of the stream.
Definition IOstream.C:33
bool eof() const noexcept
True if end of input seen.
Definition IOstream.H:289
Generic input stream using a standard (STL) stream.
Definition ISstream.H:54
Input from string buffer, using a ISstream. Always UNCOMPRESSED.
An Istream is an abstract base class for all input systems (streams, files, token lists etc)....
Definition Istream.H:60
void putBack(const token &tok)
Put back a token (copy). Only a single put back is permitted.
Definition Istream.C:71
virtual Istream & read(token &)=0
Return next token from stream.
T & back()
Access last element of the list, position [size()-1].
Definition UListI.H:253
void size(const label n)
Older name for setAddressableSize.
Definition UList.H:118
A list of keyword definitions, which are a keyword followed by a number of values (eg,...
Definition dictionary.H:133
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:98
Conditional parsing of dictionary entries.
Definition ifeqEntry.H:88
static bool evaluate(const bool doIf, DynamicList< filePos > &stack, dictionary &parentDict, Istream &is)
Definition ifeqEntry.C:341
static bool execute(const bool equal, DynamicList< filePos > &stack, dictionary &parentDict, Istream &is)
Main driver: depending on 'equal' starts evaluating or skips forward to else.
Definition ifeqEntry.C:407
Tuple2< fileName, label > filePos
Definition ifeqEntry.H:93
A functionEntry causes entries to be added/manipulated on the specified dictionary given an input str...
@ REGEX_RECURSIVE
Definition keyType.H:88
A line primitive.
Definition line.H:180
primitiveEntry(const keyType &key)
Construct from keyword and no tokens.
A token holds an item read from Istream.
Definition token.H:70
@ ERROR
Token error encountered.
Definition token.H:83
@ DOUBLE
double (double-precision) type
Definition token.H:94
@ FLAG
stream flag (1-byte bitmask)
Definition token.H:86
@ WORD
Foam::word.
Definition token.H:97
@ UNSIGNED_INTEGER_32
uint32 type
Definition token.H:91
@ EXPRESSION
Definition token.H:104
@ UNDEFINED
An undefined token-type.
Definition token.H:82
@ COMPOUND
Compound type such as List<label> etc.
Definition token.H:99
@ CHAR_DATA
String-variant: plain character content.
Definition token.H:110
@ INTEGER_64
int64 type
Definition token.H:90
@ FLOAT
float (single-precision) type
Definition token.H:93
@ DIRECTIVE
Definition token.H:101
@ BOOL
boolean type
Definition token.H:88
@ UNSIGNED_INTEGER_64
uint64 type
Definition token.H:92
@ INTEGER_32
int32 type
Definition token.H:89
@ STRING
Foam::string (usually double-quoted).
Definition token.H:98
@ PUNCTUATION
single character punctuation
Definition token.H:87
@ END_STATEMENT
End entry [isseparator].
Definition token.H:173
bool good() const noexcept
True if token is not UNDEFINED or ERROR.
Definition tokenI.H:584
bool isDirective() const noexcept
Token is DIRECTIVE (word variant).
Definition tokenI.H:1016
const word & wordToken() const
Return const reference to the word contents.
Definition tokenI.H:1022
@ DETECT
Detect if the string contains meta-characters.
Definition wordRe.H:113
#define defineTypeNameAndDebug(Type, DebugSwitch)
Define the typeName and debug information.
Definition className.H:142
#define FatalIOErrorInFunction(ios)
Report an error message using Foam::FatalIOError.
Definition error.H:629
Namespace for containing a functionEntry.
Definition calcEntry.C:33
void inplaceExpand(std::string &s, const HashTable< string > &mapping, const char sigil='$')
Inplace expand occurrences of variables according to the mapping. Does not use environment values.
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.
Namespace for OpenFOAM.
bool equal(const T &a, const T &b)
Compare two values for equality.
Definition label.H:180
IOerror FatalIOError
Error stream (stdout output on all processes), with additional 'FOAM FATAL IO ERROR' header text and ...
errorManipArg< error, int > exit(error &err, const int errNo=1)
Definition errorManip.H:125
constexpr char nl
The newline '\n' character (0x0a).
Definition Ostream.H:50
dictionary dict
volScalarField & e