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
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
00125
00126 topLevelNode->setAsChildrensParent();
00127
00128
00129
00130 std::list<std::string> openFiles;
00131 std::list<std::string> sameLevelIncludes;
00132 topLevelNode->resolve(openFiles, sameLevelIncludes, strict_);
00133
00134
00135
00136 NodePtrListPtr contents = topLevelNode->nodes();
00137 sortNodes(contents);
00138
00139
00140 if( !copyNodes_.empty() || !replaceNodes_.empty()
00141 || !renameNodes_.empty() || !blocks_.empty() )
00142 {
00143
00144 findBlockModifiers(copyNodes_, blockCopyNodes_);
00145 findBlockModifiers(renameNodes_, blockRenameNodes_);
00146 findBlockModifiers(replaceNodes_, blockReplaceNodes_);
00147
00148
00149 for(NodePtrList::iterator nodeItr = blockCopyNodes_.begin(), nodeItrEnd = blockCopyNodes_.end();
00150 nodeItr != nodeItrEnd; ++nodeItr)
00151 {
00152 processCopyNode(*nodeItr, blocks_);
00153 }
00154
00155
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
00165 for(NodePtrList::iterator nodeItr = blockReplaceNodes_.begin(),
00166 nodeItrEnd = blockReplaceNodes_.end();
00167 nodeItr != nodeItrEnd; ++nodeItr)
00168 {
00169 processReplaceNode(*nodeItr, blocks_);
00170 }
00171 }
00172
00173
00174
00175
00176 processUsingBlocks();
00177
00178
00179 for(NodePtrList::iterator nodeItr = copyNodes_.begin(), nodeItrEnd = copyNodes_.end();
00180 nodeItr != nodeItrEnd; ++nodeItr)
00181 {
00182 processCopyNode(*nodeItr, modulesAndSources_);
00183 }
00184
00185
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
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
00205
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
00282
00283 std::vector<std::string> ParseTree::children(const std::string & dotDelimitedNode) const
00284 {
00285 std::vector<std::string> result;
00286
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
00315 std::string type = (*nodeItr)->type();
00316 std::string name = (*nodeItr)->name();
00317
00318 ModuleNode * moduleNode = dynamic_cast<ModuleNode *>((*nodeItr).get());
00319 if(moduleNode != 0)
00320 {
00321
00322
00323 if(type != "es_prefer")
00324 {
00325
00326 if(name == "nameless" || name == "" || name=="main_es_input")
00327 {
00328 name = moduleNode->className();
00329 }
00330
00331
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
00346
00347 }
00348 modulesAndSources_[name] = *nodeItr;
00349 }
00350 }
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
00375 for(NodePtrMap::iterator blockItr = blocks_.begin(), blockItrEnd = blocks_.end();
00376 blockItr != blockItrEnd; ++blockItr)
00377 {
00378 blockItr->second->resolveUsingNodes(blocks_, strict_);
00379 }
00380
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
00396
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
00418
00419
00420
00421
00422
00423
00424
00425
00426
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
00441 targetMap[renameNode->to()] = targetPtr;
00442 targetMap.erase(renameNode->from());
00443
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
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
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
00487 NodePtr result;
00488 try
00489 {
00490 result = findInPath(path, modulesAndSources_);
00491 }
00492 catch(const edm::Exception & e)
00493 {
00494
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
00510 NodePtr currentPtr = findPtr(*it, targetMap);
00511
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
00548 NodePtrList::iterator modifierItr = modifierNodes.begin();
00549 while(modifierItr != modifierNodes.end())
00550 {
00551 NodePtrList::iterator next = modifierItr;
00552 ++next;
00553
00554
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
00580 if((**inputNodeItr).isInclude())
00581 {
00582 const IncludeNode * includeNode
00583 = dynamic_cast<const IncludeNode*>(inputNodeItr->get());
00584 assert(includeNode != 0);
00585
00586 findTopLevelNodes(*(includeNode->nodes()), output);
00587
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
00611
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 }
00639 }
00640