aboutsummaryrefslogtreecommitdiffstats
path: root/library/cpp
diff options
context:
space:
mode:
authorjansenin <jansenin@yandex-team.com>2023-07-31 18:31:59 +0300
committerjansenin <jansenin@yandex-team.com>2023-07-31 18:31:59 +0300
commitfeac8eca6ce672915a1c91f4942ef59c5994e215 (patch)
tree63aeb507fcf4fe0c766babc315cf1772bec59f0e /library/cpp
parentdec41c40e51aa407edef81a3c566a5a15780fc49 (diff)
downloadydb-feac8eca6ce672915a1c91f4942ef59c5994e215.tar.gz
add exception with related exceptions
Diffstat (limited to 'library/cpp')
-rw-r--r--library/cpp/yaml/fyamlcpp/fyamlcpp.cpp89
-rw-r--r--library/cpp/yaml/fyamlcpp/fyamlcpp.h40
-rw-r--r--library/cpp/yaml/fyamlcpp/fyamlcpp_ut.cpp18
3 files changed, 116 insertions, 31 deletions
diff --git a/library/cpp/yaml/fyamlcpp/fyamlcpp.cpp b/library/cpp/yaml/fyamlcpp/fyamlcpp.cpp
index d006001b9e..8f9321a252 100644
--- a/library/cpp/yaml/fyamlcpp/fyamlcpp.cpp
+++ b/library/cpp/yaml/fyamlcpp/fyamlcpp.cpp
@@ -6,8 +6,8 @@
namespace NFyaml {
-#define ENSURE_NODE_NOT_EMPTY(NODE) Y_ENSURE_EX(NODE, TFyamlEx() << "Expected non-empty Node")
-#define ENSURE_DOCUMENT_NOT_EMPTY(NODE) Y_ENSURE_EX(NODE, TFyamlEx() << "Expected non-empty Document")
+#define ENSURE_NODE_NOT_EMPTY(NODE) Y_ENSURE_EX(NODE, TFyamlEx("Expected non-empty Node"))
+#define ENSURE_DOCUMENT_NOT_EMPTY(NODE) Y_ENSURE_EX(NODE, TFyamlEx("Expected non-empty Document"))
const char* zstr = "";
@@ -312,7 +312,11 @@ TNodeRef TNodeRef::ResolveAlias() const {
TString TNodeRef::Scalar() const {
ENSURE_NODE_NOT_EMPTY(Node_);
- Y_ENSURE_EX(fy_node_is_scalar(Node_), TFyamlEx() << "Node is not Scalar: " << Path());
+ Y_ENSURE_EX(fy_node_is_scalar(Node_), ({
+ TStringStream ss;
+ ss << "Node is not Scalar: " << Path();
+ TFyamlEx(ss.Str());
+ }));
size_t size;
const char* text = fy_node_get_scalar(Node_, &size);
return TString(text, size);
@@ -331,7 +335,7 @@ TMark TNodeRef::BeginMark() const {
auto* mark = fy_event_start_mark(ev.get());
if (!mark) {
- ythrow yexception() << "can't get begin mark for a node";
+ ythrow TFyamlEx("can't get begin mark for a node");
}
return TMark{
@@ -417,7 +421,7 @@ TMark TNodeRef::EndMark() const {
}
if (!mark) {
- ythrow yexception() << "can't get end mark for a node";
+ ythrow TFyamlEx("can't get end mark for a node");
}
return TMark{
@@ -429,13 +433,21 @@ TMark TNodeRef::EndMark() const {
TMapping TNodeRef::Map() const {
ENSURE_NODE_NOT_EMPTY(Node_);
- Y_ENSURE_EX(fy_node_is_mapping(Node_), TFyamlEx() << "Node is not Mapping: " << Path());
+ Y_ENSURE_EX(fy_node_is_mapping(Node_), ({
+ TStringStream ss;
+ ss << "Node is not Mapping: " << Path();
+ TFyamlEx(ss.Str());
+ }));
return TMapping(*this);
}
TSequence TNodeRef::Sequence() const {
ENSURE_NODE_NOT_EMPTY(Node_);
- Y_ENSURE_EX(fy_node_is_sequence(Node_), TFyamlEx() << "Node is not Sequence: " << Path());
+ Y_ENSURE_EX(fy_node_is_sequence(Node_), ({
+ TStringStream ss;
+ ss << "Node is not Sequence: " << Path();
+ TFyamlEx(ss.Str());
+ }));
return TSequence(*this);
}
@@ -598,7 +610,11 @@ size_t TMapping::empty() const {
TNodePairRef TMapping::at(int index) const {
ENSURE_NODE_NOT_EMPTY(Node_);
auto res = fy_node_mapping_get_by_index(Node_, index);
- Y_ENSURE_EX(res, TFyamlEx() << "No such child: " << Path() << "/" << index);
+ Y_ENSURE_EX(res, ({
+ TStringStream ss;
+ ss << "No such child: " << Path() << "/" << index;
+ TFyamlEx(ss.Str());
+ }));
return TNodePairRef(res);
}
@@ -610,14 +626,22 @@ TNodePairRef TMapping::operator[](int index) const {
TNodeRef TMapping::at(const TString& index) const {
ENSURE_NODE_NOT_EMPTY(Node_);
auto res = fy_node_mapping_lookup_by_string(Node_, index.data(), index.size());
- Y_ENSURE_EX(res, TFyamlEx() << "No such child: " << Path() << "/" << index);
+ Y_ENSURE_EX(res, ({
+ TStringStream ss;
+ ss << "No such child: " << Path() << "/" << index;
+ TFyamlEx(ss.Str());
+ }));
return TNodeRef(res);
}
TNodePairRef TMapping::pair_at(const TString& index) const {
ENSURE_NODE_NOT_EMPTY(Node_);
auto res = fy_node_mapping_lookup_pair_by_string(Node_, index.data(), index.size());
- Y_ENSURE_EX(res, TFyamlEx() << "No such child: " << Path() << "/" << index);
+ Y_ENSURE_EX(res, ({
+ TStringStream ss;
+ ss << "No such child: " << Path() << "/" << index;
+ TFyamlEx(ss.Str());
+ }));
return TNodePairRef(res);
}
@@ -741,7 +765,11 @@ size_t TSequence::empty() const {
TNodeRef TSequence::at(int index) const {
ENSURE_NODE_NOT_EMPTY(Node_);
auto res = fy_node_sequence_get_by_index(Node_, index);
- Y_ENSURE_EX(res, TFyamlEx() << "No such index: " << Path() << "/" << index);
+ Y_ENSURE_EX(res, ({
+ TStringStream ss;
+ ss << "No such index: " << Path() << "/" << index;
+ TFyamlEx(ss.Str());
+ }));
return TNodeRef(res);
}
@@ -835,7 +863,6 @@ TDocument::TDocument(fy_document* doc, fy_diag* diag)
RegisterUserDataCleanup();
}
-
TDocument TDocument::Parse(TString str) {
const char* cstr = str.empty() ? zstr : str.cbegin();
fy_diag_cfg dcfg;
@@ -851,11 +878,7 @@ TDocument TDocument::Parse(TString str) {
};
fy_document* doc = fy_document_build_from_string(&cfg, cstr, FY_NT);
if (!doc) {
- fy_diag_error* err;
- void *iter = nullptr;
- while ((err = fy_diag_errors_iterate(diag.get(), &iter)) != nullptr) {
- ythrow yexception() << err->file << ":" << err->line << ":" << err->column << " " << err->msg;
- }
+ NDetail::ThrowAllExceptionsIfAny(diag.get());
}
return TDocument(std::move(str), doc, diag.release());
}
@@ -886,11 +909,7 @@ TNodeRef TDocument::Buildf(const char* content) {
void TDocument::Resolve() {
ENSURE_DOCUMENT_NOT_EMPTY(Document_);
if (fy_document_resolve(Document_.get()) != 0) {
- fy_diag_error* err;
- void *iter = nullptr;
- while ((err = fy_diag_errors_iterate(Diag_.get(), &iter)) != nullptr) {
- ythrow yexception() << err->line << ":" << err->column << " " << err->msg;
- }
+ NDetail::ThrowAllExceptionsIfAny(Diag_.get());
}
}
@@ -1001,11 +1020,7 @@ TParser TParser::Create(TString str)
};
auto* parser = fy_parser_create(&cfg);
if (!parser) {
- fy_diag_error* err;
- void *iter = nullptr;
- while ((err = fy_diag_errors_iterate(diag.get(), &iter)) != nullptr) {
- ythrow yexception() << err->file << ":" << err->line << ":" << err->column << " " << err->msg;
- }
+ NDetail::ThrowAllExceptionsIfAny(diag.get());
}
fy_parser_set_string(parser, stream, -1);
@@ -1024,6 +1039,24 @@ std::optional<TDocument> TParser::NextDocument() {
namespace NDetail {
+void ThrowAllExceptionsIfAny(fy_diag* diag) {
+ void* iter = nullptr;
+ fy_diag_error* err = fy_diag_errors_iterate(diag, &iter);
+ if (err != nullptr) {
+ TStringStream ss;
+ ss << err->line << ":" << err->column << " " << err->msg;
+ TFyamlEx ex(ss.Str());
+
+ while ((err = fy_diag_errors_iterate(diag, &iter)) != nullptr) {
+ TStringStream ss;
+ ss << err->line << ":" << err->column << " " << err->msg;
+ ex.AddError(ss.Str());
+ }
+
+ ythrow ex;
+ }
+}
+
void RethrowError(fy_diag* diag) {
void *iter = nullptr;
fy_diag_error* err;
@@ -1031,7 +1064,7 @@ void RethrowError(fy_diag* diag) {
while ((err = fy_diag_errors_iterate(diag, &iter)) != nullptr) {
ss << err->line << ":" << err->column << " " << err->msg << "\n";
}
- ythrow yexception() << ss.Str();
+ ythrow TFyamlEx(ss.Str());
}
void RethrowOnError(bool isError, fy_node* node) {
diff --git a/library/cpp/yaml/fyamlcpp/fyamlcpp.h b/library/cpp/yaml/fyamlcpp/fyamlcpp.h
index ca53256349..a6bdf56927 100644
--- a/library/cpp/yaml/fyamlcpp/fyamlcpp.h
+++ b/library/cpp/yaml/fyamlcpp/fyamlcpp.h
@@ -5,6 +5,7 @@
#include <util/system/yassert.h>
#include <util/stream/str.h>
#include <util/generic/hash_set.h>
+#include <util/generic/vector.h>
#include <memory>
#include <optional>
@@ -25,7 +26,42 @@ struct TStringPtrHashT {
}
};
-struct TFyamlEx : public yexception {};
+// do TFyaml(str) instead of TFyaml() << str;
+class TFyamlEx : public yexception {
+public:
+ TFyamlEx() {}
+
+ TFyamlEx(TString error) : Errors_({error}) {}
+
+ TFyamlEx(std::initializer_list<TString> errors) : Errors_(errors) {}
+
+ const TVector<TString>& Errors() {
+ return Errors_;
+ }
+
+ const char* what() const noexcept override {
+ What_ = TString(yexception::what());
+ for (auto& err : Errors_) {
+ What_.push_back('\n');
+ What_.append(err);
+ }
+
+ return What_.c_str();
+ }
+
+ TFyamlEx& AddError(TString error) {
+ Errors_.push_back(error);
+ return *this;
+ }
+
+ TStringBuf AsStrBuf() const {
+ return what();
+ }
+
+private:
+ TVector<TString> Errors_;
+ mutable TString What_;
+};
enum class ENodeType {
Scalar,
@@ -65,6 +101,8 @@ private:
std::unique_ptr<T> Data_ = nullptr;
};
+void ThrowAllExceptionsIfAny(fy_diag* diag);
+
void RethrowError(fy_diag* diag);
void RethrowOnError(bool isError, fy_node* node);
diff --git a/library/cpp/yaml/fyamlcpp/fyamlcpp_ut.cpp b/library/cpp/yaml/fyamlcpp/fyamlcpp_ut.cpp
index 2f6e14138c..67e918a297 100644
--- a/library/cpp/yaml/fyamlcpp/fyamlcpp_ut.cpp
+++ b/library/cpp/yaml/fyamlcpp/fyamlcpp_ut.cpp
@@ -31,7 +31,7 @@ config: b
)";
UNIT_ASSERT_EXCEPTION_CONTAINS(
NFyaml::TDocument::Parse(yaml),
- yexception,
+ NFyaml::TFyamlEx,
"3:1 duplicate key");
}
@@ -42,9 +42,23 @@ anchor: *does_not_exists
auto doc = NFyaml::TDocument::Parse(yaml);
UNIT_ASSERT_EXCEPTION_CONTAINS(
doc.Resolve(),
- yexception,
+ NFyaml::TFyamlEx,
"2:10 invalid alias");
}
+ {
+ const char *yaml = R"(
+a: 1
+a: 2
+a: 3
+)";
+ try {
+ NFyaml::TDocument::Parse(yaml);
+ UNIT_FAIL("exception must've happend");
+ } catch (NFyaml::TFyamlEx e) {
+ UNIT_ASSERT(TString(e.what()).Contains("3:1 duplicate key"));
+ UNIT_ASSERT(e.Errors().ysize() == 1);
+ }
+ }
}
Y_UNIT_TEST(Out) {