Visualization Library 2.1.0

A lightweight C++ OpenGL middleware for 2D/3D graphics

VL     Star     Watch     Fork     Issue

[Download] [Tutorials] [All Classes] [Grouped Classes]
ParserVLT.hpp
Go to the documentation of this file.
1 /**************************************************************************************/
2 /* */
3 /* Visualization Library */
4 /* http://visualizationlibrary.org */
5 /* */
6 /* Copyright (c) 2005-2020, Michele Bosi */
7 /* All rights reserved. */
8 /* */
9 /* Redistribution and use in source and binary forms, with or without modification, */
10 /* are permitted provided that the following conditions are met: */
11 /* */
12 /* - Redistributions of source code must retain the above copyright notice, this */
13 /* list of conditions and the following disclaimer. */
14 /* */
15 /* - Redistributions in binary form must reproduce the above copyright notice, this */
16 /* list of conditions and the following disclaimer in the documentation and/or */
17 /* other materials provided with the distribution. */
18 /* */
19 /* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND */
20 /* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED */
21 /* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE */
22 /* DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR */
23 /* ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES */
24 /* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; */
25 /* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON */
26 /* ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT */
27 /* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS */
28 /* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */
29 /* */
30 /**************************************************************************************/
31 
32 #ifndef VLXParserVLT_INCLUDE_ONCE
33 #define VLXParserVLT_INCLUDE_ONCE
34 
35 #include <vlX/Parser.hpp>
36 #include <vlX/VLTTokenizer.hpp>
37 #include <vlX/Defines.hpp>
38 #include <cstdlib>
39 
40 #ifdef _MSC_VER
41  #define atoll _atoi64
42 #endif
43 
44 namespace vlX
45 {
47  class ParserVLT: public Parser
48  {
50 
51  public:
53  {
54  mTokenizer = new VLTTokenizer;
55  mVersion = 0;
56  }
57 
58  bool getToken(VLTToken& token) { return mTokenizer->getToken(token); }
59 
60  bool parseHeader()
61  {
62  mVersion = 0;
63  mEncoding.clear();
64 
65  // VLX
66  if (!getToken(mToken) || mToken.mType != VLTToken::Identifier || mToken.mString != "VLX")
67  {
68  vl::Log::error("'VLX' header not found!\n");
69  return false;
70  }
71 
72  // version
73  if (!getToken(mToken) || mToken.mType != VLTToken::Identifier || mToken.mString != "version")
74  return false;
75 
76  if (!getToken(mToken) || mToken.mType != VLTToken::Equals)
77  return false;
78 
79  if (!getToken(mToken) || mToken.mType != VLTToken::Integer)
80  return false;
81  else
82  mVersion = (unsigned short)atoi( mToken.mString.c_str() );
83 
84  // encoding
85  if (!getToken(mToken) || mToken.mType != VLTToken::Identifier || mToken.mString != "encoding")
86  return false;
87 
88  if (!getToken(mToken) || mToken.mType != VLTToken::Equals)
89  return false;
90 
91  if (!getToken(mToken) || mToken.mType != VLTToken::Identifier || mToken.mString != "ascii")
92  return false;
93  else
94  mEncoding = mToken.mString;
95 
96  return true;
97  }
98 
99  bool parse()
100  {
101  class CloseFileClass
102  {
103  public:
104  CloseFileClass(vl::VirtualFile* f): mFile(f) {}
105  ~CloseFileClass()
106  {
107  if (mFile)
108  mFile->close();
109  }
110  private:
112  } CloseFile(tokenizer()->inputFile());
113 
114  // clear metadata
115  mMetadata.clear();
116 
117  // read version and encoding
118  if (!parseHeader())
119  {
120  vl::Log::error( vl::Say("Line %n : error parsing VLT header at '%s'.\n") << tokenizer()->lineNumber() << mToken.mString );
121  return false;
122  }
123 
125  {
126  vl::Log::error("VLX version not supported.\n");
127  return false;
128  }
129 
130  if (mEncoding != "ascii")
131  {
132  vl::Log::error("Encoding not supported.\n");
133  return false;
134  }
135 
136  while(getToken(mToken) && mToken.mType != VLTToken::TOKEN_EOF)
137  {
138  if(mToken.mType == VLTToken::TagHeader)
139  {
140  mLastTag = mToken.mString;
141 
142  if(getToken(mToken) && mToken.mType == VLTToken::LeftCurlyBracket)
143  {
145  st->setLineNumber( tokenizer()->lineNumber() );
146 
147  if (!parseStructure(st.get()))
148  {
149  if (mToken.mString.length())
150  vl::Log::error( vl::Say("Line %n : parse error at '%s'.\n") << mTokenizer->lineNumber() << mToken.mString.c_str() );
151  else
152  vl::Log::error( vl::Say("Line %n : parse error.\n") << mTokenizer->lineNumber() );
153  return false;
154  }
155 
156  mStructures.push_back(st);
157  }
158  else
159  {
160  vl::Log::error( vl::Say("Line %n : parse error at '%s'.\n") << mTokenizer->lineNumber() << mToken.mString.c_str() );
161  return false;
162  }
163  }
164  else
165  {
166  vl::Log::error( vl::Say("Line %n : parse error at '%s'.\n") << mTokenizer->lineNumber() << mToken.mString.c_str() );
167  return false;
168  }
169  }
170 
171  parseMetadata();
172 
173  VL_CHECK(mToken.mType == VLTToken::TOKEN_EOF)
174  return mToken.mType == VLTToken::TOKEN_EOF;
175  }
176 
178  {
179  // consume last tag if there was one
180  if (!mLastTag.empty())
181  {
182  object->setTag(mLastTag.c_str());
183  mLastTag.clear();
184  }
185 
186  while(getToken(mToken))
187  {
188  if (mToken.mType == VLTToken::RightCurlyBracket)
189  {
190  return true;
191  }
192  else
193  if (mToken.mType == VLTToken::Identifier)
194  {
195  // ID field requires a proper #identifier
196  if (mToken.mString.length() == 2)
197  {
198  if (mToken.mString == "ID")
199  {
200  // Check if ID has already been set
201  if (!object->uid().empty() && object->uid() != "#NULL")
202  {
203  vl::Log::error("ID already set.\n");
204  return false;
205  }
206 
207  // Equals
208  if (!getToken(mToken) || mToken.mType != VLTToken::Equals)
209  return false;
210 
211  // #identifier
212  if (getToken(mToken) && mToken.mType == VLTToken::ID)
213  {
214  object->setID(mToken.mString.c_str());
215  continue;
216  }
217  else
218  return false;
219  }
220  else
221  // ID is a reserved keyword: all the other case combinations are illegal
222  if (mToken.mString == "Id" || mToken.mString == "iD" || mToken.mString == "id")
223  return false;
224  }
225 
226  // non-ID key-values
227  object->value().push_back( VLXStructure::KeyValue() );
228  VLXStructure::KeyValue& name_value = object->value().back();
229 
230  // Key
231  name_value.setKey( mToken.mString.c_str() );
232 
233  // Equals
234  if (!getToken(mToken) || mToken.mType != VLTToken::Equals)
235  return false;
236 
237  // Member value
238  if (getToken(mToken))
239  {
240  name_value.value().setLineNumber( tokenizer()->lineNumber() );
241 
242  // A new <Tag>
243  if (mToken.mType == VLTToken::TagHeader)
244  {
245  if (mLastTag.empty())
246  {
247  mLastTag = mToken.mString;
248  if (!getToken(mToken))
249  return false;
250  }
251  else
252  return false;
253  }
254 
255  // A new { Structure }
256  if (mToken.mType == VLTToken::LeftCurlyBracket)
257  {
258  vl::ref<VLXStructure> object = new VLXStructure;
259  object->setLineNumber( tokenizer()->lineNumber() );
260  name_value.value().setStructure(object.get());
261  if (!parseStructure( object.get() ) )
262  return false;
263  }
264  else
265  // An [ list ]
266  if (mToken.mType == VLTToken::LeftSquareBracket)
267  {
268  vl::ref<VLXList> list = new VLXList;
269  list->setLineNumber( tokenizer()->lineNumber() );
270  name_value.value().setList(list.get());
271  if ( !parseList( list.get() ) )
272  return false;
273  }
274  else
275  // An ( array )
276  if (mToken.mType == VLTToken::LeftRoundBracket)
277  {
278  vl::ref<VLXArray> arr;
279  if ( parseArray( arr ) )
280  name_value.value().setArray(arr.get());
281  else
282  return false;
283  }
284  else
285  // A {< rawtext block >}
286  if (mToken.mType == VLTToken::LeftFancyBracket)
287  {
288  if(!getToken(mToken) || mToken.mType != VLTToken::RawtextBlock)
289  return false;
290  name_value.value().setRawtextBlock( new VLXRawtextBlock(mLastTag.c_str()) );
291  name_value.value().getRawtextBlock()->setValue( mToken.mString.c_str() );
292  // consume the tag
293  mLastTag.clear();
294  if(!getToken(mToken) || mToken.mType != VLTToken::RightFancyBracket)
295  return false;
296  }
297  else
298  // A "string"
299  if (mToken.mType == VLTToken::String)
300  {
301  if (!mLastTag.empty())
302  return false;
303  name_value.value().setString(mToken.mString.c_str());
304  }
305  else
306  // An Identifier
307  if (mToken.mType == VLTToken::Identifier)
308  {
309  if (!mLastTag.empty())
310  return false;
311  name_value.value().setIdentifier(mToken.mString.c_str());
312  }
313  else
314  // An #id
315  if (mToken.mType == VLTToken::ID)
316  {
317  if (!mLastTag.empty())
318  return false;
319  name_value.value().setID(mToken.mString.c_str());
320  }
321  else
322  // A boolean true/false
323  if (mToken.mType == VLTToken::Boolean)
324  {
325  if (!mLastTag.empty())
326  return false;
327  name_value.value().setBool(mToken.mString == "true");
328  }
329  else
330  // An integer
331  if (mToken.mType == VLTToken::Integer)
332  {
333  if (!mLastTag.empty())
334  return false;
335  name_value.value().setInteger( atoll(mToken.mString.c_str()) );
336  }
337  else
338  // A float
339  if (mToken.mType == VLTToken::real)
340  {
341  if (!mLastTag.empty())
342  return false;
343  name_value.value().setReal( atof(mToken.mString.c_str()) );
344  }
345  else
346  return false;
347  }
348  }
349  else
350  return false;
351  }
352  return false;
353  }
354 
355  bool parseList(VLXList* list)
356  {
357  // consume last tag if there was one
358  if (!mLastTag.empty())
359  {
360  list->setTag(mLastTag.c_str());
361  mLastTag.clear();
362  }
363 
364  while(getToken(mToken))
365  {
366  if (mToken.mType == VLTToken::RightSquareBracket)
367  return true;
368  else
369  {
370  VLXValue value;
371  value.setLineNumber( tokenizer()->lineNumber() );
372  switch( mToken.mType )
373  {
374  // <tag>
375  case VLTToken::TagHeader:
376  {
377  if (mLastTag.empty())
378  mLastTag = mToken.mString;
379  else
380  return false;
381  break;
382  }
383 
384  // object
386  {
387  vl::ref<VLXStructure> object = new VLXStructure;
388  object->setLineNumber( tokenizer()->lineNumber() );
389  if ( parseStructure( object.get() ) )
390  {
391  value.setStructure(object.get());
392  list->value().push_back( value );
393  }
394  else
395  return false;
396  break;
397  }
398 
399  // list
401  {
402  vl::ref<VLXList> sub_list = new VLXList;
403  sub_list->setLineNumber( tokenizer()->lineNumber() );
404  if ( parseList( sub_list.get() ) )
405  {
406  value.setList( sub_list.get() );
407  list->value().push_back( value );
408  }
409  else
410  return false;
411  break;
412  }
413 
414  // array
416  {
417  vl::ref<VLXArray> arr;
418  if (parseArray(arr))
419  {
420  value.setArray(arr.get());
421  list->value().push_back(value);
422  }
423  else
424  return false;
425  break;
426  }
427 
428  // string
429  case VLTToken::String:
430  if (!mLastTag.empty())
431  return false;
432  value.setString( mToken.mString.c_str() ); list->value().push_back( value );
433  break;
434 
435  // identifier
437  if (!mLastTag.empty())
438  return false;
439  value.setIdentifier( mToken.mString.c_str() ); list->value().push_back( value );
440  break;
441 
442  // A {< rawtext block >}
444  {
445  if(!getToken(mToken) || mToken.mType != VLTToken::RawtextBlock)
446  return false;
447 
448  value.setRawtextBlock( new VLXRawtextBlock(mLastTag.c_str()) );
449  value.getRawtextBlock()->setValue( mToken.mString.c_str() );
450  list->value().push_back( value );
451  // consume the tag
452  mLastTag.clear();
453 
454  if(!getToken(mToken) || mToken.mType != VLTToken::RightFancyBracket)
455  return false;
456  break;
457  }
458 
459  // ID
460  case VLTToken::ID:
461  if (!mLastTag.empty())
462  return false;
463  value.setID( mToken.mString.c_str() ); list->value().push_back( value );
464  break;
465 
466  // boolean
467  case VLTToken::Boolean:
468  if (!mLastTag.empty())
469  return false;
470  value.setBool( mToken.mString == "true" ); list->value().push_back( value );
471  break;
472 
473  // int
474  case VLTToken::Integer:
475  if (!mLastTag.empty())
476  return false;
477  value.setInteger( atoll(mToken.mString.c_str()) ); list->value().push_back( value );
478  break;
479 
480  // float
481  case VLTToken::real:
482  if (!mLastTag.empty())
483  return false;
484  value.setReal( atof(mToken.mString.c_str()) ); list->value().push_back( value );
485  break;
486 
487  default:
488  return false;
489  }
490  }
491  }
492  return false;
493  }
494 
496  {
497  // consume last tag if there was one
498  struct struct_consume_tag
499  {
500  struct_consume_tag(vl::ref<VLXArray>* p1, std::string* p2): p_arr(p1), p_tag(p2) {}
501 
502  ~struct_consume_tag()
503  {
504  if ((*p_arr).get() && !p_tag->empty())
505  {
506  (*p_arr)->setTag(p_tag->c_str());
507  p_tag->clear();
508  }
509  }
510 
511  vl::ref<VLXArray>* p_arr;
512  std::string* p_tag;
513  } consume_tag(&arr, &mLastTag);
514 
515  if(getToken(mToken))
516  {
517  // (1) from the fist token we decide what kind of array it is going to be
518  // (2) empty arrays default to empty VLXArrayInteger
519 
520  if (mToken.mType == VLTToken::RightRoundBracket)
521  {
522  arr = new VLXArrayInteger;
523  return true;
524  }
525  /*
526  else
527  if (mToken.mType == VLTToken::String)
528  {
529  vl::ref<VLXArrayString> arr_string;
530  arr = arr_string = new VLXArrayString;
531  do
532  arr_string->mValue.push_back(mToken.mString);
533  while(getToken(mToken) && mToken.mType == VLTToken::String);
534  return mToken.mType == VLTToken::RightRoundBracket;
535  }
536  else
537  if (mToken.mType == VLTToken::Identifier)
538  {
539  vl::ref<VLXArrayIdentifier> arr_identifier;
540  arr = arr_identifier = new VLXArrayIdentifier;
541  do
542  arr_identifier->mValue.push_back(mToken.mString);
543  while(getToken(mToken) && mToken.mType == VLTToken::Identifier);
544  return mToken.mType == VLTToken::RightRoundBracket;
545  }
546  else
547  if (mToken.mType == VLTToken::ID)
548  {
549  vl::ref<VLXArrayID> arr_uid;
550  arr = arr_uid = new VLXArrayID;
551  do
552  arr_uid->mValue.push_back(mToken.mString.c_str());
553  while(getToken(mToken) && mToken.mType == VLTToken::ID);
554  return mToken.mType == VLTToken::RightRoundBracket;
555  }
556  */
557  else
558  if (mToken.mType == VLTToken::Integer)
559  {
560  vl::ref<VLXArrayInteger> arr_integer;
561  arr = arr_integer = new VLXArrayInteger;
562  do
563  {
564  switch(mToken.mType)
565  {
566  case VLTToken::Integer: arr_integer->value().push_back( atoll( mToken.mString.c_str() ) ); break;
567  case VLTToken::RightRoundBracket: return true;
568  default:
569  return false;
570  }
571  }
572  while(getToken(mToken));
573  return false;
574  }
575  else
576  if (mToken.mType == VLTToken::real)
577  {
578  vl::ref<VLXArrayReal> arr_floating;
579  arr = arr_floating = new VLXArrayReal;
580  arr_floating->value().reserve(1024);
581  // mic fixme:
582  // READING ARRAYS OF NUMBERS IS THE MAIN HOT SPOT FOR THE VLT PARSER
583  // - we could speed things up by quickly tokenizing and aotf-ing all the numbers here
584  // - we could also use a quicker atof() that works for numbers of the type +1234.1234 using the tokenizer to determine the sub-type
585  // - ideally we should mix the following:
586  // - read big chunks of bytes instead of one by one like now
587  // - merge the quick atof with the tokenizer in one single operation, fall back to standard atof() when complex numbers are detected
588  // - proceed until we find ")"
589  // - we could disallow comments in Arrays to speedup the parsing
590  do
591  {
592  switch(mToken.mType)
593  {
594  case VLTToken::Integer:
595  case VLTToken::real: arr_floating->value().push_back( atof( mToken.mString.c_str() ) ); break;
596  case VLTToken::RightRoundBracket: return true;
597  default:
598  return false;
599  }
600  }
601  while(getToken(mToken));
602  return false;
603  }
604  else
605  return false;
606  }
607 
608  return false;
609  }
610 
611  // for debug only
612  void listTokens()
613  {
614  while(getToken(mToken) && mToken.mType != VLTToken::TOKEN_EOF)
615  {
616  switch(mToken.mType)
617  {
618  case VLTToken::LeftRoundBracket: printf("LeftSquareBracket (\n"); break;
619  case VLTToken::RightRoundBracket: printf("RightSquareBracket )\n"); break;
620  case VLTToken::LeftSquareBracket: printf("LeftSquareBracket [\n"); break;
621  case VLTToken::RightSquareBracket: printf("RightSquareBracket ]\n"); break;
622  case VLTToken::LeftCurlyBracket: printf("LeftCurlyBracket {\n"); break;
623  case VLTToken::RightCurlyBracket: printf("RightCurlyBracket } \n"); break;
624  case VLTToken::LeftFancyBracket: printf("LeftFancyBracket >}\n"); break;
625  case VLTToken::RightFancyBracket: printf("RightFancyBracket {< \n"); break;
626  case VLTToken::Equals: printf("Equals =\n"); break;
627  case VLTToken::String: printf("String = %s\n", mToken.mString.c_str()); break;
628  case VLTToken::ID: printf("ID = %s\n", mToken.mString.c_str()); break;
629  case VLTToken::Identifier: printf("Identifier = %s\n", mToken.mString.c_str()); break;
630  case VLTToken::RawtextBlock: printf("RawtextBlock = %s\n", mToken.mString.c_str()); break;
631  case VLTToken::real: printf("real = %s\n", mToken.mString.c_str()); break;
632  case VLTToken::Integer: printf("Integer = %s\n", mToken.mString.c_str()); break;
633  case VLTToken::TagHeader: printf("TagHeader = %s\n", mToken.mString.c_str()); break;
634  default:
635  break;
636  }
637  }
638  if (mToken.mType != VLTToken::TOKEN_EOF)
639  {
640  printf("Line %d: syntax error : '%s'.\n", mTokenizer->lineNumber(), mToken.mString.c_str());
641  }
642  }
643 
644  VLTTokenizer* tokenizer() { return mTokenizer.get(); }
645 
646  const VLTTokenizer* tokenizer() const { return mTokenizer.get(); }
647 
648  private:
649  std::string mLastTag;
650  vl::ref<VLTTokenizer> mTokenizer;
651  VLTToken mToken;
652  };
653 }
654 
655 #ifdef _MSC_VER
656  #undef atoll
657 #endif
658 
659 #endif
double setReal(double val)
Definition: Value.hpp:499
const VLTTokenizer * tokenizer() const
Definition: ParserVLT.hpp:646
void setKey(const char *key)
Definition: Value.hpp:592
VLXRawtextBlock * getRawtextBlock()
Definition: Value.hpp:418
Wrapper for all VLX value types.
Definition: Value.hpp:240
const T * get() const
Definition: Object.hpp:128
An abstract class representing a file.
Definition: VirtualFile.hpp:60
bool getToken(VLTToken &token)
Definition: ParserVLT.hpp:58
A simple String formatting class.
Definition: Say.hpp:124
VLX_EXPORT VLXList * setList(VLXList *)
Definition: Value.cpp:144
void parseMetadata()
Moves the <Metadata> key/value pairs in the Metadata map for quick and easy access and removes the <M...
Definition: Parser.hpp:63
vlX::VLXValue & value()
Definition: Value.hpp:594
void setValue(const char *value)
Definition: Value.hpp:88
Key/value pair used by VLXStructure.
Definition: Value.hpp:582
long long setInteger(long long val)
Definition: Value.hpp:488
unsigned short mVersion
Definition: Parser.hpp:98
VLX_EXPORT VLXRawtextBlock * setRawtextBlock(VLXRawtextBlock *)
Definition: Value.cpp:156
void setLineNumber(int line)
Definition: Value.hpp:521
Parses a VLT file translating it into a VLX hierarchy.
Definition: ParserVLT.hpp:47
void setTag(const char *tag)
Definition: Value.hpp:61
static void error(const String &message)
Use this function to provide information about run-time errors: file not found, out of memory...
Definition: Log.cpp:165
An array of 64 bits floating point numbers, can also have a tag.
Definition: Value.hpp:144
bool parseArray(vl::ref< VLXArray > &arr)
Definition: ParserVLT.hpp:495
std::string mString
std::string mEncoding
Definition: Parser.hpp:97
#define VL_INSTRUMENT_CLASS(ClassName, BaseClass)
Definition: TypeInfo.hpp:122
A token of information as defined by VLT specification.
std::vector< vl::ref< VLXStructure > > mStructures
Definition: Parser.hpp:99
const std::string & setIdentifier(const char *str)
Definition: Value.hpp:464
std::vector< VLXValue > & value()
Definition: Value.hpp:652
const std::string & setString(const char *str)
Definition: Value.hpp:452
bool parseHeader()
Definition: ParserVLT.hpp:60
A list of key/VLXValue pairs, can also have a tag.
Definition: Value.hpp:541
void listTokens()
Definition: ParserVLT.hpp:612
A simple sequence of VLXValue objects, can also have a tag.
Definition: Value.hpp:634
#define VL_SERIALIZER_VERSION
Definition: Defines.hpp:35
VLX_EXPORT VLXStructure * setStructure(VLXStructure *)
Definition: Value.cpp:134
bool setBool(bool val)
Definition: Value.hpp:510
void setLineNumber(int line)
Definition: Value.hpp:57
VLX_EXPORT VLXArray * setArray(VLXArray *)
Definition: Value.cpp:225
bool parseList(VLXList *list)
Definition: ParserVLT.hpp:355
An array of 64 bits integers, can also have a tag.
Definition: Value.hpp:133
A block of raw text.
Definition: Value.hpp:71
Tokenizer used to parse VLT files.
VLTTokenizer * tokenizer()
Definition: ParserVLT.hpp:644
const std::string & setID(const char *str)
Definition: Value.hpp:476
const std::string & uid() const
Definition: Value.hpp:605
bool parseStructure(VLXStructure *object)
Definition: ParserVLT.hpp:177
Base class for VLX parsers.
Definition: Parser.hpp:41
#define VL_CHECK(expr)
Definition: checks.hpp:73
std::map< std::string, VLXValue > mMetadata
Definition: Parser.hpp:100