.gitignore should now be working.
[Faustine.git] / interpretor / faust-0.9.47mr3 / compiler / generator / compile.cpp
1 /************************************************************************
2 ************************************************************************
3 FAUST compiler
4 Copyright (C) 2003-2004 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
23
24 /*****************************************************************************
25 ******************************************************************************
26 FAUST SIGNAL COMPILER
27 Y. Orlarey, (c) Grame 2002
28 ------------------------------------------------------------------------------
29 Compile a list of FAUST signals into a C++ class .
30
31 History :
32 ---------
33 2002-02-08 : First version
34
35 ******************************************************************************
36 *****************************************************************************/
37
38
39
40 #include "timing.hh"
41 #include "compile.hh"
42 #include "floats.hh"
43 #include "sigtype.hh"
44
45 #include <stdio.h>
46 //#include <iostream>
47
48 #include "sigprint.hh"
49 #include "ppsig.hh"
50
51 #include "sigtyperules.hh"
52 #include "simplify.hh"
53 #include "privatise.hh"
54 //#include "factorize.hh"
55
56 //#include "grouper.hh"
57 //#include "sigvisitor.hh"
58
59
60
61
62 /*****************************************************************************
63 ******************************************************************************
64
65 API
66
67 ******************************************************************************
68 *****************************************************************************/
69
70 extern int gDetailsSwitch;
71 extern string gMasterName;
72
73
74
75
76 /*****************************************************************************
77 ******************************************************************************
78
79 GENERAL COMPILER METHODS
80
81 ******************************************************************************
82 *****************************************************************************/
83
84
85
86
87
88
89
90 /*****************************************************************************
91 constructor
92 *****************************************************************************/
93
94 Compiler::Compiler(const string& name, const string& super, int numInputs, int numOutputs, bool vec)
95 : fClass(new Klass(name, super, numInputs, numOutputs, vec)),
96 fNeedToDeleteClass(true),
97 fUIRoot(uiFolder(cons(tree(0), tree(subst("$0", gMasterName))))),
98 fDescription(0)
99 {}
100
101 Compiler::Compiler(Klass* k)
102 : fClass(k),
103 fNeedToDeleteClass(false),
104 fUIRoot(uiFolder(cons(tree(0), tree(subst("$0", gMasterName))))),
105 fDescription(0)
106 {}
107
108
109 Compiler::~Compiler()
110 {
111 if (fNeedToDeleteClass) delete fClass;
112 }
113
114
115
116 /*****************************************************************************
117 user interface elements
118 *****************************************************************************/
119
120 /**
121 * Add a widget with a certain path to the user interface tree
122 */
123 void Compiler::addUIWidget(Tree path, Tree widget)
124 {
125 fUIRoot = putSubFolder(fUIRoot, path, widget);
126 }
127
128
129 /**
130 * Remove fake root folder if not needed (that is if the UI
131 * is completely enclosed in one folder
132 */
133 Tree Compiler::prepareUserInterfaceTree(Tree t)
134 {
135 Tree root, elems;
136 if (isUiFolder(t, root, elems) && isList(elems) && isNil(tl(elems)) ) {
137 Tree folder = right(hd(elems));
138 return (isUiFolder(folder)) ? folder : t;
139 }
140 return t;
141 }
142
143 //================================= some string processing utilities =================================
144
145 /**
146 * Removes enclosing whitespaces : ' toto ' -> 'toto'
147 */
148 static string wdel(const string& s)
149 {
150 size_t i = 0;
151 size_t j = s.size();
152 while (i<j && s[i]==' ') i++;
153 while (j>i && s[j-1] == ' ') j--;
154 return s.substr(i,j-i);
155 }
156
157
158 //================================= BUILD USER INTERFACE METHOD =================================
159
160 /**
161 * Generate buildUserInterface C++ lines of code corresponding
162 * to user interface element t
163 */
164 void Compiler::generateUserInterfaceTree(Tree t)
165 {
166 Tree label, elements, varname, sig;
167
168 if (isUiFolder(t, label, elements)) {
169 const int orient = tree2int(left(label));
170 const char * str = tree2str(right(label));
171 const char * model;
172
173 // extract metadata from group label str resulting in a simplifiedLabel
174 // and metadata declarations for fictive zone at address 0
175 string simplifiedLabel;
176 map<string, set<string> > metadata;
177 extractMetadata(str, simplifiedLabel, metadata);
178
179 // add metadata if any
180 for (map<string, set<string> >::iterator i = metadata.begin(); i != metadata.end(); i++) {
181 const string& key = i->first;
182 const set<string>& values = i->second;
183 for (set<string>::const_iterator j = values.begin(); j != values.end(); j++) {
184 fClass->addUICode(subst("interface->declare($0, \"$1\", \"$2\");", "0", wdel(key) ,wdel(*j)));
185 }
186 }
187 //-----------------
188
189
190 switch (orient) {
191 case 0 : model = "interface->openVerticalBox(\"$0\");"; break;
192 case 1 : model = "interface->openHorizontalBox(\"$0\");"; break;
193 case 2 : model = "interface->openTabBox(\"$0\");"; break;
194 default :
195 fprintf(stderr, "error in user interface generation 1\n");
196 exit(1);
197 }
198 fClass->addUICode(subst(model, simplifiedLabel));
199 generateUserInterfaceElements(elements);
200 fClass->addUICode("interface->closeBox();");
201
202 } else if (isUiWidget(t, label, varname, sig)) {
203
204 generateWidgetCode(label, varname, sig);
205
206 } else {
207
208 fprintf(stderr, "error in user interface generation 2\n");
209 exit(1);
210
211 }
212 }
213
214 /**
215 * Iterate generateUserInterfaceTree on a list of user interface elements
216 */
217 void Compiler::generateUserInterfaceElements(Tree elements)
218 {
219 while (!isNil(elements)) {
220 generateUserInterfaceTree(right(hd(elements)));
221 elements = tl(elements);
222 }
223 }
224
225 /**
226 * Generate buildUserInterface C++ lines of code corresponding
227 * to user interface widget t
228 */
229 void Compiler::generateWidgetCode(Tree fulllabel, Tree varname, Tree sig)
230 {
231 Tree path, c, x, y, z;
232 string label;
233 map<string, set<string> > metadata;
234
235 extractMetadata(tree2str(fulllabel), label, metadata);
236
237 // add metadata if any
238 for (map<string, set<string> >::iterator i = metadata.begin(); i != metadata.end(); i++) {
239 const string& key = i->first;
240 const set<string>& values = i->second;
241 for (set<string>::const_iterator j = values.begin(); j != values.end(); j++) {
242 fClass->addUICode(subst("interface->declare(&$0, \"$1\", \"$2\");", tree2str(varname), wdel(key) ,wdel(*j)));
243 }
244 }
245
246 if ( isSigButton(sig, path) ) {
247 fClass->incUIActiveCount();
248 fClass->addUICode(subst("interface->addButton(\"$0\", &$1);", label, tree2str(varname)));
249
250 } else if ( isSigCheckbox(sig, path) ) {
251 fClass->incUIActiveCount();
252 fClass->addUICode(subst("interface->addCheckButton(\"$0\", &$1);", label, tree2str(varname)));
253
254 } else if ( isSigVSlider(sig, path,c,x,y,z) ) {
255 fClass->incUIActiveCount();
256 fClass->addUICode(subst("interface->addVerticalSlider(\"$0\", &$1, $2, $3, $4, $5);",
257 label,
258 tree2str(varname),
259 T(tree2float(c)),
260 T(tree2float(x)),
261 T(tree2float(y)),
262 T(tree2float(z))));
263
264 } else if ( isSigHSlider(sig, path,c,x,y,z) ) {
265 fClass->incUIActiveCount();
266 fClass->addUICode(subst("interface->addHorizontalSlider(\"$0\", &$1, $2, $3, $4, $5);",
267 label,
268 tree2str(varname),
269 T(tree2float(c)),
270 T(tree2float(x)),
271 T(tree2float(y)),
272 T(tree2float(z))));
273
274 } else if ( isSigNumEntry(sig, path,c,x,y,z) ) {
275 fClass->incUIActiveCount();
276 fClass->addUICode(subst("interface->addNumEntry(\"$0\", &$1, $2, $3, $4, $5);",
277 label,
278 tree2str(varname),
279 T(tree2float(c)),
280 T(tree2float(x)),
281 T(tree2float(y)),
282 T(tree2float(z))));
283
284 } else if ( isSigVBargraph(sig, path,x,y,z) ) {
285 fClass->incUIPassiveCount();
286 fClass->addUICode(subst("interface->addVerticalBargraph(\"$0\", &$1, $2, $3);",
287 label,
288 tree2str(varname),
289 T(tree2float(x)),
290 T(tree2float(y))));
291
292 } else if ( isSigHBargraph(sig, path,x,y,z) ) {
293 fClass->incUIPassiveCount();
294 fClass->addUICode(subst("interface->addHorizontalBargraph(\"$0\", &$1, $2, $3);",
295 label,
296 tree2str(varname),
297 T(tree2float(x)),
298 T(tree2float(y))));
299
300 } else {
301 fprintf(stderr, "Error in generating widget code\n");
302 exit(1);
303 }
304 }
305
306 //==================================== USER INTERFACE MACROS ==================================
307
308 /**
309 * Generate user interface macros corresponding
310 * to user interface element t
311 */
312 void Compiler::generateMacroInterfaceTree(const string& pathname, Tree t)
313 {
314 Tree label, elements, varname, sig;
315
316 if (isUiFolder(t, label, elements)) {
317 string pathname2 = pathname;
318 //string str = unquote(tree2str(right(label)));
319 string str = tree2str(right(label));
320 if (str.length()>0) pathname2 += str + "/";
321 generateMacroInterfaceElements(pathname2, elements);
322
323 } else if (isUiWidget(t, label, varname, sig)) {
324
325 generateWidgetMacro(pathname, label, varname, sig);
326
327 } else {
328
329 fprintf(stderr, "error in user interface macro generation 2\n");
330 exit(1);
331
332 }
333 }
334
335
336 /**
337 * Iterate generateMacroInterfaceTree on a list of user interface elements
338 */
339 void Compiler::generateMacroInterfaceElements(const string& pathname, Tree elements)
340 {
341 while (!isNil(elements)) {
342 generateMacroInterfaceTree(pathname, right(hd(elements)));
343 elements = tl(elements);
344 }
345 }
346
347
348 /**
349 * Generate user interface macros corresponding
350 * to a user interface widget
351 */
352 void Compiler::generateWidgetMacro(const string& pathname, Tree fulllabel, Tree varname, Tree sig)
353 {
354 Tree path, c, x, y, z;
355 string label;
356 map<string, set<string> > metadata;
357
358 extractMetadata(tree2str(fulllabel), label, metadata);
359
360 //string pathlabel = pathname+unquote(label);
361 string pathlabel = pathname+label;
362
363
364 if ( isSigButton(sig, path) ) {
365 fClass->addUIMacro(subst("FAUST_ADDBUTTON(\"$0\", $1);", pathlabel, tree2str(varname)));
366
367 } else if ( isSigCheckbox(sig, path) ) {
368 fClass->addUIMacro(subst("FAUST_ADDCHECKBOX(\"$0\", $1);", pathlabel, tree2str(varname)));
369
370 } else if ( isSigVSlider(sig, path,c,x,y,z) ) {
371 fClass->addUIMacro(subst("FAUST_ADDVERTICALSLIDER(\"$0\", $1, $2, $3, $4, $5);",
372 pathlabel,
373 tree2str(varname),
374 T(tree2float(c)),
375 T(tree2float(x)),
376 T(tree2float(y)),
377 T(tree2float(z))));
378
379 } else if ( isSigHSlider(sig, path,c,x,y,z) ) {
380 fClass->addUIMacro(subst("FAUST_ADDHORIZONTALSLIDER(\"$0\", $1, $2, $3, $4, $5);",
381 pathlabel,
382 tree2str(varname),
383 T(tree2float(c)),
384 T(tree2float(x)),
385 T(tree2float(y)),
386 T(tree2float(z))));
387
388 } else if ( isSigNumEntry(sig, path,c,x,y,z) ) {
389 fClass->addUIMacro(subst("FAUST_ADDNUMENTRY(\"$0\", $1, $2, $3, $4, $5);",
390 pathlabel,
391 tree2str(varname),
392 T(tree2float(c)),
393 T(tree2float(x)),
394 T(tree2float(y)),
395 T(tree2float(z))));
396
397 } else if ( isSigVBargraph(sig, path,x,y,z) ) {
398 fClass->addUIMacro(subst("FAUST_ADDVERTICALBARGRAPH(\"$0\", $1, $2, $3);",
399 pathlabel,
400 tree2str(varname),
401 T(tree2float(x)),
402 T(tree2float(y))));
403
404 } else if ( isSigHBargraph(sig, path,x,y,z) ) {
405 fClass->addUIMacro(subst("FAUST_ADDHORIZONTALBARGRAPH(\"$0\", $1, $2, $3);",
406 pathlabel,
407 tree2str(varname),
408 T(tree2float(x)),
409 T(tree2float(y))));
410
411 } else {
412 fprintf(stderr, "Error in generating widget code\n");
413 exit(1);
414 }
415 }