diff --git a/src/Class.zig b/src/Class.zig index f31ed15..a8719b9 100644 --- a/src/Class.zig +++ b/src/Class.zig @@ -5,13 +5,14 @@ const EnumFlags = @import("EnumFlags.zig").EnumFlags; pub const FieldInfo = @import("Class/FieldInfo.zig"); pub const MethodInfo = @import("Class/MethodInfo.zig"); pub const AttributeInfo = @import("Class/AttributeInfo.zig").AttributeInfo; +pub const ConstantPool = @import("Class/ConstantPool.zig"); allocator: std.mem.Allocator, magic: u32, minor_version: u16, major_version: u16, -constant_pool: []?ConstantPoolInfo, +constant_pool: []?ConstantPool.Info, access_flags: ClassAccessFlags, this_class: u16, super_class: u16, @@ -109,16 +110,16 @@ pub fn parse(input: *std.Io.Reader, allocator: std.mem.Allocator) (ParseError || }; } -fn parseConstantPool(input: *std.Io.Reader, allocator: std.mem.Allocator) ParseError![]?ConstantPoolInfo { +fn parseConstantPool(input: *std.Io.Reader, allocator: std.mem.Allocator) ParseError![]?ConstantPool.Info { const constant_pool_size = try input.takeInt(u16, .big); - const constant_pool = try allocator.alloc(?ConstantPoolInfo, constant_pool_size - 1); + const constant_pool = try allocator.alloc(?ConstantPool.Info, constant_pool_size - 1); errdefer allocator.free(constant_pool); var i: usize = 0; while (i < constant_pool_size - 1) { defer i += 1; - const cp_info = try ConstantPoolInfo.parse(input, allocator); + const cp_info = try ConstantPool.Info.parse(input, allocator); constant_pool[i] = cp_info; switch (cp_info) { @@ -145,7 +146,7 @@ fn parseInterfaces(input: *std.Io.Reader, allocator: std.mem.Allocator) ParseErr return interfaces; } -fn parseFields(input: *std.Io.Reader, constant_pool: []const ?ConstantPoolInfo, allocator: std.mem.Allocator) (ParseError || ResolveError)![]FieldInfo { +fn parseFields(input: *std.Io.Reader, constant_pool: []const ?ConstantPool.Info, allocator: std.mem.Allocator) (ParseError || ResolveError)![]FieldInfo { const fields_count = try input.takeInt(u16, .big); const fields = try allocator.alloc(FieldInfo, fields_count); errdefer allocator.free(fields); @@ -157,7 +158,7 @@ fn parseFields(input: *std.Io.Reader, constant_pool: []const ?ConstantPoolInfo, return fields; } -fn parseMethods(input: *std.Io.Reader, constant_pool: []const ?ConstantPoolInfo, allocator: std.mem.Allocator) (ParseError || ResolveError)![]MethodInfo { +fn parseMethods(input: *std.Io.Reader, constant_pool: []const ?ConstantPool.Info, allocator: std.mem.Allocator) (ParseError || ResolveError)![]MethodInfo { const methods_count = try input.takeInt(u16, .big); const methods = try allocator.alloc(MethodInfo, methods_count); errdefer allocator.free(methods); @@ -169,7 +170,7 @@ fn parseMethods(input: *std.Io.Reader, constant_pool: []const ?ConstantPoolInfo, return methods; } -pub fn parseAttributes(input: *std.Io.Reader, constant_pool: []const ?ConstantPoolInfo, allocator: std.mem.Allocator) (ParseError || ResolveError)![]AttributeInfo { +pub fn parseAttributes(input: *std.Io.Reader, constant_pool: []const ?ConstantPool.Info, allocator: std.mem.Allocator) (ParseError || ResolveError)![]AttributeInfo { const attributes_count = try input.takeInt(u16, .big); const attributes = try allocator.alloc(AttributeInfo, attributes_count); errdefer allocator.free(attributes); @@ -259,7 +260,7 @@ pub fn format(self: *const Self, w: *std.Io.Writer) std.Io.Writer.Error!void { if (interface >= self.constant_pool.len) return error.WriteFailed; const cp_info = self.constant_pool[interface - 1]; - if (cp_info == null or @as(ConstantPoolInfo.Tag, cp_info.?) != .class) return error.WriteFailed; + if (cp_info == null or @as(ConstantPool.Info.Tag, cp_info.?) != .class) return error.WriteFailed; try w.splatByteAll(' ', depth * indent); try w.print("{d}:\n", .{ i }); @@ -297,15 +298,15 @@ pub fn format(self: *const Self, w: *std.Io.Writer) std.Io.Writer.Error!void { } } -pub fn thisClass(self: *const Self) ResolveError!ConstantPoolInfo { +pub fn thisClass(self: *const Self) ResolveError!ConstantPool.Info { const this_class = self.this_class - 1; if (this_class >= self.constant_pool.len) return ResolveError.InvalidConstantPoolIndex; const cp_info = self.constant_pool[this_class]; - if (cp_info == null or @as(ConstantPoolInfo.Tag, cp_info.?) != .class) return ResolveError.InvalidConstantType; + if (cp_info == null or @as(ConstantPool.Info.Tag, cp_info.?) != .class) return ResolveError.InvalidConstantType; return cp_info.?; } -pub fn superClass(self: *const Self) ResolveError!?ConstantPoolInfo { +pub fn superClass(self: *const Self) ResolveError!?ConstantPool.Info { if (self.super_class == 0) { const this_class = (try self.thisClass()).class; const this_class_name = (try this_class.name(self.constant_pool)).utf8; @@ -315,7 +316,7 @@ pub fn superClass(self: *const Self) ResolveError!?ConstantPoolInfo { const super_class = self.super_class - 1; if (super_class >= self.constant_pool.len) return ResolveError.InvalidConstantPoolIndex; const cp_info = self.constant_pool[super_class]; - if (cp_info == null or @as(ConstantPoolInfo.Tag, cp_info.?) != .class) return ResolveError.InvalidConstantType; + if (cp_info == null or @as(ConstantPool.Info.Tag, cp_info.?) != .class) return ResolveError.InvalidConstantType; if (self.access_flags.contains(.interface)) { const super_class_name = (try cp_info.?.class.name(self.constant_pool)).utf8; @@ -326,555 +327,3 @@ pub fn superClass(self: *const Self) ResolveError!?ConstantPoolInfo { return cp_info.?; } } - -pub const ConstantPoolInfo = union(ConstantPoolInfo.Tag) { - class: Class, - field_ref: FieldRef, - method_ref: MethodRef, - interface_method_ref: InterfaceMethodRef, - string: String, - integer: Integer, - float: Float, - long: Long, - double: Double, - name_and_type: NameAndType, - utf8: Utf8, - method_handle: MethodHandle, - method_type: MethodType, - dynamic: Dynamic, - invoke_dynamic: InvokeDynamic, - module: Module, - package: Package, - - pub const Tag = enum(u8) { - class = 7, - field_ref = 9, - method_ref = 10, - interface_method_ref = 11, - string = 8, - integer = 3, - float = 4, - long = 5, - double = 6, - name_and_type = 12, - utf8 = 1, - method_handle = 15, - method_type = 16, - dynamic = 17, - 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 { - name_index: u16, - - pub fn name(self: *const Class, 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 FieldRef = struct { - class_index: u16, - name_and_type_index: u16, - - pub fn class(self: *const FieldRef, constant_pool: []const ?ConstantPoolInfo) ResolveError!ConstantPoolInfo { - 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(Tag, cp_info.?) != .class) return ResolveError.InvalidConstantType; - return cp_info.?; - } - - pub fn nameAndType(self: *const FieldRef, 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 MethodRef = struct { - class_index: u16, - name_and_type_index: u16, - - pub fn class(self: *const MethodRef, constant_pool: []const ?ConstantPoolInfo) ResolveError!ConstantPoolInfo { - 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(Tag, cp_info.?) != .class) return ResolveError.InvalidConstantType; - return cp_info.?; - } - - pub fn nameAndType(self: *const MethodRef, 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 InterfaceMethodRef = struct { - class_index: u16, - name_and_type_index: u16, - - pub fn class(self: *const InterfaceMethodRef, constant_pool: []const ?ConstantPoolInfo) ResolveError!ConstantPoolInfo { - 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(Tag, cp_info.?) != .class) return ResolveError.InvalidConstantType; - return cp_info.?; - } - - pub fn nameAndType(self: *const InterfaceMethodRef, 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 String = struct { - string_index: u16, - - pub fn string(self: *const String, constant_pool: []const ?ConstantPoolInfo) ResolveError!ConstantPoolInfo { - const string_index = self.string_index - 1; - if (string_index >= constant_pool.len) return ResolveError.InvalidConstantPoolIndex; - const cp_info = constant_pool[string_index]; - if (cp_info == null or @as(Tag, cp_info.?) != .utf8) return ResolveError.InvalidConstantType; - return cp_info.?; - } - }; - - pub const Integer = struct { - bytes: u32, - }; - - pub const Float = struct { - bytes: u32, - }; - - pub const Long = struct { - high_bytes: u32, - low_bytes: u32, - }; - - pub const Double = struct { - high_bytes: u32, - low_bytes: u32, - }; - - pub const NameAndType = struct { - name_index: u16, - descriptor_index: u16, - - pub fn name(self: *const NameAndType, 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 descriptor(self: *const NameAndType, 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(Tag, cp_info.?) != .utf8) return ResolveError.InvalidConstantType; - return cp_info.?; - } - }; - - pub const Utf8 = struct { - bytes: []const u8, - }; - - pub const MethodHandle = struct { - reference_kind: Kind, - reference_index: u16, - - pub const Kind = enum(u8) { - get_field = 1, - get_static = 2, - put_field = 3, - put_static = 4, - invoke_virtual = 5, - invoke_static = 6, - invoke_special = 7, - new_invoke_special = 8, - invoke_interface = 9, - }; - - pub fn reference(self: *const MethodHandle, constant_pool: []const ?ConstantPoolInfo) ResolveError!ConstantPoolInfo { - const reference_index = self.reference_index - 1; - if (reference_index >= constant_pool.len) return ResolveError.InvalidConstantPoolIndex; - const cp_info = constant_pool[reference_index]; - return switch (self.reference_kind) { - .get_field, .get_static, .put_field, .put_static => blk: { - if (cp_info == null or @as(Tag, cp_info.?) != .field_ref) break :blk ResolveError.InvalidConstantType; - break :blk cp_info.?; - }, - .invoke_virtual, .invoke_static, .invoke_special, .new_invoke_special => blk: { - if (cp_info == null or @as(Tag, cp_info.?) != .method_ref) break :blk ResolveError.InvalidConstantType; - break :blk cp_info.?; - }, - .invoke_interface => blk: { - if (cp_info == null or @as(Tag, cp_info.?) != .interface_method_ref) break :blk ResolveError.InvalidConstantType; - break :blk cp_info.?; - }, - }; - } - }; - - pub const MethodType = struct { - descriptor_index: u16, - - pub fn descriptor(self: *const MethodType, 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(Tag, cp_info.?) != .utf8) return ResolveError.InvalidConstantType; - return cp_info.?; - } - }; - - 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, - - pub fn nameAndType(self: *const InvokeDynamic, 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 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; - - return switch (tag) { - .class => .{ - .class = .{ - .name_index = try input.takeInt(u16, .big), - }, - }, - .field_ref => .{ - .field_ref = .{ - .class_index = try input.takeInt(u16, .big), - .name_and_type_index = try input.takeInt(u16, .big), - }, - }, - .method_ref => .{ - .method_ref = .{ - .class_index = try input.takeInt(u16, .big), - .name_and_type_index = try input.takeInt(u16, .big), - }, - }, - .interface_method_ref => .{ - .interface_method_ref = .{ - .class_index = try input.takeInt(u16, .big), - .name_and_type_index = try input.takeInt(u16, .big), - }, - }, - .string => .{ - .string = .{ - .string_index = try input.takeInt(u16, .big), - }, - }, - .integer => .{ - .integer = .{ - .bytes = try input.takeInt(u32, .big), - }, - }, - .float => .{ - .integer = .{ - .bytes = try input.takeInt(u32, .big), - }, - }, - .long => .{ - .long = .{ - .high_bytes = try input.takeInt(u32, .big), - .low_bytes = try input.takeInt(u32, .big), - }, - }, - .double => .{ - .double = .{ - .high_bytes = try input.takeInt(u32, .big), - .low_bytes = try input.takeInt(u32, .big), - }, - }, - .name_and_type => .{ - .name_and_type = .{ - .name_index = try input.takeInt(u16, .big), - .descriptor_index = try input.takeInt(u16, .big), - }, - }, - .utf8 => blk: { - const length = try input.takeInt(u16, .big); - const bytes = try input.readAlloc(allocator, length); - - break :blk .{ - .utf8 = .{ - .bytes = bytes, - }, - }; - }, - .method_handle => blk: { - const kind_byte = try input.takeByte(); - const kind = std.enums.fromInt(MethodHandle.Kind, kind_byte) orelse return ParseError.InvalidTag; - - break :blk .{ - .method_handle = .{ - .reference_kind = kind, - .reference_index = try input.takeInt(u16, .big), - }, - }; - }, - .method_type => .{ - .method_type = .{ - .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), - }, - }, - }; - } - - pub fn deinit(self: *ConstantPoolInfo, allocator: std.mem.Allocator) void { - switch (self.*) { - .utf8 => |info| allocator.free(info.bytes), - else => {}, - } - } - - pub fn format(self: *const ConstantPoolInfo, w: *std.Io.Writer) std.Io.Writer.Error!void { - switch (self.*) { - .class => |class| try w.print("#{d}", .{ class.name_index }), - .field_ref => |field_ref| try w.print("#{d}.#{d}", .{ field_ref.class_index, field_ref.name_and_type_index }), - .method_ref => |method_ref| try w.print("#{d}.#{d}", .{ method_ref.class_index, method_ref.name_and_type_index }), - .interface_method_ref => |interface_method_ref| try w.print("#{d}.#{d}", .{ interface_method_ref.class_index, interface_method_ref.name_and_type_index }), - .string => |string| try w.print("#{d}", .{ string.string_index }), - .integer => |integer| try w.print("{d}", .{ integer.bytes }), - .float => |float| try w.print("{d}", .{ @as(f32, @bitCast(float.bytes)) }), - .long => |long| try w.print("{d}", .{ (@as(u64, long.high_bytes) << 32) | long.low_bytes }), - .double => |double| try w.print("{d}", .{ @as(f64, @bitCast((@as(u64, double.high_bytes) << 32) | double.low_bytes)) }), - .name_and_type => |name_and_type| try w.print("#{d}:#{d}", .{ name_and_type.name_index, name_and_type.descriptor_index }), - .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 }), - } - } - - pub fn indentedFormat( - self: *const ConstantPoolInfo, - 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("constant_value_type: {s}\n", .{ @tagName(self.*) }); - - switch (self.*) { - .class => |class| { - try w.splatByteAll(' ', depth * indent); - _ = try w.write("name:\n"); - const class_name = class.name(constant_pool) catch return error.WriteFailed; - try class_name.indentedFormat(w, depth, indent + 1, constant_pool); - }, - .field_ref => |field_ref| { - try w.splatByteAll(' ', depth * indent); - _ = try w.write("class:\n"); - const class = field_ref.class(constant_pool) catch return error.WriteFailed; - try class.indentedFormat(w, depth, indent + 1, constant_pool); - - try w.splatByteAll(' ', depth * indent); - _ = try w.write("name_and_type:\n"); - const name_and_type = field_ref.nameAndType(constant_pool) catch return error.WriteFailed; - try name_and_type.indentedFormat(w, depth, indent + 1, constant_pool); - }, - .method_ref => |method_ref| { - try w.splatByteAll(' ', depth * indent); - _ = try w.write("class:\n"); - const class = method_ref.class(constant_pool) catch return error.WriteFailed; - try class.indentedFormat(w, depth, indent + 1, constant_pool); - - try w.splatByteAll(' ', depth * indent); - _ = try w.write("name_and_type:\n"); - const name_and_type = method_ref.nameAndType(constant_pool) catch return error.WriteFailed; - try name_and_type.indentedFormat(w, depth, indent + 1, constant_pool); - }, - .interface_method_ref => |interface_method_ref| { - try w.splatByteAll(' ', depth * indent); - _ = try w.write("class:\n"); - const class = interface_method_ref.class(constant_pool) catch return error.WriteFailed; - try class.indentedFormat(w, depth, indent + 1, constant_pool); - - try w.splatByteAll(' ', depth * indent); - _ = try w.write("name_and_type:\n"); - const name_and_type = interface_method_ref.nameAndType(constant_pool) catch return error.WriteFailed; - try name_and_type.indentedFormat(w, depth, indent + 1, constant_pool); - }, - .string => |string| { - const s = string.string(constant_pool) catch return error.WriteFailed; - try s.indentedFormat(w, depth, indent + 1, constant_pool); - }, - .integer => |integer| { - try w.splatByteAll(' ', depth * indent); - try w.print("integer: {d}\n", .{ integer.bytes }); - }, - .float => |float| { - const f: f32 = @bitCast(float.bytes); - - try w.splatByteAll(' ', depth * indent); - try w.print("float: {d}\n", .{ f }); - }, - .long => |long| { - const l: u64 = (@as(u64, long.high_bytes) << 32) | long.low_bytes; - - try w.splatByteAll(' ', depth * indent); - try w.print("long: {d}\n", .{ l }); - }, - .double => |double| { - const l: u64 = (@as(u64, double.high_bytes) << 32) | double.low_bytes; - const d: f64 = @bitCast(l); - - try w.splatByteAll(' ', depth * indent); - try w.print("double: {d}\n", .{ d }); - }, - .name_and_type => |name_and_type| { - try w.splatByteAll(' ', depth * indent); - _ = try w.write("name:\n"); - const name = name_and_type.name(constant_pool) catch return error.WriteFailed; - try name.indentedFormat(w, depth, indent + 1, constant_pool); - - try w.splatByteAll(' ', depth * indent); - _ = try w.write("descriptor:\n"); - const descriptor = name_and_type.descriptor(constant_pool) catch return error.WriteFailed; - try descriptor.indentedFormat(w, depth, indent + 1, constant_pool); - }, - .utf8 => |utf8| { - try w.splatByteAll(' ', depth * indent); - try w.print("bytes: \"{s}\"\n", .{ utf8.bytes }); - }, - .method_handle => |method_handle| { - try w.splatByteAll(' ', depth * indent); - try w.print("kind: {t}\n", .{ method_handle.reference_kind }); - - try w.splatByteAll(' ', depth * indent); - _ = try w.write("reference:\n"); - const reference = method_handle.reference(constant_pool) catch return error.WriteFailed; - try reference.indentedFormat(w, depth, indent + 1, constant_pool); - }, - .method_type => |method_type| { - try w.splatByteAll(' ', depth * indent); - _ = try w.write("descriptor:\n"); - 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 b5b913c..ec44f51 100644 --- a/src/Class/AttributeInfo.zig +++ b/src/Class/AttributeInfo.zig @@ -3,7 +3,7 @@ const std = @import("std"); const EnumFlags = @import("../EnumFlags.zig").EnumFlags; const Class = @import("../Class.zig"); -const ConstantPoolInfo = Class.ConstantPoolInfo; +const ConstantPool = Class.ConstantPool; const ParseError = Class.ParseError; const ResolveError = Class.ResolveError; @@ -44,11 +44,11 @@ pub const AttributeInfo = union(enum) { const Self = @This(); - pub fn parse(input: *std.Io.Reader, constant_pool: []const ?ConstantPoolInfo, allocator: std.mem.Allocator) (ParseError || ResolveError)!AttributeInfo { + pub fn parse(input: *std.Io.Reader, constant_pool: []const ?ConstantPool.Info, allocator: std.mem.Allocator) (ParseError || ResolveError)!AttributeInfo { const attribute_name_index = try input.takeInt(u16, .big) - 1; if (attribute_name_index >= constant_pool.len) return ResolveError.InvalidConstantPoolIndex; const cp_info = constant_pool[attribute_name_index]; - if (cp_info == null or @as(ConstantPoolInfo.Tag, cp_info.?) != .utf8) return ResolveError.InvalidConstantType; + if (cp_info == null or @as(ConstantPool.Info.Tag, cp_info.?) != .utf8) return ResolveError.InvalidConstantType; const attribute_name = cp_info.?.utf8; const attribute_length = try input.takeInt(u32, .big); @@ -266,7 +266,7 @@ pub const AttributeInfo = union(enum) { w: *std.Io.Writer, depth: usize, indent: u8, - constant_pool: []const ?ConstantPoolInfo, + constant_pool: []const ?ConstantPool.Info, ) std.Io.Writer.Error!void { switch (self.*) { .new => |new| { @@ -347,7 +347,7 @@ pub const AttributeInfo = union(enum) { 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; + if (cp_info == null or @as(ConstantPool.Info.Tag, cp_info.?) != .class) return error.WriteFailed; try w.splatByteAll(' ', depth * exception_indent); try w.print("{d}:\n", .{ i }); @@ -486,7 +486,7 @@ pub const AttributeInfo = union(enum) { 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; + if (cp_info == null or @as(ConstantPool.Info.Tag, cp_info.?) != .package) return error.WriteFailed; try w.splatByteAll(' ', depth * package_indent); try w.print("{d}:\n", .{ i }); @@ -517,7 +517,7 @@ pub const AttributeInfo = union(enum) { 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; + if (cp_info == null or @as(ConstantPool.Info.Tag, cp_info.?) != .class) return error.WriteFailed; try w.splatByteAll(' ', depth * class_indent); try w.print("{d}:\n", .{ i }); @@ -549,7 +549,7 @@ pub const AttributeInfo = union(enum) { 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; + if (cp_info == null or @as(ConstantPool.Info.Tag, cp_info.?) != .class) return error.WriteFailed; try w.splatByteAll(' ', depth * class_indent); try w.print("{d}:\n", .{ i }); @@ -580,11 +580,11 @@ pub const NewAttribute = struct { allocator.free(self.info); } - pub fn attributeName(self: *const Self, constant_pool: []const ?ConstantPoolInfo) ResolveError!ConstantPoolInfo { + pub fn attributeName(self: *const Self, constant_pool: []const ?ConstantPool.Info) ResolveError!ConstantPool.Info { const attribute_name_index = self.attribute_name_index - 1; if (attribute_name_index >= constant_pool.len) return ResolveError.InvalidConstantPoolIndex; const cp_info = constant_pool[attribute_name_index]; - if (cp_info == null or @as(ConstantPoolInfo.Tag, cp_info.?) != .utf8) return ResolveError.InvalidConstantType; + if (cp_info == null or @as(ConstantPool.Info.Tag, cp_info.?) != .utf8) return ResolveError.InvalidConstantType; return cp_info.?; } @@ -601,7 +601,7 @@ pub const ConstantValue = struct { }; } - pub fn constantValue(self: *const Self, constant_pool: []const ?ConstantPoolInfo) ResolveError!ConstantPoolInfo { + pub fn constantValue(self: *const Self, constant_pool: []const ?ConstantPool.Info) ResolveError!ConstantPool.Info { const constant_value_index = self.constant_value_index - 1; if (constant_value_index >= constant_pool.len) return ResolveError.InvalidConstantPoolIndex; const cp_info = constant_pool[constant_value_index]; @@ -631,7 +631,7 @@ pub const Code = struct { w: *std.Io.Writer, depth: usize, indent: u8, - constant_pool: []const ?ConstantPoolInfo, + constant_pool: []const ?ConstantPool.Info, ) std.Io.Writer.Error!void { try w.splatByteAll(' ', depth * indent); try w.print("start_pc: {d}\n", .{ self.start_pc }); @@ -650,17 +650,17 @@ pub const Code = struct { } } - pub fn catchType(self: *const ExceptionHandler, constant_pool: []const ?ConstantPoolInfo) ResolveError!?ConstantPoolInfo { + pub fn catchType(self: *const ExceptionHandler, constant_pool: []const ?ConstantPool.Info) ResolveError!?ConstantPool.Info { if (self.catch_type == 0) return null; const catch_type = self.catch_type - 1; if (catch_type >= constant_pool.len) return ResolveError.InvalidConstantPoolIndex; const cp_info = constant_pool[catch_type]; - if (cp_info == null or @as(ConstantPoolInfo.Tag, cp_info.?) != .class) return ResolveError.InvalidConstantType; + if (cp_info == null or @as(ConstantPool.Info.Tag, cp_info.?) != .class) return ResolveError.InvalidConstantType; return cp_info.?; } }; - pub fn parse(input: *std.Io.Reader, constant_pool: []const ?ConstantPoolInfo, allocator: std.mem.Allocator) (ParseError || ResolveError)!Self { + pub fn parse(input: *std.Io.Reader, constant_pool: []const ?ConstantPool.Info, allocator: std.mem.Allocator) (ParseError || ResolveError)!Self { const max_stack = try input.takeInt(u16, .big); const max_locals = try input.takeInt(u16, .big); @@ -947,7 +947,7 @@ pub const InnerClasses = struct { w: *std.Io.Writer, depth: usize, indent: u8, - constant_pool: []const ?ConstantPoolInfo, + constant_pool: []const ?ConstantPool.Info, ) std.Io.Writer.Error!void { try w.splatByteAll(' ', depth * indent); try w.print("flags: {f}\n", .{ self.inner_class_access_flags }); @@ -972,31 +972,31 @@ pub const InnerClasses = struct { } } - pub fn innerClass(self: *const InnerClass, constant_pool: []const ?ConstantPoolInfo) ResolveError!ConstantPoolInfo { + pub fn innerClass(self: *const InnerClass, constant_pool: []const ?ConstantPool.Info) ResolveError!ConstantPool.Info { 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(ConstantPoolInfo.Tag, cp_info.?) != .class) return ResolveError.InvalidConstantType; + if (cp_info == null or @as(ConstantPool.Info.Tag, cp_info.?) != .class) return ResolveError.InvalidConstantType; return cp_info.?; } - pub fn outerClass(self: *const InnerClass, constant_pool: []const ?ConstantPoolInfo) ResolveError!?ConstantPoolInfo { + pub fn outerClass(self: *const InnerClass, constant_pool: []const ?ConstantPool.Info) ResolveError!?ConstantPool.Info { 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(ConstantPoolInfo.Tag, cp_info.?) != .class) return ResolveError.InvalidConstantType; + if (cp_info == null or @as(ConstantPool.Info.Tag, cp_info.?) != .class) return ResolveError.InvalidConstantType; return cp_info.?; } - pub fn innerName(self: *const InnerClass, constant_pool: []const ?ConstantPoolInfo) ResolveError!?ConstantPoolInfo { + pub fn innerName(self: *const InnerClass, constant_pool: []const ?ConstantPool.Info) ResolveError!?ConstantPool.Info { 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(ConstantPoolInfo.Tag, cp_info.?) != .utf8) return ResolveError.InvalidConstantType; + if (cp_info == null or @as(ConstantPool.Info.Tag, cp_info.?) != .utf8) return ResolveError.InvalidConstantType; return cp_info.?; } }; @@ -1037,20 +1037,20 @@ pub const EnclosingMethod = struct { }; } - pub fn class(self: *const EnclosingMethod, constant_pool: []const ?ConstantPoolInfo) ResolveError!ConstantPoolInfo { + pub fn class(self: *const EnclosingMethod, constant_pool: []const ?ConstantPool.Info) ResolveError!ConstantPool.Info { 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(ConstantPoolInfo.Tag, cp_info.?) != .class) return ResolveError.InvalidConstantType; + if (cp_info == null or @as(ConstantPool.Info.Tag, cp_info.?) != .class) return ResolveError.InvalidConstantType; return cp_info.?; } - pub fn method(self: *const EnclosingMethod, constant_pool: []const ?ConstantPoolInfo) ResolveError!?ConstantPoolInfo { + pub fn method(self: *const EnclosingMethod, constant_pool: []const ?ConstantPool.Info) ResolveError!?ConstantPool.Info { 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(ConstantPoolInfo.Tag, cp_info.?) != .name_and_type) return ResolveError.InvalidConstantType; + if (cp_info == null or @as(ConstantPool.Info.Tag, cp_info.?) != .name_and_type) return ResolveError.InvalidConstantType; return cp_info.?; } }; @@ -1068,11 +1068,11 @@ pub const Signature = struct { }; } - pub fn signature(self: *const Signature, constant_pool: []const ?ConstantPoolInfo) ResolveError!ConstantPoolInfo { + pub fn signature(self: *const Signature, constant_pool: []const ?ConstantPool.Info) ResolveError!ConstantPool.Info { const signature_index = self.signature_index - 1; if (signature_index >= constant_pool.len) return ResolveError.InvalidConstantPoolIndex; const cp_info = constant_pool[signature_index]; - if (cp_info == null or @as(ConstantPoolInfo.Tag, cp_info.?) != .utf8) return ResolveError.InvalidConstantType; + if (cp_info == null or @as(ConstantPool.Info.Tag, cp_info.?) != .utf8) return ResolveError.InvalidConstantType; return cp_info.?; } }; @@ -1088,11 +1088,11 @@ pub const SourceFile = struct { }; } - pub fn sourceFile(self: *const SourceFile, constant_pool: []const ?ConstantPoolInfo) ResolveError!ConstantPoolInfo { + pub fn sourceFile(self: *const SourceFile, constant_pool: []const ?ConstantPool.Info) ResolveError!ConstantPool.Info { const source_file_index = self.source_file_index - 1; if (source_file_index >= constant_pool.len) return ResolveError.InvalidConstantPoolIndex; const cp_info = constant_pool[source_file_index]; - if (cp_info == null or @as(ConstantPoolInfo.Tag, cp_info.?) != .utf8) return ResolveError.InvalidConstantType; + if (cp_info == null or @as(ConstantPool.Info.Tag, cp_info.?) != .utf8) return ResolveError.InvalidConstantType; return cp_info.?; } }; @@ -1174,7 +1174,7 @@ pub const LocalVariableTable = struct { w: *std.Io.Writer, depth: usize, indent: u8, - constant_pool: []const ?ConstantPoolInfo, + constant_pool: []const ?ConstantPool.Info, ) std.Io.Writer.Error!void { try w.splatByteAll(' ', depth * indent); try w.print("start_pc: {d}\n", .{ self.start_pc }); @@ -1193,19 +1193,19 @@ pub const LocalVariableTable = struct { try descriptor_.indentedFormat(w, depth, indent + 1, constant_pool); } - pub fn name(self: *const LocalVariable, constant_pool: []const ?ConstantPoolInfo) ResolveError!ConstantPoolInfo { + pub fn name(self: *const LocalVariable, constant_pool: []const ?ConstantPool.Info) ResolveError!ConstantPool.Info { 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; + if (cp_info == null or @as(ConstantPool.Info.Tag, cp_info.?) != .utf8) return ResolveError.InvalidConstantType; return cp_info.?; } - pub fn descriptor(self: *const LocalVariable, constant_pool: []const ?ConstantPoolInfo) ResolveError!ConstantPoolInfo { + pub fn descriptor(self: *const LocalVariable, constant_pool: []const ?ConstantPool.Info) ResolveError!ConstantPool.Info { 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; + if (cp_info == null or @as(ConstantPool.Info.Tag, cp_info.?) != .utf8) return ResolveError.InvalidConstantType; return cp_info.?; } }; @@ -1251,7 +1251,7 @@ pub const LocalVariableTypeTable = struct { w: *std.Io.Writer, depth: usize, indent: u8, - constant_pool: []const ?ConstantPoolInfo, + constant_pool: []const ?ConstantPool.Info, ) std.Io.Writer.Error!void { try w.splatByteAll(' ', depth * indent); try w.print("start_pc: {d}\n", .{ self.start_pc }); @@ -1270,19 +1270,19 @@ pub const LocalVariableTypeTable = struct { try signature_.indentedFormat(w, depth, indent + 1, constant_pool); } - pub fn name(self: *const LocalVariableType, constant_pool: []const ?ConstantPoolInfo) ResolveError!ConstantPoolInfo { + pub fn name(self: *const LocalVariableType, constant_pool: []const ?ConstantPool.Info) ResolveError!ConstantPool.Info { 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; + if (cp_info == null or @as(ConstantPool.Info.Tag, cp_info.?) != .utf8) return ResolveError.InvalidConstantType; return cp_info.?; } - pub fn signature(self: *const LocalVariableType, constant_pool: []const ?ConstantPoolInfo) ResolveError!ConstantPoolInfo { + pub fn signature(self: *const LocalVariableType, constant_pool: []const ?ConstantPool.Info) ResolveError!ConstantPool.Info { const signature_index = self.signature_index - 1; if (signature_index >= constant_pool.len) return ResolveError.InvalidConstantPoolIndex; const cp_info = constant_pool[signature_index]; - if (cp_info == null or @as(ConstantPoolInfo.Tag, cp_info.?) != .utf8) return ResolveError.InvalidConstantType; + if (cp_info == null or @as(ConstantPool.Info.Tag, cp_info.?) != .utf8) return ResolveError.InvalidConstantType; return cp_info.?; } }; @@ -1623,7 +1623,7 @@ pub const BootstrapMethods = struct { w: *std.Io.Writer, depth: usize, indent: u8, - constant_pool: []const ?ConstantPoolInfo, + constant_pool: []const ?ConstantPool.Info, ) std.Io.Writer.Error!void { const bootstrap_method = self.bootstrapMethod(constant_pool) catch return error.WriteFailed; try w.splatByteAll(' ', depth * indent); @@ -1641,7 +1641,7 @@ pub const BootstrapMethods = struct { 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; + if (cp_info == null or !@as(ConstantPool.Info.Tag, cp_info.?).loadable()) return error.WriteFailed; try w.splatByteAll(' ', depth * bootstrap_argument_indent); try w.print("{d}:\n", .{ i }); @@ -1649,11 +1649,11 @@ pub const BootstrapMethods = struct { } } - pub fn bootstrapMethod(self: *const BootstrapMethod, constant_pool: []const ?ConstantPoolInfo) ResolveError!ConstantPoolInfo { + pub fn bootstrapMethod(self: *const BootstrapMethod, constant_pool: []const ?ConstantPool.Info) ResolveError!ConstantPool.Info { 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; + if (cp_info == null or @as(ConstantPool.Info.Tag, cp_info.?) != .method_handle) return ResolveError.InvalidConstantType; return cp_info.?; } }; @@ -1711,7 +1711,7 @@ pub const MethodParameters = struct { w: *std.Io.Writer, depth: usize, indent: u8, - constant_pool: []const ?ConstantPoolInfo, + constant_pool: []const ?ConstantPool.Info, ) std.Io.Writer.Error!void { try w.splatByteAll(' ', depth * indent); try w.print("flags: {f}\n", .{ self.access_flags }); @@ -1722,11 +1722,11 @@ pub const MethodParameters = struct { try name_.indentedFormat(w, depth, indent + 1, constant_pool); } - pub fn name(self: *const Parameter, constant_pool: []const ?ConstantPoolInfo) ResolveError!ConstantPoolInfo { + pub fn name(self: *const Parameter, constant_pool: []const ?ConstantPool.Info) ResolveError!ConstantPool.Info { 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; + if (cp_info == null or @as(ConstantPool.Info.Tag, cp_info.?) != .utf8) return ResolveError.InvalidConstantType; return cp_info.?; } }; @@ -1787,7 +1787,7 @@ pub const Module = struct { w: *std.Io.Writer, depth: usize, indent: u8, - constant_pool: []const ?ConstantPoolInfo, + constant_pool: []const ?ConstantPool.Info, ) std.Io.Writer.Error!void { const requires_ = self.requires(constant_pool) catch return error.WriteFailed; try w.splatByteAll(' ', depth * indent); @@ -1805,20 +1805,20 @@ pub const Module = struct { } } - pub fn requires(self: *const Requires, constant_pool: []const ?ConstantPoolInfo) ResolveError!ConstantPoolInfo { + pub fn requires(self: *const Requires, constant_pool: []const ?ConstantPool.Info) ResolveError!ConstantPool.Info { const requires_index = self.requires_index - 1; if (requires_index >= constant_pool.len) return ResolveError.InvalidConstantPoolIndex; const cp_info = constant_pool[requires_index]; - if (cp_info == null or @as(ConstantPoolInfo.Tag, cp_info.?) != .module) return ResolveError.InvalidConstantType; + if (cp_info == null or @as(ConstantPool.Info.Tag, cp_info.?) != .module) return ResolveError.InvalidConstantType; return cp_info.?; } - pub fn requiresVersion(self: *const Requires, constant_pool: []const ?ConstantPoolInfo) ResolveError!?ConstantPoolInfo { + pub fn requiresVersion(self: *const Requires, constant_pool: []const ?ConstantPool.Info) ResolveError!?ConstantPool.Info { if (self.requires_version_index == 0) return null; const requires_version_index = self.requires_version_index - 1; if (requires_version_index >= constant_pool.len) return ResolveError.InvalidConstantPoolIndex; const cp_info = constant_pool[requires_version_index]; - if (cp_info == null or @as(ConstantPoolInfo.Tag, cp_info.?) != .utf8) return ResolveError.InvalidConstantType; + if (cp_info == null or @as(ConstantPool.Info.Tag, cp_info.?) != .utf8) return ResolveError.InvalidConstantType; return cp_info.?; } }; @@ -1838,7 +1838,7 @@ pub const Module = struct { w: *std.Io.Writer, depth: usize, indent: u8, - constant_pool: []const ?ConstantPoolInfo, + constant_pool: []const ?ConstantPool.Info, ) std.Io.Writer.Error!void { const exports_ = self.exports(constant_pool) catch return error.WriteFailed; try w.splatByteAll(' ', depth * indent); @@ -1859,7 +1859,7 @@ pub const Module = struct { if (index >= constant_pool.len) return error.WriteFailed; const cp_info = constant_pool[index]; - if (cp_info == null or @as(ConstantPoolInfo.Tag, cp_info.?) != .module) return error.WriteFailed; + if (cp_info == null or @as(ConstantPool.Info.Tag, cp_info.?) != .module) return error.WriteFailed; try w.splatByteAll(' ', depth * exports_to_indent); try w.print("{d}:\n", .{ i }); @@ -1867,11 +1867,11 @@ pub const Module = struct { } } - pub fn exports(self: *const Exports, constant_pool: []const ?ConstantPoolInfo) ResolveError!ConstantPoolInfo { + pub fn exports(self: *const Exports, constant_pool: []const ?ConstantPool.Info) ResolveError!ConstantPool.Info { const exports_index = self.exports_index - 1; if (exports_index >= constant_pool.len) return ResolveError.InvalidConstantPoolIndex; const cp_info = constant_pool[exports_index]; - if (cp_info == null or @as(ConstantPoolInfo.Tag, cp_info.?) != .package) return ResolveError.InvalidConstantType; + if (cp_info == null or @as(ConstantPool.Info.Tag, cp_info.?) != .package) return ResolveError.InvalidConstantType; return cp_info.?; } }; @@ -1891,7 +1891,7 @@ pub const Module = struct { w: *std.Io.Writer, depth: usize, indent: u8, - constant_pool: []const ?ConstantPoolInfo, + constant_pool: []const ?ConstantPool.Info, ) std.Io.Writer.Error!void { const opens_ = self.opens(constant_pool) catch return error.WriteFailed; try w.splatByteAll(' ', depth * indent); @@ -1912,7 +1912,7 @@ pub const Module = struct { if (index >= constant_pool.len) return error.WriteFailed; const cp_info = constant_pool[index]; - if (cp_info == null or @as(ConstantPoolInfo.Tag, cp_info.?) != .module) return error.WriteFailed; + if (cp_info == null or @as(ConstantPool.Info.Tag, cp_info.?) != .module) return error.WriteFailed; try w.splatByteAll(' ', depth * opens_to_indent); try w.print("{d}:\n", .{ i }); @@ -1920,11 +1920,11 @@ pub const Module = struct { } } - pub fn opens(self: *const Opens, constant_pool: []const ?ConstantPoolInfo) ResolveError!ConstantPoolInfo { + pub fn opens(self: *const Opens, constant_pool: []const ?ConstantPool.Info) ResolveError!ConstantPool.Info { const opens_index = self.opens_index - 1; if (opens_index >= constant_pool.len) return ResolveError.InvalidConstantPoolIndex; const cp_info = constant_pool[opens_index]; - if (cp_info == null or @as(ConstantPoolInfo.Tag, cp_info.?) != .package) return ResolveError.InvalidConstantType; + if (cp_info == null or @as(ConstantPool.Info.Tag, cp_info.?) != .package) return ResolveError.InvalidConstantType; return cp_info.?; } }; @@ -1938,7 +1938,7 @@ pub const Module = struct { w: *std.Io.Writer, depth: usize, indent: u8, - constant_pool: []const ?ConstantPoolInfo, + constant_pool: []const ?ConstantPool.Info, ) std.Io.Writer.Error!void { const provides_ = self.provides(constant_pool) catch return error.WriteFailed; try w.splatByteAll(' ', depth * indent); @@ -1956,7 +1956,7 @@ pub const Module = struct { 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; + if (cp_info == null or @as(ConstantPool.Info.Tag, cp_info.?) != .class) return error.WriteFailed; try w.splatByteAll(' ', depth * provides_with_indent); try w.print("{d}:\n", .{ i }); @@ -1964,11 +1964,11 @@ pub const Module = struct { } } - pub fn provides(self: *const Provides, constant_pool: []const ?ConstantPoolInfo) ResolveError!ConstantPoolInfo { + pub fn provides(self: *const Provides, constant_pool: []const ?ConstantPool.Info) ResolveError!ConstantPool.Info { const provides_index = self.provides_index - 1; if (provides_index >= constant_pool.len) return ResolveError.InvalidConstantPoolIndex; const cp_info = constant_pool[provides_index]; - if (cp_info == null or @as(ConstantPoolInfo.Tag, cp_info.?) != .class) return ResolveError.InvalidConstantType; + if (cp_info == null or @as(ConstantPool.Info.Tag, cp_info.?) != .class) return ResolveError.InvalidConstantType; return cp_info.?; } }; @@ -2088,7 +2088,7 @@ pub const Module = struct { w: *std.Io.Writer, depth: usize, indent: u8, - constant_pool: []const ?ConstantPoolInfo, + constant_pool: []const ?ConstantPool.Info, ) std.Io.Writer.Error!void { const module_name = self.moduleName(constant_pool) catch return error.WriteFailed; try w.splatByteAll(' ', depth * indent); @@ -2152,7 +2152,7 @@ pub const Module = struct { 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; + if (cp_info == null or @as(ConstantPool.Info.Tag, cp_info.?) != .class) return error.WriteFailed; try w.splatByteAll(' ', depth * uses_indent); try w.print("{d}:\n", .{ i }); @@ -2172,20 +2172,20 @@ pub const Module = struct { } } - pub fn moduleName(self: *const Module, constant_pool: []const ?ConstantPoolInfo) ResolveError!ConstantPoolInfo { + pub fn moduleName(self: *const Module, constant_pool: []const ?ConstantPool.Info) ResolveError!ConstantPool.Info { const module_name_index = self.module_name_index - 1; if (module_name_index >= constant_pool.len) return ResolveError.InvalidConstantPoolIndex; const cp_info = constant_pool[module_name_index]; - if (cp_info == null or @as(ConstantPoolInfo.Tag, cp_info.?) != .utf8) return ResolveError.InvalidConstantType; + if (cp_info == null or @as(ConstantPool.Info.Tag, cp_info.?) != .utf8) return ResolveError.InvalidConstantType; return cp_info.?; } - pub fn moduleVersion(self: *const Module, constant_pool: []const ?ConstantPoolInfo) ResolveError!?ConstantPoolInfo { + pub fn moduleVersion(self: *const Module, constant_pool: []const ?ConstantPool.Info) ResolveError!?ConstantPool.Info { if (self.module_version_index == 0) return null; const module_version_index = self.module_version_index - 1; if (module_version_index >= constant_pool.len) return ResolveError.InvalidConstantPoolIndex; const cp_info = constant_pool[module_version_index]; - if (cp_info == null or @as(ConstantPoolInfo.Tag, cp_info.?) != .utf8) return ResolveError.InvalidConstantType; + if (cp_info == null or @as(ConstantPool.Info.Tag, cp_info.?) != .utf8) return ResolveError.InvalidConstantType; return cp_info.?; } }; @@ -2224,11 +2224,11 @@ pub const ModuleMainClass = struct { }; } - pub fn mainClass(self: *const ModuleMainClass, constant_pool: []const ?ConstantPoolInfo) ResolveError!ConstantPoolInfo { + pub fn mainClass(self: *const ModuleMainClass, constant_pool: []const ?ConstantPool.Info) ResolveError!ConstantPool.Info { 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; + if (cp_info == null or @as(ConstantPool.Info.Tag, cp_info.?) != .class) return ResolveError.InvalidConstantType; return cp_info.?; } }; @@ -2244,11 +2244,11 @@ pub const NestHost = struct { }; } - pub fn hostClass(self: *const NestHost, constant_pool: []const ?ConstantPoolInfo) ResolveError!ConstantPoolInfo { + pub fn hostClass(self: *const NestHost, constant_pool: []const ?ConstantPool.Info) ResolveError!ConstantPool.Info { 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; + if (cp_info == null or @as(ConstantPool.Info.Tag, cp_info.?) != .class) return ResolveError.InvalidConstantType; return cp_info.?; } }; @@ -2285,7 +2285,7 @@ pub const Record = struct { descriptor_index: u16, attributes: []AttributeInfo, - pub fn parse(input: *std.Io.Reader, constant_pool: []const ?ConstantPoolInfo, allocator: std.mem.Allocator) (ParseError || ResolveError)!RecordComponentInfo { + pub fn parse(input: *std.Io.Reader, constant_pool: []const ?ConstantPool.Info, allocator: std.mem.Allocator) (ParseError || ResolveError)!RecordComponentInfo { const name_index = try input.takeInt(u16, .big); const descriptor_index = try input.takeInt(u16, .big); @@ -2315,7 +2315,7 @@ pub const Record = struct { w: *std.Io.Writer, depth: usize, indent: u8, - constant_pool: []const ?ConstantPoolInfo, + constant_pool: []const ?ConstantPool.Info, ) std.Io.Writer.Error!void { const name_ = self.name(constant_pool) catch return error.WriteFailed; try w.splatByteAll(' ', depth * indent); @@ -2341,24 +2341,24 @@ pub const Record = struct { } } - pub fn name(self: *const RecordComponentInfo, constant_pool: []const ?ConstantPoolInfo) ResolveError!ConstantPoolInfo { + pub fn name(self: *const RecordComponentInfo, constant_pool: []const ?ConstantPool.Info) ResolveError!ConstantPool.Info { 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; + if (cp_info == null or @as(ConstantPool.Info.Tag, cp_info.?) != .utf8) return ResolveError.InvalidConstantType; return cp_info.?; } - pub fn descriptor(self: *const RecordComponentInfo, constant_pool: []const ?ConstantPoolInfo) ResolveError!ConstantPoolInfo { + pub fn descriptor(self: *const RecordComponentInfo, constant_pool: []const ?ConstantPool.Info) ResolveError!ConstantPool.Info { 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; + if (cp_info == null or @as(ConstantPool.Info.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 { + pub fn parse(input: *std.Io.Reader, constant_pool: []const ?ConstantPool.Info, allocator: std.mem.Allocator) (ParseError || ResolveError)!Self { const components_count = try input.takeInt(u16, .big); const components = try allocator.alloc(RecordComponentInfo, components_count); for (components) |*component| { diff --git a/src/Class/ConstantPool.zig b/src/Class/ConstantPool.zig new file mode 100644 index 0000000..cdf4063 --- /dev/null +++ b/src/Class/ConstantPool.zig @@ -0,0 +1,581 @@ +const std = @import("std"); + +const Class = @import("../Class.zig"); +const AttributeInfo = Class.AttributeInfo; +const ParseError = Class.ParseError; +const ResolveError = Class.ResolveError; + +pub const Info = union(Info.Tag) { + class: Info.Class, + field_ref: FieldRef, + method_ref: MethodRef, + interface_method_ref: InterfaceMethodRef, + string: String, + integer: Integer, + float: Float, + long: Long, + double: Double, + name_and_type: NameAndType, + utf8: Utf8, + method_handle: MethodHandle, + method_type: MethodType, + dynamic: Dynamic, + invoke_dynamic: InvokeDynamic, + module: Module, + package: Package, + + pub const Tag = enum(u8) { + class = 7, + field_ref = 9, + method_ref = 10, + interface_method_ref = 11, + string = 8, + integer = 3, + float = 4, + long = 5, + double = 6, + name_and_type = 12, + utf8 = 1, + method_handle = 15, + method_type = 16, + dynamic = 17, + 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 { + name_index: u16, + + const Self = @This(); + + pub fn name(self: *const Self, constant_pool: []const ?Info) ResolveError!Info { + 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 FieldRef = struct { + class_index: u16, + name_and_type_index: u16, + + const Self = @This(); + + pub fn class(self: *const Self, constant_pool: []const ?Info) ResolveError!Info { + 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(Tag, cp_info.?) != .class) return ResolveError.InvalidConstantType; + return cp_info.?; + } + + pub fn nameAndType(self: *const Self, constant_pool: []const ?Info) ResolveError!Info { + 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 MethodRef = struct { + class_index: u16, + name_and_type_index: u16, + + const Self = @This(); + + pub fn class(self: *const Self, constant_pool: []const ?Info) ResolveError!Info { + 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(Tag, cp_info.?) != .class) return ResolveError.InvalidConstantType; + return cp_info.?; + } + + pub fn nameAndType(self: *const Self, constant_pool: []const ?Info) ResolveError!Info { + 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 InterfaceMethodRef = struct { + class_index: u16, + name_and_type_index: u16, + + const Self = @This(); + + pub fn class(self: *const Self, constant_pool: []const ?Info) ResolveError!Info { + 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(Tag, cp_info.?) != .class) return ResolveError.InvalidConstantType; + return cp_info.?; + } + + pub fn nameAndType(self: *const Self, constant_pool: []const ?Info) ResolveError!Info { + 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 String = struct { + string_index: u16, + + const Self = @This(); + + pub fn string(self: *const Self, constant_pool: []const ?Info) ResolveError!Info { + const string_index = self.string_index - 1; + if (string_index >= constant_pool.len) return ResolveError.InvalidConstantPoolIndex; + const cp_info = constant_pool[string_index]; + if (cp_info == null or @as(Tag, cp_info.?) != .utf8) return ResolveError.InvalidConstantType; + return cp_info.?; + } + }; + + pub const Integer = struct { + bytes: u32, + }; + + pub const Float = struct { + bytes: u32, + }; + + pub const Long = struct { + high_bytes: u32, + low_bytes: u32, + }; + + pub const Double = struct { + high_bytes: u32, + low_bytes: u32, + }; + + pub const NameAndType = struct { + name_index: u16, + descriptor_index: u16, + + const Self = @This(); + + pub fn name(self: *const Self, constant_pool: []const ?Info) ResolveError!Info { + 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 descriptor(self: *const Self, constant_pool: []const ?Info) ResolveError!Info { + 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(Tag, cp_info.?) != .utf8) return ResolveError.InvalidConstantType; + return cp_info.?; + } + }; + + pub const Utf8 = struct { + bytes: []const u8, + }; + + pub const MethodHandle = struct { + reference_kind: Kind, + reference_index: u16, + + const Self = @This(); + + pub const Kind = enum(u8) { + get_field = 1, + get_static = 2, + put_field = 3, + put_static = 4, + invoke_virtual = 5, + invoke_static = 6, + invoke_special = 7, + new_invoke_special = 8, + invoke_interface = 9, + }; + + pub fn reference(self: *const Self, constant_pool: []const ?Info) ResolveError!Info { + const reference_index = self.reference_index - 1; + if (reference_index >= constant_pool.len) return ResolveError.InvalidConstantPoolIndex; + const cp_info = constant_pool[reference_index]; + return switch (self.reference_kind) { + .get_field, .get_static, .put_field, .put_static => blk: { + if (cp_info == null or @as(Tag, cp_info.?) != .field_ref) break :blk ResolveError.InvalidConstantType; + break :blk cp_info.?; + }, + .invoke_virtual, .invoke_static, .invoke_special, .new_invoke_special => blk: { + if (cp_info == null or @as(Tag, cp_info.?) != .method_ref) break :blk ResolveError.InvalidConstantType; + break :blk cp_info.?; + }, + .invoke_interface => blk: { + if (cp_info == null or @as(Tag, cp_info.?) != .interface_method_ref) break :blk ResolveError.InvalidConstantType; + break :blk cp_info.?; + }, + }; + } + }; + + pub const MethodType = struct { + descriptor_index: u16, + + const Self = @This(); + + pub fn descriptor(self: *const Self, constant_pool: []const ?Info) ResolveError!Info { + 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(Tag, cp_info.?) != .utf8) return ResolveError.InvalidConstantType; + return cp_info.?; + } + }; + + pub const Dynamic = struct { + bootstrap_method_attr_index: u16, + name_and_type_index: u16, + + const Self = @This(); + + pub fn nameAndType(self: *const Self, constant_pool: []const ?Info) ResolveError!Info { + 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, + + const Self = @This(); + + pub fn nameAndType(self: *const Self, constant_pool: []const ?Info) ResolveError!Info { + 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 Module = struct { + name_index: u16, + + const Self = @This(); + + pub fn name(self: *const Self, constant_pool: []const ?Info) ResolveError!Info { + 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, + + const Self = @This(); + + pub fn name(self: *const Self, constant_pool: []const ?Info) ResolveError!Info { + 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!Info { + const tag_byte = try input.takeByte(); + const tag = std.enums.fromInt(Tag, tag_byte) orelse return ParseError.InvalidTag; + + return switch (tag) { + .class => .{ + .class = .{ + .name_index = try input.takeInt(u16, .big), + }, + }, + .field_ref => .{ + .field_ref = .{ + .class_index = try input.takeInt(u16, .big), + .name_and_type_index = try input.takeInt(u16, .big), + }, + }, + .method_ref => .{ + .method_ref = .{ + .class_index = try input.takeInt(u16, .big), + .name_and_type_index = try input.takeInt(u16, .big), + }, + }, + .interface_method_ref => .{ + .interface_method_ref = .{ + .class_index = try input.takeInt(u16, .big), + .name_and_type_index = try input.takeInt(u16, .big), + }, + }, + .string => .{ + .string = .{ + .string_index = try input.takeInt(u16, .big), + }, + }, + .integer => .{ + .integer = .{ + .bytes = try input.takeInt(u32, .big), + }, + }, + .float => .{ + .integer = .{ + .bytes = try input.takeInt(u32, .big), + }, + }, + .long => .{ + .long = .{ + .high_bytes = try input.takeInt(u32, .big), + .low_bytes = try input.takeInt(u32, .big), + }, + }, + .double => .{ + .double = .{ + .high_bytes = try input.takeInt(u32, .big), + .low_bytes = try input.takeInt(u32, .big), + }, + }, + .name_and_type => .{ + .name_and_type = .{ + .name_index = try input.takeInt(u16, .big), + .descriptor_index = try input.takeInt(u16, .big), + }, + }, + .utf8 => blk: { + const length = try input.takeInt(u16, .big); + const bytes = try input.readAlloc(allocator, length); + + break :blk .{ + .utf8 = .{ + .bytes = bytes, + }, + }; + }, + .method_handle => blk: { + const kind_byte = try input.takeByte(); + const kind = std.enums.fromInt(MethodHandle.Kind, kind_byte) orelse return ParseError.InvalidTag; + + break :blk .{ + .method_handle = .{ + .reference_kind = kind, + .reference_index = try input.takeInt(u16, .big), + }, + }; + }, + .method_type => .{ + .method_type = .{ + .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), + }, + }, + }; + } + + pub fn deinit(self: *Info, allocator: std.mem.Allocator) void { + switch (self.*) { + .utf8 => |info| allocator.free(info.bytes), + else => {}, + } + } + + pub fn format(self: *const Info, w: *std.Io.Writer) std.Io.Writer.Error!void { + switch (self.*) { + .class => |class| try w.print("#{d}", .{ class.name_index }), + .field_ref => |field_ref| try w.print("#{d}.#{d}", .{ field_ref.class_index, field_ref.name_and_type_index }), + .method_ref => |method_ref| try w.print("#{d}.#{d}", .{ method_ref.class_index, method_ref.name_and_type_index }), + .interface_method_ref => |interface_method_ref| try w.print("#{d}.#{d}", .{ interface_method_ref.class_index, interface_method_ref.name_and_type_index }), + .string => |string| try w.print("#{d}", .{ string.string_index }), + .integer => |integer| try w.print("{d}", .{ integer.bytes }), + .float => |float| try w.print("{d}", .{ @as(f32, @bitCast(float.bytes)) }), + .long => |long| try w.print("{d}", .{ (@as(u64, long.high_bytes) << 32) | long.low_bytes }), + .double => |double| try w.print("{d}", .{ @as(f64, @bitCast((@as(u64, double.high_bytes) << 32) | double.low_bytes)) }), + .name_and_type => |name_and_type| try w.print("#{d}:#{d}", .{ name_and_type.name_index, name_and_type.descriptor_index }), + .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 }), + } + } + + pub fn indentedFormat( + self: *const Info, + w: *std.Io.Writer, + depth: usize, + indent: u8, + constant_pool: []const ?Info, + ) std.Io.Writer.Error!void { + try w.splatByteAll(' ', depth * indent); + try w.print("constant_value_type: {s}\n", .{ @tagName(self.*) }); + + switch (self.*) { + .class => |class| { + try w.splatByteAll(' ', depth * indent); + _ = try w.write("name:\n"); + const class_name = class.name(constant_pool) catch return error.WriteFailed; + try class_name.indentedFormat(w, depth, indent + 1, constant_pool); + }, + .field_ref => |field_ref| { + try w.splatByteAll(' ', depth * indent); + _ = try w.write("class:\n"); + const class = field_ref.class(constant_pool) catch return error.WriteFailed; + try class.indentedFormat(w, depth, indent + 1, constant_pool); + + try w.splatByteAll(' ', depth * indent); + _ = try w.write("name_and_type:\n"); + const name_and_type = field_ref.nameAndType(constant_pool) catch return error.WriteFailed; + try name_and_type.indentedFormat(w, depth, indent + 1, constant_pool); + }, + .method_ref => |method_ref| { + try w.splatByteAll(' ', depth * indent); + _ = try w.write("class:\n"); + const class = method_ref.class(constant_pool) catch return error.WriteFailed; + try class.indentedFormat(w, depth, indent + 1, constant_pool); + + try w.splatByteAll(' ', depth * indent); + _ = try w.write("name_and_type:\n"); + const name_and_type = method_ref.nameAndType(constant_pool) catch return error.WriteFailed; + try name_and_type.indentedFormat(w, depth, indent + 1, constant_pool); + }, + .interface_method_ref => |interface_method_ref| { + try w.splatByteAll(' ', depth * indent); + _ = try w.write("class:\n"); + const class = interface_method_ref.class(constant_pool) catch return error.WriteFailed; + try class.indentedFormat(w, depth, indent + 1, constant_pool); + + try w.splatByteAll(' ', depth * indent); + _ = try w.write("name_and_type:\n"); + const name_and_type = interface_method_ref.nameAndType(constant_pool) catch return error.WriteFailed; + try name_and_type.indentedFormat(w, depth, indent + 1, constant_pool); + }, + .string => |string| { + const s = string.string(constant_pool) catch return error.WriteFailed; + try s.indentedFormat(w, depth, indent + 1, constant_pool); + }, + .integer => |integer| { + try w.splatByteAll(' ', depth * indent); + try w.print("integer: {d}\n", .{ integer.bytes }); + }, + .float => |float| { + const f: f32 = @bitCast(float.bytes); + + try w.splatByteAll(' ', depth * indent); + try w.print("float: {d}\n", .{ f }); + }, + .long => |long| { + const l: u64 = (@as(u64, long.high_bytes) << 32) | long.low_bytes; + + try w.splatByteAll(' ', depth * indent); + try w.print("long: {d}\n", .{ l }); + }, + .double => |double| { + const l: u64 = (@as(u64, double.high_bytes) << 32) | double.low_bytes; + const d: f64 = @bitCast(l); + + try w.splatByteAll(' ', depth * indent); + try w.print("double: {d}\n", .{ d }); + }, + .name_and_type => |name_and_type| { + try w.splatByteAll(' ', depth * indent); + _ = try w.write("name:\n"); + const name = name_and_type.name(constant_pool) catch return error.WriteFailed; + try name.indentedFormat(w, depth, indent + 1, constant_pool); + + try w.splatByteAll(' ', depth * indent); + _ = try w.write("descriptor:\n"); + const descriptor = name_and_type.descriptor(constant_pool) catch return error.WriteFailed; + try descriptor.indentedFormat(w, depth, indent + 1, constant_pool); + }, + .utf8 => |utf8| { + try w.splatByteAll(' ', depth * indent); + try w.print("bytes: \"{s}\"\n", .{ utf8.bytes }); + }, + .method_handle => |method_handle| { + try w.splatByteAll(' ', depth * indent); + try w.print("kind: {t}\n", .{ method_handle.reference_kind }); + + try w.splatByteAll(' ', depth * indent); + _ = try w.write("reference:\n"); + const reference = method_handle.reference(constant_pool) catch return error.WriteFailed; + try reference.indentedFormat(w, depth, indent + 1, constant_pool); + }, + .method_type => |method_type| { + try w.splatByteAll(' ', depth * indent); + _ = try w.write("descriptor:\n"); + 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/FieldInfo.zig b/src/Class/FieldInfo.zig index 952cf38..12a75a3 100644 --- a/src/Class/FieldInfo.zig +++ b/src/Class/FieldInfo.zig @@ -3,7 +3,7 @@ const std = @import("std"); const EnumFlags = @import("../EnumFlags.zig").EnumFlags; const Class = @import("../Class.zig"); -const ConstantPoolInfo = Class.ConstantPoolInfo; +const ConstantPool = Class.ConstantPool; const AttributeInfo = Class.AttributeInfo; const ResolveError = Class.ResolveError; @@ -26,7 +26,7 @@ pub const FieldAccessFlags = EnumFlags(enum(u16) { @"enum" = 0x4000, }); -pub fn parse(input: *std.Io.Reader, constant_pool: []const ?ConstantPoolInfo, allocator: std.mem.Allocator) !Self { +pub fn parse(input: *std.Io.Reader, constant_pool: []const ?ConstantPool.Info, allocator: std.mem.Allocator) !Self { const access_flags: FieldAccessFlags = .{ .mask = try input.takeInt(u16, .big) }; const name_index = try input.takeInt(u16, .big); const descriptor_index = try input.takeInt(u16, .big); @@ -51,7 +51,7 @@ pub fn indentedFormat( w: *std.Io.Writer, depth: usize, indent: u8, - constant_pool: []const ?ConstantPoolInfo, + constant_pool: []const ?ConstantPool.Info, ) std.Io.Writer.Error!void { try w.splatByteAll(' ', depth * indent); try w.print("flags: {f}\n", .{ self.access_flags }); @@ -80,19 +80,19 @@ pub fn indentedFormat( } } -pub fn name(self: *const Self, constant_pool: []const ?ConstantPoolInfo) ResolveError!ConstantPoolInfo { +pub fn name(self: *const Self, constant_pool: []const ?ConstantPool.Info) ResolveError!ConstantPool.Info { 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; + if (cp_info == null or @as(ConstantPool.Info.Tag, cp_info.?) != .utf8) return ResolveError.InvalidConstantType; return cp_info.?; } -pub fn descriptor(self: *const Self, constant_pool: []const ?ConstantPoolInfo) ResolveError!ConstantPoolInfo { +pub fn descriptor(self: *const Self, constant_pool: []const ?ConstantPool.Info) ResolveError!ConstantPool.Info { 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; + if (cp_info == null or @as(ConstantPool.Info.Tag, cp_info.?) != .utf8) return ResolveError.InvalidConstantType; return cp_info.?; } diff --git a/src/Class/MethodInfo.zig b/src/Class/MethodInfo.zig index a9c3e61..f58a7bf 100644 --- a/src/Class/MethodInfo.zig +++ b/src/Class/MethodInfo.zig @@ -3,7 +3,7 @@ const std = @import("std"); const EnumFlags = @import("../EnumFlags.zig").EnumFlags; const Class = @import("../Class.zig"); -const ConstantPoolInfo = Class.ConstantPoolInfo; +const ConstantPool = Class.ConstantPool; const AttributeInfo = Class.AttributeInfo; const ResolveError = Class.ResolveError; @@ -29,7 +29,7 @@ pub const MethodAccessFlags = EnumFlags(enum(u16) { synthetic = 0x1000, }); -pub fn parse(input: *std.Io.Reader, constant_pool: []const ?ConstantPoolInfo, allocator: std.mem.Allocator) !Self { +pub fn parse(input: *std.Io.Reader, constant_pool: []const ?ConstantPool.Info, 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); @@ -54,7 +54,7 @@ pub fn indentedFormat( w: *std.Io.Writer, depth: usize, indent: u8, - constant_pool: []const ?ConstantPoolInfo, + constant_pool: []const ?ConstantPool.Info, ) std.Io.Writer.Error!void { try w.splatByteAll(' ', depth * indent); try w.print("flags: {f}\n", .{ self.access_flags }); @@ -83,19 +83,19 @@ pub fn indentedFormat( } } -pub fn name(self: *const Self, constant_pool: []const ?ConstantPoolInfo) ResolveError!ConstantPoolInfo { +pub fn name(self: *const Self, constant_pool: []const ?ConstantPool.Info) ResolveError!ConstantPool.Info { 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; + if (cp_info == null or @as(ConstantPool.Info.Tag, cp_info.?) != .utf8) return ResolveError.InvalidConstantType; return cp_info.?; } -pub fn descriptor(self: *const Self, constant_pool: []const ?ConstantPoolInfo) ResolveError!ConstantPoolInfo { +pub fn descriptor(self: *const Self, constant_pool: []const ?ConstantPool.Info) ResolveError!ConstantPool.Info { 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; + if (cp_info == null or @as(ConstantPool.Info.Tag, cp_info.?) != .utf8) return ResolveError.InvalidConstantType; return cp_info.?; }