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