using System.Collections; using System.ComponentModel; using System.Reflection; namespace Nerfed.Builder; public class ArgsParser where TArgs : new() { private enum ArgType { None, Key, Value } public TArgs Arguments { get; } private readonly string[] args; private readonly Dictionary argKeyPropertyMap = new Dictionary(); public ArgsParser(string[] args) { this.args = args; Arguments = new TArgs(); PropertyInfo[] properties = Arguments.GetType().GetProperties(BindingFlags.Instance | BindingFlags.Public); foreach (PropertyInfo property in properties) { ArgumentAttribute argAttribute = property.GetCustomAttribute(); if (argAttribute == null || string.IsNullOrEmpty(argAttribute.ArgKey)) { continue; } argKeyPropertyMap.Add(argAttribute.ArgKey, property); } } public bool Parse() { PropertyInfo property = null; ArgType lastArgType = ArgType.None; for (int i = 0; i < args.Length; i++) { string arg = args[i]; if (arg[0] == '-') { if (!argKeyPropertyMap.TryGetValue(arg, out property)) { Console.Error.WriteLine($"Invalid argument: {arg}, no such argument key exists"); return false; } // Boolean arguments require no value, set to true immidiately. if (property.PropertyType == typeof(bool)) { property.SetValue(Arguments, true); lastArgType = ArgType.Value; } else { lastArgType = ArgType.Key; } } else { if (lastArgType == ArgType.None) { Console.Error.WriteLine($"Invalid argument: {arg}, no argument key was provided"); return false; } Type propertyType = property.PropertyType; if (propertyType.IsArray) { throw new InvalidOperationException("Arrays are not supported, use List instead"); } bool propertyTypeIsList = propertyType.IsGenericType && propertyType.GetGenericTypeDefinition() == typeof(List<>); if (propertyTypeIsList) { propertyType = propertyType.GenericTypeArguments[0]; } TypeConverter typeConverter = TypeDescriptor.GetConverter(propertyType); object value = typeConverter.ConvertFromString(arg); if (value is string stringValue) { if (!string.IsNullOrEmpty(stringValue)) { if (stringValue[0] == '"') { stringValue = stringValue.Substring(1, stringValue.Length - 1); } if (stringValue[^1] == '"') { stringValue = stringValue.Substring(0, stringValue.Length - 1); } value = stringValue; } } if (propertyTypeIsList) { IList list = (IList)property.GetValue(Arguments); if (list == null) { list = (IList)Activator.CreateInstance(property.PropertyType); property.SetValue(Arguments, list); } list.Add(value); } else { property.SetValue(Arguments, value); } lastArgType = ArgType.Value; } } return true; } }