java-class-parser/src/Class/AttributeInfo.zig
2026-07-05 13:58:11 +02:00

1911 lines
72 KiB
Zig

const std = @import("std");
const EnumFlags = @import("../EnumFlags.zig").EnumFlags;
const Class = @import("../Class.zig");
const ConstantPoolInfo = Class.ConstantPoolInfo;
const ParseError = Class.ParseError;
const ResolveError = Class.ResolveError;
pub const AttributeInfo = union(enum) {
new: NewAttribute,
predefined: union(enum) {
constant_value: ConstantValue,
code: Code,
stack_map_table: StackMapTable,
exceptions: Exceptions,
inner_classes: InnerClasses,
enclosing_method: EnclosingMethod,
synthetic: Synthetic,
signature: Signature,
source_file: SourceFile,
source_debug_extension: SourceDebugExtension,
line_number_table: LineNumberTable,
local_variable_table: LocalVariableTable,
local_variable_type_table: LocalVariableTypeTable,
deprecated: Deprecated,
runtime_visible_annotations: RuntimeVisibleAnnotations,
runtime_invisible_annotations: RuntimeInvisibleAnnotations,
runtime_visible_parameter_annotations: RuntimeVisibleParameterAnnotations,
runtime_invisible_parameter_annotations: RuntimeInvisibleParameterAnnotations,
// runtime_visible_type_annotations: RuntimeVisibleTypeAnnotations,
// runtime_invisible_type_annotations: RuntimeInvisibleTypeAnnotations,
annotation_default: AnnotationDefault,
bootstrap_methods: BootstrapMethods,
method_parameters: MethodParameters,
module: Module,
module_packages: ModulePackages,
module_main_class: ModuleMainClass,
nest_host: NestHost,
nest_members: NestMembers,
record: Record,
permitted_subclasses: PermittedSubclasses,
},
const Self = @This();
pub fn parse(input: *std.Io.Reader, constant_pool: []const ?ConstantPoolInfo, 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;
const attribute_name = cp_info.?.utf8;
const attribute_length = try input.takeInt(u32, .big);
var limited_buf: [1024]u8 = undefined;
var limited_reader: std.Io.Reader.Limited = .init(input, .limited(attribute_length), &limited_buf);
const limited = &limited_reader.interface;
if (std.mem.eql(u8, attribute_name.bytes, "ConstantValue")) {
return .{
.predefined = .{
.constant_value = try ConstantValue.parse(limited),
},
};
} else if (std.mem.eql(u8, attribute_name.bytes, "Code")) {
return .{
.predefined = .{
.code = try Code.parse(limited, constant_pool, allocator),
},
};
} else if (std.mem.eql(u8, attribute_name.bytes, "StackMapTable")) {
return .{
.predefined = .{
.stack_map_table = try StackMapTable.parse(limited, allocator),
},
};
} else if (std.mem.eql(u8, attribute_name.bytes, "Exceptions")) {
return .{
.predefined = .{
.exceptions = try Exceptions.parse(limited, allocator),
},
};
} else if (std.mem.eql(u8, attribute_name.bytes, "InnerClasses")) {
return .{
.predefined = .{
.inner_classes = try InnerClasses.parse(limited, allocator),
},
};
} else if (std.mem.eql(u8, attribute_name.bytes, "EnclosingMethod")) {
return .{
.predefined = .{
.enclosing_method = try EnclosingMethod.parse(limited),
},
};
} else if (std.mem.eql(u8, attribute_name.bytes, "Synthetic")) {
return .{
.predefined = .{
.synthetic = .{},
},
};
} else if (std.mem.eql(u8, attribute_name.bytes, "Signature")) {
return .{
.predefined = .{
.signature = try Signature.parse(limited),
},
};
} else if (std.mem.eql(u8, attribute_name.bytes, "SourceFile")) {
return .{
.predefined = .{
.source_file = try SourceFile.parse(limited),
},
};
} else if (std.mem.eql(u8, attribute_name.bytes, "SourceDebugExtension")) {
return .{
.predefined = .{
.source_debug_extension = try SourceDebugExtension.parse(limited, attribute_length, allocator),
},
};
} else if (std.mem.eql(u8, attribute_name.bytes, "LineNumberTable")) {
return .{
.predefined = .{
.line_number_table = try LineNumberTable.parse(limited, allocator),
},
};
} else if (std.mem.eql(u8, attribute_name.bytes, "LocalVariableTable")) {
return .{
.predefined = .{
.local_variable_table = try LocalVariableTable.parse(limited, allocator),
},
};
} else if (std.mem.eql(u8, attribute_name.bytes, "LocalVariableTypeTable")) {
return .{
.predefined = .{
.local_variable_type_table = try LocalVariableTypeTable.parse(limited, allocator),
},
};
} else if (std.mem.eql(u8, attribute_name.bytes, "Deprecated")) {
return .{
.predefined = .{
.deprecated = .{},
},
};
} else if (std.mem.eql(u8, attribute_name.bytes, "RuntimeVisibleAnnotations")) {
return .{
.predefined = .{
.runtime_visible_annotations = try RuntimeVisibleAnnotations.parse(limited, allocator),
},
};
} else if (std.mem.eql(u8, attribute_name.bytes, "RuntimeInvisibleAnnotations")) {
return .{
.predefined = .{
.runtime_invisible_annotations = try RuntimeInvisibleAnnotations.parse(limited, allocator),
},
};
} else if (std.mem.eql(u8, attribute_name.bytes, "RuntimeVisibleParameterAnnotations")) {
return .{
.predefined = .{
.runtime_visible_parameter_annotations = try RuntimeVisibleParameterAnnotations.parse(limited, allocator),
},
};
} else if (std.mem.eql(u8, attribute_name.bytes, "RuntimeInvisibleParameterAnnotations")) {
return .{
.predefined = .{
.runtime_invisible_parameter_annotations = try RuntimeInvisibleParameterAnnotations.parse(limited, allocator),
},
};
} else if (std.mem.eql(u8, attribute_name.bytes, "AnnotationDefault")) {
return .{
.predefined = .{
.annotation_default = try AnnotationDefault.parse(limited, allocator),
},
};
} else if (std.mem.eql(u8, attribute_name.bytes, "BootstrapMethods")) {
return .{
.predefined = .{
.bootstrap_methods = try BootstrapMethods.parse(limited, allocator),
},
};
} else if (std.mem.eql(u8, attribute_name.bytes, "MethodParameters")) {
return .{
.predefined = .{
.method_parameters = try MethodParameters.parse(limited, allocator),
},
};
} else if (std.mem.eql(u8, attribute_name.bytes, "Module")) {
return .{
.predefined = .{
.module = try Module.parse(limited, allocator),
},
};
} else if (std.mem.eql(u8, attribute_name.bytes, "ModulePackages")) {
return .{
.predefined = .{
.module_packages = try ModulePackages.parse(limited, allocator),
},
};
} else if (std.mem.eql(u8, attribute_name.bytes, "ModuleMainClass")) {
return .{
.predefined = .{
.module_main_class = try ModuleMainClass.parse(limited),
},
};
} else if (std.mem.eql(u8, attribute_name.bytes, "NestHost")) {
return .{
.predefined = .{
.nest_host = try NestHost.parse(limited),
},
};
} else if (std.mem.eql(u8, attribute_name.bytes, "NestMembers")) {
return .{
.predefined = .{
.nest_members = try NestMembers.parse(limited, allocator),
},
};
} else if (std.mem.eql(u8, attribute_name.bytes, "Record")) {
return .{
.predefined = .{
.record = try Record.parse(limited, constant_pool, allocator),
},
};
} else if (std.mem.eql(u8, attribute_name.bytes, "PermittedSubclasses")) {
return .{
.predefined = .{
.permitted_subclasses = try PermittedSubclasses.parse(limited, allocator),
},
};
} else {
return .{
.new = try NewAttribute.parse(limited, attribute_name_index + 1, attribute_length, allocator),
};
}
}
pub fn deinit(self: *Self, allocator: std.mem.Allocator) void {
switch (self.*) {
.new => |*new| new.deinit(allocator),
.predefined => |*predefined| switch (predefined.*) {
.code => |*code| code.deinit(allocator),
.stack_map_table => |*stack_map_table| stack_map_table.deinit(allocator),
.exceptions => |*exceptions| exceptions.deinit(allocator),
.inner_classes => |*inner_classes| inner_classes.deinit(allocator),
.source_debug_extension => |*source_debug_extension| source_debug_extension.deinit(allocator),
.line_number_table => |*line_number_table| line_number_table.deinit(allocator),
.local_variable_table => |*local_variable_table| local_variable_table.deinit(allocator),
.local_variable_type_table => |*local_variable_type_table| local_variable_type_table.deinit(allocator),
.runtime_visible_annotations => |*runtime_visible_annotations| runtime_visible_annotations.deinit(allocator),
.runtime_invisible_annotations => |*runtime_invisible_annotations| runtime_invisible_annotations.deinit(allocator),
.runtime_visible_parameter_annotations => |*runtime_visible_parameter_annotations| runtime_visible_parameter_annotations.deinit(allocator),
.runtime_invisible_parameter_annotations => |*runtime_invisible_parameter_annotations| runtime_invisible_parameter_annotations.deinit(allocator),
.annotation_default => |*annotation_default| annotation_default.deinit(allocator),
.bootstrap_methods => |*bootstrap_methods| bootstrap_methods.deinit(allocator),
.method_parameters => |*method_parameters| method_parameters.deinit(allocator),
.module => |*module| module.deinit(allocator),
.module_packages => |*module_packages| module_packages.deinit(allocator),
.nest_members => |*nest_members| nest_members.deinit(allocator),
.record => |*record| record.deinit(allocator),
.permitted_subclasses => |*permitted_subclasses| permitted_subclasses.deinit(allocator),
else => {},
},
}
}
pub fn indentedFormat(
self: *const Self,
w: *std.Io.Writer,
depth: usize,
indent: u8,
constant_pool: []const ?ConstantPoolInfo,
) std.Io.Writer.Error!void {
switch (self.*) {
.new => |new| {
try w.splatByteAll(' ', depth * indent);
_ = try w.write("predefined: no\n");
try w.splatByteAll(' ', depth * indent);
_ = try w.write("name:\n");
const attribute_name = new.attributeName(constant_pool) catch return error.WriteFailed;
try attribute_name.indentedFormat(w, depth, indent + 1, constant_pool);
},
.predefined => |predefined| {
try w.splatByteAll(' ', depth * indent);
_ = try w.write("predefined: yes\n");
try w.splatByteAll(' ', depth * indent);
try w.print("type: {s}\n", .{ @tagName(predefined) });
switch (predefined) {
.constant_value => |attr| {
const constant_value = attr.constantValue(constant_pool) catch return error.WriteFailed;
try constant_value.indentedFormat(w, depth, indent + 1, constant_pool);
},
.code => |attr| {
try w.splatByteAll(' ', depth * indent);
try w.print("max_stack: {d}\n", .{ attr.max_stack });
try w.splatByteAll(' ', depth * indent);
try w.print("max_locals: {d}\n", .{ attr.max_locals });
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}: 0x{x}\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 a.indentedFormat(w, depth, attr_indent + 1, constant_pool);
}
},
//.stack_map_table,
.exceptions => |attr| {
try w.splatByteAll(' ', depth * indent);
_ = try w.write("exceptions:\n");
var exception_indent = indent;
for (attr.exception_index_table, 0..) |exception_index, i| {
exception_indent += 1;
defer exception_indent -= 1;
const index = exception_index - 1;
if (index >= constant_pool.len) return error.WriteFailed;
const cp_info = constant_pool[index];
if (cp_info == null or @as(ConstantPoolInfo.Tag, cp_info.?) != .class) return error.WriteFailed;
try w.splatByteAll(' ', depth * exception_indent);
try w.print("{d}:\n", .{ i });
try cp_info.?.indentedFormat(w, depth, exception_indent + 1, constant_pool);
}
},
.inner_classes => |attr| {
try w.splatByteAll(' ', depth * indent);
_ = try w.write("classes:\n");
var class_indent = indent;
for (attr.classes, 0..) |*class, i| {
class_indent += 1;
defer class_indent -= 1;
try w.splatByteAll(' ', depth * class_indent);
try w.print("{d}:\n", .{ i });
try class.indentedFormat(w, depth, class_indent + 1, constant_pool);
}
},
.enclosing_method => |attr| {
const class = attr.class(constant_pool) catch return error.WriteFailed;
try w.splatByteAll(' ', depth * indent);
_ = try w.write("class:\n");
try class.indentedFormat(w, depth, indent + 1, constant_pool);
const method = attr.method(constant_pool) catch return error.WriteFailed;
if (method) |m| {
try w.splatByteAll(' ', depth * indent);
_ = try w.write("method:\n");
try m.indentedFormat(w, depth, indent + 1, constant_pool);
}
},
.synthetic => {},
.signature => |attr| {
const signature = attr.signature(constant_pool) catch return error.WriteFailed;
try w.splatByteAll(' ', depth * indent);
_ = try w.write("signature:\n");
try signature.indentedFormat(w, depth, indent + 1, constant_pool);
},
.source_file => |attr| {
const source_file = attr.sourceFile(constant_pool) catch return error.WriteFailed;
try w.splatByteAll(' ', depth * indent);
_ = try w.write("source_file:\n");
try source_file.indentedFormat(w, depth, indent + 1, constant_pool);
},
//.source_debug_extension,
//.line_number_table,
//.local_variable_table,
//.local_variable_type_table,
.deprecated => {},
//.runtime_visible_annotations,
//.runtime_invisible_annotations,
//.runtime_visible_parameter_annotations,
//.runtime_invisible_parameter_annotations,
//.annotation_default,
//.bootstrap_methods,
.method_parameters => |attr| {
try w.splatByteAll(' ', depth * indent);
_ = try w.write("parameters:\n");
var parameter_indent = indent;
for (attr.parameters, 0..) |parameter, i| {
parameter_indent += 1;
defer parameter_indent -= 1;
try w.splatByteAll(' ', depth * parameter_indent);
try w.print("{d}:\n", .{ i });
try parameter.indentedFormat(w, depth, parameter_indent, constant_pool);
}
},
//.module,
.module_packages => |attr| {
try w.splatByteAll(' ', depth * indent);
_ = try w.write("packages:\n");
var package_indent = indent;
for (attr.package_indeces, 0..) |package_index, i| {
package_indent += 1;
defer package_indent -= 1;
const index = package_index - 1;
if (index >= constant_pool.len) return error.WriteFailed;
const cp_info = constant_pool[index];
if (cp_info == null or @as(ConstantPoolInfo.Tag, cp_info.?) != .package) return error.WriteFailed;
try w.splatByteAll(' ', depth * package_indent);
try w.print("{d}:\n", .{ i });
try cp_info.?.indentedFormat(w, depth, package_indent + 1, constant_pool);
}
},
.module_main_class => |attr| {
const main_class = attr.mainClass(constant_pool) catch return error.WriteFailed;
try w.splatByteAll(' ', depth * indent);
_ = try w.write("main_class:\n");
try main_class.indentedFormat(w, depth, indent + 1, constant_pool);
},
.nest_host => |attr| {
const host_class = attr.hostClass(constant_pool) catch return error.WriteFailed;
try w.splatByteAll(' ', depth * indent);
_ = try w.write("host_class:\n");
try host_class.indentedFormat(w, depth, indent + 1, constant_pool);
},
.nest_members => |attr| {
try w.splatByteAll(' ', depth * indent);
_ = try w.write("classes:\n");
var class_indent = indent;
for (attr.classes, 0..) |class_index, i| {
class_indent += 1;
defer class_indent -= 1;
const index = class_index - 1;
if (index >= constant_pool.len) return error.WriteFailed;
const cp_info = constant_pool[index];
if (cp_info == null or @as(ConstantPoolInfo.Tag, cp_info.?) != .class) return error.WriteFailed;
try w.splatByteAll(' ', depth * class_indent);
try w.print("{d}:\n", .{ i });
try cp_info.?.indentedFormat(w, depth, class_indent + 1, constant_pool);
}
},
.record => |attr| {
try w.splatByteAll(' ', depth * indent);
_ = try w.write("components:\n");
var component_indent = indent;
for (attr.components, 0..) |component, i| {
component_indent += 1;
defer component_indent -= 1;
try w.splatByteAll(' ', depth * component_indent);
try w.print("{d}:\n", .{ i });
try component.indentedFormat(w, depth, component_indent, constant_pool);
}
},
.permitted_subclasses => |attr| {
try w.splatByteAll(' ', depth * indent);
_ = try w.write("classes:\n");
var class_indent = indent;
for (attr.classes, 0..) |class_index, i| {
class_indent += 1;
defer class_indent -= 1;
const index = class_index - 1;
if (index >= constant_pool.len) return error.WriteFailed;
const cp_info = constant_pool[index];
if (cp_info == null or @as(ConstantPoolInfo.Tag, cp_info.?) != .class) return error.WriteFailed;
try w.splatByteAll(' ', depth * class_indent);
try w.print("{d}:\n", .{ i });
try cp_info.?.indentedFormat(w, depth, class_indent + 1, constant_pool);
}
},
else => {},
}
},
}
}
};
pub const NewAttribute = struct {
attribute_name_index: u16,
info: []u8,
const Self = @This();
pub fn parse(input: *std.Io.Reader, attribute_name_index: u16, attribute_length: u32, allocator: std.mem.Allocator) ParseError!Self {
return .{
.attribute_name_index = attribute_name_index,
.info = try input.readAlloc(allocator, attribute_length),
};
}
pub fn deinit(self: *Self, allocator: std.mem.Allocator) void {
allocator.free(self.info);
}
pub fn attributeName(self: *const Self, constant_pool: []const ?ConstantPoolInfo) ResolveError!ConstantPoolInfo {
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;
return cp_info.?;
}
};
pub const ConstantValue = struct {
constant_value_index: u16,
const Self = @This();
pub fn parse(input: *std.Io.Reader) ParseError!Self {
return .{
.constant_value_index = try input.takeInt(u16, .big),
};
}
pub fn constantValue(self: *const Self, constant_pool: []const ?ConstantPoolInfo) ResolveError!ConstantPoolInfo {
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];
if (cp_info == null) return ResolveError.InvalidConstantType;
return cp_info.?;
}
};
pub const Code = struct {
max_stack: u16,
max_locals: u16,
code: []u8,
exception_table: []ExceptionHandler,
attributes: []AttributeInfo,
const Self = @This();
pub const ExceptionHandler = struct {
start_pc: u16,
end_pc: u16,
handler_pc: u16,
catch_type: u16,
};
pub fn parse(input: *std.Io.Reader, constant_pool: []const ?ConstantPoolInfo, allocator: std.mem.Allocator) (ParseError || ResolveError)!Self {
const max_stack = try input.takeInt(u16, .big);
const max_locals = try input.takeInt(u16, .big);
const code_length = try input.takeInt(u32, .big);
const code = try input.readAlloc(allocator, code_length);
errdefer allocator.free(code);
const exception_table_length = try input.takeInt(u16, .big);
const exception_table = try allocator.alloc(ExceptionHandler, exception_table_length);
errdefer allocator.free(exception_table);
for (exception_table) |*exception_handler| {
exception_handler.* = .{
.start_pc = try input.takeInt(u16, .big),
.end_pc = try input.takeInt(u16, .big),
.handler_pc = try input.takeInt(u16, .big),
.catch_type = try input.takeInt(u16, .big),
};
}
const attribute_count = try input.takeInt(u16, .big);
const attributes = try allocator.alloc(AttributeInfo, attribute_count);
errdefer allocator.free(attributes);
for (attributes) |*attribute| {
attribute.* = try .parse(input, constant_pool, allocator);
}
return .{
.max_stack = max_stack,
.max_locals = max_locals,
.code = code,
.exception_table = exception_table,
.attributes = attributes,
};
}
pub fn deinit(self: *Self, allocator: std.mem.Allocator) void {
allocator.free(self.code);
allocator.free(self.exception_table);
for (self.attributes) |*attr| {
attr.deinit(allocator);
}
allocator.free(self.attributes);
}
};
pub const StackMapTable = struct {
entries: []StackMapFrame,
const Self = @This();
pub const StackMapFrame = union(enum) {
// 0-63
same_frame,
// 64-127
same_locals_1_stack_item_frame: struct {
stack: [1]VerificationTypeInfo,
},
// 247
same_locals_1_stack_item_frame_extended: struct {
offset_delta: u16,
stack: [1]VerificationTypeInfo,
},
// 248-250
chop_frame: struct {
offset_delta: u16,
},
// 251
same_frame_extended: struct {
offset_delta: u16,
},
// 252-254
append_frame: struct {
offset_delta: u16,
locals: []const VerificationTypeInfo,
},
// 255
full_frame: struct {
offset_delta: u16,
locals: []const VerificationTypeInfo,
stack: []const VerificationTypeInfo,
},
pub fn parse(input: *std.Io.Reader, allocator: std.mem.Allocator) ParseError!StackMapFrame {
const frame_type = try input.takeByte();
return switch (frame_type) {
0...63 => .same_frame,
64...127 => .{
.same_locals_1_stack_item_frame = .{
.stack = .{ try .parse(input) },
},
},
247 => .{
.same_locals_1_stack_item_frame_extended = .{
.offset_delta = try input.takeInt(u16, .big),
.stack = .{ try .parse(input) },
},
},
248...250 => .{
.chop_frame = .{
.offset_delta = try input.takeInt(u16, .big),
},
},
252...254 => blk: {
const offset_delta = try input.takeInt(u16, .big);
const length = frame_type - 251;
const locals = try allocator.alloc(StackMapTable.VerificationTypeInfo, length);
errdefer allocator.free(locals);
for (locals) |*local| {
local.* = try .parse(input);
}
break :blk .{
.append_frame = .{
.offset_delta = offset_delta,
.locals = locals,
},
};
},
255 => blk: {
const offset_delta = try input.takeInt(u16, .big);
const number_of_locals = try input.takeInt(u16, .big);
const locals = try allocator.alloc(StackMapTable.VerificationTypeInfo, number_of_locals);
errdefer allocator.free(locals);
for (locals) |*local| {
local.* = try .parse(input);
}
const number_of_stack_items = try input.takeInt(u16, .big);
const stack = try allocator.alloc(StackMapTable.VerificationTypeInfo, number_of_stack_items);
errdefer allocator.free(stack);
for (stack) |*stack_item| {
stack_item.* = try .parse(input);
}
break :blk .{
.full_frame = .{
.offset_delta = offset_delta,
.locals = locals,
.stack = stack,
},
};
},
else => unreachable,
};
}
pub fn deinit(self: *StackMapFrame, allocator: std.mem.Allocator) void {
switch (self.*) {
.append_frame => |frame| allocator.free(frame.locals),
.full_frame => |frame| {
allocator.free(frame.locals);
allocator.free(frame.stack);
},
else => {},
}
}
};
pub const VerificationTypeInfo = union(VerificationTypeInfo.Tag) {
top,
integer,
float,
double,
long,
null,
uninitialized_this,
object: struct {
cpool_index: u16,
},
uninitialized: struct {
cpool_index: u16,
},
pub const Tag = enum(u8) {
top = 0,
integer = 1,
float = 2,
double = 3,
long = 4,
null = 5,
uninitialized_this = 6,
object = 7,
uninitialized = 8,
};
pub fn parse(input: *std.Io.Reader) ParseError!VerificationTypeInfo {
const tag_byte = try input.takeByte();
const tag = std.enums.fromInt(StackMapTable.VerificationTypeInfo.Tag, tag_byte) orelse return ParseError.InvalidTag;
return switch (tag) {
.top => .top,
.integer => .integer,
.float => .float,
.double => .double,
.long => .long,
.null => .null,
.uninitialized_this => .uninitialized_this,
.object => .{
.object = .{
.cpool_index = try input.takeInt(u16, .big),
},
},
.uninitialized => .{
.uninitialized = .{
.cpool_index = try input.takeInt(u16, .big),
},
},
};
}
};
pub fn parse(input: *std.Io.Reader, allocator: std.mem.Allocator) ParseError!Self {
const number_of_entries = try input.takeInt(u16, .big);
const entries = try allocator.alloc(StackMapTable.StackMapFrame, number_of_entries);
errdefer allocator.free(entries);
for (entries) |*entry| {
entry.* = try .parse(input, allocator);
}
return .{
.entries = entries,
};
}
pub fn deinit(self: *Self, allocator: std.mem.Allocator) void {
for (self.entries) |*entry| {
entry.deinit(allocator);
}
allocator.free(self.entries);
}
};
pub const Exceptions = struct {
exception_index_table: []u16,
const Self = @This();
pub fn parse(input: *std.Io.Reader, allocator: std.mem.Allocator) ParseError!Self {
const number_of_exceptions = try input.takeInt(u16, .big);
const exception_index_table = try allocator.alloc(u16, number_of_exceptions);
errdefer allocator.free(exception_index_table);
for (exception_index_table) |*exception_index| {
exception_index.* = try input.takeInt(u16, .big);
}
return .{
.exception_index_table = exception_index_table,
};
}
pub fn deinit(self: *Self, allocator: std.mem.Allocator) void {
allocator.free(self.exception_index_table);
}
};
pub const InnerClasses = struct {
classes: []InnerClass,
const Self = @This();
pub const InnerClass = struct {
inner_class_info_index: u16,
outer_class_info_index: u16,
inner_name_index: u16,
inner_class_access_flags: InnerClassAccessFlags,
pub fn indentedFormat(
self: *const InnerClass,
w: *std.Io.Writer,
depth: usize,
indent: u8,
constant_pool: []const ?ConstantPoolInfo,
) std.Io.Writer.Error!void {
try w.splatByteAll(' ', depth * indent);
try w.print("flags: {f}\n", .{ self.inner_class_access_flags });
const inner_class = self.innerClass(constant_pool) catch return error.WriteFailed;
try w.splatByteAll(' ', depth * indent);
_ = try w.write("inner_class:\n");
try inner_class.indentedFormat(w, depth, indent + 1, constant_pool);
const outer_class = self.outerClass(constant_pool) catch return error.WriteFailed;
if (outer_class) |oc| {
try w.splatByteAll(' ', depth * indent);
_ = try w.write("outer_class:\n");
try oc.indentedFormat(w, depth, indent + 1, constant_pool);
}
const inner_name = self.innerName(constant_pool) catch return error.WriteFailed;
if (inner_name) |in| {
try w.splatByteAll(' ', depth * indent);
_ = try w.write("inner_name:\n");
try in.indentedFormat(w, depth, indent + 1, constant_pool);
}
}
pub fn innerClass(self: *const InnerClass, constant_pool: []const ?ConstantPoolInfo) ResolveError!ConstantPoolInfo {
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;
return cp_info.?;
}
pub fn outerClass(self: *const InnerClass, constant_pool: []const ?ConstantPoolInfo) ResolveError!?ConstantPoolInfo {
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;
return cp_info.?;
}
pub fn innerName(self: *const InnerClass, constant_pool: []const ?ConstantPoolInfo) ResolveError!?ConstantPoolInfo {
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;
return cp_info.?;
}
};
pub const InnerClassAccessFlags = EnumFlags(enum(u16) {
public = 0x0001,
private = 0x0002,
protected = 0x0004,
static = 0x0008,
final = 0x0010,
interface = 0x0200,
abstract = 0x0400,
synthetic = 0x1000,
annotation = 0x2000,
@"enum" = 0x4000,
});
pub fn parse(input: *std.Io.Reader, allocator: std.mem.Allocator) ParseError!Self {
const number_of_classes = try input.takeInt(u16, .big);
const classes = try allocator.alloc(InnerClass, number_of_classes);
errdefer allocator.free(classes);
for (classes) |*class| {
class.* = .{
.inner_class_info_index = try input.takeInt(u16, .big),
.outer_class_info_index = try input.takeInt(u16, .big),
.inner_name_index = try input.takeInt(u16, .big),
.inner_class_access_flags = .{ .mask = try input.takeInt(u16, .big) },
};
}
return .{
.classes = classes,
};
}
pub fn deinit(self: *Self, allocator: std.mem.Allocator) void {
allocator.free(self.classes);
}
};
pub const EnclosingMethod = struct {
class_index: u16,
method_index: u16,
const Self = @This();
pub fn parse(input: *std.Io.Reader) ParseError!Self {
return .{
.class_index = try input.takeInt(u16, .big),
.method_index = try input.takeInt(u16, .big),
};
}
pub fn class(self: *const EnclosingMethod, 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(ConstantPoolInfo.Tag, cp_info.?) != .class) return ResolveError.InvalidConstantType;
return cp_info.?;
}
pub fn method(self: *const EnclosingMethod, constant_pool: []const ?ConstantPoolInfo) ResolveError!?ConstantPoolInfo {
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;
return cp_info.?;
}
};
pub const Synthetic = struct { };
pub const Signature = struct {
signature_index: u16,
const Self = @This();
pub fn parse(input: *std.Io.Reader) ParseError!Self {
return .{
.signature_index = try input.takeInt(u16, .big),
};
}
pub fn signature(self: *const Signature, constant_pool: []const ?ConstantPoolInfo) ResolveError!ConstantPoolInfo {
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;
return cp_info.?;
}
};
pub const SourceFile = struct {
source_file_index: u16,
const Self = @This();
pub fn parse(input: *std.Io.Reader) ParseError!Self {
return .{
.source_file_index = try input.takeInt(u16, .big),
};
}
pub fn sourceFile(self: *const SourceFile, constant_pool: []const ?ConstantPoolInfo) ResolveError!ConstantPoolInfo {
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;
return cp_info.?;
}
};
pub const SourceDebugExtension = struct {
debug_extension: []u8,
const Self = @This();
pub fn parse(input: *std.Io.Reader, length: usize, allocator: std.mem.Allocator) ParseError!Self {
return .{
.debug_extension = try input.readAlloc(allocator, length),
};
}
pub fn deinit(self: *Self, allocator: std.mem.Allocator) void {
allocator.free(self.debug_extension);
}
};
pub const LineNumberTable = struct {
line_number_table: []const LineNumber,
const Self = @This();
pub const LineNumber = struct {
start_pc: u16,
line_number: u16,
};
pub fn parse(input: *std.Io.Reader, allocator: std.mem.Allocator) ParseError!Self {
const line_number_table_length = try input.takeInt(u16, .big);
const line_number_table = try allocator.alloc(LineNumber, line_number_table_length);
errdefer allocator.free(line_number_table);
for (line_number_table) |*line_number| {
line_number.* = .{
.start_pc = try input.takeInt(u16, .big),
.line_number = try input.takeInt(u16, .big),
};
}
return .{
.line_number_table = line_number_table,
};
}
pub fn deinit(self: *Self, allocator: std.mem.Allocator) void {
allocator.free(self.line_number_table);
}
};
pub const LocalVariableTable = struct {
local_variable_table: []LocalVariable,
const Self = @This();
pub const LocalVariable = struct {
start_pc: u16,
length: u16,
name_index: u16,
descriptor_index: u16,
index: u16,
};
pub fn parse(input: *std.Io.Reader, allocator: std.mem.Allocator) ParseError!Self {
const local_variable_table_length = try input.takeInt(u16, .big);
const local_variable_table = try allocator.alloc(LocalVariable, local_variable_table_length);
errdefer allocator.free(local_variable_table);
for (local_variable_table) |*local_variable| {
local_variable.* = .{
.start_pc = try input.takeInt(u16, .big),
.length = try input.takeInt(u16, .big),
.name_index = try input.takeInt(u16, .big),
.descriptor_index = try input.takeInt(u16, .big),
.index = try input.takeInt(u16, .big),
};
}
return .{
.local_variable_table = local_variable_table,
};
}
pub fn deinit(self: *Self, allocator: std.mem.Allocator) void {
allocator.free(self.local_variable_table);
}
};
pub const LocalVariableTypeTable = struct {
local_variable_type_table: []LocalVariableType,
const Self = @This();
pub const LocalVariableType = struct {
start_pc: u16,
length: u16,
name_index: u16,
signature_index: u16,
index: u16,
};
pub fn parse(input: *std.Io.Reader, allocator: std.mem.Allocator) ParseError!Self {
const local_variable_type_table_length = try input.takeInt(u16, .big);
const local_variable_type_table = try allocator.alloc(LocalVariableType, local_variable_type_table_length);
errdefer allocator.free(local_variable_type_table);
for (local_variable_type_table) |*local_variable_type| {
local_variable_type.* = .{
.start_pc = try input.takeInt(u16, .big),
.length = try input.takeInt(u16, .big),
.name_index = try input.takeInt(u16, .big),
.signature_index = try input.takeInt(u16, .big),
.index = try input.takeInt(u16, .big),
};
}
return .{
.local_variable_type_table = local_variable_type_table,
};
}
pub fn deinit(self: *Self, allocator: std.mem.Allocator) void {
allocator.free(self.local_variable_type_table);
}
};
pub const Deprecated = struct { };
pub const ElementValue = union(enum) {
// B, C, D, F, I, J, S, Z, s
const_value_index: u16,
// e
enum_const_value: struct {
type_name_index: u16,
const_name_index: u16,
},
// c
class_info_index: u16,
// @
annotation_value: Annotation,
// [
array_value: struct {
values: []ElementValue,
},
pub fn parse(input: *std.Io.Reader, allocator: std.mem.Allocator) ParseError!ElementValue {
const tag = try input.takeByte();
return switch (tag) {
'B', 'C', 'D', 'F', 'I', 'J', 'S', 'Z', 's' => .{
.const_value_index = try input.takeInt(u16, .big),
},
'e' => .{
.enum_const_value = .{
.type_name_index = try input.takeInt(u16, .big),
.const_name_index = try input.takeInt(u16, .big),
},
},
'c' => .{
.class_info_index = try input.takeInt(u16, .big),
},
'@' => .{
.annotation_value = try .parse(input, allocator),
},
'[' => .{
.array_value = blk: {
const num_values = try input.takeInt(u16, .big);
const values = try allocator.alloc(ElementValue, num_values);
errdefer allocator.free(values);
for (values) |*value| {
value.* = try .parse(input, allocator);
}
break :blk .{
.values = values,
};
},
},
else => unreachable,
};
}
pub fn deinit(self: *ElementValue, allocator: std.mem.Allocator) void {
switch (self.*) {
.annotation_value => |*element_value| element_value.deinit(allocator),
.array_value => |element_value| {
for (element_value.values) |*value| {
value.deinit(allocator);
}
allocator.free(element_value.values);
},
else => {},
}
}
};
pub const ElementValuePair = struct {
element_name_index: u16,
value: ElementValue,
};
pub const Annotation = struct {
type_index: u16,
element_value_pairs: []ElementValuePair,
pub fn parse(input: *std.Io.Reader, allocator: std.mem.Allocator) ParseError!Annotation {
const type_index = try input.takeInt(u16, .big);
const num_element_value_pairs = try input.takeInt(u16, .big);
const element_value_pairs = try allocator.alloc(ElementValuePair, num_element_value_pairs);
errdefer allocator.free(element_value_pairs);
for (element_value_pairs) |*element_value_pair| {
element_value_pair.* = .{
.element_name_index = try input.takeInt(u16, .big),
.value = try .parse(input, allocator),
};
}
return .{
.type_index = type_index,
.element_value_pairs = element_value_pairs,
};
}
pub fn deinit(self: *Annotation, allocator: std.mem.Allocator) void {
for (self.element_value_pairs) |*element_value_pair| {
element_value_pair.value.deinit(allocator);
}
allocator.free(self.element_value_pairs);
}
};
pub const RuntimeVisibleAnnotations = struct {
annotations: []Annotation,
const Self = @This();
pub fn parse(input: *std.Io.Reader, allocator: std.mem.Allocator) ParseError!Self {
const num_annotations = try input.takeInt(u16, .big);
const annotations = try allocator.alloc(Annotation, num_annotations);
errdefer allocator.free(annotations);
for (annotations) |*annotation| {
annotation.* = try .parse(input, allocator);
}
return .{
.annotations = annotations,
};
}
pub fn deinit(self: *Self, allocator: std.mem.Allocator) void {
for (self.annotations) |*annotation| {
annotation.deinit(allocator);
}
allocator.free(self.annotations);
}
};
pub const RuntimeInvisibleAnnotations = struct {
annotations: []Annotation,
const Self = @This();
pub fn parse(input: *std.Io.Reader, allocator: std.mem.Allocator) ParseError!Self {
const num_annotations = try input.takeInt(u16, .big);
const annotations = try allocator.alloc(Annotation, num_annotations);
errdefer allocator.free(annotations);
for (annotations) |*annotation| {
annotation.* = try .parse(input, allocator);
}
return .{
.annotations = annotations,
};
}
pub fn deinit(self: *Self, allocator: std.mem.Allocator) void {
for (self.annotations) |*annotation| {
annotation.deinit(allocator);
}
allocator.free(self.annotations);
}
};
pub const ParameterAnnotation = struct {
annotations: []Annotation,
};
pub const RuntimeVisibleParameterAnnotations = struct {
parameter_annotations: []ParameterAnnotation,
const Self = @This();
pub fn parse(input: *std.Io.Reader, allocator: std.mem.Allocator) ParseError!Self {
const num_parameters = try input.takeByte();
const parameter_annotations = try allocator.alloc(ParameterAnnotation, num_parameters);
errdefer allocator.free(parameter_annotations);
for (parameter_annotations) |*parameter_annotation| {
const num_annotations = try input.takeInt(u16, .big);
const annotations = try allocator.alloc(Annotation, num_annotations);
errdefer allocator.free(annotations);
for (annotations) |*annotation| {
annotation.* = try .parse(input, allocator);
}
parameter_annotation.* = .{
.annotations = annotations,
};
}
return .{
.parameter_annotations = parameter_annotations,
};
}
pub fn deinit(self: *Self, allocator: std.mem.Allocator) void {
for (self.parameter_annotations) |parameter_annotation| {
for (parameter_annotation.annotations) |*annotation| {
annotation.deinit(allocator);
}
allocator.free(parameter_annotation.annotations);
}
allocator.free(self.parameter_annotations);
}
};
pub const RuntimeInvisibleParameterAnnotations = struct {
parameter_annotations: []ParameterAnnotation,
const Self = @This();
pub fn parse(input: *std.Io.Reader, allocator: std.mem.Allocator) ParseError!Self {
const num_parameters = try input.takeByte();
const parameter_annotations = try allocator.alloc(ParameterAnnotation, num_parameters);
errdefer allocator.free(parameter_annotations);
for (parameter_annotations) |*parameter_annotation| {
const num_annotations = try input.takeInt(u16, .big);
const annotations = try allocator.alloc(Annotation, num_annotations);
errdefer allocator.free(annotations);
for (annotations) |*annotation| {
annotation.* = try .parse(input, allocator);
}
parameter_annotation.* = .{
.annotations = annotations,
};
}
return .{
.parameter_annotations = parameter_annotations,
};
}
pub fn deinit(self: *Self, allocator: std.mem.Allocator) void {
for (self.parameter_annotations) |parameter_annotation| {
for (parameter_annotation.annotations) |*annotation| {
annotation.deinit(allocator);
}
allocator.free(parameter_annotation.annotations);
}
allocator.free(self.parameter_annotations);
}
};
// TODO: TypeAnnotation structure
// pub const TypeAnnotation = struct {
// target_info: union(TargetType) {
// type_parameter_target: TypeParameterTarget,
// supertype_target: SupertypeTarget,
// type_parameter_bound_target: TypeParameterBoundTarget,
// emtpy_target: EmptyTarget,
// formal_parameter_target: FormalParameterTarget,
// throws_target: ThrowsTarget,
// localvar_target: LocalvarTarget,
// catch_target: CatchTarget,
// offset_target: OffsetTarget,
// type_argument_target: TypeArgumentTarget,
// },
// target_path: TypePath,
// type_index: u16,
// element_value_pairs: []ElementValuePair,
//
// pub const TargetType = enum(u8) {
// type_parameter_target = 0x00,
// type
// };
//
// pub const TypePath = struct {
// path: []Path,
//
// pub const Path = struct {
// type_path_kind: u8,
// type_argument_index: u8,
// };
// };
// };
// pub const RuntimeVisibleTypeAnnotations = struct {
// type_annotations: []TypeAnnotation,
//
// const Self = @This();
// };
//
// pub const RuntimeInvisibleTypeAnnotations = struct {
// type_annotations: []TypeAnnotation,
//
// const Self = @This();
// };
pub const AnnotationDefault = struct {
default_value: ElementValue,
const Self = @This();
pub fn parse(input: *std.Io.Reader, allocator: std.mem.Allocator) ParseError!Self {
return .{
.default_value = try .parse(input, allocator),
};
}
pub fn deinit(self: *Self, allocator: std.mem.Allocator) void {
self.default_value.deinit(allocator);
}
};
pub const BootstrapMethods = struct {
bootstrap_methods: []BootstrapMethod,
const Self = @This();
pub const BootstrapMethod = struct {
bootstrap_method_ref: u16,
bootstrap_arguments: []u16,
};
pub fn parse(input: *std.Io.Reader, allocator: std.mem.Allocator) ParseError!Self {
const num_bootstrap_methods = try input.takeInt(u16, .big);
const bootstrap_methods = try allocator.alloc(BootstrapMethod, num_bootstrap_methods);
errdefer allocator.free(bootstrap_methods);
for (bootstrap_methods) |*bootstrap_method| {
const bootstrap_method_ref = try input.takeInt(u16, .big);
const num_bootstrap_arguments = try input.takeInt(u16, .big);
const bootstrap_arguments = try allocator.alloc(u16, num_bootstrap_arguments);
errdefer allocator.free(bootstrap_arguments);
for (bootstrap_arguments) |*bootstrap_argument| {
bootstrap_argument.* = try input.takeInt(u16, .big);
}
bootstrap_method.* = .{
.bootstrap_method_ref = bootstrap_method_ref,
.bootstrap_arguments = bootstrap_arguments,
};
}
return .{
.bootstrap_methods = bootstrap_methods,
};
}
pub fn deinit(self: *Self, allocator: std.mem.Allocator) void {
for (self.bootstrap_methods) |bootstrap_method| {
allocator.free(bootstrap_method.bootstrap_arguments);
}
allocator.free(self.bootstrap_methods);
}
};
pub const MethodParameters = struct {
parameters: []Parameter,
const Self = @This();
pub const Parameter = struct {
name_index: u16,
access_flags: ParameterAccessFlags,
pub const ParameterAccessFlags = EnumFlags(enum(u16) {
final = 0x0010,
synthetic = 0x1000,
mandated = 0x8000,
});
pub fn indentedFormat(
self: *const Parameter,
w: *std.Io.Writer,
depth: usize,
indent: u8,
constant_pool: []const ?ConstantPoolInfo,
) std.Io.Writer.Error!void {
try w.splatByteAll(' ', depth * indent);
try w.print("flags: {f}\n", .{ self.access_flags });
const name_ = self.name(constant_pool) catch return error.WriteFailed;
try w.splatByteAll(' ', depth * indent);
_ = try w.write("name:\n");
try name_.indentedFormat(w, depth, indent + 1, constant_pool);
}
pub fn name(self: *const Parameter, constant_pool: []const ?ConstantPoolInfo) ResolveError!ConstantPoolInfo {
const name_index = self.name_index - 1;
if (name_index >= constant_pool.len) return ResolveError.InvalidConstantPoolIndex;
const cp_info = constant_pool[name_index];
if (cp_info == null or @as(ConstantPoolInfo.Tag, cp_info.?) != .utf8) return ResolveError.InvalidConstantType;
return cp_info.?;
}
};
pub fn parse(input: *std.Io.Reader, allocator: std.mem.Allocator) ParseError!Self {
const parameter_count = try input.takeByte();
const parameters = try allocator.alloc(Parameter, parameter_count);
errdefer allocator.free(parameters);
for (parameters) |*parameter| {
parameter.* = .{
.name_index = try input.takeInt(u16, .big),
.access_flags = .{ .mask = try input.takeInt(u16, .big) },
};
}
return .{
.parameters = parameters,
};
}
pub fn deinit(self: *Self, allocator: std.mem.Allocator) void {
allocator.free(self.parameters);
}
};
pub const Module = struct {
module_name_index: u16,
module_flags: ModuleFlags,
module_version_index: u16,
requires: []Requires,
exports: []Exports,
opens: []Opens,
uses_indeces: []u16,
provides: []Provides,
const Self = @This();
pub const ModuleFlags = EnumFlags(enum(u16) {
open = 0x0020,
sythetic = 0x1000,
mandated = 0x8000,
});
pub const Requires = struct {
requires_index: u16,
requires_flags: RequiresFlags,
requires_version_index: u16,
pub const RequiresFlags = EnumFlags(enum(u16) {
transitive = 0x0020,
static_phase = 0x0040,
synthetic = 0x1000,
mandated = 0x8000,
});
};
pub const Exports = struct {
exports_index: u16,
exports_flags: ExportsFlags,
exports_to_indeces: []u16,
pub const ExportsFlags = EnumFlags(enum(u16) {
synthetic = 0x1000,
mandated = 0x8000,
});
};
pub const Opens = struct {
opens_index: u16,
opens_flags: OpensFlags,
opens_to_indeces: []u16,
pub const OpensFlags = EnumFlags(enum(u16) {
synthetic = 0x1000,
mandated = 0x8000,
});
};
pub const Provides = struct {
provides_index: u16,
provides_with_indeces: []u16,
};
pub fn parse(input: *std.Io.Reader, allocator: std.mem.Allocator) ParseError!Self {
const module_name_index = try input.takeInt(u16, .big);
const module_flags: ModuleFlags = .{ .mask = try input.takeInt(u16, .big) };
const module_version_index = try input.takeInt(u16, .big);
const requires_count = try input.takeInt(u16, .big);
const requires = try allocator.alloc(Requires, requires_count);
errdefer allocator.free(requires);
for (requires) |*r| {
const requires_index = try input.takeInt(u16, .big);
const requires_flags: Requires.RequiresFlags = .{ .mask = try input.takeInt(u16, .big) };
const requires_version_index = try input.takeInt(u16, .big);
r.* = .{
.requires_index = requires_index,
.requires_flags = requires_flags,
.requires_version_index = requires_version_index,
};
}
const exports_count = try input.takeInt(u16, .big);
const exports = try allocator.alloc(Exports, exports_count);
errdefer allocator.free(exports);
for (exports) |*e| {
const exports_index = try input.takeInt(u16, .big);
const exports_flags: Exports.ExportsFlags = .{ .mask = try input.takeInt(u16, .big) };
const exports_to_count = try input.takeInt(u16, .big);
const exports_to_indeces = try allocator.alloc(u16, exports_to_count);
errdefer allocator.free(exports_to_indeces);
for (exports_to_indeces) |*i| {
i.* = try input.takeInt(u16, .big);
}
e.* = .{
.exports_index = exports_index,
.exports_flags = exports_flags,
.exports_to_indeces = exports_to_indeces,
};
}
const opens_count = try input.takeInt(u16, .big);
const opens = try allocator.alloc(Opens, opens_count);
errdefer allocator.free(opens);
for (opens) |*o| {
const opens_index = try input.takeInt(u16, .big);
const opens_flags: Opens.OpensFlags = .{ .mask = try input.takeInt(u16, .big) };
const opens_to_count = try input.takeInt(u16, .big);
const opens_to_indeces = try allocator.alloc(u16, opens_to_count);
errdefer allocator.free(opens_to_indeces);
for (opens_to_indeces) |*i| {
i.* = try input.takeInt(u16, .big);
}
o.* = .{
.opens_index = opens_index,
.opens_flags = opens_flags,
.opens_to_indeces = opens_to_indeces,
};
}
const uses_count = try input.takeInt(u16, .big);
const uses_indeces = try allocator.alloc(u16, uses_count);
errdefer allocator.free(uses_indeces);
for (uses_indeces) |*i| {
i.* = try input.takeInt(u16, .big);
}
const provides_count = try input.takeInt(u16, .big);
const provides = try allocator.alloc(Provides, provides_count);
errdefer allocator.free(provides);
for (provides) |*p| {
const provides_index = try input.takeInt(u16, .big);
const provides_with_count = try input.takeInt(u16, .big);
const provides_with_indeces = try allocator.alloc(u16, provides_with_count);
errdefer allocator.free(provides_with_indeces);
for (provides_with_indeces) |*i| {
i.* = try input.takeInt(u16, .big);
}
p.* = .{
.provides_index = provides_index,
.provides_with_indeces = provides_with_indeces,
};
}
return .{
.module_name_index = module_name_index,
.module_flags = module_flags,
.module_version_index = module_version_index,
.requires = requires,
.exports = exports,
.opens = opens,
.uses_indeces = uses_indeces,
.provides = provides,
};
}
pub fn deinit(self: *Self, allocator: std.mem.Allocator) void {
allocator.free(self.requires);
for (self.exports) |*e| {
allocator.free(e.exports_to_indeces);
}
allocator.free(self.exports);
for (self.opens) |*o| {
allocator.free(o.opens_to_indeces);
}
allocator.free(self.opens);
allocator.free(self.uses_indeces);
for (self.provides) |*p| {
allocator.free(p.provides_with_indeces);
}
allocator.free(self.provides);
}
};
pub const ModulePackages = struct {
package_indeces: []u16,
const Self = @This();
pub fn parse(input: *std.Io.Reader, allocator: std.mem.Allocator) ParseError!Self {
const package_count = try input.takeInt(u16, .big);
const package_indeces = try allocator.alloc(u16, package_count);
errdefer allocator.free(package_indeces);
for (package_indeces) |*package_index| {
package_index.* = try input.takeInt(u16, .big);
}
return .{
.package_indeces = package_indeces,
};
}
pub fn deinit(self: *Self, allocator: std.mem.Allocator) void {
allocator.free(self.package_indeces);
}
};
pub const ModuleMainClass = struct {
main_class_index: u16,
const Self = @This();
pub fn parse(input: *std.Io.Reader) ParseError!Self {
return .{
.main_class_index = try input.takeInt(u16, .big),
};
}
pub fn mainClass(self: *const ModuleMainClass, constant_pool: []const ?ConstantPoolInfo) ResolveError!ConstantPoolInfo {
const main_class_index = self.main_class_index - 1;
if (main_class_index >= constant_pool.len) return ResolveError.InvalidConstantPoolIndex;
const cp_info = constant_pool[main_class_index];
if (cp_info == null or @as(ConstantPoolInfo.Tag, cp_info.?) != .class) return ResolveError.InvalidConstantType;
return cp_info.?;
}
};
pub const NestHost = struct {
host_class_index: u16,
const Self = @This();
pub fn parse(input: *std.Io.Reader) ParseError!Self {
return .{
.host_class_index = try input.takeInt(u16, .big),
};
}
pub fn hostClass(self: *const NestHost, constant_pool: []const ?ConstantPoolInfo) ResolveError!ConstantPoolInfo {
const host_class_index = self.host_class_index - 1;
if (host_class_index >= constant_pool.len) return ResolveError.InvalidConstantPoolIndex;
const cp_info = constant_pool[host_class_index];
if (cp_info == null or @as(ConstantPoolInfo.Tag, cp_info.?) != .class) return ResolveError.InvalidConstantType;
return cp_info.?;
}
};
pub const NestMembers = struct {
classes: []u16,
const Self = @This();
pub fn parse(input: *std.Io.Reader, allocator: std.mem.Allocator) ParseError!Self {
const number_of_classes = try input.takeInt(u16, .big);
const classes = try allocator.alloc(u16, number_of_classes);
for (classes) |*class| {
class.* = try input.takeInt(u16, .big);
}
return .{
.classes = classes,
};
}
pub fn deinit(self: *Self, allocator: std.mem.Allocator) void {
allocator.free(self.classes);
}
};
pub const Record = struct {
components: []RecordComponentInfo,
const Self = @This();
pub const RecordComponentInfo = struct {
name_index: u16,
descriptor_index: u16,
attributes: []AttributeInfo,
pub fn parse(input: *std.Io.Reader, constant_pool: []const ?ConstantPoolInfo, allocator: std.mem.Allocator) (ParseError || ResolveError)!RecordComponentInfo {
const name_index = try input.takeInt(u16, .big);
const descriptor_index = try input.takeInt(u16, .big);
const attribute_count = try input.takeInt(u16, .big);
const attributes = try allocator.alloc(AttributeInfo, attribute_count);
errdefer allocator.free(attributes);
for (attributes) |*attribute| {
attribute.* = try .parse(input, constant_pool, allocator);
}
return .{
.name_index = name_index,
.descriptor_index = descriptor_index,
.attributes = attributes,
};
}
pub fn deinit(self: *RecordComponentInfo, allocator: std.mem.Allocator) void {
for (self.attributes) |*attribute| {
attribute.deinit(allocator);
}
allocator.free(self.attributes);
}
pub fn indentedFormat(
self: *const RecordComponentInfo,
w: *std.Io.Writer,
depth: usize,
indent: u8,
constant_pool: []const ?ConstantPoolInfo,
) std.Io.Writer.Error!void {
const name_ = self.name(constant_pool) catch return error.WriteFailed;
try w.splatByteAll(' ', depth * indent);
_ = try w.write("name:\n");
try name_.indentedFormat(w, depth, indent + 1, constant_pool);
const descriptor_ = self.descriptor(constant_pool) catch return error.WriteFailed;
try w.splatByteAll(' ', depth * indent);
_ = try w.write("descriptor:\n");
try descriptor_.indentedFormat(w, depth, indent + 1, constant_pool);
try w.splatByteAll(' ', depth * indent);
_ = try w.write("attributes:\n");
var attr_indent = indent;
for (self.attributes, 0..) |*attr, i| {
attr_indent += 1;
defer attr_indent -= 1;
try w.splatByteAll(' ', depth * attr_indent);
try w.print("{d}:\n", .{ i });
try attr.indentedFormat(w, depth, attr_indent + 1, constant_pool);
}
}
pub fn name(self: *const RecordComponentInfo, constant_pool: []const ?ConstantPoolInfo) ResolveError!ConstantPoolInfo {
const name_index = self.name_index - 1;
if (name_index >= constant_pool.len) return ResolveError.InvalidConstantPoolIndex;
const cp_info = constant_pool[name_index];
if (cp_info == null or @as(ConstantPoolInfo.Tag, cp_info.?) != .utf8) return ResolveError.InvalidConstantType;
return cp_info.?;
}
pub fn descriptor(self: *const RecordComponentInfo, constant_pool: []const ?ConstantPoolInfo) ResolveError!ConstantPoolInfo {
const descriptor_index = self.descriptor_index - 1;
if (descriptor_index >= constant_pool.len) return ResolveError.InvalidConstantPoolIndex;
const cp_info = constant_pool[descriptor_index];
if (cp_info == null or @as(ConstantPoolInfo.Tag, cp_info.?) != .utf8) return ResolveError.InvalidConstantType;
return cp_info.?;
}
};
pub fn parse(input: *std.Io.Reader, constant_pool: []const ?ConstantPoolInfo, allocator: std.mem.Allocator) (ParseError || ResolveError)!Self {
const components_count = try input.takeInt(u16, .big);
const components = try allocator.alloc(RecordComponentInfo, components_count);
for (components) |*component| {
component.* = try .parse(input, constant_pool, allocator);
}
return .{
.components = components,
};
}
pub fn deinit(self: *Self, allocator: std.mem.Allocator) void {
for (self.components) |*component| {
component.deinit(allocator);
}
allocator.free(self.components);
}
};
pub const PermittedSubclasses = struct {
classes: []u16,
const Self = @This();
pub fn parse(input: *std.Io.Reader, allocator: std.mem.Allocator) ParseError!Self {
const number_of_classes = try input.takeInt(u16, .big);
const classes = try allocator.alloc(u16, number_of_classes);
for (classes) |*class| {
class.* = try input.takeInt(u16, .big);
}
return .{
.classes = classes,
};
}
pub fn deinit(self: *Self, allocator: std.mem.Allocator) void {
allocator.free(self.classes);
}
};