const std = @import("std"); const EnumFlags = @import("../EnumFlags.zig").EnumFlags; const Class = @import("../Class.zig"); const ConstantPoolInfo = Class.ConstantPoolInfo; const AttributeInfo = Class.AttributeInfo; const ResolveError = Class.ResolveError; access_flags: MethodAccessFlags, name_index: u16, descriptor_index: u16, attributes: []AttributeInfo, const Self = @This(); pub const MethodAccessFlags = EnumFlags(enum(u16) { public = 0x0001, private = 0x0002, protected = 0x0004, static = 0x0008, final = 0x0010, synchronized = 0x0020, bridge = 0x0040, varargs = 0x0080, native = 0x0100, abstract = 0x0400, strict = 0x0800, synthetic = 0x1000, }); pub fn parse(input: *std.Io.Reader, constant_pool: []const ?ConstantPoolInfo, allocator: std.mem.Allocator) !Self { const access_flags: MethodAccessFlags = .{ .mask = try input.takeInt(u16, .big) }; const name_index = try input.takeInt(u16, .big); const descriptor_index = try input.takeInt(u16, .big); const attributes = try Class.parseAttributes(input, constant_pool, allocator); return .{ .access_flags = access_flags, .name_index = name_index, .descriptor_index = descriptor_index, .attributes = attributes, }; } pub fn deinit(self: *Self, allocator: std.mem.Allocator) void { for (self.attributes) |*attr_info| { attr_info.deinit(allocator); } allocator.free(self.attributes); } pub fn indentedFormat( self: *const Self, w: *std.Io.Writer, depth: usize, indent: u8, constant_pool: []const ?ConstantPoolInfo, ) std.Io.Writer.Error!void { try w.splatByteAll(' ', depth * indent); try w.print("flags: {f}\n", .{ self.access_flags }); try w.splatByteAll(' ', depth * indent); _ = try w.write("name:\n"); const method_name = self.name(constant_pool) catch return error.WriteFailed; try method_name.indentedFormat(w, depth, indent + 1, constant_pool); try w.splatByteAll(' ', depth * indent); _ = try w.write("descriptor:\n"); const method_descriptor = self.descriptor(constant_pool) catch return error.WriteFailed; try method_descriptor.indentedFormat(w, depth, indent + 1, constant_pool); try w.splatByteAll(' ', depth * indent); _ = try w.write("attributes:\n"); var attr_indent = indent; for (self.attributes, 0..) |*attribute, j| { attr_indent += 1; defer attr_indent -= 1; try w.splatByteAll(' ', depth * attr_indent); try w.print("{d}:\n", .{ j }); try attribute.indentedFormat(w, depth, attr_indent + 1, constant_pool); } } pub fn name(self: *const Self, constant_pool: []const ?ConstantPoolInfo) ResolveError!ConstantPoolInfo { const name_index = self.name_index - 1; if (name_index >= constant_pool.len) return ResolveError.InvalidConstantPoolIndex; const cp_info = constant_pool[name_index]; if (cp_info == null or @as(ConstantPoolInfo.Tag, cp_info.?) != .utf8) return ResolveError.InvalidConstantType; return cp_info.?; } pub fn descriptor(self: *const Self, constant_pool: []const ?ConstantPoolInfo) ResolveError!ConstantPoolInfo { const descriptor_index = self.descriptor_index - 1; if (descriptor_index >= constant_pool.len) return ResolveError.InvalidConstantPoolIndex; const cp_info = constant_pool[descriptor_index]; if (cp_info == null or @as(ConstantPoolInfo.Tag, cp_info.?) != .utf8) return ResolveError.InvalidConstantType; return cp_info.?; }