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-------------------------------------------------------------------------------
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"
33
34// * * * * * * * * * * * * * * Static Data Members * * * * * * * * * * * * * //
35
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 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
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
242void 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,
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,
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(
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// ************************************************************************* //
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:35
#define w1
Definition: blockCreate.C:34
A 1D vector of objects of type <T> that resizes itself as necessary to accept the new objects.
Definition: DynamicList.H:72
T remove()
Remove and return the last element. Fatal on an empty list.
Definition: DynamicListI.H:655
void append(const T &val)
Copy append an element to the end of this list.
Definition: DynamicListI.H:503
void evaluate()
Evaluate boundary conditions.
label lineNumber() const noexcept
Const access to the current stream line number.
Definition: IOstream.H:318
virtual const fileName & name() const
Return the name of the stream.
Definition: IOstream.C:40
bool eof() const noexcept
True if end of input seen.
Definition: IOstream.H:239
Generic input stream using a standard (STL) stream.
Definition: ISstream.H:58
Input from string buffer, using a ISstream. Always UNCOMPRESSED.
Definition: StringStream.H:112
An Istream is an abstract base class for all input systems (streams, files, token lists etc)....
Definition: Istream.H:64
void putBack(const token &tok)
Put back a token. Only a single put back is permitted.
Definition: Istream.C:70
static autoPtr< Time > New()
Construct (dummy) Time - no functionObjects or libraries.
Definition: Time.C:717
A 2-tuple for storing two objects of dissimilar types. The container is similar in purpose to std::pa...
Definition: Tuple2.H:58
void size(const label n)
Older name for setAddressableSize.
Definition: UList.H:114
T & last()
Return the last element of the list.
Definition: UListI.H:216
A list of keyword definitions, which are a keyword followed by a number of values (eg,...
Definition: dictionary.H:126
Conditional parsing of dictionary entries.
Definition: ifeqEntry.H:92
A functionEntry causes entries to be added/manipulated on the specified dictionary given an input str...
Definition: functionEntry.H:69
virtual bool execute()
Calculate the output fields.
@ REGEX_RECURSIVE
Definition: keyType.H:87
A line primitive.
Definition: line.H:68
A keyword and a list of tokens comprise a primitiveEntry. A primitiveEntry can be read,...
A token holds an item read from Istream.
Definition: token.H:69
@ LABEL
label (integer) type
Definition: token.H:85
@ ERROR
Token error encountered.
Definition: token.H:79
@ DOUBLE
double (double-precision) type
Definition: token.H:87
@ VARIABLE
Definition: token.H:98
@ FLAG
stream flag (1-byte bitmask)
Definition: token.H:82
@ WORD
Foam::word.
Definition: token.H:90
@ EXPRESSION
Definition: token.H:96
@ UNDEFINED
An undefined token-type.
Definition: token.H:78
@ COMPOUND
Compound type such as List<label> etc.
Definition: token.H:92
@ FLOAT
float (single-precision) type
Definition: token.H:86
@ VERBATIM
Definition: token.H:100
@ DIRECTIVE
Definition: token.H:94
@ BOOL
boolean type
Definition: token.H:84
@ STRING
Foam::string (usually double-quoted)
Definition: token.H:91
@ PUNCTUATION
single character punctuation
Definition: token.H:83
@ END_STATEMENT
End entry [isseparator].
Definition: token.H:154
bool isDirective() const noexcept
Token is DIRECTIVE (word variant)
Definition: tokenI.H:625
const word & wordToken() const
Return const reference to the word contents.
Definition: tokenI.H:631
@ DETECT
Detect if the string contains meta-characters.
Definition: wordRe.H:108
#define defineTypeNameAndDebug(Type, DebugSwitch)
Define the typeName and debug information.
Definition: className.H:121
#define FatalIOErrorInFunction(ios)
Report an error message using Foam::FatalIOError.
Definition: error.H:473
void inplaceExpand(std::string &s, const HashTable< string > &mapping, const char sigil='$')
Definition: stringOps.C:731
Namespace for OpenFOAM.
bool equal(const T &s1, const T &s2)
Compare two values for equality.
Definition: doubleFloat.H:46
IOerror FatalIOError
errorManipArg< error, int > exit(error &err, const int errNo=1)
Definition: errorManip.H:130
constexpr char nl
The newline '\n' character (0x0a)
Definition: Ostream.H:53
dictionary dict
volScalarField & e
Definition: createFields.H:11