Compare commits
2 commits
master
...
feature/in
| Author | SHA1 | Date | |
|---|---|---|---|
| 28ac986827 | |||
| 51e90fae80 |
31 changed files with 2110 additions and 3747 deletions
|
|
@ -1,27 +1,17 @@
|
|||
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(@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");
|
||||
}
|
||||
public static void main() {
|
||||
new Main().sayHello();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void run() {
|
||||
Main.main(new String[] { "Hello" });
|
||||
Main.main();
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
@ -47,3 +37,4 @@ public class Main implements Runnable, Supplier<Integer>, Interface {
|
|||
private static final String name = "Inner John";
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -19,8 +19,6 @@
|
|||
zls
|
||||
javaPackages.compiler.openjdk25
|
||||
jdt-language-server
|
||||
kotlin
|
||||
kotlin-language-server
|
||||
];
|
||||
|
||||
buildInputs = with pkgs; [];
|
||||
|
|
|
|||
596
src/Class.zig
596
src/Class.zig
|
|
@ -4,13 +4,14 @@ 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").AttributeInfo;
|
||||
pub const ConstantPool = @import("Class/ConstantPool.zig");
|
||||
pub const AttributeInfo = @import("Class/AttributeInfo.zig");
|
||||
|
||||
allocator: std.mem.Allocator,
|
||||
|
||||
magic: u32,
|
||||
minor_version: u16,
|
||||
major_version: u16,
|
||||
constant_pool: ConstantPool,
|
||||
constant_pool: []?ConstantPoolInfo,
|
||||
access_flags: ClassAccessFlags,
|
||||
this_class: u16,
|
||||
super_class: u16,
|
||||
|
|
@ -21,7 +22,7 @@ attributes: []AttributeInfo,
|
|||
|
||||
const Self = @This();
|
||||
|
||||
pub const ClassAccessFlags = EnumFlags(enum(u16) {
|
||||
pub const ClassFlags = enum(u16) {
|
||||
public = 0x0001,
|
||||
final = 0x0010,
|
||||
super = 0x0020,
|
||||
|
|
@ -30,8 +31,9 @@ pub const ClassAccessFlags = EnumFlags(enum(u16) {
|
|||
synthetic = 0x1000,
|
||||
annotation = 0x2000,
|
||||
@"enum" = 0x4000,
|
||||
module = 0x8000,
|
||||
});
|
||||
};
|
||||
|
||||
pub const ClassAccessFlags = EnumFlags(ClassFlags);
|
||||
|
||||
pub const ParseError = std.Io.Reader.Error || std.mem.Allocator.Error || error {
|
||||
InvalidMagicNumber,
|
||||
|
|
@ -43,7 +45,7 @@ pub const ResolveError = error {
|
|||
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);
|
||||
if (magic != 0xCAFEBABE) {
|
||||
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 major_version = try input.takeInt(u16, .big);
|
||||
|
||||
var constant_pool: ConstantPool = try .parse(input, allocator);
|
||||
errdefer constant_pool.deinit(allocator);
|
||||
const constant_pool = try parseConstantPool(input, 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 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);
|
||||
errdefer allocator.free(interfaces);
|
||||
|
||||
const fields = try parseFields(input, constant_pool, allocator);
|
||||
const fields = try parseFields(input, allocator);
|
||||
errdefer {
|
||||
for (fields) |*field| {
|
||||
field.deinit(allocator);
|
||||
|
|
@ -71,7 +78,7 @@ pub fn parse(input: *std.Io.Reader, allocator: std.mem.Allocator) (ParseError ||
|
|||
allocator.free(fields);
|
||||
}
|
||||
|
||||
const methods = try parseMethods(input, constant_pool, allocator);
|
||||
const methods = try parseMethods(input, allocator);
|
||||
errdefer {
|
||||
for (methods) |*method| {
|
||||
method.deinit(allocator);
|
||||
|
|
@ -79,7 +86,7 @@ pub fn parse(input: *std.Io.Reader, allocator: std.mem.Allocator) (ParseError ||
|
|||
allocator.free(methods);
|
||||
}
|
||||
|
||||
const attributes = try parseAttributes(input, constant_pool, allocator);
|
||||
const attributes = try parseAttributes(input, allocator);
|
||||
errdefer {
|
||||
for (attributes) |*attribute| {
|
||||
attribute.deinit(allocator);
|
||||
|
|
@ -88,6 +95,7 @@ pub fn parse(input: *std.Io.Reader, allocator: std.mem.Allocator) (ParseError ||
|
|||
}
|
||||
|
||||
return .{
|
||||
.allocator = allocator,
|
||||
.magic = magic,
|
||||
.minor_version = minor_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 {
|
||||
const interfaces_count = try input.takeInt(u16, .big);
|
||||
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;
|
||||
}
|
||||
|
||||
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 = try allocator.alloc(FieldInfo, fields_count);
|
||||
errdefer allocator.free(fields);
|
||||
|
||||
for (0..fields_count) |i| {
|
||||
fields[i] = try FieldInfo.parse(input, constant_pool, allocator);
|
||||
fields[i] = try FieldInfo.parse(input, allocator);
|
||||
}
|
||||
|
||||
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 = try allocator.alloc(MethodInfo, methods_count);
|
||||
errdefer allocator.free(methods);
|
||||
|
||||
for (0..methods_count) |i| {
|
||||
methods[i] = try .parse(input, constant_pool, allocator);
|
||||
methods[i] = try MethodInfo.parse(input, allocator);
|
||||
}
|
||||
|
||||
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 = try allocator.alloc(AttributeInfo, attributes_count);
|
||||
errdefer allocator.free(attributes);
|
||||
|
||||
for (0..attributes_count) |i| {
|
||||
attributes[i] = try AttributeInfo.parse(input, constant_pool, allocator);
|
||||
attributes[i] = try AttributeInfo.parse(input, allocator);
|
||||
}
|
||||
|
||||
return attributes;
|
||||
}
|
||||
|
||||
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);
|
||||
pub fn deinit(self: *Self) void {
|
||||
self.freeConstantPool();
|
||||
self.freeInterfaces();
|
||||
self.freeFields();
|
||||
self.freeMethods();
|
||||
self.freeAttributes();
|
||||
}
|
||||
|
||||
fn freeInterfaces(self: *Self, allocator: std.mem.Allocator) void {
|
||||
allocator.free(self.interfaces);
|
||||
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 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| {
|
||||
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| {
|
||||
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| {
|
||||
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 {
|
||||
|
|
@ -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;
|
||||
_ = 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");
|
||||
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");
|
||||
|
|
@ -219,11 +258,13 @@ pub fn format(self: *const Self, w: *std.Io.Writer) std.Io.Writer.Error!void {
|
|||
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.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");
|
||||
|
|
@ -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.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");
|
||||
|
|
@ -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.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");
|
||||
|
|
@ -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.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 {
|
||||
return self.constant_pool.getTag(self.this_class, .class);
|
||||
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 superClass(self: *const Self) ResolveError!?ConstantPool.Info {
|
||||
return self.constant_pool.getTagOptional(self.super_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 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
26
src/Class/AttributeInfo/Code.zig
Normal file
26
src/Class/AttributeInfo/Code.zig
Normal 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 {
|
||||
}
|
||||
|
||||
582
src/Class/AttributeInfo/Instructions.zig
Normal file
582
src/Class/AttributeInfo/Instructions.zig
Normal 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,
|
||||
};
|
||||
|
||||
|
|
@ -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);
|
||||
}
|
||||
|
|
@ -3,7 +3,7 @@ const std = @import("std");
|
|||
const EnumFlags = @import("../EnumFlags.zig").EnumFlags;
|
||||
|
||||
const Class = @import("../Class.zig");
|
||||
const ConstantPool = Class.ConstantPool;
|
||||
const ConstantPoolInfo = Class.ConstantPoolInfo;
|
||||
const AttributeInfo = Class.AttributeInfo;
|
||||
const ResolveError = Class.ResolveError;
|
||||
|
||||
|
|
@ -14,7 +14,7 @@ attributes: []AttributeInfo,
|
|||
|
||||
const Self = @This();
|
||||
|
||||
pub const FieldAccessFlags = EnumFlags(enum(u16) {
|
||||
pub const FieldFlags = enum(u16) {
|
||||
public = 0x0001,
|
||||
private = 0x0002,
|
||||
protected = 0x0004,
|
||||
|
|
@ -24,13 +24,15 @@ pub const FieldAccessFlags = EnumFlags(enum(u16) {
|
|||
transient = 0x0080,
|
||||
synthetic = 0x1000,
|
||||
@"enum" = 0x4000,
|
||||
});
|
||||
};
|
||||
|
||||
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));
|
||||
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) };
|
||||
const name_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 .{
|
||||
.access_flags = access_flags,
|
||||
.name_index = name_index,
|
||||
|
|
@ -46,12 +48,13 @@ pub fn deinit(self: *Self, allocator: std.mem.Allocator) void {
|
|||
allocator.free(self.attributes);
|
||||
}
|
||||
|
||||
pub fn indentedFormat(
|
||||
pub fn format(
|
||||
self: *const Self,
|
||||
w: *std.Io.Writer,
|
||||
depth: usize,
|
||||
indent: u8,
|
||||
constant_pool: ConstantPool,
|
||||
allocator: std.mem.Allocator,
|
||||
constant_pool: []const ?ConstantPoolInfo,
|
||||
) std.Io.Writer.Error!void {
|
||||
try w.splatByteAll(' ', depth * indent);
|
||||
try w.print("flags: {f}\n", .{ self.access_flags });
|
||||
|
|
@ -59,12 +62,12 @@ pub fn indentedFormat(
|
|||
try w.splatByteAll(' ', depth * indent);
|
||||
_ = try w.write("name:\n");
|
||||
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.write("descriptor:\n");
|
||||
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.write("attributes:\n");
|
||||
|
|
@ -76,15 +79,23 @@ pub fn indentedFormat(
|
|||
try w.splatByteAll(' ', depth * attr_indent);
|
||||
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 {
|
||||
return constant_pool.getTag(self.name_index, .utf8);
|
||||
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 descriptor(self: *const Self, constant_pool: ConstantPool) ResolveError!ConstantPool.Info {
|
||||
return constant_pool.getTag(self.descriptor_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.?;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -3,7 +3,7 @@ const std = @import("std");
|
|||
const EnumFlags = @import("../EnumFlags.zig").EnumFlags;
|
||||
|
||||
const Class = @import("../Class.zig");
|
||||
const ConstantPool = Class.ConstantPool;
|
||||
const ConstantPoolInfo = Class.ConstantPoolInfo;
|
||||
const AttributeInfo = Class.AttributeInfo;
|
||||
const ResolveError = Class.ResolveError;
|
||||
|
||||
|
|
@ -14,7 +14,7 @@ attributes: []AttributeInfo,
|
|||
|
||||
const Self = @This();
|
||||
|
||||
pub const MethodAccessFlags = EnumFlags(enum(u16) {
|
||||
pub const MethodFlags = enum(u16) {
|
||||
public = 0x0001,
|
||||
private = 0x0002,
|
||||
protected = 0x0004,
|
||||
|
|
@ -27,13 +27,15 @@ pub const MethodAccessFlags = EnumFlags(enum(u16) {
|
|||
abstract = 0x0400,
|
||||
strict = 0x0800,
|
||||
synthetic = 0x1000,
|
||||
});
|
||||
};
|
||||
|
||||
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));
|
||||
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) };
|
||||
const name_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 .{
|
||||
.access_flags = access_flags,
|
||||
.name_index = name_index,
|
||||
|
|
@ -49,12 +51,13 @@ pub fn deinit(self: *Self, allocator: std.mem.Allocator) void {
|
|||
allocator.free(self.attributes);
|
||||
}
|
||||
|
||||
pub fn indentedFormat(
|
||||
pub fn format(
|
||||
self: *const Self,
|
||||
w: *std.Io.Writer,
|
||||
depth: usize,
|
||||
indent: u8,
|
||||
constant_pool: ConstantPool,
|
||||
allocator: std.mem.Allocator,
|
||||
constant_pool: []const ?ConstantPoolInfo,
|
||||
) std.Io.Writer.Error!void {
|
||||
try w.splatByteAll(' ', depth * indent);
|
||||
try w.print("flags: {f}\n", .{ self.access_flags });
|
||||
|
|
@ -62,12 +65,12 @@ pub fn indentedFormat(
|
|||
try w.splatByteAll(' ', depth * indent);
|
||||
_ = try w.write("name:\n");
|
||||
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.write("descriptor:\n");
|
||||
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.write("attributes:\n");
|
||||
|
|
@ -79,14 +82,23 @@ pub fn indentedFormat(
|
|||
try w.splatByteAll(' ', depth * attr_indent);
|
||||
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 {
|
||||
return constant_pool.getTag(self.name_index, .utf8);
|
||||
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 descriptor(self: *const Self, constant_pool: ConstantPool) ResolveError!ConstantPool.Info {
|
||||
return constant_pool.getTag(self.descriptor_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.?;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -10,12 +10,6 @@ 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,9 +50,10 @@ pub fn main(init: std.process.Init) !void {
|
|||
},
|
||||
else => return err,
|
||||
};
|
||||
defer class.deinit(allocator);
|
||||
defer class.deinit();
|
||||
|
||||
try stdout.print("{f}", .{ class });
|
||||
|
||||
try stdout.flush();
|
||||
}
|
||||
|
||||
|
|
|
|||
3
testsuite/.gitignore
vendored
3
testsuite/.gitignore
vendored
|
|
@ -1,3 +0,0 @@
|
|||
*.class
|
||||
!Object.class
|
||||
META-INF
|
||||
|
|
@ -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";
|
||||
}
|
||||
|
||||
|
|
@ -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 { }
|
||||
|
||||
|
|
@ -1,5 +0,0 @@
|
|||
public enum CustomAnnotationType {
|
||||
ONE,
|
||||
TWO,
|
||||
}
|
||||
|
||||
|
|
@ -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 { }
|
||||
|
||||
|
|
@ -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 {
|
||||
}
|
||||
|
|
@ -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;
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -1,6 +0,0 @@
|
|||
class Hello {
|
||||
public static void main(String[] args) {
|
||||
System.out.println("Hello, world!");
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -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.
|
|
@ -1,2 +0,0 @@
|
|||
public record Record(String name, int age) {}
|
||||
|
||||
|
|
@ -1,12 +0,0 @@
|
|||
fun main() {
|
||||
println("Hello, world!")
|
||||
|
||||
Test().apply {
|
||||
test = true
|
||||
}
|
||||
}
|
||||
|
||||
class Test {
|
||||
var test: Boolean = false
|
||||
}
|
||||
|
||||
|
|
@ -1,2 +0,0 @@
|
|||
#!/usr/bin/env bash
|
||||
javac -g -d outDir --module-source-path simple-modules $(find simple-modules -name "*.java")
|
||||
|
|
@ -1,2 +0,0 @@
|
|||
#!/usr/bin/env bash
|
||||
java --module-path outDir -m main.app/dev.katkak.modules.main.MainApp
|
||||
|
|
@ -1,6 +0,0 @@
|
|||
package dev.katkak.modules.hello;
|
||||
|
||||
public interface HelloInterface {
|
||||
void sayHello();
|
||||
}
|
||||
|
||||
|
|
@ -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!");
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -1,6 +0,0 @@
|
|||
module hello.modules {
|
||||
exports dev.katkak.modules.hello;
|
||||
|
||||
provides dev.katkak.modules.hello.HelloInterface with dev.katkak.modules.hello.HelloModules;
|
||||
}
|
||||
|
||||
|
|
@ -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();
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -1,6 +0,0 @@
|
|||
module main.app {
|
||||
requires hello.modules;
|
||||
|
||||
uses dev.katkak.modules.hello.HelloInterface;
|
||||
}
|
||||
|
||||
Loading…
Add table
Add a link
Reference in a new issue