Пример #1
0
        /// <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);
        }