aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorcrupest <crupest@outlook.com>2022-01-08 19:24:44 +0800
committercrupest <crupest@outlook.com>2022-01-08 19:24:44 +0800
commit0c7153db084060034092c1dc24222cae384722ec (patch)
tree9de1bc4636732e3cc1e1fb7309fdf2ff60683f69
parentc38f1f7c273e85c0a6d197cb27424c9ca69e234d (diff)
downloadcru-0c7153db084060034092c1dc24222cae384722ec.tar.gz
cru-0c7153db084060034092c1dc24222cae384722ec.tar.bz2
cru-0c7153db084060034092c1dc24222cae384722ec.zip
...
-rw-r--r--include/cru/common/String.hpp8
-rw-r--r--include/cru/common/StringUtil.hpp2
-rw-r--r--include/cru/toml/TomlDocument.hpp1
-rw-r--r--include/cru/toml/TomlParser.hpp7
-rw-r--r--src/common/String.cpp12
-rw-r--r--src/common/StringUtil.cpp2
-rw-r--r--src/toml/TomlDocument.cpp9
-rw-r--r--src/toml/TomlParser.cpp43
-rw-r--r--test/CMakeLists.txt1
-rw-r--r--test/common/StringTest.cpp5
-rw-r--r--test/toml/CMakeLists.txt6
-rw-r--r--test/toml/ParserTest.cpp31
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 &sections_[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");
+}