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