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