mirror of
https://github.com/ChaiScript/ChaiScript.git
synced 2026-04-30 19:09:26 +08:00
Enable warnings as errors (#694)
* Enable warnings as errors * Fix warnings * upgrade catch
This commit is contained in:
parent
cd8dacccc6
commit
0b75a8be7d
@ -155,7 +155,7 @@ else()
|
|||||||
endif()
|
endif()
|
||||||
|
|
||||||
if(MSVC)
|
if(MSVC)
|
||||||
add_definitions(/W4 /w14545 /w34242 /w34254 /w34287 /w44263 /w44265 /w44296 /w44311 /w44826 /we4289 /w14546 /w14547 /w14549 /w14555 /w14619 /w14905 /w14906 /w14928)
|
add_definitions(/WX /W4 /w14545 /w34242 /w34254 /w34287 /w44263 /w44265 /w44296 /w44311 /w44826 /we4289 /w14546 /w14547 /w14549 /w14555 /w14619 /w14905 /w14906 /w14928)
|
||||||
|
|
||||||
if(MSVC_VERSION STREQUAL "1800")
|
if(MSVC_VERSION STREQUAL "1800")
|
||||||
# VS2013 doesn't have magic statics
|
# VS2013 doesn't have magic statics
|
||||||
@ -175,10 +175,10 @@ if(MSVC)
|
|||||||
# how to workaround or fix the error. So I'm disabling it globally.
|
# how to workaround or fix the error. So I'm disabling it globally.
|
||||||
add_definitions(/wd4503)
|
add_definitions(/wd4503)
|
||||||
else()
|
else()
|
||||||
add_definitions(-Wall -Wextra -Wconversion -Wshadow -Wnon-virtual-dtor -Wold-style-cast -Wcast-align -Wcast-qual -Wunused -Woverloaded-virtual -Wno-noexcept-type -Wpedantic -Werror=return-type)
|
add_definitions(-Werror -Wall -Wextra -Wconversion -Wshadow -Wnon-virtual-dtor -Wold-style-cast -Wcast-align -Wcast-qual -Wunused -Woverloaded-virtual -Wno-noexcept-type -Wpedantic -Werror=return-type)
|
||||||
|
|
||||||
if("${CMAKE_CXX_COMPILER_ID}" STREQUAL "Clang" OR "${CMAKE_CXX_COMPILER_ID}" STREQUAL "AppleClang")
|
if("${CMAKE_CXX_COMPILER_ID}" STREQUAL "Clang" OR "${CMAKE_CXX_COMPILER_ID}" STREQUAL "AppleClang")
|
||||||
add_definitions(-Weverything -Wno-c++98-compat-pedantic -Wno-c++98-compat -Wno-documentation -Wno-switch-enum -Wno-weak-vtables -Wno-missing-prototypes -Wno-padded -Wno-missing-noreturn -Wno-exit-time-destructors -Wno-documentation-unknown-command -Wno-unused-template -Wno-undef -Wno-double-promotion)
|
add_definitions(-Weverything -Wno-c++98-compat-pedantic -Wno-c++98-compat -Wno-documentation -Wno-switch-enum -Wno-weak-vtables -Wno-missing-prototypes -Wno-padded -Wno-missing-noreturn -Wno-exit-time-destructors -Wno-documentation-unknown-command -Wno-unused-template -Wno-undef -Wno-double-promotion -Wno-switch-default -Wno-nrvo -Wno-shadow-uncaptured-local -Wno-unsafe-buffer-usage-in-libc-call -Wno-c++20-extensions -Wno-unknown-warning-option -Wno-poison-system-directories -Wno-c++20-compat -Wno-c++17-compat)
|
||||||
else()
|
else()
|
||||||
add_definitions(-Wnoexcept)
|
add_definitions(-Wnoexcept)
|
||||||
endif()
|
endif()
|
||||||
@ -390,8 +390,16 @@ if(BUILD_TESTING)
|
|||||||
)
|
)
|
||||||
|
|
||||||
if(NOT UNIT_TEST_LIGHT)
|
if(NOT UNIT_TEST_LIGHT)
|
||||||
|
add_library(catch2 STATIC unittests/catch_amalgamated.cpp)
|
||||||
|
if(NOT MSVC)
|
||||||
|
target_compile_options(catch2 PRIVATE -Wno-conversion -Wno-noexcept -Wno-maybe-uninitialized)
|
||||||
|
endif()
|
||||||
|
if("${CMAKE_CXX_COMPILER_ID}" STREQUAL "Clang" OR "${CMAKE_CXX_COMPILER_ID}" STREQUAL "AppleClang")
|
||||||
|
target_compile_options(catch2 PUBLIC -Wno-unknown-warning-option -Wno-covered-switch-default -Wno-disabled-macro-expansion -Wno-unsafe-buffer-usage -Wno-unused-macros)
|
||||||
|
endif()
|
||||||
|
|
||||||
add_executable(compiled_tests unittests/compiled_tests.cpp)
|
add_executable(compiled_tests unittests/compiled_tests.cpp)
|
||||||
target_link_libraries(compiled_tests ${LIBS} ${CHAISCRIPT_LIBS})
|
target_link_libraries(compiled_tests catch2 ${LIBS} ${CHAISCRIPT_LIBS})
|
||||||
catch_discover_tests(compiled_tests TEST_PREFIX "compiled.")
|
catch_discover_tests(compiled_tests TEST_PREFIX "compiled.")
|
||||||
|
|
||||||
add_executable(static_chaiscript_test unittests/static_chaiscript.cpp)
|
add_executable(static_chaiscript_test unittests/static_chaiscript.cpp)
|
||||||
@ -403,7 +411,7 @@ if(BUILD_TESTING)
|
|||||||
add_test(NAME Boxed_Cast_Test COMMAND boxed_cast_test)
|
add_test(NAME Boxed_Cast_Test COMMAND boxed_cast_test)
|
||||||
|
|
||||||
add_executable(type_info_test unittests/type_info_test.cpp)
|
add_executable(type_info_test unittests/type_info_test.cpp)
|
||||||
target_link_libraries(type_info_test ${LIBS})
|
target_link_libraries(type_info_test catch2 ${LIBS})
|
||||||
add_test(NAME Type_Info_Test COMMAND type_info_test)
|
add_test(NAME Type_Info_Test COMMAND type_info_test)
|
||||||
|
|
||||||
add_executable(c_linkage_test unittests/c_linkage_test.cpp)
|
add_executable(c_linkage_test unittests/c_linkage_test.cpp)
|
||||||
|
|||||||
@ -33,6 +33,13 @@ same as the Catch name; see also ``TEST_PREFIX`` and ``TEST_SUFFIX``.
|
|||||||
[TEST_SUFFIX suffix]
|
[TEST_SUFFIX suffix]
|
||||||
[PROPERTIES name1 value1...]
|
[PROPERTIES name1 value1...]
|
||||||
[TEST_LIST var]
|
[TEST_LIST var]
|
||||||
|
[REPORTER reporter]
|
||||||
|
[OUTPUT_DIR dir]
|
||||||
|
[OUTPUT_PREFIX prefix]
|
||||||
|
[OUTPUT_SUFFIX suffix]
|
||||||
|
[DISCOVERY_MODE <POST_BUILD|PRE_TEST>]
|
||||||
|
[SKIP_IS_FAILURE]
|
||||||
|
[ADD_TAGS_AS_LABELS]
|
||||||
)
|
)
|
||||||
|
|
||||||
``catch_discover_tests`` sets up a post-build command on the test executable
|
``catch_discover_tests`` sets up a post-build command on the test executable
|
||||||
@ -90,86 +97,222 @@ same as the Catch name; see also ``TEST_PREFIX`` and ``TEST_SUFFIX``.
|
|||||||
executable is being used in multiple calls to ``catch_discover_tests()``.
|
executable is being used in multiple calls to ``catch_discover_tests()``.
|
||||||
Note that this variable is only available in CTest.
|
Note that this variable is only available in CTest.
|
||||||
|
|
||||||
|
``REPORTER reporter``
|
||||||
|
Use the specified reporter when running the test case. The reporter will
|
||||||
|
be passed to the Catch executable as ``--reporter reporter``.
|
||||||
|
|
||||||
|
``OUTPUT_DIR dir``
|
||||||
|
If specified, the parameter is passed along as
|
||||||
|
``--out dir/<test_name>`` to Catch executable. The actual file name is the
|
||||||
|
same as the test name. This should be used instead of
|
||||||
|
``EXTRA_ARGS --out foo`` to avoid race conditions writing the result output
|
||||||
|
when using parallel test execution.
|
||||||
|
|
||||||
|
``OUTPUT_PREFIX prefix``
|
||||||
|
May be used in conjunction with ``OUTPUT_DIR``.
|
||||||
|
If specified, ``prefix`` is added to each output file name, like so
|
||||||
|
``--out dir/prefix<test_name>``.
|
||||||
|
|
||||||
|
``OUTPUT_SUFFIX suffix``
|
||||||
|
May be used in conjunction with ``OUTPUT_DIR``.
|
||||||
|
If specified, ``suffix`` is added to each output file name, like so
|
||||||
|
``--out dir/<test_name>suffix``. This can be used to add a file extension to
|
||||||
|
the output e.g. ".xml".
|
||||||
|
|
||||||
|
``DL_PATHS path...``
|
||||||
|
Specifies paths that need to be set for the dynamic linker to find shared
|
||||||
|
libraries/DLLs when running the test executable (PATH/LD_LIBRARY_PATH respectively).
|
||||||
|
These paths will both be set when retrieving the list of test cases from the
|
||||||
|
test executable and when the tests are executed themselves. This requires
|
||||||
|
cmake/ctest >= 3.22.
|
||||||
|
|
||||||
|
``DL_FRAMEWORK_PATHS path...``
|
||||||
|
Specifies paths that need to be set for the dynamic linker to find libraries
|
||||||
|
packaged as frameworks on Apple platforms when running the test executable
|
||||||
|
(DYLD_FRAMEWORK_PATH). These paths will both be set when retrieving the list
|
||||||
|
of test cases from the test executable and when the tests are executed themselves.
|
||||||
|
This requires cmake/ctest >= 3.22.
|
||||||
|
|
||||||
|
``DISCOVERY_MODE mode``
|
||||||
|
Provides control over when ``catch_discover_tests`` performs test discovery.
|
||||||
|
By default, ``POST_BUILD`` sets up a post-build command to perform test discovery
|
||||||
|
at build time. In certain scenarios, like cross-compiling, this ``POST_BUILD``
|
||||||
|
behavior is not desirable. By contrast, ``PRE_TEST`` delays test discovery until
|
||||||
|
just prior to test execution. This way test discovery occurs in the target environment
|
||||||
|
where the test has a better chance at finding appropriate runtime dependencies.
|
||||||
|
|
||||||
|
``DISCOVERY_MODE`` defaults to the value of the
|
||||||
|
``CMAKE_CATCH_DISCOVER_TESTS_DISCOVERY_MODE`` variable if it is not passed when
|
||||||
|
calling ``catch_discover_tests``. This provides a mechanism for globally selecting
|
||||||
|
a preferred test discovery behavior without having to modify each call site.
|
||||||
|
|
||||||
|
``SKIP_IS_FAILURE``
|
||||||
|
Disables skipped test detection.
|
||||||
|
|
||||||
|
``ADD_TAGS_AS_LABELS``
|
||||||
|
Adds all test tags as CTest labels.
|
||||||
|
|
||||||
#]=======================================================================]
|
#]=======================================================================]
|
||||||
|
|
||||||
#------------------------------------------------------------------------------
|
#------------------------------------------------------------------------------
|
||||||
function(catch_discover_tests TARGET)
|
function(catch_discover_tests TARGET)
|
||||||
|
|
||||||
cmake_parse_arguments(
|
cmake_parse_arguments(
|
||||||
""
|
""
|
||||||
""
|
"SKIP_IS_FAILURE;ADD_TAGS_AS_LABELS"
|
||||||
"TEST_PREFIX;TEST_SUFFIX;WORKING_DIRECTORY;TEST_LIST"
|
"TEST_PREFIX;TEST_SUFFIX;WORKING_DIRECTORY;TEST_LIST;REPORTER;OUTPUT_DIR;OUTPUT_PREFIX;OUTPUT_SUFFIX;DISCOVERY_MODE"
|
||||||
"TEST_SPEC;EXTRA_ARGS;PROPERTIES"
|
"TEST_SPEC;EXTRA_ARGS;PROPERTIES;DL_PATHS;DL_FRAMEWORK_PATHS"
|
||||||
${ARGN}
|
${ARGN}
|
||||||
)
|
)
|
||||||
|
|
||||||
|
if(${CMAKE_VERSION} VERSION_LESS "3.19")
|
||||||
|
message(FATAL_ERROR "This script requires JSON support from CMake version 3.19 or greater.")
|
||||||
|
endif()
|
||||||
|
|
||||||
if(NOT _WORKING_DIRECTORY)
|
if(NOT _WORKING_DIRECTORY)
|
||||||
set(_WORKING_DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}")
|
set(_WORKING_DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}")
|
||||||
endif()
|
endif()
|
||||||
if(NOT _TEST_LIST)
|
if(NOT _TEST_LIST)
|
||||||
set(_TEST_LIST ${TARGET}_TESTS)
|
set(_TEST_LIST ${TARGET}_TESTS)
|
||||||
endif()
|
endif()
|
||||||
|
if(_DL_PATHS AND ${CMAKE_VERSION} VERSION_LESS "3.22.0")
|
||||||
|
message(FATAL_ERROR "The DL_PATHS option requires at least cmake 3.22")
|
||||||
|
endif()
|
||||||
|
if(_DL_FRAMEWORK_PATHS AND ${CMAKE_VERSION} VERSION_LESS "3.22.0")
|
||||||
|
message(FATAL_ERROR "The DL_FRAMEWORK_PATHS option requires at least cmake 3.22")
|
||||||
|
endif()
|
||||||
|
if(NOT _DISCOVERY_MODE)
|
||||||
|
if(NOT CMAKE_CATCH_DISCOVER_TESTS_DISCOVERY_MODE)
|
||||||
|
set(CMAKE_CATCH_DISCOVER_TESTS_DISCOVERY_MODE "POST_BUILD")
|
||||||
|
endif()
|
||||||
|
set(_DISCOVERY_MODE ${CMAKE_CATCH_DISCOVER_TESTS_DISCOVERY_MODE})
|
||||||
|
endif()
|
||||||
|
if(NOT _DISCOVERY_MODE MATCHES "^(POST_BUILD|PRE_TEST)$")
|
||||||
|
message(FATAL_ERROR "Unknown DISCOVERY_MODE: ${_DISCOVERY_MODE}")
|
||||||
|
endif()
|
||||||
|
|
||||||
## Generate a unique name based on the extra arguments
|
## Generate a unique name based on the extra arguments
|
||||||
string(SHA1 args_hash "${_TEST_SPEC} ${_EXTRA_ARGS}")
|
string(SHA1 args_hash "${_TEST_SPEC} ${_EXTRA_ARGS} ${_REPORTER} ${_OUTPUT_DIR} ${_OUTPUT_PREFIX} ${_OUTPUT_SUFFIX}")
|
||||||
string(SUBSTRING ${args_hash} 0 7 args_hash)
|
string(SUBSTRING ${args_hash} 0 7 args_hash)
|
||||||
|
|
||||||
# Define rule to generate test list for aforementioned test executable
|
# Define rule to generate test list for aforementioned test executable
|
||||||
set(ctest_include_file "${CMAKE_CURRENT_BINARY_DIR}/${TARGET}_include-${args_hash}.cmake")
|
set(ctest_file_base "${CMAKE_CURRENT_BINARY_DIR}/${TARGET}-${args_hash}")
|
||||||
set(ctest_tests_file "${CMAKE_CURRENT_BINARY_DIR}/${TARGET}_tests-${args_hash}.cmake")
|
set(ctest_include_file "${ctest_file_base}_include.cmake")
|
||||||
|
set(ctest_tests_file "${ctest_file_base}_tests.cmake")
|
||||||
|
|
||||||
get_property(crosscompiling_emulator
|
get_property(crosscompiling_emulator
|
||||||
TARGET ${TARGET}
|
TARGET ${TARGET}
|
||||||
PROPERTY CROSSCOMPILING_EMULATOR
|
PROPERTY CROSSCOMPILING_EMULATOR
|
||||||
)
|
)
|
||||||
add_custom_command(
|
if(NOT _SKIP_IS_FAILURE)
|
||||||
TARGET ${TARGET} POST_BUILD
|
set(_PROPERTIES ${_PROPERTIES} SKIP_RETURN_CODE 4)
|
||||||
BYPRODUCTS "${ctest_tests_file}"
|
endif()
|
||||||
COMMAND "${CMAKE_COMMAND}"
|
|
||||||
-D "TEST_TARGET=${TARGET}"
|
|
||||||
-D "TEST_EXECUTABLE=$<TARGET_FILE:${TARGET}>"
|
|
||||||
-D "TEST_EXECUTOR=${crosscompiling_emulator}"
|
|
||||||
-D "TEST_WORKING_DIR=${_WORKING_DIRECTORY}"
|
|
||||||
-D "TEST_SPEC=${_TEST_SPEC}"
|
|
||||||
-D "TEST_EXTRA_ARGS=${_EXTRA_ARGS}"
|
|
||||||
-D "TEST_PROPERTIES=${_PROPERTIES}"
|
|
||||||
-D "TEST_PREFIX=${_TEST_PREFIX}"
|
|
||||||
-D "TEST_SUFFIX=${_TEST_SUFFIX}"
|
|
||||||
-D "TEST_LIST=${_TEST_LIST}"
|
|
||||||
-D "CTEST_FILE=${ctest_tests_file}"
|
|
||||||
-P "${_CATCH_DISCOVER_TESTS_SCRIPT}"
|
|
||||||
VERBATIM
|
|
||||||
)
|
|
||||||
|
|
||||||
file(WRITE "${ctest_include_file}"
|
if(_DISCOVERY_MODE STREQUAL "POST_BUILD")
|
||||||
"if(EXISTS \"${ctest_tests_file}\")\n"
|
add_custom_command(
|
||||||
" include(\"${ctest_tests_file}\")\n"
|
TARGET ${TARGET} POST_BUILD
|
||||||
"else()\n"
|
BYPRODUCTS "${ctest_tests_file}"
|
||||||
" add_test(${TARGET}_NOT_BUILT-${args_hash} ${TARGET}_NOT_BUILT-${args_hash})\n"
|
COMMAND "${CMAKE_COMMAND}"
|
||||||
"endif()\n"
|
-D "TEST_TARGET=${TARGET}"
|
||||||
)
|
-D "TEST_EXECUTABLE=$<TARGET_FILE:${TARGET}>"
|
||||||
|
-D "TEST_EXECUTOR=${crosscompiling_emulator}"
|
||||||
if(NOT ${CMAKE_VERSION} VERSION_LESS "3.10.0")
|
-D "TEST_WORKING_DIR=${_WORKING_DIRECTORY}"
|
||||||
# Add discovered tests to directory TEST_INCLUDE_FILES
|
-D "TEST_SPEC=${_TEST_SPEC}"
|
||||||
set_property(DIRECTORY
|
-D "TEST_EXTRA_ARGS=${_EXTRA_ARGS}"
|
||||||
APPEND PROPERTY TEST_INCLUDE_FILES "${ctest_include_file}"
|
-D "TEST_PROPERTIES=${_PROPERTIES}"
|
||||||
|
-D "TEST_PREFIX=${_TEST_PREFIX}"
|
||||||
|
-D "TEST_SUFFIX=${_TEST_SUFFIX}"
|
||||||
|
-D "TEST_LIST=${_TEST_LIST}"
|
||||||
|
-D "TEST_REPORTER=${_REPORTER}"
|
||||||
|
-D "TEST_OUTPUT_DIR=${_OUTPUT_DIR}"
|
||||||
|
-D "TEST_OUTPUT_PREFIX=${_OUTPUT_PREFIX}"
|
||||||
|
-D "TEST_OUTPUT_SUFFIX=${_OUTPUT_SUFFIX}"
|
||||||
|
-D "TEST_DL_PATHS=${_DL_PATHS}"
|
||||||
|
-D "TEST_DL_FRAMEWORK_PATHS=${_DL_FRAMEWORK_PATHS}"
|
||||||
|
-D "CTEST_FILE=${ctest_tests_file}"
|
||||||
|
-D "ADD_TAGS_AS_LABELS=${_ADD_TAGS_AS_LABELS}"
|
||||||
|
-P "${_CATCH_DISCOVER_TESTS_SCRIPT}"
|
||||||
|
VERBATIM
|
||||||
)
|
)
|
||||||
else()
|
|
||||||
# Add discovered tests as directory TEST_INCLUDE_FILE if possible
|
file(WRITE "${ctest_include_file}"
|
||||||
get_property(test_include_file_set DIRECTORY PROPERTY TEST_INCLUDE_FILE SET)
|
"if(EXISTS \"${ctest_tests_file}\")\n"
|
||||||
if (NOT ${test_include_file_set})
|
" include(\"${ctest_tests_file}\")\n"
|
||||||
set_property(DIRECTORY
|
"else()\n"
|
||||||
PROPERTY TEST_INCLUDE_FILE "${ctest_include_file}"
|
" add_test(${TARGET}_NOT_BUILT-${args_hash} ${TARGET}_NOT_BUILT-${args_hash})\n"
|
||||||
|
"endif()\n"
|
||||||
|
)
|
||||||
|
|
||||||
|
elseif(_DISCOVERY_MODE STREQUAL "PRE_TEST")
|
||||||
|
|
||||||
|
get_property(GENERATOR_IS_MULTI_CONFIG GLOBAL
|
||||||
|
PROPERTY GENERATOR_IS_MULTI_CONFIG
|
||||||
|
)
|
||||||
|
|
||||||
|
if(GENERATOR_IS_MULTI_CONFIG)
|
||||||
|
set(ctest_tests_file "${ctest_file_base}_tests-$<CONFIG>.cmake")
|
||||||
|
endif()
|
||||||
|
|
||||||
|
string(CONCAT ctest_include_content
|
||||||
|
"if(EXISTS \"$<TARGET_FILE:${TARGET}>\")" "\n"
|
||||||
|
" if(NOT EXISTS \"${ctest_tests_file}\" OR" "\n"
|
||||||
|
" NOT \"${ctest_tests_file}\" IS_NEWER_THAN \"$<TARGET_FILE:${TARGET}>\" OR\n"
|
||||||
|
" NOT \"${ctest_tests_file}\" IS_NEWER_THAN \"\${CMAKE_CURRENT_LIST_FILE}\")\n"
|
||||||
|
" include(\"${_CATCH_DISCOVER_TESTS_SCRIPT}\")" "\n"
|
||||||
|
" catch_discover_tests_impl(" "\n"
|
||||||
|
" TEST_EXECUTABLE" " [==[" "$<TARGET_FILE:${TARGET}>" "]==]" "\n"
|
||||||
|
" TEST_EXECUTOR" " [==[" "${crosscompiling_emulator}" "]==]" "\n"
|
||||||
|
" TEST_WORKING_DIR" " [==[" "${_WORKING_DIRECTORY}" "]==]" "\n"
|
||||||
|
" TEST_SPEC" " [==[" "${_TEST_SPEC}" "]==]" "\n"
|
||||||
|
" TEST_EXTRA_ARGS" " [==[" "${_EXTRA_ARGS}" "]==]" "\n"
|
||||||
|
" TEST_PROPERTIES" " [==[" "${_PROPERTIES}" "]==]" "\n"
|
||||||
|
" TEST_PREFIX" " [==[" "${_TEST_PREFIX}" "]==]" "\n"
|
||||||
|
" TEST_SUFFIX" " [==[" "${_TEST_SUFFIX}" "]==]" "\n"
|
||||||
|
" TEST_LIST" " [==[" "${_TEST_LIST}" "]==]" "\n"
|
||||||
|
" TEST_REPORTER" " [==[" "${_REPORTER}" "]==]" "\n"
|
||||||
|
" TEST_OUTPUT_DIR" " [==[" "${_OUTPUT_DIR}" "]==]" "\n"
|
||||||
|
" TEST_OUTPUT_PREFIX" " [==[" "${_OUTPUT_PREFIX}" "]==]" "\n"
|
||||||
|
" TEST_OUTPUT_SUFFIX" " [==[" "${_OUTPUT_SUFFIX}" "]==]" "\n"
|
||||||
|
" CTEST_FILE" " [==[" "${ctest_tests_file}" "]==]" "\n"
|
||||||
|
" TEST_DL_PATHS" " [==[" "${_DL_PATHS}" "]==]" "\n"
|
||||||
|
" TEST_DL_FRAMEWORK_PATHS" " [==[" "${_DL_FRAMEWORK_PATHS}" "]==]" "\n"
|
||||||
|
" ADD_TAGS_AS_LABELS" " [==[" "${_ADD_TAGS_AS_LABELS}" "]==]" "\n"
|
||||||
|
" )" "\n"
|
||||||
|
" endif()" "\n"
|
||||||
|
" include(\"${ctest_tests_file}\")" "\n"
|
||||||
|
"else()" "\n"
|
||||||
|
" add_test(${TARGET}_NOT_BUILT ${TARGET}_NOT_BUILT)" "\n"
|
||||||
|
"endif()" "\n"
|
||||||
|
)
|
||||||
|
|
||||||
|
if(GENERATOR_IS_MULTI_CONFIG)
|
||||||
|
foreach(_config ${CMAKE_CONFIGURATION_TYPES})
|
||||||
|
file(GENERATE OUTPUT "${ctest_file_base}_include-${_config}.cmake" CONTENT "${ctest_include_content}" CONDITION $<CONFIG:${_config}>)
|
||||||
|
endforeach()
|
||||||
|
string(CONCAT ctest_include_multi_content
|
||||||
|
"if(NOT CTEST_CONFIGURATION_TYPE)" "\n"
|
||||||
|
" message(\"No configuration for testing specified, use '-C <cfg>'.\")" "\n"
|
||||||
|
"else()" "\n"
|
||||||
|
" include(\"${ctest_file_base}_include-\${CTEST_CONFIGURATION_TYPE}.cmake\")" "\n"
|
||||||
|
"endif()" "\n"
|
||||||
)
|
)
|
||||||
|
file(GENERATE OUTPUT "${ctest_include_file}" CONTENT "${ctest_include_multi_content}")
|
||||||
else()
|
else()
|
||||||
message(FATAL_ERROR
|
file(GENERATE OUTPUT "${ctest_file_base}_include.cmake" CONTENT "${ctest_include_content}")
|
||||||
"Cannot set more than one TEST_INCLUDE_FILE"
|
file(WRITE "${ctest_include_file}" "include(\"${ctest_file_base}_include.cmake\")")
|
||||||
)
|
|
||||||
endif()
|
endif()
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
|
# Add discovered tests to directory TEST_INCLUDE_FILES
|
||||||
|
set_property(DIRECTORY
|
||||||
|
APPEND PROPERTY TEST_INCLUDE_FILES "${ctest_include_file}"
|
||||||
|
)
|
||||||
|
|
||||||
endfunction()
|
endfunction()
|
||||||
|
|
||||||
###############################################################################
|
###############################################################################
|
||||||
|
|
||||||
set(_CATCH_DISCOVER_TESTS_SCRIPT
|
set(_CATCH_DISCOVER_TESTS_SCRIPT
|
||||||
${CMAKE_CURRENT_LIST_DIR}/CatchAddTests.cmake
|
${CMAKE_CURRENT_LIST_DIR}/CatchAddTests.cmake
|
||||||
|
CACHE INTERNAL "Catch2 full path to CatchAddTests.cmake helper file"
|
||||||
)
|
)
|
||||||
|
|||||||
@ -1,18 +1,12 @@
|
|||||||
# Distributed under the OSI-approved BSD 3-Clause License. See accompanying
|
# Distributed under the OSI-approved BSD 3-Clause License. See accompanying
|
||||||
# file Copyright.txt or https://cmake.org/licensing for details.
|
# file Copyright.txt or https://cmake.org/licensing for details.
|
||||||
|
|
||||||
set(prefix "${TEST_PREFIX}")
|
|
||||||
set(suffix "${TEST_SUFFIX}")
|
|
||||||
set(spec ${TEST_SPEC})
|
|
||||||
set(extra_args ${TEST_EXTRA_ARGS})
|
|
||||||
set(properties ${TEST_PROPERTIES})
|
|
||||||
set(script)
|
|
||||||
set(suite)
|
|
||||||
set(tests)
|
|
||||||
|
|
||||||
function(add_command NAME)
|
function(add_command NAME)
|
||||||
set(_args "")
|
set(_args "")
|
||||||
foreach(_arg ${ARGN})
|
# use ARGV* instead of ARGN, because ARGN splits arrays into multiple arguments
|
||||||
|
math(EXPR _last_arg ${ARGC}-1)
|
||||||
|
foreach(_n RANGE 1 ${_last_arg})
|
||||||
|
set(_arg "${ARGV${_n}}")
|
||||||
if(_arg MATCHES "[^-./:a-zA-Z0-9_]")
|
if(_arg MATCHES "[^-./:a-zA-Z0-9_]")
|
||||||
set(_args "${_args} [==[${_arg}]==]") # form a bracket_argument
|
set(_args "${_args} [==[${_arg}]==]") # form a bracket_argument
|
||||||
else()
|
else()
|
||||||
@ -22,55 +16,239 @@ function(add_command NAME)
|
|||||||
set(script "${script}${NAME}(${_args})\n" PARENT_SCOPE)
|
set(script "${script}${NAME}(${_args})\n" PARENT_SCOPE)
|
||||||
endfunction()
|
endfunction()
|
||||||
|
|
||||||
# Run test executable to get list of available tests
|
function(catch_discover_tests_impl)
|
||||||
if(NOT EXISTS "${TEST_EXECUTABLE}")
|
|
||||||
message(FATAL_ERROR
|
cmake_parse_arguments(
|
||||||
"Specified test executable '${TEST_EXECUTABLE}' does not exist"
|
""
|
||||||
|
""
|
||||||
|
"TEST_EXECUTABLE;TEST_WORKING_DIR;TEST_OUTPUT_DIR;TEST_OUTPUT_PREFIX;TEST_OUTPUT_SUFFIX;TEST_PREFIX;TEST_REPORTER;TEST_SPEC;TEST_SUFFIX;TEST_LIST;CTEST_FILE"
|
||||||
|
"TEST_EXTRA_ARGS;TEST_PROPERTIES;TEST_EXECUTOR;TEST_DL_PATHS;TEST_DL_FRAMEWORK_PATHS;ADD_TAGS_AS_LABELS"
|
||||||
|
${ARGN}
|
||||||
|
)
|
||||||
|
|
||||||
|
set(add_tags "${_ADD_TAGS_AS_LABELS}")
|
||||||
|
set(prefix "${_TEST_PREFIX}")
|
||||||
|
set(suffix "${_TEST_SUFFIX}")
|
||||||
|
set(spec ${_TEST_SPEC})
|
||||||
|
set(extra_args ${_TEST_EXTRA_ARGS})
|
||||||
|
set(properties ${_TEST_PROPERTIES})
|
||||||
|
set(reporter ${_TEST_REPORTER})
|
||||||
|
set(output_dir ${_TEST_OUTPUT_DIR})
|
||||||
|
set(output_prefix ${_TEST_OUTPUT_PREFIX})
|
||||||
|
set(output_suffix ${_TEST_OUTPUT_SUFFIX})
|
||||||
|
set(dl_paths ${_TEST_DL_PATHS})
|
||||||
|
set(dl_framework_paths ${_TEST_DL_FRAMEWORK_PATHS})
|
||||||
|
set(environment_modifications "")
|
||||||
|
set(script)
|
||||||
|
set(suite)
|
||||||
|
set(tests)
|
||||||
|
|
||||||
|
if(WIN32)
|
||||||
|
set(dl_paths_variable_name PATH)
|
||||||
|
elseif(APPLE)
|
||||||
|
set(dl_paths_variable_name DYLD_LIBRARY_PATH)
|
||||||
|
else()
|
||||||
|
set(dl_paths_variable_name LD_LIBRARY_PATH)
|
||||||
|
endif()
|
||||||
|
|
||||||
|
# Run test executable to get list of available tests
|
||||||
|
if(NOT EXISTS "${_TEST_EXECUTABLE}")
|
||||||
|
message(FATAL_ERROR
|
||||||
|
"Specified test executable '${_TEST_EXECUTABLE}' does not exist"
|
||||||
|
)
|
||||||
|
endif()
|
||||||
|
|
||||||
|
if(dl_paths)
|
||||||
|
cmake_path(CONVERT "$ENV{${dl_paths_variable_name}}" TO_NATIVE_PATH_LIST env_dl_paths)
|
||||||
|
list(PREPEND env_dl_paths "${dl_paths}")
|
||||||
|
cmake_path(CONVERT "${env_dl_paths}" TO_NATIVE_PATH_LIST paths)
|
||||||
|
set(ENV{${dl_paths_variable_name}} "${paths}")
|
||||||
|
endif()
|
||||||
|
|
||||||
|
if(APPLE AND dl_framework_paths)
|
||||||
|
cmake_path(CONVERT "$ENV{DYLD_FRAMEWORK_PATH}" TO_NATIVE_PATH_LIST env_dl_framework_paths)
|
||||||
|
list(PREPEND env_dl_framework_paths "${dl_framework_paths}")
|
||||||
|
cmake_path(CONVERT "${env_dl_framework_paths}" TO_NATIVE_PATH_LIST paths)
|
||||||
|
set(ENV{DYLD_FRAMEWORK_PATH} "${paths}")
|
||||||
|
endif()
|
||||||
|
|
||||||
|
execute_process(
|
||||||
|
COMMAND ${_TEST_EXECUTOR} "${_TEST_EXECUTABLE}" ${spec} --list-tests --reporter json
|
||||||
|
OUTPUT_VARIABLE listing_output
|
||||||
|
RESULT_VARIABLE result
|
||||||
|
WORKING_DIRECTORY "${_TEST_WORKING_DIR}"
|
||||||
|
)
|
||||||
|
if(NOT ${result} EQUAL 0)
|
||||||
|
message(FATAL_ERROR
|
||||||
|
"Error listing tests from executable '${_TEST_EXECUTABLE}':\n"
|
||||||
|
" Result: ${result}\n"
|
||||||
|
" Output: ${listing_output}\n"
|
||||||
|
)
|
||||||
|
endif()
|
||||||
|
|
||||||
|
# Prepare reporter
|
||||||
|
if(reporter)
|
||||||
|
set(reporter_arg "--reporter ${reporter}")
|
||||||
|
|
||||||
|
# Run test executable to check whether reporter is available
|
||||||
|
# note that the use of --list-reporters is not the important part,
|
||||||
|
# we only want to check whether the execution succeeds with ${reporter_arg}
|
||||||
|
execute_process(
|
||||||
|
COMMAND ${_TEST_EXECUTOR} "${_TEST_EXECUTABLE}" ${spec} ${reporter_arg} --list-reporters
|
||||||
|
OUTPUT_VARIABLE reporter_check_output
|
||||||
|
RESULT_VARIABLE reporter_check_result
|
||||||
|
WORKING_DIRECTORY "${_TEST_WORKING_DIR}"
|
||||||
|
)
|
||||||
|
if(${reporter_check_result} EQUAL 255)
|
||||||
|
message(FATAL_ERROR
|
||||||
|
"\"${reporter}\" is not a valid reporter!\n"
|
||||||
|
)
|
||||||
|
elseif(NOT ${reporter_check_result} EQUAL 0)
|
||||||
|
message(FATAL_ERROR
|
||||||
|
"Error checking for reporter in test executable '${_TEST_EXECUTABLE}':\n"
|
||||||
|
" Result: ${reporter_check_result}\n"
|
||||||
|
" Output: ${reporter_check_output}\n"
|
||||||
|
)
|
||||||
|
endif()
|
||||||
|
endif()
|
||||||
|
|
||||||
|
# Prepare output dir
|
||||||
|
if(output_dir AND NOT IS_ABSOLUTE ${output_dir})
|
||||||
|
set(output_dir "${_TEST_WORKING_DIR}/${output_dir}")
|
||||||
|
if(NOT EXISTS ${output_dir})
|
||||||
|
file(MAKE_DIRECTORY ${output_dir})
|
||||||
|
endif()
|
||||||
|
endif()
|
||||||
|
|
||||||
|
if(dl_paths)
|
||||||
|
foreach(path ${dl_paths})
|
||||||
|
cmake_path(NATIVE_PATH path native_path)
|
||||||
|
list(PREPEND environment_modifications "${dl_paths_variable_name}=path_list_prepend:${native_path}")
|
||||||
|
endforeach()
|
||||||
|
endif()
|
||||||
|
|
||||||
|
if(APPLE AND dl_framework_paths)
|
||||||
|
foreach(path ${dl_framework_paths})
|
||||||
|
cmake_path(NATIVE_PATH path native_path)
|
||||||
|
list(PREPEND environment_modifications "DYLD_FRAMEWORK_PATH=path_list_prepend:${native_path}")
|
||||||
|
endforeach()
|
||||||
|
endif()
|
||||||
|
|
||||||
|
# Parse JSON output for list of tests/class names/tags
|
||||||
|
string(JSON version GET "${listing_output}" "version")
|
||||||
|
if(NOT version STREQUAL "1")
|
||||||
|
message(FATAL_ERROR "Unsupported catch output version: '${version}'")
|
||||||
|
endif()
|
||||||
|
|
||||||
|
# Speed-up reparsing by cutting away unneeded parts of JSON.
|
||||||
|
string(JSON test_listing GET "${listing_output}" "listings" "tests")
|
||||||
|
string(JSON num_tests LENGTH "${test_listing}")
|
||||||
|
|
||||||
|
# Exit early if no tests are detected
|
||||||
|
if(num_tests STREQUAL "0")
|
||||||
|
file(WRITE "${_CTEST_FILE}" "")
|
||||||
|
return()
|
||||||
|
endif()
|
||||||
|
|
||||||
|
# CMake's foreach-RANGE is inclusive, so we have to subtract 1
|
||||||
|
math(EXPR num_tests "${num_tests} - 1")
|
||||||
|
|
||||||
|
foreach(idx RANGE ${num_tests})
|
||||||
|
string(JSON single_test GET ${test_listing} ${idx})
|
||||||
|
string(JSON test_tags GET "${single_test}" "tags")
|
||||||
|
string(JSON plain_name GET "${single_test}" "name")
|
||||||
|
|
||||||
|
# Escape characters in test case names that would be parsed by Catch2
|
||||||
|
# Note that the \ escaping must happen FIRST! Do not change the order.
|
||||||
|
set(escaped_name "${plain_name}")
|
||||||
|
foreach(char \\ , [ ] ;)
|
||||||
|
string(REPLACE ${char} "\\${char}" escaped_name "${escaped_name}")
|
||||||
|
endforeach(char)
|
||||||
|
# ...add output dir
|
||||||
|
if(output_dir)
|
||||||
|
string(REGEX REPLACE "[^A-Za-z0-9_]" "_" escaped_name_clean "${escaped_name}")
|
||||||
|
set(output_dir_arg "--out ${output_dir}/${output_prefix}${escaped_name_clean}${output_suffix}")
|
||||||
|
endif()
|
||||||
|
|
||||||
|
# ...and add to script
|
||||||
|
add_command(add_test
|
||||||
|
"${prefix}${plain_name}${suffix}"
|
||||||
|
${_TEST_EXECUTOR}
|
||||||
|
"${_TEST_EXECUTABLE}"
|
||||||
|
"${escaped_name}"
|
||||||
|
${extra_args}
|
||||||
|
"${reporter_arg}"
|
||||||
|
"${output_dir_arg}"
|
||||||
|
)
|
||||||
|
add_command(set_tests_properties
|
||||||
|
"${prefix}${plain_name}${suffix}"
|
||||||
|
PROPERTIES
|
||||||
|
WORKING_DIRECTORY "${_TEST_WORKING_DIR}"
|
||||||
|
${properties}
|
||||||
|
)
|
||||||
|
|
||||||
|
if(add_tags)
|
||||||
|
string(JSON num_tags LENGTH "${test_tags}")
|
||||||
|
math(EXPR num_tags "${num_tags} - 1")
|
||||||
|
set(tag_list "")
|
||||||
|
if(num_tags GREATER_EQUAL "0")
|
||||||
|
foreach(tag_idx RANGE ${num_tags})
|
||||||
|
string(JSON a_tag GET "${test_tags}" "${tag_idx}")
|
||||||
|
# Catch2's tags can contain semicolons, which are list element separators
|
||||||
|
# in CMake, so we have to escape them. Ideally we could use the [=[...]=]
|
||||||
|
# syntax for this, but CTest currently keeps the square quotes in the label
|
||||||
|
# name. So we add 2 backslashes to escape it instead.
|
||||||
|
# **IMPORTANT**: The number of backslashes depends on how many layers
|
||||||
|
# of CMake the tag goes. If this script is changed, the
|
||||||
|
# number of backslashes to escape may change as well.
|
||||||
|
string(REPLACE ";" "\\;" a_tag "${a_tag}")
|
||||||
|
list(APPEND tag_list "${a_tag}")
|
||||||
|
endforeach()
|
||||||
|
|
||||||
|
add_command(set_tests_properties
|
||||||
|
"${prefix}${plain_name}${suffix}"
|
||||||
|
PROPERTIES
|
||||||
|
LABELS "${tag_list}"
|
||||||
|
)
|
||||||
|
endif()
|
||||||
|
endif(add_tags)
|
||||||
|
|
||||||
|
if(environment_modifications)
|
||||||
|
add_command(set_tests_properties
|
||||||
|
"${prefix}${plain_name}${suffix}"
|
||||||
|
PROPERTIES
|
||||||
|
ENVIRONMENT_MODIFICATION "${environment_modifications}")
|
||||||
|
endif()
|
||||||
|
|
||||||
|
list(APPEND tests "${prefix}${plain_name}${suffix}")
|
||||||
|
endforeach()
|
||||||
|
|
||||||
|
# Create a list of all discovered tests, which users may use to e.g. set
|
||||||
|
# properties on the tests
|
||||||
|
add_command(set ${_TEST_LIST} ${tests})
|
||||||
|
|
||||||
|
# Write CTest script
|
||||||
|
file(WRITE "${_CTEST_FILE}" "${script}")
|
||||||
|
endfunction()
|
||||||
|
|
||||||
|
if(CMAKE_SCRIPT_MODE_FILE)
|
||||||
|
catch_discover_tests_impl(
|
||||||
|
TEST_EXECUTABLE ${TEST_EXECUTABLE}
|
||||||
|
TEST_EXECUTOR ${TEST_EXECUTOR}
|
||||||
|
TEST_WORKING_DIR ${TEST_WORKING_DIR}
|
||||||
|
TEST_SPEC ${TEST_SPEC}
|
||||||
|
TEST_EXTRA_ARGS ${TEST_EXTRA_ARGS}
|
||||||
|
TEST_PROPERTIES ${TEST_PROPERTIES}
|
||||||
|
TEST_PREFIX ${TEST_PREFIX}
|
||||||
|
TEST_SUFFIX ${TEST_SUFFIX}
|
||||||
|
TEST_LIST ${TEST_LIST}
|
||||||
|
TEST_REPORTER ${TEST_REPORTER}
|
||||||
|
TEST_OUTPUT_DIR ${TEST_OUTPUT_DIR}
|
||||||
|
TEST_OUTPUT_PREFIX ${TEST_OUTPUT_PREFIX}
|
||||||
|
TEST_OUTPUT_SUFFIX ${TEST_OUTPUT_SUFFIX}
|
||||||
|
TEST_DL_PATHS ${TEST_DL_PATHS}
|
||||||
|
TEST_DL_FRAMEWORK_PATHS ${TEST_DL_FRAMEWORK_PATHS}
|
||||||
|
CTEST_FILE ${CTEST_FILE}
|
||||||
|
ADD_TAGS_AS_LABELS ${ADD_TAGS_AS_LABELS}
|
||||||
)
|
)
|
||||||
endif()
|
endif()
|
||||||
execute_process(
|
|
||||||
COMMAND ${TEST_EXECUTOR} "${TEST_EXECUTABLE}" ${spec} --list-test-names-only
|
|
||||||
OUTPUT_VARIABLE output
|
|
||||||
RESULT_VARIABLE result
|
|
||||||
)
|
|
||||||
# Catch --list-test-names-only reports the number of tests, so 0 is... surprising
|
|
||||||
if(${result} EQUAL 0)
|
|
||||||
message(WARNING
|
|
||||||
"Test executable '${TEST_EXECUTABLE}' contains no tests!\n"
|
|
||||||
)
|
|
||||||
elseif(${result} LESS 0)
|
|
||||||
message(FATAL_ERROR
|
|
||||||
"Error running test executable '${TEST_EXECUTABLE}':\n"
|
|
||||||
" Result: ${result}\n"
|
|
||||||
" Output: ${output}\n"
|
|
||||||
)
|
|
||||||
endif()
|
|
||||||
|
|
||||||
string(REPLACE "\n" ";" output "${output}")
|
|
||||||
|
|
||||||
# Parse output
|
|
||||||
foreach(line ${output})
|
|
||||||
set(test ${line})
|
|
||||||
# ...and add to script
|
|
||||||
add_command(add_test
|
|
||||||
"${prefix}${test}${suffix}"
|
|
||||||
${TEST_EXECUTOR}
|
|
||||||
"${TEST_EXECUTABLE}"
|
|
||||||
${test}
|
|
||||||
${extra_args}
|
|
||||||
)
|
|
||||||
add_command(set_tests_properties
|
|
||||||
"${prefix}${test}${suffix}"
|
|
||||||
PROPERTIES
|
|
||||||
WORKING_DIRECTORY "${TEST_WORKING_DIR}"
|
|
||||||
${properties}
|
|
||||||
)
|
|
||||||
list(APPEND tests "${prefix}${test}${suffix}")
|
|
||||||
endforeach()
|
|
||||||
|
|
||||||
# Create a list of all discovered tests, which users may use to e.g. set
|
|
||||||
# properties on the tests
|
|
||||||
add_command(set ${TEST_LIST} ${tests})
|
|
||||||
|
|
||||||
# Write CTest script
|
|
||||||
file(WRITE "${CTEST_FILE}" "${script}")
|
|
||||||
|
|||||||
72
cmake/CatchShardTests.cmake
Normal file
72
cmake/CatchShardTests.cmake
Normal file
@ -0,0 +1,72 @@
|
|||||||
|
|
||||||
|
# Copyright Catch2 Authors
|
||||||
|
# Distributed under the Boost Software License, Version 1.0.
|
||||||
|
# (See accompanying file LICENSE.txt or copy at
|
||||||
|
# https://www.boost.org/LICENSE_1_0.txt)
|
||||||
|
|
||||||
|
# SPDX-License-Identifier: BSL-1.0
|
||||||
|
|
||||||
|
# Supported optional args:
|
||||||
|
# * SHARD_COUNT - number of shards to split target's tests into
|
||||||
|
# * REPORTER - reporter spec to use for tests
|
||||||
|
# * TEST_SPEC - test spec used for filtering tests
|
||||||
|
function(catch_add_sharded_tests TARGET)
|
||||||
|
if(${CMAKE_VERSION} VERSION_LESS "3.10.0")
|
||||||
|
message(FATAL_ERROR "add_sharded_catch_tests only supports CMake versions 3.10.0 and up")
|
||||||
|
endif()
|
||||||
|
|
||||||
|
cmake_parse_arguments(
|
||||||
|
""
|
||||||
|
""
|
||||||
|
"SHARD_COUNT;REPORTER;TEST_SPEC"
|
||||||
|
""
|
||||||
|
${ARGN}
|
||||||
|
)
|
||||||
|
|
||||||
|
if(NOT DEFINED _SHARD_COUNT)
|
||||||
|
set(_SHARD_COUNT 2)
|
||||||
|
endif()
|
||||||
|
|
||||||
|
# Generate a unique name based on the extra arguments
|
||||||
|
string(SHA1 args_hash "${_TEST_SPEC} ${_EXTRA_ARGS} ${_REPORTER} ${_OUTPUT_DIR} ${_OUTPUT_PREFIX} ${_OUTPUT_SUFFIX} ${_SHARD_COUNT}")
|
||||||
|
string(SUBSTRING ${args_hash} 0 7 args_hash)
|
||||||
|
|
||||||
|
set(ctest_include_file "${CMAKE_CURRENT_BINARY_DIR}/${TARGET}-sharded-tests-include-${args_hash}.cmake")
|
||||||
|
set(ctest_tests_file "${CMAKE_CURRENT_BINARY_DIR}/${TARGET}-sharded-tests-impl-${args_hash}.cmake")
|
||||||
|
|
||||||
|
file(WRITE "${ctest_include_file}"
|
||||||
|
"if(EXISTS \"${ctest_tests_file}\")\n"
|
||||||
|
" include(\"${ctest_tests_file}\")\n"
|
||||||
|
"else()\n"
|
||||||
|
" add_test(${TARGET}_NOT_BUILT-${args_hash} ${TARGET}_NOT_BUILT-${args_hash})\n"
|
||||||
|
"endif()\n"
|
||||||
|
)
|
||||||
|
|
||||||
|
set_property(DIRECTORY
|
||||||
|
APPEND PROPERTY TEST_INCLUDE_FILES "${ctest_include_file}"
|
||||||
|
)
|
||||||
|
|
||||||
|
set(shard_impl_script_file "${_CATCH_DISCOVER_SHARD_TESTS_IMPL_SCRIPT}")
|
||||||
|
|
||||||
|
add_custom_command(
|
||||||
|
TARGET ${TARGET} POST_BUILD
|
||||||
|
BYPRODUCTS "${ctest_tests_file}"
|
||||||
|
COMMAND "${CMAKE_COMMAND}"
|
||||||
|
-D "TARGET_NAME=${TARGET}"
|
||||||
|
-D "TEST_BINARY=$<TARGET_FILE:${TARGET}>"
|
||||||
|
-D "CTEST_FILE=${ctest_tests_file}"
|
||||||
|
-D "SHARD_COUNT=${_SHARD_COUNT}"
|
||||||
|
-D "REPORTER_SPEC=${_REPORTER}"
|
||||||
|
-D "TEST_SPEC=${_TEST_SPEC}"
|
||||||
|
-P "${shard_impl_script_file}"
|
||||||
|
VERBATIM
|
||||||
|
)
|
||||||
|
endfunction()
|
||||||
|
|
||||||
|
|
||||||
|
###############################################################################
|
||||||
|
|
||||||
|
set(_CATCH_DISCOVER_SHARD_TESTS_IMPL_SCRIPT
|
||||||
|
${CMAKE_CURRENT_LIST_DIR}/CatchShardTestsImpl.cmake
|
||||||
|
CACHE INTERNAL "Catch2 full path to CatchShardTestsImpl.cmake helper file"
|
||||||
|
)
|
||||||
52
cmake/CatchShardTestsImpl.cmake
Normal file
52
cmake/CatchShardTestsImpl.cmake
Normal file
@ -0,0 +1,52 @@
|
|||||||
|
|
||||||
|
# Copyright Catch2 Authors
|
||||||
|
# Distributed under the Boost Software License, Version 1.0.
|
||||||
|
# (See accompanying file LICENSE.txt or copy at
|
||||||
|
# https://www.boost.org/LICENSE_1_0.txt)
|
||||||
|
|
||||||
|
# SPDX-License-Identifier: BSL-1.0
|
||||||
|
|
||||||
|
# Indirection for CatchShardTests that allows us to delay the script
|
||||||
|
# file generation until build time.
|
||||||
|
|
||||||
|
# Expected args:
|
||||||
|
# * TEST_BINARY - full path to the test binary to run sharded
|
||||||
|
# * CTEST_FILE - full path to ctest script file to write to
|
||||||
|
# * TARGET_NAME - name of the target to shard (used for test names)
|
||||||
|
# * SHARD_COUNT - number of shards to split the binary into
|
||||||
|
# Optional args:
|
||||||
|
# * REPORTER_SPEC - reporter specs to be passed down to the binary
|
||||||
|
# * TEST_SPEC - test spec to pass down to the test binary
|
||||||
|
|
||||||
|
if(NOT EXISTS "${TEST_BINARY}")
|
||||||
|
message(FATAL_ERROR
|
||||||
|
"Specified test binary '${TEST_BINARY}' does not exist"
|
||||||
|
)
|
||||||
|
endif()
|
||||||
|
|
||||||
|
set(other_args "")
|
||||||
|
if(TEST_SPEC)
|
||||||
|
set(other_args "${other_args} ${TEST_SPEC}")
|
||||||
|
endif()
|
||||||
|
if(REPORTER_SPEC)
|
||||||
|
set(other_args "${other_args} --reporter ${REPORTER_SPEC}")
|
||||||
|
endif()
|
||||||
|
|
||||||
|
# foreach RANGE in cmake is inclusive of the end, so we have to adjust it
|
||||||
|
math(EXPR adjusted_shard_count "${SHARD_COUNT} - 1")
|
||||||
|
|
||||||
|
file(WRITE "${CTEST_FILE}"
|
||||||
|
"string(RANDOM LENGTH 8 ALPHABET \"0123456789abcdef\" rng_seed)\n"
|
||||||
|
"\n"
|
||||||
|
"foreach(shard_idx RANGE ${adjusted_shard_count})\n"
|
||||||
|
" add_test(${TARGET_NAME}-shard-" [[${shard_idx}]] "/${adjusted_shard_count}\n"
|
||||||
|
" ${TEST_BINARY}"
|
||||||
|
" --shard-index " [[${shard_idx}]]
|
||||||
|
" --shard-count ${SHARD_COUNT}"
|
||||||
|
" --rng-seed " [[0x${rng_seed}]]
|
||||||
|
" --order rand"
|
||||||
|
"${other_args}"
|
||||||
|
"\n"
|
||||||
|
" )\n"
|
||||||
|
"endforeach()\n"
|
||||||
|
)
|
||||||
@ -1,9 +1,11 @@
|
|||||||
#==================================================================================================#
|
#==================================================================================================#
|
||||||
# supported macros #
|
# supported macros #
|
||||||
# - TEST_CASE, #
|
# - TEST_CASE, #
|
||||||
|
# - TEMPLATE_TEST_CASE #
|
||||||
# - SCENARIO, #
|
# - SCENARIO, #
|
||||||
# - TEST_CASE_METHOD, #
|
# - TEST_CASE_METHOD, #
|
||||||
# - CATCH_TEST_CASE, #
|
# - CATCH_TEST_CASE, #
|
||||||
|
# - CATCH_TEMPLATE_TEST_CASE #
|
||||||
# - CATCH_SCENARIO, #
|
# - CATCH_SCENARIO, #
|
||||||
# - CATCH_TEST_CASE_METHOD. #
|
# - CATCH_TEST_CASE_METHOD. #
|
||||||
# #
|
# #
|
||||||
@ -39,9 +41,24 @@
|
|||||||
# PARSE_CATCH_TESTS_ADD_TO_CONFIGURE_DEPENDS (Default OFF) #
|
# PARSE_CATCH_TESTS_ADD_TO_CONFIGURE_DEPENDS (Default OFF) #
|
||||||
# -- causes CMake to rerun when file with tests changes so that new tests will be discovered #
|
# -- causes CMake to rerun when file with tests changes so that new tests will be discovered #
|
||||||
# #
|
# #
|
||||||
|
# One can also set (locally) the optional variable OptionalCatchTestLauncher to precise the way #
|
||||||
|
# a test should be run. For instance to use test MPI, one can write #
|
||||||
|
# set(OptionalCatchTestLauncher ${MPIEXEC} ${MPIEXEC_NUMPROC_FLAG} ${NUMPROC}) #
|
||||||
|
# just before calling this ParseAndAddCatchTests function #
|
||||||
|
# #
|
||||||
|
# The AdditionalCatchParameters optional variable can be used to pass extra argument to the test #
|
||||||
|
# command. For example, to include successful tests in the output, one can write #
|
||||||
|
# set(AdditionalCatchParameters --success) #
|
||||||
|
# #
|
||||||
|
# After the script, the ParseAndAddCatchTests_TESTS property for the target, and for each source #
|
||||||
|
# file in the target is set, and contains the list of the tests extracted from that target, or #
|
||||||
|
# from that file. This is useful, for example to add further labels or properties to the tests. #
|
||||||
|
# #
|
||||||
#==================================================================================================#
|
#==================================================================================================#
|
||||||
|
|
||||||
cmake_minimum_required(VERSION 2.8.8)
|
if(CMAKE_MINIMUM_REQUIRED_VERSION VERSION_LESS 2.8.8)
|
||||||
|
message(FATAL_ERROR "ParseAndAddCatchTests requires CMake 2.8.8 or newer")
|
||||||
|
endif()
|
||||||
|
|
||||||
option(PARSE_CATCH_TESTS_VERBOSE "Print Catch to CTest parser debug messages" OFF)
|
option(PARSE_CATCH_TESTS_VERBOSE "Print Catch to CTest parser debug messages" OFF)
|
||||||
option(PARSE_CATCH_TESTS_NO_HIDDEN_TESTS "Exclude tests with [!hide], [.] or [.foo] tags" OFF)
|
option(PARSE_CATCH_TESTS_NO_HIDDEN_TESTS "Exclude tests with [!hide], [.] or [.foo] tags" OFF)
|
||||||
@ -49,10 +66,10 @@ option(PARSE_CATCH_TESTS_ADD_FIXTURE_IN_TEST_NAME "Add fixture class name to the
|
|||||||
option(PARSE_CATCH_TESTS_ADD_TARGET_IN_TEST_NAME "Add target name to the test name" ON)
|
option(PARSE_CATCH_TESTS_ADD_TARGET_IN_TEST_NAME "Add target name to the test name" ON)
|
||||||
option(PARSE_CATCH_TESTS_ADD_TO_CONFIGURE_DEPENDS "Add test file to CMAKE_CONFIGURE_DEPENDS property" OFF)
|
option(PARSE_CATCH_TESTS_ADD_TO_CONFIGURE_DEPENDS "Add test file to CMAKE_CONFIGURE_DEPENDS property" OFF)
|
||||||
|
|
||||||
function(PrintDebugMessage)
|
function(ParseAndAddCatchTests_PrintDebugMessage)
|
||||||
if(PARSE_CATCH_TESTS_VERBOSE)
|
if(PARSE_CATCH_TESTS_VERBOSE)
|
||||||
message(STATUS "ParseAndAddCatchTests: ${ARGV}")
|
message(STATUS "ParseAndAddCatchTests: ${ARGV}")
|
||||||
endif()
|
endif()
|
||||||
endfunction()
|
endfunction()
|
||||||
|
|
||||||
# This removes the contents between
|
# This removes the contents between
|
||||||
@ -60,7 +77,7 @@ endfunction()
|
|||||||
# - full line comments (i.e. // ... )
|
# - full line comments (i.e. // ... )
|
||||||
# contents have been read into '${CppCode}'.
|
# contents have been read into '${CppCode}'.
|
||||||
# !keep partial line comments
|
# !keep partial line comments
|
||||||
function(RemoveComments CppCode)
|
function(ParseAndAddCatchTests_RemoveComments CppCode)
|
||||||
string(ASCII 2 CMakeBeginBlockComment)
|
string(ASCII 2 CMakeBeginBlockComment)
|
||||||
string(ASCII 3 CMakeEndBlockComment)
|
string(ASCII 3 CMakeEndBlockComment)
|
||||||
string(REGEX REPLACE "/\\*" "${CMakeBeginBlockComment}" ${CppCode} "${${CppCode}}")
|
string(REGEX REPLACE "/\\*" "${CMakeBeginBlockComment}" ${CppCode} "${${CppCode}}")
|
||||||
@ -72,114 +89,162 @@ function(RemoveComments CppCode)
|
|||||||
endfunction()
|
endfunction()
|
||||||
|
|
||||||
# Worker function
|
# Worker function
|
||||||
function(ParseFile SourceFile TestTarget)
|
function(ParseAndAddCatchTests_ParseFile SourceFile TestTarget)
|
||||||
# According to CMake docs EXISTS behavior is well-defined only for full paths.
|
# If SourceFile is an object library, do not scan it (as it is not a file). Exit without giving a warning about a missing file.
|
||||||
get_filename_component(SourceFile ${SourceFile} ABSOLUTE)
|
if(SourceFile MATCHES "\\\$<TARGET_OBJECTS:.+>")
|
||||||
if(NOT EXISTS ${SourceFile})
|
ParseAndAddCatchTests_PrintDebugMessage("Detected OBJECT library: ${SourceFile} this will not be scanned for tests.")
|
||||||
message(WARNING "Cannot find source file: ${SourceFile}")
|
return()
|
||||||
return()
|
endif()
|
||||||
|
# According to CMake docs EXISTS behavior is well-defined only for full paths.
|
||||||
|
get_filename_component(SourceFile ${SourceFile} ABSOLUTE)
|
||||||
|
if(NOT EXISTS ${SourceFile})
|
||||||
|
message(WARNING "Cannot find source file: ${SourceFile}")
|
||||||
|
return()
|
||||||
|
endif()
|
||||||
|
ParseAndAddCatchTests_PrintDebugMessage("parsing ${SourceFile}")
|
||||||
|
file(STRINGS ${SourceFile} Contents NEWLINE_CONSUME)
|
||||||
|
|
||||||
|
# Remove block and fullline comments
|
||||||
|
ParseAndAddCatchTests_RemoveComments(Contents)
|
||||||
|
|
||||||
|
# Find definition of test names
|
||||||
|
# https://regex101.com/r/JygOND/1
|
||||||
|
string(REGEX MATCHALL "[ \t]*(CATCH_)?(TEMPLATE_)?(TEST_CASE_METHOD|SCENARIO|TEST_CASE)[ \t]*\\([ \t\n]*\"[^\"]*\"[ \t\n]*(,[ \t\n]*\"[^\"]*\")?(,[ \t\n]*[^\,\)]*)*\\)[ \t\n]*\{+[ \t]*(//[^\n]*[Tt][Ii][Mm][Ee][Oo][Uu][Tt][ \t]*[0-9]+)*" Tests "${Contents}")
|
||||||
|
|
||||||
|
if(PARSE_CATCH_TESTS_ADD_TO_CONFIGURE_DEPENDS AND Tests)
|
||||||
|
ParseAndAddCatchTests_PrintDebugMessage("Adding ${SourceFile} to CMAKE_CONFIGURE_DEPENDS property")
|
||||||
|
set_property(
|
||||||
|
DIRECTORY
|
||||||
|
APPEND
|
||||||
|
PROPERTY CMAKE_CONFIGURE_DEPENDS ${SourceFile}
|
||||||
|
)
|
||||||
|
endif()
|
||||||
|
|
||||||
|
# check CMP0110 policy for new add_test() behavior
|
||||||
|
if(POLICY CMP0110)
|
||||||
|
cmake_policy(GET CMP0110 _cmp0110_value) # new add_test() behavior
|
||||||
|
else()
|
||||||
|
# just to be thorough explicitly set the variable
|
||||||
|
set(_cmp0110_value)
|
||||||
|
endif()
|
||||||
|
|
||||||
|
foreach(TestName ${Tests})
|
||||||
|
# Strip newlines
|
||||||
|
string(REGEX REPLACE "\\\\\n|\n" "" TestName "${TestName}")
|
||||||
|
|
||||||
|
# Get test type and fixture if applicable
|
||||||
|
string(REGEX MATCH "(CATCH_)?(TEMPLATE_)?(TEST_CASE_METHOD|SCENARIO|TEST_CASE)[ \t]*\\([^,^\"]*" TestTypeAndFixture "${TestName}")
|
||||||
|
string(REGEX MATCH "(CATCH_)?(TEMPLATE_)?(TEST_CASE_METHOD|SCENARIO|TEST_CASE)" TestType "${TestTypeAndFixture}")
|
||||||
|
string(REGEX REPLACE "${TestType}\\([ \t]*" "" TestFixture "${TestTypeAndFixture}")
|
||||||
|
|
||||||
|
# Get string parts of test definition
|
||||||
|
string(REGEX MATCHALL "\"+([^\\^\"]|\\\\\")+\"+" TestStrings "${TestName}")
|
||||||
|
|
||||||
|
# Strip wrapping quotation marks
|
||||||
|
string(REGEX REPLACE "^\"(.*)\"$" "\\1" TestStrings "${TestStrings}")
|
||||||
|
string(REPLACE "\";\"" ";" TestStrings "${TestStrings}")
|
||||||
|
|
||||||
|
# Validate that a test name and tags have been provided
|
||||||
|
list(LENGTH TestStrings TestStringsLength)
|
||||||
|
if(TestStringsLength GREATER 2 OR TestStringsLength LESS 1)
|
||||||
|
message(FATAL_ERROR "You must provide a valid test name and tags for all tests in ${SourceFile}")
|
||||||
endif()
|
endif()
|
||||||
PrintDebugMessage("parsing ${SourceFile}")
|
|
||||||
file(STRINGS ${SourceFile} Contents NEWLINE_CONSUME)
|
|
||||||
|
|
||||||
# Remove block and fullline comments
|
# Assign name and tags
|
||||||
RemoveComments(Contents)
|
list(GET TestStrings 0 Name)
|
||||||
|
if("${TestType}" STREQUAL "SCENARIO")
|
||||||
|
set(Name "Scenario: ${Name}")
|
||||||
|
endif()
|
||||||
|
if(PARSE_CATCH_TESTS_ADD_FIXTURE_IN_TEST_NAME AND "${TestType}" MATCHES "(CATCH_)?TEST_CASE_METHOD" AND TestFixture)
|
||||||
|
set(CTestName "${TestFixture}:${Name}")
|
||||||
|
else()
|
||||||
|
set(CTestName "${Name}")
|
||||||
|
endif()
|
||||||
|
if(PARSE_CATCH_TESTS_ADD_TARGET_IN_TEST_NAME)
|
||||||
|
set(CTestName "${TestTarget}:${CTestName}")
|
||||||
|
endif()
|
||||||
|
# add target to labels to enable running all tests added from this target
|
||||||
|
set(Labels ${TestTarget})
|
||||||
|
if(TestStringsLength EQUAL 2)
|
||||||
|
list(GET TestStrings 1 Tags)
|
||||||
|
string(TOLOWER "${Tags}" Tags)
|
||||||
|
# remove target from labels if the test is hidden
|
||||||
|
if("${Tags}" MATCHES ".*\\[!?(hide|\\.)\\].*")
|
||||||
|
list(REMOVE_ITEM Labels ${TestTarget})
|
||||||
|
endif()
|
||||||
|
string(REPLACE "]" ";" Tags "${Tags}")
|
||||||
|
string(REPLACE "[" "" Tags "${Tags}")
|
||||||
|
else()
|
||||||
|
# unset tags variable from previous loop
|
||||||
|
unset(Tags)
|
||||||
|
endif()
|
||||||
|
|
||||||
# Find definition of test names
|
list(APPEND Labels ${Tags})
|
||||||
string(REGEX MATCHALL "[ \t]*(CATCH_)?(TEST_CASE_METHOD|SCENARIO|TEST_CASE)[ \t]*\\([^\)]+\\)+[ \t\n]*{+[ \t]*(//[^\n]*[Tt][Ii][Mm][Ee][Oo][Uu][Tt][ \t]*[0-9]+)*" Tests "${Contents}")
|
|
||||||
|
|
||||||
if(PARSE_CATCH_TESTS_ADD_TO_CONFIGURE_DEPENDS AND Tests)
|
set(HiddenTagFound OFF)
|
||||||
PrintDebugMessage("Adding ${SourceFile} to CMAKE_CONFIGURE_DEPENDS property")
|
foreach(label ${Labels})
|
||||||
|
string(REGEX MATCH "^!hide|^\\." result ${label})
|
||||||
|
if(result)
|
||||||
|
set(HiddenTagFound ON)
|
||||||
|
break()
|
||||||
|
endif()
|
||||||
|
endforeach(label)
|
||||||
|
if(PARSE_CATCH_TESTS_NO_HIDDEN_TESTS AND ${HiddenTagFound} AND ${CMAKE_VERSION} VERSION_LESS "3.9")
|
||||||
|
ParseAndAddCatchTests_PrintDebugMessage("Skipping test \"${CTestName}\" as it has [!hide], [.] or [.foo] label")
|
||||||
|
else()
|
||||||
|
ParseAndAddCatchTests_PrintDebugMessage("Adding test \"${CTestName}\"")
|
||||||
|
if(Labels)
|
||||||
|
ParseAndAddCatchTests_PrintDebugMessage("Setting labels to ${Labels}")
|
||||||
|
endif()
|
||||||
|
|
||||||
|
# Escape commas in the test spec
|
||||||
|
string(REPLACE "," "\\," Name ${Name})
|
||||||
|
|
||||||
|
# Work around CMake 3.18.0 change in `add_test()`, before the escaped quotes were necessary,
|
||||||
|
# only with CMake 3.18.0 the escaped double quotes confuse the call. This change is reverted in 3.18.1
|
||||||
|
# And properly introduced in 3.19 with the CMP0110 policy
|
||||||
|
if(_cmp0110_value STREQUAL "NEW" OR ${CMAKE_VERSION} VERSION_EQUAL "3.18")
|
||||||
|
ParseAndAddCatchTests_PrintDebugMessage("CMP0110 set to NEW, no need for add_test(\"\") workaround")
|
||||||
|
else()
|
||||||
|
ParseAndAddCatchTests_PrintDebugMessage("CMP0110 set to OLD adding \"\" for add_test() workaround")
|
||||||
|
set(CTestName "\"${CTestName}\"")
|
||||||
|
endif()
|
||||||
|
|
||||||
|
# Handle template test cases
|
||||||
|
if("${TestTypeAndFixture}" MATCHES ".*TEMPLATE_.*")
|
||||||
|
set(Name "${Name} - *")
|
||||||
|
endif()
|
||||||
|
|
||||||
|
# Add the test and set its properties
|
||||||
|
add_test(NAME "${CTestName}" COMMAND ${OptionalCatchTestLauncher} $<TARGET_FILE:${TestTarget}> ${Name} ${AdditionalCatchParameters})
|
||||||
|
# Old CMake versions do not document VERSION_GREATER_EQUAL, so we use VERSION_GREATER with 3.8 instead
|
||||||
|
if(PARSE_CATCH_TESTS_NO_HIDDEN_TESTS AND ${HiddenTagFound} AND ${CMAKE_VERSION} VERSION_GREATER "3.8")
|
||||||
|
ParseAndAddCatchTests_PrintDebugMessage("Setting DISABLED test property")
|
||||||
|
set_tests_properties("${CTestName}" PROPERTIES DISABLED ON)
|
||||||
|
else()
|
||||||
|
set_tests_properties("${CTestName}" PROPERTIES FAIL_REGULAR_EXPRESSION "No tests ran"
|
||||||
|
LABELS "${Labels}")
|
||||||
|
endif()
|
||||||
set_property(
|
set_property(
|
||||||
DIRECTORY
|
TARGET ${TestTarget}
|
||||||
APPEND
|
APPEND
|
||||||
PROPERTY CMAKE_CONFIGURE_DEPENDS ${SourceFile}
|
PROPERTY ParseAndAddCatchTests_TESTS "${CTestName}")
|
||||||
)
|
set_property(
|
||||||
|
SOURCE ${SourceFile}
|
||||||
|
APPEND
|
||||||
|
PROPERTY ParseAndAddCatchTests_TESTS "${CTestName}")
|
||||||
endif()
|
endif()
|
||||||
|
endforeach()
|
||||||
foreach(TestName ${Tests})
|
|
||||||
# Strip newlines
|
|
||||||
string(REGEX REPLACE "\\\\\n|\n" "" TestName "${TestName}")
|
|
||||||
|
|
||||||
# Get test type and fixture if applicable
|
|
||||||
string(REGEX MATCH "(CATCH_)?(TEST_CASE_METHOD|SCENARIO|TEST_CASE)[ \t]*\\([^,^\"]*" TestTypeAndFixture "${TestName}")
|
|
||||||
string(REGEX MATCH "(CATCH_)?(TEST_CASE_METHOD|SCENARIO|TEST_CASE)" TestType "${TestTypeAndFixture}")
|
|
||||||
string(REPLACE "${TestType}(" "" TestFixture "${TestTypeAndFixture}")
|
|
||||||
|
|
||||||
# Get string parts of test definition
|
|
||||||
string(REGEX MATCHALL "\"+([^\\^\"]|\\\\\")+\"+" TestStrings "${TestName}")
|
|
||||||
|
|
||||||
# Strip wrapping quotation marks
|
|
||||||
string(REGEX REPLACE "^\"(.*)\"$" "\\1" TestStrings "${TestStrings}")
|
|
||||||
string(REPLACE "\";\"" ";" TestStrings "${TestStrings}")
|
|
||||||
|
|
||||||
# Validate that a test name and tags have been provided
|
|
||||||
list(LENGTH TestStrings TestStringsLength)
|
|
||||||
if(TestStringsLength GREATER 2 OR TestStringsLength LESS 1)
|
|
||||||
message(FATAL_ERROR "You must provide a valid test name and tags for all tests in ${SourceFile}")
|
|
||||||
endif()
|
|
||||||
|
|
||||||
# Assign name and tags
|
|
||||||
list(GET TestStrings 0 Name)
|
|
||||||
if("${TestType}" STREQUAL "SCENARIO")
|
|
||||||
set(Name "Scenario: ${Name}")
|
|
||||||
endif()
|
|
||||||
if(PARSE_CATCH_TESTS_ADD_FIXTURE_IN_TEST_NAME AND TestFixture)
|
|
||||||
set(CTestName "${TestFixture}:${Name}")
|
|
||||||
else()
|
|
||||||
set(CTestName "${Name}")
|
|
||||||
endif()
|
|
||||||
if(PARSE_CATCH_TESTS_ADD_TARGET_IN_TEST_NAME)
|
|
||||||
set(CTestName "${TestTarget}:${CTestName}")
|
|
||||||
endif()
|
|
||||||
# add target to labels to enable running all tests added from this target
|
|
||||||
set(Labels ${TestTarget})
|
|
||||||
if(TestStringsLength EQUAL 2)
|
|
||||||
list(GET TestStrings 1 Tags)
|
|
||||||
string(TOLOWER "${Tags}" Tags)
|
|
||||||
# remove target from labels if the test is hidden
|
|
||||||
if("${Tags}" MATCHES ".*\\[!?(hide|\\.)\\].*")
|
|
||||||
list(REMOVE_ITEM Labels ${TestTarget})
|
|
||||||
endif()
|
|
||||||
string(REPLACE "]" ";" Tags "${Tags}")
|
|
||||||
string(REPLACE "[" "" Tags "${Tags}")
|
|
||||||
endif()
|
|
||||||
|
|
||||||
list(APPEND Labels ${Tags})
|
|
||||||
|
|
||||||
list(FIND Labels "!hide" IndexOfHideLabel)
|
|
||||||
set(HiddenTagFound OFF)
|
|
||||||
foreach(label ${Labels})
|
|
||||||
string(REGEX MATCH "^!hide|^\\." result ${label})
|
|
||||||
if(result)
|
|
||||||
set(HiddenTagFound ON)
|
|
||||||
break()
|
|
||||||
endif(result)
|
|
||||||
endforeach(label)
|
|
||||||
if(PARSE_CATCH_TESTS_NO_HIDDEN_TESTS AND ${HiddenTagFound})
|
|
||||||
PrintDebugMessage("Skipping test \"${CTestName}\" as it has [!hide], [.] or [.foo] label")
|
|
||||||
else()
|
|
||||||
PrintDebugMessage("Adding test \"${CTestName}\"")
|
|
||||||
if(Labels)
|
|
||||||
PrintDebugMessage("Setting labels to ${Labels}")
|
|
||||||
endif()
|
|
||||||
|
|
||||||
# Add the test and set its properties
|
|
||||||
add_test(NAME "\"${CTestName}\"" COMMAND ${TestTarget} ${Name} ${AdditionalCatchParameters})
|
|
||||||
set_tests_properties("\"${CTestName}\"" PROPERTIES FAIL_REGULAR_EXPRESSION "No tests ran"
|
|
||||||
LABELS "${Labels}")
|
|
||||||
endif()
|
|
||||||
|
|
||||||
endforeach()
|
|
||||||
endfunction()
|
endfunction()
|
||||||
|
|
||||||
# entry point
|
# entry point
|
||||||
function(ParseAndAddCatchTests TestTarget)
|
function(ParseAndAddCatchTests TestTarget)
|
||||||
PrintDebugMessage("Started parsing ${TestTarget}")
|
message(DEPRECATION "ParseAndAddCatchTest: function deprecated because of possibility of missed test cases. Consider using 'catch_discover_tests' from 'Catch.cmake'")
|
||||||
get_target_property(SourceFiles ${TestTarget} SOURCES)
|
ParseAndAddCatchTests_PrintDebugMessage("Started parsing ${TestTarget}")
|
||||||
PrintDebugMessage("Found the following sources: ${SourceFiles}")
|
get_target_property(SourceFiles ${TestTarget} SOURCES)
|
||||||
foreach(SourceFile ${SourceFiles})
|
ParseAndAddCatchTests_PrintDebugMessage("Found the following sources: ${SourceFiles}")
|
||||||
ParseFile(${SourceFile} ${TestTarget})
|
foreach(SourceFile ${SourceFiles})
|
||||||
endforeach()
|
ParseAndAddCatchTests_ParseFile(${SourceFile} ${TestTarget})
|
||||||
PrintDebugMessage("Finished parsing ${TestTarget}")
|
endforeach()
|
||||||
|
ParseAndAddCatchTests_PrintDebugMessage("Finished parsing ${TestTarget}")
|
||||||
endfunction()
|
endfunction()
|
||||||
|
|||||||
@ -59,10 +59,6 @@ static_assert(_MSC_FULL_VER >= 190024210, "Visual C++ 2015 Update 3 or later req
|
|||||||
#define CHAISCRIPT_MODULE_EXPORT extern "C"
|
#define CHAISCRIPT_MODULE_EXPORT extern "C"
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#if defined(CHAISCRIPT_MSVC) || (defined(__GNUC__) && __GNUC__ >= 5) || defined(CHAISCRIPT_CLANG)
|
|
||||||
#define CHAISCRIPT_UTF16_UTF32
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#ifdef _DEBUG
|
#ifdef _DEBUG
|
||||||
#define CHAISCRIPT_DEBUG true
|
#define CHAISCRIPT_DEBUG true
|
||||||
#else
|
#else
|
||||||
|
|||||||
@ -45,11 +45,10 @@ namespace chaiscript {
|
|||||||
|
|
||||||
auto lib = std::make_shared<Module>();
|
auto lib = std::make_shared<Module>();
|
||||||
|
|
||||||
const bool no_io = std::find(t_opts.begin(), t_opts.end(), Library_Options::No_IO) != t_opts.end();
|
|
||||||
const bool no_prelude = std::find(t_opts.begin(), t_opts.end(), Library_Options::No_Prelude) != t_opts.end();
|
const bool no_prelude = std::find(t_opts.begin(), t_opts.end(), Library_Options::No_Prelude) != t_opts.end();
|
||||||
const bool no_json = std::find(t_opts.begin(), t_opts.end(), Library_Options::No_JSON) != t_opts.end();
|
const bool no_json = std::find(t_opts.begin(), t_opts.end(), Library_Options::No_JSON) != t_opts.end();
|
||||||
|
|
||||||
bootstrap::Bootstrap::bootstrap(*lib, no_io);
|
bootstrap::Bootstrap::bootstrap(*lib);
|
||||||
|
|
||||||
bootstrap::standard_library::vector_type<std::vector<Boxed_Value>>("Vector", *lib);
|
bootstrap::standard_library::vector_type<std::vector<Boxed_Value>>("Vector", *lib);
|
||||||
bootstrap::standard_library::string_type<std::string>("string", *lib);
|
bootstrap::standard_library::string_type<std::string>("string", *lib);
|
||||||
|
|||||||
@ -26,7 +26,7 @@ namespace chaiscript::bootstrap {
|
|||||||
throw std::range_error("Array index out of range. Received: " + std::to_string(index) + " expected < "
|
throw std::range_error("Array index out of range. Received: " + std::to_string(index) + " expected < "
|
||||||
+ std::to_string(extent));
|
+ std::to_string(extent));
|
||||||
} else {
|
} else {
|
||||||
return t[index];
|
return *std::next(t, static_cast<std::ptrdiff_t>(index));
|
||||||
}
|
}
|
||||||
}),
|
}),
|
||||||
"[]");
|
"[]");
|
||||||
@ -37,7 +37,7 @@ namespace chaiscript::bootstrap {
|
|||||||
throw std::range_error("Array index out of range. Received: " + std::to_string(index) + " expected < "
|
throw std::range_error("Array index out of range. Received: " + std::to_string(index) + " expected < "
|
||||||
+ std::to_string(extent));
|
+ std::to_string(extent));
|
||||||
} else {
|
} else {
|
||||||
return t[index];
|
return *std::next(t, static_cast<std::ptrdiff_t>(index));
|
||||||
}
|
}
|
||||||
}),
|
}),
|
||||||
"[]");
|
"[]");
|
||||||
@ -269,7 +269,7 @@ namespace chaiscript::bootstrap {
|
|||||||
/// \brief perform all common bootstrap functions for std::string, void and POD types
|
/// \brief perform all common bootstrap functions for std::string, void and POD types
|
||||||
/// \param[in,out] m Module to add bootstrapped functions to
|
/// \param[in,out] m Module to add bootstrapped functions to
|
||||||
/// \param[in] t_no_io If true, skip registering print_string and println_string
|
/// \param[in] t_no_io If true, skip registering print_string and println_string
|
||||||
static void bootstrap(Module &m, const bool t_no_io = false) {
|
static void bootstrap(Module &m) {
|
||||||
m.add(user_type<void>(), "void");
|
m.add(user_type<void>(), "void");
|
||||||
m.add(user_type<bool>(), "bool");
|
m.add(user_type<bool>(), "bool");
|
||||||
m.add(user_type<Boxed_Value>(), "Object");
|
m.add(user_type<Boxed_Value>(), "Object");
|
||||||
@ -437,11 +437,6 @@ namespace chaiscript::bootstrap {
|
|||||||
m.add(fun(&Build_Info::compiler_id), "compiler_id");
|
m.add(fun(&Build_Info::compiler_id), "compiler_id");
|
||||||
m.add(fun(&Build_Info::debug_build), "debug_build");
|
m.add(fun(&Build_Info::debug_build), "debug_build");
|
||||||
|
|
||||||
// print_string and println_string are registered in ChaiScript_Basic::build_eval_system()
|
|
||||||
// to support per-instance IO redirection via set_print_handler.
|
|
||||||
// When No_IO is set, the functions are still registered but the default handler
|
|
||||||
// is a no-op, so users can provide their own print handlers without any stdout output.
|
|
||||||
|
|
||||||
m.add(dispatch::make_dynamic_proxy_function(&bind_function), "bind");
|
m.add(dispatch::make_dynamic_proxy_function(&bind_function), "bind");
|
||||||
|
|
||||||
m.add(fun(&shared_ptr_unconst_clone<dispatch::Proxy_Function_Base>), "clone");
|
m.add(fun(&shared_ptr_unconst_clone<dispatch::Proxy_Function_Base>), "clone");
|
||||||
|
|||||||
@ -41,7 +41,7 @@ namespace chaiscript {
|
|||||||
// this is OK, so we're disabling size/and sign type warnings
|
// this is OK, so we're disabling size/and sign type warnings
|
||||||
#ifdef CHAISCRIPT_MSVC
|
#ifdef CHAISCRIPT_MSVC
|
||||||
#pragma warning(push)
|
#pragma warning(push)
|
||||||
#pragma warning(disable : 4244 4018 4389 4146 4365 4267 4242)
|
#pragma warning(disable : 4244 4018 4389 4146 4365 4267 4242 4702) // 4702 is for broken unreachable warning
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#ifdef __GNUC__
|
#ifdef __GNUC__
|
||||||
|
|||||||
@ -34,7 +34,6 @@
|
|||||||
#include "dynamic_object.hpp"
|
#include "dynamic_object.hpp"
|
||||||
#include "proxy_constructors.hpp"
|
#include "proxy_constructors.hpp"
|
||||||
#include "proxy_functions.hpp"
|
#include "proxy_functions.hpp"
|
||||||
#include "short_alloc.hpp"
|
|
||||||
#include "type_conversions.hpp"
|
#include "type_conversions.hpp"
|
||||||
#include "type_info.hpp"
|
#include "type_info.hpp"
|
||||||
|
|
||||||
@ -318,9 +317,6 @@ namespace chaiscript {
|
|||||||
|
|
||||||
namespace detail {
|
namespace detail {
|
||||||
struct Stack_Holder {
|
struct Stack_Holder {
|
||||||
// template <class T, std::size_t BufSize = sizeof(T)*20000>
|
|
||||||
// using SmallVector = std::vector<T, short_alloc<T, BufSize>>;
|
|
||||||
|
|
||||||
template<class T>
|
template<class T>
|
||||||
using SmallVector = std::vector<T>;
|
using SmallVector = std::vector<T>;
|
||||||
|
|
||||||
@ -377,8 +373,8 @@ namespace chaiscript {
|
|||||||
|
|
||||||
Dispatch_Engine(const Dispatch_Engine &) = delete;
|
Dispatch_Engine(const Dispatch_Engine &) = delete;
|
||||||
Dispatch_Engine &operator=(const Dispatch_Engine &) = delete;
|
Dispatch_Engine &operator=(const Dispatch_Engine &) = delete;
|
||||||
Dispatch_Engine(Dispatch_Engine &&) = default;
|
Dispatch_Engine(Dispatch_Engine &&) = delete;
|
||||||
Dispatch_Engine &operator=(Dispatch_Engine &&) = default;
|
Dispatch_Engine &operator=(Dispatch_Engine &&) = delete;
|
||||||
|
|
||||||
#ifndef CHAISCRIPT_NO_THREADS
|
#ifndef CHAISCRIPT_NO_THREADS
|
||||||
/// Track an async thread so it can be joined during destruction
|
/// Track an async thread so it can be joined during destruction
|
||||||
@ -790,13 +786,13 @@ namespace chaiscript {
|
|||||||
t_loc = uint_fast32_t(funs.first);
|
t_loc = uint_fast32_t(funs.first);
|
||||||
}
|
}
|
||||||
|
|
||||||
const auto do_attribute_call = [this](int l_num_params,
|
const auto do_attribute_call = [this](std::size_t l_num_params,
|
||||||
Function_Params l_params,
|
Function_Params l_params,
|
||||||
const std::vector<Proxy_Function> &l_funs,
|
const std::vector<Proxy_Function> &l_funs,
|
||||||
const Type_Conversions_State &l_conversions) -> Boxed_Value {
|
const Type_Conversions_State &l_conversions) -> Boxed_Value {
|
||||||
Function_Params attr_params(l_params.begin(), l_params.begin() + l_num_params);
|
Function_Params attr_params(l_params.first(l_num_params));
|
||||||
Boxed_Value bv = dispatch::dispatch(l_funs, attr_params, l_conversions);
|
Boxed_Value bv = dispatch::dispatch(l_funs, attr_params, l_conversions);
|
||||||
if (l_num_params < int(l_params.size()) || bv.get_type_info().bare_equal(user_type<dispatch::Proxy_Function_Base>())) {
|
if (l_num_params < l_params.size() || bv.get_type_info().bare_equal(user_type<dispatch::Proxy_Function_Base>())) {
|
||||||
struct This_Foist {
|
struct This_Foist {
|
||||||
This_Foist(Dispatch_Engine &e, const Boxed_Value &t_bv)
|
This_Foist(Dispatch_Engine &e, const Boxed_Value &t_bv)
|
||||||
: m_e(e) {
|
: m_e(e) {
|
||||||
@ -814,16 +810,16 @@ namespace chaiscript {
|
|||||||
try {
|
try {
|
||||||
auto func = boxed_cast<const dispatch::Proxy_Function_Base *>(bv);
|
auto func = boxed_cast<const dispatch::Proxy_Function_Base *>(bv);
|
||||||
try {
|
try {
|
||||||
return (*func)({l_params.begin() + l_num_params, l_params.end()}, l_conversions);
|
return (*func)(l_params.subspan(l_num_params), l_conversions);
|
||||||
} catch (const chaiscript::exception::bad_boxed_cast &) {
|
} catch (const chaiscript::exception::bad_boxed_cast &) {
|
||||||
} catch (const chaiscript::exception::arity_error &) {
|
} catch (const chaiscript::exception::arity_error &) {
|
||||||
} catch (const chaiscript::exception::guard_error &) {
|
} catch (const chaiscript::exception::guard_error &) {
|
||||||
}
|
}
|
||||||
throw chaiscript::exception::dispatch_error({l_params.begin() + l_num_params, l_params.end()},
|
throw chaiscript::exception::dispatch_error(l_params.subspan(l_num_params),
|
||||||
std::vector<Const_Proxy_Function>{boxed_cast<Const_Proxy_Function>(bv)});
|
std::vector<Const_Proxy_Function>{boxed_cast<Const_Proxy_Function>(bv)});
|
||||||
} catch (const chaiscript::exception::bad_boxed_cast &) {
|
} catch (const chaiscript::exception::bad_boxed_cast &) {
|
||||||
// unable to convert bv into a Proxy_Function_Base
|
// unable to convert bv into a Proxy_Function_Base
|
||||||
throw chaiscript::exception::dispatch_error({l_params.begin() + l_num_params, l_params.end()},
|
throw chaiscript::exception::dispatch_error(l_params.subspan(l_num_params),
|
||||||
std::vector<Const_Proxy_Function>(l_funs.begin(), l_funs.end()));
|
std::vector<Const_Proxy_Function>(l_funs.begin(), l_funs.end()));
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
@ -873,7 +869,7 @@ namespace chaiscript {
|
|||||||
if (!functions.empty()) {
|
if (!functions.empty()) {
|
||||||
try {
|
try {
|
||||||
if (is_no_param) {
|
if (is_no_param) {
|
||||||
auto tmp_params = params.to_vector();
|
auto tmp_params = std::vector<Boxed_Value>(params.begin(), params.end());
|
||||||
tmp_params.insert(tmp_params.begin() + 1, var(t_name));
|
tmp_params.insert(tmp_params.begin() + 1, var(t_name));
|
||||||
return do_attribute_call(2, Function_Params(tmp_params), functions, t_conversions);
|
return do_attribute_call(2, Function_Params(tmp_params), functions, t_conversions);
|
||||||
} else {
|
} else {
|
||||||
@ -948,7 +944,7 @@ namespace chaiscript {
|
|||||||
const auto &f = this->boxed_cast<Const_Proxy_Function>(params[0]);
|
const auto &f = this->boxed_cast<Const_Proxy_Function>(params[0]);
|
||||||
const Type_Conversions_State convs(m_conversions, m_conversions.conversion_saves());
|
const Type_Conversions_State convs(m_conversions, m_conversions.conversion_saves());
|
||||||
|
|
||||||
return const_var(f->call_match(Function_Params(params.begin() + 1, params.end()), convs));
|
return const_var(f->call_match(Function_Params(params.subspan(1)), convs));
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Dump all system info to stdout
|
/// Dump all system info to stdout
|
||||||
|
|||||||
@ -12,55 +12,11 @@
|
|||||||
|
|
||||||
#include "boxed_value.hpp"
|
#include "boxed_value.hpp"
|
||||||
|
|
||||||
|
#include <span>
|
||||||
|
|
||||||
namespace chaiscript {
|
namespace chaiscript {
|
||||||
class Function_Params {
|
|
||||||
public:
|
|
||||||
constexpr Function_Params(const Boxed_Value *const t_begin, const Boxed_Value *const t_end)
|
|
||||||
: m_begin(t_begin)
|
|
||||||
, m_end(t_end) {
|
|
||||||
}
|
|
||||||
|
|
||||||
explicit Function_Params(const Boxed_Value &bv)
|
using Function_Params = std::span<const Boxed_Value>;
|
||||||
: m_begin(&bv)
|
|
||||||
, m_end(m_begin + 1) {
|
|
||||||
}
|
|
||||||
|
|
||||||
explicit Function_Params(const std::vector<Boxed_Value> &vec)
|
|
||||||
: m_begin(vec.empty() ? nullptr : &vec.front())
|
|
||||||
, m_end(vec.empty() ? nullptr : &vec.front() + vec.size()) {
|
|
||||||
}
|
|
||||||
|
|
||||||
template<size_t Size>
|
|
||||||
constexpr explicit Function_Params(const std::array<Boxed_Value, Size> &a)
|
|
||||||
: m_begin(&a.front())
|
|
||||||
, m_end(&a.front() + Size) {
|
|
||||||
}
|
|
||||||
|
|
||||||
[[nodiscard]] constexpr const Boxed_Value &operator[](const std::size_t t_i) const noexcept { return m_begin[t_i]; }
|
|
||||||
|
|
||||||
[[nodiscard]] constexpr const Boxed_Value *begin() const noexcept { return m_begin; }
|
|
||||||
|
|
||||||
[[nodiscard]] constexpr const Boxed_Value &front() const noexcept { return *m_begin; }
|
|
||||||
|
|
||||||
[[nodiscard]] constexpr const Boxed_Value *end() const noexcept { return m_end; }
|
|
||||||
|
|
||||||
[[nodiscard]] constexpr std::size_t size() const noexcept { return std::size_t(m_end - m_begin); }
|
|
||||||
|
|
||||||
[[nodiscard]] std::vector<Boxed_Value> to_vector() const { return std::vector<Boxed_Value>{m_begin, m_end}; }
|
|
||||||
|
|
||||||
[[nodiscard]] constexpr bool empty() const noexcept { return m_begin == m_end; }
|
|
||||||
|
|
||||||
private:
|
|
||||||
const Boxed_Value *m_begin = nullptr;
|
|
||||||
const Boxed_Value *m_end = nullptr;
|
|
||||||
};
|
|
||||||
|
|
||||||
// Constructor specialization for array of size 0
|
|
||||||
template<>
|
|
||||||
constexpr Function_Params::Function_Params(const std::array<Boxed_Value, size_t{0}> & /* a */)
|
|
||||||
: m_begin(nullptr)
|
|
||||||
, m_end(nullptr) {
|
|
||||||
}
|
|
||||||
|
|
||||||
} // namespace chaiscript
|
} // namespace chaiscript
|
||||||
|
|
||||||
|
|||||||
@ -65,7 +65,7 @@ namespace chaiscript {
|
|||||||
bool operator==(const Param_Types &t_rhs) const noexcept { return m_types == t_rhs.m_types; }
|
bool operator==(const Param_Types &t_rhs) const noexcept { return m_types == t_rhs.m_types; }
|
||||||
|
|
||||||
std::vector<Boxed_Value> convert(Function_Params t_params, const Type_Conversions_State &t_conversions) const {
|
std::vector<Boxed_Value> convert(Function_Params t_params, const Type_Conversions_State &t_conversions) const {
|
||||||
auto vals = t_params.to_vector();
|
auto vals = std::vector<Boxed_Value>{t_params.begin(), t_params.end()};
|
||||||
const auto dynamic_object_type_info = user_type<Dynamic_Object>();
|
const auto dynamic_object_type_info = user_type<Dynamic_Object>();
|
||||||
for (size_t i = 0; i < vals.size(); ++i) {
|
for (size_t i = 0; i < vals.size(); ++i) {
|
||||||
const auto &name = m_types[i].first;
|
const auto &name = m_types[i].first;
|
||||||
@ -682,13 +682,13 @@ namespace chaiscript {
|
|||||||
public:
|
public:
|
||||||
dispatch_error(const Function_Params &t_parameters, std::vector<Const_Proxy_Function> t_functions)
|
dispatch_error(const Function_Params &t_parameters, std::vector<Const_Proxy_Function> t_functions)
|
||||||
: std::runtime_error("Error with function dispatch")
|
: std::runtime_error("Error with function dispatch")
|
||||||
, parameters(t_parameters.to_vector())
|
, parameters(t_parameters.begin(), t_parameters.end())
|
||||||
, functions(std::move(t_functions)) {
|
, functions(std::move(t_functions)) {
|
||||||
}
|
}
|
||||||
|
|
||||||
dispatch_error(const Function_Params &t_parameters, std::vector<Const_Proxy_Function> t_functions, const std::string &t_desc)
|
dispatch_error(const Function_Params &t_parameters, std::vector<Const_Proxy_Function> t_functions, const std::string &t_desc)
|
||||||
: std::runtime_error(t_desc)
|
: std::runtime_error(t_desc)
|
||||||
, parameters(t_parameters.to_vector())
|
, parameters(t_parameters.begin(), t_parameters.end())
|
||||||
, functions(std::move(t_functions)) {
|
, functions(std::move(t_functions)) {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -80,7 +80,7 @@ namespace chaiscript {
|
|||||||
}
|
}
|
||||||
|
|
||||||
template<typename Callable, typename Ret, typename... Params, size_t... I>
|
template<typename Callable, typename Ret, typename... Params, size_t... I>
|
||||||
Ret call_func(Ret (*)(Params...),
|
Ret call_func_impl(Ret (*)(Params...),
|
||||||
std::index_sequence<I...>,
|
std::index_sequence<I...>,
|
||||||
const Callable &f,
|
const Callable &f,
|
||||||
[[maybe_unused]] const chaiscript::Function_Params ¶ms,
|
[[maybe_unused]] const chaiscript::Function_Params ¶ms,
|
||||||
@ -95,14 +95,24 @@ namespace chaiscript {
|
|||||||
template<typename Callable, typename Ret, typename... Params>
|
template<typename Callable, typename Ret, typename... Params>
|
||||||
Boxed_Value
|
Boxed_Value
|
||||||
call_func(Ret (*sig)(Params...), const Callable &f, const chaiscript::Function_Params ¶ms, const Type_Conversions_State &t_conversions) {
|
call_func(Ret (*sig)(Params...), const Callable &f, const chaiscript::Function_Params ¶ms, const Type_Conversions_State &t_conversions) {
|
||||||
if constexpr (std::is_same_v<Ret, void>) {
|
return Handle_Return<Ret>::handle(call_func_impl(sig, std::index_sequence_for<Params...>{}, f, params, t_conversions));
|
||||||
call_func(sig, std::index_sequence_for<Params...>{}, f, params, t_conversions);
|
|
||||||
return Handle_Return<void>::handle();
|
|
||||||
} else {
|
|
||||||
return Handle_Return<Ret>::handle(call_func(sig, std::index_sequence_for<Params...>{}, f, params, t_conversions));
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// MSVC has a broken warning for unreachable code in this block
|
||||||
|
#ifdef _MSC_VER
|
||||||
|
#pragma warning(push)
|
||||||
|
#pragma warning(disable: 4702)
|
||||||
|
#endif
|
||||||
|
template<typename Callable, typename... Params>
|
||||||
|
Boxed_Value
|
||||||
|
call_func(void (*sig)(Params...), const Callable &f, const chaiscript::Function_Params ¶ms, const Type_Conversions_State &t_conversions) {
|
||||||
|
call_func_impl(sig, std::index_sequence_for<Params...>{}, f, params, t_conversions);
|
||||||
|
return Handle_Return<void>::handle();
|
||||||
|
}
|
||||||
|
#ifdef _MSC_VER
|
||||||
|
#pragma warning(pop)
|
||||||
|
#endif
|
||||||
|
|
||||||
} // namespace detail
|
} // namespace detail
|
||||||
} // namespace dispatch
|
} // namespace dispatch
|
||||||
|
|
||||||
|
|||||||
@ -1,137 +0,0 @@
|
|||||||
#ifndef SHORT_ALLOC_H
|
|
||||||
#define SHORT_ALLOC_H
|
|
||||||
|
|
||||||
// The MIT License (MIT)
|
|
||||||
//
|
|
||||||
// Copyright (c) 2015 Howard Hinnant
|
|
||||||
//
|
|
||||||
// Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
||||||
// of this software and associated documentation files (the "Software"), to deal
|
|
||||||
// in the Software without restriction, including without limitation the rights
|
|
||||||
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
||||||
// copies of the Software, and to permit persons to whom the Software is
|
|
||||||
// furnished to do so, subject to the following conditions:
|
|
||||||
//
|
|
||||||
// The above copyright notice and this permission notice shall be included in all
|
|
||||||
// copies or substantial portions of the Software.
|
|
||||||
//
|
|
||||||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
||||||
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
||||||
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
||||||
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
||||||
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
||||||
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
||||||
// SOFTWARE.
|
|
||||||
|
|
||||||
#include <cassert>
|
|
||||||
#include <cstddef>
|
|
||||||
|
|
||||||
template<std::size_t N, std::size_t alignment = alignof(std::max_align_t)>
|
|
||||||
class arena {
|
|
||||||
alignas(alignment) char buf_[N];
|
|
||||||
char *ptr_;
|
|
||||||
|
|
||||||
public:
|
|
||||||
~arena() { ptr_ = nullptr; }
|
|
||||||
arena() noexcept
|
|
||||||
: ptr_(buf_) {
|
|
||||||
}
|
|
||||||
arena(const arena &) = delete;
|
|
||||||
arena &operator=(const arena &) = delete;
|
|
||||||
|
|
||||||
template<std::size_t ReqAlign>
|
|
||||||
char *allocate(std::size_t n);
|
|
||||||
void deallocate(char *p, std::size_t n) noexcept;
|
|
||||||
|
|
||||||
static constexpr std::size_t size() noexcept { return N; }
|
|
||||||
std::size_t used() const noexcept { return static_cast<std::size_t>(ptr_ - buf_); }
|
|
||||||
void reset() noexcept { ptr_ = buf_; }
|
|
||||||
|
|
||||||
private:
|
|
||||||
static std::size_t align_up(std::size_t n) noexcept { return (n + (alignment - 1)) & ~(alignment - 1); }
|
|
||||||
|
|
||||||
bool pointer_in_buffer(char *p) noexcept { return buf_ <= p && p <= buf_ + N; }
|
|
||||||
};
|
|
||||||
|
|
||||||
template<std::size_t N, std::size_t alignment>
|
|
||||||
template<std::size_t ReqAlign>
|
|
||||||
char *arena<N, alignment>::allocate(std::size_t n) {
|
|
||||||
static_assert(ReqAlign <= alignment, "alignment is too small for this arena");
|
|
||||||
assert(pointer_in_buffer(ptr_) && "short_alloc has outlived arena");
|
|
||||||
auto const aligned_n = align_up(n);
|
|
||||||
if (static_cast<decltype(aligned_n)>(buf_ + N - ptr_) >= aligned_n) {
|
|
||||||
char *r = ptr_;
|
|
||||||
ptr_ += aligned_n;
|
|
||||||
return r;
|
|
||||||
}
|
|
||||||
|
|
||||||
static_assert(alignment <= alignof(std::max_align_t),
|
|
||||||
"you've chosen an "
|
|
||||||
"alignment that is larger than alignof(std::max_align_t), and "
|
|
||||||
"cannot be guaranteed by normal operator new");
|
|
||||||
return static_cast<char *>(::operator new(n));
|
|
||||||
}
|
|
||||||
|
|
||||||
template<std::size_t N, std::size_t alignment>
|
|
||||||
void arena<N, alignment>::deallocate(char *p, std::size_t n) noexcept {
|
|
||||||
assert(pointer_in_buffer(ptr_) && "short_alloc has outlived arena");
|
|
||||||
if (pointer_in_buffer(p)) {
|
|
||||||
n = align_up(n);
|
|
||||||
if (p + n == ptr_) {
|
|
||||||
ptr_ = p;
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
::operator delete(p);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
template<class T, std::size_t N, std::size_t Align = alignof(std::max_align_t)>
|
|
||||||
class short_alloc {
|
|
||||||
public:
|
|
||||||
using value_type = T;
|
|
||||||
static auto constexpr alignment = Align;
|
|
||||||
static auto constexpr size = N;
|
|
||||||
using arena_type = arena<size, alignment>;
|
|
||||||
|
|
||||||
private:
|
|
||||||
arena_type &a_;
|
|
||||||
|
|
||||||
public:
|
|
||||||
short_alloc(const short_alloc &) = default;
|
|
||||||
short_alloc &operator=(const short_alloc &) = delete;
|
|
||||||
|
|
||||||
explicit short_alloc(arena_type &a) noexcept
|
|
||||||
: a_(a) {
|
|
||||||
static_assert(size % alignment == 0, "size N needs to be a multiple of alignment Align");
|
|
||||||
}
|
|
||||||
template<class U>
|
|
||||||
explicit short_alloc(const short_alloc<U, N, alignment> &a) noexcept
|
|
||||||
: a_(a.a_) {
|
|
||||||
}
|
|
||||||
|
|
||||||
template<class _Up>
|
|
||||||
struct rebind {
|
|
||||||
using other = short_alloc<_Up, N, alignment>;
|
|
||||||
};
|
|
||||||
|
|
||||||
T *allocate(std::size_t n) { return reinterpret_cast<T *>(a_.template allocate<alignof(T)>(n * sizeof(T))); }
|
|
||||||
void deallocate(T *p, std::size_t n) noexcept { a_.deallocate(reinterpret_cast<char *>(p), n * sizeof(T)); }
|
|
||||||
|
|
||||||
template<class T1, std::size_t N1, std::size_t A1, class U, std::size_t M, std::size_t A2>
|
|
||||||
friend bool operator==(const short_alloc<T1, N1, A1> &x, const short_alloc<U, M, A2> &y) noexcept;
|
|
||||||
|
|
||||||
template<class U, std::size_t M, std::size_t A>
|
|
||||||
friend class short_alloc;
|
|
||||||
};
|
|
||||||
|
|
||||||
template<class T, std::size_t N, std::size_t A1, class U, std::size_t M, std::size_t A2>
|
|
||||||
inline bool operator==(const short_alloc<T, N, A1> &x, const short_alloc<U, M, A2> &y) noexcept {
|
|
||||||
return N == M && A1 == A2 && &x.a_ == &y.a_;
|
|
||||||
}
|
|
||||||
|
|
||||||
template<class T, std::size_t N, std::size_t A1, class U, std::size_t M, std::size_t A2>
|
|
||||||
inline bool operator!=(const short_alloc<T, N, A1> &x, const short_alloc<U, M, A2> &y) noexcept {
|
|
||||||
return !(x == y);
|
|
||||||
}
|
|
||||||
|
|
||||||
#endif // SHORT_ALLOC_HPP
|
|
||||||
@ -12,6 +12,7 @@
|
|||||||
|
|
||||||
#include "../utility/hash.hpp"
|
#include "../utility/hash.hpp"
|
||||||
|
|
||||||
|
#include <array>
|
||||||
#include <string>
|
#include <string>
|
||||||
|
|
||||||
namespace chaiscript {
|
namespace chaiscript {
|
||||||
@ -52,10 +53,10 @@ namespace chaiscript {
|
|||||||
invalid
|
invalid
|
||||||
};
|
};
|
||||||
|
|
||||||
constexpr static const char *to_string(Opers t_oper) noexcept {
|
constexpr static std::string_view to_string(Opers t_oper) noexcept {
|
||||||
constexpr const char *opers[]
|
constexpr const std::array opers
|
||||||
= {"", "==", "<", ">", "<=", ">=", "!=", "", "=", "++", "--", "*=", "+=", "/=", "-=", "", "&=", "|=", "<<=", ">>=", "%=", "^=", "", "<<", ">>", "%", "&", "|", "^", "~", "", "+", "/", "*", "-", "+", "-", ""};
|
= {"", "==", "<", ">", "<=", ">=", "!=", "", "=", "++", "--", "*=", "+=", "/=", "-=", "", "&=", "|=", "<<=", ">>=", "%=", "^=", "", "<<", ">>", "%", "&", "|", "^", "~", "", "+", "/", "*", "-", "+", "-", ""};
|
||||||
return opers[static_cast<int>(t_oper)];
|
return opers[static_cast<std::size_t>(t_oper)];
|
||||||
}
|
}
|
||||||
|
|
||||||
constexpr static Opers to_operator(std::string_view t_str, bool t_is_unary = false) noexcept {
|
constexpr static Opers to_operator(std::string_view t_str, bool t_is_unary = false) noexcept {
|
||||||
|
|||||||
@ -130,9 +130,9 @@ namespace chaiscript {
|
|||||||
namespace {
|
namespace {
|
||||||
/// Helper lookup to get the name of each node type
|
/// Helper lookup to get the name of each node type
|
||||||
constexpr const char *ast_node_type_to_string(AST_Node_Type ast_node_type) noexcept {
|
constexpr const char *ast_node_type_to_string(AST_Node_Type ast_node_type) noexcept {
|
||||||
constexpr const char *const ast_node_types[] = {"Id", "Fun_Call", "Unused_Return_Fun_Call", "Arg_List", "Equation", "Var_Decl", "Assign_Decl", "Array_Call", "Dot_Access", "Lambda", "Block", "Scopeless_Block", "Def", "While", "If", "For", "Ranged_For", "Inline_Array", "Inline_Map", "Return", "File", "Prefix", "Break", "Continue", "Map_Pair", "Value_Range", "Inline_Range", "Try", "Catch", "Finally", "Method", "Attr_Decl", "Logical_And", "Logical_Or", "Reference", "Switch", "Case", "Default", "Noop", "Class", "Binary", "Arg", "Global_Decl", "Constant", "Compiled", "Const_Var_Decl", "Const_Assign_Decl", "Using", "Enum", "Namespace_Block"};
|
constexpr std::array ast_node_types = {"Id", "Fun_Call", "Unused_Return_Fun_Call", "Arg_List", "Equation", "Var_Decl", "Assign_Decl", "Array_Call", "Dot_Access", "Lambda", "Block", "Scopeless_Block", "Def", "While", "If", "For", "Ranged_For", "Inline_Array", "Inline_Map", "Return", "File", "Prefix", "Break", "Continue", "Map_Pair", "Value_Range", "Inline_Range", "Try", "Catch", "Finally", "Method", "Attr_Decl", "Logical_And", "Logical_Or", "Reference", "Switch", "Case", "Default", "Noop", "Class", "Binary", "Arg", "Global_Decl", "Constant", "Compiled", "Const_Var_Decl", "Const_Assign_Decl", "Using", "Enum", "Namespace_Block"};
|
||||||
|
|
||||||
return ast_node_types[static_cast<int>(ast_node_type)];
|
return ast_node_types[static_cast<std::size_t>(ast_node_type)];
|
||||||
}
|
}
|
||||||
} // namespace
|
} // namespace
|
||||||
|
|
||||||
|
|||||||
@ -122,7 +122,7 @@ namespace chaiscript {
|
|||||||
chaiscript::detail::Dispatch_Engine &get_eval_engine() noexcept { return m_engine; }
|
chaiscript::detail::Dispatch_Engine &get_eval_engine() noexcept { return m_engine; }
|
||||||
|
|
||||||
/// Builds all the requirements for ChaiScript, including its evaluator and a run of its prelude.
|
/// Builds all the requirements for ChaiScript, including its evaluator and a run of its prelude.
|
||||||
void build_eval_system(const ModulePtr &t_lib, const std::vector<Options> &t_opts, const bool t_no_io = false) {
|
void build_eval_system(const ModulePtr &t_lib, const std::vector<Options> &t_opts, const bool t_no_io) {
|
||||||
if (t_lib) {
|
if (t_lib) {
|
||||||
add(t_lib);
|
add(t_lib);
|
||||||
}
|
}
|
||||||
@ -317,7 +317,7 @@ namespace chaiscript {
|
|||||||
std::vector<std::string> t_module_paths = {},
|
std::vector<std::string> t_module_paths = {},
|
||||||
std::vector<std::string> t_use_paths = {},
|
std::vector<std::string> t_use_paths = {},
|
||||||
const std::vector<chaiscript::Options> &t_opts = chaiscript::default_options(),
|
const std::vector<chaiscript::Options> &t_opts = chaiscript::default_options(),
|
||||||
const bool t_no_io = false)
|
const bool t_no_io=false)
|
||||||
: m_module_paths(ensure_minimum_path_vec(std::move(t_module_paths)))
|
: m_module_paths(ensure_minimum_path_vec(std::move(t_module_paths)))
|
||||||
, m_use_paths(ensure_minimum_path_vec(std::move(t_use_paths)))
|
, m_use_paths(ensure_minimum_path_vec(std::move(t_use_paths)))
|
||||||
, m_parser(std::move(parser))
|
, m_parser(std::move(parser))
|
||||||
@ -611,7 +611,7 @@ namespace chaiscript {
|
|||||||
/// (the symbol mentioned above), an exception is thrown.
|
/// (the symbol mentioned above), an exception is thrown.
|
||||||
///
|
///
|
||||||
/// \throw chaiscript::exception::load_module_error In the event that no matching module can be found.
|
/// \throw chaiscript::exception::load_module_error In the event that no matching module can be found.
|
||||||
std::string load_module(const std::string &t_module_name) {
|
std::string load_module([[maybe_unused]] const std::string &t_module_name) {
|
||||||
#ifdef CHAISCRIPT_NO_DYNLOAD
|
#ifdef CHAISCRIPT_NO_DYNLOAD
|
||||||
throw chaiscript::exception::load_module_error("Loadable module support was disabled (CHAISCRIPT_NO_DYNLOAD)");
|
throw chaiscript::exception::load_module_error("Loadable module support was disabled (CHAISCRIPT_NO_DYNLOAD)");
|
||||||
#else
|
#else
|
||||||
@ -777,7 +777,7 @@ namespace chaiscript {
|
|||||||
throw std::runtime_error("Namespace: " + t_namespace_name + " was already registered.");
|
throw std::runtime_error("Namespace: " + t_namespace_name + " was already registered.");
|
||||||
}
|
}
|
||||||
|
|
||||||
m_namespace_generators.emplace(std::make_pair(t_namespace_name, [=, space = Namespace()]() mutable -> Namespace & {
|
m_namespace_generators.emplace(std::make_pair(t_namespace_name, [=, space = Namespace()]() mutable noexcept -> Namespace & {
|
||||||
t_namespace_generator(space);
|
t_namespace_generator(space);
|
||||||
return space;
|
return space;
|
||||||
}));
|
}));
|
||||||
@ -786,7 +786,7 @@ namespace chaiscript {
|
|||||||
while (pos != std::string::npos) {
|
while (pos != std::string::npos) {
|
||||||
const std::string parent = t_namespace_name.substr(0, pos);
|
const std::string parent = t_namespace_name.substr(0, pos);
|
||||||
if (!m_namespace_generators.count(parent)) {
|
if (!m_namespace_generators.count(parent)) {
|
||||||
m_namespace_generators.emplace(std::make_pair(parent, [space = Namespace()]() mutable -> Namespace & {
|
m_namespace_generators.emplace(std::make_pair(parent, [space = Namespace()]() mutable noexcept -> Namespace & {
|
||||||
return space;
|
return space;
|
||||||
}));
|
}));
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1246,7 +1246,7 @@ namespace chaiscript {
|
|||||||
const auto &ns_name = this->children[0]->text;
|
const auto &ns_name = this->children[0]->text;
|
||||||
|
|
||||||
auto ns_name_bv = const_var(ns_name);
|
auto ns_name_bv = const_var(ns_name);
|
||||||
t_ss->call_function("namespace", m_ns_loc, Function_Params{ns_name_bv}, t_ss.conversions());
|
t_ss->call_function("namespace", m_ns_loc, Function_Params{&ns_name_bv, 1}, t_ss.conversions());
|
||||||
|
|
||||||
std::vector<std::string> parts;
|
std::vector<std::string> parts;
|
||||||
{
|
{
|
||||||
@ -1350,7 +1350,7 @@ namespace chaiscript {
|
|||||||
};
|
};
|
||||||
|
|
||||||
const auto call_function = [&t_ss](const auto &t_funcs, const Boxed_Value &t_param) {
|
const auto call_function = [&t_ss](const auto &t_funcs, const Boxed_Value &t_param) {
|
||||||
return dispatch::dispatch(*t_funcs, Function_Params{t_param}, t_ss.conversions());
|
return dispatch::dispatch(*t_funcs, Function_Params{&t_param, 1}, t_ss.conversions());
|
||||||
};
|
};
|
||||||
|
|
||||||
const std::string &loop_var_name = this->children[0]->text;
|
const std::string &loop_var_name = this->children[0]->text;
|
||||||
@ -1646,8 +1646,8 @@ namespace chaiscript {
|
|||||||
return Boxed_Number::do_oper(m_oper, bv);
|
return Boxed_Number::do_oper(m_oper, bv);
|
||||||
} else {
|
} else {
|
||||||
chaiscript::eval::detail::Function_Push_Pop fpp(t_ss);
|
chaiscript::eval::detail::Function_Push_Pop fpp(t_ss);
|
||||||
fpp.save_params(Function_Params{bv});
|
fpp.save_params(Function_Params{&bv, 1});
|
||||||
return t_ss->call_function(this->text, m_loc, Function_Params{bv}, t_ss.conversions());
|
return t_ss->call_function(this->text, m_loc, Function_Params{&bv, 1}, t_ss.conversions());
|
||||||
}
|
}
|
||||||
} catch (const exception::dispatch_error &e) {
|
} catch (const exception::dispatch_error &e) {
|
||||||
throw exception::eval_error("Error with prefix operator evaluation: '" + this->text + "'", e.parameters, e.functions, false, *t_ss);
|
throw exception::eval_error("Error with prefix operator evaluation: '" + this->text + "'", e.parameters, e.functions, false, *t_ss);
|
||||||
@ -1755,7 +1755,7 @@ namespace chaiscript {
|
|||||||
|
|
||||||
if (dispatch::Param_Types(
|
if (dispatch::Param_Types(
|
||||||
std::vector<std::pair<std::string, Type_Info>>{Arg_List_AST_Node<T>::get_arg_type(*catch_block.children[0], t_ss)})
|
std::vector<std::pair<std::string, Type_Info>>{Arg_List_AST_Node<T>::get_arg_type(*catch_block.children[0], t_ss)})
|
||||||
.match(Function_Params{t_except}, t_ss.conversions())
|
.match(Function_Params{&t_except, 1}, t_ss.conversions())
|
||||||
.first) {
|
.first) {
|
||||||
t_ss.add_object(name, t_except);
|
t_ss.add_object(name, t_except);
|
||||||
|
|
||||||
|
|||||||
@ -14,6 +14,7 @@
|
|||||||
#include <cstring>
|
#include <cstring>
|
||||||
#include <exception>
|
#include <exception>
|
||||||
#include <iostream>
|
#include <iostream>
|
||||||
|
#include <iterator>
|
||||||
#include <memory>
|
#include <memory>
|
||||||
#include <sstream>
|
#include <sstream>
|
||||||
#include <string>
|
#include <string>
|
||||||
@ -22,15 +23,11 @@
|
|||||||
#include "../dispatchkit/boxed_value.hpp"
|
#include "../dispatchkit/boxed_value.hpp"
|
||||||
#include "../utility/hash.hpp"
|
#include "../utility/hash.hpp"
|
||||||
#include "../utility/static_string.hpp"
|
#include "../utility/static_string.hpp"
|
||||||
|
#include "../utility/unicode.hpp"
|
||||||
#include "chaiscript_common.hpp"
|
#include "chaiscript_common.hpp"
|
||||||
#include "chaiscript_optimizer.hpp"
|
#include "chaiscript_optimizer.hpp"
|
||||||
#include "chaiscript_tracer.hpp"
|
#include "chaiscript_tracer.hpp"
|
||||||
|
|
||||||
#if defined(CHAISCRIPT_UTF16_UTF32)
|
|
||||||
#include <codecvt>
|
|
||||||
#include <locale>
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#if defined(CHAISCRIPT_MSVC) && defined(max) && defined(min)
|
#if defined(CHAISCRIPT_MSVC) && defined(max) && defined(min)
|
||||||
#define CHAISCRIPT_PUSHED_MIN_MAX
|
#define CHAISCRIPT_PUSHED_MIN_MAX
|
||||||
#pragma push_macro("max") // Why Microsoft? why? This is worse than bad
|
#pragma push_macro("max") // Why Microsoft? why? This is worse than bad
|
||||||
@ -64,41 +61,26 @@ namespace chaiscript {
|
|||||||
// Generic for u16, u32 and wchar
|
// Generic for u16, u32 and wchar
|
||||||
template<typename string_type>
|
template<typename string_type>
|
||||||
struct Char_Parser_Helper {
|
struct Char_Parser_Helper {
|
||||||
// common for all implementations
|
|
||||||
static std::string u8str_from_ll(long long val) {
|
|
||||||
using char_type = std::string::value_type;
|
|
||||||
|
|
||||||
char_type c[2];
|
|
||||||
c[1] = char_type(val);
|
|
||||||
c[0] = char_type(val >> 8);
|
|
||||||
|
|
||||||
if (c[0] == 0) {
|
|
||||||
return std::string(1, c[1]); // size, character
|
|
||||||
}
|
|
||||||
|
|
||||||
return std::string(c, 2); // char buffer, size
|
|
||||||
}
|
|
||||||
|
|
||||||
static string_type str_from_ll(long long val) {
|
static string_type str_from_ll(long long val) {
|
||||||
using target_char_type = typename string_type::value_type;
|
string_type out;
|
||||||
#if defined(CHAISCRIPT_UTF16_UTF32)
|
utility::unicode::append_codepoint(out, static_cast<std::uint32_t>(val));
|
||||||
// prepare converter
|
return out;
|
||||||
std::wstring_convert<std::codecvt_utf8<target_char_type>, target_char_type> converter;
|
|
||||||
// convert
|
|
||||||
return converter.from_bytes(u8str_from_ll(val));
|
|
||||||
#else
|
|
||||||
// no conversion available, just put value as character
|
|
||||||
return string_type(1, target_char_type(val)); // size, character
|
|
||||||
#endif
|
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
// Specialization for char AKA UTF-8
|
// Specialization for char AKA UTF-8: preserve raw two-byte packing
|
||||||
|
// of multi-character literals.
|
||||||
template<>
|
template<>
|
||||||
struct Char_Parser_Helper<std::string> {
|
struct Char_Parser_Helper<std::string> {
|
||||||
static std::string str_from_ll(long long val) {
|
static std::string str_from_ll(long long val) {
|
||||||
// little SFINAE trick to avoid base class
|
using char_type = std::string::value_type;
|
||||||
return Char_Parser_Helper<std::true_type>::u8str_from_ll(val);
|
char_type c[2];
|
||||||
|
c[1] = char_type(val);
|
||||||
|
c[0] = char_type(val >> 8);
|
||||||
|
if (c[0] == 0) {
|
||||||
|
return std::string(1, c[1]);
|
||||||
|
}
|
||||||
|
return std::string(c, 2);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
} // namespace detail
|
} // namespace detail
|
||||||
@ -128,9 +110,7 @@ namespace chaiscript {
|
|||||||
|
|
||||||
template<typename Array2D, typename First, typename Second>
|
template<typename Array2D, typename First, typename Second>
|
||||||
constexpr static void set_alphabet(Array2D &array, const First first, const Second second) noexcept {
|
constexpr static void set_alphabet(Array2D &array, const First first, const Second second) noexcept {
|
||||||
auto *first_ptr = &std::get<0>(array) + static_cast<std::size_t>(first);
|
array[static_cast<std::size_t>(first)][static_cast<std::size_t>(second)] = true;
|
||||||
auto *second_ptr = &std::get<0>(*first_ptr) + static_cast<std::size_t>(second);
|
|
||||||
*second_ptr = true;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
constexpr static std::array<std::array<bool, detail::lengthof_alphabet>, detail::max_alphabet> build_alphabet() noexcept {
|
constexpr static std::array<std::array<bool, detail::lengthof_alphabet>, detail::max_alphabet> build_alphabet() noexcept {
|
||||||
@ -360,13 +340,13 @@ namespace chaiscript {
|
|||||||
++col;
|
++col;
|
||||||
}
|
}
|
||||||
|
|
||||||
++m_pos;
|
std::advance(m_pos, 1);
|
||||||
}
|
}
|
||||||
return *this;
|
return *this;
|
||||||
}
|
}
|
||||||
|
|
||||||
constexpr Position &operator--() noexcept {
|
constexpr Position &operator--() noexcept {
|
||||||
--m_pos;
|
std::advance(m_pos, -1);
|
||||||
if (*m_pos == '\n') {
|
if (*m_pos == '\n') {
|
||||||
--line;
|
--line;
|
||||||
col = m_last_col;
|
col = m_last_col;
|
||||||
@ -377,7 +357,7 @@ namespace chaiscript {
|
|||||||
}
|
}
|
||||||
|
|
||||||
constexpr Position &operator+=(size_t t_distance) noexcept {
|
constexpr Position &operator+=(size_t t_distance) noexcept {
|
||||||
*this = (*this) + t_distance;
|
*this = *this + t_distance;
|
||||||
return *this;
|
return *this;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -406,9 +386,9 @@ namespace chaiscript {
|
|||||||
|
|
||||||
constexpr bool operator!=(const Position &t_rhs) const noexcept { return m_pos != t_rhs.m_pos; }
|
constexpr bool operator!=(const Position &t_rhs) const noexcept { return m_pos != t_rhs.m_pos; }
|
||||||
|
|
||||||
constexpr bool has_more() const noexcept { return m_pos != m_end; }
|
[[nodiscard]] constexpr bool has_more() const noexcept { return m_pos != m_end; }
|
||||||
|
|
||||||
constexpr size_t remaining() const noexcept { return static_cast<size_t>(m_end - m_pos); }
|
[[nodiscard]] constexpr size_t remaining() const noexcept { return static_cast<size_t>(m_end - m_pos); }
|
||||||
|
|
||||||
constexpr const char &operator*() const noexcept {
|
constexpr const char &operator*() const noexcept {
|
||||||
if (m_pos == m_end) {
|
if (m_pos == m_end) {
|
||||||
@ -458,7 +438,7 @@ namespace chaiscript {
|
|||||||
constexpr static Operator_Matches m_operator_matches{};
|
constexpr static Operator_Matches m_operator_matches{};
|
||||||
|
|
||||||
/// test a char in an m_alphabet
|
/// test a char in an m_alphabet
|
||||||
constexpr bool char_in_alphabet(char c, detail::Alphabet a) const noexcept { return m_alphabet[a][static_cast<uint8_t>(c)]; }
|
[[nodiscard]] constexpr bool char_in_alphabet(char c, detail::Alphabet a) const noexcept { return m_alphabet[a][static_cast<uint8_t>(c)]; }
|
||||||
|
|
||||||
/// Prints the parsed ast_nodes as a tree
|
/// Prints the parsed ast_nodes as a tree
|
||||||
void debug_print(const AST_Node &t, std::string prepend = "") const override {
|
void debug_print(const AST_Node &t, std::string prepend = "") const override {
|
||||||
@ -509,7 +489,7 @@ namespace chaiscript {
|
|||||||
if (m_position.remaining() >= len) {
|
if (m_position.remaining() >= len) {
|
||||||
const char *file_pos = &(*m_position);
|
const char *file_pos = &(*m_position);
|
||||||
for (size_t pos = 0; pos < len; ++pos) {
|
for (size_t pos = 0; pos < len; ++pos) {
|
||||||
if (sym.c_str()[pos] != file_pos[pos]) {
|
if (sym[pos] != *std::next(file_pos, static_cast<std::ptrdiff_t>(pos))) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -530,20 +510,9 @@ namespace chaiscript {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
return true;
|
return true;
|
||||||
} else if (Symbol_(m_singleline_comment)) {
|
}
|
||||||
while (m_position.has_more()) {
|
|
||||||
if (Symbol_(m_cr_lf)) {
|
if (Symbol_(m_singleline_comment) || Symbol_(m_annotation)) {
|
||||||
m_position -= 2;
|
|
||||||
break;
|
|
||||||
} else if (Char_('\n')) {
|
|
||||||
--m_position;
|
|
||||||
break;
|
|
||||||
} else {
|
|
||||||
++m_position;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return true;
|
|
||||||
} else if (Symbol_(m_annotation)) {
|
|
||||||
while (m_position.has_more()) {
|
while (m_position.has_more()) {
|
||||||
if (Symbol_(m_cr_lf)) {
|
if (Symbol_(m_cr_lf)) {
|
||||||
m_position -= 2;
|
m_position -= 2;
|
||||||
@ -1060,7 +1029,7 @@ namespace chaiscript {
|
|||||||
template<typename string_type>
|
template<typename string_type>
|
||||||
struct Char_Parser {
|
struct Char_Parser {
|
||||||
string_type &match;
|
string_type &match;
|
||||||
using char_type = typename string_type::value_type;
|
using char_type = string_type::value_type;
|
||||||
bool is_escaped = false;
|
bool is_escaped = false;
|
||||||
bool is_interpolated = false;
|
bool is_interpolated = false;
|
||||||
bool saw_interpolation_marker = false;
|
bool saw_interpolation_marker = false;
|
||||||
@ -1119,40 +1088,20 @@ namespace chaiscript {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void process_unicode() {
|
void process_unicode() {
|
||||||
const auto ch = static_cast<uint32_t>(std::stoi(hex_matches, nullptr, 16));
|
const auto ch = static_cast<std::uint32_t>(std::stoi(hex_matches, nullptr, 16));
|
||||||
const auto match_size = hex_matches.size();
|
const auto match_size = hex_matches.size();
|
||||||
hex_matches.clear();
|
hex_matches.clear();
|
||||||
is_escaped = false;
|
is_escaped = false;
|
||||||
const auto u_size = unicode_size;
|
const auto u_size = unicode_size;
|
||||||
unicode_size = 0;
|
unicode_size = 0;
|
||||||
|
|
||||||
char buf[4];
|
|
||||||
if (u_size != match_size) {
|
if (u_size != match_size) {
|
||||||
throw exception::eval_error("Incomplete unicode escape sequence");
|
throw exception::eval_error("Incomplete unicode escape sequence");
|
||||||
}
|
}
|
||||||
if (u_size == 4 && ch >= 0xD800 && ch <= 0xDFFF) {
|
if (u_size == 4 && utility::unicode::is_surrogate(ch)) {
|
||||||
throw exception::eval_error("Invalid 16 bit universal character");
|
throw exception::eval_error("Invalid 16 bit universal character");
|
||||||
}
|
}
|
||||||
|
if (utility::unicode::append_utf8(match, ch) == 0) {
|
||||||
if (ch < 0x80) {
|
|
||||||
match += static_cast<char>(ch);
|
|
||||||
} else if (ch < 0x800) {
|
|
||||||
buf[0] = static_cast<char>(0xC0 | (ch >> 6));
|
|
||||||
buf[1] = static_cast<char>(0x80 | (ch & 0x3F));
|
|
||||||
match.append(buf, 2);
|
|
||||||
} else if (ch < 0x10000) {
|
|
||||||
buf[0] = static_cast<char>(0xE0 | (ch >> 12));
|
|
||||||
buf[1] = static_cast<char>(0x80 | ((ch >> 6) & 0x3F));
|
|
||||||
buf[2] = static_cast<char>(0x80 | (ch & 0x3F));
|
|
||||||
match.append(buf, 3);
|
|
||||||
} else if (ch < 0x200000) {
|
|
||||||
buf[0] = static_cast<char>(0xF0 | (ch >> 18));
|
|
||||||
buf[1] = static_cast<char>(0x80 | ((ch >> 12) & 0x3F));
|
|
||||||
buf[2] = static_cast<char>(0x80 | ((ch >> 6) & 0x3F));
|
|
||||||
buf[3] = static_cast<char>(0x80 | (ch & 0x3F));
|
|
||||||
match.append(buf, 4);
|
|
||||||
} else {
|
|
||||||
// this must be an invalid escape sequence?
|
|
||||||
throw exception::eval_error("Invalid 32 bit universal character");
|
throw exception::eval_error("Invalid 32 bit universal character");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -1548,7 +1497,7 @@ namespace chaiscript {
|
|||||||
if (m_position.remaining() >= len) {
|
if (m_position.remaining() >= len) {
|
||||||
auto tmp = m_position;
|
auto tmp = m_position;
|
||||||
for (size_t i = 0; tmp.has_more() && i < len; ++i) {
|
for (size_t i = 0; tmp.has_more() && i < len; ++i) {
|
||||||
if (*tmp != t_s.c_str()[i]) {
|
if (*tmp != t_s[i]) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
++tmp;
|
++tmp;
|
||||||
@ -1575,7 +1524,7 @@ namespace chaiscript {
|
|||||||
return retval;
|
return retval;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool is_operator(std::string_view t_s) const noexcept { return m_operator_matches.is_match(t_s); }
|
[[nodiscard]] bool is_operator(std::string_view t_s) const noexcept { return m_operator_matches.is_match(t_s); }
|
||||||
|
|
||||||
/// Reads (and potentially captures) a symbol group from input if it matches the parameter
|
/// Reads (and potentially captures) a symbol group from input if it matches the parameter
|
||||||
bool Symbol(const utility::Static_String &t_s, const bool t_disallow_prevention = false) {
|
bool Symbol(const utility::Static_String &t_s, const bool t_disallow_prevention = false) {
|
||||||
@ -2749,7 +2698,7 @@ namespace chaiscript {
|
|||||||
bool retval = false;
|
bool retval = false;
|
||||||
const auto prev_stack_top = m_match_stack.size();
|
const auto prev_stack_top = m_match_stack.size();
|
||||||
|
|
||||||
if (m_operators[t_precedence] != Operator_Precedence::Prefix) {
|
if (t_precedence < m_operators.size() && m_operators[t_precedence] < Operator_Precedence::Prefix) {
|
||||||
if (Operator(t_precedence + 1)) {
|
if (Operator(t_precedence + 1)) {
|
||||||
retval = true;
|
retval = true;
|
||||||
std::string oper;
|
std::string oper;
|
||||||
@ -2763,7 +2712,7 @@ namespace chaiscript {
|
|||||||
}
|
}
|
||||||
|
|
||||||
switch (m_operators[t_precedence]) {
|
switch (m_operators[t_precedence]) {
|
||||||
case (Operator_Precedence::Ternary_Cond):
|
case Operator_Precedence::Ternary_Cond:
|
||||||
if (Symbol(":")) {
|
if (Symbol(":")) {
|
||||||
if (!Operator(t_precedence + 1)) {
|
if (!Operator(t_precedence + 1)) {
|
||||||
throw exception::eval_error("Incomplete '" + oper + "' expression",
|
throw exception::eval_error("Incomplete '" + oper + "' expression",
|
||||||
@ -2778,24 +2727,24 @@ namespace chaiscript {
|
|||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case (Operator_Precedence::Addition):
|
case Operator_Precedence::Addition:
|
||||||
case (Operator_Precedence::Multiplication):
|
case Operator_Precedence::Multiplication:
|
||||||
case (Operator_Precedence::Shift):
|
case Operator_Precedence::Shift:
|
||||||
case (Operator_Precedence::Equality):
|
case Operator_Precedence::Equality:
|
||||||
case (Operator_Precedence::Bitwise_And):
|
case Operator_Precedence::Bitwise_And:
|
||||||
case (Operator_Precedence::Bitwise_Xor):
|
case Operator_Precedence::Bitwise_Xor:
|
||||||
case (Operator_Precedence::Bitwise_Or):
|
case Operator_Precedence::Bitwise_Or:
|
||||||
case (Operator_Precedence::Comparison):
|
case Operator_Precedence::Comparison:
|
||||||
build_match<eval::Binary_Operator_AST_Node<Tracer>>(prev_stack_top, oper);
|
build_match<eval::Binary_Operator_AST_Node<Tracer>>(prev_stack_top, oper);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case (Operator_Precedence::Logical_And):
|
case Operator_Precedence::Logical_And:
|
||||||
build_match<eval::Logical_And_AST_Node<Tracer>>(prev_stack_top, oper);
|
build_match<eval::Logical_And_AST_Node<Tracer>>(prev_stack_top, oper);
|
||||||
break;
|
break;
|
||||||
case (Operator_Precedence::Logical_Or):
|
case Operator_Precedence::Logical_Or:
|
||||||
build_match<eval::Logical_Or_AST_Node<Tracer>>(prev_stack_top, oper);
|
build_match<eval::Logical_Or_AST_Node<Tracer>>(prev_stack_top, oper);
|
||||||
break;
|
break;
|
||||||
case (Operator_Precedence::Prefix):
|
case Operator_Precedence::Prefix:
|
||||||
assert(false); // cannot reach here because of if() statement at the top
|
assert(false); // cannot reach here because of if() statement at the top
|
||||||
break;
|
break;
|
||||||
|
|
||||||
@ -2992,7 +2941,7 @@ namespace chaiscript {
|
|||||||
/// Parses the given input string, tagging parsed ast_nodes with the given m_filename.
|
/// Parses the given input string, tagging parsed ast_nodes with the given m_filename.
|
||||||
AST_NodePtr parse_internal(const std::string &t_input, std::string t_fname) {
|
AST_NodePtr parse_internal(const std::string &t_input, std::string t_fname) {
|
||||||
const auto begin = t_input.empty() ? nullptr : &t_input.front();
|
const auto begin = t_input.empty() ? nullptr : &t_input.front();
|
||||||
const auto end = begin == nullptr ? nullptr : begin + t_input.size();
|
const auto end = begin == nullptr ? nullptr : std::next(begin, std::ssize(t_input));
|
||||||
m_position = Position(begin, end);
|
m_position = Position(begin, end);
|
||||||
m_filename = std::make_shared<std::string>(std::move(t_fname));
|
m_filename = std::make_shared<std::string>(std::move(t_fname));
|
||||||
|
|
||||||
|
|||||||
@ -8,6 +8,8 @@
|
|||||||
#define CHAISCRIPT_UTILITY_FNV1A_HPP_
|
#define CHAISCRIPT_UTILITY_FNV1A_HPP_
|
||||||
|
|
||||||
#include "../chaiscript_defines.hpp"
|
#include "../chaiscript_defines.hpp"
|
||||||
|
|
||||||
|
#include <iterator>
|
||||||
#include <cstdint>
|
#include <cstdint>
|
||||||
|
|
||||||
namespace chaiscript {
|
namespace chaiscript {
|
||||||
@ -28,7 +30,7 @@ namespace chaiscript {
|
|||||||
|
|
||||||
while (begin != end) {
|
while (begin != end) {
|
||||||
h = (h ^ (*begin)) * 0x01000193;
|
h = (h ^ (*begin)) * 0x01000193;
|
||||||
++begin;
|
std::advance(begin, 1);
|
||||||
}
|
}
|
||||||
return h;
|
return h;
|
||||||
|
|
||||||
@ -43,7 +45,7 @@ namespace chaiscript {
|
|||||||
|
|
||||||
template<size_t N>
|
template<size_t N>
|
||||||
static constexpr std::uint32_t hash(const char (&str)[N]) noexcept {
|
static constexpr std::uint32_t hash(const char (&str)[N]) noexcept {
|
||||||
return hash(std::begin(str), std::end(str) - 1);
|
return hash(std::begin(str), std::prev(std::end(str)));
|
||||||
}
|
}
|
||||||
|
|
||||||
static constexpr std::uint32_t hash(std::string_view sv) noexcept {
|
static constexpr std::uint32_t hash(std::string_view sv) noexcept {
|
||||||
@ -64,7 +66,7 @@ namespace chaiscript {
|
|||||||
hash += std::uint32_t(*begin);
|
hash += std::uint32_t(*begin);
|
||||||
hash += hash << 10;
|
hash += hash << 10;
|
||||||
hash ^= hash >> 6;
|
hash ^= hash >> 6;
|
||||||
++begin;
|
std::advance(begin, 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
hash += hash << 3;
|
hash += hash << 3;
|
||||||
|
|||||||
@ -7,6 +7,7 @@
|
|||||||
|
|
||||||
#include "../chaiscript_defines.hpp"
|
#include "../chaiscript_defines.hpp"
|
||||||
#include "quick_flat_map.hpp"
|
#include "quick_flat_map.hpp"
|
||||||
|
#include "unicode.hpp"
|
||||||
#include <cctype>
|
#include <cctype>
|
||||||
#include <cmath>
|
#include <cmath>
|
||||||
#include <cstdint>
|
#include <cstdint>
|
||||||
@ -44,21 +45,17 @@ namespace chaiscript::json {
|
|||||||
= std::variant<std::nullptr_t, chaiscript::utility::QuickFlatMap<std::string, JSON>, std::vector<JSON>, std::string, double, std::int64_t, bool>;
|
= std::variant<std::nullptr_t, chaiscript::utility::QuickFlatMap<std::string, JSON>, std::vector<JSON>, std::string, double, std::int64_t, bool>;
|
||||||
|
|
||||||
struct Internal {
|
struct Internal {
|
||||||
Internal(std::nullptr_t)
|
explicit Internal(std::nullptr_t) {}
|
||||||
: d(nullptr) {
|
Internal() = default;
|
||||||
}
|
Internal(const Class c)
|
||||||
Internal()
|
|
||||||
: d(nullptr) {
|
|
||||||
}
|
|
||||||
Internal(Class c)
|
|
||||||
: d(make_type(c)) {
|
: d(make_type(c)) {
|
||||||
}
|
}
|
||||||
template<typename T>
|
template<typename T>
|
||||||
Internal(T t)
|
explicit Internal(T t)
|
||||||
: d(std::move(t)) {
|
: d(std::move(t)) {
|
||||||
}
|
}
|
||||||
|
|
||||||
static Data make_type(Class c) {
|
static Data make_type(const Class c) {
|
||||||
switch (c) {
|
switch (c) {
|
||||||
case Class::Null:
|
case Class::Null:
|
||||||
return nullptr;
|
return nullptr;
|
||||||
@ -84,7 +81,7 @@ namespace chaiscript::json {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Class type() const noexcept { return Class(d.index()); }
|
[[nodiscard]] Class type() const noexcept { return Class(d.index()); }
|
||||||
|
|
||||||
template<auto ClassValue, typename Visitor, typename Or>
|
template<auto ClassValue, typename Visitor, typename Or>
|
||||||
decltype(auto) visit_or(Visitor &&visitor, Or &&other) const {
|
decltype(auto) visit_or(Visitor &&visitor, Or &&other) const {
|
||||||
@ -108,14 +105,14 @@ namespace chaiscript::json {
|
|||||||
auto &Float() { return get_set_type<Class::Floating>(); }
|
auto &Float() { return get_set_type<Class::Floating>(); }
|
||||||
auto &Bool() { return get_set_type<Class::Boolean>(); }
|
auto &Bool() { return get_set_type<Class::Boolean>(); }
|
||||||
|
|
||||||
auto Map() const noexcept { return std::get_if<static_cast<std::size_t>(Class::Object)>(&d); }
|
[[nodiscard]] auto Map() const noexcept { return std::get_if<static_cast<std::size_t>(Class::Object)>(&d); }
|
||||||
auto Vector() const noexcept { return std::get_if<static_cast<std::size_t>(Class::Array)>(&d); }
|
[[nodiscard]] auto Vector() const noexcept { return std::get_if<static_cast<std::size_t>(Class::Array)>(&d); }
|
||||||
auto String() const noexcept { return std::get_if<static_cast<std::size_t>(Class::String)>(&d); }
|
[[nodiscard]] auto String() const noexcept { return std::get_if<static_cast<std::size_t>(Class::String)>(&d); }
|
||||||
auto Int() const noexcept { return std::get_if<static_cast<std::size_t>(Class::Integral)>(&d); }
|
[[nodiscard]] auto Int() const noexcept { return std::get_if<static_cast<std::size_t>(Class::Integral)>(&d); }
|
||||||
auto Float() const noexcept { return std::get_if<static_cast<std::size_t>(Class::Floating)>(&d); }
|
[[nodiscard]] auto Float() const noexcept { return std::get_if<static_cast<std::size_t>(Class::Floating)>(&d); }
|
||||||
auto Bool() const noexcept { return std::get_if<static_cast<std::size_t>(Class::Boolean)>(&d); }
|
[[nodiscard]] auto Bool() const noexcept { return std::get_if<static_cast<std::size_t>(Class::Boolean)>(&d); }
|
||||||
|
|
||||||
Data d;
|
Data d{nullptr};
|
||||||
};
|
};
|
||||||
|
|
||||||
Internal internal;
|
Internal internal;
|
||||||
@ -129,12 +126,12 @@ namespace chaiscript::json {
|
|||||||
JSONWrapper(Container *val)
|
JSONWrapper(Container *val)
|
||||||
: object(val) {
|
: object(val) {
|
||||||
}
|
}
|
||||||
JSONWrapper(std::nullptr_t) {}
|
JSONWrapper(std::nullptr_t) { }
|
||||||
|
|
||||||
typename Container::iterator begin() { return object ? object->begin() : typename Container::iterator(); }
|
Container::iterator begin() { return object ? object->begin() : typename Container::iterator(); }
|
||||||
typename Container::iterator end() { return object ? object->end() : typename Container::iterator(); }
|
Container::iterator end() { return object ? object->end() : typename Container::iterator(); }
|
||||||
typename Container::const_iterator begin() const { return object ? object->begin() : typename Container::iterator(); }
|
[[nodiscard]] Container::const_iterator begin() const { return object ? object->begin() : typename Container::iterator(); }
|
||||||
typename Container::const_iterator end() const { return object ? object->end() : typename Container::iterator(); }
|
[[nodiscard]] Container::const_iterator end() const { return object ? object->end() : typename Container::iterator(); }
|
||||||
};
|
};
|
||||||
|
|
||||||
template<typename Container>
|
template<typename Container>
|
||||||
@ -147,10 +144,10 @@ namespace chaiscript::json {
|
|||||||
}
|
}
|
||||||
JSONConstWrapper(std::nullptr_t) {}
|
JSONConstWrapper(std::nullptr_t) {}
|
||||||
|
|
||||||
typename Container::const_iterator begin() const noexcept {
|
[[nodiscard]] Container::const_iterator begin() const noexcept {
|
||||||
return object ? object->begin() : typename Container::const_iterator();
|
return object ? object->begin() : typename Container::const_iterator();
|
||||||
}
|
}
|
||||||
typename Container::const_iterator end() const noexcept { return object ? object->end() : typename Container::const_iterator(); }
|
[[nodiscard]] Container::const_iterator end() const noexcept { return object ? object->end() : typename Container::const_iterator(); }
|
||||||
};
|
};
|
||||||
|
|
||||||
JSON() = default;
|
JSON() = default;
|
||||||
@ -162,7 +159,9 @@ namespace chaiscript::json {
|
|||||||
|
|
||||||
JSON(initializer_list<JSON> list)
|
JSON(initializer_list<JSON> list)
|
||||||
: internal(Class::Object) {
|
: internal(Class::Object) {
|
||||||
for (auto i = list.begin(), e = list.end(); i != e; ++i, ++i) {
|
for (auto i = list.begin(), e = list.end();
|
||||||
|
i != e;
|
||||||
|
std::advance(i, 2)) {
|
||||||
operator[](i->to_string()) = *std::next(i);
|
operator[](i->to_string()) = *std::next(i);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -471,22 +470,8 @@ namespace chaiscript::json {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
offset += 4;
|
offset += 4;
|
||||||
const auto ch = static_cast<uint32_t>(std::stoi(hex_matches, nullptr, 16));
|
const auto ch = static_cast<std::uint32_t>(std::stoi(hex_matches, nullptr, 16));
|
||||||
if (ch < 0x80) {
|
if (chaiscript::utility::unicode::append_utf8(val, ch) == 0) {
|
||||||
val += static_cast<char>(ch);
|
|
||||||
} else if (ch < 0x800) {
|
|
||||||
val += static_cast<char>(0xC0 | (ch >> 6));
|
|
||||||
val += static_cast<char>(0x80 | (ch & 0x3F));
|
|
||||||
} else if (ch < 0x10000) {
|
|
||||||
val += static_cast<char>(0xE0 | (ch >> 12));
|
|
||||||
val += static_cast<char>(0x80 | ((ch >> 6) & 0x3F));
|
|
||||||
val += static_cast<char>(0x80 | (ch & 0x3F));
|
|
||||||
} else if (ch < 0x200000) {
|
|
||||||
val += static_cast<char>(0xF0 | (ch >> 18));
|
|
||||||
val += static_cast<char>(0x80 | ((ch >> 12) & 0x3F));
|
|
||||||
val += static_cast<char>(0x80 | ((ch >> 6) & 0x3F));
|
|
||||||
val += static_cast<char>(0x80 | (ch & 0x3F));
|
|
||||||
} else {
|
|
||||||
throw std::runtime_error(std::string("JSON ERROR: String: Invalid 32 bit universal character"));
|
throw std::runtime_error(std::string("JSON ERROR: String: Invalid 32 bit universal character"));
|
||||||
}
|
}
|
||||||
} break;
|
} break;
|
||||||
|
|||||||
@ -7,6 +7,8 @@
|
|||||||
#ifndef CHAISCRIPT_UTILITY_STATIC_STRING_HPP_
|
#ifndef CHAISCRIPT_UTILITY_STATIC_STRING_HPP_
|
||||||
#define CHAISCRIPT_UTILITY_STATIC_STRING_HPP_
|
#define CHAISCRIPT_UTILITY_STATIC_STRING_HPP_
|
||||||
|
|
||||||
|
#include <iterator>
|
||||||
|
|
||||||
namespace chaiscript::utility {
|
namespace chaiscript::utility {
|
||||||
struct Static_String {
|
struct Static_String {
|
||||||
template<size_t N>
|
template<size_t N>
|
||||||
@ -21,30 +23,17 @@ namespace chaiscript::utility {
|
|||||||
|
|
||||||
constexpr auto begin() const noexcept { return data; }
|
constexpr auto begin() const noexcept { return data; }
|
||||||
|
|
||||||
constexpr auto end() const noexcept { return data + m_size; }
|
constexpr auto end() const noexcept { return std::next(data, static_cast<std::ptrdiff_t>(m_size)); }
|
||||||
|
|
||||||
constexpr bool operator==(std::string_view other) const noexcept {
|
constexpr auto operator[](const std::size_t idx) const noexcept {
|
||||||
// return std::string_view(data, m_size) == other;
|
return *std::next(data, static_cast<std::ptrdiff_t>(idx));
|
||||||
auto b1 = begin();
|
|
||||||
const auto e1 = end();
|
|
||||||
auto b2 = other.begin();
|
|
||||||
const auto e2 = other.end();
|
|
||||||
|
|
||||||
if (e1 - b1 != e2 - b2) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
while (b1 != e1) {
|
|
||||||
if (*b1 != *b2) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
++b1;
|
|
||||||
++b2;
|
|
||||||
}
|
|
||||||
return true;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
bool operator==(const std::string &t_str) const noexcept { return std::equal(begin(), end(), std::cbegin(t_str), std::cend(t_str)); }
|
constexpr bool operator==(std::string_view other) const noexcept {
|
||||||
|
return std::string_view(data, m_size) == other;
|
||||||
|
}
|
||||||
|
|
||||||
|
constexpr bool operator==(const std::string &t_str) const noexcept { return std::equal(begin(), end(), std::cbegin(t_str), std::cend(t_str)); }
|
||||||
|
|
||||||
const size_t m_size;
|
const size_t m_size;
|
||||||
const char *data = nullptr;
|
const char *data = nullptr;
|
||||||
|
|||||||
91
include/chaiscript/utility/unicode.hpp
Normal file
91
include/chaiscript/utility/unicode.hpp
Normal file
@ -0,0 +1,91 @@
|
|||||||
|
// This file is distributed under the BSD License.
|
||||||
|
// See "license.txt" for details.
|
||||||
|
// http://www.chaiscript.com
|
||||||
|
|
||||||
|
#ifndef CHAISCRIPT_UTILITY_UNICODE_HPP_
|
||||||
|
#define CHAISCRIPT_UTILITY_UNICODE_HPP_
|
||||||
|
|
||||||
|
#include <cstddef>
|
||||||
|
#include <cstdint>
|
||||||
|
#include <string>
|
||||||
|
|
||||||
|
namespace chaiscript {
|
||||||
|
namespace utility {
|
||||||
|
namespace unicode {
|
||||||
|
|
||||||
|
inline constexpr std::uint32_t max_codepoint = 0x10FFFF;
|
||||||
|
|
||||||
|
constexpr bool is_surrogate(std::uint32_t cp) noexcept { return cp >= 0xD800 && cp <= 0xDFFF; }
|
||||||
|
|
||||||
|
// Append cp to out as UTF-8. Returns bytes written, or 0 if cp >= 0x200000.
|
||||||
|
// Surrogates are not rejected here; callers that care check is_surrogate() first.
|
||||||
|
inline std::size_t append_utf8(std::string &out, std::uint32_t cp) {
|
||||||
|
if (cp < 0x80) {
|
||||||
|
out += static_cast<char>(cp);
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
if (cp < 0x800) {
|
||||||
|
out += static_cast<char>(0xC0 | (cp >> 6));
|
||||||
|
out += static_cast<char>(0x80 | (cp & 0x3F));
|
||||||
|
return 2;
|
||||||
|
}
|
||||||
|
if (cp < 0x10000) {
|
||||||
|
out += static_cast<char>(0xE0 | (cp >> 12));
|
||||||
|
out += static_cast<char>(0x80 | ((cp >> 6) & 0x3F));
|
||||||
|
out += static_cast<char>(0x80 | (cp & 0x3F));
|
||||||
|
return 3;
|
||||||
|
}
|
||||||
|
if (cp < 0x200000) {
|
||||||
|
out += static_cast<char>(0xF0 | (cp >> 18));
|
||||||
|
out += static_cast<char>(0x80 | ((cp >> 12) & 0x3F));
|
||||||
|
out += static_cast<char>(0x80 | ((cp >> 6) & 0x3F));
|
||||||
|
out += static_cast<char>(0x80 | (cp & 0x3F));
|
||||||
|
return 4;
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Append cp to out as UTF-16. Returns code units written, or 0 if cp is
|
||||||
|
// a surrogate or > max_codepoint.
|
||||||
|
template<typename CharT>
|
||||||
|
inline std::size_t append_utf16(std::basic_string<CharT> &out, std::uint32_t cp) {
|
||||||
|
if (is_surrogate(cp) || cp > max_codepoint) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
if (cp < 0x10000) {
|
||||||
|
out += static_cast<CharT>(cp);
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
const std::uint32_t v = cp - 0x10000;
|
||||||
|
out += static_cast<CharT>(0xD800 | (v >> 10));
|
||||||
|
out += static_cast<CharT>(0xDC00 | (v & 0x3FF));
|
||||||
|
return 2;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Append cp to a basic_string<CharT>. Dispatches on sizeof(CharT):
|
||||||
|
// 1 byte -> UTF-8, 2 bytes -> UTF-16, 4 bytes -> UTF-32.
|
||||||
|
// Returns code units written, or 0 if the codepoint is invalid.
|
||||||
|
template<typename CharT>
|
||||||
|
inline std::size_t append_codepoint(std::basic_string<CharT> &out, std::uint32_t cp) {
|
||||||
|
if constexpr (sizeof(CharT) == 1) {
|
||||||
|
std::string tmp;
|
||||||
|
const auto n = append_utf8(tmp, cp);
|
||||||
|
out.append(tmp.begin(), tmp.end());
|
||||||
|
return n;
|
||||||
|
} else if constexpr (sizeof(CharT) == 2) {
|
||||||
|
return append_utf16(out, cp);
|
||||||
|
} else {
|
||||||
|
static_assert(sizeof(CharT) == 4, "append_codepoint: unsupported CharT size");
|
||||||
|
if (is_surrogate(cp) || cp > max_codepoint) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
out += static_cast<CharT>(cp);
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace unicode
|
||||||
|
} // namespace utility
|
||||||
|
} // namespace chaiscript
|
||||||
|
|
||||||
|
#endif
|
||||||
@ -30,9 +30,8 @@ char *mystrdup(const char *s) {
|
|||||||
#ifdef CHAISCRIPT_MSVC
|
#ifdef CHAISCRIPT_MSVC
|
||||||
strcpy_s(d, len + 1, s); // Copy the characters
|
strcpy_s(d, len + 1, s); // Copy the characters
|
||||||
#else
|
#else
|
||||||
strncpy(d, s, len); // Copy the characters
|
strncpy(d, s, len + 1); // Copy the characters
|
||||||
#endif
|
#endif
|
||||||
d[len] = '\0';
|
|
||||||
return d; // Return the new string
|
return d; // Return the new string
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -297,7 +296,7 @@ int main(int argc, char *argv[]) {
|
|||||||
++i;
|
++i;
|
||||||
}
|
}
|
||||||
|
|
||||||
std::string arg(i ? argv[i] : "--interactive");
|
std::string arg(i ? *std::next(argv, i) : "--interactive");
|
||||||
|
|
||||||
enum {
|
enum {
|
||||||
eInteractive,
|
eInteractive,
|
||||||
@ -311,7 +310,7 @@ int main(int argc, char *argv[]) {
|
|||||||
std::cout << "insufficient input following " << arg << std::endl;
|
std::cout << "insufficient input following " << arg << std::endl;
|
||||||
return EXIT_FAILURE;
|
return EXIT_FAILURE;
|
||||||
} else {
|
} else {
|
||||||
arg = argv[++i];
|
arg = *std::next(argv, ++i);
|
||||||
}
|
}
|
||||||
} else if (arg == "-" || arg == "--stdin") {
|
} else if (arg == "-" || arg == "--stdin") {
|
||||||
arg = "";
|
arg = "";
|
||||||
|
|||||||
@ -35,9 +35,8 @@ char *mystrdup(const char *s) {
|
|||||||
#ifdef CHAISCRIPT_MSVC
|
#ifdef CHAISCRIPT_MSVC
|
||||||
strcpy_s(d, len + 1, s); // Copy the characters
|
strcpy_s(d, len + 1, s); // Copy the characters
|
||||||
#else
|
#else
|
||||||
strncpy(d, s, len); // Copy the characters
|
strncpy(d, s, len + 1); // Copy the characters
|
||||||
#endif
|
#endif
|
||||||
d[len] = '\0';
|
|
||||||
return d; // Return the new string
|
return d; // Return the new string
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -8,6 +8,7 @@
|
|||||||
// PVS-Studio Static Code Analyzer for C, C++ and C#: http://www.viva64.com
|
// PVS-Studio Static Code Analyzer for C, C++ and C#: http://www.viva64.com
|
||||||
|
|
||||||
#include <chrono>
|
#include <chrono>
|
||||||
|
#include <cstddef>
|
||||||
#include <iostream>
|
#include <iostream>
|
||||||
#include <list>
|
#include <list>
|
||||||
#include <regex>
|
#include <regex>
|
||||||
@ -34,9 +35,8 @@ char *mystrdup(const char *s) {
|
|||||||
#ifdef CHAISCRIPT_MSVC
|
#ifdef CHAISCRIPT_MSVC
|
||||||
strcpy_s(d, len + 1, s); // Copy the characters
|
strcpy_s(d, len + 1, s); // Copy the characters
|
||||||
#else
|
#else
|
||||||
strncpy(d, s, len); // Copy the characters
|
strncpy(d, s, len + 1); // Copy the characters
|
||||||
#endif
|
#endif
|
||||||
d[len] = '\0';
|
|
||||||
return d; // Return the new string
|
return d; // Return the new string
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -283,7 +283,7 @@ int main(int argc, char *argv[]) {
|
|||||||
++i;
|
++i;
|
||||||
}
|
}
|
||||||
|
|
||||||
std::string arg(i != 0 ? argv[i] : "--interactive");
|
std::string arg(i != 0 ? *std::next(argv, i) : "--interactive");
|
||||||
|
|
||||||
enum {
|
enum {
|
||||||
eInteractive,
|
eInteractive,
|
||||||
@ -297,7 +297,7 @@ int main(int argc, char *argv[]) {
|
|||||||
std::cout << "insufficient input following " << arg << '\n';
|
std::cout << "insufficient input following " << arg << '\n';
|
||||||
return EXIT_FAILURE;
|
return EXIT_FAILURE;
|
||||||
}
|
}
|
||||||
arg = argv[++i];
|
arg = *std::next(argv, ++i);
|
||||||
|
|
||||||
} else if (arg == "-" || arg == "--stdin") {
|
} else if (arg == "-" || arg == "--stdin") {
|
||||||
arg = "";
|
arg = "";
|
||||||
|
|||||||
17969
unittests/catch.hpp
17969
unittests/catch.hpp
File diff suppressed because it is too large
Load Diff
12394
unittests/catch_amalgamated.cpp
Normal file
12394
unittests/catch_amalgamated.cpp
Normal file
File diff suppressed because it is too large
Load Diff
14577
unittests/catch_amalgamated.hpp
Normal file
14577
unittests/catch_amalgamated.hpp
Normal file
File diff suppressed because it is too large
Load Diff
@ -22,11 +22,10 @@
|
|||||||
#include "../static_libs/chaiscript_parser.hpp"
|
#include "../static_libs/chaiscript_parser.hpp"
|
||||||
#include "../static_libs/chaiscript_stdlib.hpp"
|
#include "../static_libs/chaiscript_stdlib.hpp"
|
||||||
|
|
||||||
#define CATCH_CONFIG_MAIN
|
#include "catch_amalgamated.hpp"
|
||||||
|
|
||||||
#include <clocale>
|
#include <clocale>
|
||||||
|
|
||||||
#include "catch.hpp"
|
|
||||||
|
|
||||||
// lambda_tests
|
// lambda_tests
|
||||||
TEST_CASE("C++11 Lambdas Can Be Registered") {
|
TEST_CASE("C++11 Lambdas Can Be Registered") {
|
||||||
@ -190,7 +189,7 @@ TEST_CASE("Throw int or double") {
|
|||||||
chai.eval("throw(1.0)", chaiscript::exception_specification<int, double>());
|
chai.eval("throw(1.0)", chaiscript::exception_specification<int, double>());
|
||||||
REQUIRE(false);
|
REQUIRE(false);
|
||||||
} catch (const double e) {
|
} catch (const double e) {
|
||||||
CHECK(e == Approx(1.0));
|
CHECK(e == Catch::Approx(1.0));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -964,7 +963,7 @@ TEST_CASE("Pair conversions") {
|
|||||||
Pair(5, 3.14);
|
Pair(5, 3.14);
|
||||||
)cs");
|
)cs");
|
||||||
CHECK(p.first == 5);
|
CHECK(p.first == 5);
|
||||||
CHECK(p.second == Approx(3.14));
|
CHECK(p.second == Catch::Approx(3.14));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -976,7 +975,7 @@ TEST_CASE("Parse floats with non-posix locale") {
|
|||||||
#endif
|
#endif
|
||||||
chaiscript::ChaiScript_Basic chai(create_chaiscript_stdlib(), create_chaiscript_parser());
|
chaiscript::ChaiScript_Basic chai(create_chaiscript_stdlib(), create_chaiscript_parser());
|
||||||
const double parsed = chai.eval<double>("print(1.3); 1.3");
|
const double parsed = chai.eval<double>("print(1.3); 1.3");
|
||||||
CHECK(parsed == Approx(1.3));
|
CHECK(parsed == Catch::Approx(1.3));
|
||||||
const std::string str = chai.eval<std::string>("to_string(1.3)");
|
const std::string str = chai.eval<std::string>("to_string(1.3)");
|
||||||
CHECK(str == "1.3");
|
CHECK(str == "1.3");
|
||||||
}
|
}
|
||||||
@ -1270,7 +1269,7 @@ TEST_CASE("Test reference member being registered") {
|
|||||||
double d;
|
double d;
|
||||||
chai.add(chaiscript::var(Reference_MyClass(d)), "ref");
|
chai.add(chaiscript::var(Reference_MyClass(d)), "ref");
|
||||||
chai.eval("ref.x = 2.3");
|
chai.eval("ref.x = 2.3");
|
||||||
CHECK(d == Approx(2.3));
|
CHECK(d == Catch::Approx(2.3));
|
||||||
}
|
}
|
||||||
|
|
||||||
// starting with C++20 u8"" strings cannot be compared with std::string
|
// starting with C++20 u8"" strings cannot be compared with std::string
|
||||||
@ -1827,7 +1826,7 @@ TEST_CASE("vector of vectors conversion (issue #374)") {
|
|||||||
}),
|
}),
|
||||||
"sum_nested");
|
"sum_nested");
|
||||||
|
|
||||||
CHECK(chai.eval<double>("sum_nested([[1.0, 2.0], [3.0, 4.0]])") == Approx(10.0));
|
CHECK(chai.eval<double>("sum_nested([[1.0, 2.0], [3.0, 4.0]])") == Catch::Approx(10.0));
|
||||||
|
|
||||||
CHECK(chai.eval<bool>(
|
CHECK(chai.eval<bool>(
|
||||||
"auto v = VectorVectorDouble();"
|
"auto v = VectorVectorDouble();"
|
||||||
@ -1910,12 +1909,12 @@ TEST_CASE("Nested namespaces via register_namespace with :: separator") {
|
|||||||
|
|
||||||
chai.import("constants");
|
chai.import("constants");
|
||||||
|
|
||||||
CHECK(chai.eval<double>("constants.si.mu_B") == Approx(9.274));
|
CHECK(chai.eval<double>("constants.si.mu_B") == Catch::Approx(9.274));
|
||||||
CHECK(chai.eval<double>("constants.mm.mu_B") == Approx(0.05788));
|
CHECK(chai.eval<double>("constants.mm.mu_B") == Catch::Approx(0.05788));
|
||||||
|
|
||||||
// Scope resolution via :: works the same as . for access
|
// Scope resolution via :: works the same as . for access
|
||||||
CHECK(chai.eval<double>("constants::si::mu_B") == Approx(9.274));
|
CHECK(chai.eval<double>("constants::si::mu_B") == Catch::Approx(9.274));
|
||||||
CHECK(chai.eval<double>("constants::mm::mu_B") == Approx(0.05788));
|
CHECK(chai.eval<double>("constants::mm::mu_B") == Catch::Approx(0.05788));
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST_CASE("Deeply nested namespaces via register_namespace") {
|
TEST_CASE("Deeply nested namespaces via register_namespace") {
|
||||||
@ -1984,7 +1983,7 @@ TEST_CASE("Namespace block with var declarations") {
|
|||||||
}
|
}
|
||||||
)");
|
)");
|
||||||
|
|
||||||
CHECK(chai.eval<double>("config::pi") == Approx(3.14));
|
CHECK(chai.eval<double>("config::pi") == Catch::Approx(3.14));
|
||||||
CHECK(chai.eval<std::string>("config::name") == "hello");
|
CHECK(chai.eval<std::string>("config::name") == "hello");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -20,31 +20,31 @@ int main() {
|
|||||||
chaiscript_eval("var x = 42");
|
chaiscript_eval("var x = 42");
|
||||||
|
|
||||||
// Test evalString - same as Emscripten evalString()
|
// Test evalString - same as Emscripten evalString()
|
||||||
std::string s = chaiscript_eval_string("to_string(x)");
|
[[maybe_unused]] std::string s = chaiscript_eval_string("to_string(x)");
|
||||||
assert(s == "42");
|
assert(s == "42");
|
||||||
|
|
||||||
// Test evalInt - same as Emscripten evalInt()
|
// Test evalInt - same as Emscripten evalInt()
|
||||||
int i = chaiscript_eval_int("1 + 2");
|
[[maybe_unused]] int i = chaiscript_eval_int("1 + 2");
|
||||||
assert(i == 3);
|
assert(i == 3);
|
||||||
|
|
||||||
// Test evalBool - same as Emscripten evalBool()
|
// Test evalBool - same as Emscripten evalBool()
|
||||||
bool b = chaiscript_eval_bool("true");
|
[[maybe_unused]] bool b = chaiscript_eval_bool("true");
|
||||||
assert(b == true);
|
assert(b == true);
|
||||||
|
|
||||||
b = chaiscript_eval_bool("false");
|
b = chaiscript_eval_bool("false");
|
||||||
assert(b == false);
|
assert(b == false);
|
||||||
|
|
||||||
// Test evalFloat - same as Emscripten evalFloat()
|
// Test evalFloat - same as Emscripten evalFloat()
|
||||||
float f = chaiscript_eval_float("1.5f");
|
[[maybe_unused]] float f = chaiscript_eval_float("1.5f");
|
||||||
assert(std::abs(f - 1.5f) < 0.001f);
|
assert(std::abs(f - 1.5f) < 0.001f);
|
||||||
|
|
||||||
// Test evalDouble - same as Emscripten evalDouble()
|
// Test evalDouble - same as Emscripten evalDouble()
|
||||||
double d = chaiscript_eval_double("3.14");
|
[[maybe_unused]] double d = chaiscript_eval_double("3.14");
|
||||||
assert(std::abs(d - 3.14) < 0.001);
|
assert(std::abs(d - 3.14) < 0.001);
|
||||||
|
|
||||||
// Test a more complex expression
|
// Test a more complex expression
|
||||||
chaiscript_eval("def square(n) { return n * n; }");
|
chaiscript_eval("def square(n) { return n * n; }");
|
||||||
int sq = chaiscript_eval_int("square(7)");
|
[[maybe_unused]] int sq = chaiscript_eval_int("square(7)");
|
||||||
assert(sq == 49);
|
assert(sq == 49);
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
|
|||||||
@ -22,7 +22,7 @@ int main() {
|
|||||||
// through the eval wrapper functions. In WASM builds without exception
|
// through the eval wrapper functions. In WASM builds without exception
|
||||||
// support, these would abort instead of throwing.
|
// support, these would abort instead of throwing.
|
||||||
|
|
||||||
bool caught = false;
|
[[maybe_unused]] bool caught = false;
|
||||||
|
|
||||||
// Test 1: eval with undefined variable should throw
|
// Test 1: eval with undefined variable should throw
|
||||||
caught = false;
|
caught = false;
|
||||||
@ -64,7 +64,8 @@ int main() {
|
|||||||
|
|
||||||
// Test 5: Verify normal operation still works after caught exceptions
|
// Test 5: Verify normal operation still works after caught exceptions
|
||||||
chaiscript_eval("var post_exception_test = 100");
|
chaiscript_eval("var post_exception_test = 100");
|
||||||
const int result = chaiscript_eval_int("post_exception_test");
|
|
||||||
|
[[maybe_unused]] const int result = chaiscript_eval_int("post_exception_test");
|
||||||
assert(result == 100 && "normal eval must work after caught exceptions");
|
assert(result == 100 && "normal eval must work after caught exceptions");
|
||||||
|
|
||||||
std::cout << "All emscripten exception tests passed.\n";
|
std::cout << "All emscripten exception tests passed.\n";
|
||||||
|
|||||||
@ -16,9 +16,7 @@
|
|||||||
#include <cstdlib>
|
#include <cstdlib>
|
||||||
#include <iostream>
|
#include <iostream>
|
||||||
|
|
||||||
#define CATCH_CONFIG_MAIN
|
#include "catch_amalgamated.hpp"
|
||||||
|
|
||||||
#include "catch.hpp"
|
|
||||||
|
|
||||||
TEST_CASE("Type_Info objects generate expected results") {
|
TEST_CASE("Type_Info objects generate expected results") {
|
||||||
const auto test_type
|
const auto test_type
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user