From 4a8cf55ab62eaf1d32aec38b40d6df0c808b031d Mon Sep 17 00:00:00 2001 From: AWE Henry Date: Mon, 27 May 2024 16:02:15 +0800 Subject: [PATCH] Update interpreter --- example/playground/ipapilio.cpp | 18 --------- include/papilio/script/interpreter.hpp | 43 ++++------------------ src/script/interpreter.cpp | 51 ++++++++++++++++++++++++-- test/test_script_interpreter.cpp | 6 +-- 4 files changed, 58 insertions(+), 60 deletions(-) diff --git a/example/playground/ipapilio.cpp b/example/playground/ipapilio.cpp index 087c767..ec56f85 100644 --- a/example/playground/ipapilio.cpp +++ b/example/playground/ipapilio.cpp @@ -139,23 +139,6 @@ void ipapilio::addf() { std::string str_val = detail::input(std::cin, "addf"); -#ifndef PAPILIO_STDLIB_LIBCPP - long double val; - auto result = std::from_chars( - std::to_address(str_val.begin()), - std::to_address(str_val.end()), - val - ); - if(result.ec != std::errc()) - { - papilio::println( - papilio::fg(papilio::color::red) | papilio::style::bold, - "Bad value: {}", - std::make_error_code(result.ec).message() - ); - return; - } -#else float val; try { @@ -180,7 +163,6 @@ void ipapilio::addf() ); return; } -#endif m_args.push(val); papilio::println( diff --git a/include/papilio/script/interpreter.hpp b/include/papilio/script/interpreter.hpp index 0411f16..07dddd5 100644 --- a/include/papilio/script/interpreter.hpp +++ b/include/papilio/script/interpreter.hpp @@ -9,10 +9,6 @@ #include #include "../core.hpp" #include "../access.hpp" -#ifdef PAPILIO_STDLIB_LIBCPP -// from_chars of libc++ is broken, use stringstream as a fallback. -# include -#endif namespace papilio::script { @@ -41,11 +37,7 @@ namespace detail class variable_base { public: -#ifndef PAPILIO_PLATFORM_EMSCRIPTEN - using float_type = long double; -#else using float_type = float; -#endif protected: [[noreturn]] @@ -105,7 +97,7 @@ class basic_variable : public detail::variable_base } else if constexpr(floating_point) { - return variant_type(in_place_type, arg); + return variant_type(in_place_type, static_cast(arg)); } else if constexpr(basic_string_like) { @@ -144,7 +136,7 @@ class basic_variable : public detail::variable_base template basic_variable(T f) - : m_var(std::in_place_type, f) + : m_var(std::in_place_type, static_cast(f)) {} basic_variable(string_container_type str) @@ -517,6 +509,8 @@ PAPILIO_EXPORT class script_base static bool is_field_name_end_ch(char32_t ch) noexcept; static char32_t get_esc_ch(char32_t ch) noexcept; + + static float chars_to_float(const char* start, const char* stop); }; PAPILIO_EXPORT template @@ -721,33 +715,12 @@ class basic_interpreter_base : public script_base return std::make_pair(value, start); } - template - static T conv_float_impl(const char* start, const char* stop) - { - T val = static_cast(0); - -#ifndef PAPILIO_STDLIB_LIBCPP - std::from_chars(start, stop, val); - return val; - -#else - // from_chars of libc++ is broken, use stringstream as a fallback. - std::stringstream ss(std::string(start, stop)); - - ss.imbue(std::locale::classic()); - ss >> val; - - return val; -#endif - } - // Converts [start, stop) to a floating point - template - static T conv_float(iterator start, iterator stop) + static float conv_float(iterator start, iterator stop) { if constexpr(char8_like) { - return conv_float_impl( + return chars_to_float( std::bit_cast(start.base()), std::bit_cast(stop.base()) ); @@ -755,7 +728,7 @@ class basic_interpreter_base : public script_base else { std::string tmp = string_ref_type(start, stop).to_string(); - return conv_float_impl( + return chars_to_float( std::to_address(tmp.begin()), std::to_address(tmp.end()) ); @@ -1244,7 +1217,7 @@ class basic_interpreter : iterator float_end = std::find_if_not(int_end, stop, utf::is_digit); using float_type = typename variable_type::float_type; - float_type val = my_base::template conv_float( + float_type val = my_base::conv_float( start, float_end ); diff --git a/src/script/interpreter.cpp b/src/script/interpreter.cpp index b5f0d04..afde0bb 100644 --- a/src/script/interpreter.cpp +++ b/src/script/interpreter.cpp @@ -1,5 +1,10 @@ #include #include +#ifdef PAPILIO_STDLIB_LIBCPP +// from_chars of libc++ is broken, use stringstream as a fallback. +# include +# define PAPILIO_ENABLE_LIBCPP_CHARCONV_WORKAROUND 1 +#endif namespace papilio::script { @@ -7,12 +12,13 @@ bad_variable_access::~bad_variable_access() = default; invalid_conversion::~invalid_conversion() = default; -static const char* to_cstr(script_error_code ec) noexcept +static std::string_view script_ec_to_sv(script_error_code ec) noexcept { + using namespace std::literals; using enum script_error_code; #define PAPILIO_SCRIPT_ERR(code, msg) \ - case code: return msg + case code: return msg##sv switch(ec) { @@ -33,12 +39,12 @@ static const char* to_cstr(script_error_code ec) noexcept std::string to_string(script_error_code ec) { - return to_cstr(ec); + return std::string(script_ec_to_sv(ec)); } std::ostream& operator<<(std::ostream& os, script_error_code ec) { - os << to_cstr(ec); + os << script_ec_to_sv(ec); return os; } @@ -114,6 +120,43 @@ char32_t script_base::get_esc_ch(char32_t ch) noexcept return ch; } } + +float script_base::chars_to_float(const char* start, const char* stop) +{ +#ifndef PAPILIO_ENABLE_LIBCPP_CHARCONV_WORKAROUND + // Ordinary implementation using + + float val; + auto result = std::from_chars( + start, stop, val, std::chars_format::fixed + ); + if(result.ec != std::errc()) + { + throw std::runtime_error("invalid float"); + } + + return val; + +#else + // PAPILIO_ENABLE_LIBCPP_CHARCONV_WORKAROUND is defined + // Workaround for libc++ using + + std::stringstream ss; + ss.imbue(std::locale::classic()); + ss.write(start, stop - start); + + float val; + ss >> val; + + if(!ss.good()) + { + throw std::runtime_error("invalid float"); + } + + return val; + +#endif +} } // namespace papilio::script #include diff --git a/test/test_script_interpreter.cpp b/test/test_script_interpreter.cpp index 837474e..cba1c75 100644 --- a/test/test_script_interpreter.cpp +++ b/test/test_script_interpreter.cpp @@ -141,7 +141,7 @@ TEST(variable, equal) { variable var1 = 1.0f; variable var2 = 1.1f; - EXPECT_TRUE(var1.equal(var2, 0.11L)); + EXPECT_TRUE(var1.equal(var2, 0.11f)); } { @@ -203,8 +203,8 @@ TEST(variable, access) variable var = 10.0f; ASSERT_TRUE(var.get_if()); - EXPECT_DOUBLE_EQ(static_cast(*var.get_if()), 10.0); - EXPECT_DOUBLE_EQ(static_cast(var.get()), 10.0); + EXPECT_FLOAT_EQ(*var.get_if(), 10.0f); + EXPECT_FLOAT_EQ(var.get(), 10.0f); EXPECT_THROW((void)var.get(), bad_variable_access);