private static Attributes ReadAttributes(BytecodeReader reader, ushort attributesCount, ConstantPool cp)
        {
            var attributesTable = new List <object>();
            Dictionary <string, Action> nameActionDictionary = new Dictionary <string, Action>
            {
                { "Code", () => attributesTable.Add(ReadAttributeCode(reader, cp)) },
                { "ConstantValue", () => attributesTable.Add(ReadAttributeConstantValue(reader)) },
                { "StackMapTable", () => attributesTable.Add(ReadAttributeStackMapTable(reader)) },
                { "BootstrapMethods", () => attributesTable.Add(ReadAttributeBootstrapMethods(reader)) },
                { "LineNumberTable", () => attributesTable.Add(ReadAttributeLineNumberTable(reader)) },
                { "SourceFile", () => attributesTable.Add(ReadAttributeSourceFile(reader)) }
            };

            for (int i = 0; i < attributesCount; i++)
            {
                if (nameActionDictionary.TryGetValue(cp.GetConstantUtf8(reader.ReadInt()).Value, out Action readAttribute))
                {
                    readAttribute.Invoke();
                }
                else
                {
                    throw new KeyNotFoundException("Attribute type not recognized");
                }
            }
            return(new Attributes(attributesTable));
        }
        private static ConstantPool ReadConstantPool(BytecodeReader reader, ushort constantPoolCount)
        {
            // TODO: check if long and double constants reading right
            ConstantPool constantPool  = new ConstantPool();
            var          tagDictionary = new Dictionary <int, Action>
            {
                {
                    1,
                    () =>
                    {
                        ushort length = reader.ReadUShort();
                        String value  = reader.ReadString(length);
                        constantPool.AddConstantUtf8(new ConstantUtf8(length, value));
                    }
                },
                { 3, () => constantPool.AddConstantInteger(reader.ReadInt()) },
                { 4, () => constantPool.AddConstantFloat(reader.ReadFloat()) },
                { 5, () => constantPool.AddConstantLong(reader.ReadLong()) },
                { 6, () => constantPool.AddConstantDouble(reader.ReadDouble()) },
                { 7, () => constantPool.AddConstantClass(new ConstantClass(reader.ReadUShort())) },
                { 8, () => constantPool.AddConstantString(new ConstantString(reader.ReadUShort())) },
                { 9, () => constantPool.AddConstantFieldRef(new ConstantFieldRef(reader.ReadUShort(), reader.ReadUShort())) },
                { 10, () => constantPool.AddConstantMethodRef(new ConstantMethodRef(reader.ReadUShort(), reader.ReadUShort())) },
                { 11, () => constantPool.AddConstantInterfaceMethodRef(new ConstantInterfaceMethodRef(reader.ReadUShort(), reader.ReadUShort())) },
                { 12, () => constantPool.AddConstantNameAndType(new ConstantNameAndType(reader.ReadUShort(), reader.ReadUShort())) },
                { 15, () => constantPool.AddConstantMethodHandle(new ConstantMethodHandle(reader.ReadByte(), reader.ReadUShort())) },
                { 16, () => constantPool.AddConstantMethodType(new ConstantMethodType(reader.ReadUShort())) },
                { 18, () => constantPool.AddConstantInvokeDynamic(new ConstantInvokeDynamic(reader.ReadUShort(), reader.ReadUShort())) },
                { 19, () => constantPool.AddConstantModule(new ConstantModule(reader.ReadUShort())) },
                { 20, () => constantPool.AddConstantPackage(new ConstantPackage(reader.ReadUShort())) }
            };

            for (int i = 0; i < constantPoolCount; i++)
            {
                if (tagDictionary.TryGetValue(reader.ReadByte(), out Action createConstant))
                {
                    createConstant.Invoke();
                }
                else
                {
                    throw new KeyNotFoundException("Constant type not recognized");
                }
            }
            return(constantPool);
        }