Format annotation attributes

This commit is contained in:
ktkk 2026-07-07 13:38:46 +00:00
parent 3a5fd90d14
commit f12bcd2911
6 changed files with 275 additions and 16 deletions

View file

@ -447,10 +447,58 @@ pub const AttributeInfo = union(enum) {
}
},
.deprecated => {},
//.runtime_visible_annotations,
//.runtime_invisible_annotations,
//.runtime_visible_parameter_annotations,
//.runtime_invisible_parameter_annotations,
.runtime_visible_annotations => |attr| {
try w.splatByteAll(' ', depth * indent);
_ = try w.write("annotations:\n");
var annotation_indent = indent;
for (attr.annotations, 0..) |annotation, i| {
annotation_indent += 1;
defer annotation_indent -= 1;
try w.splatByteAll(' ', depth * annotation_indent);
try w.print("{d}:\n", .{ i });
try annotation.indentedFormat(w, depth, annotation_indent + 1, constant_pool);
}
},
.runtime_invisible_annotations => |attr| {
try w.splatByteAll(' ', depth * indent);
_ = try w.write("annotations:\n");
var annotation_indent = indent;
for (attr.annotations, 0..) |annotation, i| {
annotation_indent += 1;
defer annotation_indent -= 1;
try w.splatByteAll(' ', depth * annotation_indent);
try w.print("{d}:\n", .{ i });
try annotation.indentedFormat(w, depth, annotation_indent + 1, constant_pool);
}
},
.runtime_visible_parameter_annotations => |attr| {
try w.splatByteAll(' ', depth * indent);
_ = try w.write("parameter_annotations:\n");
var parameter_annotation_indent = indent;
for (attr.parameter_annotations, 0..) |parameter_annotation, i| {
parameter_annotation_indent += 1;
defer parameter_annotation_indent -= 1;
try w.splatByteAll(' ', depth * parameter_annotation_indent);
try w.print("{d}:\n", .{ i });
try parameter_annotation.indentedFormat(w, depth, parameter_annotation_indent + 1, constant_pool);
}
},
.runtime_invisible_parameter_annotations => |attr| {
try w.splatByteAll(' ', depth * indent);
_ = try w.write("parameter_annotations:\n");
var parameter_annotation_indent = indent;
for (attr.parameter_annotations, 0..) |parameter_annotation, i| {
parameter_annotation_indent += 1;
defer parameter_annotation_indent -= 1;
try w.splatByteAll(' ', depth * parameter_annotation_indent);
try w.print("{d}:\n", .{ i });
try parameter_annotation.indentedFormat(w, depth, parameter_annotation_indent + 1, constant_pool);
}
},
//.runtime_visible_type_annotations,
//.runtime_invisible_type_annotations,
//.annotation_default,
@ -1381,14 +1429,11 @@ pub const Deprecated = struct { };
pub const ElementValue = union(enum) {
// B, C, D, F, I, J, S, Z, s
const_value_index: u16,
const_value: ConstValue,
// e
enum_const_value: struct {
type_name_index: u16,
const_name_index: u16,
},
enum_const_value: EnumConstValue,
// c
class_info_index: u16,
class_const_value: ClassConstValue,
// @
annotation_value: Annotation,
// [
@ -1396,11 +1441,78 @@ pub const ElementValue = union(enum) {
values: []ElementValue,
},
pub const ConstValue = struct {
@"type": Type,
index: u16,
pub const Type = enum(u8) {
byte = 'B',
char = 'C',
double = 'D',
float = 'F',
int = 'I',
long = 'J',
short = 'S',
boolean = 'Z',
string = 's',
};
pub fn value(self: *const ConstValue, constant_pool: ConstantPool) ResolveError!ConstantPool.Info {
const value_ = try constant_pool.get(self.index);
return switch (self.@"type") {
.byte, .char, .int, .short, .boolean => blk: {
if (!value_.is(.integer)) break :blk ResolveError.InvalidConstantType;
break :blk value_;
},
.double => blk: {
if (!value_.is(.double)) break :blk ResolveError.InvalidConstantType;
break :blk value_;
},
.float => blk: {
if (!value_.is(.float)) break :blk ResolveError.InvalidConstantType;
break :blk value_;
},
.long => blk: {
if (!value_.is(.long)) break :blk ResolveError.InvalidConstantType;
break :blk value_;
},
.string => blk: {
if (!value_.is(.utf8)) break :blk ResolveError.InvalidConstantType;
break :blk value_;
},
};
}
};
pub const EnumConstValue = struct {
type_name_index: u16,
const_name_index: u16,
pub fn descriptor(self: *const EnumConstValue, constant_pool: ConstantPool) ResolveError!ConstantPool.Info {
return constant_pool.getTag(self.type_name_index, .utf8);
}
pub fn name(self: *const EnumConstValue, constant_pool: ConstantPool) ResolveError!ConstantPool.Info {
return constant_pool.getTag(self.const_name_index, .utf8);
}
};
pub const ClassConstValue = struct {
index: u16,
pub fn descriptor(self: *const ClassConstValue, constant_pool: ConstantPool) ResolveError!ConstantPool.Info {
return constant_pool.getTag(self.index, .utf8);
}
};
pub fn parse(input: *std.Io.Reader, allocator: std.mem.Allocator) ParseError!ElementValue {
const tag = try input.takeByte();
return switch (tag) {
'B', 'C', 'D', 'F', 'I', 'J', 'S', 'Z', 's' => .{
.const_value_index = try input.takeInt(u16, .big),
.const_value = .{
.@"type" = @enumFromInt(tag),
.index = try input.takeInt(u16, .big),
},
},
'e' => .{
.enum_const_value = .{
@ -1409,7 +1521,9 @@ pub const ElementValue = union(enum) {
},
},
'c' => .{
.class_info_index = try input.takeInt(u16, .big),
.class_const_value = .{
.index = try input.takeInt(u16, .big),
},
},
'@' => .{
.annotation_value = try .parse(input, allocator),
@ -1444,6 +1558,61 @@ pub const ElementValue = union(enum) {
else => {},
}
}
pub fn indentedFormat(
self: *const ElementValue,
w: *std.Io.Writer,
depth: usize,
indent: u8,
constant_pool: ConstantPool,
) std.Io.Writer.Error!void {
try w.splatByteAll(' ', depth * indent);
try w.print("type: {s}\n", .{ @tagName(self.*) });
switch (self.*) {
.const_value => |const_value| {
const value = const_value.value(constant_pool) catch return error.WriteFailed;
try w.splatByteAll(' ', depth * indent);
_ = try w.write("value:\n");
try value.indentedFormat(w, depth, indent + 1, constant_pool);
},
.enum_const_value => |enum_const_value| {
const descriptor = enum_const_value.descriptor(constant_pool) catch return error.WriteFailed;
try w.splatByteAll(' ', depth * indent);
_ = try w.write("descriptor:\n");
try descriptor.indentedFormat(w, depth, indent + 1, constant_pool);
const name = enum_const_value.name(constant_pool) catch return error.WriteFailed;
try w.splatByteAll(' ', depth * indent);
_ = try w.write("name:\n");
try name.indentedFormat(w, depth, indent + 1, constant_pool);
},
.class_const_value => |class_const_value| {
const descriptor = class_const_value.descriptor(constant_pool) catch return error.WriteFailed;
try w.splatByteAll(' ', depth * indent);
_ = try w.write("descriptor:\n");
try descriptor.indentedFormat(w, depth, indent + 1, constant_pool);
},
.annotation_value => |annotation_value| {
_ = try w.write("annotation:\n");
try annotation_value.indentedFormat(w, depth, indent + 1, constant_pool);
},
.array_value => |array_value| {
try w.splatByteAll(' ', depth * indent);
_ = try w.write("values:\n");
var value_indent = indent;
for (array_value.values, 0..) |*value, i| {
value_indent += 1;
defer value_indent -= 1;
try w.splatByteAll(' ', depth * value_indent);
try w.print("{d}:\n", .{ i });
try value.indentedFormat(w, depth, value_indent + 1, constant_pool);
}
},
}
}
};
pub const ElementValuePair = struct {
@ -1452,6 +1621,23 @@ pub const ElementValuePair = struct {
const Self = @This();
pub fn indentedFormat(
self: *const ElementValuePair,
w: *std.Io.Writer,
depth: usize,
indent: u8,
constant_pool: ConstantPool,
) std.Io.Writer.Error!void {
const element_name = self.elementName(constant_pool) catch return error.WriteFailed;
try w.splatByteAll(' ', depth * indent);
_ = try w.write("name:\n");
try element_name.indentedFormat(w, depth, indent + 1, constant_pool);
try w.splatByteAll(' ', depth * indent);
_ = try w.write("value:\n");
try self.value.indentedFormat(w, depth, indent + 1, constant_pool);
}
pub fn elementName(self: *const Self, constant_pool: ConstantPool) ResolveError!ConstantPool.Info {
return constant_pool.getTag(self.element_name_index, .utf8);
}
@ -1489,6 +1675,31 @@ pub const Annotation = struct {
allocator.free(self.element_value_pairs);
}
pub fn indentedFormat(
self: *const Annotation,
w: *std.Io.Writer,
depth: usize,
indent: u8,
constant_pool: ConstantPool,
) std.Io.Writer.Error!void {
const type_ = self.@"type"(constant_pool) catch return error.WriteFailed;
try w.splatByteAll(' ', depth * indent);
_ = try w.write("type:\n");
try type_.indentedFormat(w, depth, indent + 1, constant_pool);
try w.splatByteAll(' ', depth * indent);
_ = try w.write("element_value_pairs:\n");
var element_value_pair_indent = indent;
for (self.element_value_pairs, 0..) |element_value_pair, i| {
element_value_pair_indent += 1;
defer element_value_pair_indent -= 1;
try w.splatByteAll(' ', depth * element_value_pair_indent);
try w.print("{d}:\n", .{ i });
try element_value_pair.indentedFormat(w, depth, element_value_pair_indent + 1, constant_pool);
}
}
pub fn @"type"(self: *const Self, constant_pool: ConstantPool) ResolveError!ConstantPool.Info {
return constant_pool.getTag(self.type_index, .utf8);
}
@ -1548,6 +1759,26 @@ pub const RuntimeInvisibleAnnotations = struct {
pub const ParameterAnnotation = struct {
annotations: []Annotation,
pub fn indentedFormat(
self: *const ParameterAnnotation,
w: *std.Io.Writer,
depth: usize,
indent: u8,
constant_pool: ConstantPool,
) std.Io.Writer.Error!void {
try w.splatByteAll(' ', depth * indent);
_ = try w.write("annotations:\n");
var annotation_indent = indent;
for (self.annotations, 0..) |annotation, i| {
annotation_indent += 1;
defer annotation_indent -= 1;
try w.splatByteAll(' ', depth * annotation_indent);
try w.print("{d}:\n", .{ i });
try annotation.indentedFormat(w, depth, annotation_indent + 1, constant_pool);
}
}
};
pub const RuntimeVisibleParameterAnnotations = struct {

View file

@ -0,0 +1,14 @@
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
import java.lang.annotation.ElementType;
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.TYPE)
@CustomAnnotationAnnotation
public @interface CustomAnnotation {
public CustomAnnotationType type();
public String name() default "Bob";
}

View file

@ -0,0 +1,9 @@
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
import java.lang.annotation.ElementType;
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.ANNOTATION_TYPE)
public @interface CustomAnnotationAnnotation { }

View file

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

View file

@ -4,7 +4,6 @@ import java.lang.annotation.Target;
import java.lang.annotation.ElementType;
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.TYPE)
public @interface CustomAttribute {
}
@Target(ElementType.PARAMETER)
public @interface CustomParameterAnnotation { }

View file

@ -1,11 +1,12 @@
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(String[] args) {
public static void main(@CustomParameterAnnotation String[] args) {
final var main = new Main();
main.sayHello();