33using System . Globalization ;
44using System . Linq ;
55using System . Reflection ;
6+ using NClap . Metadata ;
67using NClap . Utilities ;
78
89namespace NClap . Types
@@ -12,15 +13,15 @@ namespace NClap.Types
1213 /// </summary>
1314 internal class EnumArgumentType : ArgumentTypeBase , IEnumArgumentType
1415 {
15- private readonly Dictionary < string , EnumArgumentValue > _valuesByCaseSensitiveName =
16- new Dictionary < string , EnumArgumentValue > ( StringComparer . Ordinal ) ;
16+ private readonly Dictionary < string , IArgumentValue > _valuesByCaseSensitiveName =
17+ new Dictionary < string , IArgumentValue > ( StringComparer . Ordinal ) ;
1718
18- private readonly Dictionary < string , EnumArgumentValue > _valuesByCaseInsensitiveName =
19- new Dictionary < string , EnumArgumentValue > ( StringComparer . OrdinalIgnoreCase ) ;
19+ private readonly Dictionary < string , IArgumentValue > _valuesByCaseInsensitiveName =
20+ new Dictionary < string , IArgumentValue > ( StringComparer . OrdinalIgnoreCase ) ;
2021
21- private readonly Dictionary < object , EnumArgumentValue > _valuesByValue = new Dictionary < object , EnumArgumentValue > ( ) ;
22+ private readonly Dictionary < object , IArgumentValue > _valuesByValue = new Dictionary < object , IArgumentValue > ( ) ;
2223
23- private readonly List < EnumArgumentValue > _values = new List < EnumArgumentValue > ( ) ;
24+ private readonly List < IArgumentValue > _values = new List < IArgumentValue > ( ) ;
2425
2526 /// <summary>
2627 /// Constructs an object to describe an empty enumeration type. Values must be
@@ -49,7 +50,20 @@ protected EnumArgumentType(Type type) : base(type)
4950 public static EnumArgumentType Create ( Type type )
5051 {
5152 var flagsAttrib = type . GetTypeInfo ( ) . GetSingleAttribute < FlagsAttribute > ( ) ;
52- return ( flagsAttrib != null ) ? new FlagsEnumArgumentType ( type ) : new EnumArgumentType ( type ) ;
53+ var argType = ( flagsAttrib != null ) ? new FlagsEnumArgumentType ( type ) : new EnumArgumentType ( type ) ;
54+
55+ var extensibleAttribs = type . GetTypeInfo ( ) . GetAttributes < ExtensibleEnumAttribute > ( ) . ToList ( ) ;
56+ if ( extensibleAttribs . Count > 0 )
57+ {
58+ var types = extensibleAttribs . Select ( a => a . Provider )
59+ . Where ( p => p != null )
60+ . Select ( ConstructEnumArgumentTypeProviderFromType )
61+ . SelectMany ( p => p . GetTypes ( ) ) ;
62+
63+ argType = new MergedEnumArgumentType ( new [ ] { argType } . Concat ( types ) ) ;
64+ }
65+
66+ return argType ;
5367 }
5468
5569 /// <summary>
@@ -64,7 +78,7 @@ public override string Format(object value)
6478 {
6579 if ( value == null ) throw new ArgumentNullException ( nameof ( value ) ) ;
6680
67- if ( _valuesByValue . TryGetValue ( value , out EnumArgumentValue enumValue ) )
81+ if ( _valuesByValue . TryGetValue ( value , out IArgumentValue enumValue ) )
6882 {
6983 return enumValue . DisplayName ;
7084 }
@@ -102,7 +116,7 @@ protected override object Parse(ArgumentParseContext context, string stringToPar
102116 var map = context . CaseSensitive ? _valuesByCaseSensitiveName : _valuesByCaseInsensitiveName ;
103117
104118 // First try looking up the string in our name map.
105- if ( ! map . TryGetValue ( stringToParse , out EnumArgumentValue value ) )
119+ if ( ! map . TryGetValue ( stringToParse , out IArgumentValue value ) )
106120 {
107121 // We might have more options if it's an enum type, but if it's not--there's
108122 // nothing else we can do.
@@ -145,7 +159,7 @@ protected override object Parse(ArgumentParseContext context, string stringToPar
145159 /// <returns>true on success; false otherwise.</returns>
146160 public bool TryGetValue ( object value , out IArgumentValue argValue )
147161 {
148- if ( ! _valuesByValue . TryGetValue ( value , out EnumArgumentValue enumArgValue ) )
162+ if ( ! _valuesByValue . TryGetValue ( value , out IArgumentValue enumArgValue ) )
149163 {
150164 argValue = null ;
151165 return false ;
@@ -159,7 +173,7 @@ public bool TryGetValue(object value, out IArgumentValue argValue)
159173 /// Defines a new value in this type.
160174 /// </summary>
161175 /// <param name="value">Value to define.</param>
162- protected void AddValue ( EnumArgumentValue value )
176+ protected void AddValue ( IArgumentValue value )
163177 {
164178 _values . Add ( value ) ;
165179 AddToValueNameMap ( _valuesByCaseSensitiveName , value ) ;
@@ -184,10 +198,22 @@ protected void AddValuesFromType(Type type)
184198 }
185199 }
186200
187- private static IEnumerable < EnumArgumentValue > GetAllValues ( Type type ) =>
201+ /// <summary>
202+ /// Defines all values in the given type.
203+ /// </summary>
204+ /// <param name="type">Type to inspect.</param>
205+ protected void AddValuesFromType ( IEnumArgumentType type )
206+ {
207+ foreach ( var value in type . GetValues ( ) )
208+ {
209+ AddValue ( value ) ;
210+ }
211+ }
212+
213+ private static IEnumerable < IArgumentValue > GetAllValues ( Type type ) =>
188214 type . GetTypeInfo ( ) . GetFields ( BindingFlags . Public | BindingFlags . Static ) . Select ( f => new EnumArgumentValue ( f ) ) ;
189215
190- private static void AddToValueMap ( Dictionary < object , EnumArgumentValue > map , EnumArgumentValue value )
216+ private static void AddToValueMap ( Dictionary < object , IArgumentValue > map , IArgumentValue value )
191217 {
192218 // We do our best to add each value to the map; but if there
193219 // are multiple members that share a value, then the first
@@ -204,7 +230,7 @@ private static void AddToValueMap(Dictionary<object, EnumArgumentValue> map, Enu
204230 /// </summary>
205231 /// <param name="map">Map to add to.</param>
206232 /// <param name="value">The value to add.</param>
207- private static void AddToValueNameMap ( Dictionary < string , EnumArgumentValue > map , EnumArgumentValue value )
233+ private static void AddToValueNameMap ( Dictionary < string , IArgumentValue > map , IArgumentValue value )
208234 {
209235 // We skip disallowed values.
210236 if ( value . Disallowed ) return ;
@@ -229,5 +255,10 @@ private static void AddToValueNameMap(Dictionary<string, EnumArgumentValue> map,
229255 map [ value . ShortName ] = value ;
230256 }
231257 }
258+
259+ private static IEnumArgumentTypeProvider ConstructEnumArgumentTypeProviderFromType ( Type type )
260+ {
261+ return ( IEnumArgumentTypeProvider ) type . GetParameterlessConstructor ( ) . Invoke ( Array . Empty < object > ( ) ) ;
262+ }
232263 }
233264}
0 commit comments