CMS 3D CMS Logo

ParseTree.cc

Go to the documentation of this file.
00001 #include "FWCore/ParameterSet/interface/ParseTree.h"
00002 #include "FWCore/Utilities/interface/EDMException.h"
00003 #include "FWCore/ParameterSet/interface/ModuleNode.h"
00004 #include "FWCore/ParameterSet/interface/ReplaceNode.h"
00005 #include "FWCore/ParameterSet/interface/IncludeNode.h"
00006 #include "FWCore/ParameterSet/interface/PSetNode.h"
00007 #include "FWCore/ParameterSet/interface/Nodes.h"
00008 #include "FWCore/ParameterSet/interface/EntryNode.h"
00009 #include "FWCore/ParameterSet/interface/VEntryNode.h"
00010 #include "FWCore/ParameterSet/interface/parse.h"
00011 #include "FWCore/MessageLogger/interface/MessageLogger.h"
00012 
00013 #include <iostream>
00014 
00015 namespace edm {
00016   namespace pset {
00017 
00018     bool ParseTree::strict_ = false;
00019     bool ParseTree::doReplaces_ = true;
00020 
00022     void ParseTree::setStrictParsing(bool strict)
00023     {
00024       strict_ = strict;
00025     }
00026 
00027     void ParseTree::doReplaces(bool doOrNotDo)
00028     {
00029       doReplaces_ = doOrNotDo;
00030     }
00031 
00032     ParseTree::ParseTree(const std::string & configString)
00033     : blocks_(),
00034       blockCopyNodes_(),
00035       blockRenameNodes_(),
00036       blockReplaceNodes_(),
00037       copyNodes_(),
00038       renameNodes_(),
00039       replaceNodes_(),
00040       modulesAndSources_(),
00041       nodes_(parse(configString.c_str()))
00042     {
00043       process();
00044     }
00045 
00046 
00047     PSetNode * ParseTree::getProcessNode() const
00048     {
00049       NodePtr processPSetNodePtr = nodes_->front();
00050       edm::pset::PSetNode * processPSetNode
00051         = dynamic_cast<edm::pset::PSetNode*>(processPSetNodePtr.get());
00052       if(processPSetNode == 0) 
00053       {
00054         throw edm::Exception(errors::Configuration,"ParseTree")
00055           << "The top node of the configuration must be a process";
00056       }
00057       return processPSetNode;
00058     }
00059 
00060 
00061     CompositeNode * ParseTree::top() const
00062     {
00063       NodePtr nodePtr = nodes_->front();
00064       edm::pset::CompositeNode * node
00065         = dynamic_cast<edm::pset::CompositeNode*>(nodePtr.get());
00066       assert(node != 0);
00067       return node;
00068     }
00069 
00070 
00071 
00072     std::vector<std::string> ParseTree::modules() const
00073     {
00074       std::vector<std::string> result;
00075       result.reserve(modulesAndSources_.size());
00076       for(NodePtrMap::const_iterator moduleMapItr = modulesAndSources_.begin(),
00077           moduleMapItrEnd = modulesAndSources_.end();
00078           moduleMapItr != moduleMapItrEnd; ++moduleMapItr)
00079       {
00080         result.push_back(moduleMapItr->first);
00081       }
00082       return result;
00083     }
00084 
00085 
00086     std::vector<std::string> ParseTree::modulesOfType(const std::string & s) const
00087     {
00088       std::vector<std::string> result;
00089       for(NodePtrMap::const_iterator moduleMapItr = modulesAndSources_.begin(),
00090           moduleMapItrEnd = modulesAndSources_.end();
00091           moduleMapItr != moduleMapItrEnd; ++moduleMapItr)
00092       {
00093         if(moduleMapItr->second->type() == s)
00094         {
00095           result.push_back(moduleMapItr->first);
00096         }
00097       }
00098       return result;
00099     }
00100 
00101 
00102 
00103     void ParseTree::process()
00104     {
00105       clear();
00106       
00107       if(nodes_->size() == 0)
00108       {
00109         throw edm::Exception(errors::Configuration,"ParseTree")
00110         << "Configuration is empty";
00111       }
00112         
00113       // make sure it has a well-defined top
00114       if(nodes_->size() > 1)
00115       {
00116          NodePtr contentsNode(new ContentsNode(nodes_));
00117          NodePtrListPtr newTop(new NodePtrList);
00118          newTop->push_back(contentsNode); 
00119          nodes_ = newTop;
00120       }
00121 
00122       CompositeNode * topLevelNode = top();
00123 
00124       // make whatever backwards link you can now.  Include Nodes
00125       // can add more as needed
00126       topLevelNode->setAsChildrensParent();
00127       // find any include nodes
00128       // maybe someday list the current file as an open file,
00129       // so it never gets circularly included
00130       std::list<std::string> openFiles;
00131       std::list<std::string> sameLevelIncludes;
00132       topLevelNode->resolve(openFiles, sameLevelIncludes, strict_);
00133       // make the final backwards links.  Needed?
00134       //processNode->setAsChildrensParent();
00135 
00136       NodePtrListPtr contents = topLevelNode->nodes();
00137       sortNodes(contents);
00138 
00139       // maybe we don't have to do anything
00140       if( !copyNodes_.empty() || !replaceNodes_.empty() 
00141        || !renameNodes_.empty() || !blocks_.empty() )
00142       {
00143         // pull out the operations on shared blocks, and do them.
00144         findBlockModifiers(copyNodes_, blockCopyNodes_);
00145         findBlockModifiers(renameNodes_, blockRenameNodes_);
00146         findBlockModifiers(replaceNodes_, blockReplaceNodes_);
00147         
00148         // do copies
00149         for(NodePtrList::iterator nodeItr = blockCopyNodes_.begin(), nodeItrEnd = blockCopyNodes_.end();
00150             nodeItr != nodeItrEnd; ++nodeItr)
00151         {
00152           processCopyNode(*nodeItr, blocks_);
00153         }
00154 
00155         // do renames before replaces
00156         for(NodePtrList::iterator nodeItr = blockRenameNodes_.begin(), nodeItrEnd = blockRenameNodes_.end();
00157             nodeItr != nodeItrEnd; ++nodeItr)
00158         {
00159           processRenameNode(*nodeItr, blocks_);
00160         }
00161 
00162         if(doReplaces_)
00163         {
00164           // now replace nodes
00165           for(NodePtrList::iterator nodeItr = blockReplaceNodes_.begin(), 
00166               nodeItrEnd = blockReplaceNodes_.end();
00167               nodeItr != nodeItrEnd; ++nodeItr)
00168           {
00169             processReplaceNode(*nodeItr, blocks_);
00170           }
00171         }
00172 
00173         // NOTE: We only bother inlining the Using blocks
00174         // if there's a chance the parameters will be modified.
00175         // If not, they'll get done later.
00176         processUsingBlocks();
00177 
00178         // do copies
00179         for(NodePtrList::iterator nodeItr = copyNodes_.begin(), nodeItrEnd = copyNodes_.end();
00180             nodeItr != nodeItrEnd; ++nodeItr)
00181         {
00182           processCopyNode(*nodeItr, modulesAndSources_);
00183         }
00184 
00185         // do renames before replaces
00186         for(NodePtrList::iterator nodeItr = renameNodes_.begin(), nodeItrEnd = renameNodes_.end();
00187             nodeItr != nodeItrEnd; ++nodeItr)
00188         {
00189           processRenameNode(*nodeItr, modulesAndSources_);
00190         }
00191 
00192         if(doReplaces_)
00193         {
00194           // now replace nodes
00195           for(NodePtrList::iterator nodeItr = replaceNodes_.begin(), 
00196               nodeItrEnd = replaceNodes_.end();
00197               nodeItr != nodeItrEnd; ++nodeItr)
00198           {
00199             processReplaceNode(*nodeItr, modulesAndSources_);
00200           }
00201         }
00202       }
00203 
00204       // check for duplicate names
00205       // if replaces aren't being used, this might fail, so disable
00206       if(doReplaces_)
00207       {
00208         validate();
00209       }
00210     }
00211 
00212 
00213     void ParseTree::replace(const std::string & dotDelimitedPath,
00214                             const std::string & value)
00215     {
00216       NodePtr entryNode(new EntryNode("replace", dotDelimitedPath, value, false));
00217       NodePtr replaceNode(new ReplaceNode("replace", dotDelimitedPath, entryNode, true, -1));
00218       top()->nodes()->push_back(replaceNode);
00219     }
00220 
00221 
00222     void ParseTree::replace(const std::string & dotDelimitedPath,
00223                             const std::vector<std::string> & values)
00224     {
00225       StringListPtr strings(new StringList(values));
00226       NodePtr vEntryNode(new VEntryNode("replace", dotDelimitedPath, strings, false));
00227       NodePtr replaceNode(new ReplaceNode("replace", dotDelimitedPath, vEntryNode, true, -1));
00228       top()->nodes()->push_back(replaceNode);
00229     }
00230 
00231 
00232     void ParseTree::print(const std::string & dotDelimitedNode) const
00233     {
00234       NodePtr nodePtr = findInPath(dotDelimitedNode);
00235       nodePtr->print(std::cout, Node::EXPANDED);
00236     }
00237 
00238     std::string ParseTree::typeOf(const std::string & dotDelimitedNode) const
00239     {
00240       return findInPath(dotDelimitedNode)->type();
00241     }
00242 
00243 
00244     std::string ParseTree::value(const std::string & dotDelimitedNode) const
00245     {
00246       std::string result = "";
00247       NodePtr nodePtr = findInPath(dotDelimitedNode);
00248       EntryNode * entryNode = dynamic_cast<EntryNode *>(nodePtr.get());
00249       if(entryNode == 0)
00250       {
00251         throw edm::Exception(errors::Configuration,"")
00252         << dotDelimitedNode << " is not a single entry";
00253       }
00254       else
00255       {
00256         result = entryNode->value();
00257       }
00258       return result;
00259     }
00260 
00261 
00263     std::vector<std::string> ParseTree::values(const std::string & dotDelimitedNode) const
00264     {
00265       std::vector<std::string> result;
00266       NodePtr nodePtr = findInPath(dotDelimitedNode);
00267       VEntryNode * vEntryNode = dynamic_cast<VEntryNode *>(nodePtr.get());
00268        
00269       if(vEntryNode == 0)
00270       {
00271         throw edm::Exception(errors::Configuration,"")
00272         << dotDelimitedNode << " is not a vector of values";
00273       }
00274       else 
00275       {
00276         result = *(vEntryNode->value());
00277       }
00278       return result;
00279     }
00280 
00281     // names of the nodes below this one.  Includes are transparent
00282 
00283     std::vector<std::string> ParseTree::children(const std::string & dotDelimitedNode) const
00284     {
00285       std::vector<std::string> result; 
00286       //TODO
00287       return result;
00288     }
00289 
00290 
00291 
00292     void ParseTree::clear() 
00293     {
00294       blocks_.clear();
00295       copyNodes_.clear();
00296       renameNodes_.clear();
00297       replaceNodes_.clear();
00298       blockCopyNodes_.clear();
00299       blockRenameNodes_.clear();
00300       blockReplaceNodes_.clear();
00301       modulesAndSources_.clear();
00302     }
00303 
00304 
00305     void ParseTree::sortNodes(const NodePtrListPtr & nodes)
00306     {
00307 
00308       NodePtrList topLevelNodes;
00309       findTopLevelNodes(*nodes, topLevelNodes);
00310 
00311       for(NodePtrList::const_iterator nodeItr = topLevelNodes.begin(),
00312           nodeItrEnd = topLevelNodes.end(); nodeItr != nodeItrEnd; ++nodeItr)
00313       {
00314         // see what the type is
00315         std::string type = (*nodeItr)->type();
00316         std::string name = (*nodeItr)->name();
00317         // see if it's ont of the many types of ModuleNode first
00318         ModuleNode * moduleNode = dynamic_cast<ModuleNode *>((*nodeItr).get());
00319         if(moduleNode != 0) 
00320         {
00321           //@@TODO FIX HACK! unnamed es_prefers need to be unmodifiable for the
00322           // time being, since they can have the same class as a different es_source
00323           if(type != "es_prefer") 
00324           {
00325             // unnamed modules are named after class
00326             if(name == "nameless" || name == "" || name=="main_es_input") 
00327             {
00328               name = moduleNode->className();
00329             }
00330 
00331             // double-check that no duplication
00332             NodePtrMap::iterator moduleMapItr = modulesAndSources_.find(name);
00333             if(moduleMapItr != modulesAndSources_.end()) 
00334             {
00335               std::ostringstream firstTrace, secondTrace;
00336               moduleNode->printTrace(secondTrace);
00337               moduleMapItr->second->printTrace(firstTrace);
00338               if(firstTrace.str().empty()) firstTrace << "main config\n";
00339               if(secondTrace.str().empty()) secondTrace << "main config\n";
00340               throw edm::Exception(errors::Configuration,"") 
00341                << "Duplicate definition of " << name
00342                << "\nfirst: " << firstTrace.str()
00343                << "second: " << secondTrace.str()
00344                << "Please edit the configuration so it is only defined once";
00345               //edm::LogWarning("ParseTree") << "Duplicate definition of "
00346               //<< name << ". Only last one will be kept.";
00347             }
00348             modulesAndSources_[name] = *nodeItr;
00349           }
00350         } // moduleNode
00351   
00352         else if(type == "block" || type == "PSet") {
00353           blocks_[name] = *nodeItr;
00354         }
00355 
00356         else if(std::string(type,0,7) == "replace") {
00357           replaceNodes_.push_back(*nodeItr);
00358         }
00359 
00360         else if(type == "copy") {
00361           copyNodes_.push_back(*nodeItr);
00362         }
00363 
00364         else if(type == "rename") {
00365           renameNodes_.push_back(*nodeItr);
00366         }
00367 
00368       }
00369     }
00370 
00371 
00372     void ParseTree::processUsingBlocks()
00373     {
00374       // look for blocks-within-blocks first
00375       for(NodePtrMap::iterator blockItr = blocks_.begin(), blockItrEnd = blocks_.end();
00376           blockItr != blockItrEnd; ++blockItr)
00377       {
00378         blockItr->second->resolveUsingNodes(blocks_, strict_);
00379       }
00380       // look for blocks-within-blocks first
00381       for(NodePtrMap::iterator blockItr = blocks_.begin(), blockItrEnd = blocks_.end();
00382           blockItr != blockItrEnd; ++blockItr)
00383       {
00384         blockItr->second->resolveUsingNodes(blocks_, strict_);
00385       }
00386 
00387 
00388       for(NodePtrMap::iterator moduleItr = modulesAndSources_.begin(),
00389           moduleItrEnd = modulesAndSources_.end();
00390           moduleItr != moduleItrEnd; ++moduleItr)
00391       {
00392         moduleItr->second->resolveUsingNodes(blocks_, strict_);
00393       }
00394 
00395       // maybe there's a using statement inside a replace PSet?
00396       // You never know.
00397       for(NodePtrList::iterator replaceItr = replaceNodes_.begin(),
00398           replaceItrEnd = replaceNodes_.end();
00399           replaceItr != replaceItrEnd;  ++replaceItr)
00400       {
00401         ReplaceNode * replaceNode = dynamic_cast<ReplaceNode *>(replaceItr->get());
00402         CompositeNode * compositeNode = dynamic_cast<CompositeNode *>(replaceNode->value().get());
00403         if(compositeNode != 0)
00404         {
00405           compositeNode->resolveUsingNodes(blocks_, strict_);
00406         }
00407       } 
00408 
00409     }
00410 
00411 
00412     void ParseTree::processCopyNode(const NodePtr & n,
00413                                 ParseTree::NodePtrMap  & targetMap)
00414     {
00415       assert(false);
00416      /*
00417       const CopyNode * copyNode = dynamic_cast<const CopyNode*>(n.get());
00418       assert(copyNode != 0);
00419 
00420       NodePtr fromPtr = findPtr(copyNode->from(), targetMap);
00421       NodePtr toPtr(fromPtr->clone());
00422       toPtr->setName(copyNode->to());
00423 
00424       // and add it in the maps here
00425       targetMap[copyNode->to()] = toPtr;
00426       removeNode(n);
00427       */
00428     }
00429 
00430 
00431     void ParseTree::processRenameNode(const NodePtr & n,
00432                                   ParseTree::NodePtrMap  & targetMap)
00433     {
00434       const RenameNode * renameNode = dynamic_cast<const RenameNode*>(n.get());
00435       assert(renameNode != 0);
00436 
00437       NodePtr targetPtr = findPtr(renameNode->from(), targetMap);
00438       targetPtr->setName(renameNode->to());
00439 
00440       // and replace it in the maps here
00441       targetMap[renameNode->to()] = targetPtr;
00442       targetMap.erase(renameNode->from());
00443       // get rid of the renameNode
00444       removeNode(n);
00445     }
00446 
00447 
00448     void ParseTree::processReplaceNode(NodePtr & n,
00449                                 ParseTree::NodePtrMap  & targetMap)
00450     {
00451       try
00452       {
00453         NodePtr targetPtr = findInPath(n->name(), targetMap);
00454         ReplaceNode * replaceNode = dynamic_cast<ReplaceNode*>(n.get());
00455         assert(replaceNode != 0);
00456         // see if we need to resolve this replace node
00457         if(replaceNode->value()->type() == "dotdelimited")
00458         {
00459           NodePtr newValue( findInPath(replaceNode->value()->name(), blocks_) );
00460           replaceNode->setValue(newValue);
00461         }
00462         checkOkToModify(replaceNode, targetPtr);
00463         // we're here to replace it.  So replace it.
00464         targetPtr->replaceWith(replaceNode);
00465         removeNode(n);
00466       }
00467       catch(edm::Exception & e)
00468       {
00469         e.append("\n");
00470         e.append(n->traceback());
00471         throw e;
00472       }
00473     }
00474 
00475 
00476     void ParseTree::removeNode(const NodePtr & victim)
00477     {
00478       CompositeNode * parent  = dynamic_cast<CompositeNode *>(victim->getParent());
00479       assert(parent != 0);
00480       parent->removeChild(victim->name());
00481     }
00482 
00483 
00484     NodePtr ParseTree::findInPath(const std::string & path) const
00485     {
00486       // try blocks_, then modulesAndSources_
00487       NodePtr result;
00488       try 
00489       {
00490         result = findInPath(path, modulesAndSources_);
00491       }
00492       catch(const edm::Exception & e)
00493       {   
00494         // may throw... that's OK.
00495         result = findInPath(path, blocks_);
00496       }
00497       return result;
00498     }
00499 
00500 
00501     NodePtr ParseTree::findInPath(const std::string & path, 
00502                                   const ParseTree::NodePtrMap  & targetMap) const
00503     {
00504       typedef std::vector<std::string> stringvec_t;
00505       stringvec_t pathElements = tokenize(path, ".");
00506       stringvec_t::const_iterator it =  pathElements.begin();
00507       stringvec_t::const_iterator end = pathElements.end();
00508 
00509       // top level should be the module
00510       NodePtr currentPtr = findPtr(*it, targetMap);
00511       // dig deeper, if we have to
00512       ++it;
00513       while(it != end)
00514       {
00515         if(currentPtr->findChild(*it, currentPtr) == false)
00516         {
00517           std::ostringstream tr;
00518           currentPtr->printTrace(tr);
00519           throw edm::Exception(errors::Configuration,"No such element")
00520              << "Could not find: " << *it << " in " 
00521              << currentPtr->type() << " " << currentPtr->name()
00522              << "\n" << tr.str();
00523         }
00524 
00525         ++it; 
00526       }
00527     
00528       return currentPtr;
00529     }
00530 
00531 
00532     NodePtr ParseTree::findPtr(const std::string & name, 
00533                                const ParseTree::NodePtrMap  & targetMap) const 
00534     {
00535       NodePtrMap::const_iterator mapItr = targetMap.find(name);
00536       if(mapItr == targetMap.end()) {
00537         throw edm::Exception(errors::Configuration,"No Such Object") 
00538                 << "Cannot find " << name;
00539       }
00540       return mapItr->second;
00541     }
00542 
00543 
00544     void ParseTree::findBlockModifiers(NodePtrList & modifierNodes,
00545                                                  NodePtrList & blockModifiers)
00546     {
00547       // need to be careful not to invalidate iterators when we erase
00548       NodePtrList::iterator modifierItr = modifierNodes.begin();
00549       while(modifierItr != modifierNodes.end())
00550       {
00551         NodePtrList::iterator next = modifierItr;
00552         ++next;
00553 
00554         // see if this name is a block name
00555         std::string topLevel = tokenize((**modifierItr).name(), ".")[0];
00556         if(blocks_.find(topLevel) != blocks_.end())
00557         {
00558           if(strict_)
00559           {
00560             throw edm::Exception(errors::Configuration)
00561               << "Strict parsing disallows modifying blocks";
00562           }
00563           else 
00564           {
00565             blockModifiers.push_back(*modifierItr);
00566             modifierNodes.erase(modifierItr);
00567           }
00568         }
00569         modifierItr = next;
00570       }
00571     }
00572 
00573 
00574     void ParseTree::findTopLevelNodes(const NodePtrList & input, NodePtrList & output)
00575     {
00576       for(NodePtrList::const_iterator inputNodeItr = input.begin(), inputNodeItrEnd = input.end();
00577           inputNodeItr != inputNodeItrEnd; ++inputNodeItr)
00578       {
00579         // make IncludeNodes transparent
00580         if((**inputNodeItr).isInclude())
00581         {
00582           const IncludeNode * includeNode 
00583             = dynamic_cast<const IncludeNode*>(inputNodeItr->get());
00584           assert(includeNode != 0);
00585           // recursive call!
00586           findTopLevelNodes(*(includeNode->nodes()), output);
00587           // just to make sure recursion didn't bite me
00588           assert((**inputNodeItr).isInclude());
00589         }
00590         else 
00591         {
00592           output.push_back(*inputNodeItr);
00593         }
00594       }
00595     }
00596 
00597 
00598     void ParseTree::checkOkToModify(const ReplaceNode * replaceNode, NodePtr targetNode)
00599     {
00600       if(targetNode->isModified() && !(replaceNode->okToRemodify()))
00601       {
00602         throw edm::Exception(errors::Configuration)
00603           << "Cannot replace a node that has already been modified: " 
00604           << targetNode->name() << "\n" << targetNode->traceback();
00605       }
00606       if( replaceNode->isEmbedded() && !(targetNode->isCloned()) 
00607           && targetNode->isTracked()
00608           && targetNode->name() != "outputCommands")
00609       {
00610         // one last chance: see if the replace is in the same include file as the
00611         // module definition
00612         std::string topLevelName = tokenize(replaceNode->name(), ".")[0];
00613         NodePtrMap::const_iterator mapItr = modulesAndSources_.find(topLevelName);
00614         if(mapItr == modulesAndSources_.end() 
00615           || mapItr->second->getParent()->name() != replaceNode->getParent()->name()) 
00616         {
00617           if(strict_)
00618           { 
00619             edm::LogWarning("Configuration")
00620             << "Do not embed replace statements to modify a parameter "
00621             << "from a module which hasn't been cloned: " 
00622             << "\n" << "  Parameter " << targetNode->name() 
00623             << " in " << topLevelName
00624             << "\n  Replace happens in " << replaceNode->getParent()->name()
00625             << "\n  This will be an error in future releases.  Please fix.";
00626           }
00627         }
00628       }
00629 
00630     }
00631 
00632    
00633     void ParseTree::validate() const
00634     {
00635       top()->validate();
00636     }
00637 
00638   }  // pset namespace
00639 } // edm namespace
00640 

Generated on Tue Jun 9 17:36:29 2009 for CMSSW by  doxygen 1.5.4