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);
}