using System.Diagnostics;
using static Towel.Syntax;
namespace ConsoleCoreSandbox
static CommandLine.Argument Version;
static CommandLine.Argument Help;
static CommandLine.Argument<string> A = "default";
static CommandLine.Argument<int> B = 7;
static CommandLine.Argument<float> C = 8.5f;
static CommandLine.Argument<string> D;
if (Version.Exists || Help.Exists)
Console.WriteLine(CommandLine.GetDefaultInfoString);
Console.WriteLine(" Summary: TODO");
Console.WriteLine(" Documentation: TODO");
Console.WriteLine(" Contact(s): TODO");
Console.WriteLine(B + 1);
Console.WriteLine(C + 1.5);
Console.WriteLine(D.HasValue ? D.Value : nameof(D) + ": " + D.Status);
#region Towel Definitions
public static class CommandLine
internal static string[] Args = Environment.GetCommandLineArgs();
public static string GetDefaultInfoString
StringBuilder stringBuilder = new StringBuilder();
Assembly entryAssembly = Assembly.GetEntryAssembly();
AssemblyName assemblyName = entryAssembly.GetName();
stringBuilder.Append(" Name: ");
stringBuilder.AppendLine(assemblyName.Name);
stringBuilder.Append(" Version: ");
stringBuilder.AppendLine(assemblyName.Version.ToString());
stringBuilder.Append(" Command Line Arguments:");
MethodInfo entryMethod = entryAssembly.EntryPoint;
Type entryType = entryMethod.DeclaringType;
FieldInfo[] fieldInfos = entryType.GetFields(
bool hasCommandLineArguments = false;
for (int i = 0; i < fieldInfos.Length; i++)
FieldInfo field = fieldInfos[i];
object fieldValue = field.GetValue(null);
if (fieldValue is IGenericArgument genericArgument)
hasCommandLineArguments = true;
stringBuilder.AppendLine();
stringBuilder.Append(" ");
stringBuilder.Append(field.Name);
stringBuilder.AppendLine(":");
stringBuilder.Append(" Type: ");
stringBuilder.Append(genericArgument.Type.Name);
if (genericArgument.HasDefaultValue)
stringBuilder.AppendLine();
stringBuilder.Append(" Default: ");
stringBuilder.Append(genericArgument.DefaultValueString);
else if (fieldValue is Argument)
hasCommandLineArguments = true;
stringBuilder.AppendLine();
stringBuilder.Append(" ");
stringBuilder.Append(field.Name);
if (!hasCommandLineArguments)
stringBuilder.Append(" None");
string result = stringBuilder.ToString();
public enum ArgumentStatus
internal ArgumentStatus _status;
return _data._status is ArgumentStatus.ValueProvided;
public ArgumentStatus Status
if (!(_data._status is ArgumentStatus.Null))
Assembly entryAssembly = Assembly.GetEntryAssembly();
MethodInfo entryMethod = entryAssembly.EntryPoint;
Type entryType = entryMethod.DeclaringType;
FieldInfo[] fieldInfos = entryType.GetFields(
foreach (FieldInfo field in fieldInfos)
if (field.GetValue(null) is Argument argumentT)
if (argumentT._data is null || !(argumentT._data._status is ArgumentStatus.Null))
if (argumentT._data == _data)
string name = field.Name;
for (int i = 0; i < Args.Length; i++)
_data._status = ArgumentStatus.DuplicateProvided;
_data._status = ArgumentStatus.NotProvided;
_data._status = ArgumentStatus.ValueProvided;
_data._status = ArgumentStatus.SyntaxError;
internal interface IGenericArgument
bool HasDefaultValue { get; }
string DefaultValueString { get; }
public struct Argument<T> : IGenericArgument
internal ArgumentStatus _status;
internal T _defaultValue;
internal bool _hasDefault;
return _data._status is ArgumentStatus.ValueProvided || _data._status is ArgumentStatus.Default
: throw new InvalidOperationException("Attempted to get a command line argument with a status of " + _data._status + ".");
public bool HasDefaultValue
return _data._hasDefault;
: throw new InvalidOperationException("Attempted to get the default value of a command line argument with no default value.");
public string DefaultValueString
? _data._defaultValue.ToString()
: throw new InvalidOperationException("Attempted to get the default value string of a command line argument with no default value.");
return _data._status is ArgumentStatus.ValueProvided || _data._status is ArgumentStatus.Default;
public ArgumentStatus Status
public Type Type => typeof(T);
if (!(_data._status is ArgumentStatus.Null))
Assembly entryAssembly = Assembly.GetEntryAssembly();
MethodInfo entryMethod = entryAssembly.EntryPoint;
Type entryType = entryMethod.DeclaringType;
FieldInfo[] fieldInfos = entryType.GetFields(
foreach (FieldInfo field in fieldInfos)
if (field.GetValue(null) is Argument<T> argumentT)
if (argumentT._data is null || !(argumentT._data._status is ArgumentStatus.Null))
if (argumentT._data == _data)
string name = field.Name + ":";
for (int i = 0; i < Args.Length; i++)
_data._status = ArgumentStatus.DuplicateProvided;
_data._status = ArgumentStatus.Default;
_data._status = ArgumentStatus.NotProvided;
else if (index == Args.Length - 1)
_data._status = ArgumentStatus.NotProvided;
else if (typeof(T) == typeof(string))
Argument<string>.Data data_string = _data as Argument<string>.Data;
data_string._value = Args[index + 1];
_data._status = ArgumentStatus.ValueProvided;
else if (TryParse(Args[index + 1], out _data._value))
_data._status = ArgumentStatus.ValueProvided;
_data._status = ArgumentStatus.ParseFailed;
_data._status = ArgumentStatus.SyntaxError;
public static implicit operator T(Argument<T> argument) => argument.Value;
public static implicit operator Argument<T>(T value) =>
public static MethodInfo GetTryParseMethod<A>() => GetTryParseMethodCache<A>.Value;
public static MethodInfo GetTryParseMethod(Type a)
_ = a ?? throw new ArgumentNullException(nameof(a));
MethodInfo methodInfo = a.GetMethod("TryParse",
new Type[] { typeof(string), a.MakeByRefType() },
return !(methodInfo is null)
&& methodInfo.ReturnType == typeof(bool)
internal static class GetTryParseMethodCache<A>
internal static readonly MethodInfo Value = GetTryParseMethod(typeof(A));
public static class Syntax
public static A TryParse<A>(string @string, A Default = default) =>
TryParse(@string, out A value)
public static bool TryParse<A>(string @string, out A value) =>
TryParseImplementation<A>.Function(@string, out value);
internal static class TryParseImplementation<A>
internal static TryParse<A> Function = (string @string, out A value) =>
static bool Default(string @string, out A value)
MethodInfo methodInfo = Meta.GetTryParseMethod<A>();
Function = methodInfo is null
: (TryParse<A>)methodInfo.CreateDelegate(typeof(TryParse<A>));
return Function(@string, out value);
public delegate bool TryParse<T>(string @string, out T value);