Rename interpretor to interpreter.
[Faustine.git] / interpreter / preprocessor / faust-0.9.47mr3 / compiler / documentator / lateq.cpp
diff --git a/interpreter/preprocessor/faust-0.9.47mr3/compiler/documentator/lateq.cpp b/interpreter/preprocessor/faust-0.9.47mr3/compiler/documentator/lateq.cpp
new file mode 100644 (file)
index 0000000..d7b0a75
--- /dev/null
@@ -0,0 +1,546 @@
+/************************************************************************
+ ************************************************************************
+    FAUST compiler
+       Copyright (C) 2003-2004 GRAME, Centre National de Creation Musicale
+    ---------------------------------------------------------------------
+    This program is free software; you can redistribute it and/or modify
+    it under the terms of the GNU General Public License as published by
+    the Free Software Foundation; either version 2 of the License, or
+    (at your option) any later version.
+
+    This program is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+    GNU General Public License for more details.
+
+    You should have received a copy of the GNU General Public License
+    along with this program; if not, write to the Free Software
+    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ ************************************************************************
+ ************************************************************************/
+
+
+
+ /**********************************************************************
+               - lateq.cpp : the Lateq methods definition (FAUST project) -
+               - for automatic generation of documentation -
+               - "lateq" stands for "LaTeX equations" -
+               - The crucial method here is println -
+
+               Historique :
+               -----------
+               17-10-2001 : (klass.cpp) implementation initiale (yo)
+               18-10-2001 : (klass.cpp) Ajout de getFreshID (yo)
+               02-11-2001 : (klass.cpp) Ajout de sous classes (yo)
+               06-11-2001 : (klass.cpp) modif impression des classes (yo)
+               16-08-2009 : (lateq.cpp) Creation de lateq depuis klass.cpp (kb)
+               2009-11-21 : (lateq.cpp) Remodelage et documentation doxygen (kb)
+
+***********************************************************************/
+
+#include <stdio.h>
+#include <iostream>
+#include <cstdlib>
+#include <set>
+#include <sstream>
+
+#include "lateq.hh"
+#include "Text.hh"
+
+
+map<string, string>            gDocMathStringMap;
+set<string>                            gDocMathKeySet;
+
+static int     getLateqIndex(const string& s);
+static bool compLateqIndexes(const string& s1, const string& s2);
+static void initDocMathKeySet();
+
+
+template <class T>
+inline std::string to_string (const T& t)
+{
+       std::stringstream ss;
+       ss << t;
+       return ss.str();
+}
+
+
+/****************************************************************
+                               Top-level "println" method (public).
+ *****************************************************************/
+
+
+/**
+ * @brief 
+ * Top-level method to print a whole set of compiled LaTeX formulas,
+ * corresponding to an <equation> faustdoc tag.
+ *
+ * @remark
+ * These formulas must have been previously compiled, 
+ * via the DocCompile class,
+ * and stored in Lateq fields as LaTeX strings.
+ */
+void Lateq::println(ostream& docout)
+{      
+       /* 1. Make titles of sub-sets of formulas. */
+       string suchthat         = gDocMathStringMap["suchthat"];
+       
+       string sInputs          = makeItemTitle(fInputSigsFormulas.size(), "inputsigtitle") + makeSignamesList(fInputSigsFormulas, "");
+       string sOutputs         = makeItemTitle(fOutputSigsFormulas.size(), "outputsigtitle") + makeSignamesList(fOutputSigsFormulas, suchthat);
+       string sConstants       = makeItemTitle(fConstSigsFormulas.size(), "constsigtitle") + makeSignamesList(fConstSigsFormulas, suchthat);
+       
+       vector<list<string> > UISignamesVector = makeUISignamesVector(fUISigsFormulas);
+       string sUIElements      = makeItemTitle(fUISigsFormulas.size(), "uisigtitle") + makeSignamesList(UISignamesVector, suchthat);
+
+       unsigned int internalSigsCount = fParamSigsFormulas.size() + fStoreSigsFormulas.size() + fRecurSigsFormulas.size() + fRDTblSigsFormulas.size() + fRWTblSigsFormulas.size() + fSelectSigsFormulas.size() + fPrefixSigsFormulas.size();
+       
+       vector<list<string> > internalSigsFormulasList;
+       if( ! fParamSigsFormulas.empty() )      internalSigsFormulasList.push_back(fParamSigsFormulas);
+       if( ! fStoreSigsFormulas.empty() )      internalSigsFormulasList.push_back(fStoreSigsFormulas);
+       if( ! fRecurSigsFormulas.empty() )      internalSigsFormulasList.push_back(fRecurSigsFormulas);
+       if( ! fRDTblSigsFormulas.empty() )      internalSigsFormulasList.push_back(fRDTblSigsFormulas);
+       if( ! fRWTblSigsFormulas.empty() )      internalSigsFormulasList.push_back(fRWTblSigsFormulas);
+       if( ! fSelectSigsFormulas.empty() )     internalSigsFormulasList.push_back(fSelectSigsFormulas);
+       if( ! fPrefixSigsFormulas.empty() )     internalSigsFormulasList.push_back(fPrefixSigsFormulas);
+       
+       string sInternals       = makeItemTitle(internalSigsCount, "intermedsigtitle") + makeSignamesList(internalSigsFormulasList, suchthat);
+       
+       /* 2. Successively print each Lateq field containing LaTeX formulas, with a title. */
+       
+       docout << endl << gDocMathStringMap["lateqcomment"] << endl;
+       docout << "\\begin{enumerate}" << endl << endl;
+       
+       printDGroup             (sOutputs, fOutputSigsFormulas, docout);
+       printOneLine    (sInputs, docout);
+       const string outputsTitle = "\\item " + sOutputs + "\\ $y_i$\\ " + gDocMathStringMap["for"] + " $i \\in [1," + to_string(fOutputSigsFormulas.size()) + "]$: ";
+       printHierarchy  (sUIElements, fUISigsFormulas, docout);
+       
+       /* The "Internal signals" item gather several fields, like a "super-item"... */
+       if( internalSigsCount > 0 ) {
+               docout << sInternals;
+       }
+       fStoreSigsFormulas.sort(compLateqIndexes);
+       printDGroup             ("", fParamSigsFormulas, docout);
+       printDGroup             ("", fStoreSigsFormulas, docout);
+       printDGroup             ("", fRecurSigsFormulas, docout);
+       printDGroup             ("", fRDTblSigsFormulas, docout);
+       printMath               ("", fRWTblSigsFormulas, docout);
+       printMath               ("", fSelectSigsFormulas, docout);
+       printMath               ("", fPrefixSigsFormulas, docout);
+
+       printDGroup             (sConstants, fConstSigsFormulas, docout);
+       
+       docout << "\\end{enumerate}" << endl << endl;
+}
+
+
+
+/****************************************************************
+                               Item title making functions (public).
+ *****************************************************************/
+
+
+string Lateq::makeItemTitle(const unsigned int formulasListSize, const string& titleName)
+{
+       string item             = "\\item ";
+       
+       /* Plural handling for titles of sub-sets of formulas. */
+       string title    = formulasListSize > 1 ? gDocMathStringMap[titleName + "2"] : gDocMathStringMap[titleName + "1"];
+       
+       return item + title;
+}
+
+
+string Lateq::makeSigDomain(const list<string>& formulasList)
+{
+       string signame = "";
+       string sigDomain = "";
+       
+       if (formulasList.size() > 0) {
+               string firstEq = *(formulasList.begin());
+               signame = getSigName(firstEq);
+               
+               if(formulasList.size() > 1) {
+                       sigDomain = " $" + signame + "_i$ " + gDocMathStringMap["for"] + " $i \\in [1," + to_string(formulasList.size()) + "]$";
+               } else {
+                       if(signame == "x" || signame == "y") {
+                               sigDomain = " $" + signame + "$"; ///< No indices for single input neither single output.
+                       } else {
+                               sigDomain = " $" + signame + "_1$"; ///< Indices "1" for all other single signal.
+                       }
+               }
+       } else {
+               sigDomain = gDocMathStringMap["emptyformulafield"];
+       }
+       return sigDomain;
+}
+
+
+string Lateq::makeSignamesList(const list<string>& formulasList, const string& ending)
+{
+       if (formulasList.size() > 0) {
+               return makeSigDomain(formulasList) + " " + ending;
+       } else {
+               return " (" + gDocMathStringMap["emptyformulafield"] + ")";
+       }
+}
+
+
+string Lateq::makeSignamesList(const vector<list<string> >& formulasListsVector, const string& ending)
+{
+       if (formulasListsVector.size() > 0) {
+               vector<list<string> >::const_iterator it;
+               string signames = "";
+               string sep = " ";
+               for (it = formulasListsVector.begin(); it != formulasListsVector.end(); ++it) {
+                       signames += sep + makeSigDomain(*it);
+                       (it != (formulasListsVector.end() - 2)) ? sep = ", " : sep = " " + gDocMathStringMap["and"] + " ";
+               }
+               return signames + " " + ending;
+       } else {
+               return " (" + gDocMathStringMap["emptyformulafield"] + ")";
+       }
+}
+
+
+string Lateq::getSigName(const string& s)
+{
+       size_t found;
+       string signame;
+       
+       found = s.find(" =");
+       if (found != string::npos) { ///< Looking for a left member.
+               signame = s.substr (0, found);
+       }
+       found = s.find("(t)");
+       if (found != string::npos) { ///< Strip "(t)" argument if exists.
+               signame = s.substr (0, found);
+       }
+       found = signame.find("[t]");
+       if (found != string::npos) { ///< Strip "[t]" argument if exists (for tables).
+               signame = s.substr (0, found);
+       }
+       found = signame.find_last_of("_");
+       if (found != string::npos) { ///< Strip indice if exists.
+               signame = signame.substr (0, found);
+       }
+       
+       return signame;
+}
+
+
+vector<list<string> > Lateq::makeUISignamesVector(const multimap<string,string>& field)
+{
+       map<char,unsigned int> uiTypesMap;
+       vector<list<string> > uiSignamesVector;
+       unsigned int vIndex = 0;
+       
+       multimap<string,string>::const_iterator it;
+       
+       for (it = field.begin(); it != field.end(); ++it) {
+               char type               = getUISigType(it->second);
+               string signame  = getUISigName(it->second);
+               
+               map<char,unsigned int>::iterator uiTypesIt;
+               uiTypesIt = uiTypesMap.find(type);
+               if( uiTypesIt != uiTypesMap.end()) {
+                       uiSignamesVector[uiTypesMap[uiTypesIt->second]].push_back(signame);
+               } else {
+                       ++vIndex;
+                       uiTypesMap.insert(pair<char,unsigned int>(type, vIndex));
+                       list<string>* tmpList = new(list<string>);
+                       tmpList->push_back(signame);
+                       uiSignamesVector.push_back(*tmpList);
+               }
+       }
+       
+       return uiSignamesVector;
+}
+
+
+string Lateq::getUISigName(const string& s)
+{
+       size_t found;
+       string signame;
+       
+       found = s.find("${u_");
+       if (found != string::npos) { ///< Looking for a UI signal name "{u_?}_{i}(t)".
+               signame = s.substr (found+1, 12);
+       }
+       
+       return signame;
+}
+
+
+char Lateq::getUISigType(const string& s)
+{
+       size_t found;
+       char sigtype = '0';
+       
+       found = s.find("${u_");
+       if (found != string::npos) { ///< Looking for a UI signal name "{u_?}_{i}".
+               sigtype = s.at (found+4);
+       }
+       
+       return sigtype;
+}
+
+
+
+/****************************************************************
+                               Secondary printing methods (private).
+ *****************************************************************/
+
+
+/**
+ * Print a sorted list of input signals names ("x_i"),
+ * on a single line, separated by commas.
+ *
+ * @param[in]  section         The title to print for these formulas.
+ * @param[out] docout          The LaTeX output file to print into.
+ */
+void Lateq::printOneLine(const string& section, ostream& docout)
+{
+       docout << section << endl << endl;
+}
+
+
+/**
+ * @brief Print a dgroup environment to auto-break long formulas.
+ *
+ * @remark
+ * The "dgroup" and "dmath" environments belong to the "breqn" LaTeX package.
+ * The stared variants "dgroup*" and "dmath*" force unnumbered equations.
+ *
+ * @param[in]  section         The title to print for these formulas.
+ * @param[in]  field           The list of LaTeX formulas.
+ * @param[out] docout          The LaTeX output file to print into.
+ */
+void Lateq::printDGroup(const string& section, list<string>& field, ostream& docout)
+{
+       if (field.size() > 0) {
+               docout << section << endl;
+               tab(1,docout); docout << "\\begin{dgroup*}" << endl;
+               list<string>::const_iterator s;
+               for (s = field.begin(); s != field.end(); ++s) {
+                       tab(2,docout); docout << "\\begin{" << "dmath*" << "}" << endl;
+                       tab(3,docout); docout << "\t" << *s << endl;
+                       tab(2,docout); docout << "\\end{" << "dmath*" << "}" << endl;
+               }
+               tab(1,docout); docout << "\\end{dgroup*}" << endl;
+               docout << endl;
+       }
+}
+
+
+/**
+ * @brief Print formulas for user interface signals.
+ *
+ * @param[in]  section         The title to print for these formulas.
+ * @param[in]  field           This multimap contains pairs :
+ * 1. the path_string is printed as a sub-title item, when new;
+ * 2. each latex_string is printed as a preformated row of the  
+ * supertabular environment (needed to handle long tables).
+ * @param[out] docout          The LaTeX output file to print into.
+ *
+ * @remark
+ * To decide when one should avoid to print an itemize environment, 
+ * a "global" strategy is applied : in the particular case where 
+ * ONLY empty paths were detected in the WHOLE container (all UIs
+ * are at the top level).
+ * In this particular case, UI strings are directly printed, 
+ * and their (empty!) path is ignored...
+ * In the other case, we have to print an itemize environment
+ * and manage paths printing (empty AND non-empty paths) as items.
+ *
+ * @see DocCompiler::prepareIntervallicUI
+ * @see DocCompiler::prepareBinaryUI
+ */
+void Lateq::printHierarchy(const string& section, multimap<string,string>& field, ostream& docout)
+{
+       if (field.size() > 0) {
+               docout << section << endl;
+
+               bool hasSomePaths = hasNotOnlyEmptyKeys(field); ///< Manage itemize printing for pathnames.
+               unsigned int n; ///< Manage latex indentation offset.
+                               
+               if (hasSomePaths) {
+                       tab(0,docout); docout << "\\begin{itemize}" << endl;
+                       n = 1;
+               } else {
+                       n = 0;
+               }
+
+               multimap<string,string>::iterator it;
+               string uidir = "improbable_starting_dirname";
+               bool startFlag = true;
+
+               for (it = field.begin(); it != field.end(); ++it) {
+                       /* Manage supertabular environment bounds and pathname printing. */
+                       if (it->first != uidir) {
+                               if (!startFlag) {
+                                       tab(n+2,docout); docout << "\\end{supertabular}" << endl;
+                                       tab(n+1,docout); docout << "\\end{center}" << endl;
+                               } else { 
+                                       startFlag = false; 
+                               }
+                               if (hasSomePaths) {
+                                       /* Print the current pathname if new and if pathnames requested. */
+                                       if (it->first != "") {
+                                               tab(n+0,docout); docout << "\\item \\textsf{" << it->first << "}" << endl;
+                                       } else { 
+                                               tab(n+0,docout); docout << "\\item \\emph{" << gDocMathStringMap["rootlevel"] << "}" << endl;
+                                       }
+                               }
+                               tab(n+1,docout); docout << "\\begin{center}" << endl;
+                               tab(n+2,docout); docout << "\\begin{supertabular}{lll}" << endl;
+                       }
+                       /* Print the current formula. */
+                       tab(n+3,docout); docout << it->second << endl;
+                       uidir = it->first;
+               }
+               tab(n+2,docout); docout << "\\end{supertabular}" << endl;
+               tab(n+1,docout); docout << "\\end{center}" << endl;
+               if (hasSomePaths) {
+                       tab(n+0,docout); docout << "\\end{itemize}" << endl;
+               }
+               docout << endl;
+       }
+}
+
+
+/**
+ * @brief Print formulas for select2, select3 and prefix signals.
+ *
+ * @param[in]  section         The title to print for these formulas.
+ * @param[in]  field           The list of LaTeX arrays (for braces with two lines).
+ * @param[out] docout          The LaTeX output file to print into.
+ * 
+ * @see DocCompiler::generateSelect2
+ * @see DocCompiler::generateSelect3
+ * @see DocCompiler::generatePrefix
+ */
+void Lateq::printMath(const string& section, list<string>& field, ostream& docout)
+{
+       if (field.size() > 0) {
+               docout << section;
+               docout << "\\begin{displaymath}" << endl;
+               list<string>::iterator s;
+               for (s = field.begin(); s != field.end(); ++s) {
+                       docout << *s << endl;           
+               }
+               docout << "\\end{displaymath}" << endl;
+               docout << endl;         
+       }
+}
+
+
+/** Simple handling of indentation. */
+void Lateq::tab (int n, ostream& docout) const
+{ 
+       while (n--) docout << '\t'; 
+}
+
+
+/**
+ * @brief Find out whether all keys of the multimap are empty or not.
+ * 
+ * In other words :
+ * Check that some UIs have a path (non empty). 
+ *
+ * In other other words :
+ * Check that all UIs are not at top-level.
+ */
+bool Lateq::hasNotOnlyEmptyKeys(multimap<string,string>& mm) 
+{
+       typedef multimap<string,string>::iterator MMIT;
+       pair<MMIT,MMIT> range;
+       range = mm.equal_range("");     ///< Look for pairs with empty keys.
+       bool hasOnlyEmptyPaths = (range.first == mm.begin()) && (range.second == mm.end());
+       return !hasOnlyEmptyPaths;
+}
+
+
+
+/** 
+ * Dispatch initialization of autodoc container.
+ */
+void initDocMath() 
+{
+       initDocMathKeySet();
+}
+
+
+/****************************************************************
+                               Internal static functions.
+ *****************************************************************/
+
+
+/**
+ * Compare indexes of two LaTeX strings, 
+ * for the sort() method applied on list<string> fields.
+ */
+static bool compLateqIndexes(const string& s1, const string& s2)
+{
+       return getLateqIndex(s1) < getLateqIndex(s2);
+}
+
+
+/**
+ * Find out the index of signals in LaTeX signal definition strings,
+ * between the first "_{" and "}" patterns.
+ *
+ * @param[in]  s               A LaTeX string to parse.
+ * @return             <int>   The index found, as an integer.
+ */
+static int getLateqIndex(const string& s)
+{
+       size_t p1;
+       size_t p2;
+       string sIndex;
+               
+       p1 = s.find("_{"); 
+       if (p1==string::npos) {
+               cerr << "Error : getLateqIndex found no \"{_\" substring.\n";
+               exit(1); }
+       p1 += 2;
+       
+       p2 = s.find("}", p1); 
+       if (p2==string::npos) {
+               cerr << "Error : getLateqIndex found no \"}\" substring\n.";
+               exit(1); }
+       p2 -= 3;
+       
+       sIndex = s.substr (p1, p2);
+
+       return atoi(sIndex.c_str());
+}
+
+
+/** 
+ * Initialize gDocMathKeySet, a set containing all the keywords.
+ */
+static void initDocMathKeySet()
+{
+       gDocMathKeySet.insert("inputsigtitle1");
+       gDocMathKeySet.insert("inputsigtitle2");
+       gDocMathKeySet.insert("outputsigtitle1");
+       gDocMathKeySet.insert("outputsigtitle2");
+       gDocMathKeySet.insert("constsigtitle1");
+       gDocMathKeySet.insert("constsigtitle2");
+       gDocMathKeySet.insert("uisigtitle1");
+       gDocMathKeySet.insert("uisigtitle2");
+       gDocMathKeySet.insert("intermedsigtitle1");
+       gDocMathKeySet.insert("intermedsigtitle2");
+       gDocMathKeySet.insert("lateqcomment");
+       gDocMathKeySet.insert("emptyformulafield");
+       gDocMathKeySet.insert("defaultvalue");
+       gDocMathKeySet.insert("suchthat");
+       gDocMathKeySet.insert("and");
+       gDocMathKeySet.insert("for");
+       gDocMathKeySet.insert("rootlevel");
+
+       gDocMathKeySet.insert("dgmcaption");
+}
+
+