1 /************************************************************************
2  ************************************************************************
3     FAUST compiler
4     Copyright (C) 2003-2019 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 #ifndef _SOUL_INSTRUCTIONS_H
23 #define _SOUL_INSTRUCTIONS_H
24 
25 #include <sstream>
26 #include <string>
27 #include <vector>
28 #include <utility>
29 #include <cctype>
30 
31 #include "text_instructions.hh"
32 #include "faust/gui/PathBuilder.h"
33 
34 using namespace std;
35 
36 struct SOULInstUIVisitor : public DispatchVisitor, public PathBuilder {
37     std::stringstream     fOut;
38     SOULStringTypeManager fTypeManager;
39     int                   fTab;
40     bool                  fHasBargraph;  // Whether the DSP code has some Bargraphs
41 
42     std::vector<std::pair <std::string, std::string> > fMetaAux;
43 
44     using DispatchVisitor::visit;
45 
SOULInstUIVisitorSOULInstUIVisitor46     SOULInstUIVisitor(int tab = 1) : fTypeManager(xfloat(), "*"), fTab(tab), fHasBargraph(false) {}
47 
addMetaSOULInstUIVisitor48     void addMeta()
49     {
50         if (fMetaAux.size() > 0) {
51             for (size_t i = 0; i < fMetaAux.size(); i++) {
52                 if (!std::isdigit(fMetaAux[i].first[0])) {
53                     fOut << ", " << "meta_" + gGlobal->getFreshID(fMetaAux[i].first) << ": " << quote(fMetaAux[i].second);
54                 }
55             }
56         }
57         fMetaAux.clear();
58     }
59 
getSoulMatadataSOULInstUIVisitor60     std::string getSoulMatadata()
61     {
62         if (fMetaAux.size() > 0) {
63             for (size_t i = 0; i < fMetaAux.size(); i++) {
64                 if (fMetaAux[i].first == "soul") return fMetaAux[i].second;
65             }
66         }
67         return "";
68     }
69 
visitSOULInstUIVisitor70     virtual void visit(AddMetaDeclareInst* inst)
71     {
72         fMetaAux.push_back(std::make_pair(inst->fKey, inst->fValue));
73     }
74 
visitSOULInstUIVisitor75     virtual void visit(AddButtonInst* inst)
76     {
77         if (gGlobal->gOutputLang == "soul-poly") {
78             vector<char> rep = {' ', '(', ')', '/', '\\', '.', '-'};
79             fOut << "input event " << fTypeManager.fTypeDirectTable[itfloat()]
80             << " event_" << replaceCharList(inst->fLabel, rep, '_')
81             << " [[ name: " << quote(inst->fLabel)
82             << ", group: " << quote(buildPath(inst->fLabel));
83             if (inst->fType != AddButtonInst::kDefaultButton) {
84                 fOut << ", latching";
85             }
86             fOut<< ", text: \"off|on\""
87             << ", boolean";
88             addMeta();
89             fOut << " ]];";
90         } else if (gGlobal->gOutputLang == "soul-hybrid") {
91             string soul_meta = getSoulMatadata();
92             vector<char> rep = {' ', '(', ')', '/', '\\', '.', '-'};
93             fOut << "input event " << fTypeManager.fTypeDirectTable[itfloat()]
94             << " " << ((soul_meta != "") ? soul_meta : replaceCharList(inst->fLabel, rep, '_'))
95             << " [[ name: " << quote(inst->fLabel)
96             << ", group: " << quote(buildPath(inst->fLabel));
97             if (inst->fType != AddButtonInst::kDefaultButton) {
98                 fOut << ", latching";
99             }
100             fOut << ", text: \"off|on\""
101             << ", boolean";
102             addMeta();
103             fOut << " ]];";
104         } else {
105             fOut << "input event " << fTypeManager.fTypeDirectTable[itfloat()]
106             << " event" << inst->fZone
107             << " [[ name: " << quote(inst->fLabel)
108             << ", group: " << quote(buildPath(inst->fLabel));
109             if (inst->fType != AddButtonInst::kDefaultButton) {
110                 fOut << ", latching";
111             }
112             fOut << ", text: \"off|on\""
113             << ", boolean";
114             addMeta();
115             fOut << " ]];";
116         }
117         tab(fTab, fOut);
118     }
119 
visitSOULInstUIVisitor120     virtual void visit(AddSliderInst* inst)
121     {
122         if (gGlobal->gOutputLang == "soul-poly") {
123             vector<char> rep = {' ', '(', ')', '/', '\\', '.', '-'};
124             fOut << "input event " << fTypeManager.fTypeDirectTable[itfloat()]
125             << " event_" << replaceCharList(inst->fLabel, rep, '_')
126             << " [[ name: " << quote(inst->fLabel)
127             << ", group: " << quote(buildPath(inst->fLabel))
128             << ", min: " << checkReal(inst->fMin)
129             << ", max: " << checkReal(inst->fMax)
130             << ", init: " << checkReal(inst->fInit)
131             << ", step: " << checkReal(inst->fStep);
132             addMeta();
133             fOut << " ]];";
134         } else if (gGlobal->gOutputLang == "soul-hybrid") {
135             string soul_meta = getSoulMatadata();
136             vector<char> rep = {' ', '(', ')', '/', '\\', '.'};
137             fOut << "input event " << fTypeManager.fTypeDirectTable[itfloat()]
138             << " " << ((soul_meta != "") ? soul_meta : replaceCharList(inst->fLabel, rep, '_'))
139             << " [[ name: " << quote(inst->fLabel)
140             << ", group: " << quote(buildPath(inst->fLabel))
141             << ", min: " << checkReal(inst->fMin)
142             << ", max: " << checkReal(inst->fMax)
143             << ", init: " << checkReal(inst->fInit)
144             << ", step: " << checkReal(inst->fStep);
145             addMeta();
146             fOut << " ]];";
147         } else {
148             fOut << "input event " << fTypeManager.fTypeDirectTable[itfloat()]
149             << " event" << inst->fZone
150             << " [[ name: " << quote(inst->fLabel)
151             << ", group: " << quote(buildPath(inst->fLabel))
152             << ", min: " << checkReal(inst->fMin)
153             << ", max: " << checkReal(inst->fMax)
154             << ", init: " << checkReal(inst->fInit)
155             << ", step: " << checkReal(inst->fStep);
156             addMeta();
157             fOut << " ]];";
158         }
159         tab(fTab, fOut);
160     }
161 
visitSOULInstUIVisitor162     virtual void visit(AddBargraphInst* inst)
163     {
164         // We have bargraphs
165         fHasBargraph = true;
166 
167         if (gGlobal->gOutputLang == "soul-poly") {
168             vector<char> rep = {' ', '(', ')', '/', '\\', '.', '-'};
169             fOut << "output event " << fTypeManager.fTypeDirectTable[itfloat()]
170             << " event_" << quote(replaceCharList(inst->fLabel, rep, '_'))
171             << " [[ name: " << quote(inst->fLabel)
172             << ", group: " << quote(buildPath(inst->fLabel))
173             << ", min: " << checkReal(inst->fMin)
174             << ", max: " << checkReal(inst->fMax);
175             addMeta();
176             fOut << " ]];";
177         } else if (gGlobal->gOutputLang == "soul-hybrid") {
178             string soul_meta = getSoulMatadata();
179             vector<char> rep = {' ', '(', ')', '/', '\\', '.', '-'};
180             fOut << "output event " << fTypeManager.fTypeDirectTable[itfloat()]
181             << " " << ((soul_meta != "") ? soul_meta : replaceCharList(inst->fLabel, rep, '_'))
182             << " [[ name: " << quote(inst->fLabel)
183             << ", group: " << quote(buildPath(inst->fLabel))
184             << ", min: " << checkReal(inst->fMin)
185             << ", max: " << checkReal(inst->fMax);
186             addMeta();
187             fOut << " ]];";
188         } else {
189             fOut << "output event " << fTypeManager.fTypeDirectTable[itfloat()]
190             << " event" << inst->fZone
191             << " [[ name: " << quote(inst->fLabel)
192             << ", group: " << quote(buildPath(inst->fLabel))
193             << ", min: " << checkReal(inst->fMin)
194             << ", max: " << checkReal(inst->fMax);
195             addMeta();
196             fOut << " ]];";
197         }
198         tab(fTab, fOut);
199     }
200 
visitSOULInstUIVisitor201     virtual void visit(OpenboxInst* inst)
202     {
203         switch (inst->fOrient) {
204             case OpenboxInst::kVerticalBox:
205                 pushLabel("v:" + inst->fName);
206                 break;
207             case OpenboxInst::kHorizontalBox:
208                 pushLabel("h:" + inst->fName);
209                 break;
210             case OpenboxInst::kTabBox:
211                 pushLabel("t:" + inst->fName);
212                 break;
213         }
214         fMetaAux.clear();
215     }
216 
visitSOULInstUIVisitor217     virtual void visit(CloseboxInst* inst)
218     {
219         popLabel();
220         fMetaAux.clear();
221     }
222 
223 };
224 
225 class SOULInstVisitor : public TextInstVisitor {
226    private:
227     // Polymorphic math functions
228     map<string, string> gPolyMathLibTable;
229 
230     // Whether to consider an 'int' as a 'boolean' later on in code generation
231     bool fIntAsBool;
232 
233     std::vector<std::pair <std::string, std::string> > fMetaAux;
234 
checkFloat(float val)235     inline string checkFloat(float val)
236     {
237         return (std::isinf(val)) ? "inf" : T(val);
238     }
checkDouble(double val)239     inline string checkDouble(double val)
240     {
241         return (std::isinf(val)) ? "inf" : T(val);
242     }
243 
getSoulMatadata()244     std::string getSoulMatadata()
245     {
246         if (fMetaAux.size() > 0) {
247             for (size_t i = 0; i < fMetaAux.size(); i++) {
248                 if (fMetaAux[i].first == "soul") return fMetaAux[i].second;
249             }
250         }
251         return "";
252     }
253 
254    public:
SOULInstVisitor(std::ostream * out,int tab=0)255     SOULInstVisitor(std::ostream* out, int tab = 0)
256         : TextInstVisitor(out, ".", new SOULStringTypeManager(xfloat(), ""), tab)
257     {
258         // Polymath mapping int version
259         gPolyMathLibTable["abs"]   = "abs";
260         gPolyMathLibTable["max_i"] = "max";
261         gPolyMathLibTable["min_i"] = "min";
262 
263         // Polymath mapping float version
264         gPolyMathLibTable["max_f"] = "max";
265         gPolyMathLibTable["min_f"] = "min";
266 
267         gPolyMathLibTable["fabsf"]      = "abs";
268         gPolyMathLibTable["acosf"]      = "acos";
269         gPolyMathLibTable["asinf"]      = "asin";
270         gPolyMathLibTable["atanf"]      = "atan";
271         gPolyMathLibTable["atan2f"]     = "atan2";
272         gPolyMathLibTable["ceilf"]      = "ceil";
273         gPolyMathLibTable["cosf"]       = "cos";
274         gPolyMathLibTable["expf"]       = "exp";
275         gPolyMathLibTable["exp2f"]      = "exp2";
276         gPolyMathLibTable["exp10f"]     = "exp10f";
277         gPolyMathLibTable["floorf"]     = "floor";
278         gPolyMathLibTable["fmodf"]      = "fmod";
279         gPolyMathLibTable["logf"]       = "log";
280         gPolyMathLibTable["log2f"]      = "log2";
281         gPolyMathLibTable["log10f"]     = "log10";
282         gPolyMathLibTable["powf"]       = "pow";
283         gPolyMathLibTable["remainderf"] = "remainder";
284         gPolyMathLibTable["rintf"]      = "roundToInt";
285         gPolyMathLibTable["roundf"]     = "round";
286         gPolyMathLibTable["sinf"]       = "sin";
287         gPolyMathLibTable["sqrtf"]      = "sqrt";
288         gPolyMathLibTable["tanf"]       = "tan";
289 
290         // Additional hyperbolic math functions are included in SOUL
291         gPolyMathLibTable["acoshf"] = "acosh";
292         gPolyMathLibTable["asinhf"] = "asinh";
293         gPolyMathLibTable["atanhf"] = "atanh";
294         gPolyMathLibTable["coshf"]  = "cosh";
295         gPolyMathLibTable["sinhf"]  = "sinh";
296         gPolyMathLibTable["tanhf"]  = "tanh";
297 
298         gPolyMathLibTable["isnanf"]  = "isnan";
299         gPolyMathLibTable["isinff"]  = "isinf";
300         // Manually implemented
301         gPolyMathLibTable["copysignf"]  = "copysign";
302 
303         // Polymath mapping double version
304         gPolyMathLibTable["max_"] = "max";
305         gPolyMathLibTable["min_"] = "min";
306 
307         gPolyMathLibTable["fabs"]      = "abs";
308         gPolyMathLibTable["acos"]      = "acos";
309         gPolyMathLibTable["asin"]      = "asin";
310         gPolyMathLibTable["atan"]      = "atan";
311         gPolyMathLibTable["atan2"]     = "atan2";
312         gPolyMathLibTable["ceil"]      = "ceil";
313         gPolyMathLibTable["cos"]       = "cos";
314         gPolyMathLibTable["exp"]       = "exp";
315         gPolyMathLibTable["exp2"]      = "exp2";
316         gPolyMathLibTable["exp10"]     = "exp10";
317         gPolyMathLibTable["floor"]     = "floor";
318         gPolyMathLibTable["fmod"]      = "fmod";
319         gPolyMathLibTable["log"]       = "log";
320         gPolyMathLibTable["log2"]      = "log2";
321         gPolyMathLibTable["log10"]     = "log10";
322         gPolyMathLibTable["pow"]       = "pow";
323         gPolyMathLibTable["remainder"] = "remainder";
324         gPolyMathLibTable["rint"]      = "roundToInt";
325         gPolyMathLibTable["round"]     = "round";
326         gPolyMathLibTable["sin"]       = "sin";
327         gPolyMathLibTable["sqrt"]      = "sqrt";
328         gPolyMathLibTable["tan"]       = "tan";
329 
330         // Additional hyperbolic math functions are included in SOUL
331         gPolyMathLibTable["acosh"] = "acosh";
332         gPolyMathLibTable["asinh"] = "asinh";
333         gPolyMathLibTable["atanh"] = "atanh";
334         gPolyMathLibTable["cosh"]  = "cosh";
335         gPolyMathLibTable["sinh"]  = "sinh";
336         gPolyMathLibTable["tanh"]  = "tanh";
337 
338         gPolyMathLibTable["isnan"]  = "isnan";
339         gPolyMathLibTable["isinf"]  = "isinf";
340         // Manually implemented
341         gPolyMathLibTable["copysignf"]  = "copysign";
342 
343         fIntAsBool = false;
344     }
345 
~SOULInstVisitor()346     virtual ~SOULInstVisitor() {}
347 
visit(AddMetaDeclareInst * inst)348     virtual void visit(AddMetaDeclareInst* inst)
349     {
350         fMetaAux.push_back(std::make_pair(inst->fKey, inst->fValue));
351     }
352 
visit(OpenboxInst * inst)353     virtual void visit(OpenboxInst* inst)
354     {
355         fMetaAux.clear();
356     }
357 
visit(CloseboxInst * inst)358     virtual void visit(CloseboxInst* inst)
359     {
360         fMetaAux.clear();
361     }
362 
visit(AddButtonInst * inst)363     virtual void visit(AddButtonInst* inst)
364     {
365         *fOut << "// " << inst->fLabel;
366         EndLine(' ');
367         if (gGlobal->gOutputLang == "soul-poly") {
368             vector<char> rep = {' ', '(', ')', '/', '\\', '.', '-'};
369             *fOut << "event event_" << replaceCharList(inst->fLabel, rep, '_') << " ("
370                   << fTypeManager->fTypeDirectTable[itfloat()] << " val) { " << inst->fZone
371                   << " = val; fUpdated = true; }";
372         } else if (gGlobal->gOutputLang == "soul-hybrid") {
373             string soul_meta = getSoulMatadata();
374             vector<char> rep = {' ', '(', ')', '/', '\\', '.', '-'};
375             *fOut << "event " << ((soul_meta != "") ? soul_meta : replaceCharList(inst->fLabel, rep, '_'))
376                   << " (" << fTypeManager->fTypeDirectTable[itfloat()] << " val) { "
377                   << inst->fZone << " = val; fUpdated = true; }";
378             fMetaAux.clear();
379         } else {
380             *fOut << "event event" << inst->fZone << " (" << fTypeManager->fTypeDirectTable[itfloat()] << " val) { "
381                   << inst->fZone << " = val; fUpdated = true; }";
382         }
383         EndLine(' ');
384     }
385 
visit(AddSliderInst * inst)386     virtual void visit(AddSliderInst* inst)
387     {
388         *fOut << "// " << inst->fLabel << " [init = " << checkReal(inst->fInit)
389               << ", min = " << checkReal(inst->fMin) << ", max = " << checkReal(inst->fMax)
390               << ", step = " << checkReal(inst->fStep) << "]";
391         EndLine(' ');
392         if (gGlobal->gOutputLang == "soul-poly") {
393             vector<char> rep = {' ', '(', ')', '/', '\\', '.', '-'};
394             *fOut << "event event_" << replaceCharList(inst->fLabel, rep, '_') << " ("
395                   << fTypeManager->fTypeDirectTable[itfloat()] << " val) { " << inst->fZone
396                   << " = val; fUpdated = true; }";
397         } else if (gGlobal->gOutputLang == "soul-hybrid") {
398             string soul_meta = getSoulMatadata();
399             vector<char> rep = {' ', '(', ')', '/', '\\', '.', '-'};
400             *fOut << "event " << ((soul_meta != "") ? soul_meta : replaceCharList(inst->fLabel, rep, '_'))
401                   << " (" << fTypeManager->fTypeDirectTable[itfloat()] << " val) { "
402                   << inst->fZone << " = val; fUpdated = true; }";
403             fMetaAux.clear();
404         } else {
405             *fOut << "event event" << inst->fZone << " (" << fTypeManager->fTypeDirectTable[itfloat()] << " val) { "
406                   << inst->fZone << " = val; fUpdated = true; }";
407         }
408         EndLine(' ');
409     }
410 
visit(AddBargraphInst * inst)411     virtual void visit(AddBargraphInst* inst)
412     {
413         *fOut << "// " << inst->fLabel << " [min = " << checkReal(inst->fMin) << ", max = " << checkReal(inst->fMax)
414               << "]";
415         EndLine(' ');
416     }
417 
visit(AddSoundfileInst * inst)418     virtual void visit(AddSoundfileInst* inst)
419     {
420         // Not supported for now
421         throw faustexception("ERROR : 'soundfile' primitive not yet supported for SOUL\n");
422     }
423 
visit(DeclareVarInst * inst)424     virtual void visit(DeclareVarInst* inst)
425     {
426         string name = inst->fAddress->getName();
427 
428         // special case for input/output considered as 'streams'
429         if (startWith(name, "input")) {
430             *fOut << "input stream " << fTypeManager->fTypeDirectTable[itfloat()] << " " << name;
431         } else if (startWith(name, "output")) {
432             *fOut << "output stream " << fTypeManager->fTypeDirectTable[itfloat()] << " " << name;
433         } else {
434             if (inst->fAddress->getAccess() & Address::kConst) {
435                 *fOut << "const ";
436             }
437             *fOut << fTypeManager->generateType(inst->fType, name);
438             if (inst->fValue) {
439                 *fOut << " = ";
440                 inst->fValue->accept(this);
441             }
442         }
443         EndLine();
444     }
445 
visit(DeclareFunInst * inst)446     virtual void visit(DeclareFunInst* inst) {}
447 
448     /*
449      Indexed adresses can actually be values in an array or fields in a struct type
450      */
visit(IndexedAddress * indexed)451     virtual void visit(IndexedAddress* indexed)
452     {
453         indexed->fAddress->accept(this);
454         DeclareStructTypeInst* struct_type = isStructType(indexed->getName());
455         if (struct_type) {
456             Int32NumInst* field_index = static_cast<Int32NumInst*>(indexed->fIndex);
457             *fOut << "." << struct_type->fType->getName(field_index->fNum);
458         } else {
459             if (dynamic_cast<Int32NumInst*>(indexed->fIndex)) {
460                 *fOut << "[";
461                 indexed->fIndex->accept(this);
462                 *fOut << "]";
463             } else {
464                 // wrap code is automatically added by the SOUL compiler (and the same if [idex] syntax is used)
465                 *fOut << ".at (";
466                 indexed->fIndex->accept(this);
467                 *fOut << ")";
468             }
469         }
470     }
471 
visit(StoreVarInst * inst)472     virtual void visit(StoreVarInst* inst)
473     {
474         // special case for 'output' considered as a 'stream'
475         if (startWith(inst->fAddress->getName(), "output")) {
476             inst->fAddress->accept(this);
477             *fOut << " << ";
478             inst->fValue->accept(this);
479             EndLine();
480             // special case for 'bargraph' considered as an 'output event'
481         } else if (startWith(inst->fAddress->getName(), "fHbargraph") ||
482                    startWith(inst->fAddress->getName(), "fVbargraph")) {
483 
484             // value is stored in the bargraph variable
485             {
486                 inst->fAddress->accept(this);
487                 *fOut << " = ";
488                 inst->fValue->accept(this);
489                 EndLine();
490             }
491 
492             // and the bargraph variable is sent using the 'output' event handler
493             {
494                 *fOut << "if (fControlSlice == 0) { ";
495                 *fOut << "event";
496                 inst->fAddress->accept(this);
497                 *fOut << " << ";
498                 inst->fAddress->accept(this);
499                 *fOut << "; }";
500                 tab(fTab, *fOut);
501             }
502 
503         } else {
504             inst->fAddress->accept(this);
505             *fOut << " = ";
506             inst->fValue->accept(this);
507             EndLine();
508         }
509     }
510 
visit(FloatNumInst * inst)511     virtual void visit(FloatNumInst* inst) { *fOut << checkFloat(inst->fNum); }
512 
visit(FloatArrayNumInst * inst)513     virtual void visit(FloatArrayNumInst* inst)
514     {
515         char sep = '(';
516         for (size_t i = 0; i < inst->fNumTable.size(); i++) {
517             *fOut << sep << checkFloat(inst->fNumTable[i]);
518             sep = ',';
519         }
520         *fOut << ')';
521     }
522 
visit(Int32ArrayNumInst * inst)523     virtual void visit(Int32ArrayNumInst* inst)
524     {
525         char sep = '(';
526         for (size_t i = 0; i < inst->fNumTable.size(); i++) {
527             *fOut << sep << inst->fNumTable[i];
528             sep = ',';
529         }
530         *fOut << ')';
531     }
532 
visit(Int64NumInst * inst)533     virtual void visit(Int64NumInst* inst) { *fOut << inst->fNum << "L"; }
534 
visit(DoubleNumInst * inst)535     virtual void visit(DoubleNumInst* inst) { *fOut << checkDouble(inst->fNum); }
536 
visit(DoubleArrayNumInst * inst)537     virtual void visit(DoubleArrayNumInst* inst)
538     {
539         char sep = '(';
540         for (size_t i = 0; i < inst->fNumTable.size(); i++) {
541             *fOut << sep << checkDouble(inst->fNumTable[i]);
542             sep = ',';
543         }
544         *fOut << ')';
545     }
546 
visit(::CastInst * inst)547     virtual void visit(::CastInst* inst)
548     {
549         string type = fTypeManager->generateType(inst->fType);
550         *fOut << type << " (";
551         inst->fInst->accept(this);
552         *fOut << ")";
553     }
554 
visit(BitcastInst * inst)555     virtual void visit(BitcastInst* inst) { faustassert(false); }
556 
visit(Select2Inst * inst)557     virtual void visit(Select2Inst* inst)
558     {
559         *fOut << "(bool (";
560         fIntAsBool = true;
561         inst->fCond->accept(this);
562         fIntAsBool = false;
563         *fOut << ") ? ";
564         inst->fThen->accept(this);
565         *fOut << " : ";
566         inst->fElse->accept(this);
567         *fOut << ")";
568     }
569 
visit(IfInst * inst)570     virtual void visit(IfInst* inst)
571     {
572         *fOut << "if ";
573         *fOut << "(bool (";
574         fIntAsBool = true;
575         visitCond(inst->fCond);
576         fIntAsBool = false;
577         *fOut << "))";
578         *fOut << " {";
579         fTab++;
580         tab(fTab, *fOut);
581         inst->fThen->accept(this);
582         fTab--;
583         back(1, *fOut);
584         if (inst->fElse->fCode.size() > 0) {
585             *fOut << "} else {";
586             fTab++;
587             tab(fTab, *fOut);
588             inst->fElse->accept(this);
589             fTab--;
590             back(1, *fOut);
591             *fOut << "}";
592         } else {
593             *fOut << "}";
594         }
595         tab(fTab, *fOut);
596     }
597 
visit(BinopInst * inst)598     virtual void visit(BinopInst* inst)
599     {
600         bool int_as_bool = fIntAsBool;
601         if (isBoolOpcode(inst->fOpcode) && !int_as_bool) {
602             *fOut << "int (";
603         }
604         *fOut << "(";
605 
606         // Hack to make it work again with 'soul' version 0.0.6
607         if (isLogicalOpcode(inst->fOpcode)) {
608             TypingVisitor typing;
609             inst->fInst1->accept(&typing);
610             if (isInt64Type(typing.fCurType)) {
611                 *fOut << "int64 (";
612             } else if (isInt32Type(typing.fCurType) || isBoolType(typing.fCurType)) {
613                 *fOut << "int32 (";
614             } else {
615                 faustassert(false);
616             }
617         }
618 
619         inst->fInst1->accept(this);
620 
621         // Hack to make it work again with 'soul' version 0.0.6
622         if (isLogicalOpcode(inst->fOpcode)) {
623             *fOut << ")";
624         }
625 
626         *fOut << " ";
627         *fOut << gBinOpTable[inst->fOpcode]->fName;
628         *fOut << " ";
629 
630         // Hack to make it work again with 'soul' version 0.0.6
631         if (isLogicalOpcode(inst->fOpcode)) {
632             TypingVisitor typing;
633             inst->fInst2->accept(&typing);
634             if (isInt64Type(typing.fCurType)) {
635                 *fOut << "int64 (";
636             } else if (isInt32Type(typing.fCurType) || isBoolType(typing.fCurType)) {
637                 *fOut << "int32 (";
638             } else {
639                 faustassert(false);
640             }
641         }
642 
643         inst->fInst2->accept(this);
644 
645         // Hack to make it work again with 'soul' version 0.0.6
646         if (isLogicalOpcode(inst->fOpcode)) {
647             *fOut << ")";
648         }
649 
650         *fOut << ")";
651         if (isBoolOpcode(inst->fOpcode) && !int_as_bool) {
652             *fOut << ")";
653         }
654     }
655 
visit(FunCallInst * inst)656     virtual void visit(FunCallInst* inst)
657     {
658         string name;
659         if (gPolyMathLibTable.find(inst->fName) != gPolyMathLibTable.end()) {
660             name = gPolyMathLibTable[inst->fName];
661         } else {
662             name = inst->fName;
663         }
664 
665         *fOut << gGlobal->getMathFunction(name) << ((inst->fArgs.size() > 0) ? " (" : "(");
666 
667         // Compile parameters
668         generateFunCallArgs(inst->fArgs.begin(), inst->fArgs.end(), inst->fArgs.size());
669         *fOut << ")";
670     }
671 
visit(ForLoopInst * inst)672     virtual void visit(ForLoopInst* inst)
673     {
674         // Don't generate empty loops...
675         if (inst->fCode->size() == 0) return;
676 
677         *fOut << "for (";
678 
679         fFinishLine = false;
680         inst->fInit->accept(this);
681         *fOut << "; ";
682 
683         fIntAsBool = true;
684         inst->fEnd->accept(this);
685         fIntAsBool = false;
686         *fOut << "; ";
687 
688         inst->fIncrement->accept(this);
689         fFinishLine = true;
690         *fOut << ") {";
691 
692         fTab++;
693         tab(fTab, *fOut);
694         inst->fCode->accept(this);
695         fTab--;
696         back(1, *fOut);
697         *fOut << "}";
698         tab(fTab, *fOut);
699     }
700 
getTypeManager()701     StringTypeManager* getTypeManager() { return fTypeManager; }
702 };
703 
704 // For subcontainers: variable access is specific
705 class SOULSubContainerInstVisitor : public SOULInstVisitor {
706    public:
SOULSubContainerInstVisitor(std::ostream * out,int tab=0)707     SOULSubContainerInstVisitor(std::ostream* out, int tab = 0) : SOULInstVisitor(out, tab) {}
708 
visit(NamedAddress * named)709     virtual void visit(NamedAddress* named)
710     {
711         if (named->getAccess() & Address::kStruct) {
712             *fOut << "this.";
713         }
714         *fOut << named->fName;
715     }
716 };
717 
718 #endif
719