diff --git a/src/OneScript.Native/Compiler/MethodCompiler.cs b/src/OneScript.Native/Compiler/MethodCompiler.cs index 190643ebf..c4187b040 100644 --- a/src/OneScript.Native/Compiler/MethodCompiler.cs +++ b/src/OneScript.Native/Compiler/MethodCompiler.cs @@ -1092,6 +1092,20 @@ protected override void VisitGlobalFunctionCall(CallNode node) _statementBuildParts.Push(expression); } + private static bool InjectedProcessNeeded(MethodInfo methodInfo) + { + if (methodInfo is ContextMethodInfo { InjectsProcess: true }) + { + return true; + } + var p = methodInfo.GetParameters(); + if (p.Length > 0 && p[0].ParameterType == typeof(IBslProcess)) + { + return true; + } + return false; + } + protected override void VisitObjectProcedureCall(BslSyntaxNode node) { var target = _statementBuildParts.Pop(); @@ -1102,7 +1116,8 @@ protected override void VisitObjectProcedureCall(BslSyntaxNode node) if (targetType.IsObjectValue()) { var methodInfo = FindMethodOfType(node, targetType, name); - var args = PrepareCallArguments(call.ArgumentList, methodInfo.GetParameters(), methodInfo is ContextMethodInfo { InjectsProcess: true }); + var injectProcess = InjectedProcessNeeded(methodInfo); + var args = PrepareCallArguments(call.ArgumentList, methodInfo.GetParameters(), injectProcess); _blocks.Add(Expression.Call(target, methodInfo, args)); } @@ -1168,8 +1183,8 @@ protected override void VisitObjectFunctionCall(BslSyntaxNode node) $"Метод {targetType}.{name} не является функцией", $"Method {targetType}.{name} is not a function"), ToCodePosition(node.Location)); } - - var args = PrepareCallArguments(call.ArgumentList, methodInfo.GetParameters(), methodInfo is ContextMethodInfo { InjectsProcess: true }); + + var args = PrepareCallArguments(call.ArgumentList, methodInfo.GetParameters(), InjectedProcessNeeded(methodInfo)); _statementBuildParts.Push(Expression.Call(target, methodInfo, args)); } else if (targetType.IsContext()) @@ -1266,7 +1281,7 @@ private Expression CreateMethodCall(CallNode node) } var symbol = Symbols.GetScope(binding.ScopeNumber).Methods[binding.MemberNumber]; - var args = PrepareCallArguments(node.ArgumentList, symbol.Method.GetParameters(), symbol.Method is ContextMethodInfo { InjectsProcess: true }); + var args = PrepareCallArguments(node.ArgumentList, symbol.Method.GetParameters(), InjectedProcessNeeded(symbol.Method)); var methodInfo = symbol.Method; if (methodInfo is ContextMethodInfo contextMethod) @@ -1418,8 +1433,8 @@ private List PrepareCallArguments(BslSyntaxNode argList, ParameterIn ? ConvertToExpressionTree(passedArg.Children[0]) : null).ToArray(); - var parametersToProcess = declaredParameters.Length; var declStart = injectsProcess ? 1 : 0; + var parametersToProcess = declaredParameters.Length - declStart; for (int i = 0, decl = declStart; i < parameters.Length; i++, decl++) { if (parametersToProcess == 0) diff --git a/src/Tests/OneScript.Core.Tests/HelperClasses/TestContextClass.cs b/src/Tests/OneScript.Core.Tests/HelperClasses/TestContextClass.cs index 0ce5e9f00..6992d49a4 100644 --- a/src/Tests/OneScript.Core.Tests/HelperClasses/TestContextClass.cs +++ b/src/Tests/OneScript.Core.Tests/HelperClasses/TestContextClass.cs @@ -5,13 +5,14 @@ This Source Code Form is subject to the terms of the at http://mozilla.org/MPL/2.0/. ----------------------------------------------------------*/ -using System.Collections.Generic; using OneScript.Contexts; +using OneScript.Execution; using OneScript.Types; using OneScript.Values; using ScriptEngine.Machine; using ScriptEngine.Machine.Contexts; using ScriptEngine.Types; +using System.Collections.Generic; namespace OneScript.Core.Tests { @@ -60,7 +61,46 @@ public override void SetIndexedValue(IValue index, IValue val) _indexedValues[(BslValue)index] = (BslValue)val; } - [ScriptConstructor] + #region IBslProcessTests + + [ContextMethod("Процедура0")] + public void Procedure0() { } + + [ContextMethod("Процедура0СПроцессом")] + public void Procedure0WithProcess(IBslProcess process) { } + + [ContextMethod("Процедура1")] + public void Procedure1(int intValue) { } + + [ContextMethod("Процедура1СПроцессом")] + public void Procedure1WithProcess(IBslProcess process, int intValue) { } + + [ContextMethod("Процедура1СУмолчанием")] + public void Procedure1WithDefault(int intValue = 0) { } + + [ContextMethod("Процедура1СУмолчаниемСПроцессом")] + public void Procedure1WithDefaultWithProcess(IBslProcess process, int intValue = 0) { } + + [ContextMethod("Функция0")] + public int Function0() { return 0; } + + [ContextMethod("Функция0СПроцессом")] + public int Function0WithProcess(IBslProcess process) { return 0; } + + [ContextMethod("Функция1")] + public int Function1(int intValue) { return intValue; } + + [ContextMethod("Функция1СПроцессом")] + public int Function1WithProcess(IBslProcess process, int intValue) { return intValue; } + + [ContextMethod("Функция1СУмолчанием")] + public int Function1WithDefault(int intValue = 0) { return intValue; } + + [ContextMethod("Функция1СУмолчаниемСПроцессом")] + public int Function1WithDefaultWithProcess(IBslProcess process, int intValue = 0) { return intValue; } + #endregion + + [ScriptConstructor] public static TestContextClass Constructor() { return new TestContextClass diff --git a/src/Tests/OneScript.Core.Tests/NativeCompilerTest.cs b/src/Tests/OneScript.Core.Tests/NativeCompilerTest.cs index 11ade2183..c4029976f 100644 --- a/src/Tests/OneScript.Core.Tests/NativeCompilerTest.cs +++ b/src/Tests/OneScript.Core.Tests/NativeCompilerTest.cs @@ -867,7 +867,73 @@ public void Can_Call_Member_Procedures() array.Should().HaveCount(2); } - + + [Theory] + [InlineData("Объект.Процедура0();")] + [InlineData("Объект.Процедура0СПроцессом();")] + [InlineData("Объект.Процедура1(1);")] + [InlineData("Объект.Процедура1СПроцессом(1);")] + [InlineData("Объект.Процедура1СУмолчанием();")] + [InlineData("Объект.Процедура1СУмолчаниемСПроцессом();")] + [InlineData("Объект.Процедура1СУмолчанием(1);")] + [InlineData("Объект.Процедура1СУмолчаниемСПроцессом(1);")] + public void Can_Call_Member_ProceduresWithBslProcess(string code) + { + var tm = new DefaultTypeManager(); + var testType = tm.RegisterClass(typeof(TestContextClass)); + + var block = new CompiledBlock(default); + block.Parameters.Insert("Объект", new BslTypeValue(testType)); + block.CodeBlock = code; + + var method = block.CreateDelegate>(); + var testValue = new TestContextClass(); + method(testValue); + } + + [Theory] + [InlineData("Объект.Функция0()")] + [InlineData("Объект.Функция0СПроцессом()")] + [InlineData("Объект.Функция1(1)")] + [InlineData("Объект.Функция1СПроцессом(1)")] + [InlineData("Объект.Функция1СУмолчанием()")] + [InlineData("Объект.Функция1СУмолчаниемСПроцессом()")] + [InlineData("Объект.Функция1СУмолчанием(1)")] + [InlineData("Объект.Функция1СУмолчаниемСПроцессом(1)")] + public void Can_Call_Member_FunctionsWithBslProcess(string code) + { + var tm = new DefaultTypeManager(); + var testType = tm.RegisterClass(typeof(TestContextClass)); + + var block = new CompiledBlock(default); + block.Parameters.Insert("Объект", new BslTypeValue(testType)); + block.CodeBlock = $"Результат = {code};"; + + var method = block.CreateDelegate>(); + var testValue = new TestContextClass(); + method(testValue); + } + + [Theory] + [InlineData("Объект.Процедура0СПроцессом(1)")] + [InlineData("Объект.Функция0СПроцессом(1)")] + [InlineData("Объект.Функция1СУмолчаниемСПроцессом(1, 2)")] + [InlineData("Объект.Процедура1СУмолчаниемСПроцессом(1, 2, 3);")] + public void Cannot_Call_Member_Procedures_With_Wrong_Argument_Count(string code) + { + var tm = new DefaultTypeManager(); + var testType = tm.RegisterClass(typeof(TestContextClass)); + + var block = new CompiledBlock(default); + block.Parameters.Insert("Объект", new BslTypeValue(testType)); + block.CodeBlock = code; + + var runtimeException = Assert.ThrowsAny(() => { + var method = block.CreateDelegate>(); + }); + Assert.Contains("Слишком много фактических параметров", runtimeException.Message); + } + [Fact] public void Can_Call_Member_Procedures_On_Dynamics() {