1 /************************************************************************
2 ************************************************************************
3 FAUST compiler
4 Copyright (C) 2017 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 _RUST_INSTRUCTIONS_H
23 #define _RUST_INSTRUCTIONS_H
24
25 #include <regex>
26
27 #include "text_instructions.hh"
28 #include "Text.hh"
29
30 using namespace std;
31
makeNameSingular(const string & name)32 inline string makeNameSingular(const string& name) {
33 string result = name;
34 result = std::regex_replace(result, std::regex("inputs"), "input");
35 result = std::regex_replace(result, std::regex("outputs"), "output");
36 return result;
37 }
38
39 // Visitor used to initialize fields into the DSP constructor
40 struct RustInitFieldsVisitor : public DispatchVisitor {
41 std::ostream* fOut;
42 int fTab;
43
RustInitFieldsVisitorRustInitFieldsVisitor44 RustInitFieldsVisitor(std::ostream* out, int tab = 0) : fOut(out), fTab(tab) {}
45
visitRustInitFieldsVisitor46 virtual void visit(DeclareVarInst* inst)
47 {
48 tab(fTab, *fOut);
49 *fOut << inst->fAddress->getName() << ": ";
50 ZeroInitializer(fOut, inst->fType);
51 if (inst->fAddress->getAccess() & Address::kStruct) *fOut << ",";
52 }
53
54 // Generate zero intialisation code for simple int/real scalar and arrays types
ZeroInitializerRustInitFieldsVisitor55 static void ZeroInitializer(std::ostream* fOut, Typed* typed)
56 {
57 Typed::VarType type = typed->getType();
58 ArrayTyped* array_type = dynamic_cast<ArrayTyped*>(typed);
59
60 if (array_type) {
61 if (isIntPtrType(type)) {
62 *fOut << "[0;" << array_type->fSize << "]";
63 } else if (isRealPtrType(type)) {
64 *fOut << "[0.0;" << array_type->fSize << "]";
65 }
66 } else {
67 if (isIntType(type)) {
68 *fOut << "0";
69 } else if (isRealType(type)) {
70 *fOut << "0.0";
71 }
72 }
73 }
74 };
75
76 class RustInstVisitor : public TextInstVisitor {
77 private:
78 /*
79 Global functions names table as a static variable in the visitor
80 so that each function prototype is generated as most once in the module.
81 */
82 static map<string, bool> gFunctionSymbolTable;
83 map<string, string> fMathLibTable;
84
85 public:
86 using TextInstVisitor::visit;
87
RustInstVisitor(std::ostream * out,const string & structname,int tab=0)88 RustInstVisitor(std::ostream* out, const string& structname, int tab = 0)
89 : TextInstVisitor(out, ".", new RustStringTypeManager(xfloat(), "&"), tab)
90 {
91 fTypeManager->fTypeDirectTable[Typed::kObj] = "";
92 fTypeManager->fTypeDirectTable[Typed::kObj_ptr] = "";
93
94 // Integer version
95 fMathLibTable["abs"] = "i32::abs";
96 fMathLibTable["min_i"] = "std::cmp::min";
97 fMathLibTable["max_i"] = "std::cmp::max";
98
99 // Float version
100 fMathLibTable["fabsf"] = "F32::abs";
101 fMathLibTable["acosf"] = "F32::acos";
102 fMathLibTable["asinf"] = "F32::asin";
103 fMathLibTable["atanf"] = "F32::atan";
104 fMathLibTable["atan2f"] = "F32::atan2";
105 fMathLibTable["ceilf"] = "F32::ceil";
106 fMathLibTable["cosf"] = "F32::cos";
107 fMathLibTable["expf"] = "F32::exp";
108 fMathLibTable["floorf"] = "F32::floor";
109 fMathLibTable["fmodf"] = "libm::fmodf";
110 fMathLibTable["logf"] = "F32::log";
111 fMathLibTable["log10f"] = "F32::log10";
112 fMathLibTable["max_f"] = "F32::max";
113 fMathLibTable["min_f"] = "F32::min";
114 fMathLibTable["powf"] = "F32::powf";
115 fMathLibTable["remainderf"] = "F32::rem_euclid";
116 //fMathLibTable["rintf"] = "linux_api_math::rintf"; // TODO
117 fMathLibTable["rintf"] = "F32::round";
118 fMathLibTable["roundf"] = "F32::round";
119 fMathLibTable["sinf"] = "F32::sin";
120 fMathLibTable["sqrtf"] = "F32::sqrt";
121 fMathLibTable["tanf"] = "F32::tan";
122
123 // Additional hyperbolic math functions
124 fMathLibTable["acoshf"] = "F32::acosh";
125 fMathLibTable["asinhf"] = "F32::asinh";
126 fMathLibTable["atanhf"] = "F32::atanh";
127 fMathLibTable["coshf"] = "F32::cosh";
128 fMathLibTable["sinhf"] = "F32::sinh";
129 fMathLibTable["tanhf"] = "F32::tanh";
130
131 fMathLibTable["isnanf"] = "F32::is_nan";
132 fMathLibTable["isinff"] = "F32::is_infinite";
133 fMathLibTable["copysignf"] = "F32::copysign";
134
135 // Double version
136 fMathLibTable["fabs"] = "F64::abs";
137 fMathLibTable["acos"] = "F64::acos";
138 fMathLibTable["asin"] = "F64::asin";
139 fMathLibTable["atan"] = "F64::atan";
140 fMathLibTable["atan2"] = "F64::atan2";
141 fMathLibTable["ceil"] = "F64::ceil";
142 fMathLibTable["cos"] = "F64::cos";
143 fMathLibTable["exp"] = "F64::exp";
144 fMathLibTable["floor"] = "F64::floor";
145 fMathLibTable["fmod"] = "libm::fmod";
146 fMathLibTable["log"] = "F64::log";
147 fMathLibTable["log10"] = "F64::log10";
148 fMathLibTable["max_"] = "F64::max";
149 fMathLibTable["min_"] = "F64::min";
150 fMathLibTable["pow"] = "F64::powf";
151 fMathLibTable["remainder"] = "F64::rem_euclid";
152 //fMathLibTable["rint"] = "linux_api_math::rint"; // TODO
153 fMathLibTable["rint"] = "F64::round";
154 fMathLibTable["round"] = "F64::round";
155 fMathLibTable["sin"] = "F64::sin";
156 fMathLibTable["sqrt"] = "F64::sqrt";
157 fMathLibTable["tan"] = "F64::tan";
158
159 // Additional hyperbolic math functions
160 fMathLibTable["acosh"] = "F64::acosh";
161 fMathLibTable["asinh"] = "F64::asinh";
162 fMathLibTable["atanh"] = "F64::atanh";
163 fMathLibTable["cosh"] = "F64::cosh";
164 fMathLibTable["sinh"] = "F64::sinh";
165 fMathLibTable["tanh"] = "F64::tanh";
166
167 fMathLibTable["isnan"] = "F64::is_nan";
168 fMathLibTable["isinf"] = "F64::is_infinite";
169 fMathLibTable["copysign"] = "F64::copysign";
170 }
171
~RustInstVisitor()172 virtual ~RustInstVisitor() {}
173
visit(DeclareVarInst * inst)174 virtual void visit(DeclareVarInst* inst)
175 {
176 if (inst->fAddress->getAccess() & Address::kStaticStruct) {
177 *fOut << "static mut ";
178 }
179
180 if (inst->fAddress->getAccess() & Address::kStack || inst->fAddress->getAccess() & Address::kLoop) {
181 *fOut << "let mut ";
182 }
183
184 // If type is kNoType, only generate the name, otherwise a typed expression
185 if (inst->fType->getType() == Typed::VarType::kNoType) {
186 *fOut << inst->fAddress->getName();
187 } else {
188 *fOut << fTypeManager->generateType(inst->fType, inst->fAddress->getName());
189 }
190
191 if (inst->fValue) {
192 *fOut << " = ";
193 inst->fValue->accept(this);
194 } else if (inst->fAddress->getAccess() & Address::kStaticStruct) {
195 *fOut << " = ";
196 RustInitFieldsVisitor::ZeroInitializer(fOut, inst->fType);
197 }
198
199 EndLine((inst->fAddress->getAccess() & Address::kStruct) ? ',' : ';');
200 }
201
visit(DeclareBufferIterators * inst)202 virtual void visit(DeclareBufferIterators* inst)
203 {
204 /* Generates an expression like:
205 let (outputs0, outputs1) = if let [outputs0, outputs1, ..] = outputs {
206 let outputs0 = outputs0[..count as usize].iter_mut();
207 let outputs1 = outputs1[..count as usize].iter_mut();
208 (outputs0, outputs1)
209 } else {
210 panic!("wrong number of outputs");
211 };
212 */
213
214 // Don't generate if no channels
215 if (inst->fNumChannels == 0) return;
216
217 std::string name = inst->fBufferName2;
218
219 // Build pattern matching + if let line
220 *fOut << "let (";
221 for (int i = 0; i < inst->fNumChannels; ++i) {
222 if (i > 0) {
223 *fOut << ", ";
224 }
225 *fOut << name << i;
226 }
227 *fOut << ") = if let [";
228 for (int i = 0; i < inst->fNumChannels; ++i) {
229 *fOut << name << i << ", ";
230 }
231 *fOut << "..] = " << name << " {";
232
233 // Build fixed size iterator variables
234 fTab++;
235 for (int i = 0; i < inst->fNumChannels; ++i) {
236 tab(fTab, *fOut);
237 *fOut << "let " << name << i << " = " << name << i << "[..count as usize]";
238 if (inst->fMutable) {
239 *fOut << ".iter_mut();";
240 } else {
241 *fOut << ".iter();";
242 }
243 }
244
245 // Build return tuple
246 tab(fTab, *fOut);
247 *fOut << "(";
248 for (int i = 0; i < inst->fNumChannels; ++i) {
249 if (i > 0) {
250 *fOut << ", ";
251 }
252 *fOut << name << i;
253 }
254 *fOut << ")";
255
256 // Build else branch
257 fTab--;
258 tab(fTab, *fOut);
259 *fOut << "} else {";
260
261 fTab++;
262 tab(fTab, *fOut);
263 *fOut << "panic!(\"wrong number of " << name << "\");";
264
265 fTab--;
266 tab(fTab, *fOut);
267 *fOut << "};";
268 tab(fTab, *fOut);
269 }
270
visit(DeclareFunInst * inst)271 virtual void visit(DeclareFunInst* inst)
272 {
273 // Already generated
274 if (gFunctionSymbolTable.find(inst->fName) != gFunctionSymbolTable.end()) {
275 return;
276 } else {
277 gFunctionSymbolTable[inst->fName] = true;
278 }
279
280 // Only generates additional functions
281 if (fMathLibTable.find(inst->fName) == fMathLibTable.end()) {
282 // Prototype
283 // Since functions are attached to a trait they must not be prefixed with "pub".
284 // In case we need a mechanism to attach functions to both traits and normal
285 // impls, we need a mechanism to forward the information whether to use "pub"
286 // or not. In the worst case, we have to prefix the name string like "pub fname",
287 // and handle the prefix here.
288 *fOut << "fn " << inst->fName;
289 generateFunDefArgs(inst);
290 generateFunDefBody(inst);
291 }
292 }
293
generateFunDefBody(DeclareFunInst * inst)294 virtual void generateFunDefBody(DeclareFunInst* inst)
295 {
296 *fOut << ") -> " << fTypeManager->generateType(inst->fType->fResult);
297 if (inst->fCode->fCode.size() == 0) {
298 *fOut << ";" << endl; // Pure prototype
299 } else {
300 // Function body
301 *fOut << " {";
302 fTab++;
303 tab(fTab, *fOut);
304 inst->fCode->accept(this);
305 fTab--;
306 back(1, *fOut);
307 *fOut << "}";
308 tab(fTab, *fOut);
309 }
310 }
311
visit(RetInst * inst)312 virtual void visit(RetInst* inst)
313 {
314 if (inst->fResult) {
315 inst->fResult->accept(this);
316 } else {
317 *fOut << "return";
318 EndLine();
319 }
320 }
321
visit(NamedAddress * named)322 virtual void visit(NamedAddress* named)
323 {
324 if (named->getAccess() & Address::kStruct) {
325 if (named->getAccess() & Address::kReference && named->getAccess() & Address::kMutable) {
326 *fOut << "&mut self.";
327 } else {
328 *fOut << "self.";
329 }
330 } else if (named->getAccess() & Address::kStaticStruct) {
331 if (named->getAccess() & Address::kReference && named->getAccess() & Address::kMutable) {
332 *fOut << "&mut ";
333 }
334 }
335 *fOut << named->getName();
336 }
337
visit(IndexedAddress * indexed)338 virtual void visit(IndexedAddress* indexed)
339 {
340 indexed->fAddress->accept(this);
341 if (dynamic_cast<Int32NumInst*>(indexed->fIndex)) {
342 *fOut << "[";
343 indexed->fIndex->accept(this);
344 *fOut << "]";
345 } else {
346 // Array index expression casted to 'usize' type
347 *fOut << "[";
348 indexed->fIndex->accept(this);
349 *fOut << " as usize]";
350 }
351 }
352
visit(LoadVarInst * inst)353 virtual void visit(LoadVarInst* inst)
354 {
355 if (inst->fAddress->getAccess() & Address::kStaticStruct) {
356 *fOut << "unsafe { ";
357 }
358 inst->fAddress->accept(this);
359 if (inst->fAddress->getAccess() & Address::kStaticStruct) {
360 *fOut << " }";
361 }
362 }
363
visit(LoadVarAddressInst * inst)364 virtual void visit(LoadVarAddressInst* inst)
365 {
366 *fOut << "&";
367 inst->fAddress->accept(this);
368 }
369
visit(FloatArrayNumInst * inst)370 virtual void visit(FloatArrayNumInst* inst)
371 {
372 char sep = '[';
373 for (size_t i = 0; i < inst->fNumTable.size(); i++) {
374 *fOut << sep << checkFloat(inst->fNumTable[i]);
375 sep = ',';
376 }
377 *fOut << ']';
378 }
379
visit(Int32ArrayNumInst * inst)380 virtual void visit(Int32ArrayNumInst* inst)
381 {
382 char sep = '[';
383 for (size_t i = 0; i < inst->fNumTable.size(); i++) {
384 *fOut << sep << inst->fNumTable[i];
385 sep = ',';
386 }
387 *fOut << ']';
388 }
389
visit(DoubleArrayNumInst * inst)390 virtual void visit(DoubleArrayNumInst* inst)
391 {
392 char sep = '[';
393 for (size_t i = 0; i < inst->fNumTable.size(); i++) {
394 *fOut << sep << checkDouble(inst->fNumTable[i]);
395 sep = ',';
396 }
397 *fOut << ']';
398 }
399
visit(BinopInst * inst)400 virtual void visit(BinopInst* inst)
401 {
402 // Special case for 'logical right-shift'
403 if (strcmp(gBinOpTable[inst->fOpcode]->fName, ">>>") == 0) {
404 TypingVisitor typing;
405 inst->fInst1->accept(&typing);
406 *fOut << "(((";
407 inst->fInst1->accept(this);
408 if (isInt64Type(typing.fCurType)) {
409 *fOut << " as u64)";
410 } else if (isInt32Type(typing.fCurType)) {
411 *fOut << " as u32)";
412 } else {
413 faustassert(false);
414 }
415 *fOut << " >> ";
416 inst->fInst2->accept(this);
417 *fOut << ")";
418 if (isInt64Type(typing.fCurType)) {
419 *fOut << " as i64)";
420 } else if (isInt32Type(typing.fCurType)) {
421 *fOut << " as i32)";
422 } else {
423 faustassert(false);
424 }
425 } else {
426 TextInstVisitor::visit(inst);
427 }
428 }
429
visit(::CastInst * inst)430 virtual void visit(::CastInst* inst)
431 {
432 *fOut << "(";
433 inst->fInst->accept(this);
434 *fOut << " as " << fTypeManager->generateType(inst->fType);
435 *fOut << ")";
436 }
437
visit(BitcastInst * inst)438 virtual void visit(BitcastInst* inst) { faustassert(false); }
439
visit(FunCallInst * inst)440 virtual void visit(FunCallInst* inst)
441 {
442 if (fMathLibTable.find(inst->fName) != fMathLibTable.end()) {
443 generateFunCall(inst, fMathLibTable[inst->fName]);
444 } else {
445 generateFunCall(inst, inst->fName);
446 }
447 }
448
generateFunCall(FunCallInst * inst,const std::string & fun_name)449 virtual void generateFunCall(FunCallInst* inst, const std::string& fun_name)
450 {
451 if (inst->fMethod) {
452 list<ValueInst*>::const_iterator it = inst->fArgs.begin();
453 // Compile object arg
454 (*it)->accept(this);
455 // Compile parameters
456 *fOut << fObjectAccess;
457 // Hack for 1 FIR generated names
458 if (startWith(fun_name, "instanceInit")) {
459 *fOut << "instance_init" << fun_name.substr(12) << "(";
460 } else {
461 *fOut << fun_name << "(";
462 }
463 generateFunCallArgs(++it, inst->fArgs.end(), int(inst->fArgs.size()) - 1);
464 } else {
465 *fOut << fun_name << "(";
466 // Compile parameters
467 generateFunCallArgs(inst->fArgs.begin(), inst->fArgs.end(), int(inst->fArgs.size()));
468 // Hack for 'log' function that needs a base
469 if (fun_name == "F32::log") {
470 *fOut << ", std::f32::consts::E";
471 } else if (fun_name == "F64::log") {
472 *fOut << ", std::f64::consts::E";
473 }
474 }
475 *fOut << ")";
476 }
477
visit(Select2Inst * inst)478 virtual void visit(Select2Inst* inst)
479 {
480 *fOut << "if (";
481 inst->fCond->accept(this);
482 // Force 'cond' to bool type
483 *fOut << " as i32 != 0) { ";
484 inst->fThen->accept(this);
485 *fOut << " } else { ";
486 inst->fElse->accept(this);
487 *fOut << " }";
488 }
489
visit(IfInst * inst)490 virtual void visit(IfInst* inst)
491 {
492 *fOut << "if (";
493 inst->fCond->accept(this);
494 // Force 'cond' to bool type
495 *fOut << " as i32 == 1) { ";
496 fTab++;
497 tab(fTab, *fOut);
498 inst->fThen->accept(this);
499 fTab--;
500 back(1, *fOut);
501 if (inst->fElse->fCode.size() > 0) {
502 *fOut << "} else {";
503 fTab++;
504 tab(fTab, *fOut);
505 inst->fElse->accept(this);
506 fTab--;
507 back(1, *fOut);
508 *fOut << "}";
509 } else {
510 *fOut << "}";
511 }
512 tab(fTab, *fOut);
513 }
514
visit(ForLoopInst * inst)515 virtual void visit(ForLoopInst* inst)
516 {
517 // Don't generate empty loops...
518 if (inst->fCode->size() == 0) return;
519
520 inst->fInit->accept(this);
521 *fOut << "loop {";
522 fTab++;
523 tab(fTab, *fOut);
524 inst->fCode->accept(this);
525 inst->fIncrement->accept(this);
526 *fOut << "if ";
527 inst->fEnd->accept(this);
528 *fOut << " { continue; } else { break; }";
529 fTab--;
530 tab(fTab, *fOut);
531 *fOut << "}";
532 tab(fTab, *fOut);
533 }
534
visit(SimpleForLoopInst * inst)535 virtual void visit(SimpleForLoopInst* inst)
536 {
537 // Don't generate empty loops...
538 if (inst->fCode->size() == 0) return;
539
540 *fOut << "for " << inst->getName() << " in ";
541 if (inst->fReverse) {
542 *fOut << "(";
543 inst->fLowerBound->accept(this);
544 *fOut << "..=";
545 inst->fUpperBound->accept(this);
546 *fOut << ").rev()";
547 } else {
548 inst->fLowerBound->accept(this);
549 *fOut << "..";
550 inst->fUpperBound->accept(this);
551 }
552 *fOut << " {";
553 fTab++;
554 tab(fTab, *fOut);
555 inst->fCode->accept(this);
556 fTab--;
557 back(1, *fOut);
558 *fOut << "}";
559 tab(fTab, *fOut);
560 }
561
visit(IteratorForLoopInst * inst)562 virtual void visit(IteratorForLoopInst* inst)
563 {
564 // Don't generate empty loops...
565 if (inst->fCode->size() == 0) return;
566
567 *fOut << "let zipped_iterators = ";
568 for (std::size_t i = 0; i < inst->fIterators.size(); ++i) {
569 if (i == 0) {
570 inst->fIterators[i]->accept(this);
571 } else {
572 *fOut << ".zip(";
573 inst->fIterators[i]->accept(this);
574 *fOut << ")";
575 }
576 }
577 *fOut << ";";
578 tab(fTab, *fOut);
579
580 *fOut << "for ";
581 for (std::size_t i = 0; i < inst->fIterators.size() - 1; ++i) {
582 *fOut << "(";
583 }
584 *fOut << makeNameSingular(inst->fIterators[0]->getName());
585 for (std::size_t i = 1; i < inst->fIterators.size(); ++i) {
586 *fOut << ", " << makeNameSingular(inst->fIterators[i]->getName()) << ")";
587 }
588 *fOut << " in zipped_iterators {";
589 fTab++;
590 tab(fTab, *fOut);
591 inst->fCode->accept(this);
592 fTab--;
593 back(1, *fOut);
594 *fOut << "}";
595 tab(fTab, *fOut);
596 }
597
visit(::SwitchInst * inst)598 virtual void visit(::SwitchInst* inst)
599 {
600 *fOut << "match (";
601 inst->fCond->accept(this);
602 *fOut << ") {";
603 fTab++;
604 tab(fTab, *fOut);
605 for (const auto& it : inst->fCode) {
606 if (it.first == -1) { // -1 used to code "default" case
607 *fOut << "_ => {";
608 } else {
609 *fOut << it.first << " => {";
610 }
611 fTab++;
612 tab(fTab, *fOut);
613 (it.second)->accept(this);
614 fTab--;
615 back(1, *fOut);
616 *fOut << "},";
617 tab(fTab, *fOut);
618 }
619 fTab--;
620 back(1, *fOut);
621 *fOut << "} ";
622 tab(fTab, *fOut);
623 }
624
cleanup()625 static void cleanup() { gFunctionSymbolTable.clear(); }
626 };
627
628 /**
629 * Helper visitor that allows to build a parameter lookup table.
630 */
631 class UserInterfaceParameterMapping : public InstVisitor {
632 private:
633 map<string, int> fParameterLookup;
634 int fParameterIndex;
635
636 public:
637 using InstVisitor::visit;
638
UserInterfaceParameterMapping()639 UserInterfaceParameterMapping()
640 : InstVisitor(), fParameterLookup{}, fParameterIndex{0}
641 {}
642
~UserInterfaceParameterMapping()643 virtual ~UserInterfaceParameterMapping() {}
644
getParameterLookup()645 map<string, int> getParameterLookup() {
646 return fParameterLookup;
647 }
648
visit(BlockInst * inst)649 virtual void visit(BlockInst* inst)
650 {
651 // BlockInst visitor is unimplemented in base class, so we need a trivial implementation
652 // to actually visit the user interface statements in the BlockInst.
653 for (const auto& it : inst->fCode) {
654 it->accept(this);
655 }
656 }
657
visit(AddMetaDeclareInst * inst)658 virtual void visit(AddMetaDeclareInst* inst)
659 {
660 // Only store fZone's value if it is not the 0 / nullptr special case
661 if (inst->fZone != "0") {
662 if (fParameterLookup.find(inst->fZone) == fParameterLookup.end()) {
663 fParameterLookup[inst->fZone] = fParameterIndex++;
664 }
665 }
666 }
667
visit(AddButtonInst * inst)668 virtual void visit(AddButtonInst* inst)
669 {
670 if (fParameterLookup.find(inst->fZone) == fParameterLookup.end()) {
671 fParameterLookup[inst->fZone] = fParameterIndex++;
672 }
673 }
674
visit(AddSliderInst * inst)675 virtual void visit(AddSliderInst* inst)
676 {
677 if (fParameterLookup.find(inst->fZone) == fParameterLookup.end()) {
678 fParameterLookup[inst->fZone] = fParameterIndex++;
679 }
680 }
681
visit(AddBargraphInst * inst)682 virtual void visit(AddBargraphInst* inst)
683 {
684 if (fParameterLookup.find(inst->fZone) == fParameterLookup.end()) {
685 fParameterLookup[inst->fZone] = fParameterIndex++;
686 }
687 }
688
689 };
690
691 /**
692 * Visitor for building user interface instructions based on the parameter lookup table.
693 */
694 class RustUIInstVisitor : public TextInstVisitor {
695 private:
696 map<string, int> fParameterLookup;
697
getParameterIndex(string name)698 int getParameterIndex(string name) {
699 auto parameterIndex = fParameterLookup.find(name);
700 if (parameterIndex == fParameterLookup.end()) {
701 throw runtime_error("Parameter '" + name + "' is unknown");
702 } else {
703 return parameterIndex->second;
704 }
705 }
706
707 public:
708 using TextInstVisitor::visit;
709
RustUIInstVisitor(std::ostream * out,const string & structname,map<string,int> parameterLookup,int tab=0)710 RustUIInstVisitor(std::ostream* out, const string& structname, map<string, int> parameterLookup, int tab = 0)
711 : TextInstVisitor(out, ".", new RustStringTypeManager(xfloat(), "&"), tab),
712 fParameterLookup{parameterLookup}
713 {}
714
~RustUIInstVisitor()715 virtual ~RustUIInstVisitor()
716 {}
717
visit(AddMetaDeclareInst * inst)718 virtual void visit(AddMetaDeclareInst* inst)
719 {
720 // Special case
721 if (inst->fZone == "0") {
722 *fOut << "ui_interface.declare(None, " << quote(inst->fKey) << ", " << quote(inst->fValue)
723 << ")";
724 } else {
725 *fOut << "ui_interface.declare(Some(ParamIndex(" << getParameterIndex(inst->fZone) << ")), " << quote(inst->fKey) << ", "
726 << quote(inst->fValue) << ")";
727 }
728 EndLine();
729 }
730
visit(OpenboxInst * inst)731 virtual void visit(OpenboxInst* inst)
732 {
733 string name;
734 switch (inst->fOrient) {
735 case OpenboxInst::kVerticalBox:
736 name = "ui_interface.open_vertical_box(";
737 break;
738 case OpenboxInst::kHorizontalBox:
739 name = "ui_interface.open_horizontal_box(";
740 break;
741 case OpenboxInst::kTabBox:
742 name = "ui_interface.open_tab_box(";
743 break;
744 }
745 *fOut << name << quote(inst->fName) << ")";
746 EndLine();
747 }
748
visit(CloseboxInst * inst)749 virtual void visit(CloseboxInst* inst)
750 {
751 *fOut << "ui_interface.close_box();";
752 tab(fTab, *fOut);
753 }
754
visit(AddButtonInst * inst)755 virtual void visit(AddButtonInst* inst)
756 {
757 if (inst->fType == AddButtonInst::kDefaultButton) {
758 *fOut << "ui_interface.add_button(" << quote(inst->fLabel) << ", ParamIndex(" << getParameterIndex(inst->fZone) << "))";
759 } else {
760 *fOut << "ui_interface.add_check_button(" << quote(inst->fLabel) << ", ParamIndex(" << getParameterIndex(inst->fZone) << "))";
761 }
762 EndLine();
763 }
764
visit(AddSliderInst * inst)765 virtual void visit(AddSliderInst* inst)
766 {
767 string name;
768 switch (inst->fType) {
769 case AddSliderInst::kHorizontal:
770 name = "ui_interface.add_horizontal_slider";
771 break;
772 case AddSliderInst::kVertical:
773 name = "ui_interface.add_vertical_slider";
774 break;
775 case AddSliderInst::kNumEntry:
776 name = "ui_interface.add_num_entry";
777 break;
778 }
779 *fOut << name << "(" << quote(inst->fLabel) << ", "
780 << "ParamIndex(" << getParameterIndex(inst->fZone) << "), " << checkReal(inst->fInit) << ", " << checkReal(inst->fMin) << ", "
781 << checkReal(inst->fMax) << ", " << checkReal(inst->fStep) << ")";
782 EndLine();
783 }
784
visit(AddBargraphInst * inst)785 virtual void visit(AddBargraphInst* inst)
786 {
787 string name;
788 switch (inst->fType) {
789 case AddBargraphInst::kHorizontal:
790 name = "ui_interface.add_horizontal_bargraph";
791 break;
792 case AddBargraphInst::kVertical:
793 name = "ui_interface.add_vertical_bargraph";
794 break;
795 }
796 *fOut << name << "(" << quote(inst->fLabel) << ", ParamIndex(" << getParameterIndex(inst->fZone) << "), " << checkReal(inst->fMin)
797 << ", " << checkReal(inst->fMax) << ")";
798 EndLine();
799 }
800
visit(AddSoundfileInst * inst)801 virtual void visit(AddSoundfileInst* inst)
802 {
803 // Not supported for now
804 throw faustexception("ERROR : 'soundfile' primitive not yet supported for Rust\n");
805 }
806 };
807
808 #endif
809