Compare commits
31 commits
feature/in
...
master
| Author | SHA1 | Date | |
|---|---|---|---|
| bc8d525a3e | |||
| 10c8c9b98f | |||
| 39fcd51a7c | |||
| 5ff7a358f9 | |||
| 76c436714f | |||
| a47405e903 | |||
| 89e548c8cc | |||
| f12bcd2911 | |||
| 3a5fd90d14 | |||
| a451327a6a | |||
| 114b9b099c | |||
| 0cf25ebaf4 | |||
| 0cc72ac2d9 | |||
| cb43efcbb1 | |||
| 146d90ccec | |||
| 9135e95dbd | |||
| 04cf7663af | |||
| a8c87dc421 | |||
| b8c63f726e | |||
| 5c816759bb | |||
| 41aad5e7b8 | |||
| 6971dce705 | |||
| 0fbdea320c | |||
| eefe96292e | |||
| 21644ef7f0 | |||
| 7cc907dc19 | |||
| f8b1f968e0 | |||
| 9af766e495 | |||
| 75d023cfe1 | |||
| 07d43f2fe7 | |||
| a18ae9c265 |
29 changed files with 3769 additions and 1524 deletions
|
|
@ -19,6 +19,8 @@
|
|||
zls
|
||||
javaPackages.compiler.openjdk25
|
||||
jdt-language-server
|
||||
kotlin
|
||||
kotlin-language-server
|
||||
];
|
||||
|
||||
buildInputs = with pkgs; [];
|
||||
|
|
|
|||
596
src/Class.zig
596
src/Class.zig
|
|
@ -4,14 +4,13 @@ const EnumFlags = @import("EnumFlags.zig").EnumFlags;
|
|||
|
||||
pub const FieldInfo = @import("Class/FieldInfo.zig");
|
||||
pub const MethodInfo = @import("Class/MethodInfo.zig");
|
||||
pub const AttributeInfo = @import("Class/AttributeInfo.zig");
|
||||
|
||||
allocator: std.mem.Allocator,
|
||||
pub const AttributeInfo = @import("Class/AttributeInfo.zig").AttributeInfo;
|
||||
pub const ConstantPool = @import("Class/ConstantPool.zig");
|
||||
|
||||
magic: u32,
|
||||
minor_version: u16,
|
||||
major_version: u16,
|
||||
constant_pool: []?ConstantPoolInfo,
|
||||
constant_pool: ConstantPool,
|
||||
access_flags: ClassAccessFlags,
|
||||
this_class: u16,
|
||||
super_class: u16,
|
||||
|
|
@ -22,7 +21,7 @@ attributes: []AttributeInfo,
|
|||
|
||||
const Self = @This();
|
||||
|
||||
pub const ClassFlags = enum(u16) {
|
||||
pub const ClassAccessFlags = EnumFlags(enum(u16) {
|
||||
public = 0x0001,
|
||||
final = 0x0010,
|
||||
super = 0x0020,
|
||||
|
|
@ -31,9 +30,8 @@ pub const ClassFlags = enum(u16) {
|
|||
synthetic = 0x1000,
|
||||
annotation = 0x2000,
|
||||
@"enum" = 0x4000,
|
||||
};
|
||||
|
||||
pub const ClassAccessFlags = EnumFlags(ClassFlags);
|
||||
module = 0x8000,
|
||||
});
|
||||
|
||||
pub const ParseError = std.Io.Reader.Error || std.mem.Allocator.Error || error {
|
||||
InvalidMagicNumber,
|
||||
|
|
@ -45,7 +43,7 @@ pub const ResolveError = error {
|
|||
InvalidConstantType,
|
||||
};
|
||||
|
||||
pub fn parse(input: *std.Io.Reader, allocator: std.mem.Allocator) ParseError!Self {
|
||||
pub fn parse(input: *std.Io.Reader, allocator: std.mem.Allocator) (ParseError || ResolveError)!Self {
|
||||
const magic = try input.takeInt(u32, .big);
|
||||
if (magic != 0xCAFEBABE) {
|
||||
return ParseError.InvalidMagicNumber;
|
||||
|
|
@ -54,15 +52,10 @@ pub fn parse(input: *std.Io.Reader, allocator: std.mem.Allocator) ParseError!Sel
|
|||
const minor_version = try input.takeInt(u16, .big);
|
||||
const major_version = try input.takeInt(u16, .big);
|
||||
|
||||
const constant_pool = try parseConstantPool(input, allocator);
|
||||
errdefer {
|
||||
for (constant_pool) |*cp_info| {
|
||||
if (cp_info.*) |*c| c.deinit(allocator);
|
||||
}
|
||||
allocator.free(constant_pool);
|
||||
}
|
||||
var constant_pool: ConstantPool = try .parse(input, allocator);
|
||||
errdefer constant_pool.deinit(allocator);
|
||||
|
||||
const access_flags: ClassAccessFlags = .{ .mask = try input.takeInt(u16, .big) };
|
||||
const access_flags: ClassAccessFlags = .from(try input.takeInt(u16, .big));
|
||||
|
||||
const this_class = try input.takeInt(u16, .big);
|
||||
const super_class = try input.takeInt(u16, .big);
|
||||
|
|
@ -70,7 +63,7 @@ pub fn parse(input: *std.Io.Reader, allocator: std.mem.Allocator) ParseError!Sel
|
|||
const interfaces = try parseInterfaces(input, allocator);
|
||||
errdefer allocator.free(interfaces);
|
||||
|
||||
const fields = try parseFields(input, allocator);
|
||||
const fields = try parseFields(input, constant_pool, allocator);
|
||||
errdefer {
|
||||
for (fields) |*field| {
|
||||
field.deinit(allocator);
|
||||
|
|
@ -78,7 +71,7 @@ pub fn parse(input: *std.Io.Reader, allocator: std.mem.Allocator) ParseError!Sel
|
|||
allocator.free(fields);
|
||||
}
|
||||
|
||||
const methods = try parseMethods(input, allocator);
|
||||
const methods = try parseMethods(input, constant_pool, allocator);
|
||||
errdefer {
|
||||
for (methods) |*method| {
|
||||
method.deinit(allocator);
|
||||
|
|
@ -86,7 +79,7 @@ pub fn parse(input: *std.Io.Reader, allocator: std.mem.Allocator) ParseError!Sel
|
|||
allocator.free(methods);
|
||||
}
|
||||
|
||||
const attributes = try parseAttributes(input, allocator);
|
||||
const attributes = try parseAttributes(input, constant_pool, allocator);
|
||||
errdefer {
|
||||
for (attributes) |*attribute| {
|
||||
attribute.deinit(allocator);
|
||||
|
|
@ -95,7 +88,6 @@ pub fn parse(input: *std.Io.Reader, allocator: std.mem.Allocator) ParseError!Sel
|
|||
}
|
||||
|
||||
return .{
|
||||
.allocator = allocator,
|
||||
.magic = magic,
|
||||
.minor_version = minor_version,
|
||||
.major_version = major_version,
|
||||
|
|
@ -110,30 +102,6 @@ pub fn parse(input: *std.Io.Reader, allocator: std.mem.Allocator) ParseError!Sel
|
|||
};
|
||||
}
|
||||
|
||||
fn parseConstantPool(input: *std.Io.Reader, allocator: std.mem.Allocator) ParseError![]?ConstantPoolInfo {
|
||||
const constant_pool_size = try input.takeInt(u16, .big);
|
||||
const constant_pool = try allocator.alloc(?ConstantPoolInfo, constant_pool_size - 1);
|
||||
errdefer allocator.free(constant_pool);
|
||||
|
||||
var i: usize = 0;
|
||||
while (i < constant_pool_size - 1) {
|
||||
defer i += 1;
|
||||
|
||||
const cp_info = try ConstantPoolInfo.parse(input, allocator);
|
||||
constant_pool[i] = cp_info;
|
||||
|
||||
switch (cp_info) {
|
||||
.long, .double => {
|
||||
i += 1;
|
||||
constant_pool[i] = null;
|
||||
},
|
||||
else => {},
|
||||
}
|
||||
}
|
||||
|
||||
return constant_pool;
|
||||
}
|
||||
|
||||
fn parseInterfaces(input: *std.Io.Reader, allocator: std.mem.Allocator) ParseError![]u16 {
|
||||
const interfaces_count = try input.takeInt(u16, .big);
|
||||
const interfaces = try allocator.alloc(u16, interfaces_count);
|
||||
|
|
@ -146,80 +114,73 @@ fn parseInterfaces(input: *std.Io.Reader, allocator: std.mem.Allocator) ParseErr
|
|||
return interfaces;
|
||||
}
|
||||
|
||||
fn parseFields(input: *std.Io.Reader, allocator: std.mem.Allocator) ParseError![]FieldInfo {
|
||||
fn parseFields(input: *std.Io.Reader, constant_pool: ConstantPool, allocator: std.mem.Allocator) (ParseError || ResolveError)![]FieldInfo {
|
||||
const fields_count = try input.takeInt(u16, .big);
|
||||
const fields = try allocator.alloc(FieldInfo, fields_count);
|
||||
errdefer allocator.free(fields);
|
||||
|
||||
for (0..fields_count) |i| {
|
||||
fields[i] = try FieldInfo.parse(input, allocator);
|
||||
fields[i] = try FieldInfo.parse(input, constant_pool, allocator);
|
||||
}
|
||||
|
||||
return fields;
|
||||
}
|
||||
|
||||
fn parseMethods(input: *std.Io.Reader, allocator: std.mem.Allocator) ParseError![]MethodInfo {
|
||||
fn parseMethods(input: *std.Io.Reader, constant_pool: ConstantPool, allocator: std.mem.Allocator) (ParseError || ResolveError)![]MethodInfo {
|
||||
const methods_count = try input.takeInt(u16, .big);
|
||||
const methods = try allocator.alloc(MethodInfo, methods_count);
|
||||
errdefer allocator.free(methods);
|
||||
|
||||
for (0..methods_count) |i| {
|
||||
methods[i] = try MethodInfo.parse(input, allocator);
|
||||
methods[i] = try .parse(input, constant_pool, allocator);
|
||||
}
|
||||
|
||||
return methods;
|
||||
}
|
||||
|
||||
pub fn parseAttributes(input: *std.Io.Reader, allocator: std.mem.Allocator) ParseError![]AttributeInfo {
|
||||
pub fn parseAttributes(input: *std.Io.Reader, constant_pool: ConstantPool, allocator: std.mem.Allocator) (ParseError || ResolveError)![]AttributeInfo {
|
||||
const attributes_count = try input.takeInt(u16, .big);
|
||||
const attributes = try allocator.alloc(AttributeInfo, attributes_count);
|
||||
errdefer allocator.free(attributes);
|
||||
|
||||
for (0..attributes_count) |i| {
|
||||
attributes[i] = try AttributeInfo.parse(input, allocator);
|
||||
attributes[i] = try AttributeInfo.parse(input, constant_pool, allocator);
|
||||
}
|
||||
|
||||
return attributes;
|
||||
}
|
||||
|
||||
pub fn deinit(self: *Self) void {
|
||||
self.freeConstantPool();
|
||||
self.freeInterfaces();
|
||||
self.freeFields();
|
||||
self.freeMethods();
|
||||
self.freeAttributes();
|
||||
pub fn deinit(self: *Self, allocator: std.mem.Allocator) void {
|
||||
self.constant_pool.deinit(allocator);
|
||||
self.freeInterfaces(allocator);
|
||||
self.freeFields(allocator);
|
||||
self.freeMethods(allocator);
|
||||
self.freeAttributes(allocator);
|
||||
}
|
||||
|
||||
fn freeConstantPool(self: *Self) void {
|
||||
for (self.constant_pool) |*cp_info| {
|
||||
if (cp_info.*) |*c| c.deinit(self.allocator);
|
||||
}
|
||||
self.allocator.free(self.constant_pool);
|
||||
fn freeInterfaces(self: *Self, allocator: std.mem.Allocator) void {
|
||||
allocator.free(self.interfaces);
|
||||
}
|
||||
|
||||
fn freeInterfaces(self: *Self) void {
|
||||
self.allocator.free(self.interfaces);
|
||||
}
|
||||
|
||||
fn freeFields(self: *Self) void {
|
||||
fn freeFields(self: *Self, allocator: std.mem.Allocator) void {
|
||||
for (self.fields) |*field_info| {
|
||||
field_info.deinit(self.allocator);
|
||||
field_info.deinit(allocator);
|
||||
}
|
||||
self.allocator.free(self.fields);
|
||||
allocator.free(self.fields);
|
||||
}
|
||||
|
||||
fn freeMethods(self: *Self) void {
|
||||
fn freeMethods(self: *Self, allocator: std.mem.Allocator) void {
|
||||
for (self.methods) |*method_info| {
|
||||
method_info.deinit(self.allocator);
|
||||
method_info.deinit(allocator);
|
||||
}
|
||||
self.allocator.free(self.methods);
|
||||
allocator.free(self.methods);
|
||||
}
|
||||
|
||||
fn freeAttributes(self: *Self) void {
|
||||
fn freeAttributes(self: *Self, allocator: std.mem.Allocator) void {
|
||||
for (self.attributes) |*attr| {
|
||||
attr.deinit(self.allocator);
|
||||
attr.deinit(allocator);
|
||||
}
|
||||
self.allocator.free(self.attributes);
|
||||
allocator.free(self.attributes);
|
||||
}
|
||||
|
||||
pub fn jsonStringify(self: *const Self, jws: *std.json.Stringify) !void {
|
||||
|
|
@ -246,11 +207,11 @@ pub fn format(self: *const Self, w: *std.Io.Writer) std.Io.Writer.Error!void {
|
|||
|
||||
const this_class = self.thisClass() catch return error.WriteFailed;
|
||||
_ = try w.write("this class:\n");
|
||||
try this_class.format(w, depth, indent + 1, self.constant_pool);
|
||||
try this_class.indentedFormat(w, depth, indent + 1, self.constant_pool);
|
||||
|
||||
_ = try w.write("super class:\n");
|
||||
if (self.superClass() catch return error.WriteFailed) |super_class| {
|
||||
try super_class.format(w, depth, indent + 1, self.constant_pool);
|
||||
try super_class.indentedFormat(w, depth, indent + 1, self.constant_pool);
|
||||
}
|
||||
|
||||
_ = try w.write("interfaces:\n");
|
||||
|
|
@ -258,13 +219,11 @@ pub fn format(self: *const Self, w: *std.Io.Writer) std.Io.Writer.Error!void {
|
|||
indent += 1;
|
||||
defer indent -= 1;
|
||||
|
||||
if (interface >= self.constant_pool.len) return error.WriteFailed;
|
||||
const cp_info = self.constant_pool[interface - 1];
|
||||
if (cp_info == null or @as(ConstantPoolInfo.Tag, cp_info.?) != .class) return error.WriteFailed;
|
||||
const info = self.constant_pool.getTag(interface, .class) catch return error.WriteFailed;
|
||||
|
||||
try w.splatByteAll(' ', depth * indent);
|
||||
try w.print("{d}:\n", .{ i });
|
||||
try cp_info.?.format(w, depth, indent + 1, self.constant_pool);
|
||||
try info.indentedFormat(w, depth, indent + 1, self.constant_pool);
|
||||
}
|
||||
|
||||
_ = try w.write("fields:\n");
|
||||
|
|
@ -274,7 +233,7 @@ pub fn format(self: *const Self, w: *std.Io.Writer) std.Io.Writer.Error!void {
|
|||
|
||||
try w.splatByteAll(' ', depth * indent);
|
||||
try w.print("{d}:\n", .{ i });
|
||||
try field.format(w, depth, indent + 1, self.allocator, self.constant_pool);
|
||||
try field.indentedFormat(w, depth, indent + 1, self.constant_pool);
|
||||
}
|
||||
|
||||
_ = try w.write("methods:\n");
|
||||
|
|
@ -284,7 +243,7 @@ pub fn format(self: *const Self, w: *std.Io.Writer) std.Io.Writer.Error!void {
|
|||
|
||||
try w.splatByteAll(' ', depth * indent);
|
||||
try w.print("{d}:\n", .{ i });
|
||||
try method.format(w, depth, indent + 1, self.allocator, self.constant_pool);
|
||||
try method.indentedFormat(w, depth, indent + 1, self.constant_pool);
|
||||
}
|
||||
|
||||
_ = try w.write("attributes:\n");
|
||||
|
|
@ -294,476 +253,15 @@ pub fn format(self: *const Self, w: *std.Io.Writer) std.Io.Writer.Error!void {
|
|||
|
||||
try w.splatByteAll(' ', depth * indent);
|
||||
try w.print("{d}:\n", .{ i });
|
||||
try attribute.format(w, depth, indent + 1, self.allocator, self.constant_pool);
|
||||
try attribute.indentedFormat(w, depth, indent + 1, self.constant_pool);
|
||||
}
|
||||
}
|
||||
|
||||
pub fn thisClass(self: *const Self) ResolveError!ConstantPoolInfo {
|
||||
const this_class = self.this_class - 1;
|
||||
if (this_class >= self.constant_pool.len) return ResolveError.InvalidConstantPoolIndex;
|
||||
const cp_info = self.constant_pool[this_class];
|
||||
if (cp_info == null or @as(ConstantPoolInfo.Tag, cp_info.?) != .class) return ResolveError.InvalidConstantType;
|
||||
return cp_info.?;
|
||||
pub fn thisClass(self: *const Self) ResolveError!ConstantPool.Info {
|
||||
return self.constant_pool.getTag(self.this_class, .class);
|
||||
}
|
||||
|
||||
pub fn superClass(self: *const Self) ResolveError!?ConstantPoolInfo {
|
||||
if (self.super_class == 0) {
|
||||
const this_class = (try self.thisClass()).class;
|
||||
const this_class_name = (try this_class.name(self.constant_pool)).utf8;
|
||||
if (!std.mem.eql(u8, this_class_name.bytes, "java/lang/Object")) return ResolveError.InvalidConstantType;
|
||||
return null;
|
||||
} else {
|
||||
const super_class = self.super_class - 1;
|
||||
if (super_class >= self.constant_pool.len) return ResolveError.InvalidConstantPoolIndex;
|
||||
const cp_info = self.constant_pool[super_class];
|
||||
if (cp_info == null or @as(ConstantPoolInfo.Tag, cp_info.?) != .class) return ResolveError.InvalidConstantType;
|
||||
|
||||
if (self.access_flags.contains(.interface)) {
|
||||
const super_class_name = (try cp_info.?.class.name(self.constant_pool)).utf8;
|
||||
if (!std.mem.eql(u8, super_class_name.bytes, "java/lang/Object")) return ResolveError.InvalidConstantType;
|
||||
} else {
|
||||
// TODO: Assert that superclass does not have ACC_FINAL flag set.
|
||||
}
|
||||
return cp_info.?;
|
||||
}
|
||||
pub fn superClass(self: *const Self) ResolveError!?ConstantPool.Info {
|
||||
return self.constant_pool.getTagOptional(self.super_class, .class);
|
||||
}
|
||||
|
||||
pub const ConstantPoolInfo = union(ConstantPoolInfo.Tag) {
|
||||
class: Class,
|
||||
field_ref: FieldRef,
|
||||
method_ref: MethodRef,
|
||||
interface_method_ref: InterfaceMethodRef,
|
||||
string: String,
|
||||
integer: Integer,
|
||||
float: Float,
|
||||
long: Long,
|
||||
double: Double,
|
||||
name_and_type: NameAndType,
|
||||
utf8: Utf8,
|
||||
method_handle: MethodHandle,
|
||||
method_type: MethodType,
|
||||
invoke_dynamic: InvokeDynamic,
|
||||
|
||||
pub const Tag = enum(u8) {
|
||||
class = 7,
|
||||
field_ref = 9,
|
||||
method_ref = 10,
|
||||
interface_method_ref = 11,
|
||||
string = 8,
|
||||
integer = 3,
|
||||
float = 4,
|
||||
long = 5,
|
||||
double = 6,
|
||||
name_and_type = 12,
|
||||
utf8 = 1,
|
||||
method_handle = 15,
|
||||
method_type = 16,
|
||||
invoke_dynamic = 18,
|
||||
};
|
||||
|
||||
pub const Class = struct {
|
||||
name_index: u16,
|
||||
|
||||
pub fn name(self: *const Class, constant_pool: []const ?ConstantPoolInfo) ResolveError!ConstantPoolInfo {
|
||||
const name_index = self.name_index - 1;
|
||||
if (name_index >= constant_pool.len) return ResolveError.InvalidConstantPoolIndex;
|
||||
const cp_info = constant_pool[name_index];
|
||||
if (cp_info == null or @as(Tag, cp_info.?) != .utf8) return ResolveError.InvalidConstantType;
|
||||
return cp_info.?;
|
||||
}
|
||||
};
|
||||
|
||||
pub const FieldRef = struct {
|
||||
class_index: u16,
|
||||
name_and_type_index: u16,
|
||||
|
||||
pub fn class(self: *const FieldRef, constant_pool: []const ?ConstantPoolInfo) ResolveError!ConstantPoolInfo {
|
||||
const class_index = self.class_index - 1;
|
||||
if (class_index >= constant_pool.len) return ResolveError.InvalidConstantPoolIndex;
|
||||
const cp_info = constant_pool[class_index];
|
||||
if (cp_info == null or @as(Tag, cp_info.?) != .class) return ResolveError.InvalidConstantType;
|
||||
return cp_info.?;
|
||||
}
|
||||
|
||||
pub fn nameAndType(self: *const FieldRef, constant_pool: []const ?ConstantPoolInfo) ResolveError!ConstantPoolInfo {
|
||||
const name_and_type_index = self.name_and_type_index - 1;
|
||||
if (name_and_type_index >= constant_pool.len) return ResolveError.InvalidConstantPoolIndex;
|
||||
const cp_info = constant_pool[name_and_type_index];
|
||||
if (cp_info == null or @as(Tag, cp_info.?) != .name_and_type) return ResolveError.InvalidConstantType;
|
||||
return cp_info.?;
|
||||
}
|
||||
};
|
||||
|
||||
pub const MethodRef = struct {
|
||||
class_index: u16,
|
||||
name_and_type_index: u16,
|
||||
|
||||
pub fn class(self: *const MethodRef, constant_pool: []const ?ConstantPoolInfo) ResolveError!ConstantPoolInfo {
|
||||
const class_index = self.class_index - 1;
|
||||
if (class_index >= constant_pool.len) return ResolveError.InvalidConstantPoolIndex;
|
||||
const cp_info = constant_pool[class_index];
|
||||
if (cp_info == null or @as(Tag, cp_info.?) != .class) return ResolveError.InvalidConstantType;
|
||||
return cp_info.?;
|
||||
}
|
||||
|
||||
pub fn nameAndType(self: *const MethodRef, constant_pool: []const ?ConstantPoolInfo) ResolveError!ConstantPoolInfo {
|
||||
const name_and_type_index = self.name_and_type_index - 1;
|
||||
if (name_and_type_index >= constant_pool.len) return ResolveError.InvalidConstantPoolIndex;
|
||||
const cp_info = constant_pool[name_and_type_index];
|
||||
if (cp_info == null or @as(Tag, cp_info.?) != .name_and_type) return ResolveError.InvalidConstantType;
|
||||
return cp_info.?;
|
||||
}
|
||||
};
|
||||
|
||||
pub const InterfaceMethodRef = struct {
|
||||
class_index: u16,
|
||||
name_and_type_index: u16,
|
||||
|
||||
pub fn class(self: *const InterfaceMethodRef, constant_pool: []const ?ConstantPoolInfo) ResolveError!ConstantPoolInfo {
|
||||
const class_index = self.class_index - 1;
|
||||
if (class_index >= constant_pool.len) return ResolveError.InvalidConstantPoolIndex;
|
||||
const cp_info = constant_pool[class_index];
|
||||
if (cp_info == null or @as(Tag, cp_info.?) != .class) return ResolveError.InvalidConstantType;
|
||||
return cp_info.?;
|
||||
}
|
||||
|
||||
pub fn nameAndType(self: *const InterfaceMethodRef, constant_pool: []const ?ConstantPoolInfo) ResolveError!ConstantPoolInfo {
|
||||
const name_and_type_index = self.name_and_type_index - 1;
|
||||
if (name_and_type_index >= constant_pool.len) return ResolveError.InvalidConstantPoolIndex;
|
||||
const cp_info = constant_pool[name_and_type_index];
|
||||
if (cp_info == null or @as(Tag, cp_info.?) != .name_and_type) return ResolveError.InvalidConstantType;
|
||||
return cp_info.?;
|
||||
}
|
||||
};
|
||||
|
||||
pub const String = struct {
|
||||
string_index: u16,
|
||||
|
||||
pub fn string(self: *const String, constant_pool: []const ?ConstantPoolInfo) ResolveError!ConstantPoolInfo {
|
||||
const string_index = self.string_index - 1;
|
||||
if (string_index >= constant_pool.len) return ResolveError.InvalidConstantPoolIndex;
|
||||
const cp_info = constant_pool[string_index];
|
||||
if (cp_info == null or @as(Tag, cp_info.?) != .utf8) return ResolveError.InvalidConstantType;
|
||||
return cp_info.?;
|
||||
}
|
||||
};
|
||||
|
||||
pub const Integer = struct {
|
||||
bytes: u32,
|
||||
};
|
||||
|
||||
pub const Float = struct {
|
||||
bytes: u32,
|
||||
};
|
||||
|
||||
pub const Long = struct {
|
||||
high_bytes: u32,
|
||||
low_bytes: u32,
|
||||
};
|
||||
|
||||
pub const Double = struct {
|
||||
high_bytes: u32,
|
||||
low_bytes: u32,
|
||||
};
|
||||
|
||||
pub const NameAndType = struct {
|
||||
name_index: u16,
|
||||
descriptor_index: u16,
|
||||
|
||||
pub fn name(self: *const NameAndType, constant_pool: []const ?ConstantPoolInfo) ResolveError!ConstantPoolInfo {
|
||||
const name_index = self.name_index - 1;
|
||||
if (name_index >= constant_pool.len) return ResolveError.InvalidConstantPoolIndex;
|
||||
const cp_info = constant_pool[name_index];
|
||||
if (cp_info == null or @as(Tag, cp_info.?) != .utf8) return ResolveError.InvalidConstantType;
|
||||
return cp_info.?;
|
||||
}
|
||||
|
||||
pub fn descriptor(self: *const NameAndType, constant_pool: []const ?ConstantPoolInfo) ResolveError!ConstantPoolInfo {
|
||||
const descriptor_index = self.descriptor_index - 1;
|
||||
if (descriptor_index >= constant_pool.len) return ResolveError.InvalidConstantPoolIndex;
|
||||
const cp_info = constant_pool[descriptor_index];
|
||||
if (cp_info == null or @as(Tag, cp_info.?) != .utf8) return ResolveError.InvalidConstantType;
|
||||
return cp_info.?;
|
||||
}
|
||||
};
|
||||
|
||||
pub const Utf8 = struct {
|
||||
bytes: []const u8,
|
||||
};
|
||||
|
||||
pub const MethodHandle = struct {
|
||||
reference_kind: Kind,
|
||||
reference_index: u16,
|
||||
|
||||
pub const Kind = enum(u8) {
|
||||
get_field = 1,
|
||||
get_static = 2,
|
||||
put_field = 3,
|
||||
put_static = 4,
|
||||
invoke_virtual = 5,
|
||||
invoke_static = 6,
|
||||
invoke_special = 7,
|
||||
new_invoke_special = 8,
|
||||
invoke_interface = 9,
|
||||
};
|
||||
|
||||
pub fn reference(self: *const MethodHandle, constant_pool: []const ?ConstantPoolInfo) ResolveError!ConstantPoolInfo {
|
||||
const reference_index = self.reference_index - 1;
|
||||
if (reference_index >= constant_pool.len) return ResolveError.InvalidConstantPoolIndex;
|
||||
const cp_info = constant_pool[reference_index];
|
||||
return switch (self.reference_kind) {
|
||||
.get_field, .get_static, .put_field, .put_static => blk: {
|
||||
if (cp_info == null or @as(Tag, cp_info.?) != .field_ref) break :blk ResolveError.InvalidConstantType;
|
||||
break :blk cp_info.?;
|
||||
},
|
||||
.invoke_virtual, .invoke_static, .invoke_special, .new_invoke_special => blk: {
|
||||
if (cp_info == null or @as(Tag, cp_info.?) != .method_ref) break :blk ResolveError.InvalidConstantType;
|
||||
break :blk cp_info.?;
|
||||
},
|
||||
.invoke_interface => blk: {
|
||||
if (cp_info == null or @as(Tag, cp_info.?) != .interface_method_ref) break :blk ResolveError.InvalidConstantType;
|
||||
break :blk cp_info.?;
|
||||
},
|
||||
};
|
||||
}
|
||||
};
|
||||
|
||||
pub const MethodType = struct {
|
||||
descriptor_index: u16,
|
||||
|
||||
pub fn descriptor(self: *const MethodType, constant_pool: []const ?ConstantPoolInfo) ResolveError!ConstantPoolInfo {
|
||||
const descriptor_index = self.descriptor_index - 1;
|
||||
if (descriptor_index >= constant_pool.len) return ResolveError.InvalidConstantPoolIndex;
|
||||
const cp_info = constant_pool[descriptor_index];
|
||||
if (cp_info == null or @as(Tag, cp_info.?) != .utf8) return ResolveError.InvalidConstantType;
|
||||
return cp_info.?;
|
||||
}
|
||||
};
|
||||
|
||||
pub const InvokeDynamic = struct {
|
||||
bootstrap_method_attr_index: u16,
|
||||
name_and_type_index: u16,
|
||||
|
||||
pub fn nameAndType(self: *const InvokeDynamic, constant_pool: []const ?ConstantPoolInfo) ResolveError!ConstantPoolInfo {
|
||||
const name_and_type_index = self.name_and_type_index - 1;
|
||||
if (name_and_type_index >= constant_pool.len) return ResolveError.InvalidConstantPoolIndex;
|
||||
const cp_info = constant_pool[name_and_type_index];
|
||||
if (cp_info == null or @as(Tag, cp_info.?) != .name_and_type) return ResolveError.InvalidConstantType;
|
||||
return cp_info.?;
|
||||
}
|
||||
};
|
||||
|
||||
pub fn parse(input: *std.Io.Reader, allocator: std.mem.Allocator) ParseError!ConstantPoolInfo {
|
||||
const tag_byte = try input.takeByte();
|
||||
const tag = std.enums.fromInt(Tag, tag_byte) orelse return ParseError.InvalidTag;
|
||||
|
||||
return switch (tag) {
|
||||
.class => .{
|
||||
.class = .{
|
||||
.name_index = try input.takeInt(u16, .big),
|
||||
},
|
||||
},
|
||||
.field_ref => .{
|
||||
.field_ref = .{
|
||||
.class_index = try input.takeInt(u16, .big),
|
||||
.name_and_type_index = try input.takeInt(u16, .big),
|
||||
},
|
||||
},
|
||||
.method_ref => .{
|
||||
.method_ref = .{
|
||||
.class_index = try input.takeInt(u16, .big),
|
||||
.name_and_type_index = try input.takeInt(u16, .big),
|
||||
},
|
||||
},
|
||||
.interface_method_ref => .{
|
||||
.interface_method_ref = .{
|
||||
.class_index = try input.takeInt(u16, .big),
|
||||
.name_and_type_index = try input.takeInt(u16, .big),
|
||||
},
|
||||
},
|
||||
.string => .{
|
||||
.string = .{
|
||||
.string_index = try input.takeInt(u16, .big),
|
||||
},
|
||||
},
|
||||
.integer => .{
|
||||
.integer = .{
|
||||
.bytes = try input.takeInt(u32, .big),
|
||||
},
|
||||
},
|
||||
.float => .{
|
||||
.integer = .{
|
||||
.bytes = try input.takeInt(u32, .big),
|
||||
},
|
||||
},
|
||||
.long => .{
|
||||
.long = .{
|
||||
.high_bytes = try input.takeInt(u32, .big),
|
||||
.low_bytes = try input.takeInt(u32, .big),
|
||||
},
|
||||
},
|
||||
.double => .{
|
||||
.double = .{
|
||||
.high_bytes = try input.takeInt(u32, .big),
|
||||
.low_bytes = try input.takeInt(u32, .big),
|
||||
},
|
||||
},
|
||||
.name_and_type => .{
|
||||
.name_and_type = .{
|
||||
.name_index = try input.takeInt(u16, .big),
|
||||
.descriptor_index = try input.takeInt(u16, .big),
|
||||
},
|
||||
},
|
||||
.utf8 => blk: {
|
||||
const length = try input.takeInt(u16, .big);
|
||||
const bytes = try input.readAlloc(allocator, length);
|
||||
|
||||
break :blk .{
|
||||
.utf8 = .{
|
||||
.bytes = bytes,
|
||||
},
|
||||
};
|
||||
},
|
||||
.method_handle => blk: {
|
||||
const kind_byte = try input.takeByte();
|
||||
const kind = std.enums.fromInt(MethodHandle.Kind, kind_byte) orelse return ParseError.InvalidTag;
|
||||
|
||||
break :blk .{
|
||||
.method_handle = .{
|
||||
.reference_kind = kind,
|
||||
.reference_index = try input.takeInt(u16, .big),
|
||||
},
|
||||
};
|
||||
},
|
||||
.method_type => .{
|
||||
.method_type = .{
|
||||
.descriptor_index = try input.takeInt(u16, .big),
|
||||
},
|
||||
},
|
||||
.invoke_dynamic => .{
|
||||
.invoke_dynamic = .{
|
||||
.bootstrap_method_attr_index = try input.takeInt(u16, .big),
|
||||
.name_and_type_index = try input.takeInt(u16, .big),
|
||||
},
|
||||
},
|
||||
};
|
||||
}
|
||||
|
||||
pub fn deinit(self: *ConstantPoolInfo, allocator: std.mem.Allocator) void {
|
||||
switch (self.*) {
|
||||
.utf8 => |info| allocator.free(info.bytes),
|
||||
else => {},
|
||||
}
|
||||
}
|
||||
|
||||
pub fn format(self: *const ConstantPoolInfo, w: *std.Io.Writer, depth: usize, indent: u8, constant_pool: []const ?ConstantPoolInfo) std.Io.Writer.Error!void {
|
||||
try w.splatByteAll(' ', depth * indent);
|
||||
try w.print("constant_value_type: {s}\n", .{ @tagName(self.*) });
|
||||
|
||||
switch (self.*) {
|
||||
.class => |class| {
|
||||
try w.splatByteAll(' ', depth * indent);
|
||||
_ = try w.write("name:\n");
|
||||
const class_name = class.name(constant_pool) catch return error.WriteFailed;
|
||||
try class_name.format(w, depth, indent + 1, constant_pool);
|
||||
},
|
||||
.field_ref => |field_ref| {
|
||||
try w.splatByteAll(' ', depth * indent);
|
||||
_ = try w.write("class:\n");
|
||||
const class = field_ref.class(constant_pool) catch return error.WriteFailed;
|
||||
try class.format(w, depth, indent + 1, constant_pool);
|
||||
|
||||
try w.splatByteAll(' ', depth * indent);
|
||||
_ = try w.write("name_and_type:\n");
|
||||
const name_and_type = field_ref.nameAndType(constant_pool) catch return error.WriteFailed;
|
||||
try name_and_type.format(w, depth, indent + 1, constant_pool);
|
||||
},
|
||||
.method_ref => |method_ref| {
|
||||
try w.splatByteAll(' ', depth * indent);
|
||||
_ = try w.write("class:\n");
|
||||
const class = method_ref.class(constant_pool) catch return error.WriteFailed;
|
||||
try class.format(w, depth, indent + 1, constant_pool);
|
||||
|
||||
try w.splatByteAll(' ', depth * indent);
|
||||
_ = try w.write("name_and_type:\n");
|
||||
const name_and_type = method_ref.nameAndType(constant_pool) catch return error.WriteFailed;
|
||||
try name_and_type.format(w, depth, indent + 1, constant_pool);
|
||||
},
|
||||
.interface_method_ref => |interface_method_ref| {
|
||||
try w.splatByteAll(' ', depth * indent);
|
||||
_ = try w.write("class:\n");
|
||||
const class = interface_method_ref.class(constant_pool) catch return error.WriteFailed;
|
||||
try class.format(w, depth, indent + 1, constant_pool);
|
||||
|
||||
try w.splatByteAll(' ', depth * indent);
|
||||
_ = try w.write("name_and_type:\n");
|
||||
const name_and_type = interface_method_ref.nameAndType(constant_pool) catch return error.WriteFailed;
|
||||
try name_and_type.format(w, depth, indent + 1, constant_pool);
|
||||
},
|
||||
.string => |string| {
|
||||
const s = string.string(constant_pool) catch return error.WriteFailed;
|
||||
try s.format(w, depth, indent + 1, constant_pool);
|
||||
},
|
||||
.integer => |integer| {
|
||||
try w.splatByteAll(' ', depth * indent);
|
||||
try w.print("integer: {d}\n", .{ integer.bytes });
|
||||
},
|
||||
.float => |float| {
|
||||
const f: f32 = @bitCast(float.bytes);
|
||||
|
||||
try w.splatByteAll(' ', depth * indent);
|
||||
try w.print("float: {d}\n", .{ f });
|
||||
},
|
||||
.long => |long| {
|
||||
const l: u64 = (@as(u64, long.high_bytes) << 32) | long.low_bytes;
|
||||
|
||||
try w.splatByteAll(' ', depth * indent);
|
||||
try w.print("long: {d}\n", .{ l });
|
||||
},
|
||||
.double => |double| {
|
||||
const l: u64 = (@as(u64, double.high_bytes) << 32) | double.low_bytes;
|
||||
const d: f64 = @bitCast(l);
|
||||
|
||||
try w.splatByteAll(' ', depth * indent);
|
||||
try w.print("double: {d}\n", .{ d });
|
||||
},
|
||||
.name_and_type => |name_and_type| {
|
||||
try w.splatByteAll(' ', depth * indent);
|
||||
_ = try w.write("name:\n");
|
||||
const name = name_and_type.name(constant_pool) catch return error.WriteFailed;
|
||||
try name.format(w, depth, indent + 1, constant_pool);
|
||||
|
||||
try w.splatByteAll(' ', depth * indent);
|
||||
_ = try w.write("descriptor:\n");
|
||||
const descriptor = name_and_type.descriptor(constant_pool) catch return error.WriteFailed;
|
||||
try descriptor.format(w, depth, indent + 1, constant_pool);
|
||||
},
|
||||
.utf8 => |utf8| {
|
||||
try w.splatByteAll(' ', depth * indent);
|
||||
try w.print("bytes: \"{s}\"\n", .{ utf8.bytes });
|
||||
},
|
||||
.method_handle => |method_handle| {
|
||||
try w.splatByteAll(' ', depth * indent);
|
||||
try w.print("kind: {t}\n", .{ method_handle.reference_kind });
|
||||
|
||||
try w.splatByteAll(' ', depth * indent);
|
||||
_ = try w.write("reference:\n");
|
||||
const reference = method_handle.reference(constant_pool) catch return error.WriteFailed;
|
||||
try reference.format(w, depth, indent + 1, constant_pool);
|
||||
},
|
||||
.method_type => |method_type| {
|
||||
try w.splatByteAll(' ', depth * indent);
|
||||
_ = try w.write("descriptor:\n");
|
||||
const descriptor = method_type.descriptor(constant_pool) catch return error.WriteFailed;
|
||||
try descriptor.format(w, depth, indent + 1, constant_pool);
|
||||
},
|
||||
.invoke_dynamic => |invoke_dynamic| {
|
||||
try w.splatByteAll(' ', depth * indent);
|
||||
_ = try w.write("name_and_type:\n");
|
||||
const name_and_type = invoke_dynamic.nameAndType(constant_pool) catch return error.WriteFailed;
|
||||
try name_and_type.format(w, depth, indent + 1, constant_pool);
|
||||
},
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
|
|
|
|||
File diff suppressed because it is too large
Load diff
547
src/Class/ConstantPool.zig
Normal file
547
src/Class/ConstantPool.zig
Normal file
|
|
@ -0,0 +1,547 @@
|
|||
const std = @import("std");
|
||||
|
||||
const Class = @import("../Class.zig");
|
||||
const AttributeInfo = Class.AttributeInfo;
|
||||
const ParseError = Class.ParseError;
|
||||
const ResolveError = Class.ResolveError;
|
||||
|
||||
constant_pool: []?Info,
|
||||
|
||||
const Self = @This();
|
||||
|
||||
pub const Info = union(Info.Tag) {
|
||||
class: Info.Class,
|
||||
field_ref: FieldRef,
|
||||
method_ref: MethodRef,
|
||||
interface_method_ref: InterfaceMethodRef,
|
||||
string: String,
|
||||
integer: Integer,
|
||||
float: Float,
|
||||
long: Long,
|
||||
double: Double,
|
||||
name_and_type: NameAndType,
|
||||
utf8: Utf8,
|
||||
method_handle: MethodHandle,
|
||||
method_type: MethodType,
|
||||
dynamic: Dynamic,
|
||||
invoke_dynamic: InvokeDynamic,
|
||||
module: Module,
|
||||
package: Package,
|
||||
|
||||
pub const Tag = enum(u8) {
|
||||
class = 7,
|
||||
field_ref = 9,
|
||||
method_ref = 10,
|
||||
interface_method_ref = 11,
|
||||
string = 8,
|
||||
integer = 3,
|
||||
float = 4,
|
||||
long = 5,
|
||||
double = 6,
|
||||
name_and_type = 12,
|
||||
utf8 = 1,
|
||||
method_handle = 15,
|
||||
method_type = 16,
|
||||
dynamic = 17,
|
||||
invoke_dynamic = 18,
|
||||
module = 19,
|
||||
package = 20,
|
||||
|
||||
pub fn loadable(self: Tag) bool {
|
||||
return switch (self) {
|
||||
.integer, .float, .long, .double, .class, .string, .method_handle, .method_type, .dynamic => true,
|
||||
else => false,
|
||||
};
|
||||
}
|
||||
};
|
||||
|
||||
pub const Class = struct {
|
||||
name_index: u16,
|
||||
|
||||
pub fn name(self: *const Info.Class, constant_pool: Self) ResolveError!Info {
|
||||
return constant_pool.getTag(self.name_index, .utf8);
|
||||
}
|
||||
};
|
||||
|
||||
pub const FieldRef = struct {
|
||||
class_index: u16,
|
||||
name_and_type_index: u16,
|
||||
|
||||
pub fn class(self: *const FieldRef, constant_pool: Self) ResolveError!Info {
|
||||
return constant_pool.getTag(self.class_index, .class);
|
||||
}
|
||||
|
||||
pub fn nameAndType(self: *const FieldRef, constant_pool: Self) ResolveError!Info {
|
||||
return constant_pool.getTag(self.name_and_type_index, .name_and_type);
|
||||
}
|
||||
};
|
||||
|
||||
pub const MethodRef = struct {
|
||||
class_index: u16,
|
||||
name_and_type_index: u16,
|
||||
|
||||
pub fn class(self: *const MethodRef, constant_pool: Self) ResolveError!Info {
|
||||
return constant_pool.getTag(self.class_index, .class);
|
||||
}
|
||||
|
||||
pub fn nameAndType(self: *const MethodRef, constant_pool: Self) ResolveError!Info {
|
||||
return constant_pool.getTag(self.name_and_type_index, .name_and_type);
|
||||
}
|
||||
};
|
||||
|
||||
pub const InterfaceMethodRef = struct {
|
||||
class_index: u16,
|
||||
name_and_type_index: u16,
|
||||
|
||||
pub fn class(self: *const InterfaceMethodRef, constant_pool: Self) ResolveError!Info {
|
||||
return constant_pool.getTag(self.class_index, .class);
|
||||
}
|
||||
|
||||
pub fn nameAndType(self: *const InterfaceMethodRef, constant_pool: Self) ResolveError!Info {
|
||||
return constant_pool.getTag(self.name_and_type_index, .name_and_type);
|
||||
}
|
||||
};
|
||||
|
||||
pub const String = struct {
|
||||
string_index: u16,
|
||||
|
||||
pub fn string(self: *const String, constant_pool: Self) ResolveError!Info {
|
||||
return constant_pool.getTag(self.string_index, .utf8);
|
||||
}
|
||||
};
|
||||
|
||||
pub const Integer = struct {
|
||||
bytes: u32,
|
||||
};
|
||||
|
||||
pub const Float = struct {
|
||||
bytes: u32,
|
||||
|
||||
pub fn float(self: *const Float) f32 {
|
||||
return @bitCast(self.bytes);
|
||||
}
|
||||
};
|
||||
|
||||
pub const Long = struct {
|
||||
high_bytes: u32,
|
||||
low_bytes: u32,
|
||||
|
||||
pub fn long(self: *const Long) u64 {
|
||||
return (@as(u64, self.high_bytes) << 32) | self.low_bytes;
|
||||
}
|
||||
};
|
||||
|
||||
pub const Double = struct {
|
||||
high_bytes: u32,
|
||||
low_bytes: u32,
|
||||
|
||||
pub fn double(self: *const Double) f64 {
|
||||
return @bitCast((@as(u64, self.high_bytes) << 32) | self.low_bytes);
|
||||
}
|
||||
};
|
||||
|
||||
pub const NameAndType = struct {
|
||||
name_index: u16,
|
||||
descriptor_index: u16,
|
||||
|
||||
pub fn name(self: *const NameAndType, constant_pool: Self) ResolveError!Info {
|
||||
return constant_pool.getTag(self.name_index, .utf8);
|
||||
}
|
||||
|
||||
pub fn descriptor(self: *const NameAndType, constant_pool: Self) ResolveError!Info {
|
||||
return constant_pool.getTag(self.descriptor_index, .utf8);
|
||||
}
|
||||
};
|
||||
|
||||
pub const Utf8 = struct {
|
||||
bytes: []const u8,
|
||||
};
|
||||
|
||||
pub const MethodHandle = struct {
|
||||
reference_kind: Kind,
|
||||
reference_index: u16,
|
||||
|
||||
pub const Kind = enum(u8) {
|
||||
get_field = 1,
|
||||
get_static = 2,
|
||||
put_field = 3,
|
||||
put_static = 4,
|
||||
invoke_virtual = 5,
|
||||
invoke_static = 6,
|
||||
invoke_special = 7,
|
||||
new_invoke_special = 8,
|
||||
invoke_interface = 9,
|
||||
};
|
||||
|
||||
pub fn reference(self: *const MethodHandle, constant_pool: Self) ResolveError!Info {
|
||||
const info = try constant_pool.get(self.reference_index);
|
||||
return switch (self.reference_kind) {
|
||||
.get_field, .get_static, .put_field, .put_static => blk: {
|
||||
if (!info.is(.field_ref)) break :blk ResolveError.InvalidConstantType;
|
||||
break :blk info;
|
||||
},
|
||||
.invoke_virtual, .invoke_static, .invoke_special, .new_invoke_special => blk: {
|
||||
if (!info.is(.method_ref)) break :blk ResolveError.InvalidConstantType;
|
||||
break :blk info;
|
||||
},
|
||||
.invoke_interface => blk: {
|
||||
if (!info.is(.interface_method_ref)) break :blk ResolveError.InvalidConstantType;
|
||||
break :blk info;
|
||||
},
|
||||
};
|
||||
}
|
||||
};
|
||||
|
||||
pub const MethodType = struct {
|
||||
descriptor_index: u16,
|
||||
|
||||
pub fn descriptor(self: *const MethodType, constant_pool: Self) ResolveError!Info {
|
||||
return constant_pool.getTag(self.descriptor_index, .utf8);
|
||||
}
|
||||
};
|
||||
|
||||
pub const Dynamic = struct {
|
||||
bootstrap_method_attr_index: u16,
|
||||
name_and_type_index: u16,
|
||||
|
||||
pub fn nameAndType(self: *const Dynamic, constant_pool: Self) ResolveError!Info {
|
||||
return constant_pool.getTag(self.name_and_type_index, .name_and_type);
|
||||
}
|
||||
};
|
||||
|
||||
pub const InvokeDynamic = struct {
|
||||
bootstrap_method_attr_index: u16,
|
||||
name_and_type_index: u16,
|
||||
|
||||
pub fn nameAndType(self: *const InvokeDynamic, constant_pool: Self) ResolveError!Info {
|
||||
return constant_pool.getTag(self.name_and_type_index, .name_and_type);
|
||||
}
|
||||
};
|
||||
|
||||
pub const Module = struct {
|
||||
name_index: u16,
|
||||
|
||||
pub fn name(self: *const Module, constant_pool: Self) ResolveError!Info {
|
||||
return constant_pool.getTag(self.name_index, .utf8);
|
||||
}
|
||||
};
|
||||
|
||||
pub const Package = struct {
|
||||
name_index: u16,
|
||||
|
||||
pub fn name(self: *const Package, constant_pool: Self) ResolveError!Info {
|
||||
return constant_pool.getTag(self.name_index, .utf8);
|
||||
}
|
||||
};
|
||||
|
||||
pub fn parse(input: *std.Io.Reader, allocator: std.mem.Allocator) ParseError!Info {
|
||||
const tag_byte = try input.takeByte();
|
||||
const tag = std.enums.fromInt(Tag, tag_byte) orelse return ParseError.InvalidTag;
|
||||
|
||||
return switch (tag) {
|
||||
.class => .{
|
||||
.class = .{
|
||||
.name_index = try input.takeInt(u16, .big),
|
||||
},
|
||||
},
|
||||
.field_ref => .{
|
||||
.field_ref = .{
|
||||
.class_index = try input.takeInt(u16, .big),
|
||||
.name_and_type_index = try input.takeInt(u16, .big),
|
||||
},
|
||||
},
|
||||
.method_ref => .{
|
||||
.method_ref = .{
|
||||
.class_index = try input.takeInt(u16, .big),
|
||||
.name_and_type_index = try input.takeInt(u16, .big),
|
||||
},
|
||||
},
|
||||
.interface_method_ref => .{
|
||||
.interface_method_ref = .{
|
||||
.class_index = try input.takeInt(u16, .big),
|
||||
.name_and_type_index = try input.takeInt(u16, .big),
|
||||
},
|
||||
},
|
||||
.string => .{
|
||||
.string = .{
|
||||
.string_index = try input.takeInt(u16, .big),
|
||||
},
|
||||
},
|
||||
.integer => .{
|
||||
.integer = .{
|
||||
.bytes = try input.takeInt(u32, .big),
|
||||
},
|
||||
},
|
||||
.float => .{
|
||||
.integer = .{
|
||||
.bytes = try input.takeInt(u32, .big),
|
||||
},
|
||||
},
|
||||
.long => .{
|
||||
.long = .{
|
||||
.high_bytes = try input.takeInt(u32, .big),
|
||||
.low_bytes = try input.takeInt(u32, .big),
|
||||
},
|
||||
},
|
||||
.double => .{
|
||||
.double = .{
|
||||
.high_bytes = try input.takeInt(u32, .big),
|
||||
.low_bytes = try input.takeInt(u32, .big),
|
||||
},
|
||||
},
|
||||
.name_and_type => .{
|
||||
.name_and_type = .{
|
||||
.name_index = try input.takeInt(u16, .big),
|
||||
.descriptor_index = try input.takeInt(u16, .big),
|
||||
},
|
||||
},
|
||||
.utf8 => blk: {
|
||||
const length = try input.takeInt(u16, .big);
|
||||
const bytes = try input.readAlloc(allocator, length);
|
||||
|
||||
break :blk .{
|
||||
.utf8 = .{
|
||||
.bytes = bytes,
|
||||
},
|
||||
};
|
||||
},
|
||||
.method_handle => blk: {
|
||||
const kind_byte = try input.takeByte();
|
||||
const kind = std.enums.fromInt(MethodHandle.Kind, kind_byte) orelse return ParseError.InvalidTag;
|
||||
|
||||
break :blk .{
|
||||
.method_handle = .{
|
||||
.reference_kind = kind,
|
||||
.reference_index = try input.takeInt(u16, .big),
|
||||
},
|
||||
};
|
||||
},
|
||||
.method_type => .{
|
||||
.method_type = .{
|
||||
.descriptor_index = try input.takeInt(u16, .big),
|
||||
},
|
||||
},
|
||||
.dynamic => .{
|
||||
.dynamic = .{
|
||||
.bootstrap_method_attr_index = try input.takeInt(u16, .big),
|
||||
.name_and_type_index = try input.takeInt(u16, .big),
|
||||
},
|
||||
},
|
||||
.invoke_dynamic => .{
|
||||
.invoke_dynamic = .{
|
||||
.bootstrap_method_attr_index = try input.takeInt(u16, .big),
|
||||
.name_and_type_index = try input.takeInt(u16, .big),
|
||||
},
|
||||
},
|
||||
.module => .{
|
||||
.module = .{
|
||||
.name_index = try input.takeInt(u16, .big),
|
||||
},
|
||||
},
|
||||
.package => .{
|
||||
.package = .{
|
||||
.name_index = try input.takeInt(u16, .big),
|
||||
},
|
||||
},
|
||||
};
|
||||
}
|
||||
|
||||
pub fn deinit(self: *Info, allocator: std.mem.Allocator) void {
|
||||
switch (self.*) {
|
||||
.utf8 => |info| allocator.free(info.bytes),
|
||||
else => {},
|
||||
}
|
||||
}
|
||||
|
||||
pub fn format(self: *const Info, w: *std.Io.Writer) std.Io.Writer.Error!void {
|
||||
switch (self.*) {
|
||||
.class => |class| try w.print("#{d}", .{ class.name_index }),
|
||||
.field_ref => |field_ref| try w.print("#{d}.#{d}", .{ field_ref.class_index, field_ref.name_and_type_index }),
|
||||
.method_ref => |method_ref| try w.print("#{d}.#{d}", .{ method_ref.class_index, method_ref.name_and_type_index }),
|
||||
.interface_method_ref => |interface_method_ref| try w.print("#{d}.#{d}", .{ interface_method_ref.class_index, interface_method_ref.name_and_type_index }),
|
||||
.string => |string| try w.print("#{d}", .{ string.string_index }),
|
||||
.integer => |integer| try w.print("{d}", .{ integer.bytes }),
|
||||
.float => |float| try w.print("{d}", .{ float.float() }),
|
||||
.long => |long| try w.print("{d}", .{ long.long() }),
|
||||
.double => |double| try w.print("{d}", .{ double.double() }),
|
||||
.name_and_type => |name_and_type| try w.print("#{d}:#{d}", .{ name_and_type.name_index, name_and_type.descriptor_index }),
|
||||
.utf8 => |utf8| try w.print("\"{s}\"", .{ utf8.bytes }),
|
||||
.method_handle => |method_handle| try w.print("{t} #{d}", .{ method_handle.reference_kind, method_handle.reference_index }),
|
||||
.method_type => |method_type| try w.print("#{d}", .{ method_type.descriptor_index }),
|
||||
.dynamic => |dynamic| try w.print("#{d} #{d}", .{ dynamic.bootstrap_method_attr_index, dynamic.name_and_type_index }),
|
||||
.invoke_dynamic => |invoke_dynamic| try w.print("#{d} #{d}", .{ invoke_dynamic.bootstrap_method_attr_index, invoke_dynamic.name_and_type_index }),
|
||||
.module => |module| try w.print("#{d}", .{ module.name_index }),
|
||||
.package => |package| try w.print("#{d}", .{ package.name_index }),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn indentedFormat(
|
||||
self: *const Info,
|
||||
w: *std.Io.Writer,
|
||||
depth: usize,
|
||||
indent: u8,
|
||||
constant_pool: Self,
|
||||
) std.Io.Writer.Error!void {
|
||||
try w.splatByteAll(' ', depth * indent);
|
||||
try w.print("constant_value_type: {t}\n", .{ self.* });
|
||||
|
||||
switch (self.*) {
|
||||
.class => |*class| {
|
||||
try formatInfo(w, depth, indent, "name", class, .name, constant_pool);
|
||||
},
|
||||
.field_ref => |*field_ref| {
|
||||
try formatInfo(w, depth, indent, "class", field_ref, .class, constant_pool);
|
||||
|
||||
try formatInfo(w, depth, indent, "name_and_type", field_ref, .nameAndType, constant_pool);
|
||||
},
|
||||
.method_ref => |*method_ref| {
|
||||
try formatInfo(w, depth, indent, "class", method_ref, .class, constant_pool);
|
||||
|
||||
try formatInfo(w, depth, indent, "name_and_type", method_ref, .nameAndType, constant_pool);
|
||||
},
|
||||
.interface_method_ref => |*interface_method_ref| {
|
||||
try formatInfo(w, depth, indent, "class", interface_method_ref, .class, constant_pool);
|
||||
|
||||
try formatInfo(w, depth, indent, "name_and_type", interface_method_ref, .nameAndType, constant_pool);
|
||||
},
|
||||
.string => |*string| {
|
||||
try formatInfo(w, depth, indent, "string", string, .string, constant_pool);
|
||||
},
|
||||
.integer => |*integer| {
|
||||
try w.splatByteAll(' ', depth * indent);
|
||||
try w.print("integer: {d}\n", .{ integer.bytes });
|
||||
},
|
||||
.float => |*float| {
|
||||
try w.splatByteAll(' ', depth * indent);
|
||||
try w.print("float: {d}\n", .{ float.float() });
|
||||
},
|
||||
.long => |*long| {
|
||||
try w.splatByteAll(' ', depth * indent);
|
||||
try w.print("long: {d}\n", .{ long.long() });
|
||||
},
|
||||
.double => |*double| {
|
||||
try w.splatByteAll(' ', depth * indent);
|
||||
try w.print("double: {d}\n", .{ double.double() });
|
||||
},
|
||||
.name_and_type => |*name_and_type| {
|
||||
try formatInfo(w, depth, indent, "name", name_and_type, .name, constant_pool);
|
||||
|
||||
try formatInfo(w, depth, indent, "descriptor", name_and_type, .descriptor, constant_pool);
|
||||
},
|
||||
.utf8 => |*utf8| {
|
||||
try w.splatByteAll(' ', depth * indent);
|
||||
try w.print("bytes: \"{s}\"\n", .{ utf8.bytes });
|
||||
},
|
||||
.method_handle => |*method_handle| {
|
||||
try w.splatByteAll(' ', depth * indent);
|
||||
try w.print("kind: {t}\n", .{ method_handle.reference_kind });
|
||||
|
||||
try formatInfo(w, depth, indent, "descriptor", method_handle, .reference, constant_pool);
|
||||
},
|
||||
.method_type => |*method_type| {
|
||||
try formatInfo(w, depth, indent, "descriptor", method_type, .descriptor, constant_pool);
|
||||
},
|
||||
.dynamic => |*dynamic| {
|
||||
try formatInfo(w, depth, indent, "name_and_type", dynamic, .nameAndType, constant_pool);
|
||||
},
|
||||
.invoke_dynamic => |*invoke_dynamic| {
|
||||
try formatInfo(w, depth, indent, "name_and_type", invoke_dynamic, .nameAndType, constant_pool);
|
||||
},
|
||||
.module => |*module| {
|
||||
try formatInfo(w, depth, indent, "name", module, .name, constant_pool);
|
||||
},
|
||||
.package => |*package| {
|
||||
try formatInfo(w, depth, indent, "name", package, .name, constant_pool);
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
pub fn is(self: *const Info, tag: Tag) bool {
|
||||
return @as(Tag, self.*) == tag;
|
||||
}
|
||||
};
|
||||
|
||||
pub fn parse(input: *std.Io.Reader, allocator: std.mem.Allocator) ParseError!Self {
|
||||
const constant_pool_size = try input.takeInt(u16, .big);
|
||||
const constant_pool = try allocator.alloc(?Info, constant_pool_size - 1);
|
||||
errdefer allocator.free(constant_pool);
|
||||
|
||||
var i: usize = 0;
|
||||
while (i < constant_pool_size - 1) {
|
||||
defer i += 1;
|
||||
|
||||
const info: Info = try .parse(input, allocator);
|
||||
constant_pool[i] = info;
|
||||
|
||||
switch (info) {
|
||||
.long, .double => {
|
||||
i += 1;
|
||||
constant_pool[i] = null;
|
||||
},
|
||||
else => {},
|
||||
}
|
||||
}
|
||||
|
||||
return .{
|
||||
.constant_pool = constant_pool,
|
||||
};
|
||||
}
|
||||
|
||||
pub fn deinit(self: *Self, allocator: std.mem.Allocator) void {
|
||||
for (self.constant_pool) |*info| {
|
||||
if (info.*) |*c| c.deinit(allocator);
|
||||
}
|
||||
allocator.free(self.constant_pool);
|
||||
}
|
||||
|
||||
pub fn get(self: *const Self, index: u16) ResolveError!Info {
|
||||
const actual_index = index - 1;
|
||||
if (actual_index >= self.constant_pool.len) return ResolveError.InvalidConstantPoolIndex;
|
||||
const info = self.constant_pool[actual_index];
|
||||
if (info == null) return ResolveError.InvalidConstantType;
|
||||
return info.?;
|
||||
}
|
||||
|
||||
pub fn getOptional(self: *const Self, index: u16) ResolveError!?Info {
|
||||
if (index == 0) return null;
|
||||
return self.get(index);
|
||||
}
|
||||
|
||||
pub fn getTag(self: *const Self, index: u16, expected_tag: Info.Tag) ResolveError!Info {
|
||||
const info = try self.get(index);
|
||||
if (!info.is(expected_tag)) return ResolveError.InvalidConstantType;
|
||||
return info;
|
||||
}
|
||||
|
||||
pub fn getTagOptional(self: *const Self, index: u16, expected_tag: Info.Tag) ResolveError!?Info {
|
||||
if (index == 0) return null;
|
||||
return try self.getTag(index, expected_tag);
|
||||
}
|
||||
|
||||
pub fn getLoadable(self: *const Self, index: u16) ResolveError!Info {
|
||||
const info = try self.get(index);
|
||||
if (!@as(Info.Tag, info).loadable()) return ResolveError.InvalidConstantType;
|
||||
return info;
|
||||
}
|
||||
|
||||
pub fn getLoadableOptional(self: *const Self, index: u16) ResolveError!?Info {
|
||||
if (index == 0) return null;
|
||||
return self.getLoadable(index);
|
||||
}
|
||||
|
||||
pub fn formatInfo(
|
||||
w: *std.Io.Writer,
|
||||
depth: usize,
|
||||
indent: u8,
|
||||
comptime name: []const u8,
|
||||
context: anytype,
|
||||
comptime getter: std.meta.DeclEnum(@TypeOf(context.*)),
|
||||
constant_pool: Self,
|
||||
) std.Io.Writer.Error!void {
|
||||
const func = @field(@TypeOf(context.*), @tagName(getter));
|
||||
|
||||
try w.splatByteAll(' ', depth * indent);
|
||||
_ = try w.write(name ++ ":\n");
|
||||
const info = func(context, constant_pool) catch return error.WriteFailed;
|
||||
try info.indentedFormat(w, depth, indent + 1, constant_pool);
|
||||
}
|
||||
|
|
@ -3,7 +3,7 @@ const std = @import("std");
|
|||
const EnumFlags = @import("../EnumFlags.zig").EnumFlags;
|
||||
|
||||
const Class = @import("../Class.zig");
|
||||
const ConstantPoolInfo = Class.ConstantPoolInfo;
|
||||
const ConstantPool = Class.ConstantPool;
|
||||
const AttributeInfo = Class.AttributeInfo;
|
||||
const ResolveError = Class.ResolveError;
|
||||
|
||||
|
|
@ -14,7 +14,7 @@ attributes: []AttributeInfo,
|
|||
|
||||
const Self = @This();
|
||||
|
||||
pub const FieldFlags = enum(u16) {
|
||||
pub const FieldAccessFlags = EnumFlags(enum(u16) {
|
||||
public = 0x0001,
|
||||
private = 0x0002,
|
||||
protected = 0x0004,
|
||||
|
|
@ -24,15 +24,13 @@ pub const FieldFlags = enum(u16) {
|
|||
transient = 0x0080,
|
||||
synthetic = 0x1000,
|
||||
@"enum" = 0x4000,
|
||||
};
|
||||
});
|
||||
|
||||
pub const FieldAccessFlags = EnumFlags(FieldFlags);
|
||||
|
||||
pub fn parse(input: *std.Io.Reader, allocator: std.mem.Allocator) !Self {
|
||||
const access_flags: FieldAccessFlags = .{ .mask = try input.takeInt(u16, .big) };
|
||||
pub fn parse(input: *std.Io.Reader, constant_pool: ConstantPool, allocator: std.mem.Allocator) !Self {
|
||||
const access_flags: FieldAccessFlags = .from(try input.takeInt(u16, .big));
|
||||
const name_index = try input.takeInt(u16, .big);
|
||||
const descriptor_index = try input.takeInt(u16, .big);
|
||||
const attributes = try Class.parseAttributes(input, allocator);
|
||||
const attributes = try Class.parseAttributes(input, constant_pool, allocator);
|
||||
return .{
|
||||
.access_flags = access_flags,
|
||||
.name_index = name_index,
|
||||
|
|
@ -48,13 +46,12 @@ pub fn deinit(self: *Self, allocator: std.mem.Allocator) void {
|
|||
allocator.free(self.attributes);
|
||||
}
|
||||
|
||||
pub fn format(
|
||||
pub fn indentedFormat(
|
||||
self: *const Self,
|
||||
w: *std.Io.Writer,
|
||||
depth: usize,
|
||||
indent: u8,
|
||||
allocator: std.mem.Allocator,
|
||||
constant_pool: []const ?ConstantPoolInfo,
|
||||
constant_pool: ConstantPool,
|
||||
) std.Io.Writer.Error!void {
|
||||
try w.splatByteAll(' ', depth * indent);
|
||||
try w.print("flags: {f}\n", .{ self.access_flags });
|
||||
|
|
@ -62,12 +59,12 @@ pub fn format(
|
|||
try w.splatByteAll(' ', depth * indent);
|
||||
_ = try w.write("name:\n");
|
||||
const field_name = self.name(constant_pool) catch return error.WriteFailed;
|
||||
try field_name.format(w, depth, indent + 1, constant_pool);
|
||||
try field_name.indentedFormat(w, depth, indent + 1, constant_pool);
|
||||
|
||||
try w.splatByteAll(' ', depth * indent);
|
||||
_ = try w.write("descriptor:\n");
|
||||
const field_descriptor = self.descriptor(constant_pool) catch return error.WriteFailed;
|
||||
try field_descriptor.format(w, depth, indent + 1, constant_pool);
|
||||
try field_descriptor.indentedFormat(w, depth, indent + 1, constant_pool);
|
||||
|
||||
try w.splatByteAll(' ', depth * indent);
|
||||
_ = try w.write("attributes:\n");
|
||||
|
|
@ -79,23 +76,15 @@ pub fn format(
|
|||
try w.splatByteAll(' ', depth * attr_indent);
|
||||
try w.print("{d}:\n", .{ j });
|
||||
|
||||
try attribute.format(w, depth, attr_indent + 1, allocator, constant_pool);
|
||||
try attribute.indentedFormat(w, depth, attr_indent + 1, constant_pool);
|
||||
}
|
||||
}
|
||||
|
||||
pub fn name(self: *const Self, 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 name(self: *const Self, constant_pool: ConstantPool) ResolveError!ConstantPool.Info {
|
||||
return constant_pool.getTag(self.name_index, .utf8);
|
||||
}
|
||||
|
||||
pub fn descriptor(self: *const Self, 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 descriptor(self: *const Self, constant_pool: ConstantPool) ResolveError!ConstantPool.Info {
|
||||
return constant_pool.getTag(self.descriptor_index, .utf8);
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -3,7 +3,7 @@ const std = @import("std");
|
|||
const EnumFlags = @import("../EnumFlags.zig").EnumFlags;
|
||||
|
||||
const Class = @import("../Class.zig");
|
||||
const ConstantPoolInfo = Class.ConstantPoolInfo;
|
||||
const ConstantPool = Class.ConstantPool;
|
||||
const AttributeInfo = Class.AttributeInfo;
|
||||
const ResolveError = Class.ResolveError;
|
||||
|
||||
|
|
@ -14,7 +14,7 @@ attributes: []AttributeInfo,
|
|||
|
||||
const Self = @This();
|
||||
|
||||
pub const MethodFlags = enum(u16) {
|
||||
pub const MethodAccessFlags = EnumFlags(enum(u16) {
|
||||
public = 0x0001,
|
||||
private = 0x0002,
|
||||
protected = 0x0004,
|
||||
|
|
@ -27,15 +27,13 @@ pub const MethodFlags = enum(u16) {
|
|||
abstract = 0x0400,
|
||||
strict = 0x0800,
|
||||
synthetic = 0x1000,
|
||||
};
|
||||
});
|
||||
|
||||
pub const MethodAccessFlags = EnumFlags(MethodFlags);
|
||||
|
||||
pub fn parse(input: *std.Io.Reader, allocator: std.mem.Allocator) !Self {
|
||||
const access_flags: MethodAccessFlags = .{ .mask = try input.takeInt(u16, .big) };
|
||||
pub fn parse(input: *std.Io.Reader, constant_pool: ConstantPool, allocator: std.mem.Allocator) !Self {
|
||||
const access_flags: MethodAccessFlags = .from(try input.takeInt(u16, .big));
|
||||
const name_index = try input.takeInt(u16, .big);
|
||||
const descriptor_index = try input.takeInt(u16, .big);
|
||||
const attributes = try Class.parseAttributes(input, allocator);
|
||||
const attributes = try Class.parseAttributes(input, constant_pool, allocator);
|
||||
return .{
|
||||
.access_flags = access_flags,
|
||||
.name_index = name_index,
|
||||
|
|
@ -51,13 +49,12 @@ pub fn deinit(self: *Self, allocator: std.mem.Allocator) void {
|
|||
allocator.free(self.attributes);
|
||||
}
|
||||
|
||||
pub fn format(
|
||||
pub fn indentedFormat(
|
||||
self: *const Self,
|
||||
w: *std.Io.Writer,
|
||||
depth: usize,
|
||||
indent: u8,
|
||||
allocator: std.mem.Allocator,
|
||||
constant_pool: []const ?ConstantPoolInfo,
|
||||
constant_pool: ConstantPool,
|
||||
) std.Io.Writer.Error!void {
|
||||
try w.splatByteAll(' ', depth * indent);
|
||||
try w.print("flags: {f}\n", .{ self.access_flags });
|
||||
|
|
@ -65,12 +62,12 @@ pub fn format(
|
|||
try w.splatByteAll(' ', depth * indent);
|
||||
_ = try w.write("name:\n");
|
||||
const method_name = self.name(constant_pool) catch return error.WriteFailed;
|
||||
try method_name.format(w, depth, indent + 1, constant_pool);
|
||||
try method_name.indentedFormat(w, depth, indent + 1, constant_pool);
|
||||
|
||||
try w.splatByteAll(' ', depth * indent);
|
||||
_ = try w.write("descriptor:\n");
|
||||
const method_descriptor = self.descriptor(constant_pool) catch return error.WriteFailed;
|
||||
try method_descriptor.format(w, depth, indent + 1, constant_pool);
|
||||
try method_descriptor.indentedFormat(w, depth, indent + 1, constant_pool);
|
||||
|
||||
try w.splatByteAll(' ', depth * indent);
|
||||
_ = try w.write("attributes:\n");
|
||||
|
|
@ -82,23 +79,14 @@ pub fn format(
|
|||
try w.splatByteAll(' ', depth * attr_indent);
|
||||
try w.print("{d}:\n", .{ j });
|
||||
|
||||
try attribute.format(w, depth, attr_indent + 1, allocator, constant_pool);
|
||||
try attribute.indentedFormat(w, depth, attr_indent + 1, constant_pool);
|
||||
}
|
||||
}
|
||||
|
||||
pub fn name(self: *const Self, 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 name(self: *const Self, constant_pool: ConstantPool) ResolveError!ConstantPool.Info {
|
||||
return constant_pool.getTag(self.name_index, .utf8);
|
||||
}
|
||||
|
||||
pub fn descriptor(self: *const Self, 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 descriptor(self: *const Self, constant_pool: ConstantPool) ResolveError!ConstantPool.Info {
|
||||
return constant_pool.getTag(self.descriptor_index, .utf8);
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -10,6 +10,12 @@ pub fn EnumFlags(comptime E: type) type {
|
|||
|
||||
pub const empty: Self = .{ .data = 0 };
|
||||
|
||||
pub fn from(mask: BackingInt) Self {
|
||||
return .{
|
||||
.mask = mask,
|
||||
};
|
||||
}
|
||||
|
||||
pub fn contains(self: Self, flag: E) bool {
|
||||
return (self.mask & @intFromEnum(flag)) != 0;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -50,10 +50,9 @@ pub fn main(init: std.process.Init) !void {
|
|||
},
|
||||
else => return err,
|
||||
};
|
||||
defer class.deinit();
|
||||
defer class.deinit(allocator);
|
||||
|
||||
try stdout.print("{f}", .{ class });
|
||||
|
||||
try stdout.flush();
|
||||
}
|
||||
|
||||
|
|
|
|||
3
testsuite/.gitignore
vendored
Normal file
3
testsuite/.gitignore
vendored
Normal file
|
|
@ -0,0 +1,3 @@
|
|||
*.class
|
||||
!Object.class
|
||||
META-INF
|
||||
14
testsuite/classes/java/CustomAnnotation.java
Normal file
14
testsuite/classes/java/CustomAnnotation.java
Normal file
|
|
@ -0,0 +1,14 @@
|
|||
import java.lang.annotation.Retention;
|
||||
import java.lang.annotation.RetentionPolicy;
|
||||
import java.lang.annotation.Target;
|
||||
import java.lang.annotation.ElementType;
|
||||
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
@Target(ElementType.TYPE)
|
||||
@CustomAnnotationAnnotation
|
||||
public @interface CustomAnnotation {
|
||||
public CustomAnnotationType type();
|
||||
|
||||
public String name() default "Bob";
|
||||
}
|
||||
|
||||
9
testsuite/classes/java/CustomAnnotationAnnotation.java
Normal file
9
testsuite/classes/java/CustomAnnotationAnnotation.java
Normal file
|
|
@ -0,0 +1,9 @@
|
|||
import java.lang.annotation.Retention;
|
||||
import java.lang.annotation.RetentionPolicy;
|
||||
import java.lang.annotation.Target;
|
||||
import java.lang.annotation.ElementType;
|
||||
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
@Target(ElementType.ANNOTATION_TYPE)
|
||||
public @interface CustomAnnotationAnnotation { }
|
||||
|
||||
5
testsuite/classes/java/CustomAnnotationType.java
Normal file
5
testsuite/classes/java/CustomAnnotationType.java
Normal file
|
|
@ -0,0 +1,5 @@
|
|||
public enum CustomAnnotationType {
|
||||
ONE,
|
||||
TWO,
|
||||
}
|
||||
|
||||
9
testsuite/classes/java/CustomParameterAnnotation.java
Normal file
9
testsuite/classes/java/CustomParameterAnnotation.java
Normal file
|
|
@ -0,0 +1,9 @@
|
|||
import java.lang.annotation.Retention;
|
||||
import java.lang.annotation.RetentionPolicy;
|
||||
import java.lang.annotation.Target;
|
||||
import java.lang.annotation.ElementType;
|
||||
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
@Target(ElementType.PARAMETER)
|
||||
public @interface CustomParameterAnnotation { }
|
||||
|
||||
9
testsuite/classes/java/CustomTypeAnnotation.java
Normal file
9
testsuite/classes/java/CustomTypeAnnotation.java
Normal file
|
|
@ -0,0 +1,9 @@
|
|||
import java.lang.annotation.Retention;
|
||||
import java.lang.annotation.RetentionPolicy;
|
||||
import java.lang.annotation.Target;
|
||||
import java.lang.annotation.ElementType;
|
||||
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
@Target(ElementType.TYPE_PARAMETER)
|
||||
public @interface CustomTypeAnnotation {
|
||||
}
|
||||
14
testsuite/classes/java/GenericClass.java
Normal file
14
testsuite/classes/java/GenericClass.java
Normal file
|
|
@ -0,0 +1,14 @@
|
|||
import java.util.function.Supplier;
|
||||
|
||||
public class GenericClass<@CustomTypeAnnotation T> {
|
||||
|
||||
public <T> Supplier<T> getSupplier(T value) {
|
||||
return new Supplier<T>() {
|
||||
@Override
|
||||
public T get() {
|
||||
return value;
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
}
|
||||
6
testsuite/classes/java/Hello.java
Normal file
6
testsuite/classes/java/Hello.java
Normal file
|
|
@ -0,0 +1,6 @@
|
|||
class Hello {
|
||||
public static void main(String[] args) {
|
||||
System.out.println("Hello, world!");
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -1,17 +1,27 @@
|
|||
import java.util.function.Supplier;
|
||||
|
||||
@CustomAnnotation(type = CustomAnnotationType.ONE, name = "Alice")
|
||||
public class Main implements Runnable, Supplier<Integer>, Interface {
|
||||
private static final String name = "John";
|
||||
private static final int number = 42;
|
||||
private static final double funnyNumber = 6.9;
|
||||
|
||||
public static void main() {
|
||||
new Main().sayHello();
|
||||
public static void main(@CustomParameterAnnotation String[] args) {
|
||||
final var main = new Main();
|
||||
main.sayHello();
|
||||
|
||||
try {
|
||||
main.throwSomething();
|
||||
} catch (Throwable e) {
|
||||
System.err.println("Caught " + e.getMessage());
|
||||
} finally {
|
||||
System.err.println("Finally block");
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public void run() {
|
||||
Main.main();
|
||||
Main.main(new String[] { "Hello" });
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
@ -37,4 +47,3 @@ public class Main implements Runnable, Supplier<Integer>, Interface {
|
|||
private static final String name = "Inner John";
|
||||
}
|
||||
}
|
||||
|
||||
22
testsuite/classes/java/MultiThreading.java
Normal file
22
testsuite/classes/java/MultiThreading.java
Normal file
|
|
@ -0,0 +1,22 @@
|
|||
import java.util.concurrent.Executors;
|
||||
import java.util.stream.IntStream;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
public class MultiThreading {
|
||||
private int number = 0;
|
||||
|
||||
public static void main(String[] args) throws InterruptedException {
|
||||
final var multiThreading = new MultiThreading();
|
||||
|
||||
final var service = Executors.newFixedThreadPool(3);
|
||||
IntStream.range(0, 1000)
|
||||
.forEach(count -> service.submit(multiThreading::increment));
|
||||
service.awaitTermination(1000, TimeUnit.MILLISECONDS);
|
||||
|
||||
System.out.println(multiThreading.number);
|
||||
}
|
||||
|
||||
public synchronized void increment() {
|
||||
number += 1;
|
||||
}
|
||||
}
|
||||
BIN
testsuite/classes/java/Object.class
Normal file
BIN
testsuite/classes/java/Object.class
Normal file
Binary file not shown.
2
testsuite/classes/java/Record.java
Normal file
2
testsuite/classes/java/Record.java
Normal file
|
|
@ -0,0 +1,2 @@
|
|||
public record Record(String name, int age) {}
|
||||
|
||||
12
testsuite/classes/kotlin/Main.kt
Normal file
12
testsuite/classes/kotlin/Main.kt
Normal file
|
|
@ -0,0 +1,12 @@
|
|||
fun main() {
|
||||
println("Hello, world!")
|
||||
|
||||
Test().apply {
|
||||
test = true
|
||||
}
|
||||
}
|
||||
|
||||
class Test {
|
||||
var test: Boolean = false
|
||||
}
|
||||
|
||||
2
testsuite/modules/compile-simple-modules.sh
Executable file
2
testsuite/modules/compile-simple-modules.sh
Executable file
|
|
@ -0,0 +1,2 @@
|
|||
#!/usr/bin/env bash
|
||||
javac -g -d outDir --module-source-path simple-modules $(find simple-modules -name "*.java")
|
||||
2
testsuite/modules/run-simple-module-app.sh
Executable file
2
testsuite/modules/run-simple-module-app.sh
Executable file
|
|
@ -0,0 +1,2 @@
|
|||
#!/usr/bin/env bash
|
||||
java --module-path outDir -m main.app/dev.katkak.modules.main.MainApp
|
||||
|
|
@ -0,0 +1,6 @@
|
|||
package dev.katkak.modules.hello;
|
||||
|
||||
public interface HelloInterface {
|
||||
void sayHello();
|
||||
}
|
||||
|
||||
|
|
@ -0,0 +1,12 @@
|
|||
package dev.katkak.modules.hello;
|
||||
|
||||
public class HelloModules implements HelloInterface {
|
||||
public static void doSomething() {
|
||||
System.out.println("Hello, Modules!");
|
||||
}
|
||||
|
||||
public void sayHello() {
|
||||
System.out.println("Hello!");
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -0,0 +1,6 @@
|
|||
module hello.modules {
|
||||
exports dev.katkak.modules.hello;
|
||||
|
||||
provides dev.katkak.modules.hello.HelloInterface with dev.katkak.modules.hello.HelloModules;
|
||||
}
|
||||
|
||||
|
|
@ -0,0 +1,17 @@
|
|||
package dev.katkak.modules.main;
|
||||
|
||||
import dev.katkak.modules.hello.HelloModules;
|
||||
import dev.katkak.modules.hello.HelloInterface;
|
||||
|
||||
import java.util.ServiceLoader;
|
||||
|
||||
public class MainApp {
|
||||
public static void main(String[] args) {
|
||||
HelloModules.doSomething();
|
||||
|
||||
final var services = ServiceLoader.load(HelloInterface.class);
|
||||
final var service = services.iterator().next();
|
||||
service.sayHello();
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -0,0 +1,6 @@
|
|||
module main.app {
|
||||
requires hello.modules;
|
||||
|
||||
uses dev.katkak.modules.hello.HelloInterface;
|
||||
}
|
||||
|
||||
Loading…
Add table
Add a link
Reference in a new issue