NCBI C++ ToolKit
traversal_code_generator.cpp
Go to the documentation of this file.

Go to the SVN repository for this file.

1 /* $Id: traversal_code_generator.cpp 79562 2017-09-20 18:15:56Z gouriano $
2 * ===========================================================================
3 *
4 * PUBLIC DOMAIN NOTICE
5 * National Center for Biotechnology Information
6 *
7 * This software/database is a "United States Government Work" under the
8 * terms of the United States Copyright Act. It was written as part of
9 * the author's official duties as a United States Government employee and
10 * thus cannot be copyrighted. This software/database is freely available
11 * to the public for use. The National Library of Medicine and the U.S.
12 * Government have not placed any restriction on its use or reproduction.
13 *
14 * Although all reasonable efforts have been taken to ensure the accuracy
15 * and reliability of the software and data, the NLM and the U.S.
16 * Government do not and cannot warrant the performance or results that
17 * may be obtained by using this software or data. The NLM and the U.S.
18 * Government disclaim all warranties, express or implied, including
19 * warranties of performance, merchantability or fitness for any particular
20 * purpose.
21 *
22 * Please cite the author in any work or product based on this material.
23 *
24 * ===========================================================================
25 *
26 * Author: Michael Kornbluh
27 *
28 * File Description:
29 * generates the code from the given specification file.
30 */
31 
32 #include <ncbi_pch.hpp>
33 #include <corelib/ncbitime.hpp>
34 #include <serial/error_codes.hpp>
35 #include "traversal_merger.hpp"
38 
39 #include "blocktype.hpp"
40 #include "enumtype.hpp"
41 #include "module.hpp"
42 #include "moduleset.hpp"
43 #include "reftype.hpp"
44 #include "type.hpp"
46 #include "unitype.hpp"
47 #include "filecode.hpp"
48 
49 #define NCBI_USE_ERRCODE_X Serial_DataTool
50 
52 
53 namespace {
54  const char *kAutoGenerationNotice =
55  "/// This file was generated by application DATATOOL\n"
56  "///\n"
57  "/// ATTENTION:\n"
58  "/// Don't edit or commit this file into SVN as this file will\n"
59  "/// be overridden (by DATATOOL) without warning!\n";
60 }
61 
62 // Use with CTraversalNode's DepthFirst func to pretty-print the descendents of a node
63 // with indenting.
65 public:
67  : m_Ostream(ostream) { }
68 
69  virtual bool Call( CTraversalNode& node, const CTraversalNode::TNodeVec &node_path, ECallType is_cyclic ) override {
70 
71  // print indentation
72  const size_t depth = node_path.size() - 1;
73  m_Ostream << string( depth * 2, ' ' );
74 
76  m_Ostream << "--" << endl;
77  } else {
78 
79  // mark as cyclic if it is
80  if( is_cyclic == eCallType_Cyclic ) {
81  m_Ostream << "(CYCLIC)";
82  }
83 
84  m_Ostream << node.GetTypeName() << ":" << node.GetTypeAsString() << ":" << node.GetInputClassName() << endl;
85  }
86 
87  // only continue if we're not cyclic (to avoid infinite loops)
88  return ( is_cyclic == eCallType_NonCyclic );
89  }
90 
91 private:
93 };
94 
95 // Use with CTraversalNode's DepthFirst func to output all the include
96 // lines needed for the generated code.
97 // It does not involve generating the includes needed by custom stuff
98 // from "member" clauses, etc.
100 public:
102  : m_Ostream(ostream) { }
103 
104  virtual bool Call( CTraversalNode& node, const CTraversalNode::TNodeVec& /*node_path*/, ECallType /*is_cyclic*/ ) override {
105 
106  // We can't generate an include for an unknown type
107  if( node.IsTemplate() ) {
108  return true;
109  }
110 
111  // we don't need to include anything for basic types like "int".
112  // For enums, etc. we assume the parent class is included elsewhere
115  node.GetType() == CTraversalNode::eType_Null ) {
116  return true;
117  }
118 
119  // references to primitive types are not included, since they're generated
120  // elsewhere
121  if( node.GetType() == CTraversalNode::eType_Reference ) {
122  if( node.GetCallees().empty() ) {
123  return true;
124  }
125 
126  switch( (*node.GetCallees().begin())->GetNode()->GetType() ) {
130  return true;
131  break;
132  default:
133  // keep going
134  break;
135  }
136  }
137 
138  // get class name
139  string class_name = node.GetInputClassName();
140 
141  // double colon indicates an inner class, and we assume the
142  // parent class is included elsewhere
143  string::size_type first_double_colon = class_name.find("::");
144  if( first_double_colon != string::npos ) {
145  return true;
146  }
147 
148  // chop off leading prefix since it's not part of the include file
149  if( class_name[0] == 'C' || class_name[0] == 'E' ) {
150  class_name = class_name.substr(1);
151  }
152 
153  // figure out the file name, and include it if we haven't already
154  string file_name = node.GetIncludePath() + "/" + class_name + ".hpp";
156  // haven't included this
157  m_Ostream << "#include <objects/" << file_name << ">" << endl;
159  }
160 
161  return true;
162  }
163 
164 private:
167 };
168 
169 // Use with CTraversalNode's DepthFirst func to output the code
170 // generated by each CTraversalNode
172 public:
173  CGenerateCodeCallback( const string &class_name, CNcbiOstream& ostream, CTraversalNode::EGenerateMode generate_mode )
174  : m_Ostream(ostream), m_ClassName(class_name), m_GenerateMode(generate_mode) { }
175 
176  virtual bool Call( CTraversalNode& node, const CTraversalNode::TNodeVec& /*node_path*/, ECallType /*is_cyclic*/ ) override {
177 
178  // skip functions we've already output
179  if( m_NodesSeen.find( node.Ref() ) != m_NodesSeen.end() ) {
180  return true;
181  }
182 
183  // prototypes get indented
185  m_Ostream << " ";
186  }
187 
188  // generate code and mark that we've done this node
190  m_NodesSeen.insert( node.Ref() );
191  return true;
192  }
193 
194 private:
197  const string m_ClassName;
199 };
200 
201 // Use with CTraversalNode's DepthFirst func to load all the
202 // ancestors/descendents of a node into a set
204 public:
206  : m_SetToAddTo(set_to_add_to) { }
207 
208  virtual bool Call( CTraversalNode& node, const CTraversalNode::TNodeVec& /*node_path*/, ECallType /*is_cyclic*/ ) override {
209  // we've already seen this node, so don't traverse its "children" again
210  if( m_SetToAddTo.find( node.Ref() ) != m_SetToAddTo.end() ) {
211  return false;
212  }
213 
214  m_SetToAddTo.insert( node.Ref() );
215  return true;
216  }
217 
218 private:
220 };
221 
222 // Some functions store their argument every time they're called.
223 // This generates the private member variable declaration at the bottom of
224 // the class prototype.
226 public:
228  : m_Ostream(ostream) { }
229 
230  virtual bool Call( CTraversalNode& node, const CTraversalNode::TNodeVec& /*node_path*/, ECallType /*is_cyclic*/ ) override {
231  if( node.GetDoStoreArg() ) {
232  const string arg_var = node.GetStoredArgVariable();
233  if( m_Args_seen.find(arg_var) == m_Args_seen.end() ) {
234  m_Ostream << " " << node.GetInputClassName() << "* " << arg_var << ";" << endl;
235  m_Args_seen.insert( arg_var );
236  }
237  }
238  return true;
239  }
240 
241 private:
244 };
245 
246 // Some functions store their argument every time they're called.
247 // This generates the initializer in the constructor.
248 // It always initializes to NULL.
250 public:
252  : m_Ostream(ostream) { }
253 
254  virtual bool Call( CTraversalNode& node, const CTraversalNode::TNodeVec& /*node_path*/, ECallType /*is_cyclic*/ ) override {
255  if( node.GetDoStoreArg() ) {
256  const string arg_var = node.GetStoredArgVariable();
257  if( m_Args_seen.find(arg_var) == m_Args_seen.end() ) {
258  m_Ostream << " " << arg_var << "(NULL)," << endl;
259  m_Args_seen.insert( arg_var );
260  }
261  }
262  return true;
263  }
264 
265 private:
268 };
269 
271  CFileSet& mainModules,
272  CNcbiIstream& traversal_spec_file )
273 {
274  TNameToASNMap nameToASNMap;
275  // Need to build this map because mainModules.ResolveInAnyModule
276  // is just too slow.
277  x_BuildNameToASNMap( mainModules, nameToASNMap );
278 
279  // parse spec file and extract some basic info
280  CTraversalSpecFileParser spec_file_parser( traversal_spec_file ) ;
281  string headerFileName = spec_file_parser.GetOutputFileHeader();
282  string sourceFileName = spec_file_parser.GetOutputFileSource();
283  CNcbiOfstream traversal_header_file( headerFileName.c_str() );
284  CNcbiOfstream traversal_source_file( sourceFileName.c_str() );
285 
286  CTraversalNode::TNodeSet nodesWithFunctions;
287  CTraversalNode::TNodeVec rootTraversalNodes;
288 
289  ITERATE( CTraversalSpecFileParser::TRootInfoRefVec, root_iter, spec_file_parser.GetRootTypes() ) {
290  CDataType *a_asn_root = NULL;
291 
292  TNameToASNMap::iterator root_find_iter = nameToASNMap.find( (*root_iter)->m_Root_type_name );
293  if( root_find_iter != nameToASNMap.end() ) {
294  a_asn_root = root_find_iter->second;
295  }
296 
297  if( NULL == a_asn_root ) {
298  throw runtime_error( "could not resolve root type: " + (*root_iter)->m_Root_type_name );
299  }
300 
301  // recurse to create the traversal node
302  {
303  TASNToTravMap asn_nodes_seen; // to prevent infinite recursion
304  CRef<CTraversalNode> a_traversal_root = x_CreateNode( nameToASNMap, asn_nodes_seen, "x_" + (*root_iter)->m_Root_func_name, a_asn_root, CRef<CTraversalNode>() );
305  rootTraversalNodes.push_back( a_traversal_root );
306  // remove "x_" from root node's function name since it's public
307  a_traversal_root->RemoveXFromFuncName();
308 
309  // !!!!!uncomment this code if you want to print out all the nodes
310  //CPrintTraversalNodeCallback printTraversalNodes(std::cerr);
311  //a_traversal_root->DepthFirst( printTraversalNodes, CTraversalNode::fTraversalOpts_AllowCycles );
312  }
313  }
314 
315  // For example, consider if the root is Code-break.
316  // Seq-loc is referred to multiple times, sometimes by different names.
317  // Seq-loc is "loc" under the root Code-break, but is
318  // "E" as part of Seq-loc-mix.
319  // To make sure rules only apply to the node they're supposed to apply to,
320  // we split such nodes so every node has exactly ONE unique variable
321  // name. (They will be merged again later, if possible )
323 
324  // This will attach functions to all nodes that should get them, and
325  // fill in nodesWithFunctions
326  // ( The constructor does all the work )
327  CTraversalPatternMatchCallback( spec_file_parser, nodesWithFunctions );
328 
329  // remove empty nodes (or nodes that only call empty calls)
330  // otherwise we might generate a huge number of functions
331  if( spec_file_parser.IsPruningAllowed() ) {
332  x_PruneEmptyNodes( rootTraversalNodes, nodesWithFunctions );
333  }
334 
335  // This merges functions that are completely identical.
336  // This also tremendously reduces the number of functions we output.
337  // ( The constructor does all the work )
338  if( spec_file_parser.IsMergingAllowed() ) {
339  CTraversalMerger merger( rootTraversalNodes, nodesWithFunctions );
340  }
341 
342  // Finally, generate the files
343  x_GenerateHeaderFile( spec_file_parser.GetNamespace(), spec_file_parser.GetOutputClassName(), headerFileName, traversal_header_file,
344  rootTraversalNodes, spec_file_parser.GetMembers(), spec_file_parser.GetHeaderIncludes(),
345  spec_file_parser.GetHeaderForwardDeclarations() );
346  x_GenerateSourceFile( spec_file_parser.GetNamespace(), spec_file_parser.GetOutputClassName(), headerFileName, traversal_source_file,
347  rootTraversalNodes, spec_file_parser.GetSourceIncludes() );
348 }
349 
351  vector< CRef<CTraversalNode> > &rootTraversalNodes,
352  CTraversalNode::TNodeSet &nodesWithFunctions )
353 {
354  CTraversalNode::TNodeSet usefulNodes;
355 
356  // we traverse to find all callers of useful nodes and
357  // add those to the useful nodes set
358  CAddToNodeSetCallback add_to_set_callback( usefulNodes );
359  ITERATE( CTraversalNode::TNodeSet, node_iter, nodesWithFunctions ) {
360  node_iter->GetNCPointer()->DepthFirst( add_to_set_callback,
362  }
363 
364  // force root nodes to be considered useful, since the user may call
365  // them even if they don't do anything
366  usefulNodes.insert( rootTraversalNodes.begin(), rootTraversalNodes.end() );
367 
368  // delete all nodes which are not useful
370  while( every_node_iter != CTraversalNode::GetEveryNode().end() ) {
371  // holds a reference so we don't delete the node until we've
372  // incremented the iterator.
373  CRef<CTraversalNode> node = const_cast<CTraversalNode*>(*every_node_iter)->Ref();
374 
375  if( usefulNodes.find(node) == usefulNodes.end() ) {
376  node->Clear();
377  }
378  // increment before the "node" CRef goes out of scope, in case it's destroyed
379  ++every_node_iter;
380  }
381 }
382 
384  const std::vector<std::string> & output_class_namespace,
385  const string &output_class_name,
386  const string &headerFileName,
387  CNcbiOstream& traversal_header_file,
388  vector< CRef<CTraversalNode> > &rootTraversalNodes,
390  const std::vector<std::string> &header_includes,
391  const std::vector<std::string> &header_forward_declarations )
392 {
393  // begin include guard
394  string include_guard_define;
395  x_GetIncludeGuard( include_guard_define, headerFileName );
396  traversal_header_file << "#ifndef " << include_guard_define << endl;
397  traversal_header_file << "#define " << include_guard_define << endl;
398  traversal_header_file << endl;
399 
400  // Add copyright notice to the top
401  CFileCode::WriteCopyrightHeader(traversal_header_file);
402  traversal_header_file << " */ " << endl; // close copyright notice
403  traversal_header_file << kAutoGenerationNotice;
404  traversal_header_file << endl;
405 
406  // generate include directives at top
407  CGenerateIncludesCallback generateIncludesCallback( traversal_header_file );
408  NON_CONST_ITERATE( vector< CRef<CTraversalNode> >, root_iter, rootTraversalNodes ) {
409  (*root_iter)->DepthFirst( generateIncludesCallback );
410  }
411  traversal_header_file << endl;
412 
413  // generate explicitly requested includes
414  ITERATE( std::vector<std::string>, include_iter, header_includes ) {
415  traversal_header_file << "#include " << *include_iter << endl;
416  }
417  traversal_header_file << endl;
418 
419  // generate forward declarations
420  ITERATE( std::vector<std::string>, decl_iter, header_forward_declarations ) {
421  traversal_header_file << "class " << *decl_iter << ";" << endl;
422  }
423 
424  traversal_header_file << endl;
425 
426  // open namespaces that output class is in
427  ITERATE( vector<string>, namespace_iter, output_class_namespace ) {
428  if( namespace_iter->empty() ) {
429  continue;
430  }
431  traversal_header_file << "BEGIN_SCOPE("
432  << *namespace_iter << ")" << endl;
433  }
434 
435  traversal_header_file << endl;
436 
437  traversal_header_file << "class " << output_class_name << " { " <<endl;
438  traversal_header_file << "public: " << endl;
439 
440  // generate constructor
441  {
442  traversal_header_file << " " << output_class_name << "(" << endl;
443  // constructor params
444  ITERATE( CTraversalSpecFileParser::TMemberRefVec, member_iter, members ) {
445  if( member_iter != members.begin() ) {
446  traversal_header_file << "," << endl;
447  }
448  traversal_header_file << " " << (*member_iter)->m_Type_name << " " <<
449  x_MemberVarNameToArg((*member_iter)->m_Variable_name);
450  }
451  traversal_header_file << " ) : " << endl;
452 
453  // constructor initializers that initialize from external args
454  ITERATE( CTraversalSpecFileParser::TMemberRefVec, member_iter, members ) {
455  traversal_header_file << " " << (*member_iter)->m_Variable_name << "(" <<
456  x_MemberVarNameToArg((*member_iter)->m_Variable_name) << "), " << endl;
457  }
458 
459  // constructor initializers that initialize stored args to NULL
460  CGenerateStoredArgInitializerCallback generateStoredArgInitializerCallback( traversal_header_file );
461  NON_CONST_ITERATE( vector< CRef<CTraversalNode> >, root_iter, rootTraversalNodes ) {
462  (*root_iter)->DepthFirst( generateStoredArgInitializerCallback );
463  }
464  // m_Dummy is used to make it easier to generate the constructor code.
465  // It lets us not worry about comma usage and whether or not to put the
466  // initializer colon.
467  traversal_header_file << " m_Dummy(0)" << endl;
468 
469  traversal_header_file << " { } " << endl;
470  traversal_header_file << endl;
471  }
472 
473  // generate prototypes of root functions, which are public
474  CGenerateCodeCallback generateCodeCallback( output_class_name, traversal_header_file,
476  NON_CONST_ITERATE( vector< CRef<CTraversalNode> >, root_iter, rootTraversalNodes ) {
477  // no recursion since we only want the roots
479  }
480 
481  // generate prototypes of non-root functions, which are private:
482  traversal_header_file << endl;
483  traversal_header_file << "private: " << endl;
484  NON_CONST_ITERATE( vector< CRef<CTraversalNode> >, root_iter, rootTraversalNodes ) {
485  // recurse to get non-root functions. generateCodeCallback automatically skips duplicates,
486  // so we won't print the root functions twice.
487  (*root_iter)->DepthFirst( generateCodeCallback, CTraversalNode::fTraversalOpts_Post ) ;
488  }
489 
490  // generate member variables specified in the description file
491  if( ! members.empty() ) {
492  traversal_header_file << endl;
493  ITERATE( CTraversalSpecFileParser::TMemberRefVec, member_iter, members ) {
494  traversal_header_file << " " << (*member_iter)->m_Type_name << " " <<
495  (*member_iter)->m_Variable_name << ";" << endl;
496  }
497  }
498 
499  // generate member variables created by functions which store their last value
500  traversal_header_file << endl;
501  CGenerateStoredArgVariablesCallback generateStoredArgVariablesCallback( traversal_header_file );
502  NON_CONST_ITERATE( vector< CRef<CTraversalNode> >, root_iter, rootTraversalNodes ) {
503  (*root_iter)->DepthFirst( generateStoredArgVariablesCallback ) ;
504  }
505 
506  // generate dummy variable
507  traversal_header_file << endl;
508  traversal_header_file << " int m_Dummy;" << endl;
509 
510  traversal_header_file << "}; // end of " << output_class_name << endl;
511  traversal_header_file << endl;
512 
513  // close namespaces that output class is in
514  REVERSE_ITERATE( vector<string>, namespace_iter, output_class_namespace ) {
515  if( namespace_iter->empty() ) {
516  continue;
517  }
518  traversal_header_file << "END_SCOPE("
519  << *namespace_iter << ")" << endl;
520  }
521 
522  traversal_header_file << endl;
523 
524  // end include guard
525  traversal_header_file << "#endif /* " << include_guard_define << " */" << endl;
526 }
527 
528 class CNotAlnum {
529 public:
530  bool operator()( const char &ch ) { return ! isalnum(ch); }
531 };
532 
533 void CTraversalCodeGenerator::x_GetIncludeGuard( string& include_guard_define, const string& headerFileName )
534 {
535  include_guard_define = headerFileName;
536 
537  // erase path, if any
538  include_guard_define = x_StripPath(include_guard_define);
539 
540  // strip off extension, if any
541  const string::size_type last_period = include_guard_define.find_last_of(".");
542  if( last_period != string::npos ) {
543  include_guard_define.resize( last_period );
544  }
545 
546  // remove all non-alphanumeric characters
547  string::iterator remove_iter =
548  remove_if( include_guard_define.begin(), include_guard_define.end(), CNotAlnum() );
549  include_guard_define.erase( remove_iter, include_guard_define.end() );
550 
551  // make all caps
552  NStr::ToUpper( include_guard_define );
553 
554  // add the standard ending
555  include_guard_define += "__HPP";
556 }
557 
559  const std::vector<std::string> & output_class_namespace,
560  const string &output_class_name,
561  const string &/*headerFileName*/,
562  CNcbiOstream& traversal_source_file,
563  vector< CRef<CTraversalNode> > &rootTraversalNodes,
564  const std::vector<std::string> &source_includes )
565 {
566  // Add copyright notice to the top
567  CFileCode::WriteCopyrightHeader(traversal_source_file);
568  traversal_source_file << " */ " << endl; // close copyright notice
569  traversal_source_file << kAutoGenerationNotice;
570  traversal_source_file << endl;
571 
572  // generate include directives at top
573  if (!CFileCode::GetPchHeader().empty()) {
574  traversal_source_file <<
575  "#include <" << CFileCode::GetPchHeader() << ">\n";
576  }
577  ITERATE( vector<string>, include_iter, source_includes ) {
578  traversal_source_file << "#include " << (*include_iter) << endl;
579  }
580 
581  traversal_source_file << endl;
582 
583  // open namespaces that output class is in
584  ITERATE( vector<string>, namespace_iter, output_class_namespace ) {
585  if( namespace_iter->empty() ) {
586  continue;
587  }
588  traversal_source_file << "BEGIN_SCOPE("
589  << *namespace_iter << ")" << endl;
590  }
591 
592  traversal_source_file << endl;
593 
594  // generate main body of functions
595  CGenerateCodeCallback generateCodeCallback( output_class_name, traversal_source_file,
597  NON_CONST_ITERATE( vector< CRef<CTraversalNode> >, root_iter, rootTraversalNodes ) {
598  (*root_iter)->DepthFirst( generateCodeCallback, CTraversalNode::fTraversalOpts_Post ) ;
599  }
600 
601  traversal_source_file << endl;
602 
603  // close namespaces that output class is in
604  REVERSE_ITERATE( vector<string>, namespace_iter, output_class_namespace ) {
605  if( namespace_iter->empty() ) {
606  continue;
607  }
608  traversal_source_file << "END_SCOPE("
609  << *namespace_iter << ")" << endl;
610  }
611 
612  traversal_source_file << endl;
613 }
614 
616 {
617  const string::size_type last_slash = file_name.find_last_of("/\\");
618  if( last_slash == string::npos ) {
619  return file_name;
620  } else {
621  return file_name.substr( last_slash + 1 );
622  }
623 }
624 
626 {
627  // remove initial m_ and make first letter lowercase
628  _ASSERT( NStr::StartsWith(member_var_name, "m_") );
629  string result = member_var_name.substr(2);
630  result[0] = (char)tolower(result[0]);
631  return result;
632 }
633 
635 {
636  // first, create a vector of all nodes that need to be split
637 
638  CTraversalNode::TNodeVec nodes_that_need_splitting;
640  const CTraversalNode::TNodeCallSet &callers = (*node_iter)->GetCallers();
641  if( callers.size() < 2 ) {
642  continue;
643  }
644  const string &var_name = (*callers.begin())->GetVarName();
645  // we don't use the ITERATE macro because we want to skip the first one
646  CTraversalNode::TNodeCallSet::const_iterator caller_iter = callers.begin();
647  ++caller_iter;
648  for( ; caller_iter != callers.end(); ++caller_iter ) {
649  if( (*caller_iter)->GetVarName() != var_name ) {
650  nodes_that_need_splitting.push_back( (*node_iter)->Ref() );
651  break;
652  }
653  }
654  }
655 
656  // Now split them
657  NON_CONST_ITERATE( CTraversalNode::TNodeVec, node_to_split_iter, nodes_that_need_splitting ) {
658  (*node_to_split_iter)->SplitByVarName();
659  }
660 }
661 
663 {
664  ITERATE( CFileSet::TModuleSets, mod_set_iter, mainModules.GetModuleSets() ) {
665  ITERATE( CFileModules::TModules, file_mod_iter, (*mod_set_iter)->GetModules() ) {
666  ITERATE( CDataTypeModule::TDefinitions, def_iter, (*file_mod_iter)->GetDefinitions() ) {
667 
668  CDataType *data_type = &*(*def_iter).second;
669  const string &full_name = data_type->GetFullName();
670 
671  if( nameToASNMap.find(full_name) != nameToASNMap.end() ) {
672  throw runtime_error( "Tried to add CDataType name multiple times: '" + full_name + "'" );
673  }
674 
675  nameToASNMap[full_name] = data_type;
676  }
677  }
678  }
679 }
680 
683  const TNameToASNMap &nameToASNMap,
684  TASNToTravMap &asn_nodes_seen,
685  const string &var_name,
686  CDataType *asn_node,
687  CRef<CTraversalNode> parent )
688 {
689  // To prevent infinite recursion, we check if we've seen this node already and
690  // return it if so.
691  TASNToTravMap::iterator node_location = asn_nodes_seen.find(asn_node);
692  if( node_location != asn_nodes_seen.end() ) {
693  CRef<CTraversalNode> child = node_location->second;
694  // we still have to link parent/child, though
695  if( parent ) {
696  child->AddCaller( var_name, parent );
697  }
698  return child;
699  }
700 
701 
702 // const string &member_name = asn_node->GetMemberName();
703 
704  CRef<CTraversalNode> result = CTraversalNode::Create( parent, var_name, asn_node );
705  asn_nodes_seen.insert( TASNToTravMap::value_type(asn_node, result) );
706 
707  // recurse
708  if( asn_node->IsReference() ) {
709  CReferenceDataType* ref = dynamic_cast<CReferenceDataType*>(asn_node);
710  const string &user_type_name = ref->GetUserTypeName();
711  TNameToASNMap::const_iterator type_name_iter = nameToASNMap.find(user_type_name);
712  if( type_name_iter == nameToASNMap.end() ) {
713  throw runtime_error("Could not find user type name '" + user_type_name + "'");
714  }
715  CDataType *memberType = type_name_iter->second;
716  x_CreateNode( nameToASNMap, asn_nodes_seen, asn_node->GetMemberName(), memberType, result );
717  } else if( asn_node->IsContainer() ) {
718  CDataMemberContainerType * container_type = dynamic_cast<CDataMemberContainerType*>(asn_node);
719  ITERATE( CDataMemberContainerType::TMembers, member_iter, container_type->GetMembers() ) {
720  CDataType *member_type = (*member_iter)->GetType();
721  x_CreateNode( nameToASNMap, asn_nodes_seen, member_type->GetMemberName(), member_type, result );
722  }
723  } else if( asn_node->IsUniSeq() ) {
724  CUniSequenceDataType *uni_seq = dynamic_cast<CUniSequenceDataType*>(asn_node);
725  CDataType *member_type = uni_seq->GetElementType();
726  x_CreateNode( nameToASNMap, asn_nodes_seen, member_type->GetMemberName(), member_type, result );
727  }
728 
729  // we're done with this path of traversal, so we remove this so we can find
730  // the same datatype on other paths.
731  asn_nodes_seen.erase( asn_node );
732 
733  return result;
734 }
735 
void remove_if(Container &c, Predicate *__pred)
Definition: chainer.hpp:69
CAddToNodeSetCallback(CTraversalNode::TNodeSet &set_to_add_to)
virtual bool Call(CTraversalNode &node, const CTraversalNode::TNodeVec &, ECallType) override
CTraversalNode::TNodeSet & m_SetToAddTo
const TMembers & GetMembers(void) const
Definition: blocktype.hpp:155
list< AutoPtr< CDataMember > > TMembers
Definition: blocktype.hpp:137
list< pair< string, AutoPtr< CDataType > > > TDefinitions
Definition: module.hpp:70
string GetFullName(void) const
Definition: type.cpp:973
bool IsReference(void) const
Definition: type.cpp:938
bool IsContainer(void) const
Definition: type.cpp:286
bool IsUniSeq(void) const
Definition: type.cpp:281
const string & GetMemberName(void) const
Definition: type.hpp:394
static const string & GetPchHeader(void)
Definition: filecode.hpp:129
static CNcbiOstream & WriteCopyrightHeader(CNcbiOstream &out)
Definition: filecode.cpp:250
list< AutoPtr< CDataTypeModule > > TModules
Definition: moduleset.hpp:55
const TModuleSets & GetModuleSets(void) const
Definition: moduleset.hpp:119
list< AutoPtr< CFileModules > > TModuleSets
Definition: moduleset.hpp:115
CGenerateCodeCallback(const string &class_name, CNcbiOstream &ostream, CTraversalNode::EGenerateMode generate_mode)
CTraversalNode::TNodeSet m_NodesSeen
const CTraversalNode::EGenerateMode m_GenerateMode
virtual bool Call(CTraversalNode &node, const CTraversalNode::TNodeVec &, ECallType) override
virtual bool Call(CTraversalNode &node, const CTraversalNode::TNodeVec &, ECallType) override
CGenerateIncludesCallback(CNcbiOstream &ostream)
CGenerateStoredArgInitializerCallback(CNcbiOstream &ostream)
virtual bool Call(CTraversalNode &node, const CTraversalNode::TNodeVec &, ECallType) override
virtual bool Call(CTraversalNode &node, const CTraversalNode::TNodeVec &, ECallType) override
CGenerateStoredArgVariablesCallback(CNcbiOstream &ostream)
bool operator()(const char &ch)
virtual bool Call(CTraversalNode &node, const CTraversalNode::TNodeVec &node_path, ECallType is_cyclic) override
CPrintTraversalNodeCallback(CNcbiOstream &ostream)
const string & GetUserTypeName(void) const
Definition: reftype.hpp:68
void x_BuildNameToASNMap(CFileSet &mainModules, TNameToASNMap &nameToASNMap)
CRef< CTraversalNode > x_CreateNode(const TNameToASNMap &nameToASNMap, TASNToTravMap &asn_nodes_seen, const std::string &var_name, CDataType *asn_node, CRef< CTraversalNode > parent)
CTraversalCodeGenerator(CFileSet &mainModules, CNcbiIstream &traversal_spec_file)
std::string x_MemberVarNameToArg(const std::string &member_var_name)
void x_GenerateSourceFile(const std::vector< std::string > &output_class_namespace, const std::string &output_class_name, const std::string &headerFileName, CNcbiOstream &traversal_source_file, std::vector< CRef< CTraversalNode > > &rootTraversalNodes, const std::vector< std::string > &source_includes)
void x_GenerateHeaderFile(const std::vector< std::string > &output_class_namespace, const std::string &output_class_name, const std::string &headerFileName, CNcbiOstream &traversal_header_file, vector< CRef< CTraversalNode > > &rootTraversalNodes, const CTraversalSpecFileParser::TMemberRefVec &members, const std::vector< std::string > &header_includes, const std::vector< std::string > &header_forward_declarations)
void x_GetIncludeGuard(std::string &include_guard_define, const std::string &headerFileName)
void x_PruneEmptyNodes(vector< CRef< CTraversalNode > > &rootTraversalNodes, CTraversalNode::TNodeSet &nodesWithFunctions)
std::string x_StripPath(const std::string &file_name)
const string GetStoredArgVariable(void) const
const std::string & GetTypeName() const
const string & GetTypeAsString(void) const
bool IsTemplate(void) const
bool GetDoStoreArg(void) const
EType GetType() const
static CRef< CTraversalNode > Create(CRef< CTraversalNode > caller, const string &var_name, CDataType *asn_node)
const std::string & GetInputClassName(void) const
const TNodeCallSet & GetCallees(void) const
std::vector< CRef< CTraversalNode > > TNodeVec
void RemoveXFromFuncName(void)
void GenerateCode(const string &func_class_name, CNcbiOstream &traversal_output_file, EGenerateMode generate_mode)
std::set< CRef< CNodeCall >, SRefNodeCallLessthan > TNodeCallSet
CRef< CTraversalNode > Ref()
const std::string & GetIncludePath(void) const
std::set< CRef< CTraversalNode > > TNodeSet
void AddCaller(const std::string &var_name, CRef< CTraversalNode > caller)
static const TNodeRawSet & GetEveryNode(void)
const TMemberRefVec & GetMembers(void) const
const TRootInfoRefVec & GetRootTypes(void) const
const std::vector< std::string > & GetNamespace(void) const
const std::vector< std::string > & GetHeaderForwardDeclarations(void) const
const std::string & GetOutputFileHeader(void) const
const std::string & GetOutputFileSource(void) const
const std::string & GetOutputClassName(void) const
const std::vector< std::string > & GetHeaderIncludes(void) const
std::vector< TMemberRef > TMemberRefVec
const std::vector< std::string > & GetSourceIncludes(void) const
std::vector< TRootInfoRef > TRootInfoRefVec
CDataType * GetElementType(void)
Definition: unitype.hpp:58
void erase(iterator pos)
Definition: map.hpp:167
container_type::const_iterator const_iterator
Definition: map.hpp:53
container_type::iterator iterator
Definition: map.hpp:54
const_iterator end() const
Definition: map.hpp:152
iterator_bool insert(const value_type &val)
Definition: map.hpp:165
container_type::value_type value_type
Definition: map.hpp:52
const_iterator find(const key_type &key) const
Definition: map.hpp:153
Definition: map.hpp:338
iterator_bool insert(const value_type &val)
Definition: set.hpp:149
const_iterator begin() const
Definition: set.hpp:135
const_iterator find(const key_type &key) const
Definition: set.hpp:137
const_iterator end() const
Definition: set.hpp:136
parent_type::const_iterator const_iterator
Definition: set.hpp:79
static unsigned char depth[2 *(256+1+29)+1]
const char * file_name[]
#define ITERATE(Type, Var, Cont)
ITERATE macro to sequence through container elements.
Definition: ncbimisc.hpp:815
#define NON_CONST_ITERATE(Type, Var, Cont)
Non constant version of ITERATE macro.
Definition: ncbimisc.hpp:822
#define REVERSE_ITERATE(Type, Var, Cont)
ITERATE macro to reverse sequence through container elements.
Definition: ncbimisc.hpp:827
string
Definition: cgiapp.hpp:687
#define NULL
Definition: ncbistd.hpp:225
#define END_NCBI_SCOPE
End previously defined NCBI scope.
Definition: ncbistl.hpp:103
#define BEGIN_NCBI_SCOPE
Define ncbi namespace.
Definition: ncbistl.hpp:100
IO_PREFIX::ofstream CNcbiOfstream
Portable alias for ofstream.
Definition: ncbistre.hpp:500
IO_PREFIX::ostream CNcbiOstream
Portable alias for ostream.
Definition: ncbistre.hpp:149
IO_PREFIX::istream CNcbiIstream
Portable alias for istream.
Definition: ncbistre.hpp:146
static bool StartsWith(const CTempString str, const CTempString start, ECase use_case=eCase)
Check if a string starts with a specified prefix value.
Definition: ncbistr.hpp:5412
static string & ToUpper(string &str)
Convert string to upper case – string& version.
Definition: ncbistr.cpp:424
Definition of all error codes used in serial libraries (xser.lib, xcser.lib).
constexpr bool empty(list< Ts... >) noexcept
int isalnum(Uchar c)
Definition: ncbictype.hpp:62
int tolower(Uchar c)
Definition: ncbictype.hpp:72
Defines: CTimeFormat - storage class for time format.
#define _ASSERT
else result
Definition: token2.c:20
Modified on Sat Apr 20 12:15:49 2024 by modify_doxy.py rev. 669887