public static INode Read(InspectableAssembly ia, MethodSignature signature, MethodBodyBlock rawBody)
        {
            /*Console.WriteLine("=== IL Bytes ===");
            foreach (var b in ilBytes)
                Console.Write("{0:X2} ", b);
            Console.WriteLine();*/

            var parser = new ILMethodParser(ia, signature, rawBody);
            return parser.Parse();
        }
        public void Parse(P.Program program, string filename)
        {
            var context = new ParseContext(program);

            var ia = new InspectableAssembly(filename, context);
            EntryPointQueue(ia, context);

            while(context.Todo.Count > 0)
            {
                context.Todo.Dequeue().Process();
            }
        }
        private void EntryPointQueue(InspectableAssembly ia, ParseContext context)
        {
            foreach (var typeHandle in ia.Reader.TypeDefinitions)
            {
                var parseTarget = ia.CreateParseTarget(typeHandle);
                parseTarget.MethodName = "Main";

                if (IgnoreClassList.Contains(parseTarget.ClassName))
                    continue;

                context.AddTodo(parseTarget);
            }
        }      
        public ParseTarget(ParseContext context, string assemblyName, Version assemblyVersion, string fqName)
        {
            AssemblyName = assemblyName;
            ClassName = fqName;
            AssemblyVersion = assemblyVersion;

            for(int i = 0; i < Extensions.Length; i++)
            {
                try
                {
                    var path = TryExtenstion(Extensions[i]);
                    Ia = new InspectableAssembly(path, context);
                }
                catch
                {
                    if (i == Extensions.Length - 1)
                        throw;
                }
            }
        }
        private static ElementType ReadType(InspectableAssembly ia, byte[] blob, ref int index)
        {
            var ret = new ElementType((EElementType)blob[index++]);
            // class or struct
            if (ret.Type == EElementType.Class || ret.Type == EElementType.ValueType || ret.Type == EElementType.CMod_Required || ret.Type == EElementType.CMod_Optional)
            {
                //next is metadata token?
                var tokenRaw = UncompressInt(blob, ref index);
                int token = (tokenRaw & ~0x03) >> 2;
                switch(tokenRaw & 0x03)
                {
                    case 0: //typedef 
                        token |= 0x02000000;
                        break;
                    case 1: //typeref
                        token |= 0x01000000;
                        break;
                    case 2: //typespec
                        token |= 0x20000000;
                        break;
                }

                var handle = MetadataTokens.Handle(token);
                switch (handle.Kind)
                {
                    case HandleKind.TypeDefinition:
                        ret.Target = ia.GetClassImmediate(token);
                        break;
                    default:
                        throw new Exception("Go f**k yourself handle");
                }
            }
            else if(ret.Type == EElementType.SzArray || ret.Type == EElementType.Reference)
            {
                ElementType next;
                do
                {
                    next = ReadType(ia, blob, ref index);
                    if (next.Type.IsCustomMod())
                        Console.WriteLine("?? SzArray custom mod ??");
                } while (next.Type.IsCustomMod());

                ret.Secondary = next;
            }
            else if(ret.Type == EElementType.MVar)
            {
                ret.Number = UncompressInt(blob, ref index);
            }

            return ret;
        }
        /*public static MethodSignature SetGenerics(InspectableAssembly ia, byte[] specBloc, MethodSignature @base)
        {
            

            var ret = @base.Clone();
            if (ret.NumGeneric != count)
                throw new Exception("Mismatched generic signature");

            // do parameters
            for(int i = 0; i < ret.ParameterTypes.Count; i++)
            {
                if(ret.ParameterTypes[i].Type == EElementType.MVar)
                    ret.ParameterTypes[i] = types[ret.ParameterTypes[i].Number];
                else if(ret.ParameterTypes[i].HasSecondary && ret.ParameterTypes[i].Secondary.Type == EElementType.Mvar)
                {

                }
            }
            ret.NumGeneric = 0;

            // do return type
            if (ret.ReturnType.Type == EElementType.MVar)
                ret.ReturnType = types[ret.ReturnType.Number];
            
            return ret;
        }*/

        public static IList<ElementType> ParseLocalSignature(InspectableAssembly ia, byte[] blob)
        {
            var ret = new List<ElementType>();

            int index = 0;
            if (blob[index++] != 0x07)
                throw new Exception("Bad locals signature");

            int numberOfEntries = blob[index++];
            for(; numberOfEntries > 0; numberOfEntries--)
            {
                ret.Add(ReadType(ia, blob, ref index));
            }
                
            return ret;
        }
        public static GenericSignature ParseGenericSignature(InspectableAssembly ia, byte[] specBloc)
        {
            int index = 0;
            if (specBloc[index++] != 10)
                throw new Exception("Poop generic signature");

            int count = specBloc[index++];

            var ret = new GenericSignature();
            for (int i = 0; i < count; i++)
                ret.Add(ReadType(ia, specBloc, ref index));

            return ret;
        }
        public static MethodSignature ParseMethodSignature(InspectableAssembly ia, byte[] blob)
        {
            var ret = new MethodSignature();

            int index = 0;

            ret.Flags = (EMethodFlags)blob[index++];
            if (ret.Flags.HasFlag(EMethodFlags.Generic))
                ret.NumGeneric = UncompressInt(blob, ref index);
     
            ret.NumNormal = UncompressInt(blob, ref index);

            ret.ReturnType = ReadType(ia, blob, ref index);
            if (ret.Flags.HasFlag(EMethodFlags.ExplicitThis))
            {
                ret.ThisType = ReadType(ia, blob, ref index);
                ret.NumNormal--;
            }

            for(int i = 0; i < ret.NumNormal; i++)
            {
                ret.ParameterTypes.Add(ReadType(ia, blob, ref index));
            }

            return ret;
        }
        public static FieldSignature ParseFieldSignature(InspectableAssembly ia, byte[] blob)
        {
            var ret = new FieldSignature();

            int index = 0;
            if (blob[index++] != 0x06)
                throw new Exception("Invalid field signature");

            while(index < blob.Length)
            {
                var type = ReadType(ia, blob, ref index);

                if (type.Type.IsCustomMod()) {
                    if (type.Target == ia.Context.Program.Classes[VolatileClassName])
                        ret.IsVolatile = true;

                    // other custom mods
                }
                else
                    ret.Type = type;
            }

            return ret;
        }
 public ParseTarget(InspectableAssembly ia, string fqName)
 {
     AssemblyName = Path.GetFileNameWithoutExtension(ia.Stream.Name);
     ClassName = fqName;
     AssemblyVersion = new Version();
     Ia = ia;
 }
        public ParseTarget(InspectableAssembly ia, Method m)
        {
            Ia = ia;
            Method = m;

            MethodSignature = m.Signature;
            MethodName = m.Name;

            ClassName = 
                ia.GetFullyQualifiedName(
                    ia.Reader.GetTypeDefinition(
                        ((MethodDefinition)m.SourceHandle).GetDeclaringType()));
        }
 public void AddClass(InspectableAssembly ia, TypeDefinitionHandle typeHandle, Class c)
 {
     int token = MetadataTokens.GetToken(ia.Reader, typeHandle);
     m_tokenReference.Add(token, c);
     Program.Classes.Add(c.Name, c);
 }