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 /*****************************************************************************
23 ******************************************************************************
24 LIST
25 Y. Orlarey, (c) Grame 2002
26 ------------------------------------------------------------------------------
27 This file contains several extensions to the tree library :
28 - lists : based on a operations like cons, hd , tl, ...
29 - environments : list of associations (key value)
30 - property list : used to annotate trees
31
32
33 API:
34 ----
35
36 List :
37 -----
38
39 nil = predefined empty list
40 cons (x,l) = create a nex list of head x and tail l
41 hd(cons(x,l)) = x,
42 tl (cons(x,l)) = l
43 nth(l,i) = ith element of l (or nil)
44 replace(l,i,e) = a copy of l where the ith element is e
45 len(l) = number of elements of l
46 isNil(nil) = true (false otherwise)
47 isList(cons(x,l)) = true (false otherwise)
48 list(a,b,..) = cons(a, list(b,...))
49
50 lmap(f, cons(x,l)) = cons(f(x), lmap(f,l))
51 reverse([a,b,..,z]) = [z,..,b,a]
52 reverseall([a,b,..,z]) = [ra(z),..,ra(b),ra(a)] where ra is reverseall
53
54 Set :
55 -----
56 (Sets are implemented as ordered lists of elements without duplication)
57
58 isElement(e,s) = true if e is an element of set s, false otherwise
59 addElement(e,s) = s U {e}
60 remElement(e,s) = s - {e}
61 singleton(e) = {e}
62 list2set(l) = convert a list into a set
63 setUnion(s1,s2) = s1 U s2
64 setIntersection(s1,s2) = s1 intersection s2
65 setDifference(s1,s2) = s1 - s2
66
67 Environment :
68 -------------
69
70 An 'environment' is a stack of pairs (key x value) used to keep track of lexical bindings
71
72 pushEnv (key, val, env) -> env' create a new environment
73 searchEnv (key,&v,env) -> bool search for key in env and set v accordingly
74
75 search(k1,&v, push(k2,x,env)) = true and v is set to x if k1==k2
76 = search(k1,&v,env) if k1 != k2
77 Property list :
78 ---------------
79
80 Every tree can be annotated with an 'attribut' field. This attribute field
81 can be used to manage a property list (pl). A property list is a list of pairs
82 key x value, with three basic operations :
83
84 setProperty (t, key, val) -> t add the association (key x val) to the pl of t
85 getProperty (t, key, &val) -> bool search the pp of t for the value associated to key
86 remProperty (t, key) -> t remove any association (key x ?) from the pl of t
87
88 Warning :
89 ---------
90 Since reference counters are used for garbage collecting, one must be careful not to
91 create cycles in trees. The only possible source of cycles is by setting the attribut
92 of a tree t to a tree t' that contains t as a subtree.
93
94 History :
95 ---------
96 2002-02-08 : First version
97 2002-02-20 : New description of the API, non recursive lmap and reverse
98 2002-03-29 : Added function remElement(e,set), corrected comment error
99
100 ******************************************************************************
101 *****************************************************************************/
102
103 #include "list.hh"
104 #include <stdlib.h>
105 #include <cstdlib>
106 #include <map>
107 #include "compatibility.hh"
108 #include "global.hh"
109 #include "property.hh"
110
cons(Tree a,Tree b)111 Tree cons(Tree a, Tree b)
112 {
113 return tree(gGlobal->CONS, a, b);
114 }
list0()115 Tree list0()
116 {
117 return gGlobal->nil;
118 }
119
isNil(Tree l)120 bool isNil(Tree l)
121 {
122 return (l->node() == Node(gGlobal->NIL)) && (l->arity() == 0);
123 }
isList(Tree l)124 bool isList(Tree l)
125 {
126 return (l->node() == Node(gGlobal->CONS)) && (l->arity() == 2);
127 }
128
129 //------------------------------------------------------------------------------
130 // Printing of trees with special case for lists
131 //------------------------------------------------------------------------------
132
printlist(Tree l,FILE * out)133 static bool printlist(Tree l, FILE* out)
134 {
135 if (isList(l)) {
136 char sep = '(';
137
138 do {
139 fputc(sep, out);
140 sep = ',';
141 print(hd(l));
142 l = tl(l);
143 } while (isList(l));
144
145 if (!isNil(l)) {
146 fprintf(out, " . ");
147 print(l, out);
148 }
149
150 fputc(')', out);
151 return true;
152
153 } else if (isNil(l)) {
154 fprintf(out, "nil");
155 return true;
156
157 } else {
158 return false;
159 }
160 }
161
print(Tree t,FILE * out)162 void print(Tree t, FILE* out)
163 {
164 int i;
165 double f;
166 Sym s;
167 void* p;
168
169 if (printlist(t, out)) return;
170
171 Node n = t->node();
172 if (isInt(n, &i))
173 fprintf(out, "%d", i);
174 else if (isDouble(n, &f))
175 fprintf(out, "%f", f);
176 else if (isSym(n, &s))
177 fprintf(out, "%s", name(s));
178 else if (isPointer(n, &p))
179 fprintf(out, "#%p", p);
180
181 int k = t->arity();
182 if (k > 0) {
183 char sep = '[';
184 for (int i1 = 0; i1 < k; i1++) {
185 fputc(sep, out);
186 sep = ',';
187 print(t->branch(i1), out);
188 }
189 fputc(']', out);
190 }
191 }
192
193 //------------------------------------------------------------------------------
194 // Elements of list
195 //------------------------------------------------------------------------------
196
nth(Tree l,int i)197 Tree nth(Tree l, int i)
198 {
199 while (isList(l)) {
200 if (i == 0) return hd(l);
201 l = tl(l);
202 i--;
203 }
204 return gGlobal->nil;
205 }
206
replace(Tree l,int i,Tree e)207 Tree replace(Tree l, int i, Tree e)
208 {
209 return (i == 0) ? cons(e, tl(l)) : cons(hd(l), replace(tl(l), i - 1, e));
210 }
211
len(Tree l)212 int len(Tree l)
213 {
214 int n = 0;
215 while (isList(l)) {
216 l = tl(l);
217 n++;
218 }
219 return n;
220 }
221
222 //------------------------------------------------------------------------------
223 // Mapping and reversing
224 //------------------------------------------------------------------------------
225
rconcat(Tree l,Tree q)226 Tree rconcat(Tree l, Tree q)
227 {
228 while (isList(l)) {
229 q = cons(hd(l), q);
230 l = tl(l);
231 }
232 return q;
233 }
234
concat(Tree l,Tree q)235 Tree concat(Tree l, Tree q)
236 {
237 return rconcat(reverse(l), q);
238 }
239
lrange(Tree l,int i,int j)240 Tree lrange(Tree l, int i, int j)
241 {
242 Tree r = gGlobal->nil;
243 int c = j;
244 while (c > i) r = cons(nth(l, --c), r);
245 return r;
246 }
247
248 //------------------------------------------------------------------------------
249 // Mapping and reversing
250 //------------------------------------------------------------------------------
251
rmap(tfun f,Tree l)252 static Tree rmap(tfun f, Tree l)
253 {
254 Tree r = gGlobal->nil;
255 while (isList(l)) {
256 r = cons(f(hd(l)), r);
257 l = tl(l);
258 }
259 return r;
260 }
261
reverse(Tree l)262 Tree reverse(Tree l)
263 {
264 Tree r = gGlobal->nil;
265 while (isList(l)) {
266 r = cons(hd(l), r);
267 l = tl(l);
268 }
269 return r;
270 }
271
lmap(tfun f,Tree l)272 Tree lmap(tfun f, Tree l)
273 {
274 return reverse(rmap(f, l));
275 }
276
reverseall(Tree l)277 Tree reverseall(Tree l)
278 {
279 return isList(l) ? rmap(reverseall, l) : l;
280 }
281
282 //------------------------------------------------------------------------------
283 // Sets : implemented as ordered list
284 //------------------------------------------------------------------------------
285
isElement(Tree e,Tree l)286 bool isElement(Tree e, Tree l)
287 {
288 while (isList(l)) {
289 if (hd(l) == e) return true;
290 if (hd(l) > e) return false;
291 l = tl(l);
292 }
293 return false;
294 }
295
addElement(Tree e,Tree l)296 Tree addElement(Tree e, Tree l)
297 {
298 if (isList(l)) {
299 if (e < hd(l)) {
300 return cons(e, l);
301 } else if (e == hd(l)) {
302 return l;
303 } else {
304 return cons(hd(l), addElement(e, tl(l)));
305 }
306 } else {
307 return cons(e, gGlobal->nil);
308 }
309 }
310
remElement(Tree e,Tree l)311 Tree remElement(Tree e, Tree l)
312 {
313 if (isList(l)) {
314 if (e < hd(l)) {
315 return l;
316 } else if (e == hd(l)) {
317 return tl(l);
318 } else {
319 return cons(hd(l), remElement(e, tl(l)));
320 }
321 } else {
322 return gGlobal->nil;
323 }
324 }
325
singleton(Tree e)326 Tree singleton(Tree e)
327 {
328 return list1(e);
329 }
330
list2set(Tree l)331 Tree list2set(Tree l)
332 {
333 Tree s = gGlobal->nil;
334 while (isList(l)) {
335 s = addElement(hd(l), s);
336 l = tl(l);
337 }
338 return s;
339 }
340
setUnion(Tree A,Tree B)341 Tree setUnion(Tree A, Tree B)
342 {
343 if (isNil(A)) return B;
344 if (isNil(B)) return A;
345
346 if (hd(A) == hd(B)) return cons(hd(A), setUnion(tl(A), tl(B)));
347 if (hd(A) < hd(B)) return cons(hd(A), setUnion(tl(A), B));
348 /* hd(A) > hd(B) */ return cons(hd(B), setUnion(A, tl(B)));
349 }
350
setIntersection(Tree A,Tree B)351 Tree setIntersection(Tree A, Tree B)
352 {
353 if (isNil(A)) return A;
354 if (isNil(B)) return B;
355 if (hd(A) == hd(B)) return cons(hd(A), setIntersection(tl(A), tl(B)));
356 if (hd(A) < hd(B)) return setIntersection(tl(A), B);
357 /* (hd(A) > hd(B)*/ return setIntersection(A, tl(B));
358 }
359
setDifference(Tree A,Tree B)360 Tree setDifference(Tree A, Tree B)
361 {
362 if (isNil(A)) return A;
363 if (isNil(B)) return A;
364 if (hd(A) == hd(B)) return setDifference(tl(A), tl(B));
365 if (hd(A) < hd(B)) return cons(hd(A), setDifference(tl(A), B));
366 /* (hd(A) > hd(B)*/ return setDifference(A, tl(B));
367 }
368
369 //------------------------------------------------------------------------------
370 // Environments
371 //------------------------------------------------------------------------------
372
pushEnv(Tree key,Tree val,Tree env)373 Tree pushEnv(Tree key, Tree val, Tree env)
374 {
375 return cons(cons(key, val), env);
376 }
377
searchEnv(Tree key,Tree & v,Tree env)378 bool searchEnv(Tree key, Tree& v, Tree env)
379 {
380 while (isList(env)) {
381 if (hd(hd(env)) == key) {
382 v = tl(hd(env));
383 return true;
384 }
385 env = tl(env);
386 }
387 return false;
388 }
389
390 #if 0
391
392 //------------------------------------------------------------------------------
393 // Property list
394 //------------------------------------------------------------------------------
395
396 static bool findKey (Tree pl, Tree key, Tree& val)
397 {
398 if (isNil(pl)) return false;
399 if (left(hd(pl)) == key) { val= right(hd(pl)); return true; }
400 /* left(hd(pl)) != key */ return findKey (tl(pl), key, val);
401 }
402
403 static Tree updateKey (Tree pl, Tree key, Tree val)
404 {
405 if (isNil(pl)) return cons ( cons(key,val), gGlobal->nil );
406 if (left(hd(pl)) == key) return cons ( cons(key,val), tl(pl) );
407 /* left(hd(pl)) != key */ return cons ( hd(pl), updateKey( tl(pl), key, val ));
408 }
409
410 static Tree removeKey (Tree pl, Tree key)
411 {
412 if (isNil(pl)) return gGlobal->nil;
413 if (left(hd(pl)) == key) return tl(pl);
414 /* left(hd(pl)) != key */ return cons (hd(pl), removeKey(tl(pl), key));
415 }
416
417 #endif
418
419 #if 0
420 void setProperty (Tree t, Tree key, Tree val)
421 {
422 CTree* pl = t->attribut();
423 if (pl) t->attribut(updateKey(pl, key, val));
424 else t->attribut(updateKey(gGlobal->nil, key, val));
425 }
426
427 void remProperty (Tree t, Tree key)
428 {
429 CTree* pl = t->attribut();
430 if (pl) t->attribut(removeKey(pl, key));
431 }
432
433 bool getProperty (Tree t, Tree key, Tree& val)
434 {
435 CTree* pl = t->attribut();
436 if (pl) return findKey(pl, key, val);
437 else return false;
438 }
439
440 #else
441 // nouvelle implementation
setProperty(Tree t,Tree key,Tree val)442 void setProperty(Tree t, Tree key, Tree val)
443 {
444 t->setProperty(key, val);
445 }
446
getProperty(Tree t,Tree key,Tree & val)447 bool getProperty(Tree t, Tree key, Tree& val)
448 {
449 CTree* pl = t->getProperty(key);
450 if (pl) {
451 val = pl;
452 return true;
453 } else {
454 return false;
455 }
456 }
457
remProperty(Tree t,Tree key)458 void remProperty(Tree t, Tree key)
459 {
460 throw faustexception("ERROR : remProperty not implemented\n");
461 }
462 #endif
463
464 //------------------------------------------------------------------------------
465 // Bottom Up Tree Mapping
466 //------------------------------------------------------------------------------
467
tmap(Tree key,tfun f,Tree t)468 Tree tmap(Tree key, tfun f, Tree t)
469 {
470 // printf("start tmap\n");
471 Tree p;
472
473 if (getProperty(t, key, p)) {
474 return (isNil(p)) ? t : p; // truc pour eviter les boucles
475
476 } else {
477 tvec br;
478 int n = t->arity();
479 for (int i = 0; i < n; i++) {
480 br.push_back(tmap(key, f, t->branch(i)));
481 }
482
483 Tree r1 = tree(t->node(), br);
484
485 Tree r2 = f(r1);
486 if (r2 == t) {
487 setProperty(t, key, gGlobal->nil);
488 } else {
489 setProperty(t, key, r2);
490 }
491 return r2;
492 }
493 }
494
495 //------------------------------------------------------------------------------
496 // substitute :remplace toutes les occurences de 'id' par 'val' dans 't'
497 //------------------------------------------------------------------------------
498
499 // genere une clef unique propre � cette substitution
substkey(Tree t,Tree id,Tree val)500 static Tree substkey(Tree t, Tree id, Tree val)
501 {
502 char name[256];
503 snprintf(name, 255, "SUBST<%p,%p,%p> : ", (void*)(CTree*)t, (void*)(CTree*)id, (void*)(CTree*)val);
504 return tree(unique(name));
505 }
506
507 // realise la substitution proprement dite tout en mettant a jour la propriete
508 // pour ne pas avoir a la calculer deux fois
509
subst(Tree t,Tree propkey,Tree id,Tree val)510 static Tree subst(Tree t, Tree propkey, Tree id, Tree val)
511 {
512 Tree p;
513
514 if (t == id) {
515 return val;
516
517 } else if (t->arity() == 0) {
518 return t;
519 } else if (getProperty(t, propkey, p)) {
520 return (isNil(p)) ? t : p;
521 } else {
522 tvec br;
523 int n = t->arity();
524 for (int i = 0; i < n; i++) {
525 br.push_back(subst(t->branch(i), propkey, id, val));
526 }
527
528 Tree r = tree(t->node(), br);
529
530 if (r == t) {
531 setProperty(t, propkey, gGlobal->nil);
532 } else {
533 setProperty(t, propkey, r);
534 }
535 return r;
536 }
537 }
538
539 // remplace toutes les occurences de 'id' par 'val' dans 't'
substitute(Tree t,Tree id,Tree val)540 Tree substitute(Tree t, Tree id, Tree val)
541 {
542 return subst(t, substkey(t, id, val), id, val);
543 }
544