First version of new slash-command parser.
This commit is contained in:
150
luprex/ext/slash-parser.cpp
Normal file
150
luprex/ext/slash-parser.cpp
Normal file
@@ -0,0 +1,150 @@
|
||||
#pragma once
|
||||
|
||||
#ifndef DONT_INCLUDE_SLASH_PARSER_HPP
|
||||
#include "slash-parser.hpp"
|
||||
#endif
|
||||
#include <charconv>
|
||||
|
||||
|
||||
|
||||
void SlashCommandParser::skip_white()
|
||||
{
|
||||
while ((cursor_ < linelen_) && (ascii_isspace(line_[cursor_])))
|
||||
{
|
||||
cursor_++;
|
||||
}
|
||||
}
|
||||
|
||||
std::string SlashCommandParser::read_word()
|
||||
{
|
||||
int start = cursor_;
|
||||
while ((cursor_ < linelen_) && (!ascii_isspace(line_[cursor_])))
|
||||
{
|
||||
cursor_++;
|
||||
}
|
||||
std::string result = line_.substr(start, cursor_ - start);
|
||||
skip_white();
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
SlashCommandParser::SlashCommandParser(std::string_view Line)
|
||||
{
|
||||
line_ = Line;
|
||||
linelen_ = int(Line.size());
|
||||
cursor_ = 0;
|
||||
command_ = read_word();
|
||||
if ((command_.size() < 2) || (command_[0] != '/'))
|
||||
{
|
||||
error_ = "Not a slash-command";
|
||||
return;
|
||||
}
|
||||
if (!ascii_isalpha(command_[1]))
|
||||
{
|
||||
error_ = "Slash command must start with ascii alpha";
|
||||
return;
|
||||
}
|
||||
for (int i = 1; i < int(command_.size()); i++)
|
||||
{
|
||||
if (!ascii_isalnum(command_[i]))
|
||||
{
|
||||
error_ = "Slash-command must be alphanumeric";
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
bool SlashCommandParser::Parse(std::string_view Command, std::string_view ArgTypes)
|
||||
{
|
||||
if (Command != std::string_view(command_)) return false;
|
||||
|
||||
args_.clear();
|
||||
for (int i = 0; i < int(ArgTypes.size()); i++)
|
||||
{
|
||||
switch(ArgTypes[i])
|
||||
{
|
||||
case 's':
|
||||
{
|
||||
std::string word = read_word();
|
||||
if (word.empty())
|
||||
{
|
||||
error_ = "Expected string arg";
|
||||
return false;
|
||||
}
|
||||
args_.emplace_back(word);
|
||||
break;
|
||||
}
|
||||
case 'i':
|
||||
{
|
||||
std::string word = read_word();
|
||||
const char *p = word.c_str();
|
||||
const char *last = p + word.size();
|
||||
if ((p < last) && (*p == '+')) p++;
|
||||
int64_t result;
|
||||
auto r = std::from_chars(p, last, result, 10);
|
||||
if ((r.ec != std::errc()) || (r.ptr != last)) {
|
||||
error_ = "Expected int arg";
|
||||
return false;
|
||||
}
|
||||
args_.emplace_back(result);
|
||||
break;
|
||||
}
|
||||
case 'd':
|
||||
{
|
||||
error_ = "Double args not implemented yet.";
|
||||
break;
|
||||
}
|
||||
default:
|
||||
{
|
||||
error_ = "Invalid argtypes ";
|
||||
error_ += ArgTypes;
|
||||
error_ += " parsing ";
|
||||
error_ += Command;
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (cursor_ != linelen_)
|
||||
{
|
||||
error_ = "Too many arguments for command: ";
|
||||
error_ += Command;
|
||||
return false;
|
||||
}
|
||||
|
||||
error_.clear();
|
||||
return true;
|
||||
}
|
||||
|
||||
std::string SlashCommandParser::Error() const
|
||||
{
|
||||
if (!error_.empty())
|
||||
{
|
||||
return error_;
|
||||
}
|
||||
else
|
||||
{
|
||||
return std::string("Unrecognized command: ") + command_;
|
||||
}
|
||||
}
|
||||
|
||||
std::string SlashCommandParser::StringArg(int n) const
|
||||
{
|
||||
if ((n < 0) || (n >= int(args_.size()))) return "";
|
||||
|
||||
return args_[n].s_;
|
||||
}
|
||||
|
||||
int64_t SlashCommandParser::IntArg(int n) const
|
||||
{
|
||||
if ((n < 0) || (n >= int(args_.size()))) return 0;
|
||||
|
||||
return args_[n].i_;
|
||||
}
|
||||
|
||||
double SlashCommandParser::DoubleArg(int n) const
|
||||
{
|
||||
if ((n < 0) || (n >= int(args_.size()))) return 0.0;
|
||||
|
||||
return args_[n].d_;
|
||||
}
|
||||
Reference in New Issue
Block a user