1 /*! 2 * \file mfront/src/ModelDSLCommon.cxx 3 * \brief 4 * \author Thomas Helfer 5 * \brief 11 jun 2010 6 * \copyright Copyright (C) 2006-2018 CEA/DEN, EDF R&D. All rights 7 * reserved. 8 * This project is publicly released under either the GNU GPL Licence 9 * or the CECILL-A licence. A copy of thoses licences are delivered 10 * with the sources of TFEL. CEA or EDF may also distribute this 11 * project under specific licensing conditions. 12 */ 13 14 #include <sstream> 15 #include <stdexcept> 16 #include <algorithm> 17 #include "TFEL/Raise.hxx" 18 #include "TFEL/Glossary/Glossary.hxx" 19 #include "TFEL/Glossary/GlossaryEntry.hxx" 20 #include "TFEL/Utilities/StringAlgorithms.hxx" 21 #include "TFEL/UnicodeSupport/UnicodeSupport.hxx" 22 #include "MFront/DSLUtilities.hxx" 23 #include "MFront/MFrontLogStream.hxx" 24 #include "MFront/MFrontDebugMode.hxx" 25 #include "MFront/ModelDSLCommon.hxx" 26 #include "MFront/TargetsDescription.hxx" 27 #include "MFront/ModelInterfaceFactory.hxx" 28 29 // fixing a bug on current glibc++ cygwin versions (19/08/2015) 30 #if defined __CYGWIN__ && (!defined _GLIBCXX_USE_C99) 31 #include <sstream> 32 namespace std { 33 template <typename T> to_string(const T & v)34 std::string to_string(const T& v) { 35 std::ostringstream s; 36 s << v; 37 return s.str(); 38 } 39 } 40 #endif /* defined __CYGWIN__ && (!defined _GLIBCXX_USE_C99) */ 41 42 namespace mfront { 43 is(const VariableDescriptionContainer & vc,const std::string & vn)44 static bool is(const VariableDescriptionContainer& vc, 45 const std::string& vn) { 46 for (const auto& v : vc) { 47 if (v.name == vn) { 48 return true; 49 } 50 if (v.hasAttribute(VariableDescription::depth)) { 51 const auto d = 52 v.getAttribute<unsigned short>(VariableDescription::depth); 53 for (unsigned short i = 1; i != d + 1; ++i) { 54 if (v.name + '_' + std::to_string(i) == vn) { 55 return true; 56 } 57 } 58 } 59 } 60 return false; 61 } // end of ModelDSLCommon::is() 62 isValidModelName(const std::string & n)63 bool isValidModelName(const std::string& n) { 64 return tfel::utilities::CxxTokenizer::isValidIdentifier(n, false); 65 } 66 ModelDSLCommon()67 ModelDSLCommon::ModelDSLCommon() { 68 this->reserveName("dt"); 69 this->reserveName("\u0394t"); 70 for (const auto& v : DSLBase::getDefaultReservedNames()) { 71 this->reserveName(v); 72 } 73 } 74 getMaterialKnowledgeIdentifier() const75 std::string ModelDSLCommon::getMaterialKnowledgeIdentifier() const { 76 return this->md.className; 77 } // end of ModelDSLCommon::getMaterialKnowledgeIdentifier 78 getMaterialName() const79 std::string ModelDSLCommon::getMaterialName() const { 80 return this->md.material; 81 } // end of ModelDSLCommon::getMaterialName( 82 getOverridableVariableNameByExternalName(const std::string &) const83 std::string ModelDSLCommon::getOverridableVariableNameByExternalName( 84 const std::string&) const { 85 #pragma message("unimplemented") 86 tfel::raise( 87 "ModelDSLCommon::getOverridableVariableNameByExternalName: " 88 "unimplemented feature"); 89 return ""; 90 } // end of ModelDSLCommon::getOverridableVariableNameByExternalName 91 overrideByAParameter(const std::string & n,const double v)92 void ModelDSLCommon::overrideByAParameter(const std::string& n, 93 const double v) { 94 #pragma message("unimplemented") 95 } // end of ModelDSLCommon::overrideByAParameter 96 endsInputFileProcessing()97 void ModelDSLCommon::endsInputFileProcessing() { 98 } // end of ModelDSLCommon::endsInputFileProcessing 99 reserveName(const std::string & n)100 void ModelDSLCommon::reserveName(const std::string& n) { 101 this->md.reserveName(n); 102 } 103 isNameReserved(const std::string & n) const104 bool ModelDSLCommon::isNameReserved(const std::string& n) const { 105 return this->md.isNameReserved(n); 106 } 107 getTargetType() const108 AbstractDSL::DSLTarget ModelDSLCommon::getTargetType() const { 109 return MODELDSL; 110 } 111 getClassName() const112 std::string ModelDSLCommon::getClassName() const { 113 return this->md.className; 114 } // end of ModelDSLCommon::getClassName 115 addStaticVariableDescription(const StaticVariableDescription & v)116 void ModelDSLCommon::addStaticVariableDescription( 117 const StaticVariableDescription& v) { 118 this->md.staticVars.push_back(v); 119 } // end of ModelDSLCommon::addStaticVariableDescription 120 getIntegerConstant(const std::string & n) const121 int ModelDSLCommon::getIntegerConstant(const std::string& n) const { 122 for (const auto& v : this->md.staticVars) { 123 if (v.name == n) { 124 if (v.type != "int") { 125 this->throwRuntimeError("ModelDSLCommon::getIntegerConstant", 126 "invalid type for variable '" + n + "'"); 127 } 128 return v.value; 129 } 130 } 131 this->throwRuntimeError("ModelDSLCommon::getIntegerConstant", 132 "unknown variable '" + n + "'"); 133 } // end of ModelDSLCommon::getIntegerConstant 134 setMaterial(const std::string & m)135 void ModelDSLCommon::setMaterial(const std::string& m) { 136 if (!this->md.material.empty()) { 137 this->throwRuntimeError("ModelDSLCommon::setMaterial", 138 "material name alreay defined"); 139 } 140 if (!isValidMaterialName(m)) { 141 this->throwRuntimeError("ModelDSLCommon::setMaterial", 142 "invalid material name ('" + m + "')"); 143 } 144 this->md.material = m; 145 if (!this->md.modelName.empty()) { 146 this->md.className = this->md.material + "_" + this->md.modelName; 147 } 148 } // end of ModelDSLCommon::setMaterial 149 treatLibrary()150 void ModelDSLCommon::treatLibrary() { 151 const auto& l = this->readOnlyOneToken(); 152 if (!isValidLibraryName(l)) { 153 this->throwRuntimeError("ModelDSLCommon::treatLibrary", 154 "invalid library name"); 155 } 156 if (!this->md.library.empty()) { 157 this->throwRuntimeError("ModelDSLCommon::treatLibrary", 158 "library name already registred"); 159 } 160 this->md.library = l; 161 } // end of ModelDSLCommon::treatLibrary 162 setMaterialKnowledgeIdentifier(const std::string & i)163 void ModelDSLCommon::setMaterialKnowledgeIdentifier(const std::string& i) { 164 if (!this->md.className.empty()) { 165 this->throwRuntimeError("ModelDSLCommon::setMaterialKnowledgeIdentifier", 166 "model name already defined"); 167 } 168 if (!isValidModelName(i)) { 169 this->throwRuntimeError("ModelDSLCommon::setMaterialKnowledgeIdentifier", 170 "invalid model name"); 171 } 172 this->md.modelName = i; 173 if (!this->md.material.empty()) { 174 this->md.className = this->md.material + "_" + this->md.modelName; 175 } else { 176 this->md.className = i; 177 } 178 } // end of ModelDSLCommon::setMaterialKnowledgeIdentifier 179 treatModel()180 void ModelDSLCommon::treatModel() { 181 const auto& m = this->readOnlyOneToken(); 182 if (!isValidModelName(m)) { 183 this->throwRuntimeError("ModelDSLCommon::treatModel", 184 "invalid model name"); 185 } 186 if (this->overriden_implementation_name.empty()) { 187 this->setMaterialKnowledgeIdentifier(m); 188 } 189 } // end of ModelDSLCommon::treatModel 190 setInterfaces(const std::set<std::string> & inames)191 void ModelDSLCommon::setInterfaces(const std::set<std::string>& inames) { 192 using namespace std; 193 auto& mbif = ModelInterfaceFactory::getModelInterfaceFactory(); 194 for (const auto& i : inames) { 195 if (this->interfaces.count(i) == 0) { 196 this->interfaces.insert({i, mbif.getInterface(i)}); 197 } 198 } 199 } // end of ModelDSLCommon::setInterfaces 200 generateOutputFiles()201 void ModelDSLCommon::generateOutputFiles() { 202 if (this->interfaces.empty()) { 203 this->throwRuntimeError("ModelDSLCommon::generateOutputFiles", 204 "no interface defined"); 205 } 206 //! generating sources du to external material properties and models 207 for (const auto& em : this->externalMFrontFiles) { 208 this->callMFront(em.second, {em.first}); 209 } 210 //! generating sources by the interfaces 211 for (const auto& i : this->interfaces) { 212 i.second->writeOutputFiles(this->fd, this->md); 213 } 214 } // end of ModelDSLCommon::generateOutputFiles 215 treatUnknownKeyword()216 void ModelDSLCommon::treatUnknownKeyword() { 217 TokensContainer::const_iterator p2; 218 auto treated = false; 219 --(this->current); 220 const auto key = this->current->value; 221 ++(this->current); 222 this->checkNotEndOfFile("ModelDSLCommon::treatUnknownKeyword"); 223 if (this->current->value == "[") { 224 ++(this->current); 225 this->checkNotEndOfFile("ModelDSLCommon::treatUnknownKeyword"); 226 auto s = std::vector<std::string>{}; 227 while (this->current->value != "]") { 228 this->checkNotEndOfFile("ModelDSLCommon::treatUnknownKeyword"); 229 const auto t = [this]() -> std::string { 230 if (this->current->flag == tfel::utilities::Token::String) { 231 return this->current->value.substr(1, 232 this->current->value.size() - 2); 233 } 234 return this->current->value; 235 }(); 236 ++(this->current); 237 this->checkNotEndOfFile("ModelDSLCommon::treatUnknownKeyword"); 238 if (std::find(s.begin(), s.end(), t) == s.end()) { 239 s.push_back(t); 240 } 241 if (this->current->value != "]") { 242 this->readSpecifiedToken("ModelDSLCommon::treatUnknownKeyword", ","); 243 this->checkNotEndOfFile("ModelDSLCommon::treatUnknownKeyword"); 244 if (this->current->value == "]") { 245 this->throwRuntimeError("ModelDSLCommon::treatUnknownKeyword", 246 "unexpected token ']'"); 247 } 248 } 249 } 250 ++(this->current); 251 for (auto& i : this->interfaces) { 252 auto p = 253 i.second->treatKeyword(key, s, this->current, this->tokens.end()); 254 if (p.first) { 255 if (treated) { 256 if (p2 != p.second) { 257 this->throwRuntimeError("ModelDSLCommon::treatUnknownKeyword", 258 "the keyword '" + key + 259 "' has been treated " 260 "by two interfaces/analysers but " 261 "results were differents"); 262 } 263 } 264 p2 = p.second; 265 treated = true; 266 } 267 } 268 if (!treated) { 269 this->ignoreKeyWord(key); 270 return; 271 } 272 } else { 273 for (const auto& i : this->interfaces) { 274 auto p = 275 i.second->treatKeyword(key, {}, this->current, this->tokens.end()); 276 if (p.first) { 277 if (treated) { 278 if (p2 != p.second) { 279 this->throwRuntimeError("ModelDSLCommon::treatUnknownKeyword", 280 "the keyword '" + key + 281 "' has been treated " 282 "by two interfaces/analysers but " 283 "results were differents"); 284 } 285 } 286 p2 = p.second; 287 treated = true; 288 } 289 } 290 } 291 if (!treated) { 292 DSLBase::treatUnknownKeyword(); 293 } 294 this->current = p2; 295 } // end of ModelDSLCommon::treatUnknownKeyword 296 treatDomain()297 void ModelDSLCommon::treatDomain() { 298 auto throw_if = [this](const bool b, const std::string& m) { 299 if (b) { 300 this->throwRuntimeError("ModelDSLCommon::treatDomain", m); 301 } 302 }; 303 throw_if(!this->md.domains.empty(), "domain defined"); 304 this->checkNotEndOfFile("ModelDSLCommon::treatDomain"); 305 throw_if( 306 this->current->flag != tfel::utilities::Token::String, 307 "Expected to read a string (read '" + this->current->value + "')."); 308 throw_if(this->current->value.size() < 2, "domain name too short."); 309 this->md.domains.insert( 310 this->current->value.substr(1, this->current->value.size() - 2)); 311 ++(this->current); 312 this->readSpecifiedToken("ModelDSLCommon::treatDomain", ";"); 313 } // end of ModelDSLCommon::treatDomain() 314 treatDomains()315 void ModelDSLCommon::treatDomains() { 316 auto throw_if = [this](const bool b, const std::string& m) { 317 if (b) { 318 this->throwRuntimeError("ModelDSLCommon::treatDomains", m); 319 } 320 }; 321 throw_if(!this->md.domains.empty(), "domains defined"); 322 for (const auto& d : 323 this->readArrayOfString("ModelDSLCommon::treatDomains")) { 324 throw_if(!this->md.domains.insert(d).second, 325 "domain " + d + " already defined."); 326 } 327 throw_if(this->md.domains.empty(), "@Domains does not set any domain"); 328 this->readSpecifiedToken("ModelDSLCommon::treatDomain", ";"); 329 } // end of ModelDSLCommon::treatDomains() 330 isInputVariable(const std::string & v) const331 bool ModelDSLCommon::isInputVariable(const std::string& v) const { 332 return is(this->md.inputs, v); 333 } // end of ModelDSLCommon::isInputVariable() 334 isOutputVariable(const std::string & v) const335 bool ModelDSLCommon::isOutputVariable(const std::string& v) const { 336 return is(this->md.outputs, v); 337 } // end of ModelDSLCommon::isInputVariable() 338 treatFunction()339 void ModelDSLCommon::treatFunction() { 340 auto throw_if = [this](const bool b, const std::string& m) { 341 if (b) { 342 this->throwRuntimeError("ModelDSLCommon::treatFunction", m); 343 } 344 }; 345 auto isStaticMemberName = [](const ModelDescription& d, 346 const std::string& n) -> bool { 347 for (const auto& v : d.staticMemberNames) { 348 if (v == n) { 349 return true; 350 } 351 } 352 return false; 353 }; 354 auto isMemberName = [](const ModelDescription& d, 355 const std::string& n) -> bool { 356 for (const auto& v : d.memberNames) { 357 if (v == n) { 358 return true; 359 } 360 } 361 return false; 362 }; 363 ModelDescription::Function f; 364 unsigned int openedBrackets = 0; 365 unsigned int openedParenthesis = 0; 366 f.useTimeIncrement = false; 367 this->md.registerMemberName("functor" + 368 std::to_string(this->md.functions.size())); 369 this->checkNotEndOfFile("ModelDSLCommon::treatFunction"); 370 f.name = this->current->value; 371 throw_if(!this->isValidIdentifier(f.name), 372 "function name '" + f.name + "' is not valid"); 373 this->md.registerMemberName(f.name); 374 this->reserveName(f.name + ".Domain"); 375 this->reserveName(f.name + ".Domains"); 376 f.line = this->current->line; 377 ++(this->current); 378 this->readSpecifiedToken("ModelDSLCommon::treatFunction", "{"); 379 ++openedBrackets; 380 this->checkNotEndOfFile("ModelDSLCommon::treatFunction", 381 "expected body of function '" + f.name + "'."); 382 auto currentLine = this->current->line; 383 auto newInstruction = true; 384 auto newLine = true; 385 if (getDebugMode()) { 386 f.body += "#line " + std::to_string(currentLine) + " \"" + 387 this->fd.fileName + "\"\n"; 388 } 389 for (; (this->current != this->tokens.end()) && (openedBrackets != 0); 390 ++(this->current)) { 391 if (this->current->line != currentLine) { 392 currentLine = this->current->line; 393 f.body += "\n"; 394 if (getDebugMode()) { 395 f.body += "#line " + std::to_string(currentLine) + " \"" + 396 this->fd.fileName + "\"\n"; 397 } 398 newLine = true; 399 } 400 if (this->current->value == "{") { 401 ++openedBrackets; 402 f.body += "{"; 403 newInstruction = true; 404 } else if (this->current->value == "}") { 405 --openedBrackets; 406 if (openedBrackets != 0) { 407 f.body += "}"; 408 } 409 } else if (this->current->value == "(") { 410 ++openedParenthesis; 411 f.body += "("; 412 } else if (this->current->value == ")") { 413 throw_if(openedParenthesis == 0, "unbalanced parenthesis"); 414 --openedParenthesis; 415 f.body += ")"; 416 } else if (this->current->value == ";") { 417 f.body += ";"; 418 newInstruction = true; 419 } else { 420 if (!newLine) { 421 f.body += " "; 422 } 423 const auto c = tfel::unicode::getMangledString(this->current->value); 424 if (isStaticMemberName(this->md, c)) { 425 f.body += 426 "(" + this->md.className + ":: " + c + ")"; 427 } else if (isMemberName(this->md, c)) { 428 bool treated = false; 429 if (newInstruction) { 430 auto op = std::string{}; 431 ++(this->current); 432 throw_if(this->current == tokens.end(), 433 "unexpected end of file while reading " 434 "body of function '" + 435 f.name + "'"); 436 auto modifier = false; 437 if (this->current->value == "=") { 438 op = "="; 439 modifier = true; 440 } else if (this->current->value == "+=") { 441 op = "+="; 442 modifier = true; 443 } else if (this->current->value == "-=") { 444 op = "-="; 445 modifier = true; 446 } else if (this->current->value == "*=") { 447 op = "*="; 448 modifier = true; 449 } else if (this->current->value == "/=") { 450 op = "/="; 451 modifier = true; 452 } 453 if (modifier) { 454 bool found = false; 455 for (auto p = this->md.outputs.begin(); 456 (p != this->md.outputs.end()) && (!found);) { 457 if (p->name == c) { 458 found = true; 459 } else { 460 ++p; 461 } 462 } 463 throw_if(!found, "trying to modify variable '" + c + 464 "' in the body of function '" + f.name + 465 "'"); 466 f.body += c + " " + op + " "; 467 f.modifiedVariables.insert(c); 468 auto p6 = f.depths.find(c); 469 if (p6 == f.depths.end()) { 470 f.depths[c] = 0; 471 } 472 treated = true; 473 } else { 474 --(this->current); 475 } 476 } 477 if (!treated) { 478 // treating the case of local parameters 479 for (auto p = this->md.parameters.begin(); 480 (p != this->md.parameters.end()) && (!treated); ++p) { 481 if (p->name == c) { 482 treated = true; 483 f.parameters.insert(c); 484 f.body += "(this->" + c + ")"; 485 } 486 } 487 // treating the case of local parameters 488 for (auto p = this->md.constantMaterialProperties.begin(); 489 (p != this->md.constantMaterialProperties.end()) && (!treated); 490 ++p) { 491 if (p->name == c) { 492 treated = true; 493 f.constantMaterialProperties.insert(c); 494 f.body += "(this->" + c + ")"; 495 } 496 } 497 if (!treated) { 498 if (this->isInputVariable(c)) { 499 f.usedVariables.insert(c); 500 auto dv = this->md.decomposeVariableName(c); 501 auto p6 = f.depths.find(dv.first); 502 if (p6 != f.depths.end()) { 503 if (dv.second > p6->second) { 504 f.depths[dv.first] = dv.second; 505 } 506 } else { 507 f.depths[dv.first] = dv.second; 508 } 509 } else if (this->isOutputVariable(c)) { 510 f.usedVariables.insert(c); 511 auto dv = this->md.decomposeVariableName(c); 512 auto p6 = f.depths.find(dv.first); 513 if (p6 != f.depths.end()) { 514 if (dv.second > p6->second) { 515 f.depths[dv.first] = dv.second; 516 } 517 } else { 518 f.depths[dv.first] = dv.second; 519 } 520 } 521 f.body += c; 522 } 523 } 524 } else { 525 if ((c == "dt")||(c=="\u0394t")) { 526 f.useTimeIncrement = true; 527 f.body += "dt"; 528 } else { 529 f.body += c; 530 } 531 } 532 newInstruction = false; 533 } 534 newLine = false; 535 } 536 throw_if((this->current == tokens.end()) && (openedBrackets != 0), 537 "unexpected end of file while reading body of function '" + 538 f.name + "'"); 539 throw_if( 540 openedBrackets != 0, 541 "parenthesis still opened at the end of function '" + f.name + "'"); 542 throw_if(f.modifiedVariables.empty(), 543 "function " + f.name + " does not change any variable."); 544 for (const auto& df : this->md.functions) { 545 throw_if(df.name == f.name, "function " + f.name + " already declared."); 546 } 547 for (auto p2 = f.modifiedVariables.begin(); p2 != f.modifiedVariables.end(); 548 ++p2) { 549 auto p3 = f.usedVariables.find(*p2); 550 if (p3 != f.usedVariables.end()) { 551 f.usedVariables.erase(*p3); 552 } 553 } 554 this->md.functions.push_back(f); 555 } // end of ModelDSLCommon::treatFunction() 556 treatOutput()557 void ModelDSLCommon::treatOutput() { 558 if (!this->md.functions.empty()) { 559 this->throwRuntimeError("ModelDSLCommon::treatInput", 560 "outputs must be declared before " 561 "declaring functions"); 562 } 563 VariableDescriptionContainer noutputs; 564 this->readVarList(noutputs, "real", false); 565 for (const auto& v : noutputs) { 566 if (!v.symbolic_form.empty()) { 567 this->reserveName(v.symbolic_form); 568 } 569 this->md.registerMemberName(v.name); 570 this->md.outputs.push_back(v); 571 } 572 } // end of ModelDSLCommon::treatOutput() 573 treatInput()574 void ModelDSLCommon::treatInput() { 575 if (!this->md.functions.empty()) { 576 this->throwRuntimeError("ModelDSLCommon::treatInput", 577 "inputs must be declared before " 578 "declaring functions"); 579 } 580 VariableDescriptionContainer ninputs; 581 this->readVarList(ninputs, "real", false); 582 for (const auto& v : ninputs) { 583 if (!v.symbolic_form.empty()) { 584 this->reserveName(v.symbolic_form); 585 } 586 this->md.registerMemberName(v.name); 587 this->md.inputs.push_back(v); 588 } 589 } // end of ModelDSLCommon::treatInput() 590 treatOutputMethod()591 void ModelDSLCommon::treatOutputMethod() { 592 if (!this->md.functions.empty()) { 593 this->throwRuntimeError("ModelDSLCommon::treatOutputMethod: ", 594 "variable methods must be called " 595 "before declaring functions"); 596 } 597 this->readSpecifiedToken("ModelDSLCommon::treatOutputMethod", "."); 598 this->checkNotEndOfFile("ModelDSLCommon::treatOutputMethod", 599 "Expected method name."); 600 const auto mn = this->current->value; 601 if ((mn != "setGlossaryName") && (mn != "setEntryName") && 602 (mn != "setDefaultInitialValue") && (mn != "setDepth")) { 603 this->throwRuntimeError("ModelDSLCommon::treatOutputMethod", 604 "Unknown method (valid methods for fields are " 605 "setGlossaryName, setEntryName, setDepth and " 606 "setDefaultInitialValue," 607 "read '" + 608 mn + "')."); 609 } 610 ++(this->current); 611 this->readSpecifiedToken("ModelDSLCommon::treatOutputMethod", "("); 612 if (mn == "setGlossaryName") { 613 const auto gn = this->readString("ModelDSLCommon::treatOutputMethod"); 614 this->md.setGlossaryName(this->currentVar, gn); 615 } else if (mn == "setEntryName") { 616 const auto en = this->readString("ModelDSLCommon::treatOutputMethod"); 617 this->md.setEntryName(this->currentVar, en); 618 } else if (mn == "setDefaultInitialValue") { 619 this->checkNotEndOfFile("ModelDSLCommon::treatOutputMethod", 620 "Expected intial value."); 621 const auto value = this->readDouble(); 622 auto& v = this->md.outputs.getVariable(this->currentVar); 623 v.setAttribute(VariableDescription::initialValue, value, false); 624 } else if (mn == "setDepth") { 625 this->checkNotEndOfFile("ModelDSLCommon::treatOutputMethod", 626 "Expected depth value."); 627 unsigned short value; 628 std::istringstream converter(this->current->value); 629 converter >> value; 630 if (!converter || (!converter.eof())) { 631 this->throwRuntimeError( 632 "ModelDSLCommon::treatOutputMethod", 633 "Could not read depth value of field '" + this->currentVar + "'"); 634 } 635 auto& v = this->md.outputs.getVariable(this->currentVar); 636 v.setAttribute(VariableDescription::depth, value, false); 637 for (unsigned short i = 1; i <= value; ++i) { 638 const auto vn = this->currentVar + "_" + std::to_string(i); 639 this->md.registerMemberName(vn); 640 this->md.registerMemberName("f_" + vn); 641 this->md.registerMemberName("ff_" + vn); 642 } 643 ++(this->current); 644 } else { 645 this->throwRuntimeError("ModelDSLCommon::treatOutputMethod", 646 "Internal error (untreated method '" + mn + "')"); 647 } 648 this->readSpecifiedToken("ModelDSLCommon::treatOutputMethod", ")"); 649 this->readSpecifiedToken("ModelDSLCommon::treatOutputMethod", ";"); 650 } // end of ModelDSLCommon::treatOutputMethod 651 treatInputMethod()652 void ModelDSLCommon::treatInputMethod() { 653 if (!this->md.functions.empty()) { 654 this->throwRuntimeError("ModelDSLCommon::treatInputMethod", 655 "input methods must be called " 656 "before declaring functions"); 657 } 658 this->readSpecifiedToken("ModelDSLCommon::treatInputMethod", "."); 659 this->checkNotEndOfFile("ModelDSLCommon::treatInputMethod", 660 "Expected method name."); 661 const auto mn = this->current->value; 662 if ((mn != "setGlossaryName") && (mn != "setEntryName") && 663 (mn != "setDepth")) { 664 this->throwRuntimeError( 665 "ModelDSLCommon::treatInputMethod", 666 "Unknown method (valid methods for input fields are " 667 "setGlossaryName, setEntryName, setDepth" 668 ", read '" + 669 mn + "')"); 670 } 671 ++(this->current); 672 this->readSpecifiedToken("ModelDSLCommon::treatInputMethod", "("); 673 if (mn == "setGlossaryName") { 674 const auto gn = this->readString("ModelDSLCommon::treatInputMethod"); 675 this->md.setGlossaryName(this->currentVar, gn); 676 } else if (mn == "setEntryName") { 677 const auto en = this->readString("ModelDSLCommon::treatInputMethod"); 678 this->md.setEntryName(this->currentVar, en); 679 } else if (mn == "setDepth") { 680 this->checkNotEndOfFile("ModelDSLCommon::treatInputMethod", 681 "Expected depth value."); 682 unsigned short value; 683 std::istringstream converter(this->current->value); 684 converter >> value; 685 if (!converter || (!converter.eof())) { 686 this->throwRuntimeError( 687 "ModelDSLCommon::treatInputMethod", 688 "Could not read initial value of field '" + this->currentVar + "'"); 689 } 690 auto& v = this->md.inputs.getVariable(this->currentVar); 691 v.setAttribute(VariableDescription::depth, value, false); 692 for (unsigned short i = 1; i <= value; ++i) { 693 const auto vn = this->currentVar + "_" + std::to_string(i); 694 this->md.registerMemberName(vn); 695 this->md.registerMemberName("f_" + vn); 696 this->md.registerMemberName("ff_" + vn); 697 } 698 ++(this->current); 699 } else { 700 this->throwRuntimeError("ModelDSLCommon::treatInputMethod", 701 "Internal error (untreated method '" + mn + "')"); 702 } 703 this->readSpecifiedToken("ModelDSLCommon::treatInputMethod", ")"); 704 this->readSpecifiedToken("ModelDSLCommon::treatInputMethod", ";"); 705 } // end of ModelDSLCommon::treatInputMethod 706 treatParameter()707 void ModelDSLCommon::treatParameter() { 708 auto endOfTreatment = false; 709 while ((this->current != this->tokens.end()) && (!endOfTreatment)) { 710 if (!this->isValidIdentifier(this->current->value)) { 711 this->throwRuntimeError("DSLBase::handleParameter : ", 712 "variable given is not valid (read '" + 713 this->current->value + "')."); 714 } 715 const auto n = this->current->value; 716 const auto lineNumber = this->current->line; 717 VariableDescription v("real", n, 1u, lineNumber); 718 ++(this->current); 719 this->checkNotEndOfFile("DSLBase::handleParameter"); 720 auto value = this->readInitialisationValue<double>(n, false); 721 if (value.first) { 722 const auto op = this->overriding_parameters.find(n); 723 if (op == this->overriding_parameters.end()) { 724 v.setAttribute(VariableDescription::defaultValue, value.second, 725 false); 726 } else { 727 v.setAttribute(VariableDescription::defaultValue, op->second, false); 728 } 729 } 730 if (this->current->value == ",") { 731 ++(this->current); 732 } else if (this->current->value == ";") { 733 endOfTreatment = true; 734 ++(this->current); 735 } else { 736 this->throwRuntimeError("DSLBase::handleParameter", 737 ", or ; expected after '" + n + "'"); 738 } 739 this->md.registerMemberName(v.name); 740 this->md.parameters.push_back(v); 741 } 742 if (!endOfTreatment) { 743 --(this->current); 744 this->throwRuntimeError("DSLBase::handleParameter", 745 "Expected ';' before end of file"); 746 } 747 } // end of ModelDSLCommon::treatParameter() 748 treatLocalParameter()749 void ModelDSLCommon::treatLocalParameter() { 750 VariableDescriptionContainer gp; 751 this->readVarList(gp, false); 752 for (const auto& v : gp) { 753 this->md.registerMemberName(v.name); 754 this->md.parameters.push_back(v); 755 } 756 } // end of ModelDSLCommon::treatLocalParameter() 757 treatParameterMethod()758 void ModelDSLCommon::treatParameterMethod() { 759 auto throw_if = [this](const bool b, const std::string& m) { 760 if (b) { 761 this->throwRuntimeError("ModelDSLCommon::treatParameterMethod", m); 762 } 763 }; 764 this->readSpecifiedToken("ModelDSLCommon::treatParameterMethod", "."); 765 this->checkNotEndOfFile("ModelDSLCommon::treatParameterMethod", 766 "Expected method name."); 767 const auto mn = this->current->value; 768 throw_if((mn != "setGlossaryName") && (mn != "setEntryName") && 769 (mn != "setDefaultValue"), 770 "unknown method (valid methods for local parameters are " 771 "setGlossaryName, setEntryName and setDefaultValue" 772 ", read " + 773 mn + ")."); 774 ++(this->current); 775 this->readSpecifiedToken("ModelDSLCommon::treatParameterMethod", "("); 776 if (mn == "setGlossaryName") { 777 const auto gn = this->readString("ModelDSLCommon::treatInputMethod"); 778 this->md.setGlossaryName(this->currentVar, gn); 779 } else if (mn == "setEntryName") { 780 const auto en = this->readString("ModelDSLCommon::treatInputMethod"); 781 this->md.setEntryName(this->currentVar, en); 782 } else if (mn == "setDefaultValue") { 783 this->readDefaultValue(); 784 } 785 this->readSpecifiedToken("ModelDSLCommon::treatParameterMethod", ")"); 786 this->readSpecifiedToken("ModelDSLCommon::treatParameterMethod", ";"); 787 } // end of ModelDSLCommon::treatParameterMethod 788 treatConstantMaterialProperty()789 void ModelDSLCommon::treatConstantMaterialProperty() { 790 VariableDescriptionContainer cmp; 791 this->readVarList(cmp, "real", false); 792 for (const auto& mp : cmp) { 793 this->md.registerMemberName(mp.name); 794 this->md.constantMaterialProperties.push_back(mp); 795 } 796 } // end of ModelDSLCommon::treatConstantMaterialProperty() 797 treatConstantMaterialPropertyMethod()798 void ModelDSLCommon::treatConstantMaterialPropertyMethod() { 799 auto throw_if = [this](const bool b, const std::string& m) { 800 if (b) { 801 this->throwRuntimeError( 802 "ModelDSLCommon::treatConstantMaterialPropertyMethod", m); 803 } 804 }; 805 this->readSpecifiedToken( 806 "ModelDSLCommon::treatConstantMaterialPropertyMethod", "."); 807 this->checkNotEndOfFile( 808 "ModelDSLCommon::treatConstantMaterialPropertyMethod", 809 "Expected method name."); 810 const auto mn = this->current->value; 811 ++(this->current); 812 this->readSpecifiedToken( 813 "ModelDSLCommon::treatConstantMaterialPropertyMethod", "("); 814 if (mn == "setGlossaryName") { 815 const auto gn = this->readString( 816 "ModelDSLCommon::treatConstantMaterialPropertyMethod"); 817 this->md.setGlossaryName(this->currentVar, gn); 818 } else if (mn == "setEntryName") { 819 const auto en = this->readString( 820 "ModelDSLCommon::treatConstantMaterialPropertyMethod"); 821 this->md.setEntryName(this->currentVar, en); 822 } else { 823 throw_if( 824 true, 825 "unknown method (valid methods for constant material properties are " 826 "setGlossaryName and setEntryName, read " + 827 mn + ")."); 828 } 829 this->readSpecifiedToken( 830 "ModelDSLCommon::treatConstantMaterialPropertyMethod", ")"); 831 this->readSpecifiedToken( 832 "ModelDSLCommon::treatConstantMaterialPropertyMethod", ";"); 833 } // end of ModelDSLCommon::treatConstantMaterialPropertyMethod 834 readDefaultValue()835 void ModelDSLCommon::readDefaultValue() { 836 auto throw_if = [this](const bool b, const std::string& m) { 837 if (b) { 838 this->throwRuntimeError("ModelDSLCommon::readDefaultValue", m); 839 } 840 }; 841 auto& v = this->md.parameters.getVariable(this->currentVar); 842 this->checkNotEndOfFile("ModelDSLCommon::readDefaultValue", 843 "Expected default value."); 844 if (v.type == "DoubleArray") { 845 const auto values = 846 this->readArrayOfDouble("ModelDSLCommon::readDefaultValue"); 847 v.setAttribute(VariableDescription::defaultValue, values, false); 848 } else if (v.type == "StringArray") { 849 const auto values = 850 this->readArrayOfDouble("ModelDSLCommon::readDefaultValue"); 851 v.setAttribute(VariableDescription::defaultValue, values, false); 852 } else if ((v.type == "double") || (v.type == "real")) { 853 const auto value = this->readDouble(); 854 const auto op = this->overriding_parameters.find(v.name); 855 if (op == this->overriding_parameters.end()) { 856 v.setAttribute(VariableDescription::defaultValue, value, false); 857 } else { 858 v.setAttribute(VariableDescription::defaultValue, op->second, false); 859 } 860 } else if (v.type == "string") { 861 const auto value = this->readString("ModelDSLCommon::readDefaultValue"); 862 v.setAttribute(VariableDescription::defaultValue, value, false); 863 } else if (v.type == "bool") { 864 const auto b = this->readBooleanValue("ModelDSLCommon::readDefaultValue"); 865 v.setAttribute(VariableDescription::defaultValue, b, false); 866 } else { 867 throw_if(true, "type '" + v.type + "' is not supported."); 868 } 869 } // end of ModelDSLCommon::readDefaultValue 870 treatBounds()871 void ModelDSLCommon::treatBounds() { 872 const auto b = mfront::readVariableBounds(this->current, this->end()); 873 if (this->md.outputs.contains(b.first)) { 874 this->md.outputs.getVariable(b.first).setBounds(b.second); 875 } else if (this->md.inputs.contains(b.first)) { 876 this->md.inputs.getVariable(b.first).setBounds(b.second); 877 } else { 878 this->throwRuntimeError("ModelDSLCommon::treatBounds", 879 "no variable named '" + b.first + "'"); 880 } 881 this->readSpecifiedToken("ModelDSLCommon::treatBounds", ";"); 882 } // end of ModelDSLCommon::treatBounds 883 treatPhysicalBounds()884 void ModelDSLCommon::treatPhysicalBounds() { 885 const auto b = mfront::readVariableBounds(this->current, this->end()); 886 if (this->md.outputs.contains(b.first)) { 887 this->md.outputs.getVariable(b.first).setPhysicalBounds(b.second); 888 } else if (this->md.inputs.contains(b.first)) { 889 this->md.inputs.getVariable(b.first).setPhysicalBounds(b.second); 890 } else { 891 this->throwRuntimeError("ModelDSLCommon::treatPhysicalBounds", 892 "no variable named '" + b.first + "'"); 893 } 894 this->readSpecifiedToken("ModelDSLCommon::treatPhysicalBounds", ";"); 895 } // end of ModelDSLCommon::treatPhysicalBounds 896 addMaterialLaw(const std::string & m)897 void ModelDSLCommon::addMaterialLaw(const std::string& m) { 898 this->md.addMaterialLaw(m); 899 } // end of ModelDSLCommon::addMaterialLaw 900 appendToIncludes(const std::string & c)901 void ModelDSLCommon::appendToIncludes(const std::string& c) { 902 this->md.appendToIncludes(c); 903 } // end of ModelDSLCommon::appendToIncludes 904 appendToMembers(const std::string & c)905 void ModelDSLCommon::appendToMembers(const std::string& c) { 906 this->md.appendToMembers(c); 907 } // end of ModelDSLCommon::appendToMembers 908 appendToPrivateCode(const std::string & c)909 void ModelDSLCommon::appendToPrivateCode(const std::string& c) { 910 this->md.appendToPrivateCode(c); 911 } // end of ModelDSLCommon::appendToPrivateCode 912 appendToSources(const std::string & c)913 void ModelDSLCommon::appendToSources(const std::string& c) { 914 this->md.appendToSources(c); 915 } // end of ModelDSLCommon::appendToSources 916 917 ModelDSLCommon::~ModelDSLCommon() = default; 918 919 } // end of namespace mfront 920