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 <stdio.h>
23 #include <stdlib.h>
24 #include <string.h>
25 #include <iomanip>
26 #include <iostream>
27 #include <limits>
28 #include <sstream>
29 #include <string>
30 #include <vector>
31 #include <algorithm>
32
33 #include "Text.hh"
34 #include "compatibility.hh"
35 #include "floats.hh"
36 #include "global.hh"
37
38 static string substitution(const string& model, const vector<string>& args);
39
40 /**
41 * Text substitution. Creates a string by replacing all the $n
42 * occurences in the model string, with the corresponding arguments.
43 * Example : subst("float $0 = $1;", "var", T(10.2))
44 */
subst(const string & model,const vector<string> & args)45 string subst(const string& model, const vector<string>& args)
46 {
47 return substitution(model, args);
48 }
49
subst(const string & model,const string & a0)50 string subst(const string& model, const string& a0)
51 {
52 vector<string> args(10);
53 args[0] = a0;
54 return substitution(model, args);
55 }
56
subst(const string & model,const string & a0,const string & a1)57 string subst(const string& model, const string& a0, const string& a1)
58 {
59 vector<string> args(10);
60 args[0] = a0;
61 args[1] = a1;
62 return substitution(model, args);
63 }
64
subst(const string & model,const string & a0,const string & a1,const string & a2)65 string subst(const string& model, const string& a0, const string& a1, const string& a2)
66 {
67 vector<string> args(10);
68 args[0] = a0;
69 args[1] = a1;
70 args[2] = a2;
71 return substitution(model, args);
72 }
73
subst(const string & model,const string & a0,const string & a1,const string & a2,const string & a3)74 string subst(const string& model, const string& a0, const string& a1, const string& a2, const string& a3)
75 {
76 vector<string> args(10);
77 args[0] = a0;
78 args[1] = a1;
79 args[2] = a2;
80 args[3] = a3;
81 return substitution(model, args);
82 }
83
subst(const string & model,const string & a0,const string & a1,const string & a2,const string & a3,const string & a4)84 string subst(const string& model, const string& a0, const string& a1, const string& a2, const string& a3,
85 const string& a4)
86 {
87 vector<string> args(10);
88 args[0] = a0;
89 args[1] = a1;
90 args[2] = a2;
91 args[3] = a3;
92 args[4] = a4;
93 return substitution(model, args);
94 }
95
subst(const string & model,const string & a0,const string & a1,const string & a2,const string & a3,const string & a4,const string & a5)96 string subst(const string& model, const string& a0, const string& a1, const string& a2, const string& a3,
97 const string& a4, const string& a5)
98 {
99 vector<string> args(10);
100 args[0] = a0;
101 args[1] = a1;
102 args[2] = a2;
103 args[3] = a3;
104 args[4] = a4;
105 args[5] = a5;
106 return substitution(model, args);
107 }
108
subst(const string & model,const string & a0,const string & a1,const string & a2,const string & a3,const string & a4,const string & a5,const string & a6)109 string subst(const string& model, const string& a0, const string& a1, const string& a2, const string& a3,
110 const string& a4, const string& a5, const string& a6)
111 {
112 vector<string> args(10);
113 args[0] = a0;
114 args[1] = a1;
115 args[2] = a2;
116 args[3] = a3;
117 args[4] = a4;
118 args[5] = a5;
119 args[6] = a6;
120 return substitution(model, args);
121 }
122
substitution(const string & model,const vector<string> & args)123 static string substitution(const string& model, const vector<string>& args)
124 {
125 char c;
126 int i = 0, ilast = (int)model.length() - 1;
127 string result;
128 while (i < ilast) {
129 c = model[i++];
130 if (c != '$') {
131 result += c;
132 } else {
133 c = model[i++];
134 if (c >= '0' && c <= '9') {
135 result += args[c - '0'];
136 } else {
137 result += c;
138 }
139 }
140 }
141 if (i == ilast) result += model[i];
142 return result;
143 }
144
T(char * c)145 string T(char* c)
146 {
147 return string(c);
148 }
149
T(int n)150 string T(int n)
151 {
152 char c[64];
153 snprintf(c, 63, "%d", n);
154 return string(c);
155 }
156
T(long n)157 string T(long n)
158 {
159 char c[64];
160 snprintf(c, 63, "%ld", n);
161 return string(c);
162 }
163
164 /**
165 * If needed add a trailing '.0' to the
166 * the textual representation of a floating point number
167 * to avoid confusions with an int.
168 */
ensureFloat(const string & c)169 static string ensureFloat(const string& c)
170 {
171 bool isInt = true;
172 for (size_t i = 0; i < c.size(); i++) {
173 if ((c[i] == '.') || (c[i] == 'e')) {
174 isInt = false;
175 break;
176 }
177 }
178 return (isInt) ? (c + ".0") : c;
179 }
180
181 /**
182 * Special encoding for Julia float numbers, see:
183 * https://docs.julialang.org/en/v1/manual/integers-and-floating-point-numbers/#Floating-Point-Numbers
184 */
encodeJuliaFloat(const string & c,bool & need_suffix)185 static string encodeJuliaFloat(const string& c, bool& need_suffix)
186 {
187 bool isInt = true;
188 string res;
189 for (size_t i = 0; i < c.size(); i++) {
190 if ((c[i] == '.') || (c[i] == 'e')) {
191 isInt = false;
192 }
193 if (c[i] == 'e') {
194 res += 'f';
195 need_suffix = false;
196 } else {
197 res += c[i];
198 }
199 }
200 return (isInt) ? (res + ".0") : res;
201 }
202
203 /**
204 * Convert a REAL (float/double) into a string.
205 * Adjusts the precision p to the needs.
206 */
207 template <typename REAL>
TAux(REAL n)208 static string TAux(REAL n)
209 {
210 stringstream num;
211 num << setprecision(numeric_limits<REAL>::max_digits10) << n;
212 if (gGlobal->gOutputLang == "julia") {
213 bool need_suffix = true;
214 string res = encodeJuliaFloat(num.str(), need_suffix);
215 return (need_suffix) ? (res + inumix()) : res;
216 } else {
217 return ensureFloat(num.str()) + inumix();
218 }
219 }
220
221 /**
222 * Convert a single-precision float into a string.
223 * Adjusts the precision p to the needs.
224 */
T(float n)225 string T(float n) { return TAux<float>(n); }
226
227 /**
228 * Convert a double-precision float into a string.
229 * Adjusts the precision p to the needs.
230 */
T(double n)231 string T(double n) { return TAux<double>(n); }
232
233 /**
234 * remove quotes from a string
235 */
unquote(const string & str)236 string unquote(const string& str)
237 {
238 return (str[0] == '"') ? str.substr(1, str.size() - 2) : str;
239 }
240
241 /**
242 * add quotes to a string
243 */
quote(const string & s)244 string quote(const string& s)
245 {
246 return "\"" + s + "\"";
247 }
248
249 /**
250 * Print n tabs (for indentation purpose)
251 * @param n number of tabs to print
252 * @param fout output stream
253 */
tab(int n,ostream & fout)254 void tab(int n, ostream& fout)
255 {
256 fout << '\n';
257 while (n--) fout << '\t';
258 }
259
back(int n,ostream & fout)260 void back(int n, ostream& fout)
261 {
262 long pos = fout.tellp();
263 fout.seekp(pos-n);
264 }
265
266 /**
267 * Print a list of lines
268 * @param n number of tabs of indentation
269 * @param lines list of lines to be printed
270 * @param fout output stream
271 */
printlines(int n,list<string> & lines,ostream & fout,const string & sep)272 void printlines(int n, list<string>& lines, ostream& fout, const string& sep)
273 {
274 list<string>::const_iterator s;
275 for (s = lines.begin(); s != lines.end(); s++) {
276 if (s == lines.begin()) {
277 tab(n, fout);
278 fout << *s; // No separator before first one
279 } else {
280 tab(n, fout);
281 fout << sep << *s;
282 }
283 }
284 }
285
286 /**
287 * rmWhiteSpaces(): Remove the leading and trailing white spaces of a string
288 * (but not those in the middle of the string)
289 */
290
rmWhiteSpaces(const string & s)291 string rmWhiteSpaces(const string& s)
292 {
293 size_t i = s.find_first_not_of(" \t");
294 size_t j = s.find_last_not_of(" \t");
295 if ((i != string::npos) & (j != string::npos)) {
296 return s.substr(i, 1 + j - i);
297 } else {
298 return "";
299 }
300 }
301
302 // 'Quad' (= long double) are currectly treated like 'double'
303
checkReal(double val)304 string checkReal(double val)
305 {
306 return (strcmp(ifloat(), "float") == 0) ? checkFloat(float(val)) : checkDouble(val);
307 }
308
indent(const string & str,int tabs)309 string indent(const string& str, int tabs)
310 {
311 stringstream instream(str);
312 stringstream outstream;
313 string line;
314 while (getline(instream, line, '\n')) {
315 for (int i = 0; i != tabs; ++i) {
316 outstream << '\t';
317 }
318 outstream << line << endl;
319 }
320 return outstream.str();
321 }
322
replaceChar(string str,char src,char dst)323 string replaceChar(string str, char src, char dst)
324 {
325 replace(str.begin(), str.end(), src, dst);
326 return str;
327 }
328
replaceCharList(string str,const vector<char> & ch1,char ch2)329 string replaceCharList(string str, const vector<char>& ch1, char ch2)
330 {
331 vector<char>::const_iterator beg = ch1.begin();
332 vector<char>::const_iterator end = ch1.end();
333 for (size_t i = 0; i < str.length(); ++i) {
334 if (find(beg, end, str[i]) != end) {
335 str[i] = ch2;
336 }
337 }
338 return str;
339 }
340
tokenizeString(const string & str,char sep)341 vector<string> tokenizeString(const string& str, char sep)
342 {
343 vector<string> res;
344 istringstream is(str);
345 string token;
346 while (getline(is, token, sep)) res.push_back(token);
347 return res;
348 }
349
350