Compare commits
No commits in common. "176be5dad8ee5e418ef3eda0e1eb9be0eba5b2e5" and "28ac98682734235ba2508b1bf98dfe2c3d21baa3" have entirely different histories.
176be5dad8
...
28ac986827
32 changed files with 2145 additions and 4919 deletions
40
Main.java
Normal file
40
Main.java
Normal file
|
|
@ -0,0 +1,40 @@
|
|||
import java.util.function.Supplier;
|
||||
|
||||
public class Main implements Runnable, Supplier<Integer>, Interface {
|
||||
private static final String name = "John";
|
||||
private static final int number = 42;
|
||||
private static final double funnyNumber = 6.9;
|
||||
|
||||
public static void main() {
|
||||
new Main().sayHello();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void run() {
|
||||
Main.main();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Integer get() {
|
||||
return number;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getName() {
|
||||
return name;
|
||||
}
|
||||
|
||||
public void throwSomething() throws Throwable {
|
||||
throw new Throwable() {
|
||||
@Override
|
||||
public String getMessage() {
|
||||
return "Hello";
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
public static class Inner {
|
||||
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; [];
|
||||
|
|
|
|||
598
src/Class.zig
598
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,14 +31,13 @@ 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,
|
||||
InvalidTag,
|
||||
InvalidOp,
|
||||
InvalidArrayType,
|
||||
};
|
||||
|
||||
pub const ResolveError = error {
|
||||
|
|
@ -45,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;
|
||||
|
|
@ -54,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);
|
||||
|
|
@ -65,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);
|
||||
|
|
@ -73,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);
|
||||
|
|
@ -81,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);
|
||||
|
|
@ -90,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,
|
||||
|
|
@ -104,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);
|
||||
|
|
@ -116,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 {
|
||||
|
|
@ -209,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");
|
||||
|
|
@ -221,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");
|
||||
|
|
@ -235,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");
|
||||
|
|
@ -245,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");
|
||||
|
|
@ -255,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,
|
||||
};
|
||||
|
||||
File diff suppressed because it is too large
Load diff
|
|
@ -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,95 +0,0 @@
|
|||
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");
|
||||
}
|
||||
|
||||
var a = 8;
|
||||
a <<= 3;
|
||||
final var b = a >> 1;
|
||||
switch (b) {
|
||||
case 1:
|
||||
break;
|
||||
case 32:
|
||||
System.out.println("Good");
|
||||
break;
|
||||
default:
|
||||
System.out.println("Number " + a);
|
||||
break;
|
||||
}
|
||||
|
||||
final var o = getObject();
|
||||
switch (o) {
|
||||
case Integer i:
|
||||
switch (i) {
|
||||
case 1:
|
||||
System.out.println("One");
|
||||
break;
|
||||
case 2:
|
||||
System.out.println("Two");
|
||||
break;
|
||||
case 3:
|
||||
System.out.println("Three");
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
System.out.println("Something else");
|
||||
break;
|
||||
}
|
||||
|
||||
inc(5);
|
||||
}
|
||||
|
||||
private static Object getObject() {
|
||||
return 3;
|
||||
}
|
||||
|
||||
private static void inc(int i) {
|
||||
i += 1000;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void run() {
|
||||
Main.main(new String[] { "Hello" });
|
||||
}
|
||||
|
||||
@Override
|
||||
public Integer get() {
|
||||
return number;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getName() {
|
||||
return name;
|
||||
}
|
||||
|
||||
public void throwSomething() throws Throwable {
|
||||
throw new Throwable() {
|
||||
@Override
|
||||
public String getMessage() {
|
||||
return "Hello";
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
public static class Inner {
|
||||
private static final String name = "Inner John";
|
||||
}
|
||||
}
|
||||
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
|
@ -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