1 /*!
2  * \file   mfront/src/DSLBase.cxx
3  * \brief
4  *
5  * \author Thomas Helfer
6  * \date   04 jun 2007
7  * \copyright Copyright (C) 2006-2018 CEA/DEN, EDF R&D. All rights
8  * reserved.
9  * This project is publicly released under either the GNU GPL Licence
10  * or the CECILL-A licence. A copy of thoses licences are delivered
11  * with the sources of TFEL. CEA or EDF may also distribute this
12  * project under specific licensing conditions.
13  */
14 
15 #include <cctype>
16 #include <iterator>
17 #include <sstream>
18 #include <stdexcept>
19 #include <algorithm>
20 
21 #ifdef MFRONT_HAVE_MADNEX
22 #include "Madnex/MFrontImplementation.hxx"
23 #endif /* MFRONT_HAVE_MADNEX */
24 
25 #include "TFEL/Raise.hxx"
26 #include "TFEL/Math/IntegerEvaluator.hxx"
27 #include "TFEL/UnicodeSupport/UnicodeSupport.hxx"
28 #include "TFEL/Utilities/StringAlgorithms.hxx"
29 
30 #include "MFront/MFront.hxx"
31 #include "MFront/PedanticMode.hxx"
32 #include "MFront/SupportedTypes.hxx"
33 #include "MFront/DSLBase.hxx"
34 #include "MFront/SearchPathsHandler.hxx"
35 #include "MFront/DSLUtilities.hxx"
36 #include "MFront/MFrontUtilities.hxx"
37 #include "MFront/MFrontDebugMode.hxx"
38 #include "MFront/MFrontLogStream.hxx"
39 #include "MFront/MFrontMaterialPropertyInterface.hxx"
40 #include "MFront/StaticVariableDescription.hxx"
41 #include "MFront/MaterialPropertyDSL.hxx"
42 
43 // fixing a bug on current glibc++ cygwin versions (19/08/2015)
44 #if defined __CYGWIN__ && (!defined _GLIBCXX_USE_C99)
45 #include <sstream>
46 namespace std {
47   template <typename T>
to_string(const T & v)48   std::string to_string(const T& v) {
49     std::ostringstream s;
50     s << v;
51     return s.str();
52   }
53 }
54 #endif /* defined __CYGWIN__ &&  (!defined _GLIBCXX_USE_C99) */
55 
56 namespace mfront {
57 
isInteger(const std::string & s)58   static bool isInteger(const std::string& s) {
59     const auto s2 = [&s]() -> std::string {
60       if (s.empty()) {
61         return s;
62       }
63       if ((s.back() == 'u') || (s.back() == 'U') || (s.back() == 'l') || (s.back() == 'L')) {
64         return s.substr(0, s.size() - 1);
65       } else if ((tfel::utilities::ends_with(s, "ul")) || (tfel::utilities::ends_with(s, "uL")) ||
66                  (tfel::utilities::ends_with(s, "lu")) || (tfel::utilities::ends_with(s, "Lu")) ||
67                  (tfel::utilities::ends_with(s, "Ul")) || (tfel::utilities::ends_with(s, "UL")) ||
68                  (tfel::utilities::ends_with(s, "lU")) || (tfel::utilities::ends_with(s, "LU"))) {
69         return s.substr(0, s.size() - 2);
70       }
71       return s;
72     }();
73     if (s2.empty()) {
74       return false;
75     }
76     for (const auto c : s2) {
77       if (!std::isdigit(c)) {
78         return false;
79       }
80     }
81     return true;
82   }
83 
isValidMaterialName(const std::string & n)84   bool isValidMaterialName(const std::string& n) {
85     return tfel::utilities::CxxTokenizer::isValidIdentifier(n, true);
86   }
87 
isValidLibraryName(const std::string & n)88   bool isValidLibraryName(const std::string& n) {
89     return tfel::utilities::CxxTokenizer::isValidIdentifier(n, true);
90   }
91 
92   DSLBase::VariableModifier::~VariableModifier() = default;
93 
94   DSLBase::WordAnalyser::~WordAnalyser() = default;
95 
96   DSLBase::CodeBlockParserOptions::CodeBlockParserOptions() = default;
97 
98   DSLBase::CodeBlockParserOptions::~CodeBlockParserOptions() noexcept = default;
99 
DSLBase()100   DSLBase::DSLBase() {
101     this->addSeparator("\u2297");
102     this->addSeparator("\u22C5");
103   }  // end of DSLBase::DSLBase
104 
getDefaultReservedNames()105   std::vector<std::string> DSLBase::getDefaultReservedNames() {
106     auto names = std::vector<std::string>{};
107     // names of the c++ standard
108     names.insert(names.end(),
109                  {"std",   "cout",   "cerr",   "endl",    "cos",    "sin",      "tan",           "acos",    "asin",
110                   "atan",  "atan2",  "cosh",   "sinh",    "tanh",   "acosh",    "asinh",         "atanh",   "exp",
111                   "frexp", "ldexp",  "log",    "log10",   "modf",   "exp2",     "expm1",         "ilogb",   "log1p",
112                   "log2",  "logb",   "scalbn", "scalbln", "pow",    "sqrt",     "cbrt",          "hypot",   "erf",
113                   "erfc",  "tgamma", "lgamma", "abs",     "string", "ofstream", "ostringstream", "ifstream"});
114     // tfel namespaces
115     names.insert(names.end(), {"tfel", "math", "material", "utilities", "exception", "glossary"});
116     for (const auto& v : SupportedTypes::getTypeFlags()) {
117       names.push_back(v.first);
118     }
119     names.insert(names.end(), {"policy", "errno", "mfront_errno", "mfront_errno_old"});
120     return names;
121   }
122 
getTemporaryVariableName(std::vector<std::string> & tmpnames,const std::string & p) const123   std::string DSLBase::getTemporaryVariableName(
124       std::vector<std::string>& tmpnames, const std::string& p) const {
125     if (!this->isValidIdentifier(p)) {
126       this->throwRuntimeError("DSLBase::getTemporaryVariableName",
127                               "invalid variable prefix '" + p + "'");
128     }
129     for (size_type i = 0; i != std::numeric_limits<size_type>::max(); ++i) {
130       const auto c = p + std::to_string(i);
131       if (!this->isNameReserved(c)) {
132         if (std::find(tmpnames.begin(), tmpnames.end(), c) == tmpnames.end()) {
133           tmpnames.push_back(c);
134           return c;
135         }
136       }
137     }
138     this->throwRuntimeError("DSLBase::getTemporaryVariableName",
139                             "unable to find a temporary variable");
140   }
141 
openFile(const std::string & f,const std::vector<std::string> & ecmds,const std::map<std::string,std::string> & s)142   void DSLBase::openFile(const std::string& f,
143                          const std::vector<std::string>& ecmds,
144                          const std::map<std::string, std::string>& s) {
145     if (tfel::utilities::starts_with(f, "madnex:")) {
146 #ifdef MFRONT_HAVE_MADNEX
147       const auto path = decomposeImplementationPathInMadnexFile(f);
148       const auto& material = std::get<2>(path);
149       const auto& name = std::get<3>(path);
150       const auto impl = madnex::getMFrontImplementation(
151           std::get<0>(path), std::get<1>(path), material, name);
152       this->overrideMaterialKnowledgeIdentifier(name);
153       if (!material.empty()) {
154         this->overrideMaterialName(material);
155       }
156       if (!impl.metadata.author.empty()) {
157         this->overrideAuthorName(impl.metadata.author);
158       }
159       if (!impl.metadata.date.empty()) {
160         this->overrideDate(impl.metadata.date);
161       }
162       if (!impl.metadata.description.empty()) {
163         this->overrideDescription(impl.metadata.description);
164       }
165       for (const auto& p: impl.parameters) {
166         this->overrideByAParameter(p.first, p.second);
167       }
168       CxxTokenizer::parseString(impl.source);
169 #else  /* MFRONT_HAVE_MADNEX */
170       tfel::raise("DSLBase::openFile: madnex support was not enabled");
171 #endif /* MFRONT_HAVE_MADNEX */
172     } else {
173       CxxTokenizer::openFile(f);
174     }
175     // substitutions
176     const auto pe = s.end();
177     for (auto& t : this->tokens) {
178       auto p = s.find(t.value);
179       if (p != pe) {
180         t.value = p->second;
181       }
182     }
183     // treating external commands
184     for (const auto& c : ecmds) {
185       CxxTokenizer t;
186       try {
187         t.parseString(c);
188       } catch (std::exception& e) {
189         tfel::raise(
190             "DSLBase::openFile : "
191             "error while parsing external command "
192             "'" +
193             c + "'\n" + std::string(e.what()));
194       }
195       this->tokens.insert(this->tokens.begin(), t.begin(), t.end());
196     }
197   }  // end of DSLBase::openFile
198 
getFileDescription() const199   const FileDescription& DSLBase::getFileDescription() const {
200     return this->fd;
201   }  // end of DSLBase::getFileDescription
202 
getTargetsDescription() const203   const TargetsDescription& DSLBase::getTargetsDescription() const {
204     return this->td;
205   }  // end of DSLBase::getTargetsDescription
206 
207   DSLBase::~DSLBase() = default;
208 
readNextBlock(CodeBlock & res1,CodeBlock & res2,const CodeBlockParserOptions & o1,const CodeBlockParserOptions & o2)209   void DSLBase::readNextBlock(CodeBlock& res1,
210                               CodeBlock& res2,
211                               const CodeBlockParserOptions& o1,
212                               const CodeBlockParserOptions& o2) {
213     auto pb = this->current;
214     res1 = this->readNextBlock(o1);
215     this->current = pb;
216     res2 = this->readNextBlock(o2);
217   }  // end of DSLBase::readNextBlock
218 
readNextBlock(const CodeBlockParserOptions & options)219   CodeBlock DSLBase::readNextBlock(const CodeBlockParserOptions& options) {
220     using tfel::utilities::Token;
221     auto addSpaceBetweenToken = [this](
222         std::string& r, const TokensContainer::const_iterator c,
223         const TokensContainer::const_iterator n) {
224       if ((n == this->tokens.end()) || (n->line != c->line)) {
225         return;
226       }
227       const auto csize = [&c] {
228         if ((c->flag == Token::String) || (c->flag == Token::Char)) {
229           return c->value.size() + 2;
230         }
231         return c->value.size();
232       }();
233       if (n->offset > c->offset + csize) {
234         const auto d = n->offset - csize - c->offset;
235         r += std::string(d, ' ');
236       }
237     };
238     const auto& smn = options.smn;
239     const auto& mn = options.mn;
240     const auto& delim1 = options.delim1;
241     const auto& delim2 = options.delim2;
242     const auto addThisPtr = options.qualifyMemberVariables;
243     const auto addClassName = options.qualifyStaticVariables;
244     const auto allowSemiColon = options.allowSemiColon;
245     const auto registerLine = options.registerLine;
246     auto demangle = [&options](const Token& t) {
247       if (t.flag != Token::Standard) {
248         return t.value;
249       }
250       const auto p = options.symbols.find(t.value);
251       if (p != options.symbols.end()) {
252         return p->second;
253       }
254       return tfel::unicode::getMangledString(t.value);
255     };
256     auto modifier = options.modifier;
257     auto analyser = options.analyser;
258     CodeBlock b;
259     if (!this->currentComment.empty()) {
260       b.description += this->currentComment;
261     }
262     auto& res = b.code;
263     unsigned int openedBlock = 0;
264     this->readSpecifiedToken("DSLBase::readNextBlock", delim1);
265     this->checkNotEndOfFile("DSLBase::readNextBlock", "Expected a '" + delim2 + "'.");
266     if ((this->current->value == ";") && (!allowSemiColon)) {
267       this->throwRuntimeError("DSLBase::readNextBlock",
268                               "read ';' before the end of block.\n"
269                               "Number of block opened : " +
270                                   std::to_string(openedBlock));
271     }
272     if (this->current->value == delim1) {
273       ++openedBlock;
274     }
275     if (this->current->value == delim2) {
276       ++(this->current);
277       return b;
278     }
279     auto currentLine = this->current->line;
280     if ((registerLine) && (!getDebugMode())) {
281       res = "#line ";
282       res += std::to_string(currentLine);
283       res += " \"";
284       res += this->fd.fileName;
285       res += "\"\n";
286     }
287     if (!this->current->comment.empty()) {
288       if (!b.description.empty()) {
289         b.description += '\n';
290       }
291       b.description += this->current->comment;
292     }
293     auto currentValue = demangle(*(this->current));
294     if (analyser != nullptr) {
295       analyser->exe(b, currentValue);
296     }
297     if (smn.find(currentValue) != smn.end()) {
298       b.staticMembers.insert(currentValue);
299       const auto previous = std::prev(this->current);
300       if ((previous->value != "->") && (previous->value != ".") &&
301           (previous->value != "::")) {
302         if (addClassName) {
303           res += this->getClassName();
304           res += "::";
305         }
306       }
307       res += currentValue;
308     } else if (mn.find(currentValue) != mn.end()) {
309       b.members.insert(currentValue);
310       auto cv = std::string{};
311       auto previous = std::prev(this->current);
312       if ((previous->value == "->") || (previous->value == ".") ||
313           (previous->value == "::")) {
314         cv = currentValue;
315       } else {
316         if (modifier != nullptr) {
317           cv = modifier->exe(currentValue, addThisPtr);
318         } else {
319           if (addThisPtr) {
320             cv = "this->" + currentValue;
321           } else {
322             cv = currentValue;
323           }
324         }
325       }
326       previous = std::prev(this->current);
327       if (previous->value == "*") {
328         res += "(" + cv+ ")";
329       } else {
330         res += cv;
331       }
332     } else {
333       res += currentValue;
334     }
335     addSpaceBetweenToken(res, this->current, std::next(this->current));
336     ++(this->current);
337     while ((this->current != this->tokens.end()) && (!((this->current->value == delim2) && (openedBlock == 0)))) {
338       currentValue = demangle(*(this->current));
339       if (currentLine != this->current->line) {
340         currentLine = this->current->line;
341         if ((registerLine) && (!getDebugMode())) {
342           res += "\n";
343           res += "#line ";
344           res += std::to_string(currentLine);
345           res += " \"";
346           res += this->fd.fileName;
347           res += "\"\n";
348         } else {
349           res += "\n";
350         }
351       }
352       if ((currentValue == ";") && (!allowSemiColon)) {
353         this->throwRuntimeError("DSLBase::readNextBlock",
354                                 "read ';' before the end of block.\n"
355                                 "Number of block opened : " +
356                                     std::to_string(openedBlock));
357       }
358       if (!this->current->comment.empty()) {
359         if (!b.description.empty()) {
360           b.description += '\n';
361         }
362         b.description += this->current->comment;
363       }
364       if (analyser != nullptr) {
365         analyser->exe(b, currentValue);
366       }
367       if (smn.find(currentValue) != smn.end()) {
368         b.staticMembers.insert(currentValue);
369         const auto previous = std::prev(this->current);
370         if ((previous->value != "->") && (previous->value != ".") && (previous->value != "::")) {
371           if (addClassName) {
372             res += this->getClassName();
373             res += "::";
374           }
375         }
376         res += currentValue;
377       } else if (mn.find(currentValue) != mn.end()) {
378         b.members.insert(currentValue);
379         auto cv = std::string{};
380         const auto previous = std::prev(this->current);
381         if ((previous->value == "->") || (previous->value == ".") || (previous->value == "::")) {
382           cv = currentValue;
383         } else {
384           if (modifier != nullptr) {
385             cv = modifier->exe(currentValue, addThisPtr);
386           } else {
387             if (addThisPtr) {
388               if (previous->value == "*") {
389                 cv = "(this->" + currentValue + ')';
390               } else {
391                 cv = "this->" + currentValue;
392               }
393             } else {
394               cv = currentValue;
395             }
396           }
397         }
398         res += cv;
399       } else {
400         res += currentValue;
401       }
402       addSpaceBetweenToken(res, this->current, std::next(this->current));
403       if (currentValue == delim1) {
404         ++openedBlock;
405       }
406       if (currentValue == delim2) {
407         --openedBlock;
408       }
409       ++(this->current);
410     }
411     if (this->current == this->tokens.end()) {
412       --(this->current);
413       this->throwRuntimeError("DSLBase::readNextBlock",
414                               "Expected the end of a block.\n"
415                               "Number of block opened : " +
416                                   std::to_string(openedBlock));
417     }
418     ++(this->current);
419     return b;
420   }  // end of DSLBase::readNextBlock
421 
throwRuntimeError(const std::string & m,const std::string & e) const422   void DSLBase::throwRuntimeError(const std::string& m,
423                                   const std::string& e) const {
424     auto msg = m;
425     if (!e.empty()) {
426       msg += ": " + e;
427     }
428     if (!this->tokens.empty()) {
429       auto t = this->current;
430       if (t == this->tokens.end()) {
431         --t;
432       }
433       msg += "\nError at line " + std::to_string(t->line);
434     }
435     tfel::raise(msg);
436   }  // end of DSLBase::throwRuntimeError
437 
treatImport()438   void DSLBase::treatImport() {
439     const auto m = "DSLBase::treatImport";
440     const auto oFileName = this->fd.fileName;
441     this->checkNotEndOfFile(m);
442     const auto& files = this->readStringOrArrayOfString(m);
443     this->checkNotEndOfFile(m);
444     this->readSpecifiedToken(m, ";");
445     TokensContainer oFileTokens;
446     oFileTokens.swap(this->tokens);
447     const auto ocurrent = this->current;
448     for (const auto& f : files) {
449       this->importFile(SearchPathsHandler::search(f), std::vector<std::string>(), {});
450     }
451     this->fd.fileName = oFileName;
452     this->tokens.swap(oFileTokens);
453     this->current = ocurrent;
454   }
455 
checkNotEndOfFile(const std::string & m,const std::string & e) const456   void DSLBase::checkNotEndOfFile(const std::string& m, const std::string& e) const {
457     if (this->current == this->tokens.end()) {
458       auto msg = std::string{};
459       msg += "unexpected end of file.";
460       if (!e.empty()) {
461         msg += "\n" + e;
462       }
463       if (!this->tokens.empty()) {
464         const auto previous = std::prev(this->current);
465         msg += "\nError at line " + std::to_string(previous->line);
466       }
467       this->throwRuntimeError(m, msg);
468     }
469   }  // end of DSLBase::checkNotEndOfFile
470 
readUnsignedShort(const std::string & m)471   unsigned short DSLBase::readUnsignedShort(const std::string& m) {
472     this->checkNotEndOfFile(m, "Cannot read unsigned short value.");
473     unsigned short value;
474     std::istringstream flux(current->value);
475     flux >> value;
476     if ((flux.fail()) || (!flux.eof())) {
477       this->throwRuntimeError(m, "Failed to read unsigned short value.");
478     }
479     ++(this->current);
480     return value;
481   }  // end of DSLBase::readUnsignedShort
482 
readSpecifiedToken(const std::string & m,const std::string & v)483   void DSLBase::readSpecifiedToken(const std::string& m, const std::string& v) {
484     this->checkNotEndOfFile(m, "expected '" + v + "'.");
485     if (this->current->value != v) {
486       this->throwRuntimeError(m, "expected '" + v +
487                                      "', "
488                                      "read '" +
489                                      this->current->value +
490                                      "'.\n"
491                                      "Error at line: " +
492                                      std::to_string(this->current->line));
493     }
494     ++(this->current);
495   }  // end of DSLBase::readSpecifiedToken
496 
readUntilEndOfInstruction()497   std::string DSLBase::readUntilEndOfInstruction() {
498     auto res = std::string{};
499     while ((this->current != this->tokens.end()) && (this->current->value != ";")) {
500       if (!this->current->value.empty()) {
501         if (this->current->value[0] == '@') {
502           this->throwRuntimeError("DSLBase::readUntilEndOfInstruction", "no word beginning with '@' are allowed here");
503         }
504         res += this->current->value;
505         res += " ";
506       }
507       ++(this->current);
508     }
509     this->checkNotEndOfFile("DSLBase::readUntilEndOfInstruction", "Missing ';' delimiter.");
510     if (!res.empty()) {
511       res.erase(res.length() - 1);
512     }
513     ++(this->current);
514     return res;
515   }
516 
readOnlyOneToken()517   std::string DSLBase::readOnlyOneToken() {
518     this->checkNotEndOfFile("DSLBase::readOnlyOneToken", "Expected a word.");
519     if (this->current->value == ";") {
520       this->throwRuntimeError("DSLBase::readOnlyOneToken", "no word read");
521     }
522     const auto res = this->current->value;
523     ++(this->current);
524     this->readSpecifiedToken("DSLBase::readOnlyOneToken", ";");
525     return res;
526   }  // end of DSLBase::readOnlyOneToken
527 
readVariableBounds()528   std::pair<std::string, VariableBoundsDescription> DSLBase::readVariableBounds() {
529     return mfront::readVariableBounds(this->current, this->end());
530   }  // end of DSLBase::readVariableBounds
531 
registerIntegerConstant(const std::string & n,const size_t l,const int v)532   void DSLBase::registerIntegerConstant(const std::string& n, const size_t l, const int v) {
533     if (!this->isValidIdentifier(n)) {
534       this->throwRuntimeError("DSLBase::registerIntegerConstant", "Variable name '" + n + "' is not valid.");
535     }
536     this->addStaticVariableDescription(StaticVariableDescription("int", n, l, v));
537   }  // end of DSLBase::registerIntegerConstant
538 
treatIntegerConstant()539   void DSLBase::treatIntegerConstant() {
540     this->checkNotEndOfFile("DSLBase::treatIntegerConstant", "Cannot read type of static variable.");
541     const auto name = this->current->value;
542     const auto line = this->current->line;
543     ++(this->current);
544     const auto value = this->readInitialisationValue<int>(name, true);
545     this->readSpecifiedToken("DSLBase::treatIntegerConstant", ";");
546     this->registerIntegerConstant(name, line, value.second);
547   }  // end of DSLBase::treatIntegerConstant
548 
readArrayOfVariablesSize(const std::string & n,const bool b)549   unsigned int DSLBase::readArrayOfVariablesSize(const std::string& n,
550                                                  const bool b) {
551     auto throw_if = [this](const bool c, const std::string& m) {
552       if (c) {
553         this->throwRuntimeError("DSLBase::readArrayOfVariablesSize", m);
554       }
555     };
556     this->checkNotEndOfFile("DSLBase::readArrayOfVariablesSize");
557     unsigned int asize = 1u;
558     if (this->current->value == "[") {
559       throw_if(!b, "variable '" + n + "' can't be declared an array");
560       auto array_size = std::string{};
561       ++(this->current);
562       this->checkNotEndOfFile("DSLBase::readArrayOfVariablesSize");
563       while (this->current->value != "]") {
564         throw_if(((this->current->flag != tfel::utilities::Token::Standard) &&
565                   (this->current->flag != tfel::utilities::Token::Number)) ||
566                      (this->current->value == ";"),
567                  "invalid array size for '" + n + "'");
568         array_size += this->current->value;
569         ++(this->current);
570         this->checkNotEndOfFile("DSLBase::readArrayOfVariablesSize");
571       }
572       throw_if(array_size.empty(), "empty array size for '" + n + "'");
573       tfel::math::IntegerEvaluator ev(array_size);
574       const auto& vars = ev.getVariablesNames();
575       for (const auto& v : vars) {
576         ev.setVariableValue(v, this->getIntegerConstant(v));
577       }
578       const auto iv = ev.getValue();
579       throw_if(iv <= 0, "invalid array size for '" + n + "'");
580       asize = static_cast<unsigned int>(iv);
581       this->readSpecifiedToken("DSLBase::readArrayOfVariablesSize", "]");
582       this->checkNotEndOfFile("DSLBase::readArrayOfVariablesSize");
583     }
584     return asize;
585   }  // end of DSLBase::readArrayOfVariablesSize
586 
readVarList(VariableDescriptionContainer & cont,const std::string & type,const bool allowArray)587   void DSLBase::readVarList(VariableDescriptionContainer& cont,
588                             const std::string& type,
589                             const bool allowArray) {
590     auto throw_if = [this](const bool b, const std::string& m) {
591       if (b) {
592         this->throwRuntimeError("DSLBase::readVarList", m);
593       }
594     };
595     auto endComment = std::string{};
596     auto endOfTreatment = false;
597     while ((this->current != this->tokens.end()) && (!endOfTreatment)) {
598       const auto sname = this->current->value;
599       const auto vname = tfel::unicode::getMangledString(sname);
600       throw_if(!this->isValidIdentifier(vname),
601                "variable given is not valid (read '" + sname + "').");
602       auto lineNumber = this->current->line;
603       ++(this->current);
604       this->checkNotEndOfFile("DSLBase::readVarList");
605       const auto asize = this->readArrayOfVariablesSize(sname, allowArray);
606       if (this->current->value == ",") {
607         ++(this->current);
608       } else if (this->current->value == ";") {
609         endOfTreatment = true;
610         endComment = this->current->comment;
611         ++(this->current);
612       } else {
613         throw_if(true, "',' or ';' expected after '" + sname + "'");
614       }
615       if (vname == sname) {
616         cont.push_back(VariableDescription(type, vname, asize, lineNumber));
617       } else {
618         cont.push_back(
619             VariableDescription(type, sname, vname, asize, lineNumber));
620       }
621       if (!this->currentComment.empty()) {
622         cont.back().description = this->currentComment;
623       }
624     }
625     if (!endComment.empty()) {
626       for (auto& c : cont) {
627         if (!c.description.empty()) {
628           c.description += ' ';
629         }
630         c.description += endComment;
631       }
632     }
633     if (!endOfTreatment) {
634       --(this->current);
635       throw_if(true, "expected ';' before end of file");
636     }
637   }
638 
readType()639   std::pair<std::string, bool> DSLBase::readType() {
640     auto throw_if = [this](const bool b, const std::string& m) {
641       if (b) {
642         this->throwRuntimeError("DSLBase::readType", m);
643       }
644     };
645     auto type = this->current->value;
646     throw_if(!this->isValidIdentifier(type, false), "given type '" + type + "' is not valid.");
647     ++(this->current);
648     this->checkNotEndOfFile("DSLBase::readType");
649     while (this->current->value == "::") {
650       ++(this->current);
651       this->checkNotEndOfFile("DSLBase::readType");
652       const auto t = this->current->value;
653       throw_if(!this->isValidIdentifier(t, false), "given type '" + t + "' is not valid.");
654       type += "::" + t;
655       ++(this->current);
656       this->checkNotEndOfFile("DSLBase::readType");
657     }
658     if (this->current->value == "<") {
659       bool b = false;
660       type += "<";
661       this->checkNotEndOfFile("DSLBase::readType");
662       ++(this->current);
663       this->checkNotEndOfFile("DSLBase::readType");
664       bool c = true;
665       while (c) {
666         if (isInteger(this->current->value)) {
667           type += this->current->value;
668           ++(this->current);
669         } else {
670           const auto r = this->readType();
671           type += r.first;
672           b = r.second;
673           if (!b) {
674             c = false;
675           }
676         }
677         if (c) {
678           this->checkNotEndOfFile("DSLBase::readType");
679           if (this->current->value == ",") {
680             this->readSpecifiedToken("DSLBase::readType", ",");
681             type += ",";
682           } else {
683             c = false;
684           }
685         }
686       }
687       if (b) {
688         if (this->current->value == ">>") {
689           ++(this->current);
690           return {type + '>', false};
691         } else {
692           this->readSpecifiedToken("DSLBase::readType", ">");
693         }
694         type += ">";
695       }
696     }
697     return {type, true};
698   }  // end of DSLBase::readType
699 
readVarList(VariableDescriptionContainer & cont,const bool allowArray)700   void DSLBase::readVarList(VariableDescriptionContainer& cont, const bool allowArray) {
701     this->checkNotEndOfFile("DSLBase::readVarList", "Cannot read type of varName.\n");
702     const auto r = this->readType();
703     if (!r.second) {
704       this->throwRuntimeError("DSLBase::readVarList", "unbalanced '>'");
705     }
706     this->readVarList(cont, r.first, allowArray);
707   }  // end of DSLBase::readVarList
708 
readList(const std::string & m,const std::string & db,const std::string & de,const bool b)709   std::vector<tfel::utilities::Token> DSLBase::readList(const std::string& m,
710                                                         const std::string& db,
711                                                         const std::string& de,
712                                                         const bool b) {
713     std::vector<tfel::utilities::Token> t;
714     this->readList(t, m, db, de, b);
715     return t;
716   }  // end of DSLBase::readList
717 
readList(std::vector<tfel::utilities::Token> & l,const std::string & m,const std::string & db,const std::string & de,const bool b)718   void DSLBase::readList(std::vector<tfel::utilities::Token>& l,
719                          const std::string& m,
720                          const std::string& db,
721                          const std::string& de,
722                          const bool b) {
723     l.clear();
724     this->checkNotEndOfFile(m, "Expected '" + db + "'");
725     if (this->current == this->tokens.end()) {
726       if (b) {
727         return;
728       }
729     }
730     this->checkNotEndOfFile(m, "Expected '" + db + "'");
731     if (this->current->value != db) {
732       return;
733     }
734     this->readSpecifiedToken(m, db);
735     this->checkNotEndOfFile(m, "Expected '" + de + "'");
736     while (this->current->value != de) {
737       l.push_back(*(this->current));
738       ++(this->current);
739       this->checkNotEndOfFile(m, "Expected '" + de + "'");
740       if (!((this->current->value == de) || (this->current->value == ","))) {
741         this->throwRuntimeError(m, "Expected ',' or '" + de +
742                                        "',"
743                                        " read '" +
744                                        this->current->value + "'");
745       }
746       if (this->current->value == ",") {
747         ++(this->current);
748         this->checkNotEndOfFile(m, "Expected '" + de + "'");
749         if (this->current->value == de) {
750           this->throwRuntimeError(m, "Expected a new item");
751         }
752       }
753     }
754     ++(this->current);
755   }  // end of DSLBase::readList
756 
readArrayOfString(const std::string & m)757   std::vector<std::string> DSLBase::readArrayOfString(const std::string& m) {
758     auto r = std::vector<std::string>{};
759     auto as = std::vector<tfel::utilities::Token>{};
760     this->readList(as, m, "{", "}", false);
761     r.reserve(as.size());
762     for (const auto& t : as) {
763       if (t.flag != tfel::utilities::Token::String) {
764         this->throwRuntimeError(m, "Expected a string");
765       }
766       r.push_back(t.value.substr(1, t.value.size() - 2));
767     }
768     return r;
769   }  // end of DSLBase::readArrayOfString
770 
readArrayOfDouble(const std::string & m)771   std::vector<double> DSLBase::readArrayOfDouble(const std::string& m) {
772     auto r = std::vector<double>{};
773     auto as = std::vector<tfel::utilities::Token>{};
774     this->readList(as, m, "{", "}", false);
775     r.reserve(as.size());
776     for (const auto& t : as) {
777       r.push_back(tfel::utilities::convert<double>(t.value));
778     }
779     return r;
780   }  // end of DSLBase::readArrayOfDouble
781 
readBooleanValue(const std::string & m)782   bool DSLBase::readBooleanValue(const std::string& m) {
783     bool b = false;
784     this->checkNotEndOfFile(m, "Expected a boolean value");
785     if (this->current->value == "true") {
786       b = true;
787     } else if (this->current->value == "false") {
788       b = false;
789     } else {
790       this->throwRuntimeError(m,
791                               "Expected to read 'true' or 'false' "
792                               "(read '" +
793                                   this->current->value + "')");
794     }
795     ++(this->current);
796     return b;
797   }  // end of DSLBase::readBooleanValue
798 
readString(const std::string & m)799   std::string DSLBase::readString(const std::string& m) {
800     this->checkNotEndOfFile(m, "Expected a string or '{'");
801     if (this->current->flag != tfel::utilities::Token::String) {
802       this->throwRuntimeError(m, "Expected a string");
803     }
804     const auto& r = this->current->value.substr(1, this->current->value.size() - 2);
805     ++(this->current);
806     return r;
807   }  // end of DSLBase::readString
808 
readStringOrArrayOfString(const std::string & m)809   std::vector<std::string> DSLBase::readStringOrArrayOfString(const std::string& m) {
810     this->checkNotEndOfFile(m, "Expected a string or '{'");
811     if (this->current->value == "{") {
812       return this->readArrayOfString(m);
813     }
814     return {1u, this->readString(m)};
815   }  // end of DSLBase::readStringOrArrayOfString
816 
treatLink()817   void DSLBase::treatLink() {
818     const auto nlink = readStringOrArrayOfString("DSLBase::treatLink");
819     this->readSpecifiedToken("DSLBase::treatLink", ";");
820     for (const auto& l : nlink) {
821       insert_if(this->ldflags, l);
822     }
823   }  // end of DSLBase::treatLink
824 
callMFront(const std::vector<std::string> & interfaces,const std::vector<std::string> & files)825   void DSLBase::callMFront(const std::vector<std::string>& interfaces,
826                            const std::vector<std::string>& files) {
827     MFront m;
828     for (const auto& i : interfaces) {
829       m.setInterface(i);
830     }
831     for (const auto& f : files) {
832       mergeTargetsDescription(this->td, m.treatFile(f), false);
833     }
834   }  // end of DSLBase::callMFront
835 
treatMFront()836   void DSLBase::treatMFront() {
837     this->readSpecifiedToken("DSLBase::treatMfront", "{");
838     const auto vfiles = this->readStringOrArrayOfString("DSLBase::treatMfront");
839     auto vinterfaces = std::vector<std::string>{};
840     this->checkNotEndOfFile("DSLBase::treatMfront", "Expected '}'");
841     if (!((this->current->value == "}") || (this->current->value == ","))) {
842       this->throwRuntimeError("DSLBase::treatMfront", "Expected ',' or '}', read '" + this->current->value + "'");
843     }
844     if (this->current->value == ",") {
845       ++(this->current);
846       vinterfaces = this->readStringOrArrayOfString("DSLBase::treatMfront");
847     }
848     this->readSpecifiedToken("DSLBase::treatMfront", "}");
849     this->readSpecifiedToken("DSLBase::treatMfront", ";");
850     for (const auto& f : vfiles) {
851       this->externalMFrontFiles.insert({f, vinterfaces});
852     }
853   }  // end of DSLBase::treatMfront
854 
readSpecifiedValue(const std::string & file,const std::string & value)855   std::string DSLBase::readSpecifiedValue(const std::string& file, const std::string& value) {
856     std::vector<std::string> values(1, value);
857     return this->readSpecifiedValues(file, values)[1];
858   }  // end of DSLBase::readSpecifiedValue
859 
readSpecifiedValues(const std::string & file,const std::string & value1,const std::string & value2)860   std::vector<std::string> DSLBase::readSpecifiedValues(const std::string& file,
861                                                         const std::string& value1,
862                                                         const std::string& value2) {
863     return this->readSpecifiedValues(file, {value1, value2});
864   }  // end of DSLBase::readSpecifiedValues
865 
readSpecifiedValues(const std::string & file,const std::vector<std::string> & values)866   std::vector<std::string> DSLBase::readSpecifiedValues(const std::string& file,
867                                                         const std::vector<std::string>& values) {
868     auto throw_if = [](const bool b, const std::string& m, const unsigned int l) {
869       tfel::raise_if(b, "DSLBase::readSpecifiedValues : " + m +
870                             "\n"
871                             "Error at line " +
872                             std::to_string(l));
873     };
874     tfel::utilities::CxxTokenizer cfile;
875     auto res = std::vector<std::string>(values.size());
876     cfile.openFile(file);
877     cfile.stripComments();
878     auto pt = cfile.begin();
879     const auto pte = cfile.end();
880     while (pt != pte) {
881       const auto p = find(values.begin(), values.end(), pt->value);
882       if (p != values.end()) {
883         if (pt != cfile.begin()) {
884           auto ptp = std::prev(pt);
885           throw_if(ptp->value != ";", "the keyword '" + *p +
886                                           "' does not "
887                                           "begin a new instruction.",
888                    pt->line);
889         }
890         throw_if(++pt == pte, "unexepected end of file '" + file + "' (expected " + *p + ").\n", (--pt)->line);
891         const auto value = pt->value;
892         throw_if(pt->value == ";", "unexepected token ';' (exepected " + *p + ")", pt->line);
893         throw_if(++pt == pte, "unexepected end of file '" + file + "' (expected ';').\n", (--pt)->line);
894         throw_if(pt->value != ";", "unexepected token '" + pt->value + "' (exepected ';')", pt->line);
895         res[static_cast<std::vector<std::string>::size_type>(p - values.begin())] = value;
896       }
897       ++pt;
898     }
899     return res;
900   }  // end of DSLBase::readSpecifiedValues
901 
handleMaterialPropertyDescription(const std::string & f)902   std::shared_ptr<MaterialPropertyDescription> DSLBase::handleMaterialPropertyDescription(const std::string& f) {
903     // getting informations the source files
904     MaterialPropertyDSL mp;
905     try {
906       MFrontMaterialPropertyInterface minterface;
907       const auto& path = SearchPathsHandler::search(f);
908       mp.setInterfaces({"mfront"});
909       mp.analyseFile(path);
910       const auto t = mp.getTargetsDescription();
911       if (!t.specific_targets.empty()) {
912         this->throwRuntimeError("DSLBase::handleMaterialPropertyDescription", "error while treating file '" + f +
913                                                                                   "'.\n"
914                                                                                   "Specific targets are not supported");
915       }
916       const auto& mpd = mp.getMaterialPropertyDescription();
917       const auto& mname = minterface.getFunctionName(mpd);
918       this->reserveName(mname);
919       this->reserveName(mname + "_checkBounds");
920       this->reserveName(mname + "_bounds_check_status");
921       this->appendToIncludes("#include\"" + minterface.getHeaderFileName(mpd.material, mpd.law) + ".hxx\"");
922       this->addMaterialLaw(mname);
923       this->atds.push_back(std::move(t));
924       this->externalMFrontFiles.insert({path, {"mfront"}});
925     } catch (std::exception& e) {
926       this->throwRuntimeError("DSLBase::handleMaterialPropertyDescription",
927                               "error while treating file '" + f + "'\n" + std::string(e.what()));
928     } catch (...) {
929       this->throwRuntimeError("DSLBase::handleMaterialPropertyDescription", "error while treating file '" + f + "'");
930     }
931     const auto& m = mp.getMaterialPropertyDescription();
932     return std::make_shared<MaterialPropertyDescription>(m);
933   }  // end of DSLBase::handleMaterialLaw
934 
treatMaterialLaw()935   void DSLBase::treatMaterialLaw() {
936     const auto vfiles = this->readStringOrArrayOfString("DSLBase::treatMaterialLaw");
937     this->readSpecifiedToken("DSLBase::treatMaterialLaw", ";");
938     for (const auto& f : vfiles) {
939       this->handleMaterialPropertyDescription(f);
940     }
941   }  // end of DSLBase::treatMaterialLaw
942 
treatLonelySeparator()943   void DSLBase::treatLonelySeparator() {
944     if (getPedanticMode()) {
945       getLogStream() << this->fd.fileName << ":" << this->current->line << ":" << this->current->offset
946                      << ": warning: extra ‘;’ [-pedantic]\n";
947     }
948   }  // end of DSLBase::treatLonelySperator
949 
overrideMaterialKnowledgeIdentifier(const std::string & i)950   void DSLBase::overrideMaterialKnowledgeIdentifier(const std::string& i) {
951     if (!this->overriden_implementation_name.empty()) {
952       this->throwRuntimeError("DSLBase::overrideMaterialKnowledgeIdentifier",
953                               "the implementation name is already overriden");
954     }
955     this->overriden_implementation_name = i;
956     this->setMaterialKnowledgeIdentifier(i);
957   }  // end of DSLBase::overrideMaterialKnowledgeIdentifier
958 
overrideMaterialName(const std::string & m)959   void DSLBase::overrideMaterialName(const std::string& m) {
960     if (!this->overriden_material.empty()) {
961       this->throwRuntimeError("DSLBase::overrideMaterialName",
962                               "the material name is already overriden");
963     }
964     this->overriden_material = m;
965     this->setMaterial(m);
966   }  // end of DSLBase::overrideMaterialName
967 
overrideAuthorName(const std::string & a)968   void DSLBase::overrideAuthorName(const std::string& a) {
969     if (!this->overriden_author.empty()) {
970       this->throwRuntimeError("DSLBase::overrideAuthorName",
971                               "the author is already overriden");
972     }
973     this->overriden_author = a;
974     this->setAuthor(a);
975   }  // end of DSLBase::overrideAuthorName
976 
overrideDate(const std::string & d)977   void DSLBase::overrideDate(const std::string& d) {
978     if (!this->overriden_date.empty()) {
979       this->throwRuntimeError("DSLBase::overrideDate",
980                               "the date is already overriden");
981     }
982     this->overriden_date = d;
983     this->setDate(d);
984   }  // end of DSLBase::overrideAuthorName
985 
overrideDescription(const std::string & d)986   void DSLBase::overrideDescription(const std::string& d) {
987     if (!this->overriden_description.empty()) {
988       this->throwRuntimeError("DSLBase::overrideDescription",
989                               "the description is already overriden");
990     }
991     this->overriden_description = d;
992     this->setDescription(d);
993   }  // end of DSLBase::overrideAuthorName
994 
treatMaterial()995   void DSLBase::treatMaterial() {
996     const auto& m = this->readOnlyOneToken();
997     if (this->overriden_material.empty()) {
998       this->setMaterial(m);
999    }
1000   }  // end of DSLBase::treatMaterial
1001 
treatAuthor()1002   void DSLBase::treatAuthor() {
1003     const auto author = this->readUntilEndOfInstruction();
1004     if (this->overriden_author.empty()) {
1005       this->setAuthor(author);
1006     }
1007   }  // end of DSLBase::treatAuthor
1008 
setAuthor(const std::string & a)1009   void DSLBase::setAuthor(const std::string& a) {
1010     if (!this->fd.authorName.empty()) {
1011       this->throwRuntimeError("DSLBase::setAuthor", "author already specified");
1012     }
1013     this->fd.authorName = a;
1014   }  // end of DSLBase::setAuthor
1015 
treatDate()1016   void DSLBase::treatDate() {
1017     const auto date = this->readUntilEndOfInstruction();
1018     if (this->overriden_date.empty()) {
1019       this->setDate(date);
1020     }
1021   }  // end of DSLBase::treatDate
1022 
setDate(const std::string & d)1023   void DSLBase::setDate(const std::string& d) {
1024     if (!this->fd.date.empty()) {
1025       this->throwRuntimeError("DSLBase::setDate", "date already specified");
1026     }
1027     this->fd.date = d;
1028   }  // end of DSLBase::setDate
1029 
treatDescription()1030   void DSLBase::treatDescription() {
1031     this->readSpecifiedToken("DSLBase::treatDescription", "{");
1032     this->checkNotEndOfFile("DSLBase::treatDescription");
1033     auto description = std::string{};
1034     description += "* ";
1035     auto currentLine = this->current->line;
1036     unsigned int openedBrackets = 1u;
1037     while ((this->current != this->tokens.end()) && (!((this->current->value == "}") && (openedBrackets == 1u)))) {
1038       if (this->current->value == "{") {
1039         const auto previous = std::prev(this->current);
1040         if ((previous->value.size() > 0) && (previous->value[previous->value.size() - 1] != '\\')) {
1041           ++openedBrackets;
1042         }
1043       }
1044       if (this->current->value == "}") {
1045         const auto previous = std::prev(this->current);
1046         if ((previous->value.size() > 0) && (previous->value[previous->value.size() - 1] != '\\')) {
1047           --openedBrackets;
1048         }
1049       }
1050       if (currentLine != this->current->line) {
1051         while (currentLine != this->current->line) {
1052           description += "\n* ";
1053           ++currentLine;
1054         }
1055       }
1056       if (this->current->flag == tfel::utilities::Token::String) {
1057         description += this->current->value.substr(1, this->current->value.size() - 2u);
1058       } else {
1059         description += this->current->value;
1060       }
1061       description += " ";
1062       ++(this->current);
1063     }
1064     if (this->current == this->tokens.end()) {
1065       --(this->current);
1066       this->throwRuntimeError("DSLBase::treatDescription", "File ended before the end of description.");
1067     }
1068     ++(this->current);
1069     if (this->overriden_description.empty()) {
1070       this->setDescription(description);
1071     }
1072   }  // end of DSLBase::treatDescription
1073 
setDescription(const std::string & d)1074   void DSLBase::setDescription(const std::string& d) {
1075     if (!this->fd.description.empty()) {
1076       this->throwRuntimeError("DSLBase::setDescription", "date already specified");
1077     }
1078     this->fd.description= d;
1079   }  // end of DSLBase::setDescription
1080 
treatUnknownKeyword()1081   void DSLBase::treatUnknownKeyword() {
1082     --(this->current);
1083     this->throwRuntimeError("DSLBase::treatUnknownKeyword", "unknown keyword (read '" + this->current->value + "')");
1084   }  // end of DSLBase::treatUnknownKeyword
1085 
treatIncludes()1086   void DSLBase::treatIncludes() {
1087     CodeBlockParserOptions options;
1088     this->appendToIncludes(this->readNextBlock(options).code);
1089   }
1090 
treatSources()1091   void DSLBase::treatSources() {
1092     CodeBlockParserOptions options;
1093     this->appendToSources(this->readNextBlock(options).code);
1094   }  // end of DSLBase::treatSources
1095 
treatMembers()1096   void DSLBase::treatMembers() {
1097     CodeBlockParserOptions options;
1098     options.qualifyStaticVariables = true;
1099     options.qualifyMemberVariables = true;
1100     this->appendToMembers(this->readNextBlock(options).code);
1101   }
1102 
treatPrivate()1103   void DSLBase::treatPrivate() {
1104     CodeBlockParserOptions options;
1105     options.qualifyStaticVariables = true;
1106     options.qualifyMemberVariables = true;
1107     this->appendToPrivateCode(this->readNextBlock(options).code);
1108   }  // end of DSLBase::treatPrivate
1109 
treatParser()1110   void DSLBase::treatParser() { this->readUntilEndOfInstruction(); }  // end of DSLBase::treatParser
1111 
treatStaticVar()1112   void DSLBase::treatStaticVar() {
1113     this->checkNotEndOfFile("DSLBase::treatStaticVar", "Cannot read type of static variable.");
1114     const auto type = this->current->value;
1115     if (!this->isValidIdentifier(type, false)) {
1116       --(this->current);
1117       this->throwRuntimeError("DSLBase::treatStaticVar", "type given is not valid.");
1118     }
1119     ++(this->current);
1120     this->checkNotEndOfFile("DSLBase::treatStaticVar", "Cannot read variable name.");
1121     const auto sname = this->current->value;
1122     const auto vname = tfel::unicode::getMangledString(sname);
1123     if (!this->isValidIdentifier(vname)) {
1124       this->throwRuntimeError("DSLBase::treatStaticVar",
1125                               "Variable name '" + sname + "' is not valid.");
1126     }
1127     const auto line = this->current->line;
1128     ++(this->current);
1129     this->checkNotEndOfFile("DSLBase::treatStaticVar", "Expected to read value of variable.");
1130     const auto value = this->readInitialisationValue<long double>(sname, true);
1131     this->readSpecifiedToken("DSLBase::treatStaticVar", ";");
1132     this->addStaticVariableDescription(
1133         StaticVariableDescription(type, sname, vname, line, value.second));
1134   }  // end of DSLBase::treatStaticVar
1135 
ignoreKeyWord(const std::string & key)1136   void DSLBase::ignoreKeyWord(const std::string& key) {
1137     this->checkNotEndOfFile("DSLBase::ignoreKeyWord", "error while treating keyword '" + key + "' ");
1138     while ((this->current->value != "{") && (this->current->value != ";")) {
1139       ++(this->current);
1140       this->checkNotEndOfFile("DSLBase::ignoreKeyWord", "error while treating keyword '" + key + "' ");
1141     }
1142     if (this->current->value == "{") {
1143       unsigned short openedBrackets = 1;
1144       while (!((this->current->value == "}") && (openedBrackets == 0))) {
1145         ++(this->current);
1146         this->checkNotEndOfFile("DSLBase::ignoreKeyWord", "error while treating keyword '" + key + "' ");
1147         if (this->current->value == "{") {
1148           ++openedBrackets;
1149         }
1150         if (this->current->value == "}") {
1151           --openedBrackets;
1152         }
1153       }
1154       const auto next = std::next(this->current);
1155       if (next != this->tokens.end()) {
1156         if (next->value == ";") {
1157           current = next;
1158         }
1159       }
1160     }
1161     ++(this->current);
1162   }  // end of DSLBase::ignoreKeyWord
1163 
readDouble()1164   double DSLBase::readDouble() {
1165     this->checkNotEndOfFile("DSLBase::readDouble");
1166     return CxxTokenizer::readDouble(this->current, this->tokens.end());
1167   }  // end of DSLBase::readDouble
1168 
completeTargetsDescription()1169   void DSLBase::completeTargetsDescription() {
1170     for (auto& l : this->td.libraries) {
1171       l.ldflags.insert(l.ldflags.end(), this->ldflags.begin(), this->ldflags.end());
1172     }
1173     for (const auto& t : this->atds) {
1174       for (const auto& al : t.libraries) {
1175         for (auto& l : this->td.libraries) {
1176           if (l.name != al.name) {
1177             insert_if(l.deps, al.name);
1178           }
1179         }
1180       }
1181     }
1182     for (const auto& t : this->atds) {
1183       mergeTargetsDescription(this->td, t, false);
1184     }
1185     this->ldflags.clear();
1186     this->atds.clear();
1187   }  // end of DSLBase::completeTargetsDescription()
1188 
1189 }  // end of namespace mfront
1190