#pragma once #include #include #include #include #include #include #include "ast/ast_component.hpp" #include "util/input.hpp" namespace fsh{ class _Argument { public: virtual void svalue(std::shared_ptr can) { svalue(can->gvalue(), can->gtoken_type()); } virtual void svalue(const std::string& can, const Lexer::TokenType& type = Lexer::TokenType::FLAG) {} template static std::shared_ptr<_Argument> create() {return std::make_shared();} protected: _Argument(){} }; template class Argument : public _Argument { public: Argument() {} virtual void svalue(const std::string& val, const Lexer::TokenType& type) override{ if constexpr (std::is_same_v) { value = val; } else { std::stringstream ss_val(val); if(!(ss_val >> value)) { throw std::invalid_argument("Incorrect type"); } } is_string_literal = type == Lexer::TokenType::STRING_LITERAL; } virtual T& gvalue() {return value;} static T& get(std::shared_ptr<_Argument> a) { return std::dynamic_pointer_cast >(a)->gvalue(); } private: bool is_string_literal; T value; }; class ArgInput : public _Argument { public: ArgInput() {} virtual void svalue(const std::string& val, const Lexer::TokenType& type) override{ const std::string& txt = val; if(type == Lexer::TokenType::STRING_LITERAL) { str = std::stringstream(txt); } else { file = std::ifstream(txt, std::ios::in); if(!*file) { throw std::runtime_error("Failed to open file"); } } } virtual std::istream& gvalue(){ if(str) return *str; return *file; } static std::istream& get(std::shared_ptr<_Argument> a) { return std::dynamic_pointer_cast(a)->gvalue(); } private: std::optional str; std::optional file; }; class ArgManager { friend class ArgFactory; using PosArgs = std::vector >; using FlagOpts = std::unordered_map< std::string ,std::shared_ptr<_Argument> >; public: ArgManager() {} template std::optional get(const int id) { if(id < pos_argument.size()) return Argument::get(pos_argument[id]); return std::make_optional(); } std::istream& get_input(const int id) { if(id < pos_argument.size()) return ArgInput::get(pos_argument[id]); return util::cin; } template std::optional get(const std::string& id) { if(flags.find(id) != flags.end()) return Argument::get(flags[id]); return std::make_optional(); } bool get(const std::string& id) { return flags.find(id) != flags.end(); } void push_arg(std::shared_ptr<_Argument> arg) { pos_argument.push_back(arg); } void push_flag(const std::string &id,std::shared_ptr<_Argument> arg = nullptr) { flags[id] = arg; } private: PosArgs pos_argument; FlagOpts flags; }; class ArgFactory { using FlagNode = std::optional&; using ArgNodes = std::vector >; struct ArgRule { std::shared_ptr<_Argument> (*build) (void); bool mandatory; bool extends; }; struct FlagRule { std::shared_ptr<_Argument> (*build) (void); bool specialinput; //Not implemented bool capturing; bool extends; //Not implemented }; public: template void add_rule(bool mandatory, bool extends = false) { pos_arg_rules.push_back({&_Argument::create >, mandatory, extends}); } void add_input_rule() { has_input = true; pos_arg_rules.push_back({&_Argument::create, false, false}); } template void add_rule(const std::string name, bool capturing = false) { flag_rules[name] = {_Argument::create >, false, capturing, false}; } void parse(ArgManager& manager, ArgNodes& vec, FlagNode flag) { if(flag) { parse_flag(manager, flag); } int i = 0; for(const auto& arg : vec) { std::shared_ptr<_Argument> a; if(i >= pos_arg_rules.size()) throw std::invalid_argument("More arguments then excpected"); manager.push_arg(build_arg(pos_arg_rules[i].build, arg)); if(!pos_arg_rules[i].extends) i++; } } bool ghas_input() {return has_input;} private: std::vector pos_arg_rules; std::unordered_map flag_rules; bool has_input = false; void parse_flag(ArgManager& manager, FlagNode flag) { const std::string f = *flag; int f_sz = f.size(); for(const auto& [key, rule] : flag_rules) { const std::string_view k(key); if(k == f) { manager.push_flag(f); return; } if(rule.capturing && f == k.substr(0, f_sz)) { auto arg = build_arg(rule.build, (std::string) k.substr(f_sz)); manager.push_flag(f, arg); return; } } throw std::invalid_argument("Invalid flag"); } std::shared_ptr<_Argument> build_arg(std::shared_ptr<_Argument> (*build_func) (void),const std::string& str) { auto arg = build_func(); arg->svalue(str); return arg; } std::shared_ptr<_Argument> build_arg(std::shared_ptr<_Argument> (*build_func) (void), std::shared_ptr cmd_arg) { auto arg = build_func(); arg->svalue(cmd_arg); return arg; } }; }