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