Logo ROOT   6.14/05
Reference Guide
RConversionRuleParser.cxx
Go to the documentation of this file.
1 // @(#)root/core:$Id$
2 // author: Lukasz Janyst <ljanyst@cern.ch>
3 
5 #include "TSchemaRuleProcessor.h"
6 
7 #include <algorithm>
8 #include <iostream>
9 #include <map>
10 #include <sstream>
11 #include <string>
12 #include <utility>
13 #include <vector>
14 
15 namespace {
16  static void RemoveEscapeSequences(std::string& rawString)
17  {
18  const std::vector<std::pair<std::string, std::string>> subPairs { {"\\\\","\\"},
19  {"\\\"","\""},
20  {"\\\'","\'"}};
21  size_t start_pos = 0;
22  for (auto const & subPair : subPairs){
23  start_pos = 0;
24  auto from = subPair.first;
25  auto to = subPair.second;
26  while((start_pos = rawString.find(from, start_pos)) != std::string::npos) {
27  rawString.replace(start_pos, from.length(), to);
28  start_pos += to.length();
29  }
30  }
31  }
32 }
33 
34 namespace ROOT
35 {
36  using namespace Internal;
37 
38  typedef std::list<std::pair<ROOT::Internal::TSchemaType,std::string> > SourceTypeList_t;
39 
40  //--------------------------------------------------------------------------
41  // Allocate global variables
42  /////////////////////////////////////////////////////////////////////////////
43 
46 
47  static Bool_t ValidateRule( const std::map<std::string, std::string>& rule, std::string &error_string );
48 
49  static std::string::size_type FindEndSymbol(std::string &command)
50  {
51  // Find the end of a symbol.
52 
53  if (command.length() == 0) return std::string::npos;
54  std::string::size_type cursor;
55  unsigned int level = 0;
56  for (cursor = 0 ; cursor < command.length(); ++cursor)
57  {
58  switch( command[cursor] ) {
59  case ' ':
60  case '\t':
61  case '\r':
62  case '=': if (level==0) {
63  std::string::size_type sub_cursor = cursor;
64  while( isspace(command[sub_cursor]) ) {
65  ++sub_cursor;
66  }
67  if ( command[sub_cursor] == '=' ) {
68  return sub_cursor;
69  } else {
70  return cursor;
71  }
72  } else {
73  break;
74  }
75  case '<': ++level; break;
76  case '>': if (level==0) { return std::string::npos; }
77  --level; break;
78  default: {
79  // nothing to do
80  }
81  };
82  }
83  return cursor;
84  }
85 
86 
87  /////////////////////////////////////////////////////////////////////////////
88  /// Parse the schema rule as specified in the LinkDef file
89 
90  Bool_t ParseRule( std::string command,
92  std::string &error_string )
93  {
94  std::string::size_type l=0;
95  command = TSchemaRuleProcessor::Trim( command );
96 
97  //-----------------------------------------------------------------------
98  // Remove the semicolon from the end if declared
99  //////////////////////////////////////////////////////////////////////////
100 
101  if( command[command.size()-1] == ';' )
102  command = command.substr( 0, command.size()-1 );
103 
104  //-----------------------------------------------------------------------
105  // If the first symbol does not end is not followed by equal then it
106  // defaults to being the sourceClass.
107  //////////////////////////////////////////////////////////////////////////
108 
109  {
110  std::string::size_type endsymbol = FindEndSymbol( command );
111  if ( endsymbol == command.length() || command[endsymbol] == ' ' || command[endsymbol] == '\t' ) {
112 
113 // std::string::size_type space_pos = command.find( ' ' );
114 // std::string::size_type equal_pos = command.find( '=' );
115 // if ( space_pos < equal_pos) {
116  std::string value = TSchemaRuleProcessor::Trim( command.substr( 0, endsymbol ) );
117  result["sourceClass"] = value;
118  result["targetClass"] = value;
119  if (endsymbol < command.length()) {
120  command = TSchemaRuleProcessor::Trim( command.substr( endsymbol+1 ) );
121  } else {
122  command.clear();
123  }
124 
125  //-----------------------------------------------------------------------
126  // If the first symbol is the targetClass then the 2nd symbol can be
127  // the source data member name.
128  //-----------------------------------------------------------------------
129 // space_pos = command.find( ' ' );
130 // equal_pos = command.find( '=' );
131 // if ( space_pos < equal_pos ) {
132  endsymbol = FindEndSymbol( command );
133  if ( endsymbol == command.length() || command[endsymbol] == ' ' || command[endsymbol] == '\t' ) {
134  std::string membervalue = TSchemaRuleProcessor::Trim( command.substr( 0, endsymbol ) );
135  result["source"] = membervalue;
136  result["target"] = membervalue;
137  command = TSchemaRuleProcessor::Trim( command.substr( endsymbol+1 ) );
138  }
139  }
140  }
141 
142  //-----------------------------------------------------------------------
143  // Process the input until there are no characters left
144  //////////////////////////////////////////////////////////////////////////
145 
146  while( !command.empty() ) {
147  //--------------------------------------------------------------------
148  // Find key token
149  ///////////////////////////////////////////////////////////////////////
150 
151  std::string::size_type pos = command.find( '=' );
152 
153  //--------------------------------------------------------------------
154  // No equality sign found - no keys left
155  ///////////////////////////////////////////////////////////////////////
156 
157  if( pos == std::string::npos ) {
158  error_string = "Parsing error, no key found!";
159  return false;
160  }
161 
162  //--------------------------------------------------------------------
163  // The key was found - process the arguments
164  ///////////////////////////////////////////////////////////////////////
165 
166  std::string key = TSchemaRuleProcessor::Trim( command.substr( 0, pos ) );
167  command = TSchemaRuleProcessor::Trim( command.substr( pos+1 ) );
168 
169  //--------------------------------------------------------------------
170  // Nothing left to be processed
171  ///////////////////////////////////////////////////////////////////////
172 
173  if( command.size() < 1 ) {
174  error_string = "Parsing error, wrond or no value specified for key: " + key;
175  return false;
176  }
177 
178  Bool_t hasquote = command[0] == '"';
179 
180  //--------------------------------------------------------------------
181  // Processing code tag: "{ code }"
182  ///////////////////////////////////////////////////////////////////////
183 
184  if( key == "code" ) {
185  if( command[1] != '{' ) {
186  error_string = "Parsing error while processing key: code\n";
187  error_string += "Expected \"{ at the beginning of the value.";
188  return false;
189  }
190  l = command.find( "}\"" );
191  if( l == std::string::npos ) {
192  error_string = "Parsing error while processing key: \"" + key + "\"\n";
193  error_string += "Expected }\" at the end of the value.";
194  return false;
195  }
196  auto rawCode = command.substr( 2, l-2 );
197  RemoveEscapeSequences(rawCode);
198  result[key] = rawCode;
199  ++l;
200  }
201  //--------------------------------------------------------------------
202  // Processing normal tag: "value"
203  ///////////////////////////////////////////////////////////////////////
204 
205  else {
206  if( hasquote) {
207  l = command.find( '"', 1 );
208  if (l == std::string::npos ) {
209  error_string = "\nParsing error while processing key: \"" + key + "\"\n";
210  error_string += "Expected \" at the end of the value.";
211  return false;
212  }
213  result[key] = command.substr( 1, l-1 );
214  } else {
215  l = command.find(' ', 1);
216  if (l == std::string::npos) l = command.size();
217  result[key] = command.substr( 0, l );
218  }
219  }
220 
221  //--------------------------------------------------------------------
222  // Everything went ok
223  ///////////////////////////////////////////////////////////////////////
224 
225  if( l == command.size() )
226  break;
227  command = command.substr( l+1 );
228  }
229  std::map<std::string, std::string>::const_iterator it1;
230  it1 = result.find("oldtype");
231  if ( it1 != result.end() ) {
232  std::map<std::string, std::string>::const_iterator it2;
233  it2 = result.find("source");
234  if ( it2 != result.end() ) {
235  result["source"] = it1->second + " " + it2->second;
236  }
237  }
238  if ( result.find("version") == result.end() && result.find("checksum") == result.end() ) {
239  result["version"] = "[1-]";
240  }
241 
242  //------------------------------------------------------------------------
243  // "include" tag. Replace ";" with "," for backwards compatibility with
244  // ROOT5
245  //////////////////////////////////////////////////////////////////////////
246 
247  auto const includeKeyName = "include";
248  auto includeTag = result.find(includeKeyName);
249  if (includeTag != result.end()){
250  auto & includeTagValue = includeTag->second;
251  std::replace_if (includeTagValue.begin(),
252  includeTagValue.end(),
253  [](char c){ return c == ';';},
254  ',');
255  result[includeKeyName] = includeTagValue;
256  }
257 
258  return ValidateRule( result, error_string);
259  }
260 
261  /////////////////////////////////////////////////////////////////////////////
262  /// Validate if the user specified rules are correct
263 
264  static Bool_t ValidateRule( const std::map<std::string, std::string>& rule, std::string &error_string )
265  {
266  //-----------------------------------------------------------------------
267  // Check if we have target class name
268  //////////////////////////////////////////////////////////////////////////
269 
270  std::map<std::string, std::string>::const_iterator it1, it2;
271  std::list<std::string> lst;
272  std::list<std::string>::iterator lsIt;
273 
274  it1 = rule.find( "targetClass" );
275  if( it1 == rule.end() ) {
276  error_string = "You always have to specify the targetClass ";
277  error_string += "when specyfying an IO rule";
278  return false;
279  }
280 
281  std::string className = TSchemaRuleProcessor::Trim( it1->second );
282  std::string warning = "IO rule for class " + className;
283 
284  //-----------------------------------------------------------------------
285  // Check if we have the source tag
286  //////////////////////////////////////////////////////////////////////////
287 
288  it1 = rule.find( "sourceClass" );
289  if( it1 == rule.end())
290  {
291  error_string = warning + " - sourceClass parameter is missing";
292  return false;
293  }
294 
295  //-----------------------------------------------------------------------
296  // Check if we have either version or checksum specified
297  //////////////////////////////////////////////////////////////////////////
298 
299  it1 = rule.find( "version" );
300  it2 = rule.find( "checksum" );
301  if( it1 == rule.end() && it2 == rule.end() ) {
302  error_string = warning + " - you need to specify either version or ";
303  error_string += "checksum";
304  return false;
305  }
306 
307  //-----------------------------------------------------------------------
308  // Check if the checksum has been set to right value
309  //////////////////////////////////////////////////////////////////////////
310 
311  if( it2 != rule.end() ) {
312  if( it2->second.size() < 2 || it2->second[0] != '[' ||
313  it2->second[it2->second.size()-1] != ']' ) {
314  error_string = warning + " - a comma separated list of ints";
315  error_string += " enclosed in square brackets expected";
316  error_string += " as a value of checksum parameter";
317  return false;
318  }
319 
320  TSchemaRuleProcessor::SplitList( it2->second.substr( 1, it2->second.size()-2 ),
321  lst );
322  if( lst.empty() ) {
323  error_string += warning + " - the list of checksums is empty\n";
324  }
325 
326  for( lsIt = lst.begin(); lsIt != lst.end(); ++lsIt )
327  if( !TSchemaRuleProcessor::IsANumber( *lsIt ) ) {
328  error_string = warning + " - " + *lsIt + " is not a valid value";
329  error_string += " of checksum parameter - an integer expected";
330  return false;
331  }
332  }
333 
334  //-----------------------------------------------------------------------
335  // Check if the version is correct
336  //////////////////////////////////////////////////////////////////////////
337 
338  std::pair<Int_t, Int_t> ver;
339  if( it1 != rule.end() ) {
340  if( it1->second.size() < 2 || it1->second[0] != '[' ||
341  it1->second[it1->second.size()-1] != ']' ) {
342  error_string = warning + " - a comma separated list of version specifiers ";
343  error_string += "enclosed in square brackets expected";
344  error_string += "as a value of version parameter";
345  return false;
346  }
347 
348  TSchemaRuleProcessor::SplitList( it1->second.substr( 1, it1->second.size()-2 ),
349  lst );
350  if( lst.empty() ) {
351  error_string = warning + " - the list of versions is empty";
352  }
353 
354  for( lsIt = lst.begin(); lsIt != lst.end(); ++lsIt )
355  if( !TSchemaRuleProcessor::ProcessVersion( *lsIt, ver ) ) {
356  error_string = warning + " - " + *lsIt + " is not a valid value";
357  error_string += " of version parameter";
358  return false;
359  }
360  }
361 
362  //-----------------------------------------------------------------------
363  // Check if we're dealing with renameing declaration - sourceClass,
364  // targetClass and either version or checksum required
365  //////////////////////////////////////////////////////////////////////////
366 
367  if( rule.size() == 3 || (rule.size() == 4 && it1 != rule.end() && it2 != rule.end()) )
368  return true;
369 
370  //-----------------------------------------------------------------------
371  // Check if we have all the keys we need
372  //-----------------------------------------------------------------------
373  std::string keys[] = {"target", "source"};
374  for( int i = 0; i < 2; ++i ) {
375  it1 = rule.find( keys[i] );
376  if( it1 == rule.end() ) {
377  error_string = warning + " - required parameter is missing: ";
378  error_string += keys[i];
379  return false;
380  }
381  }
382 
383  //-----------------------------------------------------------------------
384  // Check the source contains proper declarations.
385  //////////////////////////////////////////////////////////////////////////
386 
387  it1 = rule.find("code");
388  if (it1 != rule.end() && it1->second != "") {
389  SourceTypeList_t source;
390  TSchemaRuleProcessor::SplitDeclaration( rule.find("source")->second, source );
391  SourceTypeList_t::const_iterator it;
392  for( it = source.begin(); it != source.end(); ++it ) {
393  if ( ( it->first.fType == "" && it->second != "") ) {
394  error_string = warning + " - type required when listing a rule's source: ";
395  error_string += "source=\""+ rule.find("source")->second +"\"";
396  return false;
397  }
398  }
399  }
400 
401  //-----------------------------------------------------------------------
402  // Check if we have an embed parameter and if so if it has been set to
403  // the right value
404  //////////////////////////////////////////////////////////////////////////
405 
406  it1 = rule.find( "embed" );
407  if( it1 != rule.end() ) {
408  std::string emValue = TSchemaRuleProcessor::Trim( it1->second );
409  if( emValue != "true" && emValue != "false" ) {
410  error_string = warning + " - true or false expected as a value ";
411  error_string += "of embed parameter";
412  return false;
413  }
414  }
415 
416  //-----------------------------------------------------------------------
417  // Check if the include list is not empty
418  //////////////////////////////////////////////////////////////////////////
419 
420  it1 = rule.find( "include" );
421  if( it1 != rule.end() ) {
422  if( it1->second.empty() ) {
423  error_string = warning + " - the include list is empty";
424  return false;
425  }
426  }
427 
428  return true;
429  }
430 
431  /////////////////////////////////////////////////////////////////////////////
432  /// Check if given rule contains references to valid data members
433 
435  MembersTypeMap_t& members,
436  std::string& error_string)
437  {
438  std::list<std::string> mem;
439  std::list<std::string>::iterator it;
440  // MembersMap_t::iterator rIt;
441 
442  TSchemaRuleProcessor::SplitList( rule["target"], mem );
443 
444  //-----------------------------------------------------------------------
445  // Loop over the data members
446  //////////////////////////////////////////////////////////////////////////
447 
448  for( it = mem.begin(); it != mem.end(); ++it ) {
449  if( members.find( *it ) == members.end() ) {
450  error_string += "IO rule for class " + rule["targetClass"]
451  + " data member: " + *it + " was specified as a "
452  "target in the rule but doesn't seem to appear in "
453  "target class\n";
454  return false;
455  }
456  }
457  return true;
458  }
459 
460  /////////////////////////////////////////////////////////////////////////////
461  /// Write down the sources
462 
463  static void WriteAutoVariables( const std::list<std::string>& target,
464  const SourceTypeList_t& source,
465  MembersTypeMap_t& members,
466  std::string& className, std::string& mappedName,
467  std::ostream& output )
468  {
469  if (!source.empty()) {
470  Bool_t start = true;
471  SourceTypeList_t::const_iterator it;
472 
473  //--------------------------------------------------------------------
474  // Write IDs and check if we should generate the onfile structure
475  // this is done if the type was declared
476  ///////////////////////////////////////////////////////////////////////
477 
478  Bool_t generateOnFile = false;
479  output << "#if 0" << std::endl; // this is to be removed later
480  for( it = source.begin(); it != source.end(); ++it ) {
481  output << " ";
482  output << "static Int_t id_" << it->second << " = oldObj->GetId(";
483  output << "\"" << it->second << "\");" << std::endl;
484 
485  if( it->first.fType != "" )
486  generateOnFile = true;
487  }
488  output << "#endif" << std::endl; // this is to be removed later
489 
490  //--------------------------------------------------------------------
491  // Declare the on-file structure - if needed
492  ///////////////////////////////////////////////////////////////////////
493 
494  if( generateOnFile ) {
495  std::string onfileStructName = mappedName + "_Onfile";
496  output << " ";
497  output << "struct " << onfileStructName << " {\n";
498 
499  //-----------------------------------------------------------------
500  // List the data members with non-empty type declarations
501  ////////////////////////////////////////////////////////////////////
502  /// fprintf(stderr, "Seeing %s %s %s\n", it->first.fType.c_str(), it->second.c_str(), it->first.fDimensions.c_str());
503 
504  for( it = source.begin(); it != source.end(); ++it ) {
505  if( it->first.fType.size() ) {
506  if ( it->first.fDimensions.size() ) {
507  output << " typedef " << it->first.fType;
508  output << " onfile_" << it->second << "_t" << it->first.fDimensions << ";\n";
509  output << " ";
510  output << "onfile_" << it->second << "_t &" << it->second << ";\n";
511 
512  } else {
513  output << " ";
514  output << it->first.fType << " &" << it->second << ";\n";
515  }
516  }
517  }
518 
519  //-----------------------------------------------------------------
520  // Generate the constructor
521  ////////////////////////////////////////////////////////////////////
522 
523  output << " " << onfileStructName << "(";
524  for( start = true, it = source.begin(); it != source.end(); ++it ) {
525  if( it->first.fType.size() == 0)
526  continue;
527 
528  if( !start )
529  output << ", ";
530  else
531  start = false;
532 
533  if (it->first.fDimensions.size() == 0) {
534  output << it->first.fType << " &onfile_" << it->second;
535  } else {
536  output << " onfile_" << it->second << "_t" << " &onfile_" << it->second;
537  }
538  }
539  output << " ): ";
540 
541  //-----------------------------------------------------------------
542  // Generate the constructor's initializer list
543  ////////////////////////////////////////////////////////////////////
544 
545  for( start = true, it = source.begin(); it != source.end(); ++it ) {
546  if( it->first.fType == "" )
547  continue;
548 
549  if( !start )
550  output << ", ";
551  else
552  start = false;
553 
554  output << it->second << "(onfile_" << it->second << ")";
555  }
556  output << " {}\n";
557  output << " " << "};\n";
558 
559  //-----------------------------------------------------------------
560  // Initialize the structure - to be changed later
561  ////////////////////////////////////////////////////////////////////
562 
563  for( it = source.begin(); it != source.end(); ++it ) {
564  output << " ";
565  output << "static Long_t offset_Onfile_" << mappedName;
566  output << "_" << it->second << " = oldObj->GetClass()->GetDataMemberOffset(\"";
567  output << it->second << "\");\n";
568  }
569  output << " " << "char *onfile_add = (char*)oldObj->GetObject();\n";
570  output << " " << mappedName << "_Onfile onfile(\n";
571 
572  for( start = true, it = source.begin(); it != source.end(); ++it ) {
573  if( it->first.fType == "" )
574  continue;
575 
576  if( !start )
577  output << ",\n";
578 
579  else
580  start = false;
581 
582  output << " ";
583  output << "*(";
584  if (it->first.fDimensions.size() == 0) {
585  output << it->first.fType;
586  } else {
587  output << mappedName << "_Onfile::onfile_" << it->second << "_t";
588  }
589  output << "*)(onfile_add+offset_Onfile_";
590  output << mappedName << "_" << it->second << ")";
591  }
592  output << " );\n\n";
593  }
594  }
595 
596  //-----------------------------------------------------------------------
597  // Write down the targets
598  //////////////////////////////////////////////////////////////////////////
599 
600  if( !target.empty() ) {
601  output << " static TClassRef cls(\"";
602  output << className << "\");" << std::endl;
603 
604  std::list<std::string>::const_iterator it;
605  for( it = target.begin(); it != target.end(); ++it ) {
606  Internal::TSchemaType memData = members[*it];
607  output << " static Long_t offset_" << *it << " = ";
608  output << "cls->GetDataMemberOffset(\"" << *it << "\");";
609  output << std::endl;
610  if (memData.fDimensions.size()) {
611  output << " typedef " << memData.fType << " " << *it << "_t" << memData.fDimensions << ";" << std::endl;
612  output << " " << *it << "_t& " << *it << " = ";
613  output << "*(" << *it << "_t *)(target+offset_" << *it;
614  output << ");" << std::endl;
615  } else {
616  output << " " << memData.fType << "& " << *it << " = ";
617  output << "*(" << memData.fType << "*)(target+offset_" << *it;
618  output << ");" << std::endl;
619  }
620  }
621  }
622  }
623 
624  /////////////////////////////////////////////////////////////////////////////
625  /// Write the conversion function for Read rule, the function name
626  /// is being written to rule["funcname"]
627 
628  void WriteReadRuleFunc( SchemaRuleMap_t& rule, int index,
629  std::string& mappedName, MembersTypeMap_t& members,
630  std::ostream& output )
631  {
632  std::string className = rule["targetClass"];
633 
634  //-----------------------------------------------------------------------
635  // Create the function name
636  //////////////////////////////////////////////////////////////////////////
637 
638  std::ostringstream func;
639  func << "read_" << mappedName << "_" << index;
640  rule["funcname"] = func.str();
641 
642  //-----------------------------------------------------------------------
643  // Write the header
644  //////////////////////////////////////////////////////////////////////////
645 
646  output << " static void " << func.str();
647  output << "( char* target, TVirtualObject *oldObj )" << std::endl;
648  output << " {" << std::endl;
649  output << " //--- Automatically generated variables ---" << std::endl;
650 
651  //-----------------------------------------------------------------------
652  // Write the automatically generated variables
653  //////////////////////////////////////////////////////////////////////////
654 
655  std::list<std::pair<ROOT::Internal::TSchemaType,std::string> > source;
656  std::list<std::string> target;
657  TSchemaRuleProcessor::SplitDeclaration( rule["source"], source );
658  TSchemaRuleProcessor::SplitList( rule["target"], target );
659 
660  WriteAutoVariables( target, source, members, className, mappedName, output );
661  output << " " << className << "* newObj = (" << className;
662  output << "*)target;" << std::endl;
663  output << " // Supress warning message.\n";
664  output << " " << "if (oldObj) {}\n\n";
665  output << " " << "if (newObj) {}\n\n";
666 
667  //-----------------------------------------------------------------------
668  // Write the user's code
669  //////////////////////////////////////////////////////////////////////////
670 
671  output << " //--- User's code ---" << std::endl;
672  output << " " << rule["code"] << std::endl;
673  output << " }" << std::endl;
674  }
675 
676 
677  /////////////////////////////////////////////////////////////////////////////
678  /// Write the conversion function for ReadRaw rule, the function name
679  /// is being written to rule["funcname"]
680 
681  void WriteReadRawRuleFunc( SchemaRuleMap_t& rule, int index,
682  std::string& mappedName, MembersTypeMap_t& members,
683  std::ostream& output )
684  {
685  std::string className = rule["targetClass"];
686 
687  //-----------------------------------------------------------------------
688  // Create the function name
689  //////////////////////////////////////////////////////////////////////////
690 
691  std::ostringstream func;
692  func << "readraw_" << mappedName << "_" << index;
693  rule["funcname"] = func.str();
694 
695  //-----------------------------------------------------------------------
696  // Write the header
697  //////////////////////////////////////////////////////////////////////////
698 
699  output << " static void " << func.str();
700  output << "( char* target, TBuffer &b )" << std::endl;
701  output << " {" << std::endl;
702  output << "#if 0" << std::endl;
703  output << " //--- Automatically generated variables ---" << std::endl;
704 
705  //-----------------------------------------------------------------------
706  // Write the automatically generated variables
707  //////////////////////////////////////////////////////////////////////////
708 
709  std::list<std::pair<ROOT::Internal::TSchemaType,std::string> > source;
710  std::list<std::string> target;
711  TSchemaRuleProcessor::SplitList( rule["target"], target );
712 
713  WriteAutoVariables( target, source, members, className, mappedName, output );
714  output << " " << className << "* newObj = (" << className;
715  output << "*)target;" << std::endl << std::endl;
716 
717  //-----------------------------------------------------------------------
718  // Write the user's code
719  //////////////////////////////////////////////////////////////////////////
720 
721  output << " //--- User's code ---" << std::endl;
722  output << rule["code"] << std::endl;
723  output << "#endif" << std::endl;
724  output << " }" << std::endl;
725  }
726 
727  /////////////////////////////////////////////////////////////////////////////
728  /// Replace all accurances of given string with other string
729 
730  static void StrReplace( std::string& proc, const std::string& pat,
731  const std::string& tr )
732  {
733  std::string::size_type it = 0;
734  std::string::size_type s = pat.size();
735  std::string::size_type tr_len= tr.size();
736 
737  if( s == 0 ) return;
738 
739  while( 1 ) {
740  it = proc.find( pat, it );
741  if( it == std::string::npos )
742  break;
743 
744  proc.replace( it, s, tr );
745  it += tr_len;
746  }
747  }
748 
749  /////////////////////////////////////////////////////////////////////////////
750  /// Write schema rules
751 
752  void WriteSchemaList( std::list<SchemaRuleMap_t>& rules,
753  const std::string& listName, std::ostream& output )
754  {
755  std::list<SchemaRuleMap_t>::iterator it;
756  int i = 0;
757 
758  //-----------------------------------------------------------------------
759  // Loop over the rules
760  //////////////////////////////////////////////////////////////////////////
761 
762  for( it = rules.begin(); it != rules.end(); ++it ) {
763  output << " rule = &" << listName << "[" << i++;
764  output << "];" << std::endl;
765 
766  //--------------------------------------------------------------------
767  // Write down the mandatory fields
768  ///////////////////////////////////////////////////////////////////////
769 
770  output << " rule->fSourceClass = \"" << (*it)["sourceClass"];
771  output << "\";" << std::endl;
772 
773  if( it->find( "target" ) != it->end() ) {
774  output << " rule->fTarget = \"" << (*it)["target"];
775  output << "\";" << std::endl;
776  }
777 
778  if( it->find( "source" ) != it->end() ) {
779  output << " rule->fSource = \"" << (*it)["source"];
780  output << "\";" << std::endl;
781  }
782 
783  //--------------------------------------------------------------------
784  // Deal with non mandatory keys
785  ///////////////////////////////////////////////////////////////////////
786 
787  if( it->find( "funcname" ) != it->end() ) {
788  std::string code = (*it)["code"];
789  StrReplace( code, "\n", "\\n" );
790  StrReplace( code, "\"", "\\\"");
791 
792  output << " rule->fFunctionPtr = (void *)TFunc2void( ";
793  output << (*it)["funcname"] << ");" << std::endl;
794  output << " rule->fCode = \"" << code;
795  output << "\";" << std::endl;
796  }
797 
798  if( it->find( "version" ) != it->end() ) {
799  output << " rule->fVersion = \"" << (*it)["version"];
800  output << "\";" << std::endl;
801  }
802 
803  if( it->find( "checksum" ) != it->end() ) {
804  output << " rule->fChecksum = \"" << (*it)["checksum"];
805  output << "\";" << std::endl;
806  }
807 
808  if( it->find( "embed" ) != it->end() ) {
809  output << " rule->fEmbed = " << (*it)["embed"];
810  output << ";" << std::endl;
811  }
812 
813  if( it->find( "include" ) != it->end() ) {
814  output << " rule->fInclude = \"" << (*it)["include"];
815  output << "\";" << std::endl;
816  }
817 
818  if( it->find( "attributes" ) != it->end() ) {
819  output << " rule->fAttributes = \"" << (*it)["attributes"];
820  output << "\";" << std::endl;
821  }
822  }
823  }
824 
825  /////////////////////////////////////////////////////////////////////////////
826  /// Get the list of includes specified in the shema rules
827 
828  void GetRuleIncludes( std::list<std::string> &result )
829  {
830  std::list<std::string> tmp;
831  std::list<SchemaRuleMap_t>::iterator rule;
832  SchemaRuleMap_t::iterator attr;
833  SchemaRuleClassMap_t::iterator it;
834 
835  //-----------------------------------------------------------------------
836  // Processing read rules
837  //////////////////////////////////////////////////////////////////////////
838 
839  for( it = gReadRules.begin(); it != gReadRules.end(); ++it ) {
840  for( rule = it->second.begin(); rule != it->second.end(); ++rule ) {
841  attr = rule->find( "include" );
842  if( attr == rule->end() ) continue;
843  TSchemaRuleProcessor::SplitList( attr->second, tmp );
844  result.splice( result.begin(), tmp, tmp.begin(), tmp.end() );
845  }
846  }
847 
848  //-----------------------------------------------------------------------
849  // Processing read raw rules
850  //////////////////////////////////////////////////////////////////////////
851 
852  for( it = gReadRawRules.begin(); it != gReadRawRules.end(); ++it ) {
853  for( rule = it->second.begin(); rule != it->second.end(); ++rule ) {
854  attr = rule->find( "include" );
855  if( attr == rule->end() ) continue;
856  TSchemaRuleProcessor::SplitList( attr->second, tmp );
857  result.splice( result.begin(), tmp, tmp.begin(), tmp.end() );
858  }
859  }
860 
861  //-----------------------------------------------------------------------
862  // Removing duplicates
863  //////////////////////////////////////////////////////////////////////////
864 
865  result.sort();
866  result.unique();
867  }
868 
869  /////////////////////////////////////////////////////////////////////////////
870  /// I am being called when a read pragma is encountered
871 
872  void ProcessReadPragma( const char* args, std::string& error_string )
873  {
874  //-----------------------------------------------------------------------
875  // Parse the rule and check it's validity
876  //////////////////////////////////////////////////////////////////////////
877 
878  std::map<std::string, std::string> rule;
879  if( !ParseRule( args, rule, error_string ) ) {
880  error_string += "\nThe following rule has been omitted:\n read ";
881  error_string += args;
882  error_string += "\n";
883  return;
884  }
885 
886  //-----------------------------------------------------------------------
887  // Append the rule to the list
888  //////////////////////////////////////////////////////////////////////////
889 
890  SchemaRuleClassMap_t::iterator it;
891  std::string targetClass = rule["targetClass"];
892  it = gReadRules.find( targetClass );
893  if( it == gReadRules.end() ) {
894  std::list<SchemaRuleMap_t> lst;
895  lst.push_back( rule );
896  gReadRules[targetClass] = lst;
897  }
898  else
899  it->second.push_back( rule );
900  }
901 
902  /////////////////////////////////////////////////////////////////////////////
903  /// I am being called then a readraw pragma is encountered
904 
905  void ProcessReadRawPragma( const char* args, std::string& error_string)
906  {
907  //-----------------------------------------------------------------------
908  // Parse the rule and check it's validity
909  //////////////////////////////////////////////////////////////////////////
910 
911  std::map<std::string, std::string> rule;
912  if( !ParseRule( args, rule, error_string ) ) {
913  error_string += "\nThe following rule has been omitted:\n readraw ";
914  error_string += args;
915  error_string += "\n";
916  return;
917  }
918 
919  //-----------------------------------------------------------------------
920  // Append the rule to the list
921  //////////////////////////////////////////////////////////////////////////
922 
923  SchemaRuleClassMap_t::iterator it;
924  std::string targetClass = rule["targetClass"];
925  it = gReadRawRules.find( targetClass );
926  if( it == gReadRawRules.end() ) {
927  std::list<SchemaRuleMap_t> lst;
928  lst.push_back( rule );
929  gReadRawRules[targetClass] = lst;
930  }
931  else
932  it->second.push_back( rule );
933  }
934 
935 
936 }
void WriteReadRawRuleFunc(SchemaRuleMap_t &rule, int index, std::string &mappedName, MembersTypeMap_t &members, std::ostream &output)
Write the conversion function for ReadRaw rule, the function name is being written to rule["funcname"...
std::map< std::string, ROOT::Internal::TSchemaType > MembersTypeMap_t
Namespace for new ROOT classes and functions.
Definition: StringConv.hxx:21
void WriteSchemaList(std::list< SchemaRuleMap_t > &rules, const std::string &listName, std::ostream &output)
Write schema rules.
std::list< std::pair< ROOT::Internal::TSchemaType, std::string > > SourceTypeList_t
void ProcessReadPragma(const char *args, std::string &error_string)
I am being called when a read pragma is encountered.
static bool IsANumber(const std::string &source)
bool Bool_t
Definition: RtypesCore.h:59
bool HasValidDataMembers(SchemaRuleMap_t &rule, MembersTypeMap_t &members, std::string &error_string)
Check if given rule contains references to valid data members.
static void SplitDeclaration(const std::string &source, std::list< std::pair< ROOT::Internal::TSchemaType, std::string > > &result)
static std::string::size_type FindEndSymbol(std::string &command)
void GetRuleIncludes(std::list< std::string > &result)
Get the list of includes specified in the shema rules.
R__EXTERN SchemaRuleClassMap_t gReadRules
static void SplitList(const std::string &source, std::list< std::string > &result, char delimiter=',')
static void WriteAutoVariables(const std::list< std::string > &target, const SourceTypeList_t &source, MembersTypeMap_t &members, std::string &className, std::string &mappedName, std::ostream &output)
Write down the sources.
std::map< std::string, std::list< SchemaRuleMap_t > > SchemaRuleClassMap_t
void WriteReadRuleFunc(SchemaRuleMap_t &rule, int index, std::string &mappedName, MembersTypeMap_t &members, std::ostream &output)
Write the conversion function for Read rule, the function name is being written to rule["funcname"]...
void ProcessReadRawPragma(const char *args, std::string &error_string)
I am being called then a readraw pragma is encountered.
R__EXTERN SchemaRuleClassMap_t gReadRawRules
static constexpr double s
auto * l
Definition: textangle.C:4
static void StrReplace(std::string &proc, const std::string &pat, const std::string &tr)
Replace all accurances of given string with other string.
#define c(i)
Definition: RSha256.hxx:101
static Bool_t ValidateRule(const std::map< std::string, std::string > &rule, std::string &error_string)
Validate if the user specified rules are correct.
bool ParseRule(std::string rule, ROOT::Internal::MembersMap_t &result, std::string &error_string)
Parse the schema rule as specified in the LinkDef file.
std::map< std::string, std::string > SchemaRuleMap_t
static std::string Trim(const std::string &source)
std::map< std::string, std::string > MembersMap_t
Definition: TSchemaType.h:20
static bool ProcessVersion(const std::string &source, std::pair< Int_t, Int_t > &result)