diff --git a/public/configs/CMakeLists.txt b/public/configs/CMakeLists.txt index 0bebe0a..01e9243 100644 --- a/public/configs/CMakeLists.txt +++ b/public/configs/CMakeLists.txt @@ -12,5 +12,5 @@ set_target_properties( RUNTIME_OUTPUT_DIRECTORY_DEBUG ${CMAKE_SOURCE_DIR}/bin RUNTIME_OUTPUT_DIRECTORY_RELEASE ${CMAKE_SOURCE_DIR}/bin) if(MSVC) - target_compile_options(mini_lisp PRIVATE /utf-8 /Zc:preprocessor) + target_compile_options(mini_lisp PRIVATE /utf-8) endif() diff --git a/public/configs/xmake.lua b/public/configs/xmake.lua index d7a0387..9368337 100644 --- a/public/configs/xmake.lua +++ b/public/configs/xmake.lua @@ -4,6 +4,4 @@ target("mini_lisp") add_files("src/*.cpp") set_languages("c++20") set_targetdir("bin") - if is_plat("windows") then - add_cxflags("/utf-8", "/Zc:preprocessor") - end + set_encodings("utf-8") diff --git a/public/src/rjsj_test.hpp b/public/src/rjsj_test.hpp index c479f67..b26fe93 100644 --- a/public/src/rjsj_test.hpp +++ b/public/src/rjsj_test.hpp @@ -320,9 +320,14 @@ inline Value buildValueFromStr(const std::string& str) { * CONTROLLER * **************/ +struct Case { + std::string input; + std::optional output; +}; + struct Cases { const char* name; - std::vector>> cases; + std::vector cases; }; #ifdef RMLT_INTERNAL_CONCEPT_ENABLED @@ -356,7 +361,7 @@ class TestController { bool test() { std::vector> nums; bool allResult = true; - for (auto case_ : cases) { + for (const auto& case_ : cases) { env = E{}; int successNum = 0; std::cout << "\033[1mTesting " << case_.name << "\033[0m\n"; @@ -411,155 +416,24 @@ class TestController { } }; -} // namespace rjsj_mini_lisp_test +// Since gcc10, msvc 19.26(VS2019) and clang 12 +template +struct FixedString { + char str[N]; + constexpr FixedString(const char (&input)[N]) { + for (std::size_t i = 0; i < N; i++) str[i] = input[i]; + } +}; -/*********************** - * PP-META-PROGRAMMING * - ***********************/ +template +struct rjsj_mini_lisp_test_cases {}; -#if defined(_MSC_VER) && (!defined(_MSVC_TRADITIONAL) || _MSVC_TRADITIONAL) -#error Traditional MSVC preprocessing mode is not supported. Please enable /Zc:preprocessor flag. -#endif +template +std::vector collectCases() { + return {rjsj_mini_lisp_test_cases::caseCollection...}; +} -#define PP_REMOVE_PARENS(T) PP_REMOVE_PARENS_IMPL T -#define PP_REMOVE_PARENS_IMPL(...) __VA_ARGS__ -#define PP_COMMA() , -#define PP_LPAREN() ( -#define PP_RPAREN() ) -#define PP_EMPTY() -#define PP_CONCAT(A, B) PP_CONCAT_IMPL(A, B) -#define PP_CONCAT_IMPL(A, B) A##B -#define PP_INC(N) PP_CONCAT(PP_INC_, N) -#define PP_INC_0 1 -#define PP_INC_1 2 -#define PP_INC_2 3 -#define PP_INC_3 4 -#define PP_INC_4 5 -#define PP_INC_5 6 -#define PP_INC_6 7 -#define PP_INC_7 8 -#define PP_INC_8 9 -#define PP_INC_9 10 -#define PP_INC_10 11 -#define PP_INC_11 12 -#define PP_INC_12 13 -#define PP_INC_13 14 -#define PP_INC_14 15 -#define PP_INC_15 16 -#define PP_NOT(N) PP_CONCAT(PP_NOT_, N) -#define PP_BOOL(N) PP_CONCAT(PP_BOOL_, N) -#define PP_BOOL_0 0 -#define PP_BOOL_1 1 -#define PP_BOOL_2 1 -#define PP_BOOL_3 1 -#define PP_BOOL_4 1 -#define PP_BOOL_5 1 -#define PP_BOOL_6 1 -#define PP_BOOL_7 1 -#define PP_BOOL_8 1 -#define PP_BOOL_9 1 -#define PP_BOOL_10 1 -#define PP_BOOL_11 1 -#define PP_BOOL_12 1 -#define PP_BOOL_13 1 -#define PP_BOOL_14 1 -#define PP_BOOL_15 1 -#define PP_IF(PRED, THEN, ELSE) PP_CONCAT(PP_IF_, PP_BOOL(PRED))(THEN, ELSE) -#define PP_IF_1(THEN, ELSE) THEN -#define PP_IF_0(THEN, ELSE) ELSE -#define PP_COMMA_IF(N) PP_IF(N, PP_COMMA, PP_EMPTY)() -#define PP_NOT_0 1 -#define PP_NOT_1 0 -#define PP_AND(A, B) PP_CONCAT(PP_AND_, PP_CONCAT(A, B)) -#define PP_AND_00 0 -#define PP_AND_01 0 -#define PP_AND_10 0 -#define PP_AND_11 1 -#define PP_GET_N(N, ...) PP_CONCAT(PP_GET_N_, N)(__VA_ARGS__) -#define PP_GET_N_0(_0, ...) _0 -#define PP_GET_N_1(_0, _1, ...) _1 -#define PP_GET_N_2(_0, _1, _2, ...) _2 -#define PP_GET_N_3(_0, _1, _2, _3, ...) _3 -#define PP_GET_N_4(_0, _1, _2, _3, _4, ...) _4 -#define PP_GET_N_5(_0, _1, _2, _3, _4, _5, ...) _5 -#define PP_GET_N_6(_0, _1, _2, _3, _4, _5, _6, ...) _6 -#define PP_GET_N_7(_0, _1, _2, _3, _4, _5, _6, _7, ...) _7 -#define PP_GET_N_8(_0, _1, _2, _3, _4, _5, _6, _7, _8, ...) _8 -#define PP_GET_N_9(_0, _1, _2, _3, _4, _5, _6, _7, _8, _9, ...) _9 -#define PP_GET_N_10(_0, _1, _2, _3, _4, _5, _6, _7, _8, _9, _10, ...) _10 -#define PP_GET_N_11(_0, _1, _2, _3, _4, _5, _6, _7, _8, _9, _10, _11, ...) _11 -#define PP_GET_N_12(_0, _1, _2, _3, _4, _5, _6, _7, _8, _9, _10, _11, _12, ...) _12 -#define PP_GET_N_13(_0, _1, _2, _3, _4, _5, _6, _7, _8, _9, _10, _11, _12, _13, ...) _13 -#define PP_GET_N_14(_0, _1, _2, _3, _4, _5, _6, _7, _8, _9, _10, _11, _12, _13, _14, ...) _14 -#define PP_GET_N_15(_0, _1, _2, _3, _4, _5, _6, _7, _8, _9, _10, _11, _12, _13, _14, _15, ...) _15 -#define PP_GET_N_16(_0, _1, _2, _3, _4, _5, _6, _7, _8, _9, _10, _11, _12, _13, _14, _15, _16, \ - ...) \ - _16 -#define PP_IS_EMPTY(...) \ - PP_AND(PP_AND(PP_NOT(PP_HAS_COMMA(__VA_ARGS__)), PP_NOT(PP_HAS_COMMA(__VA_ARGS__()))), \ - PP_AND(PP_NOT(PP_HAS_COMMA(PP_COMMA_V __VA_ARGS__)), \ - PP_HAS_COMMA(PP_COMMA_V __VA_ARGS__()))) -#define PP_HAS_COMMA(...) \ - PP_GET_N_16(__VA_ARGS__, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0) -#define PP_COMMA_V(...) , -#define PP_VA_OPT_COMMA(...) PP_COMMA_IF(PP_NOT(PP_IS_EMPTY(__VA_ARGS__))) -#define PP_NARG(...) \ - PP_GET_N(16, __VA_ARGS__ PP_VA_OPT_COMMA(__VA_ARGS__) 16, 15, 14, 13, 12, 11, 10, 9, 8, 7, 6, \ - 5, 4, 3, 2, 1, 0) -#define PP_FOR_EACH(DO, CTX, ...) \ - PP_CONCAT(PP_FOR_EACH_, PP_NARG(__VA_ARGS__))(DO, CTX, 0, __VA_ARGS__) -#define PP_FOR_EACH_0(DO, CTX, IDX, ...) -#define PP_FOR_EACH_1(DO, CTX, IDX, VAR, ...) DO(VAR, IDX, CTX) -#define PP_FOR_EACH_2(DO, CTX, IDX, VAR, ...) \ - DO(VAR, IDX, CTX) \ - PP_FOR_EACH_1(DO, CTX, PP_INC(IDX), __VA_ARGS__) -#define PP_FOR_EACH_3(DO, CTX, IDX, VAR, ...) \ - DO(VAR, IDX, CTX) \ - PP_FOR_EACH_2(DO, CTX, PP_INC(IDX), __VA_ARGS__) -#define PP_FOR_EACH_4(DO, CTX, IDX, VAR, ...) \ - DO(VAR, IDX, CTX) \ - PP_FOR_EACH_3(DO, CTX, PP_INC(IDX), __VA_ARGS__) -#define PP_FOR_EACH_5(DO, CTX, IDX, VAR, ...) \ - DO(VAR, IDX, CTX) \ - PP_FOR_EACH_4(DO, CTX, PP_INC(IDX), __VA_ARGS__) -#define PP_FOR_EACH_6(DO, CTX, IDX, VAR, ...) \ - DO(VAR, IDX, CTX) \ - PP_FOR_EACH_5(DO, CTX, PP_INC(IDX), __VA_ARGS__) -#define PP_FOR_EACH_7(DO, CTX, IDX, VAR, ...) \ - DO(VAR, IDX, CTX) \ - PP_FOR_EACH_6(DO, CTX, PP_INC(IDX), __VA_ARGS__) -#define PP_FOR_EACH_8(DO, CTX, IDX, VAR, ...) \ - DO(VAR, IDX, CTX) \ - PP_FOR_EACH_7(DO, CTX, PP_INC(IDX), __VA_ARGS__) -#define PP_FOR_EACH_9(DO, CTX, IDX, VAR, ...) \ - DO(VAR, IDX, CTX) \ - PP_FOR_EACH_8(DO, CTX, PP_INC(IDX), __VA_ARGS__) -#define PP_FOR_EACH_10(DO, CTX, IDX, VAR, ...) \ - DO(VAR, IDX, CTX) \ - PP_FOR_EACH_9(DO, CTX, PP_INC(IDX), __VA_ARGS__) -#define PP_FOR_EACH_11(DO, CTX, IDX, VAR, ...) \ - DO(VAR, IDX, CTX) \ - PP_FOR_EACH_10(DO, CTX, PP_INC(IDX), __VA_ARGS__) -#define PP_FOR_EACH_12(DO, CTX, IDX, VAR, ...) \ - DO(VAR, IDX, CTX) \ - PP_FOR_EACH_11(DO, CTX, PP_INC(IDX), __VA_ARGS__) -#define PP_FOR_EACH_13(DO, CTX, IDX, VAR, ...) \ - DO(VAR, IDX, CTX) \ - PP_FOR_EACH_12(DO, CTX, PP_INC(IDX), __VA_ARGS__) -#define PP_FOR_EACH_14(DO, CTX, IDX, VAR, ...) \ - DO(VAR, IDX, CTX) \ - PP_FOR_EACH_13(DO, CTX, PP_INC(IDX), __VA_ARGS__) -#define PP_FOR_EACH_15(DO, CTX, IDX, VAR, ...) \ - DO(VAR, IDX, CTX) \ - PP_FOR_EACH_14(DO, CTX, PP_INC(IDX), __VA_ARGS__) -#define PP_FOR_EACH_16(DO, CTX, IDX, VAR, ...) \ - DO(VAR, IDX, CTX) \ - PP_FOR_EACH_15(DO, CTX, PP_INC(IDX), __VA_ARGS__) - -#define RMLT_INTERNAL_CASE_PREFIXED(name) PP_CONCAT(rjsj_mini_lisp_test_, name) - -#define RMLT_INTERNAL_FOREACH_ADD_PREFIX(VAR, IDX, CTX) \ - PP_COMMA_IF(IDX) RMLT_INTERNAL_CASE_PREFIXED(VAR) +} // namespace rjsj_mini_lisp_test #ifdef RJSJ_TEST_NO_EXIT #define RMLT_INTERNAL_EXIT(...) static_cast(__VA_ARGS__) @@ -573,11 +447,11 @@ class TestController { #if defined(RJSJ_TEST_ENABLED) && RJSJ_TEST_ENABLED -#define RJSJ_TEST(CTX_TYPE, ...) \ - do { \ - rjsj_mini_lisp_test::TestController controller( \ - {PP_FOR_EACH(RMLT_INTERNAL_FOREACH_ADD_PREFIX, , __VA_ARGS__)}); \ - RMLT_INTERNAL_EXIT(controller.test() ? 0 : 1); \ +#define RJSJ_TEST(CTX_TYPE, ...) \ + do { \ + rjsj_mini_lisp_test::TestController controller \ + {rjsj_mini_lisp_test::collectCases<__VA_ARGS__>()}; \ + RMLT_INTERNAL_EXIT(controller.test() ? 0 : 1); \ } while (0) #else @@ -586,14 +460,17 @@ class TestController { #endif -#define RMLT_BEGIN_CASES(NAME) \ - static const rjsj_mini_lisp_test::Cases RMLT_INTERNAL_CASE_PREFIXED(NAME) { \ - #NAME, { -#define RMLT_CASE(input, ...) {input, PP_IF(PP_IS_EMPTY(__VA_ARGS__), std::nullopt, __VA_ARGS__)}, +#define RMLT_BEGIN_CASES(NAME) \ + template <> \ + struct rjsj_mini_lisp_test::rjsj_mini_lisp_test_cases<#NAME> { \ + inline static rjsj_mini_lisp_test::Cases caseCollection { \ + #NAME, { +#define RMLT_CASE(...) {__VA_ARGS__}, + #define RMLT_END_CASES(...) \ } \ - } \ - ; + }; \ + }; /******************** * CASES DEFINITION * diff --git a/public/vs/mini-lisp.vcxproj b/public/vs/mini-lisp.vcxproj index f54907b..1bcf91a 100644 --- a/public/vs/mini-lisp.vcxproj +++ b/public/vs/mini-lisp.vcxproj @@ -49,7 +49,7 @@ true _DEBUG;_CONSOLE;%(PreprocessorDefinitions) true - true + false stdcpp20 /utf-8 %(AdditionalOptions)