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 #ifndef _DLANG_INSTRUCTIONS_H
23 #define _DLANG_INSTRUCTIONS_H
24 
25 using namespace std;
26 
27 #include "text_instructions.hh"
28 #include "type_manager.hh"
29 
30 class DLangInstVisitor : public TextInstVisitor {
31    private:
32     /*
33      Global functions names table as a static variable in the visitor
34      so that each function prototype is generated at most once in the module.
35      */
36     static map<string, bool> gFunctionSymbolTable;
37 
38     // Polymorphic math functions
39     map<string, string> gPolyMathLibTable;
40 
cast2FAUSTFLOAT(const string & str)41     string cast2FAUSTFLOAT(const string& str) { return "cast(FAUSTFLOAT)" + str; }
42 
43    public:
44     using TextInstVisitor::visit;
45 
DLangInstVisitor(std::ostream * out,int tab=0)46     DLangInstVisitor(std::ostream* out, int tab = 0) : TextInstVisitor(out, ".", xfloat(), "*", tab)
47     {
48         // Set 64 bits types
49         fTypeManager->fTypeDirectTable[Typed::kInt64]     = "long";
50         fTypeManager->fTypeDirectTable[Typed::kInt64_ptr] = "long*";
51         fTypeManager->fTypeDirectTable[Typed::kInt64_vec] = "vector<long>";
52 
53         // Int version
54         gPolyMathLibTable["abs"]   = "std.math.abs";
55         gPolyMathLibTable["max_i"] = "max";
56         gPolyMathLibTable["min_i"] = "min";
57         gPolyMathLibTable["rint"] = "round";
58 
59         // Float version
60         gPolyMathLibTable["fabsf"]  = "fabs";
61         gPolyMathLibTable["acosf"]  = "acos";
62         gPolyMathLibTable["asinf"]  = "asin";
63         gPolyMathLibTable["atanf"]  = "atan";
64         gPolyMathLibTable["atan2f"] = "atan2";
65         gPolyMathLibTable["ceilf"]  = "ceil";
66         gPolyMathLibTable["cosf"]   = "cos";
67         gPolyMathLibTable["coshf"]  = "cosh";
68         gPolyMathLibTable["expf"]   = "exp";
69         gPolyMathLibTable["floorf"] = "floor";
70         gPolyMathLibTable["fmodf"]  = "fmod";
71         gPolyMathLibTable["logf"]   = "log";
72         gPolyMathLibTable["log10f"] = "log10";
73         gPolyMathLibTable["max_f"]  = "fmax";
74         gPolyMathLibTable["min_f"]  = "fmin";
75         gPolyMathLibTable["powf"]   = "pow";
76         gPolyMathLibTable["remainderf"] = "remainder";
77         gPolyMathLibTable["roundf"] = "round";
78         gPolyMathLibTable["sinf"]   = "sin";
79         gPolyMathLibTable["sinhf"]  = "sinh";
80         gPolyMathLibTable["sqrtf"]  = "sqrt";
81         gPolyMathLibTable["tanf"]   = "tan";
82         gPolyMathLibTable["tanhf"]  = "tanh";
83 
84         // Hyperbolic
85         gPolyMathLibTable["acoshf"]     = "acosh";
86         gPolyMathLibTable["asinhf"]     = "asinh";
87         gPolyMathLibTable["atanhf"]     = "atanh";
88         gPolyMathLibTable["coshf"]      = "cosh";
89         gPolyMathLibTable["sinhf"]      = "sinh";
90         gPolyMathLibTable["tanhf"]      = "tanh";
91 
92         gPolyMathLibTable["isnanf"]     = "isNaN";
93         gPolyMathLibTable["isinff"]     = "isInfinity";
94         gPolyMathLibTable["copysignf"]  = "copysign";
95 
96         // Double version
97         gPolyMathLibTable["fabs"]  = "fabs";
98         gPolyMathLibTable["acos"]  = "acos";
99         gPolyMathLibTable["asin"]  = "asin";
100         gPolyMathLibTable["atan"]  = "atan";
101         gPolyMathLibTable["atan2"] = "atan2";
102         gPolyMathLibTable["ceil"]  = "ceil";
103         gPolyMathLibTable["cos"]   = "cos";
104         gPolyMathLibTable["cosh"]  = "cosh";
105         gPolyMathLibTable["exp"]   = "exp";
106         gPolyMathLibTable["floor"] = "floor";
107         gPolyMathLibTable["fmod"]  = "fmod";
108         gPolyMathLibTable["log"]   = "log";
109         gPolyMathLibTable["log10"] = "log10";
110         gPolyMathLibTable["max_"]  = "fmax";
111         gPolyMathLibTable["min_"]  = "fmin";
112         gPolyMathLibTable["pow"]   = "pow";
113         gPolyMathLibTable["remainder"] = "remainder";
114         gPolyMathLibTable["round"] = "round";
115         gPolyMathLibTable["sin"]   = "sin";
116         gPolyMathLibTable["sinh"]  = "sinh";
117         gPolyMathLibTable["sqrt"]  = "sqrt";
118         gPolyMathLibTable["tan"]   = "tan";
119         gPolyMathLibTable["tanh"]  = "tanh";
120 
121         // Hyperbolic
122         gPolyMathLibTable["acosh"]     = "acosh";
123         gPolyMathLibTable["asinh"]     = "asinh";
124         gPolyMathLibTable["atanh"]     = "atanh";
125         gPolyMathLibTable["cosh"]      = "cosh";
126         gPolyMathLibTable["sinh"]      = "sinh";
127         gPolyMathLibTable["tanh"]      = "tanh";
128 
129         gPolyMathLibTable["isnan"]     = "isNaN";
130         gPolyMathLibTable["isinf"]     = "isInfinity";
131         gPolyMathLibTable["copysign"]  = "copysign";
132     }
133 
~DLangInstVisitor()134     virtual ~DLangInstVisitor() {}
135 
visit(AddMetaDeclareInst * inst)136     virtual void visit(AddMetaDeclareInst* inst)
137     {
138         // Special case
139         if (inst->fZone == "0") {
140             *fOut << "uiInterface.declare(" << inst->fZone << ", " << quote(inst->fKey) << ", " << quote(inst->fValue)
141                   << ")";
142         } else {
143             *fOut << "uiInterface.declare(&" << inst->fZone << ", " << quote(inst->fKey) << ", "
144                   << quote(inst->fValue) << ")";
145         }
146         EndLine();
147     }
148 
visit(OpenboxInst * inst)149     virtual void visit(OpenboxInst* inst)
150     {
151         string name;
152         switch (inst->fOrient) {
153             case OpenboxInst::kVerticalBox:
154                 name = "uiInterface.openVerticalBox(";
155                 break;
156             case OpenboxInst::kHorizontalBox:
157                 name = "uiInterface.openHorizontalBox(";
158                 break;
159             case OpenboxInst::kTabBox:
160                 name = "uiInterface.openTabBox(";
161                 break;
162         }
163         *fOut << name << quote(inst->fName) << ")";
164         EndLine();
165     }
166 
visit(CloseboxInst * inst)167     virtual void visit(CloseboxInst* inst)
168     {
169         *fOut << "uiInterface.closeBox();";
170         tab(fTab, *fOut);
171     }
172 
visit(AddButtonInst * inst)173     virtual void visit(AddButtonInst* inst)
174     {
175         if (inst->fType == AddButtonInst::kDefaultButton) {
176             *fOut << "uiInterface.addButton(" << quote(inst->fLabel) << ", &" << inst->fZone << ")";
177         } else {
178             *fOut << "uiInterface.addCheckButton(" << quote(inst->fLabel) << ", &" << inst->fZone << ")";
179         }
180         EndLine();
181     }
182 
visit(AddSliderInst * inst)183     virtual void visit(AddSliderInst* inst)
184     {
185         string name;
186         switch (inst->fType) {
187             case AddSliderInst::kHorizontal:
188                 name = "uiInterface.addHorizontalSlider";
189                 break;
190             case AddSliderInst::kVertical:
191                 name = "uiInterface.addVerticalSlider";
192                 break;
193             case AddSliderInst::kNumEntry:
194                 name = "uiInterface.addNumEntry";
195                 break;
196         }
197         *fOut << name << "(" << quote(inst->fLabel) << ", " << "&" << inst->fZone << ", "
198               << cast2FAUSTFLOAT(checkReal(inst->fInit)) << ", "
199               << cast2FAUSTFLOAT(checkReal(inst->fMin)) << ", "
200               << cast2FAUSTFLOAT(checkReal(inst->fMax)) << ", "
201               << cast2FAUSTFLOAT(checkReal(inst->fStep)) << ")";
202         EndLine();
203     }
204 
visit(AddBargraphInst * inst)205     virtual void visit(AddBargraphInst* inst)
206     {
207         string name;
208         switch (inst->fType) {
209             case AddBargraphInst::kHorizontal:
210                 name = "uiInterface.addHorizontalBargraph";
211                 break;
212             case AddBargraphInst::kVertical:
213                 name = "uiInterface.addVerticalBargraph";
214                 break;
215         }
216         *fOut << name << "(" << quote(inst->fLabel) << ", &" << inst->fZone << ", "
217               << cast2FAUSTFLOAT(checkReal(inst->fMin)) << ", "
218               << cast2FAUSTFLOAT(checkReal(inst->fMax)) << ")";
219         EndLine();
220     }
221 
visit(AddSoundfileInst * inst)222     virtual void visit(AddSoundfileInst* inst)
223     {
224         *fOut << "uiInterface.addSoundfile(" << quote(inst->fLabel) << ", " << quote(inst->fURL) << ", &"
225               << inst->fSFZone << ")";
226         EndLine();
227     }
228 
visit(DeclareVarInst * inst)229     virtual void visit(DeclareVarInst* inst)
230     {
231         if (inst->fAddress->getAccess() & Address::kConst) {
232             *fOut << "const ";
233         }
234 
235         if (inst->fAddress->getAccess() & Address::kStaticStruct) {
236             *fOut << "__gshared ";
237         }
238 
239         if (inst->fAddress->getAccess() & Address::kVolatile) {
240             *fOut << "volatile ";
241         }
242         ArrayTyped* array_typed = dynamic_cast<ArrayTyped*>(inst->fType);
243         if (array_typed && array_typed->fSize > 1) {
244             string type = fTypeManager->fTypeDirectTable[array_typed->fType->getType()];
245             if (inst->fValue) {
246                 *fOut << type << "[] " << inst->fAddress->getName() << " = ";
247                 inst->fValue->accept(this);
248             } else {
249                 *fOut << type << "[" << array_typed->fSize << "] " << inst->fAddress->getName();
250             }
251         } else {
252             *fOut << fTypeManager->generateType(inst->fType, inst->fAddress->getName());
253             if (inst->fValue) {
254                 *fOut << " = ";
255                 inst->fValue->accept(this);
256             }
257         }
258         EndLine();
259     }
260 
visit(DeclareFunInst * inst)261     virtual void visit(DeclareFunInst* inst)
262     {
263         // Already generated
264         if (gFunctionSymbolTable.find(inst->fName) != gFunctionSymbolTable.end()) {
265             return;
266         } else {
267             gFunctionSymbolTable[inst->fName] = true;
268         }
269 
270         // Dont declare Math library functions, they are already defined in std.math
271         if (gPolyMathLibTable.find(inst->fName) != gPolyMathLibTable.end()) {
272             return;
273         }
274 
275         // Defined as macro in the architecture file...
276         if (checkMinMax(inst->fName)) {
277             return;
278         }
279 
280         // Prototype arguments
281         if (inst->fType->fAttribute & FunTyped::kInline) {
282             *fOut << "inline ";
283         }
284 
285         if (inst->fType->fAttribute & FunTyped::kLocal || inst->fType->fAttribute & FunTyped::kStatic) {
286             *fOut << "static ";
287         }
288 
289         // Prototype
290         // Special case: member function `init` renamed to `initialize` so it doesnt conflict with D `.init` property.
291         *fOut << fTypeManager->generateType(inst->fType->fResult, generateFunName(inst->fName == "init" ? "initialize" : inst->fName));
292         generateFunDefArgs(inst);
293         generateFunDefBody(inst);
294     }
295 
generateFunDefBody(DeclareFunInst * inst)296     virtual void generateFunDefBody(DeclareFunInst* inst)
297     {
298         if (inst->fCode->fCode.size() == 0) {
299             *fOut << ") nothrow @nogc;" << endl;  // Pure prototype
300         } else {
301             // Function body
302             *fOut << ") nothrow @nogc {";
303             fTab++;
304             tab(fTab, *fOut);
305             inst->fCode->accept(this);
306             fTab--;
307             back(1, *fOut);
308             *fOut << "}";
309             tab(fTab, *fOut);
310         }
311     }
312 
visit(LoadVarAddressInst * inst)313     virtual void visit(LoadVarAddressInst* inst)
314     {
315         *fOut << "&";
316         inst->fAddress->accept(this);
317     }
318 
visit(BinopInst * inst)319     virtual void visit(BinopInst* inst)
320     {
321         // Special case for 'logical right-shift'
322         if (strcmp(gBinOpTable[inst->fOpcode]->fName, ">>>") == 0) {
323             TypingVisitor typing;
324             inst->fInst1->accept(&typing);
325             if (isInt64Type(typing.fCurType)) {
326                 *fOut << "(cast(long)(cast(ulong)";
327             } else if (isInt32Type(typing.fCurType)) {
328                 *fOut << "(cast(int)(cast(uint)";
329             } else {
330                 faustassert(false);
331             }
332             inst->fInst1->accept(this);
333             *fOut << " >> ";
334             inst->fInst2->accept(this);
335             *fOut << "))";
336         } else {
337             TextInstVisitor::visit(inst);
338         }
339     }
340 
visit(::CastInst * inst)341     virtual void visit(::CastInst* inst)
342     {
343         string type = fTypeManager->generateType(inst->fType);
344         *fOut << "cast(" << type << ")";
345         inst->fInst->accept(this);
346     }
347 
348     /*
349      Indexed adresses can actually be values in an array or fields in a struct type
350      */
visit(IndexedAddress * indexed)351     virtual void visit(IndexedAddress* indexed)
352     {
353         indexed->fAddress->accept(this);
354         DeclareStructTypeInst* struct_type = isStructType(indexed->getName());
355         if (struct_type) {
356             Int32NumInst* field_index = static_cast<Int32NumInst*>(indexed->fIndex);
357             *fOut << "." << struct_type->fType->getName(field_index->fNum);
358         } else {
359             *fOut << "[";
360             indexed->fIndex->accept(this);
361             *fOut << "]";
362         }
363     }
364 
visit(BitcastInst * inst)365     virtual void visit(BitcastInst* inst) { faustassert(false); }
366 
visit(FunCallInst * inst)367     virtual void visit(FunCallInst* inst)
368     {
369         string name = gGlobal->getMathFunction(inst->fName);
370         name = (gPolyMathLibTable.find(name) != gPolyMathLibTable.end()) ? gPolyMathLibTable[name] : name;
371         generateFunCall(inst, name);
372     }
373 
visit(FloatArrayNumInst * inst)374     virtual void visit(FloatArrayNumInst* inst)
375     {
376         char sep = '[';
377         for (size_t i = 0; i < inst->fNumTable.size(); i++) {
378             *fOut << sep << checkFloat(inst->fNumTable[i]);
379             sep = ',';
380         }
381         *fOut << ']';
382     }
383 
visit(Int32ArrayNumInst * inst)384     virtual void visit(Int32ArrayNumInst* inst)
385     {
386         char sep = '[';
387         for (size_t i = 0; i < inst->fNumTable.size(); i++) {
388             *fOut << sep << inst->fNumTable[i];
389             sep = ',';
390         }
391         *fOut << ']';
392     }
393 
visit(DoubleArrayNumInst * inst)394     virtual void visit(DoubleArrayNumInst* inst)
395     {
396         char sep = '[';
397         for (size_t i = 0; i < inst->fNumTable.size(); i++) {
398             *fOut << sep << checkDouble(inst->fNumTable[i]);
399             sep = ',';
400         }
401         *fOut << ']';
402     }
403 
cleanup()404     static void cleanup() { gFunctionSymbolTable.clear(); }
405 };
406 
407 #endif
408