mirror of
https://github.com/ChaiScript/ChaiScript.git
synced 2026-01-01 03:12:23 +08:00
Merge branch 'develop' into best_practices
This commit is contained in:
commit
a880319db8
@ -24,10 +24,10 @@ matrix:
|
||||
sudo: false
|
||||
env: GCC_VER="4.9"
|
||||
compiler: gcc
|
||||
- os: linux
|
||||
sudo: false
|
||||
env: GCC_VER="4.9" CMAKE_OPTIONS="-D DYNLOAD_ENABLED:BOOL=FALSE -D MULTITHREAD_SUPPORT_ENABLED:BOOL=FALSE -D USE_STD_MAKE_SHARED:BOOL=TRUE" BUILD_ONLY=1
|
||||
compiler: gcc
|
||||
# - os: linux
|
||||
#sudo: false
|
||||
#env: GCC_VER="6" CMAKE_OPTIONS="-D DYNLOAD_ENABLED:BOOL=FALSE -D MULTITHREAD_SUPPORT_ENABLED:BOOL=FALSE -D USE_STD_MAKE_SHARED:BOOL=TRUE" BUILD_ONLY=1
|
||||
#compiler: gcc
|
||||
- os: linux
|
||||
sudo: false
|
||||
env: GCC_VER="5" CPPCHECK=1 CMAKE_OPTIONS="-D RUN_FUZZY_TESTS:BOOL=TRUE"
|
||||
|
||||
@ -4,13 +4,6 @@ if(NOT ${CMAKE_VERSION} VERSION_LESS "3.1")
|
||||
cmake_policy(SET CMP0054 NEW)
|
||||
endif()
|
||||
|
||||
IF(BIICODE)
|
||||
INIT_BIICODE_BLOCK()
|
||||
ADD_BIICODE_TARGETS()
|
||||
ELSE()
|
||||
# Your regular CMakeLists configuration here
|
||||
|
||||
|
||||
project(chaiscript)
|
||||
|
||||
option(MULTITHREAD_SUPPORT_ENABLED "Multithreaded Support Enabled" TRUE)
|
||||
@ -49,6 +42,8 @@ if(CMAKE_COMPILER_IS_GNUCC OR "${CMAKE_CXX_COMPILER_ID}" STREQUAL "Clang")
|
||||
if(ENABLE_ADDRESS_SANITIZER)
|
||||
add_definitions(-fsanitize=address -g)
|
||||
set(LINKER_FLAGS "${LINKER_FLAGS} -fsanitize=address")
|
||||
|
||||
option(BUILD_LIBFUZZ_TESTER "Build libfuzzer tool" FALSE)
|
||||
endif()
|
||||
|
||||
option(ENABLE_MEMORY_SANITIZER "Enable memory sanitizer testing in gcc/clang" FALSE)
|
||||
@ -102,7 +97,7 @@ set(CPACK_RESOURCE_FILE_LICENSE "${CMAKE_CURRENT_SOURCE_DIR}/license.txt")
|
||||
set(CPACK_RESOURCE_FILE_README "${CMAKE_CURRENT_SOURCE_DIR}/readme.md")
|
||||
set(CPACK_PACKAGE_DESCRIPTION_FILE "${CMAKE_CURRENT_SOURCE_DIR}/description.txt")
|
||||
|
||||
set(CPACK_PACKAGE_VERSION_MAJOR 6)
|
||||
set(CPACK_PACKAGE_VERSION_MAJOR 7)
|
||||
set(CPACK_PACKAGE_VERSION_MINOR 0)
|
||||
set(CPACK_PACKAGE_VERSION_PATCH 0)
|
||||
|
||||
@ -123,6 +118,7 @@ configure_file(Doxyfile.in ${CMAKE_BINARY_DIR}/Doxyfile)
|
||||
|
||||
include(CTest)
|
||||
include(CPack)
|
||||
include(cmake/Catch.cmake)
|
||||
|
||||
if(NOT MINGW)
|
||||
find_library(READLINE_LIBRARY NAMES readline PATH /usr/lib /usr/local/lib /opt/local/lib)
|
||||
@ -155,6 +151,9 @@ endif()
|
||||
if(MSVC)
|
||||
add_definitions(/std:c++latest /W4 /w14545 /w34242 /w34254 /w34287 /w44263 /w44265 /w44296 /w44311 /w44826 /we4289 /w14546 /w14547 /w14549 /w14555 /w14619 /w14905 /w14906 /w14928)
|
||||
|
||||
add_definitions(/std:c++17)
|
||||
|
||||
|
||||
if (MSVC_VERSION STREQUAL "1800")
|
||||
# VS2013 doesn't have magic statics
|
||||
add_definitions(/w44640)
|
||||
@ -163,7 +162,7 @@ if(MSVC)
|
||||
add_definitions(/w34062)
|
||||
endif()
|
||||
|
||||
add_definitions(/bigobj)
|
||||
add_definitions(/bigobj /permissive-)
|
||||
# Note on MSVC compiler flags.
|
||||
# The code base selective disables warnings as necessary when the compiler is complaining too much
|
||||
# about something that is perfectly valid, or there is simply no technical way around it
|
||||
@ -262,8 +261,8 @@ add_executable(chai src/main.cpp ${Chai_INCLUDES})
|
||||
target_link_libraries(chai ${LIBS} ${CHAISCRIPT_LIBS})
|
||||
|
||||
if(BUILD_SAMPLES)
|
||||
add_executable(example samples/example.cpp)
|
||||
target_link_libraries(example ${LIBS})
|
||||
add_executable(sanity_checks src/sanity_checks.cpp)
|
||||
target_link_libraries(sanity_checks ${LIBS})
|
||||
add_executable(test_num_exceptions samples/test_num_exceptions.cpp)
|
||||
target_link_libraries(test_num_exceptions ${LIBS} ${CHAISCRIPT_LIBS})
|
||||
add_executable(memory_leak_test samples/memory_leak_test.cpp)
|
||||
@ -287,6 +286,7 @@ if(BUILD_MODULES)
|
||||
set(MODULES stl_extra)
|
||||
endif()
|
||||
|
||||
|
||||
file(GLOB UNIT_TESTS RELATIVE ${CMAKE_CURRENT_SOURCE_DIR}/unittests/ ${CMAKE_CURRENT_SOURCE_DIR}/unittests/*.chai ${CMAKE_CURRENT_SOURCE_DIR}/unittests/3.x/*.chai)
|
||||
list(SORT UNIT_TESTS)
|
||||
|
||||
@ -411,7 +411,7 @@ if(BUILD_TESTING)
|
||||
if(NOT UNIT_TEST_LIGHT)
|
||||
add_executable(compiled_tests unittests/compiled_tests.cpp)
|
||||
target_link_libraries(compiled_tests ${LIBS} ${CHAISCRIPT_LIBS})
|
||||
ADD_CATCH_TESTS(compiled_tests)
|
||||
catch_discover_tests(compiled_tests TEST_PREFIX "compiled.")
|
||||
|
||||
add_executable(static_chaiscript_test unittests/static_chaiscript.cpp)
|
||||
target_link_libraries(static_chaiscript_test ${LIBS})
|
||||
@ -458,6 +458,15 @@ if(BUILD_TESTING)
|
||||
endif()
|
||||
endif()
|
||||
|
||||
|
||||
|
||||
if(BUILD_LIBFUZZ_TESTER)
|
||||
add_executable(fuzzer src/libfuzzer_client.cpp src/sha3.cpp)
|
||||
target_compile_options(fuzzer PRIVATE "-fsanitize=fuzzer,address")
|
||||
target_link_libraries(fuzzer PRIVATE ${LIBS} "-fsanitize=fuzzer,address")
|
||||
endif()
|
||||
|
||||
|
||||
install(TARGETS chai chaiscript_stdlib-${CHAI_VERSION} ${MODULES} RUNTIME DESTINATION bin LIBRARY DESTINATION lib/chaiscript)
|
||||
|
||||
install(DIRECTORY include/chaiscript DESTINATION include
|
||||
@ -482,5 +491,3 @@ install(FILES "${chaiscript_BINARY_DIR}/lib/pkgconfig/chaiscript.pc"
|
||||
DESTINATION lib/pkgconfig)
|
||||
|
||||
|
||||
ENDIF()
|
||||
|
||||
|
||||
4
LICENSE
4
LICENSE
@ -1,4 +1,6 @@
|
||||
Copyright 2009-2016 Jason Turner
|
||||
BSD-3-Clause License
|
||||
|
||||
Copyright 2009-2018 Jason Turner
|
||||
Copyright 2009-2012 Jonathan Turner.
|
||||
|
||||
All Rights Reserved.
|
||||
|
||||
@ -1,4 +1,4 @@
|
||||
version: 5.8.x.{build}
|
||||
version: 6.1.x.{build}
|
||||
image:
|
||||
- Visual Studio 2017
|
||||
environment:
|
||||
@ -11,7 +11,7 @@ build_script:
|
||||
|
||||
cd build
|
||||
|
||||
cmake c:\Projects\chaiscript -G "%VS_VERSION%"
|
||||
cmake c:\Projects\chaiscript -G "%VS_VERSION%" -DBUILD_TESTING:BOOL=ON -DBUILD_MODULES:BOOL=ON
|
||||
|
||||
cmake --build . --config Debug
|
||||
test_script:
|
||||
|
||||
@ -370,6 +370,25 @@ if (expression) { }
|
||||
if (statement; expression) { }
|
||||
```
|
||||
|
||||
## Switch Statements
|
||||
|
||||
``` chaiscript
|
||||
var myvalue = 2
|
||||
switch (myvalue) {
|
||||
case (1) {
|
||||
print("My Value is 1");
|
||||
break;
|
||||
}
|
||||
case (2) {
|
||||
print("My Value is 2");
|
||||
break;
|
||||
}
|
||||
default {
|
||||
print("My Value is something else.";
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
## Built in Types
|
||||
|
||||
```
|
||||
|
||||
175
cmake/Catch.cmake
Normal file
175
cmake/Catch.cmake
Normal file
@ -0,0 +1,175 @@
|
||||
# Distributed under the OSI-approved BSD 3-Clause License. See accompanying
|
||||
# file Copyright.txt or https://cmake.org/licensing for details.
|
||||
|
||||
#[=======================================================================[.rst:
|
||||
Catch
|
||||
-----
|
||||
|
||||
This module defines a function to help use the Catch test framework.
|
||||
|
||||
The :command:`catch_discover_tests` discovers tests by asking the compiled test
|
||||
executable to enumerate its tests. This does not require CMake to be re-run
|
||||
when tests change. However, it may not work in a cross-compiling environment,
|
||||
and setting test properties is less convenient.
|
||||
|
||||
This command is intended to replace use of :command:`add_test` to register
|
||||
tests, and will create a separate CTest test for each Catch test case. Note
|
||||
that this is in some cases less efficient, as common set-up and tear-down logic
|
||||
cannot be shared by multiple test cases executing in the same instance.
|
||||
However, it provides more fine-grained pass/fail information to CTest, which is
|
||||
usually considered as more beneficial. By default, the CTest test name is the
|
||||
same as the Catch name; see also ``TEST_PREFIX`` and ``TEST_SUFFIX``.
|
||||
|
||||
.. command:: catch_discover_tests
|
||||
|
||||
Automatically add tests with CTest by querying the compiled test executable
|
||||
for available tests::
|
||||
|
||||
catch_discover_tests(target
|
||||
[TEST_SPEC arg1...]
|
||||
[EXTRA_ARGS arg1...]
|
||||
[WORKING_DIRECTORY dir]
|
||||
[TEST_PREFIX prefix]
|
||||
[TEST_SUFFIX suffix]
|
||||
[PROPERTIES name1 value1...]
|
||||
[TEST_LIST var]
|
||||
)
|
||||
|
||||
``catch_discover_tests`` sets up a post-build command on the test executable
|
||||
that generates the list of tests by parsing the output from running the test
|
||||
with the ``--list-test-names-only`` argument. This ensures that the full
|
||||
list of tests is obtained. Since test discovery occurs at build time, it is
|
||||
not necessary to re-run CMake when the list of tests changes.
|
||||
However, it requires that :prop_tgt:`CROSSCOMPILING_EMULATOR` is properly set
|
||||
in order to function in a cross-compiling environment.
|
||||
|
||||
Additionally, setting properties on tests is somewhat less convenient, since
|
||||
the tests are not available at CMake time. Additional test properties may be
|
||||
assigned to the set of tests as a whole using the ``PROPERTIES`` option. If
|
||||
more fine-grained test control is needed, custom content may be provided
|
||||
through an external CTest script using the :prop_dir:`TEST_INCLUDE_FILES`
|
||||
directory property. The set of discovered tests is made accessible to such a
|
||||
script via the ``<target>_TESTS`` variable.
|
||||
|
||||
The options are:
|
||||
|
||||
``target``
|
||||
Specifies the Catch executable, which must be a known CMake executable
|
||||
target. CMake will substitute the location of the built executable when
|
||||
running the test.
|
||||
|
||||
``TEST_SPEC arg1...``
|
||||
Specifies test cases, wildcarded test cases, tags and tag expressions to
|
||||
pass to the Catch executable with the ``--list-test-names-only`` argument.
|
||||
|
||||
``EXTRA_ARGS arg1...``
|
||||
Any extra arguments to pass on the command line to each test case.
|
||||
|
||||
``WORKING_DIRECTORY dir``
|
||||
Specifies the directory in which to run the discovered test cases. If this
|
||||
option is not provided, the current binary directory is used.
|
||||
|
||||
``TEST_PREFIX prefix``
|
||||
Specifies a ``prefix`` to be prepended to the name of each discovered test
|
||||
case. This can be useful when the same test executable is being used in
|
||||
multiple calls to ``catch_discover_tests()`` but with different
|
||||
``TEST_SPEC`` or ``EXTRA_ARGS``.
|
||||
|
||||
``TEST_SUFFIX suffix``
|
||||
Similar to ``TEST_PREFIX`` except the ``suffix`` is appended to the name of
|
||||
every discovered test case. Both ``TEST_PREFIX`` and ``TEST_SUFFIX`` may
|
||||
be specified.
|
||||
|
||||
``PROPERTIES name1 value1...``
|
||||
Specifies additional properties to be set on all tests discovered by this
|
||||
invocation of ``catch_discover_tests``.
|
||||
|
||||
``TEST_LIST var``
|
||||
Make the list of tests available in the variable ``var``, rather than the
|
||||
default ``<target>_TESTS``. This can be useful when the same test
|
||||
executable is being used in multiple calls to ``catch_discover_tests()``.
|
||||
Note that this variable is only available in CTest.
|
||||
|
||||
#]=======================================================================]
|
||||
|
||||
#------------------------------------------------------------------------------
|
||||
function(catch_discover_tests TARGET)
|
||||
cmake_parse_arguments(
|
||||
""
|
||||
""
|
||||
"TEST_PREFIX;TEST_SUFFIX;WORKING_DIRECTORY;TEST_LIST"
|
||||
"TEST_SPEC;EXTRA_ARGS;PROPERTIES"
|
||||
${ARGN}
|
||||
)
|
||||
|
||||
if(NOT _WORKING_DIRECTORY)
|
||||
set(_WORKING_DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}")
|
||||
endif()
|
||||
if(NOT _TEST_LIST)
|
||||
set(_TEST_LIST ${TARGET}_TESTS)
|
||||
endif()
|
||||
|
||||
## Generate a unique name based on the extra arguments
|
||||
string(SHA1 args_hash "${_TEST_SPEC} ${_EXTRA_ARGS}")
|
||||
string(SUBSTRING ${args_hash} 0 7 args_hash)
|
||||
|
||||
# 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_tests_file "${CMAKE_CURRENT_BINARY_DIR}/${TARGET}_tests-${args_hash}.cmake")
|
||||
get_property(crosscompiling_emulator
|
||||
TARGET ${TARGET}
|
||||
PROPERTY CROSSCOMPILING_EMULATOR
|
||||
)
|
||||
add_custom_command(
|
||||
TARGET ${TARGET} POST_BUILD
|
||||
BYPRODUCTS "${ctest_tests_file}"
|
||||
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(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"
|
||||
)
|
||||
|
||||
if(NOT ${CMAKE_VERSION} VERSION_LESS "3.10.0")
|
||||
# Add discovered tests to directory TEST_INCLUDE_FILES
|
||||
set_property(DIRECTORY
|
||||
APPEND PROPERTY TEST_INCLUDE_FILES "${ctest_include_file}"
|
||||
)
|
||||
else()
|
||||
# Add discovered tests as directory TEST_INCLUDE_FILE if possible
|
||||
get_property(test_include_file_set DIRECTORY PROPERTY TEST_INCLUDE_FILE SET)
|
||||
if (NOT ${test_include_file_set})
|
||||
set_property(DIRECTORY
|
||||
PROPERTY TEST_INCLUDE_FILE "${ctest_include_file}"
|
||||
)
|
||||
else()
|
||||
message(FATAL_ERROR
|
||||
"Cannot set more than one TEST_INCLUDE_FILE"
|
||||
)
|
||||
endif()
|
||||
endif()
|
||||
|
||||
endfunction()
|
||||
|
||||
###############################################################################
|
||||
|
||||
set(_CATCH_DISCOVER_TESTS_SCRIPT
|
||||
${CMAKE_CURRENT_LIST_DIR}/CatchAddTests.cmake
|
||||
)
|
||||
76
cmake/CatchAddTests.cmake
Normal file
76
cmake/CatchAddTests.cmake
Normal file
@ -0,0 +1,76 @@
|
||||
# Distributed under the OSI-approved BSD 3-Clause License. See accompanying
|
||||
# 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)
|
||||
set(_args "")
|
||||
foreach(_arg ${ARGN})
|
||||
if(_arg MATCHES "[^-./:a-zA-Z0-9_]")
|
||||
set(_args "${_args} [==[${_arg}]==]") # form a bracket_argument
|
||||
else()
|
||||
set(_args "${_args} ${_arg}")
|
||||
endif()
|
||||
endforeach()
|
||||
set(script "${script}${NAME}(${_args})\n" PARENT_SCOPE)
|
||||
endfunction()
|
||||
|
||||
# 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()
|
||||
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}")
|
||||
185
cmake/ParseAndAddCatchTests.cmake
Normal file
185
cmake/ParseAndAddCatchTests.cmake
Normal file
@ -0,0 +1,185 @@
|
||||
#==================================================================================================#
|
||||
# supported macros #
|
||||
# - TEST_CASE, #
|
||||
# - SCENARIO, #
|
||||
# - TEST_CASE_METHOD, #
|
||||
# - CATCH_TEST_CASE, #
|
||||
# - CATCH_SCENARIO, #
|
||||
# - CATCH_TEST_CASE_METHOD. #
|
||||
# #
|
||||
# Usage #
|
||||
# 1. make sure this module is in the path or add this otherwise: #
|
||||
# set(CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH} "${CMAKE_SOURCE_DIR}/cmake.modules/") #
|
||||
# 2. make sure that you've enabled testing option for the project by the call: #
|
||||
# enable_testing() #
|
||||
# 3. add the lines to the script for testing target (sample CMakeLists.txt): #
|
||||
# project(testing_target) #
|
||||
# set(CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH} "${CMAKE_SOURCE_DIR}/cmake.modules/") #
|
||||
# enable_testing() #
|
||||
# #
|
||||
# find_path(CATCH_INCLUDE_DIR "catch.hpp") #
|
||||
# include_directories(${INCLUDE_DIRECTORIES} ${CATCH_INCLUDE_DIR}) #
|
||||
# #
|
||||
# file(GLOB SOURCE_FILES "*.cpp") #
|
||||
# add_executable(${PROJECT_NAME} ${SOURCE_FILES}) #
|
||||
# #
|
||||
# include(ParseAndAddCatchTests) #
|
||||
# ParseAndAddCatchTests(${PROJECT_NAME}) #
|
||||
# #
|
||||
# The following variables affect the behavior of the script: #
|
||||
# #
|
||||
# PARSE_CATCH_TESTS_VERBOSE (Default OFF) #
|
||||
# -- enables debug messages #
|
||||
# PARSE_CATCH_TESTS_NO_HIDDEN_TESTS (Default OFF) #
|
||||
# -- excludes tests marked with [!hide], [.] or [.foo] tags #
|
||||
# PARSE_CATCH_TESTS_ADD_FIXTURE_IN_TEST_NAME (Default ON) #
|
||||
# -- adds fixture class name to the test name #
|
||||
# PARSE_CATCH_TESTS_ADD_TARGET_IN_TEST_NAME (Default ON) #
|
||||
# -- adds cmake target name to the test name #
|
||||
# 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 #
|
||||
# #
|
||||
#==================================================================================================#
|
||||
|
||||
cmake_minimum_required(VERSION 2.8.8)
|
||||
|
||||
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_ADD_FIXTURE_IN_TEST_NAME "Add fixture class 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)
|
||||
|
||||
function(PrintDebugMessage)
|
||||
if(PARSE_CATCH_TESTS_VERBOSE)
|
||||
message(STATUS "ParseAndAddCatchTests: ${ARGV}")
|
||||
endif()
|
||||
endfunction()
|
||||
|
||||
# This removes the contents between
|
||||
# - block comments (i.e. /* ... */)
|
||||
# - full line comments (i.e. // ... )
|
||||
# contents have been read into '${CppCode}'.
|
||||
# !keep partial line comments
|
||||
function(RemoveComments CppCode)
|
||||
string(ASCII 2 CMakeBeginBlockComment)
|
||||
string(ASCII 3 CMakeEndBlockComment)
|
||||
string(REGEX REPLACE "/\\*" "${CMakeBeginBlockComment}" ${CppCode} "${${CppCode}}")
|
||||
string(REGEX REPLACE "\\*/" "${CMakeEndBlockComment}" ${CppCode} "${${CppCode}}")
|
||||
string(REGEX REPLACE "${CMakeBeginBlockComment}[^${CMakeEndBlockComment}]*${CMakeEndBlockComment}" "" ${CppCode} "${${CppCode}}")
|
||||
string(REGEX REPLACE "\n[ \t]*//+[^\n]+" "\n" ${CppCode} "${${CppCode}}")
|
||||
|
||||
set(${CppCode} "${${CppCode}}" PARENT_SCOPE)
|
||||
endfunction()
|
||||
|
||||
# Worker function
|
||||
function(ParseFile SourceFile TestTarget)
|
||||
# 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()
|
||||
PrintDebugMessage("parsing ${SourceFile}")
|
||||
file(STRINGS ${SourceFile} Contents NEWLINE_CONSUME)
|
||||
|
||||
# Remove block and fullline comments
|
||||
RemoveComments(Contents)
|
||||
|
||||
# Find definition of test names
|
||||
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)
|
||||
PrintDebugMessage("Adding ${SourceFile} to CMAKE_CONFIGURE_DEPENDS property")
|
||||
set_property(
|
||||
DIRECTORY
|
||||
APPEND
|
||||
PROPERTY CMAKE_CONFIGURE_DEPENDS ${SourceFile}
|
||||
)
|
||||
endif()
|
||||
|
||||
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()
|
||||
|
||||
# entry point
|
||||
function(ParseAndAddCatchTests TestTarget)
|
||||
PrintDebugMessage("Started parsing ${TestTarget}")
|
||||
get_target_property(SourceFiles ${TestTarget} SOURCES)
|
||||
PrintDebugMessage("Found the following sources: ${SourceFiles}")
|
||||
foreach(SourceFile ${SourceFiles})
|
||||
ParseFile(${SourceFile} ${TestTarget})
|
||||
endforeach()
|
||||
PrintDebugMessage("Finished parsing ${TestTarget}")
|
||||
endfunction()
|
||||
@ -1,7 +1,7 @@
|
||||
// This file is distributed under the BSD License.
|
||||
// See "license.txt" for details.
|
||||
// Copyright 2009-2012, Jonathan Turner (jonathan@emptycrate.com)
|
||||
// Copyright 2009-2017, Jason Turner (jason@emptycrate.com)
|
||||
// Copyright 2009-2018, Jason Turner (jason@emptycrate.com)
|
||||
// http://www.chaiscript.com
|
||||
|
||||
// This is an open source non-commercial project. Dear PVS-Studio, please check it.
|
||||
|
||||
@ -1,7 +1,7 @@
|
||||
// This file is distributed under the BSD License.
|
||||
// See "license.txt" for details.
|
||||
// Copyright 2009-2012, Jonathan Turner (jonathan@emptycrate.com)
|
||||
// Copyright 2009-2017, Jason Turner (jason@emptycrate.com)
|
||||
// Copyright 2009-2018, Jason Turner (jason@emptycrate.com)
|
||||
// http://www.chaiscript.com
|
||||
|
||||
#ifndef CHAISCRIPT_BASIC_HPP_
|
||||
|
||||
@ -1,7 +1,7 @@
|
||||
// This file is distributed under the BSD License.
|
||||
// See "license.txt" for details.
|
||||
// Copyright 2009-2012, Jonathan Turner (jonathan@emptycrate.com)
|
||||
// Copyright 2009-2017, Jason Turner (jason@emptycrate.com)
|
||||
// Copyright 2009-2018, Jason Turner (jason@emptycrate.com)
|
||||
// http://www.chaiscript.com
|
||||
|
||||
#ifndef CHAISCRIPT_DEFINES_HPP_
|
||||
@ -76,7 +76,7 @@ static_assert(_MSC_FULL_VER >= 190024210, "Visual C++ 2015 Update 3 or later req
|
||||
#include <cmath>
|
||||
|
||||
namespace chaiscript {
|
||||
constexpr static const int version_major = 6;
|
||||
constexpr static const int version_major = 7;
|
||||
constexpr static const int version_minor = 0;
|
||||
constexpr static const int version_patch = 0;
|
||||
|
||||
@ -153,8 +153,7 @@ namespace chaiscript {
|
||||
|
||||
|
||||
template<typename T>
|
||||
[[nodiscard]] constexpr auto parse_num(const std::string_view &t_str) noexcept
|
||||
-> typename std::enable_if<std::is_integral<T>::value, T>::type
|
||||
[[nodiscard]] constexpr auto parse_num(const std::string_view t_str) noexcept -> typename std::enable_if<std::is_integral<T>::value, T>::type
|
||||
{
|
||||
T t = 0;
|
||||
for (const auto c : t_str) {
|
||||
@ -168,60 +167,15 @@ namespace chaiscript {
|
||||
}
|
||||
|
||||
|
||||
template<typename T>
|
||||
[[nodiscard]] auto parse_num(const std::string_view &t_str) noexcept
|
||||
-> typename std::enable_if<!std::is_integral<T>::value, T>::type
|
||||
{
|
||||
T t = 0;
|
||||
T base = 0;
|
||||
T decimal_place = 0;
|
||||
bool exponent = false;
|
||||
bool neg_exponent = false;
|
||||
|
||||
const auto final_value = [](const T val, const T baseval, const bool hasexp, const bool negexp) -> T {
|
||||
if (!hasexp) {
|
||||
return val;
|
||||
} else {
|
||||
return baseval * std::pow(T(10), val*T(negexp?-1:1));
|
||||
}
|
||||
};
|
||||
|
||||
for (const auto c : t_str) {
|
||||
if (c == '.') {
|
||||
decimal_place = 10;
|
||||
} else if (c == 'e' || c == 'E') {
|
||||
exponent = true;
|
||||
decimal_place = 0;
|
||||
base = t;
|
||||
t = 0;
|
||||
} else if (c == '-' && exponent) {
|
||||
neg_exponent = true;
|
||||
} else if (c == '+' && exponent) {
|
||||
neg_exponent = false;
|
||||
} else if (c < '0' || c > '9') {
|
||||
return final_value(t, base, exponent, neg_exponent);
|
||||
} else if (decimal_place < T(10)) {
|
||||
t *= T(10);
|
||||
t += T(c - '0');
|
||||
} else {
|
||||
t += (T(c - '0') / (T(decimal_place)));
|
||||
decimal_place *= 10;
|
||||
}
|
||||
}
|
||||
|
||||
return final_value(t, base, exponent, neg_exponent);
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
auto parse_num(const char *t_str) -> typename std::enable_if<!std::is_integral<T>::value, T>::type
|
||||
[[nodiscard]] auto parse_num(const std::string_view t_str) -> typename std::enable_if<!std::is_integral<T>::value, T>::type
|
||||
{
|
||||
T t = 0;
|
||||
T base;
|
||||
T base{};
|
||||
T decimal_place = 0;
|
||||
int exponent = 0;
|
||||
|
||||
for (char c;; ++t_str) {
|
||||
c = *t_str;
|
||||
for (const auto c : t_str) {
|
||||
switch (c)
|
||||
{
|
||||
case '.':
|
||||
@ -251,17 +205,18 @@ namespace chaiscript {
|
||||
case '9':
|
||||
if (decimal_place < 10) {
|
||||
t *= 10;
|
||||
t += c - '0';
|
||||
t += static_cast<T>(c - '0');
|
||||
}
|
||||
else {
|
||||
t += (c - '0') / decimal_place;
|
||||
t += static_cast<T>(c - '0') / decimal_place;
|
||||
decimal_place *= 10;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
return exponent ? base * std::pow(T(10), t * exponent) : t;
|
||||
break;
|
||||
}
|
||||
}
|
||||
return exponent ? base * std::pow(T(10), t * static_cast<T>(exponent)) : t;
|
||||
}
|
||||
|
||||
struct str_equal {
|
||||
|
||||
@ -1,7 +1,7 @@
|
||||
// This file is distributed under the BSD License.
|
||||
// See "license.txt" for details.
|
||||
// Copyright 2009-2012, Jonathan Turner (jonathan@emptycrate.com)
|
||||
// Copyright 2009-2017, Jason Turner (jason@emptycrate.com)
|
||||
// Copyright 2009-2018, Jason Turner (jason@emptycrate.com)
|
||||
// http://www.chaiscript.com
|
||||
|
||||
// This is an open source non-commercial project. Dear PVS-Studio, please check it.
|
||||
|
||||
@ -1,7 +1,7 @@
|
||||
// This file is distributed under the BSD License.
|
||||
// See "license.txt" for details.
|
||||
// Copyright 2009-2012, Jonathan Turner (jonathan@emptycrate.com)
|
||||
// Copyright 2009-2017, Jason Turner (jason@emptycrate.com)
|
||||
// Copyright 2009-2018, Jason Turner (jason@emptycrate.com)
|
||||
// http://www.chaiscript.com
|
||||
|
||||
// This is an open source non-commercial project. Dear PVS-Studio, please check it.
|
||||
|
||||
@ -1,7 +1,7 @@
|
||||
// This file is distributed under the BSD License.
|
||||
// See "license.txt" for details.
|
||||
// Copyright 2009-2012, Jonathan Turner (jonathan@emptycrate.com)
|
||||
// Copyright 2009-2017, Jason Turner (jason@emptycrate.com)
|
||||
// Copyright 2009-2018, Jason Turner (jason@emptycrate.com)
|
||||
// http://www.chaiscript.com
|
||||
|
||||
// This is an open source non-commercial project. Dear PVS-Studio, please check it.
|
||||
|
||||
@ -1,7 +1,7 @@
|
||||
// This file is distributed under the BSD License.
|
||||
// See "license.txt" for details.
|
||||
// Copyright 2009-2012, Jonathan Turner (jonathan@emptycrate.com)
|
||||
// Copyright 2009-2017, Jason Turner (jason@emptycrate.com)
|
||||
// Copyright 2009-2018, Jason Turner (jason@emptycrate.com)
|
||||
// http://www.chaiscript.com
|
||||
|
||||
// This is an open source non-commercial project. Dear PVS-Studio, please check it.
|
||||
@ -135,6 +135,7 @@ namespace chaiscript
|
||||
construct_pod<T>(name, m);
|
||||
|
||||
m.add(fun(&parse_string<T>), "to_" + name);
|
||||
m.add(fun([](const T t){ return t; }), "to_" + name);
|
||||
}
|
||||
|
||||
|
||||
@ -454,7 +455,7 @@ namespace chaiscript
|
||||
m.add(fun([](const char c) { return std::string(1, c); }), "to_string");
|
||||
m.add(fun(&Boxed_Number::to_string), "to_string");
|
||||
|
||||
|
||||
|
||||
bootstrap_pod_type<double>("double", m);
|
||||
bootstrap_pod_type<long double>("long_double", m);
|
||||
bootstrap_pod_type<float>("float", m);
|
||||
|
||||
@ -1,7 +1,7 @@
|
||||
// This file is distributed under the BSD License.
|
||||
// See "license.txt" for details.
|
||||
// Copyright 2009-2012, Jonathan Turner (jonathan@emptycrate.com)
|
||||
// Copyright 2009-2017, Jason Turner (jason@emptycrate.com)
|
||||
// Copyright 2009-2018, Jason Turner (jason@emptycrate.com)
|
||||
// http://www.chaiscript.com
|
||||
|
||||
// This is an open source non-commercial project. Dear PVS-Studio, please check it.
|
||||
|
||||
@ -1,7 +1,7 @@
|
||||
// This file is distributed under the BSD License.
|
||||
// See "license.txt" for details.
|
||||
// Copyright 2009-2012, Jonathan Turner (jonathan@emptycrate.com)
|
||||
// Copyright 2009-2017, Jason Turner (jason@emptycrate.com)
|
||||
// Copyright 2009-2018, Jason Turner (jason@emptycrate.com)
|
||||
// http://www.chaiscript.com
|
||||
|
||||
// This is an open source non-commercial project. Dear PVS-Studio, please check it.
|
||||
|
||||
@ -1,7 +1,7 @@
|
||||
// This file is distributed under the BSD License.
|
||||
// See "license.txt" for details.
|
||||
// Copyright 2009-2012, Jonathan Turner (jonathan@emptycrate.com)
|
||||
// Copyright 2009-2017, Jason Turner (jason@emptycrate.com)
|
||||
// Copyright 2009-2018, Jason Turner (jason@emptycrate.com)
|
||||
// http://www.chaiscript.com
|
||||
|
||||
// This is an open source non-commercial project. Dear PVS-Studio, please check it.
|
||||
|
||||
@ -1,7 +1,7 @@
|
||||
// This file is distributed under the BSD License.
|
||||
// See "license.txt" for details.
|
||||
// Copyright 2009-2012, Jonathan Turner (jonathan@emptycrate.com)
|
||||
// Copyright 2009-2017, Jason Turner (jason@emptycrate.com)
|
||||
// Copyright 2009-2018, Jason Turner (jason@emptycrate.com)
|
||||
// http://www.chaiscript.com
|
||||
|
||||
// This is an open source non-commercial project. Dear PVS-Studio, please check it.
|
||||
|
||||
@ -1,7 +1,7 @@
|
||||
// This file is distributed under the BSD License.
|
||||
// See "license.txt" for details.
|
||||
// Copyright 2009-2012, Jonathan Turner (jonathan@emptycrate.com)
|
||||
// Copyright 2009-2017, Jason Turner (jason@emptycrate.com)
|
||||
// Copyright 2009-2018, Jason Turner (jason@emptycrate.com)
|
||||
// http://www.chaiscript.com
|
||||
|
||||
// This is an open source non-commercial project. Dear PVS-Studio, please check it.
|
||||
|
||||
107
include/chaiscript/dispatchkit/callable_traits.hpp
Normal file
107
include/chaiscript/dispatchkit/callable_traits.hpp
Normal file
@ -0,0 +1,107 @@
|
||||
// This file is distributed under the BSD License.
|
||||
// See "license.txt" for details.
|
||||
// Copyright 2009-2012, Jonathan Turner (jonathan@emptycrate.com)
|
||||
// Copyright 2009-2018, Jason Turner (jason@emptycrate.com)
|
||||
// http://www.chaiscript.com
|
||||
|
||||
#ifndef CHAISCRIPT_CALLABLE_TRAITS_HPP_
|
||||
#define CHAISCRIPT_CALLABLE_TRAITS_HPP_
|
||||
|
||||
#include <memory>
|
||||
|
||||
namespace chaiscript {
|
||||
namespace dispatch {
|
||||
namespace detail {
|
||||
|
||||
template<typename Class, typename ... Param>
|
||||
struct Constructor
|
||||
{
|
||||
template<typename ... Inner>
|
||||
std::shared_ptr<Class> operator()(Inner&& ... inner) const {
|
||||
return std::make_shared<Class>(std::forward<Inner>(inner)...);
|
||||
}
|
||||
};
|
||||
|
||||
template<typename Ret, typename Class, typename ... Param>
|
||||
struct Const_Caller
|
||||
{
|
||||
explicit Const_Caller(Ret (Class::*t_func)(Param...) const) : m_func(t_func) {}
|
||||
|
||||
template<typename ... Inner>
|
||||
Ret operator()(const Class &o, Inner&& ... inner) const {
|
||||
return (o.*m_func)(std::forward<Inner>(inner)...);
|
||||
}
|
||||
|
||||
Ret (Class::*m_func)(Param...) const;
|
||||
};
|
||||
|
||||
template<typename Ret, typename ... Param>
|
||||
struct Fun_Caller
|
||||
{
|
||||
explicit Fun_Caller(Ret( * t_func)(Param...) ) : m_func(t_func) {}
|
||||
|
||||
template<typename ... Inner>
|
||||
Ret operator()(Inner&& ... inner) const {
|
||||
return (m_func)(std::forward<Inner>(inner)...);
|
||||
}
|
||||
|
||||
Ret(*m_func)(Param...);
|
||||
};
|
||||
|
||||
template<typename Ret, typename Class, typename ... Param>
|
||||
struct Caller
|
||||
{
|
||||
explicit Caller(Ret (Class::*t_func)(Param...)) : m_func(t_func) {}
|
||||
|
||||
template<typename ... Inner>
|
||||
Ret operator()(Class &o, Inner&& ... inner) const {
|
||||
return (o.*m_func)(std::forward<Inner>(inner)...);
|
||||
}
|
||||
|
||||
Ret (Class::*m_func)(Param...);
|
||||
};
|
||||
|
||||
template<typename T>
|
||||
struct Arity
|
||||
{
|
||||
};
|
||||
|
||||
template<typename Ret, typename ... Params>
|
||||
struct Arity<Ret (Params...)>
|
||||
{
|
||||
static const size_t arity = sizeof...(Params);
|
||||
};
|
||||
|
||||
|
||||
template<typename T>
|
||||
struct Function_Signature
|
||||
{
|
||||
};
|
||||
|
||||
template<typename Ret, typename ... Params>
|
||||
struct Function_Signature<Ret (Params...)>
|
||||
{
|
||||
typedef Ret Return_Type;
|
||||
typedef Ret (Signature)(Params...);
|
||||
};
|
||||
|
||||
template<typename Ret, typename T, typename ... Params>
|
||||
struct Function_Signature<Ret (T::*)(Params...) const>
|
||||
{
|
||||
typedef Ret Return_Type;
|
||||
typedef Ret (Signature)(Params...);
|
||||
};
|
||||
|
||||
|
||||
template<typename T>
|
||||
struct Callable_Traits
|
||||
{
|
||||
typedef typename Function_Signature<decltype(&T::operator())>::Signature Signature;
|
||||
typedef typename Function_Signature<decltype(&T::operator())>::Return_Type Return_Type;
|
||||
};
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
@ -1,7 +1,7 @@
|
||||
// This file is distributed under the BSD License.
|
||||
// See "license.txt" for details.
|
||||
// Copyright 2009-2012, Jonathan Turner (jonathan@emptycrate.com)
|
||||
// Copyright 2009-2017, Jason Turner (jason@emptycrate.com)
|
||||
// Copyright 2009-2018, Jason Turner (jason@emptycrate.com)
|
||||
// http://www.chaiscript.com
|
||||
|
||||
// This is an open source non-commercial project. Dear PVS-Studio, please check it.
|
||||
@ -682,7 +682,7 @@ namespace chaiscript
|
||||
}
|
||||
|
||||
/// Returns the type info for a named type
|
||||
Type_Info get_type(const std::string_view &name, bool t_throw = true) const
|
||||
Type_Info get_type(std::string_view name, bool t_throw = true) const
|
||||
{
|
||||
chaiscript::detail::threading::shared_lock<chaiscript::detail::threading::shared_mutex> l(m_mutex);
|
||||
|
||||
@ -694,7 +694,7 @@ namespace chaiscript
|
||||
}
|
||||
|
||||
if (t_throw) {
|
||||
throw std::range_error("Type Not Known");
|
||||
throw std::range_error("Type Not Known: " + std::string(name));
|
||||
} else {
|
||||
return Type_Info();
|
||||
}
|
||||
@ -730,8 +730,8 @@ namespace chaiscript
|
||||
{
|
||||
uint_fast32_t method_missing_loc = m_method_missing_loc;
|
||||
auto method_missing_funs = get_function("method_missing", method_missing_loc);
|
||||
if (method_missing_funs.first != method_missing_loc) {
|
||||
m_method_missing_loc = uint_fast32_t(method_missing_funs.first);
|
||||
if (method_missing_funs.first != method_missing_loc) {
|
||||
m_method_missing_loc = uint_fast32_t(method_missing_funs.first);
|
||||
}
|
||||
|
||||
return std::move(method_missing_funs.second);
|
||||
@ -837,7 +837,7 @@ namespace chaiscript
|
||||
for (auto itr = stack.rbegin(); itr != stack.rend(); ++itr)
|
||||
{
|
||||
retval.insert(itr->begin(), itr->end());
|
||||
}
|
||||
}
|
||||
|
||||
// add the global values
|
||||
chaiscript::detail::threading::shared_lock<chaiscript::detail::threading::shared_mutex> l(m_mutex);
|
||||
@ -950,11 +950,11 @@ namespace chaiscript
|
||||
} catch (const chaiscript::exception::arity_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.begin() + l_num_params, l_params.end()},
|
||||
std::vector<Const_Proxy_Function>{boxed_cast<Const_Proxy_Function>(bv)});
|
||||
} catch (const chaiscript::exception::bad_boxed_cast &) {
|
||||
// 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.begin() + l_num_params, l_params.end()},
|
||||
std::vector<Const_Proxy_Function>(l_funs.begin(), l_funs.end()));
|
||||
}
|
||||
} else {
|
||||
@ -1011,7 +1011,7 @@ namespace chaiscript
|
||||
tmp_params.insert(tmp_params.begin() + 1, var(t_name));
|
||||
return do_attribute_call(2, Function_Params(tmp_params), functions, t_conversions);
|
||||
} else {
|
||||
std::array p{params[0], var(t_name), var(std::vector<Boxed_Value>(params.begin()+1, params.end()))};
|
||||
std::array<Boxed_Value, 3> p{params[0], var(t_name), var(std::vector<Boxed_Value>(params.begin()+1, params.end()))};
|
||||
return dispatch::dispatch(functions, Function_Params{p}, t_conversions);
|
||||
}
|
||||
} catch (const dispatch::option_explicit_set &e) {
|
||||
|
||||
@ -1,7 +1,7 @@
|
||||
// This file is distributed under the BSD License.
|
||||
// See "license.txt" for details.
|
||||
// Copyright 2009-2012, Jonathan Turner (jonathan@emptycrate.com)
|
||||
// Copyright 2009-2017, Jason Turner (jason@emptycrate.com)
|
||||
// Copyright 2009-2018, Jason Turner (jason@emptycrate.com)
|
||||
// http://www.chaiscript.com
|
||||
|
||||
// This is an open source non-commercial project. Dear PVS-Studio, please check it.
|
||||
|
||||
@ -1,7 +1,7 @@
|
||||
// This file is distributed under the BSD License.
|
||||
// See "license.txt" for details.
|
||||
// Copyright 2009-2012, Jonathan Turner (jonathan@emptycrate.com)
|
||||
// Copyright 2009-2017, Jason Turner (jason@emptycrate.com)
|
||||
// Copyright 2009-2018, Jason Turner (jason@emptycrate.com)
|
||||
// http://www.chaiscript.com
|
||||
|
||||
#ifndef CHAISCRIPT_DYNAMIC_OBJECT_DETAIL_HPP_
|
||||
|
||||
@ -1,7 +1,7 @@
|
||||
// This file is distributed under the BSD License.
|
||||
// See "license.txt" for details.
|
||||
// Copyright 2009-2012, Jonathan Turner (jonathan@emptycrate.com)
|
||||
// Copyright 2009-2017, Jason Turner (jason@emptycrate.com)
|
||||
// Copyright 2009-2018, Jason Turner (jason@emptycrate.com)
|
||||
// http://www.chaiscript.com
|
||||
|
||||
// This is an open source non-commercial project. Dear PVS-Studio, please check it.
|
||||
|
||||
@ -1,7 +1,7 @@
|
||||
// This file is distributed under the BSD License.
|
||||
// See "license.txt" for details.
|
||||
// Copyright 2009-2012, Jonathan Turner (jonathan@emptycrate.com)
|
||||
// Copyright 2009-2017, Jason Turner (jason@emptycrate.com)
|
||||
// Copyright 2009-2018, Jason Turner (jason@emptycrate.com)
|
||||
// http://www.chaiscript.com
|
||||
|
||||
// This is an open source non-commercial project. Dear PVS-Studio, please check it.
|
||||
|
||||
@ -1,7 +1,7 @@
|
||||
// This file is distributed under the BSD License.
|
||||
// See "license.txt" for details.
|
||||
// Copyright 2009-2012, Jonathan Turner (jonathan@emptycrate.com)
|
||||
// Copyright 2009-2017, Jason Turner (jason@emptycrate.com)
|
||||
// Copyright 2009-2018, Jason Turner (jason@emptycrate.com)
|
||||
// http://www.chaiscript.com
|
||||
|
||||
// This is an open source non-commercial project. Dear PVS-Studio, please check it.
|
||||
|
||||
@ -1,7 +1,7 @@
|
||||
// This file is distributed under the BSD License.
|
||||
// See "license.txt" for details.
|
||||
// Copyright 2009-2012, Jonathan Turner (jonathan@emptycrate.com)
|
||||
// Copyright 2009-2017, Jason Turner (jason@emptycrate.com)
|
||||
// Copyright 2009-2018, Jason Turner (jason@emptycrate.com)
|
||||
// http://www.chaiscript.com
|
||||
|
||||
// This is an open source non-commercial project. Dear PVS-Studio, please check it.
|
||||
|
||||
@ -1,7 +1,7 @@
|
||||
// This file is distributed under the BSD License.
|
||||
// See "license.txt" for details.
|
||||
// Copyright 2009-2012, Jonathan Turner (jonathan@emptycrate.com)
|
||||
// Copyright 2009-2017, Jason Turner (jason@emptycrate.com)
|
||||
// Copyright 2009-2018, Jason Turner (jason@emptycrate.com)
|
||||
// http://www.chaiscript.com
|
||||
|
||||
// This is an open source non-commercial project. Dear PVS-Studio, please check it.
|
||||
|
||||
@ -1,7 +1,7 @@
|
||||
// This file is distributed under the BSD License.
|
||||
// See "license.txt" for details.
|
||||
// Copyright 2009-2012, Jonathan Turner (jonathan@emptycrate.com)
|
||||
// Copyright 2009-2017, Jason Turner (jason@emptycrate.com)
|
||||
// Copyright 2009-2018, Jason Turner (jason@emptycrate.com)
|
||||
// http://www.chaiscript.com
|
||||
|
||||
// This is an open source non-commercial project. Dear PVS-Studio, please check it.
|
||||
|
||||
@ -1,7 +1,7 @@
|
||||
// This file is distributed under the BSD License.
|
||||
// See "license.txt" for details.
|
||||
// Copyright 2009-2012, Jonathan Turner (jonathan@emptycrate.com)
|
||||
// Copyright 2009-2017, Jason Turner (jason@emptycrate.com)
|
||||
// Copyright 2009-2018, Jason Turner (jason@emptycrate.com)
|
||||
// http://www.chaiscript.com
|
||||
|
||||
// This is an open source non-commercial project. Dear PVS-Studio, please check it.
|
||||
|
||||
@ -1,7 +1,7 @@
|
||||
// This file is distributed under the BSD License.
|
||||
// See "license.txt" for details.
|
||||
// Copyright 2009-2012, Jonathan Turner (jonathan@emptycrate.com)
|
||||
// Copyright 2009-2017, Jason Turner (jason@emptycrate.com)
|
||||
// Copyright 2009-2018, Jason Turner (jason@emptycrate.com)
|
||||
// http://www.chaiscript.com
|
||||
|
||||
// This is an open source non-commercial project. Dear PVS-Studio, please check it.
|
||||
|
||||
@ -1,7 +1,7 @@
|
||||
// This file is distributed under the BSD License.
|
||||
// See "license.txt" for details.
|
||||
// Copyright 2009-2012, Jonathan Turner (jonathan@emptycrate.com)
|
||||
// Copyright 2009-2017, Jason Turner (jason@emptycrate.com)
|
||||
// Copyright 2009-2018, Jason Turner (jason@emptycrate.com)
|
||||
// http://www.chaiscript.com
|
||||
|
||||
// This is an open source non-commercial project. Dear PVS-Studio, please check it.
|
||||
|
||||
@ -1,7 +1,7 @@
|
||||
// This file is distributed under the BSD License.
|
||||
// See "license.txt" for details.
|
||||
// Copyright 2009-2012, Jonathan Turner (jonathan@emptycrate.com)
|
||||
// Copyright 2009-2017, Jason Turner (jason@emptycrate.com)
|
||||
// Copyright 2009-2018, Jason Turner (jason@emptycrate.com)
|
||||
// http://www.chaiscript.com
|
||||
|
||||
// This is an open source non-commercial project. Dear PVS-Studio, please check it.
|
||||
|
||||
@ -1,7 +1,7 @@
|
||||
// This file is distributed under the BSD License.
|
||||
// See "license.txt" for details.
|
||||
// Copyright 2009-2012, Jonathan Turner (jonathan@emptycrate.com)
|
||||
// Copyright 2009-2017, Jason Turner (jason@emptycrate.com)
|
||||
// Copyright 2009-2018, Jason Turner (jason@emptycrate.com)
|
||||
// http://www.chaiscript.com
|
||||
|
||||
// This is an open source non-commercial project. Dear PVS-Studio, please check it.
|
||||
@ -46,9 +46,9 @@ namespace chaiscript
|
||||
|
||||
constexpr Type_Info() noexcept = default;
|
||||
|
||||
constexpr bool operator<(const Type_Info &ti) const noexcept
|
||||
bool operator<(const Type_Info &ti) const noexcept
|
||||
{
|
||||
return m_type_info < ti.m_type_info;
|
||||
return m_type_info->before(*ti.m_type_info);
|
||||
}
|
||||
|
||||
constexpr bool operator!=(const Type_Info &ti) const noexcept
|
||||
|
||||
@ -1,7 +1,7 @@
|
||||
// This file is distributed under the BSD License.
|
||||
// See "license.txt" for details.
|
||||
// Copyright 2009-2012, Jonathan Turner (jonathan@emptycrate.com)
|
||||
// Copyright 2009-2017, Jason Turner (jason@emptycrate.com)
|
||||
// Copyright 2009-2018, Jason Turner (jason@emptycrate.com)
|
||||
// http://www.chaiscript.com
|
||||
|
||||
// This is an open source non-commercial project. Dear PVS-Studio, please check it.
|
||||
|
||||
@ -1,7 +1,7 @@
|
||||
// This file is distributed under the BSD License.
|
||||
// See "license.txt" for details.
|
||||
// Copyright 2009-2012, Jonathan Turner (jonathan@emptycrate.com)
|
||||
// Copyright 2009-2017, Jason Turner (jason@emptycrate.com)
|
||||
// Copyright 2009-2018, Jason Turner (jason@emptycrate.com)
|
||||
// http://www.chaiscript.com
|
||||
|
||||
// This is an open source non-commercial project. Dear PVS-Studio, please check it.
|
||||
@ -506,11 +506,14 @@ namespace chaiscript
|
||||
/// Errors generated when loading a file
|
||||
struct file_not_found_error : std::runtime_error {
|
||||
explicit file_not_found_error(const std::string &t_filename)
|
||||
: std::runtime_error("File Not Found: " + t_filename)
|
||||
: std::runtime_error("File Not Found: " + t_filename),
|
||||
filename(t_filename)
|
||||
{ }
|
||||
|
||||
file_not_found_error(const file_not_found_error &) = default;
|
||||
~file_not_found_error() noexcept override = default;
|
||||
|
||||
std::string filename;
|
||||
};
|
||||
|
||||
}
|
||||
@ -673,9 +676,6 @@ namespace chaiscript
|
||||
/// Special type for returned values
|
||||
struct Return_Value {
|
||||
Boxed_Value retval;
|
||||
|
||||
|
||||
explicit Return_Value(Boxed_Value &&t_return_value) : retval(std::move(t_return_value)) { }
|
||||
};
|
||||
|
||||
|
||||
|
||||
@ -1,7 +1,7 @@
|
||||
// This file is distributed under the BSD License.
|
||||
// See "license.txt" for details.
|
||||
// Copyright 2009-2012, Jonathan Turner (jonathan@emptycrate.com)
|
||||
// Copyright 2009-2017, Jason Turner (jason@emptycrate.com)
|
||||
// Copyright 2009-2018, Jason Turner (jason@emptycrate.com)
|
||||
// http://www.chaiscript.com
|
||||
|
||||
// This is an open source non-commercial project. Dear PVS-Studio, please check it.
|
||||
@ -54,8 +54,8 @@
|
||||
#include "../dispatchkit/exception_specification.hpp"
|
||||
|
||||
namespace chaiscript
|
||||
{
|
||||
/// Namespace alias to provide cleaner and more explicit syntax to users.
|
||||
{
|
||||
/// Namespace alias to provide cleaner and more explicit syntax to users.
|
||||
using Namespace = dispatch::Dynamic_Object;
|
||||
|
||||
namespace detail
|
||||
@ -200,11 +200,32 @@ namespace chaiscript
|
||||
m_engine.add(fun([this](const Boxed_Value &t_bv, const std::string &t_name){ add_global(t_bv, t_name); }), "add_global");
|
||||
m_engine.add(fun([this](const Boxed_Value &t_bv, const std::string &t_name){ set_global(t_bv, t_name); }), "set_global");
|
||||
|
||||
// why this unused parameter to Namesapce?
|
||||
m_engine.add(fun([this](const std::string& t_namespace_name) { register_namespace([](Namespace& ) {}, t_namespace_name); import(t_namespace_name); }), "namespace");
|
||||
// why this unused parameter to Namespace?
|
||||
m_engine.add(fun([this](const std::string& t_namespace_name) { register_namespace([](Namespace& /*space*/) {}, t_namespace_name); import(t_namespace_name); }), "namespace");
|
||||
m_engine.add(fun([this](const std::string& t_namespace_name) { import(t_namespace_name); }), "import");
|
||||
}
|
||||
|
||||
/// Skip BOM at the beginning of file
|
||||
static bool skip_bom(std::ifstream &infile) {
|
||||
size_t bytes_needed = 3;
|
||||
char buffer[3];
|
||||
|
||||
memset(buffer, '\0', bytes_needed);
|
||||
|
||||
infile.read(buffer, static_cast<std::streamsize>(bytes_needed));
|
||||
|
||||
if ((buffer[0] == '\xef')
|
||||
&& (buffer[1] == '\xbb')
|
||||
&& (buffer[2] == '\xbf')) {
|
||||
|
||||
infile.seekg(3);
|
||||
return true;
|
||||
}
|
||||
|
||||
infile.seekg(0);
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/// Helper function for loading a file
|
||||
static std::string load_file(const std::string &t_filename) {
|
||||
@ -214,17 +235,22 @@ namespace chaiscript
|
||||
throw chaiscript::exception::file_not_found_error(t_filename);
|
||||
}
|
||||
|
||||
const auto size = infile.tellg();
|
||||
auto size = infile.tellg();
|
||||
infile.seekg(0, std::ios::beg);
|
||||
|
||||
assert(size >= 0);
|
||||
|
||||
if (skip_bom(infile)) {
|
||||
size-=3; // decrement the BOM size from file size, otherwise we'll get parsing errors
|
||||
assert(size >= 0); //and check if there's more text
|
||||
}
|
||||
|
||||
if (size == std::streampos(0))
|
||||
{
|
||||
return std::string();
|
||||
} else {
|
||||
std::vector<char> v(static_cast<size_t>(size));
|
||||
infile.read(&v[0], size);
|
||||
infile.read(&v[0], static_cast<std::streamsize>(size));
|
||||
return std::string(v.begin(), v.end());
|
||||
}
|
||||
}
|
||||
@ -369,8 +395,8 @@ namespace chaiscript
|
||||
{
|
||||
for (const auto &path : m_use_paths)
|
||||
{
|
||||
const auto appendedpath = path + t_filename;
|
||||
try {
|
||||
const auto appendedpath = path + t_filename;
|
||||
|
||||
chaiscript::detail::threading::unique_lock<chaiscript::detail::threading::recursive_mutex> l(m_use_mutex);
|
||||
chaiscript::detail::threading::unique_lock<chaiscript::detail::threading::shared_mutex> l2(m_mutex);
|
||||
@ -386,7 +412,11 @@ namespace chaiscript
|
||||
}
|
||||
|
||||
return retval; // return, we loaded it, or it was already loaded
|
||||
} catch (const exception::file_not_found_error &) {
|
||||
} catch (const exception::file_not_found_error &e) {
|
||||
if (e.filename != appendedpath) {
|
||||
// a nested file include failed
|
||||
throw;
|
||||
}
|
||||
// failed to load, try the next path
|
||||
}
|
||||
}
|
||||
@ -711,39 +741,39 @@ namespace chaiscript
|
||||
return m_engine.boxed_cast<T>(eval_file(t_filename, t_handler));
|
||||
}
|
||||
|
||||
/// \brief Imports a namespace object into the global scope of this ChaiScript instance.
|
||||
/// \param[in] t_namespace_name Name of the namespace to import.
|
||||
/// \throw std::runtime_error In the case that the namespace name was never registered.
|
||||
void import(const std::string& t_namespace_name)
|
||||
{
|
||||
chaiscript::detail::threading::unique_lock<chaiscript::detail::threading::recursive_mutex> l(m_use_mutex);
|
||||
|
||||
if (m_engine.get_scripting_objects().count(t_namespace_name)) {
|
||||
throw std::runtime_error("Namespace: " + t_namespace_name + " was already defined");
|
||||
}
|
||||
else if (m_namespace_generators.count(t_namespace_name)) {
|
||||
m_engine.add_global(var(std::ref(m_namespace_generators[t_namespace_name]())), t_namespace_name);
|
||||
}
|
||||
else {
|
||||
throw std::runtime_error("No registered namespace: " + t_namespace_name);
|
||||
}
|
||||
}
|
||||
|
||||
/// \brief Registers a namespace generator, which delays generation of the namespace until it is imported, saving memory if it is never used.
|
||||
/// \param[in] t_namespace_generator Namespace generator function.
|
||||
/// \param[in] t_namespace_name Name of the Namespace function being registered.
|
||||
/// \throw std::runtime_error In the case that the namespace name was already registered.
|
||||
void register_namespace(const std::function<void(Namespace&)>& t_namespace_generator, const std::string& t_namespace_name)
|
||||
{
|
||||
chaiscript::detail::threading::unique_lock<chaiscript::detail::threading::recursive_mutex> l(m_use_mutex);
|
||||
|
||||
if (!m_namespace_generators.count(t_namespace_name)) {
|
||||
// contain the namespace object memory within the m_namespace_generators map
|
||||
m_namespace_generators.emplace(std::make_pair(t_namespace_name, [=, space = Namespace()]() mutable -> Namespace& { t_namespace_generator(space); return space; }));
|
||||
}
|
||||
else {
|
||||
throw std::runtime_error("Namespace: " + t_namespace_name + " was already registered.");
|
||||
}
|
||||
/// \brief Imports a namespace object into the global scope of this ChaiScript instance.
|
||||
/// \param[in] t_namespace_name Name of the namespace to import.
|
||||
/// \throw std::runtime_error In the case that the namespace name was never registered.
|
||||
void import(const std::string& t_namespace_name)
|
||||
{
|
||||
chaiscript::detail::threading::unique_lock<chaiscript::detail::threading::recursive_mutex> l(m_use_mutex);
|
||||
|
||||
if (m_engine.get_scripting_objects().count(t_namespace_name)) {
|
||||
throw std::runtime_error("Namespace: " + t_namespace_name + " was already defined");
|
||||
}
|
||||
else if (m_namespace_generators.count(t_namespace_name)) {
|
||||
m_engine.add_global(var(std::ref(m_namespace_generators[t_namespace_name]())), t_namespace_name);
|
||||
}
|
||||
else {
|
||||
throw std::runtime_error("No registered namespace: " + t_namespace_name);
|
||||
}
|
||||
}
|
||||
|
||||
/// \brief Registers a namespace generator, which delays generation of the namespace until it is imported, saving memory if it is never used.
|
||||
/// \param[in] t_namespace_generator Namespace generator function.
|
||||
/// \param[in] t_namespace_name Name of the Namespace function being registered.
|
||||
/// \throw std::runtime_error In the case that the namespace name was already registered.
|
||||
void register_namespace(const std::function<void(Namespace&)>& t_namespace_generator, const std::string& t_namespace_name)
|
||||
{
|
||||
chaiscript::detail::threading::unique_lock<chaiscript::detail::threading::recursive_mutex> l(m_use_mutex);
|
||||
|
||||
if (!m_namespace_generators.count(t_namespace_name)) {
|
||||
// contain the namespace object memory within the m_namespace_generators map
|
||||
m_namespace_generators.emplace(std::make_pair(t_namespace_name, [=, space = Namespace()]() mutable -> Namespace& { t_namespace_generator(space); return space; }));
|
||||
}
|
||||
else {
|
||||
throw std::runtime_error("Namespace: " + t_namespace_name + " was already registered.");
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
@ -1,7 +1,7 @@
|
||||
// This file is distributed under the BSD License.
|
||||
// See "license.txt" for details.
|
||||
// Copyright 2009-2012, Jonathan Turner (jonathan@emptycrate.com)
|
||||
// Copyright 2009-2017, Jason Turner (jason@emptycrate.com)
|
||||
// Copyright 2009-2018, Jason Turner (jason@emptycrate.com)
|
||||
// http://www.chaiscript.com
|
||||
|
||||
// This is an open source non-commercial project. Dear PVS-Studio, please check it.
|
||||
@ -99,7 +99,7 @@ namespace chaiscript
|
||||
} else if (incoming.get_type_info().bare_equal_type_info(typeid(std::string))) {
|
||||
return Boxed_Value(*static_cast<const std::string *>(incoming.get_const_ptr()));
|
||||
} else {
|
||||
std::array params{std::move(incoming)};
|
||||
std::array<Boxed_Value, 1> params{std::move(incoming)};
|
||||
return t_ss->call_function("clone", t_loc, Function_Params{params}, t_ss.conversions());
|
||||
}
|
||||
} else {
|
||||
@ -203,7 +203,7 @@ namespace chaiscript
|
||||
}
|
||||
} else {
|
||||
chaiscript::eval::detail::Function_Push_Pop fpp(t_ss);
|
||||
std::array params{t_lhs, m_rhs};
|
||||
std::array<Boxed_Value, 2> params{t_lhs, m_rhs};
|
||||
fpp.save_params(Function_Params{params});
|
||||
return t_ss->call_function(t_oper_string, m_loc, Function_Params{params}, t_ss.conversions());
|
||||
}
|
||||
@ -250,7 +250,7 @@ namespace chaiscript
|
||||
}
|
||||
} else {
|
||||
chaiscript::eval::detail::Function_Push_Pop fpp(t_ss);
|
||||
std::array params{t_lhs, t_rhs};
|
||||
std::array<Boxed_Value, 2> params{t_lhs, t_rhs};
|
||||
fpp.save_params(Function_Params(params));
|
||||
return t_ss->call_function(t_oper_string, m_loc, Function_Params(params), t_ss.conversions());
|
||||
}
|
||||
@ -331,6 +331,7 @@ namespace chaiscript
|
||||
|
||||
Boxed_Value fn(this->children[0]->eval(t_ss));
|
||||
|
||||
using ConstFunctionTypePtr = const dispatch::Proxy_Function_Base *;
|
||||
try {
|
||||
return (*t_ss->boxed_cast<const dispatch::Proxy_Function_Base *>(fn))(Function_Params{params}, t_ss.conversions());
|
||||
}
|
||||
@ -339,7 +340,8 @@ namespace chaiscript
|
||||
}
|
||||
catch(const exception::bad_boxed_cast &){
|
||||
try {
|
||||
Const_Proxy_Function f = t_ss->boxed_cast<const Const_Proxy_Function &>(fn);
|
||||
using ConstFunctionTypeRef = const Const_Proxy_Function &;
|
||||
Const_Proxy_Function f = t_ss->boxed_cast<ConstFunctionTypeRef>(fn);
|
||||
// handle the case where there is only 1 function to try to call and dispatch fails on it
|
||||
throw exception::eval_error("Error calling function '" + this->children[0]->text + "'", params, make_vector(f), false, *t_ss);
|
||||
} catch (const exception::bad_boxed_cast &) {
|
||||
@ -455,10 +457,16 @@ namespace chaiscript
|
||||
// for the RHS
|
||||
auto rhs = this->children[1]->eval(t_ss);
|
||||
auto lhs = this->children[0]->eval(t_ss);
|
||||
std::array p{std::move(lhs), std::move(rhs)};
|
||||
std::array<Boxed_Value, 2> p{std::move(lhs), std::move(rhs)};
|
||||
return p;
|
||||
}();
|
||||
|
||||
if (params[0].is_return_value()) {
|
||||
throw exception::eval_error("Error, cannot assign to temporary value.");
|
||||
} else if (params[0].is_const()) {
|
||||
throw exception::eval_error("Error, cannot assign to constant value.");
|
||||
}
|
||||
|
||||
|
||||
if (m_oper != Operators::Opers::invalid && params[0].get_type_info().is_arithmetic() &&
|
||||
params[1].get_type_info().is_arithmetic())
|
||||
@ -466,13 +474,9 @@ namespace chaiscript
|
||||
try {
|
||||
return Boxed_Number::do_oper(m_oper, params[0], params[1]);
|
||||
} catch (const std::exception &) {
|
||||
throw exception::eval_error("Error with unsupported arithmetic assignment operation");
|
||||
throw exception::eval_error("Error with unsupported arithmetic assignment operation.");
|
||||
}
|
||||
} else if (m_oper == Operators::Opers::assign) {
|
||||
if (params[0].is_return_value()) {
|
||||
throw exception::eval_error("Error, cannot assign to temporary value.");
|
||||
}
|
||||
|
||||
try {
|
||||
|
||||
if (params[0].is_undef()) {
|
||||
@ -599,7 +603,7 @@ namespace chaiscript
|
||||
Boxed_Value eval_internal(const chaiscript::detail::Dispatch_State &t_ss) const override {
|
||||
chaiscript::eval::detail::Function_Push_Pop fpp(t_ss);
|
||||
|
||||
std::array params{this->children[0]->eval(t_ss), this->children[1]->eval(t_ss)};
|
||||
std::array<Boxed_Value, 2> params{this->children[0]->eval(t_ss), this->children[1]->eval(t_ss)};
|
||||
|
||||
try {
|
||||
fpp.save_params(Function_Params{params});
|
||||
@ -657,7 +661,7 @@ namespace chaiscript
|
||||
|
||||
if (this->children[1]->identifier == AST_Node_Type::Array_Call) {
|
||||
try {
|
||||
std::array p{retval, this->children[1]->children[1]->eval(t_ss)};
|
||||
std::array<Boxed_Value, 2> p{retval, this->children[1]->children[1]->eval(t_ss)};
|
||||
retval = t_ss->call_function("[]", m_array_loc, Function_Params{p}, t_ss.conversions());
|
||||
}
|
||||
catch(const exception::dispatch_error &e){
|
||||
@ -771,6 +775,8 @@ namespace chaiscript
|
||||
std::vector<AST_Node_Impl_Ptr<T>>(std::make_move_iterator(t_children.begin()),
|
||||
std::make_move_iterator(std::prev(t_children.end(), has_guard(t_children, 1)?2:1)))
|
||||
),
|
||||
// This apparent use after move is safe because we are only moving out the specific elements we need
|
||||
// on each operation.
|
||||
m_body_node(get_body_node(std::move(t_children))),
|
||||
m_guard_node(get_guard_node(std::move(t_children), t_children.size()-this->children.size()==2))
|
||||
|
||||
@ -933,10 +939,16 @@ namespace chaiscript
|
||||
|
||||
const auto do_loop = [&loop_var_name, &t_ss, this](const auto &ranged_thing){
|
||||
try {
|
||||
chaiscript::eval::detail::Scope_Push_Pop spp(t_ss);
|
||||
Boxed_Value &obj = t_ss.add_get_object(loop_var_name, void_var());
|
||||
for (auto loop_var : ranged_thing) {
|
||||
obj = Boxed_Value(std::move(loop_var));
|
||||
for (auto &&loop_var : ranged_thing) {
|
||||
// This scope push and pop might not be the best thing for perf
|
||||
// but we know it's 100% correct
|
||||
chaiscript::eval::detail::Scope_Push_Pop spp(t_ss);
|
||||
/// to-do make this if-constexpr with C++17 branch
|
||||
if (!std::is_same<std::decay_t<decltype(loop_var)>, Boxed_Value>::value) {
|
||||
t_ss.add_get_object(loop_var_name, Boxed_Value(std::ref(loop_var)));
|
||||
} else {
|
||||
t_ss.add_get_object(loop_var_name, Boxed_Value(loop_var));
|
||||
}
|
||||
try {
|
||||
this->children[2]->eval(t_ss);
|
||||
} catch (detail::Continue_Loop &) {
|
||||
@ -960,10 +972,9 @@ namespace chaiscript
|
||||
|
||||
try {
|
||||
const auto range_obj = call_function(range_funcs, range_expression_result);
|
||||
chaiscript::eval::detail::Scope_Push_Pop spp(t_ss);
|
||||
Boxed_Value &obj = t_ss.add_get_object(loop_var_name, void_var());
|
||||
while (!boxed_cast<bool>(call_function(empty_funcs, range_obj))) {
|
||||
obj = call_function(front_funcs, range_obj);
|
||||
chaiscript::eval::detail::Scope_Push_Pop spp(t_ss);
|
||||
t_ss.add_get_object(loop_var_name, call_function(front_funcs, range_obj));
|
||||
try {
|
||||
this->children[2]->eval(t_ss);
|
||||
} catch (detail::Continue_Loop &) {
|
||||
@ -1039,7 +1050,7 @@ namespace chaiscript
|
||||
if (this->children[currentCase]->identifier == AST_Node_Type::Case) {
|
||||
//This is a little odd, but because want to see both the switch and the case simultaneously, I do a downcast here.
|
||||
try {
|
||||
std::array p{match_value, this->children[currentCase]->children[0]->eval(t_ss)};
|
||||
std::array<Boxed_Value, 2> p{match_value, this->children[currentCase]->children[0]->eval(t_ss)};
|
||||
if (hasMatched || boxed_cast<bool>(t_ss->call_function("==", m_loc, Function_Params{p}, t_ss.conversions()))) {
|
||||
this->children[currentCase]->eval(t_ss);
|
||||
hasMatched = true;
|
||||
@ -1154,10 +1165,10 @@ namespace chaiscript
|
||||
|
||||
Boxed_Value eval_internal(const chaiscript::detail::Dispatch_State &t_ss) const override{
|
||||
if (!this->children.empty()) {
|
||||
throw detail::Return_Value(this->children[0]->eval(t_ss));
|
||||
throw detail::Return_Value{this->children[0]->eval(t_ss)};
|
||||
}
|
||||
else {
|
||||
throw detail::Return_Value(void_var());
|
||||
throw detail::Return_Value{void_var()};
|
||||
}
|
||||
}
|
||||
};
|
||||
@ -1214,6 +1225,10 @@ namespace chaiscript
|
||||
// short circuit arithmetic operations
|
||||
if (m_oper != Operators::Opers::invalid && m_oper != Operators::Opers::bitwise_and && bv.get_type_info().is_arithmetic())
|
||||
{
|
||||
if ((m_oper == Operators::Opers::pre_increment || m_oper == Operators::Opers::pre_decrement) && bv.is_const())
|
||||
{
|
||||
throw exception::eval_error("Error with prefix operator evaluation: cannot modify constant value.");
|
||||
}
|
||||
return Boxed_Number::do_oper(m_oper, bv);
|
||||
} else {
|
||||
chaiscript::eval::detail::Function_Push_Pop fpp(t_ss);
|
||||
@ -1283,7 +1298,7 @@ namespace chaiscript
|
||||
|
||||
Boxed_Value eval_internal(const chaiscript::detail::Dispatch_State &t_ss) const override{
|
||||
try {
|
||||
std::array params{
|
||||
std::array<Boxed_Value, 2> params{
|
||||
this->children[0]->children[0]->children[0]->eval(t_ss),
|
||||
this->children[0]->children[0]->children[1]->eval(t_ss)
|
||||
};
|
||||
@ -1408,7 +1423,7 @@ namespace chaiscript
|
||||
|
||||
Method_AST_Node(std::string t_ast_node_text, Parse_Location t_loc, std::vector<AST_Node_Impl_Ptr<T>> t_children) :
|
||||
AST_Node_Impl<T>(std::move(t_ast_node_text), AST_Node_Type::Method, std::move(t_loc),
|
||||
std::vector<AST_Node_Impl_Ptr<T>>(std::make_move_iterator(t_children.begin()),
|
||||
std::vector<AST_Node_Impl_Ptr<T>>(std::make_move_iterator(t_children.begin()),
|
||||
std::make_move_iterator(std::prev(t_children.end(), Def_AST_Node<T>::has_guard(t_children, 1)?2:1)))
|
||||
),
|
||||
m_body_node(Def_AST_Node<T>::get_body_node(std::move(t_children))),
|
||||
|
||||
@ -1,7 +1,7 @@
|
||||
// This file is distributed under the BSD License.
|
||||
// See "license.txt" for details.
|
||||
// Copyright 2009-2012, Jonathan Turner (jonathan@emptycrate.com)
|
||||
// Copyright 2009-2017, Jason Turner (jason@emptycrate.com)
|
||||
// Copyright 2009-2018, Jason Turner (jason@emptycrate.com)
|
||||
// http://www.chaiscript.com
|
||||
|
||||
#ifndef CHAISCRIPT_OPTIMIZER_HPP_
|
||||
@ -356,7 +356,7 @@ namespace chaiscript {
|
||||
|
||||
const auto make_constant = [&node, &fun_name](auto val){
|
||||
const auto match = fun_name + "(" + node->children[1]->children[0]->text + ")";
|
||||
return chaiscript::make_unique<eval::AST_Node_Impl<T>, eval::Constant_AST_Node<T>>(std::move(match), node->location, Boxed_Value(val));
|
||||
return chaiscript::make_unique<eval::AST_Node_Impl<T>, eval::Constant_AST_Node<T>>(std::move(match), node->location, const_var(val));
|
||||
};
|
||||
|
||||
if (fun_name == "double") {
|
||||
|
||||
@ -1,7 +1,7 @@
|
||||
// This file is distributed under the BSD License.
|
||||
// See "license.txt" for details.
|
||||
// Copyright 2009-2012, Jonathan Turner (jonathan@emptycrate.com)
|
||||
// Copyright 2009-2017, Jason Turner (jason@emptycrate.com)
|
||||
// Copyright 2009-2018, Jason Turner (jason@emptycrate.com)
|
||||
// http://www.chaiscript.com
|
||||
|
||||
// This is an open source non-commercial project. Dear PVS-Studio, please check it.
|
||||
@ -118,12 +118,34 @@ namespace chaiscript
|
||||
}
|
||||
|
||||
|
||||
template<typename Tracer, typename Optimizer>
|
||||
template<typename Tracer, typename Optimizer, std::size_t Parse_Depth=512>
|
||||
class ChaiScript_Parser final : public ChaiScript_Parser_Base {
|
||||
void *get_tracer_ptr() noexcept override {
|
||||
return &m_tracer;
|
||||
}
|
||||
|
||||
std::size_t m_current_parse_depth = 0;
|
||||
|
||||
struct Depth_Counter
|
||||
{
|
||||
static const auto max_depth = Parse_Depth;
|
||||
Depth_Counter(ChaiScript_Parser *t_parser) : parser(t_parser)
|
||||
{
|
||||
++parser->m_current_parse_depth;
|
||||
if (parser->m_current_parse_depth > max_depth) {
|
||||
throw exception::eval_error("Maximum parse depth exceeded",
|
||||
File_Position(parser->m_position.line, parser->m_position.col), *(parser->m_filename));
|
||||
}
|
||||
}
|
||||
|
||||
~Depth_Counter() noexcept
|
||||
{
|
||||
--parser->m_current_parse_depth;
|
||||
}
|
||||
|
||||
ChaiScript_Parser *parser;
|
||||
};
|
||||
|
||||
template<typename Array2D, typename First, typename Second>
|
||||
constexpr static void set_alphabet(Array2D &array, const First first, const Second second) noexcept
|
||||
{
|
||||
@ -552,10 +574,14 @@ namespace chaiscript
|
||||
|
||||
/// Skips ChaiScript whitespace, which means space and tab, but not cr/lf
|
||||
/// jespada: Modified SkipWS to skip optionally CR ('\n') and/or LF+CR ("\r\n")
|
||||
/// AlekMosingiewicz: Added exception when illegal character detected
|
||||
bool SkipWS(bool skip_cr=false) {
|
||||
bool retval = false;
|
||||
|
||||
while (m_position.has_more()) {
|
||||
if(static_cast<unsigned char>(*m_position) > 0x7e) {
|
||||
throw exception::eval_error("Illegal character", File_Position(m_position.line, m_position.col), *m_filename);
|
||||
}
|
||||
auto end_line = (*m_position != 0) && ((*m_position == '\n') || (*m_position == '\r' && *(m_position+1) == '\n'));
|
||||
|
||||
if ( char_in_alphabet(*m_position,detail::white_alphabet) || (skip_cr && end_line)) {
|
||||
@ -766,6 +792,7 @@ namespace chaiscript
|
||||
|
||||
#ifdef CHAISCRIPT_CLANG
|
||||
#pragma GCC diagnostic ignored "-Wtautological-compare"
|
||||
#pragma GCC diagnostic ignored "-Wsign-conversion"
|
||||
#endif
|
||||
|
||||
#endif
|
||||
@ -781,7 +808,10 @@ namespace chaiscript
|
||||
return const_var(static_cast<unsigned int>(u));
|
||||
} else if (!unsigned_ && !longlong_ && u >= std::numeric_limits<long>::min() && u <= std::numeric_limits<long>::max()) {
|
||||
return const_var(static_cast<long>(u));
|
||||
} else if ((unsigned_ || base != 10) && !longlong_ && u >= std::numeric_limits<unsigned long>::min() && u <= std::numeric_limits<unsigned long>::max()) {
|
||||
} else if ((unsigned_ || base != 10) && !longlong_
|
||||
|
||||
&& u >= std::numeric_limits<unsigned long>::min()
|
||||
&& u <= std::numeric_limits<unsigned long>::max()) {
|
||||
return const_var(static_cast<unsigned long>(u));
|
||||
} else if (!unsigned_ && u >= std::numeric_limits<long long>::min() && u <= std::numeric_limits<long long>::max()) {
|
||||
return const_var(static_cast<long long>(u));
|
||||
@ -948,7 +978,7 @@ namespace chaiscript
|
||||
} break;
|
||||
case utility::hash("__FUNC__"): {
|
||||
std::string fun_name = "NOT_IN_FUNCTION";
|
||||
for (size_t idx = m_match_stack.size() - 1; idx > 0; --idx)
|
||||
for (size_t idx = m_match_stack.empty() ? 0 : m_match_stack.size() - 1; idx > 0; --idx)
|
||||
{
|
||||
if (m_match_stack[idx-1]->identifier == AST_Node_Type::Id
|
||||
&& m_match_stack[idx-0]->identifier == AST_Node_Type::Arg_List) {
|
||||
@ -961,7 +991,7 @@ namespace chaiscript
|
||||
} break;
|
||||
case utility::hash("__CLASS__"): {
|
||||
std::string fun_name = "NOT_IN_CLASS";
|
||||
for (size_t idx = m_match_stack.size() - 1; idx > 1; --idx)
|
||||
for (size_t idx = m_match_stack.empty() ? 0 : m_match_stack.size() - 1; idx > 1; --idx)
|
||||
{
|
||||
if (m_match_stack[idx-2]->identifier == AST_Node_Type::Id
|
||||
&& m_match_stack[idx-1]->identifier == AST_Node_Type::Id
|
||||
@ -1071,7 +1101,7 @@ namespace chaiscript
|
||||
bool saw_interpolation_marker = false;
|
||||
bool is_octal = false;
|
||||
bool is_hex = false;
|
||||
bool is_unicode = false;
|
||||
std::size_t unicode_size = 0;
|
||||
const bool interpolation_allowed;
|
||||
|
||||
string_type octal_matches;
|
||||
@ -1095,12 +1125,12 @@ namespace chaiscript
|
||||
process_hex();
|
||||
}
|
||||
|
||||
if (is_unicode) {
|
||||
if (unicode_size > 0) {
|
||||
process_unicode();
|
||||
}
|
||||
} catch (const std::invalid_argument &) {
|
||||
// escape sequence was invalid somehow, we'll pick this
|
||||
// up in the next part of parsing
|
||||
} catch (const exception::eval_error &) {
|
||||
// Something happened with parsing, we'll catch it later?
|
||||
}
|
||||
}
|
||||
|
||||
@ -1130,13 +1160,43 @@ namespace chaiscript
|
||||
|
||||
void process_unicode()
|
||||
{
|
||||
if (!hex_matches.empty()) {
|
||||
auto val = stoll(hex_matches, nullptr, 16);
|
||||
hex_matches.clear();
|
||||
match += detail::Char_Parser_Helper<string_type>::str_from_ll(val);
|
||||
}
|
||||
const auto ch = static_cast<uint32_t>(std::stoi(hex_matches, nullptr, 16));
|
||||
const auto match_size = hex_matches.size();
|
||||
hex_matches.clear();
|
||||
is_escaped = false;
|
||||
is_unicode = false;
|
||||
const auto u_size = unicode_size;
|
||||
unicode_size = 0;
|
||||
|
||||
char buf[4];
|
||||
if (u_size != match_size) {
|
||||
throw exception::eval_error("Incomplete unicode escape sequence");
|
||||
}
|
||||
if (u_size == 4 && ch >= 0xD800 && ch <= 0xDFFF) {
|
||||
throw exception::eval_error("Invalid 16 bit universal character");
|
||||
}
|
||||
|
||||
|
||||
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");
|
||||
}
|
||||
}
|
||||
|
||||
void parse(const char_type t_char, const int line, const int col, const std::string &filename) {
|
||||
@ -1172,16 +1232,16 @@ namespace chaiscript
|
||||
} else {
|
||||
process_hex();
|
||||
}
|
||||
} else if (is_unicode) {
|
||||
} else if (unicode_size > 0) {
|
||||
if (is_hex_char) {
|
||||
hex_matches.push_back(t_char);
|
||||
|
||||
if(hex_matches.size() == 4) {
|
||||
// Format is specified to be 'slash'uABCD
|
||||
// on collecting from A to D do parsing
|
||||
process_unicode();
|
||||
}
|
||||
return;
|
||||
if(hex_matches.size() == unicode_size) {
|
||||
// Format is specified to be 'slash'uABCD
|
||||
// on collecting from A to D do parsing
|
||||
process_unicode();
|
||||
}
|
||||
return;
|
||||
} else {
|
||||
// Not a unicode anymore, try parsing any way
|
||||
// May be someone used 'slash'uAA only
|
||||
@ -1204,7 +1264,9 @@ namespace chaiscript
|
||||
} else if (t_char == 'x') {
|
||||
is_hex = true;
|
||||
} else if (t_char == 'u') {
|
||||
is_unicode = true;
|
||||
unicode_size = 4;
|
||||
} else if (t_char == 'U') {
|
||||
unicode_size = 8;
|
||||
} else {
|
||||
switch (t_char) {
|
||||
case ('\'') : match.push_back('\''); break;
|
||||
@ -1235,6 +1297,7 @@ namespace chaiscript
|
||||
|
||||
/// Reads (and potentially captures) a quoted string from input. Translates escaped sequences.
|
||||
bool Quoted_String() {
|
||||
Depth_Counter dc{this};
|
||||
SkipWS();
|
||||
|
||||
const auto start = m_position;
|
||||
@ -1350,6 +1413,7 @@ namespace chaiscript
|
||||
|
||||
/// Reads (and potentially captures) a char group from input. Translates escaped sequences.
|
||||
bool Single_Quoted_String() {
|
||||
Depth_Counter dc{this};
|
||||
SkipWS();
|
||||
|
||||
const auto start = m_position;
|
||||
@ -1389,6 +1453,7 @@ namespace chaiscript
|
||||
|
||||
/// Reads (and potentially captures) a char from input if it matches the parameter
|
||||
bool Char(const char t_c) {
|
||||
Depth_Counter dc{this};
|
||||
SkipWS();
|
||||
return Char_(t_c);
|
||||
}
|
||||
@ -1413,6 +1478,7 @@ namespace chaiscript
|
||||
|
||||
/// Reads (and potentially captures) a string from input if it matches the parameter
|
||||
bool Keyword(const utility::Static_String &t_s) {
|
||||
Depth_Counter dc{this};
|
||||
SkipWS();
|
||||
const auto start = m_position;
|
||||
bool retval = Keyword_(t_s);
|
||||
@ -1431,6 +1497,7 @@ namespace chaiscript
|
||||
|
||||
/// 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) {
|
||||
Depth_Counter dc{this};
|
||||
SkipWS();
|
||||
const auto start = m_position;
|
||||
bool retval = Symbol_(t_s);
|
||||
@ -1465,6 +1532,7 @@ namespace chaiscript
|
||||
|
||||
/// Reads until the end of the current statement
|
||||
bool Eos() {
|
||||
Depth_Counter dc{this};
|
||||
SkipWS();
|
||||
|
||||
return Eol_(true);
|
||||
@ -1472,6 +1540,7 @@ namespace chaiscript
|
||||
|
||||
/// Reads (and potentially captures) an end-of-line group from input
|
||||
bool Eol() {
|
||||
Depth_Counter dc{this};
|
||||
SkipWS();
|
||||
|
||||
return Eol_();
|
||||
@ -1479,6 +1548,7 @@ namespace chaiscript
|
||||
|
||||
/// Reads a comma-separated list of values from input. Id's only, no types allowed
|
||||
bool Id_Arg_List() {
|
||||
Depth_Counter dc{this};
|
||||
SkipWS(true);
|
||||
bool retval = false;
|
||||
|
||||
@ -1504,6 +1574,7 @@ namespace chaiscript
|
||||
|
||||
/// Reads a comma-separated list of values from input, for function declarations
|
||||
bool Decl_Arg_List() {
|
||||
Depth_Counter dc{this};
|
||||
SkipWS(true);
|
||||
bool retval = false;
|
||||
|
||||
@ -1530,6 +1601,7 @@ namespace chaiscript
|
||||
|
||||
/// Reads a comma-separated list of values from input
|
||||
bool Arg_List() {
|
||||
Depth_Counter dc{this};
|
||||
SkipWS(true);
|
||||
bool retval = false;
|
||||
|
||||
@ -1555,6 +1627,7 @@ namespace chaiscript
|
||||
|
||||
/// Reads possible special container values, including ranges and map_pairs
|
||||
bool Container_Arg_List() {
|
||||
Depth_Counter dc{this};
|
||||
bool retval = false;
|
||||
SkipWS(true);
|
||||
|
||||
@ -1592,6 +1665,7 @@ namespace chaiscript
|
||||
|
||||
/// Reads a lambda (anonymous function) from input
|
||||
bool Lambda() {
|
||||
Depth_Counter dc{this};
|
||||
bool retval = false;
|
||||
|
||||
const auto prev_stack_top = m_match_stack.size();
|
||||
@ -1633,6 +1707,7 @@ namespace chaiscript
|
||||
|
||||
/// Reads a function definition from input
|
||||
bool Def(const bool t_class_context = false, const std::string &t_class_name = "") {
|
||||
Depth_Counter dc{this};
|
||||
bool retval = false;
|
||||
|
||||
const auto prev_stack_top = m_match_stack.size();
|
||||
@ -1692,6 +1767,7 @@ namespace chaiscript
|
||||
|
||||
/// Reads a function definition from input
|
||||
bool Try() {
|
||||
Depth_Counter dc{this};
|
||||
bool retval = false;
|
||||
|
||||
const auto prev_stack_top = m_match_stack.size();
|
||||
@ -1746,6 +1822,7 @@ namespace chaiscript
|
||||
|
||||
/// Reads an if/else if/else block from input
|
||||
bool If() {
|
||||
Depth_Counter dc{this};
|
||||
bool retval = false;
|
||||
|
||||
const auto prev_stack_top = m_match_stack.size();
|
||||
@ -1811,6 +1888,7 @@ namespace chaiscript
|
||||
|
||||
/// Reads a class block from input
|
||||
bool Class(const bool t_class_allowed) {
|
||||
Depth_Counter dc{this};
|
||||
bool retval = false;
|
||||
|
||||
size_t prev_stack_top = m_match_stack.size();
|
||||
@ -1843,6 +1921,7 @@ namespace chaiscript
|
||||
|
||||
/// Reads a while block from input
|
||||
bool While() {
|
||||
Depth_Counter dc{this};
|
||||
bool retval = false;
|
||||
|
||||
const auto prev_stack_top = m_match_stack.size();
|
||||
@ -1872,6 +1951,7 @@ namespace chaiscript
|
||||
|
||||
/// Reads the ranged `for` conditions from input
|
||||
bool Range_Expression() {
|
||||
Depth_Counter dc{this};
|
||||
// the first element will have already been captured by the For_Guards() call that preceeds it
|
||||
return Char(':') && Equation();
|
||||
}
|
||||
@ -1879,6 +1959,7 @@ namespace chaiscript
|
||||
|
||||
/// Reads the C-style `for` conditions from input
|
||||
bool For_Guards() {
|
||||
Depth_Counter dc{this};
|
||||
if (!(Equation() && Eol()))
|
||||
{
|
||||
if (!Eol())
|
||||
@ -1910,6 +1991,7 @@ namespace chaiscript
|
||||
|
||||
/// Reads a for block from input
|
||||
bool For() {
|
||||
Depth_Counter dc{this};
|
||||
bool retval = false;
|
||||
|
||||
const auto prev_stack_top = m_match_stack.size();
|
||||
@ -1953,6 +2035,7 @@ namespace chaiscript
|
||||
|
||||
/// Reads a case block from input
|
||||
bool Case() {
|
||||
Depth_Counter dc{this};
|
||||
bool retval = false;
|
||||
|
||||
const auto prev_stack_top = m_match_stack.size();
|
||||
@ -1993,6 +2076,7 @@ namespace chaiscript
|
||||
|
||||
/// Reads a switch statement from input
|
||||
bool Switch() {
|
||||
Depth_Counter dc{this};
|
||||
const auto prev_stack_top = m_match_stack.size();
|
||||
|
||||
if (Keyword("switch")) {
|
||||
@ -2036,6 +2120,7 @@ namespace chaiscript
|
||||
|
||||
/// Reads a curly-brace C-style class block from input
|
||||
bool Class_Block(const std::string &t_class_name) {
|
||||
Depth_Counter dc{this};
|
||||
bool retval = false;
|
||||
|
||||
const auto prev_stack_top = m_match_stack.size();
|
||||
@ -2060,6 +2145,7 @@ namespace chaiscript
|
||||
|
||||
/// Reads a curly-brace C-style block from input
|
||||
bool Block() {
|
||||
Depth_Counter dc{this};
|
||||
bool retval = false;
|
||||
|
||||
const auto prev_stack_top = m_match_stack.size();
|
||||
@ -2084,6 +2170,7 @@ namespace chaiscript
|
||||
|
||||
/// Reads a return statement from input
|
||||
bool Return() {
|
||||
Depth_Counter dc{this};
|
||||
const auto prev_stack_top = m_match_stack.size();
|
||||
|
||||
if (Keyword("return")) {
|
||||
@ -2097,6 +2184,7 @@ namespace chaiscript
|
||||
|
||||
/// Reads a break statement from input
|
||||
bool Break() {
|
||||
Depth_Counter dc{this};
|
||||
const auto prev_stack_top = m_match_stack.size();
|
||||
|
||||
if (Keyword("break")) {
|
||||
@ -2109,6 +2197,7 @@ namespace chaiscript
|
||||
|
||||
/// Reads a continue statement from input
|
||||
bool Continue() {
|
||||
Depth_Counter dc{this};
|
||||
const auto prev_stack_top = m_match_stack.size();
|
||||
|
||||
if (Keyword("continue")) {
|
||||
@ -2121,6 +2210,7 @@ namespace chaiscript
|
||||
|
||||
/// Reads a dot expression(member access), then proceeds to check if it's a function or array call
|
||||
bool Dot_Fun_Array() {
|
||||
Depth_Counter dc{this};
|
||||
bool retval = false;
|
||||
|
||||
const auto prev_stack_top = m_match_stack.size();
|
||||
@ -2191,6 +2281,7 @@ namespace chaiscript
|
||||
|
||||
/// Reads a variable declaration from input
|
||||
bool Var_Decl(const bool t_class_context = false, const std::string &t_class_name = "") {
|
||||
Depth_Counter dc{this};
|
||||
bool retval = false;
|
||||
|
||||
const auto prev_stack_top = m_match_stack.size();
|
||||
@ -2246,6 +2337,7 @@ namespace chaiscript
|
||||
|
||||
/// Reads an expression surrounded by parentheses from input
|
||||
bool Paren_Expression() {
|
||||
Depth_Counter dc{this};
|
||||
if (Char('(')) {
|
||||
if (!Operator()) {
|
||||
throw exception::eval_error("Incomplete expression", File_Position(m_position.line, m_position.col), *m_filename);
|
||||
@ -2261,6 +2353,7 @@ namespace chaiscript
|
||||
|
||||
/// Reads, and identifies, a short-form container initialization from input
|
||||
bool Inline_Container() {
|
||||
Depth_Counter dc{this};
|
||||
const auto prev_stack_top = m_match_stack.size();
|
||||
|
||||
if (Char('[')) {
|
||||
@ -2292,6 +2385,7 @@ namespace chaiscript
|
||||
|
||||
/// Parses a variable specified with a & aka reference
|
||||
bool Reference() {
|
||||
Depth_Counter dc{this};
|
||||
const auto prev_stack_top = m_match_stack.size();
|
||||
|
||||
if (Symbol("&")) {
|
||||
@ -2308,6 +2402,7 @@ namespace chaiscript
|
||||
|
||||
/// Reads a unary prefixed expression from input
|
||||
bool Prefix() {
|
||||
Depth_Counter dc{this};
|
||||
const auto prev_stack_top = m_match_stack.size();
|
||||
using SS = utility::Static_String;
|
||||
const std::array<utility::Static_String, 6> prefix_opers{{
|
||||
@ -2338,6 +2433,7 @@ namespace chaiscript
|
||||
|
||||
/// Parses any of a group of 'value' style ast_node groups from input
|
||||
bool Value() {
|
||||
Depth_Counter dc{this};
|
||||
return Var_Decl() || Dot_Fun_Array() || Prefix();
|
||||
}
|
||||
|
||||
@ -2354,7 +2450,9 @@ namespace chaiscript
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
bool Operator(const size_t t_precedence = 0) {
|
||||
Depth_Counter dc{this};
|
||||
bool retval = false;
|
||||
const auto prev_stack_top = m_match_stack.size();
|
||||
|
||||
@ -2419,6 +2517,7 @@ namespace chaiscript
|
||||
|
||||
/// Reads a pair of values used to create a map initialization from input
|
||||
bool Map_Pair() {
|
||||
Depth_Counter dc{this};
|
||||
bool retval = false;
|
||||
|
||||
const auto prev_stack_top = m_match_stack.size();
|
||||
@ -2446,6 +2545,7 @@ namespace chaiscript
|
||||
|
||||
/// Reads a pair of values used to create a range initialization from input
|
||||
bool Value_Range() {
|
||||
Depth_Counter dc{this};
|
||||
bool retval = false;
|
||||
|
||||
const auto prev_stack_top = m_match_stack.size();
|
||||
@ -2473,6 +2573,7 @@ namespace chaiscript
|
||||
|
||||
/// Parses a string of binary equation operators
|
||||
bool Equation() {
|
||||
Depth_Counter dc{this};
|
||||
const auto prev_stack_top = m_match_stack.size();
|
||||
|
||||
using SS = utility::Static_String;
|
||||
@ -2498,6 +2599,7 @@ namespace chaiscript
|
||||
|
||||
/// Parses statements allowed inside of a class block
|
||||
bool Class_Statements(const std::string &t_class_name) {
|
||||
Depth_Counter dc{this};
|
||||
bool retval = false;
|
||||
|
||||
bool has_more = true;
|
||||
@ -2526,6 +2628,7 @@ namespace chaiscript
|
||||
|
||||
/// Top level parser, starts parsing of all known parses
|
||||
bool Statements(const bool t_class_allowed = false) {
|
||||
Depth_Counter dc{this};
|
||||
bool retval = false;
|
||||
|
||||
bool has_more = true;
|
||||
|
||||
@ -1,7 +1,7 @@
|
||||
// This file is distributed under the BSD License.
|
||||
// See "license.txt" for details.
|
||||
// Copyright 2009-2012, Jonathan Turner (jonathan@emptycrate.com)
|
||||
// Copyright 2009-2017, Jason Turner (jason@emptycrate.com)
|
||||
// Copyright 2009-2018, Jason Turner (jason@emptycrate.com)
|
||||
// http://www.chaiscript.com
|
||||
|
||||
#ifndef CHAISCRIPT_POSIX_HPP_
|
||||
|
||||
@ -1,7 +1,7 @@
|
||||
// This file is distributed under the BSD License.
|
||||
// See "license.txt" for details.
|
||||
// Copyright 2009-2012, Jonathan Turner (jonathan@emptycrate.com)
|
||||
// and 2009-2017, Jason Turner (jason@emptycrate.com)
|
||||
// and 2009-2018, Jason Turner (jason@emptycrate.com)
|
||||
// http://www.chaiscript.com
|
||||
|
||||
#ifndef CHAISCRIPT_PRELUDE_HPP_
|
||||
|
||||
@ -1,7 +1,7 @@
|
||||
// This file is distributed under the BSD License.
|
||||
// See "license.txt" for details.
|
||||
// Copyright 2009-2012, Jonathan Turner (jonathan@emptycrate.com)
|
||||
// Copyright 2009-2017, Jason Turner (jason@emptycrate.com)
|
||||
// Copyright 2009-2018, Jason Turner (jason@emptycrate.com)
|
||||
// http://www.chaiscript.com
|
||||
|
||||
#ifndef CHAISCRIPT_TRACER_HPP_
|
||||
|
||||
@ -1,7 +1,7 @@
|
||||
// This file is distributed under the BSD License.
|
||||
// See "license.txt" for details.
|
||||
// Copyright 2009-2012, Jonathan Turner (jonathan@emptycrate.com)
|
||||
// Copyright 2009-2017, Jason Turner (jason@emptycrate.com)
|
||||
// Copyright 2009-2018, Jason Turner (jason@emptycrate.com)
|
||||
// http://www.chaiscript.com
|
||||
|
||||
#ifndef CHAISCRIPT_UNKNOWN_HPP_
|
||||
|
||||
@ -1,7 +1,7 @@
|
||||
// This file is distributed under the BSD License.
|
||||
// See "license.txt" for details.
|
||||
// Copyright 2009-2012, Jonathan Turner (jonathan@emptycrate.com)
|
||||
// Copyright 2009-2017, Jason Turner (jason@emptycrate.com)
|
||||
// Copyright 2009-2018, Jason Turner (jason@emptycrate.com)
|
||||
// http://www.chaiscript.com
|
||||
|
||||
#ifndef CHAISCRIPT_WINDOWS_HPP_
|
||||
|
||||
50
include/chaiscript/utility/fnv1a.hpp
Normal file
50
include/chaiscript/utility/fnv1a.hpp
Normal file
@ -0,0 +1,50 @@
|
||||
// This file is distributed under the BSD License.
|
||||
// See "license.txt" for details.
|
||||
// Copyright 2009-2012, Jonathan Turner (jonathan@emptycrate.com)
|
||||
// Copyright 2009-2018, Jason Turner (jason@emptycrate.com)
|
||||
// http://www.chaiscript.com
|
||||
|
||||
#ifndef CHAISCRIPT_UTILITY_FNV1A_HPP_
|
||||
#define CHAISCRIPT_UTILITY_FNV1A_HPP_
|
||||
|
||||
|
||||
#include <cstdint>
|
||||
#include "../chaiscript_defines.hpp"
|
||||
|
||||
|
||||
namespace chaiscript
|
||||
{
|
||||
|
||||
|
||||
namespace utility
|
||||
{
|
||||
|
||||
|
||||
static constexpr std::uint32_t fnv1a_32(const char *s, std::uint32_t h = 0x811c9dc5) {
|
||||
#ifdef __GNUC__
|
||||
#pragma GCC diagnostic push
|
||||
#pragma GCC diagnostic ignored "-Wsign-conversion"
|
||||
#endif
|
||||
|
||||
#ifdef CHAISCRIPT_MSVC
|
||||
#pragma warning(push)
|
||||
#pragma warning(disable : 4307)
|
||||
#endif
|
||||
return (*s == 0) ? h : fnv1a_32(s+1, ((h ^ (*s)) * 0x01000193));
|
||||
#ifdef CHAISCRIPT_MSVC
|
||||
#pragma warning(pop)
|
||||
#endif
|
||||
|
||||
#ifdef __GNUC__
|
||||
#pragma GCC diagnostic pop
|
||||
#endif
|
||||
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
#endif
|
||||
@ -50,7 +50,7 @@ class JSON
|
||||
private:
|
||||
|
||||
|
||||
using Data = std::variant<std::nullptr_t, chaiscript::utility::QuickFlatMap<std::string, JSON>, std::vector<JSON>, std::string, double, int64_t, bool>;
|
||||
using Data = std::variant<std::nullptr_t, chaiscript::utility::QuickFlatMap<std::string, JSON>, std::vector<JSON>, std::string, double, std::int64_t, bool>;
|
||||
|
||||
struct Internal
|
||||
{
|
||||
@ -66,7 +66,7 @@ class JSON
|
||||
case Class::Array: return std::vector<JSON>{};
|
||||
case Class::String: return std::string{};
|
||||
case Class::Floating: return double{};
|
||||
case Class::Integral: return int64_t{};
|
||||
case Class::Integral: return std::int64_t{};
|
||||
case Class::Boolean: return bool{};
|
||||
}
|
||||
throw std::runtime_error("unknown type");
|
||||
@ -191,7 +191,7 @@ class JSON
|
||||
explicit JSON( T b, typename enable_if<is_same<T,bool>::value>::type* = nullptr ) noexcept : internal( static_cast<bool>(b) ) {}
|
||||
|
||||
template <typename T>
|
||||
explicit JSON( T i, typename enable_if<is_integral<T>::value && !is_same<T,bool>::value>::type* = nullptr ) noexcept : internal( static_cast<int64_t>(i) ) {}
|
||||
explicit JSON( T i, typename enable_if<is_integral<T>::value && !is_same<T,bool>::value>::type* = nullptr ) noexcept : internal( static_cast<std::int64_t>(i) ) {}
|
||||
|
||||
template <typename T>
|
||||
explicit JSON( T f, typename enable_if<is_floating_point<T>::value>::type* = nullptr ) noexcept : internal( static_cast<double>(f) ) {}
|
||||
@ -280,10 +280,10 @@ class JSON
|
||||
[](){ return double{}; }
|
||||
);
|
||||
}
|
||||
int64_t to_int() const noexcept {
|
||||
std::int64_t to_int() const noexcept {
|
||||
return internal.visit_or<Class::Integral>(
|
||||
[](const auto &o){ return o; },
|
||||
[](){ return int64_t{}; }
|
||||
[](){ return std::int64_t{}; }
|
||||
);
|
||||
}
|
||||
bool to_bool() const noexcept {
|
||||
@ -321,7 +321,7 @@ class JSON
|
||||
bool skip = true;
|
||||
for( auto &p : *internal.Map() ) {
|
||||
if( !skip ) { s += ",\n"; }
|
||||
s += ( pad + "\"" + p.first + "\" : " + p.second.dump( depth + 1, tab ) );
|
||||
s += ( pad + "\"" + json_escape(p.first) + "\" : " + p.second.dump( depth + 1, tab ) );
|
||||
skip = false;
|
||||
}
|
||||
s += ( "\n" + pad.erase( 0, 2 ) + "}" ) ;
|
||||
@ -497,7 +497,7 @@ struct JSONParser {
|
||||
char c = '\0';
|
||||
bool isDouble = false;
|
||||
bool isNegative = false;
|
||||
int64_t exp = 0;
|
||||
std::int64_t exp = 0;
|
||||
bool isExpNegative = false;
|
||||
if( offset < str.size() && str.at(offset) == '-' ) {
|
||||
isNegative = true;
|
||||
@ -535,7 +535,7 @@ struct JSONParser {
|
||||
break;
|
||||
}
|
||||
}
|
||||
exp = chaiscript::parse_num<int64_t>( exp_str ) * (isExpNegative?-1:1);
|
||||
exp = chaiscript::parse_num<std::int64_t>( exp_str ) * (isExpNegative?-1:1);
|
||||
}
|
||||
else if( offset < str.size() && (!isspace( c ) && c != ',' && c != ']' && c != '}' )) {
|
||||
throw std::runtime_error(std::string("JSON ERROR: Number: unexpected character '") + c + "'");
|
||||
@ -546,9 +546,9 @@ struct JSONParser {
|
||||
return JSON((isNegative?-1:1) * chaiscript::parse_num<double>( val ) * std::pow( 10, exp ));
|
||||
} else {
|
||||
if( !exp_str.empty() ) {
|
||||
return JSON((isNegative?-1:1) * static_cast<double>(chaiscript::parse_num<int64_t>( val )) * std::pow( 10, exp ));
|
||||
return JSON((isNegative?-1:1) * static_cast<double>(chaiscript::parse_num<std::int64_t>( val )) * std::pow( 10, exp ));
|
||||
} else {
|
||||
return JSON((isNegative?-1:1) * chaiscript::parse_num<int64_t>( val ));
|
||||
return JSON((isNegative?-1:1) * chaiscript::parse_num<std::int64_t>( val ));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -80,7 +80,7 @@ namespace chaiscript
|
||||
try {
|
||||
const std::map<std::string, Boxed_Value> m = chaiscript::boxed_cast<const std::map<std::string, Boxed_Value> &>(t_bv);
|
||||
|
||||
json::JSON obj;
|
||||
json::JSON obj(json::JSON::Class::Object);
|
||||
for (const auto &o : m)
|
||||
{
|
||||
obj[o.first] = to_json_object(o.second);
|
||||
@ -93,7 +93,7 @@ namespace chaiscript
|
||||
try {
|
||||
const std::vector<Boxed_Value> v = chaiscript::boxed_cast<const std::vector<Boxed_Value> &>(t_bv);
|
||||
|
||||
json::JSON obj;
|
||||
json::JSON obj(json::JSON::Class::Array);
|
||||
for (size_t i = 0; i < v.size(); ++i)
|
||||
{
|
||||
obj[i] = to_json_object(v[i]);
|
||||
@ -110,7 +110,7 @@ namespace chaiscript
|
||||
{
|
||||
return json::JSON(bn.get_as<double>());
|
||||
} else {
|
||||
return json::JSON(bn.get_as<long>());
|
||||
return json::JSON(bn.get_as<std::int64_t>());
|
||||
}
|
||||
} catch (const chaiscript::detail::exception::bad_any_cast &) {
|
||||
// not a number
|
||||
@ -132,7 +132,7 @@ namespace chaiscript
|
||||
try {
|
||||
const chaiscript::dispatch::Dynamic_Object &o = boxed_cast<const dispatch::Dynamic_Object &>(t_bv);
|
||||
|
||||
json::JSON obj;
|
||||
json::JSON obj(json::JSON::Class::Object);
|
||||
for (const auto &attr : o.get_attrs())
|
||||
{
|
||||
obj[attr.first] = to_json_object(attr.second);
|
||||
@ -142,6 +142,8 @@ namespace chaiscript
|
||||
// not a dynamic object
|
||||
}
|
||||
|
||||
if (t_bv.is_null()) return json::JSON(); // a null value
|
||||
|
||||
throw std::runtime_error("Unknown object type to convert to JSON");
|
||||
}
|
||||
|
||||
|
||||
@ -1,7 +1,7 @@
|
||||
// This file is distributed under the BSD License.
|
||||
// See "license.txt" for details.
|
||||
// Copyright 2009-2012, Jonathan Turner (jonathan@emptycrate.com)
|
||||
// Copyright 2009-2017, Jason Turner (jason@emptycrate.com)
|
||||
// Copyright 2009-2018, Jason Turner (jason@emptycrate.com)
|
||||
// http://www.chaiscript.com
|
||||
|
||||
#ifndef CHAISCRIPT_UTILITY_STATIC_STRING_HPP_
|
||||
|
||||
@ -1,7 +1,7 @@
|
||||
// This file is distributed under the BSD License.
|
||||
// See "license.txt" for details.
|
||||
// Copyright 2009-2012, Jonathan Turner (jonathan@emptycrate.com)
|
||||
// Copyright 2009-2017, Jason Turner (jason@emptycrate.com)
|
||||
// Copyright 2009-2018, Jason Turner (jason@emptycrate.com)
|
||||
// http://www.chaiscript.com
|
||||
|
||||
// This is an open source non-commercial project. Dear PVS-Studio, please check it.
|
||||
|
||||
@ -1,4 +1,6 @@
|
||||
Copyright 2009-2016 Jason Turner
|
||||
BSD-3-Clause License
|
||||
|
||||
Copyright 2009-2018 Jason Turner
|
||||
Copyright 2009-2012 Jonathan Turner.
|
||||
|
||||
All Rights Reserved.
|
||||
|
||||
@ -1,6 +1,19 @@
|
||||
Notes:
|
||||
=======
|
||||
Current Version: 6.0.0
|
||||
Current Version: 6.1.0
|
||||
|
||||
### Changes since 6.0.0
|
||||
|
||||
* Add namespacing support #290 @stephenberry
|
||||
* Add utf parsing support
|
||||
* cheatsheet.md updates
|
||||
* `add_class` utility support for scoped enums #306 @StanEpp
|
||||
* Parser optimizations #300 @niXman
|
||||
* Various JSON fixes #377 #400 #409 #371 @totalgee @dinghram @arcoRocks
|
||||
* Various cleanups, bugfixes and warning fixes and minor performance improvements
|
||||
* Support for C++17 compilers!
|
||||
* Support for UTF8 BOM #439 @AlekMosingiewicz @MarioLiebisch
|
||||
|
||||
|
||||
### Changes since 5.8.6
|
||||
|
||||
|
||||
@ -1,7 +1,7 @@
|
||||
// This file is distributed under the BSD License.
|
||||
// See "license.txt" for details.
|
||||
// Copyright 2009-2012, Jonathan Turner (jonathan@emptycrate.com)
|
||||
// Copyright 2009-2017, Jason Turner (jason@emptycrate.com)
|
||||
// Copyright 2009-2018, Jason Turner (jason@emptycrate.com)
|
||||
// http://www.chaiscript.com
|
||||
|
||||
// This is an open source non-commercial project. Dear PVS-Studio, please check it.
|
||||
|
||||
@ -1,7 +1,7 @@
|
||||
// This file is distributed under the BSD License.
|
||||
// See "license.txt" for details.
|
||||
// Copyright 2009-2012, Jonathan Turner (jonathan@emptycrate.com)
|
||||
// Copyright 2009-2017, Jason Turner (jason@emptycrate.com)
|
||||
// Copyright 2009-2018, Jason Turner (jason@emptycrate.com)
|
||||
// http://www.chaiscript.com
|
||||
|
||||
// This is an open source non-commercial project. Dear PVS-Studio, please check it.
|
||||
@ -20,6 +20,7 @@
|
||||
#include "../static_libs/chaiscript_parser.hpp"
|
||||
#include "../static_libs/chaiscript_stdlib.hpp"
|
||||
|
||||
#include "sha3.h"
|
||||
|
||||
#ifdef READLINE_AVAILABLE
|
||||
#include <readline/readline.h>
|
||||
@ -323,17 +324,28 @@ def assert_throws(desc, x)
|
||||
}
|
||||
})chaiscript");
|
||||
|
||||
SHA3 sha3;
|
||||
std::string sha = sha3(data, size);
|
||||
|
||||
std::string input(reinterpret_cast<const char *>(data), size);
|
||||
try {
|
||||
chai.eval(std::string(reinterpret_cast<const char *>(data), size));
|
||||
} catch (const chaiscript::exception::eval_error &ee) {
|
||||
std::cout << ee.pretty_print();
|
||||
std::cout << '\n';
|
||||
} catch (const chaiscript::Boxed_Value &e) {
|
||||
std::cout << "Unhandled exception thrown of type " << e.get_type_info().name() << '\n';
|
||||
std::ofstream ofs("VALID/" + sha);
|
||||
ofs << input;
|
||||
} catch (const chaiscript::exception::eval_error &) {
|
||||
std::ofstream ofs("EVAL_ERROR/" + sha);
|
||||
ofs << input;
|
||||
} catch (const chaiscript::Boxed_Value &) {
|
||||
std::ofstream ofs("BOXED_VALUE/" + sha);
|
||||
ofs << input;
|
||||
} catch (const chaiscript::exception::load_module_error &e) {
|
||||
std::cout << "Unhandled module load error\n" << e.what() << '\n';
|
||||
} catch (const std::exception &e) {
|
||||
std::cout << "unhandled unknown exception: " << e.what() << '\n';
|
||||
} catch (const std::exception &) {
|
||||
std::ofstream ofs("STD_EXCEPTION/" + sha);
|
||||
ofs << input;
|
||||
} catch (...) {
|
||||
std::ofstream ofs("UNKOWN_EXCEPTION/" + sha);
|
||||
ofs << input;
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
||||
10
src/main.cpp
10
src/main.cpp
@ -1,7 +1,7 @@
|
||||
// This file is distributed under the BSD License.
|
||||
// See "license.txt" for details.
|
||||
// Copyright 2009-2012, Jonathan Turner (jonathan@emptycrate.com)
|
||||
// Copyright 2009-2017, Jason Turner (jason@emptycrate.com)
|
||||
// Copyright 2009-2018, Jason Turner (jason@emptycrate.com)
|
||||
// http://www.chaiscript.com
|
||||
|
||||
// This is an open source non-commercial project. Dear PVS-Studio, please check it.
|
||||
@ -164,15 +164,15 @@ void help(int n) {
|
||||
}
|
||||
}
|
||||
|
||||
bool throws_exception(const std::function<void ()> &f)
|
||||
std::string throws_exception(const std::function<void ()> &f)
|
||||
{
|
||||
try {
|
||||
f();
|
||||
} catch (...) {
|
||||
return true;
|
||||
} catch (const std::exception &e) {
|
||||
return e.what();
|
||||
}
|
||||
|
||||
return false;
|
||||
return "";
|
||||
}
|
||||
|
||||
chaiscript::exception::eval_error get_eval_error(const std::function<void ()> &f)
|
||||
|
||||
@ -4,6 +4,11 @@
|
||||
// and Jason Turner (jason@emptycrate.com)
|
||||
// http://www.chaiscript.com
|
||||
|
||||
|
||||
// NOT TO BE USED AS A SOURCE OF BEST PRACTICES
|
||||
// FOR CHAISCRIPT
|
||||
|
||||
|
||||
#include <iostream>
|
||||
#include <ctime>
|
||||
|
||||
@ -156,7 +161,7 @@ int main(int /*argc*/, char * /*argv*/[]) {
|
||||
|
||||
//Ability to create our own container types when needed. std::vector and std::map are
|
||||
//mostly supported currently
|
||||
chai.add(bootstrap::standard_library::vector_type<std::vector<int> >("IntVector"));
|
||||
//chai.add(bootstrap::standard_library::vector_type<std::vector<int> >("IntVector"));
|
||||
|
||||
|
||||
// Test ability to register a function that excepts a shared_ptr version of a type
|
||||
289
src/sha3.cpp
Normal file
289
src/sha3.cpp
Normal file
@ -0,0 +1,289 @@
|
||||
// //////////////////////////////////////////////////////////
|
||||
// sha3.cpp
|
||||
// Copyright (c) 2014,2015 Stephan Brumme. All rights reserved.
|
||||
// see http://create.stephan-brumme.com/disclaimer.html
|
||||
//
|
||||
|
||||
#include "sha3.h"
|
||||
|
||||
// big endian architectures need #define __BYTE_ORDER __BIG_ENDIAN
|
||||
#ifndef _MSC_VER
|
||||
#include <endian.h>
|
||||
#endif
|
||||
|
||||
|
||||
/// same as reset()
|
||||
SHA3::SHA3(Bits bits)
|
||||
: m_blockSize(200 - 2 * (bits / 8)),
|
||||
m_bits(bits)
|
||||
{
|
||||
reset();
|
||||
}
|
||||
|
||||
|
||||
/// restart
|
||||
void SHA3::reset()
|
||||
{
|
||||
for (size_t i = 0; i < StateSize; i++)
|
||||
m_hash[i] = 0;
|
||||
|
||||
m_numBytes = 0;
|
||||
m_bufferSize = 0;
|
||||
}
|
||||
|
||||
|
||||
/// constants and local helper functions
|
||||
namespace
|
||||
{
|
||||
const unsigned int Rounds = 24;
|
||||
const uint64_t XorMasks[Rounds] =
|
||||
{
|
||||
0x0000000000000001ULL, 0x0000000000008082ULL, 0x800000000000808aULL,
|
||||
0x8000000080008000ULL, 0x000000000000808bULL, 0x0000000080000001ULL,
|
||||
0x8000000080008081ULL, 0x8000000000008009ULL, 0x000000000000008aULL,
|
||||
0x0000000000000088ULL, 0x0000000080008009ULL, 0x000000008000000aULL,
|
||||
0x000000008000808bULL, 0x800000000000008bULL, 0x8000000000008089ULL,
|
||||
0x8000000000008003ULL, 0x8000000000008002ULL, 0x8000000000000080ULL,
|
||||
0x000000000000800aULL, 0x800000008000000aULL, 0x8000000080008081ULL,
|
||||
0x8000000000008080ULL, 0x0000000080000001ULL, 0x8000000080008008ULL
|
||||
};
|
||||
|
||||
/// rotate left and wrap around to the right
|
||||
inline uint64_t rotateLeft(uint64_t x, uint8_t numBits)
|
||||
{
|
||||
return (x << numBits) | (x >> (64 - numBits));
|
||||
}
|
||||
|
||||
/// convert litte vs big endian
|
||||
inline uint64_t swap(uint64_t x)
|
||||
{
|
||||
#if defined(__GNUC__) || defined(__clang__)
|
||||
return __builtin_bswap64(x);
|
||||
#endif
|
||||
#ifdef _MSC_VER
|
||||
return _byteswap_uint64(x);
|
||||
#endif
|
||||
|
||||
return (x >> 56) |
|
||||
((x >> 40) & 0x000000000000FF00ULL) |
|
||||
((x >> 24) & 0x0000000000FF0000ULL) |
|
||||
((x >> 8) & 0x00000000FF000000ULL) |
|
||||
((x << 8) & 0x000000FF00000000ULL) |
|
||||
((x << 24) & 0x0000FF0000000000ULL) |
|
||||
((x << 40) & 0x00FF000000000000ULL) |
|
||||
(x << 56);
|
||||
}
|
||||
|
||||
|
||||
/// return x % 5 for 0 <= x <= 9
|
||||
unsigned int mod5(unsigned int x)
|
||||
{
|
||||
if (x < 5)
|
||||
return x;
|
||||
|
||||
return x - 5;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/// process a full block
|
||||
void SHA3::processBlock(const void* data)
|
||||
{
|
||||
#if defined(__BYTE_ORDER) && (__BYTE_ORDER != 0) && (__BYTE_ORDER == __BIG_ENDIAN)
|
||||
#define LITTLEENDIAN(x) swap(x)
|
||||
#else
|
||||
#define LITTLEENDIAN(x) (x)
|
||||
#endif
|
||||
|
||||
const uint64_t* data64 = (const uint64_t*) data;
|
||||
// mix data into state
|
||||
for (unsigned int i = 0; i < m_blockSize / 8; i++)
|
||||
m_hash[i] ^= LITTLEENDIAN(data64[i]);
|
||||
|
||||
// re-compute state
|
||||
for (unsigned int round = 0; round < Rounds; round++)
|
||||
{
|
||||
// Theta
|
||||
uint64_t coefficients[5];
|
||||
for (unsigned int i = 0; i < 5; i++)
|
||||
coefficients[i] = m_hash[i] ^ m_hash[i + 5] ^ m_hash[i + 10] ^ m_hash[i + 15] ^ m_hash[i + 20];
|
||||
|
||||
for (unsigned int i = 0; i < 5; i++)
|
||||
{
|
||||
uint64_t one = coefficients[mod5(i + 4)] ^ rotateLeft(coefficients[mod5(i + 1)], 1);
|
||||
m_hash[i ] ^= one;
|
||||
m_hash[i + 5] ^= one;
|
||||
m_hash[i + 10] ^= one;
|
||||
m_hash[i + 15] ^= one;
|
||||
m_hash[i + 20] ^= one;
|
||||
}
|
||||
|
||||
// temporary
|
||||
uint64_t one;
|
||||
|
||||
// Rho Pi
|
||||
uint64_t last = m_hash[1];
|
||||
one = m_hash[10]; m_hash[10] = rotateLeft(last, 1); last = one;
|
||||
one = m_hash[ 7]; m_hash[ 7] = rotateLeft(last, 3); last = one;
|
||||
one = m_hash[11]; m_hash[11] = rotateLeft(last, 6); last = one;
|
||||
one = m_hash[17]; m_hash[17] = rotateLeft(last, 10); last = one;
|
||||
one = m_hash[18]; m_hash[18] = rotateLeft(last, 15); last = one;
|
||||
one = m_hash[ 3]; m_hash[ 3] = rotateLeft(last, 21); last = one;
|
||||
one = m_hash[ 5]; m_hash[ 5] = rotateLeft(last, 28); last = one;
|
||||
one = m_hash[16]; m_hash[16] = rotateLeft(last, 36); last = one;
|
||||
one = m_hash[ 8]; m_hash[ 8] = rotateLeft(last, 45); last = one;
|
||||
one = m_hash[21]; m_hash[21] = rotateLeft(last, 55); last = one;
|
||||
one = m_hash[24]; m_hash[24] = rotateLeft(last, 2); last = one;
|
||||
one = m_hash[ 4]; m_hash[ 4] = rotateLeft(last, 14); last = one;
|
||||
one = m_hash[15]; m_hash[15] = rotateLeft(last, 27); last = one;
|
||||
one = m_hash[23]; m_hash[23] = rotateLeft(last, 41); last = one;
|
||||
one = m_hash[19]; m_hash[19] = rotateLeft(last, 56); last = one;
|
||||
one = m_hash[13]; m_hash[13] = rotateLeft(last, 8); last = one;
|
||||
one = m_hash[12]; m_hash[12] = rotateLeft(last, 25); last = one;
|
||||
one = m_hash[ 2]; m_hash[ 2] = rotateLeft(last, 43); last = one;
|
||||
one = m_hash[20]; m_hash[20] = rotateLeft(last, 62); last = one;
|
||||
one = m_hash[14]; m_hash[14] = rotateLeft(last, 18); last = one;
|
||||
one = m_hash[22]; m_hash[22] = rotateLeft(last, 39); last = one;
|
||||
one = m_hash[ 9]; m_hash[ 9] = rotateLeft(last, 61); last = one;
|
||||
one = m_hash[ 6]; m_hash[ 6] = rotateLeft(last, 20); last = one;
|
||||
m_hash[ 1] = rotateLeft(last, 44);
|
||||
|
||||
// Chi
|
||||
for (unsigned int j = 0; j < 25; j += 5)
|
||||
{
|
||||
// temporaries
|
||||
uint64_t one = m_hash[j];
|
||||
uint64_t two = m_hash[j + 1];
|
||||
|
||||
m_hash[j] ^= m_hash[j + 2] & ~two;
|
||||
m_hash[j + 1] ^= m_hash[j + 3] & ~m_hash[j + 2];
|
||||
m_hash[j + 2] ^= m_hash[j + 4] & ~m_hash[j + 3];
|
||||
m_hash[j + 3] ^= one & ~m_hash[j + 4];
|
||||
m_hash[j + 4] ^= two & ~one;
|
||||
}
|
||||
|
||||
// Iota
|
||||
m_hash[0] ^= XorMasks[round];
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/// add arbitrary number of bytes
|
||||
void SHA3::add(const void* data, size_t numBytes)
|
||||
{
|
||||
const uint8_t* current = (const uint8_t*) data;
|
||||
|
||||
// copy data to buffer
|
||||
if (m_bufferSize > 0)
|
||||
{
|
||||
while (numBytes > 0 && m_bufferSize < m_blockSize)
|
||||
{
|
||||
m_buffer[m_bufferSize++] = *current++;
|
||||
numBytes--;
|
||||
}
|
||||
}
|
||||
|
||||
// full buffer
|
||||
if (m_bufferSize == m_blockSize)
|
||||
{
|
||||
processBlock((void*)m_buffer);
|
||||
m_numBytes += m_blockSize;
|
||||
m_bufferSize = 0;
|
||||
}
|
||||
|
||||
// no more data ?
|
||||
if (numBytes == 0)
|
||||
return;
|
||||
|
||||
// process full blocks
|
||||
while (numBytes >= m_blockSize)
|
||||
{
|
||||
processBlock(current);
|
||||
current += m_blockSize;
|
||||
m_numBytes += m_blockSize;
|
||||
numBytes -= m_blockSize;
|
||||
}
|
||||
|
||||
// keep remaining bytes in buffer
|
||||
while (numBytes > 0)
|
||||
{
|
||||
m_buffer[m_bufferSize++] = *current++;
|
||||
numBytes--;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/// process everything left in the internal buffer
|
||||
void SHA3::processBuffer()
|
||||
{
|
||||
// add padding
|
||||
size_t offset = m_bufferSize;
|
||||
// add a "1" byte
|
||||
m_buffer[offset++] = 0x06;
|
||||
// fill with zeros
|
||||
while (offset < m_blockSize)
|
||||
m_buffer[offset++] = 0;
|
||||
|
||||
// and add a single set bit
|
||||
m_buffer[offset - 1] |= 0x80;
|
||||
|
||||
processBlock(m_buffer);
|
||||
}
|
||||
|
||||
|
||||
/// return latest hash as 16 hex characters
|
||||
std::string SHA3::getHash()
|
||||
{
|
||||
// process remaining bytes
|
||||
processBuffer();
|
||||
|
||||
// convert hash to string
|
||||
static const char dec2hex[16 + 1] = "0123456789abcdef";
|
||||
|
||||
// number of significant elements in hash (uint64_t)
|
||||
unsigned int hashLength = m_bits / 64;
|
||||
|
||||
std::string result;
|
||||
result.reserve(m_bits / 4);
|
||||
for (unsigned int i = 0; i < hashLength; i++)
|
||||
for (unsigned int j = 0; j < 8; j++) // 64 bits => 8 bytes
|
||||
{
|
||||
// convert a byte to hex
|
||||
unsigned char oneByte = (unsigned char) (m_hash[i] >> (8 * j));
|
||||
result += dec2hex[oneByte >> 4];
|
||||
result += dec2hex[oneByte & 15];
|
||||
}
|
||||
|
||||
// SHA3-224's last entry in m_hash provides only 32 bits instead of 64 bits
|
||||
unsigned int remainder = m_bits - hashLength * 64;
|
||||
unsigned int processed = 0;
|
||||
while (processed < remainder)
|
||||
{
|
||||
// convert a byte to hex
|
||||
unsigned char oneByte = (unsigned char) (m_hash[hashLength] >> processed);
|
||||
result += dec2hex[oneByte >> 4];
|
||||
result += dec2hex[oneByte & 15];
|
||||
|
||||
processed += 8;
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
/// compute SHA3 of a memory block
|
||||
std::string SHA3::operator()(const void* data, size_t numBytes)
|
||||
{
|
||||
reset();
|
||||
add(data, numBytes);
|
||||
return getHash();
|
||||
}
|
||||
|
||||
|
||||
/// compute SHA3 of a string, excluding final zero
|
||||
std::string SHA3::operator()(const std::string& text)
|
||||
{
|
||||
reset();
|
||||
add(text.c_str(), text.size());
|
||||
return getHash();
|
||||
}
|
||||
81
src/sha3.h
Normal file
81
src/sha3.h
Normal file
@ -0,0 +1,81 @@
|
||||
// //////////////////////////////////////////////////////////
|
||||
// sha3.h
|
||||
// Copyright (c) 2014,2015 Stephan Brumme. All rights reserved.
|
||||
// see http://create.stephan-brumme.com/disclaimer.html
|
||||
//
|
||||
|
||||
#pragma once
|
||||
|
||||
//#include "hash.h"
|
||||
#include <string>
|
||||
|
||||
// define fixed size integer types
|
||||
#ifdef _MSC_VER
|
||||
// Windows
|
||||
typedef unsigned __int8 uint8_t;
|
||||
typedef unsigned __int64 uint64_t;
|
||||
#else
|
||||
// GCC
|
||||
#include <stdint.h>
|
||||
#endif
|
||||
|
||||
|
||||
/// compute SHA3 hash
|
||||
/** Usage:
|
||||
SHA3 sha3;
|
||||
std::string myHash = sha3("Hello World"); // std::string
|
||||
std::string myHash2 = sha3("How are you", 11); // arbitrary data, 11 bytes
|
||||
|
||||
// or in a streaming fashion:
|
||||
|
||||
SHA3 sha3;
|
||||
while (more data available)
|
||||
sha3.add(pointer to fresh data, number of new bytes);
|
||||
std::string myHash3 = sha3.getHash();
|
||||
*/
|
||||
class SHA3 //: public Hash
|
||||
{
|
||||
public:
|
||||
/// algorithm variants
|
||||
enum Bits { Bits224 = 224, Bits256 = 256, Bits384 = 384, Bits512 = 512 };
|
||||
|
||||
/// same as reset()
|
||||
explicit SHA3(Bits bits = Bits256);
|
||||
|
||||
/// compute hash of a memory block
|
||||
std::string operator()(const void* data, size_t numBytes);
|
||||
/// compute hash of a string, excluding final zero
|
||||
std::string operator()(const std::string& text);
|
||||
|
||||
/// add arbitrary number of bytes
|
||||
void add(const void* data, size_t numBytes);
|
||||
|
||||
/// return latest hash as hex characters
|
||||
std::string getHash();
|
||||
|
||||
/// restart
|
||||
void reset();
|
||||
|
||||
private:
|
||||
/// process a full block
|
||||
void processBlock(const void* data);
|
||||
/// process everything left in the internal buffer
|
||||
void processBuffer();
|
||||
|
||||
/// 1600 bits, stored as 25x64 bit, BlockSize is no more than 1152 bits (Keccak224)
|
||||
enum { StateSize = 1600 / (8 * 8),
|
||||
MaxBlockSize = 200 - 2 * (224 / 8) };
|
||||
|
||||
/// hash
|
||||
uint64_t m_hash[StateSize];
|
||||
/// size of processed data in bytes
|
||||
uint64_t m_numBytes;
|
||||
/// block size (less or equal to MaxBlockSize)
|
||||
size_t m_blockSize;
|
||||
/// valid bytes in m_buffer
|
||||
size_t m_bufferSize;
|
||||
/// bytes not processed yet
|
||||
uint8_t m_buffer[MaxBlockSize];
|
||||
/// variant
|
||||
Bits m_bits;
|
||||
};
|
||||
@ -1,7 +1,7 @@
|
||||
// This file is distributed under the BSD License.
|
||||
// See "license.txt" for details.
|
||||
// Copyright 2009-2012, Jonathan Turner (jonathan@emptycrate.com)
|
||||
// Copyright 2009-2017, Jason Turner (jason@emptycrate.com)
|
||||
// Copyright 2009-2018, Jason Turner (jason@emptycrate.com)
|
||||
// http://www.chaiscript.com
|
||||
|
||||
// This is an open source non-commercial project. Dear PVS-Studio, please check it.
|
||||
|
||||
@ -1,2 +1,2 @@
|
||||
assert_throws("Mismatched types in equation, lhs is const.", fun() { 1 = 2 } );
|
||||
assert_throws("Mismatched types in equation, lhs is const.", fun() { 1 + 2 = 2 } );
|
||||
assert_throws("Error: \"Error, cannot assign to constant value.\"", fun() { 1 = 2 } );
|
||||
assert_throws("Error: \"Error, cannot assign to constant value.\"", fun() { 1 + 2 = 2 } );
|
||||
|
||||
@ -66,10 +66,10 @@ var group = group_guard.get_contained_functions();
|
||||
assert_equal(true, group[0].has_guard())
|
||||
assert_equal(false, group[1].has_guard())
|
||||
|
||||
assert_throws("Function does not have a guard", fun() { group[0].get_guard(); } );
|
||||
assert_throws("Function does not have a guard", fun() { without_guard.get_guard(); } );
|
||||
assert_throws("Function does not have a guard", fun[group]() { group[1].get_guard(); } );
|
||||
assert_throws("Function does not have a guard", fun[without_guard]() { without_guard.get_guard(); } );
|
||||
|
||||
var guard = with_guard.get_guard();
|
||||
|
||||
assert_equal(false, guard.has_guard());
|
||||
assert_throws("Function does not have a guard", fun() { guard.get_guard(); } );
|
||||
assert_throws("Function does not have a guard", fun[guard]() { guard.get_guard(); } );
|
||||
|
||||
@ -1 +1 @@
|
||||
assert_throws("Illegal const function assignment", fun() { clone = `-` } );
|
||||
assert_throws("Error: \"Error, cannot assign to constant value.\"", fun() { clone = `-` } );
|
||||
|
||||
@ -1 +1,2 @@
|
||||
assert_throws("Invalid function reassignment", fun() { var x = 5; x = `-`; } );
|
||||
assert_throws("Error: \"Unable to find appropriate'=' operator.\" With parameters: (int, const Function)", fun() { auto x = 5; x = `-`; } );
|
||||
|
||||
|
||||
@ -1,2 +1,8 @@
|
||||
|
||||
assert_throws("Parse failure", fun() { eval("[\"hello\":5,\"j\",\"k\"]") } );
|
||||
try {
|
||||
eval("[\"hello\":5,\"j\",\"k\"]");
|
||||
assert_true(false);
|
||||
} catch (eval_error ee) {
|
||||
}
|
||||
|
||||
|
||||
|
||||
@ -13,4 +13,4 @@ assert_equal(0, i -= i)
|
||||
assert_equal(3, j *= 1.5)
|
||||
assert_equal(1.5, j /= 2)
|
||||
assert_equal(2.5, j += 1)
|
||||
assert_throws("No modulus for float", fun() { k % 2 } );
|
||||
assert_throws("Error: \"Error with numeric operator calling: %\"", fun[k]() { k % 2 } );
|
||||
|
||||
@ -1,2 +1,2 @@
|
||||
assert_throws("Mismatched types in equation, lhs is const.", fun() { 1 = 2 } );
|
||||
assert_throws("Mismatched types in equation, lhs is const.", fun() { 1 + 2 = 2 } );
|
||||
assert_throws("Error: \"Error, cannot assign to constant value.\"", fun() { 1 = 2 } );
|
||||
assert_throws("Error: \"Error, cannot assign to constant value.\"", fun() { 1 + 2 = 2 } );
|
||||
|
||||
19562
unittests/catch.hpp
19562
unittests/catch.hpp
File diff suppressed because it is too large
Load Diff
@ -4,7 +4,7 @@
|
||||
|
||||
#ifdef _MSC_VER
|
||||
#pragma warning(push)
|
||||
#pragma warning(disable : 4062 4242 4640 4702 6330 28251)
|
||||
#pragma warning(disable : 4062 4242 4566 4640 4702 6330 28251)
|
||||
#endif
|
||||
|
||||
|
||||
@ -352,7 +352,29 @@ TEST_CASE("Functor cast")
|
||||
CHECK(d == 3 * 6);
|
||||
}
|
||||
|
||||
TEST_CASE("Non-ASCII characters in the middle of string")
|
||||
{
|
||||
chaiscript::ChaiScript_Basic chai(create_chaiscript_stdlib(),create_chaiscript_parser());
|
||||
CHECK_THROWS_AS(chai.eval<std::string>("prin\xeft \"Hello World\""), chaiscript::exception::eval_error);
|
||||
}
|
||||
|
||||
TEST_CASE("Non-ASCII characters in the beginning of string")
|
||||
{
|
||||
chaiscript::ChaiScript_Basic chai(create_chaiscript_stdlib(),create_chaiscript_parser());
|
||||
CHECK_THROWS_AS(chai.eval<std::string>("\xefprint \"Hello World\""), chaiscript::exception::eval_error);
|
||||
}
|
||||
|
||||
TEST_CASE("Non-ASCII characters in the end of string")
|
||||
{
|
||||
chaiscript::ChaiScript_Basic chai(create_chaiscript_stdlib(),create_chaiscript_parser());
|
||||
CHECK_THROWS_AS(chai.eval<std::string>("print \"Hello World\"\xef"), chaiscript::exception::eval_error);
|
||||
}
|
||||
|
||||
TEST_CASE("BOM in string")
|
||||
{
|
||||
chaiscript::ChaiScript_Basic chai(create_chaiscript_stdlib(),create_chaiscript_parser());
|
||||
CHECK_THROWS_AS(chai.eval<std::string>("\xef\xbb\xbfprint \"Hello World\""), chaiscript::exception::eval_error);
|
||||
}
|
||||
|
||||
int set_state_test_myfun()
|
||||
{
|
||||
@ -382,7 +404,7 @@ TEST_CASE("Set and restore chai state")
|
||||
// set state should have reverted the state of the functions and dropped
|
||||
// the 'myfun'
|
||||
|
||||
CHECK_THROWS_AS(chai.eval<int>("myfun()"), chaiscript::exception::eval_error &);
|
||||
CHECK_THROWS_AS(chai.eval<int>("myfun()"), chaiscript::exception::eval_error);
|
||||
|
||||
// set state should not affect the local variables
|
||||
CHECK(chai.eval<int>("i") == 1);
|
||||
@ -390,7 +412,7 @@ TEST_CASE("Set and restore chai state")
|
||||
// After resetting the locals we expect the 'i' to be gone
|
||||
chai.set_locals(locals);
|
||||
|
||||
CHECK_THROWS_AS(chai.eval<int>("i"), chaiscript::exception::eval_error &);
|
||||
CHECK_THROWS_AS(chai.eval<int>("i"), chaiscript::exception::eval_error);
|
||||
}
|
||||
|
||||
|
||||
@ -468,8 +490,8 @@ TEST_CASE("Simultaneous ChaiScript tests")
|
||||
CHECK(chai.eval<int>("do_something(" + std::to_string(i) + ")") == i + 2);
|
||||
CHECK(chai2.eval<int>("do_something_else(" + std::to_string(i) + ")") == i * 2);
|
||||
|
||||
CHECK_THROWS_AS(chai2.eval("do_something(1)"), chaiscript::exception::eval_error &);
|
||||
CHECK_THROWS_AS(chai2.eval("i"), chaiscript::exception::eval_error &);
|
||||
CHECK_THROWS_AS(chai2.eval("do_something(1)"), chaiscript::exception::eval_error);
|
||||
CHECK_THROWS_AS(chai2.eval("i"), chaiscript::exception::eval_error);
|
||||
CHECK_NOTHROW(chai2.eval("do_something_else(1)"));
|
||||
}
|
||||
}
|
||||
@ -1271,6 +1293,16 @@ TEST_CASE("Test reference member being registered")
|
||||
CHECK(d == Approx(2.3));
|
||||
}
|
||||
|
||||
TEST_CASE("Test unicode matches C++")
|
||||
{
|
||||
chaiscript::ChaiScript_Basic chai(create_chaiscript_stdlib(),create_chaiscript_parser());
|
||||
CHECK(u8"\U000000AC" == chai.eval<std::string>(R"("\U000000AC")"));
|
||||
CHECK("\xF0\x9F\x8D\x8C" == chai.eval<std::string>(R"("\xF0\x9F\x8D\x8C")"));
|
||||
CHECK(u8"\U0001F34C" == chai.eval<std::string>(R"("\U0001F34C")"));
|
||||
CHECK(u8"\u2022" == chai.eval<std::string>(R"("\u2022")"));
|
||||
|
||||
}
|
||||
|
||||
|
||||
const int add_3(const int &i)
|
||||
{
|
||||
|
||||
@ -10,5 +10,7 @@ var o = MyClass();
|
||||
|
||||
assert_true(o.is_explicit());
|
||||
|
||||
assert_throws("error", fun[o](){o.x = 2})
|
||||
assert_throws("Error: \"'x' is not a function.\"", fun[o](){o.x = 2})
|
||||
|
||||
|
||||
|
||||
|
||||
2
unittests/eval_file_with_bom.chai
Normal file
2
unittests/eval_file_with_bom.chai
Normal file
@ -0,0 +1,2 @@
|
||||
eval_file("file_with_bom.inc")
|
||||
assert_true(alwaysTrue())
|
||||
@ -40,3 +40,13 @@ assert_equal(res3[2], "member2")
|
||||
assert_true(__FILE__.find("execution_context.chai") != -1)
|
||||
|
||||
|
||||
assert_equal(eval("__FILE__"), "__EVAL__")
|
||||
assert_equal(eval("__LINE__"), 1)
|
||||
assert_equal(eval("__FUNC__"), "NOT_IN_FUNCTION")
|
||||
assert_equal(eval("__CLASS__"), "NOT_IN_CLASS")
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
11
unittests/failed_deep_include.chai
Normal file
11
unittests/failed_deep_include.chai
Normal file
@ -0,0 +1,11 @@
|
||||
|
||||
|
||||
try {
|
||||
use("failed_deep_include.inc")
|
||||
assert_true(false);
|
||||
} catch (e) {
|
||||
puts("Caught exception while trying to use file");
|
||||
assert_equal(e.what(), "File Not Found: totally_missing_file.inc");
|
||||
}
|
||||
|
||||
|
||||
3
unittests/failed_deep_include.inc
Normal file
3
unittests/failed_deep_include.inc
Normal file
@ -0,0 +1,3 @@
|
||||
use("totally_missing_file.inc");
|
||||
|
||||
|
||||
3
unittests/file_with_bom.inc
Normal file
3
unittests/file_with_bom.inc
Normal file
@ -0,0 +1,3 @@
|
||||
def alwaysTrue() {
|
||||
return true
|
||||
}
|
||||
@ -66,10 +66,10 @@ auto group = group_guard.get_contained_functions();
|
||||
assert_equal(true, group[0].has_guard())
|
||||
assert_equal(false, group[1].has_guard())
|
||||
|
||||
assert_throws("Function does not have a guard", fun() { group[0].get_guard(); } );
|
||||
assert_throws("Function does not have a guard", fun() { without_guard.get_guard(); } );
|
||||
assert_throws("Function does not have a guard", fun[group]() { group[1].get_guard(); } );
|
||||
assert_throws("Function does not have a guard", fun[without_guard]() { without_guard.get_guard(); } );
|
||||
|
||||
auto guard = with_guard.get_guard();
|
||||
|
||||
assert_equal(false, guard.has_guard());
|
||||
assert_throws("Function does not have a guard", fun() { guard.get_guard(); } );
|
||||
assert_throws("Function does not have a guard", fun[guard]() { guard.get_guard(); } );
|
||||
|
||||
@ -1,2 +1,2 @@
|
||||
assert_throws("Function already defined", fun(){ def foo(x) { x + 1 }; def foo(x) { x + 1 } } );
|
||||
assert_throws("Error: \"Function redefined 'foo'\"", fun(){ def foo(x) { x + 1 }; def foo(x) { x + 1 } } );
|
||||
|
||||
|
||||
@ -1 +1 @@
|
||||
assert_throws("Illegal const function assignment", fun() { clone = `-` } );
|
||||
assert_throws("Error: \"Error, cannot assign to constant value.\"", fun() { clone = `-` } );
|
||||
|
||||
@ -1 +1,4 @@
|
||||
assert_throws("Invalid function reassignment", fun() { auto x = 5; x = `-`; } );
|
||||
assert_throws("Error: \"Unable to find appropriate'=' operator.\" With parameters: (int, const Function)", fun() { auto x = 5; x = `-`; } );
|
||||
|
||||
|
||||
|
||||
|
||||
19
unittests/json_15.chai
Normal file
19
unittests/json_15.chai
Normal file
@ -0,0 +1,19 @@
|
||||
// Various to_json() tests
|
||||
assert_equal(to_json(-13570), "-13570")
|
||||
assert_equal(to_json(0.654321), "0.654321")
|
||||
assert_equal(to_json("ChaiScript"), "\"ChaiScript\"")
|
||||
assert_equal(to_json(true), "true")
|
||||
assert_equal(to_json([1, 2, 3]), "[1, 2, 3]")
|
||||
assert_equal(to_json(Vector()), "[]") // empty vector
|
||||
assert_equal(to_json([]), "[]") // empty vector
|
||||
assert_equal(to_json(Map()), "{\n\n}") // empty map
|
||||
assert_equal(to_json(Dynamic_Object()), "{\n\n}") // empty object
|
||||
|
||||
// Round-trip JSON tests
|
||||
assert_equal(from_json(to_json([])), [])
|
||||
assert_equal(from_json(to_json(Map())), Map())
|
||||
assert_equal(to_json(from_json("null")), "null")
|
||||
assert_equal(from_json(to_json(["a": 5, "b": "stuff"])), ["a": 5, "b": "stuff"])
|
||||
auto x = [3.5, true, false, "test", [], Vector(), Map()]
|
||||
assert_equal(from_json(to_json(x)), x)
|
||||
assert_equal(from_json(to_json(["aa\\zz":"aa\\zz"])), ["aa\\zz": "aa\\zz"])
|
||||
@ -1,2 +1,3 @@
|
||||
assert_equal(from_json("100"), 100)
|
||||
assert_equal(from_json("-100"), -100)
|
||||
assert_equal(to_json(4294967295), "4294967295")
|
||||
|
||||
@ -1,2 +1,8 @@
|
||||
|
||||
assert_throws("Parse failure", fun() { eval("[\"hello\":5,\"j\",\"k\"]") } );
|
||||
try {
|
||||
eval("[\"hello\":5,\"j\",\"k\"]");
|
||||
assert_true(false);
|
||||
} catch (eval_error ee) {
|
||||
}
|
||||
|
||||
|
||||
|
||||
@ -13,4 +13,6 @@ assert_equal(0, i -= i)
|
||||
assert_equal(3, j *= 1.5)
|
||||
assert_equal(1.5, j /= 2)
|
||||
assert_equal(2.5, j += 1)
|
||||
assert_throws("No modulus for float", fun() { k % 2 } );
|
||||
assert_throws("Error: \"Error with numeric operator calling: %\"", fun[k]() { k % 2 } );
|
||||
|
||||
|
||||
|
||||
@ -29,3 +29,13 @@ assert_equal(2, j += 1);
|
||||
assert_equal(1, --j);
|
||||
assert_equal(2, ++j);
|
||||
|
||||
|
||||
assert_throws("Error: \"Error with prefix operator evaluation: cannot modify constant value.\"", fun() { ++4; });
|
||||
assert_throws("Error: \"Error with prefix operator evaluation: cannot modify constant value.\"", fun() { --4; });
|
||||
|
||||
assert_throws("Error: \"Error, cannot assign to constant value.\"", fun() { 5 = 5; });
|
||||
assert_throws("Error: \"Error, cannot assign to constant value.\"", fun() { int(5) = 5; });
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
12
unittests/ranged_for_2.chai
Normal file
12
unittests/ranged_for_2.chai
Normal file
@ -0,0 +1,12 @@
|
||||
def keys(map)
|
||||
{
|
||||
auto v = Vector(); // create empty vector
|
||||
for( i : map )
|
||||
{
|
||||
v.push_back(i.first); // append key to the vector
|
||||
}
|
||||
v; // return the new vector
|
||||
}
|
||||
print(keys(["1a":111, "2b":222]));
|
||||
|
||||
|
||||
@ -6,6 +6,20 @@ try {
|
||||
print("Caught Error: " + e.what());
|
||||
}
|
||||
|
||||
def get_value()
|
||||
{
|
||||
var i = 5;
|
||||
return i;
|
||||
}
|
||||
|
||||
def get_value_2()
|
||||
{
|
||||
return 5;
|
||||
}
|
||||
|
||||
// TODO these should be fixed somehow
|
||||
//assert_throws("Cannot assign to temporary", fun[](){ get_value() = 3; });
|
||||
//assert_throws("Cannot assign to temporary", fun[](){ get_value_2() = 3; });
|
||||
|
||||
|
||||
try {
|
||||
|
||||
@ -1,5 +1,7 @@
|
||||
|
||||
#ifndef CHAISCRIPT_NO_THREADS
|
||||
#define CHAISCRIPT_NO_THREADS
|
||||
#endif
|
||||
|
||||
/// ChaiScript as a static is unsupported with thread support enabled
|
||||
///
|
||||
|
||||
@ -1,11 +1,4 @@
|
||||
assert_equal('\u00aa', '\u00AA')
|
||||
assert_equal('\u00bb', '\uBB')
|
||||
assert_equal('\ucc', '\u00CC')
|
||||
assert_equal('\udd', '\uDD')
|
||||
assert_equal("\u00aa", "\u00AA")
|
||||
assert_equal("\u00bb", "\xC2\xBB")
|
||||
|
||||
assert_equal('\u0ee', '\uEE')
|
||||
assert_equal('\ue', '\u000E')
|
||||
|
||||
assert_equal("\u30\u31\u32", "012")
|
||||
assert_equal("\u33Test", "3Test")
|
||||
assert_equal("Test\u0040", "Test@")
|
||||
|
||||
@ -1,5 +1,16 @@
|
||||
assert_equal("\uc39c", "Ü")
|
||||
assert_equal("U for \uc39cmlauts", "U for Ümlauts")
|
||||
assert_equal("More \uc39cml\uc3a4\uc3bcts", "More Ümläüts")
|
||||
assert_equal("\uc39c", "쎜")
|
||||
assert_equal("U for \u00dcmlauts", "U for Ümlauts")
|
||||
|
||||
assert_equal("Thorn \uc3be sign", "Thorn þ sign")
|
||||
assert_equal("Thorn \u00fe sign", "Thorn þ sign")
|
||||
assert_equal("Test\u0020Me", "Test Me")
|
||||
assert_equal("Test\u2022Me", "Test•Me")
|
||||
|
||||
assert_equal("\xF0\x9F\x8D\x8C", "🍌")
|
||||
assert_equal("\U0001F34C", "🍌")
|
||||
|
||||
assert_throws("Error: \"Invalid 16 bit universal character\"", fun(){ parse("\"\\uD83C\""); });
|
||||
assert_throws("Error: \"Incomplete unicode escape sequence\"", fun(){ parse("\"\\uD83 \""); });
|
||||
|
||||
assert_equal("\U00024B62", "𤭢")
|
||||
|
||||
assert_equal("Test\U0001F534Me", "Test🔴Me")
|
||||
|
||||
@ -42,12 +42,14 @@ def assert_not_equal(x, y)
|
||||
|
||||
def assert_throws(desc, x)
|
||||
{
|
||||
if (throws_exception(x))
|
||||
auto result = trim(throws_exception(x));
|
||||
if (result == desc)
|
||||
{
|
||||
// Passes
|
||||
} else {
|
||||
// Fails
|
||||
print("assert_throws failure, function did not throw exception: " + to_string(desc));
|
||||
print("assert_throws failed: got '${result}' expected '${desc}'");
|
||||
exit(-1);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@ -1,2 +1,2 @@
|
||||
assert_throws("Variable already defined", fun() { auto y = 10; auto y = 20; })
|
||||
assert_throws("Error: \"Variable redefined 'y'\"", fun() { auto y = 10; auto y = 20; })
|
||||
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user