cmGeneratorExpressionEvaluator.cxx 24 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711
  1. /*============================================================================
  2. CMake - Cross Platform Makefile Generator
  3. Copyright 2012 Stephen Kelly <[email protected]>
  4. Distributed under the OSI-approved BSD License (the "License");
  5. see accompanying file Copyright.txt for details.
  6. This software is distributed WITHOUT ANY WARRANTY; without even the
  7. implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
  8. See the License for more information.
  9. ============================================================================*/
  10. #include "cmMakefile.h"
  11. #include "cmGeneratorExpressionEvaluator.h"
  12. #include "cmGeneratorExpressionParser.h"
  13. #include "cmGeneratorExpressionDAGChecker.h"
  14. #include "cmGeneratorExpression.h"
  15. //----------------------------------------------------------------------------
  16. static void reportError(cmGeneratorExpressionContext *context,
  17. const std::string &expr, const std::string &result)
  18. {
  19. context->HadError = true;
  20. if (context->Quiet)
  21. {
  22. return;
  23. }
  24. cmOStringStream e;
  25. e << "Error evaluating generator expression:\n"
  26. << " " << expr << "\n"
  27. << result;
  28. context->Makefile->GetCMakeInstance()
  29. ->IssueMessage(cmake::FATAL_ERROR, e.str().c_str(),
  30. context->Backtrace);
  31. }
  32. //----------------------------------------------------------------------------
  33. struct cmGeneratorExpressionNode
  34. {
  35. virtual ~cmGeneratorExpressionNode() {}
  36. virtual bool GeneratesContent() const { return true; }
  37. virtual bool AcceptsSingleArbitraryContentParameter() const
  38. { return false; }
  39. virtual int NumExpectedParameters() const { return 1; }
  40. virtual std::string Evaluate(const std::vector<std::string> &parameters,
  41. cmGeneratorExpressionContext *context,
  42. const GeneratorExpressionContent *content,
  43. cmGeneratorExpressionDAGChecker *dagChecker
  44. ) const = 0;
  45. };
  46. //----------------------------------------------------------------------------
  47. static const struct ZeroNode : public cmGeneratorExpressionNode
  48. {
  49. ZeroNode() {}
  50. virtual bool GeneratesContent() const { return false; }
  51. std::string Evaluate(const std::vector<std::string> &,
  52. cmGeneratorExpressionContext *,
  53. const GeneratorExpressionContent *,
  54. cmGeneratorExpressionDAGChecker *) const
  55. {
  56. // Unreachable
  57. return std::string();
  58. }
  59. } zeroNode;
  60. //----------------------------------------------------------------------------
  61. static const struct OneNode : public cmGeneratorExpressionNode
  62. {
  63. OneNode() {}
  64. virtual bool AcceptsSingleArbitraryContentParameter() const { return true; }
  65. std::string Evaluate(const std::vector<std::string> &,
  66. cmGeneratorExpressionContext *,
  67. const GeneratorExpressionContent *,
  68. cmGeneratorExpressionDAGChecker *) const
  69. {
  70. // Unreachable
  71. return std::string();
  72. }
  73. } oneNode;
  74. //----------------------------------------------------------------------------
  75. #define BOOLEAN_OP_NODE(OPNAME, OP, SUCCESS_VALUE, FAILURE_VALUE) \
  76. static const struct OP ## Node : public cmGeneratorExpressionNode \
  77. { \
  78. OP ## Node () {} \
  79. /* We let -1 carry the meaning 'at least one' */ \
  80. virtual int NumExpectedParameters() const { return -1; } \
  81. \
  82. std::string Evaluate(const std::vector<std::string> &parameters, \
  83. cmGeneratorExpressionContext *context, \
  84. const GeneratorExpressionContent *content, \
  85. cmGeneratorExpressionDAGChecker *) const \
  86. { \
  87. std::vector<std::string>::const_iterator it = parameters.begin(); \
  88. const std::vector<std::string>::const_iterator end = parameters.end(); \
  89. for ( ; it != end; ++it) \
  90. { \
  91. if (*it == #FAILURE_VALUE) \
  92. { \
  93. return #FAILURE_VALUE; \
  94. } \
  95. else if (*it != #SUCCESS_VALUE) \
  96. { \
  97. reportError(context, content->GetOriginalExpression(), \
  98. "Parameters to $<" #OP "> must resolve to either '0' or '1'."); \
  99. return std::string(); \
  100. } \
  101. } \
  102. return #SUCCESS_VALUE; \
  103. } \
  104. } OPNAME;
  105. BOOLEAN_OP_NODE(andNode, AND, 1, 0)
  106. BOOLEAN_OP_NODE(orNode, OR, 0, 1)
  107. #undef BOOLEAN_OP_NODE
  108. //----------------------------------------------------------------------------
  109. static const struct NotNode : public cmGeneratorExpressionNode
  110. {
  111. NotNode() {}
  112. std::string Evaluate(const std::vector<std::string> &parameters,
  113. cmGeneratorExpressionContext *context,
  114. const GeneratorExpressionContent *content,
  115. cmGeneratorExpressionDAGChecker *) const
  116. {
  117. if (*parameters.begin() != "0" && *parameters.begin() != "1")
  118. {
  119. reportError(context, content->GetOriginalExpression(),
  120. "$<NOT> parameter must resolve to exactly one '0' or '1' value.");
  121. return std::string();
  122. }
  123. return *parameters.begin() == "0" ? "1" : "0";
  124. }
  125. } notNode;
  126. //----------------------------------------------------------------------------
  127. static const struct BoolNode : public cmGeneratorExpressionNode
  128. {
  129. BoolNode() {}
  130. virtual int NumExpectedParameters() const { return 1; }
  131. std::string Evaluate(const std::vector<std::string> &parameters,
  132. cmGeneratorExpressionContext *,
  133. const GeneratorExpressionContent *,
  134. cmGeneratorExpressionDAGChecker *) const
  135. {
  136. return !cmSystemTools::IsOff(parameters.begin()->c_str()) ? "1" : "0";
  137. }
  138. } boolNode;
  139. //----------------------------------------------------------------------------
  140. static const struct StrEqualNode : public cmGeneratorExpressionNode
  141. {
  142. StrEqualNode() {}
  143. virtual int NumExpectedParameters() const { return 2; }
  144. std::string Evaluate(const std::vector<std::string> &parameters,
  145. cmGeneratorExpressionContext *,
  146. const GeneratorExpressionContent *,
  147. cmGeneratorExpressionDAGChecker *) const
  148. {
  149. return *parameters.begin() == parameters.at(1) ? "1" : "0";
  150. }
  151. } strEqualNode;
  152. //----------------------------------------------------------------------------
  153. static const struct Angle_RNode : public cmGeneratorExpressionNode
  154. {
  155. Angle_RNode() {}
  156. virtual int NumExpectedParameters() const { return 0; }
  157. std::string Evaluate(const std::vector<std::string> &,
  158. cmGeneratorExpressionContext *,
  159. const GeneratorExpressionContent *,
  160. cmGeneratorExpressionDAGChecker *) const
  161. {
  162. return ">";
  163. }
  164. } angle_rNode;
  165. //----------------------------------------------------------------------------
  166. static const struct CommaNode : public cmGeneratorExpressionNode
  167. {
  168. CommaNode() {}
  169. virtual int NumExpectedParameters() const { return 0; }
  170. std::string Evaluate(const std::vector<std::string> &,
  171. cmGeneratorExpressionContext *,
  172. const GeneratorExpressionContent *,
  173. cmGeneratorExpressionDAGChecker *) const
  174. {
  175. return ",";
  176. }
  177. } commaNode;
  178. //----------------------------------------------------------------------------
  179. static const struct ConfigurationNode : public cmGeneratorExpressionNode
  180. {
  181. ConfigurationNode() {}
  182. virtual int NumExpectedParameters() const { return 0; }
  183. std::string Evaluate(const std::vector<std::string> &,
  184. cmGeneratorExpressionContext *context,
  185. const GeneratorExpressionContent *,
  186. cmGeneratorExpressionDAGChecker *) const
  187. {
  188. return context->Config ? context->Config : "";
  189. }
  190. } configurationNode;
  191. //----------------------------------------------------------------------------
  192. static const struct ConfigurationTestNode : public cmGeneratorExpressionNode
  193. {
  194. ConfigurationTestNode() {}
  195. virtual int NumExpectedParameters() const { return 1; }
  196. std::string Evaluate(const std::vector<std::string> &parameters,
  197. cmGeneratorExpressionContext *context,
  198. const GeneratorExpressionContent *content,
  199. cmGeneratorExpressionDAGChecker *) const
  200. {
  201. if (!context->Config)
  202. {
  203. return std::string();
  204. }
  205. cmsys::RegularExpression configValidator;
  206. configValidator.compile("^[A-Za-z0-9_]*$");
  207. if (!configValidator.find(parameters.begin()->c_str()))
  208. {
  209. reportError(context, content->GetOriginalExpression(),
  210. "Expression syntax not recognized.");
  211. return std::string();
  212. }
  213. return *parameters.begin() == context->Config ? "1" : "0";
  214. }
  215. } configurationTestNode;
  216. //----------------------------------------------------------------------------
  217. static const struct TargetPropertyNode : public cmGeneratorExpressionNode
  218. {
  219. TargetPropertyNode() {}
  220. // This node handles errors on parameter count itself.
  221. virtual int NumExpectedParameters() const { return -1; }
  222. std::string Evaluate(const std::vector<std::string> &parameters,
  223. cmGeneratorExpressionContext *context,
  224. const GeneratorExpressionContent *content,
  225. cmGeneratorExpressionDAGChecker *dagCheckerParent
  226. ) const
  227. {
  228. if (parameters.size() != 1 && parameters.size() != 2)
  229. {
  230. reportError(context, content->GetOriginalExpression(),
  231. "$<TARGET_PROPERTY:...> expression requires one or two parameters");
  232. return std::string();
  233. }
  234. cmGeneratorTarget* target = context->Target;
  235. std::string propertyName = *parameters.begin();
  236. if (parameters.size() == 2)
  237. {
  238. target = context->Makefile->FindGeneratorTargetToUse(
  239. parameters.begin()->c_str());
  240. if (!target)
  241. {
  242. cmOStringStream e;
  243. e << "Target \""
  244. << target
  245. << "\" not found.";
  246. reportError(context, content->GetOriginalExpression(), e.str());
  247. }
  248. propertyName = parameters.at(1);
  249. }
  250. cmGeneratorExpressionDAGChecker dagChecker(context->Backtrace,
  251. target->GetName(),
  252. propertyName,
  253. content,
  254. dagCheckerParent);
  255. if (!dagChecker.check())
  256. {
  257. dagChecker.reportError(context, content->GetOriginalExpression());
  258. return std::string();
  259. }
  260. const char *prop = target->GetProperty(propertyName.c_str());
  261. return prop ? prop : "";
  262. }
  263. } targetPropertyNode;
  264. //----------------------------------------------------------------------------
  265. template<bool linker, bool soname>
  266. struct TargetFilesystemArtifactResultCreator
  267. {
  268. static std::string Create(cmTarget* target,
  269. cmGeneratorExpressionContext *context,
  270. const GeneratorExpressionContent *content);
  271. };
  272. //----------------------------------------------------------------------------
  273. template<>
  274. struct TargetFilesystemArtifactResultCreator<false, true>
  275. {
  276. static std::string Create(cmTarget* target,
  277. cmGeneratorExpressionContext *context,
  278. const GeneratorExpressionContent *content)
  279. {
  280. // The target soname file (.so.1).
  281. if(target->IsDLLPlatform())
  282. {
  283. ::reportError(context, content->GetOriginalExpression(),
  284. "TARGET_SONAME_FILE is not allowed "
  285. "for DLL target platforms.");
  286. return std::string();
  287. }
  288. if(target->GetType() != cmTarget::SHARED_LIBRARY)
  289. {
  290. ::reportError(context, content->GetOriginalExpression(),
  291. "TARGET_SONAME_FILE is allowed only for "
  292. "SHARED libraries.");
  293. return std::string();
  294. }
  295. std::string result = target->GetDirectory(context->Config);
  296. result += "/";
  297. result += target->GetSOName(context->Config);
  298. return result;
  299. }
  300. };
  301. //----------------------------------------------------------------------------
  302. template<>
  303. struct TargetFilesystemArtifactResultCreator<true, false>
  304. {
  305. static std::string Create(cmTarget* target,
  306. cmGeneratorExpressionContext *context,
  307. const GeneratorExpressionContent *content)
  308. {
  309. // The file used to link to the target (.so, .lib, .a).
  310. if(!target->IsLinkable())
  311. {
  312. ::reportError(context, content->GetOriginalExpression(),
  313. "TARGET_LINKER_FILE is allowed only for libraries and "
  314. "executables with ENABLE_EXPORTS.");
  315. return std::string();
  316. }
  317. return target->GetFullPath(context->Config,
  318. target->HasImportLibrary());
  319. }
  320. };
  321. //----------------------------------------------------------------------------
  322. template<>
  323. struct TargetFilesystemArtifactResultCreator<false, false>
  324. {
  325. static std::string Create(cmTarget* target,
  326. cmGeneratorExpressionContext *context,
  327. const GeneratorExpressionContent *)
  328. {
  329. return target->GetFullPath(context->Config, false, true);
  330. }
  331. };
  332. //----------------------------------------------------------------------------
  333. template<bool dirQual, bool nameQual>
  334. struct TargetFilesystemArtifactResultGetter
  335. {
  336. static std::string Get(const std::string &result);
  337. };
  338. //----------------------------------------------------------------------------
  339. template<>
  340. struct TargetFilesystemArtifactResultGetter<false, true>
  341. {
  342. static std::string Get(const std::string &result)
  343. { return cmSystemTools::GetFilenameName(result); }
  344. };
  345. //----------------------------------------------------------------------------
  346. template<>
  347. struct TargetFilesystemArtifactResultGetter<true, false>
  348. {
  349. static std::string Get(const std::string &result)
  350. { return cmSystemTools::GetFilenamePath(result); }
  351. };
  352. //----------------------------------------------------------------------------
  353. template<>
  354. struct TargetFilesystemArtifactResultGetter<false, false>
  355. {
  356. static std::string Get(const std::string &result)
  357. { return result; }
  358. };
  359. //----------------------------------------------------------------------------
  360. template<bool linker, bool soname, bool dirQual, bool nameQual>
  361. struct TargetFilesystemArtifact : public cmGeneratorExpressionNode
  362. {
  363. TargetFilesystemArtifact() {}
  364. virtual int NumExpectedParameters() const { return 1; }
  365. std::string Evaluate(const std::vector<std::string> &parameters,
  366. cmGeneratorExpressionContext *context,
  367. const GeneratorExpressionContent *content,
  368. cmGeneratorExpressionDAGChecker *) const
  369. {
  370. // Lookup the referenced target.
  371. std::string name = *parameters.begin();
  372. cmsys::RegularExpression targetValidator;
  373. targetValidator.compile("^[A-Za-z0-9_.-]+$");
  374. if (!targetValidator.find(name.c_str()))
  375. {
  376. ::reportError(context, content->GetOriginalExpression(),
  377. "Expression syntax not recognized.");
  378. return std::string();
  379. }
  380. cmTarget* target = context->Makefile->FindTargetToUse(name.c_str());
  381. if(!target)
  382. {
  383. ::reportError(context, content->GetOriginalExpression(),
  384. "No target \"" + name + "\"");
  385. return std::string();
  386. }
  387. if(target->GetType() >= cmTarget::UTILITY &&
  388. target->GetType() != cmTarget::UNKNOWN_LIBRARY)
  389. {
  390. ::reportError(context, content->GetOriginalExpression(),
  391. "Target \"" + name + "\" is not an executable or library.");
  392. return std::string();
  393. }
  394. context->Targets.insert(target);
  395. std::string result =
  396. TargetFilesystemArtifactResultCreator<linker, soname>::Create(
  397. target,
  398. context,
  399. content);
  400. if (context->HadError)
  401. {
  402. return std::string();
  403. }
  404. return
  405. TargetFilesystemArtifactResultGetter<dirQual, nameQual>::Get(result);
  406. }
  407. };
  408. //----------------------------------------------------------------------------
  409. static const
  410. TargetFilesystemArtifact<false, false, false, false> targetFileNode;
  411. static const
  412. TargetFilesystemArtifact<true, false, false, false> targetLinkerFileNode;
  413. static const
  414. TargetFilesystemArtifact<false, true, false, false> targetSoNameFileNode;
  415. static const
  416. TargetFilesystemArtifact<false, false, false, true> targetFileNameNode;
  417. static const
  418. TargetFilesystemArtifact<true, false, false, true> targetLinkerFileNameNode;
  419. static const
  420. TargetFilesystemArtifact<false, true, false, true> targetSoNameFileNameNode;
  421. static const
  422. TargetFilesystemArtifact<false, false, true, false> targetFileDirNode;
  423. static const
  424. TargetFilesystemArtifact<true, false, true, false> targetLinkerFileDirNode;
  425. static const
  426. TargetFilesystemArtifact<false, true, true, false> targetSoNameFileDirNode;
  427. //----------------------------------------------------------------------------
  428. static const
  429. cmGeneratorExpressionNode* GetNode(const std::string &identifier)
  430. {
  431. if (identifier == "0")
  432. return &zeroNode;
  433. if (identifier == "1")
  434. return &oneNode;
  435. if (identifier == "AND")
  436. return &andNode;
  437. if (identifier == "OR")
  438. return &orNode;
  439. if (identifier == "NOT")
  440. return &notNode;
  441. else if (identifier == "CONFIGURATION")
  442. return &configurationNode;
  443. else if (identifier == "CONFIG")
  444. return &configurationTestNode;
  445. else if (identifier == "TARGET_FILE")
  446. return &targetFileNode;
  447. else if (identifier == "TARGET_LINKER_FILE")
  448. return &targetLinkerFileNode;
  449. else if (identifier == "TARGET_SONAME_FILE")
  450. return &targetSoNameFileNode;
  451. else if (identifier == "TARGET_FILE_NAME")
  452. return &targetFileNameNode;
  453. else if (identifier == "TARGET_LINKER_FILE_NAME")
  454. return &targetLinkerFileNameNode;
  455. else if (identifier == "TARGET_SONAME_FILE_NAME")
  456. return &targetSoNameFileNameNode;
  457. else if (identifier == "TARGET_FILE_DIR")
  458. return &targetFileDirNode;
  459. else if (identifier == "TARGET_LINKER_FILE_DIR")
  460. return &targetLinkerFileDirNode;
  461. else if (identifier == "TARGET_SONAME_FILE_DIR")
  462. return &targetSoNameFileDirNode;
  463. else if (identifier == "STREQUAL")
  464. return &strEqualNode;
  465. else if (identifier == "BOOL")
  466. return &boolNode;
  467. else if (identifier == "ANGLE-R")
  468. return &angle_rNode;
  469. else if (identifier == "COMMA")
  470. return &commaNode;
  471. else if (identifier == "TARGET_PROPERTY")
  472. return &targetPropertyNode;
  473. return 0;
  474. }
  475. //----------------------------------------------------------------------------
  476. GeneratorExpressionContent::GeneratorExpressionContent(
  477. const char *startContent,
  478. unsigned int length)
  479. : StartContent(startContent), ContentLength(length)
  480. {
  481. }
  482. //----------------------------------------------------------------------------
  483. std::string GeneratorExpressionContent::GetOriginalExpression() const
  484. {
  485. return std::string(this->StartContent, this->ContentLength);
  486. }
  487. //----------------------------------------------------------------------------
  488. std::string GeneratorExpressionContent::Evaluate(
  489. cmGeneratorExpressionContext *context,
  490. cmGeneratorExpressionDAGChecker *dagChecker) const
  491. {
  492. std::string identifier;
  493. {
  494. std::vector<cmGeneratorExpressionEvaluator*>::const_iterator it
  495. = this->IdentifierChildren.begin();
  496. const std::vector<cmGeneratorExpressionEvaluator*>::const_iterator end
  497. = this->IdentifierChildren.end();
  498. for ( ; it != end; ++it)
  499. {
  500. identifier += (*it)->Evaluate(context, dagChecker);
  501. if (context->HadError)
  502. {
  503. return std::string();
  504. }
  505. }
  506. }
  507. const cmGeneratorExpressionNode *node = GetNode(identifier);
  508. if (!node)
  509. {
  510. reportError(context, this->GetOriginalExpression(),
  511. "Expression did not evaluate to a known generator expression");
  512. return std::string();
  513. }
  514. if (!node->GeneratesContent())
  515. {
  516. return std::string();
  517. }
  518. if (node->AcceptsSingleArbitraryContentParameter())
  519. {
  520. std::string result;
  521. std::vector<std::vector<cmGeneratorExpressionEvaluator*> >::const_iterator
  522. pit = this->ParamChildren.begin();
  523. const
  524. std::vector<std::vector<cmGeneratorExpressionEvaluator*> >::const_iterator
  525. pend = this->ParamChildren.end();
  526. for ( ; pit != pend; ++pit)
  527. {
  528. if (!result.empty())
  529. {
  530. result += ",";
  531. }
  532. std::vector<cmGeneratorExpressionEvaluator*>::const_iterator it
  533. = pit->begin();
  534. const std::vector<cmGeneratorExpressionEvaluator*>::const_iterator end
  535. = pit->end();
  536. for ( ; it != end; ++it)
  537. {
  538. result += (*it)->Evaluate(context, dagChecker);
  539. if (context->HadError)
  540. {
  541. return std::string();
  542. }
  543. }
  544. }
  545. return result;
  546. }
  547. std::vector<std::string> parameters;
  548. {
  549. std::vector<std::vector<cmGeneratorExpressionEvaluator*> >::const_iterator
  550. pit = this->ParamChildren.begin();
  551. const
  552. std::vector<std::vector<cmGeneratorExpressionEvaluator*> >::const_iterator
  553. pend = this->ParamChildren.end();
  554. for ( ; pit != pend; ++pit)
  555. {
  556. std::string parameter;
  557. std::vector<cmGeneratorExpressionEvaluator*>::const_iterator it =
  558. pit->begin();
  559. const std::vector<cmGeneratorExpressionEvaluator*>::const_iterator end =
  560. pit->end();
  561. for ( ; it != end; ++it)
  562. {
  563. parameter += (*it)->Evaluate(context, dagChecker);
  564. if (context->HadError)
  565. {
  566. return std::string();
  567. }
  568. }
  569. parameters.push_back(parameter);
  570. }
  571. }
  572. int numExpected = node->NumExpectedParameters();
  573. if ((numExpected != -1 && (unsigned int)numExpected != parameters.size()))
  574. {
  575. if (numExpected == 0)
  576. {
  577. reportError(context, this->GetOriginalExpression(),
  578. "$<" + identifier + "> expression requires no parameters.");
  579. }
  580. else if (numExpected == 1)
  581. {
  582. reportError(context, this->GetOriginalExpression(),
  583. "$<" + identifier + "> expression requires "
  584. "exactly one parameter.");
  585. }
  586. else
  587. {
  588. cmOStringStream e;
  589. e << "$<" + identifier + "> expression requires "
  590. << numExpected
  591. << " comma separated parameters, but got "
  592. << parameters.size() << " instead.";
  593. reportError(context, this->GetOriginalExpression(), e.str());
  594. }
  595. return std::string();
  596. }
  597. if (numExpected == -1 && parameters.empty())
  598. {
  599. reportError(context, this->GetOriginalExpression(), "$<" + identifier
  600. + "> expression requires at least one parameter.");
  601. return std::string();
  602. }
  603. return node->Evaluate(parameters, context, this, dagChecker);
  604. }
  605. //----------------------------------------------------------------------------
  606. static void deleteAll(const std::vector<cmGeneratorExpressionEvaluator*> &c)
  607. {
  608. std::vector<cmGeneratorExpressionEvaluator*>::const_iterator it
  609. = c.begin();
  610. const std::vector<cmGeneratorExpressionEvaluator*>::const_iterator end
  611. = c.end();
  612. for ( ; it != end; ++it)
  613. {
  614. delete *it;
  615. }
  616. }
  617. //----------------------------------------------------------------------------
  618. GeneratorExpressionContent::~GeneratorExpressionContent()
  619. {
  620. deleteAll(this->IdentifierChildren);
  621. typedef std::vector<cmGeneratorExpressionEvaluator*> EvaluatorVector;
  622. typedef std::vector<cmGeneratorExpressionToken> TokenVector;
  623. std::vector<EvaluatorVector>::const_iterator pit =
  624. this->ParamChildren.begin();
  625. const std::vector<EvaluatorVector>::const_iterator pend =
  626. this->ParamChildren.end();
  627. for ( ; pit != pend; ++pit)
  628. {
  629. deleteAll(*pit);
  630. }
  631. }