From f8b1f968e09960f40823eadccd8759c6d886a732 Mon Sep 17 00:00:00 2001 From: ktkk Date: Sun, 5 Jul 2026 00:25:25 +0200 Subject: [PATCH] Format additional predefined attribute infos --- src/Class.zig | 86 +++++++++++++++- src/Class/AttributeInfo.zig | 200 +++++++++++++++++++++++++++++++++--- src/Class/FieldInfo.zig | 3 +- src/Class/MethodInfo.zig | 3 +- 4 files changed, 273 insertions(+), 19 deletions(-) diff --git a/src/Class.zig b/src/Class.zig index 1d96a19..df4f523 100644 --- a/src/Class.zig +++ b/src/Class.zig @@ -274,7 +274,7 @@ pub fn format(self: *const Self, w: *std.Io.Writer) std.Io.Writer.Error!void { try w.splatByteAll(' ', depth * indent); try w.print("{d}:\n", .{ i }); - try field.indentedFormat(w, depth, indent + 1, self.allocator, self.constant_pool); + try field.indentedFormat(w, depth, indent + 1, self.constant_pool); } _ = try w.write("methods:\n"); @@ -284,7 +284,7 @@ pub fn format(self: *const Self, w: *std.Io.Writer) std.Io.Writer.Error!void { try w.splatByteAll(' ', depth * indent); try w.print("{d}:\n", .{ i }); - try method.indentedFormat(w, depth, indent + 1, self.allocator, self.constant_pool); + try method.indentedFormat(w, depth, indent + 1, self.constant_pool); } _ = try w.write("attributes:\n"); @@ -294,7 +294,7 @@ pub fn format(self: *const Self, w: *std.Io.Writer) std.Io.Writer.Error!void { try w.splatByteAll(' ', depth * indent); try w.print("{d}:\n", .{ i }); - try attribute.indentedFormat(w, depth, indent + 1, self.allocator, self.constant_pool); + try attribute.indentedFormat(w, depth, indent + 1, self.constant_pool); } } @@ -342,7 +342,10 @@ pub const ConstantPoolInfo = union(ConstantPoolInfo.Tag) { utf8: Utf8, method_handle: MethodHandle, method_type: MethodType, + dynamic: Dynamic, invoke_dynamic: InvokeDynamic, + module: Module, + package: Package, pub const Tag = enum(u8) { class = 7, @@ -358,7 +361,10 @@ pub const ConstantPoolInfo = union(ConstantPoolInfo.Tag) { utf8 = 1, method_handle = 15, method_type = 16, + dynamic = 17, invoke_dynamic = 18, + module = 19, + package = 20, }; pub const Class = struct { @@ -540,6 +546,19 @@ pub const ConstantPoolInfo = union(ConstantPoolInfo.Tag) { } }; + pub const Dynamic = struct { + bootstrap_method_attr_index: u16, + name_and_type_index: u16, + + pub fn nameAndType(self: *const Dynamic, constant_pool: []const ?ConstantPoolInfo) ResolveError!ConstantPoolInfo { + const name_and_type_index = self.name_and_type_index - 1; + if (name_and_type_index >= constant_pool.len) return ResolveError.InvalidConstantPoolIndex; + const cp_info = constant_pool[name_and_type_index]; + if (cp_info == null or @as(Tag, cp_info.?) != .name_and_type) return ResolveError.InvalidConstantType; + return cp_info.?; + } + }; + pub const InvokeDynamic = struct { bootstrap_method_attr_index: u16, name_and_type_index: u16, @@ -553,6 +572,30 @@ pub const ConstantPoolInfo = union(ConstantPoolInfo.Tag) { } }; + pub const Module = struct { + name_index: u16, + + pub fn name(self: *const Module, 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(Tag, cp_info.?) != .utf8) return ResolveError.InvalidConstantType; + return cp_info.?; + } + }; + + pub const Package = struct { + name_index: u16, + + pub fn name(self: *const Package, 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(Tag, cp_info.?) != .utf8) return ResolveError.InvalidConstantType; + return cp_info.?; + } + }; + pub fn parse(input: *std.Io.Reader, allocator: std.mem.Allocator) ParseError!ConstantPoolInfo { const tag_byte = try input.takeByte(); const tag = std.enums.fromInt(Tag, tag_byte) orelse return ParseError.InvalidTag; @@ -640,12 +683,28 @@ pub const ConstantPoolInfo = union(ConstantPoolInfo.Tag) { .descriptor_index = try input.takeInt(u16, .big), }, }, + .dynamic => .{ + .dynamic = .{ + .bootstrap_method_attr_index = try input.takeInt(u16, .big), + .name_and_type_index = try input.takeInt(u16, .big), + }, + }, .invoke_dynamic => .{ .invoke_dynamic = .{ .bootstrap_method_attr_index = try input.takeInt(u16, .big), .name_and_type_index = try input.takeInt(u16, .big), }, }, + .module => .{ + .module = .{ + .name_index = try input.takeInt(u16, .big), + }, + }, + .package => .{ + .package = .{ + .name_index = try input.takeInt(u16, .big), + }, + }, }; } @@ -671,7 +730,10 @@ pub const ConstantPoolInfo = union(ConstantPoolInfo.Tag) { .utf8 => |utf8| try w.print("\"{s}\"", .{ utf8.bytes }), .method_handle => |method_handle| try w.print("{s} #{d}", .{ @tagName(method_handle.reference_kind), method_handle.reference_index }), .method_type => |method_type| try w.print("#{d}", .{ method_type.descriptor_index }), + .dynamic => |dynamic| try w.print("#{d} #{d}", .{ dynamic.bootstrap_method_attr_index, dynamic.name_and_type_index }), .invoke_dynamic => |invoke_dynamic| try w.print("#{d} #{d}", .{ invoke_dynamic.bootstrap_method_attr_index, invoke_dynamic.name_and_type_index }), + .module => |module| try w.print("#{d}", .{ module.name_index }), + .package => |package| try w.print("#{d}", .{ package.name_index }), } } @@ -782,12 +844,30 @@ pub const ConstantPoolInfo = union(ConstantPoolInfo.Tag) { const descriptor = method_type.descriptor(constant_pool) catch return error.WriteFailed; try descriptor.indentedFormat(w, depth, indent + 1, constant_pool); }, + .dynamic => |dynamic| { + try w.splatByteAll(' ', depth * indent); + _ = try w.write("name_and_type:\n"); + const name_and_type = dynamic.nameAndType(constant_pool) catch return error.WriteFailed; + try name_and_type.indentedFormat(w, depth, indent + 1, constant_pool); + }, .invoke_dynamic => |invoke_dynamic| { try w.splatByteAll(' ', depth * indent); _ = try w.write("name_and_type:\n"); const name_and_type = invoke_dynamic.nameAndType(constant_pool) catch return error.WriteFailed; try name_and_type.indentedFormat(w, depth, indent + 1, constant_pool); }, + .module => |module| { + try w.splatByteAll(' ', depth * indent); + _ = try w.write("name:\n"); + const name = module.name(constant_pool) catch return error.WriteFailed; + try name.indentedFormat(w, depth, indent + 1, constant_pool); + }, + .package => |package| { + try w.splatByteAll(' ', depth * indent); + _ = try w.write("name:\n"); + const name = package.name(constant_pool) catch return error.WriteFailed; + try name.indentedFormat(w, depth, indent + 1, constant_pool); + }, } } }; diff --git a/src/Class/AttributeInfo.zig b/src/Class/AttributeInfo.zig index 4b17b67..e41738d 100644 --- a/src/Class/AttributeInfo.zig +++ b/src/Class/AttributeInfo.zig @@ -259,7 +259,6 @@ pub const AttributeInfo = union(enum) { w: *std.Io.Writer, depth: usize, indent: u8, - allocator: std.mem.Allocator, constant_pool: []const ?ConstantPoolInfo, ) std.Io.Writer.Error!void { switch (self.*) { @@ -325,7 +324,7 @@ pub const AttributeInfo = union(enum) { try w.splatByteAll(' ', depth * attr_indent); try w.print("{d}:\n", .{ i }); - try a.indentedFormat(w, depth, attr_indent + 1, allocator, constant_pool); + try a.indentedFormat(w, depth, attr_indent + 1, constant_pool); } }, //.stack_map_table, @@ -333,12 +332,14 @@ pub const AttributeInfo = union(enum) { try w.splatByteAll(' ', depth * indent); _ = try w.write("exceptions:\n"); var exception_indent = indent; - for (attr.exception_index_table, 0..) |exception, i| { + for (attr.exception_index_table, 0..) |exception_index, i| { exception_indent += 1; defer exception_indent -= 1; - if (exception >= constant_pool.len) return error.WriteFailed; - const cp_info = constant_pool[exception - 1]; + const index = exception_index - 1; + + if (index >= constant_pool.len) return error.WriteFailed; + const cp_info = constant_pool[index]; if (cp_info == null or @as(ConstantPoolInfo.Tag, cp_info.?) != .class) return error.WriteFailed; try w.splatByteAll(' ', depth * exception_indent); @@ -396,14 +397,102 @@ pub const AttributeInfo = union(enum) { //.runtime_invisible_parameter_annotations, //.annotation_default, //.bootstrap_methods, - //.method_parameters, + .method_parameters => |attr| { + try w.splatByteAll(' ', depth * indent); + _ = try w.write("parameters:\n"); + var parameter_indent = indent; + for (attr.parameters, 0..) |parameter, i| { + parameter_indent += 1; + defer parameter_indent -= 1; + + try w.splatByteAll(' ', depth * parameter_indent); + try w.print("{d}:\n", .{ i }); + try parameter.indentedFormat(w, depth, parameter_indent, constant_pool); + } + }, //.module, - //.module_packages, - //.module_main_class, - //.nest_host, - //.nest_members, - //.record, - //.permitted_subclasses, + .module_packages => |attr| { + try w.splatByteAll(' ', depth * indent); + _ = try w.write("packages:\n"); + var package_indent = indent; + for (attr.package_indeces, 0..) |package_index, i| { + package_indent += 1; + defer package_indent -= 1; + + const index = package_index - 1; + + if (index >= constant_pool.len) return error.WriteFailed; + const cp_info = constant_pool[index]; + if (cp_info == null or @as(ConstantPoolInfo.Tag, cp_info.?) != .package) return error.WriteFailed; + + try w.splatByteAll(' ', depth * package_indent); + try w.print("{d}:\n", .{ i }); + try cp_info.?.indentedFormat(w, depth, package_indent + 1, constant_pool); + } + }, + .module_main_class => |attr| { + const main_class = attr.mainClass(constant_pool) catch return error.WriteFailed; + try w.splatByteAll(' ', depth * indent); + _ = try w.write("main_class:\n"); + try main_class.indentedFormat(w, depth, indent + 1, constant_pool); + }, + .nest_host => |attr| { + const host_class = attr.hostClass(constant_pool) catch return error.WriteFailed; + try w.splatByteAll(' ', depth * indent); + _ = try w.write("host_class:\n"); + try host_class.indentedFormat(w, depth, indent + 1, constant_pool); + }, + .nest_members => |attr| { + try w.splatByteAll(' ', depth * indent); + _ = try w.write("classes:\n"); + var class_indent = indent; + for (attr.classes, 0..) |class_index, i| { + class_indent += 1; + defer class_indent -= 1; + + const index = class_index - 1; + + if (index >= constant_pool.len) return error.WriteFailed; + const cp_info = constant_pool[index]; + if (cp_info == null or @as(ConstantPoolInfo.Tag, cp_info.?) != .class) return error.WriteFailed; + + try w.splatByteAll(' ', depth * class_indent); + try w.print("{d}:\n", .{ i }); + try cp_info.?.indentedFormat(w, depth, class_indent + 1, constant_pool); + } + }, + .record => |attr| { + try w.splatByteAll(' ', depth * indent); + _ = try w.write("components:\n"); + var component_indent = indent; + for (attr.components, 0..) |component, i| { + component_indent += 1; + defer component_indent -= 1; + + try w.splatByteAll(' ', depth * component_indent); + try w.print("{d}:\n", .{ i }); + try component.indentedFormat(w, depth, component_indent, constant_pool); + } + }, + .permitted_subclasses => |attr| { + try w.splatByteAll(' ', depth * indent); + _ = try w.write("classes:\n"); + var class_indent = indent; + for (attr.classes, 0..) |class_index, i| { + class_indent += 1; + defer class_indent -= 1; + + const index = class_index - 1; + + if (index >= constant_pool.len) return error.WriteFailed; + const cp_info = constant_pool[index]; + if (cp_info == null or @as(ConstantPoolInfo.Tag, cp_info.?) != .class) return error.WriteFailed; + + try w.splatByteAll(' ', depth * class_indent); + try w.print("{d}:\n", .{ i }); + try cp_info.?.indentedFormat(w, depth, class_indent + 1, constant_pool); + } + }, else => {}, } }, @@ -1392,6 +1481,30 @@ pub const MethodParameters = struct { }; pub const ParameterAccessFlags = EnumFlags(ParameterFlags); + + pub fn indentedFormat( + self: *const Parameter, + 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 }); + + const name_ = self.name(constant_pool) catch return error.WriteFailed; + try w.splatByteAll(' ', depth * indent); + _ = try w.write("name:\n"); + try name_.indentedFormat(w, depth, indent + 1, constant_pool); + } + + pub fn name(self: *const Parameter, 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 parse(input: *std.Io.Reader, allocator: std.mem.Allocator) ParseError!Self { @@ -1448,6 +1561,14 @@ pub const ModuleMainClass = struct { .main_class_index = try input.takeInt(u16, .big), }; } + + pub fn mainClass(self: *const ModuleMainClass, constant_pool: []const ?ConstantPoolInfo) ResolveError!ConstantPoolInfo { + const main_class_index = self.main_class_index - 1; + if (main_class_index >= constant_pool.len) return ResolveError.InvalidConstantPoolIndex; + const cp_info = constant_pool[main_class_index]; + if (cp_info == null or @as(ConstantPoolInfo.Tag, cp_info.?) != .class) return ResolveError.InvalidConstantType; + return cp_info.?; + } }; pub const NestHost = struct { @@ -1460,6 +1581,14 @@ pub const NestHost = struct { .host_class_index = try input.takeInt(u16, .big), }; } + + pub fn hostClass(self: *const NestHost, constant_pool: []const ?ConstantPoolInfo) ResolveError!ConstantPoolInfo { + const host_class_index = self.host_class_index - 1; + if (host_class_index >= constant_pool.len) return ResolveError.InvalidConstantPoolIndex; + const cp_info = constant_pool[host_class_index]; + if (cp_info == null or @as(ConstantPoolInfo.Tag, cp_info.?) != .class) return ResolveError.InvalidConstantType; + return cp_info.?; + } }; pub const NestMembers = struct { @@ -1518,6 +1647,53 @@ pub const Record = struct { } allocator.free(self.attributes); } + + pub fn indentedFormat( + self: *const RecordComponentInfo, + w: *std.Io.Writer, + depth: usize, + indent: u8, + constant_pool: []const ?ConstantPoolInfo, + ) std.Io.Writer.Error!void { + const name_ = self.name(constant_pool) catch return error.WriteFailed; + try w.splatByteAll(' ', depth * indent); + _ = try w.write("name:\n"); + try name_.indentedFormat(w, depth, indent + 1, constant_pool); + + const descriptor_ = self.descriptor(constant_pool) catch return error.WriteFailed; + try w.splatByteAll(' ', depth * indent); + _ = try w.write("descriptor:\n"); + try 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..) |*attr, i| { + attr_indent += 1; + defer attr_indent -= 1; + + try w.splatByteAll(' ', depth * attr_indent); + try w.print("{d}:\n", .{ i }); + + try attr.indentedFormat(w, depth, attr_indent + 1, constant_pool); + } + } + + pub fn name(self: *const RecordComponentInfo, 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 RecordComponentInfo, 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.?; + } }; pub fn parse(input: *std.Io.Reader, constant_pool: []const ?ConstantPoolInfo, allocator: std.mem.Allocator) (ParseError || ResolveError)!Self { diff --git a/src/Class/FieldInfo.zig b/src/Class/FieldInfo.zig index ed3cb61..62325d9 100644 --- a/src/Class/FieldInfo.zig +++ b/src/Class/FieldInfo.zig @@ -53,7 +53,6 @@ pub fn indentedFormat( w: *std.Io.Writer, depth: usize, indent: u8, - allocator: std.mem.Allocator, constant_pool: []const ?ConstantPoolInfo, ) std.Io.Writer.Error!void { try w.splatByteAll(' ', depth * indent); @@ -79,7 +78,7 @@ pub fn indentedFormat( try w.splatByteAll(' ', depth * attr_indent); try w.print("{d}:\n", .{ j }); - try attribute.indentedFormat(w, depth, attr_indent + 1, allocator, constant_pool); + try attribute.indentedFormat(w, depth, attr_indent + 1, constant_pool); } } diff --git a/src/Class/MethodInfo.zig b/src/Class/MethodInfo.zig index 7a457ee..87ad266 100644 --- a/src/Class/MethodInfo.zig +++ b/src/Class/MethodInfo.zig @@ -56,7 +56,6 @@ pub fn indentedFormat( w: *std.Io.Writer, depth: usize, indent: u8, - allocator: std.mem.Allocator, constant_pool: []const ?ConstantPoolInfo, ) std.Io.Writer.Error!void { try w.splatByteAll(' ', depth * indent); @@ -82,7 +81,7 @@ pub fn indentedFormat( try w.splatByteAll(' ', depth * attr_indent); try w.print("{d}:\n", .{ j }); - try attribute.indentedFormat(w, depth, attr_indent + 1, allocator, constant_pool); + try attribute.indentedFormat(w, depth, attr_indent + 1, constant_pool); } }