Skip to content

消除msvc的预处理器问题 #2

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 2 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion public/configs/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -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()
4 changes: 1 addition & 3 deletions public/configs/xmake.lua
Original file line number Diff line number Diff line change
Expand Up @@ -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")
195 changes: 36 additions & 159 deletions public/src/rjsj_test.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -320,9 +320,14 @@ inline Value buildValueFromStr(const std::string& str) {
* CONTROLLER *
**************/

struct Case {
std::string input;
std::optional<std::string> output;
};

struct Cases {
const char* name;
std::vector<std::pair<std::string, std::optional<std::string>>> cases;
std::vector<Case> cases;
};

#ifdef RMLT_INTERNAL_CONCEPT_ENABLED
Expand Down Expand Up @@ -356,7 +361,7 @@ class TestController {
bool test() {
std::vector<std::pair<int, int>> 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";
Expand Down Expand Up @@ -411,155 +416,24 @@ class TestController {
}
};

} // namespace rjsj_mini_lisp_test
// Since gcc10, msvc 19.26(VS2019) and clang 12
template <std::size_t N>
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 <FixedString InputStr>
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 <FixedString... InputStr>
std::vector<rjsj_mini_lisp_test::Cases> collectCases() {
return {rjsj_mini_lisp_test_cases<InputStr>::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<void>(__VA_ARGS__)
Expand All @@ -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<CTX_TYPE> 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<CTX_TYPE> controller \
{rjsj_mini_lisp_test::collectCases<__VA_ARGS__>()}; \
RMLT_INTERNAL_EXIT(controller.test() ? 0 : 1); \
} while (0)

#else
Expand All @@ -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 *
Expand Down
2 changes: 1 addition & 1 deletion public/vs/mini-lisp.vcxproj
Original file line number Diff line number Diff line change
Expand Up @@ -49,7 +49,7 @@
<SDLCheck>true</SDLCheck>
<PreprocessorDefinitions>_DEBUG;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<ConformanceMode>true</ConformanceMode>
<UseStandardPreprocessor>true</UseStandardPreprocessor>
<UseStandardPreprocessor>false</UseStandardPreprocessor>
<LanguageStandard>stdcpp20</LanguageStandard>
<AdditionalOptions>/utf-8 %(AdditionalOptions)</AdditionalOptions>
</ClCompile>
Expand Down