2 classvar <>handling = false;
3 classvar <>debug = false;
4 classvar <>inProtectedFunction = false;
6 var <>what, <>protectedBacktrace, <>path;
9 var protectedBacktrace, instance;
10 if (debug || inProtectedFunction, {
11 protectedBacktrace = this.getBackTrace.caller;
12 inProtectedFunction = false;
14 ^super.newCopyArgs(what ? this.name, protectedBacktrace, thisProcess.nowExecutingPath);
17 ^"EXCEPTION: " ++ what
20 this.errorString.postln;
21 if(protectedBacktrace.notNil, { this.postProtectedBacktrace });
23 // this.adviceLink.postln;
24 "^^ The preceding error dump is for %\n".postf(this.errorString);
27 ^("For advice: [http://supercollider.sf.net/wiki/index.php/%]"
28 .format(this.adviceLinkPage));
31 ^this.errorString.tr($ , $_).tr($\n, $_);
33 postProtectedBacktrace {
34 var out, currentFrame, def, ownerClass, methodName, pos, tempStr;
36 "\nPROTECTED CALL STACK:".postln;
37 currentFrame = protectedBacktrace;
38 while({currentFrame.notNil}, {
39 def = currentFrame.functionDef;
40 if(def.isKindOf(Method), {
41 ownerClass = def.ownerClass;
42 methodName = def.name;
43 if(ownerClass == Function && { #['protect', 'try'].includes(methodName) }, {
46 out << "\t%:%\t%\n".format(ownerClass, methodName, currentFrame.address);
48 out << "\ta FunctionDef\t%\n".format(currentFrame.address);
49 // sourceCode may be ridiculously huge,
50 // so steal the technique from Object:asString to reduce the printed size
51 tempStr = String.streamContentsLimit({ |stream|
52 stream << "\t\tsourceCode = " <<< (def.sourceCode ? "<an open Function>");
55 if(tempStr.size >= 512) { out << "...etc..." << $" };
58 def.argNames.do({|name, i|
59 out << "\t\targ % = %\n".format(name, currentFrame.args[i]);
61 def.varNames.do({|name, i|
62 out << "\t\tvar % = %\n".format(name, currentFrame.vars[i]);
64 currentFrame = currentFrame.caller;
66 // lose everything after the last Function:protect
67 // it just duplicates the normal stack with less info
68 // but, an Error in a routine in a Scheduler
69 // may not have a try/protect in the protectedBacktrace
70 // then, pos is nil and we should print everything
73 out.collection.copyFromStart(pos)
88 ^if(path.isNil) { "" } { "PATH:" + path ++ "\n" }
95 *new { arg what, receiver;
96 ^super.new(what).receiver_(receiver)
99 this.errorString.postln;
102 this.errorPathString.post;
103 if(protectedBacktrace.notNil, { this.postProtectedBacktrace });
105 // this.adviceLink.postln;
106 "^^ The preceding error dump is for %\nRECEIVER: %\n".postf(this.errorString, receiver);
114 PrimitiveFailedError : MethodError {
115 var <>failedPrimitiveName;
118 ^super.new(Thread.primitiveErrorString, receiver)
119 .failedPrimitiveName_(thisThread.failedPrimitiveName)
122 ^"ERROR: Primitive '%' failed.\n%".format(failedPrimitiveName, what ? "")
126 SubclassResponsibilityError : MethodError {
127 var <>method, <>class;
128 *new { arg receiver, method, class;
129 ^super.new(nil, receiver).method_(method).class_(class)
132 ^"ERROR: '" ++ method.name ++ "' should have been implemented by "
137 ShouldNotImplementError : MethodError {
138 var <>method, <>class;
139 *new { arg receiver, method, class;
140 ^super.new(nil, receiver).method_(method).class_(class)
143 ^"ERROR: '" ++ method.ownerClass.name ++ "-" ++ method.name
144 ++ "' Message not valid for this subclass: "
149 DoesNotUnderstandError : MethodError {
150 var <>selector, <>args;
151 *new { arg receiver, selector, args;
152 ^super.new(nil, receiver).selector_(selector).args_(args)
155 ^"ERROR: Message '" ++ selector ++ "' not understood."
158 this.errorString.postln;
163 this.errorPathString.post;
164 if(protectedBacktrace.notNil, { this.postProtectedBacktrace });
166 // this.adviceLink.postln;
167 "^^ The preceding error dump is for %\nRECEIVER: %\n".postf(this.errorString, receiver);
170 ^"%#%".format(this.class.name, selector)
175 MustBeBooleanError : MethodError {
177 ^"ERROR: Non Boolean in test."
181 NotYetImplementedError : MethodError {
184 OutOfContextReturnError : MethodError {
185 var <>method, <>result;
186 *new { arg receiver, method, result;
187 ^super.new(nil, receiver).method_(method).result_(result)
190 ^"ERROR: '" ++ method.ownerClass.name ++ "-" ++ method.name
191 ++ "' Out of context return of value: " ++ result
195 ImmutableError : MethodError {
197 *new { arg receiver, value;
198 ^super.new(nil, receiver).value_(value)
201 ^"ERROR: Object is immutable: " ++ receiver
205 BinaryOpFailureError : DoesNotUnderstandError {
207 ^"ERROR: binary operator '" ++ selector ++ "' failed."
211 DeprecatedError : MethodError {
212 var <>method, <>class, <>alternateMethod;
214 *new { arg receiver, method, alternateMethod, class;
215 ^super.new(nil).receiver_(receiver).method_(method).class_(class).alternateMethod_(alternateMethod)
218 var methodSignature = { arg m;
219 m.ownerClass.name.asString ++ ":" ++ m.name;
221 var searchForCaller = { arg backtrace, m;
223 backtrace.notNil and: {
224 backtrace.functionDef !== m
227 backtrace = backtrace.caller;
229 // backtrace.caller may now be a FunctionDef,
230 // useless for troubleshooting
231 // so roll back to the last real method
233 backtrace.notNil and: {
234 backtrace = backtrace.caller;
235 backtrace.functionDef.isKindOf(Method).not
238 if(backtrace.notNil) { backtrace.tryPerform(\functionDef) };
241 if(protectedBacktrace.notNil) {
242 caller = searchForCaller.value(protectedBacktrace, method);
245 caller = searchForCaller.value(this.getBackTrace, method);
250 if(caller.isKindOf(Method)) {
251 caller = methodSignature.value(caller);
253 caller = caller.asString;
256 string = "WARNING: Called from %, method % is deprecated and will be removed.".format(
258 methodSignature.value(method)
260 if(alternateMethod.notNil, {
261 string = string + "Use" + methodSignature.value(alternateMethod) + "instead.";
267 this.errorString.postln;
268 this.errorPathString.post;
269 // this.adviceLink.postln;
273 Error.handling = true;
276 if(protectedBacktrace.notNil, { this.postProtectedBacktrace });
278 Error.handling = false;
281 Error.handling = false;