跳转到内容

模組:沙盒/a2569875/PythonScript/Librarys/DataTypes

维基百科,自由的百科全书
-- Module:PythonScript/Librarys/DataTypes
-- 進階資料結構標準庫:完整實作 enum 與 array 模組
local DataTypes = {}

local PyClass = require("Module:沙盒/a2569875/PythonScript/Class")
local Runtime = require("Module:沙盒/a2569875/PythonScript/Runtime")
local RUtils = require("Module:沙盒/a2569875/PythonScript/Runtime/Utils")
local Evaluator = require("Module:沙盒/a2569875/PythonScript/Evaluator")

local B = Runtime.builtins

local enum_initialized = false
local enum_mod_cache = nil
local array_initialized = false
local array_mod_cache = nil

-- ==========================================
-- 0. 純 Lua 52-bit 位元運算與輔助函式 (供 Flag 與 array 使用)
-- ==========================================
local function bit_and(a, b)
    a, b = math.floor(a), math.floor(b)
    local res, bit = 0, 1
    while a > 0 and b > 0 do
        local ra, rb = a % 2, b % 2
        if ra == 1 and rb == 1 then res = res + bit end
        a = (a - ra) / 2
        b = (b - rb) / 2
        bit = bit * 2
    end
    return res
end

local function bit_or(a, b)
    a, b = math.floor(a), math.floor(b)
    local res, bit = 0, 1
    while a > 0 or b > 0 do
        local ra, rb = a % 2, b % 2
        if ra == 1 or rb == 1 then res = res + bit end
        a = (a - ra) / 2
        b = (b - rb) / 2
        bit = bit * 2
    end
    return res
end

local function bit_xor(a, b)
    a, b = math.floor(a), math.floor(b)
    local res, bit = 0, 1
    while a > 0 or b > 0 do
        local ra, rb = a % 2, b % 2
        if ra ~= rb then res = res + bit end
        a = (a - ra) / 2
        b = (b - rb) / 2
        bit = bit * 2
    end
    return res
end

local function is_power_of_two(n)
    if type(n) ~= "number" or n <= 0 or math.floor(n) ~= n then return false end
    return bit_and(n, n - 1) == 0
end

local function fn(name, func)
    return { __type = "builtin_method", __name = name, __call = func }
end

-- ==========================================
-- 1. ENUM 模組核心實作
-- ==========================================
local function ensure_enum_init()
    if enum_initialized then return end
    enum_initialized = true

    local auto_counter = 0
    local AUTO_SENTINEL = {}

    -- [A] 實作 auto() 與延遲運算式支援 (如 RW = R | W)
    local auto_cls
    local function make_auto_expr(op, left, right)
        local inst = PyClass.make_instance(auto_cls)
        auto_counter = auto_counter + 1
        inst.__dict._seq = auto_counter
        inst.__dict._expr = { op = op, left = left, right = right }
        inst.__dict.value = AUTO_SENTINEL
        return inst
    end

    auto_cls = PyClass.make_class("auto", { B.object }, {
        __init__ = fn("__init__", function(a)
            local self = a[1]
            auto_counter = auto_counter + 1
            self.__dict._seq = auto_counter
            self.__dict.value = (a[2] ~= nil) and a[2] or AUTO_SENTINEL
            return nil
        end),
        __or__     = fn("__or__",     function(a) return make_auto_expr("|", a[1], a[2]) end),
        __ror__    = fn("__ror__",    function(a) return make_auto_expr("|", a[2], a[1]) end),
        __and__    = fn("__and__",    function(a) return make_auto_expr("&", a[1], a[2]) end),
        __rand__   = fn("__rand__",   function(a) return make_auto_expr("&", a[2], a[1]) end),
        __xor__    = fn("__xor__",    function(a) return make_auto_expr("^", a[1], a[2]) end),
        __rxor__   = fn("__rxor__",   function(a) return make_auto_expr("^", a[2], a[1]) end),
        __invert__ = fn("__invert__", function(a) return make_auto_expr("~", a[1], nil)  end),
        __add__    = fn("__add__",    function(a) return make_auto_expr("+", a[1], a[2]) end),
        __radd__   = fn("__radd__",   function(a) return make_auto_expr("+", a[2], a[1]) end),
    })
    auto_cls.__dict["__module__"] = "enum"

    -- [B] member / nonmember / property 包裝器
    local member_cls = PyClass.make_class("member", { B.object }, {
        __init__ = fn("__init__", function(a)
            auto_counter = auto_counter + 1
            a[1].__dict._seq = auto_counter
            a[1].__dict.value = a[2]
            a[1]._is_force_member = true
            return nil
        end)
    })
    local nonmember_cls = PyClass.make_class("nonmember", { B.object }, {
        __init__ = fn("__init__", function(a)
            a[1].__dict.value = a[2]
            a[1]._is_nonmember = true
            return nil
        end)
    })

    local enum_property = fn("property", function(a)
        return { __type = "property", _is_enum_property = true, fget = a[1], fset = a[2], fdel = a[3] }
    end)

    -- [C] EnumType 元類別
    local EnumType = PyClass.make_class("EnumType", { B.type }, {})
    EnumType.__dict["__module__"] = "enum"

    -- [D] 成員方法與比較/位元運算建構
    local Enum, ReprEnum, IntEnum, StrEnum, Flag, IntFlag
    local create_composite_flag

    local function unwrap_enum_val(v)
        if type(v) == "table" and v._is_enum_member then
            return v.__dict._value
        end
        return v
    end

    local enum_dict = {
        __module__ = "enum",
        name = {
            __type = "property", _is_enum_property = true,
            fget = fn("name", function(a) return a[1].__dict._name end)
        },
        value = {
            __type = "property", _is_enum_property = true,
            fget = fn("value", function(a) return a[1].__dict._value end)
        },
        __repr__ = fn("__repr__", function(a)
            local self = a[1]
            local cls = self.__class
            local cname = cls.__name
            local mname = self.__dict._name or tostring(self.__dict._value)
            if cls._is_global_enum then
                local mod_name = (cls.__dict and cls.__dict["__module__"]) or "__main__"
                return mod_name .. "." .. mname
            end
            local v_repr = RUtils.to_str(self.__dict._value, true)
            if self.__dict._name == nil and cls._is_flag_class then
                return string.format("<%s: %s>", cname, v_repr)
            end
            return string.format("<%s.%s: %s>", cname, mname, v_repr)
        end),
        __str__ = fn("__str__", function(a)
            local self = a[1]
            local cls = self.__class
            local mname = self.__dict._name
            if cls._is_global_enum and mname then return mname end
            if mname == nil and cls._is_flag_class then
                return string.format("%s(%s)", cls.__name, tostring(self.__dict._value))
            end
            return cls.__name .. "." .. tostring(mname)
        end),
        __format__ = fn("__format__", function(a)
            local self, spec = a[1], a[2] or ""
            local s = B.str.__call({ self })
            return RUtils.format_value({ s, spec })
        end),
        __hash__ = fn("__hash__", function(a)
            local self = a[1]
            if self.__builtin_value ~= nil then
                return RUtils.hash_impl({ self.__builtin_value })
            end
            return RUtils.hash_impl({ self.__dict._name or self.__dict._value })
        end),
        __eq__ = fn("__eq__", function(a)
            local self, other = a[1], a[2]
            if self == other then return true end
            if self.__class._is_int_mixin then
                if type(other) == "table" and other._is_enum_member then
                    if not other.__class._is_int_mixin and other.__class ~= self.__class then return false end
                    return RUtils.runtime_is_equal(self.__dict._value, other.__dict._value)
                end
                if type(other) == "number" or (type(other) == "table" and other.__type == "int") or type(other) == "boolean" then
                    return RUtils.runtime_is_equal(self.__dict._value, other)
                end
                return false
            elseif self.__class._is_str_mixin then
                if type(other) == "table" and other._is_enum_member then
                    if not other.__class._is_str_mixin and other.__class ~= self.__class then return false end
                    return self.__dict._value == other.__dict._value
                end
                return type(other) == "string" and (self.__dict._value == other)
            else
                if type(other) == "table" and other._is_enum_member and other.__class == self.__class then
                    return RUtils.runtime_is_equal(self.__dict._value, other.__dict._value)
                end
                return false
            end
        end),
        __ne__ = fn("__ne__", function(a)
            local eq_m = PyClass.get_attr(a[1], "__eq__")
            return not RUtils.to_bool(Evaluator.invoke(eq_m, { a[2] }, {}))
        end),
        __bool__ = fn("__bool__", function(a)
            local self = a[1]
            if self.__class._is_flag_class then
                return self.__dict._value ~= 0
            end
            return true
        end),
        __setattr__ = fn("__setattr__", function(a)
            local self, k, v = a[1], a[2], a[3]
            if not self._enum_locked then
                PyClass.raw_set_attr(self, k, v)
                return nil
            end
            Runtime.raise("AttributeError", string.format("Cannot reassign member attribute '%s'", tostring(k)))
        end),
        __delattr__ = fn("__delattr__", function(a)
            Runtime.raise("AttributeError", string.format("%s: cannot delete attribute '%s'", a[1].__class.__name, tostring(a[2])))
        end),
        -- 供類別層級 [] 取值使用 (支援 Color['RED'])
        __getitem__ = {
            __type = "classmethod",
            __func = fn("__getitem__", function(a)
                local cls, key = a[1], a[2]
                local member = cls._member_map and cls._member_map[key]
                if not member then Runtime.raise("KeyError", tostring(key)) end
                return member
            end)
        },
    }
    enum_dict.__class_getitem__ = enum_dict.__getitem__

    Enum = PyClass.make_class("Enum", { B.object }, enum_dict)
    Enum._is_enum_class = true
    Enum._is_enum_base = true
    Enum.__class = EnumType

    -- [E] ReprEnum:保留混入型別 (int / str) 的 __str__ 與 __format__
    local repr_enum_dict = {
        __module__ = "enum",
        __str__ = fn("__str__", function(a)
            local self = a[1]
            if self.__class._is_global_enum and self.__dict._name then
                return self.__dict._name
            end
            return RUtils.to_str(self.__dict._value, false)
        end),
        __format__ = fn("__format__", function(a)
            local self, spec = a[1], a[2] or ""
            return RUtils.format_value({ self.__dict._value, spec })
        end)
    }
    ReprEnum = PyClass.make_class("ReprEnum", { Enum }, repr_enum_dict)
    ReprEnum._is_enum_class = true
    ReprEnum._is_enum_base = true
    ReprEnum._is_repr_enum = true
    ReprEnum.__class = EnumType

    -- [F] IntEnum:混入 int 的比較與算術運算
    local int_mixin_methods = {
        __module__ = "enum",
        __int__   = fn("__int__",   function(a) return a[1].__dict._value end),
        __index__ = fn("__index__", function(a) return a[1].__dict._value end),
        __float__ = fn("__float__", function(a) return tonumber(a[1].__dict._value) * 1.0 end),
        __lt__    = fn("__lt__",    function(a) return RUtils.runtime_is_less(unwrap_enum_val(a[1]), unwrap_enum_val(a[2])) end),
        __le__    = fn("__le__",    function(a)
            local v1, v2 = unwrap_enum_val(a[1]), unwrap_enum_val(a[2])
            return RUtils.runtime_is_equal(v1, v2) or RUtils.runtime_is_less(v1, v2)
        end),
        __gt__    = fn("__gt__",    function(a) return RUtils.runtime_is_less(unwrap_enum_val(a[2]), unwrap_enum_val(a[1])) end),
        __ge__    = fn("__ge__",    function(a)
            local v1, v2 = unwrap_enum_val(a[1]), unwrap_enum_val(a[2])
            return RUtils.runtime_is_equal(v1, v2) or RUtils.runtime_is_less(v2, v1)
        end),
        __add__      = fn("__add__",      function(a) return unwrap_enum_val(a[1]) + unwrap_enum_val(a[2]) end),
        __radd__     = fn("__radd__",     function(a) return unwrap_enum_val(a[2]) + unwrap_enum_val(a[1]) end),
        __sub__      = fn("__sub__",      function(a) return unwrap_enum_val(a[1]) - unwrap_enum_val(a[2]) end),
        __rsub__     = fn("__rsub__",     function(a) return unwrap_enum_val(a[2]) - unwrap_enum_val(a[1]) end),
        __mul__      = fn("__mul__",      function(a) return unwrap_enum_val(a[1]) * unwrap_enum_val(a[2]) end),
        __rmul__     = fn("__rmul__",     function(a) return unwrap_enum_val(a[2]) * unwrap_enum_val(a[1]) end),
        __truediv__  = fn("__truediv__",  function(a) return unwrap_enum_val(a[1]) / unwrap_enum_val(a[2]) end),
        __rtruediv__ = fn("__rtruediv__", function(a) return unwrap_enum_val(a[2]) / unwrap_enum_val(a[1]) end),
        __floordiv__ = fn("__floordiv__", function(a) return math.floor(unwrap_enum_val(a[1]) / unwrap_enum_val(a[2])) end),
        __rfloordiv__= fn("__rfloordiv__",function(a) return math.floor(unwrap_enum_val(a[2]) / unwrap_enum_val(a[1])) end),
        __mod__      = fn("__mod__",      function(a) return unwrap_enum_val(a[1]) % unwrap_enum_val(a[2]) end),
        __rmod__     = fn("__rmod__",     function(a) return unwrap_enum_val(a[2]) % unwrap_enum_val(a[1]) end),
        __neg__      = fn("__neg__",      function(a) return -unwrap_enum_val(a[1]) end),
        __pos__      = fn("__pos__",      function(a) return unwrap_enum_val(a[1]) end),
        __abs__      = fn("__abs__",      function(a) return math.abs(unwrap_enum_val(a[1])) end),
        __or__       = fn("__or__",       function(a) return bit_or(unwrap_enum_val(a[1]), unwrap_enum_val(a[2])) end),
        __ror__      = fn("__ror__",      function(a) return bit_or(unwrap_enum_val(a[2]), unwrap_enum_val(a[1])) end),
        __and__      = fn("__and__",      function(a) return bit_and(unwrap_enum_val(a[1]), unwrap_enum_val(a[2])) end),
        __rand__     = fn("__rand__",     function(a) return bit_and(unwrap_enum_val(a[2]), unwrap_enum_val(a[1])) end),
        __xor__      = fn("__xor__",      function(a) return bit_xor(unwrap_enum_val(a[1]), unwrap_enum_val(a[2])) end),
        __rxor__     = fn("__rxor__",     function(a) return bit_xor(unwrap_enum_val(a[2]), unwrap_enum_val(a[1])) end),
    }
    IntEnum = PyClass.make_class("IntEnum", { B.int, ReprEnum }, int_mixin_methods)
    IntEnum._is_enum_class = true
    IntEnum._is_enum_base = true
    IntEnum._is_int_mixin = true
    IntEnum.__class = EnumType

    -- [G] StrEnum:混入 str 的比較與串接運算
    local str_mixin_methods = {
        __module__   = "enum",
        __lt__       = fn("__lt__",       function(a) return tostring(unwrap_enum_val(a[1])) < tostring(unwrap_enum_val(a[2])) end),
        __le__       = fn("__le__",       function(a) return tostring(unwrap_enum_val(a[1])) <= tostring(unwrap_enum_val(a[2])) end),
        __gt__       = fn("__gt__",       function(a) return tostring(unwrap_enum_val(a[1])) > tostring(unwrap_enum_val(a[2])) end),
        __ge__       = fn("__ge__",       function(a) return tostring(unwrap_enum_val(a[1])) >= tostring(unwrap_enum_val(a[2])) end),
        __add__      = fn("__add__",      function(a) return tostring(unwrap_enum_val(a[1])) .. tostring(unwrap_enum_val(a[2])) end),
        __radd__     = fn("__radd__",     function(a) return tostring(unwrap_enum_val(a[2])) .. tostring(unwrap_enum_val(a[1])) end),
        __contains__ = fn("__contains__", function(a)
            local s, sub = tostring(unwrap_enum_val(a[1])), tostring(unwrap_enum_val(a[2]))
            return s:find(sub, 1, true) ~= nil
        end),
        __len__      = fn("__len__",      function(a) return mw.ustring.len(a[1].__dict._value) end),
    }
    StrEnum = PyClass.make_class("StrEnum", { B.str, ReprEnum }, str_mixin_methods)
    StrEnum._is_enum_class = true
    StrEnum._is_enum_base = true
    StrEnum._is_str_mixin = true
    StrEnum.__class = EnumType

    -- [H] Flag 與 IntFlag 位元合成引擎
    local function decompose_flag_members(cls, val)
        local members = {}
        local covered = 0
        for _, m in ipairs(cls._member_list or {}) do
            local mv = m.__dict._value
            if mv > 0 and is_power_of_two(mv) and bit_and(val, mv) == mv then
                table.insert(members, m)
                covered = bit_or(covered, mv)
            end
        end
        -- 若有複合名稱但含單一位元未涵蓋,再檢查其他成員
        if covered ~= bit_and(val, cls._all_flags_mask or 0) then
            for _, m in ipairs(cls._member_list or {}) do
                local mv = m.__dict._value
                if mv > 0 and not is_power_of_two(mv) and bit_and(val, mv) == mv then
                    if bit_and(covered, mv) ~= mv then
                        table.insert(members, m)
                        covered = bit_or(covered, mv)
                    end
                end
            end
        end
        local leftover = val - bit_and(val, covered)
        return members, leftover
    end

    create_composite_flag = function(cls, raw_val)
        if type(raw_val) ~= "number" or math.floor(raw_val) ~= raw_val then
            Runtime.raise("ValueError", string.format("%s is not a valid %s", RUtils.to_str(raw_val, true), cls.__name))
        end
        local boundary = cls._boundary_mode or (cls._is_int_mixin and "KEEP" or "STRICT")
        local mask = cls._all_flags_mask or 0

        local val = raw_val
        if val < 0 then
            if boundary == "EJECT" then return val end
            if boundary == "STRICT" then
                Runtime.raise("ValueError", string.format("%d is not a valid %s", val, cls.__name))
            elseif boundary == "CONFORM" then
                -- 二補數轉換後與 mask 交集
                local two_comp = (mask + 1) * 2 + val
                val = bit_and(two_comp, mask)
            end
        end

        if cls._value_map and cls._value_map[val] then
            return cls._value_map[val]
        end

        local unknown = val - bit_and(val, mask)
        if unknown ~= 0 then
            if boundary == "STRICT" then
                Runtime.raise("ValueError", string.format("%d is not a valid %s", raw_val, cls.__name))
            elseif boundary == "CONFORM" then
                val = bit_and(val, mask)
                if cls._value_map and cls._value_map[val] then return cls._value_map[val] end
            elseif boundary == "EJECT" then
                return raw_val
            end
            -- KEEP 模式則保留原 val 繼續往下建構複合 Flag
        end

        local parts, leftover = decompose_flag_members(cls, val)
        local name_parts = {}
        for _, m in ipairs(parts) do table.insert(name_parts, m.__dict._name) end
        if leftover > 0 then table.insert(name_parts, tostring(leftover)) end
        local comp_name = (#name_parts > 0) and table.concat(name_parts, "|") or nil

        local inst = PyClass.make_instance(cls)
        inst._is_enum_member = true
        inst.__dict._name = comp_name
        inst.__dict._value = val
        if cls._is_int_mixin then inst.__builtin_value = val end
        inst._enum_locked = true
        cls._value_map[val] = inst
        return inst
    end

    local function extract_flag_int(self, other, allow_int)
        if type(other) == "table" and other._is_enum_member and other.__class == self.__class then
            return other.__dict._value
        elseif allow_int and (type(other) == "number" or type(other) == "boolean") and math.floor(RUtils.unwrap_num(other)) == RUtils.unwrap_num(other) then
            return RUtils.unwrap_num(other)
        end
        return nil
    end

    local flag_dict = {
        __module__ = "enum",
        __or__ = fn("__or__", function(a)
            local self, other = a[1], a[2]
            local ov = extract_flag_int(self, other, self.__class._is_int_mixin)
            if ov == nil then Runtime.raise("TypeError", "unsupported operand type(s) for |") end
            return create_composite_flag(self.__class, bit_or(self.__dict._value, ov))
        end),
        __ror__ = fn("__ror__", function(a)
            local self, other = a[1], a[2]
            local ov = extract_flag_int(self, other, self.__class._is_int_mixin)
            if ov == nil then Runtime.raise("TypeError", "unsupported operand type(s) for |") end
            return create_composite_flag(self.__class, bit_or(ov, self.__dict._value))
        end),
        __and__ = fn("__and__", function(a)
            local self, other = a[1], a[2]
            local ov = extract_flag_int(self, other, self.__class._is_int_mixin)
            if ov == nil then Runtime.raise("TypeError", "unsupported operand type(s) for &") end
            return create_composite_flag(self.__class, bit_and(self.__dict._value, ov))
        end),
        __rand__ = fn("__rand__", function(a)
            local self, other = a[1], a[2]
            local ov = extract_flag_int(self, other, self.__class._is_int_mixin)
            if ov == nil then Runtime.raise("TypeError", "unsupported operand type(s) for &") end
            return create_composite_flag(self.__class, bit_and(ov, self.__dict._value))
        end),
        __xor__ = fn("__xor__", function(a)
            local self, other = a[1], a[2]
            local ov = extract_flag_int(self, other, self.__class._is_int_mixin)
            if ov == nil then Runtime.raise("TypeError", "unsupported operand type(s) for ^") end
            return create_composite_flag(self.__class, bit_xor(self.__dict._value, ov))
        end),
        __rxor__ = fn("__rxor__", function(a)
            local self, other = a[1], a[2]
            local ov = extract_flag_int(self, other, self.__class._is_int_mixin)
            if ov == nil then Runtime.raise("TypeError", "unsupported operand type(s) for ^") end
            return create_composite_flag(self.__class, bit_xor(ov, self.__dict._value))
        end),
        __invert__ = fn("__invert__", function(a)
            local self = a[1]
            local cls = self.__class
            if cls._boundary_mode == "EJECT" then
                return -(self.__dict._value + 1)
            end
            local mask = cls._all_flags_mask or 0
            local inv = bit_xor(mask, bit_and(mask, self.__dict._value))
            return create_composite_flag(cls, inv)
        end),
        __contains__ = fn("__contains__", function(a)
            local self, other = a[1], a[2]
            local ov = extract_flag_int(self, other, self.__class._is_int_mixin)
            if ov == nil then
                Runtime.raise("TypeError", "unsupported operand type(s) for 'in'")
            end
            if ov == 0 then return false end
            return bit_and(self.__dict._value, ov) == ov
        end),
        __iter__ = fn("__iter__", function(a)
            local self = a[1]
            local parts = decompose_flag_members(self.__class, self.__dict._value)
            return B.iter({ { __type = "list", elements = parts } })
        end),
        __len__ = fn("__len__", function(a)
            local self = a[1]
            local parts = decompose_flag_members(self.__class, self.__dict._value)
            return #parts
        end),
    }
    Flag = PyClass.make_class("Flag", { Enum }, flag_dict)
    Flag._is_enum_class = true
    Flag._is_enum_base = true
    Flag._is_flag_class = true
    Flag.__class = EnumType

    local int_flag_dict = {}
    for k, v in pairs(int_mixin_methods) do int_flag_dict[k] = v end
    for k, v in pairs(flag_dict) do int_flag_dict[k] = v end
    IntFlag = PyClass.make_class("IntFlag", { B.int, ReprEnum, Flag }, int_flag_dict)
    IntFlag._is_enum_class = true
    IntFlag._is_enum_base = true
    IntFlag._is_flag_class = true
    IntFlag._is_int_mixin = true
    IntFlag.__class = EnumType

    -- ==========================================
    -- [I] 攔截 PyClass.make_class:建構 Enum 子類別的黑魔法核心
    -- ==========================================
    local orig_make_class = PyClass.make_class

    local function find_source_positions(cls_name, keys)
        local pos_map = {}
        local tb = Runtime.Traceback
        local file_entry = tb and tb.files and tb.files[tb.current_file_idx or 1]
        local raw_code = file_entry and file_entry.raw_code or ""
        if raw_code == "" then return pos_map end

        local cls_start = raw_code:find("class%s+" .. cls_name .. "[%s%(%:]+") or 1
        for _, k in ipairs(keys) do
            local pat = "[\r\n;][ \t]*" .. k:gsub("([^%w_])", "%%%1") .. "[ \t]*[:=]"
            local s = raw_code:find(pat, cls_start)
            if s then pos_map[k] = s end
        end
        return pos_map
    end

    local function eval_auto_expr(node, resolved_map)
        if type(node) == "number" then return node end
        if type(node) == "table" then
            if node.__class == auto_cls then
                if node.__dict._expr then
                    local e = node.__dict._expr
                    local lv = eval_auto_expr(e.left, resolved_map)
                    local rv = e.right and eval_auto_expr(e.right, resolved_map) or 0
                    if e.op == "|" then return bit_or(lv, rv)
                    elseif e.op == "&" then return bit_and(lv, rv)
                    elseif e.op == "^" then return bit_xor(lv, rv)
                    elseif e.op == "+" then return lv + rv
                    elseif e.op == "~" then return bit_xor(0xFFFFFFFF, lv) end
                end
                return resolved_map[node] or node.__dict.value
            elseif node._is_enum_member then
                return node.__dict._value
            end
        end
        return tonumber(node) or 0
    end

    PyClass.make_class = function(name, bases, dict)
        local is_enum_sub = false
        local is_flag_sub = false
        local is_int_sub = false
        local is_str_sub = false

        for _, b in ipairs(bases or {}) do
            if type(b) == "table" then
                if b._is_enum_class then is_enum_sub = true end
                if b._is_flag_class then is_flag_sub = true end
                if b._is_int_mixin or b == B.int then is_int_sub = true end
                if b._is_str_mixin or b == B.str then is_str_sub = true end
            end
        end

        if not is_enum_sub or not dict or dict._skip_enum_meta then
            if dict then dict._skip_enum_meta = nil end
            return orig_make_class(name, bases, dict)
        end

        -- 1. 讀取 _ignore_ 與 _boundary_ 設定
        local ignore_set = {
            _ignore_ = true, _order_ = true, __order__ = true,
            _boundary_ = true, boundary = true,
            _generate_next_value_ = true, _missing_ = true
        }
        local raw_ignore = dict["_ignore_"]
        if type(raw_ignore) == "string" then
            for w in raw_ignore:gmatch("%S+") do ignore_set[w] = true end
        elseif type(raw_ignore) == "table" and raw_ignore.elements then
            for _, w in ipairs(raw_ignore.elements) do ignore_set[tostring(w)] = true end
        end

        local boundary_raw = dict["_boundary_"] or dict["boundary"]
        local boundary_mode = nil
        if boundary_raw ~= nil then
            if type(boundary_raw) == "table" and boundary_raw._is_enum_member then
                boundary_mode = tostring(boundary_raw.__dict._name or boundary_raw.__dict._value):upper()
            elseif type(boundary_raw) == "string" then
                boundary_mode = boundary_raw:upper()
            end
        end

        -- 2. 分離成員候選者與一般方法/描述器
        local raw_candidates = {}
        local cand_keys = {}
        local class_dict = {}
        local custom_init = dict["__init__"]
        local custom_gnv = dict["_generate_next_value_"]

        for k, v in pairs(dict) do
            if type(k) == "string" and (k:match("^__.*__$") or ignore_set[k]) then
                if k ~= "_ignore_" and k ~= "__init__" then
                    class_dict[k] = v
                end
            elseif type(v) == "table" and v._is_nonmember then
                class_dict[k] = v.__dict.value
            elseif type(v) == "table" and v._is_force_member then
                table.insert(cand_keys, k)
                raw_candidates[k] = { val = v.__dict.value, seq = v.__dict._seq }
            elseif type(v) == "table" and (
                v.__type == "function" or v.__type == "builtin_method" or
                v.__type == "classmethod" or v.__type == "staticmethod" or
                v.__type == "property" or v._is_enum_property or v.__type == "class"
            ) then
                class_dict[k] = v
            else
                local seq = (type(v) == "table" and v.__class == auto_cls and v.__dict._seq) or nil
                table.insert(cand_keys, k)
                raw_candidates[k] = { val = v, seq = seq }
            end
        end

        -- 3. 依據原始碼位置與 auto() 序號還原定義順序
        local pos_map = find_source_positions(name, cand_keys)
        local order_hint = dict["_order_"] or dict["__order__"]
        local order_idx = {}
        if type(order_hint) == "string" then
            local idx = 0
            for w in order_hint:gsub(",", " "):gmatch("%S+") do idx = idx + 1; order_idx[w] = idx end
        elseif type(order_hint) == "table" and order_hint.elements then
            for i, w in ipairs(order_hint.elements) do order_idx[tostring(w)] = i end
        end

        table.sort(cand_keys, function(a, b)
            if order_idx[a] and order_idx[b] then return order_idx[a] < order_idx[b] end
            local pa, pb = pos_map[a], pos_map[b]
            if pa and pb and pa ~= pb then return pa < pb end
            local sa, sb = raw_candidates[a].seq, raw_candidates[b].seq
            if sa and sb and sa ~= sb then return sa < sb end
            return tostring(a) < tostring(b)
        end)

        -- 4. 處理 auto() 自動賦值
        local last_values = {}
        local resolved_autos = {}
        local count = 0

        for _, k in ipairs(cand_keys) do
            local entry = raw_candidates[k]
            local v = entry.val
            if type(v) == "table" and v.__class == auto_cls then
                if v.__dict._expr then
                    v = eval_auto_expr(v, resolved_autos)
                elseif v.__dict.value ~= AUTO_SENTINEL then
                    v = v.__dict.value
                else
                    if custom_gnv then
                        local fn_gnv = (custom_gnv.__type == "staticmethod" or custom_gnv.__type == "classmethod") and custom_gnv.__func or custom_gnv
                        v = Evaluator.invoke(fn_gnv, { k, 1, count, { __type = "list", elements = last_values } }, {})
                    elseif is_str_sub then
                        v = k:lower()
                    elseif is_flag_sub then
                        local max_bit = 0
                        for _, lv in ipairs(last_values) do
                            if type(lv) == "number" and lv > max_bit then max_bit = lv end
                        end
                        if max_bit == 0 then v = 1
                        else
                            local p = 1
                            while p <= max_bit do p = p * 2 end
                            v = p
                        end
                    else
                        local max_int = 0
                        for _, lv in ipairs(last_values) do
                            if type(lv) == "number" and math.floor(lv) == lv and lv > max_int then
                                max_int = lv
                            end
                        end
                        v = max_int + 1
                    end
                end
                resolved_autos[entry.val] = v
                entry.val = v
            end
            count = count + 1
            table.insert(last_values, entry.val)
        end

        -- 5. 建立 Enum 子類別本體
        local cls = orig_make_class(name, bases, class_dict)
        cls._is_enum_class = true
        cls._is_flag_class = is_flag_sub
        cls._is_int_mixin = is_int_sub
        cls._is_str_mixin = is_str_sub
        cls._boundary_mode = boundary_mode or (is_flag_sub and (is_int_sub and "KEEP" or "STRICT") or nil)
        cls.__class = EnumType

        cls._member_list = {}
        cls._member_map = {}
        cls._value_map = {}
        cls._aliases = {}
        cls._all_flags_mask = 0
        cls._single_bit_mask = 0

        -- 6. 實例化列舉成員與處理別名 (Aliases)
        for _, k in ipairs(cand_keys) do
            local raw_val = raw_candidates[k].val
            local member_val = raw_val
            local init_args = { raw_val }

            if is_int_sub then
                if type(raw_val) == "table" and raw_val.__type == "tuple" then
                    member_val = B.int.__call({ raw_val.elements[1] })
                    init_args = raw_val.elements
                else
                    member_val = B.int.__call({ raw_val })
                end
            elseif is_str_sub then
                if type(raw_val) == "table" and raw_val.__type == "tuple" then
                    member_val = tostring(raw_val.elements[1])
                    init_args = raw_val.elements
                else
                    if type(raw_val) ~= "string" then
                        Runtime.raise("TypeError", string.format("%s is not a string", RUtils.to_str(raw_val, true)))
                    end
                    member_val = raw_val
                end
            elseif custom_init and type(raw_val) == "table" and raw_val.__type == "tuple" then
                init_args = raw_val.elements
            end

            -- 檢查是否為既有成員的別名 (Alias)
            local existing_canonical = nil
            for _, m in ipairs(cls._member_list) do
                if RUtils.runtime_is_equal(m.__dict._value, member_val) and type(m.__dict._value) == type(member_val) then
                    existing_canonical = m
                    break
                end
            end

            if existing_canonical then
                cls._member_map[k] = existing_canonical
                cls.__dict[k] = existing_canonical
                table.insert(cls._aliases, { alias = k, canonical = existing_canonical.__dict._name, value = member_val })
            else
                local inst = PyClass.make_instance(cls)
                inst._is_enum_member = true
                inst.__dict._name = k
                inst.__dict._value = member_val
                if is_int_sub or is_str_sub then
                    inst.__builtin_value = member_val
                end

                if custom_init then
                    local call_args = { inst }
                    for _, arg in ipairs(init_args) do table.insert(call_args, arg) end
                    Evaluator.invoke(custom_init, call_args, {})
                end
                inst._enum_locked = true

                table.insert(cls._member_list, inst)
                cls._member_map[k] = inst
                cls.__dict[k] = inst
                if type(member_val) ~= "table" then
                    cls._value_map[member_val] = inst
                end

                if is_flag_sub and type(member_val) == "number" and member_val > 0 then
                    cls._all_flags_mask = bit_or(cls._all_flags_mask, member_val)
                    if is_power_of_two(member_val) then
                        cls._single_bit_mask = bit_or(cls._single_bit_mask, member_val)
                    end
                end
            end
        end

        -- 7. 建構 __members__ 字典 (含別名)
        local members_pairs = {}
        for _, k in ipairs(cand_keys) do
            table.insert(members_pairs, { key = k, value = cls._member_map[k] })
        end
        cls.__dict["__members__"] = { __type = "dict", pairs = members_pairs }

        -- 8. 掛載 Cls(val) 值反查構造器
        local function enum_lookup_by_value(args)
            local offset = (args and args[1] == cls) and 1 or 0
            if not args or #args <= offset then
                Runtime.raise("TypeError", string.format("%s() missing required argument: 'value'", cls.__name))
            end
            local target_val = args[offset + 1]
            if type(target_val) == "table" and target_val._is_enum_member and target_val.__class == cls then
                return target_val
            end
            if type(target_val) ~= "table" and cls._value_map[target_val] ~= nil then
                return cls._value_map[target_val]
            end
            for _, m in ipairs(cls._member_list) do
                if RUtils.runtime_is_equal(m.__dict._value, target_val) and type(m.__dict._value) == type(target_val) then
                    return m
                end
            end
            if cls._is_flag_class and type(target_val) == "number" and math.floor(target_val) == target_val then
                return create_composite_flag(cls, target_val)
            end
            local missing_fn = dict["_missing_"]
            if missing_fn then
                local fn_m = (missing_fn.__type == "classmethod" or missing_fn.__type == "staticmethod") and missing_fn.__func or missing_fn
                local res = Evaluator.invoke(fn_m, { cls, target_val }, {})
                if res ~= nil and res ~= B.None then return res end
            end
            Runtime.raise("ValueError", string.format("%s is not a valid %s", RUtils.to_str(target_val, true), cls.__name))
        end

        cls.__dict["__new__"] = {
            __type = "staticmethod",
            __func = fn("__new__", enum_lookup_by_value)
        }
        cls.__dict["__init__"] = fn("__init__", function() return nil end)
        cls.__call = enum_lookup_by_value
        setmetatable(cls, { __call = function(_, args, kwargs) return enum_lookup_by_value(args, kwargs) end })

        cls._enum_locked = true
        return cls
    end

    -- ==========================================
    -- [J] 掛載系統級攔截:支援 iter(Color), len(Color), reversed(Color) 與屬性鎖定
    -- ==========================================
    if not B._enum_patched then
        B._enum_patched = true
        local orig_len = B.len
        local orig_iter = B.iter
        local orig_reversed = B.reversed
        local orig_raw_set_attr = PyClass.raw_set_attr
        local orig_runtime_eq = RUtils.runtime_is_equal

        B.len = function(args)
            local obj = args and args[1]
            if type(obj) == "table" and obj.__type == "class" and obj._is_enum_class then
                return #(obj._member_list or {})
            end
            return orig_len(args)
        end

        B.iter = function(args)
            local obj = args and args[1]
            if type(obj) == "table" and obj.__type == "class" and obj._is_enum_class then
                return orig_iter({ { __type = "list", elements = obj._member_list or {} } })
            end
            return orig_iter(args)
        end

        B.reversed = function(args)
            local obj = args and args[1]
            if type(obj) == "table" and obj.__type == "class" and obj._is_enum_class then
                return orig_reversed({ { __type = "list", elements = obj._member_list or {} } })
            end
            return orig_reversed(args)
        end

        PyClass.raw_set_attr = function(obj, attr_name, value)
            if type(obj) == "table" and obj.__type == "class" and obj._is_enum_class and obj._enum_locked then
                if obj._member_map and obj._member_map[attr_name] then
                    Runtime.raise("AttributeError", "cannot reassign member '" .. tostring(attr_name) .. "'")
                end
            end
            return orig_raw_set_attr(obj, attr_name, value)
        end

        RUtils.runtime_is_equal = function(a, b, seen)
            if a == b then return true end
            if type(a) == "table" and a._is_enum_member and a.__builtin_value ~= nil then
                if type(b) == "table" and b._is_enum_member then
                    if b.__builtin_value ~= nil then return orig_runtime_eq(a.__builtin_value, b.__builtin_value, seen) end
                    return false
                end
                return orig_runtime_eq(a.__builtin_value, b, seen)
            end
            if type(b) == "table" and b._is_enum_member and b.__builtin_value ~= nil then
                return orig_runtime_eq(a, b.__builtin_value, seen)
            end
            return orig_runtime_eq(a, b, seen)
        end
    end

    -- ==========================================
    -- [K] 建立 EnumCheck、FlagBoundary、@unique、@verify、@global_enum
    -- ==========================================
    local EnumCheck = PyClass.make_class("EnumCheck", { StrEnum }, {
        CONTINUOUS  = "no skipped integer values",
        NAMED_FLAGS = "multi-flag aliases may not contain unnamed flags",
        UNIQUE      = "one name per value",
        _order_     = "CONTINUOUS NAMED_FLAGS UNIQUE"
    })

    local FlagBoundary = PyClass.make_class("FlagBoundary", { StrEnum }, {
        STRICT  = "strict",
        CONFORM = "conform",
        EJECT   = "eject",
        KEEP    = "keep",
        _order_ = "STRICT CONFORM EJECT KEEP"
    })

    local function check_unique(cls)
        if cls._aliases and #cls._aliases > 0 then
            local parts = {}
            for _, al in ipairs(cls._aliases) do
                table.insert(parts, string.format("%s -> %s", al.alias, al.canonical))
            end
            Runtime.raise("ValueError", string.format("duplicate values found in <enum '%s'>: %s", cls.__name, table.concat(parts, ", ")))
        end
        return cls
    end

    local function check_continuous(cls)
        local vals = {}
        for _, m in ipairs(cls._member_list or {}) do
            local v = m.__dict._value
            if type(v) ~= "number" or math.floor(v) ~= v then
                Runtime.raise("ValueError", string.format("invalid enum '%s': non-integer values present", cls.__name))
            end
            table.insert(vals, v)
        end
        if #vals >= 2 then
            table.sort(vals)
            local val_set = {}
            for _, v in ipairs(vals) do val_set[v] = true end
            local missing = {}
            for i = vals[1], vals[#vals] do
                if not val_set[i] then table.insert(missing, tostring(i)) end
            end
            if #missing > 0 then
                Runtime.raise("ValueError", string.format("invalid enum '%s': missing values %s", cls.__name, table.concat(missing, ", ")))
            end
        end
        return cls
    end

    local function check_named_flags(cls)
        local single_mask = cls._single_bit_mask or 0
        local bad = {}
        for _, m in ipairs(cls._member_list or {}) do
            local v = m.__dict._value
            if type(v) == "number" and v > 0 and not is_power_of_two(v) then
                if bit_and(v, single_mask) ~= v then
                    table.insert(bad, m.__dict._name)
                end
            end
        end
        if #bad > 0 then
            Runtime.raise("ValueError", string.format("invalid Flag '%s': alias %s is missing value", cls.__name, table.concat(bad, ", ")))
        end
        return cls
    end

    local unique_fn = fn("unique", function(a)
        local offset = (a[1] == enum_mod_cache) and 1 or 0
        return check_unique(a[offset + 1])
    end)

    local verify_fn = fn("verify", function(a)
        local start_i = (a[1] == enum_mod_cache) and 2 or 1
        local checks = {}
        for i = start_i, #a do table.insert(checks, a[i]) end
        return fn("verify_decorator", function(dec_args)
            local cls = dec_args[1]
            for _, chk in ipairs(checks) do
                local cname = (type(chk) == "table" and chk._is_enum_member) and chk.__dict._name or tostring(chk)
                if cname == "UNIQUE" or chk == EnumCheck.__dict.UNIQUE then
                    check_unique(cls)
                elseif cname == "CONTINUOUS" or chk == EnumCheck.__dict.CONTINUOUS then
                    check_continuous(cls)
                elseif cname == "NAMED_FLAGS" or chk == EnumCheck.__dict.NAMED_FLAGS then
                    check_named_flags(cls)
                end
            end
            return cls
        end)
    end)

    local global_enum_fn = fn("global_enum", function(a)
        local offset = (a[1] == enum_mod_cache) and 1 or 0
        local cls = a[offset + 1]
        cls._is_global_enum = true
        local scope = Runtime.Traceback.current_scope
        if scope then
            local root = scope
            while root.parent do root = root.parent end
            for k, m in pairs(cls._member_map or {}) do
                root.vars[k] = m
            end
        end
        return cls
    end)

    -- 封裝匯出 enum 模組
    enum_mod_cache = PyClass.make_instance(PyClass.make_class("module", {}, {}))
    local d = enum_mod_cache.__dict
    d["__name__"]     = "enum"
    d.Enum            = Enum
    d.IntEnum         = IntEnum
    d.StrEnum         = StrEnum
    d.Flag            = Flag
    d.IntFlag         = IntFlag
    d.ReprEnum        = ReprEnum
    d.EnumType        = EnumType
    d.EnumMeta        = EnumType
    d.EnumCheck       = EnumCheck
    d.CONTINUOUS      = EnumCheck.__dict.CONTINUOUS
    d.NAMED_FLAGS     = EnumCheck.__dict.NAMED_FLAGS
    d.UNIQUE          = EnumCheck.__dict.UNIQUE
    d.FlagBoundary    = FlagBoundary
    d.STRICT          = FlagBoundary.__dict.STRICT
    d.CONFORM         = FlagBoundary.__dict.CONFORM
    d.EJECT           = FlagBoundary.__dict.EJECT
    d.KEEP            = FlagBoundary.__dict.KEEP
    d.auto            = auto_cls
    d.unique          = unique_fn
    d.verify          = verify_fn
    d.property        = enum_property
    d.member          = member_cls
    d.nonmember       = nonmember_cls
    d.global_enum     = global_enum_fn
end

-- ==========================================
-- 2. ARRAY 模組核心實作
-- ==========================================
local TYPECODE_SPECS = {
    b = { size = 1, kind = "int",   signed = true,  min = -128,                max = 127 },
    B = { size = 1, kind = "int",   signed = false, min = 0,                   max = 255 },
    u = { size = 2, kind = "uchar" },
    w = { size = 4, kind = "uchar" },
    h = { size = 2, kind = "int",   signed = true,  min = -32768,              max = 32767 },
    H = { size = 2, kind = "int",   signed = false, min = 0,                   max = 65535 },
    i = { size = 4, kind = "int",   signed = true,  min = -2147483648,         max = 2147483647 },
    I = { size = 4, kind = "int",   signed = false, min = 0,                   max = 4294967295 },
    l = { size = 4, kind = "int",   signed = true,  min = -2147483648,         max = 2147483647 },
    L = { size = 4, kind = "int",   signed = false, min = 0,                   max = 4294967295 },
    q = { size = 8, kind = "int64", signed = true  },
    Q = { size = 8, kind = "int64", signed = false },
    f = { size = 4, kind = "float", single = true  },
    d = { size = 8, kind = "float", single = false },
}

-- Little-Endian 二進位整數與 IEEE-754 浮點數打包/解包器
local function pack_uint_le(val, nbytes)
    local bytes = {}
    for i = 1, nbytes do
        local r = val % 256
        bytes[i] = string.char(r)
        val = (val - r) / 256
    end
    return table.concat(bytes)
end

local function unpack_uint_le(s, pos, nbytes)
    local val, mult = 0, 1
    for i = 0, nbytes - 1 do
        val = val + string.byte(s, pos + i) * mult
        mult = mult * 256
    end
    return val
end

local function pack_float32_le(x)
    if x == 0 then
        local is_neg = (1 / x == -math.huge)
        return string.char(0, 0, 0, is_neg and 128 or 0)
    elseif x ~= x then
        return string.char(0, 0, 192, 127)
    elseif x == math.huge or x == -math.huge then
        return string.char(0, 0, 128, x < 0 and 255 or 127)
    end
    local sign = 0
    if x < 0 then sign = 128; x = -x end
    local mant, exp = math.frexp(x)
    exp = exp + 126
    if exp <= 0 then
        mant = math.floor(mant * 2 ^ (24 + exp) + 0.5)
        exp = 0
    else
        mant = math.floor((mant * 2 - 1) * 2 ^ 23 + 0.5)
        if mant >= 2 ^ 23 then mant = 0; exp = exp + 1 end
        if exp >= 255 then return string.char(0, 0, 128, sign + 127) end
    end
    local b1 = mant % 256; mant = (mant - b1) / 256
    local b2 = mant % 256; local b3_m = (mant - b2) / 256
    local b3 = b3_m + (exp % 2) * 128
    local b4 = sign + math.floor(exp / 2)
    return string.char(b1, b2, b3, b4)
end

local function unpack_float32_le(s, pos)
    local b1, b2, b3, b4 = string.byte(s, pos, pos + 3)
    local sign = (b4 >= 128) and -1 or 1
    local exp = (b4 % 128) * 2 + math.floor(b3 / 128)
    local mant = ((b3 % 128) * 256 + b2) * 256 + b1
    if exp == 0 and mant == 0 then return 0.0 * sign
    elseif exp == 255 then return (mant == 0) and (math.huge * sign) or (0/0)
    elseif exp == 0 then return sign * math.ldexp(mant, -149)
    else return sign * math.ldexp(mant + 2 ^ 23, exp - 150) end
end

local function pack_float64_le(x)
    if x == 0 then
        local is_neg = (1 / x == -math.huge)
        return string.char(0, 0, 0, 0, 0, 0, 0, is_neg and 128 or 0)
    elseif x ~= x then
        return string.char(0, 0, 0, 0, 0, 0, 248, 127)
    elseif x == math.huge or x == -math.huge then
        return string.char(0, 0, 0, 0, 0, 0, 240, x < 0 and 255 or 127)
    end
    local sign = 0
    if x < 0 then sign = 128; x = -x end
    local mant, exp = math.frexp(x)
    exp = exp + 1022
    if exp <= 0 then
        mant = math.floor(mant * 2 ^ (53 + exp) + 0.5)
        exp = 0
    else
        mant = math.floor((mant * 2 - 1) * 2 ^ 52 + 0.5)
        if mant >= 2 ^ 52 then mant = 0; exp = exp + 1 end
        if exp >= 2047 then return string.char(0, 0, 0, 0, 0, 0, 240, sign + 127) end
    end
    local bytes = {}
    for i = 1, 6 do
        local r = mant % 256
        bytes[i] = string.char(r)
        mant = (mant - r) / 256
    end
    bytes[7] = string.char(mant + (exp % 16) * 16)
    bytes[8] = string.char(sign + math.floor(exp / 16))
    return table.concat(bytes)
end

local function unpack_float64_le(s, pos)
    local b1, b2, b3, b4, b5, b6, b7, b8 = string.byte(s, pos, pos + 7)
    local sign = (b8 >= 128) and -1 or 1
    local exp = (b8 % 128) * 16 + math.floor(b7 / 16)
    local mant = ((((((b7 % 16) * 256 + b6) * 256 + b5) * 256 + b4) * 256 + b3) * 256 + b2) * 256 + b1
    if exp == 0 and mant == 0 then return 0.0 * sign
    elseif exp == 2047 then return (mant == 0) and (math.huge * sign) or (0/0)
    elseif exp == 0 then return sign * math.ldexp(mant, -1074)
    else return sign * math.ldexp(mant + 2 ^ 52, exp - 1075) end
end

local function validate_and_coerce_item(tc, spec, val)
    if type(val) == "table" and val.__type == "instance" and val.__builtin_value ~= nil then
        val = val.__builtin_value
    end
    if spec.kind == "uchar" then
        if type(val) ~= "string" or mw.ustring.len(val) ~= 1 then
            Runtime.raise("TypeError", "array item must be unicode character")
        end
        return val
    elseif spec.kind == "float" then
        if type(val) == "boolean" then val = val and 1.0 or 0.0 end
        local n = RUtils.unwrap_num(val)
        if type(n) ~= "number" then
            Runtime.raise("TypeError", "must be real number, not " .. RUtils.get_type_str(val))
        end
        if spec.single then
            return unpack_float32_le(pack_float32_le(n), 1)
        end
        return n
    elseif spec.kind == "int" then
        if type(val) == "number" and math.floor(val) ~= val then
            Runtime.raise("TypeError", "'" .. RUtils.get_type_str(val) .. "' object cannot be interpreted as an integer")
        end
        if type(val) == "table" and val.__type == "int" and val.is_big then
            Runtime.raise("OverflowError", "int too big to convert")
        end
        local n = RUtils.unwrap_num(val)
        if type(n) ~= "number" or math.floor(n) ~= n then
            Runtime.raise("TypeError", "'" .. RUtils.get_type_str(val) .. "' object cannot be interpreted as an integer")
        end
        if n < spec.min then
            Runtime.raise("OverflowError", spec.signed and "signed integer is less than minimum" or "can't convert negative value to unsigned int")
        elseif n > spec.max then
            Runtime.raise("OverflowError", (spec.signed and "signed" or "unsigned") .. " integer is greater than maximum")
        end
        return n
    elseif spec.kind == "int64" then
        if type(val) == "number" and math.floor(val) ~= val then
            Runtime.raise("TypeError", "'float' object cannot be interpreted as an integer")
        end
        local n = RUtils.unwrap_num(val)
        if type(n) ~= "number" then
            Runtime.raise("TypeError", "'" .. RUtils.get_type_str(val) .. "' object cannot be interpreted as an integer")
        end
        if not spec.signed and n < 0 then
            Runtime.raise("OverflowError", "can't convert negative value to unsigned int")
        end
        return n
    end
end

local function pack_item(tc, spec, v)
    if spec.kind == "uchar" then
        return pack_uint_le(mw.ustring.codepoint(v, 1), spec.size)
    elseif spec.kind == "float" then
        return spec.single and pack_float32_le(v) or pack_float64_le(v)
    elseif spec.kind == "int" or spec.kind == "int64" then
        local u = v
        if u < 0 then u = u + (256 ^ spec.size) end
        return pack_uint_le(u, spec.size)
    end
end

local function unpack_item(tc, spec, s, pos)
    if spec.kind == "uchar" then
        local cp = unpack_uint_le(s, pos, spec.size)
        return mw.ustring.char(cp)
    elseif spec.kind == "float" then
        return spec.single and unpack_float32_le(s, pos) or unpack_float64_le(s, pos)
    elseif spec.kind == "int" or spec.kind == "int64" then
        local u = unpack_uint_le(s, pos, spec.size)
        if spec.signed then
            local half = 2 ^ (spec.size * 8 - 1)
            if u >= half then u = u - 2 * half end
        end
        return u
    end
end

local function ensure_array_init()
    if array_initialized then return end
    array_initialized = true

    local array_cls
    local function make_array_inst(tc, elements)
        local spec = TYPECODE_SPECS[tc]
        local inst = PyClass.make_instance(array_cls)
        inst._is_array = true
        inst.__dict._tc = tc
        inst.__dict._spec = spec
        inst.__dict._elements = elements or {}
        return inst
    end

    local array_dict = {
        __module__ = "array",
        typecode = {
            __type = "property",
            fget = fn("typecode", function(a) return a[1].__dict._tc end)
        },
        itemsize = {
            __type = "property",
            fget = fn("itemsize", function(a) return a[1].__dict._spec.size end)
        },
        __init__ = fn("__init__", function(a)
            local self, tc, init = a[1], a[2], a[3]
            if type(tc) ~= "string" or #tc ~= 1 then
                Runtime.raise("TypeError", "array() argument 1 must be a unicode character, not " .. RUtils.get_type_str(tc))
            end
            local spec = TYPECODE_SPECS[tc]
            if not spec then
                Runtime.raise("ValueError", "bad typecode (must be b, B, u, h, H, i, I, l, L, q, Q, f, d or w)")
            end
            self._is_array = true
            self.__dict._tc = tc
            self.__dict._spec = spec
            self.__dict._elements = {}

            if init ~= nil then
                if type(init) == "table" and (init.__type == "bytes" or init.__type == "bytearray" or init.__type == "memoryview") then
                    Evaluator.invoke(PyClass.get_attr(self, "frombytes"), { init }, {})
                elseif type(init) == "string" then
                    if spec.kind == "uchar" then
                        Evaluator.invoke(PyClass.get_attr(self, "fromunicode"), { init }, {})
                    else
                        Runtime.raise("TypeError", "cannot use a str to initialize an array with typecode '" .. tc .. "'")
                    end
                else
                    Evaluator.invoke(PyClass.get_attr(self, "extend"), { init }, {})
                end
            end
            return nil
        end),
        append = fn("append", function(a)
            local self, v = a[1], a[2]
            local coerced = validate_and_coerce_item(self.__dict._tc, self.__dict._spec, v)
            table.insert(self.__dict._elements, coerced)
            return B.None
        end),
        extend = fn("extend", function(a)
            local self, iter_obj = a[1], a[2]
            if type(iter_obj) == "table" and (iter_obj.__type == "bytes" or iter_obj.__type == "bytearray") then
                Runtime.raise("TypeError", "can only extend with array of same kind")
            end
            if type(iter_obj) == "table" and iter_obj._is_array then
                if iter_obj.__dict._tc ~= self.__dict._tc then
                    Runtime.raise("TypeError", "can only extend with array of same kind")
                end
                local src = {}
                for _, item in ipairs(iter_obj.__dict._elements) do table.insert(src, item) end
                for _, item in ipairs(src) do table.insert(self.__dict._elements, item) end
                return B.None
            end
            local tc, spec = self.__dict._tc, self.__dict._spec
            local elts = self.__dict._elements
            local iter_fn = RUtils.get_iterator(iter_obj)
            while true do
                local has_next, item = iter_fn()
                if not has_next then break end
                table.insert(elts, validate_and_coerce_item(tc, spec, item))
            end
            return B.None
        end),
        insert = fn("insert", function(a)
            local self, idx, v = a[1], RUtils.unwrap_num(a[2]), a[3]
            if type(idx) ~= "number" or math.floor(idx) ~= idx then
                Runtime.raise("TypeError", "integer argument expected")
            end
            local coerced = validate_and_coerce_item(self.__dict._tc, self.__dict._spec, v)
            local elts = self.__dict._elements
            local len = #elts
            if idx < 0 then idx = math.max(0, len + idx)
            elseif idx > len then idx = len end
            table.insert(elts, idx + 1, coerced)
            return B.None
        end),
        pop = fn("pop", function(a)
            local self = a[1]
            local elts = self.__dict._elements
            if #elts == 0 then Runtime.raise("IndexError", "pop from empty array") end
            local idx = (a[2] ~= nil) and RUtils.unwrap_num(a[2]) or -1
            if type(idx) ~= "number" or math.floor(idx) ~= idx then
                Runtime.raise("TypeError", "integer argument expected")
            end
            if idx < 0 then idx = #elts + idx end
            if idx < 0 or idx >= #elts then Runtime.raise("IndexError", "pop index out of range") end
            return table.remove(elts, idx + 1)
        end),
        remove = fn("remove", function(a)
            local self, v = a[1], a[2]
            local elts = self.__dict._elements
            for i, item in ipairs(elts) do
                if RUtils.runtime_is_equal(item, v) then
                    table.remove(elts, i)
                    return B.None
                end
            end
            Runtime.raise("ValueError", "array.remove(x): x not in array")
        end),
        index = fn("index", function(a)
            local self, v = a[1], a[2]
            local elts = self.__dict._elements
            local len = #elts
            local start_i = (a[3] ~= nil) and RUtils.unwrap_num(a[3]) or 0
            local stop_i  = (a[4] ~= nil) and RUtils.unwrap_num(a[4]) or len
            if start_i < 0 then start_i = math.max(0, len + start_i) end
            if stop_i < 0 then stop_i = math.max(0, len + stop_i) end
            stop_i = math.min(len, stop_i)
            for i = start_i + 1, stop_i do
                if RUtils.runtime_is_equal(elts[i], v) then return i - 1 end
            end
            Runtime.raise("ValueError", "array.index(x): x not in array")
        end),
        count = fn("count", function(a)
            local self, v = a[1], a[2]
            local c = 0
            for _, item in ipairs(self.__dict._elements) do
                if RUtils.runtime_is_equal(item, v) then c = c + 1 end
            end
            return c
        end),
        reverse = fn("reverse", function(a)
            local elts = a[1].__dict._elements
            local i, j = 1, #elts
            while i < j do
                elts[i], elts[j] = elts[j], elts[i]
                i = i + 1; j = j - 1
            end
            return B.None
        end),
        tolist = fn("tolist", function(a)
            local copy = {}
            for i, v in ipairs(a[1].__dict._elements) do copy[i] = v end
            return { __type = "list", elements = copy }
        end),
        fromlist = fn("fromlist", function(a)
            local self, lst = a[1], a[2]
            if type(lst) ~= "table" or lst.__type ~= "list" then
                Runtime.raise("TypeError", "arg must be list")
            end
            local tc, spec = self.__dict._tc, self.__dict._spec
            local staged = {}
            for i, item in ipairs(lst.elements) do
                staged[i] = validate_and_coerce_item(tc, spec, item)
            end
            for _, item in ipairs(staged) do
                table.insert(self.__dict._elements, item)
            end
            return B.None
        end),
        tobytes = fn("tobytes", function(a)
            local self = a[1]
            local tc, spec = self.__dict._tc, self.__dict._spec
            local chunks = {}
            for i, v in ipairs(self.__dict._elements) do
                chunks[i] = pack_item(tc, spec, v)
            end
            return { __type = "bytes", _data = table.concat(chunks) }
        end),
        frombytes = fn("frombytes", function(a)
            local self, b = a[1], a[2]
            local data
            if type(b) == "table" and (b.__type == "bytes" or b.__type == "bytearray" or b.__type == "memoryview") then
                if b.__type == "memoryview" and b._released then
                    Runtime.raise("ValueError", "operation forbidden on released memoryview object")
                end
                data = b._data
            else
                Runtime.raise("TypeError", "a bytes-like object is required, not '" .. RUtils.get_type_str(b) .. "'")
            end
            local tc, spec = self.__dict._tc, self.__dict._spec
            local sz = spec.size
            if #data % sz ~= 0 then
                Runtime.raise("ValueError", "bytes length not a multiple of item size")
            end
            local elts = self.__dict._elements
            for pos = 1, #data, sz do
                table.insert(elts, unpack_item(tc, spec, data, pos))
            end
            return B.None
        end),
        tounicode = fn("tounicode", function(a)
            local self = a[1]
            if self.__dict._spec.kind ~= "uchar" then
                Runtime.raise("ValueError", "tounicode() may only be called on unicode type arrays")
            end
            return table.concat(self.__dict._elements)
        end),
        fromunicode = fn("fromunicode", function(a)
            local self, s = a[1], a[2]
            if self.__dict._spec.kind ~= "uchar" then
                Runtime.raise("ValueError", "fromunicode() may only be called on unicode type arrays")
            end
            if type(s) ~= "string" then
                Runtime.raise("TypeError", "fromunicode() argument must be str, not " .. RUtils.get_type_str(s))
            end
            local elts = self.__dict._elements
            for i = 1, mw.ustring.len(s) do
                table.insert(elts, mw.ustring.sub(s, i, i))
            end
            return B.None
        end),
        tofile = fn("tofile", function(a)
            local self, f = a[1], a[2]
            local ok, write_m = pcall(PyClass.get_attr, f, "write")
            if not ok or not write_m then
                Runtime.raise("TypeError", "tofile() argument must be a file-like object with a write() method")
            end
            local bytes_obj = Evaluator.invoke(PyClass.get_attr(self, "tobytes"), {}, {})
            -- 相容 io.BytesIO 與 io.StringIO
            local payload = bytes_obj
            if type(f) == "table" and f.__dict and f.__dict._is_bytes == false then
                payload = bytes_obj._data
            end
            Evaluator.invoke(write_m, { payload }, {})
            return B.None
        end),
        fromfile = fn("fromfile", function(a)
            local self, f, n = a[1], a[2], RUtils.unwrap_num(a[3])
            if type(n) ~= "number" or math.floor(n) ~= n then
                Runtime.raise("TypeError", "an integer is required")
            end
            if n < 0 then Runtime.raise("ValueError", "negative count") end
            local ok, read_m = pcall(PyClass.get_attr, f, "read")
            if not ok or not read_m then
                Runtime.raise("TypeError", "fromfile() argument 1 must be a file-like object with a read() method")
            end
            local tc, spec = self.__dict._tc, self.__dict._spec
            local sz = spec.size
            local need_bytes = n * sz
            local res = Evaluator.invoke(read_m, { need_bytes }, {})
            local raw_data = (type(res) == "table" and res._data) or (type(res) == "string" and res) or ""
            local full_items = math.floor(#raw_data / sz)
            local elts = self.__dict._elements
            for i = 0, full_items - 1 do
                table.insert(elts, unpack_item(tc, spec, raw_data, i * sz + 1))
            end
            if full_items < n then
                Runtime.raise("EOFError", "read() didn't return enough bytes")
            end
            return B.None
        end),
        byteswap = fn("byteswap", function(a)
            local self = a[1]
            local tc, spec = self.__dict._tc, self.__dict._spec
            local sz = spec.size
            if sz == 1 then return B.None end
            local elts = self.__dict._elements
            for i, v in ipairs(elts) do
                local packed = pack_item(tc, spec, v)
                local rev = packed:reverse()
                elts[i] = unpack_item(tc, spec, rev, 1)
            end
            return B.None
        end),
        buffer_info = fn("buffer_info", function(a)
            local self = a[1]
            return { __type = "tuple", elements = { B.id({ self }), #self.__dict._elements } }
        end),
        __len__ = fn("__len__", function(a) return #a[1].__dict._elements end),
        __iter__ = fn("__iter__", function(a)
            return B.iter({ { __type = "list", elements = a[1].__dict._elements } })
        end),
        __contains__ = fn("__contains__", function(a)
            local self, v = a[1], a[2]
            for _, item in ipairs(self.__dict._elements) do
                if RUtils.runtime_is_equal(item, v) then return true end
            end
            return false
        end),
        __getitem__ = fn("__getitem__", function(a)
            local self, idx = a[1], a[2]
            local elts = self.__dict._elements
            local len = #elts
            if type(idx) == "table" and idx.__type == "instance" and idx.__class == B.slice then
                local step = (idx.__dict.step ~= B.None and idx.__dict.step ~= nil) and RUtils.unwrap_num(idx.__dict.step) or 1
                if step == 0 then Runtime.raise("ValueError", "slice step cannot be zero") end
                local start_i, stop_i
                if step > 0 then
                    start_i = (idx.__dict.start ~= B.None and idx.__dict.start ~= nil) and RUtils.unwrap_num(idx.__dict.start) or 0
                    stop_i  = (idx.__dict.stop ~= B.None and idx.__dict.stop ~= nil) and RUtils.unwrap_num(idx.__dict.stop) or len
                    if start_i < 0 then start_i = math.max(0, len + start_i) else start_i = math.min(len, start_i) end
                    if stop_i < 0 then stop_i = math.max(0, len + stop_i) else stop_i = math.min(len, stop_i) end
                else
                    start_i = (idx.__dict.start ~= B.None and idx.__dict.start ~= nil) and RUtils.unwrap_num(idx.__dict.start) or (len - 1)
                    stop_i  = (idx.__dict.stop ~= B.None and idx.__dict.stop ~= nil) and RUtils.unwrap_num(idx.__dict.stop) or -1
                    if start_i < 0 then start_i = len + start_i end
                    if start_i >= len then start_i = len - 1 end
                    if idx.__dict.stop ~= B.None and idx.__dict.stop ~= nil and stop_i < 0 then stop_i = len + stop_i end
                end
                local sliced = {}
                local cur = start_i
                while (step > 0 and cur < stop_i) or (step < 0 and cur > stop_i) do
                    if cur >= 0 and cur < len then
                        table.insert(sliced, elts[cur + 1])
                    end
                    cur = cur + step
                end
                return make_array_inst(self.__dict._tc, sliced)
            end
            local n = RUtils.unwrap_num(idx)
            if type(n) ~= "number" or math.floor(n) ~= n then
                Runtime.raise("TypeError", "array indices must be integers")
            end
            if n < 0 then n = len + n end
            if n < 0 or n >= len then Runtime.raise("IndexError", "array index out of range") end
            return elts[n + 1]
        end),
        __setitem__ = fn("__setitem__", function(a)
            local self, idx, v = a[1], a[2], a[3]
            local elts = self.__dict._elements
            local len = #elts
            local n = RUtils.unwrap_num(idx)
            if type(n) ~= "number" or math.floor(n) ~= n then
                Runtime.raise("TypeError", "array indices must be integers")
            end
            if n < 0 then n = len + n end
            if n < 0 or n >= len then Runtime.raise("IndexError", "array assignment index out of range") end
            elts[n + 1] = validate_and_coerce_item(self.__dict._tc, self.__dict._spec, v)
            return B.None
        end),
        __delitem__ = fn("__delitem__", function(a)
            local self, idx = a[1], a[2]
            local elts = self.__dict._elements
            local len = #elts
            local n = RUtils.unwrap_num(idx)
            if type(n) ~= "number" or math.floor(n) ~= n then
                Runtime.raise("TypeError", "array indices must be integers")
            end
            if n < 0 then n = len + n end
            if n < 0 or n >= len then Runtime.raise("IndexError", "array assignment index out of range") end
            table.remove(elts, n + 1)
            return B.None
        end),
        __add__ = fn("__add__", function(a)
            local self, other = a[1], a[2]
            if type(other) ~= "table" or not other._is_array then
                Runtime.raise("TypeError", "can only append array to array")
            end
            if self.__dict._tc ~= other.__dict._tc then
                Runtime.raise("TypeError", "bad argument type for built-in operation")
            end
            local combined = {}
            for _, v in ipairs(self.__dict._elements) do table.insert(combined, v) end
            for _, v in ipairs(other.__dict._elements) do table.insert(combined, v) end
            return make_array_inst(self.__dict._tc, combined)
        end),
        __mul__ = fn("__mul__", function(a)
            local self, n = a[1], RUtils.unwrap_num(a[2])
            if type(n) ~= "number" or math.floor(n) ~= n then
                Runtime.raise("TypeError", "can't multiply sequence by non-int")
            end
            local res = {}
            for _ = 1, math.max(0, n) do
                for _, v in ipairs(self.__dict._elements) do table.insert(res, v) end
            end
            return make_array_inst(self.__dict._tc, res)
        end),
        __rmul__ = fn("__rmul__", function(a)
            return Evaluator.invoke(PyClass.get_attr(a[1], "__mul__"), { a[2] }, {})
        end),
        __eq__ = fn("__eq__", function(a)
            local self, other = a[1], a[2]
            if type(other) ~= "table" or not other._is_array then return false end
            local e1, e2 = self.__dict._elements, other.__dict._elements
            if #e1 ~= #e2 then return false end
            for i = 1, #e1 do
                if not RUtils.runtime_is_equal(e1[i], e2[i]) then return false end
            end
            return true
        end),
        __ne__ = fn("__ne__", function(a)
            local eq_m = PyClass.get_attr(a[1], "__eq__")
            return not RUtils.to_bool(Evaluator.invoke(eq_m, { a[2] }, {}))
        end),
        __repr__ = fn("__repr__", function(a)
            local self = a[1]
            local tc = self.__dict._tc
            local elts = self.__dict._elements
            if #elts == 0 then
                return string.format("array('%s')", tc)
            end
            if self.__dict._spec.kind == "uchar" then
                local s = table.concat(elts)
                return string.format("array('%s', %s)", tc, RUtils.to_str(s, true))
            end
            local list_repr = RUtils.to_str({ __type = "list", elements = elts }, true)
            return string.format("array('%s', %s)", tc, list_repr)
        end),
    }
    array_dict.__str__ = array_dict.__repr__

    array_cls = PyClass.make_class("array", { B.object }, array_dict)

    array_mod_cache = PyClass.make_instance(PyClass.make_class("module", {}, {}))
    local d = array_mod_cache.__dict
    d["__name__"]  = "array"
    d.array        = array_cls
    d.ArrayType    = array_cls
    d.typecodes    = "bBuhHiIlLqQfdw"
end

-- ==========================================
-- 3. 對外模組匯出介面
-- ==========================================
function DataTypes.init_enum()
    ensure_enum_init()
    return enum_mod_cache
end

function DataTypes.init_array()
    ensure_array_init()
    return array_mod_cache
end

function DataTypes.get_module(name)
    if name == "enum" then return DataTypes.init_enum() end
    if name == "array" then return DataTypes.init_array() end
    Runtime.raise("ModuleNotFoundError", "No module named '" .. tostring(name) .. "'")
end

return DataTypes