VoxelEngine/src/logic/CommandsInterpreter.hpp
Vyacheslav Ivanov 5dd7a15c09
fix: optimization: PVS-Studio warning V832
It's better to use '= default;' syntax instead of empty constructor and destructor body.
Using '= default;' can help the compiler generate more optimal code.

Reported by: PVS-Studio

Signed-off-by: Vyacheslav Ivanov <islavaivanov76@gmail.com>
2024-08-02 01:57:43 +03:00

160 lines
4.3 KiB
C++

#ifndef LOGIC_COMMANDS_INTERPRETER_HPP_
#define LOGIC_COMMANDS_INTERPRETER_HPP_
#include "../data/dynamic.hpp"
#include <string>
#include <vector>
#include <functional>
#include <unordered_map>
namespace cmd {
enum class ArgType {
number, integer, enumvalue, selector, 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::string: return "string";
default: return "<unknown>";
}
}
struct Argument {
std::string name;
ArgType type;
bool optional;
dynamic::Value def;
dynamic::Value origin;
std::string enumname;
};
class Command;
class CommandsInterpreter;
struct Prompt {
Command* command;
dynamic::List_sptr args; // positional arguments list
dynamic::Map_sptr kwargs; // keyword arguments table
};
using executor_func = std::function<dynamic::Value(
CommandsInterpreter*,
dynamic::List_sptr args,
dynamic::Map_sptr kwargs
)>;
class Command {
std::string name;
std::vector<Argument> args;
std::unordered_map<std::string, Argument> kwargs;
std::string description;
executor_func executor;
public:
Command() = default;
Command(
std::string name,
std::vector<Argument> args,
std::unordered_map<std::string, Argument> 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;
}
dynamic::Value execute(CommandsInterpreter* interpreter, const Prompt& prompt) {
return executor(interpreter, prompt.args, prompt.kwargs);
}
const std::string& getName() const {
return name;
}
const std::vector<Argument>& getArgs() const {
return args;
}
const std::unordered_map<std::string, Argument>& 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<std::string, Command> commands;
public:
void add(
std::string_view scheme,
std::string_view description,
executor_func
);
Command* get(const std::string& name);
const std::unordered_map<std::string, Command>& getCommands() const {
return commands;
}
};
class CommandsInterpreter {
std::unique_ptr<CommandsRepository> repository;
std::unordered_map<std::string, dynamic::Value> variables;
public:
CommandsInterpreter() : repository(std::make_unique<CommandsRepository>()) {}
CommandsInterpreter(const CommandsInterpreter&) = delete;
CommandsInterpreter(std::unique_ptr<CommandsRepository> repository)
: repository(std::move(repository)){}
Prompt parse(std::string_view text);
dynamic::Value execute(std::string_view input) {
return execute(parse(input));
}
dynamic::Value execute(const Prompt& prompt) {
return prompt.command->execute(this, prompt);
}
dynamic::Value& operator[](const std::string& name) {
return variables[name];
}
CommandsRepository* getRepository() const {
return repository.get();
}
};
}
#endif // LOGIC_COMMANDS_INTERPRETER_HPP_