Files
integration/luprex/ext/slash-parser.hpp

115 lines
4.2 KiB
C++
Raw Normal View History

////////////////////////////////////////////////////////////////////////////////////
//
// A slash-command parser. The intended use is as follows:
//
// SlashCommandParser parser(Command);
//
// if parser.Parse("/command1", "syntax1") { ... handle command1 ... }
// else if parser.Parse("/command2", "syntax2") { ... handle command2 ... }
// else if parser.Parse("/command3", "syntax3") { ... handle command3 ... }
// else { ... print an error message ... }
//
////////////////////////////////////////////////////////////////////////////////////
#pragma once
#include <string>
#include <vector>
#include <string_view>
#include <map>
#include <cstdint>
class SlashCommandParser
{
public:
struct Value
{
std::string s_;
int64_t i_;
double d_;
Value(const std::string &s) : s_(s), i_(0), d_(0) {}
Value(int64_t i) : s_(), i_(i), d_(0) {}
Value(double d) : s_(), i_(0), d_(d) {}
};
std::vector<Value> args_;
private:
int cursor_;
std::string command_;
std::string line_;
int linelen_;
std::string error_;
static bool ascii_isupper(char c) { return (c >= 'A') && (c <= 'Z'); }
static bool ascii_islower(char c) { return (c >= 'a') && (c <= 'z'); }
static bool ascii_isdigit(char c) { return (c >= '0') && (c <= '9'); }
static bool ascii_isalpha(char c) { return ascii_isupper(c) || ascii_islower(c); }
static bool ascii_isalnum(char c) { return ascii_isalpha(c) || ascii_isdigit(c); }
static bool ascii_isspace(char c) { return (c==0)||(c==' ')||(c=='\t')||(c=='\r')||(c=='\n')||(c=='\f')||(c=='\v'); }
void skip_white();
std::string read_word();
public:
// Initialize the slash-command parser with the full command line.
//
// The command line is stored. The first keyword (the slash-command
// itself) is extracted and stored. If the command-line doesn't
// start with a slash-command, an error message is stored.
//
// After initializing the parser, you should call Parse once
// for every known command.
//
SlashCommandParser(std::string_view Line);
// Parse: Try to parse a slash-command.
//
// The intent is that you should call 'Parse' once for every
// known command. Hopefully, one of these 'Parse' commands
// will return true. If not, then the command couldn't be parsed.
//
// You must pass in the name of a slash-command (eg, "/compile")
// followed by the argument types that the command accepts.
//
// The argument types are represented as a string containing the
// characters i (for int64), s (for string), and d (for double).
// For example, if ArgTypes is "sid", then the command expects a
// string, then an int64, then a double.
//
// If the command matches, and the arguments parse correctly,
// returns true, stores the parsed arguments, and clears the
// stored error message.
//
// If the command matches, but the syntax is wrong, returns false
// and stores the error message.
//
// If the command doesn't match, returns false.
//
bool Parse(std::string_view Command, std::string_view ArgTypes);
// Error: Declare that parsing has failed, and get an error message.
//
// You call this if you tried calling Parse on every known command,
// and none of the Parse calls returned true. Returns an error
// message indicating what went wrong.
//
std::string Error() const;
// Get the Nth argument.
//
// After Parse returns true, the parsed arguments are stored in the
// SlashCommandParser. You can use these functions to fetch the
// parsed arguments.
//
// For example, if you call Parse("/hello", "sid") and it returns
// true, you should then call StringArg(0), then IntArg(1), then
// DoubleArg(2) to get all the arguments.
//
std::string StringArg(int n) const;
int64_t IntArg(int n) const;
double DoubleArg(int n) const;
};