diff options
author | crupest <crupest@outlook.com> | 2022-01-08 19:24:44 +0800 |
---|---|---|
committer | crupest <crupest@outlook.com> | 2022-01-08 19:24:44 +0800 |
commit | 0c7153db084060034092c1dc24222cae384722ec (patch) | |
tree | 9de1bc4636732e3cc1e1fb7309fdf2ff60683f69 | |
parent | c38f1f7c273e85c0a6d197cb27424c9ca69e234d (diff) | |
download | cru-0c7153db084060034092c1dc24222cae384722ec.tar.gz cru-0c7153db084060034092c1dc24222cae384722ec.tar.bz2 cru-0c7153db084060034092c1dc24222cae384722ec.zip |
...
-rw-r--r-- | include/cru/common/String.hpp | 8 | ||||
-rw-r--r-- | include/cru/common/StringUtil.hpp | 2 | ||||
-rw-r--r-- | include/cru/toml/TomlDocument.hpp | 1 | ||||
-rw-r--r-- | include/cru/toml/TomlParser.hpp | 7 | ||||
-rw-r--r-- | src/common/String.cpp | 12 | ||||
-rw-r--r-- | src/common/StringUtil.cpp | 2 | ||||
-rw-r--r-- | src/toml/TomlDocument.cpp | 9 | ||||
-rw-r--r-- | src/toml/TomlParser.cpp | 43 | ||||
-rw-r--r-- | test/CMakeLists.txt | 1 | ||||
-rw-r--r-- | test/common/StringTest.cpp | 5 | ||||
-rw-r--r-- | test/toml/CMakeLists.txt | 6 | ||||
-rw-r--r-- | test/toml/ParserTest.cpp | 31 |
12 files changed, 122 insertions, 5 deletions
diff --git a/include/cru/common/String.hpp b/include/cru/common/String.hpp index 86e0a134..0ae223cf 100644 --- a/include/cru/common/String.hpp +++ b/include/cru/common/String.hpp @@ -165,7 +165,10 @@ class CRU_BASE_API String { } inline void append(StringView str); - String substr(size_type start, size_type size) const { + String substr(size_type start, size_type size = -1) const { + if (size == -1) { + size = this->size_ - start; + } return String(this->buffer_ + start, size); } @@ -189,6 +192,9 @@ class CRU_BASE_API String { std::vector<String> SplitToLines(bool remove_space_line = false) const; + bool StartWith(StringView str) const; + bool EndWith(StringView str) const; + public: void AppendCodePoint(CodePoint code_point); diff --git a/include/cru/common/StringUtil.hpp b/include/cru/common/StringUtil.hpp index a35da695..a0cb6b0b 100644 --- a/include/cru/common/StringUtil.hpp +++ b/include/cru/common/StringUtil.hpp @@ -222,5 +222,5 @@ Index CRU_BASE_API Utf16NextWord(const char16_t* ptr, Index size, char16_t CRU_BASE_API ToLower(char16_t c); char16_t CRU_BASE_API ToUpper(char16_t c); -char16_t CRU_BASE_API IsWhitespace(char16_t c); +bool CRU_BASE_API IsWhitespace(char16_t c); } // namespace cru diff --git a/include/cru/toml/TomlDocument.hpp b/include/cru/toml/TomlDocument.hpp index 9b549daa..637690f7 100644 --- a/include/cru/toml/TomlDocument.hpp +++ b/include/cru/toml/TomlDocument.hpp @@ -37,6 +37,7 @@ class TomlDocument { public: TomlSection* GetSection(const String& name); + TomlSection* GetSectionOrCreate(const String& name); const TomlSection* GetSection(const String& name) const; void SetSection(const String& name, TomlSection section); void DeleteSection(const String& name); diff --git a/include/cru/toml/TomlParser.hpp b/include/cru/toml/TomlParser.hpp index b5bcaa0b..52332506 100644 --- a/include/cru/toml/TomlParser.hpp +++ b/include/cru/toml/TomlParser.hpp @@ -1,10 +1,17 @@ #pragma once +#include "cru/common/Exception.hpp" #include "cru/toml/TomlDocument.hpp" #include <optional> namespace cru::toml { +// A very simple and tolerant TOML parser. +class TomlParsingException : public Exception { + public: + using Exception::Exception; +}; + class TomlParser { public: explicit TomlParser(String input); diff --git a/src/common/String.cpp b/src/common/String.cpp index ade2a72d..1c2ff022 100644 --- a/src/common/String.cpp +++ b/src/common/String.cpp @@ -206,7 +206,7 @@ String::iterator String::erase(const_iterator start, const_iterator end) { auto s = const_cast<iterator>(start); auto e = const_cast<iterator>(end); - std::memmove(e, s, (cend() - end) * sizeof(value_type)); + std::memmove(s, e, (cend() - end) * sizeof(value_type)); this->size_ = new_size; this->buffer_[new_size] = 0; @@ -298,6 +298,16 @@ std::vector<String> String::SplitToLines(bool remove_space_line) const { return result; } +bool String::StartWith(StringView str) const { + if (str.size() > size_) return false; + return std::memcmp(str.data(), buffer_, str.size()) == 0; +} + +bool String::EndWith(StringView str) const { + if (str.size() > size_) return false; + return std::memcmp(str.data(), buffer_ + size_ - str.size(), str.size()) == 0; +} + std::string String::ToUtf8() const { return cru::ToUtf8(buffer_, size_); } void String::AppendCodePoint(CodePoint code_point) { diff --git a/src/common/StringUtil.cpp b/src/common/StringUtil.cpp index d3948c6a..440db8c4 100644 --- a/src/common/StringUtil.cpp +++ b/src/common/StringUtil.cpp @@ -253,7 +253,7 @@ char16_t ToUpper(char16_t c) { return c; } -char16_t IsWhitespace(char16_t c) { +bool IsWhitespace(char16_t c) { return c == u' ' || c == u'\t' || c == u'\n' || c == u'\r'; } } // namespace cru diff --git a/src/toml/TomlDocument.cpp b/src/toml/TomlDocument.cpp index a785b4e4..052af170 100644 --- a/src/toml/TomlDocument.cpp +++ b/src/toml/TomlDocument.cpp @@ -31,6 +31,15 @@ const TomlSection* TomlDocument::GetSection(const String& name) const { return &it->second; } +TomlSection* TomlDocument::GetSectionOrCreate(const String& name) { + auto it = sections_.find(name); + if (it == sections_.end()) { + sections_[name] = TomlSection(); + return §ions_[name]; + } + return &it->second; +} + void TomlDocument::SetSection(const String& name, TomlSection section) { sections_[name] = std::move(section); } diff --git a/src/toml/TomlParser.cpp b/src/toml/TomlParser.cpp index d54624f6..7f19c711 100644 --- a/src/toml/TomlParser.cpp +++ b/src/toml/TomlParser.cpp @@ -17,6 +17,47 @@ TomlDocument TomlParser::Parse() { } void TomlParser::DoParse(TomlDocument& document) { - // TODO: Implement this. + std::vector<String> lines = input_.SplitToLines(true); + + String current_section_name; + + for (auto& line : lines) { + line.Trim(); + if (line.StartWith(u"[") && line.EndWith(u"]")) { + current_section_name = line.substr(1, line.size() - 2); + } else if (line.StartWith(u"#")) { + // Ignore comments. + } else { + auto equal_index = line.Find(u'='); + + if (equal_index == -1) { + throw TomlParsingException(u"Invalid TOML line: " + line); + } + + auto key = line.substr(0, equal_index).Trim(); + auto value = line.substr(equal_index + 1).Trim(); + + auto remove_quote = [](const String& str) -> String { + if (str.size() < 2) { + return str; + } + + if (str.StartWith(u"\"") && str.EndWith(u"\"")) { + return str.substr(1, str.size() - 2); + } + + if (str.StartWith(u"\'") && str.EndWith(u"\'")) { + return str.substr(1, str.size() - 2); + } + + return str; + }; + + key = remove_quote(key); + value = remove_quote(value); + + document.GetSectionOrCreate(current_section_name)->SetValue(key, value); + } + } } } // namespace cru::toml diff --git a/test/CMakeLists.txt b/test/CMakeLists.txt index 455aad90..c5e18d61 100644 --- a/test/CMakeLists.txt +++ b/test/CMakeLists.txt @@ -8,6 +8,7 @@ target_link_libraries(cru_test_base INTERFACE GTest::gtest GTest::gtest_main) add_subdirectory(common) add_subdirectory(platform) add_subdirectory(xml) +add_subdirectory(toml) if(WIN32) add_subdirectory(win) diff --git a/test/common/StringTest.cpp b/test/common/StringTest.cpp index f11f9197..2dc72478 100644 --- a/test/common/StringTest.cpp +++ b/test/common/StringTest.cpp @@ -28,6 +28,11 @@ TEST(String, Format) { ASSERT_EQ(Format(u"{} + {} = {}", 123, 321, 444), String(u"123 + 321 = 444")); } +TEST(String, Trim) { + using cru::String; + ASSERT_EQ(String(u" abc ").Trim(), u"abc"); +} + TEST(String, SplitToLines) { using cru::String; diff --git a/test/toml/CMakeLists.txt b/test/toml/CMakeLists.txt new file mode 100644 index 00000000..22766ecd --- /dev/null +++ b/test/toml/CMakeLists.txt @@ -0,0 +1,6 @@ +add_executable(cru_toml_test + ParserTest.cpp +) +target_link_libraries(cru_toml_test PRIVATE cru_toml cru_test_base) + +gtest_discover_tests(cru_toml_test) diff --git a/test/toml/ParserTest.cpp b/test/toml/ParserTest.cpp new file mode 100644 index 00000000..5bbb5fe7 --- /dev/null +++ b/test/toml/ParserTest.cpp @@ -0,0 +1,31 @@ +#include "cru/toml/TomlDocument.hpp" +#include "cru/toml/TomlParser.hpp" + +#include <gtest/gtest.h> + +using namespace cru::toml; + +TEST(CruTomlParserTest, Simple) { + TomlParser parser( + uR"( +a1 = v1 +"a2" = "v2" +# comment + +[s1] +# comment +a3 = v3 +"a4" = "v4" + +[s2] +a5 = v5 +"a6" = "v6" + )"); + auto document = parser.Parse(); + ASSERT_EQ(document.GetSection(u"")->GetValue(u"a1"), u"v1"); + ASSERT_EQ(document.GetSection(u"")->GetValue(u"a2"), u"v2"); + ASSERT_EQ(document.GetSection(u"s1")->GetValue(u"a3"), u"v3"); + ASSERT_EQ(document.GetSection(u"s1")->GetValue(u"a4"), u"v4"); + ASSERT_EQ(document.GetSection(u"s2")->GetValue(u"a5"), u"v5"); + ASSERT_EQ(document.GetSection(u"s2")->GetValue(u"a6"), u"v6"); +} |