/// <summary> /// Builds an AST by inspecting the processes /// </summary> /// <param name="simulation">The simulation instance to build the AST for.</param> /// <param name="decompile">Set to <c>true</c> to enable decompilation of the IL code.</param> public virtual Network Parse(Simulation simulation, bool decompile = false) { var sourceasm = simulation.Processes.First().Instance.GetType().Assembly; var network = new NetworkState() { Source = sourceasm, Name = sourceasm.GetName().Name, Parent = null }; network.Processes = simulation.Processes .Where(n => n.Instance.GetType().GetCustomAttributes(typeof(IgnoreAttribute), true).FirstOrDefault() == null && !(n.Instance is SimulationProcess)) .Select(x => Parse(network, x, simulation)) .ToArray(); if (network.Processes.Length == 0) { throw new Exception("No processes were found in the list"); } network.Busses = network.Processes.SelectMany(x => x.InternalBusses.Concat(x.InputBusses).Concat(x.OutputBusses)).Distinct().ToArray(); network.Constants = network.ConstantLookup.Values.ToArray(); if (decompile) { foreach (var pr in network.Processes.Cast <ProcessState>().Where(x => x.Decompile)) { if (pr.SourceInstance.Instance is SimpleProcess) { var st = pr.SourceType; var method = st.GetMethod("OnTick", BindingFlags.Instance | BindingFlags.NonPublic, null, CallingConventions.Any, new Type[] { }, null); if (method == null) { throw new Exception($"Could not find the \"OnTick\" method in class: {st.FullName}"); } Decompile(network, pr, method); } else if (pr.SourceInstance.Instance is StateProcess) { var st = pr.SourceType; var method = st.GetMethod("OnTickAsync", BindingFlags.Instance | BindingFlags.NonPublic, null, CallingConventions.Any, new Type[] { }, null); if (method == null) { throw new Exception($"Could not find the \"OnTickAsync\" method in class: {st.FullName}"); } Decompile(network, pr, method); } else { throw new Exception("Unexpected decompile flag on unsupported process type"); } } } network.Constants = network.ConstantLookup.Values.ToArray(); // Patch up all types if they are missing foreach (var el in network.All().OfType <DataElement>().Where(x => x.CecilType == null)) { el.CecilType = LoadType(el.Type); } foreach (var el in network.All().OfType <DataElement>().Where(x => x.DefaultValue == null)) { if (new[] { typeof(byte), typeof(sbyte), typeof(short), typeof(ushort), typeof(int), typeof(uint), typeof(long), typeof(ulong) }.Any(x => el.CecilType.IsSameTypeReference(x))) { el.DefaultValue = 0; } else if (el.CecilType.IsSameTypeReference(typeof(bool))) { el.DefaultValue = false; } } // Assign bus names, processes are handled elsewhere foreach (var el in network.All().OfType <AST.Bus>()) { if (el.SourceInstance != null && simulation.BusNames.ContainsKey(el.SourceInstance)) { el.InstanceName = simulation.BusNames[el.SourceInstance]; } } return(network); }