haxe/src/haxe/Exception.cs
// Patched for whitelist-friendly runtime:
// - Keeps inheritance from System.Exception (required for `throw new haxe.exceptions.*`)
// - Removes StackTrace/System.Diagnostics usage
// - Keeps Haxe API surface + IHxObject dynamic plumbing

#pragma warning disable 109, 114, 219, 429, 168, 162

namespace haxe
{
    public class Exception : global::System.Exception, global::haxe.lang.IHxObject
    {
        public Exception(global::haxe.lang.EmptyObject empty)
            : base(null, null)
        {
            this.__skipStack = 0;
        }

        public Exception(string message, global::haxe.Exception previous, object native)
            : base(message, (previous == null) ? null : previous)
        {
            unchecked
            {
                this.__skipStack = 0;

                this.__previousException = previous;

                // Keep a native exception reference if possible (cheap + whitelist-safe)
                if (native is global::System.Exception se)
                {
                    this.__nativeException = se;
                }
                else
                {
                    // If native is null or not an Exception, fall back to this
                    this.__nativeException = this;
                }

                // No StackTrace capture in whitelist build
                this.__nativeStack = null;
                this.__ownStack = false;

                // cache message for cases when base.Message is not what Haxe expects
                this.__message = message;
            }
        }

        // ---- Static API ----

        public static global::haxe.Exception caught(object value)
        {
            if (value is global::haxe.Exception he)
            {
                return he;
            }

            if (value is global::System.Exception se)
            {
                return new global::haxe.Exception(se.Message, default(global::haxe.Exception), se);
            }

            return new global::haxe.ValueException(value, default(global::haxe.Exception), value);
        }

        public static object thrown(object value)
        {
            if (value is global::haxe.Exception he)
            {
                return he.get_native();
            }

            if (value is global::System.Exception)
            {
                return value;
            }

            global::haxe.ValueException e = new global::haxe.ValueException(value, default(global::haxe.Exception), default(object));
            e.__shiftStack();
            return e.get_native();
        }

        // ---- Fields ----

        
        public global::Array<object> __exceptionStack;

        // In original code it's System.Diagnostics.StackTrace.
        // For whitelist safety keep it as object placeholder.
        
        public object __nativeStack;

        
        public bool __ownStack;

        
        public int __skipStack;

        
        public global::System.Exception __nativeException;

        
        public global::haxe.Exception __previousException;

        
        public string __message;

        // ---- Public instance API ----

        public virtual object unwrap()
        {
            return this.__nativeException;
        }

        public virtual string toString()
        {
            return this.get_message();
        }

        public virtual string details()
        {
            // Whitelist-safe: no stack printing.
            // Keep roughly same formatting expectations.
            if (this.get_previous() == null)
            {
                return global::haxe.lang.Runtime.concat("Exception: ", this.toString());
            }

            string result = "";
            global::haxe.Exception e = this;
            global::haxe.Exception prev = null;

            while (e != null)
            {
                if (prev == null)
                {
                    result = global::haxe.lang.Runtime.concat(
                        global::haxe.lang.Runtime.concat("Exception: ", e.get_message()),
                        result
                    );
                }
                else
                {
                    result = global::haxe.lang.Runtime.concat(
                        global::haxe.lang.Runtime.concat(
                            global::haxe.lang.Runtime.concat("Exception: ", e.get_message()),
                            "\n\nNext "
                        ),
                        result
                    );
                }

                prev = e;
                e = e.get_previous();
            }

            return result;
        }

        
        public void __shiftStack()
        {
            // Keep counter behavior (some code increments skip)
            this.__skipStack++;
        }

        public virtual string get_message()
        {
            // Prefer cached message; fall back to base.Message.
            return this.__message ?? this.Message;
        }

        public virtual global::haxe.Exception get_previous()
        {
            return this.__previousException;
        }

        public object get_native()
        {
            // Must be System.Exception (or null). Keep native if present else this.
            return (object)(this.__nativeException ?? this);
        }

        public virtual global::Array<object> get_stack()
        {
            // Whitelist-safe: always empty stack
            global::Array<object> s = this.__exceptionStack;
            if (s == null)
            {
                s = new global::Array<object>(new object[] { });
                this.__exceptionStack = s;
            }
            return s;
        }

        // ---- IHxObject dynamic plumbing ----

        public virtual object __hx_lookupField(string field, int hash, bool throwErrors, bool isCheck)
        {
            if (isCheck) return global::haxe.lang.Runtime.undefined;
            if (throwErrors) throw new global::System.Exception("Field not found.");
            return null;
        }

        public virtual double __hx_lookupField_f(string field, int hash, bool throwErrors)
        {
            if (throwErrors) throw new global::System.Exception("Field not found or incompatible field type.");
            return default(double);
        }

        public virtual object __hx_lookupSetField(string field, int hash, object value)
        {
            throw new global::System.Exception("Cannot access field for writing.");
        }

        public virtual double __hx_lookupSetField_f(string field, int hash, double value)
        {
            throw new global::System.Exception("Cannot access field for writing or incompatible type.");
        }

        public virtual double __hx_setField_f(string field, int hash, double value, bool handleProperties)
        {
            unchecked
            {
                switch (hash)
                {
                    case 1177754921: // __skipStack
                        this.__skipStack = (int)value;
                        return value;

                    default:
                        return this.__hx_lookupSetField_f(field, hash, value);
                }
            }
        }

        public virtual object __hx_setField(string field, int hash, object value, bool handleProperties)
        {
            unchecked
            {
                switch (hash)
                {
                    case 78945784: // __previousException
                        this.__previousException = (global::haxe.Exception)value;
                        return value;

                    case 221637784: // __nativeException
                        this.__nativeException = (global::System.Exception)value;
                        return value;

                    case 1177754921: // __skipStack
                        this.__skipStack = (int)(global::haxe.lang.Runtime.toInt(value));
                        return value;

                    case 1460447810: // __ownStack
                        this.__ownStack = global::haxe.lang.Runtime.toBool(value);
                        return value;

                    case 863972113: // __nativeStack (object)
                        this.__nativeStack = value;
                        return value;

                    case 1066783641: // __exceptionStack
                        this.__exceptionStack = (global::Array<object>)global::Array<object>.__hx_cast<object>((global::Array)value);
                        return value;

                    default:
                        return this.__hx_lookupSetField(field, hash, value);
                }
            }
        }

        public virtual object __hx_getField(string field, int hash, bool throwErrors, bool isCheck, bool handleProperties)
        {
            unchecked
            {
                switch (hash)
                {
                    case 1203028895: return (global::haxe.lang.Function)(new global::haxe.lang.Closure(this, "get_stack", 1203028895));
                    case 312752480:  return (global::haxe.lang.Function)(new global::haxe.lang.Closure(this, "get_native", 312752480));
                    case 1489662016: return (global::haxe.lang.Function)(new global::haxe.lang.Closure(this, "get_previous", 1489662016));
                    case 537630174:  return (global::haxe.lang.Function)(new global::haxe.lang.Closure(this, "get_message", 537630174));
                    case 1274465926: return (global::haxe.lang.Function)(new global::haxe.lang.Closure(this, "__shiftStack", 1274465926));
                    case 727112898:  return (global::haxe.lang.Function)(new global::haxe.lang.Closure(this, "details", 727112898));
                    case 946786476:  return (global::haxe.lang.Function)(new global::haxe.lang.Closure(this, "toString", 946786476));
                    case 1825849507: return (global::haxe.lang.Function)(new global::haxe.lang.Closure(this, "unwrap", 1825849507));

                    case 78945784:   return this.__previousException;
                    case 221637784:  return this.__nativeException;
                    case 1177754921: return this.__skipStack;
                    case 1460447810: return this.__ownStack;
                    case 863972113:  return this.__nativeStack;
                    case 1066783641: return this.__exceptionStack;

                    case 572311959:  return this.get_native();
                    case 598785079:  return this.get_previous();
                    case 67856200:   return this.get_stack();
                    case 437335495:  return this.get_message();

                    default:
                        return this.__hx_lookupField(field, hash, throwErrors, isCheck);
                }
            }
        }

        public virtual double __hx_getField_f(string field, int hash, bool throwErrors, bool handleProperties)
        {
            unchecked
            {
                switch (hash)
                {
                    case 1177754921:
                        return (double)this.__skipStack;
                    default:
                        return this.__hx_lookupField_f(field, hash, throwErrors);
                }
            }
        }

        public virtual object __hx_invokeField(string field, int hash, object[] dynargs)
        {
            unchecked
            {
                switch (hash)
                {
                    case 1203028895: return this.get_stack();
                    case 312752480:  return this.get_native();
                    case 1489662016: return this.get_previous();
                    case 537630174:  return this.get_message();
                    case 1274465926: this.__shiftStack(); break;
                    case 727112898:  return this.details();
                    case 946786476:  return this.toString();
                    case 1825849507: return this.unwrap();

                    default:
                        return ((global::haxe.lang.Function)this.__hx_getField(field, hash, true, false, false)).__hx_invokeDynamic(dynargs);
                }

                return null;
            }
        }

        public virtual void __hx_getFields(global::Array<string> baseArr)
        {
            baseArr.push("__previousException");
            baseArr.push("__nativeException");
            baseArr.push("__skipStack");
            baseArr.push("__ownStack");
            baseArr.push("__nativeStack");
            baseArr.push("__exceptionStack");
            baseArr.push("native");
            baseArr.push("previous");
            baseArr.push("stack");
            baseArr.push("message");
        }

        public override string ToString()
        {
            return this.toString();
        }
    }
}