Added error handling
This commit is contained in:
@ -15,6 +15,7 @@ set(FSH_SOURCE_FILES
|
||||
src/ast/ast_print.cpp
|
||||
src/util/input.cpp
|
||||
src/util/text.cpp
|
||||
src/util/error.cpp
|
||||
src/cmd/arg.cpp
|
||||
src/cmd/cmd_base.cpp
|
||||
)
|
||||
|
||||
@ -7,6 +7,7 @@
|
||||
|
||||
#include "lexer.hpp"
|
||||
#include "util/text.hpp"
|
||||
#include "util/error.hpp"
|
||||
|
||||
namespace fsh {
|
||||
|
||||
@ -67,9 +68,29 @@ namespace fsh {
|
||||
private:
|
||||
};
|
||||
|
||||
class AstBuildError : public std::runtime_error {
|
||||
class AstBuildError : public util::LazyError {
|
||||
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) {
|
||||
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]);
|
||||
}
|
||||
|
||||
|
||||
@ -8,6 +8,7 @@
|
||||
|
||||
#include "ast/ast.hpp"
|
||||
#include "cmd/args/arg.hpp"
|
||||
#include "util/error.hpp"
|
||||
|
||||
namespace fsh {
|
||||
|
||||
|
||||
@ -17,7 +17,7 @@ namespace fsh {
|
||||
virtual void run(std::istream& in, std::ostream& out, ArgManager& args) override {
|
||||
|
||||
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 {
|
||||
auto name = *(args.get<std::string>(0));
|
||||
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:
|
||||
|
||||
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);
|
||||
|
||||
|
||||
@ -21,11 +21,11 @@ namespace fsh {
|
||||
std::string filename = args.get<std::string>(0).value();
|
||||
|
||||
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)) {
|
||||
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 <fstream>
|
||||
#include <stdexcept>
|
||||
#include "error.hpp"
|
||||
|
||||
// Razlicite pomocne funkcije za tekstove
|
||||
namespace fsh::util {
|
||||
@ -25,19 +26,19 @@ namespace fsh::util {
|
||||
|
||||
static inline std::ifstream input(const std::string& x) {
|
||||
std::ifstream in(x, std::ios::in);
|
||||
if (!in) { throw std::runtime_error("Can't open file"); }
|
||||
if (!in) { throw FileOpenError(); }
|
||||
return in;
|
||||
}
|
||||
|
||||
static inline std::ofstream output(const std::string& x) {
|
||||
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;
|
||||
}
|
||||
|
||||
static inline std::ofstream output_append(const std::string& x) {
|
||||
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;
|
||||
}
|
||||
|
||||
|
||||
@ -14,6 +14,7 @@ fsh_source_files = [
|
||||
'src/ast/ast_print.cpp',
|
||||
'src/util/input.cpp',
|
||||
'src/util/text.cpp',
|
||||
'src/util/error.cpp',
|
||||
'src/cmd/arg.cpp',
|
||||
'src/cmd/cmd_base.cpp'
|
||||
]
|
||||
|
||||
@ -21,7 +21,7 @@ namespace fsh {
|
||||
it++;
|
||||
return std::shared_ptr<TokenNode<T>>(new TokenNode<T>(value));
|
||||
} else {
|
||||
throw AstBuildError(std::string("Got unexcpected: ") + util::tokens[token_type]);
|
||||
throw AstUnexpectedTypeError(token_type);
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
@ -56,7 +56,7 @@ namespace fsh {
|
||||
auto Rr = Optional<RRedirectNode>(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));
|
||||
}
|
||||
|
||||
|
||||
@ -1,5 +1,6 @@
|
||||
#include "cmd/args/arg.hpp"
|
||||
#include "cmd/args/arg_generic.hpp"
|
||||
#include "util/error.hpp"
|
||||
#include <iostream>
|
||||
#include <string>
|
||||
|
||||
@ -12,7 +13,7 @@ namespace fsh {
|
||||
str = std::stringstream(txt);
|
||||
} else {
|
||||
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/args/arg.hpp"
|
||||
#include "util/input.hpp"
|
||||
#include "util/error.hpp"
|
||||
|
||||
namespace fsh {
|
||||
|
||||
@ -13,7 +14,7 @@ namespace fsh {
|
||||
arg_factory.parse(args, vec, flag);
|
||||
if (arg_factory.ghas_input()) {
|
||||
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);
|
||||
else
|
||||
|
||||
@ -4,6 +4,7 @@
|
||||
#include <string>
|
||||
#include "lexer.hpp"
|
||||
#include "util/text.hpp"
|
||||
#include "util/error.hpp"
|
||||
|
||||
namespace fsh {
|
||||
|
||||
@ -57,7 +58,7 @@ namespace fsh {
|
||||
LexerStateMachine::State LexerStateMachine::handle_string_literal() {
|
||||
const int c = parser.peek();
|
||||
if (c == std::char_traits<char>::eof()) {
|
||||
throw std::runtime_error("Excpected \" before \\n");
|
||||
throw util::LexerError("Excpected \" before \\n");
|
||||
} else if (c == '\"') {
|
||||
parser.consume();
|
||||
return set_type(Lexer::TokenType::STRING_LITERAL);
|
||||
@ -72,7 +73,7 @@ namespace fsh {
|
||||
if (util::contains(c, "\t><| ") || c == std::char_traits<char>::eof()) {
|
||||
return set_type(type);
|
||||
} else if (c == '\"') {
|
||||
throw std::runtime_error("Invalid \"");
|
||||
throw util::LexerError("Invalid \"");
|
||||
} else {
|
||||
token += parser.consume();
|
||||
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