using System.Text; namespace JCIL.Java.Class; public enum ConstantType { Class = 7, FieldRef = 9, MethodRef = 10, InterfaceMethodRef = 11, String = 8, Integer = 3, Float = 4, Long = 5, Double = 6, NameAndType = 12, Utf8 = 1, MethodHandle = 15, MethodType = 16, InvokeDynamic = 18, } public sealed record NameAndType(string Name, string Descriptor); public sealed record MethodRef(Class Class, NameAndType Method); public sealed record FieldRef(Class Class, NameAndType Field); public record struct Constant(ConstantType Type, object Value) { public static Constant Read(Class self, TypeLoader loader, Reader reader) { object value; var type = (ConstantType)reader.ReadUInt8(); switch (type) { case ConstantType.Class: case ConstantType.String: case ConstantType.MethodType: { value = reader.ReadUInt16(); break; } case ConstantType.Integer: { value = reader.ReadInt32(); break; } case ConstantType.Float: { value = reader.ReadFloat(); break; } case ConstantType.Long: { value = reader.ReadInt64(); break; } case ConstantType.Double: { value = reader.ReadDouble(); break; } case ConstantType.FieldRef: case ConstantType.MethodRef: case ConstantType.NameAndType: case ConstantType.InvokeDynamic: case ConstantType.InterfaceMethodRef: { value = (reader.ReadUInt16(), reader.ReadUInt16()); break; } case ConstantType.Utf8: { var length = reader.ReadUInt16(); var buffer = new byte[length]; reader.Stream.ReadExactly(buffer); value = Encoding.UTF8.GetString(buffer); break; } case ConstantType.MethodHandle: { value = (reader.ReadUInt8(), reader.ReadUInt16()); break; } default: { value = null!; break; } } return new Constant(type, value); } public static object? Resolve(TypeLoader loader, Constant[] constants, ushort i) { if (i == 0 || i > constants.Length) return null; i -= 1; switch (constants[i]) { case { Type: ConstantType.Class, Value: ushort index }: { var name = (string) Resolve(loader, constants, index)!; constants[i] = new Constant(ConstantType.Class, loader.GetClass(name.AsMemory())); break; } case { Type: ConstantType.MethodRef, Value: (ushort classIndex, ushort nameTypeIndex) }: { var name = (Class)Resolve(loader, constants, classIndex)!; var descriptor = (NameAndType)Resolve(loader, constants, nameTypeIndex)!; constants[i] = new Constant(ConstantType.MethodRef, new MethodRef(name, descriptor)); break; } case { Type: ConstantType.FieldRef, Value: (ushort classIndex, ushort nameTypeIndex) }: { var name = (Class)Resolve(loader, constants, classIndex)!; var descriptor = (NameAndType)Resolve(loader, constants, nameTypeIndex)!; constants[i] = new Constant(ConstantType.FieldRef, new FieldRef(name, descriptor)); break; } case { Type: ConstantType.InterfaceMethodRef, Value: (ushort classIndex, ushort nameTypeIndex) }: { var name = (Class)Resolve(loader, constants, classIndex)!; var descriptor = (NameAndType)Resolve(loader, constants, nameTypeIndex)!; constants[i] = new Constant(ConstantType.InterfaceMethodRef, new MethodRef(name, descriptor)); break; } case { Type: ConstantType.String, Value: ushort index }: { var text = (string)Resolve(loader, constants, index)!; constants[i] = new Constant(ConstantType.String, text); break; } case { Type: ConstantType.NameAndType, Value: (ushort nameIndex, ushort descriptorIndex) }: { var name = (string)Resolve(loader, constants, nameIndex)!; var descriptor = (string)Resolve(loader, constants, descriptorIndex)!; constants[i] = new Constant(ConstantType.NameAndType, new NameAndType(name, descriptor)); break; } } return constants[i].Value; } }