diff --git a/src/Class.zig b/src/Class.zig index 458627f..f31ed15 100644 --- a/src/Class.zig +++ b/src/Class.zig @@ -364,6 +364,13 @@ pub const ConstantPoolInfo = union(ConstantPoolInfo.Tag) { invoke_dynamic = 18, module = 19, package = 20, + + pub fn loadable(self: Tag) bool { + return switch (self) { + .integer, .float, .long, .double, .class, .string, .method_handle, .method_type, .dynamic => true, + else => false, + }; + } }; pub const Class = struct { diff --git a/src/Class/AttributeInfo.zig b/src/Class/AttributeInfo.zig index 300d02d..b5b913c 100644 --- a/src/Class/AttributeInfo.zig +++ b/src/Class/AttributeInfo.zig @@ -444,8 +444,22 @@ pub const AttributeInfo = union(enum) { //.runtime_invisible_annotations, //.runtime_visible_parameter_annotations, //.runtime_invisible_parameter_annotations, + //.runtime_visible_type_annotations, + //.runtime_invisible_type_annotations, //.annotation_default, - //.bootstrap_methods, + .bootstrap_methods => |attr| { + try w.splatByteAll(' ', depth * indent); + _ = try w.write("bootstrap_methods:\n"); + var bootstrap_method_indent = indent; + for (attr.bootstrap_methods, 0..) |bootstrap_method, i| { + bootstrap_method_indent += 1; + defer bootstrap_method_indent -= 1; + + try w.splatByteAll(' ', depth * bootstrap_method_indent); + try w.print("{d}:\n", .{ i }); + try bootstrap_method.indentedFormat(w, depth, bootstrap_method_indent + 1, constant_pool); + } + }, .method_parameters => |attr| { try w.splatByteAll(' ', depth * indent); _ = try w.write("parameters:\n"); @@ -456,7 +470,7 @@ pub const AttributeInfo = union(enum) { try w.splatByteAll(' ', depth * parameter_indent); try w.print("{d}:\n", .{ i }); - try parameter.indentedFormat(w, depth, parameter_indent, constant_pool); + try parameter.indentedFormat(w, depth, parameter_indent + 1, constant_pool); } }, .module => |attr| try attr.indentedFormat(w, depth, indent, constant_pool), @@ -1603,6 +1617,45 @@ pub const BootstrapMethods = struct { pub const BootstrapMethod = struct { bootstrap_method_ref: u16, bootstrap_arguments: []u16, + + pub fn indentedFormat( + self: *const BootstrapMethod, + w: *std.Io.Writer, + depth: usize, + indent: u8, + constant_pool: []const ?ConstantPoolInfo, + ) std.Io.Writer.Error!void { + const bootstrap_method = self.bootstrapMethod(constant_pool) catch return error.WriteFailed; + try w.splatByteAll(' ', depth * indent); + _ = try w.write("bootstrap_method:\n"); + try bootstrap_method.indentedFormat(w, depth, indent + 1, constant_pool); + + try w.splatByteAll(' ', depth * indent); + _ = try w.write("bootstrap_arguments:\n"); + var bootstrap_argument_indent = indent; + for (self.bootstrap_arguments, 0..) |bootstrap_argument, i| { + bootstrap_argument_indent += 1; + defer bootstrap_argument_indent -= 1; + + const index = bootstrap_argument - 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.?).loadable()) return error.WriteFailed; + + try w.splatByteAll(' ', depth * bootstrap_argument_indent); + try w.print("{d}:\n", .{ i }); + try cp_info.?.indentedFormat(w, depth, bootstrap_argument_indent + 1, constant_pool); + } + } + + pub fn bootstrapMethod(self: *const BootstrapMethod, constant_pool: []const ?ConstantPoolInfo) ResolveError!ConstantPoolInfo { + const bootstrap_method_ref = self.bootstrap_method_ref - 1; + if (bootstrap_method_ref >= constant_pool.len) return ResolveError.InvalidConstantPoolIndex; + const cp_info = constant_pool[bootstrap_method_ref]; + if (cp_info == null or @as(ConstantPoolInfo.Tag, cp_info.?) != .method_handle) return ResolveError.InvalidConstantType; + return cp_info.?; + } }; pub fn parse(input: *std.Io.Reader, allocator: std.mem.Allocator) ParseError!Self {