Compare commits

...

91 Commits

Author SHA1 Message Date
Jason Turner
4a3315cfd1 Merge pull request #144 from ChaiScript/develop
Merge release 5.5.0 to master
2014-11-10 12:48:25 -07:00
Jason Turner
8a30581eaf Update release notes for version 5.5.0 2014-11-10 12:45:49 -07:00
Jason Turner
a51281a5be Merge branch 'develop' of http://github.com/ChaiScript/ChaiScript into develop 2014-11-06 15:13:51 -07:00
Jason Turner
e0919f7228 Merge branch 'develop' of https://github.com/ChaiScript/ChaiScript into develop 2014-11-06 15:13:30 -07:00
Jason Turner
fa5966bd04 Enable optimizations options for LTO and profile 2014-11-06 15:12:53 -07:00
Jason Turner
f4f2391801 Add support for clang/gcc MemorySanitizer 2014-11-04 15:22:09 -07:00
Jason Turner
5daf837037 Increment version number to 5.5.0 2014-11-04 09:47:32 -07:00
Jason Turner
99396ba05c Add \r skipping code from @jespada 2014-11-03 21:37:25 -07:00
Jason Turner
f5304ac75c Merge branch 'develop' of http://github.com/ChaiScript/ChaiScript into develop 2014-11-03 18:36:10 -07:00
Jason Turner
3f460fdd20 Fix 64bit msvc warning 2014-11-03 18:34:33 -07:00
Jason Turner
4f972bcf67 Refine lifetime of parameters to functions
Fixes crash caused when making function calls in a global context, and
probably fixes other things.
2014-11-03 09:13:30 -07:00
Jason Turner
5d5e881971 Fix arity of functions
A value was being accessed after it was moved.
2014-11-03 08:24:02 -07:00
Jason Turner
5515d058bb Fix some warnings for clang / 64bit windows 2014-11-03 07:33:53 -07:00
Jason Turner
79c5f71975 Fix compilation on gcc 4.6 2014-11-02 21:47:42 -07:00
Jason Turner
c876a89030 Fix crash during user_defined_conversions_2
Temporaries created during user conversion operations were being dropped
before the result of the conversion was able to be used. This fixes that
by temporarily storing the result of the conversion inside the
current Function_Push_Pop context.
2014-11-02 21:37:01 -07:00
Jason Turner
20c0e6016e Add type_conversion helper and failing unit test 2014-11-02 14:08:57 -07:00
Jason Turner
dd12785b72 Reduce virtual calls for get_arity
Saves compiled code size and some minor runtime differences
2014-11-01 18:40:42 -06:00
Jason Turner
87cee688a8 Fix broken type conversion call implementation
- We need to properly order the function so that the one with the least
   number if type differences is the one that is tried first.
2014-11-01 15:52:02 -06:00
Jason Turner
e2cf8a48be Correct check for which types might have conversions 2014-10-29 07:07:12 -06:00
Jason Turner
7c766f87a4 Add thread specific cache of type info
Reduces the number of locks necessary to check of a user defined type
conversion should be scanned for / applied.
2014-10-28 22:12:03 -06:00
Jason Turner
e85be6eb3d Add C++ test for user defined conversion 2014-10-28 20:23:19 -06:00
Jason Turner
7b42d5307a Add ability to register a user defined type conversion
Currently this adds a fair bit of overhead. It will need to be evaluated
further before it's merged.
2014-10-28 14:52:24 -06:00
Jason Turner
43d6f0cf16 Rename dynamic_cast into type_conversion
Prep work for getting user defined type conversions implemented
2014-10-28 12:43:30 -06:00
Jason Turner
86e26966c1 More code cleanups 2014-10-28 10:53:29 -06:00
Jason Turner
9e8b833d11 Code cleanups 2014-10-18 16:18:56 -06:00
Jason Turner
48c97bce9c Add faux-inheritance example 2014-10-12 22:13:40 -07:00
Jason Turner
021e2a7949 Fix returning of boolean values from functors 2014-10-12 22:12:54 -07:00
Jason Turner
78cd980067 Work around broken Apple clang implementation
This line of code does not cause an error on clang-3.4 or clang-3.5
on Linux. Apple's clang is somewhere between the two, no way to know
where.

For an unknown reason, specifying default move operations in 'Data'
causes the compiler to think that Boxed_Value is an incomplete type.

This is highly illogical since Data is only used via a shared_ptr, so
the size / type of Boxed_Value should be fully known (and is known on
every other compiler/platform combination).
2014-10-01 15:49:11 -06:00
Jason Turner
58d9e69479 Work around missing move operations in MSVC12 2014-10-05 21:53:44 -06:00
Jason Turner
935e9de19e GCC 4.6 fixes to cleanups 2014-10-05 14:58:27 -06:00
Jason Turner
f547b4bb10 Enable moving of data into Boxed_Values when possible 2014-10-05 12:11:46 -06:00
Jason Turner
87e40237d3 Enable moving of Any objects 2014-10-05 11:47:50 -06:00
Jason Turner
5619f2602d Eliminate extra dynamic allocation in the Stack 2014-10-05 08:58:29 -06:00
Jason Turner
5986531bba dispatchkit modernization 2014-10-04 22:59:52 -06:00
Jason Turner
8ecc11c275 First pass of modernization of chaiscript_eval.hpp done 2014-10-04 18:31:08 -06:00
Jason Turner
81dc4949d2 1/4 through modernization of chaiscript_eval.hpp 2014-10-04 15:34:32 -06:00
Jason Turner
9a7d03df05 Modernization of chaiscript_parser 2014-10-04 09:37:33 -06:00
Jason Turner
4f5a6da280 Move constructor and noexcept correctness 2014-09-21 14:19:41 -06:00
Jason Turner
e4b9be6e09 Merge remote-tracking branch 'origin/develop' into code_cleanups
Conflicts:
	.decent_ci-Linux.yaml
2014-09-20 14:27:37 -06:00
Jason Turner
0a7e7b3a0d Merge pull request #137 from ChaiScript/enable_decent_ci
Enable decent ci
2014-09-20 14:24:24 -06:00
Jason Turner
e1b80abac4 Update documenation to-dos regarding gcc 4.6 2014-09-20 14:20:37 -06:00
Jason Turner
b6e8605aee Attempt again to satisfy gcc 4.6 2014-09-20 14:17:41 -06:00
Jason Turner
0e381e333e Attempt to satisfy G++4.6 and decltype usage 2014-09-20 08:31:18 -06:00
Jason Turner
8c31255012 Windows and GCC 4.6 error cleanups 2014-09-20 07:21:30 -06:00
Jason Turner
01cf906e18 Clean up 32bit windows warnings 2014-09-19 21:58:28 -06:00
Jason Turner
e55700b86b Remove static in bind_first - VS12 warns on it 2014-09-19 21:52:18 -06:00
Jason Turner
81184cbbd7 Rollback template alias, not supported in gcc 4.6 2014-09-19 21:46:52 -06:00
Jason Turner
c00c38bc22 Fix spelling of "USE_LIBCXX" flag 2014-09-19 10:34:51 -06:00
Jason Turner
ae1897e2ea Update to force CI rebuild 2014-09-19 10:25:04 -06:00
Jason Turner
93c1cfde99 Try out some alias templates for cleanup 2014-09-18 20:48:34 -06:00
Jason Turner
2321f1d709 Enable clang linux builds 2014-09-18 20:07:15 -06:00
Jason Turner
cfd4a73a89 Add VS 2014 CI Support 2014-09-16 13:30:47 -06:00
Jason Turner
04782b6a33 Add gcc-4.6 to test configuration 2014-09-16 08:02:12 -06:00
Jason Turner
5861c45fc1 C++11 related cleanup and improvments 2014-09-15 21:16:44 -06:00
Jason Turner
d62a452a9d Correct -I path for cppcheck run 2014-09-15 07:12:19 -06:00
Jason Turner
3ccb155358 Fix up usage of cppcheck, enable samples build 2014-09-14 21:57:07 -06:00
Jason Turner
6c2ccf3869 Various cleanups prefering lambda to bind 2014-09-14 21:53:11 -06:00
Jason Turner
f02a9fa885 Merge remote-tracking branch 'origin/enable_decent_ci' into code_cleanups 2014-09-14 20:10:52 -06:00
Jason Turner
0036ebfe5d Update .decent_ci-Windows.yaml 2014-09-14 12:44:20 -06:00
Jason Turner
7b28f9ef57 Fix results location 2014-09-13 23:11:17 -06:00
Jason Turner
bd8a78eccc Initial decent_ci files 2014-09-13 21:53:12 -06:00
Jason Turner
9436533ddb Merge commit '243f400' into develop
Conflicts:
	include/chaiscript/dispatchkit/bind_first.hpp
2014-09-12 15:18:38 -06:00
Jason Turner
243f4001d1 Code cleanups 2014-09-12 15:16:24 -06:00
Jason Turner
3bd2a9c00d Clean up bind_first implementation 2014-09-10 07:40:16 -06:00
Jason Turner
fde90ad980 Throw exception if user attempts to use null Boxed_Value 2014-09-09 13:43:05 -06:00
Jason Turner
308eb34d05 Correct test_module changes 2014-09-08 21:15:02 -06:00
Jason Turner
4a70ffe599 Add failing unit test for accessing member of null object 2014-09-08 18:23:53 -06:00
Jason Turner
52179d8333 Merge branch 'develop' of https://github.com/ChaiScript/ChaiScript into develop 2014-09-08 11:11:35 -06:00
Jason Turner
eed90b521d Spelling corrections and comment fixes 2014-09-08 11:10:53 -06:00
Jason Turner
166f3501c3 Ignore missing system include files 2014-09-05 08:41:58 -06:00
Jason Turner
29b1fca76c Use g++-4.8 for cppcheck building 2014-09-05 08:09:22 -06:00
Jason Turner
8d36b66c89 Fix call to cppcheck 2014-09-05 07:45:36 -06:00
Jason Turner
f78fb77128 Merge pull request #135 from ChaiScript/develop
Develop
2014-08-31 20:03:18 -06:00
Jason Turner
bb08cc3699 Add documenation for "class" keyword 2014-08-31 19:54:43 -06:00
Jason Turner
6692607507 Update version number to 5.4.0, update releasenotes 2014-08-31 19:45:07 -06:00
Jason Turner
6bea42c1c0 Speed up to_string performance by relying on C++ versions
Addresses #134, fixing issues introduced by #132
2014-08-31 16:03:42 -06:00
Jason Turner
251790f144 Fix some MSVC warnings 2014-08-31 12:04:02 -06:00
Jason Turner
4ee9ba9c96 Make up some of the performance losses #132 2014-08-30 14:49:31 -06:00
Jason Turner
a71903f185 Add strong reference to range objects #132 2014-08-30 13:36:36 -06:00
Jason Turner
3fe80d70c6 Roll back name of range class, it's half baked from the range fix 2014-08-27 12:24:46 -06:00
Jason Turner
9c05779fac Add failing range test
Crash occurs if the user attempts to use a range and the source
of the range has gone out of scope. #132
2014-08-27 12:15:47 -06:00
Jason Turner
a6e3fd5b42 Make reflection API part of stdlib
removes the reflection module completely. Reflection and the
ability to catch eval errors is too useful.
2014-08-27 12:05:03 -06:00
Jason Turner
6a3f19d575 Add copy constructor for Type_Info 2014-08-26 09:28:51 -06:00
Jason Turner
9b7e4d2e78 Let a subscript out of range be catchable from chaiscript 2014-08-26 08:51:02 -06:00
Jason Turner
f546e46582 Update to cppcheck 1.66 2014-08-22 21:29:14 -06:00
Jason Turner
fa1f4b795b Add class keyword for easier user defined types.
Issue #118
2014-08-22 21:11:49 -06:00
Jason Turner
cb1c7730cf Add the ability to look up user defined typenames
Closes #124
2014-08-17 09:05:29 -06:00
Jason Turner
3a775097dd Reduce size of Any template wrapper. 2014-08-17 06:52:11 -06:00
Jason Turner
5692dfc58a Move to unique_ptr for Any implemenation
Speed and size improvements
2014-08-15 20:38:35 -06:00
Jason Turner
c5f6c549ec Reduce compiled size with template reductions 2014-08-15 20:14:15 -06:00
Jason Turner
14a280713f Update version to 5.3.2 2014-06-11 15:15:51 -06:00
55 changed files with 3759 additions and 3502 deletions

13
.decent_ci-Linux.yaml Normal file
View File

@@ -0,0 +1,13 @@
compilers:
- name: "clang"
version: "3.5"
cmake_extra_flags: -DUSE_LIBCXX:BOOL=OFF -DBUILD_SAMPLES:BOOL=ON -DBUILD_PACKAGE:BOOL=ON -DBUILD_TESTING:BOOL=ON
- name: "gcc"
version: "4.8"
cmake_extra_flags: -DBUILD_PACKAGE:BOOL=ON -DBUILD_TESTING:BOOL=ON -DBUILD_TESTING:BOOL=ON
- name: "gcc"
version: "4.6"
cmake_extra_flags: -DBUILD_SAMPLES:BOOL=ON -DBUILD_PACKAGE:BOOL=ON -DBUILD_TESTING:BOOL=ON
- name: cppcheck
compiler_extra_flags: --enable=all -I include --inline-suppr

7
.decent_ci-MacOS.yaml Normal file
View File

@@ -0,0 +1,7 @@
compilers:
- name: clang
cmake_extra_flags: -DBUILD_SAMPLES:BOOL=ON -DBUILD_PACKAGE:BOOL=ON -DBUILD_TESTING:BOOL=ON -DCOMMIT_SHA=$COMMIT_SHA
- name: clang
build_type: Debug
cmake_extra_flags: -DBUILD_SAMPLES:BOOL=ON -DBUILD_PACKAGE:BOOL=ON -DBUILD_TESTING:BOOL=ON -DCOMMIT_SHA=$COMMIT_SHA

20
.decent_ci-Windows.yaml Normal file
View File

@@ -0,0 +1,20 @@
compilers:
- name: Visual Studio
version: 14
cmake_extra_flags: -DBUILD_SAMPLES:BOOL=ON -DBUILD_PACKAGE:BOOL=ON -DBUILD_TESTING:BOOL=ON -DCOMMIT_SHA=%COMMIT_SHA%
compiler_extra_flags: /ANALYZE
- name: Visual Studio
version: 14
architecture: Win64
cmake_extra_flags: -DBUILD_SAMPLES:BOOL=ON -DBUILD_PACKAGE:BOOL=ON -DBUILD_TESTING:BOOL=ON -DCOMMIT_SHA=%COMMIT_SHA%
compiler_extra_flags: /ANALYZE
- name: Visual Studio
version: 12
cmake_extra_flags: -DBUILD_SAMPLES:BOOL=ON -DBUILD_PACKAGE:BOOL=ON -DBUILD_TESTING:BOOL=ON -DCOMMIT_SHA=%COMMIT_SHA%
compiler_extra_flags: /ANALYZE
- name: Visual Studio
version: 12
architecture: Win64
cmake_extra_flags: -DBUILD_SAMPLES:BOOL=ON -DBUILD_PACKAGE:BOOL=ON -DBUILD_TESTING:BOOL=ON -DCOMMIT_SHA=%COMMIT_SHA%
compiler_extra_flags: /ANALYZE

4
.decent_ci.yaml Normal file
View File

@@ -0,0 +1,4 @@
results_repository : ChaiScript/ChaiScript-BuildResults
results_path : _posts
results_base_url : https://chaiscript.github.io/ChaiScript-BuildResults
aging_pull_requests_notification: true

View File

@@ -10,7 +10,7 @@ else()
endif() endif()
option(BUILD_MODULES "Build Extra Modules (stl, reflection)" TRUE) option(BUILD_MODULES "Build Extra Modules (stl)" TRUE)
option(BUILD_SAMPLES "Build Samples Folder" FALSE) option(BUILD_SAMPLES "Build Samples Folder" FALSE)
@@ -36,11 +36,38 @@ if(CMAKE_COMPILER_IS_GNUCC OR "${CMAKE_CXX_COMPILER_ID}" STREQUAL "Clang")
set(LINKER_FLAGS "${LINKER_FLAGS} -fsanitize=address") set(LINKER_FLAGS "${LINKER_FLAGS} -fsanitize=address")
endif() endif()
option(ENABLE_MEMORY_SANITIZER "Enable memory sanitizer testing in gcc/clang" FALSE)
if(ENABLE_MEMORY_SANITIZER)
add_definitions(-fsanitize=memory -g)
set(LINKER_FLAGS "${LINKER_FLAGS} -fsanitize=memory")
endif()
option(ENABLE_UNDEFINED_SANITIZER "Enable undefined behavior sanitizer testing in gcc/clang" FALSE) option(ENABLE_UNDEFINED_SANITIZER "Enable undefined behavior sanitizer testing in gcc/clang" FALSE)
if(ENABLE_UNDEFINED_SANITIZER) if(ENABLE_UNDEFINED_SANITIZER)
add_definitions(-fsanitize=undefined -g) add_definitions(-fsanitize=undefined -g)
set(LINKER_FLAGS "${LINKER_FLAGS} -fsanitize=undefined") set(LINKER_FLAGS "${LINKER_FLAGS} -fsanitize=undefined")
endif() endif()
option(ENABLE_LTO "Enable Link Time Optimization" FALSE)
if (ENABLE_LTO)
add_definitions(-flto)
set(LINKER_FLAGS "${LINKER_FLAGS} -flto")
endif()
option(PROFILE_GENERATE "Generate profile data" FALSE)
if (PROFILE_GENERATE)
add_definitions(-fprofile-generate)
set(LINKER_FLAGS "${LINKER_FLAGS} -fprofile-generate")
endif()
option(PROFILE_USE "Use profile data" FALSE)
if (PROFILE_USE)
add_definitions(-fprofile-use)
set(LINKER_FLAGS "${LINKER_FLAGS} -fprofile-use")
endif()
endif() endif()
list(APPEND CPACK_SOURCE_IGNORE_FILES "${CMAKE_CURRENT_BINARY_DIR}") list(APPEND CPACK_SOURCE_IGNORE_FILES "${CMAKE_CURRENT_BINARY_DIR}")
@@ -54,8 +81,8 @@ 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_DESCRIPTION_FILE "${CMAKE_CURRENT_SOURCE_DIR}/description.txt")
set(CPACK_PACKAGE_VERSION_MAJOR 5) set(CPACK_PACKAGE_VERSION_MAJOR 5)
set(CPACK_PACKAGE_VERSION_MINOR 3) set(CPACK_PACKAGE_VERSION_MINOR 5)
set(CPACK_PACKAGE_VERSION_PATCH 1) set(CPACK_PACKAGE_VERSION_PATCH 0)
set(CPACK_PACKAGE_EXECUTABLES "chai;ChaiScript Eval") set(CPACK_PACKAGE_EXECUTABLES "chai;ChaiScript Eval")
set(CPACK_PACKAGE_VENDOR "ChaiScript.com") set(CPACK_PACKAGE_VENDOR "ChaiScript.com")
@@ -154,7 +181,7 @@ endif()
include_directories(include) include_directories(include)
set(Chai_INCLUDES include/chaiscript/chaiscript.hpp include/chaiscript/chaiscript_threading.hpp include/chaiscript/dispatchkit/bad_boxed_cast.hpp include/chaiscript/dispatchkit/bind_first.hpp include/chaiscript/dispatchkit/bootstrap.hpp include/chaiscript/dispatchkit/bootstrap_stl.hpp include/chaiscript/dispatchkit/boxed_cast.hpp include/chaiscript/dispatchkit/boxed_cast_helper.hpp include/chaiscript/dispatchkit/boxed_number.hpp include/chaiscript/dispatchkit/boxed_value.hpp include/chaiscript/dispatchkit/dispatchkit.hpp include/chaiscript/dispatchkit/dynamic_cast_conversion.hpp include/chaiscript/dispatchkit/dynamic_object.hpp include/chaiscript/dispatchkit/exception_specification.hpp include/chaiscript/dispatchkit/function_call.hpp include/chaiscript/dispatchkit/function_call_detail.hpp include/chaiscript/dispatchkit/handle_return.hpp include/chaiscript/dispatchkit/operators.hpp include/chaiscript/dispatchkit/proxy_constructors.hpp include/chaiscript/dispatchkit/proxy_functions.hpp include/chaiscript/dispatchkit/proxy_functions_detail.hpp include/chaiscript/dispatchkit/register_function.hpp include/chaiscript/dispatchkit/type_info.hpp include/chaiscript/language/chaiscript_algebraic.hpp include/chaiscript/language/chaiscript_common.hpp include/chaiscript/language/chaiscript_engine.hpp include/chaiscript/language/chaiscript_eval.hpp include/chaiscript/language/chaiscript_parser.hpp include/chaiscript/language/chaiscript_prelude.chai include/chaiscript/language/chaiscript_prelude_docs.hpp include/chaiscript/utility/utility.hpp) set(Chai_INCLUDES include/chaiscript/chaiscript.hpp include/chaiscript/chaiscript_threading.hpp include/chaiscript/dispatchkit/bad_boxed_cast.hpp include/chaiscript/dispatchkit/bind_first.hpp include/chaiscript/dispatchkit/bootstrap.hpp include/chaiscript/dispatchkit/bootstrap_stl.hpp include/chaiscript/dispatchkit/boxed_cast.hpp include/chaiscript/dispatchkit/boxed_cast_helper.hpp include/chaiscript/dispatchkit/boxed_number.hpp include/chaiscript/dispatchkit/boxed_value.hpp include/chaiscript/dispatchkit/dispatchkit.hpp include/chaiscript/dispatchkit/type_conversions.hpp include/chaiscript/dispatchkit/dynamic_object.hpp include/chaiscript/dispatchkit/exception_specification.hpp include/chaiscript/dispatchkit/function_call.hpp include/chaiscript/dispatchkit/function_call_detail.hpp include/chaiscript/dispatchkit/handle_return.hpp include/chaiscript/dispatchkit/operators.hpp include/chaiscript/dispatchkit/proxy_constructors.hpp include/chaiscript/dispatchkit/proxy_functions.hpp include/chaiscript/dispatchkit/proxy_functions_detail.hpp include/chaiscript/dispatchkit/register_function.hpp include/chaiscript/dispatchkit/type_info.hpp include/chaiscript/language/chaiscript_algebraic.hpp include/chaiscript/language/chaiscript_common.hpp include/chaiscript/language/chaiscript_engine.hpp include/chaiscript/language/chaiscript_eval.hpp include/chaiscript/language/chaiscript_parser.hpp include/chaiscript/language/chaiscript_prelude.chai include/chaiscript/language/chaiscript_prelude_docs.hpp include/chaiscript/utility/utility.hpp)
set_source_files_properties(${Chai_INCLUDES} PROPERTIES HEADER_FILE_ONLY TRUE) set_source_files_properties(${Chai_INCLUDES} PROPERTIES HEADER_FILE_ONLY TRUE)
@@ -203,6 +230,8 @@ if(BUILD_SAMPLES)
target_link_libraries(example ${LIBS}) target_link_libraries(example ${LIBS})
add_executable(memory_leak_test samples/memory_leak_test.cpp) add_executable(memory_leak_test samples/memory_leak_test.cpp)
target_link_libraries(memory_leak_test ${LIBS}) target_link_libraries(memory_leak_test ${LIBS})
add_executable(inheritance samples/inheritance.cpp)
target_link_libraries(inheritance ${LIBS})
endif() endif()
@@ -210,9 +239,7 @@ if(BUILD_MODULES)
add_library(stl_extra MODULE src/stl_extra.cpp) add_library(stl_extra MODULE src/stl_extra.cpp)
target_link_libraries(stl_extra ${LIBS}) target_link_libraries(stl_extra ${LIBS})
add_library(reflection MODULE src/reflection.cpp) set(MODULES stl_extra)
target_link_libraries(reflection ${LIBS})
set(MODULES stl_extra reflection)
endif() 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) file(GLOB UNIT_TESTS RELATIVE ${CMAKE_CURRENT_SOURCE_DIR}/unittests/ ${CMAKE_CURRENT_SOURCE_DIR}/unittests/*.chai ${CMAKE_CURRENT_SOURCE_DIR}/unittests/3.x/*.chai)
@@ -275,6 +302,10 @@ if(BUILD_TESTING)
target_link_libraries(type_info_test ${LIBS}) target_link_libraries(type_info_test ${LIBS})
add_test(NAME Type_Info_Test COMMAND type_info_test) add_test(NAME Type_Info_Test COMMAND type_info_test)
add_executable(type_name_test unittests/type_name_test.cpp)
target_link_libraries(type_name_test ${LIBS})
add_test(NAME Type_Name_Test COMMAND type_name_test)
add_executable(eval_catch_exception_test unittests/eval_catch_exception_test.cpp) add_executable(eval_catch_exception_test unittests/eval_catch_exception_test.cpp)
target_link_libraries(eval_catch_exception_test ${LIBS}) target_link_libraries(eval_catch_exception_test ${LIBS})
add_test(NAME Eval_Catch_Exception_Test COMMAND eval_catch_exception_test) add_test(NAME Eval_Catch_Exception_Test COMMAND eval_catch_exception_test)

View File

@@ -1,12 +1,12 @@
#!/bin/bash #!/bin/bash
pushd .. pushd ..
wget http://sourceforge.net/projects/cppcheck/files/cppcheck/1.64/cppcheck-1.65.tar.bz2 wget http://sourceforge.net/projects/cppcheck/files/cppcheck/1.66/cppcheck-1.66.tar.bz2
tar -xvf cppcheck-1.65.tar.bz2 tar -xvf cppcheck-1.66.tar.bz2
cd cppcheck-1.65 cd cppcheck-1.66
make -j2 CXX=g++-4.8 make -j2
popd popd
../cppcheck-1.65/cppcheck --enable=all -I include --inline-suppr --std=c++11 --platform=unix64 src/main.cpp src/chai*.cpp --template ' - __{severity}__: [{file}:{line}](../blob/TRAVIS_COMMIT/{file}#L{line}) {message} ({id})' 2>output ../cppcheck-1.66/cppcheck --enable=all -I include --inline-suppr --suppress=missingIncludeSystem --std=c++11 --platform=unix64 src/main.cpp src/chai*.cpp --template ' - __{severity}__: [{file}:{line}](../blob/TRAVIS_COMMIT/{file}#L{line}) {message} ({id})' 2>output
sed -i "s/TRAVIS_COMMIT/${TRAVIS_COMMIT}/g" output sed -i "s/TRAVIS_COMMIT/${TRAVIS_COMMIT}/g" output
echo -n '{ "body": " ' > output.json echo -n '{ "body": " ' > output.json
echo -n `awk '{printf "%s\\\\n", $0;}' output` >> output.json echo -n `awk '{printf "%s\\\\n", $0;}' output` >> output.json

View File

@@ -75,7 +75,7 @@
/// ///
/// @subsection compiling Compiling ChaiScript Applications /// @subsection compiling Compiling ChaiScript Applications
/// ///
/// ChaiScript is a header only library with only one dependecy: The /// ChaiScript is a header only library with only one dependency: The
/// operating system provided dynamic library loader, which has to be specified on some platforms. /// operating system provided dynamic library loader, which has to be specified on some platforms.
/// ///
/// @subsubsection compilinggcc Compiling with GCC /// @subsubsection compilinggcc Compiling with GCC
@@ -112,7 +112,7 @@
/// ///
/// @subsubsection evalmethod Method 'eval' /// @subsubsection evalmethod Method 'eval'
/// ///
/// The eval method is somewhat more verbose and can be used to get typesafely return values /// The eval method is somewhat more verbose and can be used to get type safely return values
/// from the script. /// from the script.
/// ///
/// ~~~~~~~~{.cpp} /// ~~~~~~~~{.cpp}
@@ -311,7 +311,7 @@
/// As much as possible, ChaiScript attempts to convert between &, *, const &, const *, std::shared_ptr<T>, /// As much as possible, ChaiScript attempts to convert between &, *, const &, const *, std::shared_ptr<T>,
/// std::shared_ptr<const T>, std::reference_wrapper<T>, std::reference_wrapper<const T> and value types automatically. /// std::shared_ptr<const T>, std::reference_wrapper<T>, std::reference_wrapper<const T> and value types automatically.
/// ///
/// If a chaiscript::var object was created in C++ from a pointer, it cannot be convered to a shared_ptr (this would add invalid reference counting). /// If a chaiscript::var object was created in C++ from a pointer, it cannot be converted to a shared_ptr (this would add invalid reference counting).
/// Const may be added, but never removed. /// Const may be added, but never removed.
/// ///
/// The take away is that you can pretty much expect function calls to Just Work when you need them to. /// The take away is that you can pretty much expect function calls to Just Work when you need them to.
@@ -497,6 +497,21 @@
/// print(rect.area()) /// print(rect.area())
/// ~~~~~~~~~ /// ~~~~~~~~~
/// ///
/// Since ChaiScript 5.4.0 it has been possible to use the "class" keyword to simplify this code.
///
/// ~~~~~~~~~
/// class Rectangle {
/// attr height
/// attr width
/// def Rectangle() { this.height = 10; this.width = 20 }
/// def area() { this.height * this.width }
/// }
///
/// var rect = Rectangle()
/// rect.height = 30
/// print(rect.area())
/// ~~~~~~~~~
///
/// @sa @ref keywordattr /// @sa @ref keywordattr
/// @sa @ref keyworddef /// @sa @ref keyworddef

View File

@@ -45,8 +45,8 @@
namespace chaiscript { namespace chaiscript {
static const int version_major = 5; static const int version_major = 5;
static const int version_minor = 3; static const int version_minor = 5;
static const int version_patch = 1; static const int version_patch = 0;
} }
#endif #endif

View File

@@ -28,7 +28,7 @@ namespace chaiscript {
virtual ~bad_any_cast() CHAISCRIPT_NOEXCEPT {} virtual ~bad_any_cast() CHAISCRIPT_NOEXCEPT {}
/// \brief Description of what error occured /// \brief Description of what error occurred
virtual const char * what() const CHAISCRIPT_NOEXCEPT CHAISCRIPT_OVERRIDE virtual const char * what() const CHAISCRIPT_NOEXCEPT CHAISCRIPT_OVERRIDE
{ {
return m_what.c_str(); return m_what.c_str();
@@ -44,17 +44,30 @@ namespace chaiscript {
private: private:
struct Data struct Data
{ {
Data(const std::type_info &t_type)
: m_type(t_type)
{
}
Data &operator=(const Data &) = delete;
virtual ~Data() {} virtual ~Data() {}
virtual void *data() = 0; virtual void *data() = 0;
virtual const std::type_info &type() const = 0; const std::type_info &type() const
virtual std::shared_ptr<Data> clone() const = 0; {
return m_type;
}
virtual std::unique_ptr<Data> clone() const = 0;
const std::type_info &m_type;
}; };
template<typename T> template<typename T>
struct Data_Impl : Data struct Data_Impl : Data
{ {
Data_Impl(T t_type) explicit Data_Impl(T t_type)
: m_type(typeid(T)), : Data(typeid(T)),
m_data(std::move(t_type)) m_data(std::move(t_type))
{ {
} }
@@ -66,23 +79,17 @@ namespace chaiscript {
return &m_data; return &m_data;
} }
const std::type_info &type() const CHAISCRIPT_OVERRIDE std::unique_ptr<Data> clone() const CHAISCRIPT_OVERRIDE
{ {
return m_type; return std::unique_ptr<Data>(new Data_Impl<T>(m_data));
}
std::shared_ptr<Data> clone() const CHAISCRIPT_OVERRIDE
{
return std::shared_ptr<Data>(new Data_Impl<T>(m_data));
} }
Data_Impl &operator=(const Data_Impl&) = delete; Data_Impl &operator=(const Data_Impl&) = delete;
const std::type_info &m_type;
T m_data; T m_data;
}; };
std::shared_ptr<Data> m_data; std::unique_ptr<Data> m_data;
public: public:
// construct/copy/destruct // construct/copy/destruct
@@ -98,12 +105,19 @@ namespace chaiscript {
} }
} }
template<typename ValueType> #if _MSC_VER != 1800
Any(const ValueType &t_value) Any(Any &&) = default;
: m_data(std::shared_ptr<Data>(new Data_Impl<ValueType>(t_value))) Any &operator=(Any &&t_any) = default;
#endif
template<typename ValueType,
typename = typename std::enable_if<!std::is_same<Any, typename std::decay<ValueType>::type>::value>::type>
explicit Any(ValueType &&t_value)
: m_data(std::unique_ptr<Data>(new Data_Impl<typename std::decay<ValueType>::type>(std::forward<ValueType>(t_value))))
{ {
} }
Any & operator=(const Any &t_any) Any & operator=(const Any &t_any)
{ {
Any copy(t_any); Any copy(t_any);
@@ -111,13 +125,6 @@ namespace chaiscript {
return *this; return *this;
} }
template<typename ValueType>
Any & operator=(const ValueType &t_value)
{
m_data = std::shared_ptr<Data>(new Data_Impl<ValueType>(t_value));
return *this;
}
template<typename ToType> template<typename ToType>
ToType &cast() const ToType &cast() const
{ {
@@ -127,7 +134,6 @@ namespace chaiscript {
} else { } else {
throw chaiscript::detail::exception::bad_any_cast(); throw chaiscript::detail::exception::bad_any_cast();
} }
} }
@@ -138,9 +144,7 @@ namespace chaiscript {
// modifiers // modifiers
Any & swap(Any &t_other) Any & swap(Any &t_other)
{ {
std::shared_ptr<Data> data = t_other.m_data; std::swap(t_other.m_data, m_data);
t_other.m_data = m_data;
m_data = data;
return *this; return *this;
} }

View File

@@ -10,6 +10,7 @@
#include <string> #include <string>
#include <typeinfo> #include <typeinfo>
#include "../chaiscript_defines.hpp"
#include "type_info.hpp" #include "type_info.hpp"
namespace chaiscript { namespace chaiscript {
@@ -28,14 +29,14 @@ namespace chaiscript
class bad_boxed_cast : public std::bad_cast class bad_boxed_cast : public std::bad_cast
{ {
public: public:
bad_boxed_cast(const Type_Info &t_from, const std::type_info &t_to, bad_boxed_cast(Type_Info t_from, const std::type_info &t_to,
std::string t_what) CHAISCRIPT_NOEXCEPT std::string t_what) CHAISCRIPT_NOEXCEPT
: from(t_from), to(&t_to), m_what(std::move(t_what)) : from(std::move(t_from)), to(&t_to), m_what(std::move(t_what))
{ {
} }
bad_boxed_cast(const Type_Info &t_from, const std::type_info &t_to) CHAISCRIPT_NOEXCEPT bad_boxed_cast(Type_Info t_from, const std::type_info &t_to)
: from(t_from), to(&t_to), m_what("Cannot perform boxed_cast") : from(std::move(t_from)), to(&t_to), m_what("Cannot perform boxed_cast")
{ {
} }
@@ -46,7 +47,7 @@ namespace chaiscript
virtual ~bad_boxed_cast() CHAISCRIPT_NOEXCEPT {} virtual ~bad_boxed_cast() CHAISCRIPT_NOEXCEPT {}
/// \brief Description of what error occured /// \brief Description of what error occurred
virtual const char * what() const CHAISCRIPT_NOEXCEPT CHAISCRIPT_OVERRIDE virtual const char * what() const CHAISCRIPT_NOEXCEPT CHAISCRIPT_OVERRIDE
{ {
return m_what.c_str(); return m_what.c_str();

View File

@@ -14,79 +14,20 @@ namespace chaiscript
namespace detail namespace detail
{ {
template<int> struct Placeholder
struct Placeholder {
{ static std::tuple<decltype(std::placeholders::_1),decltype(std::placeholders::_2),decltype(std::placeholders::_3),decltype(std::placeholders::_4),decltype(std::placeholders::_5),decltype(std::placeholders::_6),decltype(std::placeholders::_7),decltype(std::placeholders::_8),decltype(std::placeholders::_9),decltype(std::placeholders::_10)> placeholder() {
}; return std::tuple<decltype(std::placeholders::_1),decltype(std::placeholders::_2),decltype(std::placeholders::_3),decltype(std::placeholders::_4),decltype(std::placeholders::_5),decltype(std::placeholders::_6),decltype(std::placeholders::_7),decltype(std::placeholders::_8),decltype(std::placeholders::_9),decltype(std::placeholders::_10)>(std::placeholders::_1,std::placeholders::_2,std::placeholders::_3,std::placeholders::_4,std::placeholders::_5,std::placeholders::_6,std::placeholders::_7,std::placeholders::_8,std::placeholders::_9,std::placeholders::_10);
}
template<> };
struct Placeholder<1>
{
static decltype(std::placeholders::_1) value() { return std::placeholders::_1; }
};
template<>
struct Placeholder<2>
{
static decltype(std::placeholders::_2) value() { return std::placeholders::_2; }
};
template<>
struct Placeholder<3>
{
static decltype(std::placeholders::_3) value() { return std::placeholders::_3; }
};
template<>
struct Placeholder<4>
{
static decltype(std::placeholders::_4) value() { return std::placeholders::_4; }
};
template<>
struct Placeholder<5>
{
static decltype(std::placeholders::_5) value() { return std::placeholders::_5; }
};
template<>
struct Placeholder<6>
{
static decltype(std::placeholders::_6) value() { return std::placeholders::_6; }
};
template<>
struct Placeholder<7>
{
static decltype(std::placeholders::_7) value() { return std::placeholders::_7; }
};
template<>
struct Placeholder<8>
{
static decltype(std::placeholders::_8) value() { return std::placeholders::_8; }
};
template<>
struct Placeholder<9>
{
static decltype(std::placeholders::_9) value() { return std::placeholders::_9; }
};
template<>
struct Placeholder<10>
{
static decltype(std::placeholders::_10) value() { return std::placeholders::_10; }
};
template<int count, int maxcount, typename Sig> template<int count, int maxcount, typename Sig>
struct Bind_First struct Bind_First
{ {
template<typename F, typename ... InnerParams> template<typename F, typename ... InnerParams>
static std::function<Sig> bind(F f, InnerParams ... innerparams) static std::function<Sig> bind(F&& f, InnerParams ... innerparams)
{ {
return Bind_First<count - 1, maxcount, Sig>::bind(f, innerparams..., Placeholder<maxcount - count + 1>::value()); return Bind_First<count - 1, maxcount, Sig>::bind(std::forward<F>(f), innerparams..., std::get<maxcount - count>(Placeholder::placeholder()));
} }
}; };
@@ -94,37 +35,42 @@ namespace chaiscript
struct Bind_First<0, maxcount, Sig> struct Bind_First<0, maxcount, Sig>
{ {
template<typename F, typename ... InnerParams> template<typename F, typename ... InnerParams>
static std::function<Sig> bind(F f, InnerParams ... innerparams) static std::function<Sig> bind(F&& f, InnerParams ... innerparams)
{ {
return std::bind(f, innerparams...); return std::bind(std::forward<F>(f), innerparams...);
} }
}; };
template<typename O, typename Ret, typename P1, typename ... Param> template<typename O, typename Ret, typename P1, typename ... Param>
std::function<Ret (Param...)> bind_first(Ret (*f)(P1, Param...), O o) std::function<Ret (Param...)> bind_first(Ret (*f)(P1, Param...), O&& o)
{ {
return Bind_First<sizeof...(Param), sizeof...(Param), Ret (Param...)>::bind(f, o); return Bind_First<sizeof...(Param), sizeof...(Param), Ret (Param...)>::bind(f, std::forward<O>(o));
} }
template<typename O, typename Ret, typename Class, typename ... Param> template<typename O, typename Ret, typename Class, typename ... Param>
std::function<Ret (Param...)> bind_first(Ret (Class::*f)(Param...), O o) std::function<Ret (Param...)> bind_first(Ret (Class::*f)(Param...), O&& o)
{ {
return Bind_First<sizeof...(Param), sizeof...(Param), Ret (Param...)>::bind(f, o); return Bind_First<sizeof...(Param), sizeof...(Param), Ret (Param...)>::bind(f, std::forward<O>(o));
} }
template<typename O, typename Ret, typename Class, typename ... Param> template<typename O, typename Ret, typename Class, typename ... Param>
std::function<Ret (Param...)> bind_first(Ret (Class::*f)(Param...) const, O o) std::function<Ret (Param...)> bind_first(Ret (Class::*f)(Param...) const, O&& o)
{ {
return Bind_First<sizeof...(Param), sizeof...(Param), Ret (Param...)>::bind(f, o); return Bind_First<sizeof...(Param), sizeof...(Param), Ret (Param...)>::bind(f, std::forward<O>(o));
} }
template<typename O, typename Ret, typename P1, typename ... Param> template<typename O, typename Ret, typename P1, typename ... Param>
std::function<Ret (Param...)> bind_first(const std::function<Ret (P1, Param...)> &f, O o) std::function<Ret (Param...)> bind_first(const std::function<Ret (P1, Param...)> &f, O&& o)
{ {
return Bind_First<sizeof...(Param), sizeof...(Param), Ret (Param...)>::bind(f, o); return Bind_First<sizeof...(Param), sizeof...(Param), Ret (Param...)>::bind(f, std::forward<O>(o));
} }
template<typename O, typename Ret, typename P1, typename ... Param>
std::function<Ret (Param...)> bind_first(std::function<Ret (P1, Param...)> &&f, O&& o)
{
return Bind_First<sizeof...(Param), sizeof...(Param), Ret (Param...)>::bind(std::move(f), std::forward<O>(o));
}
} }
} }

View File

@@ -24,7 +24,7 @@
#include "boxed_number.hpp" #include "boxed_number.hpp"
#include "boxed_value.hpp" #include "boxed_value.hpp"
#include "dispatchkit.hpp" #include "dispatchkit.hpp"
#include "dynamic_cast_conversion.hpp" #include "type_conversions.hpp"
#include "dynamic_object.hpp" #include "dynamic_object.hpp"
#include "operators.hpp" #include "operators.hpp"
#include "proxy_constructors.hpp" #include "proxy_constructors.hpp"
@@ -32,6 +32,8 @@
#include "proxy_functions_detail.hpp" #include "proxy_functions_detail.hpp"
#include "register_function.hpp" #include "register_function.hpp"
#include "type_info.hpp" #include "type_info.hpp"
#include "../utility/utility.hpp"
#include "../language/chaiscript_common.hpp"
namespace chaiscript namespace chaiscript
{ {
@@ -44,13 +46,9 @@ namespace chaiscript
/// \param[in] v Boxed_Number to copy into the new object /// \param[in] v Boxed_Number to copy into the new object
/// \returns The newly created object. /// \returns The newly created object.
template<typename P1> template<typename P1>
std::shared_ptr<P1> construct_pod(Boxed_Number v) std::shared_ptr<P1> construct_pod(const Boxed_Number &v)
{ {
std::shared_ptr<P1> p(new P1()); return std::make_shared<P1>(v.get_as<P1>());
Boxed_Value bv(p);
Boxed_Number nb(bv);
nb = v;
return p;
} }
} }
@@ -111,9 +109,7 @@ namespace chaiscript
} }
/** /// to_string function for internal use. Uses ostream operator<<
* to_string function for internal use. Uses ostream operator<<
*/
template<typename Input> template<typename Input>
std::string to_string(Input i) std::string to_string(Input i)
{ {
@@ -122,10 +118,8 @@ namespace chaiscript
return ss.str(); return ss.str();
} }
/** /// Internal function for converting from a string to a value
* Internal function for converting from a string to a value /// uses ostream operator >> to perform the conversion
* uses ostream operator >> to perform the conversion
*/
template<typename Input> template<typename Input>
Input parse_string(const std::string &i) Input parse_string(const std::string &i)
{ {
@@ -134,12 +128,10 @@ namespace chaiscript
ss >> t; ss >> t;
return t; return t;
} }
/** /// Add all common functions for a POD type. All operators, and
* Add all common functions for a POD type. All operators, and /// common conversions
* common conversions
*/
template<typename T> template<typename T>
ModulePtr bootstrap_pod_type(const std::string &name, ModulePtr m = ModulePtr(new Module())) ModulePtr bootstrap_pod_type(const std::string &name, ModulePtr m = ModulePtr(new Module()))
{ {
@@ -153,22 +145,18 @@ namespace chaiscript
} }
/** /// "clone" function for a shared_ptr type. This is used in the case
* "clone" function for a shared_ptr type. This is used in the case /// where you do not want to make a deep copy of an object during cloning
* where you do not want to make a deep copy of an object during cloning /// but want to instead maintain the shared_ptr. It is needed internally
* but want to instead maintain the shared_ptr. It is needed internally /// for handling of Proxy_Function object (that is,
* for handling of Proxy_Function object (that is, /// function variables.
* function variables.
*/
template<typename Type> template<typename Type>
std::shared_ptr<Type> shared_ptr_clone(const std::shared_ptr<Type> &p) std::shared_ptr<Type> shared_ptr_clone(const std::shared_ptr<Type> &p)
{ {
return p; return p;
} }
/** /// Specific version of shared_ptr_clone just for Proxy_Functions
* Specific version of shared_ptr_clone just for Proxy_Functions
*/
template<typename Type> template<typename Type>
std::shared_ptr<typename std::remove_const<Type>::type> std::shared_ptr<typename std::remove_const<Type>::type>
shared_ptr_unconst_clone(const std::shared_ptr<typename std::add_const<Type>::type> &p) shared_ptr_unconst_clone(const std::shared_ptr<typename std::add_const<Type>::type> &p)
@@ -178,11 +166,9 @@ namespace chaiscript
/** /// Assignment function for shared_ptr objects, does not perform a copy of the
* Assignment function for shared_ptr objects, does not perform a copy of the /// object pointed to, instead maintains the shared_ptr concept.
* object pointed to, instead maintains the shared_ptr concept. /// Similar to shared_ptr_clone. Used for Proxy_Function.
* Similar to shared_ptr_clone. Used for Proxy_Function.
*/
template<typename Type> template<typename Type>
Boxed_Value ptr_assign(Boxed_Value lhs, const std::shared_ptr<Type> &rhs) Boxed_Value ptr_assign(Boxed_Value lhs, const std::shared_ptr<Type> &rhs)
{ {
@@ -196,10 +182,8 @@ namespace chaiscript
} }
} }
/** /// Class consisting of only static functions. All default bootstrapping occurs
* Class consisting of only static functions. All default bootstrapping occurs /// from this class.
* from this class.
*/
class Bootstrap class Bootstrap
{ {
private: private:
@@ -227,9 +211,7 @@ namespace chaiscript
} }
/** /// Add all arithmetic operators for PODs
* Add all arithmetic operators for PODs
*/
static void opers_arithmetic_pod(ModulePtr m = ModulePtr(new Module())) static void opers_arithmetic_pod(ModulePtr m = ModulePtr(new Module()))
{ {
m->add(fun(&Boxed_Number::equals), "=="); m->add(fun(&Boxed_Number::equals), "==");
@@ -269,11 +251,8 @@ namespace chaiscript
} }
/** /// Create a bound function object. The first param is the function to bind
* Create a bound function object. The first param is the function to bind /// the remaining parameters are the args to bind into the result
* the remaining parameters are the args to bind into the
* result
*/
static Boxed_Value bind_function(const std::vector<Boxed_Value> &params) static Boxed_Value bind_function(const std::vector<Boxed_Value> &params)
{ {
if (params.size() < 2) if (params.size() < 2)
@@ -283,7 +262,7 @@ namespace chaiscript
Const_Proxy_Function f = boxed_cast<Const_Proxy_Function>(params[0]); Const_Proxy_Function f = boxed_cast<Const_Proxy_Function>(params[0]);
return Boxed_Value(Const_Proxy_Function(new dispatch::Bound_Function(f, return Boxed_Value(Const_Proxy_Function(std::make_shared<dispatch::Bound_Function>(f,
std::vector<Boxed_Value>(params.begin() + 1, params.end())))); std::vector<Boxed_Value>(params.begin() + 1, params.end()))));
} }
@@ -328,9 +307,7 @@ namespace chaiscript
return e.what(); return e.what();
} }
/** /// Boolean specialization of internal to_string function
* Boolean specialization of internal to_string function
*/
static std::string bool_to_string(bool b) static std::string bool_to_string(bool b)
{ {
if (b) if (b)
@@ -357,12 +334,44 @@ namespace chaiscript
return vbv; return vbv;
} }
static bool has_parse_tree(const chaiscript::Const_Proxy_Function &t_pf)
{
if (auto pf = std::dynamic_pointer_cast<const chaiscript::dispatch::Dynamic_Proxy_Function>(t_pf))
{
if (pf->get_parse_tree())
{
return true;
} else {
return false;
}
} else {
return false;
}
}
static chaiscript::AST_NodePtr get_parse_tree(const chaiscript::Const_Proxy_Function &t_pf)
{
if (auto pf = std::dynamic_pointer_cast<const chaiscript::dispatch::Dynamic_Proxy_Function>(t_pf))
{
if (pf->get_parse_tree())
{
return pf->get_parse_tree();
} else {
throw std::runtime_error("Function does not have a parse tree");
}
} else {
throw std::runtime_error("Function does not have a parse tree");
}
}
template<typename Function> template<typename Function>
static std::function<std::vector<Boxed_Value> (const dispatch::Proxy_Function_Base*)> return_boxed_value_vector(const Function &f) static std::function<std::vector<Boxed_Value> (const dispatch::Proxy_Function_Base*)> return_boxed_value_vector(const Function &f)
{ {
return std::bind(&do_return_boxed_value_vector<Function>, f, std::placeholders::_1); return std::bind(&do_return_boxed_value_vector<Function>, f, std::placeholders::_1);
} }
public: public:
/// \brief perform all common bootstrap functions for std::string, void and POD types /// \brief perform all common bootstrap functions for std::string, void and POD types
/// \param[in,out] m Module to add bootstrapped functions to /// \param[in,out] m Module to add bootstrapped functions to
@@ -380,7 +389,7 @@ namespace chaiscript
m->add(fun(&dispatch::Proxy_Function_Base::annotation), "get_annotation"); m->add(fun(&dispatch::Proxy_Function_Base::annotation), "get_annotation");
m->add(fun(&dispatch::Proxy_Function_Base::operator==), "=="); m->add(fun(&dispatch::Proxy_Function_Base::operator==), "==");
m->add(fun(return_boxed_value_vector(&dispatch::Proxy_Function_Base::get_param_types)), "get_param_types"); m->add(fun(return_boxed_value_vector(&dispatch::Proxy_Function_Base::get_param_types)), "get_param_types");
m->add(fun(return_boxed_value_vector(&dispatch::Proxy_Function_Base::get_contained_functions)), "get_contained_functions"); m->add(fun(return_boxed_value_vector(&dispatch::Proxy_Function_Base::get_contained_functions)), "get_contained_functions");
@@ -409,9 +418,12 @@ namespace chaiscript
m->add(fun(&Boxed_Value::is_ref), "is_var_reference"); m->add(fun(&Boxed_Value::is_ref), "is_var_reference");
m->add(fun(&Boxed_Value::is_pointer), "is_var_pointer"); m->add(fun(&Boxed_Value::is_pointer), "is_var_pointer");
m->add(fun(&Boxed_Value::is_type), "is_type"); m->add(fun(&Boxed_Value::is_type), "is_type");
m->add(fun(&Boxed_Value::get_attr), "get_var_attr");
m->add(fun(&Boxed_Value::copy_attrs), "copy_var_attrs");
m->add(fun(&Boxed_Value::get_type_info), "get_type_info"); m->add(fun(&Boxed_Value::get_type_info), "get_type_info");
m->add(user_type<Type_Info>(), "Type_Info"); m->add(user_type<Type_Info>(), "Type_Info");
m->add(constructor<Type_Info (const Type_Info &)>(), "Type_Info");
operators::equal<Type_Info>(m); operators::equal<Type_Info>(m);
@@ -431,8 +443,8 @@ namespace chaiscript
operators::assign<bool>(m); operators::assign<bool>(m);
operators::equal<bool>(m); operators::equal<bool>(m);
m->add(fun(&to_string<const std::string &>), "internal_to_string"); m->add(fun(&to_string<const std::string &>), "to_string");
m->add(fun(&Bootstrap::bool_to_string), "internal_to_string"); m->add(fun(&Bootstrap::bool_to_string), "to_string");
m->add(fun(&unknown_assign), "="); m->add(fun(&unknown_assign), "=");
m->add(fun(&throw_exception), "throw"); m->add(fun(&throw_exception), "throw");
m->add(fun(&what), "what"); m->add(fun(&what), "what");
@@ -463,8 +475,7 @@ namespace chaiscript
m->add(fun(&print), "print_string"); m->add(fun(&print), "print_string");
m->add(fun(&println), "println_string"); m->add(fun(&println), "println_string");
m->add(Proxy_Function(new dispatch::Dynamic_Proxy_Function(std::bind(&bind_function, std::placeholders::_1))), m->add(Proxy_Function(new dispatch::Dynamic_Proxy_Function(&bind_function)), "bind");
"bind");
m->add(fun(&shared_ptr_unconst_clone<dispatch::Proxy_Function_Base>), "clone"); m->add(fun(&shared_ptr_unconst_clone<dispatch::Proxy_Function_Base>), "clone");
m->add(fun(&ptr_assign<std::remove_const<dispatch::Proxy_Function_Base>::type>), "="); m->add(fun(&ptr_assign<std::remove_const<dispatch::Proxy_Function_Base>::type>), "=");
@@ -472,6 +483,68 @@ namespace chaiscript
m->add(fun(&Boxed_Value::type_match), "type_match"); m->add(fun(&Boxed_Value::type_match), "type_match");
m->add(chaiscript::fun(&has_parse_tree), "has_parse_tree");
m->add(chaiscript::fun(&get_parse_tree), "get_parse_tree");
m->add(chaiscript::base_class<std::exception, chaiscript::exception::eval_error>());
// chaiscript::bootstrap::standard_library::vector_type<std::vector<std::shared_ptr<chaiscript::AST_Node> > >("AST_NodeVector", m);
chaiscript::utility::add_class<chaiscript::exception::eval_error>(*m,
"eval_error",
{ },
{ {fun(&chaiscript::exception::eval_error::reason), "reason"},
{fun(std::function<std::vector<Boxed_Value> (const chaiscript::exception::eval_error &t_eval_error)>([](const chaiscript::exception::eval_error &t_eval_error) -> std::vector<Boxed_Value> {
std::vector<Boxed_Value> retval;
std::transform(t_eval_error.call_stack.begin(), t_eval_error.call_stack.end(),
std::back_inserter(retval),
&chaiscript::var<std::shared_ptr<const chaiscript::AST_Node>>);
return retval;
})), "call_stack"} }
);
chaiscript::utility::add_class<chaiscript::File_Position>(*m,
"File_Position",
{ constructor<File_Position()>(),
constructor<File_Position(int, int)>() },
{ {fun(&File_Position::line), "line"},
{fun(&File_Position::column), "column"} }
);
chaiscript::utility::add_class<AST_Node>(*m,
"AST_Node",
{ },
{ {fun(&AST_Node::text), "text"},
{fun(&AST_Node::identifier), "identifier"},
{fun(&AST_Node::filename), "filename"},
{fun(&AST_Node::start), "start"},
{fun(&AST_Node::end), "end"},
{fun(&AST_Node::to_string), "to_string"},
{fun(std::function<std::vector<Boxed_Value> (const chaiscript::AST_Node &t_node)>([](const chaiscript::AST_Node &t_node) -> std::vector<Boxed_Value> {
std::vector<Boxed_Value> retval;
std::transform(t_node.children.begin(), t_node.children.end(),
std::back_inserter(retval),
&chaiscript::var<std::shared_ptr<chaiscript::AST_Node>>);
return retval;
})), "children"},
{fun(&AST_Node::replace_child), "replace_child"}
}
);
chaiscript::utility::add_class<parser::ChaiScript_Parser>(*m,
"ChaiScript_Parser",
{ constructor<parser::ChaiScript_Parser ()>() },
{ {fun(&parser::ChaiScript_Parser::parse), "parse"},
{fun(&parser::ChaiScript_Parser::ast), "ast"} }
);
return m; return m;
} }
}; };

View File

@@ -185,7 +185,7 @@ namespace chaiscript
copy_constructor<Bidir_Type>(type + "_Range", m); copy_constructor<Bidir_Type>(type + "_Range", m);
m->add(constructor<Bidir_Type (typename Bidir_Type::container_type &)>(), "range"); m->add(constructor<Bidir_Type (typename Bidir_Type::container_type &)>(), "range_internal");
m->add(fun(&Bidir_Type::empty), "empty"); m->add(fun(&Bidir_Type::empty), "empty");
m->add(fun(&Bidir_Type::pop_front), "pop_front"); m->add(fun(&Bidir_Type::pop_front), "pop_front");
@@ -278,9 +278,9 @@ namespace chaiscript
template<typename ContainerType> template<typename ContainerType>
ModulePtr container_type(const std::string &/*type*/, ModulePtr m = ModulePtr(new Module())) ModulePtr container_type(const std::string &/*type*/, ModulePtr m = ModulePtr(new Module()))
{ {
m->add(fun( std::function<size_t (const ContainerType *)>( [](const ContainerType *a) { return a->size(); } ) ), "size"); m->add(fun<size_t (const ContainerType *)>([](const ContainerType *a) { return a->size(); } ), "size");
m->add(fun( std::function<bool (const ContainerType *)>( [](const ContainerType *a) { return a->empty(); } ) ), "empty"); m->add(fun<bool (const ContainerType *)>([](const ContainerType *a) { return a->empty(); } ), "empty");
m->add(fun( std::function<void (ContainerType *)>( [](ContainerType *a) { a->clear(); } ) ), "clear"); m->add(fun<void (ContainerType *)>([](ContainerType *a) { a->clear(); } ), "clear");
return m; return m;
} }
@@ -348,10 +348,12 @@ namespace chaiscript
ModulePtr front_insertion_sequence_type(const std::string &, ModulePtr m = ModulePtr(new Module())) ModulePtr front_insertion_sequence_type(const std::string &, ModulePtr m = ModulePtr(new Module()))
{ {
typedef typename ContainerType::reference (ContainerType::*frontptr)(); typedef typename ContainerType::reference (ContainerType::*frontptr)();
typedef typename ContainerType::const_reference (ContainerType::*constfrontptr)() const;
typedef void (ContainerType::*pushptr)(typename ContainerType::const_reference); typedef void (ContainerType::*pushptr)(typename ContainerType::const_reference);
typedef void (ContainerType::*popptr)(); typedef void (ContainerType::*popptr)();
m->add(fun(static_cast<frontptr>(&ContainerType::front)), "front"); m->add(fun(static_cast<frontptr>(&ContainerType::front)), "front");
m->add(fun(static_cast<constfrontptr>(&ContainerType::front)), "front");
std::string push_front_name; std::string push_front_name;
if (typeid(typename ContainerType::value_type) == typeid(Boxed_Value)) if (typeid(typename ContainerType::value_type) == typeid(Boxed_Value))
@@ -475,7 +477,10 @@ namespace chaiscript
m->add(user_type<VectorType>(), type); m->add(user_type<VectorType>(), type);
typedef typename VectorType::reference (VectorType::*frontptr)(); typedef typename VectorType::reference (VectorType::*frontptr)();
typedef typename VectorType::const_reference (VectorType::*constfrontptr)() const;
m->add(fun(static_cast<frontptr>(&VectorType::front)), "front"); m->add(fun(static_cast<frontptr>(&VectorType::front)), "front");
m->add(fun(static_cast<constfrontptr>(&VectorType::front)), "front");
back_insertion_sequence_type<VectorType>(type, m); back_insertion_sequence_type<VectorType>(type, m);
@@ -488,24 +493,26 @@ namespace chaiscript
if (typeid(VectorType) == typeid(std::vector<Boxed_Value>)) if (typeid(VectorType) == typeid(std::vector<Boxed_Value>))
{ {
m->eval("def Vector::`==`(rhs) : type_match(rhs, this) { \ m->eval(R"(
if ( rhs.size() != this.size() ) { \ def Vector::`==`(rhs) : type_match(rhs, this) {
return false; \ if ( rhs.size() != this.size() ) {
} else { \ return false;
auto r1 = range(this); \ } else {
auto r2 = range(rhs); \ auto r1 = range(this);
while (!r1.empty()) \ auto r2 = range(rhs);
{ \ while (!r1.empty())
if (!eq(r1.front(), r2.front())) \ {
{ \ if (!eq(r1.front(), r2.front()))
return false; \ {
} \ return false;
r1.pop_front(); \ }
r2.pop_front(); \ r1.pop_front();
} \ r2.pop_front();
return true; \ }
} \ true;
}"); }
} )"
);
} }
return m; return m;

View File

@@ -14,11 +14,11 @@
#include "bad_boxed_cast.hpp" #include "bad_boxed_cast.hpp"
#include "boxed_cast_helper.hpp" #include "boxed_cast_helper.hpp"
#include "boxed_value.hpp" #include "boxed_value.hpp"
#include "dynamic_cast_conversion.hpp" #include "type_conversions.hpp"
#include "type_info.hpp" #include "type_info.hpp"
namespace chaiscript { namespace chaiscript {
class Dynamic_Cast_Conversions; class Type_Conversions;
namespace detail { namespace detail {
namespace exception { namespace exception {
class bad_any_cast; class bad_any_cast;
@@ -72,7 +72,7 @@ namespace chaiscript
/// assert(i == 5); /// assert(i == 5);
/// \endcode /// \endcode
template<typename Type> template<typename Type>
typename detail::Cast_Helper<Type>::Result_Type boxed_cast(const Boxed_Value &bv, const Dynamic_Cast_Conversions *t_conversions = nullptr) typename detail::Cast_Helper<Type>::Result_Type boxed_cast(const Boxed_Value &bv, const Type_Conversions *t_conversions = nullptr)
{ {
try { try {
return detail::Cast_Helper<Type>::cast(bv, t_conversions); return detail::Cast_Helper<Type>::cast(bv, t_conversions);
@@ -86,18 +86,18 @@ namespace chaiscript
#pragma warning(disable : 4127) #pragma warning(disable : 4127)
#endif #endif
if (std::is_polymorphic<typename detail::Stripped_Type<Type>::type>::value && t_conversions) if (t_conversions && t_conversions->convertable_type<Type>())
{ {
try { try {
// std::cout << "trying an up conversion " << typeid(Type).name() << std::endl; // std::cout << "trying an up conversion " << typeid(Type).name() << std::endl;
// We will not catch any bad_boxed_dynamic_cast that is thrown, let the user get it // We will not catch any bad_boxed_dynamic_cast that is thrown, let the user get it
// either way, we are not responsible if it doesn't work // either way, we are not responsible if it doesn't work
return detail::Cast_Helper<Type>::cast(t_conversions->boxed_dynamic_cast<Type>(bv), t_conversions); return detail::Cast_Helper<Type>::cast(t_conversions->boxed_type_conversion<Type>(bv), t_conversions);
} catch (...) { } catch (...) {
try { try {
// std::cout << "trying a down conversion " << typeid(Type).name() << std::endl; // std::cout << "trying a down conversion " << typeid(Type).name() << std::endl;
// try going the other way - down the inheritance graph // try going the other way - down the inheritance graph
return detail::Cast_Helper<Type>::cast(t_conversions->boxed_dynamic_down_cast<Type>(bv), t_conversions); return detail::Cast_Helper<Type>::cast(t_conversions->boxed_type_down_conversion<Type>(bv), t_conversions);
} catch (const chaiscript::detail::exception::bad_any_cast &) { } catch (const chaiscript::detail::exception::bad_any_cast &) {
throw exception::bad_boxed_cast(bv.get_type_info(), typeid(Type)); throw exception::bad_boxed_cast(bv.get_type_info(), typeid(Type));
} }

View File

@@ -17,37 +17,32 @@
namespace chaiscript namespace chaiscript
{ {
class Dynamic_Cast_Conversions; class Type_Conversions;
namespace detail namespace detail
{ {
// Cast_Helper_Inner helper classes // Cast_Helper_Inner helper classes
/** template<typename T>
* Generic Cast_Helper_Inner, for casting to any type T* throw_if_null(T *t)
*/ {
if (t) return t;
throw std::runtime_error("Attempted to dereference null Boxed_Value");
}
/// Generic Cast_Helper_Inner, for casting to any type
template<typename Result> template<typename Result>
struct Cast_Helper_Inner struct Cast_Helper_Inner
{ {
typedef typename std::reference_wrapper<typename std::add_const<Result>::type > Result_Type; typedef typename std::reference_wrapper<typename std::add_const<Result>::type > Result_Type;
static Result_Type cast(const Boxed_Value &ob, const Dynamic_Cast_Conversions *) static Result_Type cast(const Boxed_Value &ob, const Type_Conversions *)
{ {
if (ob.is_ref()) if (ob.get_type_info().bare_equal_type_info(typeid(Result)))
{ {
if (!ob.get_type_info().is_const()) return *(static_cast<const Result *>(throw_if_null(ob.get_const_ptr())));
{
return std::cref((ob.get().cast<std::reference_wrapper<Result> >()).get());
} else {
return ob.get().cast<std::reference_wrapper<const Result> >();
}
} else { } else {
if (!ob.get_type_info().is_const()) throw chaiscript::detail::exception::bad_any_cast();
{
return std::cref(*(ob.get().cast<std::shared_ptr<Result> >()));
} else {
return std::cref(*(ob.get().cast<std::shared_ptr<const Result> >()));
}
} }
} }
}; };
@@ -57,23 +52,18 @@ namespace chaiscript
{ {
}; };
/** /// Cast_Helper_Inner for casting to a const & type
* Cast_Helper_Inner for casting to a const & type
*/
template<typename Result> template<typename Result>
struct Cast_Helper_Inner<const Result &> : Cast_Helper_Inner<Result> struct Cast_Helper_Inner<const Result &> : Cast_Helper_Inner<Result>
{ {
}; };
/** /// Cast_Helper_Inner for casting to a const * type
* Cast_Helper_Inner for casting to a const * type
*/
template<typename Result> template<typename Result>
struct Cast_Helper_Inner<const Result *> struct Cast_Helper_Inner<const Result *>
{ {
typedef const Result * Result_Type; typedef const Result * Result_Type;
static Result_Type cast(const Boxed_Value &ob, const Type_Conversions *)
static Result_Type cast(const Boxed_Value &ob, const Dynamic_Cast_Conversions *)
{ {
if (ob.is_ref()) if (ob.is_ref())
{ {
@@ -94,15 +84,12 @@ namespace chaiscript
} }
}; };
/** /// Cast_Helper_Inner for casting to a * type
* Cast_Helper_Inner for casting to a * type
*/
template<typename Result> template<typename Result>
struct Cast_Helper_Inner<Result *> struct Cast_Helper_Inner<Result *>
{ {
typedef Result * Result_Type; typedef Result * Result_Type;
static Result_Type cast(const Boxed_Value &ob, const Type_Conversions *)
static Result_Type cast(const Boxed_Value &ob, const Dynamic_Cast_Conversions *)
{ {
if (ob.is_ref()) if (ob.is_ref())
{ {
@@ -113,49 +100,43 @@ namespace chaiscript
} }
}; };
/**
* Cast_Helper_Inner for casting to a & type /// Cast_Helper_Inner for casting to a & type
*/
template<typename Result> template<typename Result>
struct Cast_Helper_Inner<Result &> struct Cast_Helper_Inner<Result &>
{ {
typedef Result& Result_Type; typedef Result& Result_Type;
static Result_Type cast(const Boxed_Value &ob, const Dynamic_Cast_Conversions *) static Result_Type cast(const Boxed_Value &ob, const Type_Conversions *)
{ {
if (ob.is_ref()) if (!ob.get_type_info().is_const() && ob.get_type_info().bare_equal_type_info(typeid(Result)))
{ {
return ob.get().cast<std::reference_wrapper<Result> >(); return *(static_cast<Result *>(throw_if_null(ob.get_ptr())));
} else { } else {
Result &r = *(ob.get().cast<std::shared_ptr<Result> >()); throw chaiscript::detail::exception::bad_any_cast();
return r;
} }
} }
}; };
/** /// Cast_Helper_Inner for casting to a std::shared_ptr<> type
* Cast_Helper_Inner for casting to a std::shared_ptr<> type
*/
template<typename Result> template<typename Result>
struct Cast_Helper_Inner<typename std::shared_ptr<Result> > struct Cast_Helper_Inner<typename std::shared_ptr<Result> >
{ {
typedef typename std::shared_ptr<Result> Result_Type; typedef typename std::shared_ptr<Result> Result_Type;
static Result_Type cast(const Boxed_Value &ob, const Dynamic_Cast_Conversions *) static Result_Type cast(const Boxed_Value &ob, const Type_Conversions *)
{ {
return ob.get().cast<std::shared_ptr<Result> >(); return ob.get().cast<std::shared_ptr<Result> >();
} }
}; };
/** /// Cast_Helper_Inner for casting to a std::shared_ptr<const> type
* Cast_Helper_Inner for casting to a std::shared_ptr<const> type
*/
template<typename Result> template<typename Result>
struct Cast_Helper_Inner<typename std::shared_ptr<const Result> > struct Cast_Helper_Inner<typename std::shared_ptr<const Result> >
{ {
typedef typename std::shared_ptr<const Result> Result_Type; typedef typename std::shared_ptr<const Result> Result_Type;
static Result_Type cast(const Boxed_Value &ob, const Dynamic_Cast_Conversions *) static Result_Type cast(const Boxed_Value &ob, const Type_Conversions *)
{ {
if (!ob.get_type_info().is_const()) if (!ob.get_type_info().is_const())
{ {
@@ -166,9 +147,7 @@ namespace chaiscript
} }
}; };
/** /// Cast_Helper_Inner for casting to a const std::shared_ptr<> & type
* Cast_Helper_Inner for casting to a const std::shared_ptr<> & type
*/
template<typename Result> template<typename Result>
struct Cast_Helper_Inner<const std::shared_ptr<Result> > : Cast_Helper_Inner<std::shared_ptr<Result> > struct Cast_Helper_Inner<const std::shared_ptr<Result> > : Cast_Helper_Inner<std::shared_ptr<Result> >
{ {
@@ -180,9 +159,7 @@ namespace chaiscript
}; };
/** /// Cast_Helper_Inner for casting to a const std::shared_ptr<const> & type
* Cast_Helper_Inner for casting to a const std::shared_ptr<const> & type
*/
template<typename Result> template<typename Result>
struct Cast_Helper_Inner<const std::shared_ptr<const Result> > : Cast_Helper_Inner<std::shared_ptr<const Result> > struct Cast_Helper_Inner<const std::shared_ptr<const Result> > : Cast_Helper_Inner<std::shared_ptr<const Result> >
{ {
@@ -195,23 +172,32 @@ namespace chaiscript
/** /// Cast_Helper_Inner for casting to a Boxed_Value type
* Cast_Helper_Inner for casting to a Boxed_Value type
*/
template<> template<>
struct Cast_Helper_Inner<Boxed_Value> struct Cast_Helper_Inner<Boxed_Value>
{ {
typedef const Boxed_Value & Result_Type; typedef const Boxed_Value & Result_Type;
static Result_Type cast(const Boxed_Value &ob, const Dynamic_Cast_Conversions *) static Result_Type cast(const Boxed_Value &ob, const Type_Conversions *)
{ {
return ob; return ob;
} }
}; };
/** /// Cast_Helper_Inner for casting to a Boxed_Value & type
* Cast_Helper_Inner for casting to a const Boxed_Value & type template<>
*/ struct Cast_Helper_Inner<Boxed_Value &>
{
typedef Boxed_Value& Result_Type;
static Result_Type cast(const Boxed_Value &ob, const Type_Conversions *)
{
return const_cast<Boxed_Value &>(ob);
}
};
/// Cast_Helper_Inner for casting to a const Boxed_Value & type
template<> template<>
struct Cast_Helper_Inner<const Boxed_Value> : Cast_Helper_Inner<Boxed_Value> struct Cast_Helper_Inner<const Boxed_Value> : Cast_Helper_Inner<Boxed_Value>
{ {
@@ -223,9 +209,7 @@ namespace chaiscript
}; };
/** /// Cast_Helper_Inner for casting to a std::reference_wrapper type
* Cast_Helper_Inner for casting to a std::reference_wrapper type
*/
template<typename Result> template<typename Result>
struct Cast_Helper_Inner<std::reference_wrapper<Result> > : Cast_Helper_Inner<Result &> struct Cast_Helper_Inner<std::reference_wrapper<Result> > : Cast_Helper_Inner<Result &>
{ {
@@ -256,15 +240,13 @@ namespace chaiscript
{ {
}; };
/** /// The exposed Cast_Helper object that by default just calls the Cast_Helper_Inner
* The exposed Cast_Helper object that by default just calls the Cast_Helper_Inner
*/
template<typename T> template<typename T>
struct Cast_Helper struct Cast_Helper
{ {
typedef typename Cast_Helper_Inner<T>::Result_Type Result_Type; typedef typename Cast_Helper_Inner<T>::Result_Type Result_Type;
static Result_Type cast(const Boxed_Value &ob, const Dynamic_Cast_Conversions *t_conversions) static Result_Type cast(const Boxed_Value &ob, const Type_Conversions *t_conversions)
{ {
return Cast_Helper_Inner<T>::cast(ob, t_conversions); return Cast_Helper_Inner<T>::cast(ob, t_conversions);
} }

View File

@@ -19,7 +19,7 @@
#include "type_info.hpp" #include "type_info.hpp"
namespace chaiscript { namespace chaiscript {
class Dynamic_Cast_Conversions; class Type_Conversions;
} // namespace chaiscript } // namespace chaiscript
namespace chaiscript namespace chaiscript
@@ -233,7 +233,7 @@ namespace chaiscript
template<typename LHS, bool Float> template<typename LHS, bool Float>
static Boxed_Value oper_rhs(Operators::Opers t_oper, const Boxed_Value &t_lhs, const Boxed_Value &t_rhs) static Boxed_Value oper_rhs(Operators::Opers t_oper, const Boxed_Value &t_lhs, const Boxed_Value &t_rhs)
{ {
const Type_Info &inp_ = t_rhs.get_type_info(); const auto &inp_ = t_rhs.get_type_info();
if (inp_ == typeid(int)) { if (inp_ == typeid(int)) {
return Go<LHS, int, Float>::go(t_oper, t_lhs, t_rhs); return Go<LHS, int, Float>::go(t_oper, t_lhs, t_rhs);
@@ -334,10 +334,10 @@ namespace chaiscript
{ {
} }
Boxed_Number(const Boxed_Value &v) Boxed_Number(Boxed_Value v)
: bv(v) : bv(std::move(v))
{ {
validate_boxed_number(v); validate_boxed_number(bv);
} }
template<typename T> explicit Boxed_Number(T t) template<typename T> explicit Boxed_Number(T t)
@@ -826,31 +826,25 @@ namespace chaiscript
namespace detail namespace detail
{ {
/** /// Cast_Helper for converting from Boxed_Value to Boxed_Number
* Cast_Helper for converting from Boxed_Value to Boxed_Number
*/
template<> template<>
struct Cast_Helper<Boxed_Number> struct Cast_Helper<Boxed_Number>
{ {
typedef Boxed_Number Result_Type; typedef Boxed_Number Result_Type;
static Result_Type cast(const Boxed_Value &ob, const Dynamic_Cast_Conversions *) static Result_Type cast(const Boxed_Value &ob, const Type_Conversions *)
{ {
return Boxed_Number(ob); return Boxed_Number(ob);
} }
}; };
/** /// Cast_Helper for converting from Boxed_Value to Boxed_Number
* Cast_Helper for converting from Boxed_Value to Boxed_Number
*/
template<> template<>
struct Cast_Helper<const Boxed_Number &> : Cast_Helper<Boxed_Number> struct Cast_Helper<const Boxed_Number &> : Cast_Helper<Boxed_Number>
{ {
}; };
/** /// Cast_Helper for converting from Boxed_Value to Boxed_Number
* Cast_Helper for converting from Boxed_Value to Boxed_Number
*/
template<> template<>
struct Cast_Helper<const Boxed_Number> : Cast_Helper<Boxed_Number> struct Cast_Helper<const Boxed_Number> : Cast_Helper<Boxed_Number>
{ {

View File

@@ -13,6 +13,7 @@
#include <type_traits> #include <type_traits>
#include "../chaiscript_threading.hpp" #include "../chaiscript_threading.hpp"
#include "../chaiscript_defines.hpp"
#include "any.hpp" #include "any.hpp"
#include "type_info.hpp" #include "type_info.hpp"
@@ -35,10 +36,10 @@ namespace chaiscript
struct Data struct Data
{ {
Data(const Type_Info &ti, Data(const Type_Info &ti,
const chaiscript::detail::Any &to, chaiscript::detail::Any to,
bool tr, bool tr,
const void *t_void_ptr) const void *t_void_ptr)
: m_type_info(ti), m_obj(to), m_data_ptr(ti.is_const()?nullptr:const_cast<void *>(t_void_ptr)), m_const_data_ptr(t_void_ptr), : m_type_info(ti), m_obj(std::move(to)), m_data_ptr(ti.is_const()?nullptr:const_cast<void *>(t_void_ptr)), m_const_data_ptr(t_void_ptr),
m_is_ref(tr) m_is_ref(tr)
{ {
} }
@@ -51,18 +52,28 @@ namespace chaiscript
m_data_ptr = rhs.m_data_ptr; m_data_ptr = rhs.m_data_ptr;
m_const_data_ptr = rhs.m_const_data_ptr; m_const_data_ptr = rhs.m_const_data_ptr;
if (rhs.m_attrs)
{
m_attrs = std::unique_ptr<std::map<std::string, Boxed_Value>>(new std::map<std::string, Boxed_Value>(*rhs.m_attrs));
}
return *this; return *this;
} }
~Data() Data(const Data &) = delete;
{
} #if !defined(__APPLE__) && (!defined(_MSC_VER) || _MSC_VER != 1800)
Data(Data &&) = default;
Data &operator=(Data &&rhs) = default;
#endif
Type_Info m_type_info; Type_Info m_type_info;
chaiscript::detail::Any m_obj; chaiscript::detail::Any m_obj;
void *m_data_ptr; void *m_data_ptr;
const void *m_const_data_ptr; const void *m_const_data_ptr;
bool m_is_ref; bool m_is_ref;
std::unique_ptr<std::map<std::string, Boxed_Value>> m_attrs;
}; };
struct Object_Data struct Object_Data
@@ -94,32 +105,53 @@ namespace chaiscript
); );
} }
template<typename T>
static std::shared_ptr<Data> get(std::shared_ptr<T> &&obj)
{
auto ptr = obj.get();
return std::make_shared<Data>(
detail::Get_Type_Info<T>::get(),
chaiscript::detail::Any(std::move(obj)),
false,
ptr
);
}
template<typename T> template<typename T>
static std::shared_ptr<Data> get(T *t) static std::shared_ptr<Data> get(T *t)
{ {
return get(std::ref(*t)); return get(std::ref(*t));
} }
template<typename T>
static std::shared_ptr<Data> get(const T *t)
{
return get(std::cref(*t));
}
template<typename T> template<typename T>
static std::shared_ptr<Data> get(std::reference_wrapper<T> obj) static std::shared_ptr<Data> get(std::reference_wrapper<T> obj)
{ {
auto p = &obj.get();
return std::make_shared<Data>( return std::make_shared<Data>(
detail::Get_Type_Info<T>::get(), detail::Get_Type_Info<T>::get(),
chaiscript::detail::Any(obj), chaiscript::detail::Any(std::move(obj)),
true, true,
&obj.get() p
); );
} }
template<typename T> template<typename T>
static std::shared_ptr<Data> get(const T& t) static std::shared_ptr<Data> get(T t)
{ {
auto p = std::make_shared<T>(t); auto p = std::make_shared<T>(std::move(t));
auto ptr = p.get();
return std::make_shared<Data>( return std::make_shared<Data>(
detail::Get_Type_Info<T>::get(), detail::Get_Type_Info<T>::get(),
chaiscript::detail::Any(p), chaiscript::detail::Any(std::move(p)),
false, false,
p.get() ptr
); );
} }
@@ -137,27 +169,26 @@ namespace chaiscript
public: public:
/// Basic Boxed_Value constructor /// Basic Boxed_Value constructor
template<typename T> template<typename T,
explicit Boxed_Value(T t) typename = typename std::enable_if<!std::is_same<Boxed_Value, typename std::decay<T>::type>::value>::type>
: m_data(Object_Data::get(t)) explicit Boxed_Value(T &&t)
: m_data(Object_Data::get(std::forward<T>(t)))
{ {
} }
/// Copy constructor - each copy shares the same data pointer
Boxed_Value(const Boxed_Value &t_so)
: m_data(t_so.m_data)
{
}
/// Unknown-type constructor /// Unknown-type constructor
Boxed_Value() Boxed_Value()
: m_data(Object_Data::get()) : m_data(Object_Data::get())
{ {
} }
~Boxed_Value() #if !defined(_MSC_VER) || _MSC_VER != 1800
{ Boxed_Value(Boxed_Value&&) = default;
} Boxed_Value& operator=(Boxed_Value&&) = default;
#endif
Boxed_Value(const Boxed_Value&) = default;
Boxed_Value& operator=(const Boxed_Value&) = default;
void swap(Boxed_Value &rhs) void swap(Boxed_Value &rhs)
{ {
@@ -172,67 +203,79 @@ namespace chaiscript
return *this; return *this;
} }
/// shared data assignment, same as copy construction const Type_Info &get_type_info() const CHAISCRIPT_NOEXCEPT
Boxed_Value &operator=(const Boxed_Value &rhs)
{
Boxed_Value temp(rhs);
swap(temp);
return *this;
}
const Type_Info &get_type_info() const
{ {
return m_data->m_type_info; return m_data->m_type_info;
} }
/// return true if the object is uninitialized /// return true if the object is uninitialized
bool is_undef() const bool is_undef() const CHAISCRIPT_NOEXCEPT
{ {
return m_data->m_type_info.is_undef(); return m_data->m_type_info.is_undef();
} }
bool is_const() const bool is_const() const CHAISCRIPT_NOEXCEPT
{ {
return m_data->m_type_info.is_const(); return m_data->m_type_info.is_const();
} }
bool is_type(const Type_Info &ti) const bool is_type(const Type_Info &ti) const CHAISCRIPT_NOEXCEPT
{ {
return m_data->m_type_info.bare_equal(ti); return m_data->m_type_info.bare_equal(ti);
} }
bool is_null() const bool is_null() const CHAISCRIPT_NOEXCEPT
{ {
return (m_data->m_data_ptr == nullptr && m_data->m_const_data_ptr == nullptr); return (m_data->m_data_ptr == nullptr && m_data->m_const_data_ptr == nullptr);
} }
const chaiscript::detail::Any & get() const const chaiscript::detail::Any & get() const CHAISCRIPT_NOEXCEPT
{ {
return m_data->m_obj; return m_data->m_obj;
} }
bool is_ref() const bool is_ref() const CHAISCRIPT_NOEXCEPT
{ {
return m_data->m_is_ref; return m_data->m_is_ref;
} }
bool is_pointer() const bool is_pointer() const CHAISCRIPT_NOEXCEPT
{ {
return !is_ref(); return !is_ref();
} }
void *get_ptr() const void *get_ptr() const CHAISCRIPT_NOEXCEPT
{ {
return m_data->m_data_ptr; return m_data->m_data_ptr;
} }
const void *get_const_ptr() const const void *get_const_ptr() const CHAISCRIPT_NOEXCEPT
{ {
return m_data->m_const_data_ptr; return m_data->m_const_data_ptr;
} }
Boxed_Value get_attr(const std::string &t_name)
{
if (!m_data->m_attrs)
{
m_data->m_attrs = std::unique_ptr<std::map<std::string, Boxed_Value>>(new std::map<std::string, Boxed_Value>());
}
return (*m_data->m_attrs)[t_name];
}
Boxed_Value &copy_attrs(const Boxed_Value &t_obj)
{
if (t_obj.m_data->m_attrs)
{
m_data->m_attrs = std::unique_ptr<std::map<std::string, Boxed_Value>>(new std::map<std::string, Boxed_Value>(*t_obj.m_data->m_attrs));
}
return *this;
}
/// \returns true if the two Boxed_Values share the same internal type /// \returns true if the two Boxed_Values share the same internal type
static bool type_match(Boxed_Value l, Boxed_Value r) static bool type_match(const Boxed_Value &l, const Boxed_Value &r) CHAISCRIPT_NOEXCEPT
{ {
return l.get_type_info() == r.get_type_info(); return l.get_type_info() == r.get_type_info();
} }
@@ -269,7 +312,7 @@ namespace chaiscript
template<typename T> template<typename T>
Boxed_Value const_var_impl(const T &t) Boxed_Value const_var_impl(const T &t)
{ {
return Boxed_Value(std::shared_ptr<typename std::add_const<T>::type >(new T(t))); return Boxed_Value(std::make_shared<typename std::add_const<T>::type >(t));
} }
/// \brief Takes a pointer to a value, adds const to the pointed to type and returns an immutable Boxed_Value. /// \brief Takes a pointer to a value, adds const to the pointed to type and returns an immutable Boxed_Value.

View File

@@ -27,7 +27,7 @@
#include "boxed_cast.hpp" #include "boxed_cast.hpp"
#include "boxed_cast_helper.hpp" #include "boxed_cast_helper.hpp"
#include "boxed_value.hpp" #include "boxed_value.hpp"
#include "dynamic_cast_conversion.hpp" #include "type_conversions.hpp"
#include "dynamic_object.hpp" #include "dynamic_object.hpp"
#include "proxy_constructors.hpp" #include "proxy_constructors.hpp"
#include "proxy_functions.hpp" #include "proxy_functions.hpp"
@@ -53,9 +53,7 @@ namespace chaiscript
{ {
namespace exception namespace exception
{ {
/** /// Exception thrown in the case that an object name is invalid because it is a reserved word
* Exception thrown in the case that an object name is invalid because it is a reserved word
*/
class reserved_word_error : public std::runtime_error class reserved_word_error : public std::runtime_error
{ {
public: public:
@@ -75,18 +73,16 @@ namespace chaiscript
std::string m_word; std::string m_word;
}; };
/** /// Exception thrown in the case that an object name is invalid because it contains illegal characters
* Exception thrown in the case that an object name is invalid because it contains illegal characters
*/
class illegal_name_error : public std::runtime_error class illegal_name_error : public std::runtime_error
{ {
public: public:
illegal_name_error(const std::string &t_name) throw() illegal_name_error(const std::string &t_name) CHAISCRIPT_NOEXCEPT
: std::runtime_error("Reserved name not allowed in object name: " + t_name), m_name(t_name) : std::runtime_error("Reserved name not allowed in object name: " + t_name), m_name(t_name)
{ {
} }
virtual ~illegal_name_error() throw() {} virtual ~illegal_name_error() CHAISCRIPT_NOEXCEPT {}
std::string name() const std::string name() const
{ {
@@ -98,18 +94,16 @@ namespace chaiscript
}; };
/** /// Exception thrown in the case that an object name is invalid because it already exists in current context
* Exception thrown in the case that an object name is invalid because it already exists in current context
*/
class name_conflict_error : public std::runtime_error class name_conflict_error : public std::runtime_error
{ {
public: public:
name_conflict_error(const std::string &t_name) throw() name_conflict_error(const std::string &t_name) CHAISCRIPT_NOEXCEPT
: std::runtime_error("Name already exists in current context " + t_name), m_name(t_name) : std::runtime_error("Name already exists in current context " + t_name), m_name(t_name)
{ {
} }
virtual ~name_conflict_error() throw() {} virtual ~name_conflict_error() CHAISCRIPT_NOEXCEPT {}
std::string name() const std::string name() const
{ {
@@ -122,9 +116,7 @@ namespace chaiscript
}; };
/** /// Exception thrown in the case that a non-const object was added as a shared object
* Exception thrown in the case that a non-const object was added as a shared object
*/
class global_non_const : public std::runtime_error class global_non_const : public std::runtime_error
{ {
public: public:
@@ -143,37 +135,37 @@ namespace chaiscript
class Module class Module
{ {
public: public:
Module &add(const Type_Info &ti, const std::string &name) Module &add(Type_Info ti, std::string name)
{ {
m_typeinfos.push_back(std::make_pair(ti, name)); m_typeinfos.emplace_back(std::move(ti), std::move(name));
return *this; return *this;
} }
Module &add(const Dynamic_Cast_Conversion &d) Module &add(Type_Conversion d)
{ {
m_conversions.push_back(d); m_conversions.push_back(std::move(d));
return *this; return *this;
} }
Module &add(const Proxy_Function &f, const std::string &name) Module &add(Proxy_Function f, std::string name)
{ {
m_funcs.push_back(std::make_pair(f, name)); m_funcs.emplace_back(std::move(f), std::move(name));
return *this; return *this;
} }
Module &add_global_const(const Boxed_Value &t_bv, const std::string &t_name) Module &add_global_const(Boxed_Value t_bv, std::string t_name)
{ {
if (!t_bv.is_const()) if (!t_bv.is_const())
{ {
throw chaiscript::exception::global_non_const(); throw chaiscript::exception::global_non_const();
} }
m_globals.push_back(std::make_pair(t_bv, t_name)); m_globals.emplace_back(std::move(t_bv), std::move(t_name));
return *this; return *this;
} }
//Add a bit of chaiscript to eval during module implementation //Add a bit of ChaiScript to eval during module implementation
Module &eval(const std::string &str) Module &eval(const std::string &str)
{ {
m_evals.push_back(str); m_evals.push_back(str);
@@ -205,21 +197,21 @@ namespace chaiscript
std::vector<std::pair<Proxy_Function, std::string> > m_funcs; std::vector<std::pair<Proxy_Function, std::string> > m_funcs;
std::vector<std::pair<Boxed_Value, std::string> > m_globals; std::vector<std::pair<Boxed_Value, std::string> > m_globals;
std::vector<std::string> m_evals; std::vector<std::string> m_evals;
std::vector<Dynamic_Cast_Conversion> m_conversions; std::vector<Type_Conversion> m_conversions;
template<typename T, typename InItr> template<typename T, typename InItr>
static void apply(InItr begin, InItr end, T &t) static void apply(InItr begin, const InItr end, T &t)
{ {
while (begin != end) for_each(begin, end, [&t](typename std::iterator_traits<InItr>::reference obj)
{ {
try { try {
t.add(begin->first, begin->second); t.add(obj.first, obj.second);
} catch (const chaiscript::exception::name_conflict_error &) { } catch (const chaiscript::exception::name_conflict_error &) {
/// \todo Should we throw an error if there's a name conflict /// \todo Should we throw an error if there's a name conflict
/// while applying a module? /// while applying a module?
} }
++begin; }
} );
} }
template<typename T, typename InItr> template<typename T, typename InItr>
@@ -258,24 +250,22 @@ namespace chaiscript
namespace detail namespace detail
{ {
/** /// A Proxy_Function implementation that is able to take
* A Proxy_Function implementation that is able to take /// a vector of Proxy_Functions and perform a dispatch on them. It is
* a vector of Proxy_Functions and perform a dispatch on them. It is /// used specifically in the case of dealing with Function object variables
* used specifically in the case of dealing with Function object variables
*/
class Dispatch_Function : public dispatch::Proxy_Function_Base class Dispatch_Function : public dispatch::Proxy_Function_Base
{ {
public: public:
Dispatch_Function(const std::vector<Proxy_Function> &t_funcs) Dispatch_Function(std::vector<Proxy_Function> t_funcs)
: Proxy_Function_Base(build_type_infos(t_funcs)), : Proxy_Function_Base(build_type_infos(t_funcs), calculate_arity(t_funcs)),
m_funcs(t_funcs) m_funcs(std::move(t_funcs))
{ {
} }
virtual bool operator==(const dispatch::Proxy_Function_Base &rhs) const CHAISCRIPT_OVERRIDE virtual bool operator==(const dispatch::Proxy_Function_Base &rhs) const CHAISCRIPT_OVERRIDE
{ {
try { try {
const Dispatch_Function &dispatchfun = dynamic_cast<const Dispatch_Function &>(rhs); const auto &dispatchfun = dynamic_cast<const Dispatch_Function &>(rhs);
return m_funcs == dispatchfun.m_funcs; return m_funcs == dispatchfun.m_funcs;
} catch (const std::bad_cast &) { } catch (const std::bad_cast &) {
return false; return false;
@@ -290,52 +280,30 @@ namespace chaiscript
} }
virtual int get_arity() const CHAISCRIPT_OVERRIDE static int calculate_arity(const std::vector<Proxy_Function> &t_funcs)
{ {
typedef std::vector<Proxy_Function> function_vec; if (t_funcs.empty()) {
return -1;
auto begin = m_funcs.begin();
const function_vec::const_iterator end = m_funcs.end();
if (begin != end)
{
int arity = (*begin)->get_arity();
++begin;
while (begin != end)
{
if (arity != (*begin)->get_arity())
{
// The arities in the list do not match, so it's unspecified
return -1;
}
++begin;
}
return arity;
} }
return -1; // unknown arity const auto arity = t_funcs.front()->get_arity();
for (const auto &func : t_funcs)
{
if (arity != func->get_arity())
{
// The arities in the list do not match, so it's unspecified
return -1;
}
}
return arity;
} }
virtual bool call_match(const std::vector<Boxed_Value> &vals, const Dynamic_Cast_Conversions &t_conversions) const CHAISCRIPT_OVERRIDE virtual bool call_match(const std::vector<Boxed_Value> &vals, const Type_Conversions &t_conversions) const CHAISCRIPT_OVERRIDE
{ {
auto begin = m_funcs.begin(); return std::any_of(m_funcs.cbegin(), m_funcs.cend(),
auto end = m_funcs.end(); [&vals, &t_conversions](const Proxy_Function &f){ return f->call_match(vals, t_conversions); });
while (begin != end)
{
if ((*begin)->call_match(vals, t_conversions))
{
return true;
} else {
++begin;
}
}
return false;
} }
virtual std::string annotation() const CHAISCRIPT_OVERRIDE virtual std::string annotation() const CHAISCRIPT_OVERRIDE
@@ -344,9 +312,9 @@ namespace chaiscript
} }
protected: protected:
virtual Boxed_Value do_call(const std::vector<Boxed_Value> &params, const Dynamic_Cast_Conversions &t_conversions) const CHAISCRIPT_OVERRIDE virtual Boxed_Value do_call(const std::vector<Boxed_Value> &params, const Type_Conversions &t_conversions) const CHAISCRIPT_OVERRIDE
{ {
return dispatch::dispatch(m_funcs.begin(), m_funcs.end(), params, t_conversions); return dispatch::dispatch(m_funcs, params, t_conversions);
} }
private: private:
@@ -354,10 +322,8 @@ namespace chaiscript
static std::vector<Type_Info> build_type_infos(const std::vector<Proxy_Function> &t_funcs) static std::vector<Type_Info> build_type_infos(const std::vector<Proxy_Function> &t_funcs)
{ {
typedef std::vector<Proxy_Function> function_vec; auto begin = t_funcs.cbegin();
const auto &end = t_funcs.cend();
auto begin = t_funcs.begin();
const function_vec::const_iterator end = t_funcs.end();
if (begin != end) if (begin != end)
{ {
@@ -399,23 +365,20 @@ namespace chaiscript
return std::vector<Type_Info>(); return std::vector<Type_Info>();
} }
}; };
} }
namespace detail namespace detail
{ {
/** /// Main class for the dispatchkit. Handles management
* Main class for the dispatchkit. Handles management /// of the object stack, functions and registered types.
* of the object stack, functions and registered types.
*/
class Dispatch_Engine class Dispatch_Engine
{ {
public: public:
typedef std::map<std::string, chaiscript::Type_Info> Type_Name_Map; typedef std::map<std::string, chaiscript::Type_Info> Type_Name_Map;
typedef std::map<std::string, Boxed_Value> Scope; typedef std::map<std::string, Boxed_Value> Scope;
typedef std::deque<Scope> StackData; typedef std::vector<Scope> StackData;
typedef std::shared_ptr<StackData> Stack;
struct State struct State
{ {
@@ -430,8 +393,7 @@ namespace chaiscript
Dispatch_Engine() Dispatch_Engine()
: m_stack_holder(this), : m_stack_holder(this),
m_place_holder(std::shared_ptr<dispatch::Placeholder_Object>(new dispatch::Placeholder_Object())) m_place_holder(std::make_shared<dispatch::Placeholder_Object>())
{ {
} }
@@ -446,67 +408,56 @@ namespace chaiscript
return chaiscript::boxed_cast<Type>(bv, &m_conversions); return chaiscript::boxed_cast<Type>(bv, &m_conversions);
} }
/** /// Add a new conversion for upcasting to a base class
* Add a new conversion for upcasting to a base class void add(const Type_Conversion &d)
*/
void add(const Dynamic_Cast_Conversion &d)
{ {
m_conversions.add_conversion(d); m_conversions.add_conversion(d);
} }
/** /// Add a new named Proxy_Function to the system
* Add a new named Proxy_Function to the system
*/
void add(const Proxy_Function &f, const std::string &name) void add(const Proxy_Function &f, const std::string &name)
{ {
validate_object_name(name); validate_object_name(name);
add_function(f, name); add_function(f, name);
} }
/** /// Set the value of an object, by name. If the object
* Set the value of an object, by name. If the object /// is not available in the current scope it is created
* is not available in the current scope it is created
*/
void add(const Boxed_Value &obj, const std::string &name) void add(const Boxed_Value &obj, const std::string &name)
{ {
validate_object_name(name); validate_object_name(name);
StackData &stack = get_stack_data(); auto &stack = get_stack_data();
for (int i = static_cast<int>(stack.size())-1; i >= 0; --i) for (auto stack_elem = stack.rbegin(); stack_elem != stack.rend(); ++stack_elem)
{ {
std::map<std::string, Boxed_Value>::const_iterator itr = stack[i].find(name); auto itr = stack_elem->find(name);
if (itr != stack[i].end()) if (itr != stack_elem->end())
{ {
stack[i][name] = obj; itr->second = std::move(obj);
return; return;
} }
} }
add_object(name, obj); add_object(name, std::move(obj));
} }
/** /// Adds a named object to the current scope
* Adds a named object to the current scope
*/
void add_object(const std::string &name, const Boxed_Value &obj) const void add_object(const std::string &name, const Boxed_Value &obj) const
{ {
StackData &stack = get_stack_data(); auto &stack = get_stack_data();
validate_object_name(name); validate_object_name(name);
Scope &scope = stack.back(); auto &scope = stack.back();
auto itr = scope.find(name); if (scope.find(name) != scope.end())
if (itr != stack.back().end())
{ {
throw chaiscript::exception::name_conflict_error(name); throw chaiscript::exception::name_conflict_error(name);
} else { } else {
stack.back().insert(std::make_pair(name, obj)); scope.insert(std::make_pair(name, obj));
} }
} }
/** /// Adds a new global shared object, between all the threads
* Adds a new global shared object, between all the threads
*/
void add_global_const(const Boxed_Value &obj, const std::string &name) void add_global_const(const Boxed_Value &obj, const std::string &name)
{ {
validate_object_name(name); validate_object_name(name);
@@ -526,9 +477,7 @@ namespace chaiscript
} }
/** /// Adds a new global (non-const) shared object, between all the threads
* Adds a new global (non-const) shared object, between all the threads
*/
void add_global(const Boxed_Value &obj, const std::string &name) void add_global(const Boxed_Value &obj, const std::string &name)
{ {
validate_object_name(name); validate_object_name(name);
@@ -544,18 +493,13 @@ namespace chaiscript
} }
/** /// Adds a new scope to the stack
* Adds a new scope to the stack
*/
void new_scope() void new_scope()
{ {
StackData &stack = get_stack_data(); get_stack_data().emplace_back();
stack.push_back(Scope());
} }
/** /// Pops the current scope from the stack
* Pops the current scope from the stack
*/
void pop_scope() void pop_scope()
{ {
StackData &stack = get_stack_data(); StackData &stack = get_stack_data();
@@ -571,9 +515,8 @@ namespace chaiscript
/// Pushes a new stack on to the list of stacks /// Pushes a new stack on to the list of stacks
void new_stack() void new_stack()
{ {
Stack s(new Stack::element_type()); // add a new Stack with 1 element
s->push_back(Scope()); m_stack_holder->stacks.emplace_back(1);
m_stack_holder->stacks.push_back(s);
} }
void pop_stack() void pop_stack()
@@ -581,17 +524,9 @@ namespace chaiscript
m_stack_holder->stacks.pop_back(); m_stack_holder->stacks.pop_back();
} }
/// \returns the current stack /// Searches the current stack for an object of the given name
Stack get_stack() const /// includes a special overload for the _ place holder object to
{ /// ensure that it is always in scope.
return m_stack_holder->stacks.back();
}
/**
* Searches the current stack for an object of the given name
* includes a special overload for the _ place holder object to
* ensure that it is always in scope.
*/
Boxed_Value get_object(const std::string &name) const Boxed_Value get_object(const std::string &name) const
{ {
// Is it a placeholder object? // Is it a placeholder object?
@@ -600,13 +535,13 @@ namespace chaiscript
return m_place_holder; return m_place_holder;
} }
StackData &stack = get_stack_data(); auto &stack = get_stack_data();
// Is it in the stack? // Is it in the stack?
for (int i = static_cast<int>(stack.size())-1; i >= 0; --i) for (auto stack_elem = stack.rbegin(); stack_elem != stack.rend(); ++stack_elem)
{ {
std::map<std::string, Boxed_Value>::const_iterator stackitr = stack[i].find(name); const auto stackitr = stack_elem->find(name);
if (stackitr != stack[i].end()) if (stackitr != stack_elem->end())
{ {
return stackitr->second; return stackitr->second;
} }
@@ -616,7 +551,7 @@ namespace chaiscript
{ {
chaiscript::detail::threading::shared_lock<chaiscript::detail::threading::shared_mutex> l(m_global_object_mutex); chaiscript::detail::threading::shared_lock<chaiscript::detail::threading::shared_mutex> l(m_global_object_mutex);
auto itr = m_state.m_global_objects.find(name); const auto itr = m_state.m_global_objects.find(name);
if (itr != m_state.m_global_objects.end()) if (itr != m_state.m_global_objects.end())
{ {
return itr->second; return itr->second;
@@ -627,9 +562,7 @@ namespace chaiscript
return get_function_object(name); return get_function_object(name);
} }
/** /// Registers a new named type
* Registers a new named type
*/
void add(const Type_Info &ti, const std::string &name) void add(const Type_Info &ti, const std::string &name)
{ {
add_global_const(const_var(ti), name + "_type"); add_global_const(const_var(ti), name + "_type");
@@ -639,14 +572,12 @@ namespace chaiscript
m_state.m_types.insert(std::make_pair(name, ti)); m_state.m_types.insert(std::make_pair(name, ti));
} }
/** /// Returns the type info for a named type
* Returns the type info for a named type
*/
Type_Info get_type(const std::string &name) const Type_Info get_type(const std::string &name) const
{ {
chaiscript::detail::threading::shared_lock<chaiscript::detail::threading::shared_mutex> l(m_mutex); chaiscript::detail::threading::shared_lock<chaiscript::detail::threading::shared_mutex> l(m_mutex);
auto itr = m_state.m_types.find(name); const auto itr = m_state.m_types.find(name);
if (itr != m_state.m_types.end()) if (itr != m_state.m_types.end())
{ {
@@ -656,11 +587,9 @@ namespace chaiscript
throw std::range_error("Type Not Known"); throw std::range_error("Type Not Known");
} }
/** /// Returns the registered name of a known type_info object
* Returns the registered name of a known type_info object /// compares the "bare_type_info" for the broadest possible
* compares the "bare_type_info" for the broadest possible /// match
* match
*/
std::string get_type_name(const Type_Info &ti) const std::string get_type_name(const Type_Info &ti) const
{ {
chaiscript::detail::threading::shared_lock<chaiscript::detail::threading::shared_mutex> l(m_mutex); chaiscript::detail::threading::shared_lock<chaiscript::detail::threading::shared_mutex> l(m_mutex);
@@ -676,9 +605,7 @@ namespace chaiscript
return ti.bare_name(); return ti.bare_name();
} }
/** /// Return all registered types
* Return all registered types
*/
std::vector<std::pair<std::string, Type_Info> > get_types() const std::vector<std::pair<std::string, Type_Info> > get_types() const
{ {
chaiscript::detail::threading::shared_lock<chaiscript::detail::threading::shared_mutex> l(m_mutex); chaiscript::detail::threading::shared_lock<chaiscript::detail::threading::shared_mutex> l(m_mutex);
@@ -686,26 +613,22 @@ namespace chaiscript
return std::vector<std::pair<std::string, Type_Info> >(m_state.m_types.begin(), m_state.m_types.end()); return std::vector<std::pair<std::string, Type_Info> >(m_state.m_types.begin(), m_state.m_types.end());
} }
/** /// Return a function by name
* Return a function by name std::vector< Proxy_Function > get_function(const std::string &t_name) const
*/ {
std::vector< Proxy_Function > chaiscript::detail::threading::shared_lock<chaiscript::detail::threading::shared_mutex> l(m_mutex);
get_function(const std::string &t_name) const
const auto &funs = get_functions_int();
auto itr = funs.find(t_name);
if (itr != funs.end())
{ {
chaiscript::detail::threading::shared_lock<chaiscript::detail::threading::shared_mutex> l(m_mutex); return itr->second;
} else {
const std::map<std::string, std::vector<Proxy_Function> > &funs = get_functions_int(); return std::vector<Proxy_Function>();
auto itr
= funs.find(t_name);
if (itr != funs.end())
{
return itr->second;
} else {
return std::vector<Proxy_Function>();
}
} }
}
/// \returns a function object (Boxed_Value wrapper) if it exists /// \returns a function object (Boxed_Value wrapper) if it exists
/// \throws std::range_error if it does not /// \throws std::range_error if it does not
@@ -713,7 +636,7 @@ namespace chaiscript
{ {
chaiscript::detail::threading::shared_lock<chaiscript::detail::threading::shared_mutex> l(m_mutex); chaiscript::detail::threading::shared_lock<chaiscript::detail::threading::shared_mutex> l(m_mutex);
const std::map<std::string, Proxy_Function> &funs = get_function_objects_int(); const auto &funs = get_function_objects_int();
auto itr = funs.find(t_name); auto itr = funs.find(t_name);
@@ -725,22 +648,33 @@ namespace chaiscript
} }
} }
/** /// Return true if a function exists
* Return true if a function exists
*/
bool function_exists(const std::string &name) const bool function_exists(const std::string &name) const
{ {
chaiscript::detail::threading::shared_lock<chaiscript::detail::threading::shared_mutex> l(m_mutex); chaiscript::detail::threading::shared_lock<chaiscript::detail::threading::shared_mutex> l(m_mutex);
const std::map<std::string, std::vector<Proxy_Function> > &functions = get_functions_int(); const auto &functions = get_functions_int();
return functions.find(name) != functions.end(); return functions.find(name) != functions.end();
} }
/// \returns All values in the local thread state in the parent scope, or if it doesn't exist,
/// the current scope.
std::map<std::string, Boxed_Value> get_parent_locals() const
{
auto &stack = get_stack_data();
if (stack.size() > 1)
{
return stack[1];
} else {
return stack[0];
}
}
/// \returns All values in the local thread state, added through the add() function /// \returns All values in the local thread state, added through the add() function
std::map<std::string, Boxed_Value> get_locals() const std::map<std::string, Boxed_Value> get_locals() const
{ {
StackData &stack = get_stack_data(); auto &stack = get_stack_data();
Scope &scope = stack.front(); auto &scope = stack.front();
return scope; return scope;
} }
@@ -751,8 +685,8 @@ namespace chaiscript
/// Any existing locals are removed and the given set of variables is added /// Any existing locals are removed and the given set of variables is added
void set_locals(const std::map<std::string, Boxed_Value> &t_locals) void set_locals(const std::map<std::string, Boxed_Value> &t_locals)
{ {
StackData &stack = get_stack_data(); auto &stack = get_stack_data();
Scope &scope = stack.front(); auto &scope = stack.front();
scope = t_locals; scope = t_locals;
} }
@@ -766,12 +700,11 @@ namespace chaiscript
Stack_Holder &s = *m_stack_holder; Stack_Holder &s = *m_stack_holder;
// We don't want the current context, but one up if it exists // We don't want the current context, but one up if it exists
StackData &stack = (s.stacks.size()==1)?(*(s.stacks.back())):(*s.stacks[s.stacks.size()-2]); StackData &stack = (s.stacks.size()==1)?(s.stacks.back()):(s.stacks[s.stacks.size()-2]);
std::map<std::string, Boxed_Value> retval; std::map<std::string, Boxed_Value> retval;
// note: map insert doesn't overwrite existing values, which is why this works // note: map insert doesn't overwrite existing values, which is why this works
for (auto itr = stack.rbegin(); itr != stack.rend(); ++itr) for (auto itr = stack.rbegin(); itr != stack.rend(); ++itr)
{ {
retval.insert(itr->begin(), itr->end()); retval.insert(itr->begin(), itr->end());
@@ -795,7 +728,7 @@ namespace chaiscript
{ {
chaiscript::detail::threading::shared_lock<chaiscript::detail::threading::shared_mutex> l(m_mutex); chaiscript::detail::threading::shared_lock<chaiscript::detail::threading::shared_mutex> l(m_mutex);
const std::map<std::string, Proxy_Function> &funs = get_function_objects_int(); const auto &funs = get_function_objects_int();
std::map<std::string, Boxed_Value> objs; std::map<std::string, Boxed_Value> objs;
@@ -808,22 +741,20 @@ namespace chaiscript
} }
/** /// Get a vector of all registered functions
* Get a vector of all registered functions
*/
std::vector<std::pair<std::string, Proxy_Function > > get_functions() const std::vector<std::pair<std::string, Proxy_Function > > get_functions() const
{ {
chaiscript::detail::threading::shared_lock<chaiscript::detail::threading::shared_mutex> l(m_mutex); chaiscript::detail::threading::shared_lock<chaiscript::detail::threading::shared_mutex> l(m_mutex);
std::vector<std::pair<std::string, Proxy_Function> > rets; std::vector<std::pair<std::string, Proxy_Function> > rets;
const std::map<std::string, std::vector<Proxy_Function> > &functions = get_functions_int(); const auto &functions = get_functions_int();
for (const auto & function : functions) for (const auto & function : functions)
{ {
for (const auto & internal_func : function.second) for (const auto & internal_func : function.second)
{ {
rets.push_back(std::make_pair(function.first, internal_func)); rets.emplace_back(function.first, internal_func);
} }
} }
@@ -837,16 +768,14 @@ namespace chaiscript
m_state.m_reserved_words.insert(name); m_state.m_reserved_words.insert(name);
} }
const Dynamic_Cast_Conversions &conversions() const const Type_Conversions &conversions() const
{ {
return m_conversions; return m_conversions;
} }
Boxed_Value call_function(const std::string &t_name, const std::vector<Boxed_Value> &params) const Boxed_Value call_function(const std::string &t_name, const std::vector<Boxed_Value> &params) const
{ {
std::vector<Proxy_Function> functions = get_function(t_name); return dispatch::dispatch(get_function(t_name), params, m_conversions);
return dispatch::dispatch(functions.begin(), functions.end(), params, m_conversions);
} }
Boxed_Value call_function(const std::string &t_name) const Boxed_Value call_function(const std::string &t_name) const
@@ -854,40 +783,29 @@ namespace chaiscript
return call_function(t_name, std::vector<Boxed_Value>()); return call_function(t_name, std::vector<Boxed_Value>());
} }
Boxed_Value call_function(const std::string &t_name, const Boxed_Value &p1) const Boxed_Value call_function(const std::string &t_name, Boxed_Value p1) const
{ {
std::vector<Boxed_Value> params; return call_function(t_name, std::vector<Boxed_Value>({std::move(p1)}));
params.push_back(p1);
return call_function(t_name, params);
} }
Boxed_Value call_function(const std::string &t_name, const Boxed_Value &p1, const Boxed_Value &p2) const Boxed_Value call_function(const std::string &t_name, Boxed_Value p1, Boxed_Value p2) const
{ {
std::vector<Boxed_Value> params; return call_function(t_name, std::vector<Boxed_Value>({std::move(p1), std::move(p2)}));
params.push_back(p1);
params.push_back(p2);
return call_function(t_name, params);
} }
/** /// Dump object info to stdout
* Dump object info to stdout
*/
void dump_object(const Boxed_Value &o) const void dump_object(const Boxed_Value &o) const
{ {
std::cout << (o.is_const()?"const ":"") << type_name(o) << std::endl; std::cout << (o.is_const()?"const ":"") << type_name(o) << std::endl;
} }
/** /// Dump type info to stdout
* Dump type info to stdout
*/
void dump_type(const Type_Info &type) const void dump_type(const Type_Info &type) const
{ {
std::cout << (type.is_const()?"const ":"") << get_type_name(type); std::cout << (type.is_const()?"const ":"") << get_type_name(type);
} }
/** /// Dump function to stdout
* Dump function to stdout
*/
void dump_function(const std::pair<const std::string, Proxy_Function > &f) const void dump_function(const std::pair<const std::string, Proxy_Function > &f) const
{ {
std::vector<Type_Info> params = f.second->get_param_types(); std::vector<Type_Info> params = f.second->get_param_types();
@@ -915,25 +833,21 @@ namespace chaiscript
std::cout << ") " << std::endl; std::cout << ") " << std::endl;
} }
/** /// Returns true if a call can be made that consists of the first parameter
* Returns true if a call can be made that consists of the first parameter /// (the function) with the remaining parameters as its arguments.
* (the function) with the remaining parameters as its arguments.
*/
Boxed_Value call_exists(const std::vector<Boxed_Value> &params) Boxed_Value call_exists(const std::vector<Boxed_Value> &params)
{ {
if (params.size() < 1) if (params.empty())
{ {
throw chaiscript::exception::arity_error(static_cast<int>(params.size()), 1); throw chaiscript::exception::arity_error(static_cast<int>(params.size()), 1);
} }
Const_Proxy_Function f = this->boxed_cast<Const_Proxy_Function>(params[0]); const Const_Proxy_Function &f = this->boxed_cast<Const_Proxy_Function>(params[0]);
return Boxed_Value(f->call_match(std::vector<Boxed_Value>(params.begin() + 1, params.end()), m_conversions)); return Boxed_Value(f->call_match(std::vector<Boxed_Value>(params.begin() + 1, params.end()), m_conversions));
} }
/** /// Dump all system info to stdout
* Dump all system info to stdout
*/
void dump_system() const void dump_system() const
{ {
std::cout << "Registered Types: " << std::endl; std::cout << "Registered Types: " << std::endl;
@@ -960,9 +874,7 @@ namespace chaiscript
std::cout << std::endl; std::cout << std::endl;
} }
/** /// return true if the Boxed_Value matches the registered type by name
* return true if the Boxed_Value matches the registered type by name
*/
bool is_type(const Boxed_Value &r, const std::string &user_typename) const bool is_type(const Boxed_Value &r, const std::string &user_typename) const
{ {
try { try {
@@ -1003,6 +915,22 @@ namespace chaiscript
m_state = t_state; m_state = t_state;
} }
void save_function_params(std::initializer_list<Boxed_Value> t_params)
{
Stack_Holder &s = *m_stack_holder;
s.call_params.insert(s.call_params.begin(), std::move(t_params));
}
void save_function_params(std::vector<Boxed_Value> &&t_params)
{
Stack_Holder &s = *m_stack_holder;
for (auto &&param : t_params)
{
s.call_params.insert(s.call_params.begin(), std::move(param));
}
}
void save_function_params(const std::vector<Boxed_Value> &t_params) void save_function_params(const std::vector<Boxed_Value> &t_params)
{ {
Stack_Holder &s = *m_stack_holder; Stack_Holder &s = *m_stack_holder;
@@ -1011,7 +939,15 @@ namespace chaiscript
void new_function_call() void new_function_call()
{ {
Stack_Holder &s = *m_stack_holder;
if (s.call_depth == 0)
{
m_conversions.enable_conversion_saves(true);
}
++m_stack_holder->call_depth; ++m_stack_holder->call_depth;
save_function_params(m_conversions.take_saves());
} }
void pop_function_call() void pop_function_call()
@@ -1026,17 +962,16 @@ namespace chaiscript
/// \todo Critical: this needs to be smarter, memory can expand quickly /// \todo Critical: this needs to be smarter, memory can expand quickly
/// in tight loops involving function calls /// in tight loops involving function calls
s.call_params.clear(); s.call_params.clear();
m_conversions.enable_conversion_saves(false);
} }
} }
private: private:
/** /// Returns the current stack
* Returns the current stack /// make const/non const versions
* make const/non const versions
*/
StackData &get_stack_data() const StackData &get_stack_data() const
{ {
return *(m_stack_holder->stacks.back()); return m_stack_holder->stacks.back();
} }
const std::map<std::string, Proxy_Function> &get_function_objects_int() const const std::map<std::string, Proxy_Function> &get_function_objects_int() const
@@ -1061,17 +996,17 @@ namespace chaiscript
static bool function_less_than(const Proxy_Function &lhs, const Proxy_Function &rhs) static bool function_less_than(const Proxy_Function &lhs, const Proxy_Function &rhs)
{ {
const std::vector<Type_Info> lhsparamtypes = lhs->get_param_types(); const auto &lhsparamtypes = lhs->get_param_types();
const std::vector<Type_Info> rhsparamtypes = rhs->get_param_types(); const auto &rhsparamtypes = rhs->get_param_types();
const size_t lhssize = lhsparamtypes.size(); const auto lhssize = lhsparamtypes.size();
const size_t rhssize = rhsparamtypes.size(); const auto rhssize = rhsparamtypes.size();
const Type_Info boxed_type = user_type<Boxed_Value>(); CHAISCRIPT_CONSTEXPR auto boxed_type = user_type<Boxed_Value>();
const Type_Info boxed_pod_type = user_type<Boxed_Number>(); CHAISCRIPT_CONSTEXPR auto boxed_pod_type = user_type<Boxed_Number>();
std::shared_ptr<const dispatch::Dynamic_Proxy_Function> dynamic_lhs(std::dynamic_pointer_cast<const dispatch::Dynamic_Proxy_Function>(lhs)); auto dynamic_lhs(std::dynamic_pointer_cast<const dispatch::Dynamic_Proxy_Function>(lhs));
std::shared_ptr<const dispatch::Dynamic_Proxy_Function> dynamic_rhs(std::dynamic_pointer_cast<const dispatch::Dynamic_Proxy_Function>(rhs)); auto dynamic_rhs(std::dynamic_pointer_cast<const dispatch::Dynamic_Proxy_Function>(rhs));
if (dynamic_lhs && dynamic_rhs) if (dynamic_lhs && dynamic_rhs)
{ {
@@ -1099,11 +1034,10 @@ namespace chaiscript
} }
for (size_t i = 1; i < lhssize && i < rhssize; ++i) for (size_t i = 1; i < lhssize && i < rhssize; ++i)
{ {
const Type_Info lt = lhsparamtypes[i]; const Type_Info &lt = lhsparamtypes[i];
const Type_Info rt = rhsparamtypes[i]; const Type_Info &rt = rhsparamtypes[i];
if (lt.bare_equal(rt) && lt.is_const() == rt.is_const()) if (lt.bare_equal(rt) && lt.is_const() == rt.is_const())
{ {
@@ -1154,9 +1088,7 @@ namespace chaiscript
} }
/** /// Throw a reserved_word exception if the name is not allowed
* Throw a reserved_word exception if the name is not allowed
*/
void validate_object_name(const std::string &name) const void validate_object_name(const std::string &name) const
{ {
if (name.find("::") != std::string::npos) { if (name.find("::") != std::string::npos) {
@@ -1171,29 +1103,24 @@ namespace chaiscript
} }
} }
/** /// Implementation detail for adding a function.
* Implementation detail for adding a function. /// \throws exception::name_conflict_error if there's a function matching the given one being added
* \throws exception::name_conflict_error if there's a function matching the given one being added
*/
void add_function(const Proxy_Function &t_f, const std::string &t_name) void add_function(const Proxy_Function &t_f, const std::string &t_name)
{ {
chaiscript::detail::threading::unique_lock<chaiscript::detail::threading::shared_mutex> l(m_mutex); chaiscript::detail::threading::unique_lock<chaiscript::detail::threading::shared_mutex> l(m_mutex);
std::map<std::string, std::vector<Proxy_Function> > &funcs = get_functions_int(); auto &funcs = get_functions_int();
auto itr auto itr = funcs.find(t_name);
= funcs.find(t_name);
std::map<std::string, Proxy_Function> &func_objs = get_function_objects_int(); auto &func_objs = get_function_objects_int();
if (itr != funcs.end()) if (itr != funcs.end())
{ {
std::vector<Proxy_Function> &vec = itr->second; auto &vec = itr->second;
for (std::vector<Proxy_Function>::const_iterator itr2 = vec.begin(); for (const auto &func : vec)
itr2 != vec.end();
++itr2)
{ {
if ((*t_f) == *(*itr2)) if ((*t_f) == *(func))
{ {
throw chaiscript::exception::name_conflict_error(t_name); throw chaiscript::exception::name_conflict_error(t_name);
} }
@@ -1201,19 +1128,16 @@ namespace chaiscript
vec.push_back(t_f); vec.push_back(t_f);
std::stable_sort(vec.begin(), vec.end(), &function_less_than); std::stable_sort(vec.begin(), vec.end(), &function_less_than);
func_objs[t_name] = Proxy_Function(new Dispatch_Function(vec)); func_objs[t_name] = std::make_shared<Dispatch_Function>(vec);
} else if (t_f->has_arithmetic_param()) { } else if (t_f->has_arithmetic_param()) {
// if the function is the only function but it also contains // if the function is the only function but it also contains
// arithmetic operators, we must wrap it in a dispatch function // arithmetic operators, we must wrap it in a dispatch function
// to allow for automatic arithmetic type conversions // to allow for automatic arithmetic type conversions
std::vector<Proxy_Function> vec; std::vector<Proxy_Function> vec({t_f});
vec.push_back(t_f);
funcs.insert(std::make_pair(t_name, vec)); funcs.insert(std::make_pair(t_name, vec));
func_objs[t_name] = Proxy_Function(new Dispatch_Function(vec)); func_objs[t_name] = std::make_shared<Dispatch_Function>(std::move(vec));
} else { } else {
std::vector<Proxy_Function> vec; funcs.insert(std::make_pair(t_name, std::vector<Proxy_Function>{t_f}));
vec.push_back(t_f);
funcs.insert(std::make_pair(t_name, vec));
func_objs[t_name] = t_f; func_objs[t_name] = t_f;
} }
@@ -1228,18 +1152,16 @@ namespace chaiscript
Stack_Holder() Stack_Holder()
: call_depth(0) : call_depth(0)
{ {
Stack s(new StackData()); stacks.emplace_back(1);
s->push_back(Scope());
stacks.push_back(s);
} }
std::deque<Stack> stacks; std::deque<StackData> stacks;
std::list<Boxed_Value> call_params; std::list<Boxed_Value> call_params;
int call_depth; int call_depth;
}; };
Dynamic_Cast_Conversions m_conversions; Type_Conversions m_conversions;
chaiscript::detail::threading::Thread_Storage<Stack_Holder> m_stack_holder; chaiscript::detail::threading::Thread_Storage<Stack_Holder> m_stack_holder;

View File

@@ -1,294 +0,0 @@
// This file is distributed under the BSD License.
// See "license.txt" for details.
// Copyright 2009-2012, Jonathan Turner (jonathan@emptycrate.com)
// Copyright 2009-2014, Jason Turner (jason@emptycrate.com)
// http://www.chaiscript.com
#ifndef CHAISCRIPT_DYNAMIC_CAST_CONVERSION_HPP_
#define CHAISCRIPT_DYNAMIC_CAST_CONVERSION_HPP_
#include <memory>
#include <set>
#include <stdexcept>
#include <string>
#include <type_traits>
#include <typeinfo>
#include "../chaiscript_threading.hpp"
#include "bad_boxed_cast.hpp"
#include "boxed_cast_helper.hpp"
#include "boxed_value.hpp"
#include "type_info.hpp"
namespace chaiscript
{
namespace exception
{
class bad_boxed_dynamic_cast : public bad_boxed_cast
{
public:
bad_boxed_dynamic_cast(const Type_Info &t_from, const std::type_info &t_to,
const std::string &t_what) CHAISCRIPT_NOEXCEPT
: bad_boxed_cast(t_from, t_to, t_what)
{
}
bad_boxed_dynamic_cast(const Type_Info &t_from, const std::type_info &t_to) CHAISCRIPT_NOEXCEPT
: bad_boxed_cast(t_from, t_to)
{
}
bad_boxed_dynamic_cast(const std::string &w) CHAISCRIPT_NOEXCEPT
: bad_boxed_cast(w)
{
}
virtual ~bad_boxed_dynamic_cast() CHAISCRIPT_NOEXCEPT {}
};
}
namespace detail
{
class Dynamic_Conversion
{
public:
virtual Boxed_Value convert(const Boxed_Value &derived) const = 0;
virtual Boxed_Value convert_down(const Boxed_Value &base) const = 0;
const Type_Info &base() const
{
return m_base;
}
const Type_Info &derived() const
{
return m_derived;
}
protected:
Dynamic_Conversion(const Type_Info &t_base, const Type_Info &t_derived)
: m_base(t_base), m_derived(t_derived)
{
}
virtual ~Dynamic_Conversion() {}
private:
Type_Info m_base;
Type_Info m_derived;
};
template<typename From, typename To>
class Dynamic_Caster
{
public:
static Boxed_Value cast(const Boxed_Value &t_from)
{
if (t_from.get_type_info().bare_equal(user_type<From>()))
{
if (t_from.is_pointer())
{
// Dynamic cast out the contained boxed value, which we know is the type we want
if (t_from.is_const())
{
std::shared_ptr<const To> data
= std::dynamic_pointer_cast<const To>(detail::Cast_Helper<std::shared_ptr<const From> >::cast(t_from, nullptr));
if (!data)
{
throw std::bad_cast();
}
return Boxed_Value(data);
} else {
std::shared_ptr<To> data
= std::dynamic_pointer_cast<To>(detail::Cast_Helper<std::shared_ptr<From> >::cast(t_from, nullptr));
if (!data)
{
throw std::bad_cast();
}
return Boxed_Value(data);
}
} else {
// Pull the reference out of the contained boxed value, which we know is the type we want
if (t_from.is_const())
{
const From &d = detail::Cast_Helper<const From &>::cast(t_from, nullptr);
const To &data = dynamic_cast<const To &>(d);
return Boxed_Value(std::cref(data));
} else {
From &d = detail::Cast_Helper<From &>::cast(t_from, nullptr);
To &data = dynamic_cast<To &>(d);
return Boxed_Value(std::ref(data));
}
}
} else {
throw chaiscript::exception::bad_boxed_dynamic_cast(t_from.get_type_info(), typeid(To), "Unknown dynamic_cast_conversion");
}
}
};
template<typename Base, typename Derived>
class Dynamic_Conversion_Impl : public Dynamic_Conversion
{
public:
Dynamic_Conversion_Impl()
: Dynamic_Conversion(user_type<Base>(), user_type<Derived>())
{
}
virtual Boxed_Value convert_down(const Boxed_Value &t_base) const CHAISCRIPT_OVERRIDE
{
return Dynamic_Caster<Base, Derived>::cast(t_base);
}
virtual Boxed_Value convert(const Boxed_Value &t_derived) const CHAISCRIPT_OVERRIDE
{
return Dynamic_Caster<Derived, Base>::cast(t_derived);
}
};
}
class Dynamic_Cast_Conversions
{
public:
Dynamic_Cast_Conversions()
{
}
Dynamic_Cast_Conversions(const Dynamic_Cast_Conversions &t_other)
: m_conversions(t_other.get_conversions())
{
}
void add_conversion(const std::shared_ptr<detail::Dynamic_Conversion> &conversion)
{
chaiscript::detail::threading::unique_lock<chaiscript::detail::threading::shared_mutex> l(m_mutex);
m_conversions.insert(conversion);
}
template<typename Base, typename Derived>
bool dynamic_cast_converts() const
{
return dynamic_cast_converts(user_type<Base>(), user_type<Derived>());
}
bool dynamic_cast_converts(const Type_Info &base, const Type_Info &derived) const
{
return has_conversion(base, derived) || has_conversion(derived, base);
}
template<typename Base>
Boxed_Value boxed_dynamic_cast(const Boxed_Value &derived) const
{
try {
return get_conversion(user_type<Base>(), derived.get_type_info())->convert(derived);
} catch (const std::out_of_range &) {
throw exception::bad_boxed_dynamic_cast(derived.get_type_info(), typeid(Base), "No known conversion");
} catch (const std::bad_cast &) {
throw exception::bad_boxed_dynamic_cast(derived.get_type_info(), typeid(Base), "Unable to perform dynamic_cast operation");
}
}
template<typename Derived>
Boxed_Value boxed_dynamic_down_cast(const Boxed_Value &base) const
{
try {
return get_conversion(base.get_type_info(), user_type<Derived>())->convert_down(base);
} catch (const std::out_of_range &) {
throw exception::bad_boxed_dynamic_cast(base.get_type_info(), typeid(Derived), "No known conversion");
} catch (const std::bad_cast &) {
throw exception::bad_boxed_dynamic_cast(base.get_type_info(), typeid(Derived), "Unable to perform dynamic_cast operation");
}
}
bool has_conversion(const Type_Info &base, const Type_Info &derived) const
{
chaiscript::detail::threading::shared_lock<chaiscript::detail::threading::shared_mutex> l(m_mutex);
return find(base, derived) != m_conversions.end();
}
std::shared_ptr<detail::Dynamic_Conversion> get_conversion(const Type_Info &base, const Type_Info &derived) const
{
chaiscript::detail::threading::shared_lock<chaiscript::detail::threading::shared_mutex> l(m_mutex);
auto itr =
find(base, derived);
if (itr != m_conversions.end())
{
return *itr;
} else {
throw std::out_of_range("No such conversion exists from " + derived.bare_name() + " to " + base.bare_name());
}
}
private:
std::set<std::shared_ptr<detail::Dynamic_Conversion> >::const_iterator find(
const Type_Info &base, const Type_Info &derived) const
{
for (auto itr = m_conversions.begin();
itr != m_conversions.end();
++itr)
{
if ((*itr)->base().bare_equal(base) && (*itr)->derived().bare_equal(derived))
{
return itr;
}
}
return m_conversions.end();
}
std::set<std::shared_ptr<detail::Dynamic_Conversion> > get_conversions() const
{
chaiscript::detail::threading::shared_lock<chaiscript::detail::threading::shared_mutex> l(m_mutex);
return m_conversions;
}
mutable chaiscript::detail::threading::shared_mutex m_mutex;
std::set<std::shared_ptr<detail::Dynamic_Conversion> > m_conversions;
};
typedef std::shared_ptr<chaiscript::detail::Dynamic_Conversion> Dynamic_Cast_Conversion;
/// \brief Used to register a base / parent class relationship with ChaiScript. Necessary if you
/// want automatic conversions up your inheritance hierarchy.
///
/// Create a new base class registration for applying to a module or to the chaiscript engine
/// Currently, due to limitations in module loading on Windows, and for the sake of portability,
/// if you have a type that is introduced in a loadable module and is used by multiple modules
/// (through a tertiary dll that is shared between the modules, static linking the new type
/// into both loadable modules would not be portable), you need to register the base type
/// relationship in all modules that use the newly added type in a polymorphic way.
///
/// Example:
/// \code
/// class Base
/// {};
/// class Derived : public Base
/// {};
///
/// chaiscript::ChaiScript chai;
/// chai.add(chaiscript::base_class<Base, Derived>());
/// \endcode
///
template<typename Base, typename Derived>
Dynamic_Cast_Conversion base_class()
{
//Can only be used with related polymorphic types
//may be expanded some day to support conversions other than child -> parent
static_assert(std::is_base_of<Base,Derived>::value, "Classes are not related by inheritance");
static_assert(std::is_polymorphic<Base>::value, "Base class must be polymorphic");
static_assert(std::is_polymorphic<Derived>::value, "Derived class must be polymorphic");
return std::shared_ptr<detail::Dynamic_Conversion>(new detail::Dynamic_Conversion_Impl<Base, Derived>());
}
}
#endif

View File

@@ -23,7 +23,7 @@
#include "type_info.hpp" #include "type_info.hpp"
namespace chaiscript { namespace chaiscript {
class Dynamic_Cast_Conversions; class Type_Conversions;
namespace dispatch { namespace dispatch {
class Proxy_Function_Base; class Proxy_Function_Base;
} // namespace dispatch } // namespace dispatch
@@ -64,18 +64,16 @@ namespace chaiscript
namespace detail namespace detail
{ {
/** /// A Proxy_Function implementation designed for calling a function
* A Proxy_Function implementation designed for calling a function /// that is automatically guarded based on the first param based on the
* that is automatically guarded based on the first param based on the /// param's type name
* param's type name
*/
class Dynamic_Object_Function : public Proxy_Function_Base class Dynamic_Object_Function : public Proxy_Function_Base
{ {
public: public:
Dynamic_Object_Function( Dynamic_Object_Function(
std::string t_type_name, std::string t_type_name,
const Proxy_Function &t_func) const Proxy_Function &t_func)
: Proxy_Function_Base(t_func->get_param_types()), : Proxy_Function_Base(t_func->get_param_types(), t_func->get_arity()),
m_type_name(std::move(t_type_name)), m_func(t_func), m_doti(user_type<Dynamic_Object>()) m_type_name(std::move(t_type_name)), m_func(t_func), m_doti(user_type<Dynamic_Object>())
{ {
assert( (t_func->get_arity() > 0 || t_func->get_arity() < 0) assert( (t_func->get_arity() > 0 || t_func->get_arity() < 0)
@@ -86,7 +84,7 @@ namespace chaiscript
std::string t_type_name, std::string t_type_name,
const Proxy_Function &t_func, const Proxy_Function &t_func,
const Type_Info &t_ti) const Type_Info &t_ti)
: Proxy_Function_Base(build_param_types(t_func->get_param_types(), t_ti)), : Proxy_Function_Base(build_param_types(t_func->get_param_types(), t_ti), t_func->get_arity()),
m_type_name(std::move(t_type_name)), m_func(t_func), m_ti(new Type_Info(t_ti)), m_doti(user_type<Dynamic_Object>()) m_type_name(std::move(t_type_name)), m_func(t_func), m_ti(new Type_Info(t_ti)), m_doti(user_type<Dynamic_Object>())
{ {
assert( (t_func->get_arity() > 0 || t_func->get_arity() < 0) assert( (t_func->get_arity() > 0 || t_func->get_arity() < 0)
@@ -96,11 +94,11 @@ namespace chaiscript
virtual ~Dynamic_Object_Function() {} virtual ~Dynamic_Object_Function() {}
Dynamic_Object_Function &operator=(const Dynamic_Object_Function) = delete; Dynamic_Object_Function &operator=(const Dynamic_Object_Function) = delete;
Dynamic_Object_Function(Dynamic_Object_Function &) = delete;
virtual bool operator==(const Proxy_Function_Base &f) const CHAISCRIPT_OVERRIDE virtual bool operator==(const Proxy_Function_Base &f) const CHAISCRIPT_OVERRIDE
{ {
const Dynamic_Object_Function *df = dynamic_cast<const Dynamic_Object_Function *>(&f); if (const auto *df = dynamic_cast<const Dynamic_Object_Function *>(&f))
if (df)
{ {
return df->m_type_name == m_type_name && (*df->m_func) == (*m_func); return df->m_type_name == m_type_name && (*df->m_func) == (*m_func);
} else { } else {
@@ -108,7 +106,7 @@ namespace chaiscript
} }
} }
virtual bool call_match(const std::vector<Boxed_Value> &vals, const Dynamic_Cast_Conversions &t_conversions) const CHAISCRIPT_OVERRIDE virtual bool call_match(const std::vector<Boxed_Value> &vals, const Type_Conversions &t_conversions) const CHAISCRIPT_OVERRIDE
{ {
if (dynamic_object_typename_match(vals, m_type_name, m_ti, t_conversions)) if (dynamic_object_typename_match(vals, m_type_name, m_ti, t_conversions))
{ {
@@ -123,12 +121,6 @@ namespace chaiscript
return {m_func}; return {m_func};
} }
virtual int get_arity() const CHAISCRIPT_OVERRIDE
{
return m_func->get_arity();
}
virtual std::string annotation() const CHAISCRIPT_OVERRIDE virtual std::string annotation() const CHAISCRIPT_OVERRIDE
{ {
return m_func->annotation(); return m_func->annotation();
@@ -136,7 +128,7 @@ namespace chaiscript
protected: protected:
virtual Boxed_Value do_call(const std::vector<Boxed_Value> &params, const Dynamic_Cast_Conversions &t_conversions) const CHAISCRIPT_OVERRIDE virtual Boxed_Value do_call(const std::vector<Boxed_Value> &params, const Type_Conversions &t_conversions) const CHAISCRIPT_OVERRIDE
{ {
if (dynamic_object_typename_match(params, m_type_name, m_ti, t_conversions)) if (dynamic_object_typename_match(params, m_type_name, m_ti, t_conversions))
{ {
@@ -146,7 +138,7 @@ namespace chaiscript
} }
} }
virtual bool compare_first_type(const Boxed_Value &bv, const Dynamic_Cast_Conversions &t_conversions) const CHAISCRIPT_OVERRIDE virtual bool compare_first_type(const Boxed_Value &bv, const Type_Conversions &t_conversions) const CHAISCRIPT_OVERRIDE
{ {
return dynamic_object_typename_match(bv, m_type_name, m_ti, t_conversions); return dynamic_object_typename_match(bv, m_type_name, m_ti, t_conversions);
} }
@@ -164,7 +156,7 @@ namespace chaiscript
} }
bool dynamic_object_typename_match(const Boxed_Value &bv, const std::string &name, bool dynamic_object_typename_match(const Boxed_Value &bv, const std::string &name,
const std::shared_ptr<Type_Info> &ti, const Dynamic_Cast_Conversions &t_conversions) const const std::unique_ptr<Type_Info> &ti, const Type_Conversions &t_conversions) const
{ {
if (bv.get_type_info().bare_equal(m_doti)) if (bv.get_type_info().bare_equal(m_doti))
{ {
@@ -186,7 +178,7 @@ namespace chaiscript
} }
bool dynamic_object_typename_match(const std::vector<Boxed_Value> &bvs, const std::string &name, bool dynamic_object_typename_match(const std::vector<Boxed_Value> &bvs, const std::string &name,
const std::shared_ptr<Type_Info> &ti, const Dynamic_Cast_Conversions &t_conversions) const const std::unique_ptr<Type_Info> &ti, const Type_Conversions &t_conversions) const
{ {
if (bvs.size() > 0) if (bvs.size() > 0)
{ {
@@ -198,7 +190,7 @@ namespace chaiscript
std::string m_type_name; std::string m_type_name;
Proxy_Function m_func; Proxy_Function m_func;
std::shared_ptr<Type_Info> m_ti; std::unique_ptr<Type_Info> m_ti;
const Type_Info m_doti; const Type_Info m_doti;
@@ -217,7 +209,7 @@ namespace chaiscript
Dynamic_Object_Constructor( Dynamic_Object_Constructor(
std::string t_type_name, std::string t_type_name,
const Proxy_Function &t_func) const Proxy_Function &t_func)
: Proxy_Function_Base(build_type_list(t_func->get_param_types())), : Proxy_Function_Base(build_type_list(t_func->get_param_types()), t_func->get_arity() - 1),
m_type_name(std::move(t_type_name)), m_func(t_func) m_type_name(std::move(t_type_name)), m_func(t_func)
{ {
assert( (t_func->get_arity() > 0 || t_func->get_arity() < 0) assert( (t_func->get_arity() > 0 || t_func->get_arity() < 0)
@@ -250,33 +242,24 @@ namespace chaiscript
} }
} }
virtual bool call_match(const std::vector<Boxed_Value> &vals, const Dynamic_Cast_Conversions &t_conversions) const CHAISCRIPT_OVERRIDE virtual bool call_match(const std::vector<Boxed_Value> &vals, const Type_Conversions &t_conversions) const CHAISCRIPT_OVERRIDE
{ {
std::vector<Boxed_Value> new_vals; std::vector<Boxed_Value> new_vals{Boxed_Value(Dynamic_Object(m_type_name))};
new_vals.push_back(Boxed_Value(Dynamic_Object(m_type_name)));
new_vals.insert(new_vals.end(), vals.begin(), vals.end()); new_vals.insert(new_vals.end(), vals.begin(), vals.end());
return m_func->call_match(new_vals, t_conversions); return m_func->call_match(new_vals, t_conversions);
} }
virtual int get_arity() const CHAISCRIPT_OVERRIDE
{
// "this" is not considered part of the arity
return m_func->get_arity() - 1;
}
virtual std::string annotation() const CHAISCRIPT_OVERRIDE virtual std::string annotation() const CHAISCRIPT_OVERRIDE
{ {
return m_func->annotation(); return m_func->annotation();
} }
protected: protected:
virtual Boxed_Value do_call(const std::vector<Boxed_Value> &params, const Dynamic_Cast_Conversions &t_conversions) const CHAISCRIPT_OVERRIDE virtual Boxed_Value do_call(const std::vector<Boxed_Value> &params, const Type_Conversions &t_conversions) const CHAISCRIPT_OVERRIDE
{ {
std::vector<Boxed_Value> new_params; auto bv = var(Dynamic_Object(m_type_name));
chaiscript::Boxed_Value bv = var(Dynamic_Object(m_type_name)); std::vector<Boxed_Value> new_params{bv};
new_params.push_back(bv);
new_params.insert(new_params.end(), params.begin(), params.end()); new_params.insert(new_params.end(), params.begin(), params.end());
(*m_func)(new_params, t_conversions); (*m_func)(new_params, t_conversions);

View File

@@ -23,6 +23,7 @@ namespace chaiscript
{ {
namespace detail namespace detail
{ {
/// \todo make this a variadic template
struct Exception_Handler_Base struct Exception_Handler_Base
{ {
virtual void handle(const Boxed_Value &bv, const Dispatch_Engine &t_engine) = 0; virtual void handle(const Boxed_Value &bv, const Dispatch_Engine &t_engine) = 0;

View File

@@ -18,7 +18,7 @@
namespace chaiscript { namespace chaiscript {
class Boxed_Value; class Boxed_Value;
class Dynamic_Cast_Conversions; class Type_Conversions;
namespace detail { namespace detail {
template <typename T> struct Cast_Helper; template <typename T> struct Cast_Helper;
} // namespace detail } // namespace detail
@@ -28,66 +28,56 @@ namespace chaiscript
{ {
namespace dispatch namespace dispatch
{ {
/** /// Build a function caller that knows how to dispatch on a set of functions
* Build a function caller that knows how to dispatch on a set of functions /// example:
* example: /// std::function<void (int)> f =
* std::function<void (int)> f = /// build_function_caller(dispatchkit.get_function("print"));
* build_function_caller(dispatchkit.get_function("print")); /// \returns A std::function object for dispatching
* \returns A std::function object for dispatching /// \param[in] funcs the set of functions to dispatch on.
* \param[in] funcs the set of functions to dispatch on.
*/
template<typename FunctionType> template<typename FunctionType>
std::function<FunctionType> std::function<FunctionType>
functor(const std::vector<Const_Proxy_Function> &funcs, const Dynamic_Cast_Conversions *t_conversions) functor(const std::vector<Const_Proxy_Function> &funcs, const Type_Conversions *t_conversions)
{ {
FunctionType *p=nullptr; FunctionType *p=nullptr;
return detail::build_function_caller_helper(p, funcs, t_conversions); return detail::build_function_caller_helper(p, funcs, t_conversions);
} }
/** /// Build a function caller for a particular Proxy_Function object
* Build a function caller for a particular Proxy_Function object /// useful in the case that a function is being pass out from scripting back
* useful in the case that a function is being pass out from scripting back /// into code
* into code /// example:
* example: /// void my_function(Proxy_Function f)
* void my_function(Proxy_Function f) /// {
* { /// std::function<void (int)> local_f =
* std::function<void (int)> local_f = /// build_function_caller(f);
* build_function_caller(f); /// }
* } /// \returns A std::function object for dispatching
* \returns A std::function object for dispatching /// \param[in] func A function to execute.
* \param[in] func A function to execute.
*/
template<typename FunctionType> template<typename FunctionType>
std::function<FunctionType> std::function<FunctionType>
functor(Const_Proxy_Function func, const Dynamic_Cast_Conversions *t_conversions) functor(Const_Proxy_Function func, const Type_Conversions *t_conversions)
{ {
std::vector<Const_Proxy_Function> funcs; return functor<FunctionType>(std::vector<Const_Proxy_Function>({func}), t_conversions);
funcs.push_back(func);
return functor<FunctionType>(funcs, t_conversions);
} }
/** /// Helper for automatically unboxing a Boxed_Value that contains a function object
* Helper for automatically unboxing a Boxed_Value that contains a function object /// and creating a typesafe C++ function caller from it.
* and creating a typesafe C++ function caller from it.
*/
template<typename FunctionType> template<typename FunctionType>
std::function<FunctionType> std::function<FunctionType>
functor(const Boxed_Value &bv, const Dynamic_Cast_Conversions *t_conversions) functor(const Boxed_Value &bv, const Type_Conversions *t_conversions)
{ {
return functor<FunctionType>(boxed_cast<Const_Proxy_Function >(bv, t_conversions), t_conversions); return functor<FunctionType>(boxed_cast<Const_Proxy_Function >(bv, t_conversions), t_conversions);
} }
} }
namespace detail{ namespace detail{
/** /// Cast helper to handle automatic casting to const std::function &
* Cast helper to handle automatic casting to const std::function &
*/
template<typename Signature> template<typename Signature>
struct Cast_Helper<const std::function<Signature> &> struct Cast_Helper<const std::function<Signature> &>
{ {
typedef std::function<Signature> Result_Type; typedef std::function<Signature> Result_Type;
static Result_Type cast(const Boxed_Value &ob, const Dynamic_Cast_Conversions *t_conversions) static Result_Type cast(const Boxed_Value &ob, const Type_Conversions *t_conversions)
{ {
if (ob.get_type_info().bare_equal(user_type<Const_Proxy_Function>())) if (ob.get_type_info().bare_equal(user_type<Const_Proxy_Function>()))
{ {
@@ -98,15 +88,13 @@ namespace chaiscript
} }
}; };
/** /// Cast helper to handle automatic casting to std::function
* Cast helper to handle automatic casting to std::function
*/
template<typename Signature> template<typename Signature>
struct Cast_Helper<std::function<Signature> > struct Cast_Helper<std::function<Signature> >
{ {
typedef std::function<Signature> Result_Type; typedef std::function<Signature> Result_Type;
static Result_Type cast(const Boxed_Value &ob, const Dynamic_Cast_Conversions *t_conversions) static Result_Type cast(const Boxed_Value &ob, const Type_Conversions *t_conversions)
{ {
if (ob.get_type_info().bare_equal(user_type<Const_Proxy_Function>())) if (ob.get_type_info().bare_equal(user_type<Const_Proxy_Function>()))
{ {
@@ -117,15 +105,13 @@ namespace chaiscript
} }
}; };
/** /// Cast helper to handle automatic casting to const std::function
* Cast helper to handle automatic casting to const std::function
*/
template<typename Signature> template<typename Signature>
struct Cast_Helper<const std::function<Signature> > struct Cast_Helper<const std::function<Signature> >
{ {
typedef std::function<Signature> Result_Type; typedef std::function<Signature> Result_Type;
static Result_Type cast(const Boxed_Value &ob, const Dynamic_Cast_Conversions *t_conversions) static Result_Type cast(const Boxed_Value &ob, const Type_Conversions *t_conversions)
{ {
if (ob.get_type_info().bare_equal(user_type<Const_Proxy_Function>())) if (ob.get_type_info().bare_equal(user_type<Const_Proxy_Function>()))
{ {

View File

@@ -17,7 +17,7 @@
#include "boxed_cast.hpp" #include "boxed_cast.hpp"
#include "boxed_number.hpp" #include "boxed_number.hpp"
#include "boxed_value.hpp" #include "boxed_value.hpp"
#include "dynamic_cast_conversion.hpp" #include "type_conversions.hpp"
#include "proxy_functions.hpp" #include "proxy_functions.hpp"
namespace chaiscript namespace chaiscript
@@ -26,15 +26,13 @@ namespace chaiscript
{ {
namespace detail namespace detail
{ {
/** /// Internal helper class for handling the return
* Internal helper class for handling the return /// value of a build_function_caller
* value of a build_function_caller
*/
template<typename Ret, bool is_arithmetic> template<typename Ret, bool is_arithmetic>
struct Function_Caller_Ret struct Function_Caller_Ret
{ {
static Ret call(const std::vector<Const_Proxy_Function> &t_funcs, static Ret call(const std::vector<Const_Proxy_Function> &t_funcs,
const std::vector<Boxed_Value> &params, const Dynamic_Cast_Conversions &t_conversions) const std::vector<Boxed_Value> &params, const Type_Conversions &t_conversions)
{ {
return boxed_cast<Ret>(dispatch::dispatch(t_funcs, params, t_conversions)); return boxed_cast<Ret>(dispatch::dispatch(t_funcs, params, t_conversions));
} }
@@ -47,7 +45,7 @@ namespace chaiscript
struct Function_Caller_Ret<Ret, true> struct Function_Caller_Ret<Ret, true>
{ {
static Ret call(const std::vector<Const_Proxy_Function> &t_funcs, static Ret call(const std::vector<Const_Proxy_Function> &t_funcs,
const std::vector<Boxed_Value> &params, const Dynamic_Cast_Conversions &t_conversions) const std::vector<Boxed_Value> &params, const Type_Conversions &t_conversions)
{ {
return Boxed_Number(dispatch::dispatch(t_funcs, params, t_conversions)).get_as<Ret>(); return Boxed_Number(dispatch::dispatch(t_funcs, params, t_conversions)).get_as<Ret>();
} }
@@ -61,7 +59,7 @@ namespace chaiscript
struct Function_Caller_Ret<void, false> struct Function_Caller_Ret<void, false>
{ {
static void call(const std::vector<Const_Proxy_Function> &t_funcs, static void call(const std::vector<Const_Proxy_Function> &t_funcs,
const std::vector<Boxed_Value> &params, const Dynamic_Cast_Conversions &t_conversions) const std::vector<Boxed_Value> &params, const Type_Conversions &t_conversions)
{ {
dispatch::dispatch(t_funcs, params, t_conversions); dispatch::dispatch(t_funcs, params, t_conversions);
} }
@@ -73,7 +71,7 @@ namespace chaiscript
template<typename Ret, typename ... Param> template<typename Ret, typename ... Param>
struct Build_Function_Caller_Helper struct Build_Function_Caller_Helper
{ {
Build_Function_Caller_Helper(std::vector<Const_Proxy_Function> t_funcs, const Dynamic_Cast_Conversions &t_conversions) Build_Function_Caller_Helper(std::vector<Const_Proxy_Function> t_funcs, const Type_Conversions &t_conversions)
: m_funcs(std::move(t_funcs)), : m_funcs(std::move(t_funcs)),
m_conversions(t_conversions) m_conversions(t_conversions)
{ {
@@ -81,7 +79,7 @@ namespace chaiscript
Ret operator()(Param...param) Ret operator()(Param...param)
{ {
return Function_Caller_Ret<Ret, std::is_arithmetic<Ret>::value>::call(m_funcs, { return Function_Caller_Ret<Ret, std::is_arithmetic<Ret>::value && !std::is_same<Ret, bool>::value>::call(m_funcs, {
(std::is_reference<Param>::value&&!(std::is_same<chaiscript::Boxed_Value, typename std::remove_const<typename std::remove_reference<Param>::type>::type>::value))?Boxed_Value(std::ref(param)):Boxed_Value(param)... (std::is_reference<Param>::value&&!(std::is_same<chaiscript::Boxed_Value, typename std::remove_const<typename std::remove_reference<Param>::type>::type>::value))?Boxed_Value(std::ref(param)):Boxed_Value(param)...
}, m_conversions }, m_conversions
@@ -90,13 +88,13 @@ namespace chaiscript
} }
std::vector<Const_Proxy_Function> m_funcs; std::vector<Const_Proxy_Function> m_funcs;
Dynamic_Cast_Conversions m_conversions; Type_Conversions m_conversions;
}; };
template<typename Ret, typename ... Params> template<typename Ret, typename ... Params>
std::function<Ret (Params...)> build_function_caller_helper(Ret (Params...), const std::vector<Const_Proxy_Function> &funcs, const Dynamic_Cast_Conversions *t_conversions) std::function<Ret (Params...)> build_function_caller_helper(Ret (Params...), const std::vector<Const_Proxy_Function> &funcs, const Type_Conversions *t_conversions)
{ {
if (funcs.size() == 1) if (funcs.size() == 1)
{ {
@@ -112,7 +110,7 @@ namespace chaiscript
// we cannot make any other guesses or assumptions really, so continuing // we cannot make any other guesses or assumptions really, so continuing
} }
return std::function<Ret (Params...)>(Build_Function_Caller_Helper<Ret, Params...>(funcs, t_conversions?*t_conversions:Dynamic_Cast_Conversions())); return std::function<Ret (Params...)>(Build_Function_Caller_Helper<Ret, Params...>(funcs, t_conversions?*t_conversions:Type_Conversions()));
} }
} }
} }

View File

@@ -48,6 +48,15 @@ namespace chaiscript
} }
}; };
template<typename Ret>
struct Handle_Return<const Ret *>
{
static Boxed_Value handle(const Ret *p)
{
return Boxed_Value(p);
}
};
template<typename Ret> template<typename Ret>
struct Handle_Return<std::shared_ptr<Ret> &> struct Handle_Return<std::shared_ptr<Ret> &>
{ {

View File

@@ -8,6 +8,7 @@
#define CHAISCRIPT_OPERATORS_HPP_ #define CHAISCRIPT_OPERATORS_HPP_
#include "../chaiscript_defines.hpp" #include "../chaiscript_defines.hpp"
#include "register_function.hpp"
namespace chaiscript namespace chaiscript
{ {
@@ -15,442 +16,446 @@ namespace chaiscript
{ {
namespace operators namespace operators
{ {
template<typename Ret, typename L, typename R> namespace detail
Ret assign(L l, R r) {
{ /// \todo make this return a decltype once we drop gcc 4.6
return (l = r); template<typename L, typename R>
} auto assign(L l, R r) -> L&
{
return (l = r);
}
template<typename Ret, typename L, typename R> template<typename L, typename R>
Ret assign_bitwise_and(L l, R r) auto assign_bitwise_and(L l, R r) -> decltype((l &= r))
{ {
return (l &= r); return (l &= r);
} }
template<typename Ret, typename L, typename R> template<typename L, typename R>
Ret assign_xor(L l, R r) auto assign_xor(L l, R r) -> decltype((l^=r))
{ {
return (l ^= r); return (l ^= r);
} }
template<typename Ret, typename L, typename R> template<typename L, typename R>
Ret assign_bitwise_or(L l, R r) auto assign_bitwise_or(L l, R r) -> decltype((l |= r))
{ {
return (l |= r); return (l |= r);
} }
template<typename Ret, typename L, typename R> template<typename L, typename R>
Ret assign_difference(L l, R r) auto assign_difference(L l, R r) -> decltype(( l -= r))
{ {
return (l -= r); return (l -= r);
} }
template<typename Ret, typename L, typename R> template<typename L, typename R>
Ret assign_left_shift(L l, R r) auto assign_left_shift(L l, R r) -> decltype(( l <<= r))
{ {
return (l <<= r); return (l <<= r);
} }
template<typename Ret, typename L, typename R> template<typename L, typename R>
Ret assign_product(L l, R r) auto assign_product(L l, R r) -> decltype(( l *= r ))
{ {
return (l *= r); return (l *= r);
} }
template<typename Ret, typename L, typename R> template<typename L, typename R>
Ret assign_quotient(L l, R r) auto assign_quotient(L l, R r) -> decltype(( l /= r ))
{ {
return (l /= r); return (l /= r);
} }
template<typename Ret, typename L, typename R> template<typename L, typename R>
Ret assign_remainder(L l, R r) auto assign_remainder(L l, R r) -> decltype(( l %= r ))
{ {
return (l %= r); return (l %= r);
} }
template<typename Ret, typename L, typename R> template<typename L, typename R>
Ret assign_right_shift(L l, R r) auto assign_right_shift(L l, R r) -> decltype(( l >>= r))
{ {
return (l >>= r); return (l >>= r);
} }
template<typename Ret, typename L, typename R> /// \todo make this return a decltype once we drop gcc 4.6
Ret assign_sum(L l, R r) template<typename L, typename R>
{ auto assign_sum(L l, R r) -> L&
return (l += r); {
} return (l += r);
}
template<typename Ret, typename L> template<typename L>
Ret prefix_decrement(L l) auto prefix_decrement(L l) -> decltype(( --l ))
{ {
return (--l); return (--l);
} }
template<typename Ret, typename L> template<typename L>
Ret prefix_increment(L l) auto prefix_increment(L l) -> decltype(( ++l ))
{ {
return (++l); return (++l);
} }
template<typename Ret, typename L, typename R> template<typename L, typename R>
Ret equal(L l, R r) auto equal(L l, R r) -> decltype(( l == r ))
{ {
return (l == r); return (l == r);
} }
template<typename Ret, typename L, typename R> template<typename L, typename R>
Ret greater_than(L l, R r) auto greater_than(L l, R r) -> decltype(( l > r ))
{ {
return (l > r); return (l > r);
} }
template<typename Ret, typename L, typename R> template<typename L, typename R>
Ret greater_than_equal(L l, R r) auto greater_than_equal(L l, R r) -> decltype(( l >= r ))
{ {
return (l >= r); return (l >= r);
} }
template<typename Ret, typename L, typename R> template<typename L, typename R>
Ret less_than(L l, R r) auto less_than(L l, R r) -> decltype(( l < r ))
{ {
return (l < r); return (l < r);
} }
template<typename Ret, typename L, typename R> template<typename L, typename R>
Ret less_than_equal(L l, R r) auto less_than_equal(L l, R r) -> decltype(( l <= r ))
{ {
return (l <= r); return (l <= r);
} }
template<typename Ret, typename L> template<typename L>
Ret logical_compliment(L l) auto logical_compliment(L l) -> decltype(( !l ))
{ {
return (!l); return (!l);
} }
template<typename Ret, typename L, typename R> template<typename L, typename R>
Ret not_equal(L l, R r) auto not_equal(L l, R r) -> decltype(( l != r ))
{ {
return (l != r); return (l != r);
} }
template<typename Ret, typename L, typename R> template<typename L, typename R>
Ret addition(L l, R r) auto addition(L l, R r) -> decltype(( l + r ))
{ {
return (l + r); return (l + r);
} }
template<typename Ret, typename L> template<typename L>
Ret unary_plus(L l) auto unary_plus(L l) -> decltype(( +l ))
{ {
return (+l); return (+l);
} }
template<typename Ret, typename L, typename R> template<typename L, typename R>
Ret subtraction(L l, R r) auto subtraction(L l, R r) -> decltype(( l - r ))
{ {
return (l - r); return (l - r);
} }
template<typename Ret, typename L> template<typename L>
Ret unary_minus(L l) auto unary_minus(L l) -> decltype(( -l ))
{ {
#ifdef CHAISCRIPT_MSVC #ifdef CHAISCRIPT_MSVC
#pragma warning(push) #pragma warning(push)
#pragma warning(disable : 4146) #pragma warning(disable : 4146)
return (-l); return (-l);
#pragma warning(pop) #pragma warning(pop)
#else #else
return (-l); return (-l);
#endif #endif
} }
template<typename Ret, typename L, typename R> template<typename L, typename R>
Ret bitwise_and(L l, R r) auto bitwise_and(L l, R r) -> decltype(( l & r ))
{ {
return (l & r); return (l & r);
} }
template<typename Ret, typename L> template<typename L>
Ret bitwise_compliment(L l) auto bitwise_compliment(L l) -> decltype(( ~l ))
{ {
return (~l); return (~l);
} }
template<typename Ret, typename L, typename R> template<typename L, typename R>
Ret bitwise_xor(L l, R r) auto bitwise_xor(L l, R r) -> decltype(( l ^ r ))
{ {
return (l ^ r); return (l ^ r);
} }
template<typename Ret, typename L, typename R> template<typename L, typename R>
Ret bitwise_or(L l, R r) auto bitwise_or(L l, R r) -> decltype(( l | r ))
{ {
return (l | r); return (l | r);
} }
template<typename Ret, typename L, typename R> template<typename L, typename R>
Ret division(L l, R r) auto division(L l, R r) -> decltype(( l / r ))
{ {
return (l / r); return (l / r);
} }
template<typename Ret, typename L, typename R> template<typename L, typename R>
Ret left_shift(L l, R r) auto left_shift(L l, R r) -> decltype(( l << r ))
{ {
return l << r; return l << r;
} }
template<typename Ret, typename L, typename R> template<typename L, typename R>
Ret multiplication(L l, R r) auto multiplication(L l, R r) -> decltype(( l * r ))
{ {
return l * r; return l * r;
} }
template<typename Ret, typename L, typename R> template<typename L, typename R>
Ret remainder(L l, R r) auto remainder(L l, R r) -> decltype(( l % r ))
{ {
return (l % r); return (l % r);
} }
template<typename Ret, typename L, typename R>
Ret right_shift(L l, R r)
{
return (l >> r);
}
template<typename L, typename R>
auto right_shift(L l, R r) -> decltype(( l >> r ))
{
return (l >> r);
}
}
template<typename T> template<typename T>
ModulePtr assign(ModulePtr m = ModulePtr(new Module())) ModulePtr assign(ModulePtr m = ModulePtr(new Module()))
{ {
m->add(fun(&assign<T &, T &, const T&>), "="); m->add(chaiscript::fun(&detail::assign<T &, const T&>), "=");
return m; return m;
} }
template<typename T> template<typename T>
ModulePtr assign_bitwise_and(ModulePtr m = ModulePtr(new Module())) ModulePtr assign_bitwise_and(ModulePtr m = ModulePtr(new Module()))
{ {
m->add(fun(&assign_bitwise_and<T &, T &, const T&>), "&="); m->add(chaiscript::fun(&detail::assign_bitwise_and<T &, const T&>), "&=");
return m; return m;
} }
template<typename T> template<typename T>
ModulePtr assign_xor(ModulePtr m = ModulePtr(new Module())) ModulePtr assign_xor(ModulePtr m = ModulePtr(new Module()))
{ {
m->add(fun(&assign_xor<T &, T &, const T&>), "^="); m->add(chaiscript::fun(&detail::assign_xor<T &, const T&>), "^=");
return m; return m;
} }
template<typename T> template<typename T>
ModulePtr assign_bitwise_or(ModulePtr m = ModulePtr(new Module())) ModulePtr assign_bitwise_or(ModulePtr m = ModulePtr(new Module()))
{ {
m->add(fun(&assign_bitwise_or<T &, T &, const T&>), "|="); m->add(chaiscript::fun(&detail::assign_bitwise_or<T &, const T&>), "|=");
return m; return m;
} }
template<typename T> template<typename T>
ModulePtr assign_difference(ModulePtr m = ModulePtr(new Module())) ModulePtr assign_difference(ModulePtr m = ModulePtr(new Module()))
{ {
m->add(fun(&assign_difference<T &, T &, const T&>), "-="); m->add(chaiscript::fun(&detail::assign_difference<T &, const T&>), "-=");
return m; return m;
} }
template<typename T> template<typename T>
ModulePtr assign_left_shift(ModulePtr m = ModulePtr(new Module())) ModulePtr assign_left_shift(ModulePtr m = ModulePtr(new Module()))
{ {
m->add(fun(&assign_left_shift<T &, T &, const T&>), "<<="); m->add(chaiscript::fun(&detail::assign_left_shift<T &, const T&>), "<<=");
return m; return m;
} }
template<typename T> template<typename T>
ModulePtr assign_product(ModulePtr m = ModulePtr(new Module())) ModulePtr assign_product(ModulePtr m = ModulePtr(new Module()))
{ {
m->add(fun(&assign_product<T &, T &, const T&>), "*="); m->add(chaiscript::fun(&detail::assign_product<T &, const T&>), "*=");
return m; return m;
} }
template<typename T> template<typename T>
ModulePtr assign_quotient(ModulePtr m = ModulePtr(new Module())) ModulePtr assign_quotient(ModulePtr m = ModulePtr(new Module()))
{ {
m->add(fun(&assign_quotient<T &, T &, const T&>), "/="); m->add(chaiscript::fun(&detail::assign_quotient<T &, const T&>), "/=");
return m; return m;
} }
template<typename T> template<typename T>
ModulePtr assign_remainder(ModulePtr m = ModulePtr(new Module())) ModulePtr assign_remainder(ModulePtr m = ModulePtr(new Module()))
{ {
m->add(fun(&assign_remainder<T &, T &, const T&>), "%="); m->add(chaiscript::fun(&detail::assign_remainder<T &, const T&>), "%=");
return m; return m;
} }
template<typename T> template<typename T>
ModulePtr assign_right_shift(ModulePtr m = ModulePtr(new Module())) ModulePtr assign_right_shift(ModulePtr m = ModulePtr(new Module()))
{ {
m->add(fun(&assign_right_shift<T &, T &, const T&>), ">>="); m->add(chaiscript::fun(&detail::assign_right_shift<T &, const T&>), ">>=");
return m; return m;
} }
template<typename T> template<typename T>
ModulePtr assign_sum(ModulePtr m = ModulePtr(new Module())) ModulePtr assign_sum(ModulePtr m = ModulePtr(new Module()))
{ {
m->add(fun(&assign_sum<T &, T &, const T&>), "+="); m->add(chaiscript::fun(&detail::assign_sum<T &, const T&>), "+=");
return m; return m;
} }
template<typename T> template<typename T>
ModulePtr prefix_decrement(ModulePtr m = ModulePtr(new Module())) ModulePtr prefix_decrement(ModulePtr m = ModulePtr(new Module()))
{ {
m->add(fun(&prefix_decrement<T &, T &>), "--"); m->add(chaiscript::fun(&detail::prefix_decrement<T &>), "--");
return m; return m;
} }
template<typename T> template<typename T>
ModulePtr prefix_increment(ModulePtr m = ModulePtr(new Module())) ModulePtr prefix_increment(ModulePtr m = ModulePtr(new Module()))
{ {
m->add(fun(&prefix_increment<T &, T &>), "++"); m->add(chaiscript::fun(&detail::prefix_increment<T &>), "++");
return m; return m;
} }
template<typename T> template<typename T>
ModulePtr equal(ModulePtr m = ModulePtr(new Module())) ModulePtr equal(ModulePtr m = ModulePtr(new Module()))
{ {
m->add(fun(&equal<bool, const T&, const T&>), "=="); m->add(chaiscript::fun(&detail::equal<const T&, const T&>), "==");
return m; return m;
} }
template<typename T> template<typename T>
ModulePtr greater_than(ModulePtr m = ModulePtr(new Module())) ModulePtr greater_than(ModulePtr m = ModulePtr(new Module()))
{ {
m->add(fun(&greater_than<bool, const T&, const T&>), ">"); m->add(chaiscript::fun(&detail::greater_than<const T&, const T&>), ">");
return m; return m;
} }
template<typename T> template<typename T>
ModulePtr greater_than_equal(ModulePtr m = ModulePtr(new Module())) ModulePtr greater_than_equal(ModulePtr m = ModulePtr(new Module()))
{ {
m->add(fun(&greater_than_equal<bool, const T&, const T&>), ">="); m->add(chaiscript::fun(&detail::greater_than_equal<const T&, const T&>), ">=");
return m; return m;
} }
template<typename T> template<typename T>
ModulePtr less_than(ModulePtr m = ModulePtr(new Module())) ModulePtr less_than(ModulePtr m = ModulePtr(new Module()))
{ {
m->add(fun(&less_than<bool, const T&, const T&>), "<"); m->add(chaiscript::fun(&detail::less_than<const T&, const T&>), "<");
return m; return m;
} }
template<typename T> template<typename T>
ModulePtr less_than_equal(ModulePtr m = ModulePtr(new Module())) ModulePtr less_than_equal(ModulePtr m = ModulePtr(new Module()))
{ {
m->add(fun(&less_than_equal<bool, const T&, const T&>), "<="); m->add(chaiscript::fun(&detail::less_than_equal<const T&, const T&>), "<=");
return m; return m;
} }
template<typename T> template<typename T>
ModulePtr logical_compliment(ModulePtr m = ModulePtr(new Module())) ModulePtr logical_compliment(ModulePtr m = ModulePtr(new Module()))
{ {
m->add(fun(&logical_compliment<bool, const T &>), "!"); m->add(chaiscript::fun(&detail::logical_compliment<const T &>), "!");
return m; return m;
} }
template<typename T> template<typename T>
ModulePtr not_equal(ModulePtr m = ModulePtr(new Module())) ModulePtr not_equal(ModulePtr m = ModulePtr(new Module()))
{ {
m->add(fun(&not_equal<bool, const T &, const T &>), "!="); m->add(chaiscript::fun(&detail::not_equal<const T &, const T &>), "!=");
return m; return m;
} }
template<typename T> template<typename T>
ModulePtr addition(ModulePtr m = ModulePtr(new Module())) ModulePtr addition(ModulePtr m = ModulePtr(new Module()))
{ {
m->add(fun(&addition<T, const T &, const T &>), "+"); m->add(chaiscript::fun(&detail::addition<const T &, const T &>), "+");
return m; return m;
} }
template<typename T> template<typename T>
ModulePtr unary_plus(ModulePtr m = ModulePtr(new Module())) ModulePtr unary_plus(ModulePtr m = ModulePtr(new Module()))
{ {
m->add(fun(&unary_plus<T, const T &>), "+"); m->add(chaiscript::fun(&detail::unary_plus<const T &>), "+");
return m; return m;
} }
template<typename T> template<typename T>
ModulePtr subtraction(ModulePtr m = ModulePtr(new Module())) ModulePtr subtraction(ModulePtr m = ModulePtr(new Module()))
{ {
m->add(fun(&subtraction<T, const T &, const T &>), "-"); m->add(chaiscript::fun(&detail::subtraction<const T &, const T &>), "-");
return m; return m;
} }
template<typename T> template<typename T>
ModulePtr unary_minus(ModulePtr m = ModulePtr(new Module())) ModulePtr unary_minus(ModulePtr m = ModulePtr(new Module()))
{ {
m->add(fun(&unary_minus<T, const T &>), "-"); m->add(chaiscript::fun(&detail::unary_minus<const T &>), "-");
return m; return m;
} }
template<typename T> template<typename T>
ModulePtr bitwise_and(ModulePtr m = ModulePtr(new Module())) ModulePtr bitwise_and(ModulePtr m = ModulePtr(new Module()))
{ {
m->add(fun(&bitwise_and<T, const T &, const T &>), "&"); m->add(chaiscript::fun(&detail::bitwise_and<const T &, const T &>), "&");
return m; return m;
} }
template<typename T> template<typename T>
ModulePtr bitwise_compliment(ModulePtr m = ModulePtr(new Module())) ModulePtr bitwise_compliment(ModulePtr m = ModulePtr(new Module()))
{ {
m->add(fun(&bitwise_compliment<T, const T &>), "~"); m->add(chaiscript::fun(&detail::bitwise_compliment<const T &>), "~");
return m; return m;
} }
template<typename T> template<typename T>
ModulePtr bitwise_xor(ModulePtr m = ModulePtr(new Module())) ModulePtr bitwise_xor(ModulePtr m = ModulePtr(new Module()))
{ {
m->add(fun(&bitwise_xor<T, const T &, const T &>), "^"); m->add(chaiscript::fun(&detail::bitwise_xor<const T &, const T &>), "^");
return m; return m;
} }
template<typename T> template<typename T>
ModulePtr bitwise_or(ModulePtr m = ModulePtr(new Module())) ModulePtr bitwise_or(ModulePtr m = ModulePtr(new Module()))
{ {
m->add(fun(&bitwise_or<T, const T &, const T &>), "|"); m->add(chaiscript::fun(&detail::bitwise_or<const T &, const T &>), "|");
return m; return m;
} }
template<typename T> template<typename T>
ModulePtr division(ModulePtr m = ModulePtr(new Module())) ModulePtr division(ModulePtr m = ModulePtr(new Module()))
{ {
m->add(fun(&division<T, const T &, const T &>), "/"); m->add(chaiscript::fun(&detail::division<const T &, const T &>), "/");
return m; return m;
} }
template<typename T> template<typename T>
ModulePtr left_shift(ModulePtr m = ModulePtr(new Module())) ModulePtr left_shift(ModulePtr m = ModulePtr(new Module()))
{ {
m->add(fun(&left_shift<T, const T &, const T &>), "<<"); m->add(chaiscript::fun(&detail::left_shift<const T &, const T &>), "<<");
return m; return m;
} }
template<typename T> template<typename T>
ModulePtr multiplication(ModulePtr m = ModulePtr(new Module())) ModulePtr multiplication(ModulePtr m = ModulePtr(new Module()))
{ {
m->add(fun(&multiplication<T, const T &, const T &>), "*"); m->add(chaiscript::fun(&detail::multiplication<const T &, const T &>), "*");
return m; return m;
} }
template<typename T> template<typename T>
ModulePtr remainder(ModulePtr m = ModulePtr(new Module())) ModulePtr remainder(ModulePtr m = ModulePtr(new Module()))
{ {
m->add(fun(&remainder<T, const T &, const T &>), "%"); m->add(chaiscript::fun(&detail::remainder<const T &, const T &>), "%");
return m; return m;
} }
template<typename T> template<typename T>
ModulePtr right_shift(ModulePtr m = ModulePtr(new Module())) ModulePtr right_shift(ModulePtr m = ModulePtr(new Module()))
{ {
m->add(fun(&right_shift<T, const T &, const T &>), ">>"); m->add(chaiscript::fun(&detail::right_shift<const T &, const T &>), ">>");
return m; return m;
} }
} }

View File

@@ -21,7 +21,7 @@ namespace chaiscript
template<typename Class, typename ... Params> template<typename Class, typename ... Params>
std::shared_ptr<Class> constructor_(Params ... params) std::shared_ptr<Class> constructor_(Params ... params)
{ {
return std::shared_ptr<Class>(new Class(params...)); return std::make_shared<Class>(params...);
} }
template<typename Class, typename ... Params > template<typename Class, typename ... Params >

View File

@@ -26,7 +26,7 @@
#include "type_info.hpp" #include "type_info.hpp"
namespace chaiscript { namespace chaiscript {
class Dynamic_Cast_Conversions; class Type_Conversions;
namespace exception { namespace exception {
class bad_boxed_cast; class bad_boxed_cast;
struct arity_error; struct arity_error;
@@ -55,7 +55,7 @@ namespace chaiscript
public: public:
virtual ~Proxy_Function_Base() {} virtual ~Proxy_Function_Base() {}
Boxed_Value operator()(const std::vector<Boxed_Value> &params, const chaiscript::Dynamic_Cast_Conversions &t_conversions) const Boxed_Value operator()(const std::vector<Boxed_Value> &params, const chaiscript::Type_Conversions &t_conversions) const
{ {
Boxed_Value bv = do_call(params, t_conversions); Boxed_Value bv = do_call(params, t_conversions);
return bv; return bv;
@@ -63,12 +63,12 @@ namespace chaiscript
/// Returns a vector containing all of the types of the parameters the function returns/takes /// Returns a vector containing all of the types of the parameters the function returns/takes
/// if the function is variadic or takes no arguments (arity of 0 or -1), the returned /// if the function is variadic or takes no arguments (arity of 0 or -1), the returned
/// value containes exactly 1 Type_Info object: the return type /// value contains exactly 1 Type_Info object: the return type
/// \returns the types of all parameters. /// \returns the types of all parameters.
const std::vector<Type_Info> &get_param_types() const { return m_types; } const std::vector<Type_Info> &get_param_types() const { return m_types; }
virtual bool operator==(const Proxy_Function_Base &) const = 0; virtual bool operator==(const Proxy_Function_Base &) const = 0;
virtual bool call_match(const std::vector<Boxed_Value> &vals, const Dynamic_Cast_Conversions &t_conversions) const = 0; virtual bool call_match(const std::vector<Boxed_Value> &vals, const Type_Conversions &t_conversions) const = 0;
bool has_arithmetic_param() const bool has_arithmetic_param() const
{ {
@@ -82,15 +82,13 @@ namespace chaiscript
//! Return true if the function is a possible match //! Return true if the function is a possible match
//! to the passed in values //! to the passed in values
bool filter(const std::vector<Boxed_Value> &vals, const Dynamic_Cast_Conversions &t_conversions) const bool filter(const std::vector<Boxed_Value> &vals, const Type_Conversions &t_conversions) const
{ {
int arity = get_arity(); if (m_arity < 0)
if (arity < 0)
{ {
return true; return true;
} else if (size_t(arity) == vals.size()) { } else if (size_t(m_arity) == vals.size()) {
if (arity == 0) if (m_arity == 0)
{ {
return true; return true;
} else { } else {
@@ -102,11 +100,14 @@ namespace chaiscript
} }
/// \returns the number of arguments the function takes or -1 if it is variadic /// \returns the number of arguments the function takes or -1 if it is variadic
virtual int get_arity() const = 0; int get_arity() const
{
return m_arity;
}
virtual std::string annotation() const = 0; virtual std::string annotation() const = 0;
static bool compare_type_to_param(const Type_Info &ti, const Boxed_Value &bv, const Dynamic_Cast_Conversions &t_conversions) static bool compare_type_to_param(const Type_Info &ti, const Boxed_Value &bv, const Type_Conversions &t_conversions)
{ {
if (ti.is_undef() if (ti.is_undef()
|| ti.bare_equal(user_type<Boxed_Value>()) || ti.bare_equal(user_type<Boxed_Value>())
@@ -114,7 +115,7 @@ namespace chaiscript
&& (ti.bare_equal(user_type<Boxed_Number>()) && (ti.bare_equal(user_type<Boxed_Number>())
|| ti.bare_equal(bv.get_type_info()) || ti.bare_equal(bv.get_type_info())
|| bv.get_type_info().bare_equal(user_type<std::shared_ptr<const Proxy_Function_Base> >()) || bv.get_type_info().bare_equal(user_type<std::shared_ptr<const Proxy_Function_Base> >())
|| t_conversions.dynamic_cast_converts(ti, bv.get_type_info()) || t_conversions.converts(ti, bv.get_type_info())
) )
) )
) )
@@ -125,10 +126,10 @@ namespace chaiscript
} }
} }
protected: protected:
virtual Boxed_Value do_call(const std::vector<Boxed_Value> &params, const Dynamic_Cast_Conversions &t_conversions) const = 0; virtual Boxed_Value do_call(const std::vector<Boxed_Value> &params, const Type_Conversions &t_conversions) const = 0;
Proxy_Function_Base(std::vector<Type_Info> t_types) Proxy_Function_Base(std::vector<Type_Info> t_types, int t_arity)
: m_types(std::move(t_types)), m_has_arithmetic_param(false) : m_types(std::move(t_types)), m_has_arithmetic_param(false), m_arity(t_arity)
{ {
for (size_t i = 1; i < m_types.size(); ++i) for (size_t i = 1; i < m_types.size(); ++i)
{ {
@@ -141,7 +142,7 @@ namespace chaiscript
} }
virtual bool compare_first_type(const Boxed_Value &bv, const Dynamic_Cast_Conversions &t_conversions) const virtual bool compare_first_type(const Boxed_Value &bv, const Type_Conversions &t_conversions) const
{ {
const std::vector<Type_Info> &types = get_param_types(); const std::vector<Type_Info> &types = get_param_types();
@@ -175,14 +176,14 @@ namespace chaiscript
std::vector<Type_Info> m_types; std::vector<Type_Info> m_types;
bool m_has_arithmetic_param; bool m_has_arithmetic_param;
int m_arity;
}; };
} }
/// \brief Common typedef used for passing of any registered function in ChaiScript /// \brief Common typedef used for passing of any registered function in ChaiScript
typedef std::shared_ptr<dispatch::Proxy_Function_Base> Proxy_Function; typedef std::shared_ptr<dispatch::Proxy_Function_Base> Proxy_Function;
/// \brief Const version of Proxy_Function chaiscript. Points to a const Proxy_Function. This is how most registered functions /// \brief Const version of Proxy_Function. Points to a const Proxy_Function. This is how most registered functions
/// are handled internally. /// are handled internally.
typedef std::shared_ptr<const dispatch::Proxy_Function_Base> Const_Proxy_Function; typedef std::shared_ptr<const dispatch::Proxy_Function_Base> Const_Proxy_Function;
@@ -216,7 +217,7 @@ namespace chaiscript
AST_NodePtr t_parsenode = AST_NodePtr(), AST_NodePtr t_parsenode = AST_NodePtr(),
std::string t_description = "", std::string t_description = "",
Proxy_Function t_guard = Proxy_Function()) Proxy_Function t_guard = Proxy_Function())
: Proxy_Function_Base(build_param_type_list(t_arity)), : Proxy_Function_Base(build_param_type_list(t_arity), t_arity),
m_f(std::move(t_f)), m_arity(t_arity), m_description(std::move(t_description)), m_guard(std::move(t_guard)), m_parsenode(std::move(t_parsenode)) m_f(std::move(t_f)), m_arity(t_arity), m_description(std::move(t_description)), m_guard(std::move(t_guard)), m_parsenode(std::move(t_parsenode))
{ {
} }
@@ -233,16 +234,12 @@ namespace chaiscript
&& !this->m_guard && !prhs->m_guard); && !this->m_guard && !prhs->m_guard);
} }
virtual bool call_match(const std::vector<Boxed_Value> &vals, const Dynamic_Cast_Conversions &t_conversions) const CHAISCRIPT_OVERRIDE virtual bool call_match(const std::vector<Boxed_Value> &vals, const Type_Conversions &t_conversions) const CHAISCRIPT_OVERRIDE
{ {
return (m_arity < 0 || vals.size() == size_t(m_arity)) return (m_arity < 0 || vals.size() == size_t(m_arity))
&& test_guard(vals, t_conversions); && test_guard(vals, t_conversions);
} }
virtual int get_arity() const CHAISCRIPT_OVERRIDE
{
return m_arity;
}
Proxy_Function get_guard() const Proxy_Function get_guard() const
{ {
@@ -260,7 +257,7 @@ namespace chaiscript
} }
protected: protected:
virtual Boxed_Value do_call(const std::vector<Boxed_Value> &params, const Dynamic_Cast_Conversions &t_conversions) const CHAISCRIPT_OVERRIDE virtual Boxed_Value do_call(const std::vector<Boxed_Value> &params, const Type_Conversions &t_conversions) const CHAISCRIPT_OVERRIDE
{ {
if (m_arity < 0 || params.size() == size_t(m_arity)) if (m_arity < 0 || params.size() == size_t(m_arity))
{ {
@@ -278,7 +275,7 @@ namespace chaiscript
} }
private: private:
bool test_guard(const std::vector<Boxed_Value> &params, const Dynamic_Cast_Conversions &t_conversions) const bool test_guard(const std::vector<Boxed_Value> &params, const Type_Conversions &t_conversions) const
{ {
if (m_guard) if (m_guard)
{ {
@@ -338,8 +335,8 @@ namespace chaiscript
public: public:
Bound_Function(const Const_Proxy_Function &t_f, Bound_Function(const Const_Proxy_Function &t_f,
const std::vector<Boxed_Value> &t_args) const std::vector<Boxed_Value> &t_args)
: Proxy_Function_Base(build_param_type_info(t_f, t_args)), : Proxy_Function_Base(build_param_type_info(t_f, t_args), (t_f->get_arity()<0?-1:static_cast<int>(build_param_type_info(t_f, t_args).size())-1)),
m_f(t_f), m_args(t_args), m_arity(t_f->get_arity()<0?-1:static_cast<int>(get_param_types().size())-1) m_f(t_f), m_args(t_args)
{ {
assert(m_f->get_arity() < 0 || m_f->get_arity() == static_cast<int>(m_args.size())); assert(m_f->get_arity() < 0 || m_f->get_arity() == static_cast<int>(m_args.size()));
} }
@@ -351,7 +348,7 @@ namespace chaiscript
virtual ~Bound_Function() {} virtual ~Bound_Function() {}
virtual bool call_match(const std::vector<Boxed_Value> &vals, const Dynamic_Cast_Conversions &t_conversions) const CHAISCRIPT_OVERRIDE virtual bool call_match(const std::vector<Boxed_Value> &vals, const Type_Conversions &t_conversions) const CHAISCRIPT_OVERRIDE
{ {
return m_f->call_match(build_param_list(vals), t_conversions); return m_f->call_match(build_param_list(vals), t_conversions);
} }
@@ -395,11 +392,6 @@ namespace chaiscript
return args; return args;
} }
virtual int get_arity() const CHAISCRIPT_OVERRIDE
{
return m_arity;
}
virtual std::string annotation() const CHAISCRIPT_OVERRIDE virtual std::string annotation() const CHAISCRIPT_OVERRIDE
{ {
return "Bound: " + m_f->annotation(); return "Bound: " + m_f->annotation();
@@ -429,7 +421,7 @@ namespace chaiscript
return retval; return retval;
} }
virtual Boxed_Value do_call(const std::vector<Boxed_Value> &params, const Dynamic_Cast_Conversions &t_conversions) const CHAISCRIPT_OVERRIDE virtual Boxed_Value do_call(const std::vector<Boxed_Value> &params, const Type_Conversions &t_conversions) const CHAISCRIPT_OVERRIDE
{ {
return (*m_f)(build_param_list(params), t_conversions); return (*m_f)(build_param_list(params), t_conversions);
} }
@@ -437,7 +429,34 @@ namespace chaiscript
private: private:
Const_Proxy_Function m_f; Const_Proxy_Function m_f;
std::vector<Boxed_Value> m_args; std::vector<Boxed_Value> m_args;
int m_arity; };
class Proxy_Function_Impl_Base : public Proxy_Function_Base
{
public:
Proxy_Function_Impl_Base(const std::vector<Type_Info> &t_types)
: Proxy_Function_Base(t_types, static_cast<int>(t_types.size()) - 1)
{
}
virtual ~Proxy_Function_Impl_Base() {}
virtual std::string annotation() const CHAISCRIPT_OVERRIDE
{
return "";
}
virtual bool call_match(const std::vector<Boxed_Value> &vals, const Type_Conversions &t_conversions) const CHAISCRIPT_OVERRIDE
{
if (int(vals.size()) != get_arity())
{
return false;
}
return compare_types(m_types, vals) || compare_types_with_cast(vals, t_conversions);
}
virtual bool compare_types_with_cast(const std::vector<Boxed_Value> &vals, const Type_Conversions &t_conversions) const = 0;
}; };
/** /**
@@ -446,41 +465,25 @@ namespace chaiscript
* type checking of Boxed_Value parameters, in a type safe manner * type checking of Boxed_Value parameters, in a type safe manner
*/ */
template<typename Func> template<typename Func>
class Proxy_Function_Impl : public Proxy_Function_Base class Proxy_Function_Impl : public Proxy_Function_Impl_Base
{ {
public: public:
Proxy_Function_Impl(std::function<Func> f) Proxy_Function_Impl(std::function<Func> f)
: Proxy_Function_Base(detail::build_param_type_list(static_cast<Func *>(nullptr))), : Proxy_Function_Impl_Base(detail::build_param_type_list(static_cast<Func *>(nullptr))),
m_f(std::move(f)), m_dummy_func(nullptr) m_f(std::move(f)), m_dummy_func(nullptr)
{ {
} }
virtual ~Proxy_Function_Impl() {} virtual ~Proxy_Function_Impl() {}
virtual bool compare_types_with_cast(const std::vector<Boxed_Value> &vals, const Type_Conversions &t_conversions) const CHAISCRIPT_OVERRIDE
{
return detail::compare_types_cast(m_dummy_func, vals, t_conversions);
}
virtual bool operator==(const Proxy_Function_Base &t_func) const CHAISCRIPT_OVERRIDE virtual bool operator==(const Proxy_Function_Base &t_func) const CHAISCRIPT_OVERRIDE
{ {
const Proxy_Function_Impl *pimpl = dynamic_cast<const Proxy_Function_Impl<Func> *>(&t_func); return dynamic_cast<const Proxy_Function_Impl<Func> *>(&t_func) != nullptr;
return pimpl != nullptr;
}
virtual int get_arity() const CHAISCRIPT_OVERRIDE
{
return static_cast<int>(m_types.size()) - 1;
}
virtual bool call_match(const std::vector<Boxed_Value> &vals, const Dynamic_Cast_Conversions &t_conversions) const CHAISCRIPT_OVERRIDE
{
if (int(vals.size()) != get_arity())
{
return false;
}
return compare_types(m_types, vals) || detail::compare_types_cast(m_dummy_func, vals, t_conversions);
}
virtual std::string annotation() const CHAISCRIPT_OVERRIDE
{
return "";
} }
std::function<Func> internal_function() const std::function<Func> internal_function() const
@@ -489,7 +492,7 @@ namespace chaiscript
} }
protected: protected:
virtual Boxed_Value do_call(const std::vector<Boxed_Value> &params, const Dynamic_Cast_Conversions &t_conversions) const CHAISCRIPT_OVERRIDE virtual Boxed_Value do_call(const std::vector<Boxed_Value> &params, const Type_Conversions &t_conversions) const
{ {
return detail::Do_Call<typename std::function<Func>::result_type>::go(m_f, params, t_conversions); return detail::Do_Call<typename std::function<Func>::result_type>::go(m_f, params, t_conversions);
} }
@@ -507,8 +510,8 @@ namespace chaiscript
{ {
public: public:
Attribute_Access(T Class::* t_attr) Attribute_Access(T Class::* t_attr)
: Proxy_Function_Base(param_types()), : Proxy_Function_Base(param_types(), 1),
m_attr(t_attr) m_attr(t_attr)
{ {
} }
@@ -526,13 +529,7 @@ namespace chaiscript
} }
} }
virtual bool call_match(const std::vector<Boxed_Value> &vals, const Type_Conversions &) const CHAISCRIPT_OVERRIDE
virtual int get_arity() const CHAISCRIPT_OVERRIDE
{
return 1;
}
virtual bool call_match(const std::vector<Boxed_Value> &vals, const Dynamic_Cast_Conversions &) const CHAISCRIPT_OVERRIDE
{ {
if (vals.size() != 1) if (vals.size() != 1)
{ {
@@ -548,7 +545,7 @@ namespace chaiscript
} }
protected: protected:
virtual Boxed_Value do_call(const std::vector<Boxed_Value> &params, const Dynamic_Cast_Conversions &t_conversions) const CHAISCRIPT_OVERRIDE virtual Boxed_Value do_call(const std::vector<Boxed_Value> &params, const Type_Conversions &t_conversions) const CHAISCRIPT_OVERRIDE
{ {
if (params.size() == 1) if (params.size() == 1)
{ {
@@ -605,7 +602,7 @@ namespace chaiscript
{ {
template<typename FuncType> template<typename FuncType>
bool types_match_except_for_arithmetic(const FuncType &t_func, const std::vector<Boxed_Value> &plist, bool types_match_except_for_arithmetic(const FuncType &t_func, const std::vector<Boxed_Value> &plist,
const Dynamic_Cast_Conversions &t_conversions) const Type_Conversions &t_conversions)
{ {
if (t_func->get_arity() != static_cast<int>(plist.size())) if (t_func->get_arity() != static_cast<int>(plist.size()))
{ {
@@ -633,7 +630,7 @@ namespace chaiscript
template<typename InItr> template<typename InItr>
Boxed_Value dispatch_with_conversions(InItr begin, const InItr &end, const std::vector<Boxed_Value> &plist, Boxed_Value dispatch_with_conversions(InItr begin, const InItr &end, const std::vector<Boxed_Value> &plist,
const Dynamic_Cast_Conversions &t_conversions) const Type_Conversions &t_conversions)
{ {
InItr orig(begin); InItr orig(begin);
@@ -695,17 +692,42 @@ namespace chaiscript
* each function against the set of parameters, in order, until a matching * each function against the set of parameters, in order, until a matching
* function is found or throw dispatch_error if no matching function is found * function is found or throw dispatch_error if no matching function is found
*/ */
template<typename InItr> template<typename Funcs>
Boxed_Value dispatch(InItr begin, const InItr &end, Boxed_Value dispatch(const Funcs &funcs,
const std::vector<Boxed_Value> &plist, const Dynamic_Cast_Conversions &t_conversions) const std::vector<Boxed_Value> &plist, const Type_Conversions &t_conversions)
{ {
InItr orig(begin);
while (begin != end) std::multimap<size_t, const Proxy_Function_Base *> ordered_funcs;
for (const auto &func : funcs)
{
size_t numdiffs = 0;
const auto arity = func->get_arity();
if (arity == -1)
{
numdiffs = plist.size();
} else if (arity == static_cast<int>(plist.size())) {
for (size_t i = 0; i < plist.size(); ++i)
{
if (!func->get_param_types()[i+1].bare_equal(plist[i].get_type_info()))
{
++numdiffs;
}
}
} else {
continue;
}
ordered_funcs.insert(std::make_pair(numdiffs, func.get()));
}
for (const auto &func : ordered_funcs )
{ {
try { try {
if ((*begin)->filter(plist, t_conversions)) if (func.second->filter(plist, t_conversions))
{ {
return (*(*begin))(plist, t_conversions); return (*(func.second))(plist, t_conversions);
} }
} catch (const exception::bad_boxed_cast &) { } catch (const exception::bad_boxed_cast &) {
//parameter failed to cast, try again //parameter failed to cast, try again
@@ -715,22 +737,9 @@ namespace chaiscript
//guard failed to allow the function to execute, //guard failed to allow the function to execute,
//try again //try again
} }
++begin;
} }
return detail::dispatch_with_conversions(orig, end, plist, t_conversions); return detail::dispatch_with_conversions(funcs.cbegin(), funcs.cend(), plist, t_conversions);
}
/**
* Take a vector of functions and a vector of parameters. Attempt to execute
* each function against the set of parameters, in order, until a matching
* function is found or throw dispatch_error if no matching function is found
*/
template<typename Funcs>
Boxed_Value dispatch(const Funcs &funcs,
const std::vector<Boxed_Value> &plist, const Dynamic_Cast_Conversions &t_conversions)
{
return dispatch::dispatch(funcs.begin(), funcs.end(), plist, t_conversions);
} }
} }
} }

View File

@@ -20,7 +20,7 @@
#include "type_info.hpp" #include "type_info.hpp"
namespace chaiscript { namespace chaiscript {
class Dynamic_Cast_Conversions; class Type_Conversions;
namespace exception { namespace exception {
class bad_boxed_cast; class bad_boxed_cast;
} // namespace exception } // namespace exception
@@ -53,29 +53,6 @@ namespace chaiscript
{ {
namespace detail namespace detail
{ {
template<typename ... Rest>
struct Build_Param_Type_List;
template<typename Param, typename ... Rest>
struct Build_Param_Type_List<Param, Rest...>
{
static void build(std::vector<Type_Info> &t_params)
{
t_params.push_back(chaiscript::detail::Get_Type_Info<Param>::get());
Build_Param_Type_List<Rest...>::build(t_params);
}
};
// 0th case
template<>
struct Build_Param_Type_List<>
{
static void build(std::vector<Type_Info> &)
{
}
};
/** /**
* Used by Proxy_Function_Impl to return a list of all param types * Used by Proxy_Function_Impl to return a list of all param types
* it contains. * it contains.
@@ -83,12 +60,8 @@ namespace chaiscript
template<typename Ret, typename ... Params> template<typename Ret, typename ... Params>
std::vector<Type_Info> build_param_type_list(Ret (*)(Params...)) std::vector<Type_Info> build_param_type_list(Ret (*)(Params...))
{ {
/// \todo this code was previously using { chaiscript::detail::Get_Type_Info<Ret>::get()... } /// \note somehow this is responsible for a large part of the code generation
/// but this seems to indicate another bug with MSVC's uniform initializer lists return { user_type<Ret>(), user_type<Params>()... };
std::vector<Type_Info> params;
params.push_back(chaiscript::detail::Get_Type_Info<Ret>::get());
Build_Param_Type_List<Params...>::build(params);
return params;
} }
@@ -99,7 +72,7 @@ namespace chaiscript
template<typename Param, typename ... Rest> template<typename Param, typename ... Rest>
struct Try_Cast<Param, Rest...> struct Try_Cast<Param, Rest...>
{ {
static void do_try(const std::vector<Boxed_Value> &params, int generation, const Dynamic_Cast_Conversions &t_conversions) static void do_try(const std::vector<Boxed_Value> &params, int generation, const Type_Conversions &t_conversions)
{ {
boxed_cast<Param>(params[generation], &t_conversions); boxed_cast<Param>(params[generation], &t_conversions);
Try_Cast<Rest...>::do_try(params, generation+1, t_conversions); Try_Cast<Rest...>::do_try(params, generation+1, t_conversions);
@@ -110,7 +83,7 @@ namespace chaiscript
template<> template<>
struct Try_Cast<> struct Try_Cast<>
{ {
static void do_try(const std::vector<Boxed_Value> &, int, const Dynamic_Cast_Conversions &) static void do_try(const std::vector<Boxed_Value> &, int, const Type_Conversions &)
{ {
} }
}; };
@@ -118,12 +91,12 @@ namespace chaiscript
/** /**
* Used by Proxy_Function_Impl to determine if it is equivalent to another * Used by Proxy_Function_Impl to determine if it is equivalent to another
* Proxy_Function_Impl object. This function is primarly used to prevent * Proxy_Function_Impl object. This function is primarily used to prevent
* registration of two functions with the exact same signatures * registration of two functions with the exact same signatures
*/ */
template<typename Ret, typename ... Params> template<typename Ret, typename ... Params>
bool compare_types_cast(Ret (*)(Params...), bool compare_types_cast(Ret (*)(Params...),
const std::vector<Boxed_Value> &params, const Dynamic_Cast_Conversions &t_conversions) const std::vector<Boxed_Value> &params, const Type_Conversions &t_conversions)
{ {
try { try {
Try_Cast<Params...>::do_try(params, 0, t_conversions); Try_Cast<Params...>::do_try(params, 0, t_conversions);
@@ -140,7 +113,7 @@ namespace chaiscript
template<typename ... InnerParams> template<typename ... InnerParams>
static Ret do_call(const std::function<Ret (Params...)> &f, static Ret do_call(const std::function<Ret (Params...)> &f,
const std::vector<Boxed_Value> &params, const Dynamic_Cast_Conversions &t_conversions, InnerParams &&... innerparams) const std::vector<Boxed_Value> &params, const Type_Conversions &t_conversions, InnerParams &&... innerparams)
{ {
return Call_Func<Ret, count - 1, Params...>::do_call(f, params, t_conversions, std::forward<InnerParams>(innerparams)..., params[sizeof...(Params) - count]); return Call_Func<Ret, count - 1, Params...>::do_call(f, params, t_conversions, std::forward<InnerParams>(innerparams)..., params[sizeof...(Params) - count]);
} }
@@ -155,7 +128,7 @@ namespace chaiscript
#endif #endif
template<typename ... InnerParams> template<typename ... InnerParams>
static Ret do_call(const std::function<Ret (Params...)> &f, static Ret do_call(const std::function<Ret (Params...)> &f,
const std::vector<Boxed_Value> &, const Dynamic_Cast_Conversions &t_conversions, InnerParams &&... innerparams) const std::vector<Boxed_Value> &, const Type_Conversions &t_conversions, InnerParams &&... innerparams)
{ {
return f(boxed_cast<Params>(std::forward<InnerParams>(innerparams), &t_conversions)...); return f(boxed_cast<Params>(std::forward<InnerParams>(innerparams), &t_conversions)...);
} }
@@ -166,13 +139,13 @@ namespace chaiscript
/** /**
* Used by Proxy_Function_Impl to perform typesafe execution of a function. * Used by Proxy_Function_Impl to perform typesafe execution of a function.
* The function attempts to unbox each paramter to the expected type. * The function attempts to unbox each parameter to the expected type.
* if any unboxing fails the execution of the function fails and * if any unboxing fails the execution of the function fails and
* the bad_boxed_cast is passed up to the caller. * the bad_boxed_cast is passed up to the caller.
*/ */
template<typename Ret, typename ... Params> template<typename Ret, typename ... Params>
Ret call_func(const std::function<Ret (Params...)> &f, Ret call_func(const std::function<Ret (Params...)> &f,
const std::vector<Boxed_Value> &params, const Dynamic_Cast_Conversions &t_conversions) const std::vector<Boxed_Value> &params, const Type_Conversions &t_conversions)
{ {
if (params.size() == sizeof...(Params)) if (params.size() == sizeof...(Params))
{ {
@@ -198,7 +171,7 @@ namespace chaiscript
struct Do_Call struct Do_Call
{ {
template<typename Fun> template<typename Fun>
static Boxed_Value go(const std::function<Fun> &fun, const std::vector<Boxed_Value> &params, const Dynamic_Cast_Conversions &t_conversions) static Boxed_Value go(const std::function<Fun> &fun, const std::vector<Boxed_Value> &params, const Type_Conversions &t_conversions)
{ {
return Handle_Return<Ret>::handle(call_func(fun, params, t_conversions)); return Handle_Return<Ret>::handle(call_func(fun, params, t_conversions));
} }
@@ -208,7 +181,7 @@ namespace chaiscript
struct Do_Call<void> struct Do_Call<void>
{ {
template<typename Fun> template<typename Fun>
static Boxed_Value go(const std::function<Fun> &fun, const std::vector<Boxed_Value> &params, const Dynamic_Cast_Conversions &t_conversions) static Boxed_Value go(const std::function<Fun> &fun, const std::vector<Boxed_Value> &params, const Type_Conversions &t_conversions)
{ {
call_func(fun, params, t_conversions); call_func(fun, params, t_conversions);
return Handle_Return<void>::handle(); return Handle_Return<void>::handle();

View File

@@ -0,0 +1,447 @@
// This file is distributed under the BSD License.
// See "license.txt" for details.
// Copyright 2009-2012, Jonathan Turner (jonathan@emptycrate.com)
// Copyright 2009-2014, Jason Turner (jason@emptycrate.com)
// http://www.chaiscript.com
#ifndef CHAISCRIPT_DYNAMIC_CAST_CONVERSION_HPP_
#define CHAISCRIPT_DYNAMIC_CAST_CONVERSION_HPP_
#include <atomic>
#include <memory>
#include <set>
#include <stdexcept>
#include <string>
#include <type_traits>
#include <typeinfo>
#include "../chaiscript_threading.hpp"
#include "bad_boxed_cast.hpp"
#include "boxed_cast_helper.hpp"
#include "boxed_value.hpp"
#include "type_info.hpp"
namespace chaiscript
{
namespace exception
{
class bad_boxed_dynamic_cast : public bad_boxed_cast
{
public:
bad_boxed_dynamic_cast(const Type_Info &t_from, const std::type_info &t_to,
const std::string &t_what) CHAISCRIPT_NOEXCEPT
: bad_boxed_cast(t_from, t_to, t_what)
{
}
bad_boxed_dynamic_cast(const Type_Info &t_from, const std::type_info &t_to) CHAISCRIPT_NOEXCEPT
: bad_boxed_cast(t_from, t_to)
{
}
bad_boxed_dynamic_cast(const std::string &w) CHAISCRIPT_NOEXCEPT
: bad_boxed_cast(w)
{
}
virtual ~bad_boxed_dynamic_cast() CHAISCRIPT_NOEXCEPT {}
};
class bad_boxed_type_cast : public bad_boxed_cast
{
public:
bad_boxed_type_cast(const Type_Info &t_from, const std::type_info &t_to,
const std::string &t_what) CHAISCRIPT_NOEXCEPT
: bad_boxed_cast(t_from, t_to, t_what)
{
}
bad_boxed_type_cast(const Type_Info &t_from, const std::type_info &t_to) CHAISCRIPT_NOEXCEPT
: bad_boxed_cast(t_from, t_to)
{
}
bad_boxed_type_cast(const std::string &w) CHAISCRIPT_NOEXCEPT
: bad_boxed_cast(w)
{
}
virtual ~bad_boxed_type_cast() CHAISCRIPT_NOEXCEPT {}
};
}
namespace detail
{
class Type_Conversion_Base
{
public:
virtual Boxed_Value convert(const Boxed_Value &from) const = 0;
virtual Boxed_Value convert_down(const Boxed_Value &to) const = 0;
const Type_Info &to() const
{
return m_to;
}
const Type_Info &from() const
{
return m_from;
}
protected:
Type_Conversion_Base(const Type_Info &t_to, const Type_Info &t_from)
: m_to(t_to), m_from(t_from)
{
}
virtual ~Type_Conversion_Base() {}
private:
Type_Info m_to;
Type_Info m_from;
};
template<typename From, typename To>
class Dynamic_Caster
{
public:
static Boxed_Value cast(const Boxed_Value &t_from)
{
if (t_from.get_type_info().bare_equal(chaiscript::user_type<From>()))
{
if (t_from.is_pointer())
{
// Dynamic cast out the contained boxed value, which we know is the type we want
if (t_from.is_const())
{
std::shared_ptr<const To> data
= std::dynamic_pointer_cast<const To>(detail::Cast_Helper<std::shared_ptr<const From> >::cast(t_from, nullptr));
if (!data)
{
throw std::bad_cast();
}
return Boxed_Value(data);
} else {
std::shared_ptr<To> data
= std::dynamic_pointer_cast<To>(detail::Cast_Helper<std::shared_ptr<From> >::cast(t_from, nullptr));
if (!data)
{
throw std::bad_cast();
}
return Boxed_Value(data);
}
} else {
// Pull the reference out of the contained boxed value, which we know is the type we want
if (t_from.is_const())
{
const From &d = detail::Cast_Helper<const From &>::cast(t_from, nullptr);
const To &data = dynamic_cast<const To &>(d);
return Boxed_Value(std::cref(data));
} else {
From &d = detail::Cast_Helper<From &>::cast(t_from, nullptr);
To &data = dynamic_cast<To &>(d);
return Boxed_Value(std::ref(data));
}
}
} else {
throw chaiscript::exception::bad_boxed_dynamic_cast(t_from.get_type_info(), typeid(To), "Unknown dynamic_cast_conversion");
}
}
};
template<typename Base, typename Derived>
class Dynamic_Conversion_Impl : public Type_Conversion_Base
{
public:
Dynamic_Conversion_Impl()
: Type_Conversion_Base(chaiscript::user_type<Base>(), chaiscript::user_type<Derived>())
{
}
virtual Boxed_Value convert_down(const Boxed_Value &t_base) const CHAISCRIPT_OVERRIDE
{
return Dynamic_Caster<Base, Derived>::cast(t_base);
}
virtual Boxed_Value convert(const Boxed_Value &t_derived) const CHAISCRIPT_OVERRIDE
{
return Dynamic_Caster<Derived, Base>::cast(t_derived);
}
};
template<typename Callable>
class Type_Conversion_Impl : public Type_Conversion_Base
{
public:
Type_Conversion_Impl(Type_Info t_from, Type_Info t_to, Callable t_func)
: Type_Conversion_Base(std::move(t_to), std::move(t_from)),
m_func(std::move(t_func))
{
}
virtual Boxed_Value convert_down(const Boxed_Value &) const CHAISCRIPT_OVERRIDE
{
throw chaiscript::exception::bad_boxed_type_cast("No conversion exists");
}
virtual Boxed_Value convert(const Boxed_Value &t_from) const CHAISCRIPT_OVERRIDE
{
/// \todo better handling of errors from the conversion function
return m_func(t_from);
}
private:
Callable m_func;
};
}
class Type_Conversions
{
public:
struct Less_Than
{
bool operator()(const std::type_info *t_lhs, const std::type_info *t_rhs) const
{
return *t_lhs != *t_rhs && t_lhs->before(*t_rhs);
}
};
Type_Conversions()
: m_num_types(0),
m_thread_cache(this),
m_conversion_saves(this)
{
}
Type_Conversions(const Type_Conversions &t_other)
: m_conversions(t_other.get_conversions()), m_num_types(m_conversions.size()),
m_thread_cache(this),
m_conversion_saves(this)
{
}
const std::set<const std::type_info *, Less_Than> &thread_cache() const
{
auto &cache = *m_thread_cache;
if (cache.size() != m_num_types)
{
chaiscript::detail::threading::shared_lock<chaiscript::detail::threading::shared_mutex> l(m_mutex);
cache = m_convertableTypes;
}
return cache;
}
void add_conversion(const std::shared_ptr<detail::Type_Conversion_Base> &conversion)
{
chaiscript::detail::threading::unique_lock<chaiscript::detail::threading::shared_mutex> l(m_mutex);
/// \todo error if a conversion already exists
m_conversions.insert(conversion);
m_convertableTypes.insert({conversion->to().bare_type_info(), conversion->from().bare_type_info()});
m_num_types = m_convertableTypes.size();
}
template<typename T>
bool convertable_type() const
{
return thread_cache().count(user_type<T>().bare_type_info()) != 0;
}
template<typename To, typename From>
bool converts() const
{
return converts(user_type<To>(), user_type<From>());
}
bool converts(const Type_Info &to, const Type_Info &from) const
{
const auto &types = thread_cache();
if (types.count(to.bare_type_info()) != 0 && types.count(from.bare_type_info()) != 0)
{
return has_conversion(to, from) || has_conversion(from, to);
} else {
return false;
}
}
template<typename To>
Boxed_Value boxed_type_conversion(const Boxed_Value &from) const
{
try {
Boxed_Value ret = get_conversion(user_type<To>(), from.get_type_info())->convert(from);
if (m_conversion_saves->enabled) m_conversion_saves->saves.push_back(ret);
return ret;
} catch (const std::out_of_range &) {
throw exception::bad_boxed_dynamic_cast(from.get_type_info(), typeid(To), "No known conversion");
} catch (const std::bad_cast &) {
throw exception::bad_boxed_dynamic_cast(from.get_type_info(), typeid(To), "Unable to perform dynamic_cast operation");
}
}
template<typename From>
Boxed_Value boxed_type_down_conversion(const Boxed_Value &to) const
{
try {
Boxed_Value ret = get_conversion(to.get_type_info(), user_type<From>())->convert_down(to);
if (m_conversion_saves->enabled) m_conversion_saves->saves.push_back(ret);
return ret;
} catch (const std::out_of_range &) {
throw exception::bad_boxed_dynamic_cast(to.get_type_info(), typeid(From), "No known conversion");
} catch (const std::bad_cast &) {
throw exception::bad_boxed_dynamic_cast(to.get_type_info(), typeid(From), "Unable to perform dynamic_cast operation");
}
}
void enable_conversion_saves(bool t_val)
{
m_conversion_saves->enabled = t_val;
}
std::vector<Boxed_Value> take_saves()
{
std::vector<Boxed_Value> ret;
std::swap(ret, m_conversion_saves->saves);
return ret;
}
bool has_conversion(const Type_Info &to, const Type_Info &from) const
{
chaiscript::detail::threading::shared_lock<chaiscript::detail::threading::shared_mutex> l(m_mutex);
return find(to, from) != m_conversions.end();
}
std::shared_ptr<detail::Type_Conversion_Base> get_conversion(const Type_Info &to, const Type_Info &from) const
{
chaiscript::detail::threading::shared_lock<chaiscript::detail::threading::shared_mutex> l(m_mutex);
auto itr = find(to, from);
if (itr != m_conversions.end())
{
return *itr;
} else {
throw std::out_of_range("No such conversion exists from " + from.bare_name() + " to " + to.bare_name());
}
}
private:
std::set<std::shared_ptr<detail::Type_Conversion_Base> >::const_iterator find(
const Type_Info &to, const Type_Info &from) const
{
return std::find_if(m_conversions.begin(), m_conversions.end(),
[&to, &from](const std::shared_ptr<detail::Type_Conversion_Base> &conversion)
{
return conversion->to().bare_equal(to) && conversion->from().bare_equal(from);
}
);
}
std::set<std::shared_ptr<detail::Type_Conversion_Base>> get_conversions() const
{
chaiscript::detail::threading::shared_lock<chaiscript::detail::threading::shared_mutex> l(m_mutex);
return m_conversions;
}
struct Conversion_Saves
{
Conversion_Saves()
: enabled(false)
{}
bool enabled;
std::vector<Boxed_Value> saves;
};
mutable chaiscript::detail::threading::shared_mutex m_mutex;
std::set<std::shared_ptr<detail::Type_Conversion_Base>> m_conversions;
std::set<const std::type_info *, Less_Than> m_convertableTypes;
std::atomic_size_t m_num_types;
chaiscript::detail::threading::Thread_Storage<std::set<const std::type_info *, Less_Than>> m_thread_cache;
chaiscript::detail::threading::Thread_Storage<Conversion_Saves> m_conversion_saves;
};
typedef std::shared_ptr<chaiscript::detail::Type_Conversion_Base> Type_Conversion;
/// \brief Used to register a to / parent class relationship with ChaiScript. Necessary if you
/// want automatic conversions up your inheritance hierarchy.
///
/// Create a new to class registration for applying to a module or to the ChaiScript engine
/// Currently, due to limitations in module loading on Windows, and for the sake of portability,
/// if you have a type that is introduced in a loadable module and is used by multiple modules
/// (through a tertiary dll that is shared between the modules, static linking the new type
/// into both loadable modules would not be portable), you need to register the type
/// relationship in all modules that use the newly added type in a polymorphic way.
///
/// Example:
/// \code
/// class Base
/// {};
/// class Derived : public Base
/// {};
///
/// chaiscript::ChaiScript chai;
/// chai.add(chaiscript::to_class<Base, Derived>());
/// \endcode
///
template<typename Base, typename Derived>
Type_Conversion base_class()
{
//Can only be used with related polymorphic types
//may be expanded some day to support conversions other than child -> parent
static_assert(std::is_base_of<Base,Derived>::value, "Classes are not related by inheritance");
static_assert(std::is_polymorphic<Base>::value, "Base class must be polymorphic");
static_assert(std::is_polymorphic<Derived>::value, "Derived class must be polymorphic");
return std::make_shared<detail::Dynamic_Conversion_Impl<Base, Derived>>();
}
template<typename Callable>
Type_Conversion type_conversion(const Type_Info &t_from, const Type_Info &t_to,
const Callable &t_func)
{
return std::make_shared<detail::Type_Conversion_Impl<Callable>>(t_from, t_to, t_func);
}
template<typename From, typename To, typename Callable>
Type_Conversion type_conversion(const Callable &t_function)
{
auto func = [t_function](const Boxed_Value &t_bv) -> Boxed_Value {
// not even attempting to call boxed_cast so that we don't get caught in some call recursion
return chaiscript::Boxed_Value(t_function(detail::Cast_Helper<const From &>::cast(t_bv, nullptr)));
};
return std::make_shared<detail::Type_Conversion_Impl<decltype(func)>>(user_type<From>(), user_type<To>(), func);
}
template<typename From, typename To>
Type_Conversion type_conversion()
{
static_assert(std::is_convertible<From, To>::value, "Types are not automatically convertible");
auto func = [](const Boxed_Value &t_bv) -> Boxed_Value {
// not even attempting to call boxed_cast so that we don't get caught in some call recursion
std::cout << " Type conversion to : " << typeid(To).name() << " from " << typeid(From).name() << std::endl;
auto &&from = detail::Cast_Helper<From>::cast(t_bv, nullptr);
std::cout << "Ptr" << static_cast<const void *>(from) << std::endl;
std::cout << "Ptr" << from << std::endl;
To to(from);
return chaiscript::Boxed_Value(to);
};
return std::make_shared<detail::Type_Conversion_Impl<decltype(func)>>(user_type<From>(), user_type<To>(), func);
}
}
#endif

View File

@@ -25,6 +25,7 @@ namespace chaiscript
}; };
} }
/// \brief Compile time deduced information about a type /// \brief Compile time deduced information about a type
class Type_Info class Type_Info
{ {
@@ -38,7 +39,7 @@ namespace chaiscript
{ {
} }
Type_Info() CHAISCRIPT_CONSTEXPR Type_Info()
: m_type_info(nullptr), m_bare_type_info(nullptr), : m_type_info(nullptr), m_bare_type_info(nullptr),
m_is_const(false), m_is_reference(false), m_is_pointer(false), m_is_const(false), m_is_reference(false), m_is_pointer(false),
m_is_void(false), m_is_arithmetic(false), m_is_void(false), m_is_arithmetic(false),
@@ -46,63 +47,49 @@ namespace chaiscript
{ {
} }
Type_Info(const Type_Info &ti) #if !defined(_MSC_VER) || _MSC_VER != 1800
: m_type_info(ti.m_type_info), Type_Info(Type_Info&&) = default;
m_bare_type_info(ti.m_bare_type_info), Type_Info& operator=(Type_Info&&) = default;
m_is_const(ti.m_is_const), m_is_reference(ti.m_is_reference), #endif
m_is_pointer(ti.m_is_pointer),
m_is_void(ti.m_is_void), m_is_arithmetic(ti.m_is_arithmetic),
m_is_undef(ti.m_is_undef)
{
}
Type_Info &operator=(const Type_Info &ti) Type_Info(const Type_Info&) = default;
{ Type_Info& operator=(const Type_Info&) = default;
m_type_info = ti.m_type_info;
m_bare_type_info = ti.m_bare_type_info;
m_is_const = ti.m_is_const;
m_is_reference = ti.m_is_reference;
m_is_pointer = ti.m_is_pointer;
m_is_void = ti.m_is_void;
m_is_arithmetic = ti.m_is_arithmetic;
m_is_undef = ti.m_is_undef;
return *this;
}
bool operator<(const Type_Info &ti) const
CHAISCRIPT_CONSTEXPR bool operator<(const Type_Info &ti) const CHAISCRIPT_NOEXCEPT
{ {
return m_type_info < ti.m_type_info; return m_type_info < ti.m_type_info;
} }
bool operator==(const Type_Info &ti) const CHAISCRIPT_CONSTEXPR bool operator==(const Type_Info &ti) const CHAISCRIPT_NOEXCEPT
{ {
return ti.m_type_info == m_type_info return ti.m_type_info == m_type_info
|| (ti.m_type_info && m_type_info && *ti.m_type_info == *m_type_info); || (ti.m_type_info && m_type_info && *ti.m_type_info == *m_type_info);
} }
bool operator==(const std::type_info &ti) const CHAISCRIPT_CONSTEXPR bool operator==(const std::type_info &ti) const CHAISCRIPT_NOEXCEPT
{ {
return m_type_info != nullptr && (*m_type_info) == ti; return m_type_info != nullptr && (*m_type_info) == ti;
} }
bool bare_equal(const Type_Info &ti) const CHAISCRIPT_CONSTEXPR bool bare_equal(const Type_Info &ti) const CHAISCRIPT_NOEXCEPT
{ {
return ti.m_bare_type_info == m_bare_type_info return ti.m_bare_type_info == m_bare_type_info
|| (ti.m_bare_type_info && m_bare_type_info && *ti.m_bare_type_info == *m_bare_type_info); || (ti.m_bare_type_info && m_bare_type_info && *ti.m_bare_type_info == *m_bare_type_info);
} }
bool bare_equal_type_info(const std::type_info &ti) const CHAISCRIPT_CONSTEXPR bool bare_equal_type_info(const std::type_info &ti) const CHAISCRIPT_NOEXCEPT
{ {
return m_bare_type_info != nullptr return m_bare_type_info != nullptr
&& (*m_bare_type_info) == ti; && (*m_bare_type_info) == ti;
} }
bool is_const() const { return m_is_const; } CHAISCRIPT_CONSTEXPR bool is_const() const CHAISCRIPT_NOEXCEPT { return m_is_const; }
bool is_reference() const { return m_is_reference; } CHAISCRIPT_CONSTEXPR bool is_reference() const CHAISCRIPT_NOEXCEPT { return m_is_reference; }
bool is_void() const { return m_is_void; } CHAISCRIPT_CONSTEXPR bool is_void() const CHAISCRIPT_NOEXCEPT { return m_is_void; }
bool is_arithmetic() const { return m_is_arithmetic; } CHAISCRIPT_CONSTEXPR bool is_arithmetic() const CHAISCRIPT_NOEXCEPT { return m_is_arithmetic; }
bool is_undef() const { return m_is_undef || m_bare_type_info == nullptr; } CHAISCRIPT_CONSTEXPR bool is_undef() const CHAISCRIPT_NOEXCEPT { return m_is_undef || m_bare_type_info == nullptr; }
bool is_pointer() const { return m_is_pointer; } CHAISCRIPT_CONSTEXPR bool is_pointer() const CHAISCRIPT_NOEXCEPT { return m_is_pointer; }
std::string name() const std::string name() const
{ {
@@ -114,7 +101,7 @@ namespace chaiscript
} }
} }
std::string bare_name() const std::string bare_name() const
{ {
if (m_bare_type_info) if (m_bare_type_info)
{ {
@@ -124,6 +111,11 @@ namespace chaiscript
} }
} }
CHAISCRIPT_CONSTEXPR const std::type_info *bare_type_info() const
{
return m_bare_type_info;
}
private: private:
const std::type_info *m_type_info; const std::type_info *m_type_info;
const std::type_info *m_bare_type_info; const std::type_info *m_bare_type_info;
@@ -215,11 +207,6 @@ namespace chaiscript
} }
}; };
template<typename T>
struct Stripped_Type
{
typedef typename Bare_Type<typename detail::Get_Type_Info<T>::type>::type type;
};
} }
/// \brief Creates a Type_Info object representing the type passed in /// \brief Creates a Type_Info object representing the type passed in

View File

@@ -37,7 +37,7 @@ namespace chaiscript
Comparison, Addition, Subtraction, Multiplication, Division, Modulus, Array_Call, Dot_Access, Quoted_String, Single_Quoted_String, Comparison, Addition, Subtraction, Multiplication, Division, Modulus, Array_Call, Dot_Access, Quoted_String, Single_Quoted_String,
Lambda, Block, Def, While, If, For, Inline_Array, Inline_Map, Return, File, Prefix, Break, Continue, Map_Pair, Value_Range, Lambda, Block, Def, While, If, For, Inline_Array, Inline_Map, Return, File, Prefix, Break, Continue, Map_Pair, Value_Range,
Inline_Range, Annotation, Try, Catch, Finally, Method, Attr_Decl, Shift, Equality, Bitwise_And, Bitwise_Xor, Bitwise_Or, Inline_Range, Annotation, Try, Catch, Finally, Method, Attr_Decl, Shift, Equality, Bitwise_And, Bitwise_Xor, Bitwise_Or,
Logical_And, Logical_Or, Reference, Switch, Case, Default, Ternary_Cond, Noop Logical_And, Logical_Or, Reference, Switch, Case, Default, Ternary_Cond, Noop, Class
}; };
}; };
@@ -69,6 +69,7 @@ namespace chaiscript
/// \brief Typedef for pointers to AST_Node objects. Used in building of the AST_Node tree /// \brief Typedef for pointers to AST_Node objects. Used in building of the AST_Node tree
typedef std::shared_ptr<AST_Node> AST_NodePtr; typedef std::shared_ptr<AST_Node> AST_NodePtr;
typedef std::shared_ptr<const AST_Node> AST_NodePtr_Const;
/// \brief Classes which may be thrown during error cases when ChaiScript is executing. /// \brief Classes which may be thrown during error cases when ChaiScript is executing.
@@ -82,7 +83,7 @@ namespace chaiscript
File_Position end_position; File_Position end_position;
std::string filename; std::string filename;
std::string detail; std::string detail;
std::vector<AST_NodePtr> call_stack; std::vector<AST_NodePtr_Const> call_stack;
eval_error(const std::string &t_why, const File_Position &t_where, const std::string &t_fname, eval_error(const std::string &t_why, const File_Position &t_where, const std::string &t_fname,
const std::vector<Boxed_Value> &t_parameters, const std::vector<chaiscript::Const_Proxy_Function> &t_functions, const std::vector<Boxed_Value> &t_parameters, const std::vector<chaiscript::Const_Proxy_Function> &t_functions,
@@ -425,23 +426,19 @@ namespace chaiscript
/// Prints the contents of an AST node, including its children, recursively /// Prints the contents of an AST node, including its children, recursively
std::string to_string(const std::string &t_prepend = "") { std::string to_string(const std::string &t_prepend = "") const {
std::ostringstream oss; std::ostringstream oss;
oss << t_prepend << "(" << ast_node_type_to_string(this->identifier) << ") " oss << t_prepend << "(" << ast_node_type_to_string(this->identifier) << ") "
<< this->text << " : " << this->start.line << ", " << this->start.column << std::endl; << this->text << " : " << this->start.line << ", " << this->start.column << std::endl;
for (size_t j = 0; j < this->children.size(); ++j) { for (size_t j = 0; j < this->children.size(); ++j) {
oss << this->children[j]->to_string(t_prepend + " "); oss << this->children[j]->to_string(t_prepend + " ");
} }
return oss.str(); return oss.str();
} }
std::string internal_to_string() { Boxed_Value eval(chaiscript::detail::Dispatch_Engine &t_e) const
return to_string();
}
Boxed_Value eval(chaiscript::detail::Dispatch_Engine &t_e)
{ {
try { try {
return eval_internal(t_e); return eval_internal(t_e);
@@ -470,7 +467,7 @@ namespace chaiscript
virtual ~AST_Node() {} virtual ~AST_Node() {}
virtual Boxed_Value eval_internal(chaiscript::detail::Dispatch_Engine &) virtual Boxed_Value eval_internal(chaiscript::detail::Dispatch_Engine &) const
{ {
throw std::runtime_error("Undispatched ast_node (internal error)"); throw std::runtime_error("Undispatched ast_node (internal error)");
} }
@@ -510,6 +507,9 @@ namespace chaiscript
/// Creates a new scope then pops it on destruction /// Creates a new scope then pops it on destruction
struct Scope_Push_Pop struct Scope_Push_Pop
{ {
Scope_Push_Pop(const Scope_Push_Pop &) = delete;
Scope_Push_Pop& operator=(const Scope_Push_Pop &) = delete;
Scope_Push_Pop(chaiscript::detail::Dispatch_Engine &t_de) Scope_Push_Pop(chaiscript::detail::Dispatch_Engine &t_de)
: m_de(t_de) : m_de(t_de)
{ {
@@ -523,9 +523,6 @@ namespace chaiscript
private: private:
// explicitly unimplemented copy and assignment
Scope_Push_Pop(const Scope_Push_Pop &);
Scope_Push_Pop& operator=(const Scope_Push_Pop &);
chaiscript::detail::Dispatch_Engine &m_de; chaiscript::detail::Dispatch_Engine &m_de;
}; };
@@ -533,6 +530,9 @@ namespace chaiscript
/// Creates a new function call and pops it on destruction /// Creates a new function call and pops it on destruction
struct Function_Push_Pop struct Function_Push_Pop
{ {
Function_Push_Pop(const Function_Push_Pop &) = delete;
Function_Push_Pop& operator=(const Function_Push_Pop &) = delete;
Function_Push_Pop(chaiscript::detail::Dispatch_Engine &t_de) Function_Push_Pop(chaiscript::detail::Dispatch_Engine &t_de)
: m_de(t_de) : m_de(t_de)
{ {
@@ -549,11 +549,13 @@ namespace chaiscript
m_de.save_function_params(t_params); m_de.save_function_params(t_params);
} }
void save_params(std::initializer_list<Boxed_Value> t_params)
{
m_de.save_function_params(std::move(t_params));
}
private: private:
// explicitly unimplemented copy and assignment
Function_Push_Pop(const Function_Push_Pop &);
Function_Push_Pop& operator=(const Function_Push_Pop &);
chaiscript::detail::Dispatch_Engine &m_de; chaiscript::detail::Dispatch_Engine &m_de;
}; };
@@ -561,6 +563,9 @@ namespace chaiscript
/// Creates a new scope then pops it on destruction /// Creates a new scope then pops it on destruction
struct Stack_Push_Pop struct Stack_Push_Pop
{ {
Stack_Push_Pop(const Stack_Push_Pop &) = delete;
Stack_Push_Pop& operator=(const Stack_Push_Pop &) = delete;
Stack_Push_Pop(chaiscript::detail::Dispatch_Engine &t_de) Stack_Push_Pop(chaiscript::detail::Dispatch_Engine &t_de)
: m_de(t_de) : m_de(t_de)
{ {
@@ -574,9 +579,6 @@ namespace chaiscript
private: private:
// explicitly unimplemented copy and assignment
Stack_Push_Pop(const Stack_Push_Pop &);
Stack_Push_Pop& operator=(const Stack_Push_Pop &);
chaiscript::detail::Dispatch_Engine &m_de; chaiscript::detail::Dispatch_Engine &m_de;
}; };

View File

@@ -26,7 +26,7 @@
#include "../dispatchkit/boxed_cast_helper.hpp" #include "../dispatchkit/boxed_cast_helper.hpp"
#include "../dispatchkit/boxed_value.hpp" #include "../dispatchkit/boxed_value.hpp"
#include "../dispatchkit/dispatchkit.hpp" #include "../dispatchkit/dispatchkit.hpp"
#include "../dispatchkit/dynamic_cast_conversion.hpp" #include "../dispatchkit/type_conversions.hpp"
#include "../dispatchkit/proxy_functions.hpp" #include "../dispatchkit/proxy_functions.hpp"
#include "chaiscript_common.hpp" #include "chaiscript_common.hpp"
@@ -282,7 +282,7 @@ namespace chaiscript
return Boxed_Value(); return Boxed_Value();
} }
} }
catch (const chaiscript::eval::detail::Return_Value &rv) { catch (chaiscript::eval::detail::Return_Value &rv) {
return rv.retval; return rv.retval;
} }
} }
@@ -330,6 +330,7 @@ namespace chaiscript
m_engine.add_reserved_word("break"); m_engine.add_reserved_word("break");
m_engine.add_reserved_word("true"); m_engine.add_reserved_word("true");
m_engine.add_reserved_word("false"); m_engine.add_reserved_word("false");
m_engine.add_reserved_word("class");
m_engine.add_reserved_word("_"); m_engine.add_reserved_word("_");
if (t_lib) if (t_lib)
@@ -344,12 +345,21 @@ namespace chaiscript
m_engine.add(fun(&chaiscript::detail::Dispatch_Engine::function_exists, std::ref(m_engine)), "function_exists"); m_engine.add(fun(&chaiscript::detail::Dispatch_Engine::function_exists, std::ref(m_engine)), "function_exists");
m_engine.add(fun(&chaiscript::detail::Dispatch_Engine::get_function_objects, std::ref(m_engine)), "get_functions"); m_engine.add(fun(&chaiscript::detail::Dispatch_Engine::get_function_objects, std::ref(m_engine)), "get_functions");
m_engine.add(fun(&chaiscript::detail::Dispatch_Engine::get_scripting_objects, std::ref(m_engine)), "get_objects"); m_engine.add(fun(&chaiscript::detail::Dispatch_Engine::get_scripting_objects, std::ref(m_engine)), "get_objects");
m_engine.add(Proxy_Function(new dispatch::Dynamic_Proxy_Function(std::bind(&chaiscript::detail::Dispatch_Engine::call_exists, std::ref(m_engine), std::placeholders::_1))), m_engine.add(Proxy_Function(new dispatch::Dynamic_Proxy_Function(
"call_exists"); [this](const std::vector<Boxed_Value> &t_params) {
return m_engine.call_exists(t_params);
})), "call_exists");
m_engine.add(fun<Boxed_Value (const dispatch::Proxy_Function_Base *, const std::vector<Boxed_Value> &)>(std::bind(&chaiscript::dispatch::Proxy_Function_Base::operator(), std::placeholders::_1, std::placeholders::_2, std::ref(m_engine.conversions()))), "call"); m_engine.add(fun<Boxed_Value (const dispatch::Proxy_Function_Base *, const std::vector<Boxed_Value> &)>(std::bind(&chaiscript::dispatch::Proxy_Function_Base::operator(), std::placeholders::_1, std::placeholders::_2, std::ref(m_engine.conversions()))), "call");
m_engine.add(fun(&chaiscript::detail::Dispatch_Engine::get_type_name, std::ref(m_engine)), "name"); m_engine.add(fun(&chaiscript::detail::Dispatch_Engine::get_type_name, std::ref(m_engine)), "name");
m_engine.add(fun(&chaiscript::detail::Dispatch_Engine::get_type, std::ref(m_engine)), "type");
m_engine.add(fun<void (const Type_Info &, const Type_Info &, const std::function<Boxed_Value (const Boxed_Value &)> &)> (
[=](const Type_Info &t_from, const Type_Info &t_to, const std::function<Boxed_Value (const Boxed_Value &)> &t_func) {
m_engine.add(chaiscript::type_conversion(t_from, t_to, t_func));
}
), "add_type_conversion");
typedef std::string (ChaiScript::*load_mod_1)(const std::string&); typedef std::string (ChaiScript::*load_mod_1)(const std::string&);
typedef void (ChaiScript::*load_mod_2)(const std::string&, const std::string&); typedef void (ChaiScript::*load_mod_2)(const std::string&, const std::string&);
@@ -381,7 +391,7 @@ namespace chaiscript
throw chaiscript::exception::file_not_found_error(t_filename); throw chaiscript::exception::file_not_found_error(t_filename);
} }
std::streampos size = infile.tellg(); const auto size = infile.tellg();
infile.seekg(0, std::ios::beg); infile.seekg(0, std::ios::beg);
assert(size >= 0); assert(size >= 0);
@@ -390,7 +400,7 @@ namespace chaiscript
{ {
return std::string(); return std::string();
} else { } else {
std::vector<char> v(static_cast<unsigned int>(size)); std::vector<char> v(static_cast<size_t>(size));
infile.read(&v[0], size); infile.read(&v[0], size);
return std::string(v.begin(), v.end()); return std::string(v.begin(), v.end());
} }
@@ -456,7 +466,7 @@ namespace chaiscript
u.in_ptr = &ChaiScript::use; u.in_ptr = &ChaiScript::use;
if ( dladdr((void*)(u.out_ptr), &rInfo) && rInfo.dli_fname ) { if ( dladdr((void*)(u.out_ptr), &rInfo) && rInfo.dli_fname ) {
std::string dllpath(rInfo.dli_fname); std::string dllpath(rInfo.dli_fname);
size_t lastslash = dllpath.rfind('/'); const size_t lastslash = dllpath.rfind('/');
if (lastslash != std::string::npos) if (lastslash != std::string::npos)
{ {
dllpath.erase(lastslash); dllpath.erase(lastslash);
@@ -464,15 +474,15 @@ namespace chaiscript
// Let's see if this is a link that we should expand // Let's see if this is a link that we should expand
std::vector<char> buf(2048); std::vector<char> buf(2048);
size_t pathlen = readlink(dllpath.c_str(), &buf.front(), buf.size()); const size_t pathlen = readlink(dllpath.c_str(), &buf.front(), buf.size());
if (pathlen > 0 && pathlen < buf.size()) if (pathlen > 0 && pathlen < buf.size())
{ {
dllpath = std::string(&buf.front(), pathlen); dllpath = std::string(&buf.front(), pathlen);
} }
m_modulepaths.insert(m_modulepaths.begin(), dllpath+"/"); m_modulepaths.insert(m_modulepaths.begin(), dllpath+"/");
} }
#endif #endif
// attempt to load the stdlib // attempt to load the stdlib
@@ -503,6 +513,18 @@ namespace chaiscript
return ss.str(); return ss.str();
} }
std::string get_type_name(const Type_Info &ti) const
{
return m_engine.get_type_name(ti);
}
template<typename T>
std::string get_type_name() const
{
return get_type_name(user_type<T>());
}
/// \brief Loads and parses a file. If the file is already, it is not reloaded /// \brief Loads and parses a file. If the file is already, it is not reloaded
/// The use paths specified at ChaiScript construction time are searched for the /// The use paths specified at ChaiScript construction time are searched for the
/// requested file. /// requested file.
@@ -510,10 +532,10 @@ namespace chaiscript
/// \param[in] t_filename Filename to load and evaluate /// \param[in] t_filename Filename to load and evaluate
void use(const std::string &t_filename) void use(const std::string &t_filename)
{ {
for (size_t i = 0; i < m_usepaths.size(); ++i) for (const auto &path : m_usepaths)
{ {
try { try {
const std::string appendedpath = m_usepaths[i] + t_filename; 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::recursive_mutex> l(m_use_mutex);
chaiscript::detail::threading::unique_lock<chaiscript::detail::threading::shared_mutex> l2(m_mutex); chaiscript::detail::threading::unique_lock<chaiscript::detail::threading::shared_mutex> l2(m_mutex);
@@ -528,14 +550,12 @@ namespace chaiscript
return; // return, we loaded it, or it was already loaded return; // return, we loaded it, or it was already loaded
} catch (const exception::file_not_found_error &) { } catch (const exception::file_not_found_error &) {
if (i == m_usepaths.size() - 1)
{
throw exception::file_not_found_error(t_filename);
}
// failed to load, try the next path // failed to load, try the next path
} }
} }
// failed to load by any name
throw exception::file_not_found_error(t_filename);
} }
/// \brief Adds a constant object that is available in all contexts and to all threads /// \brief Adds a constant object that is available in all contexts and to all threads
@@ -666,7 +686,7 @@ namespace chaiscript
/// chaiscript::ChaiScript chai; /// chaiscript::ChaiScript chai;
/// chai.add(chaiscript::base_class<std::runtime_error, chaiscript::dispatch_error>()); /// chai.add(chaiscript::base_class<std::runtime_error, chaiscript::dispatch_error>());
/// \endcode /// \endcode
ChaiScript &add(const Dynamic_Cast_Conversion &d) ChaiScript &add(const Type_Conversion &d)
{ {
m_engine.add(d); m_engine.add(d);
return *this; return *this;
@@ -703,15 +723,9 @@ namespace chaiscript
version_stripped_name.erase(version_pos); version_stripped_name.erase(version_pos);
} }
std::vector<std::string> prefixes; std::vector<std::string> prefixes{"lib", "cyg", ""};
prefixes.push_back("lib");
prefixes.push_back("cyg");
prefixes.push_back("");
std::vector<std::string> postfixes; std::vector<std::string> postfixes{".dll", ".so", ""};
postfixes.push_back(".dll");
postfixes.push_back(".so");
postfixes.push_back("");
for (auto & elem : m_modulepaths) for (auto & elem : m_modulepaths)
{ {
@@ -720,7 +734,7 @@ namespace chaiscript
for (auto & postfix : postfixes) for (auto & postfix : postfixes)
{ {
try { try {
std::string name = elem + prefix + t_module_name + postfix; const auto name = elem + prefix + t_module_name + postfix;
// std::cerr << "trying location: " << name << std::endl; // std::cerr << "trying location: " << name << std::endl;
load_module(version_stripped_name, name); load_module(version_stripped_name, name);
return name; return name;
@@ -832,7 +846,7 @@ namespace chaiscript
/// ///
/// \param[in] t_input Script to execute /// \param[in] t_input Script to execute
/// \param[in] t_handler Optional Exception_Handler used for automatic unboxing of script thrown exceptions /// \param[in] t_handler Optional Exception_Handler used for automatic unboxing of script thrown exceptions
/// \param[in] t_filename Optional filename to report to the user for where the error occured. Useful /// \param[in] t_filename Optional filename to report to the user for where the error occurred. Useful
/// in special cases where you are loading a file internally instead of using eval_file /// in special cases where you are loading a file internally instead of using eval_file
/// ///
/// \return result of the script execution /// \return result of the script execution
@@ -866,7 +880,7 @@ namespace chaiscript
} }
} }
/// \brief Loads the file specified by filename, evaluates it, and returns the typesafe result. /// \brief Loads the file specified by filename, evaluates it, and returns the type safe result.
/// \tparam T Type to extract from the result value of the script execution /// \tparam T Type to extract from the result value of the script execution
/// \param[in] t_filename File to load and parse. /// \param[in] t_filename File to load and parse.
/// \param[in] t_handler Optional Exception_Handler used for automatic unboxing of script thrown exceptions /// \param[in] t_handler Optional Exception_Handler used for automatic unboxing of script thrown exceptions

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@@ -40,9 +40,9 @@ def new(x) {
eval(type_name(x))(); eval(type_name(x))();
} }
def clone(x) : function_exists(type_name(x)) && call_exists(eval(type_name(x)), x) def clone(x) : function_exists(type_name(x)) && call_exists(eval(type_name(x)), x)
{ {
eval(type_name(x))(x); eval(type_name(x))(x).copy_var_attrs(x);
} }
@@ -56,11 +56,6 @@ def to_string(x) : call_exists(range, x) && !x.is_type("string"){
"[" + x.join(", ") + "]"; "[" + x.join(", ") + "]";
} }
# Basic to_string function
def to_string(x) {
internal_to_string(x);
}
# Prints to console with no carriage return # Prints to console with no carriage return
def puts(x) { def puts(x) {
print_string(x.to_string()); print_string(x.to_string());
@@ -136,8 +131,8 @@ def insert_at(container, pos, x)
# Returns the reverse of the given container # Returns the reverse of the given container
def reverse(container) { def reverse(container) {
auto retval = new(container); auto retval := new(container);
auto r = range(container); auto r := range(container);
while (!r.empty()) { while (!r.empty()) {
retval.push_back(r.back()); retval.push_back(r.back());
r.pop_back(); r.pop_back();
@@ -147,10 +142,16 @@ def reverse(container) {
# Return a range from a range # Return a range from a range
def range(r) : call_exists(empty, r) && call_exists(pop_front, r) && call_exists(pop_back, r) && call_exists(back, r) && call_exists(front, r) def range(r) : call_exists(empty, r) && call_exists(pop_front, r) && call_exists(pop_back, r) && call_exists(back, r) && call_exists(front, r)
{ {
return clone(r); clone(r);
} }
def range(r) : call_exists(range_internal, r)
{
var ri := range_internal(r);
ri.get_var_attr("internal_obj") := r;
ri;
}
# The retro attribute that contains the underlying range # The retro attribute that contains the underlying range
attr retro::m_range; attr retro::m_range;
@@ -200,19 +201,19 @@ def retro::empty()
# Performs the second value function over the container first value # Performs the second value function over the container first value
def for_each(container, func) : call_exists(range, container) { def for_each(container, func) : call_exists(range, container) {
var t_range = range(container); var t_range := range(container);
while (!t_range.empty()) { while (!t_range.empty()) {
func(t_range.front()); func(t_range.front());
t_range.pop_front(); t_range.pop_front();
} }
} }
def back_inserter(container) { def back_inserter(container) {
bind(push_back, container, _); bind(push_back, container, _);
} }
def contains(container, item, compare_func) : call_exists(range, container) { def contains(container, item, compare_func) : call_exists(range, container) {
auto t_range = range(container); auto t_range := range(container);
while (!t_range.empty()) { while (!t_range.empty()) {
if ( compare_func(t_range.front(), item) ) { if ( compare_func(t_range.front(), item) ) {
return true; return true;
@@ -220,15 +221,15 @@ def contains(container, item, compare_func) : call_exists(range, container) {
t_range.pop_front(); t_range.pop_front();
} }
return false; false;
} }
def contains(container, item) { def contains(container, item) {
return contains(container, item, eq) contains(container, item, eq)
} }
def map(container, func, inserter) : call_exists(range, container) { def map(container, func, inserter) : call_exists(range, container) {
auto range = range(container); auto range := range(container);
while (!range.empty()) { while (!range.empty()) {
inserter(func(range.front())); inserter(func(range.front()));
range.pop_front(); range.pop_front();
@@ -237,7 +238,7 @@ def map(container, func, inserter) : call_exists(range, container) {
# Performs the second value function over the container first value. Creates a new container with the results # Performs the second value function over the container first value. Creates a new container with the results
def map(container, func) { def map(container, func) {
auto retval = new(container); auto retval := new(container);
map(container, func, back_inserter(retval)); map(container, func, back_inserter(retval));
retval; retval;
} }
@@ -245,7 +246,7 @@ def map(container, func) {
# Performs the second value function over the container first value. Starts with initial and continues with each element. # Performs the second value function over the container first value. Starts with initial and continues with each element.
def foldl(container, func, initial) : call_exists(range, container){ def foldl(container, func, initial) : call_exists(range, container){
auto retval = initial; auto retval = initial;
auto range = range(container); auto range := range(container);
while (!range.empty()) { while (!range.empty()) {
retval = (func(range.front(), retval)); retval = (func(range.front(), retval));
range.pop_front(); range.pop_front();
@@ -266,8 +267,8 @@ def product(container) {
# Returns a new container with the elements of the first value concatenated with the elements of the second value # Returns a new container with the elements of the first value concatenated with the elements of the second value
def concat(x, y) : call_exists(clone, x) { def concat(x, y) : call_exists(clone, x) {
auto retval = x; auto retval = x;
auto inserter = back_inserter(retval); auto inserter := back_inserter(retval);
auto range = range(y); auto range := range(y);
while (!range.empty()) { while (!range.empty()) {
inserter(range.front()); inserter(range.front());
range.pop_front(); range.pop_front();
@@ -277,7 +278,7 @@ def concat(x, y) : call_exists(clone, x) {
def take(container, num, inserter) : call_exists(range, container) { def take(container, num, inserter) : call_exists(range, container) {
auto r = range(container); auto r := range(container);
auto i = num; auto i = num;
while ((i > 0) && (!r.empty())) { while ((i > 0) && (!r.empty())) {
inserter(r.front()); inserter(r.front());
@@ -289,14 +290,14 @@ def take(container, num, inserter) : call_exists(range, container) {
# Returns a new container with the given number of elements taken from the container # Returns a new container with the given number of elements taken from the container
def take(container, num) { def take(container, num) {
auto retval = new(container); auto retval := new(container);
take(container, num, back_inserter(retval)); take(container, num, back_inserter(retval));
retval; retval;
} }
def take_while(container, f, inserter) : call_exists(range, container) { def take_while(container, f, inserter) : call_exists(range, container) {
auto r = range(container); auto r := range(container);
while ((!r.empty()) && f(r.front())) { while ((!r.empty()) && f(r.front())) {
inserter(r.front()); inserter(r.front());
r.pop_front(); r.pop_front();
@@ -306,14 +307,14 @@ def take_while(container, f, inserter) : call_exists(range, container) {
# Returns a new container with the given elements match the second value function # Returns a new container with the given elements match the second value function
def take_while(container, f) { def take_while(container, f) {
auto retval = new(container); auto retval := new(container);
take_while(container, f, back_inserter(retval)); take_while(container, f, back_inserter(retval));
retval; retval;
} }
def drop(container, num, inserter) : call_exists(range, container) { def drop(container, num, inserter) : call_exists(range, container) {
auto r = range(container); auto r := range(container);
auto i = num; auto i = num;
while ((i > 0) && (!r.empty())) { while ((i > 0) && (!r.empty())) {
r.pop_front(); r.pop_front();
@@ -328,14 +329,14 @@ def drop(container, num, inserter) : call_exists(range, container) {
# Returns a new container with the given number of elements dropped from the given container # Returns a new container with the given number of elements dropped from the given container
def drop(container, num) { def drop(container, num) {
auto retval = new(container); auto retval := new(container);
drop(container, num, back_inserter(retval)); drop(container, num, back_inserter(retval));
retval; retval;
} }
def drop_while(container, f, inserter) : call_exists(range, container) { def drop_while(container, f, inserter) : call_exists(range, container) {
auto r = range(container); auto r := range(container);
while ((!r.empty())&& f(r.front())) { while ((!r.empty())&& f(r.front())) {
r.pop_front(); r.pop_front();
} }
@@ -348,7 +349,7 @@ def drop_while(container, f, inserter) : call_exists(range, container) {
# Returns a new container with the given elements dropped that match the second value function # Returns a new container with the given elements dropped that match the second value function
def drop_while(container, f) { def drop_while(container, f) {
auto retval = new(container); auto retval := new(container);
drop_while(container, f, back_inserter(retval)); drop_while(container, f, back_inserter(retval));
retval; retval;
} }
@@ -356,7 +357,7 @@ def drop_while(container, f) {
# Applies the second value function to the container. Starts with the first two elements. Expects at least 2 elements. # Applies the second value function to the container. Starts with the first two elements. Expects at least 2 elements.
def reduce(container, func) : container.size() >= 2 && call_exists(range, container) { def reduce(container, func) : container.size() >= 2 && call_exists(range, container) {
auto r = range(container); auto r := range(container);
auto retval = r.front(); auto retval = r.front();
r.pop_front(); r.pop_front();
retval = func(retval, r.front()); retval = func(retval, r.front());
@@ -372,7 +373,7 @@ def reduce(container, func) : container.size() >= 2 && call_exists(range, contai
# Returns a string of the elements in container delimited by the second value string # Returns a string of the elements in container delimited by the second value string
def join(container, delim) { def join(container, delim) {
auto retval = ""; auto retval = "";
auto range = range(container); auto range := range(container);
if (!range.empty()) { if (!range.empty()) {
retval += to_string(range.front()); retval += to_string(range.front());
range.pop_front(); range.pop_front();
@@ -387,7 +388,7 @@ def join(container, delim) {
def filter(container, f, inserter) : call_exists(range, container) { def filter(container, f, inserter) : call_exists(range, container) {
auto r = range(container); auto r := range(container);
while (!r.empty()) { while (!r.empty()) {
if (f(r.front())) { if (f(r.front())) {
inserter(r.front()); inserter(r.front());
@@ -399,7 +400,7 @@ def filter(container, f, inserter) : call_exists(range, container) {
# Returns a new Vector which match the second value function # Returns a new Vector which match the second value function
def filter(container, f) { def filter(container, f) {
auto retval = new(container); auto retval := new(container);
filter(container, f, back_inserter(retval)); filter(container, f, back_inserter(retval));
retval; retval;
} }
@@ -416,7 +417,7 @@ def generate_range(x, y, inserter) {
# Returns a new Vector which represents the range from the first value to the second value # Returns a new Vector which represents the range from the first value to the second value
def generate_range(x, y) { def generate_range(x, y) {
auto retval = Vector(); auto retval := Vector();
generate_range(x,y,back_inserter(retval)); generate_range(x,y,back_inserter(retval));
retval; retval;
} }
@@ -429,8 +430,8 @@ def collate(x, y) {
def zip_with(f, x, y, inserter) : call_exists(range, x) && call_exists(range, y) { def zip_with(f, x, y, inserter) : call_exists(range, x) && call_exists(range, y) {
auto r_x = range(x); auto r_x := range(x);
auto r_y = range(y); auto r_y := range(y);
while (!r_x.empty() && !r_y.empty()) { while (!r_x.empty() && !r_y.empty()) {
inserter(f(r_x.front(), r_y.front())); inserter(f(r_x.front(), r_y.front()));
r_x.pop_front(); r_x.pop_front();
@@ -441,7 +442,7 @@ def zip_with(f, x, y, inserter) : call_exists(range, x) && call_exists(range, y)
# Returns a new Vector which joins matching elements of the second and third value with the first value function # Returns a new Vector which joins matching elements of the second and third value with the first value function
def zip_with(f, x, y) { def zip_with(f, x, y) {
auto retval = Vector(); auto retval := Vector();
zip_with(f,x,y,back_inserter(retval)); zip_with(f,x,y,back_inserter(retval));
retval; retval;
} }
@@ -505,7 +506,7 @@ def string::trim() {
def find(container, value, compare_func) : call_exists(range, container) && is_type(compare_func, "Function") { def find(container, value, compare_func) : call_exists(range, container) && is_type(compare_func, "Function") {
auto range = range(container); auto range := range(container);
while (!range.empty()) { while (!range.empty()) {
if (compare_func(range.front(), value)) { if (compare_func(range.front(), value)) {
return range; return range;
@@ -513,12 +514,12 @@ def find(container, value, compare_func) : call_exists(range, container) && is_t
range.pop_front(); range.pop_front();
} }
} }
return range; range;
} }
def find(container, value) { def find(container, value) {
return find(container, value, eq) find(container, value, eq)
} }

View File

@@ -112,7 +112,7 @@ class Map
}; };
/// \brief A concept implemented by string, Vector and Map. It is convertable to Range, default constructable and back_insertable /// \brief A concept implemented by string, Vector and Map. It is convertible to Range, default constructable and back_insertable
class Container class Container
{ {
public: public:
@@ -153,10 +153,10 @@ void print(Object o);
/// \brief ChaiScript representation of std::string. It is an std::string but only some member are exposed to ChaiScript. /// \brief ChaiScript representation of std::string. It is an std::string but only some member are exposed to ChaiScript.
/// ///
/// Because the ChaiScript string object is an std::string, it is directly convertable to and from std::string /// Because the ChaiScript string object is an std::string, it is directly convertible to and from std::string
/// using the chaiscript::boxed_cast and chaiscript::var functions. /// using the chaiscript::boxed_cast and chaiscript::var functions.
/// ///
/// With the exception of string::trim, string::rtrim, string::ltrim, all members are direct passthroughs to the /// With the exception of string::trim, string::rtrim, string::ltrim, all members are direct pass-throughs to the
/// std::string of the same name. /// std::string of the same name.
/// ///
/// \note Object and function notations are equivalent in ChaiScript. This means that /// \note Object and function notations are equivalent in ChaiScript. This means that
@@ -519,7 +519,7 @@ class Function
/// \brief Returns a vector of Type_Info objects that represent the param types for this function. /// \brief Returns a vector of Type_Info objects that represent the param types for this function.
/// The first value in the list is the return type. /// The first value in the list is the return type.
/// ///
/// If this function is a conglomeration of several functions (get_contained_values().size() > 0) /// If this function is a conglomerate of several functions (get_contained_values().size() > 0)
/// then the function returns as many Type_Info objects as it can. If the functions contained all have /// then the function returns as many Type_Info objects as it can. If the functions contained all have
/// the same arity, then it represents the arity. If they have different arities, it returns only /// the same arity, then it represents the arity. If they have different arities, it returns only
/// one value - the return type. /// one value - the return type.
@@ -534,7 +534,7 @@ class Function
/// \endcode /// \endcode
Vector get_param_types() const; Vector get_param_types() const;
/// \brief Returns true if the function has a guard to it. Always returns falls for a conglomerate function /// \brief Returns true if the function has a guard to it. Always returns false for a conglomerate function
bool has_guard() const; bool has_guard() const;
/// \brief Calls the function with the given set of parameters and returns the value; /// \brief Calls the function with the given set of parameters and returns the value;

View File

@@ -21,8 +21,29 @@ namespace chaiscript
namespace utility namespace utility
{ {
/// \todo Use of this utility, and uniform initializer lists, is causing memory errors in MSVC /// Single step command for registering a class with ChaiScript
///
/// \param[in,out] t_module Model to add class to
/// \param[in] t_class_name Name of the class being registered
/// \param[in] t_constructors Vector of constructors to add
/// \param[in] t_funcs Vector of methods to add
///
/// \example Adding a basic class to ChaiScript in one step
///
/// \code
/// chaiscript::utility::add_class<test>(*m,
/// "test",
/// { constructor<test ()>(),
/// constructor<test (const test &)>() },
/// { {fun(&test::function), "function"},
/// {fun(&test::function2), "function2"},
/// {fun(&test::function3), "function3"},
/// {fun(static_cast<std::string(test::*)(double)>(&test::functionoverload)), "functionoverload" },
/// {fun(static_cast<std::string(test::*)(int)>(&test::functionoverload)), "functionoverload" },
/// {fun(static_cast<test & (test::*)(const test &)>(&test::operator=)), "=" }
/// }
/// );
///
template<typename Class, typename ModuleType> template<typename Class, typename ModuleType>
void add_class(ModuleType &t_module, void add_class(ModuleType &t_module,
const std::string &t_class_name, const std::string &t_class_name,
@@ -36,13 +57,11 @@ namespace chaiscript
t_module.add(ctor, t_class_name); t_module.add(ctor, t_class_name);
} }
for(auto fun: t_funcs) for(const auto &fun: t_funcs)
{ {
t_module.add(fun.first, fun.second); t_module.add(fun.first, fun.second);
} }
} }
} }
} }

View File

@@ -1,6 +1,25 @@
Notes: Notes:
======= =======
Current Version: 5.3.1 Current Version: 5.5.0
### Changes since 5.4.0
* 2x performance increase
* Significant code cleanups
* Throw exception if user attempts to call function on null object
* Allow user defined type conversions
* Fix object lifetime for nested function calls made at the global scope
* Fix returning of boolean values from function calls
### Changes since 5.3.1
* Decreased compile time and build size
* Make "reflection" module built in (losing some of the time / build size gains)
* Add new "class" syntax for ChaiScript defined methods and attributes see: [unittests/class.chai](unittests/class.chai) for examples
* Minor performance enhancements
* major to_string performance enhancements
* Provide API for retrieving registered type name #124
* Added strong reference to container to range object #132
### Changes since 5.3.0 ### Changes since 5.3.0
* Add automatic conversion of arithmetic return types, following the same * Add automatic conversion of arithmetic return types, following the same

134
samples/inheritance.cpp Normal file
View File

@@ -0,0 +1,134 @@
#include <chaiscript/chaiscript.hpp>
#include <chaiscript/chaiscript_stdlib.hpp>
class BaseClass
{
public:
BaseClass()
{
}
virtual ~BaseClass() {}
virtual std::string doSomething(float, double) const = 0;
void setValue(const std::string &t_val) {
if (validateValue(t_val))
{
m_value = t_val;
}
}
std::string getValue() const {
return m_value;
}
protected:
virtual bool validateValue(const std::string &t_val) = 0;
private:
std::string m_value;
};
class ChaiScriptDerived : public BaseClass
{
public:
ChaiScriptDerived(const std::vector<chaiscript::Boxed_Value> &t_funcs)
{
// using the range-checked .at() methods to give us an exception
// instead of a crash if the user passed in too-few params
tie(t_funcs.at(0), m_doSomethingImpl);
tie(t_funcs.at(1), m_validateValueImpl);
}
std::string doSomething(float f, double d) const CHAISCRIPT_OVERRIDE
{
assert(m_doSomethingImpl);
return m_doSomethingImpl(*this, f, d);
}
protected:
bool validateValue(const std::string &t_val) CHAISCRIPT_OVERRIDE
{
assert(m_validateValueImpl);
return m_validateValueImpl(*this, t_val);
}
private:
template<typename Param>
void tie(const chaiscript::Boxed_Value &t_func, Param &t_param)
{
t_param = chaiscript::boxed_cast<Param>(t_func);
}
std::function<std::string (const ChaiScriptDerived&, float, double)> m_doSomethingImpl;
std::function<bool (ChaiScriptDerived&, const std::string &t_val)> m_validateValueImpl;
};
int main()
{
chaiscript::ChaiScript chai(chaiscript::Std_Lib::library());
chai.add(chaiscript::fun(&BaseClass::doSomething), "doSomething");
chai.add(chaiscript::fun(&BaseClass::setValue), "setValue");
chai.add(chaiscript::fun(&BaseClass::getValue), "getValue");
chai.add(chaiscript::constructor<ChaiScriptDerived (const std::vector<chaiscript::Boxed_Value> &)>(), "ChaiScriptDerived");
chai.add(chaiscript::base_class<BaseClass, ChaiScriptDerived>());
chai.add(chaiscript::user_type<BaseClass>(), "BaseClass");
chai.add(chaiscript::user_type<ChaiScriptDerived>(), "ChaiScriptDerived");
std::string script = R""(
def MakeDerived() {
return ChaiScriptDerived(
// create a dynamically created array and pass it in to the constructor
[
fun(this, f, d) {
// see here that we are calling back into the 'this' pointer
return "${this.getValue()}${f * d}";
},
fun(this, new_val) {
if (new_val.size() < 5) {
true;
} else {
print("String ${new_val} is too long");
false;
}
}
]
);
}
var myderived := MakeDerived(); // avoid a copy by using reference assignment :=
)"";
chai.eval(script);
BaseClass &myderived = chai.eval<ChaiScriptDerived&>("myderived");
// at this point in the code myderived is both a ChaiScript variable and a C++ variable. In both cases
// it is a derivation of BaseClass, and the implementation is provided via ChaiScript functors
// assigned in the MakeDerived() factory function
//
// Notice that our validateValue() function has a requirement that the new string be < 5 characters long
myderived.setValue("1234");
assert(myderived.getValue() == "1234");
// chaiscript defined function will print out an error message and refuse to allow the setting
myderived.setValue("12345");
assert(myderived.getValue() == "1234");
chai.eval("myderived.setValue(\"new\")"); // set the value via chaiscript
assert(myderived.getValue() == "new");
// call the other derived method via chaiscript and return the value to c++ land:
std::string retval = chai.eval<std::string>("myderived.doSomething(2,4.3)");
assert(retval == "new8.6");
// The whole process is fully orthogonal
}

View File

@@ -70,12 +70,12 @@ int main(int /*argc*/, char * /*argv*/[]) {
std::string command = ""; std::string command = "";
// //
// this loop increases memoryusage, if RunFile is not called (just hitting enter) // this loop increases memory usage, if RunFile is not called (just hitting enter)
// as soon RunFile gets called, memory will be freed. // as soon RunFile gets called, memory will be freed.
// //
// scenario1 - RunFile gets called every Loop: memoryusage does not change // scenario1 - RunFile gets called every Loop: memory usage does not change
// scenario2 - RunFile gets never called (just hitting enter): memoryusage increases every loop // scenario2 - RunFile gets never called (just hitting enter): memory usage increases every loop
// scenario3 - RunFile gets in changing intervals: memoryusage goes up and down, but never as // scenario3 - RunFile gets in changing intervals: memory usage goes up and down, but never as
// low as in case 1 scenario3 : // low as in case 1 scenario3 :
while(command != "quit") while(command != "quit")

View File

@@ -17,15 +17,15 @@
#else #else
char *mystrdup (const char *s) { char *mystrdup (const char *s) {
size_t len = strlen(s) + 1; // Space for length plus nul size_t len = strlen(s); // Space for length plus nul
char *d = static_cast<char*>(malloc (len)); char *d = static_cast<char*>(malloc (len+1));
if (d == nullptr) return nullptr; // No memory if (d == nullptr) return nullptr; // No memory
#ifdef CHAISCRIPT_MSVC #ifdef CHAISCRIPT_MSVC
strcpy_s(d, len, s); // Copy the characters strcpy_s(d, len, s); // Copy the characters
#else #else
strncpy(d,s,len); // Copy the characters strncpy(d,s,len); // Copy the characters
d[len] = '\0';
#endif #endif
d[len] = '\0';
return d; // Return the new string return d; // Return the new string
} }

View File

@@ -1,129 +0,0 @@
// This file is distributed under the BSD License.
// See "license.txt" for details.
// Copyright 2009-2012, Jonathan Turner (jonathan@emptycrate.com)
// Copyright 2009-2014, Jason Turner (jason@emptycrate.com)
// http://www.chaiscript.com
#include <chaiscript/chaiscript.hpp>
#include <chaiscript/dispatchkit/bootstrap.hpp>
#include <chaiscript/dispatchkit/bootstrap_stl.hpp>
#include <chaiscript/utility/utility.hpp>
#include <string>
// MSVC doesn't like that we are using C++ return types from our C declared module
// but this is the best way to do it for cross platform compatibility
#ifdef CHAISCRIPT_MSVC
#pragma warning(push)
#pragma warning(disable : 4190)
#endif
bool has_parse_tree(const chaiscript::Const_Proxy_Function &t_pf)
{
std::shared_ptr<const chaiscript::dispatch::Dynamic_Proxy_Function> pf
= std::dynamic_pointer_cast<const chaiscript::dispatch::Dynamic_Proxy_Function>(t_pf);
if (pf)
{
if (pf->get_parse_tree())
{
return true;
} else {
return false;
}
} else {
return false;
}
}
chaiscript::AST_NodePtr get_parse_tree(const chaiscript::Const_Proxy_Function &t_pf)
{
std::shared_ptr<const chaiscript::dispatch::Dynamic_Proxy_Function> pf
= std::dynamic_pointer_cast<const chaiscript::dispatch::Dynamic_Proxy_Function>(t_pf);
if (pf)
{
if (pf->get_parse_tree())
{
return pf->get_parse_tree();
} else {
throw std::runtime_error("Function does not have a parse tree");
}
} else {
throw std::runtime_error("Function does not have a parse tree");
}
}
#ifdef __llvm__
#pragma clang diagnostic push
#pragma clang diagnostic ignored "-Wreturn-type-c-linkage"
#endif
CHAISCRIPT_MODULE_EXPORT chaiscript::ModulePtr create_chaiscript_module_reflection()
{
chaiscript::ModulePtr m(new chaiscript::Module());
m->add(chaiscript::fun(&has_parse_tree), "has_parse_tree");
m->add(chaiscript::fun(&get_parse_tree), "get_parse_tree");
m->add(chaiscript::base_class<std::exception, chaiscript::exception::eval_error>());
chaiscript::bootstrap::standard_library::vector_type<std::vector<std::shared_ptr<chaiscript::AST_Node> > >("AST_NodeVector", m);
using namespace chaiscript;
chaiscript::utility::add_class<chaiscript::exception::eval_error>(*m,
"eval_error",
{ },
{ {fun(&chaiscript::exception::eval_error::reason), "reason"},
{fun(&chaiscript::exception::eval_error::call_stack), "call_stack"} }
);
chaiscript::utility::add_class<chaiscript::File_Position>(*m,
"File_Position",
{ constructor<File_Position()>(),
constructor<File_Position(int, int)>() },
{ {fun(&File_Position::line), "line"},
{fun(&File_Position::column), "column"} }
);
chaiscript::utility::add_class<AST_Node>(*m,
"AST_Node",
{ },
{ {fun(&AST_Node::text), "text"},
{fun(&AST_Node::identifier), "identifier"},
{fun(&AST_Node::filename), "filename"},
{fun(&AST_Node::start), "start"},
{fun(&AST_Node::end), "end"},
{fun(&AST_Node::internal_to_string), "internal_to_string"},
{fun(&AST_Node::children), "children"},
{fun(&AST_Node::replace_child), "replace_child"}
}
);
chaiscript::utility::add_class<parser::ChaiScript_Parser>(*m,
"ChaiScript_Parser",
{ constructor<parser::ChaiScript_Parser ()>() },
{ {fun(&parser::ChaiScript_Parser::parse), "parse"},
{fun(&parser::ChaiScript_Parser::ast), "ast"} }
);
return m;
}
#ifdef __llvm__
#pragma clang diagnostic pop
#endif
#ifdef CHAISCRIPT_MSVC
#pragma warning(pop)
#endif

View File

@@ -2,6 +2,8 @@
#include <chaiscript/chaiscript.hpp> #include <chaiscript/chaiscript.hpp>
#include <string> #include <string>
class TestBaseType class TestBaseType
{ {
public: public:
@@ -22,6 +24,30 @@ class TestBaseType
TestBaseType &operator=(const TestBaseType &); TestBaseType &operator=(const TestBaseType &);
}; };
class Type2
{
public:
Type2(TestBaseType t_bt)
: m_bt(std::move(t_bt)),
m_str("Hello World")
{
}
int get_val() const
{
return m_bt.val;
}
const char *get_str() const
{
return m_str.c_str();
}
private:
TestBaseType m_bt;
std::string m_str;
};
enum TestEnum enum TestEnum
{ {
TestValue1 = 1 TestValue1 = 1
@@ -51,12 +77,17 @@ class TestMoreDerivedType : public TestDerivedType
std::shared_ptr<TestBaseType> derived_type_factory() std::shared_ptr<TestBaseType> derived_type_factory()
{ {
return std::shared_ptr<TestBaseType>(new TestDerivedType()); return std::make_shared<TestDerivedType>();
} }
std::shared_ptr<TestBaseType> more_derived_type_factory() std::shared_ptr<TestBaseType> more_derived_type_factory()
{ {
return std::shared_ptr<TestBaseType>(new TestMoreDerivedType()); return std::make_shared<TestMoreDerivedType>();
}
std::shared_ptr<TestBaseType> null_factory()
{
return std::shared_ptr<TestBaseType>();
} }
std::string hello_world() std::string hello_world()
@@ -90,6 +121,7 @@ CHAISCRIPT_MODULE_EXPORT chaiscript::ModulePtr create_chaiscript_module_test_mo
m->add(chaiscript::user_type<TestBaseType>(), "TestBaseType"); m->add(chaiscript::user_type<TestBaseType>(), "TestBaseType");
m->add(chaiscript::user_type<TestDerivedType>(), "TestDerivedType"); m->add(chaiscript::user_type<TestDerivedType>(), "TestDerivedType");
m->add(chaiscript::user_type<TestMoreDerivedType>(), "TestMoreDerivedType"); m->add(chaiscript::user_type<TestMoreDerivedType>(), "TestMoreDerivedType");
m->add(chaiscript::user_type<Type2>(), "Type2");
m->add(chaiscript::constructor<TestBaseType ()>(), "TestBaseType"); m->add(chaiscript::constructor<TestBaseType ()>(), "TestBaseType");
// m->add(chaiscript::constructor<TestBaseType (int)>(), "TestBaseType"); // m->add(chaiscript::constructor<TestBaseType (int)>(), "TestBaseType");
@@ -111,6 +143,7 @@ CHAISCRIPT_MODULE_EXPORT chaiscript::ModulePtr create_chaiscript_module_test_mo
m->add(chaiscript::fun(&derived_type_factory), "derived_type_factory"); m->add(chaiscript::fun(&derived_type_factory), "derived_type_factory");
m->add(chaiscript::fun(&more_derived_type_factory), "more_derived_type_factory"); m->add(chaiscript::fun(&more_derived_type_factory), "more_derived_type_factory");
m->add(chaiscript::fun(&null_factory), "null_factory");
m->add(chaiscript::fun(&TestDerivedType::func), "func"); m->add(chaiscript::fun(&TestDerivedType::func), "func");
@@ -129,6 +162,12 @@ CHAISCRIPT_MODULE_EXPORT chaiscript::ModulePtr create_chaiscript_module_test_mo
m->add(chaiscript::fun(&to_int), "to_int"); m->add(chaiscript::fun(&to_int), "to_int");
m->add(chaiscript::fun(&TestBaseType::constMe), "constMe"); m->add(chaiscript::fun(&TestBaseType::constMe), "constMe");
m->add(chaiscript::type_conversion<TestBaseType, Type2>([](const TestBaseType &t_bt) { return Type2(t_bt); }));
m->add(chaiscript::fun(&Type2::get_val), "get_val");
m->add(chaiscript::fun(&Type2::get_str), "get_str");
m->add(chaiscript::type_conversion<const char *, std::string>());
m->add(chaiscript::constructor<Type2 (const TestBaseType &)>(), "Type2");
return m; return m;
} }

View File

@@ -1,4 +1,3 @@
load_module("reflection")
def deep() def deep()
{ {

View File

@@ -1,4 +1,3 @@
load_module("reflection")
var parser := ChaiScript_Parser() var parser := ChaiScript_Parser()
var parse_success = parser.parse("3 + 4", "INPUT") var parse_success = parser.parse("3 + 4", "INPUT")
var a := parser.ast() var a := parser.ast()

27
unittests/class.chai Normal file
View File

@@ -0,0 +1,27 @@
class Vector3
{
// you can use attr, auto or var in this context
attr x
auto y
var z
def Vector3(x,y,z)
{
this.x = x
this.y = y
this.z = z
}
def doSomething(mult)
{
return this.x * this.y * this.z * mult
}
}
auto v = Vector3(1,2,3)
assert_equal(1, v.x)
assert_equal(v.doSomething(2), 12)

View File

@@ -1,4 +1,3 @@
load_module("reflection")
def deep() def deep()
{ {

View File

@@ -0,0 +1,13 @@
load_module("test_module")
auto o := null_factory();
try {
o.func();
} catch (e) {
exit(0);
}
assert_true(false);

View File

@@ -1,4 +1,3 @@
load_module("reflection")
try { try {
eval("def `+`(x, y) \n { \n print(i); \n } \n \n var i = 10; \n \"1\" + 1;\n") eval("def `+`(x, y) \n { \n print(i); \n } \n \n var i = 10; \n \"1\" + 1;\n")

View File

@@ -2,3 +2,9 @@ auto x = [1, 2, 3, 4]
auto r = range(x) auto r = range(x)
r.pop_front() r.pop_front()
assert_equal(2, r.front()); assert_equal(2, r.front());
// test with temporary vector for range
auto q = range([1, 2, 3, 4])
q.pop_front()
assert_equal(2, q.front());

View File

@@ -1,4 +1,3 @@
load_module("reflection")
auto& parser = ChaiScript_Parser() auto& parser = ChaiScript_Parser()
auto parse_success = parser.parse("3 + 4", "INPUT") auto parse_success = parser.parse("3 + 4", "INPUT")
auto& a = parser.ast() auto& a = parser.ast()

View File

@@ -2,6 +2,7 @@
#include <chaiscript/chaiscript_defines.hpp> #include <chaiscript/chaiscript_defines.hpp>
#include <chaiscript/dispatchkit/type_info.hpp> #include <chaiscript/dispatchkit/type_info.hpp>
#include <iostream>
#include <cstdlib> #include <cstdlib>
void test_type(const chaiscript::Type_Info &ti, bool t_is_const, bool t_is_pointer, bool t_is_reference, bool t_is_void, void test_type(const chaiscript::Type_Info &ti, bool t_is_const, bool t_is_pointer, bool t_is_reference, bool t_is_void,
@@ -30,5 +31,7 @@ int main()
test_type(chaiscript::user_type<const int *>(), true, true, false, false, false); test_type(chaiscript::user_type<const int *>(), true, true, false, false, false);
test_type(chaiscript::Type_Info(), false, false, false, false, true); test_type(chaiscript::Type_Info(), false, false, false, false, true);
std::cout << "Size of Type_Info " << sizeof(chaiscript::Type_Info) << std::endl;
return EXIT_SUCCESS; return EXIT_SUCCESS;
} }

View File

@@ -0,0 +1,22 @@
// Tests to make sure that the order in which function dispatches occur is correct
#include <chaiscript/chaiscript.hpp>
#include <cstdlib>
class MyClass
{
};
int main()
{
chaiscript::ChaiScript chai;
auto type = chaiscript::user_type<MyClass>();
chai.add(type, "MyClass");
if (chai.get_type_name(type) == "MyClass" && chai.get_type_name<MyClass>() == "MyClass")
{
return EXIT_SUCCESS;
} else {
return EXIT_FAILURE;
}
}

View File

@@ -0,0 +1,11 @@
add_type_conversion(type("string"), type("Type_Info"), fun(s) { return type(s); });
// This looks simple, but it takes the string "string" and using the registered
// conversion above, automatically converts that into a Type_Info object, which then
// allows the Type_Info.name() function to be called
assert_equal("string".name(), "string");

View File

@@ -0,0 +1,27 @@
load_module("test_module")
auto t := TestBaseType();
// This uses the TestBaseType to Type2 user type
// conversion which was added in the module and then calls
// "get_val()" which exists on the Type2 type
//assert_equal(t.get_val(), 10);
//print("Made it past test 1");
var t2 := Type2(t);
var str = string(get_str(t2));
assert_equal("Hello World", str);
print("Made it past test 2");
assert_equal(11, size(get_str(t2)));
print("Made it past test 3");
assert_equal(11, t2.get_str().size());
print("Made it past test 4");
assert_equal(11, t.get_str().size());
print("Made it past test 5");