primitiveEntryIO.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) 2011-2015 OpenFOAM Foundation
9  Copyright (C) 2017-2023 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 "primitiveEntry.H"
30 #include "functionEntry.H"
31 #include "evalEntry.H"
32 
33 // * * * * * * * * * * * * * Private Member Functions * * * * * * * * * * * //
34 
35 bool Foam::primitiveEntry::acceptToken
36 (
37  const token& tok,
38  const dictionary& dict,
39  Istream& is
40 )
41 {
42  bool accept = tok.good();
43 
44  if (tok.isDirective())
45  {
46  // Directive (wordToken) begins with '#'. Eg, "#include"
47  // Remove leading '#' sigil before dispatching
48 
49  const word& key = tok.wordToken();
50 
51  // Min-size is 2: sigil '#' with any content
52  accept =
53  (
54  (disableFunctionEntries || key.size() < 2)
55  || !expandFunction(key.substr(1), dict, is)
56  );
57  }
58  else if (tok.isExpression())
59  {
60  // Expression (stringToken): ${{ expr }}
61  // Surrounding delimiters are stripped as required in evalEntry
62 
63  const string& key = tok.stringToken();
64 
65  // Min-size is 6: decorators '${{}}' with any content
66  accept =
67  (
68  (disableFunctionEntries || key.size() < 6)
70  (
71  dict,
72  *this,
73  key,
74  1, // Field width is 1
75  is // For error messages
76  )
77  );
78  }
79  else if (tok.isVariable())
80  {
81  // Variable (stringToken): starts with '$'
82  // Eg, "$varName" or "${varName}"
83  // Remove leading '$' sigil before dispatching
84 
85  const string& key = tok.stringToken();
86 
87  // Min-size is 2: sigil '$' with any content
88  accept =
89  (
90  (disableFunctionEntries || key.size() < 2)
91  || !expandVariable(key.substr(1), dict)
92  );
93  }
94 
95  return accept;
96 }
97 
98 
99 bool Foam::primitiveEntry::expandFunction
100 (
101  const word& functionName,
102  const dictionary& dict,
104 )
105 {
106  return functionEntry::execute(functionName, dict, *this, is);
107 }
108 
109 
111 {
113 
114  // Track balanced bracket/brace pairs, with max stack depth of 60.
115  // Use a bitmask to track the opening char: 0 = '()', 1 = '{}'
116  //
117  // Notes
118  // - the bitmask is set *before* increasing the depth since the left
119  // shift implicitly carries a 1-offset with it.
120  // Eg, (1u << 0) already corresponds to depth=1 (the first bit)
121  //
122  // - similarly, the bitmask is tested *after* decreasing depth
123 
124  uint64_t balanced = 0u;
125  int depth = 0;
126  token tok;
127 
128  while
129  (
130  !is.read(tok).bad() && tok.good()
131  && !(tok == token::END_STATEMENT && depth == 0)
132  )
133  {
134  if (tok.isPunctuation())
135  {
136  const char c = tok.pToken();
137  switch (c)
138  {
139  case token::BEGIN_LIST:
140  {
141  if (depth >= 0 && depth < 61)
142  {
143  balanced &= ~(1u << depth); // clear bit
144  }
145  ++depth;
146  }
147  break;
148 
149  case token::BEGIN_BLOCK:
150  {
151  if (depth >= 0 && depth < 61)
152  {
153  balanced |= (1u << depth); // set bit
154  }
155  ++depth;
156  }
157  break;
158 
159  case token::END_LIST:
160  {
161  --depth;
162  if (depth < 0)
163  {
164  reportReadWarning
165  (
166  is,
167  "Too many closing ')' ... was a ';' forgotten?"
168  );
169  }
170  else if (depth < 61 && ((balanced >> depth) & 1u))
171  {
172  // Bit was set, but expected it to be unset.
173  reportReadWarning(is, "Imbalanced '{' with ')'");
174  }
175  }
176  break;
177 
178  case token::END_BLOCK:
179  {
180  --depth;
181  if (depth < 0)
182  {
183  reportReadWarning
184  (
185  is,
186  "Too many closing '}' ... was a ';' forgotten?"
187  );
188  }
189  else if (depth < 61 && !((balanced >> depth) & 1u))
190  {
191  // Bit was unset, but expected it to be set.
192  reportReadWarning(is, "Imbalanced '(' with '}'");
193  }
194  }
195  break;
196  }
197  }
198 
199  if (acceptToken(tok, dict, is))
200  {
201  ITstream::add_tokens(std::move(tok)); // Add at tokenIndex
202  }
203 
204  // With/without move: clear any old content and force to have a
205  // known good token so that we can rely on it for the return value.
206 
207  tok = token::punctuationToken::NULL_TOKEN;
208  }
209 
210  if (depth)
211  {
212  reportReadWarning(is, "Imbalanced brackets");
213  }
214 
216  return tok.good();
217 }
218 
219 
220 void Foam::primitiveEntry::readEntry(const dictionary& dict, Istream& is)
221 {
222  const label keywordLineNumber = is.lineNumber();
223 
224  if (ITstream::empty())
225  {
226  ITstream::resize(16);
227  }
228  ITstream::seek(0);
229 
230  if (read(dict, is)) // Read with 'lazy' appending
231  {
232  ITstream::resize(tokenIndex()); // Truncate to number tokens read
233  ITstream::seek(0);
234  }
235  else
236  {
237  std::ostringstream os;
238  os << "ill defined primitiveEntry starting at keyword '"
239  << keyword() << '\''
240  << " on line " << keywordLineNumber
241  << " and ending at line " << is.lineNumber();
242 
244  (
245  is,
246  os.str()
247  );
248  }
249 }
250 
251 
252 // * * * * * * * * * * * * * * * * Constructors * * * * * * * * * * * * * * //
253 
255 (
256  const keyType& key,
257  const dictionary& dict,
258  Istream& is
259 )
260 :
261  entry(key),
262  ITstream
263  (
264  static_cast<IOstreamOption>(is),
265  fileName::concat(is.name(), key, '/')
266  )
267 {
268  readEntry(dict, is);
269 }
270 
271 
273 :
274  primitiveEntry(key, dictionary::null, is)
275 {}
276 
277 
278 // * * * * * * * * * * * * * * * Member Functions * * * * * * * * * * * * * //
279 
280 void Foam::primitiveEntry::write(Ostream& os, const bool contentsOnly) const
281 {
282  if (!contentsOnly)
283  {
284  os.writeKeyword(keyword());
285  }
286 
287  // Like FlatOutput::OutputAdaptor write()
288  // with open/close = '\0', separator = token::SPACE
289 
290  bool started = false; // Separate from previous token?
291  for (const token& tok : *this)
292  {
293  if (started)
294  {
295  os << token::SPACE;
296  }
297  else
298  {
299  started = true;
300  }
301 
302  // Output token with direct handling in Ostream(s),
303  // or use normal '<<' output operator
304  if (!os.write(tok))
305  {
306  os << tok;
307  }
308  }
309 
310  if (!contentsOnly)
311  {
312  os.endEntry();
313  }
314 }
315 
316 
317 void Foam::primitiveEntry::write(Ostream& os) const
318 {
319  this->write(os, false);
320 }
321 
322 
323 // * * * * * * * * * * * * * * * IOstream Operators * * * * * * * * * * * * //
324 
325 template<>
326 Foam::Ostream& Foam::operator<<
327 (
328  Ostream& os,
329  const InfoProxy<primitiveEntry>& iproxy
330 )
331 {
332  const auto& e = *iproxy;
333 
334  e.print(os);
335 
336  constexpr label nPrintTokens = 10;
337 
338  os << " primitiveEntry '" << e.keyword() << "' comprises ";
339 
340  for (label i=0; i<min(e.size(), nPrintTokens); ++i)
341  {
342  os << nl << " " << e[i].info();
343  }
344 
345  if (e.size() > nPrintTokens)
346  {
347  os << " ...";
348  }
349 
350  os << endl;
351 
352  return os;
353 }
354 
355 
356 // ************************************************************************* //
void add_tokens(const token &tok)
Copy append a token at the current tokenIndex, incrementing the index.
Definition: ITstream.C:735
Begin block [isseparator].
Definition: token.H:165
bool good() const noexcept
True if token is not UNDEFINED or ERROR.
Definition: tokenI.H:507
A class for handling keywords in dictionaries.
Definition: keyType.H:66
bool isPunctuation() const noexcept
Token is PUNCTUATION.
Definition: tokenI.H:561
dictionary dict
punctuationToken pToken() const
Return punctuation character.
Definition: tokenI.H:587
static bool execute(const word &functionName, dictionary &parentDict, Istream &is)
Execute the functionEntry in a sub-dict context.
Definition: functionEntry.C:91
A class for handling file names.
Definition: fileName.H:72
void seek(label pos)
Move tokenIndex to the specified position.
Definition: ITstream.C:380
bool bad() const noexcept
True if stream is corrupted.
Definition: IOstream.H:305
virtual Ostream & write(const char c) override
Write character.
Definition: OBJstream.C:69
void resize(const label len)
Adjust allocated size of list.
Definition: ListI.H:160
A list of keyword definitions, which are a keyword followed by a number of values (eg...
Definition: dictionary.H:129
An Istream is an abstract base class for all input systems (streams, files, token lists etc)...
Definition: Istream.H:57
constexpr char nl
The newline &#39;\n&#39; character (0x0a)
Definition: Ostream.H:50
bool empty() const noexcept
True if List is empty (ie, size() is zero)
Definition: UList.H:666
A token holds an item read from Istream.
Definition: token.H:65
Ostream & endl(Ostream &os)
Add newline and flush stream.
Definition: Ostream.H:531
Begin list [isseparator].
Definition: token.H:161
End entry [isseparator].
Definition: token.H:160
bool read(const char *buf, int32_t &val)
Same as readInt32.
Definition: int32.H:127
A keyword and a list of tokens comprise a primitiveEntry. A primitiveEntry can be read...
void write(vtk::formatter &fmt, const Type &val, const label n=1)
Component-wise write of a value (N times)
static int disableFunctionEntries
Enable or disable use of function entries and variable expansions.
Definition: entry.H:139
const dimensionedScalar e
Elementary charge.
Definition: createFields.H:11
virtual Istream & read(token &)=0
Return next token from stream.
word name(const expressions::valueTypeCode typeCode)
A word representation of a valueTypeCode. Empty for expressions::valueTypeCode::INVALID.
Definition: exprTraits.C:127
static bool execute(const dictionary &parentDict, primitiveEntry &thisEntry, Istream &is)
Execute in a primitiveEntry context, extracts token or line.
Definition: evalEntry.C:243
Space [isspace].
Definition: token.H:131
virtual void write(Ostream &os) const
Write.
End list [isseparator].
Definition: token.H:162
label min(const labelHashSet &set, label minValue=labelMax)
Find the min value in labelHashSet, optionally limited by second argument.
Definition: hashSets.C:26
An Ostream is an abstract base class for all output systems (streams, files, token lists...
Definition: Ostream.H:56
OBJstream os(runTime.globalPath()/outputName)
#define FUNCTION_NAME
virtual const dictionary & dict() const
This entry is not a dictionary, calling this function generates a FatalError.
label lineNumber() const noexcept
Const access to the current stream line number.
Definition: IOstream.H:390
bool fatalCheck(const char *operation) const
Check IOstream status for given operation.
Definition: IOstream.C:51
auto key(const Type &t) -> typename std::enable_if< std::is_enum< Type >::value, typename std::underlying_type< Type >::type >::type
Definition: foamGltfBase.H:103
const dimensionedScalar c
Speed of light in a vacuum.
primitiveEntry(const keyType &key)
Construct from keyword and no tokens.
virtual Ostream & endEntry()
Write end entry (&#39;;&#39;) followed by newline.
Definition: Ostream.C:117
virtual bool read(const dictionary &dict, Istream &is)
Read tokens from the given stream.
End block [isseparator].
Definition: token.H:166
virtual Ostream & writeKeyword(const keyType &kw)
Write the keyword followed by an appropriate indentation.
Definition: Ostream.C:60
#define SafeFatalIOErrorInFunction(ios, msg)
Report an error message using Foam::FatalIOError.
Definition: error.H:660