Merge pull request #506 from andrewcsmith/patch-2
[supercollider.git] / SCClassLibrary / Common / Collections / EnvironmentRedirect.sc
blobae9df4b41dc797253240b2d1dcbe69eb9866d50a
1 // abstract class that dispatches assignment / reference in environments.
3 EnvironmentRedirect {
5         var <envir;
6         var <dispatch;
8         *new { arg envir;
9                 ^super.newCopyArgs(envir ?? { Environment.new(32, Environment.new) })
10         }
11         *make { arg function;
12                 ^this.new.make(function)
13         }
14         *use { arg function;
15                 ^this.new.use(function)
16         }
17         *newFrom { arg aCollection;
18                 var newCollection = this.new;
19                 aCollection.keysValuesDo({ arg k,v, i; newCollection.put(k,v) });
20                 ^newCollection
21         }
23         // override in subclasses
25         at { arg key;
26                 ^envir.at(key)
27         }
29         put { arg key, obj;
30                 envir.put(key, obj);
31                 dispatch.value(key, obj);
32         }
34         localPut { arg key, obj;
35         envir.put(key, obj)
36      }
38         removeAt { arg key;
39                 ^envir.removeAt(key)
40         }
42         // behave like environment
45         *push {
46                 ^this.new.push;
47         }
49         *pop {
50                 ^Environment.pop;
51         }
53         pop {
54                 ^Environment.pop
55         }
57         push {
58                 if(currentEnvironment !== this) {
59                         Environment.push(this)
60                 } { "this environment is already current".warn }
61         }
64         make { arg function;
65                 // pushes the Envir, executes function, returns the Envir
66                 // usually used to create an environment by adding new variables to it.
67                 var result, saveEnvir;
69                 saveEnvir = currentEnvironment;
70                 currentEnvironment = this;
71                 protect {
72                         function.value(this);
73                 }{
74                         currentEnvironment = saveEnvir;
75                 };
76         }
78         use { arg function;
79                 // temporarily replaces the currentEnvironment with this,
80                 // executes function, returns the result of the function
81                 var result, saveEnvir;
83                 saveEnvir = currentEnvironment;
84                 currentEnvironment = this;
85                 protect {
86                         result = function.value(this);
87                 }{
88                         currentEnvironment = saveEnvir;
89                 };
90                 ^result
91         }
93         do { arg function;
94                 envir.do(function)
95         }
97         keysValuesDo { arg function;
98                 envir.keysValuesDo(function);
99         }
101         keysValuesArrayDo { arg argArray, function;
102                 envir.keysValuesArrayDo(argArray, function);
103         }
104         findKeyForValue { arg val;
105                 ^envir.findKeyForValue(val)
106         }
107         sortedKeysValuesDo { arg function;
108                 envir.sortedKeysValuesDo(function);
109         }
110         putAll { arg ... dictionaries;
111                 dictionaries.do {|dict|
112                         dict.keysValuesDo { arg key, value;
113                                 this.put(key, value)
114                         }
115                 }
116         }
118         choose {
119         ^envir.choose
120      }
122      clear { envir.clear }
124      know_ { arg flag; envir.know = flag }
125      know { ^envir.know }
127         doesNotUnderstand { arg selector ... args;
128                 var func;
129                 if (this.know) {
130                         if (selector.isSetter) {
131                                 selector = selector.asGetter;
132                                 ^this[selector] = args[0];
133                         };
134                         ^this.doFunctionPerform(selector, args)
136                 };
137                 ^this.superPerformList(\doesNotUnderstand, selector, args);
138         }
140         doFunctionPerform { arg selector, args;
141                 envir[\forward] !? {
142                         if(envir[selector].isNil) {
143                                 ^envir[\forward].functionPerformList(\value, this, selector, args);
144                         }
145                 };
146                 ^this[selector].functionPerformList(\value, this, args);
147         }
149      linkDoc { arg doc, pushNow=true;
150         doc = doc ? Document.current;
151         doc.envir_(this);
152         if(pushNow and: { currentEnvironment !== this }) { this.push };
153      }
155      unlinkDoc { arg doc, popNow = false;
156         doc = doc ? Document.current;
157         if(doc.envir === this) { doc.envir_(nil) };
158         if(popNow and:  { currentEnvironment === this }) { this.pop };
159      }
161      // networking
162      dispatch_ { arg disp;
163              dispatch = disp.envir_(this);
164         }
165         envir_ { arg argEnvir;
166                 envir = argEnvir;
167                 if(dispatch.notNil) { this.dispatch = dispatch };
168         }
175 LazyEnvir : EnvironmentRedirect {
176         var <>proxyClass=\Maybe;
178         makeProxy {
179                 ^proxyClass.asClass.new
180         }
182         at { arg key;
183                 var proxy;
184                 proxy = super.at(key);
185                 if(proxy.isNil) {
186                         proxy = this.makeProxy(key);
187                         envir.put(key, proxy);
188                 };
189                 ^proxy
191         }
193         put { arg key, obj;
194                 this.at(key).source_(obj);
195                 dispatch.value(key, obj); // forward to dispatch for networking
196         }
198         removeAt { arg key;
199                 var proxy;
200                 proxy = envir.removeAt(key);
201                 if(proxy.notNil) { proxy.clear };
202         }
204         localPut { arg key, obj;
205         this.at(key).source_(obj);
206      }