From 50d00a840f248badfba678956d7763c395c65650 Mon Sep 17 00:00:00 2001 From: ToruNiina Date: Fri, 5 May 2017 16:48:54 +0900 Subject: [PATCH] add acceptors for toml values --- tests/test_acceptor.cpp | 246 +++++++++++++++++-- toml/acceptor.hpp | 506 ++++++++++++++++++++++++++++++++++------ 2 files changed, 670 insertions(+), 82 deletions(-) diff --git a/tests/test_acceptor.cpp b/tests/test_acceptor.cpp index a16d83c..9ca3aa8 100644 --- a/tests/test_acceptor.cpp +++ b/tests/test_acceptor.cpp @@ -37,29 +37,247 @@ inline wrapping_iterator wrap(T v) {return wrapping_iterator(v);} BOOST_AUTO_TEST_CASE(test_conditions) { - BOOST_CHECK( toml::is_space::invoke(wrap(' '))); - BOOST_CHECK(!toml::is_space::invoke(wrap('a'))); + BOOST_CHECK( toml::is_space::invoke(wrap(' '))); + BOOST_CHECK(!toml::is_space::invoke(wrap('a'))); - BOOST_CHECK( toml::is_tab::invoke(wrap('\t'))); - BOOST_CHECK(!toml::is_tab::invoke(wrap('a'))); + BOOST_CHECK( toml::is_tab::invoke(wrap('\t'))); + BOOST_CHECK(!toml::is_tab::invoke(wrap('a'))); for(char c = '0'; c <= '9'; ++c) - BOOST_CHECK(toml::is_number::invoke(wrap(c))); - BOOST_CHECK(!toml::is_number::invoke(wrap('a'))); + BOOST_CHECK(toml::is_number::invoke(wrap(c))); + BOOST_CHECK(!toml::is_number::invoke(wrap('a'))); for(char c = 'a'; c <= 'z'; ++c) - BOOST_CHECK(toml::is_lowercase::invoke(wrap(c))); - BOOST_CHECK(!toml::is_lowercase::invoke(wrap('A'))); + BOOST_CHECK(toml::is_lowercase::invoke(wrap(c))); + BOOST_CHECK(!toml::is_lowercase::invoke(wrap('A'))); for(char c = 'A'; c <= 'Z'; ++c) - BOOST_CHECK(toml::is_uppercase::invoke(wrap(c))); - BOOST_CHECK(!toml::is_uppercase::invoke(wrap('a'))); + BOOST_CHECK(toml::is_uppercase::invoke(wrap(c))); + BOOST_CHECK(!toml::is_uppercase::invoke(wrap('a'))); - BOOST_CHECK(toml::is_whitespace::invoke(wrap(' '))); - BOOST_CHECK(toml::is_whitespace::invoke(wrap('\t'))); + BOOST_CHECK(toml::is_whitespace::invoke(wrap(' '))); + BOOST_CHECK(toml::is_whitespace::invoke(wrap('\t'))); std::string barekey("hoge1-piyo2_fuga3"); - BOOST_CHECK(toml::is_barekey::invoke(barekey.cbegin()) == barekey.cend()); + BOOST_CHECK(toml::is_barekey::invoke(barekey.cbegin()) == barekey.cend()); std::string partial("hoge1.piyo2_fuga3"); - BOOST_CHECK(toml::is_barekey::invoke(partial.cbegin()) == partial.cbegin()+5); + BOOST_CHECK(toml::is_barekey::invoke(partial.cbegin()) == partial.cbegin()+5); } + +BOOST_AUTO_TEST_CASE(test_basic_inline_string) +{ + using is_valid = toml::is_basic_inline_string; + { + const std::string simple("\"hoge1-piyo2_fuga3\""); + BOOST_CHECK(is_valid::invoke(simple.cbegin()) == simple.cend()); + } + { + const std::string quote("\"hoge1-\\\"piyo2\\\"_fuga3\""); + BOOST_CHECK(is_valid::invoke(quote.cbegin()) == quote.cend()); + } + { + const std::string escape("\"I'm a string. \\\"You can quote me\\\". Name\\tJos\\u00E9\\nLocation\\tSF.\""); + BOOST_CHECK(is_valid::invoke(escape.cbegin()) == escape.cend()); + } + { + const std::string empty("\"\""); + BOOST_CHECK(is_valid::invoke(empty.cbegin()) == empty.cend()); + } + + { + const std::string newline("\"newline\r\nhoge\""); + BOOST_CHECK(is_valid::invoke(newline.cbegin()) == newline.cbegin()); + } + { + const std::string invalid_escape("\"foo\\abar\""); + BOOST_CHECK(is_valid::invoke(invalid_escape.cbegin()) == invalid_escape.cbegin()); + } + { + const std::string invalid_charactor("\"foo\0bar\""); + BOOST_CHECK(is_valid::invoke(invalid_charactor.cbegin()) == invalid_charactor.cbegin()); + } + { + const std::string multi("\"\"\"multiline\"\"\""); + BOOST_CHECK(is_valid::invoke(multi.cbegin()) == multi.cbegin()); + } +} + +BOOST_AUTO_TEST_CASE(test_basic_multiline_string) +{ + using is_valid = toml::is_basic_multiline_string; + { + const std::string simple("\"\"\"foobar\"\"\""); + BOOST_CHECK(is_valid::invoke(simple.cbegin()) == simple.cend()); + } + { + const std::string quote("\"\"\"hoge1-\"piyo2\"_fuga3\"\"\""); + BOOST_CHECK(is_valid::invoke(quote.cbegin()) == quote.cend()); + } + { + const std::string newline("\"\"\"hoge1-\npiyo2_\r\nfuga3\"\"\""); + BOOST_CHECK(is_valid::invoke(newline.cbegin()) == newline.cend()); + } + { + const std::string escape("\"\"\"I'm a string. \"You can quote me\". Name\\tJos\\u00E9\\nLocation\\tSF.\"\"\""); + BOOST_CHECK(is_valid::invoke(escape.cbegin()) == escape.cend()); + } + { + const std::string empty("\"\"\"\"\"\""); + BOOST_CHECK(is_valid::invoke(empty.cbegin()) == empty.cend()); + } + { + const std::string ending_backslash("\"\"\"hoge\\\n piyo\\\n\"\"\""); + BOOST_CHECK(is_valid::invoke(ending_backslash.cbegin()) == ending_backslash.cend()); + } + + { + const std::string invalid_escape("\"\"\"foo\\abar\"\"\""); + BOOST_CHECK(is_valid::invoke(invalid_escape.cbegin()) == invalid_escape.cbegin()); + } + { + const std::string invalid_charactor("\"\"\"foo\0bar\"\"\""); + BOOST_CHECK(is_valid::invoke(invalid_charactor.cbegin()) == invalid_charactor.cbegin()); + } + { + const std::string single("\"singleline\""); + BOOST_CHECK(is_valid::invoke(single.cbegin()) == single.cbegin()); + } +} + +BOOST_AUTO_TEST_CASE(test_literal_inline_string) +{ + using is_valid = toml::is_literal_inline_string; + { + const std::string simple("'foobar'"); + BOOST_CHECK(is_valid::invoke(simple.cbegin()) == simple.cend()); + } + { + const std::string nonescape("'C:\\Users\\nodejs\\templates'"); + BOOST_CHECK(is_valid::invoke(nonescape.cbegin()) == nonescape.cend()); + } + { + const std::string empty("''"); + BOOST_CHECK(is_valid::invoke(empty.cbegin()) == empty.cend()); + } + + { + const std::string quote("'hoge1-'piyo2'_fuga3'"); + BOOST_CHECK(is_valid::invoke(quote.cbegin()) == quote.cbegin() + 8); + } + { + const std::string newline("'hoge1-\npiyo2_\r\nfuga3'"); + BOOST_CHECK(is_valid::invoke(newline.cbegin()) == newline.cbegin()); + } + { + const std::string invalid_charactor("'foo\0bar'"); + BOOST_CHECK(is_valid::invoke(invalid_charactor.cbegin()) == invalid_charactor.cbegin()); + } + { + const std::string multi("'''multiline'''"); + BOOST_CHECK(is_valid::invoke(multi.cbegin()) == multi.cbegin()); + } +} + +BOOST_AUTO_TEST_CASE(test_literal_multiline_string) +{ + using is_valid = toml::is_literal_multiline_string; + { + const std::string simple("'''foobar'''"); + BOOST_CHECK(is_valid::invoke(simple.cbegin()) == simple.cend()); + } + { + const std::string quote("'''hoge1-'piyo2'_fuga3'''"); + BOOST_CHECK(is_valid::invoke(quote.cbegin()) == quote.cend()); + } + { + const std::string nonescape("'''C:\\Users\\nodejs\\templates'''"); + BOOST_CHECK(is_valid::invoke(nonescape.cbegin()) == nonescape.cend()); + } + { + const std::string newline("'''hoge1-\npiyo2_\r\nfuga3'''"); + BOOST_CHECK(is_valid::invoke(newline.cbegin()) == newline.cend()); + } + { + const std::string empty("''''''"); + BOOST_CHECK(is_valid::invoke(empty.cbegin()) == empty.cend()); + } + + { + const std::string invalid_charactor("'''foo\0bar'''"); + BOOST_CHECK(is_valid::invoke(invalid_charactor.cbegin()) == invalid_charactor.cbegin()); + } + { + const std::string single("'singleline'"); + BOOST_CHECK(is_valid::invoke(single.cbegin()) == single.cbegin()); + } +} + +BOOST_AUTO_TEST_CASE(test_integer) +{ + using is_valid = toml::is_integer; + { + const std::string simple("1"); + BOOST_CHECK(is_valid::invoke(simple.cbegin()) == simple.cend()); + } + { + const std::string psign("+1234"); + BOOST_CHECK(is_valid::invoke(psign.cbegin()) == psign.cend()); + const std::string nsign("-1234"); + BOOST_CHECK(is_valid::invoke(nsign.cbegin()) == nsign.cend()); + } + { + const std::string zero("0"); + BOOST_CHECK(is_valid::invoke(zero.cbegin()) == zero.cend()); + } + { + const std::string us("1_2_3_4_5"); + BOOST_CHECK(is_valid::invoke(us.cbegin()) == us.cend()); + } + + { + const std::string f("12.34"); + BOOST_CHECK(is_valid::invoke(f.cbegin()) == f.cbegin()+2); + } + { + const std::string f("12e34"); + BOOST_CHECK(is_valid::invoke(f.cbegin()) == f.cbegin()+2); + } + { + const std::string ascii("1234a"); + BOOST_CHECK(is_valid::invoke(ascii.cbegin()) == ascii.cbegin()+4); + } +} + +BOOST_AUTO_TEST_CASE(test_float) +{ + using is_valid = toml::is_float; + { + const std::string simplef("1.0"); + BOOST_CHECK(is_valid::invoke(simplef.cbegin()) == simplef.cend()); + const std::string simplee("1e0"); + BOOST_CHECK(is_valid::invoke(simplee.cbegin()) == simplee.cend()); + const std::string both("6.626e-34"); + BOOST_CHECK(is_valid::invoke(both.cbegin()) == both.cend()); + } + { + const std::string psign("+1.0"); + BOOST_CHECK(is_valid::invoke(psign.cbegin()) == psign.cend()); + const std::string nsign("-1.0"); + BOOST_CHECK(is_valid::invoke(nsign.cbegin()) == nsign.cend()); + } + { + const std::string psmall("+0.001"); + BOOST_CHECK(is_valid::invoke(psmall.cbegin()) == psmall.cend()); + const std::string nsmall("-0.001"); + BOOST_CHECK(is_valid::invoke(nsmall.cbegin()) == nsmall.cend()); + } + { + const std::string zero("0.0"); + BOOST_CHECK(is_valid::invoke(zero.cbegin()) == zero.cend()); + } + { + const std::string us("9_224_617.445_991_228_313"); + BOOST_CHECK(is_valid::invoke(us.cbegin()) == us.cend()); + } +} + diff --git a/toml/acceptor.hpp b/toml/acceptor.hpp index d3409c4..e8d5edb 100644 --- a/toml/acceptor.hpp +++ b/toml/acceptor.hpp @@ -2,6 +2,8 @@ #define TOML11_ACCEPTOR #include #include +#include +#include "exception.hpp" namespace toml { @@ -11,7 +13,7 @@ struct is_charactor { typedef charT value_type; constexpr static value_type target = c; - + template::value_type, value_type>::value>::type> @@ -21,34 +23,6 @@ struct is_charactor } }; -template -struct is_none_of -{ - typedef charT value_type; - - template::value_type, - value_type>::value>::type> - constexpr static Iterator invoke(Iterator iter) - { - return *iter == head ? iter : is_not_a::invoke(iter); - } -}; - -template -struct is_none_of -{ - typedef charT value_type; - - template::value_type, - value_type>::value>::type> - constexpr static Iterator invoke(Iterator iter) - { - return *iter == tail ? iter : std::next(iter); - } -}; - template struct is_in_range { @@ -56,7 +30,7 @@ struct is_in_range constexpr static value_type upper = up; constexpr static value_type lower = lw; static_assert(lower <= upper, "lower <= upper"); - + template::value_type, value_type>::value>::type> @@ -66,10 +40,8 @@ struct is_in_range } }; -template -struct is_one_of; template -struct is_one_of +struct is_one_of { typedef typename headT::value_type value_type; static_assert( @@ -100,45 +72,106 @@ struct is_one_of } }; -template -struct is_chain_of; -template -struct is_chain_of +// just a wrapper for maybe_ignored +template +struct is_ignorable { - typedef typename headT::value_type value_type; - static_assert( - std::is_same::value_type>::value, - "different value_type"); + typedef typename condT::value_type value_type; template::value_type, value_type>::value>::type> static Iterator invoke(Iterator iter) { - const Iterator tmp = headT::invoke(iter); - return (tmp != iter) ? is_chain_of::invoke(tmp) : iter; - } -}; -template -struct is_chain_of -{ - typedef typename tailT::value_type value_type; - - template::value_type, - value_type>::value>::type> - static Iterator invoke(Iterator iter) - { - const Iterator tmp = tailT::invoke(iter); + const Iterator tmp = condT::invoke(iter); return (tmp != iter) ? tmp : iter; } }; template +struct maybe_ignored : std::false_type{}; +template +struct maybe_ignored> : std::true_type{}; + +template +struct is_chain_of_impl +{ + typedef typename headT::value_type value_type; + static_assert(std::is_same::value_type>::value, + "different value_type"); + + constexpr static bool ignorable = maybe_ignored::value; + + template::value_type, + value_type>::value>::type> + static Iterator invoke(Iterator iter, Iterator rollback) + { + const Iterator tmp = headT::invoke(iter); + return (tmp == iter && not ignorable) ? rollback : + is_chain_of_impl::invoke(tmp, rollback); + } +}; + +template +struct is_chain_of_impl +{ + typedef typename tailT::value_type value_type; + constexpr static bool ignorable = maybe_ignored::value; + + template::value_type, + value_type>::value>::type> + static Iterator invoke(Iterator iter, Iterator rollback) + { + const Iterator tmp = tailT::invoke(iter); + return (tmp == iter) ? (ignorable ? iter : rollback) : tmp; + } +}; + +template +struct is_chain_of +{ + typedef typename is_chain_of_impl::value_type value_type; + + template::value_type, + value_type>::value>::type> + static Iterator invoke(Iterator iter) + { + return is_chain_of_impl::invoke(iter, iter); + } +}; + +template struct is_repeat_of { typedef typename condT::value_type value_type; + template::value_type, + value_type>::value>::type> + static Iterator invoke(Iterator iter) + { + const Iterator rollback = iter; + Iterator tmp; + for(auto i=0ul; i +struct is_repeat_of::infinity()> +{ + typedef typename condT::value_type value_type; + template::value_type, value_type>::value>::type> @@ -154,19 +187,356 @@ struct is_repeat_of } }; -using is_space = is_charactor; -using is_tab = is_charactor; -using is_number = is_in_range; -using is_lowercase = is_in_range; -using is_uppercase = is_in_range; -using is_alphabet = is_one_of; -using is_whitespace = is_one_of; -using is_newline = is_one_of, - is_chain_of, is_charactor>>; -using is_barekey_component = is_one_of, is_charactor>; -using is_barekey = is_repeat_of; +template +struct is_none_of +{ + typedef typename headT::value_type value_type; + static_assert( + std::is_same::value_type>::value, + "different value_type"); + template::value_type, + value_type>::value>::type> + static Iterator invoke(Iterator iter) + { + const Iterator tmp = headT::invoke(iter); + return (tmp != iter) ? iter : is_none_of::invoke(iter); + } +}; + +template +struct is_none_of +{ + typedef typename tailT::value_type value_type; + + template::value_type, + value_type>::value>::type> + static Iterator invoke(Iterator iter) + { + const Iterator tmp = tailT::invoke(iter); + return (tmp != iter) ? iter : std::next(iter); + } +}; + +template +struct is_not_but +{ + typedef typename notT::value_type value_type; + static_assert( + std::is_same::value, + "different value type"); + + template::value_type, + value_type>::value>::type> + static Iterator invoke(Iterator iter) + { + return (iter != notT::invoke(iter)) ? iter : butT::invoke(iter); + } +}; + +template +using is_space = is_charactor; +template +using is_tab = is_charactor; +template +using is_number = is_in_range; +template +using is_lowercase = is_in_range; +template +using is_uppercase = is_in_range; +template +using is_alphabet = is_one_of, is_uppercase>; +template +using is_hex = is_one_of, is_in_range, + is_in_range>; +template +using is_whitespace = is_one_of, is_tab>; +template +using is_newline = is_one_of, + is_chain_of, is_charactor>>; +template +using is_barekey_component = is_one_of, is_number, + is_charactor, is_charactor>; +template +using is_barekey = is_repeat_of, + std::numeric_limits::infinity()>; +template +using is_comment = + is_chain_of< + is_charactor, + is_repeat_of>, + std::numeric_limits::infinity()>, + is_newline + >; + +template +using is_basic_inline_string_component = + is_one_of< + is_none_of< is_in_range, is_charactor, + is_charactor, is_newline>, + is_chain_of, is_charactor>, + is_chain_of, is_charactor>, + is_chain_of, is_charactor>, + is_chain_of, is_charactor>, + is_chain_of, is_charactor>, + is_chain_of, is_charactor>, + is_chain_of, is_charactor>, + is_chain_of, is_charactor, + is_repeat_of, 4>>, + is_chain_of, is_charactor, + is_repeat_of, 8>> + >; +template +using is_basic_inline_string = + is_not_but< + is_repeat_of, 3>, // not multiline + is_chain_of< + is_charactor, + is_ignorable, + std::numeric_limits::infinity()>>, + is_charactor + > + >; +template +using is_basic_multiline_string_component = + is_one_of< + is_none_of< is_in_range, + is_repeat_of, 3>, + is_charactor>, + is_newline, + is_chain_of, is_newline>, + is_chain_of, is_charactor>, + is_chain_of, is_charactor>, + is_chain_of, is_charactor>, + is_chain_of, is_charactor>, + is_chain_of, is_charactor>, + is_chain_of, is_charactor>, + is_chain_of, is_charactor>, + is_chain_of, is_charactor, + is_repeat_of, 4>>, + is_chain_of, is_charactor, + is_repeat_of, 8>> + >; +template +using is_basic_multiline_string = + is_chain_of< + is_repeat_of, 3>, + is_ignorable, + std::numeric_limits::infinity()>>, + is_repeat_of, 3> + >; + +template +using is_literal_inline_string_component = + is_none_of, is_charactor>; + +template +using is_literal_inline_string = + is_not_but< + is_repeat_of, 3>, + is_chain_of< + is_charactor, + is_ignorable, + std::numeric_limits::infinity()>>, + is_charactor + > + >; + +template +using is_literal_multiline_string_component = + is_one_of< + is_none_of, + is_repeat_of, 3>>, + is_newline + >; + +template +using is_literal_multiline_string = + is_chain_of< + is_repeat_of, 3>, + is_ignorable, + std::numeric_limits::infinity()>>, + is_repeat_of, 3> + >; + +template +using is_sign = is_one_of, is_charactor>; +template +using is_nonzero_number = is_in_range; + +template +using is_integer_component = + is_not_but< + is_repeat_of, 2>, + is_one_of< + is_charactor, is_number + > + >; +template +using is_integer = + is_chain_of< + is_ignorable>, + is_one_of< + is_charactor, + is_chain_of< + is_nonzero_number, + is_ignorable, + std::numeric_limits::infinity()> + > + > + > + >; + +template +using is_fractional_part = + is_chain_of< + is_charactor, + is_repeat_of, + std::numeric_limits::infinity()> + >; +template +using is_exponent_part = + is_chain_of< + is_one_of, is_charactor>, + is_integer + >; +template +using is_float = + is_one_of< + is_chain_of< + is_integer, + is_fractional_part, + is_exponent_part + >, + is_chain_of< + is_integer, + is_fractional_part + >, + is_chain_of< + is_integer, + is_exponent_part + > + >; + +template +using is_boolean = + is_one_of< + is_chain_of< + is_charactor, + is_charactor, + is_charactor, + is_charactor + >, + is_chain_of< + is_charactor, + is_charactor, + is_charactor, + is_charactor, + is_charactor + > + >; + +template +using is_local_time = + is_chain_of< + is_repeat_of, 2>, + is_charactor, + is_repeat_of, 2>, + is_charactor, + is_repeat_of, 2>, + is_ignorable, + std::numeric_limits::infinity()> + > + >; + +template +using is_local_date = + is_chain_of< + is_repeat_of, 4>, + is_charactor, + is_repeat_of, 2>, + is_charactor, + is_repeat_of, 2> + >; + +template +using is_local_date_time = + is_chain_of< + is_local_date, + is_charactor, + is_local_time + >; + +template +using is_offset = + is_one_of< + is_charactor, + is_chain_of< + is_sign, + is_repeat_of, 2>, + is_charactor, + is_repeat_of, 2> + > + >; + +template +using is_offset_date_time = + is_chain_of< + is_local_date_time, + is_offset + >; + +template +using is_elemental_type = + is_one_of< + is_basic_inline_string, + is_basic_multiline_string, + is_literal_inline_string, + is_literal_multiline_string, + is_integer, + is_float, + is_boolean, + is_local_time, + is_local_date, + is_local_date_time, + is_offset_date_time + >; + +template +using is_skippable_in_array = + is_repeat_of< + is_one_of, is_newline, is_comment>, + std::numeric_limits::infinity() + >; + +template +using is_array_component = + is_chain_of< + is_ignorable>, + is_elemental_type, + is_ignorable> + >; + +template +using is_array = + is_chain_of< + is_charactor, + is_ignorable< + is_repeat_of< + is_chain_of, is_charactor>, + std::numeric_limits::infinite() + > + >, + is_ignorable< + is_chain_of< + is_array_component, is_ignorable> + > + >, + is_charactor + >; }//toml #endif// TOML11_ACCEPTOR