@@ -89,12 +89,21 @@ internal IEnumerable<BslTypeValue> TypesInternal()
8989 public bool ContainsType ( IValue type )
9090 {
9191 if ( type is BslTypeValue typeVal )
92+ {
93+ if ( typeVal . TypeValue . Equals ( BasicTypes . Undefined ) )
94+ {
95+ // тип "Неопределено" содержится в любом явно определенном составном типе
96+ // и не содержится в типе Произвольный (когда явно не указан состав типов)
97+ // или когда указан один конкретный тип
98+ return ( _types . Count > 1 ) ;
99+ }
92100 return _types . Contains ( typeVal ) ;
101+ }
93102
94103 throw RuntimeException . InvalidArgumentType ( nameof ( type ) ) ;
95104 }
96105
97- IValueAdjuster GetAdjusterForType ( BslTypeValue type )
106+ private IValueAdjuster GetAdjusterForType ( BslTypeValue type )
98107 {
99108 var value = type . TypeValue ;
100109
@@ -110,6 +119,9 @@ IValueAdjuster GetAdjusterForType(BslTypeValue type)
110119 if ( value . Equals ( BasicTypes . Boolean ) )
111120 return new BooleanTypeAdjuster ( ) ;
112121
122+ if ( value . Equals ( BasicTypes . Undefined ) )
123+ return new UndefinedTypeAdjuster ( ) ;
124+
113125 return null ;
114126 }
115127
@@ -122,16 +134,15 @@ public IValue AdjustValue(IValue pValue = null)
122134 return value ?? ValueFactory . Create ( ) ;
123135 }
124136
125- if ( value != null && value . SystemType != BasicTypes . Undefined )
137+ if ( value != null )
126138 {
127139 var valueType = new BslTypeValue ( value . SystemType ) ;
128- if ( _types . Contains ( valueType ) )
140+ if ( ContainsType ( valueType ) )
129141 {
130142 // Если такой тип у нас есть
131143 var adjuster = GetAdjusterForType ( valueType ) ;
132- var adjustedValue = adjuster . Adjust ( value ) ;
133- if ( adjustedValue != null )
134- return adjustedValue ;
144+ var adjustedValue = adjuster ? . Adjust ( value ) ?? value ;
145+ return adjustedValue ;
135146 }
136147 }
137148
@@ -146,41 +157,25 @@ public IValue AdjustValue(IValue pValue = null)
146157 return ValueFactory . Create ( ) ;
147158 }
148159
149- internal static BslTypeValue TypeNumber ( )
150- {
151- return new BslTypeValue ( BasicTypes . Number ) ;
152- }
153-
154- internal static BslTypeValue TypeBoolean ( )
155- {
156- return new BslTypeValue ( BasicTypes . Boolean ) ;
157- }
158-
159- internal static BslTypeValue TypeString ( )
160- {
161- return new BslTypeValue ( BasicTypes . String ) ;
162- }
163-
164- internal static BslTypeValue TypeDate ( )
165- {
166- return new BslTypeValue ( BasicTypes . Date ) ;
167- }
168-
169160 public static TypeDescription StringType ( int length = 0 ,
170- AllowedLengthEnum allowedLength = AllowedLengthEnum . Variable )
161+ AllowedLengthEnum allowedLength = AllowedLengthEnum . Variable )
171162 {
172- return TypeDescriptionBuilder . Build ( TypeString ( ) , new StringQualifiers ( length , allowedLength ) ) ;
163+ return TypeDescriptionBuilder . OfType ( BasicTypes . String )
164+ . SetStringQualifiers ( new StringQualifiers ( length , allowedLength ) )
165+ . Build ( ) ;
173166 }
174167
175168 public static TypeDescription IntegerType ( int length = 10 ,
176- AllowedSignEnum allowedSign = AllowedSignEnum . Any )
169+ AllowedSignEnum allowedSign = AllowedSignEnum . Any )
177170 {
178- return TypeDescriptionBuilder . Build ( TypeNumber ( ) , new NumberQualifiers ( length , 0 , allowedSign ) ) ;
171+ return TypeDescriptionBuilder . OfType ( BasicTypes . Number )
172+ . SetNumberQualifiers ( new NumberQualifiers ( length , 0 , allowedSign ) )
173+ . Build ( ) ;
179174 }
180175
181176 public static TypeDescription BooleanType ( )
182177 {
183- return TypeDescriptionBuilder . Build ( TypeBoolean ( ) ) ;
178+ return TypeDescriptionBuilder . OfType ( BasicTypes . Boolean ) . Build ( ) ;
184179 }
185180
186181 [ ScriptConstructor ]
@@ -194,71 +189,156 @@ public static TypeDescription Constructor(
194189 IValue p6 = null ,
195190 IValue p7 = null )
196191 {
192+ var builder = new TypeDescriptionBuilder ( ) ;
193+
194+ // параметры, которые заведомо не квалификаторы, заменяем на null, но оставляем,
195+ // чтобы указать номер параметра при выводе ошибки несоответствия типа
196+ var qualifiers = new [ ] { null , p2 , p3 , p4 , p5 , p6 , p7 } ;
197+
197198 var rawSource = source ? . GetRawValue ( ) ;
198-
199199 if ( rawSource == null || rawSource . SystemType == BasicTypes . Undefined )
200200 {
201201 // пустой первый параметр - нет объекта-основания
202202 // добавляемые/вычитаемые типы не допускаются, квалификаторы игнорируются
203203
204204 // квалификакторы передаются только для контроля типов
205- return ConstructByQualifiers ( context . TypeManager , BslUndefinedValue . Instance , p2 , p3 , p4 , p5 , p6 , p7 ) ;
206205 }
207-
208- if ( rawSource is TypeDescription )
206+ else
207+ if ( rawSource is TypeDescription typeDesc )
209208 {
210- return ConstructByOtherDescription ( context . TypeManager , rawSource , p2 , p3 , p4 , p5 , p6 , p7 ) ;
211- }
209+ // Если 1 парарметр - ОписаниеТипов, то 2 - добавляемые типы, 3 - убираемые типы,
210+ builder . SourceDescription ( typeDesc ) ;
211+
212+ var typesToAdd = CheckAndParseTypeList ( context . TypeManager , p2 , 2 ) ;
213+ var typesToRemove = CheckAndParseTypeList ( context . TypeManager , p3 , 3 ) ;
214+
215+ builder . RemoveTypes ( typesToRemove ) ;
216+ builder . AddTypes ( typesToAdd ) ;
212217
218+ qualifiers [ 1 ] = null ; // эти параметры не квалификаторы
219+ qualifiers [ 2 ] = null ; // эти параметры не квалификаторы
220+
221+ }
222+ else
213223 if ( rawSource . SystemType == BasicTypes . String || rawSource is ArrayImpl )
214224 {
215- return ConstructByQualifiers ( context . TypeManager , rawSource , p2 , p3 , p4 , p5 , p6 , p7 ) ;
225+ // Если 1 парарметр - Массив или строка, то это набор конкретных типов
226+ // остальные параметры (2 и далее) - клвалификаторы в произвольном порядке
227+ var typesList = CheckAndParseTypeList ( context . TypeManager , rawSource , 1 ) ;
228+ builder . AddTypes ( typesList ) ;
229+ } else
230+ throw RuntimeException . InvalidArgumentValue ( ) ;
231+
232+ CheckAndAddQualifiers ( builder , qualifiers ) ;
233+ return builder . Build ( ) ;
234+ }
235+
236+ /// <summary>
237+ /// Преобразует входящий параметр в список типов.
238+ /// </summary>
239+ /// <param name="types">В качестве типов могут быть переданы Строка или Массив Типов</param>
240+ /// <param name="nParam">Номер параметра, который будет указан в исключении, если параметр typeList задан неверно</param>
241+ /// <exception cref="RuntimeException">Если typeList не может быть разобран как набор типов</exception>
242+ /// <returns>Список переданных типов, приведенный к конкретным TypeTypeValue</returns>
243+ private static List < BslTypeValue > CheckAndParseTypeList ( ITypeManager typeManager , IValue types , int nParam )
244+ {
245+ types = types ? . GetRawValue ( ) ;
246+ if ( types == null || types . SystemType == BasicTypes . Undefined )
247+ return new List < BslTypeValue > ( ) ;
248+
249+ if ( types . SystemType == BasicTypes . String )
250+ {
251+ return FromTypeNames ( typeManager , types . AsString ( ) ) ;
252+ }
253+ if ( types is ArrayImpl arrayOfTypes )
254+ {
255+ return FromArrayOfTypes ( arrayOfTypes ) ;
216256 }
217257
218- throw RuntimeException . InvalidArgumentValue ( ) ;
258+ throw RuntimeException . InvalidNthArgumentType ( nParam ) ;
219259 }
220260
221- private static TypeDescription ConstructByQualifiers ( ITypeManager typeManager , IValue types ,
222- IValue p2 = null ,
223- IValue p3 = null ,
224- IValue p4 = null ,
225- IValue p5 = null ,
226- IValue p6 = null ,
227- IValue p7 = null )
261+ private static List < BslTypeValue > FromTypeNames ( ITypeManager typeManager , string types )
228262 {
229- var builder = new TypeDescriptionBuilder ( ) ;
230- var typesList = TypeList . Construct ( typeManager , types , 1 ) ;
231- builder . AddTypes ( typesList . List ( ) ) ;
263+ var typeNames = types . Split ( ',' ) ;
264+ var typesList = new List < BslTypeValue > ( ) ;
265+ foreach ( var typeName in typeNames )
266+ {
267+ if ( string . IsNullOrWhiteSpace ( typeName ) )
268+ continue ;
232269
233- builder . AddQualifiers ( new [ ] { p2 , p3 , p4 , p5 , p6 , p7 } , 1 ) ;
270+ var typeValue = new BslTypeValue ( typeManager . GetTypeByName ( typeName . Trim ( ) ) ) ;
271+ if ( ! typesList . Contains ( typeValue ) )
272+ typesList . Add ( typeValue ) ;
273+ }
234274
235- return builder . Build ( ) ;
275+ return typesList ;
236276 }
237277
238- private static TypeDescription ConstructByOtherDescription ( ITypeManager typeManager ,
239- IValue typeDescription = null ,
240- IValue addTypes = null ,
241- IValue removeTypes = null ,
242- IValue p4 = null ,
243- IValue p5 = null ,
244- IValue p6 = null ,
245- IValue p7 = null )
278+ private static List < BslTypeValue > FromArrayOfTypes ( ArrayImpl arrayOfTypes )
246279 {
247- var builder = new TypeDescriptionBuilder ( ) ;
280+ var typesList = new List < BslTypeValue > ( ) ;
281+ foreach ( var type in arrayOfTypes )
282+ {
283+ if ( type . GetRawValue ( ) is BslTypeValue rawType )
284+ {
285+ typesList . Add ( rawType ) ;
286+ }
287+ }
288+ return typesList ;
289+ }
248290
249- if ( typeDescription is TypeDescription typeDesc )
291+ private static void CheckAndAddQualifiers ( TypeDescriptionBuilder builder , IValue [ ] parameters )
292+ {
293+ for ( var i = 0 ; i < parameters . Length ; i ++ )
250294 {
251- builder . SourceDescription ( typeDesc ) ;
295+ var rawQualifier = parameters [ i ] ? . GetRawValue ( ) ;
296+ if ( rawQualifier != null && ! rawQualifier . Equals ( ValueFactory . Create ( ) ) )
297+ {
298+ CheckAndAddOneQualifier ( builder , rawQualifier , i + 1 ) ;
299+ }
252300 }
253-
254- var removeTypesList = TypeList . Construct ( typeManager , removeTypes , 3 ) ;
255- builder . RemoveTypes ( removeTypesList . List ( ) ) ;
301+ }
256302
257- var addTypesList = TypeList . Construct ( typeManager , addTypes , 2 ) ;
258- builder . AddTypes ( addTypesList . List ( ) ) ;
259- builder . AddQualifiers ( new [ ] { p4 , p5 , p6 , p7 } , 3 ) ;
303+ /// <summary>
304+ /// Проверяет, что переданный параметр является квалификатором типа.
305+ /// Если тип параметра не является квалификатором, бросает исключение с указанием номера параметра.
306+ /// </summary>
307+ /// <param name="builder">Построитель описания типов, которому будет присвоен квалификатор</param>
308+ /// <param name="qualifier">Проверяемый входящий параметр</param>
309+ /// <param name="nParam">Порядковый номер параметра для выброса исключения</param>
310+ /// <exception cref="RuntimeException">Если qualifier не является квалификатором типа</exception>
311+ private static void CheckAndAddOneQualifier ( TypeDescriptionBuilder builder , IValue qualifier , int nParam )
312+ {
313+ switch ( qualifier )
314+ {
315+ case NumberQualifiers nq :
316+ builder . SetNumberQualifiers ( nq ) ;
317+ break ;
260318
261- return builder . Build ( ) ;
319+ case StringQualifiers sq :
320+ builder . SetStringQualifiers ( sq ) ;
321+ break ;
322+
323+ case DateQualifiers dq :
324+ builder . SetDateQualifiers ( dq ) ;
325+ break ;
326+
327+ case BinaryDataQualifiers bdq :
328+ builder . SetBinaryDataQualifiers ( bdq ) ;
329+ break ;
330+
331+ default :
332+ throw RuntimeException . InvalidNthArgumentType ( nParam ) ;
333+ }
334+ }
335+ }
336+
337+ internal class UndefinedTypeAdjuster : IValueAdjuster
338+ {
339+ public IValue Adjust ( IValue value )
340+ {
341+ return ValueFactory . Create ( ) ;
262342 }
263343 }
264344}
0 commit comments