argparser/src/list-type.h
2023-05-17 10:17:56 +02:00

85 lines
3.2 KiB
C++

#ifndef ARGPARSER_LIST_TYPE_H
#define ARGPARSER_LIST_TYPE_H
#include "errors.h"
#include "type.h"
#include <memory>
#include <string>
#include <vector>
namespace argparser {
template<typename T>
class list_type : public type_impl<std::vector<T>> {
public:
list_type(std::string name, type_handle_impl<T> element_type) : type_impl<std::vector<T>>(std::move(name)), element_type(element_type) {}
std::vector<T> parse(const char *begin, const char *end, const char *&parse_end, internal::parser_allow_undelimited allow_undelimited) override {
auto cur_pos = begin;
std::vector<T> values{};
bool is_delimited;
if (*cur_pos == '[') {
is_delimited = true;
cur_pos++;
} else {
if (!internal::enum_flag_contains(allow_undelimited, internal::parser_allow_undelimited::Comma)) {
throw errors::type_parsing_error(this->name, std::string(begin, end), cur_pos - begin, "expected '['");
} else {
is_delimited = false;
}
}
if (cur_pos >= end) {
throw errors::type_parsing_error(this->name, std::string(begin, end), end - begin, "unexpected end of input");
}
internal::parser_allow_undelimited sub_parse_allow_undelimited = internal::parser_allow_undelimited::Parenthesis;
if (!is_delimited) {
sub_parse_allow_undelimited & allow_undelimited;
}
while (true) {
const char *this_parse_end;
auto val = element_type->parse(cur_pos, end, this_parse_end, sub_parse_allow_undelimited);
values.push_back(val);
cur_pos = this_parse_end;
while (std::isspace(*cur_pos) && cur_pos <= end)
cur_pos++;
if (cur_pos >= end) {
if (!is_delimited) {
break;
} else {
throw errors::type_parsing_error(this->name, std::string(begin, end), end - begin, "unexpected end of input");
}
}
if (*cur_pos == ',') {
cur_pos++;
auto s = std::string_view(cur_pos, end);
auto close_bracket_pos = s.find_first_of(']');
if (s.find_first_not_of(internal::whitespace) == close_bracket_pos) {
break;
}
} else if (!is_delimited || *cur_pos == ']') {
break;
} else {
throw errors::type_parsing_error(this->name, std::string(begin, end), end - begin, "expected , or ]");
}
}
if (is_delimited) {
if (*cur_pos != ']') {
throw errors::type_parsing_error(this->name, std::string(begin, end), end - begin, "unexpected end of input");
} else {
cur_pos++;
}
}
parse_end = cur_pos;
return values;
}
private:
type_handle_impl<T> element_type;
};
}// namespace argparser
#endif//ARGPARSER_LIST_TYPE_H