HelpBrowser: path box becomes a more conventional search box
[supercollider.git] / SCClassLibrary / JITLib / Patterns / Fdef.sc
blob13f75471f0d7983987d9d7abe0973b30cb8b9ffb
1 // maybe we want to call "value" "reduce" and only use one class.
3 Maybe : Ref {
5         classvar <callers, <current, <>callFunc;
6         classvar <>defaultValue;
7         classvar <>protected = false, <>verbose = false;
8         classvar <>defaultValue=1;
10         source { ^value }
11         source_ { arg obj; this.value = obj }
13         clear { value = nil }
15         value { arg ... args;
16                 ^this.reduceFuncProxy(args)
17         }
18         valueArray { arg args;
19                         ^this.reduceFuncProxy(args)
20         }
21         valueEnvir { arg ... args;
22                 ^this.notYetImplemented(thisMethod)
23                 //^value.valueEnvir(*args) ? defaultValue
24         }
25         valueArrayEnvir {  arg ... args;
26                 ^this.notYetImplemented(thisMethod)
27                 //^value.valueArrayEnvir(args) ? defaultValue
28         }
29         functionPerformList { arg selector, arglist;
30                 ^this.performList(selector, arglist)
31         }
33         // this allows recursion
34         apply { arg ... args;
35                 ^this.reduceFuncProxy(args, false)
36         }
37         // function composition
38         o { arg ... args;
39                 ^NAryValueProxy(this, args)
40         }
41         <> { arg that;
42                 ^o (this, that)
43         }
45         // use in list comprehension
46         all {
47                 ^this.source.all
48         }
49         do { arg function;
50                 this.source.do(function) // problem: on the fly change is not picked up in this case.
51         }
53         doesNotUnderstand { arg selector ... args;
54                 ^this.composeNAryOp(selector, args)
55         }
57         // streams and patterns
59         embedInStream { arg inval;
60                 ^Prout { arg inval;
61                         var curVal, str;
62                         var outval;
63                         while {
64                                 if(curVal !== value) { str = value.asStream; curVal = value };
65                                 outval = str.next(inval);
66                                 outval.notNil
67                         } {
68                                 inval = outval.yield;
69                         }
70                 }.embedInStream(inval)
71         }
73         // math
74         composeUnaryOp { arg aSelector;
75                 ^UnaryOpFunctionProxy.new(aSelector, this)
76         }
77         composeBinaryOp { arg aSelector, something, adverb;
78                 ^BinaryOpFunctionProxy.new(aSelector, this, something, adverb);
79         }
80         reverseComposeBinaryOp { arg aSelector, something, adverb;
81                 ^BinaryOpFunctionProxy.new(aSelector, something, this, adverb);
82         }
83         composeNAryOp { arg aSelector, anArgList;
84                 ^NAryOpFunctionProxy.new(aSelector, this, anArgList)
85         }
88         // used by AbstractFunction:reduceFuncProxy
89         // to prevent reduction of enclosed functions
90         valueFuncProxy { arg args;
91                 ^this.catchRecursion {
92                         value.valueFuncProxy(args)
93                 } ?? { this.valueEmpty(args) };
94         }
96         valueEmpty { arg args;
97                 if(verbose) {
98                         (Char.bullet ++ " ? incomplete definition: %\n").postf(this.infoString(args))
99                 };
100                 ^defaultValue
101         }
103         reduceFuncProxy { arg args, protect=true;
105                 ^if(protect.not) {
106                         value.reduceFuncProxy(args)
107                 } {
108                         this.catchRecursion {
109                                 value.reduceFuncProxy(args)
110                         }
111                 } ?? { this.valueEmpty(args) };
112         }
114         catchRecursion { arg func;
115                 var val, previous;
116                 try {
117                         protect {
118                                 previous = current;
119                                 current = this;
121                                 if(this.includedInCallers) {
122                                         if(verbose) {
123                                                 (Char.bullet ++ " ! Couldn't solve a recursive definition in %\n")
124                                                 .postf(this.infoString)
125                                         };
126                                         callFunc.value(this, callers, \recursion);
127                                         this.throw;
128                                 };
129                                 // add this to the list of current callers
130                                 callers = callers.add(this);
131                                 // evaluate function
132                                 val = func.value;
134                                 callFunc.value(this, callers, val);
136                         } { |exception|
137                                 if(verbose and: { exception.isKindOf(Exception)} ) {
138                                         ("Error or incomplete specification" + exception.errorString).postln;
139                                 };
140                         /*      if(exception.isKindOf(this.class).not) {
141                                         Exception.throw;
142                                 }*/
143                                 // remove again
144                                 callers.pop;
145                                 current = previous;
146                         };
147                 }
148                 ^val
149         }
151         includedInCallers {
152                 ^callers.notNil and: { callers.includes(this) }
153         }
155         postString {
156                 var res = this.findKey;
157                 ^if(res.notNil) { "~" ++ res } { this.asString }
158         }
160         infoString { arg args;
161                 var who, str="", src;
162                 who = this.findKey;
163                 if(who.isNil) { ^this.asString };
164                 who = "~" ++ who;
165                 src = this.source.postString;
166                 if(args.notNil and: {args.notEmpty}) {
167                         args = args.collect(_.postString);
168                         str = "\nArguments passed: %".format(args)
169                 };
170                 ^"% <- %".format(who, src.asString) ++ str
171         }
173         findKey {
174                 ^currentEnvironment.findKeyForValue(this)
175         }
177         storeOn { arg stream;
178         // maybe should try to catch a recursion here:
179         stream << this.class.name << "(" <<< value << ")" }
183 Fdef : Maybe {
184         classvar <>all;
186         *initClass {
187                 all = IdentityDictionary.new
188         }
190         *new { arg key, val;
191                 var res;
192                 res = all[key];
193                 if(res.isNil) {
194                         res = super.new.source_(val);
195                         all[key] = res
196                 } {
197                         if(val.notNil) { res.source = val };
198                 }
199                 ^res
200         }