#ifndef ARGPARSER_BUILTIN_PARSER_H #define ARGPARSER_BUILTIN_PARSER_H #include "defs.h" #include "errors.h" #include "parser_func.h" #include #include #include namespace argparser::internal { template class automatic_parser { public: static parser_func make_parser(const std::string &name) { return [name](const char *begin, const char *end, const char *&parse_end, internal::parser_allow_undelimited) { T val; auto pos = begin; while (pos < end && isspace(*pos)) pos++; auto res = std::from_chars(pos, end, val); if (res.ec == std::errc{}) { parse_end = res.ptr; return val; } else { throw errors::type_parsing_error(name, std::string(begin, end), pos - begin, "invalid number"); } }; } }; constexpr parse_opt string_parse_opt_with_default(parse_opt opt) { if ((opt & parse_opt::AnyString) == parse_opt::None) { return opt | parse_opt::AnyString; } else { return opt; } } constexpr bool string_parser_enable_bare(parse_opt opt) { return enum_flag_contains(string_parse_opt_with_default(opt), parse_opt::BareString); } constexpr bool string_parser_enable_single_quoted(parse_opt opt) { return enum_flag_contains(string_parse_opt_with_default(opt), parse_opt::SingleQuotedString); } constexpr bool string_parser_enable_double_quoted(parse_opt opt) { return enum_flag_contains(string_parse_opt_with_default(opt), parse_opt::DoubleQuotedString); } template class automatic_parser { static std::string trim_string(const std::string &str) { auto start = str.find_first_not_of(whitespace); auto end = str.find_last_not_of(whitespace); return str.substr(start == std::string::npos ? 0 : start, end == std::string::npos ? 0 : end); } public: static parser_func make_parser(const std::string &name) { return [name](const char *begin, const char *end, const char *&parse_end, internal::parser_allow_undelimited allow_undelimited) { auto str = std::string_view(begin, end); if (str.length() == 0) { if (parse_opt == parse_opt::None || enum_flag_contains(parse_opt, parse_opt::BareString)) { parse_end = begin; return std::string(""); } else { throw errors::type_parsing_error(name, std::string(""), 0, "unexpected empty input"); } } if (str[0] == '\'' && string_parser_enable_single_quoted(parse_opt)) { auto ss = std::stringstream(std::string(str)); std::string val; ss >> std::quoted(val, '\'', '\\'); auto len = ss.tellg(); parse_end = begin + len; if (enum_flag_contains(parse_opt, parse_opt::TrimString)) { return trim_string(val); } else { return val; } } if (str[0] == '"' && string_parser_enable_double_quoted(parse_opt)) { auto ss = std::stringstream(std::string(str)); std::string val; ss >> std::quoted(val, '"', '\\'); auto len = ss.tellg(); parse_end = begin + len; if (enum_flag_contains(parse_opt, parse_opt::TrimString)) { return trim_string(val); } else { return val; } } if (string_parser_enable_bare(parse_opt)) { std::string illegal_characters = "\"'"; if (!internal::enum_flag_contains(allow_undelimited, internal::parser_allow_undelimited::Comma)) { illegal_characters += ","; } if (!internal::enum_flag_contains(allow_undelimited, internal::parser_allow_undelimited::Parenthesis)) { illegal_characters += "()"; } if (!internal::enum_flag_contains(allow_undelimited, internal::parser_allow_undelimited::Brackets)) { illegal_characters += "[]"; } auto pos = str.find_first_of(illegal_characters); if (pos == std::string_view::npos) { parse_end = end; } else { parse_end = begin + pos; } std::string val{begin, parse_end}; if (enum_flag_contains(parse_opt, parse_opt::TrimString) || enum_flag_contains(parse_opt, parse_opt::TrimBareString)) { return trim_string(val); } else { return val; } } throw errors::type_parsing_error(name, std::string(begin, end), 0, "failed to parse string"); }; } }; template parser_func make_enum_parser(const std::string &name, internal::string_map values) { if (values.size() == 0) { throw errors::empty_enum_map_error(name); } return [name, values](const char *begin, const char *end, const char *&parse_end, internal::parser_allow_undelimited) { auto input = std::basic_string_view(begin, end); auto start = input.find_first_not_of(whitespace); if (start == std::string::npos) { input = ""; } else { input = std::basic_string_view(begin + start, end); } T value; size_t value_len = 0; for (const auto &[str, val]: values) { if (str.length() <= input.length()) { if (input.starts_with(str)) { if (str.length() > value_len) { value = val; value_len = str.length(); } } } } if (value_len == 0) { std::string expected_values = values.begin()->first; for (auto it = std::next(values.begin()); it != values.end(); it++) { if (std::next(it) != values.end()) { expected_values += ", " + it->first; } else { expected_values += " or " + it->first; } } throw errors::type_parsing_error(name, std::string(begin, end), 0, std::format("expected {}", expected_values)); } else { parse_end = begin + value_len; return value; } }; } }// namespace argparser::internal #endif//ARGPARSER_BUILTIN_PARSER_H