From a53e2f0ad8f72b99db653813057377635b01c91f Mon Sep 17 00:00:00 2001 From: Sergey Batanov Date: Thu, 17 Aug 2023 11:28:59 +0300 Subject: [PATCH 1/8] =?UTF-8?q?#1327:=20=D0=9A=D1=80=D0=B0=D1=81=D0=BD?= =?UTF-8?q?=D1=8B=D0=B5=20=D1=82=D0=B5=D1=81=D1=82=D1=8B=20=D0=BD=D0=B0=20?= =?UTF-8?q?=D0=BF=D1=80=D0=B5=D0=BE=D0=B1=D1=80=D0=B0=D0=B7=D0=BE=D0=B2?= =?UTF-8?q?=D0=B0=D0=BD=D0=B8=D0=B5=20=D1=82=D0=B8=D0=BF=D0=BE=D0=B2.?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- tests/typedescription.os | 145 +++++++++++++++++++++++++++++++++++++++ 1 file changed, 145 insertions(+) diff --git a/tests/typedescription.os b/tests/typedescription.os index d780c3620..c9e0846c8 100644 --- a/tests/typedescription.os +++ b/tests/typedescription.os @@ -32,6 +32,11 @@ ВсеТесты.Добавить("ТестДолжен_ПроверитьПриведениеБезПриведения"); ВсеТесты.Добавить("ТестДолжен_ПроверитьПриведениеЧисел"); + ВсеТесты.Добавить("ТестДолжен_Преобразование_ОписаниеБезТипов"); + ВсеТесты.Добавить("ТестДолжен_Преобразование_ОписаниеБезТипов_КвалификаторыИгнорируются"); + + ВсеТесты.Добавить("ТестДолжен_ПроверитьОдинаковыйПорядокТипов"); + Возврат ВсеТесты; КонецФункции @@ -445,3 +450,143 @@ юТест.ПроверитьРавенство(Описание.ПривестиЗначение(12345.555), 999.99, "Забивает девятками"); КонецПроцедуры + +Процедура ТестДолжен_Преобразование_ОписаниеБезТипов() Экспорт + + МассивТиповНеопределено = Новый Массив; + МассивТиповНеопределено.Добавить(Тип("Неопределено")); + + ПроверяемыеОписания = Новый СписокЗначений; + ПроверяемыеОписания.Добавить( + Новый ОписаниеТипов, + "Новый ОписаниеТипов" + ); + ПроверяемыеОписания.Добавить( + Новый ОписаниеТипов("Неопределено"), + "Новый ОписаниеТипов(""Неопределено"")" + ); + ПроверяемыеОписания.Добавить( + Новый ОписаниеТипов(МассивТиповНеопределено), + "Новый ОписаниеТипов(МассивТиповНеопределено)" + ); + ПроверяемыеОписания.Добавить( + Новый ОписаниеТипов("Undefined"), + "Новый ОписаниеТипов(""Undefined"")" + ); + + Для Каждого мЭлементПроверки Из ПроверяемыеОписания Цикл + + ОписаниеБезТипов = мЭлементПроверки.Значение; + ОписаниеСлучая = мЭлементПроверки.Представление; + + юТест.ПроверитьРавенство(ОписаниеБезТипов.ПривестиЗначение(), Неопределено, "Приведение без параметра. " + ОписаниеСлучая); + юТест.ПроверитьРавенство(ОписаниеБезТипов.ПривестиЗначение(1), 1, "Приведение числа. " + ОписаниеСлучая); + юТест.ПроверитьРавенство(ОписаниеБезТипов.ПривестиЗначение("1"), "1", "Приведение строки. " + ОписаниеСлучая); + юТест.ПроверитьРавенство(ОписаниеБезТипов.ПривестиЗначение(Тип("Строка")), Тип("Строка"), "Приведение Типа. " + ОписаниеСлучая); + юТест.ПроверитьРавенство(ОписаниеБезТипов.ПривестиЗначение('20230817104356'), '20230817104356', "Приведение даты. " + ОписаниеСлучая); + + ДД = ПолучитьДвоичныеДанныеИзСтроки("Строка"); + юТест.ПроверитьРавенство(ОписаниеБезТипов.ПривестиЗначение(ДД), ДД, "Двоичные данные не ломаются. " + ОписаниеСлучая); + + юТест.ПроверитьРавенство(ОписаниеБезТипов.Типы().Количество(), 0, "Типы() пустой. " + ОписаниеСлучая); + юТест.ПроверитьЛожь(ОписаниеБезТипов.СодержитТип(Тип("Неопределено")), "Нет типа Неопределено. " + ОписаниеСлучая); + + КонецЦикла; + +КонецПроцедуры + +Процедура ТестДолжен_Преобразование_ОписаниеБезТипов_КвалификаторыИгнорируются() Экспорт + + КЧ = Новый КвалификаторыЧисла(1); + КС = Новый КвалификаторыСтроки(1); + КД = Новый КвалификаторыДаты(ЧастиДаты.Время); + + МассивТиповНеопределено = Новый Массив; + МассивТиповНеопределено.Добавить(Тип("Неопределено")); + + ПроверяемыеОписания = Новый СписокЗначений; + ПроверяемыеОписания.Добавить( + Новый ОписаниеТипов(, КЧ, КС, КД), + "Новый ОписаниеТипов(, КЧ, КС, КД)" + ); + ПроверяемыеОписания.Добавить( + Новый ОписаниеТипов("Неопределено", КЧ, КС, КД), + "Новый ОписаниеТипов(""Неопределено"", КЧ, КС, КД)" + ); + ПроверяемыеОписания.Добавить( + Новый ОписаниеТипов(МассивТиповНеопределено, КЧ, КС, КД), + "Новый ОписаниеТипов(МассивТиповНеопределено, КЧ, КС, КД)" + ); + ПроверяемыеОписания.Добавить( + Новый ОписаниеТипов("Undefined", КЧ, КС, КД), + "Новый ОписаниеТипов(""Undefined"", КЧ, КС, КД)" + ); + + Для Каждого мЭлементПроверки Из ПроверяемыеОписания Цикл + + ОписаниеБезТипов = мЭлементПроверки.Значение; + ОписаниеСлучая = мЭлементПроверки.Представление; + + юТест.ПроверитьРавенство(ОписаниеБезТипов.ПривестиЗначение(), Неопределено, "Приведение без параметра. " + ОписаниеСлучая); + юТест.ПроверитьРавенство(ОписаниеБезТипов.ПривестиЗначение(123), 123, "Число не режется. " + ОписаниеСлучая); // не 1 + юТест.ПроверитьРавенство(ОписаниеБезТипов.ПривестиЗначение("123"), "123", "Строка не режется. " + ОписаниеСлучая); // не "1" + юТест.ПроверитьРавенство(ОписаниеБезТипов.ПривестиЗначение(Тип("Строка")), Тип("Строка"), "Значение типа Тип не ломается. " + ОписаниеСлучая); + юТест.ПроверитьРавенство(ОписаниеБезТипов.ПривестиЗначение('20230817104356'), '20230817104356', "Дата не режется. " + ОписаниеСлучая); // не `00010101104356` + + ДД = ПолучитьДвоичныеДанныеИзСтроки("Строка"); + юТест.ПроверитьРавенство(ОписаниеБезТипов.ПривестиЗначение(ДД), ДД, "Двоичные данные не ломаются. " + ОписаниеСлучая); + + юТест.ПроверитьРавенство(ОписаниеБезТипов.Типы().Количество(), 0, "Типы() пустой. " + ОписаниеСлучая); + юТест.ПроверитьЛожь(ОписаниеБезТипов.СодержитТип(Тип("Неопределено")), "Нет типа Неопределено. " + ОписаниеСлучая); + + КонецЦикла; + +КонецПроцедуры + +Процедура ТестДолжен_ПроверитьОдинаковыйПорядокТипов() Экспорт + + ОТ = Новый ОписаниеТипов("Число, Строка"); + ПроверитьПорядокТипов(ОТ.Типы(), "Строка, Число"); + + ОТ = Новый ОписаниеТипов("Строка, Число"); + ПроверитьПорядокТипов(ОТ.Типы(), "Строка, Число"); + + ОТ = Новый ОписаниеТипов("Строка, Число, Строка"); + ПроверитьПорядокТипов(ОТ.Типы(), "Строка, Число"); + + ОТ = Новый ОписаниеТипов("Число, Число, Строка"); + ПроверитьПорядокТипов(ОТ.Типы(), "Строка, Число"); + + ОТ = Новый ОписаниеТипов("Число, Число, Строка, Дата, Булево, Неопределено"); + ПроверитьПорядокТипов(ОТ.Типы(), "Булево, Строка, Дата, Число"); + + ОТ = Новый ОписаниеТипов("Неопределено, Число, Дата, Строка, Дата, Булево"); + ПроверитьПорядокТипов(ОТ.Типы(), "Булево, Строка, Дата, Число"); + +КонецПроцедуры + +Процедура ПроверитьПорядокТипов(Знач ТипыОписанияТипов, Знач ОжидаемыйПорядок, Знач Текст = Неопределено) + + Если Текст = Неопределено Тогда + Текст = СтрШаблон("Ожидаемый порядок: %1 + |Полученный порядок: %2", ОжидаемыйПорядок, СтрСоединить(ТипыОписанияТипов, ", ") + ); + КонецЕсли; + + ТипыСтроками = СтрРазделить(ОжидаемыйПорядок, ","); + + юТест.ПроверитьБольшеИлиРавно(ТипыОписанияТипов.Количество(), ТипыСтроками.Количество(), Текст); + + ИндексТипа = 0; + Для Каждого мТипСтрокой Из ТипыСтроками Цикл + + ТипОписания = ТипыОписанияТипов[ИндексТипа]; + ТипОжидаемый = Тип(СокрЛП(мТипСтрокой)); + + юТест.ПроверитьРавенство(ТипОписания, ТипОжидаемый); + + ИндексТипа = ИндексТипа + 1; + + КонецЦикла; + +КонецПроцедуры From ffc423076c6860b30108b66213c798b3d0b1d655 Mon Sep 17 00:00:00 2001 From: Sergey Batanov Date: Thu, 24 Aug 2023 18:02:05 +0300 Subject: [PATCH 2/8] =?UTF-8?q?#1327:=20=D0=A0=D0=B5=D1=84=D0=B0=D0=BA?= =?UTF-8?q?=D1=82=D0=BE=D1=80=D0=B8=D0=BD=D0=B3=20=D0=9E=D0=BF=D0=B8=D1=81?= =?UTF-8?q?=D0=B0=D0=BD=D0=B8=D1=8F=20=D1=82=D0=B8=D0=BF=D0=BE=D0=B2.?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../TypeDescriptions/TypeDescription.cs | 186 +++++------------- .../TypeDescriptionBuilder.cs | 116 +++++++++++ .../TypeDescriptions/TypeList.cs | 121 ++++++++++++ 3 files changed, 290 insertions(+), 133 deletions(-) create mode 100644 src/OneScript.StandardLibrary/TypeDescriptions/TypeDescriptionBuilder.cs create mode 100644 src/OneScript.StandardLibrary/TypeDescriptions/TypeList.cs diff --git a/src/OneScript.StandardLibrary/TypeDescriptions/TypeDescription.cs b/src/OneScript.StandardLibrary/TypeDescriptions/TypeDescription.cs index 8585c1d59..b133c3fbf 100644 --- a/src/OneScript.StandardLibrary/TypeDescriptions/TypeDescription.cs +++ b/src/OneScript.StandardLibrary/TypeDescriptions/TypeDescription.cs @@ -5,6 +5,7 @@ This Source Code Form is subject to the terms of the at http://mozilla.org/MPL/2.0/. ----------------------------------------------------------*/ +using System; using System.Collections.Generic; using System.Linq; using OneScript.Contexts; @@ -24,25 +25,34 @@ public class TypeDescription : AutoContext private const string TYPE_BINARYDATA_NAME = "ДвоичныеДанные"; - public TypeDescription(IEnumerable types = null, - NumberQualifiers numberQualifiers = null, - StringQualifiers stringQualifiers = null, - DateQualifiers dateQualifiers = null, - BinaryDataQualifiers binaryDataQualifiers = null) + public TypeDescription(IEnumerable types = null) { if (types != null) { _types.AddRange(types); } + + NumberQualifiers = new NumberQualifiers(); + StringQualifiers = new StringQualifiers(); + DateQualifiers = new DateQualifiers(); + BinaryDataQualifiers = new BinaryDataQualifiers(); + } - NumberQualifiers = numberQualifiers != null && _types.Contains(TypeNumber()) ? - numberQualifiers : new NumberQualifiers(); - StringQualifiers = stringQualifiers != null && _types.Contains(TypeString()) ? - stringQualifiers : new StringQualifiers(); - DateQualifiers = dateQualifiers != null && _types.Contains(TypeDate()) ? - dateQualifiers : new DateQualifiers(); - BinaryDataQualifiers = binaryDataQualifiers != null && _types.Any(x => x.TypeValue.Name == TYPE_BINARYDATA_NAME) ? - binaryDataQualifiers : new BinaryDataQualifiers(); + internal TypeDescription(IEnumerable types, + NumberQualifiers numberQualifiers, + StringQualifiers stringQualifiers, + DateQualifiers dateQualifiers, + BinaryDataQualifiers binaryDataQualifiers) + { + if (types != null) + { + _types.AddRange(types); + } + + NumberQualifiers = numberQualifiers; + StringQualifiers = stringQualifiers; + DateQualifiers = dateQualifiers; + BinaryDataQualifiers = binaryDataQualifiers; } [ContextProperty("КвалификаторыЧисла", "NumberQualifiers")] @@ -70,6 +80,11 @@ public ArrayImpl Types() return result; } + internal IEnumerable TypesInternal() + { + return _types; + } + [ContextMethod("СодержитТип", "ContainsType")] public bool ContainsType(IValue type) { @@ -136,62 +151,22 @@ public IValue AdjustValue(IValue value = null) return adjuster?.Adjust(value) ?? ValueFactory.Create(); } - private static IList ConstructTypeList(ITypeManager typeManager, IValue types) - { - var typesList = new List(); - if (types == null) - return typesList; - - types = types.GetRawValue(); - if (types.SystemType == BasicTypes.String) - { - var typeNames = types.AsString().Split(','); - foreach (var typeName in typeNames) - { - if (string.IsNullOrWhiteSpace(typeName)) - continue; - - var typeValue = new BslTypeValue(typeManager.GetTypeByName(typeName.Trim())); - if (!typesList.Contains(typeValue)) - typesList.Add(typeValue); - } - } else if (types is ArrayImpl arrayOfTypes) - { - foreach (var type in arrayOfTypes) - { - var rawType = type.GetRawValue() as BslTypeValue; - if (rawType == null) - continue; - - if (!typesList.Contains(rawType)) - typesList.Add(rawType); - } - } - else if (types.SystemType != BasicTypes.Undefined) - { - return null; // далее будет исключение - } - // для Неопределено возвращается пустой список - - return typesList; - } - - static BslTypeValue TypeNumber() + internal static BslTypeValue TypeNumber() { return new BslTypeValue(BasicTypes.Number); } - static BslTypeValue TypeBoolean() + internal static BslTypeValue TypeBoolean() { return new BslTypeValue(BasicTypes.Boolean); } - static BslTypeValue TypeString() + internal static BslTypeValue TypeString() { return new BslTypeValue(BasicTypes.String); } - static BslTypeValue TypeDate() + internal static BslTypeValue TypeDate() { return new BslTypeValue(BasicTypes.Date); } @@ -199,54 +174,18 @@ static BslTypeValue TypeDate() public static TypeDescription StringType(int length = 0, AllowedLengthEnum allowedLength = AllowedLengthEnum.Variable) { - var stringQualifier = new StringQualifiers(length, allowedLength); - return new TypeDescription(new BslTypeValue[] { TypeString() }, null, stringQualifier); + return TypeDescriptionBuilder.Build(TypeString(), new StringQualifiers(length, allowedLength)); } public static TypeDescription IntegerType(int length = 10, AllowedSignEnum allowedSign = AllowedSignEnum.Any) { - var numberQualifier = new NumberQualifiers(length, 0, allowedSign); - return new TypeDescription(new BslTypeValue[] { TypeNumber() }, numberQualifier); + return TypeDescriptionBuilder.Build(TypeNumber(), new NumberQualifiers(length, 0, allowedSign)); } public static TypeDescription BooleanType() { - return new TypeDescription(new BslTypeValue[] { TypeBoolean() }); - } - - - private class TypeQualifiersSet - { - public readonly NumberQualifiers numberQualifiers = null; - public readonly StringQualifiers stringQualifiers = null; - public readonly DateQualifiers dateQualifiers = null; - public readonly BinaryDataQualifiers binaryDataQualifiers = null; - - public TypeQualifiersSet(IValue p2, IValue p3, IValue p4, IValue p5, IValue p6, IValue p7) - { - int nParam = 1; - foreach (var qual in new[] { p2, p3, p4, p5, p6, p7 }) - { - nParam++; - - if (qual == null || qual.Equals(BslUndefinedValue.Instance)) - continue; - - switch (qual.GetRawValue()) - { - case NumberQualifiers nq: numberQualifiers = nq; break; - - case StringQualifiers sq: stringQualifiers = sq; break; - - case DateQualifiers dq: dateQualifiers = dq; break; - - case BinaryDataQualifiers bdq: binaryDataQualifiers = bdq; break; - - default: throw RuntimeException.InvalidNthArgumentType(nParam); - } - } - } + return TypeDescriptionBuilder.Build(TypeBoolean()); } [ScriptConstructor] @@ -267,10 +206,8 @@ public static TypeDescription Constructor( // пустой первый параметр - нет объекта-основания // добавляемые/вычитаемые типы не допускаются, квалификаторы игнорируются - // только для контроля типов - var _ = new TypeQualifiersSet(p2, p3, p4, p5, p6, p7); - - return new TypeDescription(); + // квалификакторы передаются только для контроля типов + return ConstructByQualifiers(context.TypeManager, new TypeDescription(), p2, p3, p4, p5, p6, p7); } if (rawSource is TypeDescription) @@ -286,7 +223,7 @@ public static TypeDescription Constructor( throw RuntimeException.InvalidArgumentValue(); } - public static TypeDescription ConstructByQualifiers(ITypeManager typeManager, IValue types, + private static TypeDescription ConstructByQualifiers(ITypeManager typeManager, IValue types, IValue p2 = null, IValue p3 = null, IValue p4 = null, @@ -294,20 +231,16 @@ public static TypeDescription ConstructByQualifiers(ITypeManager typeManager, IV IValue p6 = null, IValue p7 = null) { - var typesList = ConstructTypeList(typeManager, types); - if (typesList == null) - throw RuntimeException.InvalidNthArgumentType(1); + var builder = new TypeDescriptionBuilder(); + var typesList = TypeList.Construct(typeManager, types, 1); + builder.AddTypes(typesList.List()); - var qualSet = new TypeQualifiersSet(p2,p3,p4,p5,p6,p7); + builder.AddQualifiers(new[] { p2, p3, p4, p5, p6, p7 }, 1); - return new TypeDescription(typesList, - qualSet.numberQualifiers, - qualSet.stringQualifiers, - qualSet.dateQualifiers, - qualSet.binaryDataQualifiers); + return builder.Build(); } - public static TypeDescription ConstructByOtherDescription(ITypeManager typeManager, + private static TypeDescription ConstructByOtherDescription(ITypeManager typeManager, IValue typeDescription = null, IValue addTypes = null, IValue removeTypes = null, @@ -316,34 +249,21 @@ public static TypeDescription ConstructByOtherDescription(ITypeManager typeManag IValue p6 = null, IValue p7 = null) { - var removeTypesList = ConstructTypeList(typeManager, removeTypes); - if (removeTypesList == null) - throw RuntimeException.InvalidNthArgumentType(3); + var builder = new TypeDescriptionBuilder(); - var typesList = new List(); if (typeDescription is TypeDescription typeDesc) { - foreach (var type in typeDesc._types) - { - if (!removeTypesList.Contains(type)) - { - typesList.Add(type); - } - } + builder.SourceDescription(typeDesc); } + + var removeTypesList = TypeList.Construct(typeManager, removeTypes, 3); + builder.RemoveTypes(removeTypesList.List()); - var addTypesList = ConstructTypeList(typeManager, addTypes); - if (addTypesList == null) - throw RuntimeException.InvalidNthArgumentType(2); - typesList.AddRange(addTypesList); - - var qualSet = new TypeQualifiersSet(null, null, p4, p5, p6, p7); + var addTypesList = TypeList.Construct(typeManager, addTypes, 2); + builder.AddTypes(addTypesList.List()); + builder.AddQualifiers(new[] { p4, p5, p6, p7 }, 3); - return new TypeDescription(typesList, - qualSet.numberQualifiers, - qualSet.stringQualifiers, - qualSet.dateQualifiers, - qualSet.binaryDataQualifiers); + return builder.Build(); } } } diff --git a/src/OneScript.StandardLibrary/TypeDescriptions/TypeDescriptionBuilder.cs b/src/OneScript.StandardLibrary/TypeDescriptions/TypeDescriptionBuilder.cs new file mode 100644 index 000000000..e330cc2c7 --- /dev/null +++ b/src/OneScript.StandardLibrary/TypeDescriptions/TypeDescriptionBuilder.cs @@ -0,0 +1,116 @@ +using System.Collections.Generic; +using System.Linq; +using OneScript.Exceptions; +using OneScript.Values; +using ScriptEngine.Machine; + +namespace OneScript.StandardLibrary.TypeDescriptions +{ + internal class TypeDescriptionBuilder + { + private NumberQualifiers _numberQualifiers; + private StringQualifiers _stringQualifiers; + private DateQualifiers _dateQualifiers; + private BinaryDataQualifiers _binaryDataQualifiers; + + private const string TYPE_BINARYDATA_NAME = "ДвоичныеДанные"; + + private List _types = new List(); + + internal TypeDescriptionBuilder() + { + } + + public TypeDescriptionBuilder SourceDescription(TypeDescription source) + { + _numberQualifiers = source.NumberQualifiers; + _stringQualifiers = source.StringQualifiers; + _dateQualifiers = source.DateQualifiers; + _binaryDataQualifiers = source.BinaryDataQualifiers; + return AddTypes(source.TypesInternal()); + } + + public TypeDescriptionBuilder AddTypes(IEnumerable types) + { + _types.AddRange(types); + return this; + } + + public TypeDescriptionBuilder RemoveTypes(IEnumerable types) + { + _types.RemoveAll(types.Contains); + return this; + } + + public TypeDescriptionBuilder AddQualifiers(IValue[] qualifiers, int nParam = 0) + { + foreach (var qualifier in qualifiers) + { + nParam++; + AddQualifier(qualifier, nParam); + } + + return this; + } + + public TypeDescriptionBuilder AddQualifier(IValue qualifier, int nParam = 0) + { + if (qualifier != null && !qualifier.Equals(BslUndefinedValue.Instance)) + { + switch (qualifier.GetRawValue()) + { + case NumberQualifiers nq: + _numberQualifiers = nq; + break; + + case StringQualifiers sq: + _stringQualifiers = sq; + break; + + case DateQualifiers dq: + _dateQualifiers = dq; + break; + + case BinaryDataQualifiers bdq: + _binaryDataQualifiers = bdq; + break; + + default: + throw nParam == 0 + ? RuntimeException.InvalidArgumentType() + : RuntimeException.InvalidNthArgumentType(nParam); + } + } + + return this; + } + + public TypeDescription Build() + { + _types = new List(_types.Distinct()); + var hasNumber = _types.Contains(TypeDescription.TypeNumber()); + var hasString =_types.Contains(TypeDescription.TypeString()); + var hasDate = _types.Contains(TypeDescription.TypeDate()); + var hasBinaryData = _types.Any(x => x.TypeValue.Name == TYPE_BINARYDATA_NAME); + + if (!hasNumber || _numberQualifiers == null) _numberQualifiers = new NumberQualifiers(); + if (!hasString || _stringQualifiers == null) _stringQualifiers = new StringQualifiers(); + if (!hasDate || _dateQualifiers == null) _dateQualifiers = new DateQualifiers(); + if (!hasBinaryData || _binaryDataQualifiers == null) _binaryDataQualifiers = new BinaryDataQualifiers(); + + return new TypeDescription(_types, + _numberQualifiers, + _stringQualifiers, + _dateQualifiers, + _binaryDataQualifiers + ); + + } + + public static TypeDescription Build(BslTypeValue type, IValue qualifier = null) + { + var builder = new TypeDescriptionBuilder(); + return builder.AddTypes(new[] { type }).AddQualifier(qualifier).Build(); + } + } +} \ No newline at end of file diff --git a/src/OneScript.StandardLibrary/TypeDescriptions/TypeList.cs b/src/OneScript.StandardLibrary/TypeDescriptions/TypeList.cs new file mode 100644 index 000000000..ebf80b0bc --- /dev/null +++ b/src/OneScript.StandardLibrary/TypeDescriptions/TypeList.cs @@ -0,0 +1,121 @@ +/*---------------------------------------------------------- +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.Generic; +using System.Linq; +using OneScript.Exceptions; +using OneScript.StandardLibrary.Collections; +using OneScript.Types; +using OneScript.Values; +using ScriptEngine.Machine; + +namespace OneScript.StandardLibrary.TypeDescriptions +{ + internal class TypeList + { + private readonly IList _list; + + public TypeList(IEnumerable list) + { + _list = new List(list); + } + + public int Count => _list.Count; + + public bool Contains(BslTypeValue type) + { + return _list.Contains(type); + } + + public bool Contains(string typeName) + { + return _list.Any(x => string.Compare( + x.TypeValue.Name, + typeName, + StringComparison.OrdinalIgnoreCase) == 0 + ); + } + + public IList List() + { + return _list; + } + + /// + /// Возвращает типы как Массив + /// + /// Массив, содержащий элементы типа Тип + public ArrayImpl AsArray() + { + return new ArrayImpl(_list); + } + + public TypeList Modify(TypeList typesToRemove, TypeList typesToAdd) + { + var typesList = _list.Where(type => !typesToRemove.Contains(type)).ToList(); + typesList.AddRange(typesToAdd._list); + return new TypeList(typesList); + } + + public TypeList Modify(TypeList typesToRemove) + { + var typesList = _list.Where(type => !typesToRemove.Contains(type)).ToList(); + return new TypeList(typesList); + } + + public static TypeList Construct(ITypeManager typeManager, IValue types, int nParam) + { + types = types?.GetRawValue(); + if (types == null || types.SystemType == BasicTypes.Undefined) + return new TypeList(Array.Empty()); + + if (types.SystemType == BasicTypes.String) + { + return FromTypeNames(typeManager, types.AsString()); + } + if (types is ArrayImpl arrayOfTypes) + { + return FromArrayOfTypes(arrayOfTypes); + } + + throw RuntimeException.InvalidNthArgumentType(nParam); + } + + public static TypeList FromTypeNames(ITypeManager typeManager, string types) + { + var typeNames = types.Split(','); + var typesList = new List(); + foreach (var typeName in typeNames) + { + if (string.IsNullOrWhiteSpace(typeName)) + continue; + + var typeValue = new BslTypeValue(typeManager.GetTypeByName(typeName.Trim())); + if (!typesList.Contains(typeValue)) + typesList.Add(typeValue); + } + + return new TypeList(typesList); + } + + public static TypeList FromArrayOfTypes(ArrayImpl arrayOfTypes) + { + var typesList = new List(); + foreach (var type in arrayOfTypes) + { + var rawType = type.GetRawValue() as BslTypeValue; + if (rawType == null) + continue; + + if (!typesList.Contains(rawType)) + typesList.Add(rawType); + } + return new TypeList(typesList); + } + } +} \ No newline at end of file From 9bb678ca5df43f236afee31a519604d0b9db3450 Mon Sep 17 00:00:00 2001 From: Sergey Batanov Date: Fri, 1 Sep 2023 23:10:30 +0300 Subject: [PATCH 3/8] =?UTF-8?q?#1327=20=D0=9F=D0=BE=D1=80=D1=8F=D0=B4?= =?UTF-8?q?=D0=BE=D0=BA=20=D1=82=D0=B8=D0=BF=D0=BE=D0=B2=20=D0=B2=20=D0=9E?= =?UTF-8?q?=D0=BF=D0=B8=D1=81=D0=B0=D0=BD=D0=B8=D0=B8=20=D0=A2=D0=B8=D0=BF?= =?UTF-8?q?=D0=BE=D0=B2.?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../TypeDescriptions/TypeDescription.cs | 2 +- .../TypeDescriptionBuilder.cs | 56 ++++++++++++++++++- 2 files changed, 56 insertions(+), 2 deletions(-) diff --git a/src/OneScript.StandardLibrary/TypeDescriptions/TypeDescription.cs b/src/OneScript.StandardLibrary/TypeDescriptions/TypeDescription.cs index b133c3fbf..51bd1275a 100644 --- a/src/OneScript.StandardLibrary/TypeDescriptions/TypeDescription.cs +++ b/src/OneScript.StandardLibrary/TypeDescriptions/TypeDescription.cs @@ -207,7 +207,7 @@ public static TypeDescription Constructor( // добавляемые/вычитаемые типы не допускаются, квалификаторы игнорируются // квалификакторы передаются только для контроля типов - return ConstructByQualifiers(context.TypeManager, new TypeDescription(), p2, p3, p4, p5, p6, p7); + return ConstructByQualifiers(context.TypeManager, BslUndefinedValue.Instance, p2, p3, p4, p5, p6, p7); } if (rawSource is TypeDescription) diff --git a/src/OneScript.StandardLibrary/TypeDescriptions/TypeDescriptionBuilder.cs b/src/OneScript.StandardLibrary/TypeDescriptions/TypeDescriptionBuilder.cs index e330cc2c7..38fd9f17d 100644 --- a/src/OneScript.StandardLibrary/TypeDescriptions/TypeDescriptionBuilder.cs +++ b/src/OneScript.StandardLibrary/TypeDescriptions/TypeDescriptionBuilder.cs @@ -1,6 +1,8 @@ -using System.Collections.Generic; +using System; +using System.Collections.Generic; using System.Linq; using OneScript.Exceptions; +using OneScript.Types; using OneScript.Values; using ScriptEngine.Machine; @@ -88,6 +90,8 @@ public TypeDescriptionBuilder AddQualifier(IValue qualifier, int nParam = 0) public TypeDescription Build() { _types = new List(_types.Distinct()); + _types.RemoveAll(type => type.TypeValue.ImplementingClass == typeof(BslUndefinedValue)); + _types.Sort(new TypeComparer()); var hasNumber = _types.Contains(TypeDescription.TypeNumber()); var hasString =_types.Contains(TypeDescription.TypeString()); var hasDate = _types.Contains(TypeDescription.TypeDate()); @@ -112,5 +116,55 @@ public static TypeDescription Build(BslTypeValue type, IValue qualifier = null) var builder = new TypeDescriptionBuilder(); return builder.AddTypes(new[] { type }).AddQualifier(qualifier).Build(); } + + private class TypeComparer : IComparer + { + private static readonly IDictionary primitives = new Dictionary(); + public int Compare(BslTypeValue x, BslTypeValue y) + { + if (x.TypeValue.Equals(y)) return 0; + + var primitiveX = PrimitiveIndex(x); + var primitiveY = PrimitiveIndex(y); + + if (primitiveX != -1) + { + if (primitiveY != -1) + return primitiveX - primitiveY; + + return -1; + } + + if (primitiveY != -1) + return 1; + + return x.TypeValue.Id.CompareTo(y.TypeValue.Id); + } + + private int PrimitiveIndex(BslTypeValue type) + { + if (StringComparer.CurrentCultureIgnoreCase.Equals(type.TypeValue.Name, TYPE_BINARYDATA_NAME)) + { + // Пора двоичным данным стать примитивом + return 1; + } + + if (primitives.ContainsKey(type.TypeValue)) + return primitives[type.TypeValue]; + + return -1; + } + + static TypeComparer() + { + primitives.Add(BasicTypes.Boolean, 0); + primitives.Add(BasicTypes.String, 2); + primitives.Add(BasicTypes.Date, 3); + primitives.Add(BasicTypes.Null, 4); + primitives.Add(BasicTypes.Number, 5); + primitives.Add(BasicTypes.Type, 6); + } + + } } } \ No newline at end of file From 37d99c8b6884b1711f1abb6e7ce6fa0076ccdced Mon Sep 17 00:00:00 2001 From: Sergey Batanov Date: Fri, 1 Sep 2023 23:14:05 +0300 Subject: [PATCH 4/8] =?UTF-8?q?#1327=20=D0=A2=D0=B5=D1=81=D1=82=20=D0=BD?= =?UTF-8?q?=D0=B0=20=D0=BF=D0=BE=D1=80=D1=8F=D0=B4=D0=BE=D0=BA.?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- tests/typedescription.os | 3 +++ 1 file changed, 3 insertions(+) diff --git a/tests/typedescription.os b/tests/typedescription.os index c9e0846c8..65592c65c 100644 --- a/tests/typedescription.os +++ b/tests/typedescription.os @@ -563,6 +563,9 @@ ОТ = Новый ОписаниеТипов("Неопределено, Число, Дата, Строка, Дата, Булево"); ПроверитьПорядокТипов(ОТ.Типы(), "Булево, Строка, Дата, Число"); + ОТ = Новый ОписаниеТипов("ДвоичныеДанные, Неопределено, Тип, NULL, Число, Дата, Строка, Дата, Булево"); + ПроверитьПорядокТипов(ОТ.Типы(), "Булево, ДвоичныеДанные, Строка, Дата, Null, Число, Тип"); + КонецПроцедуры Процедура ПроверитьПорядокТипов(Знач ТипыОписанияТипов, Знач ОжидаемыйПорядок, Знач Текст = Неопределено) From 1748964883ae092c02e1c8a459aa31d55eeb3084 Mon Sep 17 00:00:00 2001 From: Sergey Batanov Date: Sat, 2 Sep 2023 10:34:28 +0300 Subject: [PATCH 5/8] =?UTF-8?q?#1327=20=D0=9B=D0=B8=D1=86=D0=B5=D0=BD?= =?UTF-8?q?=D0=B7=D0=B8=D1=8F.?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../TypeDescriptions/TypeDescriptionBuilder.cs | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/src/OneScript.StandardLibrary/TypeDescriptions/TypeDescriptionBuilder.cs b/src/OneScript.StandardLibrary/TypeDescriptions/TypeDescriptionBuilder.cs index 38fd9f17d..d1731a4f4 100644 --- a/src/OneScript.StandardLibrary/TypeDescriptions/TypeDescriptionBuilder.cs +++ b/src/OneScript.StandardLibrary/TypeDescriptions/TypeDescriptionBuilder.cs @@ -1,4 +1,11 @@ -using System; +/*---------------------------------------------------------- +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.Generic; using System.Linq; using OneScript.Exceptions; From 604ec354869155fd00acb155e10bfd2a2c631772 Mon Sep 17 00:00:00 2001 From: Sergey Batanov Date: Sat, 16 Sep 2023 22:26:04 +0300 Subject: [PATCH 6/8] =?UTF-8?q?#1327:=20=D0=9F=D0=BE=D1=80=D1=8F=D0=B4?= =?UTF-8?q?=D0=BE=D0=BA=20=D0=BF=D1=80=D0=B8=D0=B2=D0=B5=D0=B4=D0=B5=D0=BD?= =?UTF-8?q?=D0=B8=D1=8F.?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../TypeDescriptions/TypeDescription.cs | 29 ++++++++----------- tests/typedescription.os | 12 ++++++++ 2 files changed, 24 insertions(+), 17 deletions(-) diff --git a/src/OneScript.StandardLibrary/TypeDescriptions/TypeDescription.cs b/src/OneScript.StandardLibrary/TypeDescriptions/TypeDescription.cs index 51bd1275a..59528f4d4 100644 --- a/src/OneScript.StandardLibrary/TypeDescriptions/TypeDescription.cs +++ b/src/OneScript.StandardLibrary/TypeDescriptions/TypeDescription.cs @@ -114,41 +114,36 @@ IValueAdjuster GetAdjusterForType(BslTypeValue type) } [ContextMethod("ПривестиЗначение", "AdjustValue")] - public IValue AdjustValue(IValue value = null) + public IValue AdjustValue(IValue pValue = null) { - + var value = pValue?.GetRawValue(); if (_types.Count == 0) { return value ?? ValueFactory.Create(); } - BslTypeValue typeToCast = null; - if (value != null && value.SystemType != BasicTypes.Undefined) { var valueType = new BslTypeValue(value.SystemType); if (_types.Contains(valueType)) { // Если такой тип у нас есть - typeToCast = valueType; + var adjuster = GetAdjusterForType(valueType); + var adjustedValue = adjuster.Adjust(value); + if (adjustedValue != null) + return adjustedValue; } } - if (typeToCast == null) + foreach (var type in _types) { - // Если типа нет, то нужно брать значение по-умолчанию - if (_types.Count != 1) - { - // много типов - Неопределено - return ValueFactory.Create(); - } - - typeToCast = _types[0]; + var adjuster = GetAdjusterForType(type); + var adjustedValue = adjuster?.Adjust(value); + if (adjustedValue != null) + return adjustedValue; } - var adjuster = GetAdjusterForType(typeToCast); - - return adjuster?.Adjust(value) ?? ValueFactory.Create(); + return ValueFactory.Create(); } internal static BslTypeValue TypeNumber() diff --git a/tests/typedescription.os b/tests/typedescription.os index 65592c65c..4bec441b9 100644 --- a/tests/typedescription.os +++ b/tests/typedescription.os @@ -36,6 +36,7 @@ ВсеТесты.Добавить("ТестДолжен_Преобразование_ОписаниеБезТипов_КвалификаторыИгнорируются"); ВсеТесты.Добавить("ТестДолжен_ПроверитьОдинаковыйПорядокТипов"); + ВсеТесты.Добавить("ТестДолжен_ПроверитьПорядокПриведенияТипов"); Возврат ВсеТесты; @@ -543,6 +544,17 @@ КонецПроцедуры +Процедура ТестДолжен_ПроверитьПорядокПриведенияТипов() Экспорт + + ОписаниеТипов = Новый ОписаниеТипов("Число, Строка", Новый КвалификаторыСтроки(1)); + + юТест.ПроверитьРавенство(ОписаниеТипов.ПривестиЗначение(Истина), "Д"); // TODO: локализация + юТест.ПроверитьРавенство(ОписаниеТипов.ПривестиЗначение("Строка"), "С"); + юТест.ПроверитьРавенство(ОписаниеТипов.ПривестиЗначение(15), 15); + юТест.ПроверитьРавенство(ОписаниеТипов.ПривестиЗначение('20230911'), "1"); // TODO: локализация + +КонецПроцедуры + Процедура ТестДолжен_ПроверитьОдинаковыйПорядокТипов() Экспорт ОТ = Новый ОписаниеТипов("Число, Строка"); From 83ab2e01d0558dcfea9e2af47fec0267fc800cbf Mon Sep 17 00:00:00 2001 From: Sergey Batanov Date: Sat, 23 Sep 2023 19:04:11 +0300 Subject: [PATCH 7/8] =?UTF-8?q?#1337:=20=D0=90=D0=B4=D0=B0=D0=BF=D1=82?= =?UTF-8?q?=D0=B0=D1=86=D0=B8=D1=8F=20=D0=B4=D0=BB=D1=8F=202.0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../TypeDescriptions/TypeComparer.cs | 66 ++++++ .../TypeDescriptions/TypeDescription.cs | 218 ++++++++++++------ .../TypeDescriptionBuilder.cs | 113 ++------- .../TypeDescriptions/TypeList.cs | 121 ---------- tests/typedescription.os | 31 ++- 5 files changed, 266 insertions(+), 283 deletions(-) create mode 100644 src/OneScript.StandardLibrary/TypeDescriptions/TypeComparer.cs delete mode 100644 src/OneScript.StandardLibrary/TypeDescriptions/TypeList.cs diff --git a/src/OneScript.StandardLibrary/TypeDescriptions/TypeComparer.cs b/src/OneScript.StandardLibrary/TypeDescriptions/TypeComparer.cs new file mode 100644 index 000000000..b48b568aa --- /dev/null +++ b/src/OneScript.StandardLibrary/TypeDescriptions/TypeComparer.cs @@ -0,0 +1,66 @@ +/*---------------------------------------------------------- +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.Generic; +using OneScript.Types; +using OneScript.Values; + +namespace OneScript.StandardLibrary.TypeDescriptions +{ + internal class TypeComparer : IComparer + { + private const string TYPE_BINARYDATA_NAME = "ДвоичныеДанные"; + private static readonly IDictionary primitives = new Dictionary(); + + public int Compare(BslTypeValue x, BslTypeValue y) + { + if (x.TypeValue.Equals(y)) return 0; + + var primitiveX = PrimitiveIndex(x); + var primitiveY = PrimitiveIndex(y); + + if (primitiveX != -1) + { + if (primitiveY != -1) + return primitiveX - primitiveY; + + return -1; + } + + if (primitiveY != -1) + return 1; + + return x.TypeValue.Id.CompareTo(y.TypeValue.Id); + } + + private int PrimitiveIndex(BslTypeValue type) + { + if (StringComparer.CurrentCultureIgnoreCase.Equals(type.TypeValue.Name, TYPE_BINARYDATA_NAME)) + { + // Пора двоичным данным стать примитивом + return 1; + } + + if (primitives.TryGetValue(type.TypeValue, out var index)) + return index; + + return -1; + } + + static TypeComparer() + { + primitives.Add(BasicTypes.Boolean, 0); + primitives.Add(BasicTypes.String, 2); + primitives.Add(BasicTypes.Date, 3); + primitives.Add(BasicTypes.Null, 4); + primitives.Add(BasicTypes.Number, 5); + primitives.Add(BasicTypes.Type, 6); + } + + } +} + \ No newline at end of file diff --git a/src/OneScript.StandardLibrary/TypeDescriptions/TypeDescription.cs b/src/OneScript.StandardLibrary/TypeDescriptions/TypeDescription.cs index 59528f4d4..c85daecc0 100644 --- a/src/OneScript.StandardLibrary/TypeDescriptions/TypeDescription.cs +++ b/src/OneScript.StandardLibrary/TypeDescriptions/TypeDescription.cs @@ -89,12 +89,21 @@ internal IEnumerable TypesInternal() public bool ContainsType(IValue type) { if (type is BslTypeValue typeVal) + { + if (typeVal.TypeValue.Equals(BasicTypes.Undefined)) + { + // тип "Неопределено" содержится в любом явно определенном составном типе + // и не содержится в типе Произвольный (когда явно не указан состав типов) + // или когда указан один конкретный тип + return (_types.Count > 1); + } return _types.Contains(typeVal); + } throw RuntimeException.InvalidArgumentType(nameof(type)); } - IValueAdjuster GetAdjusterForType(BslTypeValue type) + private IValueAdjuster GetAdjusterForType(BslTypeValue type) { var value = type.TypeValue; @@ -110,6 +119,9 @@ IValueAdjuster GetAdjusterForType(BslTypeValue type) if (value.Equals(BasicTypes.Boolean)) return new BooleanTypeAdjuster(); + if (value.Equals(BasicTypes.Undefined)) + return new UndefinedTypeAdjuster(); + return null; } @@ -122,16 +134,15 @@ public IValue AdjustValue(IValue pValue = null) return value ?? ValueFactory.Create(); } - if (value != null && value.SystemType != BasicTypes.Undefined) + if (value != null) { var valueType = new BslTypeValue(value.SystemType); - if (_types.Contains(valueType)) + if (ContainsType(valueType)) { // Если такой тип у нас есть var adjuster = GetAdjusterForType(valueType); - var adjustedValue = adjuster.Adjust(value); - if (adjustedValue != null) - return adjustedValue; + var adjustedValue = adjuster?.Adjust(value) ?? value; + return adjustedValue; } } @@ -146,41 +157,25 @@ public IValue AdjustValue(IValue pValue = null) return ValueFactory.Create(); } - internal static BslTypeValue TypeNumber() - { - return new BslTypeValue(BasicTypes.Number); - } - - internal static BslTypeValue TypeBoolean() - { - return new BslTypeValue(BasicTypes.Boolean); - } - - internal static BslTypeValue TypeString() - { - return new BslTypeValue(BasicTypes.String); - } - - internal static BslTypeValue TypeDate() - { - return new BslTypeValue(BasicTypes.Date); - } - public static TypeDescription StringType(int length = 0, - AllowedLengthEnum allowedLength = AllowedLengthEnum.Variable) + AllowedLengthEnum allowedLength = AllowedLengthEnum.Variable) { - return TypeDescriptionBuilder.Build(TypeString(), new StringQualifiers(length, allowedLength)); + return TypeDescriptionBuilder.OfType(BasicTypes.String) + .SetStringQualifiers(new StringQualifiers(length, allowedLength)) + .Build(); } public static TypeDescription IntegerType(int length = 10, - AllowedSignEnum allowedSign = AllowedSignEnum.Any) + AllowedSignEnum allowedSign = AllowedSignEnum.Any) { - return TypeDescriptionBuilder.Build(TypeNumber(), new NumberQualifiers(length, 0, allowedSign)); + return TypeDescriptionBuilder.OfType(BasicTypes.Number) + .SetNumberQualifiers(new NumberQualifiers(length, 0, allowedSign)) + .Build(); } public static TypeDescription BooleanType() { - return TypeDescriptionBuilder.Build(TypeBoolean()); + return TypeDescriptionBuilder.OfType(BasicTypes.Boolean).Build(); } [ScriptConstructor] @@ -194,71 +189,156 @@ public static TypeDescription Constructor( IValue p6 = null, IValue p7 = null) { + var builder = new TypeDescriptionBuilder(); + + // параметры, которые заведомо не квалификаторы, заменяем на null, но оставляем, + // чтобы указать номер параметра при выводе ошибки несоответствия типа + var qualifiers = new[] { null, p2, p3, p4, p5, p6, p7 }; + var rawSource = source?.GetRawValue(); - if (rawSource == null || rawSource.SystemType == BasicTypes.Undefined) { // пустой первый параметр - нет объекта-основания // добавляемые/вычитаемые типы не допускаются, квалификаторы игнорируются // квалификакторы передаются только для контроля типов - return ConstructByQualifiers(context.TypeManager, BslUndefinedValue.Instance, p2, p3, p4, p5, p6, p7); } - - if (rawSource is TypeDescription) + else + if (rawSource is TypeDescription typeDesc) { - return ConstructByOtherDescription(context.TypeManager, rawSource, p2, p3, p4, p5, p6, p7); - } + // Если 1 парарметр - ОписаниеТипов, то 2 - добавляемые типы, 3 - убираемые типы, + builder.SourceDescription(typeDesc); + + var typesToAdd = CheckAndParseTypeList(context.TypeManager, p2, 2); + var typesToRemove = CheckAndParseTypeList(context.TypeManager, p3, 3); + + builder.RemoveTypes(typesToRemove); + builder.AddTypes(typesToAdd); + qualifiers[1] = null; // эти параметры не квалификаторы + qualifiers[2] = null; // эти параметры не квалификаторы + + } + else if (rawSource.SystemType == BasicTypes.String || rawSource is ArrayImpl) { - return ConstructByQualifiers(context.TypeManager, rawSource, p2, p3, p4, p5, p6, p7); + // Если 1 парарметр - Массив или строка, то это набор конкретных типов + // остальные параметры (2 и далее) - клвалификаторы в произвольном порядке + var typesList = CheckAndParseTypeList(context.TypeManager, rawSource, 1); + builder.AddTypes(typesList); + } else + throw RuntimeException.InvalidArgumentValue(); + + CheckAndAddQualifiers(builder, qualifiers); + return builder.Build(); + } + + /// + /// Преобразует входящий параметр в список типов. + /// + /// В качестве типов могут быть переданы Строка или Массив Типов + /// Номер параметра, который будет указан в исключении, если параметр typeList задан неверно + /// Если typeList не может быть разобран как набор типов + /// Список переданных типов, приведенный к конкретным TypeTypeValue + private static List CheckAndParseTypeList(ITypeManager typeManager, IValue types, int nParam) + { + types = types?.GetRawValue(); + if (types == null || types.SystemType == BasicTypes.Undefined) + return new List(); + + if (types.SystemType == BasicTypes.String) + { + return FromTypeNames(typeManager, types.AsString()); + } + if (types is ArrayImpl arrayOfTypes) + { + return FromArrayOfTypes(arrayOfTypes); } - throw RuntimeException.InvalidArgumentValue(); + throw RuntimeException.InvalidNthArgumentType(nParam); } - private static TypeDescription ConstructByQualifiers(ITypeManager typeManager, IValue types, - IValue p2 = null, - IValue p3 = null, - IValue p4 = null, - IValue p5 = null, - IValue p6 = null, - IValue p7 = null) + private static List FromTypeNames(ITypeManager typeManager, string types) { - var builder = new TypeDescriptionBuilder(); - var typesList = TypeList.Construct(typeManager, types, 1); - builder.AddTypes(typesList.List()); + var typeNames = types.Split(','); + var typesList = new List(); + foreach (var typeName in typeNames) + { + if (string.IsNullOrWhiteSpace(typeName)) + continue; - builder.AddQualifiers(new[] { p2, p3, p4, p5, p6, p7 }, 1); + var typeValue = new BslTypeValue(typeManager.GetTypeByName(typeName.Trim())); + if (!typesList.Contains(typeValue)) + typesList.Add(typeValue); + } - return builder.Build(); + return typesList; } - private static TypeDescription ConstructByOtherDescription(ITypeManager typeManager, - IValue typeDescription = null, - IValue addTypes = null, - IValue removeTypes = null, - IValue p4 = null, - IValue p5 = null, - IValue p6 = null, - IValue p7 = null) + private static List FromArrayOfTypes(ArrayImpl arrayOfTypes) { - var builder = new TypeDescriptionBuilder(); + var typesList = new List(); + foreach (var type in arrayOfTypes) + { + if (type.GetRawValue() is BslTypeValue rawType) + { + typesList.Add(rawType); + } + } + return typesList; + } - if (typeDescription is TypeDescription typeDesc) + private static void CheckAndAddQualifiers(TypeDescriptionBuilder builder, IValue[] parameters) + { + for (var i = 0; i < parameters.Length; i++) { - builder.SourceDescription(typeDesc); + var rawQualifier = parameters[i]?.GetRawValue(); + if (rawQualifier != null && !rawQualifier.Equals(ValueFactory.Create())) + { + CheckAndAddOneQualifier(builder, rawQualifier, i + 1); + } } - - var removeTypesList = TypeList.Construct(typeManager, removeTypes, 3); - builder.RemoveTypes(removeTypesList.List()); + } - var addTypesList = TypeList.Construct(typeManager, addTypes, 2); - builder.AddTypes(addTypesList.List()); - builder.AddQualifiers(new[] { p4, p5, p6, p7 }, 3); + /// + /// Проверяет, что переданный параметр является квалификатором типа. + /// Если тип параметра не является квалификатором, бросает исключение с указанием номера параметра. + /// + /// Построитель описания типов, которому будет присвоен квалификатор + /// Проверяемый входящий параметр + /// Порядковый номер параметра для выброса исключения + /// Если qualifier не является квалификатором типа + private static void CheckAndAddOneQualifier(TypeDescriptionBuilder builder, IValue qualifier, int nParam) + { + switch (qualifier) + { + case NumberQualifiers nq: + builder.SetNumberQualifiers(nq); + break; - return builder.Build(); + case StringQualifiers sq: + builder.SetStringQualifiers(sq); + break; + + case DateQualifiers dq: + builder.SetDateQualifiers(dq); + break; + + case BinaryDataQualifiers bdq: + builder.SetBinaryDataQualifiers(bdq); + break; + + default: + throw RuntimeException.InvalidNthArgumentType(nParam); + } + } + } + + internal class UndefinedTypeAdjuster : IValueAdjuster + { + public IValue Adjust(IValue value) + { + return ValueFactory.Create(); } } } diff --git a/src/OneScript.StandardLibrary/TypeDescriptions/TypeDescriptionBuilder.cs b/src/OneScript.StandardLibrary/TypeDescriptions/TypeDescriptionBuilder.cs index d1731a4f4..0b87a3186 100644 --- a/src/OneScript.StandardLibrary/TypeDescriptions/TypeDescriptionBuilder.cs +++ b/src/OneScript.StandardLibrary/TypeDescriptions/TypeDescriptionBuilder.cs @@ -5,17 +5,14 @@ This Source Code Form is subject to the terms of the at http://mozilla.org/MPL/2.0/. ----------------------------------------------------------*/ -using System; using System.Collections.Generic; using System.Linq; -using OneScript.Exceptions; using OneScript.Types; using OneScript.Values; -using ScriptEngine.Machine; namespace OneScript.StandardLibrary.TypeDescriptions { - internal class TypeDescriptionBuilder + internal partial class TypeDescriptionBuilder { private NumberQualifiers _numberQualifiers; private StringQualifiers _stringQualifiers; @@ -51,46 +48,27 @@ public TypeDescriptionBuilder RemoveTypes(IEnumerable types) return this; } - public TypeDescriptionBuilder AddQualifiers(IValue[] qualifiers, int nParam = 0) + public TypeDescriptionBuilder SetNumberQualifiers(NumberQualifiers nq) { - foreach (var qualifier in qualifiers) - { - nParam++; - AddQualifier(qualifier, nParam); - } - + _numberQualifiers = nq; return this; } - public TypeDescriptionBuilder AddQualifier(IValue qualifier, int nParam = 0) + public TypeDescriptionBuilder SetStringQualifiers(StringQualifiers sq) { - if (qualifier != null && !qualifier.Equals(BslUndefinedValue.Instance)) - { - switch (qualifier.GetRawValue()) - { - case NumberQualifiers nq: - _numberQualifiers = nq; - break; - - case StringQualifiers sq: - _stringQualifiers = sq; - break; - - case DateQualifiers dq: - _dateQualifiers = dq; - break; - - case BinaryDataQualifiers bdq: - _binaryDataQualifiers = bdq; - break; + _stringQualifiers = sq; + return this; + } - default: - throw nParam == 0 - ? RuntimeException.InvalidArgumentType() - : RuntimeException.InvalidNthArgumentType(nParam); - } - } + public TypeDescriptionBuilder SetDateQualifiers(DateQualifiers dq) + { + _dateQualifiers = dq; + return this; + } + public TypeDescriptionBuilder SetBinaryDataQualifiers(BinaryDataQualifiers bq) + { + _binaryDataQualifiers = bq; return this; } @@ -99,9 +77,9 @@ public TypeDescription Build() _types = new List(_types.Distinct()); _types.RemoveAll(type => type.TypeValue.ImplementingClass == typeof(BslUndefinedValue)); _types.Sort(new TypeComparer()); - var hasNumber = _types.Contains(TypeDescription.TypeNumber()); - var hasString =_types.Contains(TypeDescription.TypeString()); - var hasDate = _types.Contains(TypeDescription.TypeDate()); + var hasNumber = _types.Any(type => type.TypeValue == BasicTypes.Number); + var hasString =_types.Any(type => type.TypeValue == BasicTypes.String); + var hasDate = _types.Any(type => type.TypeValue == BasicTypes.Date); var hasBinaryData = _types.Any(x => x.TypeValue.Name == TYPE_BINARYDATA_NAME); if (!hasNumber || _numberQualifiers == null) _numberQualifiers = new NumberQualifiers(); @@ -118,60 +96,11 @@ public TypeDescription Build() } - public static TypeDescription Build(BslTypeValue type, IValue qualifier = null) + public static TypeDescriptionBuilder OfType(TypeDescriptor commonType) { var builder = new TypeDescriptionBuilder(); - return builder.AddTypes(new[] { type }).AddQualifier(qualifier).Build(); - } - - private class TypeComparer : IComparer - { - private static readonly IDictionary primitives = new Dictionary(); - public int Compare(BslTypeValue x, BslTypeValue y) - { - if (x.TypeValue.Equals(y)) return 0; - - var primitiveX = PrimitiveIndex(x); - var primitiveY = PrimitiveIndex(y); - - if (primitiveX != -1) - { - if (primitiveY != -1) - return primitiveX - primitiveY; - - return -1; - } - - if (primitiveY != -1) - return 1; - - return x.TypeValue.Id.CompareTo(y.TypeValue.Id); - } - - private int PrimitiveIndex(BslTypeValue type) - { - if (StringComparer.CurrentCultureIgnoreCase.Equals(type.TypeValue.Name, TYPE_BINARYDATA_NAME)) - { - // Пора двоичным данным стать примитивом - return 1; - } - - if (primitives.ContainsKey(type.TypeValue)) - return primitives[type.TypeValue]; - - return -1; - } - - static TypeComparer() - { - primitives.Add(BasicTypes.Boolean, 0); - primitives.Add(BasicTypes.String, 2); - primitives.Add(BasicTypes.Date, 3); - primitives.Add(BasicTypes.Null, 4); - primitives.Add(BasicTypes.Number, 5); - primitives.Add(BasicTypes.Type, 6); - } - + builder.AddTypes(new[] { new BslTypeValue(commonType) }); + return builder; } } } \ No newline at end of file diff --git a/src/OneScript.StandardLibrary/TypeDescriptions/TypeList.cs b/src/OneScript.StandardLibrary/TypeDescriptions/TypeList.cs deleted file mode 100644 index ebf80b0bc..000000000 --- a/src/OneScript.StandardLibrary/TypeDescriptions/TypeList.cs +++ /dev/null @@ -1,121 +0,0 @@ -/*---------------------------------------------------------- -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.Generic; -using System.Linq; -using OneScript.Exceptions; -using OneScript.StandardLibrary.Collections; -using OneScript.Types; -using OneScript.Values; -using ScriptEngine.Machine; - -namespace OneScript.StandardLibrary.TypeDescriptions -{ - internal class TypeList - { - private readonly IList _list; - - public TypeList(IEnumerable list) - { - _list = new List(list); - } - - public int Count => _list.Count; - - public bool Contains(BslTypeValue type) - { - return _list.Contains(type); - } - - public bool Contains(string typeName) - { - return _list.Any(x => string.Compare( - x.TypeValue.Name, - typeName, - StringComparison.OrdinalIgnoreCase) == 0 - ); - } - - public IList List() - { - return _list; - } - - /// - /// Возвращает типы как Массив - /// - /// Массив, содержащий элементы типа Тип - public ArrayImpl AsArray() - { - return new ArrayImpl(_list); - } - - public TypeList Modify(TypeList typesToRemove, TypeList typesToAdd) - { - var typesList = _list.Where(type => !typesToRemove.Contains(type)).ToList(); - typesList.AddRange(typesToAdd._list); - return new TypeList(typesList); - } - - public TypeList Modify(TypeList typesToRemove) - { - var typesList = _list.Where(type => !typesToRemove.Contains(type)).ToList(); - return new TypeList(typesList); - } - - public static TypeList Construct(ITypeManager typeManager, IValue types, int nParam) - { - types = types?.GetRawValue(); - if (types == null || types.SystemType == BasicTypes.Undefined) - return new TypeList(Array.Empty()); - - if (types.SystemType == BasicTypes.String) - { - return FromTypeNames(typeManager, types.AsString()); - } - if (types is ArrayImpl arrayOfTypes) - { - return FromArrayOfTypes(arrayOfTypes); - } - - throw RuntimeException.InvalidNthArgumentType(nParam); - } - - public static TypeList FromTypeNames(ITypeManager typeManager, string types) - { - var typeNames = types.Split(','); - var typesList = new List(); - foreach (var typeName in typeNames) - { - if (string.IsNullOrWhiteSpace(typeName)) - continue; - - var typeValue = new BslTypeValue(typeManager.GetTypeByName(typeName.Trim())); - if (!typesList.Contains(typeValue)) - typesList.Add(typeValue); - } - - return new TypeList(typesList); - } - - public static TypeList FromArrayOfTypes(ArrayImpl arrayOfTypes) - { - var typesList = new List(); - foreach (var type in arrayOfTypes) - { - var rawType = type.GetRawValue() as BslTypeValue; - if (rawType == null) - continue; - - if (!typesList.Contains(rawType)) - typesList.Add(rawType); - } - return new TypeList(typesList); - } - } -} \ No newline at end of file diff --git a/tests/typedescription.os b/tests/typedescription.os index 4bec441b9..8a58a8228 100644 --- a/tests/typedescription.os +++ b/tests/typedescription.os @@ -31,6 +31,8 @@ ВсеТесты.Добавить("ТестДолжен_ПроверитьПриведениеДат"); ВсеТесты.Добавить("ТестДолжен_ПроверитьПриведениеБезПриведения"); ВсеТесты.Добавить("ТестДолжен_ПроверитьПриведениеЧисел"); + ВсеТесты.Добавить("ТестДолжен_ПроверитьПриведениеНеопределено"); + ВсеТесты.Добавить("ТестДолжен_ПроверитьПриведениеОбъектов"); ВсеТесты.Добавить("ТестДолжен_Преобразование_ОписаниеБезТипов"); ВсеТесты.Добавить("ТестДолжен_Преобразование_ОписаниеБезТипов_КвалификаторыИгнорируются"); @@ -490,7 +492,7 @@ юТест.ПроверитьРавенство(ОписаниеБезТипов.ПривестиЗначение(ДД), ДД, "Двоичные данные не ломаются. " + ОписаниеСлучая); юТест.ПроверитьРавенство(ОписаниеБезТипов.Типы().Количество(), 0, "Типы() пустой. " + ОписаниеСлучая); - юТест.ПроверитьЛожь(ОписаниеБезТипов.СодержитТип(Тип("Неопределено")), "Нет типа Неопределено. " + ОписаниеСлучая); + // юТест.ПроверитьЛожь(ОписаниеБезТипов.СодержитТип(Тип("Неопределено")), "Нет типа Неопределено. " + ОписаниеСлучая); КонецЦикла; @@ -580,6 +582,33 @@ КонецПроцедуры +Процедура ТестДолжен_ПроверитьПриведениеНеопределено() Экспорт + + ОТ = Новый ОписаниеТипов("Число, Строка"); + юТест.ПроверитьИстину(ОТ.СодержитТип(Тип("Неопределено")), "Неопределено содержится в описании типов"); + юТест.ПроверитьРавенство(ОТ.Типы().Найти(Тип("Неопределено")), Неопределено, "Неопределено не содержится в типах"); + юТест.ПроверитьРавенство(ОТ.ПривестиЗначение(Неопределено), Неопределено, "Неопределено в неопределено"); + + ОТ = Новый ОписаниеТипов; + юТест.ПроверитьРавенство(ОТ.ПривестиЗначение(Неопределено), Неопределено, "Неопределено в неопределено"); + юТест.ПроверитьЛожь(ОТ.СодержитТип(Тип("Неопределено")), "Неопределено не содержится в описании типов (без типов)"); + юТест.ПроверитьРавенство(ОТ.Типы().Найти(Тип("Неопределено")), Неопределено, "Неопределено не содержится в типах"); + +КонецПроцедуры + +Процедура ТестДолжен_ПроверитьПриведениеОбъектов() Экспорт + + ОТ = Новый ОписаниеТипов("Массив, Структура, Строка"); + + М1 = Новый Массив; + М1.Добавить(1); + М1.Добавить(2); + + М2 = ОТ.ПривестиЗначение(М1); + юТест.ПроверитьРавенство(М2, М1, "Массив тот же самый"); + +КонецПроцедуры + Процедура ПроверитьПорядокТипов(Знач ТипыОписанияТипов, Знач ОжидаемыйПорядок, Знач Текст = Неопределено) Если Текст = Неопределено Тогда From 3d2a15c76b5c6c150598959f2e951a4daca511af Mon Sep 17 00:00:00 2001 From: Sergey Batanov Date: Fri, 29 Sep 2023 17:55:06 +0300 Subject: [PATCH 8/8] =?UTF-8?q?#1327:=20=D0=B2=D0=BE=20=D1=81=D0=BB=D0=B0?= =?UTF-8?q?=D0=B2=D1=83=20=D1=81=D0=BE=D0=BD=D0=B0=D1=80=D0=B0.?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../TypeDescriptions/TypeDescription.cs | 59 +++++++++---------- .../TypeDescriptionBuilder.cs | 2 +- 2 files changed, 28 insertions(+), 33 deletions(-) diff --git a/src/OneScript.StandardLibrary/TypeDescriptions/TypeDescription.cs b/src/OneScript.StandardLibrary/TypeDescriptions/TypeDescription.cs index c85daecc0..0f9c3b164 100644 --- a/src/OneScript.StandardLibrary/TypeDescriptions/TypeDescription.cs +++ b/src/OneScript.StandardLibrary/TypeDescriptions/TypeDescription.cs @@ -23,8 +23,6 @@ public class TypeDescription : AutoContext { private readonly List _types = new List(); - private const string TYPE_BINARYDATA_NAME = "ДвоичныеДанные"; - public TypeDescription(IEnumerable types = null) { if (types != null) @@ -196,39 +194,36 @@ public static TypeDescription Constructor( var qualifiers = new[] { null, p2, p3, p4, p5, p6, p7 }; var rawSource = source?.GetRawValue(); - if (rawSource == null || rawSource.SystemType == BasicTypes.Undefined) + if (rawSource != null && rawSource.SystemType != BasicTypes.Undefined) { - // пустой первый параметр - нет объекта-основания - // добавляемые/вычитаемые типы не допускаются, квалификаторы игнорируются + if (rawSource is TypeDescription typeDesc) + { + // Если 1 парарметр - ОписаниеТипов, то 2 - добавляемые типы, 3 - убираемые типы, + builder.SourceDescription(typeDesc); - // квалификакторы передаются только для контроля типов - } - else - if (rawSource is TypeDescription typeDesc) - { - // Если 1 парарметр - ОписаниеТипов, то 2 - добавляемые типы, 3 - убираемые типы, - builder.SourceDescription(typeDesc); - - var typesToAdd = CheckAndParseTypeList(context.TypeManager, p2, 2); - var typesToRemove = CheckAndParseTypeList(context.TypeManager, p3, 3); - - builder.RemoveTypes(typesToRemove); - builder.AddTypes(typesToAdd); - - qualifiers[1] = null; // эти параметры не квалификаторы - qualifiers[2] = null; // эти параметры не квалификаторы + var typesToAdd = CheckAndParseTypeList(context.TypeManager, p2, 2); + var typesToRemove = CheckAndParseTypeList(context.TypeManager, p3, 3); - } - else - if (rawSource.SystemType == BasicTypes.String || rawSource is ArrayImpl) - { - // Если 1 парарметр - Массив или строка, то это набор конкретных типов - // остальные параметры (2 и далее) - клвалификаторы в произвольном порядке - var typesList = CheckAndParseTypeList(context.TypeManager, rawSource, 1); - builder.AddTypes(typesList); - } else - throw RuntimeException.InvalidArgumentValue(); - + builder.RemoveTypes(typesToRemove); + builder.AddTypes(typesToAdd); + + qualifiers[1] = null; // эти параметры не квалификаторы + qualifiers[2] = null; // эти параметры не квалификаторы + } + else if (rawSource.SystemType == BasicTypes.String || rawSource is ArrayImpl) + { + // Если 1 парарметр - Массив или строка, то это набор конкретных типов + // остальные параметры (2 и далее) - клвалификаторы в произвольном порядке + var typesList = CheckAndParseTypeList(context.TypeManager, rawSource, 1); + builder.AddTypes(typesList); + } + else + throw RuntimeException.InvalidArgumentValue(); + } /* else + пустой первый параметр - нет объекта-основания + добавляемые/вычитаемые типы не допускаются, квалификаторы игнорируются + квалификакторы передаются только для контроля типов + */ CheckAndAddQualifiers(builder, qualifiers); return builder.Build(); } diff --git a/src/OneScript.StandardLibrary/TypeDescriptions/TypeDescriptionBuilder.cs b/src/OneScript.StandardLibrary/TypeDescriptions/TypeDescriptionBuilder.cs index 0b87a3186..551d8e7d0 100644 --- a/src/OneScript.StandardLibrary/TypeDescriptions/TypeDescriptionBuilder.cs +++ b/src/OneScript.StandardLibrary/TypeDescriptions/TypeDescriptionBuilder.cs @@ -12,7 +12,7 @@ This Source Code Form is subject to the terms of the namespace OneScript.StandardLibrary.TypeDescriptions { - internal partial class TypeDescriptionBuilder + internal class TypeDescriptionBuilder { private NumberQualifiers _numberQualifiers; private StringQualifiers _stringQualifiers;