local EType = {} EType.__index = EType function EType:__eq(other) for k, v in pairs(self) do if rawget(other, k) ~= v then return false end end for k, v in pairs(other) do if rawget(self, k) ~= v then return false end end return true end function EType:__tostring() if self.kind == "scalar" then return (self.unsigned and "u" or "i") .. self.bits elseif self.kind == "func" then return (tostring(self.input) .. "->" .. tostring(self.output)) elseif self.kind == "struct" then return ("(" .. table.concat(self.fields, ",") .. ")") elseif self.kind == "pointer" then return tostring(self.to) .. "*" elseif self.kind == "array" then return tostring(self.element_etype) .. "[" .. (self.length or "?") .. "]" elseif self.kind == "string" then return "string" end error("Unimplemented " .. self.kind) end function EType:byte_size() if self.kind == "scalar" then return (self.bits + 7) // 8 end error("Unimplemented " .. self.kind) end local ETypes = {} function ETypes.scalar(unsigned, bits) return setmetatable({kind = "scalar", bits = bits, unsigned = unsigned}, EType) end function ETypes.func(input_etype, output_etype) assert(input_etype ~= nil, "Nil function input") assert(output_etype ~= nil, "Nil function output") return setmetatable({kind = "func", input = input_etype, output = output_etype, modifiers = {}}, EType) end function ETypes.array(element_etype, length) return setmetatable({kind = "array", element_etype = element_etype, length = length}, EType) end function ETypes.struct(fields) return setmetatable({kind = "struct", fields = fields, modifiers = {}}, EType) end function ETypes.string() return setmetatable({kind = "string"}, EType) end function ETypes.ref(child) assert(child, "Nil pointee type") return setmetatable({kind = "pointer", to = child}, EType) end function ETypes.deref(ptr) assert(ptr and ptr.kind == "pointer", "Non-pointer type") return ptr.to end function ETypes.is(etype) return type(etype) == "table" and getmetatable(etype) == EType end return ETypes