diff --git a/new/AutoItInterpreter/Runtime/DelegateBuilder.cs b/new/AutoItInterpreter/Runtime/DelegateBuilder.cs index 49060fc..ca61f5e 100644 --- a/new/AutoItInterpreter/Runtime/DelegateBuilder.cs +++ b/new/AutoItInterpreter/Runtime/DelegateBuilder.cs @@ -1,4 +1,4 @@ -using System.Runtime.CompilerServices; +using System.Runtime.CompilerServices; using System.Runtime.InteropServices; using System.Reflection.Emit; using System.Reflection; @@ -13,6 +13,7 @@ namespace Unknown6656.AutoIt3.Runtime; + using static AST; /// @@ -20,9 +21,13 @@ namespace Unknown6656.AutoIt3.Runtime; /// public sealed class DelegateBuilder { - public static DelegateBuilder Instance { get; } = new DelegateBuilder(); + private const string FN_FUNCTION = "_function"; + private const string FN_RETTYPE = "_rettype"; + private const string FN_POINTER = "_pointer"; + public static DelegateBuilder Instance { get; } = new DelegateBuilder(); + private readonly AssemblyBuilder _assembly; private readonly ModuleBuilder _module; @@ -33,14 +38,20 @@ private DelegateBuilder() _module = _assembly.DefineDynamicModule(nameof(DelegateBuilder)); } + /// + /// Creates a user-space script function callback which has the given function and internally invokes the given .NET . + /// + /// The function signature. + /// The internally wrapped .NET callback. + /// Returns the user-space script function callback. public UserFunctionCallback? CreateUserFunctionCallback(SIGNATURE signature, Func<(object?, Type)[], Type, object?> callback) { try { TypeBuilder type_builder = _module.DefineType(GetRandomName(), TypeAttributes.Sealed | TypeAttributes.Abstract | TypeAttributes.Public | TypeAttributes.BeforeFieldInit, typeof(object)); - FieldBuilder field_func_builder = type_builder.DefineField("_function", typeof(Func<(object, Type)[], Type, object>), FieldAttributes.Public | FieldAttributes.Static); - FieldBuilder field_rettype_builder = type_builder.DefineField("_rettype", typeof(Type), FieldAttributes.Public | FieldAttributes.Static); - FieldBuilder field_ptr_builder = type_builder.DefineField("_pointer", typeof(nint), FieldAttributes.Public | FieldAttributes.Static); + FieldBuilder field_func_builder = type_builder.DefineField(FN_FUNCTION, typeof(Func<(object, Type)[], Type, object>), FieldAttributes.Public | FieldAttributes.Static); + FieldBuilder field_rettype_builder = type_builder.DefineField(FN_RETTYPE, typeof(Type), FieldAttributes.Public | FieldAttributes.Static); + FieldBuilder field_ptr_builder = type_builder.DefineField(FN_POINTER, typeof(nint), FieldAttributes.Public | FieldAttributes.Static); Type? rettype = ConvertType(signature.ReturnType.Type, false); Type?[] @params = signature.ParameterTypes.ToArray(t => ConvertType(t, true)); @@ -120,6 +131,11 @@ private DelegateBuilder() return null; } + /// + /// Creates a new native delegate using the given function signature. + /// + /// The function signature. + /// The newly created . public NativeDelegateWrapper? CreateNativeDelegateType(SIGNATURE signature) { try @@ -293,18 +309,34 @@ ParameterBuilder ProcessParameter(int index, TYPE type) return null; // TODO } #if DEBUG + /// + /// Saves the delegate containing the internally generated assembly to the given file path. + /// + /// File path, under which the internally generated assembly shall be saved. public void SaveAssembly(string path) => new Lokad.ILPack.AssemblyGenerator().GenerateAssembly(_assembly, path); #endif private static string GetRandomName(string prefix = "", string suffix = "") => prefix + Guid.NewGuid() + suffix; } +/// +/// Represents a user-space script function callback, which can be used for the invocation of AutoIt user functions via .NET delegates. +/// +/// The internal function pointer. public unsafe record UserFunctionCallback(nint FunctionPointer) { /// - /// A string prefix reserved only for interpreter errors. Must be a sequence which no one in their right mind would use as a real function return value. + /// A string prefix reserved only for interpreter errors. + /// + /// THIS MUST BE AN UNIQUE SEQUENCE WHICH NO ONE IN THEIR RIGHT MIND WOULD USE AS A REAL FUNCTION RETURN VALUE. /// internal static readonly string ErrorPrefix = $"{DateTime.UtcNow}\U0001F1EA\U0001F1F7\U0001F1F7\U0001F1F4\U0001F1F7:"; + /// + /// Creates a new .NET callback from the given user-space script function. + /// + /// The user-space script function from which the .NET delegate shall be created. + /// AutoIt interpreter instance. + /// The corresponding .NET delegate. public static Func<(object?, Type)[], Type, object?> CreateNativeCallback(ScriptFunction function, Interpreter interpreter) => (arguments, type) => { if (arguments.Length < function.ParameterCount.MinimumCount) @@ -330,13 +362,28 @@ public unsafe record UserFunctionCallback(nint FunctionPointer) }; } +/// +/// Represents a native function wrapper using a delegate. +/// +/// The underlying .NET delegate instance. +/// An array containing the types of the delegate arguments. +/// The delegate's return type. +/// The pointing towards the wrapped .NET function. public unsafe record NativeDelegateWrapper(object Delegate, Type[] ArgTypes, Type RetType, MethodInfo Invoker) { internal static readonly FieldInfo _methodPtr = typeof(Delegate).GetField(nameof(_methodPtr), BindingFlags.NonPublic | BindingFlags.Instance)!; internal static readonly FieldInfo _methodPtrAux = typeof(Delegate).GetField(nameof(_methodPtrAux), BindingFlags.NonPublic | BindingFlags.Instance)!; - public object? CallCPP(void* funcptr, params object?[] arguments) => CallCPP((nint)funcptr, arguments); + /// + /// Calls the given function pointer with the given arguments and returns the function return value of the called function. + /// + /// WARNING: Debugging this method will most certainly crash the entire application due to missing debug symbols! + /// + /// Function pointer to be called. + /// The function arguments to be passed. + /// Function return value. + public object? CallCPP(void* funcptr, params object?[]? arguments) => CallCPP((nint)funcptr, arguments); /// /// Calls the given function pointer with the given arguments and returns the function return value of the called function. @@ -347,7 +394,7 @@ public unsafe record NativeDelegateWrapper(object Delegate, Type[] ArgTypes, Typ /// The function arguments to be passed. /// Function return value. [DebuggerNonUserCode, DebuggerHidden, DebuggerStepThrough] - public object? CallCPP(nint funcptr, params object?[] arguments) + public object? CallCPP(nint funcptr, params object?[]? arguments) { nint orig = default; object? result; @@ -373,8 +420,26 @@ public unsafe record NativeDelegateWrapper(object Delegate, Type[] ArgTypes, Typ return result; } - public Variant CallCPPfromAutoit(void* funcptr, Interpreter interpreter, Variant[] arguments) => CallCPPfromAutoit((nint)funcptr, interpreter, arguments); + /// + /// Calls the given function pointer from the AutoIt context with the given arguments and returns the function return value of the called function. + /// + /// WARNING: Debugging this method will most certainly crash the entire application due to missing debug symbols! + /// + /// The AutoIt interpreter instance. + /// Function pointer to be called. + /// The function arguments to be passed. + /// Function return value. + public Variant CallCPPfromAutoit(void* funcptr, Interpreter interpreter, Variant[]? arguments) => CallCPPfromAutoit((nint)funcptr, interpreter, arguments); + /// + /// Calls the given function pointer from the AutoIt context with the given arguments and returns the function return value of the called function. + /// + /// WARNING: Debugging this method will most certainly crash the entire application due to missing debug symbols! + /// + /// The AutoIt interpreter instance. + /// Function pointer to be called. + /// The function arguments to be passed. + /// Function return value. public Variant CallCPPfromAutoit(nint funcptr, Interpreter interpreter, Variant[]? arguments) { object?[] cpp_arguments = new object?[ArgTypes.Length]; diff --git a/new/AutoItInterpreter/Runtime/Function.cs b/new/AutoItInterpreter/Runtime/Function.cs index 735a4dd..907d85c 100644 --- a/new/AutoItInterpreter/Runtime/Function.cs +++ b/new/AutoItInterpreter/Runtime/Function.cs @@ -1,4 +1,4 @@ -using System.Collections.Concurrent; +using System.Collections.Concurrent; using System.Collections.Generic; using System.Reflection; using System.Linq; @@ -53,6 +53,9 @@ public abstract class ScriptFunction /// public abstract SourceLocation Location { get; } + /// + /// Returns the parameter count of this function. + /// public abstract (int MinimumCount, int MaximumCount) ParameterCount { get; } /// @@ -144,6 +147,9 @@ orderby loc ascending from line in _lines[loc] select (loc, line)).ToArray(); + /// + /// Returns the jump labels defined in this function. + /// public ReadOnlyIndexer JumpLabels { get; } @@ -203,6 +209,9 @@ public class NativeFunction public override (int MinimumCount, int MaximumCount) ParameterCount { get; } + /// + /// Returns the default values for the optional parameters of this function. + /// public Variant[] DefaultValues { get; } public override SourceLocation Location { get; } = SourceLocation.Unknown; @@ -224,6 +233,12 @@ protected NativeFunction(Interpreter interpreter, int param_count, Func + /// Executes the current function on the given call frame with the given arguments. + /// + /// Call frame, on which the current function shall be executed. + /// Function arguments. + /// The return value of the function call. public FunctionReturnValue Execute(NativeCallFrame frame, Variant[] args) { List a = [.. args, .. DefaultValues.Skip(args.Length - ParameterCount.MinimumCount)]; @@ -244,51 +259,112 @@ public FunctionReturnValue Execute(NativeCallFrame frame, Variant[] args) /// /// Creates a new (parameterless) native function using the given delegate. - /// The function internally gets assigned an unique name, but will not be registered in the function resolver. + /// The function internally gets assigned an unique name, but will not be registered in the function resolver. /// /// The interpreter instance. - /// The delegate representing the function's internal logic. + /// The delegate representing the function's internal logic. /// The operating systems supported by the given delegate. /// The newly created native function. - public static NativeFunction FromDelegate(Interpreter interpreter, Func execute, OS os = OS.Any) => - FromDelegate(interpreter, 0, (f, _) => execute(f), os); + public static NativeFunction FromDelegate(Interpreter interpreter, Func @delegate, OS os = OS.Any) => + FromDelegate(interpreter, 0, (f, _) => @delegate(f), os); /// /// Creates a new native function using the given delegate. - /// The function internally gets assigned an unique name, but will not be registered in the function resolver. + /// The function internally gets assigned an unique name, but will not be registered in the function resolver. /// /// The interpreter instance. /// The number of parameters expected by the delegate. - /// The delegate representing the function's internal logic. + /// The delegate representing the function's internal logic. /// The operating systems supported by the given delegate. /// The newly created native function. - public static NativeFunction FromDelegate(Interpreter interpreter, int param_count, Func execute, OS os = OS.Any) => - FromDelegate(interpreter, null, param_count, execute, os); + public static NativeFunction FromDelegate(Interpreter interpreter, int param_count, Func @delegate, OS os = OS.Any) => + FromDelegate(interpreter, null, param_count, @delegate, os); - public static NativeFunction FromDelegate(Interpreter interpreter, string? name, int param_count, Func execute, OS os = OS.Any) => - new(interpreter, param_count, execute, os, name); + /// + /// Creates a new native function using the given delegate. + /// Please note that the function will not be registered in the function resolver. + /// + /// The interpreter instance. + /// The name of the function. + /// The number of parameters expected by the delegate. + /// The delegate representing the function's internal logic. + /// The operating systems supported by the given delegate. + /// The newly created native function. + public static NativeFunction FromDelegate(Interpreter interpreter, string? name, int param_count, Func @delegate, OS os = OS.Any) => + new(interpreter, param_count, @delegate, os, name); + /// + /// Creates a new native function using the given delegate. + /// The function internally gets assigned an unique name, but will not be registered in the function resolver. + /// + /// The interpreter instance. + /// The minimum parameter count expected by the function. + /// The maximum parameter count expected by the function. This value must be equals or larger than . + /// The delegate representing the function's internal logic. + /// The default values for the function's optional parameters. The length of this array must be equals or larger than the difference of and . + /// The newly created native function. public static NativeFunction FromDelegate(Interpreter interpreter, int min_param_count, int max_param_count, Func @delegate, params Variant[] default_values) => FromDelegate(interpreter, min_param_count, max_param_count, @delegate, OS.Any, default_values); + /// + /// Creates a new native function using the given delegate. + /// Please note that the function will not be registered in the function resolver. + /// + /// The name of the function. + /// The interpreter instance. + /// The minimum parameter count expected by the function. + /// The maximum parameter count expected by the function. This value must be equals or larger than . + /// The delegate representing the function's internal logic. + /// The default values for the function's optional parameters. The length of this array must be equals or larger than the difference of and . + /// The newly created native function. public static NativeFunction FromDelegate(Interpreter interpreter, string? name, int min_param_count, int max_param_count, Func @delegate, params Variant[] default_values) => FromDelegate(interpreter, name, min_param_count, max_param_count, @delegate, OS.Any, default_values); + /// + /// Creates a new native function using the given delegate. + /// The function internally gets assigned an unique name, but will not be registered in the function resolver. + /// + /// The interpreter instance. + /// The minimum parameter count expected by the function. + /// The maximum parameter count expected by the function. This value must be equals or larger than . + /// The delegate representing the function's internal logic. + /// The operating systems supported by the given delegate. + /// The default values for the function's optional parameters. The length of this array must be equals or larger than the difference of and . + /// The newly created native function. public static NativeFunction FromDelegate(Interpreter interpreter, int min_param_count, int max_param_count, Func @delegate, OS os, params Variant[] default_values) => FromDelegate(interpreter, null, min_param_count, max_param_count, @delegate, os, default_values); + /// + /// Creates a new native function using the given delegate. + /// Please note that the function will not be registered in the function resolver. + /// + /// The name of the function. + /// The interpreter instance. + /// The minimum parameter count expected by the function. + /// The maximum parameter count expected by the function. This value must be equals or larger than . + /// The delegate representing the function's internal logic. + /// The operating systems supported by the given delegate. + /// The default values for the function's optional parameters. The length of this array must be equals or larger than the difference of and . + /// The newly created native function. public static NativeFunction FromDelegate(Interpreter interpreter, string? name, int min_param_count, int max_param_count, Func @delegate, OS os, params Variant[] default_values) => new(interpreter, (min_param_count, max_param_count), default_values, @delegate, os, name); } /// -/// Represents an unmanaged .NET framework function. -/// The refrence to the .NET function is provided via an instance of . +/// Represents an unmanaged .NET function. +/// The reference to the .NET function is provided via an instance of . /// public sealed class NETFrameworkFunction : NativeFunction { - internal NETFrameworkFunction(Interpreter interpreter, MethodInfo method, object? instance) + /// + /// Creates a new unmanaged .NET method. + /// The reference to the .NET function is provided via the given parameter. + /// + /// The interpreter instance. + /// The which this instance of the .NET function will be wrapping. + /// The .NET object instance, on which this method will be executed. A value of indicates a static invocation. + public NETFrameworkFunction(Interpreter interpreter, MethodInfo method, object? instance) : this(interpreter, method, method.GetParameters(), instance) { }