diff options
author | innokentii <innokentii@yandex-team.com> | 2023-03-02 13:04:09 +0300 |
---|---|---|
committer | innokentii <innokentii@yandex-team.com> | 2023-03-02 13:04:09 +0300 |
commit | 502e6daf19bdde912acdb7fff06f1e69e9ccfddf (patch) | |
tree | fc85748caec9a506aae3d7821b42c2c3d5ac1a46 | |
parent | ed0c1088f25e4078c42314bc9c0d67ac971a0710 (diff) | |
download | ydb-502e6daf19bdde912acdb7fff06f1e69e9ccfddf.tar.gz |
Add multidoc support to fyamlcpp
add multidoc support to libfyaml
-rw-r--r-- | library/cpp/yaml/fyamlcpp/fyamlcpp.cpp | 72 | ||||
-rw-r--r-- | library/cpp/yaml/fyamlcpp/fyamlcpp.h | 37 | ||||
-rw-r--r-- | library/cpp/yaml/fyamlcpp/fyamlcpp_ut.cpp | 36 |
3 files changed, 137 insertions, 8 deletions
diff --git a/library/cpp/yaml/fyamlcpp/fyamlcpp.cpp b/library/cpp/yaml/fyamlcpp/fyamlcpp.cpp index 42ee6b830d..fc804128e4 100644 --- a/library/cpp/yaml/fyamlcpp/fyamlcpp.cpp +++ b/library/cpp/yaml/fyamlcpp/fyamlcpp.cpp @@ -280,6 +280,11 @@ TNode TNodeRef::Copy() const { return TNode(fy_node_copy(fy_node_document(Node_), Node_)); } +TNode TNodeRef::Copy(const TDocument& to) const { + ENSURE_NODE_NOT_EMPTY(Node_); + return TNode(fy_node_copy(to.Document_.get(), Node_)); +} + TString TNodeRef::Path() const { ENSURE_NODE_NOT_EMPTY(Node_); char* path = fy_node_get_path(Node_); @@ -801,14 +806,77 @@ void TDocument::UnregisterUserDataCleanup() { fy_document_unregister_meta(Document_.get()); } +TMark TDocument::BeginMark() const { + ENSURE_DOCUMENT_NOT_EMPTY(Document_); + auto* fyds = fy_document_get_document_state(Document_.get()); + auto* mark = fy_document_state_start_mark(fyds); + return TMark{ + mark->input_pos, + mark->line, + mark->column, + }; +} + +TMark TDocument::EndMark() const { + ENSURE_DOCUMENT_NOT_EMPTY(Document_); + auto* fyds = fy_document_get_document_state(Document_.get()); + auto* mark = fy_document_state_end_mark(fyds); + return TMark{ + mark->input_pos, + mark->line, + mark->column, + }; +} + std::unique_ptr<char, void(*)(char*)> TJsonEmitter::EmitToCharArray() const { std::unique_ptr<char, void(*)(char*)> res( - fy_emit_document_to_string( - Document_.Document_.get(), + fy_emit_node_to_string( + Node_.Node_, (fy_emitter_cfg_flags)(FYECF_DEFAULT | FYECF_SORT_KEYS | FYECF_MODE_JSON_TP)), &NDetail::FreeChar); return res; } +TParser::TParser(fy_parser* parser, fy_diag* diag) + : Parser_(parser, fy_parser_destroy) + , Diag_(diag, fy_diag_destroy) +{} + +TParser TParser::Create(const char* stream) +{ + fy_diag_cfg dcfg; + fy_diag_cfg_default(&dcfg); + std::unique_ptr<fy_diag, void(*)(fy_diag*)> diag(fy_diag_create(&dcfg), fy_diag_destroy); + fy_diag_set_collect_errors(diag.get(), true); + fy_parse_cfg cfg{ + "", + // FYPCF_PARSE_COMMENTS, + FYPCF_QUIET, + nullptr, + diag.get() + }; + 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; + } + } + + fy_parser_set_string(parser, stream, -1); + + return TParser(parser, diag.release()); +} + +std::optional<TDocument> TParser::NextDocument() { + auto* doc = fy_parse_load_document(Parser_.get()); + if (!doc) { + return std::nullopt; + } + + return TDocument(doc, fy_document_get_diag(doc)); +} + namespace NDetail { void RethrowError(fy_diag* diag) { diff --git a/library/cpp/yaml/fyamlcpp/fyamlcpp.h b/library/cpp/yaml/fyamlcpp/fyamlcpp.h index 7437b74ef7..5b645a557c 100644 --- a/library/cpp/yaml/fyamlcpp/fyamlcpp.h +++ b/library/cpp/yaml/fyamlcpp/fyamlcpp.h @@ -8,6 +8,7 @@ #include <memory> #include <optional> +struct fy_parser; struct fy_node; struct fy_document; struct fy_diag; @@ -67,6 +68,8 @@ class TSequenceIterator; class TReverseSequenceIterator; class TSequence; class TJsonEmitter; +class TParser; +struct TMark; class TDocumentIterator { friend class TDocument; @@ -88,6 +91,7 @@ class TNodeRef { friend class TSequence; friend class TSequenceIterator; friend class TReverseSequenceIterator; + friend class TJsonEmitter; TNodeRef(fy_node* node) : Node_(node) @@ -112,6 +116,8 @@ public: TNode Copy() const; + TNode Copy(const TDocument& to) const; + bool IsAlias() const; TNodeRef ResolveAlias() const; @@ -500,7 +506,9 @@ private: class TDocument { friend class TNode; + friend class TNodeRef; friend class TJsonEmitter; + friend class TParser; TDocument(fy_document* doc = nullptr, fy_diag* diag = nullptr); @@ -550,7 +558,6 @@ public: return it; } - TDocumentNodeIterator end() { return TDocumentNodeIterator(TNodeRef(nullptr)); } @@ -559,6 +566,10 @@ public: std::unique_ptr<char, void(*)(char*)> EmitToCharArray() const; + TMark BeginMark() const; + + TMark EndMark() const; + private: std::unique_ptr<fy_document, void(*)(fy_document*)> Document_; std::unique_ptr<fy_diag, void(*)(fy_diag*)> Diag_; @@ -578,16 +589,30 @@ private: class TJsonEmitter { public: - TJsonEmitter(const TDocument& doc) : Document_(doc) {} + TJsonEmitter(TDocument& doc) : Node_(doc.Root()) {} + TJsonEmitter(const TNodeRef& node) : Node_(node) {} std::unique_ptr<char, void(*)(char*)> EmitToCharArray() const; private: - const TDocument& Document_; + const TNodeRef Node_; +}; + +class TParser { + TParser(fy_parser* doc, fy_diag* diag); +public: + static TParser Create(const char* cstr); + + std::optional<TDocument> NextDocument(); +private: + std::unique_ptr<fy_parser, void(*)(fy_parser*)> Parser_; + std::unique_ptr<fy_diag, void(*)(fy_diag*)> Diag_; +}; - fy_document* Document() const { - return Document_.Document_.get(); - } +struct TMark { + size_t InputPos; + int Line; + int Column; }; } // namesapce NFyaml diff --git a/library/cpp/yaml/fyamlcpp/fyamlcpp_ut.cpp b/library/cpp/yaml/fyamlcpp/fyamlcpp_ut.cpp index f9aab7b011..94093c4157 100644 --- a/library/cpp/yaml/fyamlcpp/fyamlcpp_ut.cpp +++ b/library/cpp/yaml/fyamlcpp/fyamlcpp_ut.cpp @@ -50,4 +50,40 @@ test: output UNIT_ASSERT_VALUES_EQUAL(ss.Str(), "test: output\n"); } + + Y_UNIT_TEST(Parser) { + const char *yaml = R"( +test: a +--- +test: b +)"; + auto parser = NFyaml::TParser::Create(yaml); + + TStringStream ss; + + auto docOpt = parser.NextDocument(); + UNIT_ASSERT(docOpt); + ss << *docOpt; + UNIT_ASSERT_VALUES_EQUAL(ss.Str(), "test: a\n"); + auto beginMark = docOpt->BeginMark(); + UNIT_ASSERT_VALUES_EQUAL(beginMark.InputPos, 1); + auto endMark = docOpt->EndMark(); + UNIT_ASSERT_VALUES_EQUAL(endMark.InputPos, 12); + UNIT_ASSERT_VALUES_EQUAL(TStringBuf(yaml).SubStr(beginMark.InputPos, endMark.InputPos - 4), ss.Str()); + + ss.clear(); + + auto docOpt2 = parser.NextDocument(); + UNIT_ASSERT(docOpt2); + ss << *docOpt2; + UNIT_ASSERT_VALUES_EQUAL(ss.Str(), "---\ntest: b\n"); + beginMark = docOpt2->BeginMark(); + UNIT_ASSERT_VALUES_EQUAL(beginMark.InputPos, 9); + endMark = docOpt2->EndMark(); + UNIT_ASSERT_VALUES_EQUAL(endMark.InputPos, 21); + UNIT_ASSERT_VALUES_EQUAL(TStringBuf(yaml).SubStr(beginMark.InputPos, endMark.InputPos), ss.Str()); + + auto docOpt3 = parser.NextDocument(); + UNIT_ASSERT(!docOpt3); + } } |