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 "ppbox.hh"
23 #include "Text.hh"
24 #include "boxes.hh"
25 #include "exception.hh"
26 #include "global.hh"
27 #include "list.hh"
28 #include "prim2.hh"
29 #include "signals.hh"
30 #include "xtended.hh"
31 
prim0name(CTree * (* ptr)())32 const char* prim0name(CTree *(*ptr)())
33 {
34     return "prim0???";
35 }
36 
prim1name(CTree * (* ptr)(CTree *))37 const char* prim1name(CTree *(*ptr)(CTree *))
38 {
39     if (ptr == sigDelay1) return "mem";
40     if (ptr == sigIntCast) return "int";
41     if (ptr == sigFloatCast) return "float";
42     if (ptr == sigLowest) return "lowest";
43     if (ptr == sigHighest) return "highest";
44     return "prim1???";
45 }
46 
prim2name(CTree * (* ptr)(CTree *,CTree *))47 const char* prim2name(CTree *(*ptr)(CTree *, CTree *))
48 {
49     if (ptr == sigAdd) return "+";
50     if (ptr == sigSub) return "-";
51     if (ptr == sigMul) return "*";
52     if (ptr == sigDiv) return "/";
53     if (ptr == sigRem) return "%";
54 
55     if (ptr == sigAND) return "&";
56     if (ptr == sigOR) return "|";
57     if (ptr == sigXOR) return "xor";
58 
59     if (ptr == sigLeftShift) return "<<";
60     if (ptr == sigLRightShift) return ">>";
61     if (ptr == sigARightShift) return ">>>";
62 
63     if (ptr == sigLT) return "<";
64     if (ptr == sigLE) return "<=";
65     if (ptr == sigGT) return ">";
66     if (ptr == sigGE) return ">=";
67     if (ptr == sigEQ) return "==";
68     if (ptr == sigNE) return "!=";
69 
70     if (ptr == sigDelay) return "@";
71     if (ptr == sigPrefix) return "prefix";
72     if (ptr == sigAttach) return "attach";
73     if (ptr == sigEnable) return "enable";
74     if (ptr == sigControl) return "control";
75 
76     return "prim2???";
77 }
78 
prim3name(CTree * (* ptr)(CTree *,CTree *,CTree *))79 const char* prim3name(CTree *(*ptr)(CTree *, CTree *, CTree *))
80 {
81     if (ptr == sigReadOnlyTable) return "rdtable";
82     if (ptr == sigSelect2) return "select2";
83     if (ptr == sigAssertBounds) return "assertbounds";
84     return "prim3???";
85 }
86 
prim4name(CTree * (* ptr)(CTree *,CTree *,CTree *,CTree *))87 const char* prim4name(CTree *(*ptr)(CTree *, CTree *, CTree *, CTree *))
88 {
89     if (ptr == sigSelect3) return "select3";
90     return "prim4???";
91 }
92 
prim5name(CTree * (* ptr)(CTree *,CTree *,CTree *,CTree *,CTree *))93 const char* prim5name(CTree *(*ptr)(CTree *, CTree *, CTree *, CTree *, CTree *))
94 {
95     if (ptr == sigWriteReadTable) return "rwtable";
96     return "prim5???";
97 }
98 
streambinop(ostream & fout,Tree t1,const char * op,Tree t2,int curPriority,int upPriority)99 static void streambinop(ostream &fout, Tree t1, const char *op, Tree t2, int curPriority, int upPriority)
100 {
101     if (upPriority > curPriority) fout << '(';
102     fout << boxpp(t1, curPriority) << op << boxpp(t2, curPriority);
103     if (upPriority > curPriority) fout << ')';
104 }
105 
printRule(ostream & fout,Tree rule)106 static void printRule(ostream &fout, Tree rule)
107 {
108     Tree lhs = left(rule);
109     Tree rhs = right(rule);
110     char sep = '(';
111     while (!isNil(lhs)) {
112         fout << sep << boxpp(hd(lhs));
113         sep = ',';
114         lhs = tl(lhs);
115     }
116     fout << ") => " << boxpp(rhs) << "; ";
117 }
118 
119 /*****************************************************************************
120      Convert type as a string
121 *****************************************************************************/
122 
type2str(int type)123 static string type2str(int type)
124 {
125     switch (type) {
126         case 0:
127             return "int";
128 
129         case 1:
130             return "float";
131 
132         default:
133             return "";
134     }
135 }
136 
137 // If t has a node of type symbol, return its name, otherwise error
print(ostream & fout) const138 ostream& boxpp::print(ostream &fout) const
139 {
140     int    i, id;
141     double r;
142     prim0  p0;
143     prim1  p1;
144     prim2  p2;
145     prim3  p3;
146     prim4  p4;
147     prim5  p5;
148 
149     Tree t1, t2, t3, ff, label, cur, min, max, step, type, name, file, arg, body, fun, args, abstr, genv, vis, lenv,
150         ldef, slot, ident, rules, chan, ins, outs, lroutes;
151 
152     const char* str;
153 
154     xtended* xt = (xtended*)getUserData(box);
155 
156     // Primitive elements
157     if (xt)
158         fout << xt->name();
159     else if (isBoxInt(box, &i))
160         fout << i;
161     else if (isBoxReal(box, &r))
162         fout << T(r);
163     else if (isBoxCut(box))
164         fout << '!';
165     else if (isBoxWire(box))
166         fout << '_';
167     else if (isBoxIdent(box, &str))
168         fout << str;
169     else if (isBoxPrim0(box, &p0))
170         fout << prim0name(p0);
171     else if (isBoxPrim1(box, &p1))
172         fout << prim1name(p1);
173     else if (isBoxPrim2(box, &p2))
174         fout << prim2name(p2);
175     else if (isBoxPrim3(box, &p3))
176         fout << prim3name(p3);
177     else if (isBoxPrim4(box, &p4))
178         fout << prim4name(p4);
179     else if (isBoxPrim5(box, &p5))
180         fout << prim5name(p5);
181 
182     else if (isBoxAbstr(box, arg, body))
183         fout << "\\" << boxpp(arg) << ".(" << boxpp(body) << ")";
184     else if (isBoxAppl(box, fun, args))
185         fout << boxpp(fun) << boxpp(args);
186 
187     else if (isBoxWithLocalDef(box, body, ldef))
188         fout << boxpp(body) << " with { " << envpp(ldef) << " }";
189 
190     // Foreign elements
191     else if (isBoxFFun(box, ff)) {
192         fout << "ffunction(" << type2str(ffrestype(ff));
193         Tree namelist = nth(ffsignature(ff), 1);
194         char sep      = ' ';
195         for (int i1 = 0; i1 < gGlobal->gFloatSize; i1++) {
196             fout << sep << tree2str(nth(namelist, i1));
197             sep = '|';
198         }
199         sep = '(';
200         for (int i1 = 0; i1 < ffarity(ff); i1++) {
201             fout << sep << type2str(ffargtype(ff, i1));
202             sep = ',';
203         }
204         fout << ')';
205         fout << ',' << ffincfile(ff) << ',' << fflibfile(ff) << ')';
206     } else if (isBoxFConst(box, type, name, file))
207         fout << "fconstant(" << type2str(tree2int(type)) << ' ' << tree2str(name) << ", " << tree2str(file) << ')';
208     else if (isBoxFVar(box, type, name, file))
209         fout << "fvariable(" << type2str(tree2int(type)) << ' ' << tree2str(name) << ", " << tree2str(file) << ')';
210 
211     // Block diagram binary operator
212     else if (isBoxSeq(box, t1, t2))
213         streambinop(fout, t1, " : ", t2, 1, priority);
214     else if (isBoxSplit(box, t1, t2))
215         streambinop(fout, t1, "<:", t2, 1, priority);
216     else if (isBoxMerge(box, t1, t2))
217         streambinop(fout, t1, ":>", t2, 1, priority);
218     else if (isBoxPar(box, t1, t2))
219         streambinop(fout, t1, ",", t2, 2, priority);
220     else if (isBoxRec(box, t1, t2))
221         streambinop(fout, t1, "~", t2, 4, priority);
222 
223     // Iterative block diagram construction
224     else if (isBoxIPar(box, t1, t2, t3))
225         fout << "par(" << boxpp(t1) << ", " << boxpp(t2) << ") {" << boxpp(t3) << "}";
226     else if (isBoxISeq(box, t1, t2, t3))
227         fout << "seq(" << boxpp(t1) << ", " << boxpp(t2) << ") {" << boxpp(t3) << "}";
228     else if (isBoxISum(box, t1, t2, t3))
229         fout << "sum(" << boxpp(t1) << ", " << boxpp(t2) << ") {" << boxpp(t3) << "}";
230     else if (isBoxIProd(box, t1, t2, t3))
231         fout << "prod(" << boxpp(t1) << ", " << boxpp(t2) << ") {" << boxpp(t3) << "}";
232 
233     else if (isBoxInputs(box, t1))
234         fout << "inputs(" << boxpp(t1) << ")";
235     else if (isBoxOutputs(box, t1))
236         fout << "outputs(" << boxpp(t1) << ")";
237 
238     // User interface
239     else if (isBoxButton(box, label))
240         fout << "button(" << tree2quotedstr(label) << ')';
241     else if (isBoxCheckbox(box, label))
242         fout << "checkbox(" << tree2quotedstr(label) << ')';
243     else if (isBoxVSlider(box, label, cur, min, max, step)) {
244         fout << "vslider(" << tree2quotedstr(label) << ", " << boxpp(cur) << ", " << boxpp(min) << ", " << boxpp(max)
245              << ", " << boxpp(step) << ')';
246     } else if (isBoxHSlider(box, label, cur, min, max, step)) {
247         fout << "hslider(" << tree2quotedstr(label) << ", " << boxpp(cur) << ", " << boxpp(min) << ", " << boxpp(max)
248              << ", " << boxpp(step) << ')';
249     } else if (isBoxVGroup(box, label, t1)) {
250         fout << "vgroup(" << tree2quotedstr(label) << ", " << boxpp(t1, 0) << ')';
251     } else if (isBoxHGroup(box, label, t1)) {
252         fout << "hgroup(" << tree2quotedstr(label) << ", " << boxpp(t1, 0) << ')';
253     } else if (isBoxTGroup(box, label, t1)) {
254         fout << "tgroup(" << tree2quotedstr(label) << ", " << boxpp(t1, 0) << ')';
255     } else if (isBoxHBargraph(box, label, min, max)) {
256         fout << "hbargraph(" << tree2quotedstr(label) << ", " << boxpp(min) << ", " << boxpp(max) << ')';
257     } else if (isBoxMetadata(box, t1, t2)) {
258         fout << boxpp(t1, 0) << "/* md */";
259     } else if (isBoxVBargraph(box, label, min, max)) {
260         fout << "vbargraph(" << tree2quotedstr(label) << ", " << boxpp(min) << ", " << boxpp(max) << ')';
261     } else if (isBoxNumEntry(box, label, cur, min, max, step)) {
262         fout << "nentry(" << tree2quotedstr(label) << ", " << boxpp(cur) << ", " << boxpp(min) << ", " << boxpp(max)
263              << ", " << boxpp(step) << ')';
264     } else if (isBoxSoundfile(box, label, chan)) {
265         fout << "soundfile(" << tree2quotedstr(label) << ", " << boxpp(chan) << ')';
266     }
267 
268     else if (isNil(box)) {
269         fout << "()";
270     } else if (isList(box)) {
271         Tree l   = box;
272         char sep = '(';
273 
274         do {
275             fout << sep << boxpp(hd(l));
276             sep = ',';
277             l   = tl(l);
278         } while (isList(l));
279 
280         fout << ')';
281 
282     } else if (isBoxWaveform(box)) {
283         fout << "waveform";
284         char sep = '{';
285         for (int i1 = 0; i1 < box->arity(); i1++) {
286             fout << sep << boxpp(box->branch(i1));
287             sep = ',';
288         }
289         fout << '}';
290         /*
291         size_t n = box->arity();
292         if (n < 6) {
293             // small waveform, print all data
294             fout << "waveform";
295             char sep = '{';
296             for (size_t i=0; i<n; i++) {
297                 fout << sep << boxpp(box->branch(i));
298                 sep = ',';
299             }
300             fout << '}';
301         } else {
302             // large waveform print only first and last values
303             fout << "waveform{" << box->branch(0) << ", ..<" << n-2 << ">..," << box->branch(n-1) << "}";
304         }
305         */
306 
307     } else if (isBoxEnvironment(box)) {
308         fout << "environment";
309 
310     } else if (isClosure(box, abstr, genv, vis, lenv)) {
311         fout << "closure[" << boxpp(abstr) << ", genv = " << envpp(genv) << ", lenv = " << envpp(lenv) << "]";
312     } else if (isBoxComponent(box, label)) {
313         fout << "component(" << tree2quotedstr(label) << ')';
314     } else if (isBoxAccess(box, t1, t2)) {
315         fout << boxpp(t1) << '.' << boxpp(t2);
316     } else if (isImportFile(box, label)) {
317         fout << "import(" << tree2quotedstr(label) << ')';
318     } else if (isBoxSlot(box, &id)) {
319         // fout << "#" << id;
320         fout << "x" << id;
321     } else if (isBoxSymbolic(box, slot, body)) {
322         fout << "\\(" << boxpp(slot) << ").(" << boxpp(body) << ")";
323     }
324 
325     // pattern Matching Extensions
326     else if (isBoxCase(box, rules)) {
327         fout << "case {";
328         while (!isNil(rules)) {
329             printRule(fout, hd(rules));
330             rules = tl(rules);
331         }
332         fout << "}";
333     }
334 #if 1
335     // More useful for debugging output
336     else if (isBoxPatternVar(box, ident)) {
337         fout << "<" << boxpp(ident) << ">";
338     }
339 #else
340     // Beautify messages involving lhs patterns
341     else if (isBoxPatternVar(box, ident)) {
342         fout << boxpp(ident);
343     }
344 #endif
345 
346     else if (isBoxPatternMatcher(box)) {
347         fout << "PM[" << box << "]";
348     }
349 
350     else if (isBoxRoute(box, ins, outs, lroutes)) {
351         fout << "route(" << boxpp(ins) << "," << boxpp(outs) << "," << boxpp(lroutes) << ")";
352     }
353 
354     else if (isBoxError(box)) {
355         fout << "ERROR";
356     }
357 
358     // else if (isImportFile(box, filename)) {
359     //    printf("filename %s\n", tree2str(filename));
360     //    fout << tree2quotedstr(filename);
361     //}
362 
363     // None of the previous tests succeded, then it is not a valid box
364     else {
365         stringstream error;
366         error << "ERROR in box::print() : " << *box << " is not a valid box" << endl;
367         throw faustexception(error.str());
368     }
369 
370     return fout;
371 }
372 
373 /*****************************************************************************
374      Environment printing
375 *****************************************************************************/
376 
print(ostream & fout) const377 ostream& envpp::print(ostream& fout) const
378 {
379     const char* sep = "";
380     Tree        l   = fEnv;
381 
382     fout << '{';
383     while (isList(l)) {
384         fout << sep << boxpp(hd(hd(l))) << "=" << boxpp(tl(hd(l)));
385         sep = ", ";
386         l   = tl(l);
387     }
388     fout << '}';
389     return fout;
390 }
391