diff --git a/CmakeLists.txt b/CmakeLists.txt index 94b0663..95dd909 100644 --- a/CmakeLists.txt +++ b/CmakeLists.txt @@ -7,6 +7,7 @@ set(CMAKE_CXX_STANDARD_REQUIRED ON) # Source files set(FSH_SOURCE_FILES + src/main.cpp src/fsh.cpp src/lexer.cpp src/ast/ast.cpp @@ -14,8 +15,8 @@ set(FSH_SOURCE_FILES src/ast/ast_print.cpp src/util/input.cpp src/util/text.cpp + src/cmd/arg.cpp src/cmd/cmd_base.cpp - src/main.cpp ) # Include directories diff --git a/include/cmd/arg.hpp b/include/cmd/arg.hpp deleted file mode 100644 index 2fc9bad..0000000 --- a/include/cmd/arg.hpp +++ /dev/null @@ -1,224 +0,0 @@ -#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 unsigned int id) { - if((unsigned int) id < pos_argument.size()) return Argument::get(pos_argument[id]); - return std::make_optional(); - } - - std::istream& get_input(const unsigned 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); - } - unsigned 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; - } - -}; - -} \ No newline at end of file diff --git a/include/cmd/args/arg.hpp b/include/cmd/args/arg.hpp new file mode 100644 index 0000000..0654a38 --- /dev/null +++ b/include/cmd/args/arg.hpp @@ -0,0 +1,67 @@ +#pragma once + +#include +#include +#include +#include +#include + +#include "ast/ast_component.hpp" +#include "util/input.hpp" + +#include "cmd/args/arg_generic.hpp" +#include "cmd/args/arg_input.hpp" +#include "cmd/args/arg_manager.hpp" + +namespace fsh{ + +class ArgFactory { +public: + using FlagNode = std::optional&; + using ArgNodes = std::vector >; + using BuildFunc = std::shared_ptr<_Argument> (*) (void); + + struct ArgRule + { + BuildFunc build; + bool mandatory; + bool extends; + }; + + struct FlagRule + { + BuildFunc build; + bool specialinput; //Not implemented + bool capturing; + bool extends; //Not implemented + }; + + + void add_input_rule() { + has_input = true; + pos_arg_rules.push_back({&_Argument::create, false, false}); + } + + template + void add_rule(bool mandatory, bool extends = false) { + pos_arg_rules.push_back({&_Argument::create >, mandatory, extends}); + } + + 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); + 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); + std::shared_ptr<_Argument> build_arg(BuildFunc build_func, const std::string& str); + std::shared_ptr<_Argument> build_arg(BuildFunc build_func, std::shared_ptr cmd_arg); +}; +} \ No newline at end of file diff --git a/include/cmd/args/arg_base.hpp b/include/cmd/args/arg_base.hpp new file mode 100644 index 0000000..bdc3640 --- /dev/null +++ b/include/cmd/args/arg_base.hpp @@ -0,0 +1,22 @@ +#pragma once + +#include + +#include "ast/ast_component.hpp" + +namespace fsh{ + +class _Argument { +public: + virtual void svalue(const std::string& can, const Lexer::TokenType& type = Lexer::TokenType::FLAG) {} + virtual void svalue(std::shared_ptr can) { + svalue(can->gvalue(), can->gtoken_type()); + } + + template + static std::shared_ptr<_Argument> create() {return std::make_shared();} +protected: + _Argument(){} +}; + +} \ No newline at end of file diff --git a/include/cmd/args/arg_generic.hpp b/include/cmd/args/arg_generic.hpp new file mode 100644 index 0000000..8c3ea72 --- /dev/null +++ b/include/cmd/args/arg_generic.hpp @@ -0,0 +1,39 @@ +#pragma once + +#include + +#include "cmd/args/arg_base.hpp" +#include "ast/ast_component.hpp" + +namespace fsh{ + +template +class Argument : public _Argument { +public: + static T& get(std::shared_ptr<_Argument> a) { + return std::dynamic_pointer_cast >(a)->gvalue(); + } + + Argument() {} + + virtual void svalue(const std::string& val, const Lexer::TokenType& type) override; + virtual T& gvalue() {return value;} +private: + bool is_string_literal; // Currently no getter + T value; +}; + +template +void Argument::svalue(const std::string& val, const Lexer::TokenType& type) { + 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; +} + +} \ No newline at end of file diff --git a/include/cmd/args/arg_input.hpp b/include/cmd/args/arg_input.hpp new file mode 100644 index 0000000..c0352b4 --- /dev/null +++ b/include/cmd/args/arg_input.hpp @@ -0,0 +1,26 @@ +#pragma once + +#include +#include + +#include "cmd/args/arg_base.hpp" + +namespace fsh{ + +class ArgInput : public _Argument { +public: + static std::istream& get(std::shared_ptr<_Argument> a) { + return std::dynamic_pointer_cast(a)->gvalue(); + } + + ArgInput() {} + + virtual void svalue(const std::string& val, const Lexer::TokenType& type) override; + virtual std::istream& gvalue(); + +private: + std::optional str; + std::optional file; +}; + +} \ No newline at end of file diff --git a/include/cmd/args/arg_manager.hpp b/include/cmd/args/arg_manager.hpp new file mode 100644 index 0000000..71f9c84 --- /dev/null +++ b/include/cmd/args/arg_manager.hpp @@ -0,0 +1,48 @@ +#pragma once +#include "cmd/args/arg_generic.hpp" +#include "cmd/args/arg_input.hpp" +#include "util/input.hpp" + +namespace fsh{ + +class ArgManager { + friend class ArgFactory; + + using PosArgs = std::vector >; + using FlagOpts = std::unordered_map< std::string ,std::shared_ptr<_Argument> >; + +public: + ArgManager() {} + + + std::istream& get_input(const unsigned int id) { + if(id < pos_argument.size()) return ArgInput::get(pos_argument[id]); + return util::cin; + } + + template + std::optional get(const unsigned int id) { + if((unsigned int) id < pos_argument.size()) return Argument::get(pos_argument[id]); + return std::make_optional(); + } + 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; +}; +} \ No newline at end of file diff --git a/include/cmd/cmd_base.hpp b/include/cmd/cmd_base.hpp index a5ea205..a02bb8b 100644 --- a/include/cmd/cmd_base.hpp +++ b/include/cmd/cmd_base.hpp @@ -7,7 +7,7 @@ #include #include "ast/ast.hpp" -#include "cmd/arg.hpp" +#include "cmd/args/arg.hpp" namespace fsh{ diff --git a/include/cmd/cmd_wc.hpp b/include/cmd/cmd_wc.hpp index 6f28f49..38f92a4 100644 --- a/include/cmd/cmd_wc.hpp +++ b/include/cmd/cmd_wc.hpp @@ -14,19 +14,30 @@ class CmdWc : public Command { factory.add_rule("-w"); } - virtual void run(std::istream& in, std::ostream& out, ArgManager& args) override { + int count_chars(std::istream& in) { int i = 0; char c; + while(in.get(c)) i++; + return i; + } + + int count_words(std::istream& in) { + int i = 0; + char c; + bool prev_space = true; + while(in.get(c)) { + i+= prev_space & !std::isspace(c); + prev_space = std::isspace(c); + } + return i; + } + + virtual void run(std::istream& in, std::ostream& out, ArgManager& args) override { + bool prev_space = true; if(args.get("-c")) { - while(in.get(c)) i++; - out << i << "\n"; + out << count_chars(in) << "\n"; } else if (args.get("-w")) { - bool prev_space = true; - while(in.get(c)) { - if(std::isspace(c)) { prev_space = true; } - else if(prev_space) { prev_space = false; i++;} - } - out << i << "\n"; + out << count_words(in) << "\n"; } else { throw std::invalid_argument("Didn't provide flag"); } diff --git a/include/fsh.hpp b/include/fsh.hpp index cfd0005..5ad36df 100644 --- a/include/fsh.hpp +++ b/include/fsh.hpp @@ -9,11 +9,7 @@ namespace fsh { - - -class fsh -{ - +class fsh { public: std::unordered_map environment; diff --git a/meson.build b/meson.build index 73f2f97..2d8d29c 100644 --- a/meson.build +++ b/meson.build @@ -7,14 +7,15 @@ project( fsh_source_files = [ 'src/fsh.cpp', + 'src/main.cpp', 'src/lexer.cpp', 'src/ast/ast.cpp', 'src/ast/ast_exec.cpp', 'src/ast/ast_print.cpp', 'src/util/input.cpp', 'src/util/text.cpp', - 'src/cmd/cmd_base.cpp', - 'src/main.cpp' + 'src/cmd/arg.cpp', + 'src/cmd/cmd_base.cpp' ] diff --git a/src/cmd/arg.cpp b/src/cmd/arg.cpp new file mode 100644 index 0000000..ea17c18 --- /dev/null +++ b/src/cmd/arg.cpp @@ -0,0 +1,72 @@ +#include "cmd/args/arg.hpp" + +namespace fsh { + +void ArgInput::svalue(const std::string& val, const Lexer::TokenType& type) { + 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"); + } + } +} + + +std::istream& ArgInput::gvalue(){ + if(str) + return *str; + return *file; +} + + + +void ArgFactory::parse(ArgManager& manager, ArgNodes& vec, FlagNode flag) { + if(flag) { + parse_flag(manager, flag); + } + unsigned 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++; + } +} + + +void ArgFactory::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> ArgFactory::build_arg(BuildFunc build_func, const std::string& str) { + auto arg = build_func(); + arg->svalue(str); + return arg; +} + +std::shared_ptr<_Argument> ArgFactory::build_arg(BuildFunc build_func, std::shared_ptr cmd_arg) { + auto arg = build_func(); + arg->svalue(cmd_arg); + return arg; +} + +} \ No newline at end of file diff --git a/src/cmd/cmd_base.cpp b/src/cmd/cmd_base.cpp index 4019708..43c726e 100644 --- a/src/cmd/cmd_base.cpp +++ b/src/cmd/cmd_base.cpp @@ -8,9 +8,6 @@ namespace fsh { arg_factory.parse(args, vec, flag); if(arg_factory.ghas_input()) { - /* Fixed util::cin has to be extern otherwise it will be allocated for each include (I think)*/ - // std::cout << "Is util::cin == in: " << (&in != &util::cin) << "\n"; - if(&args.get_input(0) != &util::cin && &in!= &util::cin) { throw std::runtime_error("Tried to set input to command twice"); }