3091 lines
119 KiB
Zig
3091 lines
119 KiB
Zig
const std = @import("std");
|
|
|
|
const EnumFlags = @import("../EnumFlags.zig").EnumFlags;
|
|
|
|
const Class = @import("../Class.zig");
|
|
const ConstantPool = Class.ConstantPool;
|
|
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: ConstantPool, allocator: std.mem.Allocator) (ParseError || ResolveError)!AttributeInfo {
|
|
const attribute_name_index = try input.takeInt(u16, .big);
|
|
const attribute_name = try constant_pool.getTag(attribute_name_index, .utf8);
|
|
const name = attribute_name.utf8.bytes;
|
|
|
|
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, name, "ConstantValue")) {
|
|
return .{
|
|
.predefined = .{
|
|
.constant_value = try ConstantValue.parse(limited),
|
|
},
|
|
};
|
|
} else if (std.mem.eql(u8, name, "Code")) {
|
|
return .{
|
|
.predefined = .{
|
|
.code = try Code.parse(limited, constant_pool, allocator),
|
|
},
|
|
};
|
|
} else if (std.mem.eql(u8, name, "StackMapTable")) {
|
|
return .{
|
|
.predefined = .{
|
|
.stack_map_table = try StackMapTable.parse(limited, allocator),
|
|
},
|
|
};
|
|
} else if (std.mem.eql(u8, name, "Exceptions")) {
|
|
return .{
|
|
.predefined = .{
|
|
.exceptions = try Exceptions.parse(limited, allocator),
|
|
},
|
|
};
|
|
} else if (std.mem.eql(u8, name, "InnerClasses")) {
|
|
return .{
|
|
.predefined = .{
|
|
.inner_classes = try InnerClasses.parse(limited, allocator),
|
|
},
|
|
};
|
|
} else if (std.mem.eql(u8, name, "EnclosingMethod")) {
|
|
return .{
|
|
.predefined = .{
|
|
.enclosing_method = try EnclosingMethod.parse(limited),
|
|
},
|
|
};
|
|
} else if (std.mem.eql(u8, name, "Synthetic")) {
|
|
return .{
|
|
.predefined = .{
|
|
.synthetic = .{},
|
|
},
|
|
};
|
|
} else if (std.mem.eql(u8, name, "Signature")) {
|
|
return .{
|
|
.predefined = .{
|
|
.signature = try Signature.parse(limited),
|
|
},
|
|
};
|
|
} else if (std.mem.eql(u8, name, "SourceFile")) {
|
|
return .{
|
|
.predefined = .{
|
|
.source_file = try SourceFile.parse(limited),
|
|
},
|
|
};
|
|
} else if (std.mem.eql(u8, name, "SourceDebugExtension")) {
|
|
return .{
|
|
.predefined = .{
|
|
.source_debug_extension = try SourceDebugExtension.parse(limited, attribute_length, allocator),
|
|
},
|
|
};
|
|
} else if (std.mem.eql(u8, name, "LineNumberTable")) {
|
|
return .{
|
|
.predefined = .{
|
|
.line_number_table = try LineNumberTable.parse(limited, allocator),
|
|
},
|
|
};
|
|
} else if (std.mem.eql(u8, name, "LocalVariableTable")) {
|
|
return .{
|
|
.predefined = .{
|
|
.local_variable_table = try LocalVariableTable.parse(limited, allocator),
|
|
},
|
|
};
|
|
} else if (std.mem.eql(u8, name, "LocalVariableTypeTable")) {
|
|
return .{
|
|
.predefined = .{
|
|
.local_variable_type_table = try LocalVariableTypeTable.parse(limited, allocator),
|
|
},
|
|
};
|
|
} else if (std.mem.eql(u8, name, "Deprecated")) {
|
|
return .{
|
|
.predefined = .{
|
|
.deprecated = .{},
|
|
},
|
|
};
|
|
} else if (std.mem.eql(u8, name, "RuntimeVisibleAnnotations")) {
|
|
return .{
|
|
.predefined = .{
|
|
.runtime_visible_annotations = try RuntimeVisibleAnnotations.parse(limited, allocator),
|
|
},
|
|
};
|
|
} else if (std.mem.eql(u8, name, "RuntimeInvisibleAnnotations")) {
|
|
return .{
|
|
.predefined = .{
|
|
.runtime_invisible_annotations = try RuntimeInvisibleAnnotations.parse(limited, allocator),
|
|
},
|
|
};
|
|
} else if (std.mem.eql(u8, name, "RuntimeVisibleParameterAnnotations")) {
|
|
return .{
|
|
.predefined = .{
|
|
.runtime_visible_parameter_annotations = try RuntimeVisibleParameterAnnotations.parse(limited, allocator),
|
|
},
|
|
};
|
|
} else if (std.mem.eql(u8, name, "RuntimeInvisibleParameterAnnotations")) {
|
|
return .{
|
|
.predefined = .{
|
|
.runtime_invisible_parameter_annotations = try RuntimeInvisibleParameterAnnotations.parse(limited, allocator),
|
|
},
|
|
};
|
|
} else if (std.mem.eql(u8, name, "RuntimeVisibleTypeAnnotations")) {
|
|
return .{
|
|
.predefined = .{
|
|
.runtime_invisible_type_annotations = try RuntimeInvisibleTypeAnnotations.parse(limited, allocator),
|
|
},
|
|
};
|
|
} else if (std.mem.eql(u8, name, "RuntimeInvisibleTypeAnnotations")) {
|
|
return .{
|
|
.predefined = .{
|
|
.runtime_invisible_type_annotations = try RuntimeInvisibleTypeAnnotations.parse(limited, allocator),
|
|
},
|
|
};
|
|
} else if (std.mem.eql(u8, name, "AnnotationDefault")) {
|
|
return .{
|
|
.predefined = .{
|
|
.annotation_default = try AnnotationDefault.parse(limited, allocator),
|
|
},
|
|
};
|
|
} else if (std.mem.eql(u8, name, "BootstrapMethods")) {
|
|
return .{
|
|
.predefined = .{
|
|
.bootstrap_methods = try BootstrapMethods.parse(limited, allocator),
|
|
},
|
|
};
|
|
} else if (std.mem.eql(u8, name, "MethodParameters")) {
|
|
return .{
|
|
.predefined = .{
|
|
.method_parameters = try MethodParameters.parse(limited, allocator),
|
|
},
|
|
};
|
|
} else if (std.mem.eql(u8, name, "Module")) {
|
|
return .{
|
|
.predefined = .{
|
|
.module = try Module.parse(limited, allocator),
|
|
},
|
|
};
|
|
} else if (std.mem.eql(u8, name, "ModulePackages")) {
|
|
return .{
|
|
.predefined = .{
|
|
.module_packages = try ModulePackages.parse(limited, allocator),
|
|
},
|
|
};
|
|
} else if (std.mem.eql(u8, name, "ModuleMainClass")) {
|
|
return .{
|
|
.predefined = .{
|
|
.module_main_class = try ModuleMainClass.parse(limited),
|
|
},
|
|
};
|
|
} else if (std.mem.eql(u8, name, "NestHost")) {
|
|
return .{
|
|
.predefined = .{
|
|
.nest_host = try NestHost.parse(limited),
|
|
},
|
|
};
|
|
} else if (std.mem.eql(u8, name, "NestMembers")) {
|
|
return .{
|
|
.predefined = .{
|
|
.nest_members = try NestMembers.parse(limited, allocator),
|
|
},
|
|
};
|
|
} else if (std.mem.eql(u8, name, "Record")) {
|
|
return .{
|
|
.predefined = .{
|
|
.record = try Record.parse(limited, constant_pool, allocator),
|
|
},
|
|
};
|
|
} else if (std.mem.eql(u8, name, "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),
|
|
.runtime_visible_type_annotations => |*runtime_visible_type_annotations| runtime_visible_type_annotations.deinit(allocator),
|
|
.runtime_invisible_type_annotations => |*runtime_invisible_type_annotations| runtime_invisible_type_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: ConstantPool,
|
|
) 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: {t}\n", .{ predefined });
|
|
|
|
switch (predefined) {
|
|
.constant_value => |attr| {
|
|
const constant_value = attr.constantValue(constant_pool) catch return error.WriteFailed;
|
|
try w.splatByteAll(' ', depth * indent);
|
|
_ = try w.write("constant_value:\n");
|
|
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 exception.indentedFormat(w, depth, exception_indent + 1, constant_pool);
|
|
}
|
|
|
|
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 => |attr| {
|
|
try w.splatByteAll(' ', depth * indent);
|
|
_ = try w.write("entries:\n");
|
|
var stack_map_frame_indent = indent;
|
|
for (attr.entries, 0..) |*stack_map_frame, i| {
|
|
stack_map_frame_indent += 1;
|
|
defer stack_map_frame_indent -= 1;
|
|
|
|
try w.splatByteAll(' ', depth * stack_map_frame_indent);
|
|
try w.print("{d}:\n", .{ i });
|
|
|
|
try stack_map_frame.indentedFormat(w, depth, stack_map_frame_indent + 1, constant_pool);
|
|
}
|
|
},
|
|
.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 info = constant_pool.getTag(exception_index, .class) catch return error.WriteFailed;
|
|
|
|
try w.splatByteAll(' ', depth * exception_indent);
|
|
try w.print("{d}:\n", .{ i });
|
|
try 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 => |attr| {
|
|
try w.splatByteAll(' ', depth * indent);
|
|
try w.print("debug_extension: {s}\n", .{ attr.debug_extension });
|
|
},
|
|
.line_number_table => |attr| {
|
|
try w.splatByteAll(' ', depth * indent);
|
|
_ = try w.write("line_number_table:\n");
|
|
var line_number_indent = indent;
|
|
for (attr.line_number_table, 0..) |*line_number, i| {
|
|
line_number_indent += 1;
|
|
defer line_number_indent -= 1;
|
|
|
|
try w.splatByteAll(' ', depth * line_number_indent);
|
|
try w.print("{d}:\n", .{ i });
|
|
|
|
try line_number.indentedFormat(w, depth, line_number_indent + 1);
|
|
}
|
|
},
|
|
.local_variable_table => |attr| {
|
|
try w.splatByteAll(' ', depth * indent);
|
|
_ = try w.write("local_variable_table:\n");
|
|
var local_variable_indent = indent;
|
|
for (attr.local_variable_table, 0..) |*local_variable, i| {
|
|
local_variable_indent += 1;
|
|
defer local_variable_indent -= 1;
|
|
|
|
try w.splatByteAll(' ', depth * local_variable_indent);
|
|
try w.print("{d}:\n", .{ i });
|
|
|
|
try local_variable.indentedFormat(w, depth, local_variable_indent + 1, constant_pool);
|
|
}
|
|
},
|
|
.local_variable_type_table => |attr| {
|
|
try w.splatByteAll(' ', depth * indent);
|
|
_ = try w.write("local_variable_type_table:\n");
|
|
var local_variable_type_indent = indent;
|
|
for (attr.local_variable_type_table, 0..) |*local_variable_type, i| {
|
|
local_variable_type_indent += 1;
|
|
defer local_variable_type_indent -= 1;
|
|
|
|
try w.splatByteAll(' ', depth * local_variable_type_indent);
|
|
try w.print("{d}:\n", .{ i });
|
|
|
|
try local_variable_type.indentedFormat(w, depth, local_variable_type_indent + 1, constant_pool);
|
|
}
|
|
},
|
|
.deprecated => {},
|
|
.runtime_visible_annotations => |attr| {
|
|
try w.splatByteAll(' ', depth * indent);
|
|
_ = try w.write("annotations:\n");
|
|
var annotation_indent = indent;
|
|
for (attr.annotations, 0..) |annotation, i| {
|
|
annotation_indent += 1;
|
|
defer annotation_indent -= 1;
|
|
|
|
try w.splatByteAll(' ', depth * annotation_indent);
|
|
try w.print("{d}:\n", .{ i });
|
|
try annotation.indentedFormat(w, depth, annotation_indent + 1, constant_pool);
|
|
}
|
|
},
|
|
.runtime_invisible_annotations => |attr| {
|
|
try w.splatByteAll(' ', depth * indent);
|
|
_ = try w.write("annotations:\n");
|
|
var annotation_indent = indent;
|
|
for (attr.annotations, 0..) |annotation, i| {
|
|
annotation_indent += 1;
|
|
defer annotation_indent -= 1;
|
|
|
|
try w.splatByteAll(' ', depth * annotation_indent);
|
|
try w.print("{d}:\n", .{ i });
|
|
try annotation.indentedFormat(w, depth, annotation_indent + 1, constant_pool);
|
|
}
|
|
},
|
|
.runtime_visible_parameter_annotations => |attr| {
|
|
try w.splatByteAll(' ', depth * indent);
|
|
_ = try w.write("parameter_annotations:\n");
|
|
var parameter_annotation_indent = indent;
|
|
for (attr.parameter_annotations, 0..) |parameter_annotation, i| {
|
|
parameter_annotation_indent += 1;
|
|
defer parameter_annotation_indent -= 1;
|
|
|
|
try w.splatByteAll(' ', depth * parameter_annotation_indent);
|
|
try w.print("{d}:\n", .{ i });
|
|
try parameter_annotation.indentedFormat(w, depth, parameter_annotation_indent + 1, constant_pool);
|
|
}
|
|
},
|
|
.runtime_invisible_parameter_annotations => |attr| {
|
|
try w.splatByteAll(' ', depth * indent);
|
|
_ = try w.write("parameter_annotations:\n");
|
|
var parameter_annotation_indent = indent;
|
|
for (attr.parameter_annotations, 0..) |parameter_annotation, i| {
|
|
parameter_annotation_indent += 1;
|
|
defer parameter_annotation_indent -= 1;
|
|
|
|
try w.splatByteAll(' ', depth * parameter_annotation_indent);
|
|
try w.print("{d}:\n", .{ i });
|
|
try parameter_annotation.indentedFormat(w, depth, parameter_annotation_indent + 1, constant_pool);
|
|
}
|
|
},
|
|
.runtime_visible_type_annotations => |attr| {
|
|
try w.splatByteAll(' ', depth * indent);
|
|
_ = try w.write("type_annotations:\n");
|
|
var type_annotation_indent = indent;
|
|
for (attr.type_annotations, 0..) |type_annotation, i| {
|
|
type_annotation_indent += 1;
|
|
defer type_annotation_indent -= 1;
|
|
|
|
try w.splatByteAll(' ', depth * type_annotation_indent);
|
|
try w.print("{d}:\n", .{ i });
|
|
try type_annotation.indentedFormat(w, depth, type_annotation_indent + 1, constant_pool);
|
|
}
|
|
},
|
|
.runtime_invisible_type_annotations => |attr| {
|
|
try w.splatByteAll(' ', depth * indent);
|
|
_ = try w.write("type_annotations:\n");
|
|
var type_annotation_indent = indent;
|
|
for (attr.type_annotations, 0..) |type_annotation, i| {
|
|
type_annotation_indent += 1;
|
|
defer type_annotation_indent -= 1;
|
|
|
|
try w.splatByteAll(' ', depth * type_annotation_indent);
|
|
try w.print("{d}:\n", .{ i });
|
|
try type_annotation.indentedFormat(w, depth, type_annotation_indent + 1, constant_pool);
|
|
}
|
|
},
|
|
.annotation_default => |attr| {
|
|
try w.splatByteAll(' ', depth * indent);
|
|
_ = try w.write("default_value:\n");
|
|
try attr.default_value.indentedFormat(w, depth, indent + 1, constant_pool);
|
|
},
|
|
.bootstrap_methods => |attr| {
|
|
try w.splatByteAll(' ', depth * indent);
|
|
_ = try w.write("bootstrap_methods:\n");
|
|
var bootstrap_method_indent = indent;
|
|
for (attr.bootstrap_methods, 0..) |bootstrap_method, i| {
|
|
bootstrap_method_indent += 1;
|
|
defer bootstrap_method_indent -= 1;
|
|
|
|
try w.splatByteAll(' ', depth * bootstrap_method_indent);
|
|
try w.print("{d}:\n", .{ i });
|
|
try bootstrap_method.indentedFormat(w, depth, bootstrap_method_indent + 1, constant_pool);
|
|
}
|
|
},
|
|
.method_parameters => |attr| {
|
|
try w.splatByteAll(' ', depth * indent);
|
|
_ = try w.write("parameters:\n");
|
|
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 + 1, constant_pool);
|
|
}
|
|
},
|
|
.module => |attr| try attr.indentedFormat(w, depth, indent, constant_pool),
|
|
.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 info = constant_pool.getTag(package_index, .package) catch return error.WriteFailed;
|
|
|
|
try w.splatByteAll(' ', depth * package_indent);
|
|
try w.print("{d}:\n", .{ i });
|
|
try 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 info = constant_pool.getTag(class_index, .class) catch return error.WriteFailed;
|
|
|
|
try w.splatByteAll(' ', depth * class_indent);
|
|
try w.print("{d}:\n", .{ i });
|
|
try 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 + 1, 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 info = constant_pool.getTag(class_index, .class) catch return error.WriteFailed;
|
|
|
|
try w.splatByteAll(' ', depth * class_indent);
|
|
try w.print("{d}:\n", .{ i });
|
|
try info.indentedFormat(w, depth, class_indent + 1, constant_pool);
|
|
}
|
|
},
|
|
}
|
|
},
|
|
}
|
|
}
|
|
};
|
|
|
|
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: ConstantPool) ResolveError!ConstantPool.Info {
|
|
return constant_pool.getTag(self.attribute_name_index, .utf8);
|
|
}
|
|
};
|
|
|
|
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: ConstantPool) ResolveError!ConstantPool.Info {
|
|
return constant_pool.get(self.constant_value_index);
|
|
}
|
|
};
|
|
|
|
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 indentedFormat(
|
|
self: *const ExceptionHandler,
|
|
w: *std.Io.Writer,
|
|
depth: usize,
|
|
indent: u8,
|
|
constant_pool: ConstantPool,
|
|
) std.Io.Writer.Error!void {
|
|
try w.splatByteAll(' ', depth * indent);
|
|
try w.print("start_pc: {d}\n", .{ self.start_pc });
|
|
|
|
try w.splatByteAll(' ', depth * indent);
|
|
try w.print("end_pc: {d}\n", .{ self.end_pc });
|
|
|
|
try w.splatByteAll(' ', depth * indent);
|
|
try w.print("handler_pc: {d}\n", .{ self.handler_pc });
|
|
|
|
const catch_type = self.catchType(constant_pool) catch return error.WriteFailed;
|
|
if (catch_type) |ct| {
|
|
try w.splatByteAll(' ', depth * indent);
|
|
_ = try w.write("catch_type:\n");
|
|
try ct.indentedFormat(w, depth, indent + 1, constant_pool);
|
|
}
|
|
}
|
|
|
|
pub fn catchType(self: *const ExceptionHandler, constant_pool: ConstantPool) ResolveError!?ConstantPool.Info {
|
|
return constant_pool.getTagOptional(self.catch_type, .class);
|
|
}
|
|
};
|
|
|
|
pub fn parse(input: *std.Io.Reader, constant_pool: ConstantPool, 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),
|
|
},
|
|
},
|
|
251 => .{
|
|
.same_frame_extended = .{
|
|
.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 fn indentedFormat(
|
|
self: *const StackMapFrame,
|
|
w: *std.Io.Writer,
|
|
depth: usize,
|
|
indent: u8,
|
|
constant_pool: ConstantPool,
|
|
) std.Io.Writer.Error!void {
|
|
try w.splatByteAll(' ', depth * indent);
|
|
try w.print("frame_type: {s}\n", .{ @tagName(self.*) });
|
|
|
|
switch (self.*) {
|
|
.same_locals_1_stack_item_frame => |same_locals_1_stack_item_frame| {
|
|
try w.splatByteAll(' ', depth * indent);
|
|
_ = try w.write("stack:\n");
|
|
var stack_indent = indent;
|
|
for (&same_locals_1_stack_item_frame.stack, 0..) |*info, i| {
|
|
stack_indent += 1;
|
|
defer stack_indent -= 1;
|
|
|
|
try w.splatByteAll(' ', depth * stack_indent);
|
|
try w.print("{d}:\n", .{ i });
|
|
|
|
try info.indentedFormat(w, depth, stack_indent + 1, constant_pool);
|
|
}
|
|
},
|
|
.same_locals_1_stack_item_frame_extended => |same_locals_1_stack_item_frame_extended| {
|
|
try w.splatByteAll(' ', depth * indent);
|
|
try w.print("offset_delta: {d}\n", .{ same_locals_1_stack_item_frame_extended.offset_delta });
|
|
|
|
try w.splatByteAll(' ', depth * indent);
|
|
_ = try w.write("stack:\n");
|
|
var stack_indent = indent;
|
|
for (&same_locals_1_stack_item_frame_extended.stack, 0..) |*info, i| {
|
|
stack_indent += 1;
|
|
defer stack_indent -= 1;
|
|
|
|
try w.splatByteAll(' ', depth * stack_indent);
|
|
try w.print("{d}:\n", .{ i });
|
|
|
|
try info.indentedFormat(w, depth, stack_indent + 1, constant_pool);
|
|
}
|
|
},
|
|
.chop_frame => |chop_frame| {
|
|
try w.splatByteAll(' ', depth * indent);
|
|
try w.print("offset_delta: {d}\n", .{ chop_frame.offset_delta });
|
|
},
|
|
.append_frame => |append_frame| {
|
|
try w.splatByteAll(' ', depth * indent);
|
|
try w.print("offset_delta: {d}\n", .{ append_frame.offset_delta });
|
|
|
|
try w.splatByteAll(' ', depth * indent);
|
|
_ = try w.write("locals:\n");
|
|
var locals_indent = indent;
|
|
for (append_frame.locals, 0..) |*info, i| {
|
|
locals_indent += 1;
|
|
defer locals_indent -= 1;
|
|
|
|
try w.splatByteAll(' ', depth * locals_indent);
|
|
try w.print("{d}:\n", .{ i });
|
|
|
|
try info.indentedFormat(w, depth, locals_indent + 1, constant_pool);
|
|
}
|
|
},
|
|
.full_frame => |full_frame| {
|
|
try w.splatByteAll(' ', depth * indent);
|
|
try w.print("offset_delta: {d}\n", .{ full_frame.offset_delta });
|
|
|
|
try w.splatByteAll(' ', depth * indent);
|
|
_ = try w.write("locals:\n");
|
|
var locals_indent = indent;
|
|
for (full_frame.locals, 0..) |*info, i| {
|
|
locals_indent += 1;
|
|
defer locals_indent -= 1;
|
|
|
|
try w.splatByteAll(' ', depth * locals_indent);
|
|
try w.print("{d}:\n", .{ i });
|
|
|
|
try info.indentedFormat(w, depth, locals_indent + 1, constant_pool);
|
|
}
|
|
|
|
try w.splatByteAll(' ', depth * indent);
|
|
_ = try w.write("stack:\n");
|
|
var stack_indent = indent;
|
|
for (full_frame.stack, 0..) |*info, i| {
|
|
stack_indent += 1;
|
|
defer stack_indent -= 1;
|
|
|
|
try w.splatByteAll(' ', depth * stack_indent);
|
|
try w.print("{d}:\n", .{ i });
|
|
|
|
try info.indentedFormat(w, depth, stack_indent + 1, constant_pool);
|
|
}
|
|
},
|
|
else => {},
|
|
}
|
|
}
|
|
};
|
|
|
|
pub const VerificationTypeInfo = union(VerificationTypeInfo.Tag) {
|
|
top,
|
|
integer,
|
|
float,
|
|
double,
|
|
long,
|
|
null,
|
|
uninitialized_this,
|
|
object: Object,
|
|
uninitialized: Uninitialized,
|
|
|
|
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 const Object = struct {
|
|
cpool_index: u16,
|
|
|
|
pub fn class(self: *const Object, constant_pool: ConstantPool) ResolveError!ConstantPool.Info {
|
|
return constant_pool.getTag(self.cpool_index, .class);
|
|
}
|
|
};
|
|
|
|
pub const Uninitialized = struct {
|
|
offset: u16,
|
|
};
|
|
|
|
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 = .{
|
|
.offset = try input.takeInt(u16, .big),
|
|
},
|
|
},
|
|
};
|
|
}
|
|
|
|
pub fn indentedFormat(
|
|
self: *const VerificationTypeInfo,
|
|
w: *std.Io.Writer,
|
|
depth: usize,
|
|
indent: u8,
|
|
constant_pool: ConstantPool,
|
|
) std.Io.Writer.Error!void {
|
|
try w.splatByteAll(' ', depth * indent);
|
|
try w.print("tag: {s}\n", .{ @tagName(self.*) });
|
|
|
|
switch (self.*) {
|
|
.object => |object| {
|
|
const class = object.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);
|
|
},
|
|
.uninitialized => |uninitialized| {
|
|
try w.splatByteAll(' ', depth * indent);
|
|
try w.print("offset: {d}\n", .{ uninitialized.offset });
|
|
},
|
|
else => {},
|
|
}
|
|
}
|
|
};
|
|
|
|
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 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 indentedFormat(
|
|
self: *const InnerClass,
|
|
w: *std.Io.Writer,
|
|
depth: usize,
|
|
indent: u8,
|
|
constant_pool: ConstantPool,
|
|
) 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: ConstantPool) ResolveError!ConstantPool.Info {
|
|
return constant_pool.getTag(self.inner_class_info_index, .class);
|
|
}
|
|
|
|
pub fn outerClass(self: *const InnerClass, constant_pool: ConstantPool) ResolveError!?ConstantPool.Info {
|
|
return constant_pool.getTagOptional(self.outer_class_info_index, .class);
|
|
}
|
|
|
|
pub fn innerName(self: *const InnerClass, constant_pool: ConstantPool) ResolveError!?ConstantPool.Info {
|
|
return constant_pool.getTagOptional(self.inner_name_index, .utf8);
|
|
}
|
|
};
|
|
|
|
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 = .from(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: ConstantPool) ResolveError!ConstantPool.Info {
|
|
return constant_pool.getTag(self.class_index, .class);
|
|
}
|
|
|
|
pub fn method(self: *const EnclosingMethod, constant_pool: ConstantPool) ResolveError!?ConstantPool.Info {
|
|
return constant_pool.getTagOptional(self.method_index, .name_and_type);
|
|
}
|
|
};
|
|
|
|
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: ConstantPool) ResolveError!ConstantPool.Info {
|
|
return constant_pool.getTag(self.signature_index, .utf8);
|
|
}
|
|
};
|
|
|
|
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: ConstantPool) ResolveError!ConstantPool.Info {
|
|
return constant_pool.getTag(self.source_file_index, .utf8);
|
|
}
|
|
};
|
|
|
|
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 indentedFormat(
|
|
self: *const LineNumber,
|
|
w: *std.Io.Writer,
|
|
depth: usize,
|
|
indent: u8,
|
|
) std.Io.Writer.Error!void {
|
|
try w.splatByteAll(' ', depth * indent);
|
|
try w.print("start_pc: {d}\n", .{ self.start_pc });
|
|
|
|
try w.splatByteAll(' ', depth * indent);
|
|
try w.print("line_number: {d}\n", .{ self.line_number });
|
|
}
|
|
};
|
|
|
|
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 indentedFormat(
|
|
self: *const LocalVariable,
|
|
w: *std.Io.Writer,
|
|
depth: usize,
|
|
indent: u8,
|
|
constant_pool: ConstantPool,
|
|
) std.Io.Writer.Error!void {
|
|
try w.splatByteAll(' ', depth * indent);
|
|
try w.print("start_pc: {d}\n", .{ self.start_pc });
|
|
|
|
try w.splatByteAll(' ', depth * indent);
|
|
try w.print("length: {d}\n", .{ self.length });
|
|
|
|
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);
|
|
}
|
|
|
|
pub fn name(self: *const LocalVariable, constant_pool: ConstantPool) ResolveError!ConstantPool.Info {
|
|
return constant_pool.getTag(self.name_index, .utf8);
|
|
}
|
|
|
|
pub fn descriptor(self: *const LocalVariable, constant_pool: ConstantPool) ResolveError!ConstantPool.Info {
|
|
return constant_pool.getTag(self.descriptor_index, .utf8);
|
|
}
|
|
};
|
|
|
|
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 indentedFormat(
|
|
self: *const LocalVariableType,
|
|
w: *std.Io.Writer,
|
|
depth: usize,
|
|
indent: u8,
|
|
constant_pool: ConstantPool,
|
|
) std.Io.Writer.Error!void {
|
|
try w.splatByteAll(' ', depth * indent);
|
|
try w.print("start_pc: {d}\n", .{ self.start_pc });
|
|
|
|
try w.splatByteAll(' ', depth * indent);
|
|
try w.print("length: {d}\n", .{ self.length });
|
|
|
|
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 signature_ = self.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);
|
|
}
|
|
|
|
pub fn name(self: *const LocalVariableType, constant_pool: ConstantPool) ResolveError!ConstantPool.Info {
|
|
return constant_pool.getTag(self.name_index, .utf8);
|
|
}
|
|
|
|
pub fn signature(self: *const LocalVariableType, constant_pool: ConstantPool) ResolveError!ConstantPool.Info {
|
|
return constant_pool.getTag(self.signature_index, .utf8);
|
|
}
|
|
};
|
|
|
|
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: ConstValue,
|
|
// e
|
|
enum_const_value: EnumConstValue,
|
|
// c
|
|
class_const_value: ClassConstValue,
|
|
// @
|
|
annotation_value: Annotation,
|
|
// [
|
|
array_value: struct {
|
|
values: []ElementValue,
|
|
},
|
|
|
|
pub const ConstValue = struct {
|
|
@"type": Type,
|
|
index: u16,
|
|
|
|
pub const Type = enum(u8) {
|
|
byte = 'B',
|
|
char = 'C',
|
|
double = 'D',
|
|
float = 'F',
|
|
int = 'I',
|
|
long = 'J',
|
|
short = 'S',
|
|
boolean = 'Z',
|
|
string = 's',
|
|
};
|
|
|
|
pub fn value(self: *const ConstValue, constant_pool: ConstantPool) ResolveError!ConstantPool.Info {
|
|
const value_ = try constant_pool.get(self.index);
|
|
return switch (self.@"type") {
|
|
.byte, .char, .int, .short, .boolean => blk: {
|
|
if (!value_.is(.integer)) break :blk ResolveError.InvalidConstantType;
|
|
break :blk value_;
|
|
},
|
|
.double => blk: {
|
|
if (!value_.is(.double)) break :blk ResolveError.InvalidConstantType;
|
|
break :blk value_;
|
|
},
|
|
.float => blk: {
|
|
if (!value_.is(.float)) break :blk ResolveError.InvalidConstantType;
|
|
break :blk value_;
|
|
},
|
|
.long => blk: {
|
|
if (!value_.is(.long)) break :blk ResolveError.InvalidConstantType;
|
|
break :blk value_;
|
|
},
|
|
.string => blk: {
|
|
if (!value_.is(.utf8)) break :blk ResolveError.InvalidConstantType;
|
|
break :blk value_;
|
|
},
|
|
};
|
|
}
|
|
};
|
|
|
|
pub const EnumConstValue = struct {
|
|
type_name_index: u16,
|
|
const_name_index: u16,
|
|
|
|
pub fn descriptor(self: *const EnumConstValue, constant_pool: ConstantPool) ResolveError!ConstantPool.Info {
|
|
return constant_pool.getTag(self.type_name_index, .utf8);
|
|
}
|
|
|
|
pub fn name(self: *const EnumConstValue, constant_pool: ConstantPool) ResolveError!ConstantPool.Info {
|
|
return constant_pool.getTag(self.const_name_index, .utf8);
|
|
}
|
|
};
|
|
|
|
pub const ClassConstValue = struct {
|
|
index: u16,
|
|
|
|
pub fn descriptor(self: *const ClassConstValue, constant_pool: ConstantPool) ResolveError!ConstantPool.Info {
|
|
return constant_pool.getTag(self.index, .utf8);
|
|
}
|
|
};
|
|
|
|
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 = .{
|
|
.@"type" = @enumFromInt(tag),
|
|
.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_const_value = .{
|
|
.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 fn indentedFormat(
|
|
self: *const ElementValue,
|
|
w: *std.Io.Writer,
|
|
depth: usize,
|
|
indent: u8,
|
|
constant_pool: ConstantPool,
|
|
) std.Io.Writer.Error!void {
|
|
try w.splatByteAll(' ', depth * indent);
|
|
try w.print("type: {s}\n", .{ @tagName(self.*) });
|
|
|
|
switch (self.*) {
|
|
.const_value => |const_value| {
|
|
const value = const_value.value(constant_pool) catch return error.WriteFailed;
|
|
try w.splatByteAll(' ', depth * indent);
|
|
_ = try w.write("value:\n");
|
|
try value.indentedFormat(w, depth, indent + 1, constant_pool);
|
|
},
|
|
.enum_const_value => |enum_const_value| {
|
|
const descriptor = enum_const_value.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);
|
|
|
|
const name = enum_const_value.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);
|
|
},
|
|
.class_const_value => |class_const_value| {
|
|
const descriptor = class_const_value.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);
|
|
},
|
|
.annotation_value => |annotation_value| {
|
|
_ = try w.write("annotation:\n");
|
|
try annotation_value.indentedFormat(w, depth, indent + 1, constant_pool);
|
|
},
|
|
.array_value => |array_value| {
|
|
try w.splatByteAll(' ', depth * indent);
|
|
_ = try w.write("values:\n");
|
|
var value_indent = indent;
|
|
for (array_value.values, 0..) |*value, i| {
|
|
value_indent += 1;
|
|
defer value_indent -= 1;
|
|
|
|
try w.splatByteAll(' ', depth * value_indent);
|
|
try w.print("{d}:\n", .{ i });
|
|
|
|
try value.indentedFormat(w, depth, value_indent + 1, constant_pool);
|
|
}
|
|
},
|
|
}
|
|
}
|
|
};
|
|
|
|
pub const ElementValuePair = struct {
|
|
element_name_index: u16,
|
|
value: ElementValue,
|
|
|
|
const Self = @This();
|
|
|
|
pub fn indentedFormat(
|
|
self: *const ElementValuePair,
|
|
w: *std.Io.Writer,
|
|
depth: usize,
|
|
indent: u8,
|
|
constant_pool: ConstantPool,
|
|
) std.Io.Writer.Error!void {
|
|
const element_name = self.elementName(constant_pool) catch return error.WriteFailed;
|
|
try w.splatByteAll(' ', depth * indent);
|
|
_ = try w.write("name:\n");
|
|
try element_name.indentedFormat(w, depth, indent + 1, constant_pool);
|
|
|
|
try w.splatByteAll(' ', depth * indent);
|
|
_ = try w.write("value:\n");
|
|
try self.value.indentedFormat(w, depth, indent + 1, constant_pool);
|
|
}
|
|
|
|
pub fn elementName(self: *const Self, constant_pool: ConstantPool) ResolveError!ConstantPool.Info {
|
|
return constant_pool.getTag(self.element_name_index, .utf8);
|
|
}
|
|
};
|
|
|
|
pub const Annotation = struct {
|
|
type_index: u16,
|
|
element_value_pairs: []ElementValuePair,
|
|
|
|
const Self = @This();
|
|
|
|
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 fn indentedFormat(
|
|
self: *const Annotation,
|
|
w: *std.Io.Writer,
|
|
depth: usize,
|
|
indent: u8,
|
|
constant_pool: ConstantPool,
|
|
) std.Io.Writer.Error!void {
|
|
const type_ = self.@"type"(constant_pool) catch return error.WriteFailed;
|
|
try w.splatByteAll(' ', depth * indent);
|
|
_ = try w.write("type:\n");
|
|
try type_.indentedFormat(w, depth, indent + 1, constant_pool);
|
|
|
|
try w.splatByteAll(' ', depth * indent);
|
|
_ = try w.write("element_value_pairs:\n");
|
|
var element_value_pair_indent = indent;
|
|
for (self.element_value_pairs, 0..) |element_value_pair, i| {
|
|
element_value_pair_indent += 1;
|
|
defer element_value_pair_indent -= 1;
|
|
|
|
try w.splatByteAll(' ', depth * element_value_pair_indent);
|
|
try w.print("{d}:\n", .{ i });
|
|
try element_value_pair.indentedFormat(w, depth, element_value_pair_indent + 1, constant_pool);
|
|
}
|
|
}
|
|
|
|
pub fn @"type"(self: *const Self, constant_pool: ConstantPool) ResolveError!ConstantPool.Info {
|
|
return constant_pool.getTag(self.type_index, .utf8);
|
|
}
|
|
};
|
|
|
|
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 fn indentedFormat(
|
|
self: *const ParameterAnnotation,
|
|
w: *std.Io.Writer,
|
|
depth: usize,
|
|
indent: u8,
|
|
constant_pool: ConstantPool,
|
|
) std.Io.Writer.Error!void {
|
|
try w.splatByteAll(' ', depth * indent);
|
|
_ = try w.write("annotations:\n");
|
|
var annotation_indent = indent;
|
|
for (self.annotations, 0..) |annotation, i| {
|
|
annotation_indent += 1;
|
|
defer annotation_indent -= 1;
|
|
|
|
try w.splatByteAll(' ', depth * annotation_indent);
|
|
try w.print("{d}:\n", .{ i });
|
|
try annotation.indentedFormat(w, depth, annotation_indent + 1, constant_pool);
|
|
}
|
|
}
|
|
};
|
|
|
|
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);
|
|
}
|
|
};
|
|
|
|
pub const TypeAnnotation = struct {
|
|
target_type: TargetType,
|
|
target_info: TargetInfo,
|
|
target_path: TypePath,
|
|
type_index: u16,
|
|
element_value_pairs: []ElementValuePair,
|
|
|
|
const Self = @This();
|
|
|
|
pub const TargetType = enum(u8) {
|
|
/// type parameter declaration of generic class or interface
|
|
type_parameter_generic_class_interface = 0x00,
|
|
/// type parameter declaration of generic method or constructor
|
|
type_parameter_generic_method_constructor = 0x01,
|
|
/// type in extends or implements clause of class declaration
|
|
/// (including the direct superclass or direct superinterface of an anonymous class declaration),
|
|
/// or in extends clause of interface declaration
|
|
type_in_extends_implements = 0x10,
|
|
/// type in bound of type parameter declaration of generic class or interface
|
|
type_in_bound_generic_class_interface = 0x11,
|
|
/// type in bound of type parameter declaration of generic method or constructor
|
|
type_in_bound_generic_method_constructor = 0x12,
|
|
/// type in field or record component declaration
|
|
type_in_field_record_component = 0x13,
|
|
/// return type of method, or type of newly constructed object
|
|
return_type_method_newly_constructed_object = 0x14,
|
|
/// receiver type of method or constructor
|
|
receiver_type_method_constructor = 0x15,
|
|
/// type in formal parameter declaration of method, constructor, or lambda expression
|
|
type_in_formal_parameter_declaration_method_constructor_lambda = 0x16,
|
|
/// type in throws clause of method or constructor
|
|
type_in_throws_method_constructor = 0x17,
|
|
/// type in local variable declaration
|
|
type_in_local_variable = 0x40,
|
|
/// type in resource variable declaration
|
|
type_in_resource_variable = 0x41,
|
|
/// type in exception parameter declaration
|
|
type_in_exception_parameter = 0x42,
|
|
/// type in instanceof expression
|
|
type_in_instanceof = 0x43,
|
|
/// type in new expression
|
|
type_in_new = 0x44,
|
|
/// type in method reference expression using ::new
|
|
type_in_method_reference_new = 0x45,
|
|
/// type in method reference expression using ::Identifier
|
|
type_in_method_reference_identifier = 0x46,
|
|
/// type in cast expression
|
|
type_in_cast = 0x47,
|
|
/// type argument for generic constructor in new expression or explicit constructor invocation statement
|
|
type_generic_constructor_new_explicit = 0x48,
|
|
/// type argument for generic method in method invocation expression
|
|
type_generic_method_invocation = 0x49,
|
|
/// type argument for generic constructor in method reference expression using ::new
|
|
type_generic_constructor_method_reference_new = 0x4a,
|
|
/// type argument for generic method in method reference expression using ::Identifier
|
|
type_generic_method_method_reference_identifier = 0x4b,
|
|
};
|
|
|
|
pub const TargetInfo = union(enum) {
|
|
type_parameter: TypeParameter,
|
|
supertype: SuperType,
|
|
type_parameter_bound: TypeParameterBound,
|
|
empty: Empty,
|
|
formal_parameter: FormalParameter,
|
|
throws: Throws,
|
|
localvar: Localvar,
|
|
@"catch": Catch,
|
|
offset: Offset,
|
|
type_argument: TypeArgument,
|
|
|
|
pub const TypeParameter = struct {
|
|
type_parameter_index: u8,
|
|
};
|
|
|
|
pub const SuperType = struct {
|
|
supertype_index: u16,
|
|
};
|
|
|
|
pub const TypeParameterBound = struct {
|
|
type_parameter_index: u8,
|
|
bound_index: u8,
|
|
};
|
|
|
|
pub const Empty = struct { };
|
|
|
|
pub const FormalParameter = struct {
|
|
formal_parameter_index: u8,
|
|
};
|
|
|
|
pub const Throws = struct {
|
|
throws_type_index: u16,
|
|
};
|
|
|
|
pub const Localvar = struct {
|
|
table: []Entry,
|
|
|
|
pub const Entry = struct {
|
|
start_pc: u16,
|
|
length: u16,
|
|
index: u16,
|
|
|
|
pub fn indentedFormat(
|
|
self: *const Entry,
|
|
w: *std.Io.Writer,
|
|
depth: usize,
|
|
indent: u8,
|
|
) std.Io.Writer.Error!void {
|
|
try w.splatByteAll(' ', depth * indent);
|
|
try w.print("start_pc: {d}\n", .{ self.start_pc });
|
|
|
|
try w.splatByteAll(' ', depth * indent);
|
|
try w.print("length: {d}\n", .{ self.length });
|
|
|
|
try w.splatByteAll(' ', depth * indent);
|
|
try w.print("start_pc: {d}\n", .{ self.index });
|
|
}
|
|
};
|
|
};
|
|
|
|
pub const Catch = struct {
|
|
exception_table_index: u16,
|
|
};
|
|
|
|
pub const Offset = struct {
|
|
offset: u16,
|
|
};
|
|
|
|
pub const TypeArgument = struct {
|
|
offset: u16,
|
|
type_argument_index: u8,
|
|
};
|
|
|
|
pub fn indentedFormat(
|
|
self: *const TargetInfo,
|
|
w: *std.Io.Writer,
|
|
depth: usize,
|
|
indent: u8,
|
|
) std.Io.Writer.Error!void {
|
|
try w.splatByteAll(' ', depth * indent);
|
|
try w.print("target_info_type: {t}\n", .{ self.* });
|
|
|
|
switch (self.*) {
|
|
.type_parameter => |*type_parameter| {
|
|
try w.splatByteAll(' ', depth * indent);
|
|
try w.print("type_parameter_index: {d}\n", .{ type_parameter.type_parameter_index });
|
|
},
|
|
.supertype => |*supertype| {
|
|
try w.splatByteAll(' ', depth * indent);
|
|
try w.print("supertype_index: {d}\n", .{ supertype.supertype_index });
|
|
},
|
|
.type_parameter_bound => |*type_parameter_bound| {
|
|
try w.splatByteAll(' ', depth * indent);
|
|
try w.print("type_parameter_index: {d}\n", .{ type_parameter_bound.type_parameter_index });
|
|
|
|
try w.splatByteAll(' ', depth * indent);
|
|
try w.print("bound_index: {d}\n", .{ type_parameter_bound.bound_index });
|
|
},
|
|
.formal_parameter => |*formal_parameter| {
|
|
try w.splatByteAll(' ', depth * indent);
|
|
try w.print("formal_parameter_index: {d}\n", .{ formal_parameter.formal_parameter_index });
|
|
},
|
|
.throws => |*throws| {
|
|
try w.splatByteAll(' ', depth * indent);
|
|
try w.print("throws_type_index: {d}\n", .{ throws.throws_type_index });
|
|
},
|
|
.localvar => |*localvar| {
|
|
try w.splatByteAll(' ', depth * indent);
|
|
_ = try w.write("table:\n");
|
|
var entry_indent = indent;
|
|
for (localvar.table, 0..) |*entry, i| {
|
|
entry_indent += 1;
|
|
defer entry_indent -= 1;
|
|
|
|
try w.splatByteAll(' ', depth * entry_indent);
|
|
try w.print("{d}:\n", .{ i });
|
|
|
|
try entry.indentedFormat(w, depth, indent);
|
|
}
|
|
},
|
|
.@"catch" => |*@"catch"| {
|
|
try w.splatByteAll(' ', depth * indent);
|
|
try w.print("exception_table_index: {d}\n", .{ @"catch".exception_table_index });
|
|
},
|
|
.offset => |*offset| {
|
|
try w.splatByteAll(' ', depth * indent);
|
|
try w.print("offset: {d}\n", .{ offset.offset });
|
|
},
|
|
.type_argument => |*type_argument| {
|
|
try w.splatByteAll(' ', depth * indent);
|
|
try w.print("offset: {d}\n", .{ type_argument.offset });
|
|
|
|
try w.splatByteAll(' ', depth * indent);
|
|
try w.print("type_argument_index: {d}\n", .{ type_argument.type_argument_index });
|
|
},
|
|
else => {},
|
|
}
|
|
}
|
|
};
|
|
|
|
pub const TypePath = struct {
|
|
paths: []Path,
|
|
|
|
pub const Path = struct {
|
|
type_path_kind: u8,
|
|
type_argument_index: u8,
|
|
|
|
pub fn indentedFormat(
|
|
self: *const Path,
|
|
w: *std.Io.Writer,
|
|
depth: usize,
|
|
indent: u8,
|
|
) std.Io.Writer.Error!void {
|
|
try w.splatByteAll(' ', depth * indent);
|
|
try w.print("type_path_kind: {d}\n", .{ self.type_path_kind });
|
|
|
|
try w.splatByteAll(' ', depth * indent);
|
|
try w.print("type_argument_index: {d}\n", .{ self.type_argument_index });
|
|
}
|
|
};
|
|
|
|
pub fn parse(input: *std.Io.Reader, allocator: std.mem.Allocator) ParseError!TypePath {
|
|
const length = try input.takeByte();
|
|
const paths = try allocator.alloc(Path, length);
|
|
errdefer allocator.free(paths);
|
|
for (paths) |*path| {
|
|
path.* = .{
|
|
.type_path_kind = try input.takeByte(),
|
|
.type_argument_index = try input.takeByte(),
|
|
};
|
|
}
|
|
|
|
return .{
|
|
.paths = paths,
|
|
};
|
|
}
|
|
|
|
pub fn deinit(self: *TypePath, allocator: std.mem.Allocator) void {
|
|
allocator.free(self.paths);
|
|
}
|
|
|
|
pub fn indentedFormat(
|
|
self: *const TypePath,
|
|
w: *std.Io.Writer,
|
|
depth: usize,
|
|
indent: u8,
|
|
) std.Io.Writer.Error!void {
|
|
try w.splatByteAll(' ', depth * indent);
|
|
_ = try w.write("paths:\n");
|
|
var path_indent = indent;
|
|
for (self.paths, 0..) |path, i| {
|
|
path_indent += 1;
|
|
defer path_indent -= 1;
|
|
|
|
try w.splatByteAll(' ', depth * path_indent);
|
|
try w.print("{d}:\n", .{ i });
|
|
try path.indentedFormat(w, depth, path_indent + 1);
|
|
}
|
|
}
|
|
};
|
|
|
|
pub fn parse(input: *std.Io.Reader, allocator: std.mem.Allocator) ParseError!Self {
|
|
const target_type: TargetType = @enumFromInt(try input.takeInt(u8, .big));
|
|
const target_info: TargetInfo = switch (target_type) {
|
|
.type_parameter_generic_class_interface, .type_parameter_generic_method_constructor => .{
|
|
.type_parameter = .{
|
|
.type_parameter_index = try input.takeByte(),
|
|
},
|
|
},
|
|
.type_in_extends_implements => .{
|
|
.supertype = .{
|
|
.supertype_index = try input.takeInt(u16, .big),
|
|
},
|
|
},
|
|
.type_in_bound_generic_class_interface, .type_in_bound_generic_method_constructor => .{
|
|
.type_parameter_bound = .{
|
|
.type_parameter_index = try input.takeByte(),
|
|
.bound_index = try input.takeByte(),
|
|
},
|
|
},
|
|
.type_in_field_record_component, .return_type_method_newly_constructed_object, .receiver_type_method_constructor => .{
|
|
.empty = .{},
|
|
},
|
|
.type_in_formal_parameter_declaration_method_constructor_lambda => .{
|
|
.formal_parameter = .{
|
|
.formal_parameter_index = try input.takeByte(),
|
|
},
|
|
},
|
|
.type_in_throws_method_constructor => .{
|
|
.throws = .{
|
|
.throws_type_index = try input.takeInt(u16, .big),
|
|
},
|
|
},
|
|
.type_in_local_variable, .type_in_resource_variable => blk: {
|
|
const table_length = try input.takeInt(u16, .big);
|
|
const table = try allocator.alloc(TargetInfo.Localvar.Entry, table_length);
|
|
errdefer allocator.free(table);
|
|
for (table) |*entry| {
|
|
entry.* = .{
|
|
.start_pc = try input.takeInt(u16, .big),
|
|
.length = try input.takeInt(u16, .big),
|
|
.index = try input.takeInt(u16, .big),
|
|
};
|
|
}
|
|
|
|
break :blk .{
|
|
.localvar = .{
|
|
.table = table,
|
|
},
|
|
};
|
|
},
|
|
.type_in_exception_parameter => .{
|
|
.@"catch" = . {
|
|
.exception_table_index = try input.takeInt(u16, .big),
|
|
},
|
|
},
|
|
.type_in_instanceof, .type_in_new, .type_in_method_reference_new, .type_in_method_reference_identifier => .{
|
|
.offset = .{
|
|
.offset = try input.takeInt(u16, .big),
|
|
},
|
|
},
|
|
.type_in_cast, .type_generic_constructor_new_explicit, .type_generic_method_invocation, .type_generic_constructor_method_reference_new, .type_generic_method_method_reference_identifier => .{
|
|
.type_argument = .{
|
|
.offset = try input.takeInt(u16, .big),
|
|
.type_argument_index = try input.takeByte(),
|
|
},
|
|
},
|
|
};
|
|
|
|
var target_path: TypePath = try .parse(input, allocator);
|
|
errdefer target_path.deinit(allocator);
|
|
|
|
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 .{
|
|
.target_type = target_type,
|
|
.target_info = target_info,
|
|
.target_path = target_path,
|
|
.type_index = type_index,
|
|
.element_value_pairs = element_value_pairs,
|
|
};
|
|
}
|
|
|
|
pub fn deinit(self: *Self, allocator: std.mem.Allocator) void {
|
|
switch (self.target_info) {
|
|
.localvar => |localvar| allocator.free(localvar.table),
|
|
else => {},
|
|
}
|
|
for (self.element_value_pairs) |*element_value_pair| {
|
|
element_value_pair.value.deinit(allocator);
|
|
}
|
|
allocator.free(self.element_value_pairs);
|
|
}
|
|
|
|
pub fn indentedFormat(
|
|
self: *const Self,
|
|
w: *std.Io.Writer,
|
|
depth: usize,
|
|
indent: u8,
|
|
constant_pool: ConstantPool,
|
|
) std.Io.Writer.Error!void {
|
|
try w.splatByteAll(' ', depth * indent);
|
|
try w.print("target_type: {t}\n", .{ self.target_type });
|
|
|
|
try w.splatByteAll(' ', depth * indent);
|
|
_ = try w.write("target_info:\n");
|
|
try self.target_info.indentedFormat(w, depth + 1, indent);
|
|
|
|
try w.splatByteAll(' ', depth * indent);
|
|
_ = try w.write("target_path:\n");
|
|
try self.target_path.indentedFormat(w, depth + 1, indent);
|
|
|
|
const type_ = self.@"type"(constant_pool) catch return error.WriteFailed;
|
|
try w.splatByteAll(' ', depth * indent);
|
|
_ = try w.write("type:\n");
|
|
try type_.indentedFormat(w, depth, indent + 1, constant_pool);
|
|
|
|
try w.splatByteAll(' ', depth * indent);
|
|
_ = try w.write("element_value_pairs:\n");
|
|
var element_value_pair_indent = indent;
|
|
for (self.element_value_pairs, 0..) |element_value_pair, i| {
|
|
element_value_pair_indent += 1;
|
|
defer element_value_pair_indent -= 1;
|
|
|
|
try w.splatByteAll(' ', depth * element_value_pair_indent);
|
|
try w.print("{d}:\n", .{ i });
|
|
try element_value_pair.indentedFormat(w, depth, element_value_pair_indent + 1, constant_pool);
|
|
}
|
|
}
|
|
|
|
pub fn @"type"(self: *const Self, constant_pool: ConstantPool) ResolveError!ConstantPool.Info {
|
|
return constant_pool.getTag(self.type_index, .utf8);
|
|
}
|
|
};
|
|
|
|
pub const RuntimeVisibleTypeAnnotations = struct {
|
|
type_annotations: []TypeAnnotation,
|
|
|
|
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 type_annotations = try allocator.alloc(TypeAnnotation, num_annotations);
|
|
errdefer allocator.free(type_annotations);
|
|
for (type_annotations) |*type_annotation| {
|
|
type_annotation.* = try .parse(input, allocator);
|
|
}
|
|
|
|
return .{
|
|
.type_annotations = type_annotations,
|
|
};
|
|
}
|
|
|
|
pub fn deinit(self: *Self, allocator: std.mem.Allocator) void {
|
|
for (self.type_annotations) |*type_annotation| {
|
|
type_annotation.deinit(allocator);
|
|
}
|
|
allocator.free(self.type_annotations);
|
|
}
|
|
};
|
|
|
|
pub const RuntimeInvisibleTypeAnnotations = struct {
|
|
type_annotations: []TypeAnnotation,
|
|
|
|
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 type_annotations = try allocator.alloc(TypeAnnotation, num_annotations);
|
|
errdefer allocator.free(type_annotations);
|
|
for (type_annotations) |*type_annotation| {
|
|
type_annotation.* = try .parse(input, allocator);
|
|
}
|
|
|
|
return .{
|
|
.type_annotations = type_annotations,
|
|
};
|
|
}
|
|
|
|
pub fn deinit(self: *Self, allocator: std.mem.Allocator) void {
|
|
for (self.type_annotations) |*type_annotation| {
|
|
type_annotation.deinit(allocator);
|
|
}
|
|
allocator.free(self.type_annotations);
|
|
}
|
|
};
|
|
|
|
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 indentedFormat(
|
|
self: *const BootstrapMethod,
|
|
w: *std.Io.Writer,
|
|
depth: usize,
|
|
indent: u8,
|
|
constant_pool: ConstantPool,
|
|
) std.Io.Writer.Error!void {
|
|
const bootstrap_method = self.bootstrapMethod(constant_pool) catch return error.WriteFailed;
|
|
try w.splatByteAll(' ', depth * indent);
|
|
_ = try w.write("bootstrap_method:\n");
|
|
try bootstrap_method.indentedFormat(w, depth, indent + 1, constant_pool);
|
|
|
|
try w.splatByteAll(' ', depth * indent);
|
|
_ = try w.write("bootstrap_arguments:\n");
|
|
var bootstrap_argument_indent = indent;
|
|
for (self.bootstrap_arguments, 0..) |bootstrap_argument, i| {
|
|
bootstrap_argument_indent += 1;
|
|
defer bootstrap_argument_indent -= 1;
|
|
|
|
const info = constant_pool.getLoadable(bootstrap_argument) catch return error.WriteFailed;
|
|
|
|
try w.splatByteAll(' ', depth * bootstrap_argument_indent);
|
|
try w.print("{d}:\n", .{ i });
|
|
try info.indentedFormat(w, depth, bootstrap_argument_indent + 1, constant_pool);
|
|
}
|
|
}
|
|
|
|
pub fn bootstrapMethod(self: *const BootstrapMethod, constant_pool: ConstantPool) ResolveError!ConstantPool.Info {
|
|
return constant_pool.getTag(self.bootstrap_method_ref, .method_handle);
|
|
}
|
|
};
|
|
|
|
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: ConstantPool,
|
|
) 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;
|
|
if (name_) |n| {
|
|
try w.splatByteAll(' ', depth * indent);
|
|
_ = try w.write("name:\n");
|
|
try n.indentedFormat(w, depth, indent + 1, constant_pool);
|
|
}
|
|
}
|
|
|
|
pub fn name(self: *const Parameter, constant_pool: ConstantPool) ResolveError!?ConstantPool.Info {
|
|
return constant_pool.getTagOptional(self.name_index, .utf8);
|
|
}
|
|
};
|
|
|
|
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 = .from(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 fn indentedFormat(
|
|
self: *const Requires,
|
|
w: *std.Io.Writer,
|
|
depth: usize,
|
|
indent: u8,
|
|
constant_pool: ConstantPool,
|
|
) std.Io.Writer.Error!void {
|
|
const requires_ = self.requires(constant_pool) catch return error.WriteFailed;
|
|
try w.splatByteAll(' ', depth * indent);
|
|
_ = try w.write("requires:\n");
|
|
try requires_.indentedFormat(w, depth, indent + 1, constant_pool);
|
|
|
|
try w.splatByteAll(' ', depth * indent);
|
|
try w.print("flags: {f}\n", .{ self.requires_flags });
|
|
|
|
const version = self.requiresVersion(constant_pool) catch return error.WriteFailed;
|
|
if (version) |v| {
|
|
try w.splatByteAll(' ', depth * indent);
|
|
_ = try w.write("version:\n");
|
|
try v.indentedFormat(w, depth, indent + 1, constant_pool);
|
|
}
|
|
}
|
|
|
|
pub fn requires(self: *const Requires, constant_pool: ConstantPool) ResolveError!ConstantPool.Info {
|
|
return constant_pool.getTag(self.requires_index, .module);
|
|
}
|
|
|
|
pub fn requiresVersion(self: *const Requires, constant_pool: ConstantPool) ResolveError!?ConstantPool.Info {
|
|
return constant_pool.getTagOptional(self.requires_version_index, .utf8);
|
|
}
|
|
};
|
|
|
|
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 fn indentedFormat(
|
|
self: *const Exports,
|
|
w: *std.Io.Writer,
|
|
depth: usize,
|
|
indent: u8,
|
|
constant_pool: ConstantPool,
|
|
) std.Io.Writer.Error!void {
|
|
const exports_ = self.exports(constant_pool) catch return error.WriteFailed;
|
|
try w.splatByteAll(' ', depth * indent);
|
|
_ = try w.write("exports:\n");
|
|
try exports_.indentedFormat(w, depth, indent + 1, constant_pool);
|
|
|
|
try w.splatByteAll(' ', depth * indent);
|
|
try w.print("flags: {f}\n", .{ self.exports_flags });
|
|
|
|
try w.splatByteAll(' ', depth * indent);
|
|
_ = try w.write("exports_to:\n");
|
|
var exports_to_indent = indent;
|
|
for (self.exports_to_indeces, 0..) |exports_to_index, i| {
|
|
exports_to_indent += 1;
|
|
defer exports_to_indent -= 1;
|
|
|
|
const info = constant_pool.getTag(exports_to_index, .module) catch return error.WriteFailed;
|
|
|
|
try w.splatByteAll(' ', depth * exports_to_indent);
|
|
try w.print("{d}:\n", .{ i });
|
|
try info.indentedFormat(w, depth, exports_to_indent + 1, constant_pool);
|
|
}
|
|
}
|
|
|
|
pub fn exports(self: *const Exports, constant_pool: ConstantPool) ResolveError!ConstantPool.Info {
|
|
return constant_pool.getTag(self.exports_index, .package);
|
|
}
|
|
};
|
|
|
|
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 fn indentedFormat(
|
|
self: *const Opens,
|
|
w: *std.Io.Writer,
|
|
depth: usize,
|
|
indent: u8,
|
|
constant_pool: ConstantPool,
|
|
) std.Io.Writer.Error!void {
|
|
const opens_ = self.opens(constant_pool) catch return error.WriteFailed;
|
|
try w.splatByteAll(' ', depth * indent);
|
|
_ = try w.write("opens:\n");
|
|
try opens_.indentedFormat(w, depth, indent + 1, constant_pool);
|
|
|
|
try w.splatByteAll(' ', depth * indent);
|
|
try w.print("flags: {f}\n", .{ self.opens_flags });
|
|
|
|
try w.splatByteAll(' ', depth * indent);
|
|
_ = try w.write("opens_to:\n");
|
|
var opens_to_indent = indent;
|
|
for (self.opens_to_indeces, 0..) |opens_to_index, i| {
|
|
opens_to_indent += 1;
|
|
defer opens_to_indent -= 1;
|
|
|
|
const info = constant_pool.getTag(opens_to_index, .module) catch return error.WriteFailed;
|
|
|
|
try w.splatByteAll(' ', depth * opens_to_indent);
|
|
try w.print("{d}:\n", .{ i });
|
|
try info.indentedFormat(w, depth, opens_to_indent + 1, constant_pool);
|
|
}
|
|
}
|
|
|
|
pub fn opens(self: *const Opens, constant_pool: ConstantPool) ResolveError!ConstantPool.Info {
|
|
return constant_pool.getTag(self.opens_index, .package);
|
|
}
|
|
};
|
|
|
|
pub const Provides = struct {
|
|
provides_index: u16,
|
|
provides_with_indeces: []u16,
|
|
|
|
pub fn indentedFormat(
|
|
self: *const Provides,
|
|
w: *std.Io.Writer,
|
|
depth: usize,
|
|
indent: u8,
|
|
constant_pool: ConstantPool,
|
|
) std.Io.Writer.Error!void {
|
|
const provides_ = self.provides(constant_pool) catch return error.WriteFailed;
|
|
try w.splatByteAll(' ', depth * indent);
|
|
_ = try w.write("provides:\n");
|
|
try provides_.indentedFormat(w, depth, indent + 1, constant_pool);
|
|
|
|
try w.splatByteAll(' ', depth * indent);
|
|
_ = try w.write("provides_with:\n");
|
|
var provides_with_indent = indent;
|
|
for (self.provides_with_indeces, 0..) |provides_with_index, i| {
|
|
provides_with_indent += 1;
|
|
defer provides_with_indent -= 1;
|
|
|
|
const info = constant_pool.getTag(provides_with_index, .class) catch return error.WriteFailed;
|
|
|
|
try w.splatByteAll(' ', depth * provides_with_indent);
|
|
try w.print("{d}:\n", .{ i });
|
|
try info.indentedFormat(w, depth, provides_with_indent + 1, constant_pool);
|
|
}
|
|
}
|
|
|
|
pub fn provides(self: *const Provides, constant_pool: ConstantPool) ResolveError!ConstantPool.Info {
|
|
return constant_pool.getTag(self.provides_index, .class);
|
|
}
|
|
};
|
|
|
|
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 = .from(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 = .from(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 = .from(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 = .from(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 fn indentedFormat(
|
|
self: *const Module,
|
|
w: *std.Io.Writer,
|
|
depth: usize,
|
|
indent: u8,
|
|
constant_pool: ConstantPool,
|
|
) std.Io.Writer.Error!void {
|
|
const module_name = self.moduleName(constant_pool) catch return error.WriteFailed;
|
|
try w.splatByteAll(' ', depth * indent);
|
|
_ = try w.write("name:\n");
|
|
try module_name.indentedFormat(w, depth, indent + 1, constant_pool);
|
|
|
|
try w.splatByteAll(' ', depth * indent);
|
|
try w.print("flags: {f}\n", .{ self.module_flags });
|
|
|
|
const module_version = self.moduleVersion(constant_pool) catch return error.WriteFailed;
|
|
if (module_version) |m| {
|
|
try w.splatByteAll(' ', depth * indent);
|
|
_ = try w.write("version:\n");
|
|
try m.indentedFormat(w, depth, indent + 1, constant_pool);
|
|
}
|
|
|
|
try w.splatByteAll(' ', depth * indent);
|
|
_ = try w.write("requires:\n");
|
|
var requires_indent = indent;
|
|
for (self.requires, 0..) |requires, i| {
|
|
requires_indent += 1;
|
|
defer requires_indent -= 1;
|
|
|
|
try w.splatByteAll(' ', depth * requires_indent);
|
|
try w.print("{d}:\n", .{ i });
|
|
try requires.indentedFormat(w, depth, requires_indent + 1, constant_pool);
|
|
}
|
|
|
|
try w.splatByteAll(' ', depth * indent);
|
|
_ = try w.write("exports:\n");
|
|
var exports_indent = indent;
|
|
for (self.exports, 0..) |exports, i| {
|
|
exports_indent += 1;
|
|
defer exports_indent -= 1;
|
|
|
|
try w.splatByteAll(' ', depth * exports_indent);
|
|
try w.print("{d}:\n", .{ i });
|
|
try exports.indentedFormat(w, depth, exports_indent + 1, constant_pool);
|
|
}
|
|
|
|
try w.splatByteAll(' ', depth * indent);
|
|
_ = try w.write("opens:\n");
|
|
var opens_indent = indent;
|
|
for (self.opens, 0..) |opens, i| {
|
|
opens_indent += 1;
|
|
defer opens_indent -= 1;
|
|
|
|
try w.splatByteAll(' ', depth * opens_indent);
|
|
try w.print("{d}:\n", .{ i });
|
|
try opens.indentedFormat(w, depth, opens_indent + 1, constant_pool);
|
|
}
|
|
|
|
try w.splatByteAll(' ', depth * indent);
|
|
_ = try w.write("uses:\n");
|
|
var uses_indent = indent;
|
|
for (self.uses_indeces, 0..) |uses_index, i| {
|
|
uses_indent += 1;
|
|
defer uses_indent -= 1;
|
|
|
|
const info = constant_pool.getTag(uses_index, .class) catch return error.WriteFailed;
|
|
|
|
try w.splatByteAll(' ', depth * uses_indent);
|
|
try w.print("{d}:\n", .{ i });
|
|
try info.indentedFormat(w, depth, uses_indent + 1, constant_pool);
|
|
}
|
|
|
|
try w.splatByteAll(' ', depth * indent);
|
|
_ = try w.write("provides:\n");
|
|
var provides_indent = indent;
|
|
for (self.provides, 0..) |provides, i| {
|
|
provides_indent += 1;
|
|
defer provides_indent -= 1;
|
|
|
|
try w.splatByteAll(' ', depth * provides_indent);
|
|
try w.print("{d}:\n", .{ i });
|
|
try provides.indentedFormat(w, depth, provides_indent + 1, constant_pool);
|
|
}
|
|
}
|
|
|
|
pub fn moduleName(self: *const Module, constant_pool: ConstantPool) ResolveError!ConstantPool.Info {
|
|
return constant_pool.getTag(self.module_name_index, .module);
|
|
}
|
|
|
|
pub fn moduleVersion(self: *const Module, constant_pool: ConstantPool) ResolveError!?ConstantPool.Info {
|
|
return constant_pool.getTagOptional(self.module_version_index, .utf8);
|
|
}
|
|
};
|
|
|
|
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: ConstantPool) ResolveError!ConstantPool.Info {
|
|
return constant_pool.getTag(self.main_class_index, .class);
|
|
}
|
|
};
|
|
|
|
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: ConstantPool) ResolveError!ConstantPool.Info {
|
|
return constant_pool.getTag(self.host_class_index, .class);
|
|
}
|
|
};
|
|
|
|
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: ConstantPool, 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: ConstantPool,
|
|
) 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: ConstantPool) ResolveError!ConstantPool.Info {
|
|
return constant_pool.getTag(self.name_index, .utf8);
|
|
}
|
|
|
|
pub fn descriptor(self: *const RecordComponentInfo, constant_pool: ConstantPool) ResolveError!ConstantPool.Info {
|
|
return constant_pool.getTag(self.descriptor_index, .utf8);
|
|
}
|
|
};
|
|
|
|
pub fn parse(input: *std.Io.Reader, constant_pool: ConstantPool, 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);
|
|
}
|
|
};
|