static void doDumpStack(string msg, Exception err, int depth, StringWriter w) { // message for (int sp = 0; sp < depth; sp++) { w.Write(" "); } if (!(err is Err.Val) && msg == err.Message) { w.Write(err.GetType() + ": "); } w.WriteLine(msg); // stack string stack = err.StackTrace; if (err is Err.Val) { Err e = ((Err.Val)err).err(); if (e.m_stack != null) { stack = e.m_stack; } } if (stack != null) { string[] lines = stack.Split('\n'); for (int i = 0; i < lines.Length; i++) { // TODO - could be *way* more efficient string s = lines[i].Trim(); int parOpen = s.IndexOf('('); int parClose = s.IndexOf(')', parOpen); string source = s.Substring(parClose + 1, s.Length - parClose - 1); if (source == "") { source = "Unknown Source"; } else { source = source.Substring(4); int index = source.LastIndexOf("\\"); if (index != -1) { source = source.Substring(index + 1); } index = source.LastIndexOf(":line"); source = source.Substring(0, index + 1) + source.Substring(index + 6); } string target = s.Substring(0, parOpen); if (target.StartsWith("at Fan.")) { int a = target.IndexOf(".", 7); int b = target.IndexOf(".", a + 1); string pod = target.Substring(7, a - 7); string type = target.Substring(a + 1, b - a - 1); string meth = target.Substring(b + 1); // check for closures int dollar1 = type.IndexOf('$'); int dollar2 = dollar1 < 0 ? -1 : type.IndexOf('$', dollar1 + 1); if (dollar2 > 0) { // don't print callX for closures if (meth.StartsWith("call")) { continue; } // remap closure class back to original method if (meth.StartsWith("doCall")) { meth = type.Substring(dollar1 + 1, dollar2 - dollar1 - 1); type = type.Substring(0, dollar1); } } target = FanStr.decapitalize(pod) + "::" + type + "." + meth; } for (int sp = 0; sp < depth; sp++) { w.Write(" "); } w.Write(" "); w.Write(target); w.Write(" ("); w.Write(source); w.Write(")"); w.Write("\n"); } } // inner exception Exception cause = err.InnerException; if (cause != null) { doDumpStack(msg, cause, depth + 1, w); } }