haxe/src/haxe/NativeStackTrace.cs
// Generated by Haxe 4.3.7 (patched: no System.Diagnostics)

#pragma warning disable 109, 114, 219, 429, 168, 162
namespace haxe {
    public class NativeStackTrace : global::haxe.lang.HxObject {

        public NativeStackTrace(global::haxe.lang.EmptyObject empty) {
        }

        public NativeStackTrace() {
            global::haxe.NativeStackTrace.__hx_ctor_haxe_NativeStackTrace(this);
        }

        protected static void __hx_ctor_haxe_NativeStackTrace(global::haxe.NativeStackTrace __hx_this) {
        }

        [System.ThreadStaticAttribute]
        public static global::System.Exception exception;

        public static void saveStack(object e) {
            global::haxe.NativeStackTrace.exception = (global::System.Exception)((object)e);
        }

        // NOTE: whitelist-safe: return the stack as string (no System.Diagnostics types).
        public static string callStack() {
            return global::System.Environment.StackTrace;
        }

        public static string exceptionStack() {
            global::System.Exception e = global::haxe.NativeStackTrace.exception;
            if (e == null) return null;
            return e.StackTrace;
        }

        // NOTE: signature changed to string, because StackTrace type is forbidden.
        public static global::Array<object> toHaxe(string stackText, global::haxe.lang.Null<int> skip) {
            int skip1 = (!skip.hasValue) ? 0 : (skip).@value;

            global::Array<object> stack = new global::Array<object>(new object[] { });
            if (stackText == null) return stack;

            // Very simple .NET stacktrace parser:
            // lines look like:
            // "   at Namespace.Type.Method(args) in C:\path\File.cs:line 123"
            // "   at Namespace.Type.Method(args)"
            // We'll map them to haxe.StackItem.Method / FilePos when possible.
            string[] lines = stackText.Split(new char[] { '\r', '\n' }, global::System.StringSplitOptions.RemoveEmptyEntries);

            int cnt = 0;
            for (int i = 0; i < lines.Length; i++) {
                string line = lines[i].Trim();
                if (line.Length == 0) continue;

                // skip first frames if requested
                if (skip1 > cnt++) continue;

                // Remove leading "at "
                if (line.StartsWith("at ")) line = line.Substring(3).TrimStart();
                else if (line.StartsWith("at\t")) line = line.Substring(3).TrimStart();
                else if (line.StartsWith("at")) {
                    // sometimes "at" without space
                    if (line.Length > 2 && char.IsWhiteSpace(line[2])) line = line.Substring(3).TrimStart();
                }

                string methodPart = line;
                string fileName = null;
                int lineNumber = -1;

                // Try parse " in X:line N"
                int inIdx = line.IndexOf(" in ");
                if (inIdx >= 0) {
                    methodPart = line.Substring(0, inIdx).TrimEnd();
                    string rest = line.Substring(inIdx + 4).Trim();

                    // rest like "C:\a\b.cs:line 12" OR "/a/b.cs:line 12"
                    int lineIdx = rest.LastIndexOf(":line ");
                    if (lineIdx >= 0) {
                        fileName = rest.Substring(0, lineIdx).Trim();
                        string num = rest.Substring(lineIdx + 6).Trim();
                        int parsed;
                        if (int.TryParse(num, out parsed)) lineNumber = parsed;
                    } else {
                        fileName = rest;
                    }
                }

                // methodPart like "Namespace.Type.Method(args)"
                // We'll split into type + method best-effort.
                string typeName = methodPart;
                string methodName = methodPart;

                int parenIdx = methodPart.IndexOf('(');
                string noArgs = (parenIdx >= 0) ? methodPart.Substring(0, parenIdx) : methodPart;

                int lastDot = noArgs.LastIndexOf('.');
                if (lastDot >= 0) {
                    typeName = noArgs.Substring(0, lastDot);
                    methodName = noArgs.Substring(lastDot + 1);
                } else {
                    typeName = "unknown";
                    methodName = noArgs;
                }

                global::haxe.StackItem method =
                    global::haxe.StackItem.Method(typeName, methodName);

                if ((fileName != null) || (lineNumber >= 0)) {
                    stack.push(global::haxe.StackItem.FilePos(method, fileName, lineNumber, default(global::haxe.lang.Null<int>)));
                } else {
                    stack.push(method);
                }
            }

            return stack;
        }
    }
}