/// <summary>Duplicates the runnable object.</summary>
        /// <returns>The duplicate.</returns>
        public CompiledCommandRunnable Duplicate()
        {
            CompiledCommandRunnable newCopy = MemberwiseClone() as CompiledCommandRunnable;

            newCopy.EntryData = new AbstractCommandEntryData[EntryData.Length];
            return(newCopy);
        }
        /// <summary>Compiles a command script.</summary>
        /// <param name="script">The command script to compile.</param>
        /// <returns>The compiled result.</returns>
        public static CompiledCommandStackEntry Compile(CommandScript script)
        {
            string tname = "__script__" + IDINCR++ + "__" + NameTrimMatcher.TrimToMatches(script.Name);
            CompiledCommandStackEntry Created = new()
            {
                Entries      = script.CommandArray,
                Script       = script,
                AssemblyName = tname
            };
            AssemblyName              asmname  = new(tname) { Name = tname };
            AssemblyBuilder           asmbuild = AssemblyBuilder.DefineDynamicAssembly(asmname, AssemblyBuilderAccess.RunAndCollect);
            ModuleBuilder             modbuild = asmbuild.DefineDynamicModule(tname);
            CompiledCommandStackEntry ccse     = Created;

            ccse.AdaptedILPoints = new Label[ccse.Entries.Length + 1];
            TypeBuilder        typebuild_c   = modbuild.DefineType(tname + "__CENTRAL", TypeAttributes.Class | TypeAttributes.Public, typeof(CompiledCommandRunnable));
            MethodBuilder      methodbuild_c = typebuild_c.DefineMethod("Run", MethodAttributes.Public | MethodAttributes.Virtual, typeof(void), RUN_METHOD_PARAMETERS);
            ILGeneratorTracker ilgen         = new ILGeneratorTracker(methodbuild_c.GetILGenerator(), new Type[] { typebuild_c }.JoinWith(RUN_METHOD_PARAMETERS), $"Script_{tname}").ConfigureTracker(Created.System);

            ilgen.AddCode(OpCodes.Nop, tname, "--- SCRIPT ---");
            CILAdaptationValues values = new()
            {
                Entry          = ccse,
                Script         = script,
                ILGen          = ilgen,
                Method         = methodbuild_c,
                DBMode         = script.Debug,
                EntryFields    = new FieldInfo[ccse.Entries.Length],
                ArgumentFields = new FieldInfo[ccse.Entries.Length][],
                Type           = typebuild_c
            };

            for (int i = 0; i < ccse.Entries.Length; i++)
            {
                values.EntryFields[i] = typebuild_c.DefineField("_field_entry_" + i, typeof(CommandEntry), FieldAttributes.Public | FieldAttributes.InitOnly);
            }
            values.PushVarSet();
            for (int i = 0; i < ccse.AdaptedILPoints.Length; i++)
            {
                ccse.AdaptedILPoints[i] = ilgen.DefineLabel();
            }
            int tagID = 0;
            List <TagArgumentBit>     toClean = new();
            List <ILGeneratorTracker> ILGens
#if SAVE
                = new();
#else
                = null;
#endif
            values.Trackers = ILGens;
            List <KeyValuePair <FieldInfo, Object> > specialFieldValues = new();
            for (int i = 0; i < ccse.Entries.Length; i++)
            {
                CommandEntry curEnt = ccse.Entries[i];
                curEnt.CCSE      = ccse;
                curEnt.DBMode    = values.DBMode;
                curEnt.VarLookup = values.CreateVarLookup();
                for (int a = 0; a < curEnt.Arguments.Length; a++)
                {
                    Argument arg = curEnt.Arguments[a];
                    for (int b = 0; b < arg.Bits.Length; b++)
                    {
                        if (arg.Bits[b] is TagArgumentBit tab)
                        {
                            tagID++;
                            try
                            {
                                GenerateTagData(typebuild_c, ccse, tab, ref tagID, values, i, toClean, (a + 1).ToString(), curEnt, specialFieldValues, ILGens);
                            }
                            catch (TagErrorInducedException ex)
                            {
                                TagException(curEnt, "argument " + TextStyle.Separate + a + TextStyle.Base, tab, ex.SubTagIndex, ex);
                            }
                            catch (ErrorInducedException ex)
                            {
                                TagException(curEnt, "argument " + TextStyle.Separate + a + TextStyle.Base, tab, 0, ex);
                            }
                        }
                    }
                    ILGeneratorTracker compiled = ArgumentCompiler.Compile(arg, Created, values);
                    curEnt.Arguments[a] = arg.TrueForm;
                    ILGens?.Add(compiled);
                }
                foreach (KeyValuePair <string, Argument> argPair in curEnt.NamedArguments)
                {
                    for (int b = 0; b < argPair.Value.Bits.Length; b++)
                    {
                        if (argPair.Value.Bits[b] is TagArgumentBit tab)
                        {
                            tagID++;
                            try
                            {
                                GenerateTagData(typebuild_c, ccse, tab, ref tagID, values, i, toClean, "named " + argPair.Key, curEnt, specialFieldValues, ILGens);
                            }
                            catch (TagErrorInducedException ex)
                            {
                                TagException(curEnt, "named argument '" + TextStyle.Separate + argPair.Key + TextStyle.Base + "'", tab, ex.SubTagIndex, ex);
                            }
                            catch (ErrorInducedException ex)
                            {
                                TagException(curEnt, "named argument '" + TextStyle.Separate + argPair.Key + TextStyle.Base + "'", tab, 0, ex);
                            }
                        }
                    }
                    ILGeneratorTracker compiled = ArgumentCompiler.Compile(argPair.Value, Created, values);
                    ILGens?.Add(compiled);
                }
                if (!curEnt.IsCallback)
                {
                    try
                    {
                        curEnt.Command.PreAdaptToCIL(values, i);
                    }
                    catch (ErrorInducedException ex)
                    {
                        throw new ErrorInducedException("On script line " + curEnt.ScriptLine + " (" + curEnt.CommandLine + "), early compile (PreAdapt) error occured: " + ex.Message);
                    }
                    curEnt.VarLookup = values.CreateVarLookup();
                }
                if (curEnt.NamedArguments.TryGetValue(CommandEntry.SAVE_NAME_ARG_ID, out Argument avarname))
                {
                    if (!curEnt.VarLookup.ContainsKey(avarname.ToString()))
                    {
                        throw new ErrorInducedException("Error in command line " + curEnt.ScriptLine + ": (" + curEnt.CommandLine + "): Invalid variable save name: " + avarname.ToString());
                    }
                }
                if (curEnt.IsCallback)
                {
                    try
                    {
                        curEnt.Command.PreAdaptToCIL(values, i);
                    }
                    catch (ErrorInducedException ex)
                    {
                        throw new ErrorInducedException("On script line " + curEnt.ScriptLine + " (" + curEnt.CommandLine + "), early compile (PreAdapt) error occured: " + ex.Message);
                    }
                }
                curEnt.DBMode = values.DBMode;
            }
            values.LoadRunnable();
            ilgen.Emit(OpCodes.Ldfld, CompiledCommandRunnable.IndexField);
            ilgen.Emit(OpCodes.Switch, ccse.AdaptedILPoints);
            for (int i = 0; i < ccse.Entries.Length; i++)
            {
                ilgen.Comment($"Begin command code section {i}: {ccse.Entries[i].CommandLine}");
                ilgen.MarkLabel(ccse.AdaptedILPoints[i]);
                try
                {
                    ccse.Entries[i].Command.AdaptToCIL(values, i);
                }
                catch (ErrorInducedException ex)
                {
                    throw new ErrorInducedException("On script line " + ccse.Entries[i].ScriptLine + " (" + ccse.Entries[i].CommandLine + "), compile error (Adapt) occured: " + ex.Message);
                }
            }
            ilgen.MarkLabel(ccse.AdaptedILPoints[^ 1]);
            values.MarkCommand(ccse.Entries.Length);
            ilgen.Emit(OpCodes.Ret);
            typebuild_c.DefineMethodOverride(methodbuild_c, CompiledCommandRunnable.RunMethod);
            ConstructorBuilder ctor      = typebuild_c.DefineConstructor(MethodAttributes.Public, CallingConventions.HasThis, CONSTRUCTOR_PARAMS);
            ILGeneratorTracker ctorilgen = new ILGeneratorTracker(ctor.GetILGenerator(), new Type[] { typebuild_c }.JoinWith(CONSTRUCTOR_PARAMS), tname).ConfigureTracker(ccse.System);
            ILGens?.Add(ctorilgen);
            ctorilgen.Emit(OpCodes.Ldarg_0);                                   // Load 'this'
            ctorilgen.Emit(OpCodes.Ldarg_1);                                   // Load: CCSE
            ctorilgen.Emit(OpCodes.Stfld, CompiledCommandRunnable.EntryField); // Store it to the readonly field.
            for (int i = 0; i < values.EntryFields.Length; i++)
            {
                ctorilgen.Emit(OpCodes.Ldarg_0);                      // Load 'this'
                ctorilgen.Emit(OpCodes.Ldarg_2);                      // Load input array
                ctorilgen.Emit(OpCodes.Ldc_I4, i);                    // Load index in the array
                ctorilgen.Emit(OpCodes.Ldelem_Ref);                   // Load the value from the array
                ctorilgen.Emit(OpCodes.Stfld, values.EntryFields[i]); // Store it to the readonly field.
                FieldInfo[] argFields = values.ArgumentFields[i];
                if (argFields != null)
                {
                    for (int arg = 0; arg < argFields.Length; arg++)
                    {
                        if (argFields[arg] != null)
                        {
                            ctorilgen.Emit(OpCodes.Ldarg_0);                                         // Load 'this'
                            ctorilgen.Emit(OpCodes.Ldarg_0);                                         // Load 'this'
                            ctorilgen.Emit(OpCodes.Ldfld, values.EntryFields[i]);                    // Load the entry field
                            ctorilgen.Emit(OpCodes.Ldfld, CILAdaptationValues.Entry_ArgumentsField); // Load the arguments field
                            ctorilgen.Emit(OpCodes.Ldc_I4, arg);                                     // Load the argument index
                            ctorilgen.Emit(OpCodes.Ldelem_Ref);                                      // Load the argument value from the array
                            ctorilgen.Emit(OpCodes.Stfld, argFields[arg]);                           // Store it to the readonly field.
                        }
                    }
                }
            }
            for (int i = 0; i < specialFieldValues.Count; i++)
            {
                ctorilgen.Emit(OpCodes.Ldarg_0);                                        // Load 'this'
                ctorilgen.Emit(OpCodes.Ldarg_3);                                        // Load input array
                ctorilgen.Emit(OpCodes.Ldc_I4, i);                                      // Load index in the array
                ctorilgen.Emit(OpCodes.Ldelem_Ref);                                     // Load the value from the array
                ctorilgen.Emit(OpCodes.Castclass, specialFieldValues[i].Key.FieldType); // Guarantee the type.
                ctorilgen.Emit(OpCodes.Stfld, specialFieldValues[i].Key);               // Store it to the field.
            }
            ctorilgen.Emit(OpCodes.Ret);                                                // return
            Type     t_c         = typebuild_c.CreateType();
            object[] fieldValues = new object[specialFieldValues.Count];
            for (int i = 0; i < fieldValues.Length; i++)
            {
                fieldValues[i] = specialFieldValues[i].Value;
            }
            CompiledCommandRunnable runnable = Activator.CreateInstance(t_c, ccse, ccse.Entries, fieldValues) as CompiledCommandRunnable;
            ccse.ReferenceCompiledRunnable = runnable;
            ccse.Variables = values.Variables.ToArray();
            foreach (SingleCILVariable variable in ccse.Variables)
            {
                variable.Field = variable.Field.DeclaringType.GetField(variable.Field.Name); // Patch runtime field issues
            }
            ccse.VariableSetters = new Action <CompiledCommandRunnable, TemplateObject> [ccse.Variables.Length];
            runnable.EntryData   = new AbstractCommandEntryData[Created.Entries.Length];
            runnable.Debug       = script.Debug;
#if SAVE
            StringBuilder outp = new();
            for (int i = 0; i < ilgen.Codes.Count; i++)
            {
                outp.Append(ilgen.Codes[i].Key + ": " + ilgen.Codes[i].Value?.ToString()?.Replace("\n", "\\n")?.Replace("\r", "\\r") + "\n");
            }
            for (int n = 0; n < ILGens.Count; n++)
            {
                outp.Append("\n\n\n// -----\n\n\n");
                for (int i = 0; i < ILGens[n].Codes.Count; i++)
                {
                    outp.Append(ILGens[n].Codes[i].Key + ": " + ILGens[n].Codes[i].Value?.ToString()?.Replace("\n", "\\n")?.Replace("\r", "\\r") + "\n");
                }
            }
            System.IO.File.WriteAllText("script_" + tname + ".il", outp.ToString());
#endif
            return(Created);
        }