/// <summary> /// Parses the specified content to a new <see cref="InfoContext"/>. /// </summary> public static InfoContext Parse(string content) { var ctx = new InfoContext(); Match m = new Regex(MAIN_PARSER).Match(content); ctx.Content = content; if (!m.Success) { ctx.ErrorReason = "The content specified failed to successfully parse."; return(ctx); } ctx.Modules = new Regex(MODULE_PARSER) .Matches(m.Groups[1].Value) .Where(x => x.Success) .Select(x => x.Groups[1].Value); ctx.Groups = new Regex(GROUP_PARSER) .Matches(m.Groups[2].Value) .Where(x => x.Success) .Select(x => x.Groups[1].Value); ctx.Root = m.Groups[2].Value + m.Groups[3].Value; ctx.HasPriority = m.Groups[4].Success; if (ctx.HasPriority) { ctx.Priority = int.TryParse(m.Groups[4].Value, out int index) ? index : 0; } ctx.Type = GetTypeValue(m.Groups[5].Value); // If an overload index is specified AND the type (if specified) is not a command if (ctx.Type.GetValueOrDefault(InfoType.Command) != InfoType.Command && m.Groups[4].Success) { ctx.ErrorReason = $"{ctx.Type?.ToString()}s do not support overload indexing."; return(ctx); } ctx.Parameter = m.Groups[6].Value; // If a parameter is specified AND the type (if specified) is not a command if (ctx.Type.GetValueOrDefault(InfoType.Command) != InfoType.Command && Check.NotNull(m.Groups[6].Value)) { ctx.ErrorReason = $"{ctx.Type.ToString()}s do not support parameters."; return(ctx); } ctx.Page = (int.TryParse(m.Groups[7].Value, out int page) ? page : 1) - 1; return(ctx); }
public ContextNode Search(string content) { InfoContext ctx = InfoContext.Parse(content); InfoType type = InfoType.Unknown; if (!ctx.IsSuccess) { throw new Exception($"The InfoContext failed to parse: {ctx.ErrorReason}"); } // Get the initial location of the parent to peek ModuleInfo module = GetInnerModule(ctx); ModuleInfo group = GetInnerGroup(ctx, module); IEnumerable <CommandInfo> commands = null; ParameterInfo parameter = null; // If a type wasn't initialized, find the closest matching value type = ctx.Type.GetValueOrDefault(GetValue(ctx.Root, group ?? module).Type); switch (type) { case InfoType.Module: module = GetModule(ctx.Root, group ?? module); break; case InfoType.Group: group = GetGroup(ctx.Root, group ?? module); break; case InfoType.Command: commands = GetCommands(ctx.Root, group ?? module); break; } if (type == InfoType.Command) { if (!Check.NotNullOrEmpty(commands)) { throw new ValueNotFoundException($"No commands could be found that matched the name '{ctx.Root}'."); } // If a priority was specified, slim the search down to that specific command if (ctx.HasPriority) { commands = commands.Where(x => x.Priority == ctx.Priority); if (!Check.NotNullOrEmpty(commands)) { throw new ValueNotFoundException($"The priority for the specified command does not exist."); } if (commands.Count() > 1) { throw new MultiMatchException("The priority for the specified command exists in more than one instance."); } type = InfoType.Overload; } // If a parameter was specified, attempt to find the best match possible if (Check.NotNull(ctx.Parameter)) { IEnumerable <ParameterInfo> parameters = new List <ParameterInfo>(); commands.ForEach(x => parameters = parameters.Concat(GetParameters(x, ctx.Parameter))); if (!Check.NotNullOrEmpty(parameters)) { throw new ValueNotFoundException("The parameter specified could not be found within any of the commands"); } if (parameters.Count() > 1) { throw new MultiMatchException($"The parameter enlisted is specified for multiple commands."); } parameter = parameters.First(); type = InfoType.Parameter; } } // Return the node value based on the finalized type that was found or given return(type switch { InfoType.Module => new ModuleNode(module), InfoType.Group => new ModuleNode(group), InfoType.Overload => new OverloadNode(commands.First()), InfoType.Command => new CommandNode(commands), InfoType.Parameter => new ParameterNode(parameter), _ => throw new ValueNotFoundException("A ContextNode value could not be created with the given context.") });