Beispiel #1
0
        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);
        }