diff --git a/src/OneScript.Native/Runtime/CallableMethod.cs b/src/OneScript.Native/Runtime/CallableMethod.cs index f61237aad..35e972f6d 100644 --- a/src/OneScript.Native/Runtime/CallableMethod.cs +++ b/src/OneScript.Native/Runtime/CallableMethod.cs @@ -8,6 +8,7 @@ This Source Code Form is subject to the terms of the using System.Collections.Generic; using System.Linq.Expressions; using OneScript.Contexts; +using OneScript.Exceptions; using OneScript.Execution; using OneScript.Native.Compiler; using OneScript.Values; @@ -42,7 +43,16 @@ public BslValue Invoke(IBslProcess process, object target, BslValue[] args) { throw new InvalidOperationException($"Method {_method} was not compiled"); } - + if (_method.GetBslParameters().Length < args.Length) + { + throw RuntimeException.TooManyArgumentsPassed(); + } + if (_method.GetBslParameters().Length > args.Length) + { + // TODO: значения параметров по-умолчанию? + throw RuntimeException.TooFewArgumentsPassed(); + } + var callableWrapper = GetCallableWrapper(target); return _delegate.Invoke(callableWrapper, args, process); } diff --git a/src/OneScript.StandardLibrary/DelegateAction.cs b/src/OneScript.StandardLibrary/DelegateAction.cs index 32fb02697..3ab1b2721 100644 --- a/src/OneScript.StandardLibrary/DelegateAction.cs +++ b/src/OneScript.StandardLibrary/DelegateAction.cs @@ -83,6 +83,16 @@ public override void CallAsProcedure(int methodNumber, IValue[] arguments, IBslP _action(process, arguments); } + [ContextMethod("Выполнить")] + public BslValue Execute(IBslProcess process, params BslValue[] p) + { + var retValue = _action(process, p); + return retValue is IValueReference r + ? r.BslValue + : (BslValue)(retValue ?? ValueFactory.Create()) + ; + } + [ScriptConstructor] public static DelegateAction Create(IRuntimeContextInstance target, string methodName) { diff --git a/src/ScriptEngine/Machine/MachineInstance.cs b/src/ScriptEngine/Machine/MachineInstance.cs index eb5d73bf1..fc735a311 100644 --- a/src/ScriptEngine/Machine/MachineInstance.cs +++ b/src/ScriptEngine/Machine/MachineInstance.cs @@ -138,7 +138,11 @@ private void SetExecutionFrame(ExecutionFrame frame, MachineMethodInfo methodInf frame.MethodName = methodInfo.Name; frame.InstructionPointer = methDescr.EntryPoint; - var parameters = methodInfo.GetBslParameters(); + var parameters = methodInfo.GetBslParameters(); + if (argValues.Length > parameters.Length) + { + throw RuntimeException.TooManyArgumentsPassed(); + } var variables = methDescr.LocalVariables; var locals = new IVariable[variables.Length]; int i = 0; @@ -171,6 +175,10 @@ private void SetExecutionFrame(ExecutionFrame frame, MachineMethodInfo methodInf for (; i < parameters.Length; i++) { var paramDef = parameters[i]; + if (!paramDef.HasDefaultValue) + { + throw RuntimeException.TooFewArgumentsPassed(); + } var value = paramDef.HasDefaultValue ? (IValue)paramDef.DefaultValue : ValueFactory.Create(); locals[i] = Variable.Create(value, variables[i]); } diff --git a/src/Tests/DocumenterTests/XmlDocConversionTest.cs b/src/Tests/DocumenterTests/XmlDocConversionTest.cs index 19534c9c0..da3b2c4e1 100644 --- a/src/Tests/DocumenterTests/XmlDocConversionTest.cs +++ b/src/Tests/DocumenterTests/XmlDocConversionTest.cs @@ -31,7 +31,8 @@ public void TestConversionOfTextBlock() var expected = @"Для Каждого Переменная Из ПеременныеСреды() Цикл Сообщить(Переменная.Ключ + "" = "" + Переменная.Значение); -КонецЦикла;"; +КонецЦикла;" + .ReplaceLineEndings("\n"); Assert.Equal(expected, text); } diff --git a/tests/cross-delegate-native.os b/tests/cross-delegate-native.os new file mode 100644 index 000000000..27ef557e1 --- /dev/null +++ b/tests/cross-delegate-native.os @@ -0,0 +1,99 @@ +#native + +/////////////////////////////////////////////////////////////////////// +// Тест класса Действие/Action +/////////////////////////////////////////////////////////////////////// + +Перем юТест; + +//////////////////////////////////////////////////////////////////// +// Программный интерфейс + +Функция ПолучитьСписокТестов(ЮнитТестирование) Экспорт + + юТест = ЮнитТестирование; + + ВсеТесты = Новый Массив; + + ВсеТесты.Добавить("ТестДолжен_ВыполнитьДействиеОбъектаТеста_Стэковый"); + ВсеТесты.Добавить("ТестДолжен_ВыполнитьДействиеОбъектаТеста_Родной"); + + ВсеТесты.Добавить("ТестДолжен_ПроверитьКоличествоПараметров_Стэковый"); + ВсеТесты.Добавить("ТестДолжен_ПроверитьКоличествоПараметров_Родной"); + + Возврат ВсеТесты; + +КонецФункции + +Процедура ТестДолжен_ВыполнитьДействиеОбъектаТеста(Знач ТипДелегата) + + Делегат = ТестовыйДелегат(ТипДелегата); + Делегат.Выполнить("123", 456); + +КонецПроцедуры + +Процедура ТестДолжен_ПроверитьКоличествоПараметров(Знач ТипДелегата) + + Делегат = ТестовыйДелегат(ТипДелегата); + + ЕстьОшибка = Ложь; + Попытка + Делегат.Выполнить("123"); + Исключение + ЕстьОшибка = Истина; + КонецПопытки; + + юТест.ПроверитьИстину(ЕстьОшибка, "Вызов с недостаточным количеством параметров должен бросать исключение"); + + ЕстьОшибка = Ложь; + Попытка + Делегат.Выполнить("123", 456, '00010101'); + Исключение + ЕстьОшибка = Истина; + КонецПопытки; + + юТест.ПроверитьИстину(ЕстьОшибка, "Вызов с избыточным количеством параметров должен бросать исключение"); + +КонецПроцедуры + +Процедура ТестДолжен_ВыполнитьДействиеОбъектаТеста_Стэковый() Экспорт + ТестДолжен_ВыполнитьДействиеОбъектаТеста("#stack"); +КонецПроцедуры + +Процедура ТестДолжен_ВыполнитьДействиеОбъектаТеста_Родной() Экспорт + ТестДолжен_ВыполнитьДействиеОбъектаТеста("#native"); +КонецПроцедуры + +Процедура ТестДолжен_ПроверитьКоличествоПараметров_Родной() Экспорт + ТестДолжен_ПроверитьКоличествоПараметров("#native") +КонецПроцедуры + +Процедура ТестДолжен_ПроверитьКоличествоПараметров_Стэковый() Экспорт + ТестДолжен_ПроверитьКоличествоПараметров("#stack") +КонецПроцедуры + +Функция ТестовыйДелегат(Знач ТипДелегата) + + ПутьКСкрипту = юТест.ИмяВременногоФайла("os"); + ИмяКласса = "Класс" + СтрЗаменить(Новый УникальныйИдентификатор, "-", ""); + + ТекстКласса = ТипДелегата + + " + | + |Процедура Тест(Парам, Парам2) Экспорт + | Сообщить(Парам + Парам2); + |КонецПроцедуры"; + + ЗаписьТекста = Новый ЗаписьТекста(ПутьКСкрипту); + ЗаписьТекста.Записать(ТекстКласса); + ЗаписьТекста.Закрыть(); + + ПодключитьСценарий(ПутьКСкрипту, ИмяКласса); + + Класс = Новый(ИмяКласса); + + Делегат = Новый Действие(Класс, "Тест"); + + Возврат Делегат; + +КонецФункции diff --git a/tests/cross-delegate-stack.os b/tests/cross-delegate-stack.os new file mode 100644 index 000000000..01c7739ac --- /dev/null +++ b/tests/cross-delegate-stack.os @@ -0,0 +1,99 @@ +#stack + +/////////////////////////////////////////////////////////////////////// +// Тест класса Действие/Action +/////////////////////////////////////////////////////////////////////// + +Перем юТест; + +//////////////////////////////////////////////////////////////////// +// Программный интерфейс + +Функция ПолучитьСписокТестов(ЮнитТестирование) Экспорт + + юТест = ЮнитТестирование; + + ВсеТесты = Новый Массив; + + ВсеТесты.Добавить("ТестДолжен_ВыполнитьДействиеОбъектаТеста_Стэковый"); + ВсеТесты.Добавить("ТестДолжен_ВыполнитьДействиеОбъектаТеста_Родной"); + + ВсеТесты.Добавить("ТестДолжен_ПроверитьКоличествоПараметров_Стэковый"); + ВсеТесты.Добавить("ТестДолжен_ПроверитьКоличествоПараметров_Родной"); + + Возврат ВсеТесты; + +КонецФункции + +Процедура ТестДолжен_ВыполнитьДействиеОбъектаТеста(Знач ТипДелегата) + + Делегат = ТестовыйДелегат(ТипДелегата); + Делегат.Выполнить("123", 456); + +КонецПроцедуры + +Процедура ТестДолжен_ПроверитьКоличествоПараметров(Знач ТипДелегата) + + Делегат = ТестовыйДелегат(ТипДелегата); + + ЕстьОшибка = Ложь; + Попытка + Делегат.Выполнить("123"); + Исключение + ЕстьОшибка = Истина; + КонецПопытки; + + юТест.ПроверитьИстину(ЕстьОшибка, "Вызов с недостаточным количеством параметров должен бросать исключение"); + + ЕстьОшибка = Ложь; + Попытка + Делегат.Выполнить("123", 456, '00010101'); + Исключение + ЕстьОшибка = Истина; + КонецПопытки; + + юТест.ПроверитьИстину(ЕстьОшибка, "Вызов с избыточным количеством параметров должен бросать исключение"); + +КонецПроцедуры + +Процедура ТестДолжен_ВыполнитьДействиеОбъектаТеста_Стэковый() Экспорт + ТестДолжен_ВыполнитьДействиеОбъектаТеста("#stack"); +КонецПроцедуры + +Процедура ТестДолжен_ВыполнитьДействиеОбъектаТеста_Родной() Экспорт + ТестДолжен_ВыполнитьДействиеОбъектаТеста("#native"); +КонецПроцедуры + +Процедура ТестДолжен_ПроверитьКоличествоПараметров_Родной() Экспорт + ТестДолжен_ПроверитьКоличествоПараметров("#native") +КонецПроцедуры + +Процедура ТестДолжен_ПроверитьКоличествоПараметров_Стэковый() Экспорт + ТестДолжен_ПроверитьКоличествоПараметров("#stack") +КонецПроцедуры + +Функция ТестовыйДелегат(Знач ТипДелегата) + + ПутьКСкрипту = юТест.ИмяВременногоФайла("os"); + ИмяКласса = "Класс" + СтрЗаменить(Новый УникальныйИдентификатор, "-", ""); + + ТекстКласса = ТипДелегата + + " + | + |Процедура Тест(Парам, Парам2) Экспорт + | Сообщить(Парам + Парам2); + |КонецПроцедуры"; + + ЗаписьТекста = Новый ЗаписьТекста(ПутьКСкрипту); + ЗаписьТекста.Записать(ТекстКласса); + ЗаписьТекста.Закрыть(); + + ПодключитьСценарий(ПутьКСкрипту, ИмяКласса); + + Класс = Новый(ИмяКласса); + + Делегат = Новый Действие(Класс, "Тест"); + + Возврат Делегат; + +КонецФункции