예제 #1
0
 /// <summary>Configures the <see cref="ILGeneratorTracker"/> for FS output handling.</summary>
 public static ILGeneratorTracker ConfigureTracker(this ILGeneratorTracker tracker, ScriptEngine engine)
 {
     tracker.BaseCode      = TextStyle.Base;
     tracker.EmphasizeCode = TextStyle.Separate;
     tracker.MinorCode     = TextStyle.Minor;
     tracker.Error         = engine.Context.BadOutput;
     return(tracker);
 }
예제 #2
0
        /// <summary>Adapts the tag base to CIL.</summary>
        /// <param name="ilgen">IL Generator.</param>
        /// <param name="tab">The TagArgumentBit.</param>
        /// <param name="values">Related adaptation values.</param>
        /// <returns>Whether any adaptation was done.</returns>
        public override bool AdaptToCIL(ILGeneratorTracker ilgen, TagArgumentBit tab, CILAdaptationValues values)
        {
            int index = (int)((tab.Bits[0].Variable.Bits[0] as TextArgumentBit).InputValue as IntegerTag).Internal;

            ilgen.Emit(OpCodes.Ldarg_0);                                      // Load argument: TagData
            ilgen.Emit(OpCodes.Ldfld, TagData.Field_TagData_Runnable);        // Load TagData.Runnable
            ilgen.Emit(OpCodes.Ldfld, values.LocalVariableData(index).Field); // Load Runnable.Var
            return(true);
        }
예제 #3
0
        public static TagReturnType Compiler_Tag_As(ILGeneratorTracker ilgen, TagArgumentBit tab, int bit, TagReturnType prevType)
        {
            ilgen.Emit(OpCodes.Ldfld, Field_DynamicTag_Internal); // Load field "Internal" on the input DynamicTag instance.
            ilgen.Emit(OpCodes.Ldarg_0);                          // Load argument: TagData.
            string  type_name = tab.Bits[bit].Variable.ToString();
            TagType varType   = tab.Engine.TagSystem.Types.RegisteredTypes[type_name.ToLowerFast()];

            ilgen.Emit(OpCodes.Call, varType.CreatorMethod); // Run the creator method for the type on the input tag.
            return(new TagReturnType(varType, false));
        }
예제 #4
0
        /// <summary>Generates a compiled call to the TagArgumentBit.</summary>
        /// <param name="ilgen">The IL Generator.</param>
        /// <param name="tab_loc">The TagArgumentBit helper local-variable location.</param>
        /// <param name="load_Error">The OpCode to load the error object.</param>
        /// <param name="load_Runnable">The OpCode to load the runnable object.</param>
        /// <param name="obj_loc">The TemplateObject helper local-variable location.</param>
        /// <param name="return_raw">Whether a raw value should be returned.</param>
        public void GenerateCall(ILGeneratorTracker ilgen, int tab_loc, OpCode load_Error, OpCode load_Runnable, int obj_loc, bool return_raw)
        {
            ilgen.Emit(OpCodes.Stloc, tab_loc); // Store the TAB to the proper location
            Label exceptionLabel = default;

            if (Data.HasFallback)
            {
                exceptionLabel = ilgen.BeginExceptionBlock();   // try {
            }
            ilgen.Emit(OpCodes.Ldloc, tab_loc);                 // Load the tag onto stack
            ilgen.Emit(load_Error);                             // Load the error object onto stack
            ilgen.Emit(load_Runnable);                          // Load the runnable object onto stack.
            ilgen.Emit(OpCodes.Call, TagArgumentBit_PrepParse); // Call the PrepParse method (pulls TagArgumentBit + Error + CSE from stack)
            ilgen.Emit(OpCodes.Ldloc, tab_loc);                 // Load the tag onto stack
            ilgen.Emit(OpCodes.Ldfld, TagArgumentBit_Data);     // Read 'data' (from current tab)
            ilgen.Emit(load_Runnable);                          // Load the runnable object onto stack.
            ilgen.Emit(load_Error);                             // Load the error object onto stack.
            ilgen.Emit(OpCodes.Call, GetResultMethod, 3);       // Call the GetResultMethod (takes three params: (TagData, CompiledCommandRunnable, Action<string>), and returns a TemplateObject).
            if (CompiledReturnType.IsRaw && !return_raw)
            {
                ilgen.Emit(OpCodes.Newobj, CompiledReturnType.Type.RawInternalConstructor); // Handle raw translation if needed.
            }
            ilgen.Emit(OpCodes.Stloc, obj_loc);                                             // Store the TemplateObject where it belongs
            if (Data.HasFallback)
            {
                ilgen.Emit(OpCodes.Leave, exceptionLabel);                       // }
                ilgen.BeginCatchBlock(typeof(TagErrorInducedException));         // catch (Exception ex) {
                ilgen.Emit(OpCodes.Pop);                                         // pop the exception off stack
                ilgen.Emit(OpCodes.Ldloc, tab_loc);                              // Load the tag onto stack
                ilgen.Emit(OpCodes.Ldfld, TagArgumentBit_Data);                  // Read 'data' (from current tab)
                ilgen.Emit(OpCodes.Ldfld, TagData.Field_Fallback);               // Read 'data'.Fallback field
                ilgen.Emit(load_Error);                                          // Load the error object onto stack
                ilgen.Emit(load_Runnable);                                       // Load the runnable object onto stack.
                ilgen.Emit(OpCodes.Callvirt, ArgumentCompiler.Argument_Parse);   // Virtual call the Argument.Parse method, which returns a TemplateObject
                ilgen.Emit(OpCodes.Ldloc, tab_loc);                              // Load the tag onto stack
                ilgen.Emit(OpCodes.Ldfld, TagArgumentBit_Data);                  // Read 'data' (from current tab)
                ilgen.Emit(OpCodes.Call, CompiledReturnType.Type.CreatorMethod); // Validate type
                if (CompiledReturnType.IsRaw && return_raw)
                {
                    ilgen.Emit(OpCodes.Ldfld, CompiledReturnType.Type.RawInternalField); // Handle raw translation if needed.
                }
                ilgen.Emit(OpCodes.Stloc, obj_loc);                                      // Store the TemplateObject where it belongs
                ilgen.EndExceptionBlock();                                               // }
            }
        }
예제 #5
0
        /// <summary>Creates a variable setter for the given variable.</summary>
        /// <param name="variable">The variable.</param>
        /// <returns>The setter action.</returns>
        public static Action <CompiledCommandRunnable, TemplateObject> CreateVariableSetter(SingleCILVariable variable)
        {
            DynamicMethod      genMethod = new("script_" + variable.Field.DeclaringType.Name + "_var_" + variable.Index + "_setter", typeof(void), SETTER_ACTION_PARAMS);
            ILGeneratorTracker ILGen     = new ILGeneratorTracker(genMethod.GetILGenerator(), SETTER_ACTION_PARAMS, genMethod.Name).ConfigureTracker(variable.Type.Type.Engine);

            ILGen.Emit(OpCodes.Ldarg_0);                                    // Load argument: runnable
            ILGen.Emit(OpCodes.Castclass, variable.Field.DeclaringType);    // Jank patch for type misinterpretation in CILL validator
            ILGen.Emit(OpCodes.Ldarg_1);                                    // Load argument: input variable value
            ILGen.Emit(OpCodes.Ldsfld, TagData.FIELD_TAGDATA_SIMPLE_ERROR); // Grab a blank TagData
            ILGen.Emit(OpCodes.Call, variable.Type.Type.CreatorMethod);     // Ensure type
            if (variable.Type.IsRaw)
            {
                ILGen.Emit(OpCodes.Ldfld, variable.Type.Type.RawInternalField); // Handle raw if needed.
            }
            ILGen.Emit(OpCodes.Stfld, variable.Field);                          // Store to field.
            ILGen.Emit(OpCodes.Ret);                                            // Return.
            return(genMethod.CreateDelegate(typeof(Action <CompiledCommandRunnable, TemplateObject>)) as Action <CompiledCommandRunnable, TemplateObject>);
        }
예제 #6
0
 /// <summary>Adapts the tag base to CIL.</summary>
 /// <param name="ilgen">IL Generator.</param>
 /// <param name="tab">The TagArgumentBit.</param>
 /// <param name="values">Related adaptation values.</param>
 /// <returns>Whether any adaptation was done.</returns>
 public virtual bool AdaptToCIL(ILGeneratorTracker ilgen, TagArgumentBit tab, CILAdaptationValues values)
 {
     return(false);
 }
예제 #7
0
        /// <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);
        }