public virtual object Execute(ExecutionInformation info, IReadOnlyList <ICommand> arguments, IReadOnlyList <Type> returnTypes) { string result; if (arguments.Count == 0) { if (returnTypes.Contains(typeof(ICommand))) { return(this); } result = string.Empty; } else { var comResult = arguments[0].Execute(info, Array.Empty <ICommand>(), CommandSystemTypes.ReturnString); result = ((IPrimitiveResult <string>)comResult).Get(); } var filter = info.GetFilter(); var commandResults = filter.Filter(commands, result).ToArray(); // The special case when the command is empty and only might match because of fuzzy matching. // We only allow this if the command explicitly allows an empty overload. if (string.IsNullOrEmpty(result) && (commandResults.Length == 0 || commandResults.Length > 1 || (commandResults.Length == 1 && !string.IsNullOrEmpty(commandResults[0].Key)))) { throw new CommandException(string.Format(strings.cmd_help_info_contains_subfunctions, SuggestionsJoinTrim(commands.Keys)), CommandExceptionReason.AmbiguousCall); } // We found too many matching commands if (commandResults.Length > 1) { throw new CommandException(string.Format(strings.cmd_help_error_ambiguous_command, SuggestionsJoinTrim(commandResults.Select(g => g.Key))), CommandExceptionReason.AmbiguousCall); } // We either found no matching command if (commandResults.Length == 0) { throw new CommandException(string.Format(strings.cmd_help_info_contains_subfunctions, SuggestionsJoinTrim(commands.Keys)), CommandExceptionReason.AmbiguousCall); } var argSubList = arguments.TrySegment(1); return(commandResults[0].Value.Execute(info, argSubList, returnTypes)); }
/// <summary> /// Try to fit the given arguments to the underlying function. /// This function will throw an exception if the parameters can't be applied. /// The parameters that are extracted from the arguments will be returned if they can be applied successfully. /// </summary> /// <param name="info">The current call <see cref="ExecutionInformation"/>.</param> /// <param name="arguments">The arguments that are applied to this function.</param> /// <param name="returnTypes">The possible return types.</param> /// <param name="takenArguments">How many arguments could be set.</param> private object[] FitArguments(ExecutionInformation info, IReadOnlyList <ICommand> arguments, IReadOnlyList <CommandResultType> returnTypes, out int takenArguments) { var parameters = new object[CommandParameter.Length]; var filterLazy = new Lazy <Algorithm.IFilter>(() => info.GetFilter(), false); // takenArguments: Index through arguments which have been moved into a parameter // p: Iterate through parameters takenArguments = 0; for (int p = 0; p < parameters.Length; p++) { var arg = CommandParameter[p].type; switch (CommandParameter[p].kind) { case ParamKind.SpecialArguments: parameters[p] = arguments; break; case ParamKind.SpecialReturns: parameters[p] = returnTypes; break; case ParamKind.Dependency: if (info.TryGet(arg, out var obj)) { parameters[p] = obj; } else if (CommandParameter[p].optional) { parameters[p] = null; } else { throw new MissingContextCommandException($"Command '{internCommand.Name}' missing execution context '{arg.Name}'", arg); } break; case ParamKind.NormalCommand: if (takenArguments >= arguments.Count) { parameters[p] = GetDefault(arg); break; } parameters[p] = arguments[takenArguments]; takenArguments++; break; case ParamKind.NormalParam: case ParamKind.NormalTailString: if (takenArguments >= arguments.Count) { parameters[p] = GetDefault(arg); break; } var argResultP = arguments[takenArguments].Execute(info, Array.Empty <ICommand>(), XCommandSystem.ReturnString); if (CommandParameter[p].kind == ParamKind.NormalTailString && argResultP is TailStringCommandResult tailString) { parameters[p] = tailString.TailString; } else { parameters[p] = ConvertParam(((StringCommandResult)argResultP).Content, arg, filterLazy.Value); } takenArguments++; break; case ParamKind.NormalArray: if (takenArguments >= arguments.Count) { parameters[p] = GetDefault(arg); break; } var typeArr = arg.GetElementType(); var args = Array.CreateInstance(typeArr, arguments.Count - takenArguments); for (int i = 0; i < args.Length; i++, takenArguments++) { var argResultA = ((StringCommandResult)arguments[takenArguments].Execute(info, Array.Empty <ICommand>(), XCommandSystem.ReturnString)).Content; var convResult = ConvertParam(argResultA, typeArr, filterLazy.Value); args.SetValue(convResult, i); } parameters[p] = args; break; default: throw Util.UnhandledDefault(CommandParameter[p].kind); } } // Check if we were able to set enough arguments int wantArgumentCount = Math.Min(parameters.Length, RequiredParameters); if (takenArguments < wantArgumentCount && !returnTypes.Contains(CommandResultType.Command)) { throw ThrowAtLeastNArguments(wantArgumentCount); } return(parameters); }