Added error handling
This commit is contained in:
@ -15,6 +15,7 @@ set(FSH_SOURCE_FILES
|
|||||||
src/ast/ast_print.cpp
|
src/ast/ast_print.cpp
|
||||||
src/util/input.cpp
|
src/util/input.cpp
|
||||||
src/util/text.cpp
|
src/util/text.cpp
|
||||||
|
src/util/error.cpp
|
||||||
src/cmd/arg.cpp
|
src/cmd/arg.cpp
|
||||||
src/cmd/cmd_base.cpp
|
src/cmd/cmd_base.cpp
|
||||||
)
|
)
|
||||||
|
|||||||
@ -7,6 +7,7 @@
|
|||||||
|
|
||||||
#include "lexer.hpp"
|
#include "lexer.hpp"
|
||||||
#include "util/text.hpp"
|
#include "util/text.hpp"
|
||||||
|
#include "util/error.hpp"
|
||||||
|
|
||||||
namespace fsh {
|
namespace fsh {
|
||||||
|
|
||||||
@ -67,9 +68,29 @@ namespace fsh {
|
|||||||
private:
|
private:
|
||||||
};
|
};
|
||||||
|
|
||||||
class AstBuildError : public std::runtime_error {
|
class AstBuildError : public util::LazyError {
|
||||||
public:
|
public:
|
||||||
AstBuildError(std::string err) : std::runtime_error(err) {}
|
AstBuildError() {}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
class AstUnexpectedTypeError : public AstBuildError {
|
||||||
|
public:
|
||||||
|
AstUnexpectedTypeError(Lexer::TokenType type) : type(type){};
|
||||||
|
private:
|
||||||
|
Lexer::TokenType type;
|
||||||
|
|
||||||
|
std::string build_msg() const noexcept override {
|
||||||
|
return (std::string) "Unexpected " + util::tokens[type];
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
class AstNoRedirectError : public AstBuildError {
|
||||||
|
private:
|
||||||
|
std::string build_msg() const noexcept override {
|
||||||
|
return "No redirects provided";
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
@ -27,7 +27,7 @@ namespace fsh {
|
|||||||
}
|
}
|
||||||
|
|
||||||
Command& get(const std::string n) {
|
Command& get(const std::string n) {
|
||||||
if (cmds.find(n) == cmds.end()) { throw std::runtime_error("Command not found " + n); }
|
if (cmds.find(n) == cmds.end()) { throw util::CmdNotFoundError(n); }
|
||||||
return *(cmds[n]);
|
return *(cmds[n]);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -8,6 +8,7 @@
|
|||||||
|
|
||||||
#include "ast/ast.hpp"
|
#include "ast/ast.hpp"
|
||||||
#include "cmd/args/arg.hpp"
|
#include "cmd/args/arg.hpp"
|
||||||
|
#include "util/error.hpp"
|
||||||
|
|
||||||
namespace fsh {
|
namespace fsh {
|
||||||
|
|
||||||
|
|||||||
@ -17,7 +17,7 @@ namespace fsh {
|
|||||||
virtual void run(std::istream& in, std::ostream& out, ArgManager& args) override {
|
virtual void run(std::istream& in, std::ostream& out, ArgManager& args) override {
|
||||||
|
|
||||||
if(std::remove(args.get<std::string>(0).value().c_str())) {
|
if(std::remove(args.get<std::string>(0).value().c_str())) {
|
||||||
throw std::runtime_error("Could not delete file");
|
throw util::FileDeleteError();
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@ -15,7 +15,7 @@ namespace fsh {
|
|||||||
virtual void run(std::istream& in, std::ostream& out, ArgManager& args) override {
|
virtual void run(std::istream& in, std::ostream& out, ArgManager& args) override {
|
||||||
auto name = *(args.get<std::string>(0));
|
auto name = *(args.get<std::string>(0));
|
||||||
if (std::ifstream(name, std::ios::in).good() || !std::ofstream(name, std::ios::out).is_open()) {
|
if (std::ifstream(name, std::ios::in).good() || !std::ofstream(name, std::ios::out).is_open()) {
|
||||||
throw std::runtime_error("File exists");
|
throw util::FileExistsError();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|||||||
@ -33,7 +33,7 @@ namespace fsh {
|
|||||||
protected:
|
protected:
|
||||||
|
|
||||||
std::string replace_all(std::string str,const std::string &what,const std::string &with) {
|
std::string replace_all(std::string str,const std::string &what,const std::string &with) {
|
||||||
if(what == "") throw std::runtime_error("\"\" cannot be used as what");
|
if(what == "") throw util::CmdError("What cannot be empty string");
|
||||||
|
|
||||||
unsigned long long pos = str.find(what);
|
unsigned long long pos = str.find(what);
|
||||||
|
|
||||||
|
|||||||
@ -21,11 +21,11 @@ namespace fsh {
|
|||||||
std::string filename = args.get<std::string>(0).value();
|
std::string filename = args.get<std::string>(0).value();
|
||||||
|
|
||||||
if(!std::ifstream(filename, std::ios_base::in)) {
|
if(!std::ifstream(filename, std::ios_base::in)) {
|
||||||
throw std::runtime_error("File does not exist");
|
throw util::FileExistsError();
|
||||||
}
|
}
|
||||||
|
|
||||||
if(!std::ofstream(filename, std::ios_base::out)) {
|
if(!std::ofstream(filename, std::ios_base::out)) {
|
||||||
throw std::runtime_error("Failed to truncate");
|
throw util::CmdError("Failed to truncate");
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
76
include/util/error.hpp
Normal file
76
include/util/error.hpp
Normal file
@ -0,0 +1,76 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <stdexcept>
|
||||||
|
#include <optional>
|
||||||
|
|
||||||
|
namespace fsh::util {
|
||||||
|
// Generates msg only once what has been called
|
||||||
|
// Usefull for errors meant to be silently discarded frequently
|
||||||
|
class LazyError : public std::exception {
|
||||||
|
|
||||||
|
public:
|
||||||
|
LazyError() {}
|
||||||
|
LazyError(const std::string& msg_) : msg_(msg_) {}
|
||||||
|
LazyError(const char* msg_) : msg_(msg_) {}
|
||||||
|
|
||||||
|
const char* what() const noexcept override;
|
||||||
|
|
||||||
|
protected:
|
||||||
|
mutable std::optional<std::string> msg_;
|
||||||
|
|
||||||
|
virtual std::string build_msg() const noexcept;
|
||||||
|
};
|
||||||
|
|
||||||
|
class CmdNotFoundError : public LazyError {
|
||||||
|
public:
|
||||||
|
CmdNotFoundError(std::string cmd_) : cmd_(cmd_) {}
|
||||||
|
|
||||||
|
protected:
|
||||||
|
std::string build_msg() const noexcept override;
|
||||||
|
|
||||||
|
private:
|
||||||
|
std::string cmd_;
|
||||||
|
};
|
||||||
|
|
||||||
|
class CmdError : public LazyError {
|
||||||
|
public:
|
||||||
|
CmdError(const std::string& msg_) : LazyError(msg_) {}
|
||||||
|
CmdError(const char* msg_) : LazyError(msg_) {}
|
||||||
|
};
|
||||||
|
|
||||||
|
class RuntimeError : public std::exception {
|
||||||
|
public:
|
||||||
|
const char* msg_;
|
||||||
|
|
||||||
|
RuntimeError() = delete;
|
||||||
|
RuntimeError(const char* msg_) : msg_(msg_) {}
|
||||||
|
|
||||||
|
const char* what() const noexcept override;
|
||||||
|
};
|
||||||
|
|
||||||
|
class FileDeleteError : public RuntimeError {
|
||||||
|
public:
|
||||||
|
FileDeleteError() : RuntimeError("Error deleting file") {}
|
||||||
|
};
|
||||||
|
|
||||||
|
class FileExistsError : public RuntimeError {
|
||||||
|
public:
|
||||||
|
FileExistsError() : RuntimeError("File already exists") {}
|
||||||
|
};
|
||||||
|
|
||||||
|
class FileOpenError : public RuntimeError {
|
||||||
|
public:
|
||||||
|
FileOpenError() : RuntimeError("Failed to open file") {}
|
||||||
|
};
|
||||||
|
|
||||||
|
class DoubleInputError : public RuntimeError {
|
||||||
|
public:
|
||||||
|
DoubleInputError() : RuntimeError("Tried to set input twice") {}
|
||||||
|
};
|
||||||
|
|
||||||
|
class LexerError : public LazyError {
|
||||||
|
public:
|
||||||
|
LexerError(const std::string& msg_) : LazyError(msg_) {}
|
||||||
|
LexerError(const char* msg_) : LazyError(msg_) {}
|
||||||
|
};
|
||||||
|
}
|
||||||
@ -4,6 +4,7 @@
|
|||||||
#include <optional>
|
#include <optional>
|
||||||
#include <fstream>
|
#include <fstream>
|
||||||
#include <stdexcept>
|
#include <stdexcept>
|
||||||
|
#include "error.hpp"
|
||||||
|
|
||||||
// Razlicite pomocne funkcije za tekstove
|
// Razlicite pomocne funkcije za tekstove
|
||||||
namespace fsh::util {
|
namespace fsh::util {
|
||||||
@ -25,19 +26,19 @@ namespace fsh::util {
|
|||||||
|
|
||||||
static inline std::ifstream input(const std::string& x) {
|
static inline std::ifstream input(const std::string& x) {
|
||||||
std::ifstream in(x, std::ios::in);
|
std::ifstream in(x, std::ios::in);
|
||||||
if (!in) { throw std::runtime_error("Can't open file"); }
|
if (!in) { throw FileOpenError(); }
|
||||||
return in;
|
return in;
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline std::ofstream output(const std::string& x) {
|
static inline std::ofstream output(const std::string& x) {
|
||||||
std::ofstream out(x, std::ios::out);
|
std::ofstream out(x, std::ios::out);
|
||||||
if (!out.is_open()) { throw std::runtime_error("Can't open file"); }
|
if (!out.is_open()) { throw FileOpenError(); }
|
||||||
return out;
|
return out;
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline std::ofstream output_append(const std::string& x) {
|
static inline std::ofstream output_append(const std::string& x) {
|
||||||
std::ofstream out(x, std::ios::app | std::ios::out);
|
std::ofstream out(x, std::ios::app | std::ios::out);
|
||||||
if (!out.is_open()) { throw std::runtime_error("Can't open file"); }
|
if (!out.is_open()) { throw FileOpenError(); }
|
||||||
return out;
|
return out;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -14,6 +14,7 @@ fsh_source_files = [
|
|||||||
'src/ast/ast_print.cpp',
|
'src/ast/ast_print.cpp',
|
||||||
'src/util/input.cpp',
|
'src/util/input.cpp',
|
||||||
'src/util/text.cpp',
|
'src/util/text.cpp',
|
||||||
|
'src/util/error.cpp',
|
||||||
'src/cmd/arg.cpp',
|
'src/cmd/arg.cpp',
|
||||||
'src/cmd/cmd_base.cpp'
|
'src/cmd/cmd_base.cpp'
|
||||||
]
|
]
|
||||||
|
|||||||
@ -21,7 +21,7 @@ namespace fsh {
|
|||||||
it++;
|
it++;
|
||||||
return std::shared_ptr<TokenNode<T>>(new TokenNode<T>(value));
|
return std::shared_ptr<TokenNode<T>>(new TokenNode<T>(value));
|
||||||
} else {
|
} else {
|
||||||
throw AstBuildError(std::string("Got unexcpected: ") + util::tokens[token_type]);
|
throw AstUnexpectedTypeError(token_type);
|
||||||
}
|
}
|
||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
@ -56,7 +56,7 @@ namespace fsh {
|
|||||||
auto Rr = Optional<RRedirectNode>(it);
|
auto Rr = Optional<RRedirectNode>(it);
|
||||||
|
|
||||||
if (!Lr) Lr = Optional<LRedirectNode>(it);
|
if (!Lr) Lr = Optional<LRedirectNode>(it);
|
||||||
if (!Lr && !Rr) throw AstBuildError("No redirects where provided");
|
if (!Lr && !Rr) throw AstNoRedirectError();
|
||||||
return std::shared_ptr<RedirectsNode>(new RedirectsNode(Lr, Rr));
|
return std::shared_ptr<RedirectsNode>(new RedirectsNode(Lr, Rr));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -1,5 +1,6 @@
|
|||||||
#include "cmd/args/arg.hpp"
|
#include "cmd/args/arg.hpp"
|
||||||
#include "cmd/args/arg_generic.hpp"
|
#include "cmd/args/arg_generic.hpp"
|
||||||
|
#include "util/error.hpp"
|
||||||
#include <iostream>
|
#include <iostream>
|
||||||
#include <string>
|
#include <string>
|
||||||
|
|
||||||
@ -12,7 +13,7 @@ namespace fsh {
|
|||||||
str = std::stringstream(txt);
|
str = std::stringstream(txt);
|
||||||
} else {
|
} else {
|
||||||
file = std::ifstream(txt, std::ios::in);
|
file = std::ifstream(txt, std::ios::in);
|
||||||
if (!*file) { throw std::runtime_error("Failed to open file"); }
|
if (!*file) { throw util::FileOpenError(); }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -1,6 +1,7 @@
|
|||||||
#include "cmd/cmd_base.hpp"
|
#include "cmd/cmd_base.hpp"
|
||||||
#include "cmd/args/arg.hpp"
|
#include "cmd/args/arg.hpp"
|
||||||
#include "util/input.hpp"
|
#include "util/input.hpp"
|
||||||
|
#include "util/error.hpp"
|
||||||
|
|
||||||
namespace fsh {
|
namespace fsh {
|
||||||
|
|
||||||
@ -13,7 +14,7 @@ namespace fsh {
|
|||||||
arg_factory.parse(args, vec, flag);
|
arg_factory.parse(args, vec, flag);
|
||||||
if (arg_factory.ghas_input()) {
|
if (arg_factory.ghas_input()) {
|
||||||
if (&args.get_input(0) != &util::cin && &in != &util::cin) {
|
if (&args.get_input(0) != &util::cin && &in != &util::cin) {
|
||||||
throw std::runtime_error("Tried to set input to command twice");
|
throw util::DoubleInputError();
|
||||||
}
|
}
|
||||||
if (&args.get_input(0) != &util::cin) run(args.get_input(0), out, args);
|
if (&args.get_input(0) != &util::cin) run(args.get_input(0), out, args);
|
||||||
else
|
else
|
||||||
|
|||||||
@ -4,6 +4,7 @@
|
|||||||
#include <string>
|
#include <string>
|
||||||
#include "lexer.hpp"
|
#include "lexer.hpp"
|
||||||
#include "util/text.hpp"
|
#include "util/text.hpp"
|
||||||
|
#include "util/error.hpp"
|
||||||
|
|
||||||
namespace fsh {
|
namespace fsh {
|
||||||
|
|
||||||
@ -57,7 +58,7 @@ namespace fsh {
|
|||||||
LexerStateMachine::State LexerStateMachine::handle_string_literal() {
|
LexerStateMachine::State LexerStateMachine::handle_string_literal() {
|
||||||
const int c = parser.peek();
|
const int c = parser.peek();
|
||||||
if (c == std::char_traits<char>::eof()) {
|
if (c == std::char_traits<char>::eof()) {
|
||||||
throw std::runtime_error("Excpected \" before \\n");
|
throw util::LexerError("Excpected \" before \\n");
|
||||||
} else if (c == '\"') {
|
} else if (c == '\"') {
|
||||||
parser.consume();
|
parser.consume();
|
||||||
return set_type(Lexer::TokenType::STRING_LITERAL);
|
return set_type(Lexer::TokenType::STRING_LITERAL);
|
||||||
@ -72,7 +73,7 @@ namespace fsh {
|
|||||||
if (util::contains(c, "\t><| ") || c == std::char_traits<char>::eof()) {
|
if (util::contains(c, "\t><| ") || c == std::char_traits<char>::eof()) {
|
||||||
return set_type(type);
|
return set_type(type);
|
||||||
} else if (c == '\"') {
|
} else if (c == '\"') {
|
||||||
throw std::runtime_error("Invalid \"");
|
throw util::LexerError("Invalid \"");
|
||||||
} else {
|
} else {
|
||||||
token += parser.consume();
|
token += parser.consume();
|
||||||
return state;
|
return state;
|
||||||
|
|||||||
22
src/util/error.cpp
Normal file
22
src/util/error.cpp
Normal file
@ -0,0 +1,22 @@
|
|||||||
|
#include <util/error.hpp>
|
||||||
|
|
||||||
|
namespace fsh::util {
|
||||||
|
|
||||||
|
const char* LazyError::what() const noexcept {
|
||||||
|
if(!msg_) {
|
||||||
|
msg_.emplace(build_msg());
|
||||||
|
}
|
||||||
|
return msg_->c_str();
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string CmdNotFoundError::build_msg() const noexcept {
|
||||||
|
return "Command not found " + cmd_;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string LazyError::build_msg() const noexcept { return ""; }
|
||||||
|
|
||||||
|
const char* RuntimeError::what() const noexcept {
|
||||||
|
return msg_;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user