Compare commits

..

2 commits

Author SHA1 Message Date
28ac986827 WIP: Instructions 2026-07-03 08:52:49 +00:00
51e90fae80 Add instructions 2026-06-26 15:35:38 +00:00
31 changed files with 2110 additions and 3747 deletions

View file

@ -1,27 +1,17 @@
import java.util.function.Supplier; import java.util.function.Supplier;
@CustomAnnotation(type = CustomAnnotationType.ONE, name = "Alice")
public class Main implements Runnable, Supplier<Integer>, Interface { public class Main implements Runnable, Supplier<Integer>, Interface {
private static final String name = "John"; private static final String name = "John";
private static final int number = 42; private static final int number = 42;
private static final double funnyNumber = 6.9; private static final double funnyNumber = 6.9;
public static void main(@CustomParameterAnnotation String[] args) { public static void main() {
final var main = new Main(); new Main().sayHello();
main.sayHello();
try {
main.throwSomething();
} catch (Throwable e) {
System.err.println("Caught " + e.getMessage());
} finally {
System.err.println("Finally block");
}
} }
@Override @Override
public void run() { public void run() {
Main.main(new String[] { "Hello" }); Main.main();
} }
@Override @Override
@ -47,3 +37,4 @@ public class Main implements Runnable, Supplier<Integer>, Interface {
private static final String name = "Inner John"; private static final String name = "Inner John";
} }
} }

View file

@ -19,8 +19,6 @@
zls zls
javaPackages.compiler.openjdk25 javaPackages.compiler.openjdk25
jdt-language-server jdt-language-server
kotlin
kotlin-language-server
]; ];
buildInputs = with pkgs; []; buildInputs = with pkgs; [];

View file

@ -4,13 +4,14 @@ const EnumFlags = @import("EnumFlags.zig").EnumFlags;
pub const FieldInfo = @import("Class/FieldInfo.zig"); pub const FieldInfo = @import("Class/FieldInfo.zig");
pub const MethodInfo = @import("Class/MethodInfo.zig"); pub const MethodInfo = @import("Class/MethodInfo.zig");
pub const AttributeInfo = @import("Class/AttributeInfo.zig").AttributeInfo; pub const AttributeInfo = @import("Class/AttributeInfo.zig");
pub const ConstantPool = @import("Class/ConstantPool.zig");
allocator: std.mem.Allocator,
magic: u32, magic: u32,
minor_version: u16, minor_version: u16,
major_version: u16, major_version: u16,
constant_pool: ConstantPool, constant_pool: []?ConstantPoolInfo,
access_flags: ClassAccessFlags, access_flags: ClassAccessFlags,
this_class: u16, this_class: u16,
super_class: u16, super_class: u16,
@ -21,7 +22,7 @@ attributes: []AttributeInfo,
const Self = @This(); const Self = @This();
pub const ClassAccessFlags = EnumFlags(enum(u16) { pub const ClassFlags = enum(u16) {
public = 0x0001, public = 0x0001,
final = 0x0010, final = 0x0010,
super = 0x0020, super = 0x0020,
@ -30,8 +31,9 @@ pub const ClassAccessFlags = EnumFlags(enum(u16) {
synthetic = 0x1000, synthetic = 0x1000,
annotation = 0x2000, annotation = 0x2000,
@"enum" = 0x4000, @"enum" = 0x4000,
module = 0x8000, };
});
pub const ClassAccessFlags = EnumFlags(ClassFlags);
pub const ParseError = std.Io.Reader.Error || std.mem.Allocator.Error || error { pub const ParseError = std.Io.Reader.Error || std.mem.Allocator.Error || error {
InvalidMagicNumber, InvalidMagicNumber,
@ -43,7 +45,7 @@ pub const ResolveError = error {
InvalidConstantType, InvalidConstantType,
}; };
pub fn parse(input: *std.Io.Reader, allocator: std.mem.Allocator) (ParseError || ResolveError)!Self { pub fn parse(input: *std.Io.Reader, allocator: std.mem.Allocator) ParseError!Self {
const magic = try input.takeInt(u32, .big); const magic = try input.takeInt(u32, .big);
if (magic != 0xCAFEBABE) { if (magic != 0xCAFEBABE) {
return ParseError.InvalidMagicNumber; return ParseError.InvalidMagicNumber;
@ -52,10 +54,15 @@ pub fn parse(input: *std.Io.Reader, allocator: std.mem.Allocator) (ParseError ||
const minor_version = try input.takeInt(u16, .big); const minor_version = try input.takeInt(u16, .big);
const major_version = try input.takeInt(u16, .big); const major_version = try input.takeInt(u16, .big);
var constant_pool: ConstantPool = try .parse(input, allocator); const constant_pool = try parseConstantPool(input, allocator);
errdefer constant_pool.deinit(allocator); errdefer {
for (constant_pool) |*cp_info| {
if (cp_info.*) |*c| c.deinit(allocator);
}
allocator.free(constant_pool);
}
const access_flags: ClassAccessFlags = .from(try input.takeInt(u16, .big)); const access_flags: ClassAccessFlags = .{ .mask = try input.takeInt(u16, .big) };
const this_class = try input.takeInt(u16, .big); const this_class = try input.takeInt(u16, .big);
const super_class = try input.takeInt(u16, .big); const super_class = try input.takeInt(u16, .big);
@ -63,7 +70,7 @@ pub fn parse(input: *std.Io.Reader, allocator: std.mem.Allocator) (ParseError ||
const interfaces = try parseInterfaces(input, allocator); const interfaces = try parseInterfaces(input, allocator);
errdefer allocator.free(interfaces); errdefer allocator.free(interfaces);
const fields = try parseFields(input, constant_pool, allocator); const fields = try parseFields(input, allocator);
errdefer { errdefer {
for (fields) |*field| { for (fields) |*field| {
field.deinit(allocator); field.deinit(allocator);
@ -71,7 +78,7 @@ pub fn parse(input: *std.Io.Reader, allocator: std.mem.Allocator) (ParseError ||
allocator.free(fields); allocator.free(fields);
} }
const methods = try parseMethods(input, constant_pool, allocator); const methods = try parseMethods(input, allocator);
errdefer { errdefer {
for (methods) |*method| { for (methods) |*method| {
method.deinit(allocator); method.deinit(allocator);
@ -79,7 +86,7 @@ pub fn parse(input: *std.Io.Reader, allocator: std.mem.Allocator) (ParseError ||
allocator.free(methods); allocator.free(methods);
} }
const attributes = try parseAttributes(input, constant_pool, allocator); const attributes = try parseAttributes(input, allocator);
errdefer { errdefer {
for (attributes) |*attribute| { for (attributes) |*attribute| {
attribute.deinit(allocator); attribute.deinit(allocator);
@ -88,6 +95,7 @@ pub fn parse(input: *std.Io.Reader, allocator: std.mem.Allocator) (ParseError ||
} }
return .{ return .{
.allocator = allocator,
.magic = magic, .magic = magic,
.minor_version = minor_version, .minor_version = minor_version,
.major_version = major_version, .major_version = major_version,
@ -102,6 +110,30 @@ pub fn parse(input: *std.Io.Reader, allocator: std.mem.Allocator) (ParseError ||
}; };
} }
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 { fn parseInterfaces(input: *std.Io.Reader, allocator: std.mem.Allocator) ParseError![]u16 {
const interfaces_count = try input.takeInt(u16, .big); const interfaces_count = try input.takeInt(u16, .big);
const interfaces = try allocator.alloc(u16, interfaces_count); const interfaces = try allocator.alloc(u16, interfaces_count);
@ -114,73 +146,80 @@ fn parseInterfaces(input: *std.Io.Reader, allocator: std.mem.Allocator) ParseErr
return interfaces; return interfaces;
} }
fn parseFields(input: *std.Io.Reader, constant_pool: ConstantPool, allocator: std.mem.Allocator) (ParseError || ResolveError)![]FieldInfo { fn parseFields(input: *std.Io.Reader, allocator: std.mem.Allocator) ParseError![]FieldInfo {
const fields_count = try input.takeInt(u16, .big); const fields_count = try input.takeInt(u16, .big);
const fields = try allocator.alloc(FieldInfo, fields_count); const fields = try allocator.alloc(FieldInfo, fields_count);
errdefer allocator.free(fields); errdefer allocator.free(fields);
for (0..fields_count) |i| { for (0..fields_count) |i| {
fields[i] = try FieldInfo.parse(input, constant_pool, allocator); fields[i] = try FieldInfo.parse(input, allocator);
} }
return fields; return fields;
} }
fn parseMethods(input: *std.Io.Reader, constant_pool: ConstantPool, allocator: std.mem.Allocator) (ParseError || ResolveError)![]MethodInfo { fn parseMethods(input: *std.Io.Reader, allocator: std.mem.Allocator) ParseError![]MethodInfo {
const methods_count = try input.takeInt(u16, .big); const methods_count = try input.takeInt(u16, .big);
const methods = try allocator.alloc(MethodInfo, methods_count); const methods = try allocator.alloc(MethodInfo, methods_count);
errdefer allocator.free(methods); errdefer allocator.free(methods);
for (0..methods_count) |i| { for (0..methods_count) |i| {
methods[i] = try .parse(input, constant_pool, allocator); methods[i] = try MethodInfo.parse(input, allocator);
} }
return methods; return methods;
} }
pub fn parseAttributes(input: *std.Io.Reader, constant_pool: ConstantPool, allocator: std.mem.Allocator) (ParseError || ResolveError)![]AttributeInfo { pub fn parseAttributes(input: *std.Io.Reader, allocator: std.mem.Allocator) ParseError![]AttributeInfo {
const attributes_count = try input.takeInt(u16, .big); const attributes_count = try input.takeInt(u16, .big);
const attributes = try allocator.alloc(AttributeInfo, attributes_count); const attributes = try allocator.alloc(AttributeInfo, attributes_count);
errdefer allocator.free(attributes); errdefer allocator.free(attributes);
for (0..attributes_count) |i| { for (0..attributes_count) |i| {
attributes[i] = try AttributeInfo.parse(input, constant_pool, allocator); attributes[i] = try AttributeInfo.parse(input, allocator);
} }
return attributes; return attributes;
} }
pub fn deinit(self: *Self, allocator: std.mem.Allocator) void { pub fn deinit(self: *Self) void {
self.constant_pool.deinit(allocator); self.freeConstantPool();
self.freeInterfaces(allocator); self.freeInterfaces();
self.freeFields(allocator); self.freeFields();
self.freeMethods(allocator); self.freeMethods();
self.freeAttributes(allocator); self.freeAttributes();
} }
fn freeInterfaces(self: *Self, allocator: std.mem.Allocator) void { fn freeConstantPool(self: *Self) void {
allocator.free(self.interfaces); for (self.constant_pool) |*cp_info| {
if (cp_info.*) |*c| c.deinit(self.allocator);
}
self.allocator.free(self.constant_pool);
} }
fn freeFields(self: *Self, allocator: std.mem.Allocator) void { fn freeInterfaces(self: *Self) void {
self.allocator.free(self.interfaces);
}
fn freeFields(self: *Self) void {
for (self.fields) |*field_info| { for (self.fields) |*field_info| {
field_info.deinit(allocator); field_info.deinit(self.allocator);
} }
allocator.free(self.fields); self.allocator.free(self.fields);
} }
fn freeMethods(self: *Self, allocator: std.mem.Allocator) void { fn freeMethods(self: *Self) void {
for (self.methods) |*method_info| { for (self.methods) |*method_info| {
method_info.deinit(allocator); method_info.deinit(self.allocator);
} }
allocator.free(self.methods); self.allocator.free(self.methods);
} }
fn freeAttributes(self: *Self, allocator: std.mem.Allocator) void { fn freeAttributes(self: *Self) void {
for (self.attributes) |*attr| { for (self.attributes) |*attr| {
attr.deinit(allocator); attr.deinit(self.allocator);
} }
allocator.free(self.attributes); self.allocator.free(self.attributes);
} }
pub fn jsonStringify(self: *const Self, jws: *std.json.Stringify) !void { pub fn jsonStringify(self: *const Self, jws: *std.json.Stringify) !void {
@ -207,11 +246,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; const this_class = self.thisClass() catch return error.WriteFailed;
_ = try w.write("this class:\n"); _ = try w.write("this class:\n");
try this_class.indentedFormat(w, depth, indent + 1, self.constant_pool); try this_class.format(w, depth, indent + 1, self.constant_pool);
_ = try w.write("super class:\n"); _ = try w.write("super class:\n");
if (self.superClass() catch return error.WriteFailed) |super_class| { if (self.superClass() catch return error.WriteFailed) |super_class| {
try super_class.indentedFormat(w, depth, indent + 1, self.constant_pool); try super_class.format(w, depth, indent + 1, self.constant_pool);
} }
_ = try w.write("interfaces:\n"); _ = try w.write("interfaces:\n");
@ -219,11 +258,13 @@ pub fn format(self: *const Self, w: *std.Io.Writer) std.Io.Writer.Error!void {
indent += 1; indent += 1;
defer indent -= 1; defer indent -= 1;
const info = self.constant_pool.getTag(interface, .class) catch return error.WriteFailed; 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;
try w.splatByteAll(' ', depth * indent); try w.splatByteAll(' ', depth * indent);
try w.print("{d}:\n", .{ i }); try w.print("{d}:\n", .{ i });
try info.indentedFormat(w, depth, indent + 1, self.constant_pool); try cp_info.?.format(w, depth, indent + 1, self.constant_pool);
} }
_ = try w.write("fields:\n"); _ = try w.write("fields:\n");
@ -233,7 +274,7 @@ pub fn format(self: *const Self, w: *std.Io.Writer) std.Io.Writer.Error!void {
try w.splatByteAll(' ', depth * indent); try w.splatByteAll(' ', depth * indent);
try w.print("{d}:\n", .{ i }); try w.print("{d}:\n", .{ i });
try field.indentedFormat(w, depth, indent + 1, self.constant_pool); try field.format(w, depth, indent + 1, self.allocator, self.constant_pool);
} }
_ = try w.write("methods:\n"); _ = try w.write("methods:\n");
@ -243,7 +284,7 @@ pub fn format(self: *const Self, w: *std.Io.Writer) std.Io.Writer.Error!void {
try w.splatByteAll(' ', depth * indent); try w.splatByteAll(' ', depth * indent);
try w.print("{d}:\n", .{ i }); try w.print("{d}:\n", .{ i });
try method.indentedFormat(w, depth, indent + 1, self.constant_pool); try method.format(w, depth, indent + 1, self.allocator, self.constant_pool);
} }
_ = try w.write("attributes:\n"); _ = try w.write("attributes:\n");
@ -253,15 +294,476 @@ pub fn format(self: *const Self, w: *std.Io.Writer) std.Io.Writer.Error!void {
try w.splatByteAll(' ', depth * indent); try w.splatByteAll(' ', depth * indent);
try w.print("{d}:\n", .{ i }); try w.print("{d}:\n", .{ i });
try attribute.indentedFormat(w, depth, indent + 1, self.constant_pool); try attribute.format(w, depth, indent + 1, self.allocator, self.constant_pool);
} }
} }
pub fn thisClass(self: *const Self) ResolveError!ConstantPool.Info { pub fn thisClass(self: *const Self) ResolveError!ConstantPoolInfo {
return self.constant_pool.getTag(self.this_class, .class); 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 superClass(self: *const Self) ResolveError!?ConstantPool.Info { pub fn superClass(self: *const Self) ResolveError!?ConstantPoolInfo {
return self.constant_pool.getTagOptional(self.super_class, .class); 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 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

View file

@ -0,0 +1,26 @@
const std = @import("std");
const Class = @import("../../Class.zig");
const AttributeInfo = Class.AttributeInfo;
const ParseError = Class.ParseError;
const Instructions = @import("Instructions.zig").Instructions;
max_stack: u16,
max_locals: u16,
code: []Instructions,
exception_table: []ExceptionHandler,
attributes: []AttributeInfo,
const Self = @This();
pub const ExceptionHandler = struct {
start_pc: u16,
end_pc: u16,
handler_pc: u16,
catch_type: u16,
};
pub fn parse(input: *std.Io.Reader, allocator: std.mem.Allocator) ParseError!Self {
}

View file

@ -0,0 +1,582 @@
const std = @import("std");
const InstructionSet = enum(u8) {
aaload = 0x32,
aastore = 0x53,
aconst_null = 0x1,
aload = 0x19,
aload_0 = 0x2a,
aload_1 = 0x2b,
aload_2 = 0x2c,
aload_3 = 0x2d,
anewarray = 0xbd,
areturn = 0xb0,
arraylength = 0xbe,
astore = 0x3a,
astore_0 = 0x4b,
astore_1 = 0x4c,
astore_2 = 0x4d,
astore_3 = 0x4e,
athrow = 0xbf,
baload = 0x33,
bastore = 0x54,
bipush = 0x10,
caload = 0x34,
castore = 0x55,
checkcast = 0xc0,
d2f = 0x90,
d2i = 0x8e,
d2l = 0x8f,
dadd = 0x63,
daload = 0x31,
dastore = 0x52,
dcmpg = 0x98,
dcmpl = 0x97,
dconst_0 = 0xe,
dconst_1 = 0xf,
ddiv = 0x6f,
dload = 0x18,
dload_0 = 0x26,
dload_1 = 0x27,
dload_2 = 0x28,
dload_3 = 0x29,
dmul = 0x6b,
dneg = 0x77,
drem = 0x73,
dreturn = 0xaf,
dstore = 0x39,
dstore_0 = 0x47,
dstore_1 = 0x48,
dstore_2 = 0x49,
dstore_3 = 0x4a,
dsub = 0x67,
dup = 0x59,
dup_x1 = 0x5a,
dup_x2 = 0x5b,
dup2 = 0x5c,
dup2_x1 = 0x5d,
dup2_x2 = 0x5e,
f2d = 0x8d,
f2i = 0x8b,
f2l = 0x8c,
fadd = 0x62,
faload = 0x30,
fastore = 0x51,
fcmpg = 0x96,
fcmpl = 0x95,
fconst_0 = 0xb,
fconst_1 = 0xc,
fconst_2 = 0xd,
fdiv = 0x6e,
fload = 0x17,
fload_0 = 0x22,
fload_1 = 0x23,
fload_2 = 0x24,
fload_3 = 0x25,
fmul = 0x6a,
fneg = 0x76,
frem = 0x72,
freturn = 0xae,
fstore = 0x38,
fstore_0 = 0x43,
fstore_1 = 0x44,
fstore_2 = 0x45,
fstore_3 = 0x46,
fsub = 0x66,
getfield = 0xb4,
getstatic = 0xb2,
goto = 0xa7,
goto_w = 0xc8,
i2b = 0x91,
i2c = 0x92,
i2d = 0x87,
i2f = 0x86,
i2l = 0x85,
i2s = 0x93,
iadd = 0x60,
iaload = 0x2e,
iand = 0x7e,
iastore = 0x4f,
iconst_m1 = 0x2,
iconst_0 = 0x3,
iconst_1 = 0x4,
iconst_2 = 0x5,
iconst_3 = 0x6,
iconst_4 = 0x7,
iconst_5 = 0x8,
idiv = 0x6c,
if_acmpeq = 0xa5,
if_acmpne = 0xa6,
if_icmpeq = 0x9f,
if_icmpne = 0xa0,
if_icmplt = 0xa1,
if_icmpge = 0xa2,
if_icmpgt = 0xa3,
if_icmple = 0xa4,
ifeq = 0x99,
ifne = 0x9a,
iflt = 0x9b,
ifge = 0x9c,
ifgt = 0x9d,
ifle = 0x9e,
ifnonnull = 0xc7,
ifnull = 0xc6,
iinc = 0x84,
iload = 0x15,
iload_0 = 0x1a,
iload_1 = 0x1b,
iload_2 = 0x1c,
iload_3 = 0x1d,
imul = 0x68,
ineg = 0x74,
instanceof = 0xc1,
invokedynamic = 0xba,
invokeinterface = 0xb9,
invokespecial = 0xb7,
invokestatic = 0xb8,
invokevirtual = 0xb6,
ior = 0x80,
irem = 0x70,
ireturn = 0xac,
ishl = 0x78,
ishr = 0x7a,
istore = 0x36,
istore_0 = 0x3b,
istore_1 = 0x3c,
istore_2 = 0x3d,
istore_3 = 0x3e,
isub = 0x64,
iushr = 0x7c,
ixor = 0x82,
jsr = 0xa8,
jsr_2 = 0xc9,
l2d = 0x8a,
l2f = 0x89,
l2i = 0x88,
ladd = 0x61,
laload = 0x2f,
land = 0x7f,
lastore = 0x50,
lcmp = 0x94,
lconst_0 = 0x9,
lconst_1 = 0xa,
ldc = 0x12,
ldc_2 = 0x13,
ldc2_w = 0x14,
ldiv = 0x6d,
lload = 0x16,
lload_0 = 0x1e,
lload_1 = 0x1f,
lload_2 = 0x20,
lload_3 = 0x21,
lmul = 0x69,
lneg = 0x75,
lookupswitch = 0xab,
lor = 0x81,
lrem = 0x71,
lreturn = 0xad,
lshl = 0x79,
lshr = 0x7b,
lstore = 0x37,
lstore_0 = 0x3f,
lstore_1 = 0x40,
lstore_2 = 0x41,
lstore_3 = 0x42,
lsub = 0x65,
lushr = 0x7d,
lxor = 0x83,
monitorenter = 0xc2,
monitorexit = 0xc3,
multianewarray = 0xc5,
new = 0xbb,
newarray = 0xbc,
nop = 0x0,
pop = 0x57,
pop2 = 0x58,
putfield = 0xb5,
putstatic = 0xb3,
ret = 0xa9,
@"return" = 0xb1,
saload = 0x35,
sastore = 0x56,
sipush = 0x11,
swap = 0x5f,
tableswitch = 0xaa,
wide = 0xc4,
};
const IndexU8 = struct {
index: u8,
};
const IndexU16 = struct {
index: u16,
const Self = @This();
pub fn from(b1: u8, b2: u8) Self {
return .{ .index = (b1 << 8) | b2 };
}
};
const IndexU32 = struct {
index: u32,
const Self = @This();
pub fn from(b1: u8, b2: u8, b3: u8, b4: u8) Self {
return .{ .index = (b1 << 24) | (b2 << 16) | (b3 << 8) | b4 };
}
};
const Byte = struct {
byte: u8,
};
const BranchU16 = struct {
branch: u16,
const Self = @This();
pub fn from(b1: u8, b2: u8) Self {
return .{ .index = (b1 << 8) | b2 };
}
};
const BranchU32 = struct {
branch: u32,
const Self = @This();
pub fn from(b1: u8, b2: u8, b3: u8, b4: u8) Self {
return .{ .branch = (b1 << 24) | (b2 << 16) | (b3 << 8) | b4 };
}
};
const IInc = struct {
index: u8,
@"const": u8,
};
const InvokeDynamic = struct {
index: u16,
const Self = @This();
pub fn from(b1: u8, b2: u8, pad1: u8, pad2: u8) Self {
_ = pad1;
_ = pad2;
return .{ .index = (b1 << 8) | b2 };
}
};
const InvokeInterface = struct {
index: u16,
count: u8,
const Self = @This();
pub fn from(b1: u8, b2: u8, count: u8, pad: u8) Self {
_ = pad;
return .{ .index = (b1 << 8) | b2, .count = count };
}
};
const LookupSwitch = struct {
default: i32,
pairs: []Pair,
const Pair = struct {
match: u32,
offset: i32,
};
};
const MultiANewArray = struct {
index: u16,
dimensions: u8,
const Self = @This();
pub fn from(b1: u8, b2: u8, dimensions: u8) Self {
return .{ .index = (b1 << 8) | b2, .dimensions = dimensions };
}
};
const NewArray = struct {
array_type: ArrayType,
const Self = @This();
const ArrayType = enum(u8) {
boolean = 4,
char = 5,
float = 6,
double = 7,
byte = 8,
short = 9,
int = 10,
long = 11,
};
pub fn from(atype: u8) Self {
const array_type = std.enums.fromInt(ArrayType, atype) orelse {
std.log.err("Invalid array type");
std.process.exit(1);
};
return .{ .array_type = array_type };
}
};
const Short = struct {
short: u16,
const Self = @This();
pub fn from(b1: u8, b2: u8) Self {
return .{ .short = (b1 << 8) | b2 };
}
};
const TableSwitch = struct {
default: i32,
low: i32,
hight: i32,
offsets: []i32,
};
const Wide = union {
form1: struct {
opcode: ModifiableInstruction,
index: u16,
},
form2: struct {
// Should always be iinc
opcode: ModifiableInstruction,
index: u16,
@"const": u16,
},
const Self = @This();
const ModifiableInstruction = enum(u8) {
iload = 0x15,
fload = 0x17,
aload = 0x19,
lload = 0x16,
dload = 0x18,
istore = 0x36,
fstore = 0x38,
astore = 0x3a,
lstore = 0x37,
dstore = 0x39,
ret = 0xa9,
iinc = 0x84,
};
};
const Instructions = union(InstructionSet) {
aaload,
aastore,
aconst_null,
aload: IndexU8,
aload_0,
aload_1,
aload_2,
aload_3,
anewarray: IndexU16,
areturn,
arraylength,
astore: IndexU8,
astore_0,
astore_1,
astore_2,
astore_3,
athrow,
baload,
bastore,
bipush: Byte,
caload,
castore,
checkcast: IndexU16,
d2f,
d2i,
d2l,
dadd,
daload,
dastore,
dcmpg,
dcmpl,
dconst_0,
dconst_1,
ddiv,
dload: IndexU8,
dload_0,
dload_1,
dload_2,
dload_3,
dmul,
dneg,
drem,
dreturn,
dstore: IndexU8,
dstore_0,
dstore_1,
dstore_2,
dstore_3,
dsub,
dup,
dup_x1,
dup_x2,
dup2,
dup2_x1,
dup2_x2,
f2d,
f2i,
f2l,
fadd,
faload,
fastore,
fcmpg,
fcmpl,
fconst_0,
fconst_1,
fconst_2,
fdiv,
fload: IndexU8,
fload_0,
fload_1,
fload_2,
fload_3,
fmul,
fneg,
frem,
freturn,
fstore: IndexU8,
fstore_0,
fstore_1,
fstore_2,
fstore_3,
fsub,
getfield: IndexU16,
getstatic: IndexU16,
goto: IndexU16,
goto_w: IndexU32,
i2b,
i2c,
i2d,
i2f,
i2l,
i2s,
iadd,
iaload,
iand,
iastore,
iconst_m1,
iconst_0,
iconst_1,
iconst_2,
iconst_3,
iconst_4,
iconst_5,
idiv,
if_acmpeq: BranchU16,
if_acmpne: BranchU16,
if_icmpeq: BranchU16,
if_icmpne: BranchU16,
if_icmplt: BranchU16,
if_icmpge: BranchU16,
if_icmpgt: BranchU16,
if_icmple: BranchU16,
ifeq: BranchU16,
ifne: BranchU16,
iflt: BranchU16,
ifge: BranchU16,
ifgt: BranchU16,
ifle: BranchU16,
ifnonnull: BranchU16,
ifnull: BranchU16,
iinc: IInc,
iload: IndexU8,
iload_0,
iload_1,
iload_2,
iload_3,
imul,
ineg,
instanceof: IndexU16,
invokedynamic: InvokeDynamic,
invokeinterface: InvokeInterface,
invokespecial: IndexU16,
invokestatic: IndexU16,
invokevirtual: IndexU16,
ior,
irem,
ireturn,
ishl,
ishr,
istore: IndexU8,
istore_0,
istore_1,
istore_2,
istore_3,
isub,
iushr,
ixor,
jsr: BranchU16,
jsr_w: BranchU32,
l2d,
l2f,
l2i,
ladd,
laload,
land,
lastore,
lcmp,
lconst_0,
lconst_1,
ldc: IndexU8,
ldc_w: IndexU16,
ldc2_w: IndexU16,
ldiv,
lload: IndexU8,
lload_0,
lload_1,
lload_2,
lload_3,
lmul,
lneg,
lookupswitch: LookupSwitch,
lor,
lrem,
lreturn,
lshl,
lshr,
lstore: IndexU8,
lstore_0,
lstore_1,
lstore_2,
lstore_3,
lsub,
lushr,
lxor,
monitorenter,
monitorexit,
mulitanewarray: MultiANewArray,
new: IndexU16,
newarray: NewArray,
nop,
pop,
pop2,
putfield: IndexU16,
putstatic: IndexU16,
ret: IndexU8,
@"return",
saload,
sastore,
sipush: Short,
swap,
tableswitch: TableSwitch,
wide: Wide,
};

View file

@ -1,547 +0,0 @@
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);
}

View file

@ -3,7 +3,7 @@ const std = @import("std");
const EnumFlags = @import("../EnumFlags.zig").EnumFlags; const EnumFlags = @import("../EnumFlags.zig").EnumFlags;
const Class = @import("../Class.zig"); const Class = @import("../Class.zig");
const ConstantPool = Class.ConstantPool; const ConstantPoolInfo = Class.ConstantPoolInfo;
const AttributeInfo = Class.AttributeInfo; const AttributeInfo = Class.AttributeInfo;
const ResolveError = Class.ResolveError; const ResolveError = Class.ResolveError;
@ -14,7 +14,7 @@ attributes: []AttributeInfo,
const Self = @This(); const Self = @This();
pub const FieldAccessFlags = EnumFlags(enum(u16) { pub const FieldFlags = enum(u16) {
public = 0x0001, public = 0x0001,
private = 0x0002, private = 0x0002,
protected = 0x0004, protected = 0x0004,
@ -24,13 +24,15 @@ pub const FieldAccessFlags = EnumFlags(enum(u16) {
transient = 0x0080, transient = 0x0080,
synthetic = 0x1000, synthetic = 0x1000,
@"enum" = 0x4000, @"enum" = 0x4000,
}); };
pub fn parse(input: *std.Io.Reader, constant_pool: ConstantPool, allocator: std.mem.Allocator) !Self { pub const FieldAccessFlags = EnumFlags(FieldFlags);
const access_flags: FieldAccessFlags = .from(try input.takeInt(u16, .big));
pub fn parse(input: *std.Io.Reader, allocator: std.mem.Allocator) !Self {
const access_flags: FieldAccessFlags = .{ .mask = try input.takeInt(u16, .big) };
const name_index = try input.takeInt(u16, .big); const name_index = try input.takeInt(u16, .big);
const descriptor_index = try input.takeInt(u16, .big); const descriptor_index = try input.takeInt(u16, .big);
const attributes = try Class.parseAttributes(input, constant_pool, allocator); const attributes = try Class.parseAttributes(input, allocator);
return .{ return .{
.access_flags = access_flags, .access_flags = access_flags,
.name_index = name_index, .name_index = name_index,
@ -46,12 +48,13 @@ pub fn deinit(self: *Self, allocator: std.mem.Allocator) void {
allocator.free(self.attributes); allocator.free(self.attributes);
} }
pub fn indentedFormat( pub fn format(
self: *const Self, self: *const Self,
w: *std.Io.Writer, w: *std.Io.Writer,
depth: usize, depth: usize,
indent: u8, indent: u8,
constant_pool: ConstantPool, allocator: std.mem.Allocator,
constant_pool: []const ?ConstantPoolInfo,
) std.Io.Writer.Error!void { ) std.Io.Writer.Error!void {
try w.splatByteAll(' ', depth * indent); try w.splatByteAll(' ', depth * indent);
try w.print("flags: {f}\n", .{ self.access_flags }); try w.print("flags: {f}\n", .{ self.access_flags });
@ -59,12 +62,12 @@ pub fn indentedFormat(
try w.splatByteAll(' ', depth * indent); try w.splatByteAll(' ', depth * indent);
_ = try w.write("name:\n"); _ = try w.write("name:\n");
const field_name = self.name(constant_pool) catch return error.WriteFailed; const field_name = self.name(constant_pool) catch return error.WriteFailed;
try field_name.indentedFormat(w, depth, indent + 1, constant_pool); try field_name.format(w, depth, indent + 1, constant_pool);
try w.splatByteAll(' ', depth * indent); try w.splatByteAll(' ', depth * indent);
_ = try w.write("descriptor:\n"); _ = try w.write("descriptor:\n");
const field_descriptor = self.descriptor(constant_pool) catch return error.WriteFailed; const field_descriptor = self.descriptor(constant_pool) catch return error.WriteFailed;
try field_descriptor.indentedFormat(w, depth, indent + 1, constant_pool); try field_descriptor.format(w, depth, indent + 1, constant_pool);
try w.splatByteAll(' ', depth * indent); try w.splatByteAll(' ', depth * indent);
_ = try w.write("attributes:\n"); _ = try w.write("attributes:\n");
@ -76,15 +79,23 @@ pub fn indentedFormat(
try w.splatByteAll(' ', depth * attr_indent); try w.splatByteAll(' ', depth * attr_indent);
try w.print("{d}:\n", .{ j }); try w.print("{d}:\n", .{ j });
try attribute.indentedFormat(w, depth, attr_indent + 1, constant_pool); try attribute.format(w, depth, attr_indent + 1, allocator, constant_pool);
} }
} }
pub fn name(self: *const Self, constant_pool: ConstantPool) ResolveError!ConstantPool.Info { pub fn name(self: *const Self, constant_pool: []const ?ConstantPoolInfo) ResolveError!ConstantPoolInfo {
return constant_pool.getTag(self.name_index, .utf8); 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 Self, constant_pool: ConstantPool) ResolveError!ConstantPool.Info { pub fn descriptor(self: *const Self, constant_pool: []const ?ConstantPoolInfo) ResolveError!ConstantPoolInfo {
return constant_pool.getTag(self.descriptor_index, .utf8); 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.?;
} }

View file

@ -3,7 +3,7 @@ const std = @import("std");
const EnumFlags = @import("../EnumFlags.zig").EnumFlags; const EnumFlags = @import("../EnumFlags.zig").EnumFlags;
const Class = @import("../Class.zig"); const Class = @import("../Class.zig");
const ConstantPool = Class.ConstantPool; const ConstantPoolInfo = Class.ConstantPoolInfo;
const AttributeInfo = Class.AttributeInfo; const AttributeInfo = Class.AttributeInfo;
const ResolveError = Class.ResolveError; const ResolveError = Class.ResolveError;
@ -14,7 +14,7 @@ attributes: []AttributeInfo,
const Self = @This(); const Self = @This();
pub const MethodAccessFlags = EnumFlags(enum(u16) { pub const MethodFlags = enum(u16) {
public = 0x0001, public = 0x0001,
private = 0x0002, private = 0x0002,
protected = 0x0004, protected = 0x0004,
@ -27,13 +27,15 @@ pub const MethodAccessFlags = EnumFlags(enum(u16) {
abstract = 0x0400, abstract = 0x0400,
strict = 0x0800, strict = 0x0800,
synthetic = 0x1000, synthetic = 0x1000,
}); };
pub fn parse(input: *std.Io.Reader, constant_pool: ConstantPool, allocator: std.mem.Allocator) !Self { pub const MethodAccessFlags = EnumFlags(MethodFlags);
const access_flags: MethodAccessFlags = .from(try input.takeInt(u16, .big));
pub fn parse(input: *std.Io.Reader, allocator: std.mem.Allocator) !Self {
const access_flags: MethodAccessFlags = .{ .mask = try input.takeInt(u16, .big) };
const name_index = try input.takeInt(u16, .big); const name_index = try input.takeInt(u16, .big);
const descriptor_index = try input.takeInt(u16, .big); const descriptor_index = try input.takeInt(u16, .big);
const attributes = try Class.parseAttributes(input, constant_pool, allocator); const attributes = try Class.parseAttributes(input, allocator);
return .{ return .{
.access_flags = access_flags, .access_flags = access_flags,
.name_index = name_index, .name_index = name_index,
@ -49,12 +51,13 @@ pub fn deinit(self: *Self, allocator: std.mem.Allocator) void {
allocator.free(self.attributes); allocator.free(self.attributes);
} }
pub fn indentedFormat( pub fn format(
self: *const Self, self: *const Self,
w: *std.Io.Writer, w: *std.Io.Writer,
depth: usize, depth: usize,
indent: u8, indent: u8,
constant_pool: ConstantPool, allocator: std.mem.Allocator,
constant_pool: []const ?ConstantPoolInfo,
) std.Io.Writer.Error!void { ) std.Io.Writer.Error!void {
try w.splatByteAll(' ', depth * indent); try w.splatByteAll(' ', depth * indent);
try w.print("flags: {f}\n", .{ self.access_flags }); try w.print("flags: {f}\n", .{ self.access_flags });
@ -62,12 +65,12 @@ pub fn indentedFormat(
try w.splatByteAll(' ', depth * indent); try w.splatByteAll(' ', depth * indent);
_ = try w.write("name:\n"); _ = try w.write("name:\n");
const method_name = self.name(constant_pool) catch return error.WriteFailed; const method_name = self.name(constant_pool) catch return error.WriteFailed;
try method_name.indentedFormat(w, depth, indent + 1, constant_pool); try method_name.format(w, depth, indent + 1, constant_pool);
try w.splatByteAll(' ', depth * indent); try w.splatByteAll(' ', depth * indent);
_ = try w.write("descriptor:\n"); _ = try w.write("descriptor:\n");
const method_descriptor = self.descriptor(constant_pool) catch return error.WriteFailed; const method_descriptor = self.descriptor(constant_pool) catch return error.WriteFailed;
try method_descriptor.indentedFormat(w, depth, indent + 1, constant_pool); try method_descriptor.format(w, depth, indent + 1, constant_pool);
try w.splatByteAll(' ', depth * indent); try w.splatByteAll(' ', depth * indent);
_ = try w.write("attributes:\n"); _ = try w.write("attributes:\n");
@ -79,14 +82,23 @@ pub fn indentedFormat(
try w.splatByteAll(' ', depth * attr_indent); try w.splatByteAll(' ', depth * attr_indent);
try w.print("{d}:\n", .{ j }); try w.print("{d}:\n", .{ j });
try attribute.indentedFormat(w, depth, attr_indent + 1, constant_pool); try attribute.format(w, depth, attr_indent + 1, allocator, constant_pool);
} }
} }
pub fn name(self: *const Self, constant_pool: ConstantPool) ResolveError!ConstantPool.Info { pub fn name(self: *const Self, constant_pool: []const ?ConstantPoolInfo) ResolveError!ConstantPoolInfo {
return constant_pool.getTag(self.name_index, .utf8); 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 Self, constant_pool: ConstantPool) ResolveError!ConstantPool.Info { pub fn descriptor(self: *const Self, constant_pool: []const ?ConstantPoolInfo) ResolveError!ConstantPoolInfo {
return constant_pool.getTag(self.descriptor_index, .utf8); 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.?;
} }

View file

@ -10,12 +10,6 @@ pub fn EnumFlags(comptime E: type) type {
pub const empty: Self = .{ .data = 0 }; pub const empty: Self = .{ .data = 0 };
pub fn from(mask: BackingInt) Self {
return .{
.mask = mask,
};
}
pub fn contains(self: Self, flag: E) bool { pub fn contains(self: Self, flag: E) bool {
return (self.mask & @intFromEnum(flag)) != 0; return (self.mask & @intFromEnum(flag)) != 0;
} }

View file

@ -50,9 +50,10 @@ pub fn main(init: std.process.Init) !void {
}, },
else => return err, else => return err,
}; };
defer class.deinit(allocator); defer class.deinit();
try stdout.print("{f}", .{ class }); try stdout.print("{f}", .{ class });
try stdout.flush(); try stdout.flush();
} }

View file

@ -1,3 +0,0 @@
*.class
!Object.class
META-INF

View file

@ -1,14 +0,0 @@
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";
}

View file

@ -1,9 +0,0 @@
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 { }

View file

@ -1,5 +0,0 @@
public enum CustomAnnotationType {
ONE,
TWO,
}

View file

@ -1,9 +0,0 @@
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 { }

View file

@ -1,9 +0,0 @@
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 {
}

View file

@ -1,14 +0,0 @@
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;
}
};
}
}

View file

@ -1,6 +0,0 @@
class Hello {
public static void main(String[] args) {
System.out.println("Hello, world!");
}
}

View file

@ -1,22 +0,0 @@
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;
}
}

Binary file not shown.

View file

@ -1,2 +0,0 @@
public record Record(String name, int age) {}

View file

@ -1,12 +0,0 @@
fun main() {
println("Hello, world!")
Test().apply {
test = true
}
}
class Test {
var test: Boolean = false
}

View file

@ -1,2 +0,0 @@
#!/usr/bin/env bash
javac -g -d outDir --module-source-path simple-modules $(find simple-modules -name "*.java")

View file

@ -1,2 +0,0 @@
#!/usr/bin/env bash
java --module-path outDir -m main.app/dev.katkak.modules.main.MainApp

View file

@ -1,6 +0,0 @@
package dev.katkak.modules.hello;
public interface HelloInterface {
void sayHello();
}

View file

@ -1,12 +0,0 @@
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!");
}
}

View file

@ -1,6 +0,0 @@
module hello.modules {
exports dev.katkak.modules.hello;
provides dev.katkak.modules.hello.HelloInterface with dev.katkak.modules.hello.HelloModules;
}

View file

@ -1,17 +0,0 @@
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();
}
}

View file

@ -1,6 +0,0 @@
module main.app {
requires hello.modules;
uses dev.katkak.modules.hello.HelloInterface;
}