diff --git a/src/OneScript.StandardLibrary/Collections/Indexes/CollectionIndex.cs b/src/OneScript.StandardLibrary/Collections/Indexes/CollectionIndex.cs index 10a415399..71fb5c62b 100644 --- a/src/OneScript.StandardLibrary/Collections/Indexes/CollectionIndex.cs +++ b/src/OneScript.StandardLibrary/Collections/Indexes/CollectionIndex.cs @@ -21,18 +21,28 @@ public class CollectionIndex : AutoCollectionContext private readonly List _fields = new List(); private readonly IIndexCollectionSource _source; - private readonly IDictionary> _data = + private readonly Dictionary> _data = new Dictionary>(); public CollectionIndex(IIndexCollectionSource source, IEnumerable fields) { + foreach (var field in fields) + { + if (field is ValueTable.ValueTableColumn column) + column.AddToIndex(); + _fields.Add(field); + } + _source = source; - _fields.AddRange(fields); + foreach (var value in _source) + { + ElementAdded(value); + } } internal bool CanBeUsedFor(IEnumerable searchFields) { - return _fields.Any() && _fields.ToHashSet().IsSubsetOf(searchFields.ToHashSet()); + return _fields.Count > 0 && _fields.All(f => searchFields.Contains(f)); } private CollectionIndexKey IndexKey(PropertyNameIndexAccessor source) @@ -55,11 +65,26 @@ internal void FieldRemoved(IValue field) { if (_fields.Contains(field)) { - while (_fields.Contains(field)) _fields.Remove(field); + while (_fields.Contains(field)) + { + if (field is ValueTable.ValueTableColumn column) + column.DeleteFromIndex(); + + _fields.Remove(field); + } Rebuild(); } } + internal void ExcludeFields() + { + foreach (var field in _fields) + { + if (field is ValueTable.ValueTableColumn column) + column.DeleteFromIndex(); + } + } + internal void ElementAdded(PropertyNameIndexAccessor element) { var key = CollectionIndexKey.Extract(element, _fields); @@ -82,10 +107,7 @@ internal void ElementRemoved(PropertyNameIndexAccessor element) } } - internal void Clear() - { - _data.Clear(); - } + internal void Clear() => _data.Clear(); internal void Rebuild() { diff --git a/src/OneScript.StandardLibrary/Collections/ValueTable/CollectionIndexes.cs b/src/OneScript.StandardLibrary/Collections/ValueTable/CollectionIndexes.cs index 371126d77..08c5328e4 100644 --- a/src/OneScript.StandardLibrary/Collections/ValueTable/CollectionIndexes.cs +++ b/src/OneScript.StandardLibrary/Collections/ValueTable/CollectionIndexes.cs @@ -32,7 +32,6 @@ public CollectionIndexes(IIndexCollectionSource owner) public CollectionIndex Add(string columns) { var newIndex = new CollectionIndex(_owner, BuildFieldList(_owner, columns)); - newIndex.Rebuild(); _indexes.Add(newIndex); return newIndex; } @@ -40,18 +39,23 @@ public CollectionIndex Add(string columns) [ContextMethod("Количество", "Count")] public override int Count() { - return _indexes.Count(); + return _indexes.Count; } [ContextMethod("Удалить", "Delete")] public void Delete(IValue index) { - _indexes.Remove(GetIndex(index)); + var idx = GetIndex(index); + idx.ExcludeFields(); + _indexes.Remove(idx); } [ContextMethod("Очистить", "Clear")] public void Clear() { + foreach (var idx in _indexes) + idx.ExcludeFields(); + _indexes.Clear(); } @@ -130,21 +134,18 @@ public CollectionIndex FindSuitableIndex(IEnumerable searchFields) return _indexes.FirstOrDefault(index => index.CanBeUsedFor(searchFields)); } - private static IList BuildFieldList(IIndexCollectionSource source, string fieldList) + private static List BuildFieldList(IIndexCollectionSource source, string fieldList) { var fields = new List(); - var fieldNames = fieldList.Split(','); + if (string.IsNullOrEmpty(fieldList)) + return fields; + + var fieldNames = fieldList.Split(',', System.StringSplitOptions.RemoveEmptyEntries); foreach (var fieldName in fieldNames) - { - if (!string.IsNullOrWhiteSpace(fieldName)) - { - var field = source.GetField(fieldName.Trim()); - if (field == null) - { - throw ColumnException.WrongColumnName(fieldName); - } - fields.Add(field); - } + { + var name = fieldName.Trim(); + var field = source.GetField(name) ?? throw ColumnException.WrongColumnName(fieldName); + fields.Add(field); } return fields; diff --git a/src/OneScript.StandardLibrary/Collections/ValueTable/ValueTable.cs b/src/OneScript.StandardLibrary/Collections/ValueTable/ValueTable.cs index 52ae1e800..3fdbff358 100644 --- a/src/OneScript.StandardLibrary/Collections/ValueTable/ValueTable.cs +++ b/src/OneScript.StandardLibrary/Collections/ValueTable/ValueTable.cs @@ -35,8 +35,8 @@ public ValueTable() Columns = new ValueTableColumnCollection(this); _rows = new List(); Indexes = new CollectionIndexes(this); - } - + } + /// /// Коллекция колонок /// @@ -70,7 +70,8 @@ public ValueTableRow Add() { var row = new ValueTableRow(this); _rows.Add(row); - Indexes.ElementAdded(row); + if (Indexes.Count() > 0) + Indexes.ElementAdded(row); return row; } @@ -83,13 +84,14 @@ public ValueTableRow Add() [ContextMethod("Вставить", "Insert")] public ValueTableRow Insert(int index) { - var row = new ValueTableRow(this); if (index < 0 || index > _rows.Count) - _rows.Add(row); // для совместимости с 1С, хотя логичней было бы исключение - else - _rows.Insert(index, row); + return Add(); // для совместимости с 1С, хотя логичней было бы исключение - Indexes.ElementAdded(row); + var row = new ValueTableRow(this); + _rows.Insert(index, row); + + if (Indexes.Count() > 0) + Indexes.ElementAdded(row); return row; } @@ -157,7 +159,7 @@ public ArrayImpl UnloadColumn(IValue column) return result; } - private List GetProcessingColumnList(string columnNames, bool emptyListInCaseOfNull = false) + private List GetProcessingColumnList(string columnNames, bool emptyListInCaseOfNull = false) { var processing_list = new List(); if (string.IsNullOrEmpty(columnNames)) // Передали пустую строку вместо списка колонок @@ -312,16 +314,18 @@ public IValue Find(IValue value, string columnNames = null) } } return ValueFactory.Create(); - } + } + + private ValueTableColumn GetColumnOrThrow(string column_name) + => this.Columns.FindColumnByName(column_name) + ?? throw ColumnException.WrongColumnName(column_name); + private bool CheckFilterCriteria(ValueTableRow Row, StructureImpl Filter) { foreach (var kv in Filter) { - var Column = Columns.FindColumnByName(kv.Key.ToString()); - if (Column == null) - throw ColumnException.WrongColumnName(kv.Key.ToString()); - + var Column = GetColumnOrThrow(kv.Key.ToString()); IValue current = Row.Get(Column); if (!current.StrictEquals(kv.Value)) return false; @@ -344,7 +348,7 @@ public ArrayImpl FindRows(StructureImpl filter) var mapped = ColumnsMap(filter); var suitableIndex = Indexes.FindSuitableIndex(mapped.Keys()); - var dataToScan = suitableIndex != null ? suitableIndex.GetData(mapped) : _rows; + var dataToScan = suitableIndex?.GetData(mapped) ?? _rows; foreach (var element in dataToScan) { @@ -361,10 +365,7 @@ private MapImpl ColumnsMap(StructureImpl filter) var result = new MapImpl(); foreach (var kv in filter) { - var key = Columns.FindColumnByName(kv.Key.ToString()); - if (key == null) - throw ColumnException.WrongColumnName(kv.Key.ToString()); - + var key = GetColumnOrThrow(kv.Key.ToString()); result.Insert(key, kv.Value); } @@ -653,10 +654,7 @@ private List GetSortRules(string Columns) if (description.Length > 2) throw RuntimeException.InvalidNthArgumentValue(1); - var sortColumn = this.Columns.FindColumnByName(description[0]); - if (sortColumn == null) - throw ColumnException.WrongColumnName(description[0]); - + var sortColumn = GetColumnOrThrow(description[0]); var rule = new ValueTableSortRule { Column = sortColumn, diff --git a/src/OneScript.StandardLibrary/Collections/ValueTable/ValueTableColumn.cs b/src/OneScript.StandardLibrary/Collections/ValueTable/ValueTableColumn.cs index a7b5956aa..8070951bb 100644 --- a/src/OneScript.StandardLibrary/Collections/ValueTable/ValueTableColumn.cs +++ b/src/OneScript.StandardLibrary/Collections/ValueTable/ValueTableColumn.cs @@ -20,18 +20,21 @@ namespace OneScript.StandardLibrary.Collections.ValueTable public class ValueTableColumn : AutoContext { private string _title; - private string _name; - private TypeDescription _valueType; + private string _name; + private readonly TypeDescription _valueType; private readonly WeakReference _owner; - private readonly int _id; - - public ValueTableColumn(ValueTableColumnCollection owner, int id, string name, string title, TypeDescription type, int width) + + private int _indicesCount = 0; + public bool IsIndexable => _indicesCount != 0; + public void AddToIndex() { _indicesCount++; } + public void DeleteFromIndex() { if (_indicesCount != 0) _indicesCount--; } + + public ValueTableColumn(ValueTableColumnCollection owner, string name, string title, TypeDescription type, int width) { _name = name; _title = title; _valueType = type ?? new TypeDescription(); Width = width; - _id = id; _owner = new WeakReference(owner); } @@ -65,7 +68,6 @@ public string Name _title = value; _name = value; - } } /// diff --git a/src/OneScript.StandardLibrary/Collections/ValueTable/ValueTableColumnCollection.cs b/src/OneScript.StandardLibrary/Collections/ValueTable/ValueTableColumnCollection.cs index 288adf683..bea283327 100644 --- a/src/OneScript.StandardLibrary/Collections/ValueTable/ValueTableColumnCollection.cs +++ b/src/OneScript.StandardLibrary/Collections/ValueTable/ValueTableColumnCollection.cs @@ -25,16 +25,40 @@ namespace OneScript.StandardLibrary.Collections.ValueTable [ContextClass("КоллекцияКолонокТаблицыЗначений", "ValueTableColumnCollection")] public class ValueTableColumnCollection : AutoContext, ICollectionContext, IDebugPresentationAcceptor { + private static readonly StringComparer _namesComparer = StringComparer.OrdinalIgnoreCase; + private readonly List _columns = new List(); - private readonly StringComparer _namesComparer = StringComparer.OrdinalIgnoreCase; private readonly ValueTable _owner; - private int maxColumnId = 0; public ValueTableColumnCollection(ValueTable owner) { _owner = owner; } + public ValueTableColumn AddUnchecked(string name, string title, TypeDescription type = null) + { + var column = new ValueTableColumn(this, name, title, type, 0); + _columns.Add(column); + return column; + } + + public ValueTableColumn AddUnchecked(string name, string title = null) + { + var column = new ValueTableColumn(this, name, title ?? name, null, 0); + _columns.Add(column); + return column; + } + + + private void CheckColumnName(string name) + { + if (!Utils.IsValidIdentifier(name)) + throw ColumnException.WrongColumnName(name); + + if (FindColumnByName(name) != null) + throw ColumnException.DuplicatedColumnName(name); + } + /// /// Добавляет колонку в таблицу значений /// @@ -46,13 +70,9 @@ public ValueTableColumnCollection(ValueTable owner) [ContextMethod("Добавить", "Add")] public ValueTableColumn Add(string name, TypeDescription type = null, string title = null, int width = 0) { - if (!Utils.IsValidIdentifier(name)) - throw ColumnException.WrongColumnName(name); + CheckColumnName(name); - if (FindColumnByName(name) != null) - throw ColumnException.DuplicatedColumnName(name); - - var column = new ValueTableColumn(this, ++maxColumnId, name, title, type, width); + var column = new ValueTableColumn(this, name, title, type, width); _columns.Add(column); return column; @@ -70,13 +90,9 @@ public ValueTableColumn Add(string name, TypeDescription type = null, string tit [ContextMethod("Вставить", "Insert")] public ValueTableColumn Insert(int index, string name, TypeDescription type = null, string title = null, int width = 0) { - if (!Utils.IsValidIdentifier(name)) - throw ColumnException.WrongColumnName(name); - - if (FindColumnByName(name) != null) - throw ColumnException.DuplicatedColumnName(name); + CheckColumnName(name); - ValueTableColumn column = new ValueTableColumn(this, ++maxColumnId, name, title, type, width); + ValueTableColumn column = new ValueTableColumn(this, name, title, type, width); _columns.Insert(index, column); return column; @@ -113,10 +129,7 @@ public int Count() [ContextMethod("Найти", "Find")] public IValue Find(string name) { - ValueTableColumn Column = FindColumnByName(name); - if (Column == null) - return ValueFactory.Create(); - return Column; + return FindColumnByName(name) ?? ValueFactory.Create(); } /// diff --git a/src/OneScript.StandardLibrary/Collections/ValueTable/ValueTableRow.cs b/src/OneScript.StandardLibrary/Collections/ValueTable/ValueTableRow.cs index a7a13aa93..8bd94093d 100644 --- a/src/OneScript.StandardLibrary/Collections/ValueTable/ValueTableRow.cs +++ b/src/OneScript.StandardLibrary/Collections/ValueTable/ValueTableRow.cs @@ -24,11 +24,8 @@ public ValueTableRow(ValueTable owner) _owner = owner; } - public int Count() - { - return _owner.Columns.Count(); - } - + public int Count() => _owner.Columns.Count(); + public int Count(IBslProcess process) => Count(); /// @@ -89,9 +86,14 @@ public void Set(IValue index, IValue value) public void Set(ValueTableColumn column, IValue value) { - _owner.Indexes.ElementRemoved(this); - _data[column] = column.ValueType.AdjustValue(value); - _owner.Indexes.ElementAdded(this); + if (column.IsIndexable) + { + _owner.Indexes.ElementRemoved(this); + _data[column] = column.ValueType.AdjustValue(value); + _owner.Indexes.ElementAdded(this); + } + else + _data[column] = column.ValueType.AdjustValue(value); } public void OnOwnerColumnRemoval(ValueTableColumn column) diff --git a/src/OneScript.StandardLibrary/Reflector.cs b/src/OneScript.StandardLibrary/Reflector.cs index f36dd01e1..1074b364c 100644 --- a/src/OneScript.StandardLibrary/Reflector.cs +++ b/src/OneScript.StandardLibrary/Reflector.cs @@ -28,7 +28,7 @@ namespace OneScript.StandardLibrary /// Как правило, рефлексия используется для проверки наличия у объекта определенных свойств/методов. /// В OneScript рефлексию можно применять для вызова методов объектов по именам методов. /// - [ContextClass("Рефлектор","Reflector")] + [ContextClass("Рефлектор", "Reflector")] public class ReflectorContext : AutoContext { private readonly ITypeManager _typeManager; @@ -55,8 +55,8 @@ public IValue CallMethod(IBslProcess process, IRuntimeContextInstance target, st if (target.DynamicMethodSignatures) argsToPass = arguments?.ToArray() ?? Array.Empty(); else - argsToPass = GetArgsToPass(arguments, methInfo.GetBslParameters()); - + argsToPass = GetArgsToPass(arguments, methInfo.GetBslParameters()); + IValue retValue = ValueFactory.Create(); if (methInfo.IsFunction()) { @@ -83,9 +83,9 @@ public IValue CallMethod(IBslProcess process, IRuntimeContextInstance target, st private static IValue[] GetArgsToPass(ArrayImpl arguments, ParameterInfo[] parameters) { - var argValues = arguments?.ToArray() ?? Array.Empty(); - // ArrayImpl не может (не должен!) содержать null или NotAValidValue - + var argValues = arguments?.ToArray() ?? Array.Empty(); + // ArrayImpl не может (не должен!) содержать null или NotAValidValue + if (argValues.Length > parameters.Length) throw RuntimeException.TooManyArgumentsPassed(); @@ -119,7 +119,7 @@ private static IValue[] GetArgsToPass(ArrayImpl arguments, ParameterInfo[] param [ContextMethod("МетодСуществует", "MethodExists")] public bool MethodExists(BslValue target, string methodName) { - if(target is BslObjectValue) + if (target is BslObjectValue) return MethodExistsForObject(target.AsObject(), methodName); if (target.SystemType == BasicTypes.Type) @@ -141,11 +141,14 @@ private static bool MethodExistsForObject(IRuntimeContextInstance target, string } } + + private const int annotNameColumnIndex = 0; + private const int annotParamsColumnIndex = 1; private static ValueTable EmptyAnnotationsTable() { var annotationsTable = new ValueTable(); - annotationsTable.Columns.Add("Имя"); - annotationsTable.Columns.Add("Параметры"); + annotationsTable.Columns.AddUnchecked("Имя"); + annotationsTable.Columns.AddUnchecked("Параметры"); return annotationsTable; } @@ -153,8 +156,8 @@ private static ValueTable EmptyAnnotationsTable() private static ValueTable CreateAnnotationTable(BslAnnotationAttribute[] annotations) { var annotationsTable = EmptyAnnotationsTable(); - var annotationNameColumn = annotationsTable.Columns.FindColumnByName("Имя"); - var annotationParamsColumn = annotationsTable.Columns.FindColumnByName("Параметры"); + var annotationNameColumn = annotationsTable.Columns.FindColumnByIndex(annotNameColumnIndex); + var annotationParamsColumn = annotationsTable.Columns.FindColumnByIndex(annotParamsColumnIndex); foreach (var annotation in annotations) { @@ -185,19 +188,20 @@ private static ValueTable FillAnnotationParameters(IEnumerable()); } @@ -263,13 +267,13 @@ private void FillPropertiesTableForObject(ValueTable result, IValue target, bool { if (target is ScriptDrivenObject scriptObject) { - var fieldsQuery = scriptObject.Module.Fields.Cast(); - + var fieldsQuery = scriptObject.Module.Fields.Cast(); + if (!withPrivate) { fieldsQuery = fieldsQuery.Where(x => x.IsPublic); - } - + } + var fields = fieldsQuery.Select(field => BslPropertyBuilder.Create() .Name(field.Name) .IsExported(field.IsPublic) @@ -278,11 +282,11 @@ private void FillPropertiesTableForObject(ValueTable result, IValue target, bool .Build() ) .OrderBy(p => p.DispatchId) - .ToArray(); - + .ToArray(); + var fieldNames = fields.Select(x => x.Name) - .ToHashSet(); - + .ToHashSet(); + var properties = scriptObject.GetProperties() .Where(prop => !fieldNames.Contains(prop.Name)); @@ -290,8 +294,8 @@ private void FillPropertiesTableForObject(ValueTable result, IValue target, bool { properties = properties.OfType() .Where(p => p.IsExported); - } - + } + FillPropertiesTable(result, properties.Concat(fields)); } else @@ -299,8 +303,8 @@ private void FillPropertiesTableForObject(ValueTable result, IValue target, bool var objectProperties = target.AsObject().GetProperties(); FillPropertiesTable(result, objectProperties); } - } - + } + private static void FillPropertiesTableForType(BslTypeValue type, ValueTable result, bool withPrivate) { var clrType = GetReflectableClrType(type); @@ -310,7 +314,7 @@ private static void FillPropertiesTableForType(BslTypeValue type, ValueTable res PropDef = x.GetCustomAttribute(), Prop = x }) - .Where(x=>x.PropDef != null) + .Where(x => x.PropDef != null) .Select(x => new ContextPropertyInfo(x.Prop)); var infos = new List(); @@ -320,20 +324,20 @@ private static void FillPropertiesTableForType(BslTypeValue type, ValueTable res if (typeof(ScriptDrivenObject).IsAssignableFrom(clrType.BaseType)) { - var flags = BindingFlags.Instance|BindingFlags.Public; + var flags = BindingFlags.Instance | BindingFlags.Public; if (withPrivate) flags |= BindingFlags.NonPublic; var nativeFields = clrType.GetFields(flags); - foreach(var field in nativeFields) + foreach (var field in nativeFields) { var prop = BslPropertyBuilder.Create() .Name(field.Name) .IsExported(field.IsPublic) .SetDispatchingIndex(indices++) .SetAnnotations(field.GetAnnotations()) - .Build(); - + .Build(); + infos.Add(prop); } } @@ -344,18 +348,18 @@ private static void FillPropertiesTableForType(BslTypeValue type, ValueTable res private static void FillMethodsTable(ValueTable result, IEnumerable methods) { - var nameColumn = result.Columns.Add("Имя", TypeDescription.StringType(), "Имя"); - var countColumn = result.Columns.Add("КоличествоПараметров", TypeDescription.IntegerType(), "Количество параметров"); - var isFunctionColumn = result.Columns.Add("ЭтоФункция", TypeDescription.BooleanType(), "Это функция"); - var annotationsColumn = result.Columns.Add("Аннотации", new TypeDescription(), "Аннотации"); - var paramsColumn = result.Columns.Add("Параметры", new TypeDescription(), "Параметры"); - var isExportlColumn = result.Columns.Add("Экспорт", TypeDescription.BooleanType(), "Экспорт"); + var nameColumn = result.Columns.AddUnchecked("Имя"); + var countColumn = result.Columns.AddUnchecked("КоличествоПараметров", "Количество параметров"); + var isFunctionColumn = result.Columns.AddUnchecked("ЭтоФункция", "Это функция"); + var annotationsColumn = result.Columns.AddUnchecked("Аннотации"); + var paramsColumn = result.Columns.AddUnchecked("Параметры"); + var isExportlColumn = result.Columns.AddUnchecked("Экспорт"); foreach (var methInfo in methods) { var annotations = methInfo.GetAnnotations(); - var parameters = methInfo.GetBslParameters(); - + var parameters = methInfo.GetBslParameters(); + ValueTableRow new_row = result.Add(); new_row.Set(nameColumn, ValueFactory.Create(methInfo.Name)); new_row.Set(countColumn, ValueFactory.Create(parameters.Length)); @@ -365,12 +369,11 @@ private static void FillMethodsTable(ValueTable result, IEnumerable properties) { - var nameColumn = result.Columns.Add("Имя", TypeDescription.StringType(), "Имя"); - var annotationsColumn = result.Columns.Add("Аннотации", new TypeDescription(), "Аннотации"); - var isExportedColumn = result.Columns.Add("Экспорт", TypeDescription.BooleanType(), "Экспорт"); - + var nameColumn = result.Columns.AddUnchecked("Имя"); + var annotationsColumn = result.Columns.AddUnchecked("Аннотации"); + var isExportedColumn = result.Columns.AddUnchecked("Экспорт"); + var systemVarNames = new string[] { "этотобъект", "thisobject" }; foreach (var propInfo in properties) @@ -530,18 +533,18 @@ public static Type ReflectContext(Type clrType) [ContextMethod("ИзвестныеТипы", "KnownTypes")] public ValueTable KnownTypes(StructureImpl filter = default) { - var result = new ValueTable(); - - var nameColumn = result.Columns.Add("Имя", TypeDescription.StringType()); - var valueColumn = result.Columns.Add("Значение", new TypeDescription(new List() { new BslTypeValue(BasicTypes.Type) })); - var primitiveColumn = result.Columns.Add("Примитивный", TypeDescription.BooleanType()); - var userColumn = result.Columns.Add("Пользовательский", TypeDescription.BooleanType()); - var collectionColumn = result.Columns.Add("Коллекция", TypeDescription.BooleanType()); - + var result = new ValueTable(); + + var nameColumn = result.Columns.AddUnchecked("Имя"); + var valueColumn = result.Columns.AddUnchecked("Значение"); + var primitiveColumn = result.Columns.AddUnchecked("Примитивный"); + var userColumn = result.Columns.AddUnchecked("Пользовательский"); + var collectionColumn = result.Columns.AddUnchecked("Коллекция"); + _typeManager.RegisteredTypes().ForEach(descriptor => { - var row = result.Add(); - + var row = result.Add(); + row.Set(nameColumn, ValueFactory.Create(descriptor.ToString())); row.Set(valueColumn, new BslTypeValue(descriptor)); row.Set(primitiveColumn, ValueFactory.Create(descriptor.ImplementingClass.IsSubclassOf(typeof(BslPrimitiveValue)))); @@ -554,8 +557,8 @@ public ValueTable KnownTypes(StructureImpl filter = default) if (filter != default) { result = result.Copy(filter); - } - + } + return result; } diff --git a/src/OneScript.StandardLibrary/TypeDescriptions/TypeComparer.cs b/src/OneScript.StandardLibrary/TypeDescriptions/TypeComparer.cs index d41fbac03..b0877c8cd 100644 --- a/src/OneScript.StandardLibrary/TypeDescriptions/TypeComparer.cs +++ b/src/OneScript.StandardLibrary/TypeDescriptions/TypeComparer.cs @@ -14,7 +14,7 @@ namespace OneScript.StandardLibrary.TypeDescriptions internal class TypeComparer : IComparer { private const string TYPE_BINARYDATA_NAME = "ДвоичныеДанные"; - private static readonly IDictionary primitives = new Dictionary(); + private static readonly Dictionary primitives = new Dictionary(); public int Compare(BslTypeValue x, BslTypeValue y) { diff --git a/src/OneScript.StandardLibrary/TypeDescriptions/TypeDescription.cs b/src/OneScript.StandardLibrary/TypeDescriptions/TypeDescription.cs index 154e5ee34..9e91465bb 100644 --- a/src/OneScript.StandardLibrary/TypeDescriptions/TypeDescription.cs +++ b/src/OneScript.StandardLibrary/TypeDescriptions/TypeDescription.cs @@ -154,26 +154,34 @@ public IValue AdjustValue(IValue value = null) public static TypeDescription StringType(int length = 0, AllowedLengthEnum allowedLength = AllowedLengthEnum.Variable) - { - return TypeDescriptionBuilder.OfType(BasicTypes.String) - .SetStringQualifiers(new StringQualifiers(length, allowedLength)) - .Build(); + { + return new TypeDescription(new[] { new BslTypeValue(BasicTypes.String) }, + new NumberQualifiers(), + new StringQualifiers(length, allowedLength), + new DateQualifiers(), + new BinaryDataQualifiers()); } public static TypeDescription IntegerType(int length = 10, AllowedSignEnum allowedSign = AllowedSignEnum.Any) - { - return TypeDescriptionBuilder.OfType(BasicTypes.Number) - .SetNumberQualifiers(new NumberQualifiers(length, 0, allowedSign)) - .Build(); + { + return new TypeDescription(new[] { new BslTypeValue(BasicTypes.Number) }, + new NumberQualifiers(length, 0, allowedSign), + new StringQualifiers(), + new DateQualifiers(), + new BinaryDataQualifiers()); } public static TypeDescription BooleanType() - { - return TypeDescriptionBuilder.OfType(BasicTypes.Boolean).Build(); - } - - [ScriptConstructor] + { + return new TypeDescription(new[] { new BslTypeValue(BasicTypes.Boolean) }, + new NumberQualifiers(), + new StringQualifiers(), + new DateQualifiers(), + new BinaryDataQualifiers()); + } + + [ScriptConstructor] public static TypeDescription Constructor( TypeActivationContext context, BslValue source = null, diff --git a/src/OneScript.StandardLibrary/TypeDescriptions/TypeDescriptionBuilder.cs b/src/OneScript.StandardLibrary/TypeDescriptions/TypeDescriptionBuilder.cs index 551d8e7d0..9f29de509 100644 --- a/src/OneScript.StandardLibrary/TypeDescriptions/TypeDescriptionBuilder.cs +++ b/src/OneScript.StandardLibrary/TypeDescriptions/TypeDescriptionBuilder.cs @@ -21,8 +21,9 @@ internal class TypeDescriptionBuilder private const string TYPE_BINARYDATA_NAME = "ДвоичныеДанные"; - private List _types = new List(); - + private static readonly TypeComparer _comparer = new TypeComparer(); + private readonly SortedSet _types = new SortedSet(_comparer); + internal TypeDescriptionBuilder() { } @@ -38,13 +39,20 @@ public TypeDescriptionBuilder SourceDescription(TypeDescription source) public TypeDescriptionBuilder AddTypes(IEnumerable types) { - _types.AddRange(types); + foreach (var type in types) + { + if (type.TypeValue.ImplementingClass != typeof(BslUndefinedValue)) + _types.Add(type); + } return this; } public TypeDescriptionBuilder RemoveTypes(IEnumerable types) { - _types.RemoveAll(types.Contains); + foreach (var type in types) + { + _types.Remove(type); + } return this; } @@ -74,14 +82,11 @@ public TypeDescriptionBuilder SetBinaryDataQualifiers(BinaryDataQualifiers bq) public TypeDescription Build() { - _types = new List(_types.Distinct()); - _types.RemoveAll(type => type.TypeValue.ImplementingClass == typeof(BslUndefinedValue)); - _types.Sort(new TypeComparer()); var hasNumber = _types.Any(type => type.TypeValue == BasicTypes.Number); - var hasString =_types.Any(type => type.TypeValue == BasicTypes.String); + 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); - + 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();