Merge branch 'master' of https://scm.cri.ensmp.fr/git/Faustine
[Faustine.git] / interpretor / faust-0.9.47mr3 / compiler / documentator / lateq.cpp
1 /************************************************************************
2 ************************************************************************
3 FAUST compiler
4 Copyright (C) 2003-2004 GRAME, Centre National de Creation Musicale
5 ---------------------------------------------------------------------
6 This program is free software; you can redistribute it and/or modify
7 it under the terms of the GNU General Public License as published by
8 the Free Software Foundation; either version 2 of the License, or
9 (at your option) any later version.
10
11 This program is distributed in the hope that it will be useful,
12 but WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 GNU General Public License for more details.
15
16 You should have received a copy of the GNU General Public License
17 along with this program; if not, write to the Free Software
18 Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
19 ************************************************************************
20 ************************************************************************/
21
22
23
24 /**********************************************************************
25 - lateq.cpp : the Lateq methods definition (FAUST project) -
26 - for automatic generation of documentation -
27 - "lateq" stands for "LaTeX equations" -
28 - The crucial method here is println -
29
30 Historique :
31 -----------
32 17-10-2001 : (klass.cpp) implementation initiale (yo)
33 18-10-2001 : (klass.cpp) Ajout de getFreshID (yo)
34 02-11-2001 : (klass.cpp) Ajout de sous classes (yo)
35 06-11-2001 : (klass.cpp) modif impression des classes (yo)
36 16-08-2009 : (lateq.cpp) Creation de lateq depuis klass.cpp (kb)
37 2009-11-21 : (lateq.cpp) Remodelage et documentation doxygen (kb)
38
39 ***********************************************************************/
40
41 #include <stdio.h>
42 #include <iostream>
43 #include <cstdlib>
44 #include <set>
45 #include <sstream>
46
47 #include "lateq.hh"
48 #include "Text.hh"
49
50
51 map<string, string> gDocMathStringMap;
52 set<string> gDocMathKeySet;
53
54 static int getLateqIndex(const string& s);
55 static bool compLateqIndexes(const string& s1, const string& s2);
56 static void initDocMathKeySet();
57
58
59 template <class T>
60 inline std::string to_string (const T& t)
61 {
62 std::stringstream ss;
63 ss << t;
64 return ss.str();
65 }
66
67
68 /****************************************************************
69 Top-level "println" method (public).
70 *****************************************************************/
71
72
73 /**
74 * @brief
75 * Top-level method to print a whole set of compiled LaTeX formulas,
76 * corresponding to an <equation> faustdoc tag.
77 *
78 * @remark
79 * These formulas must have been previously compiled,
80 * via the DocCompile class,
81 * and stored in Lateq fields as LaTeX strings.
82 */
83 void Lateq::println(ostream& docout)
84 {
85 /* 1. Make titles of sub-sets of formulas. */
86 string suchthat = gDocMathStringMap["suchthat"];
87
88 string sInputs = makeItemTitle(fInputSigsFormulas.size(), "inputsigtitle") + makeSignamesList(fInputSigsFormulas, "");
89 string sOutputs = makeItemTitle(fOutputSigsFormulas.size(), "outputsigtitle") + makeSignamesList(fOutputSigsFormulas, suchthat);
90 string sConstants = makeItemTitle(fConstSigsFormulas.size(), "constsigtitle") + makeSignamesList(fConstSigsFormulas, suchthat);
91
92 vector<list<string> > UISignamesVector = makeUISignamesVector(fUISigsFormulas);
93 string sUIElements = makeItemTitle(fUISigsFormulas.size(), "uisigtitle") + makeSignamesList(UISignamesVector, suchthat);
94
95 unsigned int internalSigsCount = fParamSigsFormulas.size() + fStoreSigsFormulas.size() + fRecurSigsFormulas.size() + fRDTblSigsFormulas.size() + fRWTblSigsFormulas.size() + fSelectSigsFormulas.size() + fPrefixSigsFormulas.size();
96
97 vector<list<string> > internalSigsFormulasList;
98 if( ! fParamSigsFormulas.empty() ) internalSigsFormulasList.push_back(fParamSigsFormulas);
99 if( ! fStoreSigsFormulas.empty() ) internalSigsFormulasList.push_back(fStoreSigsFormulas);
100 if( ! fRecurSigsFormulas.empty() ) internalSigsFormulasList.push_back(fRecurSigsFormulas);
101 if( ! fRDTblSigsFormulas.empty() ) internalSigsFormulasList.push_back(fRDTblSigsFormulas);
102 if( ! fRWTblSigsFormulas.empty() ) internalSigsFormulasList.push_back(fRWTblSigsFormulas);
103 if( ! fSelectSigsFormulas.empty() ) internalSigsFormulasList.push_back(fSelectSigsFormulas);
104 if( ! fPrefixSigsFormulas.empty() ) internalSigsFormulasList.push_back(fPrefixSigsFormulas);
105
106 string sInternals = makeItemTitle(internalSigsCount, "intermedsigtitle") + makeSignamesList(internalSigsFormulasList, suchthat);
107
108 /* 2. Successively print each Lateq field containing LaTeX formulas, with a title. */
109
110 docout << endl << gDocMathStringMap["lateqcomment"] << endl;
111 docout << "\\begin{enumerate}" << endl << endl;
112
113 printDGroup (sOutputs, fOutputSigsFormulas, docout);
114 printOneLine (sInputs, docout);
115 const string outputsTitle = "\\item " + sOutputs + "\\ $y_i$\\ " + gDocMathStringMap["for"] + " $i \\in [1," + to_string(fOutputSigsFormulas.size()) + "]$: ";
116 printHierarchy (sUIElements, fUISigsFormulas, docout);
117
118 /* The "Internal signals" item gather several fields, like a "super-item"... */
119 if( internalSigsCount > 0 ) {
120 docout << sInternals;
121 }
122 fStoreSigsFormulas.sort(compLateqIndexes);
123 printDGroup ("", fParamSigsFormulas, docout);
124 printDGroup ("", fStoreSigsFormulas, docout);
125 printDGroup ("", fRecurSigsFormulas, docout);
126 printDGroup ("", fRDTblSigsFormulas, docout);
127 printMath ("", fRWTblSigsFormulas, docout);
128 printMath ("", fSelectSigsFormulas, docout);
129 printMath ("", fPrefixSigsFormulas, docout);
130
131 printDGroup (sConstants, fConstSigsFormulas, docout);
132
133 docout << "\\end{enumerate}" << endl << endl;
134 }
135
136
137
138 /****************************************************************
139 Item title making functions (public).
140 *****************************************************************/
141
142
143 string Lateq::makeItemTitle(const unsigned int formulasListSize, const string& titleName)
144 {
145 string item = "\\item ";
146
147 /* Plural handling for titles of sub-sets of formulas. */
148 string title = formulasListSize > 1 ? gDocMathStringMap[titleName + "2"] : gDocMathStringMap[titleName + "1"];
149
150 return item + title;
151 }
152
153
154 string Lateq::makeSigDomain(const list<string>& formulasList)
155 {
156 string signame = "";
157 string sigDomain = "";
158
159 if (formulasList.size() > 0) {
160 string firstEq = *(formulasList.begin());
161 signame = getSigName(firstEq);
162
163 if(formulasList.size() > 1) {
164 sigDomain = " $" + signame + "_i$ " + gDocMathStringMap["for"] + " $i \\in [1," + to_string(formulasList.size()) + "]$";
165 } else {
166 if(signame == "x" || signame == "y") {
167 sigDomain = " $" + signame + "$"; ///< No indices for single input neither single output.
168 } else {
169 sigDomain = " $" + signame + "_1$"; ///< Indices "1" for all other single signal.
170 }
171 }
172 } else {
173 sigDomain = gDocMathStringMap["emptyformulafield"];
174 }
175 return sigDomain;
176 }
177
178
179 string Lateq::makeSignamesList(const list<string>& formulasList, const string& ending)
180 {
181 if (formulasList.size() > 0) {
182 return makeSigDomain(formulasList) + " " + ending;
183 } else {
184 return " (" + gDocMathStringMap["emptyformulafield"] + ")";
185 }
186 }
187
188
189 string Lateq::makeSignamesList(const vector<list<string> >& formulasListsVector, const string& ending)
190 {
191 if (formulasListsVector.size() > 0) {
192 vector<list<string> >::const_iterator it;
193 string signames = "";
194 string sep = " ";
195 for (it = formulasListsVector.begin(); it != formulasListsVector.end(); ++it) {
196 signames += sep + makeSigDomain(*it);
197 (it != (formulasListsVector.end() - 2)) ? sep = ", " : sep = " " + gDocMathStringMap["and"] + " ";
198 }
199 return signames + " " + ending;
200 } else {
201 return " (" + gDocMathStringMap["emptyformulafield"] + ")";
202 }
203 }
204
205
206 string Lateq::getSigName(const string& s)
207 {
208 size_t found;
209 string signame;
210
211 found = s.find(" =");
212 if (found != string::npos) { ///< Looking for a left member.
213 signame = s.substr (0, found);
214 }
215 found = s.find("(t)");
216 if (found != string::npos) { ///< Strip "(t)" argument if exists.
217 signame = s.substr (0, found);
218 }
219 found = signame.find("[t]");
220 if (found != string::npos) { ///< Strip "[t]" argument if exists (for tables).
221 signame = s.substr (0, found);
222 }
223 found = signame.find_last_of("_");
224 if (found != string::npos) { ///< Strip indice if exists.
225 signame = signame.substr (0, found);
226 }
227
228 return signame;
229 }
230
231
232 vector<list<string> > Lateq::makeUISignamesVector(const multimap<string,string>& field)
233 {
234 map<char,unsigned int> uiTypesMap;
235 vector<list<string> > uiSignamesVector;
236 unsigned int vIndex = 0;
237
238 multimap<string,string>::const_iterator it;
239
240 for (it = field.begin(); it != field.end(); ++it) {
241 char type = getUISigType(it->second);
242 string signame = getUISigName(it->second);
243
244 map<char,unsigned int>::iterator uiTypesIt;
245 uiTypesIt = uiTypesMap.find(type);
246 if( uiTypesIt != uiTypesMap.end()) {
247 uiSignamesVector[uiTypesMap[uiTypesIt->second]].push_back(signame);
248 } else {
249 ++vIndex;
250 uiTypesMap.insert(pair<char,unsigned int>(type, vIndex));
251 list<string>* tmpList = new(list<string>);
252 tmpList->push_back(signame);
253 uiSignamesVector.push_back(*tmpList);
254 }
255 }
256
257 return uiSignamesVector;
258 }
259
260
261 string Lateq::getUISigName(const string& s)
262 {
263 size_t found;
264 string signame;
265
266 found = s.find("${u_");
267 if (found != string::npos) { ///< Looking for a UI signal name "{u_?}_{i}(t)".
268 signame = s.substr (found+1, 12);
269 }
270
271 return signame;
272 }
273
274
275 char Lateq::getUISigType(const string& s)
276 {
277 size_t found;
278 char sigtype = '0';
279
280 found = s.find("${u_");
281 if (found != string::npos) { ///< Looking for a UI signal name "{u_?}_{i}".
282 sigtype = s.at (found+4);
283 }
284
285 return sigtype;
286 }
287
288
289
290 /****************************************************************
291 Secondary printing methods (private).
292 *****************************************************************/
293
294
295 /**
296 * Print a sorted list of input signals names ("x_i"),
297 * on a single line, separated by commas.
298 *
299 * @param[in] section The title to print for these formulas.
300 * @param[out] docout The LaTeX output file to print into.
301 */
302 void Lateq::printOneLine(const string& section, ostream& docout)
303 {
304 docout << section << endl << endl;
305 }
306
307
308 /**
309 * @brief Print a dgroup environment to auto-break long formulas.
310 *
311 * @remark
312 * The "dgroup" and "dmath" environments belong to the "breqn" LaTeX package.
313 * The stared variants "dgroup*" and "dmath*" force unnumbered equations.
314 *
315 * @param[in] section The title to print for these formulas.
316 * @param[in] field The list of LaTeX formulas.
317 * @param[out] docout The LaTeX output file to print into.
318 */
319 void Lateq::printDGroup(const string& section, list<string>& field, ostream& docout)
320 {
321 if (field.size() > 0) {
322 docout << section << endl;
323 tab(1,docout); docout << "\\begin{dgroup*}" << endl;
324 list<string>::const_iterator s;
325 for (s = field.begin(); s != field.end(); ++s) {
326 tab(2,docout); docout << "\\begin{" << "dmath*" << "}" << endl;
327 tab(3,docout); docout << "\t" << *s << endl;
328 tab(2,docout); docout << "\\end{" << "dmath*" << "}" << endl;
329 }
330 tab(1,docout); docout << "\\end{dgroup*}" << endl;
331 docout << endl;
332 }
333 }
334
335
336 /**
337 * @brief Print formulas for user interface signals.
338 *
339 * @param[in] section The title to print for these formulas.
340 * @param[in] field This multimap contains pairs :
341 * 1. the path_string is printed as a sub-title item, when new;
342 * 2. each latex_string is printed as a preformated row of the
343 * supertabular environment (needed to handle long tables).
344 * @param[out] docout The LaTeX output file to print into.
345 *
346 * @remark
347 * To decide when one should avoid to print an itemize environment,
348 * a "global" strategy is applied : in the particular case where
349 * ONLY empty paths were detected in the WHOLE container (all UIs
350 * are at the top level).
351 * In this particular case, UI strings are directly printed,
352 * and their (empty!) path is ignored...
353 * In the other case, we have to print an itemize environment
354 * and manage paths printing (empty AND non-empty paths) as items.
355 *
356 * @see DocCompiler::prepareIntervallicUI
357 * @see DocCompiler::prepareBinaryUI
358 */
359 void Lateq::printHierarchy(const string& section, multimap<string,string>& field, ostream& docout)
360 {
361 if (field.size() > 0) {
362 docout << section << endl;
363
364 bool hasSomePaths = hasNotOnlyEmptyKeys(field); ///< Manage itemize printing for pathnames.
365 unsigned int n; ///< Manage latex indentation offset.
366
367 if (hasSomePaths) {
368 tab(0,docout); docout << "\\begin{itemize}" << endl;
369 n = 1;
370 } else {
371 n = 0;
372 }
373
374 multimap<string,string>::iterator it;
375 string uidir = "improbable_starting_dirname";
376 bool startFlag = true;
377
378 for (it = field.begin(); it != field.end(); ++it) {
379 /* Manage supertabular environment bounds and pathname printing. */
380 if (it->first != uidir) {
381 if (!startFlag) {
382 tab(n+2,docout); docout << "\\end{supertabular}" << endl;
383 tab(n+1,docout); docout << "\\end{center}" << endl;
384 } else {
385 startFlag = false;
386 }
387 if (hasSomePaths) {
388 /* Print the current pathname if new and if pathnames requested. */
389 if (it->first != "") {
390 tab(n+0,docout); docout << "\\item \\textsf{" << it->first << "}" << endl;
391 } else {
392 tab(n+0,docout); docout << "\\item \\emph{" << gDocMathStringMap["rootlevel"] << "}" << endl;
393 }
394 }
395 tab(n+1,docout); docout << "\\begin{center}" << endl;
396 tab(n+2,docout); docout << "\\begin{supertabular}{lll}" << endl;
397 }
398 /* Print the current formula. */
399 tab(n+3,docout); docout << it->second << endl;
400 uidir = it->first;
401 }
402 tab(n+2,docout); docout << "\\end{supertabular}" << endl;
403 tab(n+1,docout); docout << "\\end{center}" << endl;
404 if (hasSomePaths) {
405 tab(n+0,docout); docout << "\\end{itemize}" << endl;
406 }
407 docout << endl;
408 }
409 }
410
411
412 /**
413 * @brief Print formulas for select2, select3 and prefix signals.
414 *
415 * @param[in] section The title to print for these formulas.
416 * @param[in] field The list of LaTeX arrays (for braces with two lines).
417 * @param[out] docout The LaTeX output file to print into.
418 *
419 * @see DocCompiler::generateSelect2
420 * @see DocCompiler::generateSelect3
421 * @see DocCompiler::generatePrefix
422 */
423 void Lateq::printMath(const string& section, list<string>& field, ostream& docout)
424 {
425 if (field.size() > 0) {
426 docout << section;
427 docout << "\\begin{displaymath}" << endl;
428 list<string>::iterator s;
429 for (s = field.begin(); s != field.end(); ++s) {
430 docout << *s << endl;
431 }
432 docout << "\\end{displaymath}" << endl;
433 docout << endl;
434 }
435 }
436
437
438 /** Simple handling of indentation. */
439 void Lateq::tab (int n, ostream& docout) const
440 {
441 while (n--) docout << '\t';
442 }
443
444
445 /**
446 * @brief Find out whether all keys of the multimap are empty or not.
447 *
448 * In other words :
449 * Check that some UIs have a path (non empty).
450 *
451 * In other other words :
452 * Check that all UIs are not at top-level.
453 */
454 bool Lateq::hasNotOnlyEmptyKeys(multimap<string,string>& mm)
455 {
456 typedef multimap<string,string>::iterator MMIT;
457 pair<MMIT,MMIT> range;
458 range = mm.equal_range(""); ///< Look for pairs with empty keys.
459 bool hasOnlyEmptyPaths = (range.first == mm.begin()) && (range.second == mm.end());
460 return !hasOnlyEmptyPaths;
461 }
462
463
464
465 /**
466 * Dispatch initialization of autodoc container.
467 */
468 void initDocMath()
469 {
470 initDocMathKeySet();
471 }
472
473
474 /****************************************************************
475 Internal static functions.
476 *****************************************************************/
477
478
479 /**
480 * Compare indexes of two LaTeX strings,
481 * for the sort() method applied on list<string> fields.
482 */
483 static bool compLateqIndexes(const string& s1, const string& s2)
484 {
485 return getLateqIndex(s1) < getLateqIndex(s2);
486 }
487
488
489 /**
490 * Find out the index of signals in LaTeX signal definition strings,
491 * between the first "_{" and "}" patterns.
492 *
493 * @param[in] s A LaTeX string to parse.
494 * @return <int> The index found, as an integer.
495 */
496 static int getLateqIndex(const string& s)
497 {
498 size_t p1;
499 size_t p2;
500 string sIndex;
501
502 p1 = s.find("_{");
503 if (p1==string::npos) {
504 cerr << "Error : getLateqIndex found no \"{_\" substring.\n";
505 exit(1); }
506 p1 += 2;
507
508 p2 = s.find("}", p1);
509 if (p2==string::npos) {
510 cerr << "Error : getLateqIndex found no \"}\" substring\n.";
511 exit(1); }
512 p2 -= 3;
513
514 sIndex = s.substr (p1, p2);
515
516 return atoi(sIndex.c_str());
517 }
518
519
520 /**
521 * Initialize gDocMathKeySet, a set containing all the keywords.
522 */
523 static void initDocMathKeySet()
524 {
525 gDocMathKeySet.insert("inputsigtitle1");
526 gDocMathKeySet.insert("inputsigtitle2");
527 gDocMathKeySet.insert("outputsigtitle1");
528 gDocMathKeySet.insert("outputsigtitle2");
529 gDocMathKeySet.insert("constsigtitle1");
530 gDocMathKeySet.insert("constsigtitle2");
531 gDocMathKeySet.insert("uisigtitle1");
532 gDocMathKeySet.insert("uisigtitle2");
533 gDocMathKeySet.insert("intermedsigtitle1");
534 gDocMathKeySet.insert("intermedsigtitle2");
535 gDocMathKeySet.insert("lateqcomment");
536 gDocMathKeySet.insert("emptyformulafield");
537 gDocMathKeySet.insert("defaultvalue");
538 gDocMathKeySet.insert("suchthat");
539 gDocMathKeySet.insert("and");
540 gDocMathKeySet.insert("for");
541 gDocMathKeySet.insert("rootlevel");
542
543 gDocMathKeySet.insert("dgmcaption");
544 }
545
546