172 lines
4.5 KiB
C++
172 lines
4.5 KiB
C++
#pragma once
|
|
|
|
#include <functional>
|
|
#include <string>
|
|
#include <unordered_map>
|
|
#include <vector>
|
|
|
|
#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 "<unknown>";
|
|
}
|
|
}
|
|
|
|
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<dv::value(
|
|
CommandsInterpreter*, const dv::value& args, const dv::value& 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;
|
|
}
|
|
|
|
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<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;
|
|
}
|
|
|
|
void clear() {
|
|
commands.clear();
|
|
}
|
|
};
|
|
|
|
class CommandsInterpreter {
|
|
std::unique_ptr<CommandsRepository> repository;
|
|
std::unordered_map<std::string, dv::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);
|
|
|
|
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();
|
|
}
|
|
};
|
|
}
|