ROOT  6.06/09
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 #include "TMetaUtils.h"
7 
8 #include <iostream>
9 #include <algorithm>
10 #include <string>
11 #include <utility>
12 #include <map>
13 #include <sstream>
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,
91  std::map<std::string, std::string> &result,
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 = "WARNING: 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 = "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  std::cout << warning << " - the list of checksums is empty";
324  std::cout << std::endl;
325  }
326 
327  for( lsIt = lst.begin(); lsIt != lst.end(); ++lsIt )
328  if( !TSchemaRuleProcessor::IsANumber( *lsIt ) ) {
329  error_string = warning + " - " + *lsIt + " is not a valid value";
330  error_string += " of checksum parameter - an integer expected";
331  return false;
332  }
333  }
334 
335  //-----------------------------------------------------------------------
336  // Check if the version is correct
337  //////////////////////////////////////////////////////////////////////////
338 
339  std::pair<Int_t, Int_t> ver;
340  if( it1 != rule.end() ) {
341  if( it1->second.size() < 2 || it1->second[0] != '[' ||
342  it1->second[it1->second.size()-1] != ']' ) {
343  error_string = warning + " - a comma separated list of version specifiers ";
344  error_string += "enclosed in square brackets expected";
345  error_string += "as a value of version parameter";
346  return false;
347  }
348 
349  TSchemaRuleProcessor::SplitList( it1->second.substr( 1, it1->second.size()-2 ),
350  lst );
351  if( lst.empty() ) {
352  error_string = warning + " - the list of versions is empty";
353  }
354 
355  for( lsIt = lst.begin(); lsIt != lst.end(); ++lsIt )
356  if( !TSchemaRuleProcessor::ProcessVersion( *lsIt, ver ) ) {
357  error_string = warning + " - " + *lsIt + " is not a valid value";
358  error_string += " of version parameter";
359  return false;
360  }
361  }
362 
363  //-----------------------------------------------------------------------
364  // Check if we're dealing with renameing declaration - sourceClass,
365  // targetClass and either version or checksum required
366  //////////////////////////////////////////////////////////////////////////
367 
368  if( rule.size() == 3 || (rule.size() == 4 && it1 != rule.end() && it2 != rule.end()) )
369  return true;
370 
371  //-----------------------------------------------------------------------
372  // Check if we have all the keys we need
373  //-----------------------------------------------------------------------
374  std::string keys[] = {"target", "source"};
375  for( int i = 0; i < 2; ++i ) {
376  it1 = rule.find( keys[i] );
377  if( it1 == rule.end() ) {
378  error_string = warning + " - required parameter is missing: ";
379  error_string += keys[i];
380  return false;
381  }
382  }
383 
384  //-----------------------------------------------------------------------
385  // Check the source contains proper declarations.
386  //////////////////////////////////////////////////////////////////////////
387 
388  it1 = rule.find("code");
389  if (it1 != rule.end() && it1->second != "") {
390  SourceTypeList_t source;
391  TSchemaRuleProcessor::SplitDeclaration( rule.find("source")->second, source );
392  SourceTypeList_t::const_iterator it;
393  for( it = source.begin(); it != source.end(); ++it ) {
394  if ( ( it->first.fType == "" && it->second != "") ) {
395  error_string = warning + " - type required when listing a rule's source: ";
396  error_string += "source=\""+ rule.find("source")->second +"\"";
397  return false;
398  }
399  }
400  }
401 
402  //-----------------------------------------------------------------------
403  // Check if we have an embed parameter and if so if it has been set to
404  // the right value
405  //////////////////////////////////////////////////////////////////////////
406 
407  it1 = rule.find( "embed" );
408  if( it1 != rule.end() ) {
409  std::string emValue = TSchemaRuleProcessor::Trim( it1->second );
410  if( emValue != "true" && emValue != "false" ) {
411  error_string = warning + " - true or false expected as a value ";
412  error_string += "of embed parameter";
413  return false;
414  }
415  }
416 
417  //-----------------------------------------------------------------------
418  // Check if the include list is not empty
419  //////////////////////////////////////////////////////////////////////////
420 
421  it1 = rule.find( "include" );
422  if( it1 != rule.end() ) {
423  if( it1->second.empty() ) {
424  error_string = warning + " - the include list is empty";
425  return false;
426  }
427  }
428 
429  return true;
430  }
431 
432  /////////////////////////////////////////////////////////////////////////////
433  /// Check if given rule contains references to valid data members
434 
436  MembersTypeMap_t& members )
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  std::cout << "WARNING: IO rule for class " + rule["targetClass"];
451  std::cout << " data member: " << *it << " was specified as a ";
452  std::cout << "target in the rule but doesn't seem to appear in ";
453  std::cout << "target class" << std::endl;
454  return false;
455  }
456  }
457  return true;
458  }
459 
460  /////////////////////////////////////////////////////////////////////////////
461  ///-----------------------------------------------------------------------
462  /// Write down the sources
463  ///-----------------------------------------------------------------------
464 
465  static void WriteAutoVariables( const std::list<std::string>& target,
466  const SourceTypeList_t& source,
467  MembersTypeMap_t& members,
468  std::string& className, std::string& mappedName,
469  std::ostream& output )
470  {
471  if (!source.empty()) {
472  Bool_t start = true;
473  SourceTypeList_t::const_iterator it;
474 
475  //--------------------------------------------------------------------
476  // Write IDs and check if we should generate the onfile structure
477  // this is done if the type was declared
478  ///////////////////////////////////////////////////////////////////////
479 
480  Bool_t generateOnFile = false;
481  output << "#if 0" << std::endl; // this is to be removed later
482  for( it = source.begin(); it != source.end(); ++it ) {
483  output << " ";
484  output << "static Int_t id_" << it->second << " = oldObj->GetId(";
485  output << "\"" << it->second << "\");" << std::endl;
486 
487  if( it->first.fType != "" )
488  generateOnFile = true;
489  }
490  output << "#endif" << std::endl; // this is to be removed later
491 
492  //--------------------------------------------------------------------
493  // Declare the on-file structure - if needed
494  ///////////////////////////////////////////////////////////////////////
495 
496  if( generateOnFile ) {
497  std::string onfileStructName = mappedName + "_Onfile";
498  output << " ";
499  output << "struct " << onfileStructName << " {\n";
500 
501  //-----------------------------------------------------------------
502  // List the data members with non-empty type declarations
503  ////////////////////////////////////////////////////////////////////
504  /// fprintf(stderr, "Seeing %s %s %s\n", it->first.fType.c_str(), it->second.c_str(), it->first.fDimensions.c_str());
505 
506  for( it = source.begin(); it != source.end(); ++it ) {
507  if( it->first.fType.size() ) {
508  if ( it->first.fDimensions.size() ) {
509  output << " typedef " << it->first.fType;
510  output << " onfile_" << it->second << "_t" << it->first.fDimensions << ";\n";
511  output << " ";
512  output << "onfile_" << it->second << "_t &" << it->second << ";\n";
513 
514  } else {
515  output << " ";
516  output << it->first.fType << " &" << it->second << ";\n";
517  }
518  }
519  }
520 
521  //-----------------------------------------------------------------
522  // Generate the constructor
523  ////////////////////////////////////////////////////////////////////
524 
525  output << " " << onfileStructName << "(";
526  for( start = true, it = source.begin(); it != source.end(); ++it ) {
527  if( it->first.fType.size() == 0)
528  continue;
529 
530  if( !start )
531  output << ", ";
532  else
533  start = false;
534 
535  if (it->first.fDimensions.size() == 0) {
536  output << it->first.fType << " &onfile_" << it->second;
537  } else {
538  output << " onfile_" << it->second << "_t" << " &onfile_" << it->second;
539  }
540  }
541  output << " ): ";
542 
543  //-----------------------------------------------------------------
544  // Generate the constructor's initializer list
545  ////////////////////////////////////////////////////////////////////
546 
547  for( start = true, it = source.begin(); it != source.end(); ++it ) {
548  if( it->first.fType == "" )
549  continue;
550 
551  if( !start )
552  output << ", ";
553  else
554  start = false;
555 
556  output << it->second << "(onfile_" << it->second << ")";
557  }
558  output << " {}\n";
559  output << " " << "};\n";
560 
561  //-----------------------------------------------------------------
562  // Initialize the structure - to be changed later
563  ////////////////////////////////////////////////////////////////////
564 
565  for( it = source.begin(); it != source.end(); ++it ) {
566  output << " ";
567  output << "static Long_t offset_Onfile_" << mappedName;
568  output << "_" << it->second << " = oldObj->GetClass()->GetDataMemberOffset(\"";
569  output << it->second << "\");\n";
570  }
571  output << " " << "char *onfile_add = (char*)oldObj->GetObject();\n";
572  output << " " << mappedName << "_Onfile onfile(\n";
573 
574  for( start = true, it = source.begin(); it != source.end(); ++it ) {
575  if( it->first.fType == "" )
576  continue;
577 
578  if( !start )
579  output << ",\n";
580 
581  else
582  start = false;
583 
584  output << " ";
585  output << "*(";
586  if (it->first.fDimensions.size() == 0) {
587  output << it->first.fType;
588  } else {
589  output << mappedName << "_Onfile::onfile_" << it->second << "_t";
590  }
591  output << "*)(onfile_add+offset_Onfile_";
592  output << mappedName << "_" << it->second << ")";
593  }
594  output << " );\n\n";
595  }
596  }
597 
598  //-----------------------------------------------------------------------
599  // Write down the targets
600  //////////////////////////////////////////////////////////////////////////
601 
602  if( !target.empty() ) {
603  output << " static TClassRef cls(\"";
604  output << className << "\");" << std::endl;
605 
606  std::list<std::string>::const_iterator it;
607  for( it = target.begin(); it != target.end(); ++it ) {
608  Internal::TSchemaType memData = members[*it];
609  output << " static Long_t offset_" << *it << " = ";
610  output << "cls->GetDataMemberOffset(\"" << *it << "\");";
611  output << std::endl;
612  if (memData.fDimensions.size()) {
613  output << " typedef " << memData.fType << " " << *it << "_t" << memData.fDimensions << ";" << std::endl;
614  output << " " << *it << "_t& " << *it << " = ";
615  output << "*(" << *it << "_t *)(target+offset_" << *it;
616  output << ");" << std::endl;
617  } else {
618  output << " " << memData.fType << "& " << *it << " = ";
619  output << "*(" << memData.fType << "*)(target+offset_" << *it;
620  output << ");" << std::endl;
621  }
622  }
623  }
624  }
625 
626  /////////////////////////////////////////////////////////////////////////////
627  /// Write the conversion function for Read rule, the function name
628  /// is being written to rule["funcname"]
629 
630  void WriteReadRuleFunc( SchemaRuleMap_t& rule, int index,
631  std::string& mappedName, MembersTypeMap_t& members,
632  std::ostream& output )
633  {
634  std::string className = rule["targetClass"];
635 
636  //-----------------------------------------------------------------------
637  // Create the function name
638  //////////////////////////////////////////////////////////////////////////
639 
640  std::ostringstream func;
641  func << "read_" << mappedName << "_" << index;
642  rule["funcname"] = func.str();
643 
644  //-----------------------------------------------------------------------
645  // Write the header
646  //////////////////////////////////////////////////////////////////////////
647 
648  output << " static void " << func.str();
649  output << "( char* target, TVirtualObject *oldObj )" << std::endl;
650  output << " {" << std::endl;
651  output << " //--- Automatically generated variables ---" << std::endl;
652 
653  //-----------------------------------------------------------------------
654  // Write the automatically generated variables
655  //////////////////////////////////////////////////////////////////////////
656 
657  std::list<std::pair<ROOT::Internal::TSchemaType,std::string> > source;
658  std::list<std::string> target;
659  TSchemaRuleProcessor::SplitDeclaration( rule["source"], source );
660  TSchemaRuleProcessor::SplitList( rule["target"], target );
661 
662  WriteAutoVariables( target, source, members, className, mappedName, output );
663  output << " " << className << "* newObj = (" << className;
664  output << "*)target;" << std::endl;
665  output << " // Supress warning message.\n";
666  output << " " << "if (oldObj) {}\n\n";
667  output << " " << "if (newObj) {}\n\n";
668 
669  //-----------------------------------------------------------------------
670  // Write the user's code
671  //////////////////////////////////////////////////////////////////////////
672 
673  output << " //--- User's code ---" << std::endl;
674  output << " " << rule["code"] << std::endl;
675  output << " }" << std::endl;
676  }
677 
678 
679  /////////////////////////////////////////////////////////////////////////////
680  /// Write the conversion function for ReadRaw rule, the function name
681  /// is being written to rule["funcname"]
682 
683  void WriteReadRawRuleFunc( SchemaRuleMap_t& rule, int index,
684  std::string& mappedName, MembersTypeMap_t& members,
685  std::ostream& output )
686  {
687  std::string className = rule["targetClass"];
688 
689  //-----------------------------------------------------------------------
690  // Create the function name
691  //////////////////////////////////////////////////////////////////////////
692 
693  std::ostringstream func;
694  func << "readraw_" << mappedName << "_" << index;
695  rule["funcname"] = func.str();
696 
697  //-----------------------------------------------------------------------
698  // Write the header
699  //////////////////////////////////////////////////////////////////////////
700 
701  output << " static void " << func.str();
702  output << "( char* target, TBuffer &b )" << std::endl;
703  output << " {" << std::endl;
704  output << "#if 0" << std::endl;
705  output << " //--- Automatically generated variables ---" << std::endl;
706 
707  //-----------------------------------------------------------------------
708  // Write the automatically generated variables
709  //////////////////////////////////////////////////////////////////////////
710 
711  std::list<std::pair<ROOT::Internal::TSchemaType,std::string> > source;
712  std::list<std::string> target;
713  TSchemaRuleProcessor::SplitList( rule["target"], target );
714 
715  WriteAutoVariables( target, source, members, className, mappedName, output );
716  output << " " << className << "* newObj = (" << className;
717  output << "*)target;" << std::endl << std::endl;
718 
719  //-----------------------------------------------------------------------
720  // Write the user's code
721  //////////////////////////////////////////////////////////////////////////
722 
723  output << " //--- User's code ---" << std::endl;
724  output << rule["code"] << std::endl;
725  output << "#endif" << std::endl;
726  output << " }" << std::endl;
727  }
728 
729  /////////////////////////////////////////////////////////////////////////////
730  /// Replace all accurances of given string with other string
731 
732  static void StrReplace( std::string& proc, const std::string& pat,
733  const std::string& tr )
734  {
735  std::string::size_type it = 0;
736  std::string::size_type s = pat.size();
737  std::string::size_type tr_len= tr.size();
738 
739  if( s == 0 ) return;
740 
741  while( 1 ) {
742  it = proc.find( pat, it );
743  if( it == std::string::npos )
744  break;
745 
746  proc.replace( it, s, tr );
747  it += tr_len;
748  }
749  }
750 
751  /////////////////////////////////////////////////////////////////////////////
752  /// Write schema rules
753 
754  void WriteSchemaList( std::list<SchemaRuleMap_t>& rules,
755  const std::string& listName, std::ostream& output )
756  {
757  std::list<SchemaRuleMap_t>::iterator it;
758  int i = 0;
759 
760  //-----------------------------------------------------------------------
761  // Loop over the rules
762  //////////////////////////////////////////////////////////////////////////
763 
764  for( it = rules.begin(); it != rules.end(); ++it ) {
765  output << " rule = &" << listName << "[" << i++;
766  output << "];" << std::endl;
767 
768  //--------------------------------------------------------------------
769  // Write down the mandatory fields
770  ///////////////////////////////////////////////////////////////////////
771 
772  output << " rule->fSourceClass = \"" << (*it)["sourceClass"];
773  output << "\";" << std::endl;
774 
775  if( it->find( "target" ) != it->end() ) {
776  output << " rule->fTarget = \"" << (*it)["target"];
777  output << "\";" << std::endl;
778  }
779 
780  if( it->find( "source" ) != it->end() ) {
781  output << " rule->fSource = \"" << (*it)["source"];
782  output << "\";" << std::endl;
783  }
784 
785  //--------------------------------------------------------------------
786  // Deal with non mandatory keys
787  ///////////////////////////////////////////////////////////////////////
788 
789  if( it->find( "funcname" ) != it->end() ) {
790  std::string code = (*it)["code"];
791  StrReplace( code, "\n", "\\n" );
792  StrReplace( code, "\"", "\\\"");
793 
794  output << " rule->fFunctionPtr = (void *)TFunc2void( ";
795  output << (*it)["funcname"] << ");" << std::endl;
796  output << " rule->fCode = \"" << code;
797  output << "\";" << std::endl;
798  }
799 
800  if( it->find( "version" ) != it->end() ) {
801  output << " rule->fVersion = \"" << (*it)["version"];
802  output << "\";" << std::endl;
803  }
804 
805  if( it->find( "checksum" ) != it->end() ) {
806  output << " rule->fChecksum = \"" << (*it)["checksum"];
807  output << "\";" << std::endl;
808  }
809 
810  if( it->find( "embed" ) != it->end() ) {
811  output << " rule->fEmbed = " << (*it)["embed"];
812  output << ";" << std::endl;
813  }
814 
815  if( it->find( "include" ) != it->end() ) {
816  output << " rule->fInclude = \"" << (*it)["include"];
817  output << "\";" << std::endl;
818  }
819 
820  if( it->find( "attributes" ) != it->end() ) {
821  output << " rule->fAttributes = \"" << (*it)["attributes"];
822  output << "\";" << std::endl;
823  }
824  }
825  }
826 
827  /////////////////////////////////////////////////////////////////////////////
828  /// Get the list of includes specified in the shema rules
829 
830  void GetRuleIncludes( std::list<std::string> &result )
831  {
832  std::list<std::string> tmp;
833  std::list<SchemaRuleMap_t>::iterator rule;
834  SchemaRuleMap_t::iterator attr;
835  SchemaRuleClassMap_t::iterator it;
836 
837  //-----------------------------------------------------------------------
838  // Processing read rules
839  //////////////////////////////////////////////////////////////////////////
840 
841  for( it = gReadRules.begin(); it != gReadRules.end(); ++it ) {
842  for( rule = it->second.begin(); rule != it->second.end(); ++rule ) {
843  attr = rule->find( "include" );
844  if( attr == rule->end() ) continue;
845  TSchemaRuleProcessor::SplitList( attr->second, tmp );
846  result.splice( result.begin(), tmp, tmp.begin(), tmp.end() );
847  }
848  }
849 
850  //-----------------------------------------------------------------------
851  // Processing read raw rules
852  //////////////////////////////////////////////////////////////////////////
853 
854  for( it = gReadRawRules.begin(); it != gReadRawRules.end(); ++it ) {
855  for( rule = it->second.begin(); rule != it->second.end(); ++rule ) {
856  attr = rule->find( "include" );
857  if( attr == rule->end() ) continue;
858  TSchemaRuleProcessor::SplitList( attr->second, tmp );
859  result.splice( result.begin(), tmp, tmp.begin(), tmp.end() );
860  }
861  }
862 
863  //-----------------------------------------------------------------------
864  // Removing duplicates
865  //////////////////////////////////////////////////////////////////////////
866 
867  result.sort();
868  result.unique();
869  }
870 
871  /////////////////////////////////////////////////////////////////////////////
872  /// I am being called when a read pragma is encountered
873 
874  void ProcessReadPragma( const char* args )
875  {
876  //-----------------------------------------------------------------------
877  // Parse the rule and check it's validity
878  //////////////////////////////////////////////////////////////////////////
879 
880  std::map<std::string, std::string> rule;
881  std::string error_string;
882  if( !ParseRule( args, rule, error_string ) ) {
883  std::cout << error_string << '\n';
884  std::cout << "The following rule has been omitted:" << std::endl;
885  std::cout << " read " << args << std::endl;
886  return;
887  }
888 
889  //-----------------------------------------------------------------------
890  // Append the rule to the list
891  //////////////////////////////////////////////////////////////////////////
892 
893  SchemaRuleClassMap_t::iterator it;
894  std::string targetClass = rule["targetClass"];
895  it = gReadRules.find( targetClass );
896  if( it == gReadRules.end() ) {
897  std::list<SchemaRuleMap_t> lst;
898  lst.push_back( rule );
899  gReadRules[targetClass] = lst;
900  }
901  else
902  it->second.push_back( rule );
903  }
904 
905  /////////////////////////////////////////////////////////////////////////////
906  /// I am being called then a readraw pragma is encountered
907 
908  void ProcessReadRawPragma( const char* args )
909  {
910  //-----------------------------------------------------------------------
911  // Parse the rule and check it's validity
912  //////////////////////////////////////////////////////////////////////////
913 
914  std::map<std::string, std::string> rule;
915  std::string error_string;
916  if( !ParseRule( args, rule, error_string ) ) {
917  std::cout << error_string << '\n';
918  std::cout << "The following rule has been omitted:" << std::endl;
919  std::cout << " readraw " << args << std::endl;
920  return;
921  }
922 
923  //-----------------------------------------------------------------------
924  // Append the rule to the list
925  //////////////////////////////////////////////////////////////////////////
926 
927  SchemaRuleClassMap_t::iterator it;
928  std::string targetClass = rule["targetClass"];
929  it = gReadRawRules.find( targetClass );
930  if( it == gReadRawRules.end() ) {
931  std::list<SchemaRuleMap_t> lst;
932  lst.push_back( rule );
933  gReadRawRules[targetClass] = lst;
934  }
935  else
936  it->second.push_back( rule );
937  }
938 
939 
940 }
std::map< std::string, std::list< SchemaRuleMap_t > > SchemaRuleClassMap_t
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"...
Namespace for new ROOT classes and functions.
Definition: ROOT.py:1
void WriteSchemaList(std::list< SchemaRuleMap_t > &rules, const std::string &listName, std::ostream &output)
Write schema rules.
static bool IsANumber(const std::string &source)
std::list< std::pair< ROOT::Internal::TSchemaType, std::string > > SourceTypeList_t
std::map< std::string, ROOT::Internal::TSchemaType > MembersTypeMap_t
bool Bool_t
Definition: RtypesCore.h:59
static void SplitDeclaration(const std::string &source, std::list< std::pair< ROOT::Internal::TSchemaType, std::string > > &result)
bool ParseRule(std::string rule, MembersMap_t &result, std::string &error_string)
Parse the schema rule as specified in the LinkDef file.
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.
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
TLine * l
Definition: textangle.C:4
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)
I am being called then a readraw pragma is encountered.
SchemaRuleClassMap_t gReadRawRules
void ProcessReadPragma(const char *args)
I am being called when a read pragma is encountered.
double func(double *x, double *p)
Definition: stressTF1.cxx:213
bool HasValidDataMembers(SchemaRuleMap_t &rule, MembersTypeMap_t &members)
Check if given rule contains references to valid data members.
static void StrReplace(std::string &proc, const std::string &pat, const std::string &tr)
Replace all accurances of given string with other string.
static Bool_t ValidateRule(const std::map< std::string, std::string > &rule, std::string &error_string)
Validate if the user specified rules are correct.
double result[121]
static void output(int code)
Definition: gifencode.c:226
float value
Definition: math.cpp:443
static std::string Trim(const std::string &source)
static bool ProcessVersion(const std::string &source, std::pair< Int_t, Int_t > &result)
std::map< std::string, std::string > SchemaRuleMap_t