1 /************************************************************************
2  ************************************************************************
3  FAUST compiler
4  Copyright (C) 2003-2018 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 #include <stdio.h>
23 
24 #include <iostream>
25 #include <set>
26 #include <sstream>
27 #include <string>
28 #include <vector>
29 
30 #include "exception.hh"
31 #include "sigToGraph.hh"
32 #include "signals.hh"
33 #include "sigtype.hh"
34 #include "sigtyperules.hh"
35 #include "xtended.hh"
36 
37 using namespace std;
38 
39 static void   recdraw(Tree sig, set<Tree>& drawn, ostream& fout);
40 static string nodeattr(Type t);
41 static string edgeattr(Type t);
42 static string sigLabel(Tree sig);
43 
44 /**
45  * Draw a list of signals as a directed graph using graphviz's dot language
46  */
sigToGraph(Tree L,ostream & fout)47 void sigToGraph(Tree L, ostream& fout)
48 {
49     set<Tree> alreadyDrawn;
50 
51     fout << "strict digraph loopgraph {\n"
52          << "    rankdir=LR; node [fontsize=10];" << endl;
53     int out = 0;
54     while (isList(L)) {
55         recdraw(hd(L), alreadyDrawn, fout);
56 
57         fout << "OUTPUT_" << out << "[color=\"red2\" style=\"filled\" fillcolor=\"pink\"];" << endl;
58         fout << 'S' << hd(L) << " -> "
59              << "OUTPUT_" << out++ << "[" << edgeattr(getCertifiedSigType(hd(L))) << "];" << endl;
60         L = tl(L);
61     }
62 
63     fout << "}" << endl;
64 }
65 
66 /******************************* IMPLEMENTATION ***********************************/
67 
68 /**
69  * Draw recursively a signal
70  */
recdraw(Tree sig,set<Tree> & drawn,ostream & fout)71 static void recdraw(Tree sig, set<Tree>& drawn, ostream& fout)
72 {
73     // cerr << ++gGlobal->TABBER << "ENTER REC DRAW OF " << sig << "$" << *sig << endl;
74     vector<Tree> subsig;
75     int          n;
76 
77     if (drawn.count(sig) == 0) {
78         drawn.insert(sig);
79         if (isList(sig)) {
80             do {
81                 recdraw(hd(sig), drawn, fout);
82                 sig = tl(sig);
83             } while (isList(sig));
84         } else {
85             // draw the node
86             fout << 'S' << sig << "[label=\"" << sigLabel(sig) << "\"" << nodeattr(getCertifiedSigType(sig)) << "];"
87                  << endl;
88 
89             // draw the subsignals
90             n = getSubSignals(sig, subsig);
91             if (n > 0) {
92                 if (n == 1 && isList(subsig[0])) {
93                     Tree id, body;
94                     faustassert(isRec(sig, id, body));
95                     if (!isRec(sig, id, body)) {
96                     }
97                     // special recursion case, recreate a vector of subsignals instead of the
98                     // list provided by getSubSignal
99                     Tree L = subsig[0];
100                     subsig.clear();
101                     n = 0;
102                     do {
103                         subsig.push_back(hd(L));
104                         L = tl(L);
105                         n += 1;
106                     } while (isList(L));
107                 }
108 
109                 for (int i = 0; i < n; i++) {
110                     recdraw(subsig[i], drawn, fout);
111                     fout << 'S' << subsig[i] << " -> " << 'S' << sig << "[" << edgeattr(getCertifiedSigType(subsig[i]))
112                          << "]" << endl;
113                 }
114             }
115         }
116     }
117     // cerr << --gGlobal->TABBER << "EXIT REC DRAW OF " << sig << endl;
118 }
119 
commonAttr(Type t)120 string commonAttr(Type t)
121 {
122     string sout;
123     // nature
124     if (t->nature() == kInt) {
125         sout += " color=\"blue\"";
126     } else {
127         sout += " color=\"red\"";
128     }
129     // vectorability
130     if (t->vectorability() == kVect && t->variability() == kSamp) {
131         sout += " style=\"bold\"";
132     }
133     return sout;
134 }
135 
136 /**
137  * Convert a signal type into edge attributes
138  */
139 
edgeattr(Type t)140 static string edgeattr(Type t)
141 {
142     string sout(commonAttr(t));
143     sout += " label =\"";
144     sout += t->getInterval().toString();
145     sout += ", ";
146     sout += t->getRes().toString();
147     sout += "\"";
148     return sout;
149 }
150 
151 /**
152  * Convert a signal type into node attributes
153  */
nodeattr(Type t)154 static string nodeattr(Type t)
155 {
156     string sout(commonAttr(t));
157 
158     // variability
159     if (t->variability() == kKonst) {
160         sout += " shape=\"box\"";
161     } else if (t->variability() == kBlock) {
162         sout += " shape=\"hexagon\"";
163     } else if (t->variability() == kSamp) {
164         sout += " shape=\"ellipse\"";
165     }
166     return sout;
167 }
168 
169 /**
170  * translate signal binary operations into strings
171  */
172 static const char* binopname[] = {"+", "-", "*", "/", "%", "<<", ">>", ">", "<", ">=", "<=", "==", "!=", "&", "|", "^"};
173 
174 /**
175  * return the label of a signal as a string
176  */
sigLabel(Tree sig)177 static string sigLabel(Tree sig)
178 {
179     int    i;
180     double r;
181     Tree   x, y, z, c, type, name, file, ff, largs, id, le, sel, var, label;
182 
183     xtended* p = (xtended*)getUserData(sig);
184 
185     stringstream fout;
186 
187     if (p) {
188         fout << p->name();
189     } else if (isSigInt(sig, &i)) {
190         fout << i;
191     } else if (isSigReal(sig, &r)) {
192         fout << r;
193     } else if (isSigWaveform(sig)) {
194         fout << "waveform";
195     }
196 
197     else if (isSigInput(sig, &i)) {
198         fout << "INPUT_" << i;
199     }
200     // else if ( isSigOutput(sig, &i, x) )             { fout << "OUTPUT_" << i; }
201 
202     else if (isSigDelay1(sig, x)) {
203         fout << "mem";
204     } else if (isSigDelay(sig, x, y)) {
205         fout << "@";
206     } else if (isSigPrefix(sig, x, y)) {
207         fout << "prefix";
208     } else if (isSigIota(sig, x)) {
209         fout << "iota";
210     } else if (isSigBinOp(sig, &i, x, y)) {
211         fout << binopname[i];
212     } else if (isSigFFun(sig, ff, largs)) {
213         fout << "ffunction:" << *ff;
214     } else if (isSigFConst(sig, type, name, file)) {
215         fout << *name;
216     } else if (isSigFVar(sig, type, name, file)) {
217         fout << *name;
218     }
219 
220     else if (isSigTable(sig, id, x, y)) {
221         fout << "table:" << id;
222     } else if (isSigWRTbl(sig, id, x, y, z)) {
223         fout << "write:" << id;
224     } else if (isSigRDTbl(sig, x, y)) {
225         fout << "read";
226     }
227 
228     else if (isSigSelect2(sig, sel, x, y)) {
229         fout << "select2";
230     }
231 
232     else if (isSigGen(sig, x)) {
233         fout << "generator";
234     }
235 
236     else if (isProj(sig, &i, x)) {
237         fout << "Proj" << i;
238     } else if (isRec(sig, var, le)) {
239         fout << "REC " << *var;
240     }
241 
242     else if (isSigIntCast(sig, x)) {
243         fout << "int";
244     } else if (isSigFloatCast(sig, x)) {
245         fout << "float";
246     }
247 #if 0
248     else if ( isSigButton(sig, label) ) 			{ fout << "button \"" << *label << '"'; }
249     else if ( isSigCheckbox(sig, label) ) 			{ fout << "checkbox \"" << *label << '"'; }
250     else if ( isSigVSlider(sig, label,c,x,y,z) )	{ fout << "vslider \"" << *label << '"';  }
251     else if ( isSigHSlider(sig, label,c,x,y,z) )	{ fout << "hslider \"" << *label << '"';  }
252     else if ( isSigNumEntry(sig, label,c,x,y,z) )	{ fout << "nentry \"" << *label << '"';  }
253 
254     else if ( isSigVBargraph(sig, label,x,y,z) )	{ fout << "vbargraph \"" << *label << '"'; 	}
255     else if ( isSigHBargraph(sig, label,x,y,z) )	{ fout << "hbargraph \"" << *label << '"'; 	}
256 #else
257     else if (isSigButton(sig, label)) {
258         fout << "button";
259     } else if (isSigCheckbox(sig, label)) {
260         fout << "checkbox";
261     } else if (isSigVSlider(sig, label, c, x, y, z)) {
262         fout << "vslider";
263     } else if (isSigHSlider(sig, label, c, x, y, z)) {
264         fout << "hslider";
265     } else if (isSigNumEntry(sig, label, c, x, y, z)) {
266         fout << "nentry";
267     }
268 
269     else if (isSigVBargraph(sig, label, x, y, z)) {
270         fout << "vbargraph";
271     } else if (isSigHBargraph(sig, label, x, y, z)) {
272         fout << "hbargraph";
273     }
274 #endif
275     else if (isSigAttach(sig, x, y)) {
276         fout << "attach";
277     }
278 
279     else if (isSigAssertBounds(sig, x, y, z)){
280         fout << "assertbounds";
281     }
282 
283     else if (isSigLowest(sig, x)){
284         fout << "lowest";
285     }
286 
287     else if (isSigHighest(sig, x)){
288         fout << "highest";
289     }
290 
291     else {
292         stringstream error;
293         error << "ERROR : sigToGraph.cpp, unrecognized signal : " << *sig << endl;
294         throw faustexception(error.str());
295     }
296 
297     return fout.str();
298 }
299