From 982ae36428f586b4dd8b13cc9b16ef9faa498940 Mon Sep 17 00:00:00 2001 From: ToruNiina Date: Tue, 19 Mar 2019 21:34:57 +0900 Subject: [PATCH 1/4] feat: add ""_toml literal --- toml.hpp | 1 + toml/literal.hpp | 55 ++++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 56 insertions(+) create mode 100644 toml/literal.hpp diff --git a/toml.hpp b/toml.hpp index 8cd95af..fde2a3c 100644 --- a/toml.hpp +++ b/toml.hpp @@ -34,6 +34,7 @@ #endif #include "toml/parser.hpp" +#include "toml/literal.hpp" #include "toml/serializer.hpp" #include "toml/from_toml.hpp" #include "toml/get.hpp" diff --git a/toml/literal.hpp b/toml/literal.hpp new file mode 100644 index 0000000..3642626 --- /dev/null +++ b/toml/literal.hpp @@ -0,0 +1,55 @@ +// Copyright Toru Niina 2019. +// Distributed under the MIT License. +#ifndef TOML11_LITERAL_HPP +#define TOML11_LITERAL_HPP +#include "parser.hpp" + +namespace toml +{ +inline namespace literals +{ +inline namespace toml_literals +{ + +inline ::toml::value operator""_toml(const char* str, std::size_t len) +{ + ::toml::detail::location> + loc(/* filename = */ std::string("TOML literal encoded in a C++ code"), + /* contents = */ std::vector(str, str + len)); + + // if there are some comments or empty lines, skip them. + using skip_line = ::toml::detail::repeat, + ::toml::detail::maybe<::toml::detail::lex_comment>, + ::toml::detail::lex_newline + >, ::toml::detail::at_least<1>>; + skip_line::invoke(loc); + + // if there are some whitespaces before a value, skip them. + using skip_ws = ::toml::detail::repeat< + ::toml::detail::lex_ws, ::toml::detail::at_least<1>>; + skip_ws::invoke(loc); + + // literal may be a bare value. try them first. + if(auto data = ::toml::detail::parse_value(loc)) + { + return data.unwrap(); + } + + // literal is a TOML file (i.e. multiline table). + if(auto data = ::toml::detail::parse_toml_file(loc)) + { + loc.iter() = loc.begin(); // rollback to the top of the literal + return ::toml::value(std::move(data.unwrap()), + ::toml::detail::region>(std::move(loc))); + } + else // none of them. + { + throw ::toml::syntax_error(data.unwrap_err()); + } +} + +} // toml_literals +} // literals +} // toml +#endif//TOML11_LITERAL_HPP From 39bc3c64fe5f307a22ccec6d51cb473bf5bd1226 Mon Sep 17 00:00:00 2001 From: ToruNiina Date: Wed, 20 Mar 2019 00:36:46 +0900 Subject: [PATCH 2/4] test: add test for ""_toml literals --- tests/CMakeLists.txt | 1 + tests/test_literals.cpp | 128 ++++++++++++++++++++++++++++++++++++++++ 2 files changed, 129 insertions(+) create mode 100644 tests/test_literals.cpp diff --git a/tests/CMakeLists.txt b/tests/CMakeLists.txt index 4f3e52a..3de9785 100644 --- a/tests/CMakeLists.txt +++ b/tests/CMakeLists.txt @@ -20,6 +20,7 @@ set(TEST_NAMES test_parse_inline_table test_parse_key test_parse_table_key + test_literals test_get test_get_related_func test_from_toml diff --git a/tests/test_literals.cpp b/tests/test_literals.cpp new file mode 100644 index 0000000..a24504e --- /dev/null +++ b/tests/test_literals.cpp @@ -0,0 +1,128 @@ +#define BOOST_TEST_MODULE "test_literals" +#ifdef UNITTEST_FRAMEWORK_LIBRARY_EXIST +#include +#else +#define BOOST_TEST_NO_LIB +#include +#endif +#include + +BOOST_AUTO_TEST_CASE(test_file_as_literal) +{ + using namespace toml::literals::toml_literals; + + { + const toml::value r{{"a", 42}, {"b", "baz"}}; + const toml::value v = u8R"( + a = 42 + b = "baz" + )"_toml; + + BOOST_CHECK_EQUAL(r, v); + } + { + const toml::value r{ + {"c", 3.14}, + {"table", toml::table{{"a", 42}, {"b", "baz"}}} + }; + const toml::value v = u8R"( + c = 3.14 + [table] + a = 42 + b = "baz" + )"_toml; + + BOOST_CHECK_EQUAL(r, v); + } +} + +BOOST_AUTO_TEST_CASE(test_value_as_literal) +{ + using namespace toml::literals::toml_literals; + + { + const toml::value v1 = u8"true"_toml; + const toml::value v2 = u8"false"_toml; + + BOOST_CHECK(v1.is_boolean()); + BOOST_CHECK(v2.is_boolean()); + BOOST_CHECK(toml::get(v1)); + BOOST_CHECK(!toml::get(v2)); + } + { + const toml::value v1 = u8"123_456"_toml; + const toml::value v2 = u8"0b0010"_toml; + const toml::value v3 = u8"0xDEADBEEF"_toml; + + BOOST_CHECK(v1.is_integer()); + BOOST_CHECK(v2.is_integer()); + BOOST_CHECK(v3.is_integer()); + BOOST_CHECK_EQUAL(toml::get(v1), 123456); + BOOST_CHECK_EQUAL(toml::get(v2), 2); + BOOST_CHECK_EQUAL(toml::get(v3), 0xDEADBEEF); + } + { + const toml::value v1 = u8"3.1415"_toml; + const toml::value v2 = u8"6.02e+23"_toml; + + BOOST_CHECK(v1.is_float()); + BOOST_CHECK(v2.is_float()); + BOOST_CHECK_CLOSE(toml::get(v1), 3.1415, 0.00001); + BOOST_CHECK_CLOSE(toml::get(v2), 6.02e23, 0.0001); + } + { + const toml::value v1 = u8R"("foo")"_toml; + const toml::value v2 = u8R"('foo')"_toml; + const toml::value v3 = u8R"("""foo""")"_toml; + const toml::value v4 = u8R"('''foo''')"_toml; + + BOOST_CHECK(v1.is_string()); + BOOST_CHECK(v2.is_string()); + BOOST_CHECK(v3.is_string()); + BOOST_CHECK(v4.is_string()); + BOOST_CHECK_EQUAL(toml::get(v1), "foo"); + BOOST_CHECK_EQUAL(toml::get(v2), "foo"); + BOOST_CHECK_EQUAL(toml::get(v3), "foo"); + BOOST_CHECK_EQUAL(toml::get(v4), "foo"); + } + { + const toml::value v1 = u8R"([1,2,3])"_toml; + + BOOST_CHECK(v1.is_array()); + BOOST_CHECK((toml::get>(v1) == std::vector{1,2,3})); + } + { + const toml::value v1 = u8R"({a = 42})"_toml; + + BOOST_CHECK(v1.is_table()); + BOOST_CHECK((toml::get>(v1) == + std::map{{"a", 42}})); + } + { + const toml::value v1 = u8"1979-05-27"_toml; + + BOOST_CHECK(v1.is_local_date()); + BOOST_CHECK_EQUAL(toml::get(v1), + toml::local_date(1979, toml::month_t::May, 27)); + } + { + const toml::value v1 = u8"12:00:00"_toml; + + BOOST_CHECK(v1.is_local_time()); + BOOST_CHECK(toml::get(v1) == std::chrono::hours(12)); + } + { + const toml::value v1 = u8"1979-05-27T07:32:00"_toml; + BOOST_CHECK(v1.is_local_datetime()); + BOOST_CHECK_EQUAL(toml::get(v1), + toml::local_datetime(toml::local_date(1979, toml::month_t::May, 27), + toml::local_time(7, 32, 0))); + } + { + const toml::value v1 = "1979-05-27T07:32:00Z"_toml; + BOOST_CHECK(v1.is_offset_datetime()); + BOOST_CHECK_EQUAL(toml::get(v1), + toml::offset_datetime(toml::local_date(1979, toml::month_t::May, 27), + toml::local_time(7, 32, 0), toml::time_offset(0, 0))); + } +} From 20ba57e389ba23329da6330433fc3fbdecd6b393 Mon Sep 17 00:00:00 2001 From: ToruNiina Date: Wed, 20 Mar 2019 00:37:13 +0900 Subject: [PATCH 3/4] fix: add missing const specifier to some of get()s --- toml/get.hpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/toml/get.hpp b/toml/get.hpp index ed211b0..c0e47bb 100644 --- a/toml/get.hpp +++ b/toml/get.hpp @@ -113,7 +113,7 @@ inline std::string get(value&& v) template::value, std::nullptr_t>::type = nullptr> -inline T get(value& v) +inline T get(const value& v) { return std::chrono::duration_cast( std::chrono::nanoseconds(v.cast())); @@ -125,7 +125,7 @@ inline T get(value& v) template::value, std::nullptr_t>::type = nullptr> -inline T get(value& v) +inline T get(const value& v) { switch(v.type()) { From b51a8d5966c0ebfb7fb22ef0dd9b8e484d22d6d2 Mon Sep 17 00:00:00 2001 From: ToruNiina Date: Wed, 20 Mar 2019 00:58:58 +0900 Subject: [PATCH 4/4] fix: add missing include file in test code --- tests/test_literals.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/tests/test_literals.cpp b/tests/test_literals.cpp index a24504e..7431f80 100644 --- a/tests/test_literals.cpp +++ b/tests/test_literals.cpp @@ -6,6 +6,7 @@ #include #endif #include +#include BOOST_AUTO_TEST_CASE(test_file_as_literal) {