From ba2c8a59b52030fdc82aaf8740d7878854dfe05a Mon Sep 17 00:00:00 2001 From: ktkk Date: Mon, 22 Jun 2026 15:34:25 +0000 Subject: [PATCH] Format instructions, exceptions, inner classes and enclosing methods --- Main.java | 13 +++++ src/Class.zig | 155 ++++++++++++++++++++++++++++++++++++++++++++++++-- 2 files changed, 163 insertions(+), 5 deletions(-) diff --git a/Main.java b/Main.java index 1458098..a3c6d9b 100644 --- a/Main.java +++ b/Main.java @@ -23,5 +23,18 @@ public class Main implements Runnable, Supplier, Interface { public String getName() { return name; } + + public void throwSomething() throws Throwable { + throw new Throwable() { + @Override + public String getMessage() { + return "Hello"; + } + }; + } + + public static class Inner { + private static final String name = "Inner John"; + } } diff --git a/src/Class.zig b/src/Class.zig index 06a1287..1622732 100644 --- a/src/Class.zig +++ b/src/Class.zig @@ -364,12 +364,112 @@ fn formatAttribute(self: *const Self, w: *std.Io.Writer, depth: usize, indent: u try w.splatByteAll(' ', depth * indent); try w.print("max_locals: {d}\n", .{ attr.max_locals }); - // TODO: Properly parse and format instructions + try w.splatByteAll(' ', depth * indent); + _ = try w.write("code:\n"); + var instr_indent = indent; + for (attr.code, 0..) |instr, i| { + instr_indent += 1; + defer instr_indent -= 1; + + try w.splatByteAll(' ', depth * instr_indent); + try w.print("{d}: {d}\n", .{ i, instr }); + } + + //try w.splatByteAll(' ', depth * indent); + //_ = try w.write("exception_table:\n"); + //var exception_indent = indent; + //for (attr.exception_table, 0..) |*exception, i| { + // exception_indent += 1; + // defer exception_indent -= 1; + + // try w.splatByteAll(' ', depth * exception_indent); + // try w.print("{d}:\n", .{ i }); + + // try self.formatExceptionHandler(w, depth, exception_indent + 1, exception); + //} + + try w.splatByteAll(' ', depth * indent); + _ = try w.write("attributes:\n"); + var attr_indent = indent; + for (attr.attributes, 0..) |*a, i| { + attr_indent += 1; + defer attr_indent -= 1; + + try w.splatByteAll(' ', depth * attr_indent); + try w.print("{d}:\n", .{ i }); + + try self.formatAttribute(w, depth, attr_indent + 1, a); + } }, //.stack_map_table, - //.exceptions, - //.inner_classes, - //.enclosing_method, + .exceptions => |attr| { + try w.splatByteAll(' ', depth * indent); + _ = try w.write("exceptions:\n"); + var attr_indent = indent; + for (attr.exception_index_table, 0..) |exception, i| { + attr_indent += 1; + defer attr_indent -= 1; + + if (exception >= self.constant_pool.len) return error.WriteFailed; + const cp_info = self.constant_pool[exception - 1]; + if (cp_info == null or @as(CpInfo.Tag, cp_info.?) != .class) return error.WriteFailed; + + try w.splatByteAll(' ', depth * attr_indent); + try w.print("{d}:\n", .{ i }); + try self.formatCpInfo(w, depth, attr_indent + 1, &cp_info.?); + } + }, + .inner_classes => |attr| { + try w.splatByteAll(' ', depth * indent); + _ = try w.write("classes:\n"); + var inner_classes_indent = indent; + for (attr.classes) |*class| { + inner_classes_indent += 1; + defer inner_classes_indent -= 1; + + const inner_class = class.innerClass(self.constant_pool) catch return error.WriteFailed; + + try w.splatByteAll(' ', depth * inner_classes_indent); + _ = try w.write("inner_class:\n"); + + try self.formatCpInfo(w, depth, inner_classes_indent + 1, &.{ .class = inner_class }); + + const outer_class = class.outerClass(self.constant_pool) catch return error.WriteFailed; + if (outer_class) |oc| { + try w.splatByteAll(' ', depth * inner_classes_indent); + _ = try w.write("outer_class:\n"); + + try self.formatCpInfo(w, depth, inner_classes_indent + 1, &.{ .class = oc }); + } + + const inner_name = class.innerName(self.constant_pool) catch return error.WriteFailed; + if (inner_name) |in| { + try w.splatByteAll(' ', depth * inner_classes_indent); + _ = try w.write("inner_name:\n"); + + try self.formatCpInfo(w, depth, inner_classes_indent + 1, &.{ .utf8 = in }); + } + + try w.splatByteAll(' ', depth * inner_classes_indent); + try w.print("flags: {f}\n", .{ class.inner_class_access_flags }); + } + }, + .enclosing_method => |attr| { + const class = attr.class(self.constant_pool) catch return error.WriteFailed; + + try w.splatByteAll(' ', depth * indent); + _ = try w.write("class:\n"); + + try self.formatCpInfo(w, depth, indent + 1, &.{ .class = class }); + + const method = attr.method(self.constant_pool) catch return error.WriteFailed; + if (method) |m| { + try w.splatByteAll(' ', depth * indent); + _ = try w.write("method:\n"); + + try self.formatCpInfo(w, depth, indent + 1, &.{ .name_and_type = m }); + } + }, .synthetic => {}, .signature => |attr| { const signature = attr.signature(self.constant_pool) catch return error.WriteFailed; @@ -383,7 +483,7 @@ fn formatAttribute(self: *const Self, w: *std.Io.Writer, depth: usize, indent: u //.line_number_table, //.local_variable_table, //.local_variable_type_table, - //.deprecated, + .deprecated => {}, //.runtime_visible_annotations, //.runtime_invisible_annotations, //.runtime_visible_parameter_annotations, @@ -1227,6 +1327,34 @@ pub const AttributeInfo = struct { outer_class_info_index: u16, inner_name_index: u16, inner_class_access_flags: InnerClassAccessFlags, + + pub fn innerClass(self: *const InnerClass, constant_pool: []const ?CpInfo) ResolveError!CpInfo.Class { + const inner_class_info_index = self.inner_class_info_index - 1; + if (inner_class_info_index >= constant_pool.len) return ResolveError.InvalidConstantPoolIndex; + const cp_info = constant_pool[inner_class_info_index]; + if (cp_info == null or @as(CpInfo.Tag, cp_info.?) != .class) return ResolveError.InvalidConstantType; + return cp_info.?.class; + } + + pub fn outerClass(self: *const InnerClass, constant_pool: []const ?CpInfo) ResolveError!?CpInfo.Class { + if (self.outer_class_info_index == 0) return null; + const outer_class_info_index = self.outer_class_info_index - 1; + if (outer_class_info_index >= constant_pool.len) return ResolveError.InvalidConstantPoolIndex; + + const cp_info = constant_pool[outer_class_info_index]; + if (cp_info == null or @as(CpInfo.Tag, cp_info.?) != .class) return ResolveError.InvalidConstantType; + return cp_info.?.class; + } + + pub fn innerName(self: *const InnerClass, constant_pool: []const ?CpInfo) ResolveError!?CpInfo.Utf8 { + if (self.inner_name_index == 0) return null; + const inner_name_index = self.inner_name_index - 1; + if (inner_name_index >= constant_pool.len) return ResolveError.InvalidConstantPoolIndex; + + const cp_info = constant_pool[inner_name_index]; + if (cp_info == null or @as(CpInfo.Tag, cp_info.?) != .utf8) return ResolveError.InvalidConstantType; + return cp_info.?.utf8; + } }; pub const InnerClassFlags = enum(u16) { @@ -1248,6 +1376,23 @@ pub const AttributeInfo = struct { pub const EnclosingMethod = struct { class_index: u16, method_index: u16, + + pub fn class(self: *const EnclosingMethod, constant_pool: []const ?CpInfo) ResolveError!CpInfo.Class { + const class_index = self.class_index - 1; + if (class_index >= constant_pool.len) return ResolveError.InvalidConstantPoolIndex; + const cp_info = constant_pool[class_index]; + if (cp_info == null or @as(CpInfo.Tag, cp_info.?) != .class) return ResolveError.InvalidConstantType; + return cp_info.?.class; + } + + pub fn method(self: *const EnclosingMethod, constant_pool: []const ?CpInfo) ResolveError!?CpInfo.NameAndType { + if (self.method_index == 0) return null; + const method_index = self.method_index - 1; + if (method_index >= constant_pool.len) return ResolveError.InvalidConstantPoolIndex; + const cp_info = constant_pool[method_index]; + if (cp_info == null or @as(CpInfo.Tag, cp_info.?) != .name_and_type) return ResolveError.InvalidConstantType; + return cp_info.?.name_and_type; + } }; pub const Synthetic = struct { };