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