diff --git a/src/logic/CommandsInterpreter.cpp b/src/logic/CommandsInterpreter.cpp index 8e157d69..8c773445 100644 --- a/src/logic/CommandsInterpreter.cpp +++ b/src/logic/CommandsInterpreter.cpp @@ -87,7 +87,7 @@ public: if (peek() == ']') { throw error("empty enumeration is not allowed"); } - auto enumvalue = std::string(readUntil(']')); + auto enumvalue = "|"+std::string(readUntil(']'))+"|"; size_t offset = enumvalue.find(' '); if (offset != std::string::npos) { goBack(enumvalue.length()-offset); @@ -157,22 +157,64 @@ public: return Command(name, std::move(args), std::move(kwargs), executor); } - CommandInput parsePrompt() { + bool typeCheck(Argument* arg, const dynamic::Value& value) { + switch (arg->type) { + case ArgType::enumvalue: { + auto& enumname = arg->enumname; + if (auto* string = std::get_if(&value)) { + if (enumname.find("|"+*string+"|") == std::string::npos) { + throw error("invalid enumeration value"); + } + } else { + if (arg->optional) { + return false; + } + throw error("enumeration value expected"); + } + break; + } + case ArgType::number: { + // FIXME + } + } + return true; + } + + Prompt parsePrompt(CommandsRepository* repo) { std::string name = parseIdentifier(); + auto command = repo->get(name); + if (command == nullptr) { + throw error("unknown command "+util::quote(name)); + } auto args = dynamic::create_list(); auto kwargs = dynamic::create_map(); + int arg_index = 0; + while (hasNext()) { auto value = parseValue(); if (hasNext() && peek() == '=') { auto key = std::get(value); nextChar(); kwargs->put(key, parseValue()); + } else { + Argument* arg; + do { + arg = command->getArgument(arg_index++); + if (arg == nullptr) { + throw error("extra positional argument"); + } + } while (!typeCheck(arg, value)); + args->put(value); } - args->put(value); } - return CommandInput {name, args, kwargs}; + while (auto arg = command->getArgument(arg_index++)) { + if (!arg->optional) { + throw error("missing argument "+util::quote(arg->name)); + } + } + return Prompt {command, args, kwargs}; } }; @@ -193,6 +235,6 @@ Command* CommandsRepository::get(const std::string& name) { return &found->second; } -CommandInput CommandsInterpreter::parse(std::string_view text) { - return CommandParser("", text).parsePrompt(); +Prompt CommandsInterpreter::parse(std::string_view text) { + return CommandParser("", text).parsePrompt(repository.get()); } diff --git a/src/logic/CommandsInterpreter.hpp b/src/logic/CommandsInterpreter.hpp index 7bc80dd6..140c9ac2 100644 --- a/src/logic/CommandsInterpreter.hpp +++ b/src/logic/CommandsInterpreter.hpp @@ -22,8 +22,10 @@ namespace cmd { std::string enumname; }; - struct CommandInput { - std::string name; // command name + class Command; + + struct Prompt { + Command* command; dynamic::List_sptr args; // positional arguments list dynamic::Map_sptr kwargs; // keyword arguments table }; @@ -50,9 +52,15 @@ namespace cmd { args(std::move(args)), kwargs(std::move(kwargs)), executor(executor) {} + + Argument* getArgument(size_t index) { + if (index >= args.size()) + return nullptr; + return &args[index]; + } - dynamic::Value execute(const CommandInput& input) { - return executor(input.args, input.kwargs); + dynamic::Value execute(const Prompt& prompt) { + return executor(prompt.args, prompt.kwargs); } const std::string& getName() const { @@ -75,7 +83,11 @@ namespace cmd { CommandsInterpreter(std::unique_ptr repository) : repository(std::move(repository)){} - CommandInput parse(std::string_view text); + Prompt parse(std::string_view text); + + CommandsRepository* getRepository() const { + return repository.get(); + } }; }