#pragma once #include #include #include #include #include "data/dv.hpp" namespace cmd { enum class ArgType { number, integer, enumvalue, selector, boolean, string }; inline std::string argtype_name(ArgType type) { switch (type) { case ArgType::number: return "number"; case ArgType::integer: return "integer"; case ArgType::enumvalue: return "enumeration"; case ArgType::selector: return "selector"; case ArgType::boolean: return "boolean"; case ArgType::string: return "string"; default: return ""; } } struct Argument { std::string name; ArgType type; bool optional; dv::value def; dv::value origin; std::string enumname; }; class Command; class CommandsInterpreter; struct Prompt { Command* command; dv::value args; // positional arguments list dv::value kwargs; // keyword arguments table }; using executor_func = std::function; class Command { std::string name; std::vector args; std::unordered_map kwargs; std::string description; executor_func executor; public: Command() = default; Command( std::string name, std::vector args, std::unordered_map kwargs, std::string description, executor_func executor ) : name(name), args(std::move(args)), kwargs(std::move(kwargs)), description(description), executor(executor) { } Argument* getArgument(size_t index) { if (index >= args.size()) return nullptr; return &args[index]; } Argument* getArgument(const std::string& keyword) { auto found = kwargs.find(keyword); if (found == kwargs.end()) { return nullptr; } return &found->second; } dv::value execute( CommandsInterpreter* interpreter, const Prompt& prompt ) { return executor(interpreter, prompt.args, prompt.kwargs); } const std::string& getName() const { return name; } const std::vector& getArgs() const { return args; } const std::unordered_map& getKwArgs() const { return kwargs; } const std::string& getDescription() const { return description; } static Command create( std::string_view scheme, std::string_view description, executor_func ); }; class CommandsRepository { std::unordered_map commands; public: void add( std::string_view scheme, std::string_view description, executor_func ); Command* get(const std::string& name); const std::unordered_map& getCommands() const { return commands; } void clear() { commands.clear(); } }; class CommandsInterpreter { std::unique_ptr repository; std::unordered_map variables; public: CommandsInterpreter() : repository(std::make_unique()) { } CommandsInterpreter(const CommandsInterpreter&) = delete; CommandsInterpreter(std::unique_ptr repository) : repository(std::move(repository)) { } Prompt parse(std::string_view text); dv::value execute(std::string_view input) { return execute(parse(input)); } dv::value execute(const Prompt& prompt) { return prompt.command->execute(this, prompt); } dv::value& operator[](const std::string& name) { return variables[name]; } CommandsRepository* getRepository() const { return repository.get(); } void reset() { repository->clear(); variables.clear(); } }; }