diff --git a/src/OneScript.Core/Contexts/ContextMethodAttribute.cs b/src/OneScript.Core/Contexts/ContextMethodAttribute.cs index 78c4c5626..3eabb3d8a 100644 --- a/src/OneScript.Core/Contexts/ContextMethodAttribute.cs +++ b/src/OneScript.Core/Contexts/ContextMethodAttribute.cs @@ -5,7 +5,10 @@ This Source Code Form is subject to the terms of the at http://mozilla.org/MPL/2.0/. ----------------------------------------------------------*/ +#nullable enable using System; +using System.Linq; +using System.Reflection; using System.Runtime.CompilerServices; using OneScript.Commons; @@ -16,6 +19,10 @@ public class ContextMethodAttribute : Attribute, INameAndAliasProvider { private readonly string _name; private readonly string _alias; + private bool _isDeprecated; + private bool _throwOnUse; + private bool _skipForDocumenter; + private Type? _converter; public ContextMethodAttribute(string name, string alias) { @@ -35,16 +42,49 @@ public ContextMethodAttribute(string name, string _ = null, { } - public bool IsDeprecated { get; set; } + public bool IsDeprecated + { + get => _isDeprecated; + set => _isDeprecated = value; + } + + public bool ThrowOnUse + { + get => _throwOnUse; + set => _throwOnUse = value; + } - public bool ThrowOnUse { get; set; } - /// /// Данный метод не будет обработан генератором документации при обходе типов /// - public bool SkipForDocumenter { get; set; } + public bool SkipForDocumenter + { + get => _skipForDocumenter; + set => _skipForDocumenter = value; + } public string Name => _name; public string Alias => _alias; + + /// + /// Конвертер возвращаемого значения функции, необходим для неподдерживаемых маршаллингом типов + /// + public Type? Converter + { + get => _converter; + set + { + if (value != null) + { + if (!value.GetInterfaces().Any(i => i.IsGenericType && i.GetGenericTypeDefinition() == typeof(IContextValueConverter<>))) + throw new Exception("Конвертер должен реализовывать интерфейс IContextValueConverter"); + + if (value.IsAbstract || value.IsInterface) + throw new Exception("Конвертер не может быть абстрактным типом или интерфейсом"); + } + + _converter = value; + } + } } } \ No newline at end of file diff --git a/src/OneScript.Core/Contexts/ContextMethodInfo.cs b/src/OneScript.Core/Contexts/ContextMethodInfo.cs index 362a2e209..b2ecf688e 100644 --- a/src/OneScript.Core/Contexts/ContextMethodInfo.cs +++ b/src/OneScript.Core/Contexts/ContextMethodInfo.cs @@ -21,6 +21,8 @@ public sealed class ContextMethodInfo : BslMethodInfo, IObjectWrapper { private readonly MethodInfo _realMethod; private readonly ContextMethodAttribute _scriptMark; + + public Type ConverterType { get; private set; } public ContextMethodInfo(MethodInfo realMethod) { @@ -39,10 +41,18 @@ public ContextMethodInfo(MethodInfo realMethod) public ContextMethodInfo(MethodInfo realMethod, ContextMethodAttribute binding) { _realMethod = realMethod; + _scriptMark = binding; + InjectsProcess = _realMethod.GetParameters().FirstOrDefault()?.ParameterType == typeof(IBslProcess); } + private void InitConverter() + { + if (_scriptMark.Converter != null) + ConverterType = _scriptMark.Converter; + } + public override Type ReturnType => _realMethod.ReturnType; public override ParameterInfo ReturnParameter => _realMethod.ReturnParameter; @@ -85,6 +95,18 @@ public override MethodInfo GetBaseDefinition() { return _realMethod.GetBaseDefinition(); } + + public bool TryGetConverter(out object converter) + { + if (_scriptMark.Converter == null) + { + converter = null; + return false; + } + + converter = Activator.CreateInstance(_scriptMark.Converter); + return true; + } public override ICustomAttributeProvider ReturnTypeCustomAttributes => _realMethod.ReturnTypeCustomAttributes; diff --git a/src/OneScript.Core/Contexts/ContextPropertyAttribute.cs b/src/OneScript.Core/Contexts/ContextPropertyAttribute.cs index 35350670a..96911307f 100644 --- a/src/OneScript.Core/Contexts/ContextPropertyAttribute.cs +++ b/src/OneScript.Core/Contexts/ContextPropertyAttribute.cs @@ -6,6 +6,7 @@ This Source Code Form is subject to the terms of the ----------------------------------------------------------*/ using System; +using System.Linq; using OneScript.Commons; namespace OneScript.Contexts @@ -15,6 +16,7 @@ public class ContextPropertyAttribute : Attribute, INameAndAliasProvider { private readonly string _name; private readonly string _alias; + private Type _converter; public ContextPropertyAttribute(string name, string alias = "") { @@ -40,5 +42,26 @@ public ContextPropertyAttribute(string name, string alias = "") public string Name => _name; public string Alias => _alias; + + /// + /// Конвертер значения свойства + /// + public Type Converter + { + get => _converter; + set + { + if (value != null) + { + if (!value.GetInterfaces().Any(i => i.IsGenericType && i.GetGenericTypeDefinition() == typeof(IContextValueConverter<>))) + throw new Exception("Конвертер должен реализовывать интерфейс IContextValueConverter"); + + if (value.IsAbstract || value.IsInterface) + throw new Exception("Конвертер не может быть абстрактным типом или интерфейсом"); + } + + _converter = value; + } + } } } \ No newline at end of file diff --git a/src/OneScript.Core/Contexts/ContextPropertyInfo.cs b/src/OneScript.Core/Contexts/ContextPropertyInfo.cs index 5b7d9b2db..3b9e104d4 100644 --- a/src/OneScript.Core/Contexts/ContextPropertyInfo.cs +++ b/src/OneScript.Core/Contexts/ContextPropertyInfo.cs @@ -10,6 +10,7 @@ This Source Code Form is subject to the terms of the using System.Linq; using System.Reflection; using OneScript.Commons; +using ScriptEngine.Machine; namespace OneScript.Contexts { @@ -20,7 +21,7 @@ public class ContextPropertyInfo : BslPropertyInfo, IObjectWrapper { private readonly PropertyInfo _realProperty; private readonly ContextPropertyAttribute _scriptMark; - + public ContextPropertyInfo(PropertyInfo wrappedInfo) { _realProperty = wrappedInfo; @@ -54,6 +55,32 @@ public override bool Equals(BslPropertyInfo other) public override string Alias => _scriptMark.Alias; + public Type ConverterType => _scriptMark.Converter; + + public bool TryGetConverter(out object converter) + { + if (ConverterType == null) + { + converter = null; + return false; + } + + converter = Activator.CreateInstance(ConverterType); + return true; + } + + public bool TryGetStrictConverter(out IContextValueConverter converter) + { + var result = TryGetConverter(out var c); + + if (result) + converter = c as IContextValueConverter; + else + converter = null; + + return result; + } + public override MethodInfo[] GetAccessors(bool nonPublic) { var getter = GetGetMethod(nonPublic); diff --git a/src/OneScript.Core/Contexts/IContextValueConverter.cs b/src/OneScript.Core/Contexts/IContextValueConverter.cs new file mode 100644 index 000000000..12a07272b --- /dev/null +++ b/src/OneScript.Core/Contexts/IContextValueConverter.cs @@ -0,0 +1,23 @@ +/*---------------------------------------------------------- +This Source Code Form is subject to the terms of the +Mozilla Public License, v.2.0. If a copy of the MPL +was not distributed with this file, You can obtain one +at http://mozilla.org/MPL/2.0/. +----------------------------------------------------------*/ +using System; +using System.Linq; +using ScriptEngine.Machine; + +namespace OneScript.Contexts +{ + public interface IContextValueConverter + { + IValue ToIValue(TClr obj); + + TClr ToClr(IValue obj); + + public static bool ImplementsIt(Type type) + => type.GetInterfaces() + .Any(i => i.IsGenericType && i.GetGenericTypeDefinition() == typeof(IContextValueConverter<>)); + } +} diff --git a/src/ScriptEngine/Machine/Contexts/ContextMethodMapper.cs b/src/ScriptEngine/Machine/Contexts/ContextMethodMapper.cs index 9d59cabef..636cdb0cb 100644 --- a/src/ScriptEngine/Machine/Contexts/ContextMethodMapper.cs +++ b/src/ScriptEngine/Machine/Contexts/ContextMethodMapper.cs @@ -152,15 +152,16 @@ private static MethodSignature CreateMetadata(MethodInfo target, ContextMethodAt } - var scriptMethInfo = new MethodSignature(); - scriptMethInfo.IsFunction = isFunc; - scriptMethInfo.IsExport = true; - scriptMethInfo.IsDeprecated = binding.IsDeprecated; - scriptMethInfo.ThrowOnUseDeprecated = binding.ThrowOnUse; - scriptMethInfo.Name = binding.Name; - scriptMethInfo.Alias = binding.Alias; - - scriptMethInfo.Params = paramDefs; + var scriptMethInfo = new MethodSignature + { + IsFunction = isFunc, + IsExport = true, + IsDeprecated = binding.IsDeprecated, + ThrowOnUseDeprecated = binding.ThrowOnUse, + Name = binding.Name, + Alias = binding.Alias, + Params = paramDefs + }; return scriptMethInfo; } @@ -168,9 +169,18 @@ private static MethodSignature CreateMetadata(MethodInfo target, ContextMethodAt private static ContextCallableDelegate CreateFunction(ContextMethodInfo target) { var methodCall = MethodCallExpression(target, out var instParam, out var argsParam, out var processParam); - - var convertRetMethod = ContextValuesMarshaller.BslReturnValueGenericConverter.MakeGenericMethod(target.ReturnType); - var convertReturnCall = Expression.Call(convertRetMethod, methodCall); + + var convertReturnCall = target.ConverterType switch + { + null => Expression.Call( + ContextValuesMarshaller.BslReturnValueGenericConverter.MakeGenericMethod(target.ReturnType), + methodCall), + _ => Expression.Call( + Expression.New(target.ConverterType), + target.ConverterType.GetMethod("ToIValue")!, + methodCall) + }; + var body = convertReturnCall; var l = Expression.Lambda>(body, instParam, argsParam, processParam); @@ -226,28 +236,24 @@ private static InvocationExpression MethodCallExpression( var (clrIndexStart, argsLen) = contextMethod.InjectsProcess ? (1, parameters.Length - 1) : (0, parameters.Length); - var argsPass = new List(); - argsPass.Add(instParam); - + var argsPass = new List { instParam }; + if (contextMethod.InjectsProcess) argsPass.Add(processParam); for (int bslIndex = 0,clrIndex = clrIndexStart; bslIndex < argsLen; bslIndex++, clrIndex++) { var targetType = parameters[clrIndex].ParameterType; - var convertMethod = ContextValuesMarshaller.BslGenericParameterConverter.MakeGenericMethod(targetType); Expression defaultArg; if (parameters[clrIndex].HasDefaultValue) - { defaultArg = Expression.Constant(parameters[clrIndex].DefaultValue, targetType); - } else - { defaultArg = ContextValuesMarshaller.GetDefaultBslValueConstant(targetType); - } var indexedArg = Expression.ArrayIndex(argsParam, Expression.Constant(bslIndex)); + + var convertMethod = ContextValuesMarshaller.BslGenericParameterConverter.MakeGenericMethod(targetType); var conversionCall = Expression.Call(convertMethod, indexedArg, defaultArg, diff --git a/src/ScriptEngine/Machine/Contexts/ContextPropertyMapper.cs b/src/ScriptEngine/Machine/Contexts/ContextPropertyMapper.cs index 9b97c2a38..acd2fc5eb 100644 --- a/src/ScriptEngine/Machine/Contexts/ContextPropertyMapper.cs +++ b/src/ScriptEngine/Machine/Contexts/ContextPropertyMapper.cs @@ -16,8 +16,8 @@ namespace ScriptEngine.Machine.Contexts { public class PropertyTarget { - private readonly BslPropertyInfo _propertyInfo; - + private readonly ContextPropertyInfo _propertyInfo; + public PropertyTarget(PropertyInfo propInfo) { _propertyInfo = new ContextPropertyInfo(propInfo); @@ -27,16 +27,6 @@ public PropertyTarget(PropertyInfo propInfo) if (string.IsNullOrEmpty(Alias)) Alias = propInfo.Name; - IValue CantReadAction(TInstance inst) - { - throw PropertyAccessException.PropIsNotReadableException(Name); - } - - void CantWriteAction(TInstance inst, IValue val) - { - throw PropertyAccessException.PropIsNotWritableException(Name); - } - if (_propertyInfo.CanRead) { var getMethodInfo = propInfo.GetGetMethod(); @@ -84,6 +74,18 @@ void CantWriteAction(TInstance inst, IValue val) { Setter = CantWriteAction; } + + return; + + void CantWriteAction(TInstance inst, IValue val) + { + throw PropertyAccessException.PropIsNotWritableException(Name); + } + + IValue CantReadAction(TInstance inst) + { + throw PropertyAccessException.PropIsNotReadableException(Name); + } } public Func Getter { get; } @@ -108,19 +110,18 @@ private Func CreateGetter(MethodInfo methInfo) private Action CreateSetter(MethodInfo methInfo) { var method = (Action)Delegate.CreateDelegate(typeof(Action), methInfo); - return (inst, val) => method(inst, ConvertParam(val)); + return (inst, val) => method(inst, ConvertValue(val)); } - private static T ConvertParam(IValue value) - { - return ContextValuesMarshaller.ConvertValueStrict(value); - } - - private static IValue ConvertReturnValue(TRet param) - { - return ContextValuesMarshaller.ConvertReturnValue(param); - } + private T ConvertValue(IValue value) + => _propertyInfo.TryGetStrictConverter(out var converter) ? + converter.ToClr(value) + : ContextValuesMarshaller.ConvertValueStrict(value); + private IValue ConvertReturnValue(TRet param) + => _propertyInfo.TryGetStrictConverter(out var converter) + ? converter!.ToIValue(param) + : ContextValuesMarshaller.ConvertReturnValue(param); } public class ContextPropertyMapper diff --git a/src/ScriptEngine/Machine/Contexts/ContextValuesMarshaller.cs b/src/ScriptEngine/Machine/Contexts/ContextValuesMarshaller.cs index f64d2aeea..de4eeb84b 100644 --- a/src/ScriptEngine/Machine/Contexts/ContextValuesMarshaller.cs +++ b/src/ScriptEngine/Machine/Contexts/ContextValuesMarshaller.cs @@ -33,7 +33,7 @@ static ContextValuesMarshaller() BslGenericParameterConverter = typeof(ContextValuesMarshaller).GetMethods() .First(x => x.Name == nameof(ConvertParam) && x.GetGenericArguments().Length == 1 && x.GetParameters().Length == 3); - + BslReturnValueGenericConverter = typeof(ContextValuesMarshaller).GetMethods() .First(x => x.Name == nameof(ConvertReturnValue) && x.GetGenericArguments().Length == 1); } @@ -88,7 +88,7 @@ public static object ConvertParam(IValue value, Type type, IBslProcess process) /// Значение целевого типа public static T ConvertParam(IValue value, T defaultValue = default) { - return ConvertParam(value, defaultValue, ForbiddenBslProcess.Instance); + return ConvertParam(value, defaultValue, ForbiddenBslProcess.Instance); } /// @@ -101,7 +101,7 @@ public static T ConvertParam(IValue value, T defaultValue = default) /// Значение целевого типа public static T ConvertParam(IValue value, T defaultValue, IBslProcess process) { - object valueObj = ConvertParam(value, typeof(T), process); + var valueObj = ConvertParam(value, typeof(T), process); return valueObj != null ? (T)valueObj : defaultValue; } @@ -163,7 +163,7 @@ private static object ConvertValueType(IValue value, Type type, IBslProcess proc { return null; } - + if (Nullable.GetUnderlyingType(type) != null) { return ConvertValueType(value, Nullable.GetUnderlyingType(type), process); @@ -293,25 +293,21 @@ private static IValue ConvertReturnValue(object objParam, Type type) } if (type.IsEnum) - { return ConvertEnum(objParam, type); - } - else if (typeof(IRuntimeContextInstance).IsAssignableFrom(type)) - { + + if (typeof(IRuntimeContextInstance).IsAssignableFrom(type)) return (IValue)(IRuntimeContextInstance)objParam; - } - else if (typeof(IValue).IsAssignableFrom(type)) - { + + if (typeof(IValue).IsAssignableFrom(type)) return (IValue)objParam; - } - else if (Nullable.GetUnderlyingType(type) != null) - { + + if (Nullable.GetUnderlyingType(type) != null) return ConvertReturnValue(objParam, Nullable.GetUnderlyingType(type)); - } - else - { - throw ValueMarshallingException.TypeNotSupported(type); - } + + if (type.GetCustomAttribute() != null && !typeof(IRuntimeContextInstance).IsAssignableFrom(type)) + return new NotBslValueWrapper(objParam); + + throw ValueMarshallingException.TypeNotSupported(type); } private static IValue ConvertEnum(object objParam, Type type) diff --git a/src/ScriptEngine/Machine/NotBslValueWrapper.cs b/src/ScriptEngine/Machine/NotBslValueWrapper.cs new file mode 100644 index 000000000..d2815aee7 --- /dev/null +++ b/src/ScriptEngine/Machine/NotBslValueWrapper.cs @@ -0,0 +1,231 @@ +/*---------------------------------------------------------- +This Source Code Form is subject to the terms of the +Mozilla Public License, v.2.0. If a copy of the MPL +was not distributed with this file, You can obtain one +at http://mozilla.org/MPL/2.0/. +----------------------------------------------------------*/ +using System; +using System.Collections.Concurrent; +using System.Collections.Generic; +using System.Linq; +using System.Reflection; +using OneScript.Commons; +using OneScript.Contexts; +using OneScript.Exceptions; +using OneScript.Execution; +using OneScript.Types; +using OneScript.Values; +using ScriptEngine.Machine.Contexts; +using ScriptEngine.Types; +using TinyIoC; + +namespace ScriptEngine.Machine +{ + public class NotBslValueWrapper : ContextIValueImpl, IObjectWrapper + { + private static readonly object InitLocker = new object(); + private readonly Type _underlyingType; + + private static readonly Dictionary PropertiesIndexers = + new Dictionary(); + private static readonly Dictionary MethodsIndexers = + new Dictionary(); + + private static readonly Dictionary> PropertiesCaches = + new Dictionary>(); + private static readonly Dictionary> MethodsCaches = + new Dictionary>(); + + public object UnderlyingObject { get; } + + public NotBslValueWrapper(object obj) + { + UnderlyingObject = obj; + _underlyingType = UnderlyingObject.GetType(); + + DefineType(obj.GetType().GetTypeFromClassMarkup()); + InitMethodsProperties(); + } + + private void InitMethodsProperties() + { + var objType = UnderlyingObject.GetType(); + + lock (InitLocker) + { + // Свойства и методы уже были закешированы + if (PropertiesIndexers.ContainsKey(objType)) + return; + + var propertiesIndex = new IndexedNamesCollection(); + var propertiesCache = new Dictionary(); + + var methodsIndex = new IndexedNamesCollection(); + var methodsCache = new Dictionary(); + + + var props = objType.GetProperties() + .Where(x => x.GetCustomAttributes(typeof(ContextPropertyAttribute), false).Length != 0) + .ToList(); + + foreach (var property in props) + { + var info = new ContextPropertyInfo(property); + var id = propertiesIndex.RegisterName(info.Name, string.IsNullOrEmpty(info.Alias) ? null : info.Alias); + + propertiesCache.Add(id, info); + } + + var methods = objType.GetMethods() + .Where(x => x.GetCustomAttributes(typeof(ContextMethodAttribute), false).Length != 0) + .ToList(); + + foreach (var method in methods) + { + var info = new ContextMethodInfo(method); + var id = methodsIndex.RegisterName(info.Name, string.IsNullOrEmpty(info.Alias) ? null : info.Alias); + + methodsCache.Add(id, info); + } + + PropertiesIndexers.Add(objType, propertiesIndex); + PropertiesCaches.Add(objType, propertiesCache); + + MethodsIndexers.Add(objType, methodsIndex); + MethodsCaches.Add(objType, methodsCache); + } + } + + public override int GetPropertyNumber(string name) + => GetPropertiesIndexer().TryGetIdOfName(name, out var id) ? id : -1; + + public override bool IsPropReadable(int propNum) + => GetPropertiesCache()[propNum].CanRead; + + public override bool IsPropWritable(int propNum) + => GetPropertiesCache()[propNum].CanWrite; + + public override IValue GetPropValue(int propNum) + { + var prop = GetPropertiesCache()[propNum]; + var getter = prop.GetGetMethod(true); + if (getter == null) + throw PropertyAccessException.PropIsNotReadableException(prop.Name); + var value = getter.Invoke(UnderlyingObject, Array.Empty()); + + if (!prop.TryGetConverter(out var converter)) + return ContextValuesMarshaller.ConvertDynamicValue(value); + + var toIValue = converter.GetType().GetMethod("ToIValue"); + return (IValue)toIValue!.Invoke(converter, new[] { value }); + } + + public override void SetPropValue(int propNum, IValue newVal) + { + var prop = GetPropertiesCache()[propNum]; + + var setter = prop.GetSetMethod(true); + if (setter == null) + throw PropertyAccessException.PropIsNotWritableException(prop.Name); + + object val; + + if (prop.TryGetConverter(out var converter)) + { + var type = converter.GetType(); + var toClrMethod = type + .GetMethod("ToClr", new [] { typeof(IValue) }); + + val = toClrMethod!.Invoke(converter, new object[] { newVal }); + } + else + val = ContextValuesMarshaller.ConvertToClrObject(newVal); + + var propType = prop.PropertyType; + if (val is NotBslValueWrapper wrapper && propType.IsInstanceOfType(wrapper.UnderlyingObject)) + val = wrapper.UnderlyingObject; + + setter.Invoke(UnderlyingObject, new [] { val }); + } + + public override int GetPropCount() + => GetPropertiesCache().Count; + + public override string GetPropName(int propNum) + => GetPropertiesCache()[propNum].Name; + + public override int GetMethodNumber(string name) + => GetMethodsIndexer().TryGetIdOfName(name, out var id) ? id : -1; + + public override int GetMethodsCount() + => GetMethodsCache().Count; + + public override BslMethodInfo GetMethodInfo(int methodNumber) + => GetMethodsCache()[methodNumber]; + + public override BslPropertyInfo GetPropertyInfo(int propertyNumber) + => GetPropertiesCache()[propertyNumber]; + + public override void CallAsProcedure(int methodNumber, IValue[] arguments, IBslProcess process) + { + var method = GetMethodsCache()[methodNumber]; + + var args = arguments.Select(ContextValuesMarshaller.ConvertToClrObject).ToList(); + + if (method.InjectsProcess) + args.Insert(0, process); + + method.Invoke(UnderlyingObject, args.ToArray()); + } + + public override void CallAsFunction(int methodNumber, IValue[] arguments, out IValue retValue, IBslProcess process) + { + var method = GetMethodsCache()[methodNumber]; + + var args = arguments.Select(c => ContextValuesMarshaller.ConvertParam(c, method.ReturnType, process)).ToList(); + + if (method.InjectsProcess) + args.Insert(0, process); + + var result = method.Invoke(UnderlyingObject, args.ToArray()); + + if (method.TryGetConverter(out var converter)) + { + var type = converter.GetType(); + var convertMethod = type + .GetMethod("ToIValue", new [] { method.ReturnType }); + + retValue = (IValue)convertMethod!.Invoke(converter, new[] { result }); + } + else + retValue = ContextValuesMarshaller.ConvertDynamicValue(result); + } + + private static int GetMemberNumberByName(Dictionary items, string name) + where T : INameAndAliasProvider + { + foreach (var kvp in from kvp in items + let v = kvp.Value + where string.Equals(v.Name, name, StringComparison.InvariantCultureIgnoreCase) || + string.Equals(v.Alias, name, StringComparison.InvariantCultureIgnoreCase) + select kvp) + { + return kvp.Key; + } + + return -1; + } + + private IndexedNamesCollection GetMethodsIndexer() + => MethodsIndexers[_underlyingType]; + + private IndexedNamesCollection GetPropertiesIndexer() + => PropertiesIndexers[_underlyingType]; + + private Dictionary GetMethodsCache() + => MethodsCaches[_underlyingType]; + + private Dictionary GetPropertiesCache() + => PropertiesCaches[_underlyingType]; + } +} diff --git a/src/ScriptEngine/Machine/TypeFactory.cs b/src/ScriptEngine/Machine/TypeFactory.cs index 6bef446da..1f46b3fa1 100644 --- a/src/ScriptEngine/Machine/TypeFactory.cs +++ b/src/ScriptEngine/Machine/TypeFactory.cs @@ -179,7 +179,15 @@ private InstanceConstructor FallbackConstructor(Refl.MethodInfo methodInfo) try { - return (IValue) methodInfo.Invoke(null, methArgs); + var value = methodInfo.Invoke(null, methArgs); + + if (value is IValue iValue) + return iValue; + + if (value is IRuntimeContextInstance rValue) + return (IValue)rValue; + + return ContextValuesMarshaller.ConvertDynamicValue(value); } catch (Refl.TargetInvocationException e) { diff --git a/tests/.vscode/launch.json b/tests/.vscode/launch.json index c952b2feb..9eecf6c9f 100644 --- a/tests/.vscode/launch.json +++ b/tests/.vscode/launch.json @@ -12,7 +12,7 @@ "args": ["-run", "${file}"], "cwd": "${workspaceRoot}", "env": {}, - "runtimeExecutable": "${workspaceRoot}/../src/oscript/bin/LinuxDebug/net6.0/oscript", + "runtimeExecutable": "${workspaceRoot}/../src/oscript/bin/LinuxDebug/net8.0/oscript", "runtimeArgs": [], "debugPort": 2801 }, @@ -24,7 +24,7 @@ "args": ["-run", "${file}"], "cwd": "${workspaceRoot}", "env": {}, - "runtimeExecutable": "${workspaceRoot}/../src/oscript/bin/Debug/net6.0/oscript", + "runtimeExecutable": "${workspaceRoot}/../src/oscript/bin/Debug/net8.0/oscript", "runtimeArgs": [], "debugPort": 2801 }