Compare commits
344 Commits
Release-2.
...
Release-5.
Author | SHA1 | Date | |
---|---|---|---|
![]() |
a67022e31e | ||
![]() |
a951d2b0af | ||
![]() |
b7e1cf41e5 | ||
![]() |
30104cc3ed | ||
![]() |
5a380abc68 | ||
![]() |
d2aba2ef56 | ||
![]() |
4ebfe264e9 | ||
![]() |
a3e299fe1b | ||
![]() |
832df7f9e8 | ||
![]() |
6c53e08e9b | ||
![]() |
b1a27020f7 | ||
![]() |
4767aeb544 | ||
![]() |
254d176266 | ||
![]() |
66deef52c8 | ||
![]() |
a5f29e93f5 | ||
![]() |
8f7793a795 | ||
![]() |
7f253bd6c1 | ||
![]() |
2969f61fe4 | ||
![]() |
7cbd494123 | ||
![]() |
ed15cc1730 | ||
![]() |
db8863c736 | ||
![]() |
13a049cf54 | ||
![]() |
4233d21e5b | ||
![]() |
f65e095e4d | ||
![]() |
f2c6745b8a | ||
![]() |
7ad58c7bcd | ||
![]() |
13ffc92bc3 | ||
![]() |
433905b33c | ||
![]() |
3a7eff1478 | ||
![]() |
ef46d1bf60 | ||
![]() |
654f7e6b01 | ||
![]() |
e853e2e4ac | ||
![]() |
4aec12c68f | ||
![]() |
1bdedd3b45 | ||
![]() |
a818e7b185 | ||
![]() |
5aed00dd0b | ||
![]() |
349425fe8a | ||
![]() |
9162b02ce9 | ||
![]() |
6c57729779 | ||
![]() |
ba9d13bf7b | ||
![]() |
56757973b6 | ||
![]() |
f1f4aeb4be | ||
![]() |
16bdfe4571 | ||
![]() |
804de05a0a | ||
![]() |
0fd4b828f2 | ||
![]() |
62891b8537 | ||
![]() |
ae02706c71 | ||
![]() |
c386af6813 | ||
![]() |
4c5df91d51 | ||
![]() |
a0f7c46cc9 | ||
![]() |
08c153abea | ||
![]() |
897ad7007f | ||
![]() |
13fb930676 | ||
![]() |
7f5fce001b | ||
![]() |
8af41b1d3c | ||
![]() |
90125d0f9a | ||
![]() |
919b6430c4 | ||
![]() |
7027f6b834 | ||
![]() |
cebd2c9763 | ||
![]() |
025db4ce3a | ||
![]() |
78f02c375e | ||
![]() |
4e14a57016 | ||
![]() |
b82895c489 | ||
![]() |
cf97a73485 | ||
![]() |
37b8e6c3f9 | ||
![]() |
c73f16fdfe | ||
![]() |
68df78a2a6 | ||
![]() |
af1e02b0bb | ||
![]() |
bca86c87e1 | ||
![]() |
a04dbf2c2d | ||
![]() |
4bcaa75fa4 | ||
![]() |
7deb2311f5 | ||
![]() |
4674594ee7 | ||
![]() |
730bad9728 | ||
![]() |
1f4900c363 | ||
![]() |
8e24eef265 | ||
![]() |
974c903d1c | ||
![]() |
9ec78752a0 | ||
![]() |
437f6a03a9 | ||
![]() |
94fefa0690 | ||
![]() |
91dc3604f5 | ||
![]() |
48ecb3e2b4 | ||
![]() |
59dfc847ae | ||
![]() |
cdfefed385 | ||
![]() |
98d2eadde2 | ||
![]() |
286b130f47 | ||
![]() |
b0b1549503 | ||
![]() |
277b4eec9a | ||
![]() |
927619bf47 | ||
![]() |
41b0c7768c | ||
![]() |
3b95931973 | ||
![]() |
13f98fa8ce | ||
![]() |
179a674b00 | ||
![]() |
ee4c9575ae | ||
![]() |
b615d2a423 | ||
![]() |
dc6998259e | ||
![]() |
b0953fb466 | ||
![]() |
1186926f30 | ||
![]() |
70db5d67ff | ||
![]() |
136b877afa | ||
![]() |
9a9d4e1ae0 | ||
![]() |
27ae40b813 | ||
![]() |
5dc0931ca2 | ||
![]() |
5a3975b7a4 | ||
![]() |
bc75df4d58 | ||
![]() |
b27aa50d6a | ||
![]() |
488f2ea393 | ||
![]() |
db0e342a96 | ||
![]() |
702b5fdba1 | ||
![]() |
3329732ceb | ||
![]() |
e1e0561c7e | ||
![]() |
52d9e1e871 | ||
![]() |
a28dfd8695 | ||
![]() |
1eb402e474 | ||
![]() |
3765c23598 | ||
![]() |
784ca41270 | ||
![]() |
425ca59a34 | ||
![]() |
abfd37644e | ||
![]() |
4bf3783d0b | ||
![]() |
4a99471304 | ||
![]() |
e0d7977f8a | ||
![]() |
92de42e42b | ||
![]() |
e3350fe55f | ||
![]() |
2ca7a7d7da | ||
![]() |
ac4bb95dfb | ||
![]() |
535adce298 | ||
![]() |
d04960bc4a | ||
![]() |
12bd5b0af5 | ||
![]() |
d6b475239a | ||
![]() |
6f1bffda3a | ||
![]() |
64382a2399 | ||
![]() |
f996c0df37 | ||
![]() |
d5e1650167 | ||
![]() |
cc927fc6bc | ||
![]() |
6f282b6a56 | ||
![]() |
194001f9a1 | ||
![]() |
a3c3b8683b | ||
![]() |
5efdcdff99 | ||
![]() |
cd97880d70 | ||
![]() |
0a9cb0cbe9 | ||
![]() |
99aaa079a4 | ||
![]() |
f4080c4c75 | ||
![]() |
4522ff0732 | ||
![]() |
b297162d13 | ||
![]() |
62cf6293e8 | ||
![]() |
6bb2678d18 | ||
![]() |
aa402fdfde | ||
![]() |
53108463df | ||
![]() |
c842bf14c1 | ||
![]() |
e2da56f199 | ||
![]() |
afa96ecbf9 | ||
![]() |
d9727973c1 | ||
![]() |
0293762904 | ||
![]() |
95c6131ce7 | ||
![]() |
e326fe6f2d | ||
![]() |
2b64c90a0e | ||
![]() |
dd0d91c7e3 | ||
![]() |
a386142fa6 | ||
![]() |
cacc744411 | ||
![]() |
2d23578e0b | ||
![]() |
f8880066ea | ||
![]() |
a85423869f | ||
![]() |
469c02ad14 | ||
![]() |
1cd9a9098c | ||
![]() |
5ff14a54db | ||
![]() |
28e3d442e2 | ||
![]() |
bb0edcb62a | ||
![]() |
9a015a5c49 | ||
![]() |
9d20f60903 | ||
![]() |
5426496b4f | ||
![]() |
a549e41558 | ||
![]() |
a82c892a4e | ||
![]() |
9e9fb3ad7d | ||
![]() |
8cc3651c76 | ||
![]() |
4d879afca7 | ||
![]() |
afae221cb3 | ||
![]() |
b064bb61e9 | ||
![]() |
c839e4bc21 | ||
![]() |
7a9baeb350 | ||
![]() |
6d4041b2a1 | ||
![]() |
1932cbfbbc | ||
![]() |
8fecf5c145 | ||
![]() |
6131a9c4c1 | ||
![]() |
881d569d8e | ||
![]() |
6c18c197c6 | ||
![]() |
f47ec0d522 | ||
![]() |
4053196188 | ||
![]() |
5b40a85024 | ||
![]() |
36faba8ed3 | ||
![]() |
7d022c4f0d | ||
![]() |
b933bb6c50 | ||
![]() |
92bfcfdcf3 | ||
![]() |
3b754cfec4 | ||
![]() |
3689c01e4b | ||
![]() |
4b90fbd07a | ||
![]() |
1a225dca67 | ||
![]() |
226666c2bb | ||
![]() |
d4ef226911 | ||
![]() |
6491262491 | ||
![]() |
2c4d69bfc0 | ||
![]() |
f423969a8e | ||
![]() |
36cd4c370a | ||
![]() |
85f69782b2 | ||
![]() |
1f130c0891 | ||
![]() |
fdd1b40a9f | ||
![]() |
6993d58fdc | ||
![]() |
1845114d36 | ||
![]() |
bba1ffde38 | ||
![]() |
18d4984258 | ||
![]() |
845eb394ac | ||
![]() |
66b2adba5c | ||
![]() |
02db23e9e2 | ||
![]() |
fbef83ecb7 | ||
![]() |
88fbf41091 | ||
![]() |
897385953c | ||
![]() |
319f9e4de9 | ||
![]() |
2786156086 | ||
![]() |
e5f9dbb93b | ||
![]() |
61b8481514 | ||
![]() |
8a0ef143c9 | ||
![]() |
f1918f147d | ||
![]() |
0d238b1617 | ||
![]() |
d22a77503c | ||
![]() |
8dec35ba19 | ||
![]() |
a91c66d286 | ||
![]() |
8ecd3a084b | ||
![]() |
79e8af4f6e | ||
![]() |
de5822873b | ||
![]() |
d6b8e32373 | ||
![]() |
bbe89e61bc | ||
![]() |
87c29ebc91 | ||
![]() |
92c836c58a | ||
![]() |
58e5df0a9a | ||
![]() |
854737ea25 | ||
![]() |
8bd512a0af | ||
![]() |
deb4cb036f | ||
![]() |
cd8bead54a | ||
![]() |
637164e457 | ||
![]() |
9dd9ffec46 | ||
![]() |
ac0688a8d7 | ||
![]() |
e3feb05e05 | ||
![]() |
2ce55d81b3 | ||
![]() |
4e06478fb8 | ||
![]() |
46a669dab1 | ||
![]() |
d9a92a5148 | ||
![]() |
f6b6936348 | ||
![]() |
0b97fcb4df | ||
![]() |
eee5c19b6e | ||
![]() |
5cc4a758ab | ||
![]() |
7c2550ba74 | ||
![]() |
41d7842963 | ||
![]() |
13b35f2f47 | ||
![]() |
18c6ed71f0 | ||
![]() |
7ac22c7072 | ||
![]() |
c9c4f1add7 | ||
![]() |
65d054b36e | ||
![]() |
894063261e | ||
![]() |
80f576a2f3 | ||
![]() |
0a2b5d7a40 | ||
![]() |
660e978da3 | ||
![]() |
e90d49bb9d | ||
![]() |
13f53839c9 | ||
![]() |
65edf30ef0 | ||
![]() |
7ef1b81504 | ||
![]() |
3aee589274 | ||
![]() |
97081b1f33 | ||
![]() |
a758c86ba5 | ||
![]() |
5f661fad20 | ||
![]() |
811764e048 | ||
![]() |
0f9b1aaf92 | ||
![]() |
912379d58c | ||
![]() |
91c05f0e73 | ||
![]() |
906140ec78 | ||
![]() |
e75a354a04 | ||
![]() |
36173d277d | ||
![]() |
e1e48d732f | ||
![]() |
6e18aa3dcd | ||
![]() |
6a18862c79 | ||
![]() |
b3dafa385e | ||
![]() |
70cc1111f3 | ||
![]() |
2d353cb189 | ||
![]() |
67bad374a9 | ||
![]() |
bff5b8bce0 | ||
![]() |
2cdfac4e47 | ||
![]() |
0caa782437 | ||
![]() |
caa67e811c | ||
![]() |
c1318eb8b4 | ||
![]() |
3f87210dc5 | ||
![]() |
c3da778103 | ||
![]() |
5a92146d28 | ||
![]() |
3ab91356e5 | ||
![]() |
fa2a7045a7 | ||
![]() |
512d6b342d | ||
![]() |
4ab29013ec | ||
![]() |
3ae748c026 | ||
![]() |
d8c979b204 | ||
![]() |
74e719c053 | ||
![]() |
43dbd8ac78 | ||
![]() |
7b77af3736 | ||
![]() |
8b35434e6f | ||
![]() |
1e867f5760 | ||
![]() |
670eb0692b | ||
![]() |
4b9d2d130f | ||
![]() |
30affb8855 | ||
![]() |
22c2be835a | ||
![]() |
a39d70dbca | ||
![]() |
10986c159f | ||
![]() |
cfa42158af | ||
![]() |
054179ead3 | ||
![]() |
8a6a46d0d3 | ||
![]() |
efae821996 | ||
![]() |
31feab6053 | ||
![]() |
7ef12f634d | ||
![]() |
c6452c4bd6 | ||
![]() |
71de169e09 | ||
![]() |
329244759f | ||
![]() |
c5f20ea158 | ||
![]() |
58c62f6333 | ||
![]() |
7f037b26d4 | ||
![]() |
b1e357423f | ||
![]() |
3a904d9f74 | ||
![]() |
d838f7a6d4 | ||
![]() |
556e7ad916 | ||
![]() |
21253043d1 | ||
![]() |
f215cae866 | ||
![]() |
ea93903884 | ||
![]() |
f03189c168 | ||
![]() |
a122403c20 | ||
![]() |
e1fbf54e40 | ||
![]() |
2b80ca8cc5 | ||
![]() |
f4e4f92dae | ||
![]() |
4358564065 | ||
![]() |
a463ee5ff2 | ||
![]() |
cd015a8437 | ||
![]() |
8be4aa08db | ||
![]() |
edee892cad | ||
![]() |
b971ee44ad | ||
![]() |
b9ae4cd528 | ||
![]() |
4ec21ff552 | ||
![]() |
f5f99961c1 | ||
![]() |
f7086c10ec | ||
![]() |
3d19138c95 | ||
![]() |
35ac7342b6 | ||
![]() |
3f9b5081c6 |
194
CMakeLists.txt
194
CMakeLists.txt
@@ -2,8 +2,13 @@ cmake_minimum_required(VERSION 2.8)
|
||||
|
||||
project(chaiscript)
|
||||
|
||||
option(MULTITHREAD_SUPPORT_ENABLED "Multithreaded Support Enabled" TRUE)
|
||||
option(BUILD_MODULES "Build Extra Modules (stl, reflection)" TRUE)
|
||||
option(BUILD_SAMPLES "Build Samples Folder" FALSE)
|
||||
|
||||
list(APPEND CPACK_SOURCE_IGNORE_FILES "${CMAKE_CURRENT_BINARY_DIR}")
|
||||
list(APPEND CPACK_SOURCE_IGNORE_FILES "\\\\.svn")
|
||||
list(APPEND CPACK_SOURCE_IGNORE_FILES "\\\\.git")
|
||||
list(APPEND CPACK_SOURCE_IGNORE_FILES ".swp")
|
||||
list(APPEND CPACK_SOURCE_IGNORE_FILES ".*~")
|
||||
|
||||
@@ -11,103 +16,212 @@ set(CPACK_RESOURCE_FILE_LICENSE "${CMAKE_CURRENT_SOURCE_DIR}/license.txt")
|
||||
set(CPACK_RESOURCE_FILE_README "${CMAKE_CURRENT_SOURCE_DIR}/readme.txt")
|
||||
set(CPACK_PACKAGE_DESCRIPTION_FILE "${CMAKE_CURRENT_SOURCE_DIR}/description.txt")
|
||||
|
||||
set(CPACK_PACKAGE_VERSION_MAJOR 2)
|
||||
set(CPACK_PACKAGE_VERSION_MINOR 3)
|
||||
set(CPACK_PACKAGE_VERSION_PATCH 3)
|
||||
set(CPACK_PACKAGE_VERSION_MAJOR 5)
|
||||
set(CPACK_PACKAGE_VERSION_MINOR 0)
|
||||
set(CPACK_PACKAGE_VERSION_PATCH 0)
|
||||
set(CPACK_PACKAGE_EXECUTABLES "chai;ChaiScript Eval")
|
||||
set(CPACK_PACKAGE_VENDOR "ChaiScript.com")
|
||||
set(CPACK_PACKAGE_CONTACT "contact@chaiscript.com")
|
||||
set(CPACK_PACKAGE_DESCRIPTION_SUMMARY "An embedded scripting language for C++")
|
||||
|
||||
set(CPACK_DEBIAN_PACKAGE_DEPENDS "libboost-dev (>=1.36.0)")
|
||||
set(CPACK_DEBIAN_PACKAGE_SECTION "devel")
|
||||
set(CPACK_DEBIAN_PACKAGE_PRIORITY "optional")
|
||||
|
||||
set(CPACK_RPM_PACKAGE_LICENSE "BSD")
|
||||
set(CPACK_RPM_PACKAGE_GROUP "Programming")
|
||||
set(CPACK_RPM_PACKAGE_REQUIRES "boost-devel >= 1.36.0, boost-thread >= 1.36.0")
|
||||
|
||||
set(CHAI_VERSION ${CPACK_PACKAGE_VERSION_MAJOR}.${CPACK_PACKAGE_VERSION_MINOR}.${CPACK_PACKAGE_VERSION_PATCH})
|
||||
|
||||
configure_file(Doxyfile.in ${CMAKE_BINARY_DIR}/Doxyfile)
|
||||
|
||||
include(CTest)
|
||||
include(CPack)
|
||||
|
||||
FIND_LIBRARY(READLINE_LIBRARY NAMES readline PATH /usr/lib /usr/local/lib /opt/local/lib)
|
||||
find_library(READLINE_LIBRARY NAMES readline PATH /usr/lib /usr/local/lib /opt/local/lib)
|
||||
|
||||
enable_testing()
|
||||
|
||||
|
||||
MESSAGE(STATUS "Detecting readline support")
|
||||
message(STATUS "Detecting readline support")
|
||||
if (READLINE_LIBRARY)
|
||||
MESSAGE(STATUS "Found: ${READLINE_LIBRARY}")
|
||||
SET (READLINE_LIB readline)
|
||||
ADD_DEFINITIONS(/DREADLINE_AVAILABLE)
|
||||
message(STATUS "Found: ${READLINE_LIBRARY}")
|
||||
set (READLINE_LIB readline)
|
||||
add_definitions(/DREADLINE_AVAILABLE)
|
||||
else(READLINE_LIBRARY)
|
||||
MESSAGE(STATUS "Not Found")
|
||||
SET (READLINE_LIB )
|
||||
SET (READLINE_FLAG )
|
||||
message(STATUS "Not Found")
|
||||
set (READLINE_LIB )
|
||||
set (READLINE_FLAG )
|
||||
endif(READLINE_LIBRARY)
|
||||
|
||||
#SET (CMAKE_C_FLAGS_REL " -Wall -O3 ${READLINE_FLAG}")
|
||||
#SET (CMAKE_CXX_FLAGS_REL " -Wall -O3 ${READLINE_FLAG}")
|
||||
if(MSVC)
|
||||
add_definitions(/W4)
|
||||
if(CMAKE_CL_64)
|
||||
add_definitions(/bigobj)
|
||||
endif()
|
||||
else()
|
||||
add_definitions(-Wall -Wextra -Wshadow -pedantic -std=c++0x)
|
||||
|
||||
#SET (CMAKE_C_FLAGS " -Wall -ggdb ${READLINE_FLAG}")
|
||||
#SET (CMAKE_CXX_FLAGS " -Wall -ggdb ${READLINE_FLAG}")
|
||||
if (APPLE)
|
||||
add_definitions(-Wno-sign-compare)
|
||||
endif()
|
||||
endif()
|
||||
|
||||
if (CMAKE_CXX_COMPILER MATCHES ".*clang")
|
||||
|
||||
option(USE_LIBCXX "Use clang's libcxx" TRUE)
|
||||
|
||||
if (USE_LIBCXX)
|
||||
add_definitions(-stdlib=libc++)
|
||||
set (EXTRA_LINKER_FLAGS -std=c++0x -stdlib=libc++)
|
||||
else ()
|
||||
set (EXTRA_LINKER_FLAGS -std=c++0x )
|
||||
endif()
|
||||
else()
|
||||
set (EXTRA_LINKER_FLAGS )
|
||||
endif()
|
||||
|
||||
include_directories(include)
|
||||
|
||||
SET(Boost_ADDITIONAL_VERSIONS "1.43" "1.43.0" "1.42" "1.42.0" "1.41")
|
||||
SET(Boost_USE_MULTITHREADED ON)
|
||||
|
||||
find_package(Boost 1.36.0 COMPONENTS thread)
|
||||
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.hpp include/chaiscript/language/chaiscript_prelude_docs.hpp include/chaiscript/utility/utility.hpp)
|
||||
|
||||
if (Boost_FOUND)
|
||||
link_directories( ${Boost_LIBRARY_DIRS} )
|
||||
set_source_files_properties(${Chai_INCLUDES} PROPERTIES HEADER_FILE_ONLY TRUE)
|
||||
|
||||
if (MULTITHREAD_SUPPORT_ENABLED)
|
||||
else()
|
||||
message(FATAL_ERROR "Can not find Boost")
|
||||
endif(Boost_FOUND)
|
||||
add_definitions(-DCHAISCRIPT_NO_THREADS)
|
||||
endif()
|
||||
|
||||
if (CMAKE_HOST_UNIX)
|
||||
SET(DYNAMIC_LOADER "dl")
|
||||
set(DYNAMIC_LOADER "dl")
|
||||
endif(CMAKE_HOST_UNIX)
|
||||
|
||||
set(LIBS ${DYNAMIC_LOADER} ${READLINE_LIB})
|
||||
|
||||
include_directories(${Boost_INCLUDE_DIRS})
|
||||
add_executable(chai src/main.cpp)
|
||||
#add_executable(dispatchkit_test contrib/test/dispatchkit_test.cpp)
|
||||
target_link_libraries(chai ${DYNAMIC_LOADER} ${Boost_LIBRARIES} ${READLINE_LIB})
|
||||
if (CMAKE_COMPILER_2005)
|
||||
# vs2005 is a bit too loud about possible loss of data warnings
|
||||
# ADD_DEFINITIONS(/wd4244)
|
||||
endif()
|
||||
|
||||
add_library(test_module MODULE src/test_module.cpp)
|
||||
target_link_libraries(test_module ${Boost_LIBRARIES})
|
||||
add_library(chaiscript_stdlib MODULE src/chaiscript_stdlib.cpp)
|
||||
target_link_libraries(chaiscript_stdlib ${LIBS} ${EXTRA_LINKER_FLAGS})
|
||||
|
||||
add_executable(chai src/main.cpp ${Chai_INCLUDES})
|
||||
target_link_libraries(chai ${LIBS} ${EXTRA_LINKER_FLAGS})
|
||||
add_dependencies(chai chaiscript_stdlib)
|
||||
|
||||
if (BUILD_SAMPLES)
|
||||
add_executable(example samples/example.cpp)
|
||||
target_link_libraries(example ${LIBS} ${EXTRA_LINKER_FLAGS})
|
||||
add_executable(memory_leak_test samples/memory_leak_test.cpp)
|
||||
target_link_libraries(memory_leak_test ${LIBS} ${EXTRA_LINKER_FLAGS})
|
||||
endif()
|
||||
|
||||
|
||||
if (BUILD_MODULES)
|
||||
add_library(stl_extra MODULE src/stl_extra.cpp)
|
||||
target_link_libraries(stl_extra ${Boost_LIBRARIES})
|
||||
target_link_libraries(stl_extra ${LIBS} ${EXTRA_LINKER_FLAGS})
|
||||
|
||||
file(GLOB UNIT_TESTS RELATIVE ${CMAKE_CURRENT_SOURCE_DIR}/unittests/ ${CMAKE_CURRENT_SOURCE_DIR}/unittests/*.chai)
|
||||
add_library(reflection MODULE src/reflection.cpp)
|
||||
target_link_libraries(reflection ${LIBS} ${EXTRA_LINKER_FLAGS})
|
||||
set(MODULES stl_extra reflection)
|
||||
endif()
|
||||
|
||||
IF(BUILD_TESTING)
|
||||
file(GLOB UNIT_TESTS RELATIVE ${CMAKE_CURRENT_SOURCE_DIR}/unittests/ ${CMAKE_CURRENT_SOURCE_DIR}/unittests/*.chai ${CMAKE_CURRENT_SOURCE_DIR}/unittests/3.x/*.chai)
|
||||
|
||||
list(SORT UNIT_TESTS)
|
||||
|
||||
if(BUILD_TESTING)
|
||||
option(UNIT_TEST_LIGHT "Unit tests light (expect module loading failures)" FALSE)
|
||||
|
||||
foreach(filename ${UNIT_TESTS})
|
||||
message(STATUS "Adding test ${filename}")
|
||||
add_test(${filename} chai ${CMAKE_CURRENT_SOURCE_DIR}/unittests/unit_test.inc ${CMAKE_CURRENT_SOURCE_DIR}/unittests/${filename})
|
||||
endforeach(filename)
|
||||
|
||||
SET_PROPERTY(TEST ${UNIT_TESTS}
|
||||
set_property(TEST ${UNIT_TESTS}
|
||||
PROPERTY ENVIRONMENT
|
||||
"CHAI_USE_PATH=${CMAKE_CURRENT_SOURCE_DIR}/unittests/"
|
||||
"CHAI_MODULE_PATH=${CMAKE_CURRENT_BINARY_DIR}/"
|
||||
)
|
||||
ENDIF(BUILD_TESTING)
|
||||
|
||||
install(TARGETS chai stl_extra test_module RUNTIME DESTINATION bin LIBRARY DESTINATION lib/chaiscript )
|
||||
if (NOT UNIT_TEST_LIGHT)
|
||||
add_executable(utility_test unittests/utility_test.cpp)
|
||||
target_link_libraries(utility_test ${LIBS} ${EXTRA_LINKER_FLAGS})
|
||||
add_test(NAME Utility_Test COMMAND utility_test)
|
||||
|
||||
add_executable(dynamic_object_test unittests/dynamic_object_test.cpp)
|
||||
target_link_libraries(dynamic_object_test ${LIBS} ${EXTRA_LINKER_FLAGS})
|
||||
add_test(NAME Dynamic_Object_Test COMMAND dynamic_object_test)
|
||||
|
||||
add_executable(functor_creation_test unittests/functor_creation_test.cpp)
|
||||
target_link_libraries(functor_creation_test ${LIBS} ${EXTRA_LINKER_FLAGS})
|
||||
add_test(NAME Functor_Creation_Test COMMAND functor_creation_test)
|
||||
|
||||
add_executable(functor_cast_test unittests/functor_cast_test.cpp)
|
||||
target_link_libraries(functor_cast_test ${LIBS} ${EXTRA_LINKER_FLAGS})
|
||||
add_test(NAME Functor_Cast_Test COMMAND functor_cast_test)
|
||||
|
||||
add_executable(boxed_cast_test unittests/boxed_cast_test.cpp)
|
||||
target_link_libraries(boxed_cast_test ${LIBS} ${EXTRA_LINKER_FLAGS})
|
||||
add_test(NAME Boxed_Cast_Test COMMAND boxed_cast_test)
|
||||
|
||||
add_executable(object_lifetime_test unittests/object_lifetime_test.cpp)
|
||||
target_link_libraries(object_lifetime_test ${LIBS} ${EXTRA_LINKER_FLAGS})
|
||||
add_test(NAME Object_Lifetime_Test COMMAND object_lifetime_test)
|
||||
|
||||
add_executable(function_ordering_test unittests/function_ordering_test.cpp)
|
||||
target_link_libraries(function_ordering_test ${LIBS} ${EXTRA_LINKER_FLAGS})
|
||||
add_test(NAME Function_Ordering_Test COMMAND function_ordering_test)
|
||||
|
||||
add_executable(type_info_test unittests/type_info_test.cpp)
|
||||
target_link_libraries(type_info_test ${LIBS} ${EXTRA_LINKER_FLAGS})
|
||||
add_test(NAME Type_Info_Test COMMAND type_info_test)
|
||||
|
||||
add_executable(eval_catch_exception_test unittests/eval_catch_exception_test.cpp)
|
||||
target_link_libraries(eval_catch_exception_test ${LIBS} ${EXTRA_LINKER_FLAGS})
|
||||
add_test(NAME Eval_Catch_Exception_Test COMMAND eval_catch_exception_test)
|
||||
|
||||
add_executable(short_comparison_test unittests/short_comparison_test.cpp)
|
||||
target_link_libraries(short_comparison_test ${LIBS} ${EXTRA_LINKER_FLAGS})
|
||||
add_test(NAME Short_Comparison_Test COMMAND short_comparison_test)
|
||||
|
||||
add_executable(cpp_lambda_test unittests/cpp_lambda_test.cpp)
|
||||
target_link_libraries(cpp_lambda_test ${LIBS} ${EXTRA_LINKER_FLAGS})
|
||||
add_test(NAME cpp_lambda_test COMMAND cpp_lambda_test)
|
||||
|
||||
|
||||
add_executable(multifile_test unittests/multifile_test_main.cpp unittests/multifile_test_chai.cpp
|
||||
unittests/multifile_test_module.cpp)
|
||||
target_link_libraries(multifile_test ${LIBS} ${EXTRA_LINKER_FLAGS})
|
||||
add_test(NAME MultiFile_Test COMMAND multifile_test)
|
||||
|
||||
add_library(test_module MODULE src/test_module.cpp)
|
||||
target_link_libraries(test_module ${LIBS} ${EXTRA_LINKER_FLAGS})
|
||||
|
||||
install(TARGETS test_module RUNTIME DESTINATION bin LIBRARY DESTINATION lib/chaiscript)
|
||||
endif()
|
||||
endif(BUILD_TESTING)
|
||||
|
||||
install(TARGETS chai ${MODULES} RUNTIME DESTINATION bin LIBRARY DESTINATION lib/chaiscript )
|
||||
install(DIRECTORY include/chaiscript DESTINATION include
|
||||
PATTERN "*.hpp"
|
||||
PATTERN "*/.svn*" EXCLUDE)
|
||||
PATTERN "*/.svn*" EXCLUDE
|
||||
PATTERN "*/.git*" EXCLUDE
|
||||
PATTERN "*~" EXCLUDE)
|
||||
install(DIRECTORY unittests DESTINATION share/chaiscript
|
||||
PATTERN "*.chai"
|
||||
PATTERN "*.inc"
|
||||
PATTERN "*/.svn*" EXCLUDE)
|
||||
PATTERN "*/.svn*" EXCLUDE
|
||||
PATTERN "*/.git*" EXCLUDE
|
||||
PATTERN "*~" EXCLUDE)
|
||||
install(DIRECTORY samples DESTINATION share/chaiscript
|
||||
PATTERN "*.chai"
|
||||
PATTERN "*/.svn*" EXCLUDE)
|
||||
PATTERN "*/.svn*" EXCLUDE
|
||||
PATTERN "*/.git*" EXCLUDE
|
||||
PATTERN "*~" EXCLUDE)
|
||||
|
||||
configure_file(contrib/pkgconfig/chaiscript.pc.in lib/pkgconfig/chaiscript.pc @ONLY)
|
||||
install(FILES "${chaiscript_BINARY_DIR}/lib/pkgconfig/chaiscript.pc"
|
||||
DESTINATION lib/pkgconfig)
|
||||
|
||||
|
1661
Doxyfile.in
Normal file
1661
Doxyfile.in
Normal file
File diff suppressed because it is too large
Load Diff
@@ -50,7 +50,7 @@ function run_test
|
||||
# Run multithreaded tests
|
||||
echo "****Building multithreaded test"
|
||||
pushd src
|
||||
g++ multithreaded.cpp -lboost_thread-mt -ldl -omultithreaded -I../include -O3
|
||||
g++ multithreaded.cpp -ldl -omultithreaded -I../include -O3
|
||||
echo "****Testing 1 thread runtime"
|
||||
/usr/bin/time -p ./multithreaded 1 2> ../../r$1-1threadruntime.out
|
||||
echo "****Testing 2 thread runtime"
|
||||
|
26
contrib/codeanalysis/is_prime.chai
Normal file
26
contrib/codeanalysis/is_prime.chai
Normal file
@@ -0,0 +1,26 @@
|
||||
def isprime(n)
|
||||
{
|
||||
for (auto i = 2; i < n; ++i)
|
||||
{
|
||||
if (n % i == 0) {return false}
|
||||
}
|
||||
|
||||
return true
|
||||
}
|
||||
|
||||
|
||||
def primes(n)
|
||||
{
|
||||
auto count = 0
|
||||
for (auto i = 2; i <= n; ++i)
|
||||
{
|
||||
if (isprime(i)) {++count}
|
||||
}
|
||||
|
||||
return count
|
||||
}
|
||||
|
||||
|
||||
auto N = 5000
|
||||
|
||||
print("primes: " + primes(N).to_string())
|
9
contrib/codeanalysis/profile_math.chai
Normal file
9
contrib/codeanalysis/profile_math.chai
Normal file
@@ -0,0 +1,9 @@
|
||||
|
||||
var something = 0;
|
||||
|
||||
for (var i = 1; i < 10000; ++i)
|
||||
{
|
||||
something += int(3 % 2 * 4 + 2 / 16.0 - 100 + (10 ^ 19) / 64 + (3 & 12) - (4 | 14)) % i;
|
||||
}
|
||||
|
||||
print(something);
|
@@ -3,7 +3,7 @@
|
||||
* chaiscript.php
|
||||
* --------------
|
||||
* Author: Jason Turner & Jonathan Turner (based on JavaScript by Ben Keen (ben.keen@gmail.com))
|
||||
* Copyright: (c) 2010 Jason Turner (lefticus@gmail.com) (c) 2009 Jonathan Turner
|
||||
* Copyright: (c) 2010 Jason Turner (jason@emptycrate.com) (c) 2009 Jonathan Turner
|
||||
* (c) 2004 Ben Keen (ben.keen@gmail.com), Nigel McNie (http://qbnz.com/highlighter)
|
||||
* Release Version: 1.0
|
||||
* Date Started: 2009/07/03
|
||||
@@ -48,10 +48,10 @@ $language_data = array (
|
||||
'ESCAPE_CHAR' => '\\',
|
||||
'KEYWORDS' => array(
|
||||
1 => array(
|
||||
'break', 'else', 'else if', 'eval', 'for', 'if', 'return', 'while', 'try', 'catch', 'finally',
|
||||
'break', 'else', 'else if', 'eval', 'for', 'if', 'return', 'while', 'try', 'catch', 'finally', 'case', 'switch', 'default',
|
||||
),
|
||||
2 => array(
|
||||
'def', 'false', 'fun', 'true', 'var', 'attr',
|
||||
'def', 'false', 'fun', 'true', 'var', 'auto', 'attr',
|
||||
),
|
||||
3 => array(
|
||||
// built in functions
|
||||
|
12
contrib/pkgconfig/chaiscript.pc.in
Normal file
12
contrib/pkgconfig/chaiscript.pc.in
Normal file
@@ -0,0 +1,12 @@
|
||||
prefix=@CMAKE_INSTALL_PREFIX@
|
||||
exec_prefix=${prefix}
|
||||
libdir=${exec_prefix}/lib
|
||||
includedir=${prefix}/include
|
||||
|
||||
Name: chaiscript
|
||||
Description: ChaiScript is a scripting language that easily embeds into your existing C++ applications. It's built to be flexible and dynamic, yet still maintain the type-safety you expect as a C++ user. It can natively use classes, methods, and attributes, even if the class inherits functionality from a parent class.
|
||||
Version: @CPACK_PACKAGE_VERSION_MAJOR@.@CPACK_PACKAGE_VERSION_MINOR@.@CPACK_PACKAGE_VERSION_PATCH@
|
||||
Requires:
|
||||
Conflicts:
|
||||
Libs:
|
||||
Cflags: -I${includedir}
|
@@ -1,69 +0,0 @@
|
||||
// This file is distributed under the BSD License.
|
||||
// See "license.txt" for details.
|
||||
// Copyright 2009, Jonathan Turner (jturner@minnow-lang.org)
|
||||
// and Jason Turner (lefticus@gmail.com)
|
||||
// http://www.chaiscript.com
|
||||
|
||||
#include <iostream>
|
||||
|
||||
#include "function_call.hpp"
|
||||
#include "chaiscript.hpp"
|
||||
#include <boost/function.hpp>
|
||||
|
||||
struct Callback_Handler
|
||||
{
|
||||
typedef std::vector<std::pair<boost::function<std::string ()>,
|
||||
boost::function<double (int)> > > Callbacks;
|
||||
|
||||
Callbacks m_callbacks;
|
||||
|
||||
void add_callbacks(boost::shared_ptr<dispatchkit::Proxy_Function> t_name,
|
||||
boost::shared_ptr<dispatchkit::Proxy_Function> t_value)
|
||||
{
|
||||
m_callbacks.push_back(
|
||||
std::make_pair(dispatchkit::build_function_caller<std::string ()>(t_name),
|
||||
dispatchkit::build_function_caller<double (int)>(t_value)
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
void do_callbacks()
|
||||
{
|
||||
int i=1;
|
||||
for (Callbacks::iterator itr = m_callbacks.begin();
|
||||
itr != m_callbacks.end();
|
||||
++itr)
|
||||
{
|
||||
std::cout << "Name: " << itr->first() << " = " << itr->second(i) << std::endl;
|
||||
++i;
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
int main(int argc, char *argv[]) {
|
||||
|
||||
chaiscript::ChaiScript_Engine chai;
|
||||
|
||||
Callback_Handler cb_handler;
|
||||
chai.get_eval_engine().add_object("cb_handler", boost::ref(cb_handler));
|
||||
dispatchkit::register_function(chai.get_eval_engine(), &Callback_Handler::add_callbacks, "add_callbacks");
|
||||
|
||||
for (int i = 1; i < argc; ++i) {
|
||||
try {
|
||||
dispatchkit::Boxed_Value val = chai.evaluate_file(argv[i]);
|
||||
}
|
||||
catch (std::exception &e) {
|
||||
std::cerr << "Could not open: " << argv[i] << std::endl;
|
||||
exit(1);
|
||||
}
|
||||
}
|
||||
|
||||
cb_handler.do_callbacks();
|
||||
|
||||
boost::function<std::string (const std::string&, const std::string &)> f =
|
||||
dispatchkit::build_functor<std::string (const std::string &, const std::string &)>
|
||||
(chai, "function(x, y) { return x + y }");
|
||||
|
||||
std::cout << "Functor call: " << f("Hello", " World") << std::endl;
|
||||
}
|
||||
|
@@ -1,212 +0,0 @@
|
||||
// This file is distributed under the BSD License.
|
||||
// See "license.txt" for details.
|
||||
// Copyright 2009, Jonathan Turner (jturner@minnow-lang.org)
|
||||
// and Jason Turner (lefticus@gmail.com)
|
||||
// http://www.chaiscript.com
|
||||
|
||||
#include <iostream>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
#include <boost/shared_ptr.hpp>
|
||||
#include <boost/function.hpp>
|
||||
|
||||
#include <chaiscript/dispatchkit/dispatchkit.hpp>
|
||||
#include <chaiscript/dispatchkit/bootstrap.hpp>
|
||||
#include <chaiscript/dispatchkit/bootstrap_stl.hpp>
|
||||
#include <chaiscript/dispatchkit/function_call.hpp>
|
||||
|
||||
using namespace dispatchkit;
|
||||
|
||||
struct Test
|
||||
{
|
||||
Test(const std::string &s)
|
||||
: number(-25), message(s)
|
||||
{
|
||||
std::cout << "Test class constructed with value: " << s << std::endl;
|
||||
}
|
||||
|
||||
void show_message()
|
||||
{
|
||||
std::cout << "Constructed Message: " << message << std::endl;
|
||||
}
|
||||
|
||||
std::string &get_message()
|
||||
{
|
||||
return message;
|
||||
}
|
||||
|
||||
int number;
|
||||
|
||||
std::string message;
|
||||
};
|
||||
|
||||
|
||||
|
||||
Boxed_Value named_func_call(Dispatch_Engine &ss,
|
||||
const std::string &nametocall, const std::vector<Boxed_Value> ¶ms)
|
||||
{
|
||||
if (params.size() == 2)
|
||||
{
|
||||
return dispatch(ss.get_function(nametocall), params);
|
||||
} else {
|
||||
throw std::runtime_error("Invalid num params");
|
||||
}
|
||||
}
|
||||
|
||||
// A function that takes a dynamic list of params
|
||||
// and calls a bunch of conversion functions on them and
|
||||
// returns the result as a boxed_value
|
||||
Boxed_Value dynamic_function(Dispatch_Engine &ss, const std::string &name,
|
||||
const std::vector<Boxed_Value> ¶ms)
|
||||
{
|
||||
if (name == "concat_string")
|
||||
{
|
||||
Boxed_Value result;
|
||||
|
||||
//Return a void if there is nothing in the array
|
||||
if (params.size() == 0)
|
||||
{
|
||||
return result;
|
||||
} else {
|
||||
//else, prepopulate the result with a string conversion of the first
|
||||
//param
|
||||
result =
|
||||
dispatch(ss.get_function("to_string"), Param_List_Builder() << params[0]);
|
||||
}
|
||||
|
||||
//Then, loop over all remaining params, converting them to strings and adding
|
||||
//them to the result. This example maybe bette served with a string += operator
|
||||
//implementation, but it works.
|
||||
for (size_t i = 1; i < params.size(); ++i)
|
||||
{
|
||||
result =
|
||||
dispatch(ss.get_function("+"), Param_List_Builder() << result <<
|
||||
dispatch(ss.get_function("to_string"), Param_List_Builder() << params[i]));
|
||||
}
|
||||
|
||||
return result;
|
||||
} else {
|
||||
throw std::runtime_error("Unknown function call");
|
||||
}
|
||||
}
|
||||
|
||||
void test(const std::string &p)
|
||||
{
|
||||
std::cout << "Test: " << p << std::endl;
|
||||
}
|
||||
|
||||
//Test main
|
||||
int main()
|
||||
{
|
||||
Dispatch_Engine ss;
|
||||
Bootstrap::bootstrap(ss);
|
||||
bootstrap_vector<std::vector<int> >(ss, "VectorInt");
|
||||
dump_system(ss);
|
||||
|
||||
//Calling a function by name and allowing the built in dispatch mechanism to
|
||||
//choose the most appropriate version of the function
|
||||
Boxed_Value addresult = dispatch(ss.get_function("+"), Param_List_Builder() << double(5.1) << double(10.3));
|
||||
|
||||
//Using the cast to unbox the resultant value and output it
|
||||
std::cout << boxed_cast<double>(addresult) << std::endl;
|
||||
|
||||
//Using the Boxed_Value as input to another function, again with automatic dispatch.
|
||||
//This time we will not bother saving the result and will instead send it straight out
|
||||
std::cout << boxed_cast<double>(
|
||||
dispatch(ss.get_function("*"), Param_List_Builder() << 2 << addresult)
|
||||
) << std::endl;
|
||||
|
||||
//Register a new function, this one with typing for us, so we don't have to ubox anything
|
||||
//right here
|
||||
|
||||
//Now we have a print method, let's try to print out the earlier example:
|
||||
//so, we dispatch the to_string and pass its result as a param to "print"
|
||||
//In this example we don't bother with temporaries and we don't have to know
|
||||
//anything about types
|
||||
dispatch(ss.get_function("print_string"),
|
||||
Param_List_Builder() << dispatch(ss.get_function("to_string"), Param_List_Builder() << addresult));
|
||||
|
||||
// Now we are going to register a new dynamic function,
|
||||
// when this function is called the objects are not unboxed, but passed
|
||||
// in in their boxed state
|
||||
ss.register_function(boost::shared_ptr<Proxy_Function>(new Dynamic_Proxy_Function(boost::bind(&dynamic_function, boost::ref(ss), "concat_string", _1))), "concat_string");
|
||||
|
||||
|
||||
// Call our newly defined dynamic function with 10 parameters, then send
|
||||
// its output to the "print" function
|
||||
dispatch(ss.get_function("print_string"),
|
||||
Param_List_Builder() << dispatch(ss.get_function("concat_string"),
|
||||
Param_List_Builder() << std::string("\n\t") << std::string("The Value Was: ")
|
||||
<< double(42.5) << std::string(".")
|
||||
<< '\n'
|
||||
<< '\t' << std::string("The old value was: ")
|
||||
<< addresult << '.' << '\n' ));
|
||||
|
||||
|
||||
|
||||
|
||||
//Register some local methods of the "Test" class
|
||||
ss.register_function(build_constructor<Test, const std::string &>(), "Test");
|
||||
|
||||
register_function(ss, &Test::get_message, "get_message");
|
||||
register_function(ss, &Test::show_message, "show_message");
|
||||
register_member(ss, &Test::number, "number");
|
||||
|
||||
//Create a new object using the "Test" constructor, passing the param "Yo".
|
||||
//Then, add the new object to the system with the name "testobj2"
|
||||
ss.add_object("testobj2",
|
||||
dispatch(ss.get_function("Test"), Param_List_Builder() << std::string("Yo")));
|
||||
|
||||
// Look up and store a reference to our new object
|
||||
std::vector<Boxed_Value> sos;
|
||||
sos.push_back(ss.get_object("testobj2"));
|
||||
|
||||
//Build a bound function proxy for calling the script handled function
|
||||
boost::function<void (Test &)> show_message =
|
||||
build_function_caller<void (Test &)>(ss.get_function("show_message"));
|
||||
|
||||
Test &t = boxed_cast<Test &>(ss.get_object("testobj2"));
|
||||
|
||||
//Print the message the object was created with
|
||||
show_message(t);
|
||||
|
||||
//Now, get a reference to the object's stored message
|
||||
Boxed_Value stringref = dispatch(ss.get_function("get_message"), sos);
|
||||
|
||||
//Unbox it using boxed_cast
|
||||
std::string &sr = boxed_cast<std::string &>(stringref);
|
||||
|
||||
//Update the value of the reference
|
||||
sr = "Bob Updated The message";
|
||||
|
||||
//Now, get a reference to the object's stored number
|
||||
Boxed_Value numberref= dispatch(ss.get_function("number"), sos);
|
||||
|
||||
//Unbox it using boxed_cast
|
||||
int &ir = boxed_cast<int &>(numberref);
|
||||
|
||||
std::cout << "Number: " << ir << std::endl;
|
||||
|
||||
//Now, prove that the reference was successfully acquired
|
||||
//and we are able to peek into the boxed types
|
||||
show_message(t);
|
||||
|
||||
|
||||
// Finally, we are going to register some named function aliases, for
|
||||
// the fun of it
|
||||
ss.register_function(boost::shared_ptr<Proxy_Function>(
|
||||
new Dynamic_Proxy_Function(boost::bind(&named_func_call, boost::ref(ss), "+", _1))), "add");
|
||||
|
||||
//Call our newly named "add" function (which in turn dispatches +)
|
||||
|
||||
std::cout << "Result of add function: " <<
|
||||
boxed_cast<int>(dispatch(ss.get_function("add"), Param_List_Builder() << 5 << 2))
|
||||
<< std::endl;
|
||||
|
||||
|
||||
ss.set_object("myfunc", boost::shared_ptr<Proxy_Function>(new Proxy_Function_Impl<boost::function<void (const std::string &)> >(&test)));
|
||||
|
||||
dispatch(ss.get_function("myfunc"), Param_List_Builder() << std::string("hello function variable"));
|
||||
|
||||
}
|
||||
|
@@ -1,23 +0,0 @@
|
||||
// This file is distributed under the BSD License.
|
||||
// See "license.txt" for details.
|
||||
// Copyright 2009, Jonathan Turner (jturner@minnow-lang.org)
|
||||
// and Jason Turner (lefticus@gmail.com)
|
||||
// http://www.chaiscript.com
|
||||
|
||||
#include "dispatchkit.hpp"
|
||||
#include "bootstrap.hpp"
|
||||
|
||||
#define BOOST_TEST_DYN_LINK
|
||||
#define BOOST_TEST_MODULE boxedcpp_unittests
|
||||
#include <boost/test/unit_test.hpp>
|
||||
|
||||
BOOST_AUTO_TEST_CASE( add_operators )
|
||||
{
|
||||
using namespace dispatchkit;
|
||||
|
||||
Dispatch_Engine ss;
|
||||
Bootstrap::bootstrap(ss);
|
||||
dump_system(ss);
|
||||
|
||||
BOOST_CHECK_EQUAL(boxed_cast<int>(dispatch(ss.get_function("+"), Param_List_Builder() << double(5.1) << double(10.3))), 15.4);
|
||||
}
|
@@ -1,148 +0,0 @@
|
||||
// This file is distributed under the BSD License.
|
||||
// See "license.txt" for details.
|
||||
// Copyright 2009, Jonathan Turner (jturner@minnow-lang.org)
|
||||
// and Jason Turner (lefticus@gmail.com)
|
||||
// http://www.chaiscript.com
|
||||
|
||||
#include <iostream>
|
||||
|
||||
#include "chaiscript.hpp"
|
||||
#include "function_call.hpp"
|
||||
#include <boost/function.hpp>
|
||||
#include <boost/date_time/posix_time/posix_time.hpp>
|
||||
#include <boost/regex.hpp>
|
||||
|
||||
|
||||
std::string load_text_file(const std::string &filename)
|
||||
{
|
||||
std::ifstream infile(filename.c_str());
|
||||
|
||||
std::string str;
|
||||
|
||||
std::string result;
|
||||
|
||||
while (std::getline(infile, str))
|
||||
{
|
||||
result += str + "\n";
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
std::vector<dispatchkit::Boxed_Value> regex_search(const std::string &str, const std::string ®ex)
|
||||
{
|
||||
boost::smatch matches;
|
||||
boost::regex_search(str, matches, boost::regex(regex));
|
||||
|
||||
std::vector<dispatchkit::Boxed_Value> results;
|
||||
|
||||
for (unsigned int i = 0; i < matches.size(); ++i)
|
||||
{
|
||||
results.push_back(dispatchkit::Boxed_Value(std::string(matches.str(i))));
|
||||
}
|
||||
|
||||
return results;
|
||||
}
|
||||
|
||||
struct Sensor_Manager
|
||||
{
|
||||
struct Sensor
|
||||
{
|
||||
int milliseconds;
|
||||
dispatchkit::Boxed_Value state_object;
|
||||
boost::function<double (dispatchkit::Boxed_Value)> sensor;
|
||||
boost::posix_time::ptime next_run;
|
||||
|
||||
Sensor(int t_milliseconds, dispatchkit::Boxed_Value t_state_object,
|
||||
boost::function<double (dispatchkit::Boxed_Value)> t_sensor)
|
||||
: milliseconds(t_milliseconds), state_object(t_state_object), sensor(t_sensor),
|
||||
next_run(boost::posix_time::microsec_clock::universal_time()
|
||||
+ boost::posix_time::milliseconds(milliseconds))
|
||||
{
|
||||
}
|
||||
|
||||
std::pair<boost::posix_time::ptime, double> get_value()
|
||||
{
|
||||
next_run = boost::posix_time::microsec_clock::universal_time()
|
||||
+ boost::posix_time::milliseconds(milliseconds);
|
||||
|
||||
return std::make_pair(boost::posix_time::microsec_clock::universal_time(),
|
||||
sensor(state_object));
|
||||
}
|
||||
};
|
||||
|
||||
std::map<std::string, Sensor> m_sensors;
|
||||
|
||||
//sensor_manager.add_sensor("CPU", 1000, global_state, function(state) { update_state(state); state["CPU"]; } )
|
||||
void add_sensor(const std::string &t_name, int t_milliseconds, dispatchkit::Boxed_Value t_state_object,
|
||||
boost::shared_ptr<dispatchkit::Proxy_Function> t_func)
|
||||
{
|
||||
m_sensors.insert(
|
||||
std::make_pair(t_name,
|
||||
Sensor(t_milliseconds, t_state_object,
|
||||
dispatchkit::build_function_caller<double (dispatchkit::Boxed_Value)>(t_func)
|
||||
)
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
std::vector<std::pair<std::string, double> > run_sensors()
|
||||
{
|
||||
std::vector<std::pair<std::string, double> > results;
|
||||
|
||||
boost::posix_time::ptime t(boost::posix_time::microsec_clock::universal_time());
|
||||
|
||||
for (std::map<std::string, Sensor>::iterator itr = m_sensors.begin();
|
||||
itr != m_sensors.end();
|
||||
++itr)
|
||||
{
|
||||
if (itr->second.next_run <= t)
|
||||
{
|
||||
results.push_back(std::make_pair(itr->first, itr->second.get_value().second));
|
||||
}
|
||||
}
|
||||
|
||||
return results;
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
|
||||
int main(int argc, char *argv[]) {
|
||||
|
||||
chaiscript::ChaiScript_Engine chai;
|
||||
|
||||
Sensor_Manager sensor_manager;
|
||||
chai.get_eval_engine().add_object("sensor_manager", boost::ref(sensor_manager));
|
||||
|
||||
dispatchkit::register_function(chai.get_eval_engine(), &Sensor_Manager::add_sensor, "add_sensor");
|
||||
dispatchkit::register_function(chai.get_eval_engine(), ®ex_search, "regex_search");
|
||||
dispatchkit::register_function(chai.get_eval_engine(), &load_text_file, "load_text_file");
|
||||
|
||||
|
||||
|
||||
for (int i = 1; i < argc; ++i) {
|
||||
try {
|
||||
chai.evaluate_file(argv[i]);
|
||||
}
|
||||
catch (std::exception &e) {
|
||||
std::cerr << "Could not open: " << argv[i] << std::endl;
|
||||
exit(1);
|
||||
}
|
||||
}
|
||||
|
||||
while (true)
|
||||
{
|
||||
usleep(1000);
|
||||
std::vector<std::pair<std::string, double> > sensor_data = sensor_manager.run_sensors();
|
||||
|
||||
for (std::vector<std::pair<std::string, double> >::iterator itr = sensor_data.begin();
|
||||
itr != sensor_data.end();
|
||||
++itr)
|
||||
{
|
||||
std::cout << "Sensor: " << itr->first << " value: " << itr->second << std::endl;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@@ -7,6 +7,9 @@ if exists("b:current_syntax")
|
||||
finish
|
||||
end
|
||||
|
||||
let s:cpo_save = &cpo
|
||||
set cpo&vim
|
||||
|
||||
syn case match
|
||||
|
||||
" syncing method
|
||||
@@ -42,14 +45,14 @@ syn match chaiscriptNumber "\<0b[01]\+\>"
|
||||
" Various language features
|
||||
syn keyword chaiscriptCond if else
|
||||
syn keyword chaiscriptRepeat while for do
|
||||
syn keyword chaiscriptStatement break continue return
|
||||
syn keyword chaiscriptStatement break continue return switch case default
|
||||
syn keyword chaiscriptExceptions try catch throw
|
||||
|
||||
"Keyword
|
||||
syn keyword chaiscriptKeyword def true false attr
|
||||
|
||||
"Built in types
|
||||
syn keyword chaiscriptType fun var
|
||||
syn keyword chaiscriptType fun var auto
|
||||
|
||||
"Built in funcs, keep it simple
|
||||
syn keyword chaiscriptFunc eval throw
|
||||
@@ -91,4 +94,6 @@ hi def link chaiscriptEval Special
|
||||
|
||||
let b:current_syntax = "chaiscript"
|
||||
|
||||
let &cpo = s:cpo_save
|
||||
unlet s:cpo_save
|
||||
" vim: nowrap sw=2 sts=2 ts=8 noet
|
||||
|
@@ -1,35 +1,760 @@
|
||||
// This file is distributed under the BSD License.
|
||||
// See "license.txt" for details.
|
||||
// Copyright 2009-2010, Jonathan Turner (jturner@minnow-lang.org)
|
||||
// and Jason Turner (lefticus@gmail.com)
|
||||
// Copyright 2009-2012, Jonathan Turner (jonathan@emptycrate.com)
|
||||
// and Jason Turner (jason@emptycrate.com)
|
||||
// http://www.chaiscript.com
|
||||
|
||||
#ifndef CHAISCRIPT_HPP_
|
||||
#define CHAISCRIPT_HPP_
|
||||
|
||||
#include <boost/bind.hpp>
|
||||
#include <boost/shared_ptr.hpp>
|
||||
#include <boost/function.hpp>
|
||||
|
||||
#include <stdexcept>
|
||||
#include <iostream>
|
||||
#include <map>
|
||||
#include <fstream>
|
||||
#include <boost/shared_ptr.hpp>
|
||||
|
||||
/// \mainpage
|
||||
/// <a href="http://www.chaiscript.com">ChaiScript</a> is a scripting language designed specifically for integration with C++. It provides
|
||||
/// seamless integration with C++ on all levels, including shared_ptr objects, functors and exceptions.
|
||||
///
|
||||
/// The parts of the ChaiScript API that the average user will be concerned with are contained in the
|
||||
/// chaiscript namespace and the chaiscript::ChaiScript class.
|
||||
///
|
||||
/// The end user parts of the API are extremely simple both in size and ease of use.
|
||||
///
|
||||
/// Currently, all source control and project management aspects of ChaiScript occur on <a href="http://www.github.com/ChaiScript/ChaiScript">github</a>.
|
||||
///
|
||||
/// <hr>
|
||||
///
|
||||
/// \sa chaiscript
|
||||
/// \sa chaiscript::ChaiScript
|
||||
/// \sa ChaiScript_Language for Built in Functions
|
||||
/// \sa \ref LangGettingStarted
|
||||
/// \sa \ref LangKeywordRef
|
||||
/// \sa \ref LangInPlaceRef
|
||||
/// \sa \ref LangObjectSystemRef
|
||||
/// \sa http://www.chaiscript.com
|
||||
/// \sa http://www.github.com/ChaiScript/ChaiScript
|
||||
///
|
||||
/// <hr>
|
||||
///
|
||||
/// \section gettingstarted API Getting Started
|
||||
///
|
||||
/// \li \ref basics
|
||||
/// \li \ref compiling
|
||||
/// \li \ref eval
|
||||
/// \li \ref addingitems
|
||||
/// \li \ref operatoroverloading
|
||||
/// \li \ref helpermacro
|
||||
/// \li \ref pointerconversions
|
||||
/// \li \ref baseclasses
|
||||
/// \li \ref functionobjects
|
||||
/// \li \ref threading
|
||||
/// \li \ref exceptions
|
||||
///
|
||||
///
|
||||
/// \subsection basics Basics
|
||||
///
|
||||
/// Basic simple example:
|
||||
///
|
||||
/// \code
|
||||
/// //main.cpp
|
||||
/// #include <chaiscript/chaiscript.hpp>
|
||||
///
|
||||
/// double function(int i, double j)
|
||||
/// {
|
||||
/// return i * j;
|
||||
/// }
|
||||
///
|
||||
/// int main()
|
||||
/// {
|
||||
/// chaiscript::ChaiScript chai;
|
||||
/// chai.add(&function, "function");
|
||||
///
|
||||
/// double d = chai.eval<double>("function(3, 4.75);");
|
||||
/// }
|
||||
/// \endcode
|
||||
///
|
||||
/// <hr>
|
||||
/// \subsection compiling Compiling ChaiScript Applications
|
||||
///
|
||||
/// ChaiScript is a header only library with only one dependecy: The
|
||||
/// operating system provided dynamic library loader, which has to be specified on some platforms.
|
||||
///
|
||||
/// \subsubsection compilinggcc Compiling with GCC
|
||||
///
|
||||
/// To compile the above application on a Unix like operating system (MacOS, Linux) with GCC you need to link
|
||||
/// the dynamic loader. For example:
|
||||
///
|
||||
/// \code
|
||||
/// gcc main.cpp -I/path/to/chaiscript/headers -ldl
|
||||
/// \endcode
|
||||
///
|
||||
/// Alternatively, you may compile without threading support.
|
||||
///
|
||||
/// \code
|
||||
/// gcc main.cpp -I/path/to/chaiscript/headers -ldl -DCHAISCRIPT_NO_THREADS
|
||||
/// \endcode
|
||||
///
|
||||
/// <hr>
|
||||
/// \subsection eval Evaluating Scripts
|
||||
///
|
||||
/// Scripts can be evaluated with the () operator, eval method or eval_file method.
|
||||
///
|
||||
/// \subsubsection parenoperator () Operator
|
||||
///
|
||||
/// operator() can be used as a handy shortcut for evaluating ChaiScript snippets.
|
||||
/// \code
|
||||
/// chaiscript::ChaiScript chai;
|
||||
/// chai("print(\"hello world\")");
|
||||
/// \endcode
|
||||
///
|
||||
/// \sa chaiscript::ChaiScript::operator()(const std::string &)
|
||||
///
|
||||
/// \subsubsection evalmethod Method 'eval'
|
||||
///
|
||||
/// The eval method is somewhat more verbose and can be used to get typesafely return values
|
||||
/// from the script.
|
||||
///
|
||||
/// \code
|
||||
/// chaiscript::ChaiScript chai;
|
||||
/// chai.eval("callsomefunc()");
|
||||
/// int result = chai.eval<int>("1 + 3");
|
||||
/// // result now equals 4
|
||||
/// \endcode
|
||||
///
|
||||
/// \sa chaiscript::ChaiScript::eval
|
||||
///
|
||||
/// \subsubsection evalfilemethod Method 'eval_file'
|
||||
///
|
||||
/// The 'eval_file' method loads a file from disk and executes the script in it
|
||||
///
|
||||
/// \code
|
||||
/// chaiscript::ChaiScript chai;
|
||||
/// chai.eval_file("myfile.chai");
|
||||
/// std::string result = chai.eval_file<std::string>("myfile.chai") // extract the last value returned from the file
|
||||
/// \endcode
|
||||
///
|
||||
/// \sa chaiscript::ChaiScript::eval_file
|
||||
///
|
||||
/// <hr>
|
||||
/// \subsection addingitems Adding Items to ChaiScript
|
||||
///
|
||||
/// ChaiScript supports 4 basic things that can be added: objects, functions, type infos and Modules
|
||||
///
|
||||
/// \subsubsection addingobjects Adding Objects
|
||||
///
|
||||
/// Named objects can be created with the chaiscript::var function.
|
||||
///
|
||||
/// \code
|
||||
/// using namespace chaiscript;
|
||||
/// ChaiScript chai;
|
||||
/// int i = 5;
|
||||
/// chai.add(var(i), "i");
|
||||
/// chai("print(i)");
|
||||
/// \endcode
|
||||
///
|
||||
/// Immutable objects can be created with the chaiscript::const_var function.
|
||||
///
|
||||
/// \code
|
||||
/// chai.add(const_var(i), "i");
|
||||
/// chai("i = 5"); // exception throw, cannot assign const var
|
||||
/// \endcode
|
||||
///
|
||||
/// Named variables can only be accessed from the context they are created in.
|
||||
/// If you want a global variable, it must be const, and created with the
|
||||
/// chaiscript::ChaiScript::add_global_const function.
|
||||
///
|
||||
/// \code
|
||||
/// chai.add_global_const(const_var(i), "i");
|
||||
/// chai("def somefun() { print(i); }; sumfun();");
|
||||
/// \endcode
|
||||
///
|
||||
/// \subsubsection addingfunctions Adding Functions
|
||||
///
|
||||
/// Functions, methods and members are all added using the same function: chaiscript::fun.
|
||||
///
|
||||
/// \code
|
||||
/// using namespace chaiscript;
|
||||
///
|
||||
/// class MyClass {
|
||||
/// public:
|
||||
/// int memberdata;
|
||||
/// void method();
|
||||
/// void method2(int);
|
||||
/// static void staticmethod();
|
||||
/// void overloadedmethod();
|
||||
/// void overloadedmethod(const std::string &);
|
||||
/// };
|
||||
///
|
||||
/// ChaiScript chai;
|
||||
/// chai.add(fun(&MyClass::memberdata), "memberdata");
|
||||
/// chai.add(fun(&MyClass::method), "method");
|
||||
/// chai.add(fun(&MyClass::staticmethod), "staticmethod");
|
||||
/// \endcode
|
||||
///
|
||||
/// Overloaded methods will need some help, to hint the compiler as to which overload you want:
|
||||
///
|
||||
/// \code
|
||||
/// chai.add(fun<void (MyClass::*)()>(&MyClass::overloadedmethod), "overloadedmethod");
|
||||
/// chai.add(fun<void (MyClass::*)(const std::string &)>(&MyClass::overloadedmethod), "overloadedmethod");
|
||||
/// \endcode
|
||||
///
|
||||
/// There are also shortcuts built into chaiscript::fun for binding up to the first two parameters of the function.
|
||||
///
|
||||
/// \code
|
||||
/// MyClass obj;
|
||||
/// chai.add(fun(&MyClass::method, &obj), "method");
|
||||
/// chai("method()"); // equiv to obj.method()
|
||||
/// chai.add(fun(&MyClass::method2, &obj, 3), "method2");
|
||||
/// chai("method2()"); // equiv to obj.method2(3)
|
||||
/// \endcode
|
||||
///
|
||||
/// \subsubsection addingtypeinfo Adding Type Info
|
||||
///
|
||||
/// ChaiScript will automatically support any type implicitly provided to it in the form
|
||||
/// of objects and function parameters / return types. However, it can be nice to let ChaiScript
|
||||
/// know more details about the types you are giving it. For instance, the "clone" functionality
|
||||
/// cannot work unless there is a copy constructor registered and the name of the type is known
|
||||
/// (so that ChaiScript can look up the copy constructor).
|
||||
///
|
||||
/// Continuing with the example "MyClass" from above:
|
||||
///
|
||||
/// \code
|
||||
/// chai.add(user_type<MyClass>(), "MyClass");
|
||||
/// \endcode
|
||||
///
|
||||
/// \subsubsection addingmodules Adding Modules
|
||||
///
|
||||
/// Modules are holders for collections of ChaiScript registrations.
|
||||
///
|
||||
/// \code
|
||||
/// ModulePtr module = get_sum_module();
|
||||
/// chai.add(module);
|
||||
/// \endcode
|
||||
///
|
||||
/// \sa chaiscript::Module
|
||||
///
|
||||
/// <hr>
|
||||
/// \subsection operatoroverloading Operator Overloading
|
||||
///
|
||||
/// Operators are just like any other function in ChaiScript, to overload an operator, simply register it.
|
||||
///
|
||||
/// \code
|
||||
/// class MyClass {
|
||||
/// MyClass operator+(const MyClass &) const;
|
||||
/// };
|
||||
///
|
||||
/// chai.add(fun(&MyClass::operator+), "+");
|
||||
///
|
||||
/// std::string append_string_int(const std::string &t_lhs, int t_rhs)
|
||||
/// {
|
||||
/// std::stringstream ss;
|
||||
/// ss << t_lhs << t_rhs;
|
||||
/// return ss.str();
|
||||
/// }
|
||||
///
|
||||
/// chai.add(fun(append_string_int), "+");
|
||||
/// \endcode
|
||||
///
|
||||
/// \sa \ref addingfunctions
|
||||
///
|
||||
/// <hr>
|
||||
/// \subsection helpermacro Class Helper Macro
|
||||
///
|
||||
/// Much of the work of adding new classes to ChaiScript can be reduced with the help
|
||||
/// of the CHAISCRIPT_CLASS helper macro.
|
||||
///
|
||||
/// \code
|
||||
/// class Test
|
||||
/// {
|
||||
/// public:
|
||||
/// void function() {}
|
||||
/// std::string function2() { return "Function2"; }
|
||||
/// void function3() {}
|
||||
/// std::string functionOverload(double) { return "double"; }
|
||||
/// std::string functionOverload(int) { return "int"; }
|
||||
/// };
|
||||
///
|
||||
/// int main()
|
||||
/// {
|
||||
///
|
||||
/// chaiscript::ModulePtr m = chaiscript::ModulePtr(new chaiscript::Module());
|
||||
///
|
||||
/// CHAISCRIPT_CLASS( m,
|
||||
/// Test,
|
||||
/// (Test ())
|
||||
/// (Test (const Test &)),
|
||||
/// ((function))
|
||||
/// ((function2))
|
||||
/// ((function3))
|
||||
/// ((functionOverload)(std::string (Test::*)(double)))
|
||||
/// ((functionOverload)(std::string (Test::*)(int)))
|
||||
/// ((operator=))
|
||||
/// );
|
||||
///
|
||||
/// chaiscript::ChaiScript chai;
|
||||
/// chai.add(m);
|
||||
/// }
|
||||
/// \endcode
|
||||
///
|
||||
/// \sa \ref addingmodules
|
||||
///
|
||||
/// <hr>
|
||||
/// \subsection pointerconversions Pointer / Object Conversions
|
||||
///
|
||||
/// 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.
|
||||
///
|
||||
/// 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).
|
||||
/// 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.
|
||||
///
|
||||
/// \code
|
||||
/// void fun1(const int *);
|
||||
/// void fun2(int *);
|
||||
/// void fun3(int);
|
||||
/// void fun4(int &);
|
||||
/// void fun5(const int &);
|
||||
/// void fun5(std::shared_ptr<int>);
|
||||
/// void fun6(std::shared_ptr<const int>);
|
||||
/// void fun7(const std::shared_ptr<int> &);
|
||||
/// void fun8(const std::shared_ptr<const int> &);
|
||||
/// void fun9(std::reference_wrapper<int>);
|
||||
/// void fun10(std::reference_wrapper<const int>);
|
||||
///
|
||||
/// int main()
|
||||
/// {
|
||||
/// using namespace chaiscript
|
||||
/// chaiscript::ChaiScript chai;
|
||||
/// chai.add(fun(fun1), "fun1");
|
||||
/// chai.add(fun(fun2), "fun2");
|
||||
/// chai.add(fun(fun3), "fun3");
|
||||
/// chai.add(fun(fun4), "fun4");
|
||||
/// chai.add(fun(fun5), "fun5");
|
||||
/// chai.add(fun(fun6), "fun6");
|
||||
/// chai.add(fun(fun7), "fun7");
|
||||
/// chai.add(fun(fun8), "fun8");
|
||||
/// chai.add(fun(fun9), "fun9");
|
||||
/// chai.add(fun(fun10), "fun10");
|
||||
///
|
||||
/// chai("var i = 10;");
|
||||
/// chai("fun1(i)");
|
||||
/// chai("fun2(i)");
|
||||
/// chai("fun3(i)");
|
||||
/// chai("fun4(i)");
|
||||
/// chai("fun5(i)");
|
||||
/// chai("fun6(i)");
|
||||
/// chai("fun7(i)");
|
||||
/// chai("fun8(i)");
|
||||
/// chai("fun9(i)");
|
||||
/// chai("fun10(i)");
|
||||
/// }
|
||||
/// \endcode
|
||||
///
|
||||
/// See the unit test unittests/boxed_cast_test.cpp for a complete breakdown of the automatic casts that
|
||||
/// available and tested.
|
||||
///
|
||||
/// <hr>
|
||||
/// \subsection baseclasses Base Classes
|
||||
///
|
||||
/// ChaiScript supports handling of passing a derived class object to a function expecting a base class object.
|
||||
/// For the process to work, the base/derived relationship must be registered with the engine.
|
||||
///
|
||||
/// \code
|
||||
/// class Base {};
|
||||
/// class Derived : public Base {};
|
||||
/// void myfunction(Base *b);
|
||||
///
|
||||
/// int main()
|
||||
/// {
|
||||
/// chaiscript::ChaiScript chai;
|
||||
/// chai.add(chaiscript::base_class<Base, Derived>());
|
||||
/// Derived d;
|
||||
/// chai.add(chaiscript::var(&d), "d");
|
||||
/// chai.add(chaiscript::fun(&myfunction), "myfunction");
|
||||
/// chai("myfunction(d)");
|
||||
/// }
|
||||
/// \endcode
|
||||
///
|
||||
/// <hr>
|
||||
///
|
||||
/// \subsection functionobjects Function Objects
|
||||
///
|
||||
/// Functions are first class objects in Chaiscript and ChaiScript supports automatic conversion
|
||||
/// between ChaiScript functions and std::function objects.
|
||||
///
|
||||
/// \code
|
||||
/// void callafunc(const std::function<void (const std::string &)> &t_func)
|
||||
/// {
|
||||
/// t_func("bob");
|
||||
/// }
|
||||
///
|
||||
/// int main()
|
||||
/// {
|
||||
/// chaiscript::ChaiScript chai;
|
||||
/// chai.add(chaiscript::fun(&callafunc), "callafunc");
|
||||
/// chai("callafunc(fun(x) { print(x); })"); // pass a lambda function to the registered function
|
||||
/// // which expects a typed std::function
|
||||
///
|
||||
/// std::function<void ()> f = chai.eval<std::function<void ()> >("dump_system");
|
||||
/// f(); // call the ChaiScript function dump_system, from C++
|
||||
/// }
|
||||
/// \endcode
|
||||
///
|
||||
/// <hr>
|
||||
///
|
||||
/// \subsection threading Threading
|
||||
///
|
||||
/// Thread safety is automatically handled within the ChaiScript system. Objects can be added
|
||||
/// and scripts executed from multiple threads. For each thread that executes scripts, a new
|
||||
/// context is created and managed by the engine.
|
||||
///
|
||||
/// Thread safety can be disabled by defining CHAISCRIPT_NO_THREADS when using the library.
|
||||
///
|
||||
/// Disabling thread safety increases performance in many cases.
|
||||
///
|
||||
/// <hr>
|
||||
///
|
||||
/// \subsection exceptions Exception Handling
|
||||
///
|
||||
/// \subsubsection exceptionsbasics Exception Handling Basics
|
||||
///
|
||||
/// Exceptions can be thrown in ChaiScript and caught in C++ or thrown in C++ and caught in
|
||||
/// ChaiScript.
|
||||
///
|
||||
/// \code
|
||||
/// void throwexception()
|
||||
/// {
|
||||
/// throw std::runtime_error("err");
|
||||
/// }
|
||||
///
|
||||
/// int main()
|
||||
/// {
|
||||
/// // Throw in C++, catch in ChaiScript
|
||||
/// chaiscript::ChaiScript chai;
|
||||
/// chai.add(chaiscript::fun(&throwexception), "throwexception");
|
||||
/// chai("try { throwexception(); } catch (e) { print(e.what()); }"); // prints "err"
|
||||
///
|
||||
/// // Throw in ChaiScript, catch in C++
|
||||
/// try {
|
||||
/// chai("throw(1)");
|
||||
/// } catch (chaiscript::Boxed_Value bv) {
|
||||
/// int i = chaiscript::boxed_cast<int>(bv);
|
||||
/// // i == 1
|
||||
/// }
|
||||
/// }
|
||||
/// \endcode
|
||||
///
|
||||
/// \subsubsection exceptionsautomatic Exception Handling Automatic Unboxing
|
||||
///
|
||||
/// As an alternative to the manual unboxing of exceptions shown above, exception specifications allow the user to tell
|
||||
/// ChaiScript what possible exceptions are expected from the script being executed.
|
||||
///
|
||||
/// Example:
|
||||
/// \code
|
||||
/// chaiscript::ChaiScript chai;
|
||||
///
|
||||
/// try {
|
||||
/// chai.eval("throw(runtime_error(\"error\"))", chaiscript::exception_specification<int, double, float, const std::string &, const std::exception &>());
|
||||
/// } catch (const double e) {
|
||||
/// } catch (int) {
|
||||
/// } catch (float) {
|
||||
/// } catch (const std::string &) {
|
||||
/// } catch (const std::exception &e) {
|
||||
/// // This is the one what will be called in the specific throw() above
|
||||
/// }
|
||||
/// \endcode
|
||||
///
|
||||
/// \sa chaiscript::Exception_Handler for details on automatic exception unboxing
|
||||
/// \sa chaiscript::exception_specification
|
||||
|
||||
|
||||
|
||||
/// \page LangObjectSystemRef ChaiScript Language Object Model Reference
|
||||
///
|
||||
///
|
||||
/// ChaiScript has an object system built in, for types defined within the ChaiScript system.
|
||||
///
|
||||
/// \code
|
||||
/// attr Rectangle::height
|
||||
/// attr Rectangle::width
|
||||
/// def Rectangle::Rectangle() { this.height = 10; this.width = 20 }
|
||||
/// def Rectangle::area() { this.height * this.width }
|
||||
///
|
||||
/// var rect = Rectangle()
|
||||
/// rect.height = 30
|
||||
/// print(rect.area())
|
||||
/// \endcode
|
||||
///
|
||||
/// \sa \ref keywordattr
|
||||
/// \sa \ref keyworddef
|
||||
|
||||
/// \page LangInPlaceRef ChaiScript Language In-Place Creation Reference
|
||||
/// \section inplacevector Vector
|
||||
///
|
||||
/// \code
|
||||
/// In-place Vector ::= "[" [expression ("," expression)*] "]"
|
||||
/// \endcode
|
||||
///
|
||||
/// \section inplacerangedvector Ranged Vector
|
||||
///
|
||||
/// \code
|
||||
/// In-place Ranged Vector ::= "[" value ".." value "]"
|
||||
/// \endcode
|
||||
///
|
||||
/// Creates a vector over a range (eg. 1..10)
|
||||
///
|
||||
/// \section inplacemap Map
|
||||
///
|
||||
/// \code
|
||||
/// In-place Map ::= "[" (string ":" expression)+ "]"
|
||||
/// \endcode
|
||||
|
||||
/// \page LangGettingStarted ChaiScript Language Getting Started
|
||||
///
|
||||
/// ChaiScript is a simple language that should feel familiar to anyone who knows
|
||||
/// C++ or ECMAScript (JavaScript).
|
||||
///
|
||||
/// <hr>
|
||||
/// \section chaiscriptloops Loops
|
||||
///
|
||||
/// Common looping constructs exist in ChaiScript
|
||||
///
|
||||
/// \code
|
||||
/// var i = 0;
|
||||
/// while (i < 10)
|
||||
/// {
|
||||
/// // do something
|
||||
/// ++i;
|
||||
/// }
|
||||
/// \endcode
|
||||
///
|
||||
/// \code
|
||||
/// for (var i = 0; i < 10; ++i)
|
||||
/// {
|
||||
/// // do something
|
||||
/// }
|
||||
/// \endcode
|
||||
///
|
||||
/// \sa \ref keywordfor
|
||||
/// \sa \ref keywordwhile
|
||||
///
|
||||
/// <hr>
|
||||
/// \section chaiscriptifs Conditionals
|
||||
///
|
||||
/// If statements work as expected
|
||||
///
|
||||
/// \code
|
||||
/// var b = true;
|
||||
///
|
||||
/// if (b) {
|
||||
/// // do something
|
||||
/// } else if (c < 10) {
|
||||
/// // do something else
|
||||
/// } else {
|
||||
/// // or do this
|
||||
/// }
|
||||
/// \endcode
|
||||
///
|
||||
/// \sa \ref keywordif
|
||||
///
|
||||
/// <hr>
|
||||
/// \section chaiscriptfunctions Functions
|
||||
///
|
||||
/// Functions are defined with the def keyword
|
||||
///
|
||||
/// \code
|
||||
/// def myfun(x) { print(x); }
|
||||
///
|
||||
/// myfun(10);
|
||||
/// \endcode
|
||||
///
|
||||
/// Functions may have "guards" which determine if which is called.
|
||||
///
|
||||
/// \code
|
||||
/// eval> def myfun2(x) : x < 10 { print("less than 10"); }
|
||||
/// eval> def myfun2(x) : x >= 10 { print("10 or greater"); }
|
||||
/// eval> myfun2(5)
|
||||
/// less than 10
|
||||
/// eval> myfun2(12)
|
||||
/// 10 or greater
|
||||
/// \endcode
|
||||
///
|
||||
/// \sa \ref keyworddef
|
||||
/// \sa \ref keywordattr
|
||||
/// \sa \ref LangObjectSystemRef
|
||||
///
|
||||
/// <hr>
|
||||
/// \section chaiscriptfunctionobjects Function Objects
|
||||
///
|
||||
/// Functions are first class types in ChaiScript and can be used as variables.
|
||||
///
|
||||
/// \code
|
||||
/// eval> var p = print;
|
||||
/// eval> p(1);
|
||||
/// 1
|
||||
/// \endcode
|
||||
///
|
||||
/// They can also be passed to functions.
|
||||
///
|
||||
/// \code
|
||||
/// eval> def callfunc(f, lhs, rhs) { return f(lhs, rhs); }
|
||||
/// eval> def dosomething(lhs, rhs) { print("lhs: ${lhs}, rhs: ${rhs}"); }
|
||||
/// eval> callfunc(dosomething, 1, 2);
|
||||
/// lhs: 1, rhs: 2
|
||||
/// \endcode
|
||||
///
|
||||
/// Operators can also be treated as functions by using the back tick operator. Building on the above example:
|
||||
///
|
||||
/// \code
|
||||
/// eval> callfunc(`+`, 1, 4);
|
||||
/// 5
|
||||
/// eval> callfunc(`*`, 3, 2);
|
||||
/// 6
|
||||
/// \endcode
|
||||
///
|
||||
/// <hr>
|
||||
/// \sa \ref LangKeywordRef
|
||||
/// \sa ChaiScript_Language for Built in Functions
|
||||
|
||||
|
||||
/// \page LangKeywordRef ChaiScript Language Keyword Reference
|
||||
///
|
||||
///
|
||||
/// <hr>
|
||||
/// \section keywordattr attr
|
||||
/// Defines a ChaiScript object attribute
|
||||
///
|
||||
/// \code
|
||||
/// Attribute Definition ::= "attr" class_name "::" attribute_name
|
||||
/// \endcode
|
||||
///
|
||||
/// \sa \ref LangObjectSystemRef
|
||||
///
|
||||
/// <hr>
|
||||
/// \section keywordbreak break
|
||||
/// Stops execution of a looping block.
|
||||
///
|
||||
/// \code
|
||||
/// Break Statement ::= "break"
|
||||
/// \endcode
|
||||
///
|
||||
/// \sa \ref keywordfor
|
||||
/// \sa \ref keywordwhile
|
||||
///
|
||||
///
|
||||
/// <hr>
|
||||
/// \section keyworddef def
|
||||
/// Begins a function or method definition
|
||||
///
|
||||
/// \code
|
||||
/// Function Definition ::= [annotation + CR/LF] "def" identifier "(" [arg ("," arg)*] ")" [":" guard] block
|
||||
/// Method Definition ::= [annotation + CR/LF] "def" class_name "::" method_name "(" [arg ("," arg)*] ")" [":" guard] block
|
||||
/// \endcode
|
||||
///
|
||||
/// annotation: meta-annotation on function, currently used as documentation. Optional.
|
||||
/// identifier: name of function. Required.
|
||||
/// args: comma-delimited list of parameter names. Optional.
|
||||
/// guards: guarding statement that act as a prerequisite for the function. Optional.
|
||||
/// { }: scoped block as function body. Required.
|
||||
///
|
||||
/// Functions return values in one of two ways:
|
||||
///
|
||||
/// By using an explicit return call, optionally passing the value to be returned.
|
||||
/// By implicitly returning the value of the last expression (if it is not a while or for loop).
|
||||
///
|
||||
/// Method definitions for known types extend those types with new methods. This includes C++ and ChaiScript defined types.
|
||||
/// Method definitions for unknown types implicitly define the named type.
|
||||
///
|
||||
/// \sa \ref LangObjectSystemRef
|
||||
///
|
||||
///
|
||||
/// <hr>
|
||||
/// \section keywordelse else
|
||||
/// \sa \ref keywordif
|
||||
///
|
||||
///
|
||||
/// <hr>
|
||||
/// \section keywordfor for
|
||||
/// \code
|
||||
/// For Block ::= "for" "(" [initial] ";" stop_condition ";" loop_expression ")" block
|
||||
/// \endcode
|
||||
/// This loop can be broken using the \ref keywordbreak command.
|
||||
///
|
||||
///
|
||||
/// <hr>
|
||||
/// \section keywordfun fun
|
||||
/// Begins an anonymous function declaration (sometimes called a lambda).
|
||||
///
|
||||
/// \code
|
||||
/// Lambda ::= "fun" "(" [variable] ("," variable)* ")" block
|
||||
/// \endcode
|
||||
///
|
||||
/// \b Examples:
|
||||
///
|
||||
/// \code
|
||||
/// // Generate an anonymous function object that adds 2 to its parameter
|
||||
/// var f = fun(x) { x + 2; }
|
||||
/// \endcode
|
||||
///
|
||||
/// \sa \ref keyworddef for more details on ChaiScript functions
|
||||
///
|
||||
///
|
||||
/// <hr>
|
||||
/// \section keywordif if
|
||||
/// Begins a conditional block of code that only executes if the condition evaluates as true.
|
||||
/// \code
|
||||
/// If Block ::= "if" "(" condition ")" block
|
||||
/// Else If Block ::= "else if" "(" condition ")" block
|
||||
/// Else Block ::= "else" block
|
||||
/// \endcode
|
||||
/// \b Example:
|
||||
/// \code
|
||||
/// if (true) {
|
||||
/// // do something
|
||||
/// } else if (false) {
|
||||
/// // do something else
|
||||
/// } else {
|
||||
/// // otherwise do this
|
||||
/// }
|
||||
/// \endcode
|
||||
///
|
||||
///
|
||||
/// <hr>
|
||||
/// \section keywordtry try
|
||||
/// \code
|
||||
/// Try Block ::= "try" block
|
||||
/// ("catch" ["(" variable ")"] [":" guards] block)+
|
||||
/// ["finally" block]
|
||||
/// \endcode
|
||||
///
|
||||
/// \sa ChaiScript_Language::throw
|
||||
///
|
||||
/// <hr>
|
||||
/// \section keywordwhile while
|
||||
///
|
||||
/// Begins a conditional block of code that loops 0 or more times, as long as the condition is true
|
||||
///
|
||||
/// \code
|
||||
/// While Block ::= "while" "(" condition ")" block
|
||||
/// \endcode
|
||||
/// This loop can be broken using the \ref keywordbreak command.
|
||||
|
||||
|
||||
/// \namespace chaiscript
|
||||
/// \brief Namespace chaiscript contains every API call that the average user will be concerned with.
|
||||
|
||||
/// \namespace chaiscript::detail
|
||||
/// \brief Classes and functions reserved for internal use. Items in this namespace are not supported.
|
||||
|
||||
#include "chaiscript_defines.hpp"
|
||||
|
||||
#include "dispatchkit/dispatchkit.hpp"
|
||||
#include "dispatchkit/bootstrap.hpp"
|
||||
#include "dispatchkit/bootstrap_stl.hpp"
|
||||
#include "dispatchkit/function_call.hpp"
|
||||
#include "dispatchkit/dynamic_object.hpp"
|
||||
|
||||
#ifdef BOOST_HAS_DECLSPEC
|
||||
#define CHAISCRIPT_MODULE_EXPORT extern "C" __declspec(dllexport)
|
||||
#else
|
||||
#define CHAISCRIPT_MODULE_EXPORT extern "C"
|
||||
#endif
|
||||
#include "dispatchkit/boxed_number.hpp"
|
||||
|
||||
#include "language/chaiscript_eval.hpp"
|
||||
#include "language/chaiscript_engine.hpp"
|
||||
|
||||
|
||||
|
||||
#endif /* CHAISCRIPT_HPP_ */
|
||||
|
28
include/chaiscript/chaiscript_defines.hpp
Normal file
28
include/chaiscript/chaiscript_defines.hpp
Normal file
@@ -0,0 +1,28 @@
|
||||
// This file is distributed under the BSD License.
|
||||
// See "license.txt" for details.
|
||||
// Copyright 2009-2012, Jonathan Turner (jonathan@emptycrate.com)
|
||||
// and Jason Turner (jason@emptycrate.com)
|
||||
// http://www.chaiscript.com
|
||||
|
||||
#ifndef CHAISCRIPT_DEFINES_HPP_
|
||||
#define CHAISCRIPT_DEFINES_HPP_
|
||||
|
||||
#ifdef _MSC_VER
|
||||
#define CHAISCRIPT_MSVC _MSC_VER
|
||||
#define CHAISCRIPT_HAS_DECLSPEc
|
||||
#endif
|
||||
|
||||
#ifdef _WIN32
|
||||
#define CHAISCRIPT_WINDOWS
|
||||
#endif
|
||||
|
||||
|
||||
#ifdef CHAISCRIPT_HAS_DECLSPEC
|
||||
#define CHAISCRIPT_MODULE_EXPORT extern "C" __declspec(dllexport)
|
||||
#else
|
||||
#define CHAISCRIPT_MODULE_EXPORT extern "C"
|
||||
#endif
|
||||
|
||||
|
||||
#endif
|
||||
|
44
include/chaiscript/chaiscript_stdlib.hpp
Normal file
44
include/chaiscript/chaiscript_stdlib.hpp
Normal file
@@ -0,0 +1,44 @@
|
||||
// This file is distributed under the BSD License.
|
||||
// See "license.txt" for details.
|
||||
// Copyright 2009-2012, Jonathan Turner (jonathan@emptycrate.com)
|
||||
// and Jason Turner (jason@emptycrate.com)
|
||||
// http://www.chaiscript.com
|
||||
|
||||
#ifndef CHAISCRIPT_STDLIB_HPP_
|
||||
#define CHAISCRIPT_STDLIB_HPP_
|
||||
|
||||
#include "chaiscript_defines.hpp"
|
||||
#include "dispatchkit/bootstrap.hpp"
|
||||
#include "dispatchkit/bootstrap_stl.hpp"
|
||||
|
||||
/// \file
|
||||
///
|
||||
/// This file generates the standard library that normal ChaiScript usage requires.
|
||||
|
||||
namespace chaiscript
|
||||
{
|
||||
class Std_Lib
|
||||
{
|
||||
public:
|
||||
|
||||
static ModulePtr library()
|
||||
{
|
||||
using namespace bootstrap;
|
||||
|
||||
ModulePtr lib = Bootstrap::bootstrap();
|
||||
|
||||
lib->add(standard_library::vector_type<std::vector<Boxed_Value> >("Vector"));
|
||||
lib->add(standard_library::string_type<std::string>("string"));
|
||||
lib->add(standard_library::map_type<std::map<std::string, Boxed_Value> >("Map"));
|
||||
lib->add(standard_library::pair_type<std::pair<Boxed_Value, Boxed_Value > >("Pair"));
|
||||
|
||||
return lib;
|
||||
}
|
||||
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
|
||||
#endif
|
||||
|
@@ -1,48 +1,135 @@
|
||||
#ifndef __chaiscript_threading_hpp__
|
||||
#define __chaiscript_threading_hpp__
|
||||
// This file is distributed under the BSD License.
|
||||
// See "license.txt" for details.
|
||||
// Copyright 2009-2012, Jonathan Turner (jonathan@emptycrate.com)
|
||||
// and Jason Turner (jason@emptycrate.com)
|
||||
// http://www.chaiscript.com
|
||||
|
||||
#ifndef CHAISCRIPT_THREADING_HPP_
|
||||
#define CHAISCRIPT_THREADING_HPP_
|
||||
|
||||
#ifndef CHAISCRIPT_NO_THREADS
|
||||
#include <boost/thread.hpp>
|
||||
#include <thread>
|
||||
#include <mutex>
|
||||
#else
|
||||
#pragma message ("ChaiScript is compiling without thread safety.")
|
||||
#endif
|
||||
|
||||
/// \file
|
||||
///
|
||||
/// This file contains code necessary for thread support in ChaiScript.
|
||||
/// If the compiler definition CHAISCRIPT_NO_THREADS is defined then thread safety
|
||||
/// is disabled in ChaiScript. This has the result that some code is faster, because mutex locks are not required.
|
||||
/// It also has the side effect that the chaiscript::ChaiScript object may not be accessed from more than
|
||||
/// one thread simultaneously.
|
||||
|
||||
namespace chaiscript
|
||||
{
|
||||
namespace detail
|
||||
{
|
||||
/// If threading is enabled, then this namespace contains std thread classes.
|
||||
/// If threading is not enabled, then stubbed in wrappers that do nothing are provided.
|
||||
/// This allows us to avoid \#ifdef code in the sections that need thread safety.
|
||||
namespace threading
|
||||
{
|
||||
|
||||
#ifndef CHAISCRIPT_NO_THREADS
|
||||
|
||||
template<typename T>
|
||||
class unique_lock : public std::unique_lock<T>
|
||||
{
|
||||
public:
|
||||
unique_lock(T &t) : std::unique_lock<T>(t) {}
|
||||
};
|
||||
|
||||
template<typename T>
|
||||
class shared_lock : public std::unique_lock<T>
|
||||
{
|
||||
public:
|
||||
shared_lock(T &t) : std::unique_lock<T>(t) {}
|
||||
void unlock() {}
|
||||
};
|
||||
|
||||
template<typename T>
|
||||
class lock_guard : public std::lock_guard<T>
|
||||
{
|
||||
public:
|
||||
lock_guard(T &t) : std::lock_guard<T>(t) {}
|
||||
};
|
||||
|
||||
class shared_mutex : public std::mutex { };
|
||||
|
||||
using std::mutex;
|
||||
|
||||
using std::recursive_mutex;
|
||||
|
||||
|
||||
|
||||
/// Typesafe thread specific storage. If threading is enabled, this class uses a mutex protected map. If
|
||||
/// threading is not enabled, the class always returns the same data, regardless of which thread it is called from.
|
||||
///
|
||||
/// \todo move to thread_local when it exists
|
||||
template<typename T>
|
||||
class Thread_Storage
|
||||
{
|
||||
public:
|
||||
~Thread_Storage()
|
||||
{
|
||||
m_thread_storage.reset();
|
||||
}
|
||||
|
||||
inline T *operator->() const
|
||||
{
|
||||
if (!m_thread_storage.get())
|
||||
{
|
||||
m_thread_storage.reset(new T());
|
||||
}
|
||||
|
||||
return m_thread_storage.get();
|
||||
return get_tls().get();
|
||||
}
|
||||
|
||||
inline T &operator*() const
|
||||
{
|
||||
return *(this->operator->());
|
||||
return *get_tls();
|
||||
}
|
||||
|
||||
|
||||
private:
|
||||
mutable boost::thread_specific_ptr<T> m_thread_storage;
|
||||
std::shared_ptr<T> get_tls() const
|
||||
{
|
||||
unique_lock<mutex> lock(m_mutex);
|
||||
|
||||
auto itr = m_instances.find(std::this_thread::get_id());
|
||||
|
||||
if (itr != m_instances.end()) { return itr->second; }
|
||||
|
||||
std::shared_ptr<T> new_instance(new T());
|
||||
|
||||
m_instances.insert(std::make_pair(std::this_thread::get_id(), new_instance));
|
||||
|
||||
return new_instance;
|
||||
}
|
||||
|
||||
mutable mutex m_mutex;
|
||||
mutable std::map<std::thread::id, std::shared_ptr<T> > m_instances;
|
||||
};
|
||||
|
||||
#else
|
||||
template<typename T>
|
||||
class unique_lock
|
||||
{
|
||||
public:
|
||||
unique_lock(T &) {}
|
||||
};
|
||||
|
||||
template<typename T>
|
||||
class shared_lock
|
||||
{
|
||||
public:
|
||||
shared_lock(T &) {}
|
||||
void unlock() {}
|
||||
};
|
||||
|
||||
template<typename T>
|
||||
class lock_guard
|
||||
{
|
||||
public:
|
||||
lock_guard(T &) {}
|
||||
};
|
||||
|
||||
class shared_mutex { };
|
||||
|
||||
class recursive_mutex {};
|
||||
|
||||
|
||||
template<typename T>
|
||||
class Thread_Storage
|
||||
@@ -63,7 +150,7 @@ namespace chaiscript
|
||||
};
|
||||
|
||||
#endif
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
162
include/chaiscript/dispatchkit/any.hpp
Normal file
162
include/chaiscript/dispatchkit/any.hpp
Normal file
@@ -0,0 +1,162 @@
|
||||
// This file is distributed under the BSD License.
|
||||
// See "license.txt" for details.
|
||||
// Copyright 2009-2012, Jonathan Turner (jonathan@emptycrate.com)
|
||||
// and Jason Turner (jason@emptycrate.com)
|
||||
// http://www.chaiscript.com
|
||||
|
||||
#ifndef CHAISCRIPT_ANY_HPP_
|
||||
#define CHAISCRIPT_ANY_HPP_
|
||||
|
||||
namespace chaiscript {
|
||||
namespace detail {
|
||||
namespace exception
|
||||
{
|
||||
/// \brief Thrown in the event that an Any cannot be cast to the desired type
|
||||
///
|
||||
/// It is used internally during function dispatch.
|
||||
///
|
||||
/// \sa chaiscript::detail::Any
|
||||
class bad_any_cast : public std::bad_cast
|
||||
{
|
||||
public:
|
||||
bad_any_cast() noexcept
|
||||
: m_what("bad any cast")
|
||||
{
|
||||
}
|
||||
|
||||
virtual ~bad_any_cast() noexcept {}
|
||||
|
||||
/// \brief Description of what error occured
|
||||
virtual const char * what() const noexcept
|
||||
{
|
||||
return m_what.c_str();
|
||||
}
|
||||
|
||||
private:
|
||||
std::string m_what;
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
class Any {
|
||||
private:
|
||||
struct Data
|
||||
{
|
||||
virtual void *data() = 0;
|
||||
virtual const std::type_info &type() const = 0;
|
||||
virtual std::shared_ptr<Data> clone() const = 0;
|
||||
};
|
||||
|
||||
template<typename T>
|
||||
struct Data_Impl : Data
|
||||
{
|
||||
Data_Impl(const T &t_type)
|
||||
: m_type(typeid(T)),
|
||||
m_data(t_type)
|
||||
{
|
||||
}
|
||||
|
||||
virtual void *data()
|
||||
{
|
||||
return &m_data;
|
||||
}
|
||||
|
||||
const std::type_info &type() const
|
||||
{
|
||||
return m_type;
|
||||
}
|
||||
|
||||
std::shared_ptr<Data> clone() const
|
||||
{
|
||||
return std::shared_ptr<Data>(new Data_Impl<T>(m_data));
|
||||
}
|
||||
|
||||
const std::type_info &m_type;
|
||||
T m_data;
|
||||
};
|
||||
|
||||
std::shared_ptr<Data> m_data;
|
||||
|
||||
public:
|
||||
// construct/copy/destruct
|
||||
Any() = default;
|
||||
|
||||
Any(const Any &t_any)
|
||||
{
|
||||
if (!t_any.empty())
|
||||
{
|
||||
m_data = t_any.m_data->clone();
|
||||
} else {
|
||||
m_data.reset();
|
||||
}
|
||||
}
|
||||
|
||||
template<typename ValueType>
|
||||
Any(const ValueType &t_value)
|
||||
{
|
||||
m_data = std::shared_ptr<Data>(new Data_Impl<ValueType>(t_value));
|
||||
}
|
||||
|
||||
Any & operator=(const Any &t_any)
|
||||
{
|
||||
Any copy(t_any);
|
||||
swap(copy);
|
||||
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>
|
||||
ToType &cast() const
|
||||
{
|
||||
if (m_data && typeid(ToType) == m_data->type())
|
||||
{
|
||||
return *static_cast<ToType *>(m_data->data());
|
||||
} else {
|
||||
throw chaiscript::detail::exception::bad_any_cast();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
~Any()
|
||||
{
|
||||
}
|
||||
|
||||
// modifiers
|
||||
Any & swap(Any &t_other)
|
||||
{
|
||||
std::shared_ptr<Data> data = t_other.m_data;
|
||||
t_other.m_data = m_data;
|
||||
m_data = data;
|
||||
return *this;
|
||||
}
|
||||
|
||||
// queries
|
||||
bool empty() const
|
||||
{
|
||||
return !bool(m_data);
|
||||
}
|
||||
|
||||
const std::type_info & type() const
|
||||
{
|
||||
if (m_data)
|
||||
{
|
||||
return m_data->type();
|
||||
} else {
|
||||
return typeid(void);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
|
60
include/chaiscript/dispatchkit/bad_boxed_cast.hpp
Normal file
60
include/chaiscript/dispatchkit/bad_boxed_cast.hpp
Normal file
@@ -0,0 +1,60 @@
|
||||
// This file is distributed under the BSD License.
|
||||
// See "license.txt" for details.
|
||||
// Copyright 2009-2012, Jonathan Turner (jonathan@emptycrate.com)
|
||||
// and Jason Turner (jason@emptycrate.com)
|
||||
// http://www.chaiscript.com
|
||||
|
||||
#ifndef CHAISCRIPT_BAD_BOXED_CAST_HPP_
|
||||
#define CHAISCRIPT_BAD_BOXED_CAST_HPP_
|
||||
|
||||
#include "type_info.hpp"
|
||||
|
||||
namespace chaiscript
|
||||
{
|
||||
namespace exception
|
||||
{
|
||||
/// \brief Thrown in the event that a Boxed_Value cannot be cast to the desired type
|
||||
///
|
||||
/// It is used internally during function dispatch and may be used by the end user.
|
||||
///
|
||||
/// \sa chaiscript::boxed_cast
|
||||
class bad_boxed_cast : public std::bad_cast
|
||||
{
|
||||
public:
|
||||
bad_boxed_cast(const Type_Info &t_from, const std::type_info &t_to,
|
||||
const std::string &t_what) noexcept
|
||||
: from(t_from), to(&t_to), m_what(t_what)
|
||||
{
|
||||
}
|
||||
|
||||
bad_boxed_cast(const Type_Info &t_from, const std::type_info &t_to) noexcept
|
||||
: from(t_from), to(&t_to), m_what("Cannot perform boxed_cast")
|
||||
{
|
||||
}
|
||||
|
||||
bad_boxed_cast(const std::string &t_what) noexcept
|
||||
: to(0), m_what(t_what)
|
||||
{
|
||||
}
|
||||
|
||||
virtual ~bad_boxed_cast() noexcept {}
|
||||
|
||||
/// \brief Description of what error occured
|
||||
virtual const char * what() const noexcept
|
||||
{
|
||||
return m_what.c_str();
|
||||
}
|
||||
|
||||
Type_Info from; ///< Type_Info contained in the Boxed_Value
|
||||
const std::type_info *to; ///< std::type_info of the desired (but failed) result type
|
||||
|
||||
private:
|
||||
std::string m_what;
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
#endif
|
||||
|
@@ -1,66 +1,133 @@
|
||||
// This file is distributed under the BSD License.
|
||||
// See "license.txt" for details.
|
||||
// Copyright 2009-2010, Jonathan Turner (jturner@minnow-lang.org)
|
||||
// and Jason Turner (lefticus@gmail.com)
|
||||
// Copyright 2009-2012, Jonathan Turner (jonathan@emptycrate.com)
|
||||
// and Jason Turner (jason@emptycrate.com)
|
||||
// http://www.chaiscript.com
|
||||
|
||||
#include <boost/preprocessor.hpp>
|
||||
#include <boost/preprocessor/arithmetic/inc.hpp>
|
||||
#ifndef CHAISCRIPT_BIND_FIRST_HPP_
|
||||
#define CHAISCRIPT_BIND_FIRST_HPP_
|
||||
|
||||
#define param(z,n,text) BOOST_PP_CAT(text, BOOST_PP_INC(n))
|
||||
|
||||
#ifndef BOOST_PP_IS_ITERATING
|
||||
#ifndef __bind_first_hpp__
|
||||
#define __bind_first_hpp__
|
||||
|
||||
#include <boost/function.hpp>
|
||||
#include <boost/bind.hpp>
|
||||
#include <boost/ref.hpp>
|
||||
|
||||
#define BOOST_PP_ITERATION_LIMITS ( 0, 8 )
|
||||
#define BOOST_PP_FILENAME_1 <chaiscript/dispatchkit/bind_first.hpp>
|
||||
|
||||
#include BOOST_PP_ITERATE()
|
||||
|
||||
|
||||
# endif
|
||||
#else
|
||||
# define n BOOST_PP_ITERATION()
|
||||
# define m BOOST_PP_INC(n)
|
||||
#include <functional>
|
||||
|
||||
namespace chaiscript
|
||||
{
|
||||
|
||||
template<typename Ret, typename O, typename Class BOOST_PP_COMMA_IF(n) BOOST_PP_ENUM_PARAMS(n, typename Param) >
|
||||
boost::function<Ret (BOOST_PP_ENUM_PARAMS(n, Param))>
|
||||
bind_first(Ret (Class::*f)(BOOST_PP_ENUM_PARAMS(n, Param)), const O &o)
|
||||
namespace detail
|
||||
{
|
||||
return boost::bind(boost::mem_fn(f), o BOOST_PP_COMMA_IF(n) BOOST_PP_ENUM(n, param, _));
|
||||
}
|
||||
|
||||
template<typename Ret, typename O, typename Class BOOST_PP_COMMA_IF(n) BOOST_PP_ENUM_PARAMS(n, typename Param) >
|
||||
boost::function<Ret (BOOST_PP_ENUM_PARAMS(n, Param))>
|
||||
bind_first(Ret (Class::*f)(BOOST_PP_ENUM_PARAMS(n, Param))const, const O &o)
|
||||
template<int>
|
||||
struct Placeholder
|
||||
{
|
||||
return boost::bind(boost::mem_fn(f), o BOOST_PP_COMMA_IF(n) BOOST_PP_ENUM(n, param, _));
|
||||
}
|
||||
};
|
||||
|
||||
template<typename Ret,typename O BOOST_PP_COMMA_IF(m) BOOST_PP_ENUM_PARAMS(m, typename Param) >
|
||||
boost::function<Ret (BOOST_PP_ENUM(n, param, Param))>
|
||||
bind_first(Ret (*f)(BOOST_PP_ENUM_PARAMS(m, Param)), const O &o)
|
||||
template<>
|
||||
struct Placeholder<1>
|
||||
{
|
||||
return boost::bind(f, o BOOST_PP_COMMA_IF(n) BOOST_PP_ENUM(n, param, _));
|
||||
}
|
||||
static decltype(std::placeholders::_1) value() { return std::placeholders::_1; }
|
||||
};
|
||||
|
||||
template<typename Ret,typename O BOOST_PP_COMMA_IF(m) BOOST_PP_ENUM_PARAMS(m, typename Param) >
|
||||
boost::function<Ret (BOOST_PP_ENUM(n, param, Param))>
|
||||
bind_first(const boost::function<Ret (BOOST_PP_ENUM_PARAMS(m, Param))> &f, const O &o)
|
||||
template<>
|
||||
struct Placeholder<2>
|
||||
{
|
||||
return boost::bind(f, o BOOST_PP_COMMA_IF(n) BOOST_PP_ENUM(n, param, _));
|
||||
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>
|
||||
struct Bind_First
|
||||
{
|
||||
template<typename F, typename ... 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());
|
||||
}
|
||||
};
|
||||
|
||||
template<int maxcount, typename Sig>
|
||||
struct Bind_First<0, maxcount, Sig>
|
||||
{
|
||||
template<typename F, typename ... InnerParams>
|
||||
static std::function<Sig> bind(F f, InnerParams ... innerparams)
|
||||
{
|
||||
return std::bind(f, innerparams...);
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
template<typename O, typename Ret, typename P1, typename ... Param>
|
||||
std::function<Ret (Param...)> bind_first(Ret (*f)(P1, Param...), O o)
|
||||
{
|
||||
return Bind_First<sizeof...(Param), sizeof...(Param), Ret (Param...)>::bind(f, o);
|
||||
}
|
||||
|
||||
template<typename O, typename Ret, typename Class, typename ... Param>
|
||||
std::function<Ret (Param...)> bind_first(Ret (Class::*f)(Param...), O o)
|
||||
{
|
||||
return Bind_First<sizeof...(Param), sizeof...(Param), Ret (Param...)>::bind(f, o);
|
||||
}
|
||||
|
||||
template<typename O, typename Ret, typename Class, typename ... Param>
|
||||
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);
|
||||
}
|
||||
|
||||
template<typename O, typename Ret, typename P1, typename ... Param>
|
||||
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);
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
#undef n
|
||||
#undef m
|
||||
|
||||
#endif
|
||||
|
@@ -1,168 +1,57 @@
|
||||
// This file is distributed under the BSD License.
|
||||
// See "license.txt" for details.
|
||||
// Copyright 2009-2010, Jonathan Turner (jturner@minnow-lang.org)
|
||||
// and Jason Turner (lefticus@gmail.com)
|
||||
// Copyright 2009-2012, Jonathan Turner (jonathan@emptycrate.com)
|
||||
// and Jason Turner (jason@emptycrate.com)
|
||||
// http://www.chaiscript.com
|
||||
|
||||
#ifndef __bootstrap_hpp
|
||||
#define __bootstrap_hpp__
|
||||
#ifndef CHAISCRIPT_BOOTSTRAP_HPP_
|
||||
#define CHAISCRIPT_BOOTSTRAP_HPP_
|
||||
|
||||
#include "dispatchkit.hpp"
|
||||
#include "dynamic_object.hpp"
|
||||
#include "register_function.hpp"
|
||||
#include "operators.hpp"
|
||||
#include "boxed_number.hpp"
|
||||
#include <sstream>
|
||||
#include <type_traits>
|
||||
|
||||
namespace chaiscript
|
||||
{
|
||||
/// \brief Classes and functions useful for bootstrapping of ChaiScript and adding of new types
|
||||
namespace bootstrap
|
||||
{
|
||||
namespace detail
|
||||
{
|
||||
|
||||
/* Special helpers for generating generic "POD" type operators
|
||||
* The POD operators are needed for general support of C++ POD
|
||||
* types without iterating out all possible combinations of operators
|
||||
* (<, >, +, +=, *=, \=, -, <=, >=, ==) and types
|
||||
* (char, uint8_t, int8_t, uint16_t, int16_t...)
|
||||
*/
|
||||
/// \brief Constructs a new POD value object from a Boxed_Number
|
||||
/// \param[in] v Boxed_Number to copy into the new object
|
||||
/// \returns The newly created object.
|
||||
template<typename P1>
|
||||
P1 &assign_pod(P1 &p1, Boxed_POD_Value v)
|
||||
std::shared_ptr<P1> construct_pod(Boxed_Number v)
|
||||
{
|
||||
|
||||
if (v.m_isfloat)
|
||||
{
|
||||
return (p1 = P1(v.d));
|
||||
} else {
|
||||
return (p1 = P1(v.i));
|
||||
std::shared_ptr<P1> p(new P1());
|
||||
Boxed_Value bv(p);
|
||||
Boxed_Number nb(bv);
|
||||
nb = v;
|
||||
return p;
|
||||
}
|
||||
}
|
||||
|
||||
template<typename P1>
|
||||
P1 construct_pod(Boxed_POD_Value v)
|
||||
/// \brief Adds a copy constructor for the given type to the given Model
|
||||
/// \param[in] type The name of the type. The copy constructor will be named "type".
|
||||
/// \param[in,out] m The Module to add the copy constructor to
|
||||
/// \tparam T The type to add a copy constructor for
|
||||
/// \returns The passed in ModulePtr, or the newly constructed one if the default param is used
|
||||
template<typename T>
|
||||
ModulePtr copy_constructor(const std::string &type, ModulePtr m = ModulePtr(new Module()))
|
||||
{
|
||||
if (v.m_isfloat)
|
||||
{
|
||||
return P1(v.d);
|
||||
} else {
|
||||
return P1(v.i);
|
||||
}
|
||||
}
|
||||
|
||||
template<typename P1>
|
||||
P1 &assign_bitwise_and_pod(P1 &p1, Boxed_POD_Value r)
|
||||
{
|
||||
if (!r.m_isfloat)
|
||||
{
|
||||
return p1 &= P1(r.i);
|
||||
}
|
||||
|
||||
throw bad_boxed_cast("&= only valid for integer types");
|
||||
}
|
||||
|
||||
template<typename P1>
|
||||
P1 &assign_xor_pod(P1 &p1, Boxed_POD_Value r)
|
||||
{
|
||||
if (!r.m_isfloat)
|
||||
{
|
||||
return p1 ^= P1(r.i);
|
||||
}
|
||||
|
||||
throw bad_boxed_cast("^= only valid for integer types");
|
||||
}
|
||||
|
||||
template<typename P1>
|
||||
P1 &assign_bitwise_or_pod(P1 &p1, Boxed_POD_Value r)
|
||||
{
|
||||
if (!r.m_isfloat)
|
||||
{
|
||||
return p1 |= P1(r.i);
|
||||
}
|
||||
|
||||
throw bad_boxed_cast("&= only valid for integer types");
|
||||
}
|
||||
|
||||
template<typename P1>
|
||||
P1 &assign_difference_pod(P1 &p1, Boxed_POD_Value r)
|
||||
{
|
||||
if (r.m_isfloat)
|
||||
{
|
||||
return p1 -= P1(r.d);
|
||||
} else {
|
||||
return p1 -= P1(r.i);
|
||||
}
|
||||
}
|
||||
|
||||
template<typename P1>
|
||||
P1 &assign_left_shift_pod(P1 &p1, Boxed_POD_Value r)
|
||||
{
|
||||
if (!r.m_isfloat)
|
||||
{
|
||||
return p1 <<= P1(r.i);
|
||||
}
|
||||
|
||||
throw bad_boxed_cast("<<= only valid for integer types");
|
||||
}
|
||||
|
||||
|
||||
template<typename P1>
|
||||
P1 &assign_product_pod(P1 &p1, Boxed_POD_Value r)
|
||||
{
|
||||
if (r.m_isfloat)
|
||||
{
|
||||
return p1 *= P1(r.d);
|
||||
} else {
|
||||
return p1 *= P1(r.i);
|
||||
}
|
||||
}
|
||||
|
||||
template<typename P1>
|
||||
P1 &assign_quotient_pod(P1 &p1, Boxed_POD_Value r)
|
||||
{
|
||||
if (r.m_isfloat)
|
||||
{
|
||||
return p1 /= P1(r.d);
|
||||
} else {
|
||||
return p1 /= P1(r.i);
|
||||
}
|
||||
}
|
||||
|
||||
template<typename P1>
|
||||
P1 &assign_remainder_pod(P1 &p1, Boxed_POD_Value r)
|
||||
{
|
||||
if (!r.m_isfloat)
|
||||
{
|
||||
return p1 %= P1(r.i);
|
||||
}
|
||||
|
||||
throw bad_boxed_cast("%= only valid for integer types");
|
||||
}
|
||||
|
||||
|
||||
template<typename P1>
|
||||
P1 &assign_right_shift_pod(P1 &p1, Boxed_POD_Value r)
|
||||
{
|
||||
if (!r.m_isfloat)
|
||||
{
|
||||
return p1 >>= P1(r.i);
|
||||
}
|
||||
|
||||
throw bad_boxed_cast(">>= only valid for integer types");
|
||||
}
|
||||
|
||||
|
||||
template<typename P1>
|
||||
P1 &assign_sum_pod(P1 &p1, Boxed_POD_Value r)
|
||||
{
|
||||
if (r.m_isfloat)
|
||||
{
|
||||
return p1 += P1(r.d);
|
||||
} else {
|
||||
return p1 += P1(r.i);
|
||||
}
|
||||
}
|
||||
|
||||
m->add(constructor<T (const T &)>(), type);
|
||||
return m;
|
||||
}
|
||||
|
||||
/// \brief Add all comparison operators for the templated type. Used during bootstrap, also available to users.
|
||||
/// \tparam T Type to create comparison operators for
|
||||
/// \param[in,out] m module to add comparison operators to
|
||||
/// \returns the passed in ModulePtr or the newly constructed one if the default params are used.
|
||||
template<typename T>
|
||||
ModulePtr opers_comparison(ModulePtr m = ModulePtr(new Module()))
|
||||
{
|
||||
@@ -175,68 +64,15 @@ namespace chaiscript
|
||||
return m;
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
ModulePtr opers_integer_arithmetic(ModulePtr m = ModulePtr(new Module()))
|
||||
{
|
||||
operators::assign_bitwise_and<T>(m);
|
||||
operators::assign_xor<T>(m);
|
||||
operators::assign_bitwise_or<T>(m);
|
||||
operators::assign_difference<T>(m);
|
||||
operators::assign_left_shift<T>(m);
|
||||
operators::assign_product<T>(m);
|
||||
operators::assign_quotient<T>(m);
|
||||
operators::assign_remainder<T>(m);
|
||||
operators::assign_right_shift<T>(m);
|
||||
operators::assign_sum<T>(m);
|
||||
|
||||
operators::prefix_decrement<T>(m);
|
||||
operators::prefix_increment<T>(m);
|
||||
operators::addition<T>(m);
|
||||
operators::unary_plus<T>(m);
|
||||
operators::subtraction<T>(m);
|
||||
operators::unary_minus<T>(m);
|
||||
operators::bitwise_and<T>(m);
|
||||
operators::bitwise_compliment<T>(m);
|
||||
operators::bitwise_xor<T>(m);
|
||||
operators::bitwise_or<T>(m);
|
||||
operators::division<T>(m);
|
||||
operators::left_shift<T>(m);
|
||||
operators::multiplication<T>(m);
|
||||
operators::remainder<T>(m);
|
||||
operators::right_shift<T>(m);
|
||||
return m;
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
ModulePtr opers_float_arithmetic(ModulePtr m = ModulePtr(new Module()))
|
||||
{
|
||||
operators::assign_difference<T>(m);
|
||||
operators::assign_product<T>(m);
|
||||
operators::assign_quotient<T>(m);
|
||||
operators::assign_sum<T>(m);
|
||||
|
||||
operators::addition<T>(m);
|
||||
operators::unary_plus<T>(m);
|
||||
operators::subtraction<T>(m);
|
||||
operators::unary_minus<T>(m);
|
||||
operators::division<T>(m);
|
||||
operators::multiplication<T>(m);
|
||||
return m;
|
||||
}
|
||||
|
||||
/**
|
||||
* Add a copy constructor for type T
|
||||
*/
|
||||
template<typename T>
|
||||
ModulePtr copy_constructor(const std::string &type, ModulePtr m = ModulePtr(new Module()))
|
||||
{
|
||||
m->add(constructor<T (const T &)>(), type);
|
||||
return m;
|
||||
}
|
||||
|
||||
/**
|
||||
* Add default and copy constructors for type T
|
||||
*/
|
||||
/// \brief Adds default and copy constructors for the given type
|
||||
/// \param[in] type The name of the type to add the constructors for.
|
||||
/// \param[in,out] m The Module to add the basic constructors to
|
||||
/// \tparam T Type to generate basic constructors for
|
||||
/// \returns The passed in ModulePtr, or the newly constructed one if the default param is used
|
||||
/// \sa copy_constructor
|
||||
/// \sa constructor
|
||||
template<typename T>
|
||||
ModulePtr basic_constructors(const std::string &type, ModulePtr m = ModulePtr(new Module()))
|
||||
{
|
||||
@@ -245,9 +81,10 @@ namespace chaiscript
|
||||
return m;
|
||||
}
|
||||
|
||||
/**
|
||||
* Add POD type constructor for type T. ie: T = type(POD)
|
||||
*/
|
||||
/// \brief Adds a constructor for a POD type
|
||||
/// \tparam T The type to add the constructor for
|
||||
/// \param[in] type The name of the type
|
||||
/// \param[in,out] m The Module to add the constructor to
|
||||
template<typename T>
|
||||
ModulePtr construct_pod(const std::string &type, ModulePtr m = ModulePtr(new Module()))
|
||||
{
|
||||
@@ -255,16 +92,6 @@ namespace chaiscript
|
||||
return m;
|
||||
}
|
||||
|
||||
/**
|
||||
* add user defined single parameter constructor for type T.
|
||||
* T = type(const U &)
|
||||
*/
|
||||
template<typename T, typename U>
|
||||
ModulePtr constructor_overload(const std::string &type, ModulePtr m = ModulePtr(new Module()))
|
||||
{
|
||||
m->add(constructor<T (const U &)>(), type);
|
||||
return m;
|
||||
}
|
||||
|
||||
/**
|
||||
* to_string function for internal use. Uses ostream operator<<
|
||||
@@ -272,10 +99,11 @@ namespace chaiscript
|
||||
template<typename Input>
|
||||
std::string to_string(Input i)
|
||||
{
|
||||
return boost::lexical_cast<std::string>(i);
|
||||
std::stringstream ss;
|
||||
ss << i;
|
||||
return ss.str();
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Internal function for converting from a string to a value
|
||||
* uses ostream operator >> to perform the conversion
|
||||
@@ -283,20 +111,13 @@ namespace chaiscript
|
||||
template<typename Input>
|
||||
Input parse_string(const std::string &i)
|
||||
{
|
||||
return boost::lexical_cast<Input>(i);
|
||||
std::stringstream ss(i);
|
||||
Input t;
|
||||
ss >> t;
|
||||
return t;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Add assignment operator for T = POD.
|
||||
*/
|
||||
template<typename T>
|
||||
ModulePtr oper_assign_pod(ModulePtr m = ModulePtr(new Module()))
|
||||
{
|
||||
m->add(fun(&detail::assign_pod<T>), "=");
|
||||
return m;
|
||||
}
|
||||
|
||||
/**
|
||||
* Add all common functions for a POD type. All operators, and
|
||||
* common conversions
|
||||
@@ -305,52 +126,14 @@ namespace chaiscript
|
||||
ModulePtr bootstrap_pod_type(const std::string &name, ModulePtr m = ModulePtr(new Module()))
|
||||
{
|
||||
m->add(user_type<T>(), name);
|
||||
basic_constructors<T>(name, m);
|
||||
operators::assign<T>(m);
|
||||
oper_assign_pod<T>(m);
|
||||
m->add(constructor<T ()>(), name);
|
||||
construct_pod<T>(name, m);
|
||||
|
||||
m->add(fun(&detail::assign_sum_pod<T>), "+=");
|
||||
m->add(fun(&detail::assign_difference_pod<T>), "-=");
|
||||
m->add(fun(&detail::assign_product_pod<T>), "*=");
|
||||
m->add(fun(&detail::assign_quotient_pod<T>), "/=");
|
||||
|
||||
m->add(fun(&to_string<T>), "to_string");
|
||||
m->add(fun(&parse_string<T>), "to_" + name);
|
||||
return m;
|
||||
}
|
||||
|
||||
/**
|
||||
* Add all common functions for a POD type. All operators, and
|
||||
* common conversions
|
||||
*/
|
||||
template<typename T>
|
||||
ModulePtr bootstrap_integer_type(const std::string &name, ModulePtr m = ModulePtr(new Module()))
|
||||
{
|
||||
bootstrap_pod_type<T>(name, m);
|
||||
|
||||
m->add(fun(&detail::assign_bitwise_and_pod<T>), "&=");
|
||||
m->add(fun(&detail::assign_xor_pod<T>), "^=");
|
||||
m->add(fun(&detail::assign_bitwise_or_pod<T>), "|=");
|
||||
m->add(fun(&detail::assign_left_shift_pod<T>), "<<=");
|
||||
m->add(fun(&detail::assign_remainder_pod<T>), "%=");
|
||||
m->add(fun(&detail::assign_right_shift_pod<T>), ">>=");
|
||||
|
||||
opers_integer_arithmetic<T>(m);
|
||||
return m;
|
||||
}
|
||||
|
||||
/**
|
||||
* Add all common functions for a POD type. All operators, and
|
||||
* common conversions
|
||||
*/
|
||||
template<typename T>
|
||||
ModulePtr bootstrap_float_type(const std::string &name, ModulePtr m = ModulePtr(new Module()))
|
||||
{
|
||||
bootstrap_pod_type<T>(name, m);
|
||||
opers_float_arithmetic<T>(m);
|
||||
return m;
|
||||
}
|
||||
|
||||
/**
|
||||
* "clone" function for a shared_ptr type. This is used in the case
|
||||
@@ -360,7 +143,7 @@ namespace chaiscript
|
||||
* function variables.
|
||||
*/
|
||||
template<typename Type>
|
||||
boost::shared_ptr<Type> shared_ptr_clone(const boost::shared_ptr<Type> &p)
|
||||
std::shared_ptr<Type> shared_ptr_clone(const std::shared_ptr<Type> &p)
|
||||
{
|
||||
return p;
|
||||
}
|
||||
@@ -369,10 +152,10 @@ namespace chaiscript
|
||||
* Specific version of shared_ptr_clone just for Proxy_Functions
|
||||
*/
|
||||
template<typename Type>
|
||||
boost::shared_ptr<typename boost::remove_const<Type>::type>
|
||||
shared_ptr_unconst_clone(const boost::shared_ptr<typename boost::add_const<Type>::type> &p)
|
||||
std::shared_ptr<typename std::remove_const<Type>::type>
|
||||
shared_ptr_unconst_clone(const std::shared_ptr<typename std::add_const<Type>::type> &p)
|
||||
{
|
||||
return boost::const_pointer_cast<typename boost::remove_const<Type>::type>(p);
|
||||
return std::const_pointer_cast<typename std::remove_const<Type>::type>(p);
|
||||
}
|
||||
|
||||
|
||||
@@ -383,7 +166,7 @@ namespace chaiscript
|
||||
* Similar to shared_ptr_clone. Used for Proxy_Function.
|
||||
*/
|
||||
template<typename Type>
|
||||
Boxed_Value ptr_assign(Boxed_Value lhs, const boost::shared_ptr<typename boost::add_const<Type>::type> &rhs)
|
||||
Boxed_Value ptr_assign(Boxed_Value lhs, const std::shared_ptr<Type> &rhs)
|
||||
{
|
||||
if (lhs.is_undef()
|
||||
|| (!lhs.get_type_info().is_const() && lhs.get_type_info().bare_equal(chaiscript::detail::Get_Type_Info<Type>::get())))
|
||||
@@ -391,7 +174,7 @@ namespace chaiscript
|
||||
lhs.assign(Boxed_Value(rhs));
|
||||
return lhs;
|
||||
} else {
|
||||
throw bad_boxed_cast("type mismatch in pointer assignment");
|
||||
throw exception::bad_boxed_cast("type mismatch in pointer assignment");
|
||||
}
|
||||
}
|
||||
|
||||
@@ -411,7 +194,7 @@ namespace chaiscript
|
||||
{
|
||||
return (lhs.assign(rhs));
|
||||
} else {
|
||||
throw bad_boxed_cast("boxed_value has a set type already");
|
||||
throw exception::bad_boxed_cast("boxed_value has a set type already");
|
||||
}
|
||||
}
|
||||
|
||||
@@ -425,21 +208,47 @@ namespace chaiscript
|
||||
std::cout << s << std::endl;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Add all arithmetic operators for PODs
|
||||
*/
|
||||
static void opers_arithmetic_pod(ModulePtr m = ModulePtr(new Module()))
|
||||
{
|
||||
m->add(fun(&operators::addition<Boxed_Value, Boxed_POD_Value, Boxed_POD_Value>), "+");
|
||||
m->add(fun(&operators::subtraction<Boxed_Value, Boxed_POD_Value, Boxed_POD_Value>), "-");
|
||||
m->add(fun(&operators::bitwise_and<Boxed_Value, Boxed_POD_Value, Boxed_POD_Value>), "&");
|
||||
m->add(fun(&operators::bitwise_xor<Boxed_Value, Boxed_POD_Value, Boxed_POD_Value>), "^");
|
||||
m->add(fun(&operators::bitwise_or<Boxed_Value, Boxed_POD_Value, Boxed_POD_Value>), "|");
|
||||
m->add(fun(&operators::division<Boxed_Value, Boxed_POD_Value, Boxed_POD_Value>), "/");
|
||||
m->add(fun(&operators::left_shift<Boxed_Value, Boxed_POD_Value, Boxed_POD_Value>), "<<");
|
||||
m->add(fun(&operators::multiplication<Boxed_Value, Boxed_POD_Value, Boxed_POD_Value>), "*");
|
||||
m->add(fun(&operators::remainder<Boxed_Value, Boxed_POD_Value, Boxed_POD_Value>), "%");
|
||||
m->add(fun(&operators::right_shift<Boxed_Value, Boxed_POD_Value, Boxed_POD_Value>), ">>");
|
||||
m->add(fun(&Boxed_Number::equals), "==");
|
||||
m->add(fun(&Boxed_Number::less_than), "<");
|
||||
m->add(fun(&Boxed_Number::greater_than), ">");
|
||||
m->add(fun(&Boxed_Number::greater_than_equal), ">=");
|
||||
m->add(fun(&Boxed_Number::less_than_equal), "<=");
|
||||
m->add(fun(&Boxed_Number::not_equal), "!=");
|
||||
|
||||
m->add(fun(&Boxed_Number::pre_decrement), "--");
|
||||
m->add(fun(&Boxed_Number::pre_increment), "++");
|
||||
m->add(fun(&Boxed_Number::sum), "+");
|
||||
m->add(fun(&Boxed_Number::unary_plus), "+");
|
||||
m->add(fun(&Boxed_Number::unary_minus), "-");
|
||||
m->add(fun(&Boxed_Number::difference), "-");
|
||||
m->add(fun(&Boxed_Number::assign_bitwise_and), "&=");
|
||||
m->add(fun(&Boxed_Number::assign), "=");
|
||||
m->add(fun(&Boxed_Number::assign_bitwise_or), "|=");
|
||||
m->add(fun(&Boxed_Number::assign_bitwise_xor), "^=");
|
||||
m->add(fun(&Boxed_Number::assign_remainder), "%=");
|
||||
m->add(fun(&Boxed_Number::assign_shift_left), "<<=");
|
||||
m->add(fun(&Boxed_Number::assign_shift_right), ">>=");
|
||||
m->add(fun(&Boxed_Number::bitwise_and), "&");
|
||||
m->add(fun(&Boxed_Number::bitwise_complement), "~");
|
||||
m->add(fun(&Boxed_Number::bitwise_xor), "^");
|
||||
m->add(fun(&Boxed_Number::bitwise_or), "|");
|
||||
m->add(fun(&Boxed_Number::assign_product), "*=");
|
||||
m->add(fun(&Boxed_Number::assign_quotient), "/=");
|
||||
m->add(fun(&Boxed_Number::assign_sum), "+=");
|
||||
m->add(fun(&Boxed_Number::assign_difference), "-=");
|
||||
m->add(fun(&Boxed_Number::quotient), "/");
|
||||
m->add(fun(&Boxed_Number::shift_left), "<<");
|
||||
m->add(fun(&Boxed_Number::product), "*");
|
||||
m->add(fun(&Boxed_Number::remainder), "%");
|
||||
m->add(fun(&Boxed_Number::shift_right), ">>");
|
||||
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -451,12 +260,12 @@ namespace chaiscript
|
||||
{
|
||||
if (params.size() < 2)
|
||||
{
|
||||
throw arity_error(params.size(), 2);
|
||||
throw exception::arity_error(static_cast<int>(params.size()), 2);
|
||||
}
|
||||
|
||||
Const_Proxy_Function f = boxed_cast<Const_Proxy_Function>(params[0]);
|
||||
|
||||
return Boxed_Value(Const_Proxy_Function(new Bound_Function(f,
|
||||
return Boxed_Value(Const_Proxy_Function(new dispatch::Bound_Function(f,
|
||||
std::vector<Boxed_Value>(params.begin() + 1, params.end()))));
|
||||
}
|
||||
|
||||
@@ -468,7 +277,7 @@ namespace chaiscript
|
||||
{
|
||||
if (params.size() < 1)
|
||||
{
|
||||
throw arity_error(params.size(), 1);
|
||||
throw exception::arity_error(static_cast<int>(params.size()), 1);
|
||||
}
|
||||
|
||||
Const_Proxy_Function f = boxed_cast<Const_Proxy_Function>(params[0]);
|
||||
@@ -476,11 +285,40 @@ namespace chaiscript
|
||||
return Boxed_Value(f->call_match(std::vector<Boxed_Value>(params.begin() + 1, params.end())));
|
||||
}
|
||||
|
||||
static bool has_guard(const Const_Proxy_Function &t_pf)
|
||||
{
|
||||
auto pf = std::dynamic_pointer_cast<const dispatch::Dynamic_Proxy_Function>(t_pf);
|
||||
if (pf)
|
||||
{
|
||||
return bool(pf->get_guard());
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
static Const_Proxy_Function get_guard(const Const_Proxy_Function &t_pf)
|
||||
{
|
||||
auto pf = std::dynamic_pointer_cast<const dispatch::Dynamic_Proxy_Function>(t_pf);
|
||||
if (pf)
|
||||
{
|
||||
if (pf->get_guard())
|
||||
{
|
||||
return pf->get_guard();
|
||||
} else {
|
||||
throw std::runtime_error("Function does not have a guard");
|
||||
}
|
||||
} else {
|
||||
throw std::runtime_error("Function does not have a guard");
|
||||
}
|
||||
}
|
||||
|
||||
static void throw_exception(const Boxed_Value &bv) {
|
||||
throw bv;
|
||||
}
|
||||
|
||||
static boost::shared_ptr<Dispatch_Engine> bootstrap2(boost::shared_ptr<Dispatch_Engine> e = boost::shared_ptr<Dispatch_Engine> (new Dispatch_Engine()))
|
||||
static std::shared_ptr<chaiscript::detail::Dispatch_Engine> bootstrap2(
|
||||
std::shared_ptr<chaiscript::detail::Dispatch_Engine> e
|
||||
= std::shared_ptr<chaiscript::detail::Dispatch_Engine> (new chaiscript::detail::Dispatch_Engine()))
|
||||
{
|
||||
e->add(user_type<void>(), "void");
|
||||
return e;
|
||||
@@ -504,29 +342,68 @@ namespace chaiscript
|
||||
}
|
||||
}
|
||||
|
||||
template<typename FunctionType>
|
||||
static std::vector<Boxed_Value> do_return_boxed_value_vector(FunctionType f,
|
||||
const dispatch::Proxy_Function_Base *b)
|
||||
{
|
||||
auto v = (b->*f)();
|
||||
|
||||
std::vector<Boxed_Value> vbv;
|
||||
|
||||
for (const auto &o: v)
|
||||
{
|
||||
vbv.push_back(const_var(o));
|
||||
}
|
||||
|
||||
return vbv;
|
||||
}
|
||||
|
||||
template<typename Function>
|
||||
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);
|
||||
}
|
||||
|
||||
public:
|
||||
/**
|
||||
* 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
|
||||
/// \returns passed in ModulePtr, or newly created one if default argument is used
|
||||
static ModulePtr bootstrap(ModulePtr m = ModulePtr(new Module()))
|
||||
{
|
||||
m->add(user_type<void>(), "void");
|
||||
m->add(user_type<bool>(), "bool");
|
||||
m->add(user_type<Boxed_Value>(), "Object");
|
||||
m->add(user_type<Boxed_POD_Value>(), "PODObject");
|
||||
m->add(user_type<Proxy_Function>(), "function");
|
||||
m->add(user_type<Boxed_Number>(), "Number");
|
||||
m->add(user_type<Proxy_Function>(), "Function");
|
||||
m->add(user_type<std::exception>(), "exception");
|
||||
|
||||
m->add(user_type<std::runtime_error>(), "runtime_error");
|
||||
m->add(constructor<std::runtime_error (const std::string &)>(), "runtime_error");
|
||||
m->add(fun(boost::function<std::string (const std::runtime_error &)>(&what)), "what");
|
||||
m->add(fun(&dispatch::Proxy_Function_Base::get_arity), "get_arity");
|
||||
m->add(fun(&dispatch::Proxy_Function_Base::annotation), "get_annotation");
|
||||
m->add(fun(&dispatch::Proxy_Function_Base::operator()), "call");
|
||||
m->add(fun(&dispatch::Proxy_Function_Base::operator==), "==");
|
||||
|
||||
m->add(user_type<Dynamic_Object>(), "Dynamic_Object");
|
||||
m->add(constructor<Dynamic_Object (const std::string &)>(), "Dynamic_Object");
|
||||
m->add(fun(&Dynamic_Object::get_type_name), "get_type_name");
|
||||
m->add(fun(&Dynamic_Object::get_attrs), "get_attrs");
|
||||
m->add(fun(&Dynamic_Object::get_attr), "get_attr");
|
||||
m->eval("def Dynamic_Object::clone() { var new_o := Dynamic_Object(this.get_type_name()); for_each(this.get_attrs(), bind(fun(new_o, x) { new_o.get_attr(x.first) = x.second; }, new_o, _) ); return new_o; }");
|
||||
|
||||
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(user_type<std::runtime_error>(), "runtime_error");
|
||||
m->add(chaiscript::base_class<std::exception, std::runtime_error>());
|
||||
|
||||
|
||||
m->add(constructor<std::runtime_error (const std::string &)>(), "runtime_error");
|
||||
m->add(fun(std::function<std::string (const std::runtime_error &)>(&what)), "what");
|
||||
|
||||
m->add(user_type<dispatch::Dynamic_Object>(), "Dynamic_Object");
|
||||
m->add(constructor<dispatch::Dynamic_Object (const std::string &)>(), "Dynamic_Object");
|
||||
m->add(fun(&dispatch::Dynamic_Object::get_type_name), "get_type_name");
|
||||
m->add(fun(&dispatch::Dynamic_Object::get_attrs), "get_attrs");
|
||||
m->add(fun(&dispatch::Dynamic_Object::get_attr), "get_attr");
|
||||
|
||||
m->eval("def Dynamic_Object::clone() { auto &new_o = Dynamic_Object(this.get_type_name()); for_each(this.get_attrs(), bind(fun(new_o, x) { new_o.get_attr(x.first) = x.second; }, new_o, _) ); return new_o; }");
|
||||
|
||||
m->add(fun(&has_guard), "has_guard");
|
||||
m->add(fun(&get_guard), "get_guard");
|
||||
|
||||
m->add(fun(&Boxed_Value::is_undef), "is_var_undef");
|
||||
m->add(fun(&Boxed_Value::is_null), "is_var_null");
|
||||
@@ -553,6 +430,7 @@ namespace chaiscript
|
||||
|
||||
basic_constructors<bool>("bool", m);
|
||||
operators::assign<bool>(m);
|
||||
operators::equal<bool>(m);
|
||||
|
||||
m->add(fun(&to_string<const std::string &>), "internal_to_string");
|
||||
m->add(fun(&Bootstrap::bool_to_string), "internal_to_string");
|
||||
@@ -560,31 +438,42 @@ namespace chaiscript
|
||||
m->add(fun(&throw_exception), "throw");
|
||||
m->add(fun(&what), "what");
|
||||
|
||||
bootstrap_float_type<double>("double", m);
|
||||
bootstrap_integer_type<int>("int", m);
|
||||
bootstrap_integer_type<size_t>("size_t", m);
|
||||
bootstrap_integer_type<char>("char", m);
|
||||
bootstrap_integer_type<boost::int64_t>("int64_t", m);
|
||||
bootstrap_pod_type<double>("double", m);
|
||||
bootstrap_pod_type<long double>("long_double", m);
|
||||
bootstrap_pod_type<float>("float", m);
|
||||
bootstrap_pod_type<int>("int", m);
|
||||
bootstrap_pod_type<unsigned int>("unsigned_int", m);
|
||||
bootstrap_pod_type<unsigned long>("unsigned_long", m);
|
||||
bootstrap_pod_type<size_t>("size_t", m);
|
||||
bootstrap_pod_type<char>("char", m);
|
||||
bootstrap_pod_type<std::int8_t>("int8_t", m);
|
||||
bootstrap_pod_type<std::int16_t>("int16_t", m);
|
||||
bootstrap_pod_type<std::int32_t>("int32_t", m);
|
||||
bootstrap_pod_type<std::int64_t>("int64_t", m);
|
||||
bootstrap_pod_type<std::uint8_t>("uint8_t", m);
|
||||
bootstrap_pod_type<std::uint16_t>("uint16_t", m);
|
||||
bootstrap_pod_type<std::uint32_t>("uint32_t", m);
|
||||
bootstrap_pod_type<std::uint64_t>("uint64_t", m);
|
||||
|
||||
operators::logical_compliment<bool>(m);
|
||||
|
||||
opers_comparison<Boxed_POD_Value>(m);
|
||||
opers_arithmetic_pod(m);
|
||||
|
||||
|
||||
m->add(fun(&print), "print_string");
|
||||
m->add(fun(&println), "println_string");
|
||||
|
||||
m->add(Proxy_Function(new Dynamic_Proxy_Function(boost::bind(&bind_function, _1))),
|
||||
m->add(Proxy_Function(new dispatch::Dynamic_Proxy_Function(std::bind(&bind_function, std::placeholders::_1))),
|
||||
"bind");
|
||||
|
||||
m->add(fun(&shared_ptr_unconst_clone<Proxy_Function_Base>), "clone");
|
||||
m->add(fun(&ptr_assign<Proxy_Function_Base>), "=");
|
||||
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::add_const<dispatch::Proxy_Function_Base>::type>), "=");
|
||||
|
||||
m->add(Proxy_Function(new Dynamic_Proxy_Function(boost::bind(&call_exists, _1))),
|
||||
m->add(Proxy_Function(new dispatch::Dynamic_Proxy_Function(std::bind(&call_exists, std::placeholders::_1))),
|
||||
"call_exists");
|
||||
|
||||
m->add(fun(&type_match), "type_match");
|
||||
m->add(fun(&Boxed_Value::type_match), "type_match");
|
||||
|
||||
return m;
|
||||
}
|
||||
|
@@ -1,25 +1,30 @@
|
||||
// This file is distributed under the BSD License.
|
||||
// See "license.txt" for details.
|
||||
// Copyright 2009-2010, Jonathan Turner (jturner@minnow-lang.org)
|
||||
// and Jason Turner (lefticus@gmail.com)
|
||||
// Copyright 2009-2012, Jonathan Turner (jonathan@emptycrate.com)
|
||||
// and Jason Turner (jason@emptycrate.com)
|
||||
// http://www.chaiscript.com
|
||||
|
||||
/**
|
||||
* \file
|
||||
* This file contains utility functions for registration of STL container
|
||||
* classes. The methodology used is based on the SGI STL concepts.
|
||||
* http://www.sgi.com/tech/stl/table_of_contents.html
|
||||
*/
|
||||
|
||||
#ifndef __bootstrap_stl_hpp__
|
||||
#define __bootstrap_stl_hpp__
|
||||
|
||||
|
||||
#ifndef CHAISCRIPT_BOOTSTRAP_STL_HPP_
|
||||
#define CHAISCRIPT_BOOTSTRAP_STL_HPP_
|
||||
|
||||
#include "dispatchkit.hpp"
|
||||
#include "bootstrap.hpp"
|
||||
#include "register_function.hpp"
|
||||
|
||||
|
||||
namespace chaiscript
|
||||
{
|
||||
namespace bootstrap
|
||||
{
|
||||
namespace standard_library
|
||||
{
|
||||
/**
|
||||
* Bidir_Range, based on the D concept of ranges.
|
||||
@@ -29,6 +34,7 @@ namespace chaiscript
|
||||
template<typename Container>
|
||||
struct Bidir_Range
|
||||
{
|
||||
typedef Container container_type;
|
||||
typedef typename std::iterator_traits<typename Container::iterator>::reference reference_type;
|
||||
|
||||
Bidir_Range(Container &c)
|
||||
@@ -83,99 +89,87 @@ namespace chaiscript
|
||||
typename Container::iterator m_end;
|
||||
};
|
||||
|
||||
template<typename Range>
|
||||
struct Retro
|
||||
template<typename Container>
|
||||
struct Const_Bidir_Range
|
||||
{
|
||||
Retro(const Range &r)
|
||||
: m_r(r)
|
||||
{}
|
||||
typedef const Container container_type;
|
||||
typedef typename std::iterator_traits<typename Container::const_iterator>::reference const_reference_type;
|
||||
|
||||
bool empty() { return m_r.empty(); }
|
||||
void pop_front() { m_r.pop_back(); }
|
||||
void pop_back() { m_r.pop_front(); }
|
||||
typename Range::reference_type front() { return m_r.back(); }
|
||||
typename Range::reference_type back() { return m_r.front(); }
|
||||
Const_Bidir_Range(const Container &c)
|
||||
: m_begin(c.begin()), m_end(c.end())
|
||||
{
|
||||
}
|
||||
|
||||
private:
|
||||
Range m_r;
|
||||
bool empty() const
|
||||
{
|
||||
return m_begin == m_end;
|
||||
}
|
||||
|
||||
void pop_front()
|
||||
{
|
||||
if (empty())
|
||||
{
|
||||
throw std::range_error("Range empty");
|
||||
}
|
||||
++m_begin;
|
||||
}
|
||||
|
||||
void pop_back()
|
||||
{
|
||||
if (empty())
|
||||
{
|
||||
throw std::range_error("Range empty");
|
||||
}
|
||||
--m_end;
|
||||
}
|
||||
|
||||
const_reference_type front() const
|
||||
{
|
||||
if (empty())
|
||||
{
|
||||
throw std::range_error("Range empty");
|
||||
}
|
||||
return *m_begin;
|
||||
}
|
||||
|
||||
const_reference_type back() const
|
||||
{
|
||||
if (empty())
|
||||
{
|
||||
throw std::range_error("Range empty");
|
||||
}
|
||||
typename Container::const_iterator pos = m_end;
|
||||
--pos;
|
||||
return *(pos);
|
||||
}
|
||||
|
||||
typename Container::const_iterator m_begin;
|
||||
typename Container::const_iterator m_end;
|
||||
};
|
||||
|
||||
namespace detail {
|
||||
|
||||
/**
|
||||
* Add Bidir_Range support for the given ContainerType
|
||||
*/
|
||||
template<typename ContainerType>
|
||||
ModulePtr input_range_type(const std::string &type, ModulePtr m = ModulePtr(new Module()))
|
||||
template<typename Bidir_Type>
|
||||
ModulePtr input_range_type_impl(const std::string &type, ModulePtr m = ModulePtr(new Module()))
|
||||
{
|
||||
m->add(user_type<Bidir_Range<ContainerType> >(), type + "_Range");
|
||||
m->add(user_type<Bidir_Type>(), type + "_Range");
|
||||
|
||||
copy_constructor<Bidir_Range<ContainerType> >(type + "_Range", m);
|
||||
copy_constructor<Bidir_Type>(type + "_Range", m);
|
||||
|
||||
m->add(constructor<Bidir_Range<ContainerType> (ContainerType &)>(), "range");
|
||||
m->add(constructor<Bidir_Type (typename Bidir_Type::container_type &)>(), "range");
|
||||
|
||||
m->add(fun(&Bidir_Range<ContainerType>::empty), "empty");
|
||||
m->add(fun(&Bidir_Range<ContainerType>::pop_front), "pop_front");
|
||||
m->add(fun(&Bidir_Range<ContainerType>::front), "front");
|
||||
m->add(fun(&Bidir_Range<ContainerType>::pop_back), "pop_back");
|
||||
m->add(fun(&Bidir_Range<ContainerType>::back), "back");
|
||||
m->add(fun(&Bidir_Type::empty), "empty");
|
||||
m->add(fun(&Bidir_Type::pop_front), "pop_front");
|
||||
m->add(fun(&Bidir_Type::front), "front");
|
||||
m->add(fun(&Bidir_Type::pop_back), "pop_back");
|
||||
m->add(fun(&Bidir_Type::back), "back");
|
||||
|
||||
return m;
|
||||
}
|
||||
|
||||
/**
|
||||
* Add random_access_container concept to the given ContainerType
|
||||
* http://www.sgi.com/tech/stl/RandomAccessContainer.html
|
||||
*/
|
||||
template<typename ContainerType>
|
||||
ModulePtr random_access_container_type(const std::string &/*type*/, ModulePtr m = ModulePtr(new Module()))
|
||||
{
|
||||
typedef typename ContainerType::reference(ContainerType::*indexoper)(size_t);
|
||||
|
||||
//In the interest of runtime safety for the m, we prefer the at() method for [] access,
|
||||
//to throw an exception in an out of bounds condition.
|
||||
m->add(
|
||||
fun(boost::function<typename ContainerType::reference (ContainerType *, int)>(boost::mem_fn(static_cast<indexoper>(&ContainerType::at)))), "[]");
|
||||
|
||||
return m;
|
||||
}
|
||||
|
||||
/**
|
||||
* Add assignable concept to the given ContainerType
|
||||
* http://www.sgi.com/tech/stl/Assignable.html
|
||||
*/
|
||||
template<typename ContainerType>
|
||||
ModulePtr assignable_type(const std::string &type, ModulePtr m = ModulePtr(new Module()))
|
||||
{
|
||||
basic_constructors<ContainerType>(type, m);
|
||||
operators::assign<ContainerType>(m);
|
||||
return m;
|
||||
}
|
||||
|
||||
/**
|
||||
* Add container concept to the given ContainerType
|
||||
* http://www.sgi.com/tech/stl/Container.html
|
||||
*/
|
||||
template<typename ContainerType>
|
||||
ModulePtr container_type(const std::string &/*type*/, ModulePtr m = ModulePtr(new Module()))
|
||||
{
|
||||
m->add(fun(boost::function<int (const ContainerType *)>(boost::mem_fn(&ContainerType::size))), "size");
|
||||
m->add(fun<bool (ContainerType::*)() const>(&ContainerType::empty), "empty");
|
||||
m->add(fun<void (ContainerType::*)()>(&ContainerType::clear), "clear");
|
||||
|
||||
return m;
|
||||
}
|
||||
|
||||
/**
|
||||
* Add default constructable concept to the given Type
|
||||
* http://www.sgi.com/tech/stl/DefaultConstructible.html
|
||||
*/
|
||||
template<typename Type>
|
||||
ModulePtr default_constructible_type(const std::string &type, ModulePtr m = ModulePtr(new Module()))
|
||||
{
|
||||
m->add(constructor<Type ()>(), type);
|
||||
return m;
|
||||
}
|
||||
|
||||
/**
|
||||
* Algorithm for inserting at a specific position into a container
|
||||
*/
|
||||
@@ -212,6 +206,76 @@ namespace chaiscript
|
||||
container.erase(itr);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
template<typename ContainerType>
|
||||
ModulePtr input_range_type(const std::string &type, ModulePtr m = ModulePtr(new Module()))
|
||||
{
|
||||
detail::input_range_type_impl<Bidir_Range<ContainerType> >(type,m);
|
||||
detail::input_range_type_impl<Const_Bidir_Range<ContainerType> >("Const_" + type, m);
|
||||
return m;
|
||||
}
|
||||
|
||||
/**
|
||||
* Add random_access_container concept to the given ContainerType
|
||||
* http://www.sgi.com/tech/stl/RandomAccessContainer.html
|
||||
*/
|
||||
template<typename ContainerType>
|
||||
ModulePtr random_access_container_type(const std::string &/*type*/, ModulePtr m = ModulePtr(new Module()))
|
||||
{
|
||||
typedef typename ContainerType::reference(ContainerType::*indexoper)(size_t);
|
||||
typedef typename ContainerType::const_reference(ContainerType::*constindexoper)(size_t) const;
|
||||
|
||||
//In the interest of runtime safety for the m, we prefer the at() method for [] access,
|
||||
//to throw an exception in an out of bounds condition.
|
||||
m->add(
|
||||
fun(std::function<typename ContainerType::reference (ContainerType *, int)>
|
||||
(std::mem_fn(static_cast<indexoper>(&ContainerType::at)))), "[]");
|
||||
m->add(
|
||||
fun(std::function<typename ContainerType::const_reference (const ContainerType *, int)>
|
||||
(std::mem_fn(static_cast<constindexoper>(&ContainerType::at)))), "[]");
|
||||
|
||||
return m;
|
||||
}
|
||||
|
||||
/**
|
||||
* Add assignable concept to the given ContainerType
|
||||
* http://www.sgi.com/tech/stl/Assignable.html
|
||||
*/
|
||||
template<typename ContainerType>
|
||||
ModulePtr assignable_type(const std::string &type, ModulePtr m = ModulePtr(new Module()))
|
||||
{
|
||||
basic_constructors<ContainerType>(type, m);
|
||||
operators::assign<ContainerType>(m);
|
||||
return m;
|
||||
}
|
||||
|
||||
/**
|
||||
* Add container concept to the given ContainerType
|
||||
* http://www.sgi.com/tech/stl/Container.html
|
||||
*/
|
||||
template<typename ContainerType>
|
||||
ModulePtr container_type(const std::string &/*type*/, ModulePtr m = ModulePtr(new Module()))
|
||||
{
|
||||
m->add(fun( std::function<int (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( std::function<void (ContainerType *)>( [](ContainerType *a) { a->clear(); } ) ), "clear");
|
||||
return m;
|
||||
}
|
||||
|
||||
/**
|
||||
* Add default constructable concept to the given Type
|
||||
* http://www.sgi.com/tech/stl/DefaultConstructible.html
|
||||
*/
|
||||
template<typename Type>
|
||||
ModulePtr default_constructible_type(const std::string &type, ModulePtr m = ModulePtr(new Module()))
|
||||
{
|
||||
m->add(constructor<Type ()>(), type);
|
||||
return m;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Add sequence concept to the given ContainerType
|
||||
* http://www.sgi.com/tech/stl/Sequence.html
|
||||
@@ -227,8 +291,8 @@ namespace chaiscript
|
||||
insert_name = "insert_at";
|
||||
}
|
||||
|
||||
m->add(fun(&insert_at<ContainerType>), insert_name);
|
||||
m->add(fun(&erase_at<ContainerType>), "erase_at");
|
||||
m->add(fun(&detail::insert_at<ContainerType>), insert_name);
|
||||
m->add(fun(&detail::erase_at<ContainerType>), "erase_at");
|
||||
|
||||
return m;
|
||||
}
|
||||
@@ -264,9 +328,12 @@ namespace chaiscript
|
||||
*http://www.sgi.com/tech/stl/FrontInsertionSequence.html
|
||||
*/
|
||||
template<typename ContainerType>
|
||||
ModulePtr front_insertion_sequence_type(const std::string &type, 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 void (ContainerType::*pushptr)(typename ContainerType::const_reference);
|
||||
typedef void (ContainerType::*popptr)();
|
||||
|
||||
m->add(fun(static_cast<frontptr>(&ContainerType::front)), "front");
|
||||
|
||||
std::string push_front_name;
|
||||
@@ -276,8 +343,9 @@ namespace chaiscript
|
||||
} else {
|
||||
push_front_name = "push_front";
|
||||
}
|
||||
m->add(fun(&ContainerType::push_front), push_front_name);
|
||||
m->add(fun(&ContainerType::pop_front), "pop_front");
|
||||
|
||||
m->add(fun(static_cast<pushptr>(&ContainerType::push_front)), push_front_name);
|
||||
m->add(fun(static_cast<popptr>(&ContainerType::pop_front)), "pop_front");
|
||||
return m;
|
||||
}
|
||||
|
||||
@@ -290,8 +358,12 @@ namespace chaiscript
|
||||
{
|
||||
m->add(user_type<PairType>(), type);
|
||||
|
||||
m->add(fun(&PairType::first), "first");
|
||||
m->add(fun(&PairType::second), "second");
|
||||
|
||||
typename PairType::first_type PairType::* f = &PairType::first;
|
||||
typename PairType::second_type PairType::* s = &PairType::second;
|
||||
|
||||
m->add(fun(f), "first");
|
||||
m->add(fun(s), "second");
|
||||
|
||||
basic_constructors<PairType>(type, m);
|
||||
m->add(constructor<PairType (const typename PairType::first_type &, const typename PairType::second_type &)>(), type);
|
||||
@@ -319,7 +391,7 @@ namespace chaiscript
|
||||
template<typename ContainerType>
|
||||
ModulePtr unique_associative_container_type(const std::string &/*type*/, ModulePtr m = ModulePtr(new Module()))
|
||||
{
|
||||
m->add(fun(boost::function<int (const ContainerType *, const typename ContainerType::key_type &)>(boost::mem_fn(&ContainerType::count))), "count");
|
||||
m->add(fun<int (const ContainerType *, const typename ContainerType::key_type &)>(&ContainerType::count), "count");
|
||||
|
||||
return m;
|
||||
}
|
||||
@@ -334,6 +406,7 @@ namespace chaiscript
|
||||
m->add(user_type<MapType>(), type);
|
||||
|
||||
typedef typename MapType::mapped_type &(MapType::*elemaccess)(const typename MapType::key_type &);
|
||||
|
||||
m->add(fun(static_cast<elemaccess>(&MapType::operator[])), "[]");
|
||||
|
||||
container_type<MapType>(type, m);
|
||||
@@ -386,13 +459,14 @@ namespace chaiscript
|
||||
assignable_type<VectorType>(type, m);
|
||||
input_range_type<VectorType>(type, m);
|
||||
|
||||
|
||||
if (typeid(VectorType) == typeid(std::vector<Boxed_Value>))
|
||||
{
|
||||
m->eval("def Vector::`==`(rhs) : type_match(rhs, this) { \
|
||||
if ( rhs.size() != this.size() ) { \
|
||||
return false; \
|
||||
} else { \
|
||||
var r1 = range(this); \
|
||||
var r2 = range(rhs); \
|
||||
auto r1 = range(this); \
|
||||
auto r2 = range(rhs); \
|
||||
while (!r1.empty()) \
|
||||
{ \
|
||||
if (!eq(r1.front(), r2.front())) \
|
||||
@@ -405,7 +479,7 @@ namespace chaiscript
|
||||
return true; \
|
||||
} \
|
||||
}");
|
||||
|
||||
}
|
||||
|
||||
return m;
|
||||
}
|
||||
@@ -438,20 +512,24 @@ namespace chaiscript
|
||||
}
|
||||
m->add(fun(&String::push_back), push_back_name);
|
||||
|
||||
typedef typename String::size_type (String::*find_func_ptr)(const String &, typename String::size_type) const;
|
||||
typedef std::function<int (const String *, const String &, int)> find_func;
|
||||
|
||||
typedef boost::function<int (const String *, const String &, int)> find_func;
|
||||
m->add(fun(find_func( [](const String *s, const String &f, int pos) { return s->find(f, pos); } )), "find");
|
||||
m->add(fun(find_func( [](const String *s, const String &f, int pos) { return s->rfind(f, pos); } ) ), "rfind");
|
||||
m->add(fun(find_func( [](const String *s, const String &f, int pos) { return s->find_first_of(f, pos); } ) ), "find_first_of");
|
||||
m->add(fun(find_func( [](const String *s, const String &f, int pos) { return s->find_last_of(f, pos); } ) ), "find_last_of");
|
||||
m->add(fun(find_func( [](const String *s, const String &f, int pos) { return s->find_last_not_of(f, pos); } ) ), "find_last_not_of");
|
||||
m->add(fun(find_func( [](const String *s, const String &f, int pos) { return s->find_first_not_of(f, pos); } ) ), "find_first_not_of");
|
||||
|
||||
m->add(fun( std::function<const char *(const String *)>( [](const String *s) { return s->c_str(); } ) ), "c_str");
|
||||
m->add(fun( std::function<const char *(const String *)>( [](const String *s) { return s->data(); } ) ), "data");
|
||||
|
||||
m->add(fun(find_func(boost::mem_fn(static_cast<find_func_ptr>(&String::find)))), "find");
|
||||
m->add(fun(find_func(boost::mem_fn(static_cast<find_func_ptr>(&String::rfind)))), "rfind");
|
||||
m->add(fun(find_func(boost::mem_fn(static_cast<find_func_ptr>(&String::find_first_of)))), "find_first_of");
|
||||
m->add(fun(find_func(boost::mem_fn(static_cast<find_func_ptr>(&String::find_last_of)))), "find_last_of");
|
||||
m->add(fun(find_func(boost::mem_fn(static_cast<find_func_ptr>(&String::find_first_not_of)))), "find_first_not_of");
|
||||
m->add(fun(find_func(boost::mem_fn(static_cast<find_func_ptr>(&String::find_last_not_of)))), "find_last_not_of");
|
||||
|
||||
return m;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
#endif
|
||||
|
107
include/chaiscript/dispatchkit/boxed_cast.hpp
Normal file
107
include/chaiscript/dispatchkit/boxed_cast.hpp
Normal file
@@ -0,0 +1,107 @@
|
||||
// This file is distributed under the BSD License.
|
||||
// See "license.txt" for details.
|
||||
// Copyright 2009-2012, Jonathan Turner (jonathan@emptycrate.com)
|
||||
// and Jason Turner (jason@emptycrate.com)
|
||||
// http://www.chaiscript.com
|
||||
|
||||
#ifndef CHAISCRIPT_BOXED_CAST_HPP_
|
||||
#define CHAISCRIPT_BOXED_CAST_HPP_
|
||||
|
||||
#include "../chaiscript_defines.hpp"
|
||||
|
||||
#include "type_info.hpp"
|
||||
#include "boxed_value.hpp"
|
||||
#include "boxed_cast_helper.hpp"
|
||||
#include "dynamic_cast_conversion.hpp"
|
||||
|
||||
#include "../chaiscript_threading.hpp"
|
||||
|
||||
namespace chaiscript
|
||||
{
|
||||
|
||||
/// \brief Function for extracting a value stored in a Boxed_Value object
|
||||
/// \tparam Type The type to extract from the Boxed_Value
|
||||
/// \param[in] bv The Boxed_Value to extract a typed value from
|
||||
/// \returns Type equivalent to the requested type
|
||||
/// \throws exception::bad_boxed_cast If the requested conversion is not possible
|
||||
///
|
||||
/// boxed_cast will attempt to make conversions between value, &, *, std::shared_ptr, std::reference_wrapper,
|
||||
/// and std::function (const and non-const) where possible. boxed_cast is used internally during function
|
||||
/// dispatch. This means that all of these conversions will be attempted automatically for you during
|
||||
/// ChaiScript function calls.
|
||||
///
|
||||
/// \li non-const values can be extracted as const or non-const
|
||||
/// \li const values can be extracted only as const
|
||||
/// \li Boxed_Value constructed from pointer or std::reference_wrapper can be extracted as reference,
|
||||
/// pointer or value types
|
||||
/// \li Boxed_Value constructed from std::shared_ptr or value types can be extracted as reference,
|
||||
/// pointer, value, or std::shared_ptr types
|
||||
///
|
||||
/// Conversions to std::function objects are attempted as well
|
||||
///
|
||||
/// Example:
|
||||
/// \code
|
||||
/// // All of the following should succeed
|
||||
/// chaiscript::Boxed_Value bv(1);
|
||||
/// std::shared_ptr<int> spi = chaiscript::boxed_cast<std::shared_ptr<int> >(bv);
|
||||
/// int i = chaiscript::boxed_cast<int>(bv);
|
||||
/// int *ip = chaiscript::boxed_cast<int *>(bv);
|
||||
/// int &ir = chaiscript::boxed_cast<int &>(bv);
|
||||
/// std::shared_ptr<const int> cspi = chaiscript::boxed_cast<std::shared_ptr<const int> >(bv);
|
||||
/// const int ci = chaiscript::boxed_cast<const int>(bv);
|
||||
/// const int *cip = chaiscript::boxed_cast<const int *>(bv);
|
||||
/// const int &cir = chaiscript::boxed_cast<const int &>(bv);
|
||||
/// \endcode
|
||||
///
|
||||
/// std::function conversion example
|
||||
/// \code
|
||||
/// chaiscript::ChaiScript chai;
|
||||
/// Boxed_Value bv = chai.eval("`+`"); // Get the functor for the + operator which is built in
|
||||
/// std::function<int (int, int)> f = chaiscript::boxed_cast<std::function<int (int, int)> >(bv);
|
||||
/// int i = f(2,3);
|
||||
/// assert(i == 5);
|
||||
/// \endcode
|
||||
template<typename Type>
|
||||
typename detail::Cast_Helper<Type>::Result_Type boxed_cast(const Boxed_Value &bv)
|
||||
{
|
||||
try {
|
||||
return detail::Cast_Helper<Type>::cast(bv);
|
||||
} catch (const chaiscript::detail::exception::bad_any_cast &) {
|
||||
|
||||
|
||||
#ifdef CHAISCRIPT_MSVC
|
||||
//Thank you MSVC, yes we know that a constant value is being used in the if
|
||||
// statment in THIS VERSION of the template instantiation
|
||||
#pragma warning(push)
|
||||
#pragma warning(disable : 4127)
|
||||
#endif
|
||||
|
||||
if (std::is_polymorphic<typename detail::Stripped_Type<Type>::type>::value)
|
||||
{
|
||||
try {
|
||||
// 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
|
||||
return detail::Cast_Helper<Type>::cast(detail::boxed_dynamic_cast<Type>(bv));
|
||||
} catch (const chaiscript::detail::exception::bad_any_cast &) {
|
||||
throw exception::bad_boxed_cast(bv.get_type_info(), typeid(Type));
|
||||
}
|
||||
} else {
|
||||
// If it's not polymorphic, just throw the error, don't waste the time on the
|
||||
// attempted dynamic_cast
|
||||
throw exception::bad_boxed_cast(bv.get_type_info(), typeid(Type));
|
||||
}
|
||||
|
||||
#ifdef CHAISCRIPT_MSVC
|
||||
#pragma warning(pop)
|
||||
#endif
|
||||
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
#endif
|
||||
|
270
include/chaiscript/dispatchkit/boxed_cast_helper.hpp
Normal file
270
include/chaiscript/dispatchkit/boxed_cast_helper.hpp
Normal file
@@ -0,0 +1,270 @@
|
||||
// This file is distributed under the BSD License.
|
||||
// See "license.txt" for details.
|
||||
// Copyright 2009-2012, Jonathan Turner (jonathan@emptycrate.com)
|
||||
// and Jason Turner (jason@emptycrate.com)
|
||||
// http://www.chaiscript.com
|
||||
|
||||
#ifndef CHAISCRIPT_BOXED_CAST_HELPER_HPP_
|
||||
#define CHAISCRIPT_BOXED_CAST_HELPER_HPP_
|
||||
|
||||
#include "type_info.hpp"
|
||||
#include "boxed_value.hpp"
|
||||
|
||||
|
||||
namespace chaiscript
|
||||
{
|
||||
namespace detail
|
||||
{
|
||||
// Cast_Helper_Inner helper classes
|
||||
|
||||
/**
|
||||
* Generic Cast_Helper_Inner, for casting to any type
|
||||
*/
|
||||
template<typename Result>
|
||||
struct Cast_Helper_Inner
|
||||
{
|
||||
typedef typename std::reference_wrapper<typename std::add_const<Result>::type > Result_Type;
|
||||
|
||||
static Result_Type cast(const Boxed_Value &ob)
|
||||
{
|
||||
if (ob.is_ref())
|
||||
{
|
||||
if (!ob.get_type_info().is_const())
|
||||
{
|
||||
return std::cref((ob.get().cast<std::reference_wrapper<Result> >()).get());
|
||||
} else {
|
||||
return ob.get().cast<std::reference_wrapper<const Result> >();
|
||||
}
|
||||
} else {
|
||||
if (!ob.get_type_info().is_const())
|
||||
{
|
||||
return std::cref(*(ob.get().cast<std::shared_ptr<Result> >()));
|
||||
} else {
|
||||
return std::cref(*(ob.get().cast<std::shared_ptr<const Result> >()));
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
template<typename Result>
|
||||
struct Cast_Helper_Inner<const Result> : Cast_Helper_Inner<Result>
|
||||
{
|
||||
};
|
||||
|
||||
/**
|
||||
* Cast_Helper_Inner for casting to a const & type
|
||||
*/
|
||||
template<typename Result>
|
||||
struct Cast_Helper_Inner<const Result &> : Cast_Helper_Inner<Result>
|
||||
{
|
||||
};
|
||||
|
||||
/**
|
||||
* Cast_Helper_Inner for casting to a const * type
|
||||
*/
|
||||
template<typename Result>
|
||||
struct Cast_Helper_Inner<const Result *>
|
||||
{
|
||||
typedef const Result * Result_Type;
|
||||
|
||||
static Result_Type cast(const Boxed_Value &ob)
|
||||
{
|
||||
if (ob.is_ref())
|
||||
{
|
||||
if (!ob.get_type_info().is_const())
|
||||
{
|
||||
return &(ob.get().cast<std::reference_wrapper<Result> >()).get();
|
||||
} else {
|
||||
return &(ob.get().cast<std::reference_wrapper<const Result> >()).get();
|
||||
}
|
||||
} else {
|
||||
if (!ob.get_type_info().is_const())
|
||||
{
|
||||
return (ob.get().cast<std::shared_ptr<Result> >()).get();
|
||||
} else {
|
||||
return (ob.get().cast<std::shared_ptr<const Result> >()).get();
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Cast_Helper_Inner for casting to a * type
|
||||
*/
|
||||
template<typename Result>
|
||||
struct Cast_Helper_Inner<Result *>
|
||||
{
|
||||
typedef Result * Result_Type;
|
||||
|
||||
static Result_Type cast(const Boxed_Value &ob)
|
||||
{
|
||||
if (ob.is_ref())
|
||||
{
|
||||
return &(ob.get().cast<std::reference_wrapper<Result> >()).get();
|
||||
} else {
|
||||
return (ob.get().cast<std::shared_ptr<Result> >()).get();
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Cast_Helper_Inner for casting to a & type
|
||||
*/
|
||||
template<typename Result>
|
||||
struct Cast_Helper_Inner<Result &>
|
||||
{
|
||||
typedef Result& Result_Type;
|
||||
|
||||
static Result &cast(const Boxed_Value &ob)
|
||||
{
|
||||
if (ob.is_ref())
|
||||
{
|
||||
return ob.get().cast<std::reference_wrapper<Result> >();
|
||||
} else {
|
||||
Result &r = *(ob.get().cast<std::shared_ptr<Result> >());
|
||||
return r;
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Cast_Helper_Inner for casting to a std::shared_ptr<> type
|
||||
*/
|
||||
template<typename Result>
|
||||
struct Cast_Helper_Inner<typename std::shared_ptr<Result> >
|
||||
{
|
||||
typedef typename std::shared_ptr<Result> Result_Type;
|
||||
|
||||
static Result_Type cast(const Boxed_Value &ob)
|
||||
{
|
||||
return ob.get().cast<std::shared_ptr<Result> >();
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Cast_Helper_Inner for casting to a std::shared_ptr<const> type
|
||||
*/
|
||||
template<typename Result>
|
||||
struct Cast_Helper_Inner<typename std::shared_ptr<const Result> >
|
||||
{
|
||||
typedef typename std::shared_ptr<const Result> Result_Type;
|
||||
|
||||
static Result_Type cast(const Boxed_Value &ob)
|
||||
{
|
||||
if (!ob.get_type_info().is_const())
|
||||
{
|
||||
return std::const_pointer_cast<const Result>(ob.get().cast<std::shared_ptr<Result> >());
|
||||
} else {
|
||||
return ob.get().cast<std::shared_ptr<const Result> >();
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Cast_Helper_Inner for casting to a const std::shared_ptr<> & type
|
||||
*/
|
||||
template<typename Result>
|
||||
struct Cast_Helper_Inner<const std::shared_ptr<Result> > : Cast_Helper_Inner<std::shared_ptr<Result> >
|
||||
{
|
||||
};
|
||||
|
||||
template<typename Result>
|
||||
struct Cast_Helper_Inner<const std::shared_ptr<Result> &> : Cast_Helper_Inner<std::shared_ptr<Result> >
|
||||
{
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Cast_Helper_Inner for casting to a const std::shared_ptr<const> & type
|
||||
*/
|
||||
template<typename Result>
|
||||
struct Cast_Helper_Inner<const std::shared_ptr<const Result> > : Cast_Helper_Inner<std::shared_ptr<const Result> >
|
||||
{
|
||||
};
|
||||
|
||||
template<typename Result>
|
||||
struct Cast_Helper_Inner<const std::shared_ptr<const Result> &> : Cast_Helper_Inner<std::shared_ptr<const Result> >
|
||||
{
|
||||
};
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Cast_Helper_Inner for casting to a Boxed_Value type
|
||||
*/
|
||||
template<>
|
||||
struct Cast_Helper_Inner<Boxed_Value>
|
||||
{
|
||||
typedef const Boxed_Value & Result_Type;
|
||||
|
||||
static Result_Type cast(const Boxed_Value &ob)
|
||||
{
|
||||
return ob;
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Cast_Helper_Inner for casting to a const Boxed_Value & type
|
||||
*/
|
||||
template<>
|
||||
struct Cast_Helper_Inner<const Boxed_Value> : Cast_Helper_Inner<Boxed_Value>
|
||||
{
|
||||
};
|
||||
|
||||
template<>
|
||||
struct Cast_Helper_Inner<const Boxed_Value &> : Cast_Helper_Inner<Boxed_Value>
|
||||
{
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Cast_Helper_Inner for casting to a std::reference_wrapper type
|
||||
*/
|
||||
template<typename Result>
|
||||
struct Cast_Helper_Inner<std::reference_wrapper<Result> > : Cast_Helper_Inner<Result &>
|
||||
{
|
||||
};
|
||||
|
||||
template<typename Result>
|
||||
struct Cast_Helper_Inner<const std::reference_wrapper<Result> > : Cast_Helper_Inner<Result &>
|
||||
{
|
||||
};
|
||||
|
||||
template<typename Result>
|
||||
struct Cast_Helper_Inner<const std::reference_wrapper<Result> &> : Cast_Helper_Inner<Result &>
|
||||
{
|
||||
};
|
||||
|
||||
template<typename Result>
|
||||
struct Cast_Helper_Inner<std::reference_wrapper<const Result> > : Cast_Helper_Inner<const Result &>
|
||||
{
|
||||
};
|
||||
|
||||
template<typename Result>
|
||||
struct Cast_Helper_Inner<const std::reference_wrapper<const Result> > : Cast_Helper_Inner<const Result &>
|
||||
{
|
||||
};
|
||||
|
||||
template<typename Result>
|
||||
struct Cast_Helper_Inner<const std::reference_wrapper<const Result> & > : Cast_Helper_Inner<const Result &>
|
||||
{
|
||||
};
|
||||
|
||||
/**
|
||||
* The exposed Cast_Helper object that by default just calls the Cast_Helper_Inner
|
||||
*/
|
||||
template<typename T>
|
||||
struct Cast_Helper
|
||||
{
|
||||
typedef typename Cast_Helper_Inner<T>::Result_Type Result_Type;
|
||||
|
||||
static Result_Type cast(const Boxed_Value &ob)
|
||||
{
|
||||
return Cast_Helper_Inner<T>::cast(ob);
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
#endif
|
717
include/chaiscript/dispatchkit/boxed_number.hpp
Normal file
717
include/chaiscript/dispatchkit/boxed_number.hpp
Normal file
@@ -0,0 +1,717 @@
|
||||
// This file is distributed under the BSD License.
|
||||
// See "license.txt" for details.
|
||||
// Copyright 2009-2012, Jonathan Turner (jonathan@emptycrate.com)
|
||||
// and Jason Turner (jason@emptycrate.com)
|
||||
// http://www.chaiscript.com
|
||||
|
||||
#ifndef CHAISCRIPT_BOXED_NUMERIC_HPP_
|
||||
#define CHAISCRIPT_BOXED_NUMERIC_HPP_
|
||||
|
||||
#include "boxed_value.hpp"
|
||||
#include "../language/chaiscript_algebraic.hpp"
|
||||
|
||||
namespace chaiscript
|
||||
{
|
||||
|
||||
#ifdef BOOST_MSVC
|
||||
#pragma warning(push)
|
||||
#pragma warning(disable : 4244 4018 4389 4146)
|
||||
#endif
|
||||
|
||||
/// \brief Represents any numeric type, generically. Used internally for generic operations between POD values
|
||||
class Boxed_Number
|
||||
{
|
||||
private:
|
||||
struct boolean
|
||||
{
|
||||
|
||||
#ifdef __GNUC__
|
||||
#pragma GCC diagnostic ignored "-Wsign-compare"
|
||||
#endif
|
||||
template<typename T, typename U>
|
||||
static Boxed_Value go(Operators::Opers t_oper, const T &t, const U &u, const Boxed_Value &)
|
||||
{
|
||||
switch (t_oper)
|
||||
{
|
||||
case Operators::equals:
|
||||
return const_var(t == u);
|
||||
case Operators::less_than:
|
||||
return const_var(t < u);
|
||||
case Operators::greater_than:
|
||||
return const_var(t > u);
|
||||
case Operators::less_than_equal:
|
||||
return const_var(t <= u);
|
||||
case Operators::greater_than_equal:
|
||||
return const_var(t >= u);
|
||||
case Operators::not_equal:
|
||||
return const_var(t != u);
|
||||
default:
|
||||
throw chaiscript::detail::exception::bad_any_cast();
|
||||
}
|
||||
throw chaiscript::detail::exception::bad_any_cast();
|
||||
}
|
||||
};
|
||||
|
||||
struct binary
|
||||
{
|
||||
template<typename T, typename U>
|
||||
static Boxed_Value go(Operators::Opers t_oper, T &t, const U &u, const Boxed_Value &t_lhs)
|
||||
{
|
||||
switch (t_oper)
|
||||
{
|
||||
case Operators::assign:
|
||||
t = u;
|
||||
break;
|
||||
case Operators::pre_increment:
|
||||
++t;
|
||||
break;
|
||||
case Operators::pre_decrement:
|
||||
--t;
|
||||
break;
|
||||
case Operators::assign_product:
|
||||
t *= u;
|
||||
break;
|
||||
case Operators::assign_sum:
|
||||
t += u;
|
||||
break;
|
||||
case Operators::assign_quotient:
|
||||
t /= u;
|
||||
break;
|
||||
case Operators::assign_difference:
|
||||
t -= u;
|
||||
break;
|
||||
default:
|
||||
throw chaiscript::detail::exception::bad_any_cast();
|
||||
}
|
||||
|
||||
return t_lhs;
|
||||
}
|
||||
};
|
||||
|
||||
struct binary_int
|
||||
{
|
||||
template<typename T, typename U>
|
||||
static Boxed_Value go(Operators::Opers t_oper, T &t, const U &u, const Boxed_Value &t_lhs)
|
||||
{
|
||||
switch (t_oper)
|
||||
{
|
||||
case Operators::assign_bitwise_and:
|
||||
t &= u;
|
||||
break;
|
||||
case Operators::assign_bitwise_or:
|
||||
t |= u;
|
||||
break;
|
||||
case Operators::assign_shift_left:
|
||||
t <<= u;
|
||||
break;
|
||||
case Operators::assign_shift_right:
|
||||
t >>= u;
|
||||
break;
|
||||
case Operators::assign_remainder:
|
||||
t %= u;
|
||||
break;
|
||||
case Operators::assign_bitwise_xor:
|
||||
t ^= u;
|
||||
break;
|
||||
default:
|
||||
throw chaiscript::detail::exception::bad_any_cast();
|
||||
}
|
||||
return t_lhs;
|
||||
}
|
||||
};
|
||||
|
||||
struct const_binary_int
|
||||
{
|
||||
template<typename T, typename U>
|
||||
static Boxed_Value go(Operators::Opers t_oper, const T &t, const U &u, const Boxed_Value &)
|
||||
{
|
||||
switch (t_oper)
|
||||
{
|
||||
case Operators::shift_left:
|
||||
return const_var(t << u);
|
||||
case Operators::shift_right:
|
||||
return const_var(t >> u);
|
||||
case Operators::remainder:
|
||||
return const_var(t % u);
|
||||
case Operators::bitwise_and:
|
||||
return const_var(t & u);
|
||||
case Operators::bitwise_or:
|
||||
return const_var(t | u);
|
||||
case Operators::bitwise_xor:
|
||||
return const_var(t ^ u);
|
||||
case Operators::bitwise_complement:
|
||||
return const_var(~t);
|
||||
default:
|
||||
throw chaiscript::detail::exception::bad_any_cast();
|
||||
}
|
||||
throw chaiscript::detail::exception::bad_any_cast();
|
||||
}
|
||||
};
|
||||
|
||||
struct const_binary
|
||||
{
|
||||
template<typename T, typename U>
|
||||
static Boxed_Value go(Operators::Opers t_oper, const T &t, const U &u, const Boxed_Value &)
|
||||
{
|
||||
switch (t_oper)
|
||||
{
|
||||
case Operators::sum:
|
||||
return const_var(t + u);
|
||||
case Operators::quotient:
|
||||
return const_var(t / u);
|
||||
case Operators::product:
|
||||
return const_var(t * u);
|
||||
case Operators::difference:
|
||||
return const_var(t - u);
|
||||
case Operators::unary_minus:
|
||||
return const_var(-t);
|
||||
case Operators::unary_plus:
|
||||
return const_var(+t);
|
||||
default:
|
||||
throw chaiscript::detail::exception::bad_any_cast();
|
||||
}
|
||||
throw chaiscript::detail::exception::bad_any_cast();
|
||||
}
|
||||
};
|
||||
|
||||
template<typename LHS, typename RHS, bool Float>
|
||||
struct Go
|
||||
{
|
||||
static Boxed_Value go(Operators::Opers t_oper, const Boxed_Value &t_lhs, const Boxed_Value &t_rhs)
|
||||
{
|
||||
if (t_oper > Operators::boolean_flag && t_oper < Operators::non_const_flag)
|
||||
{
|
||||
return boolean::go<LHS, RHS>(t_oper, *static_cast<const LHS *>(t_lhs.get_const_ptr()), *static_cast<const RHS *>(t_rhs.get_const_ptr()), t_lhs);
|
||||
} else if (t_oper > Operators::non_const_flag && t_oper < Operators::non_const_int_flag && !t_lhs.is_const()) {
|
||||
return binary::go<LHS, RHS>(t_oper, *static_cast<LHS *>(t_lhs.get_ptr()), *static_cast<const RHS *>(t_rhs.get_const_ptr()), t_lhs);
|
||||
} else if (t_oper > Operators::non_const_int_flag && t_oper < Operators::const_int_flag && !t_lhs.is_const()) {
|
||||
return binary_int::go<LHS, RHS>(t_oper, *static_cast<LHS *>(t_lhs.get_ptr()), *static_cast<const RHS *>(t_rhs.get_const_ptr()), t_lhs);
|
||||
} else if (t_oper > Operators::const_int_flag && t_oper < Operators::const_flag) {
|
||||
return const_binary_int::go<LHS, RHS>(t_oper, *static_cast<const LHS *>(t_lhs.get_const_ptr()), *static_cast<const RHS *>(t_rhs.get_const_ptr()), t_lhs);
|
||||
} else if (t_oper > Operators::const_flag) {
|
||||
return const_binary::go<LHS, RHS>(t_oper, *static_cast<const LHS *>(t_lhs.get_const_ptr()), *static_cast<const RHS *>(t_rhs.get_const_ptr()), t_lhs);
|
||||
} else {
|
||||
throw chaiscript::detail::exception::bad_any_cast();
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
template<typename LHS, typename RHS>
|
||||
struct Go<LHS, RHS, true>
|
||||
{
|
||||
static Boxed_Value go(Operators::Opers t_oper, const Boxed_Value &t_lhs, const Boxed_Value &t_rhs)
|
||||
{
|
||||
if (t_oper > Operators::boolean_flag && t_oper < Operators::non_const_flag)
|
||||
{
|
||||
return boolean::go<LHS, RHS>(t_oper, *static_cast<const LHS *>(t_lhs.get_const_ptr()), *static_cast<const RHS *>(t_rhs.get_const_ptr()), t_lhs);
|
||||
} else if (t_oper > Operators::non_const_flag && t_oper < Operators::non_const_int_flag && !t_lhs.is_const()) {
|
||||
return binary::go<LHS, RHS>(t_oper, *static_cast<LHS *>(t_lhs.get_ptr()), *static_cast<const RHS *>(t_rhs.get_const_ptr()), t_lhs);
|
||||
} else if (t_oper > Operators::non_const_int_flag && t_oper < Operators::const_int_flag) {
|
||||
throw chaiscript::detail::exception::bad_any_cast();
|
||||
} else if (t_oper > Operators::const_int_flag && t_oper < Operators::const_flag) {
|
||||
throw chaiscript::detail::exception::bad_any_cast();
|
||||
} else if (t_oper > Operators::const_flag) {
|
||||
return const_binary::go<LHS, RHS>(t_oper, *static_cast<const LHS *>(t_lhs.get_const_ptr()), *static_cast<const RHS *>(t_rhs.get_const_ptr()), t_lhs);
|
||||
} else {
|
||||
throw chaiscript::detail::exception::bad_any_cast();
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
template<typename LHS, bool Float>
|
||||
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();
|
||||
|
||||
if (inp_ == typeid(int)) {
|
||||
return Go<LHS, int, Float>::go(t_oper, t_lhs, t_rhs);
|
||||
} else if (inp_ == typeid(double)) {
|
||||
return Go<LHS, double, true>::go(t_oper, t_lhs, t_rhs);
|
||||
} else if (inp_ == typeid(float)) {
|
||||
return Go<LHS, float, true>::go(t_oper, t_lhs, t_rhs);
|
||||
} else if (inp_ == typeid(long double)) {
|
||||
return Go<LHS, long double, true>::go(t_oper, t_lhs, t_rhs);
|
||||
} else if (inp_ == typeid(char)) {
|
||||
return Go<LHS, char, Float>::go(t_oper, t_lhs, t_rhs);
|
||||
} else if (inp_ == typeid(unsigned int)) {
|
||||
return Go<LHS, unsigned int, Float>::go(t_oper, t_lhs, t_rhs);
|
||||
} else if (inp_ == typeid(long)) {
|
||||
return Go<LHS, long, Float>::go(t_oper, t_lhs, t_rhs);
|
||||
} else if (inp_ == typeid(unsigned long)) {
|
||||
return Go<LHS, unsigned long, Float>::go(t_oper, t_lhs, t_rhs);
|
||||
} else if (inp_ == typeid(std::int8_t)) {
|
||||
return Go<LHS, std::int8_t, Float>::go(t_oper, t_lhs, t_rhs);
|
||||
} else if (inp_ == typeid(std::int16_t)) {
|
||||
return Go<LHS, std::int16_t, Float>::go(t_oper, t_lhs, t_rhs);
|
||||
} else if (inp_ == typeid(std::int32_t)) {
|
||||
return Go<LHS, std::int32_t, Float>::go(t_oper, t_lhs, t_rhs);
|
||||
} else if (inp_ == typeid(std::int64_t)) {
|
||||
return Go<LHS, std::int64_t, Float>::go(t_oper, t_lhs, t_rhs);
|
||||
} else if (inp_ == typeid(std::uint8_t)) {
|
||||
return Go<LHS, std::uint8_t, Float>::go(t_oper, t_lhs, t_rhs);
|
||||
} else if (inp_ == typeid(std::uint16_t)) {
|
||||
return Go<LHS, std::uint16_t, Float>::go(t_oper, t_lhs, t_rhs);
|
||||
} else if (inp_ == typeid(std::uint32_t)) {
|
||||
return Go<LHS, std::uint32_t, Float>::go(t_oper, t_lhs, t_rhs);
|
||||
} else if (inp_ == typeid(std::uint64_t)) {
|
||||
return Go<LHS, std::uint64_t, Float>::go(t_oper, t_lhs, t_rhs);
|
||||
} else {
|
||||
throw chaiscript::detail::exception::bad_any_cast();
|
||||
}
|
||||
}
|
||||
|
||||
static Boxed_Value oper(Operators::Opers t_oper, const Boxed_Value &t_lhs, const Boxed_Value &t_rhs)
|
||||
{
|
||||
const Type_Info &inp_ = t_lhs.get_type_info();
|
||||
|
||||
if (inp_ == typeid(int)) {
|
||||
return oper_rhs<int, false>(t_oper, t_lhs, t_rhs);
|
||||
} else if (inp_ == typeid(double)) {
|
||||
return oper_rhs<double, true>(t_oper, t_lhs, t_rhs);
|
||||
} else if (inp_ == typeid(long double)) {
|
||||
return oper_rhs<long double, true>(t_oper, t_lhs, t_rhs);
|
||||
} else if (inp_ == typeid(float)) {
|
||||
return oper_rhs<float, true>(t_oper, t_lhs, t_rhs);
|
||||
} else if (inp_ == typeid(char)) {
|
||||
return oper_rhs<char, false>(t_oper, t_lhs, t_rhs);
|
||||
} else if (inp_ == typeid(unsigned int)) {
|
||||
return oper_rhs<unsigned int, false>(t_oper, t_lhs, t_rhs);
|
||||
} else if (inp_ == typeid(long)) {
|
||||
return oper_rhs<long, false>(t_oper, t_lhs, t_rhs);
|
||||
} else if (inp_ == typeid(unsigned long)) {
|
||||
return oper_rhs<unsigned long, false>(t_oper, t_lhs, t_rhs);
|
||||
} else if (inp_ == typeid(std::int8_t)) {
|
||||
return oper_rhs<std::int8_t, false>(t_oper, t_lhs, t_rhs);
|
||||
} else if (inp_ == typeid(std::int16_t)) {
|
||||
return oper_rhs<std::int16_t, false>(t_oper, t_lhs, t_rhs);
|
||||
} else if (inp_ == typeid(std::int32_t)) {
|
||||
return oper_rhs<std::int32_t, false>(t_oper, t_lhs, t_rhs);
|
||||
} else if (inp_ == typeid(std::int64_t)) {
|
||||
return oper_rhs<std::int64_t, false>(t_oper, t_lhs, t_rhs);
|
||||
} else if (inp_ == typeid(std::uint8_t)) {
|
||||
return oper_rhs<std::uint8_t, false>(t_oper, t_lhs, t_rhs);
|
||||
} else if (inp_ == typeid(std::uint16_t)) {
|
||||
return oper_rhs<std::uint16_t, false>(t_oper, t_lhs, t_rhs);
|
||||
} else if (inp_ == typeid(std::uint32_t)) {
|
||||
return oper_rhs<std::uint32_t, false>(t_oper, t_lhs, t_rhs);
|
||||
} else if (inp_ == typeid(std::uint64_t)) {
|
||||
return oper_rhs<std::uint64_t, false>(t_oper, t_lhs, t_rhs);
|
||||
} else {
|
||||
throw chaiscript::detail::exception::bad_any_cast();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
public:
|
||||
Boxed_Number()
|
||||
: bv(Boxed_Value(0))
|
||||
{
|
||||
}
|
||||
|
||||
Boxed_Number(const Boxed_Value &v)
|
||||
: bv(v)
|
||||
{
|
||||
validate_boxed_number(v);
|
||||
}
|
||||
|
||||
|
||||
bool operator==(const Boxed_Number &t_rhs) const
|
||||
{
|
||||
return boxed_cast<bool>(oper(Operators::equals, this->bv, t_rhs.bv));
|
||||
}
|
||||
|
||||
bool operator<(const Boxed_Number &t_rhs) const
|
||||
{
|
||||
return boxed_cast<bool>(oper(Operators::less_than, this->bv, t_rhs.bv));
|
||||
}
|
||||
|
||||
bool operator>(const Boxed_Number &t_rhs) const
|
||||
{
|
||||
return boxed_cast<bool>(oper(Operators::greater_than, this->bv, t_rhs.bv));
|
||||
}
|
||||
|
||||
bool operator>=(const Boxed_Number &t_rhs) const
|
||||
{
|
||||
return boxed_cast<bool>(oper(Operators::greater_than_equal, this->bv, t_rhs.bv));
|
||||
}
|
||||
|
||||
bool operator<=(const Boxed_Number &t_rhs) const
|
||||
{
|
||||
return boxed_cast<bool>(oper(Operators::less_than_equal, this->bv, t_rhs.bv));
|
||||
}
|
||||
|
||||
bool operator!=(const Boxed_Number &t_rhs) const
|
||||
{
|
||||
return boxed_cast<bool>(oper(Operators::not_equal, this->bv, t_rhs.bv));
|
||||
}
|
||||
|
||||
Boxed_Number operator--()
|
||||
{
|
||||
return oper(Operators::pre_decrement, this->bv, var(0));
|
||||
}
|
||||
|
||||
Boxed_Number operator++()
|
||||
{
|
||||
return oper(Operators::pre_increment, this->bv, var(0));
|
||||
}
|
||||
|
||||
Boxed_Number operator+(const Boxed_Number &t_rhs) const
|
||||
{
|
||||
return oper(Operators::sum, this->bv, t_rhs.bv);
|
||||
}
|
||||
|
||||
Boxed_Number operator+() const
|
||||
{
|
||||
return oper(Operators::unary_plus, this->bv, Boxed_Value(0));
|
||||
}
|
||||
|
||||
Boxed_Number operator-() const
|
||||
{
|
||||
return oper(Operators::unary_minus, this->bv, Boxed_Value(0));
|
||||
}
|
||||
|
||||
Boxed_Number operator-(const Boxed_Number &t_rhs) const
|
||||
{
|
||||
return oper(Operators::difference, this->bv, t_rhs.bv);
|
||||
}
|
||||
|
||||
Boxed_Number operator&=(const Boxed_Number &t_rhs)
|
||||
{
|
||||
return oper(Operators::assign_bitwise_and, this->bv, t_rhs.bv);
|
||||
}
|
||||
|
||||
void validate_boxed_number(const Boxed_Value &v)
|
||||
{
|
||||
const Type_Info &inp_ = v.get_type_info();
|
||||
if (inp_ == typeid(bool))
|
||||
{
|
||||
throw chaiscript::detail::exception::bad_any_cast();
|
||||
}
|
||||
|
||||
if (!inp_.is_arithmetic())
|
||||
{
|
||||
throw chaiscript::detail::exception::bad_any_cast();
|
||||
}
|
||||
}
|
||||
|
||||
Boxed_Number operator=(const Boxed_Value &v)
|
||||
{
|
||||
validate_boxed_number(v);
|
||||
bv = v;
|
||||
return *this;
|
||||
}
|
||||
|
||||
Boxed_Number operator=(const Boxed_Number &t_rhs) const
|
||||
{
|
||||
return oper(Operators::assign, this->bv, t_rhs.bv);
|
||||
}
|
||||
|
||||
Boxed_Number operator|=(const Boxed_Number &t_rhs)
|
||||
{
|
||||
return oper(Operators::assign_bitwise_or, this->bv, t_rhs.bv);
|
||||
}
|
||||
|
||||
Boxed_Number operator^=(const Boxed_Number &t_rhs)
|
||||
{
|
||||
return oper(Operators::assign_bitwise_xor, this->bv, t_rhs.bv);
|
||||
}
|
||||
|
||||
Boxed_Number operator%=(const Boxed_Number &t_rhs)
|
||||
{
|
||||
return oper(Operators::assign_remainder, this->bv, t_rhs.bv);
|
||||
}
|
||||
|
||||
Boxed_Number operator<<=(const Boxed_Number &t_rhs)
|
||||
{
|
||||
return oper(Operators::assign_shift_left, this->bv, t_rhs.bv);
|
||||
}
|
||||
|
||||
Boxed_Number operator>>=(const Boxed_Number &t_rhs)
|
||||
{
|
||||
return oper(Operators::assign_shift_right, this->bv, t_rhs.bv);
|
||||
}
|
||||
|
||||
Boxed_Number operator&(const Boxed_Number &t_rhs) const
|
||||
{
|
||||
return oper(Operators::bitwise_and, this->bv, t_rhs.bv);
|
||||
}
|
||||
|
||||
Boxed_Number operator~() const
|
||||
{
|
||||
return oper(Operators::bitwise_complement, this->bv, Boxed_Value(0));
|
||||
}
|
||||
|
||||
Boxed_Number operator^(const Boxed_Number &t_rhs) const
|
||||
{
|
||||
return oper(Operators::bitwise_xor, this->bv, t_rhs.bv);
|
||||
}
|
||||
|
||||
Boxed_Number operator|(const Boxed_Number &t_rhs) const
|
||||
{
|
||||
return oper(Operators::bitwise_or, this->bv, t_rhs.bv);
|
||||
}
|
||||
|
||||
Boxed_Number operator*=(const Boxed_Number &t_rhs)
|
||||
{
|
||||
return oper(Operators::assign_product, this->bv, t_rhs.bv);
|
||||
}
|
||||
Boxed_Number operator/=(const Boxed_Number &t_rhs)
|
||||
{
|
||||
return oper(Operators::assign_quotient, this->bv, t_rhs.bv);
|
||||
}
|
||||
Boxed_Number operator+=(const Boxed_Number &t_rhs)
|
||||
{
|
||||
return oper(Operators::assign_sum, this->bv, t_rhs.bv);
|
||||
}
|
||||
Boxed_Number operator-=(const Boxed_Number &t_rhs)
|
||||
{
|
||||
return oper(Operators::assign_difference, this->bv, t_rhs.bv);
|
||||
}
|
||||
|
||||
Boxed_Number operator/(const Boxed_Number &t_rhs) const
|
||||
{
|
||||
return oper(Operators::quotient, this->bv, t_rhs.bv);
|
||||
}
|
||||
|
||||
Boxed_Number operator<<(const Boxed_Number &t_rhs) const
|
||||
{
|
||||
return oper(Operators::shift_left, this->bv, t_rhs.bv);
|
||||
}
|
||||
|
||||
Boxed_Number operator*(const Boxed_Number &t_rhs) const
|
||||
{
|
||||
return oper(Operators::product, this->bv, t_rhs.bv);
|
||||
}
|
||||
|
||||
Boxed_Number operator%(const Boxed_Number &t_rhs) const
|
||||
{
|
||||
return oper(Operators::remainder, this->bv, t_rhs.bv);
|
||||
}
|
||||
|
||||
Boxed_Number operator>>(const Boxed_Number &t_rhs) const
|
||||
{
|
||||
return oper(Operators::shift_right, this->bv, t_rhs.bv);
|
||||
}
|
||||
|
||||
|
||||
|
||||
static bool equals(const Boxed_Number &t_lhs, const Boxed_Number &t_rhs)
|
||||
{
|
||||
return boxed_cast<bool>(oper(Operators::equals, t_lhs.bv, t_rhs.bv));
|
||||
}
|
||||
|
||||
static bool less_than(const Boxed_Number &t_lhs, const Boxed_Number &t_rhs)
|
||||
{
|
||||
return boxed_cast<bool>(oper(Operators::less_than, t_lhs.bv, t_rhs.bv));
|
||||
}
|
||||
|
||||
static bool greater_than(const Boxed_Number &t_lhs, const Boxed_Number &t_rhs)
|
||||
{
|
||||
return boxed_cast<bool>(oper(Operators::greater_than, t_lhs.bv, t_rhs.bv));
|
||||
}
|
||||
|
||||
static bool greater_than_equal(const Boxed_Number &t_lhs, const Boxed_Number &t_rhs)
|
||||
{
|
||||
return boxed_cast<bool>(oper(Operators::greater_than_equal, t_lhs.bv, t_rhs.bv));
|
||||
}
|
||||
|
||||
static bool less_than_equal(const Boxed_Number &t_lhs, const Boxed_Number &t_rhs)
|
||||
{
|
||||
return boxed_cast<bool>(oper(Operators::less_than_equal, t_lhs.bv, t_rhs.bv));
|
||||
}
|
||||
|
||||
static bool not_equal(const Boxed_Number &t_lhs, const Boxed_Number &t_rhs)
|
||||
{
|
||||
return boxed_cast<bool>(oper(Operators::not_equal, t_lhs.bv, t_rhs.bv));
|
||||
}
|
||||
|
||||
static Boxed_Number pre_decrement(Boxed_Number t_lhs)
|
||||
{
|
||||
return oper(Operators::pre_decrement, t_lhs.bv, var(0));
|
||||
}
|
||||
|
||||
static Boxed_Number pre_increment(Boxed_Number t_lhs)
|
||||
{
|
||||
return oper(Operators::pre_increment, t_lhs.bv, var(0));
|
||||
}
|
||||
|
||||
static const Boxed_Number sum(const Boxed_Number &t_lhs, const Boxed_Number &t_rhs)
|
||||
{
|
||||
return oper(Operators::sum, t_lhs.bv, t_rhs.bv);
|
||||
}
|
||||
|
||||
static const Boxed_Number unary_plus(const Boxed_Number &t_lhs)
|
||||
{
|
||||
return oper(Operators::unary_plus, t_lhs.bv, Boxed_Value(0));
|
||||
}
|
||||
|
||||
static const Boxed_Number unary_minus(const Boxed_Number &t_lhs)
|
||||
{
|
||||
return oper(Operators::unary_minus, t_lhs.bv, Boxed_Value(0));
|
||||
}
|
||||
|
||||
static const Boxed_Number difference(const Boxed_Number &t_lhs, const Boxed_Number &t_rhs)
|
||||
{
|
||||
return oper(Operators::difference, t_lhs.bv, t_rhs.bv);
|
||||
}
|
||||
|
||||
static Boxed_Number assign_bitwise_and(Boxed_Number t_lhs, const Boxed_Number &t_rhs)
|
||||
{
|
||||
return oper(Operators::assign_bitwise_and, t_lhs.bv, t_rhs.bv);
|
||||
}
|
||||
|
||||
static Boxed_Number assign(Boxed_Number t_lhs, const Boxed_Number &t_rhs)
|
||||
{
|
||||
return oper(Operators::assign, t_lhs.bv, t_rhs.bv);
|
||||
}
|
||||
|
||||
static Boxed_Number assign_bitwise_or(Boxed_Number t_lhs, const Boxed_Number &t_rhs)
|
||||
{
|
||||
return oper(Operators::assign_bitwise_or, t_lhs.bv, t_rhs.bv);
|
||||
}
|
||||
|
||||
static Boxed_Number assign_bitwise_xor(Boxed_Number t_lhs, const Boxed_Number &t_rhs)
|
||||
{
|
||||
return oper(Operators::assign_bitwise_xor, t_lhs.bv, t_rhs.bv);
|
||||
}
|
||||
|
||||
static Boxed_Number assign_remainder(Boxed_Number t_lhs, const Boxed_Number &t_rhs)
|
||||
{
|
||||
return oper(Operators::assign_remainder, t_lhs.bv, t_rhs.bv);
|
||||
}
|
||||
|
||||
static Boxed_Number assign_shift_left(Boxed_Number t_lhs, const Boxed_Number &t_rhs)
|
||||
{
|
||||
return oper(Operators::assign_shift_left, t_lhs.bv, t_rhs.bv);
|
||||
}
|
||||
|
||||
static Boxed_Number assign_shift_right(Boxed_Number t_lhs, const Boxed_Number &t_rhs)
|
||||
{
|
||||
return oper(Operators::assign_shift_right, t_lhs.bv, t_rhs.bv);
|
||||
}
|
||||
|
||||
static const Boxed_Number bitwise_and(const Boxed_Number &t_lhs, const Boxed_Number &t_rhs)
|
||||
{
|
||||
return oper(Operators::bitwise_and, t_lhs.bv, t_rhs.bv);
|
||||
}
|
||||
|
||||
static const Boxed_Number bitwise_complement(const Boxed_Number &t_lhs)
|
||||
{
|
||||
return oper(Operators::bitwise_complement, t_lhs.bv, Boxed_Value(0));
|
||||
}
|
||||
|
||||
static const Boxed_Number bitwise_xor(const Boxed_Number &t_lhs, const Boxed_Number &t_rhs)
|
||||
{
|
||||
return oper(Operators::bitwise_xor, t_lhs.bv, t_rhs.bv);
|
||||
}
|
||||
|
||||
static const Boxed_Number bitwise_or(const Boxed_Number &t_lhs, const Boxed_Number &t_rhs)
|
||||
{
|
||||
return oper(Operators::bitwise_or, t_lhs.bv, t_rhs.bv);
|
||||
}
|
||||
|
||||
static Boxed_Number assign_product(Boxed_Number t_lhs, const Boxed_Number &t_rhs)
|
||||
{
|
||||
return oper(Operators::assign_product, t_lhs.bv, t_rhs.bv);
|
||||
}
|
||||
|
||||
static Boxed_Number assign_quotient(Boxed_Number t_lhs, const Boxed_Number &t_rhs)
|
||||
{
|
||||
return oper(Operators::assign_quotient, t_lhs.bv, t_rhs.bv);
|
||||
}
|
||||
|
||||
static Boxed_Number assign_sum(Boxed_Number t_lhs, const Boxed_Number &t_rhs)
|
||||
{
|
||||
return oper(Operators::assign_sum, t_lhs.bv, t_rhs.bv);
|
||||
}
|
||||
static Boxed_Number assign_difference(Boxed_Number t_lhs, const Boxed_Number &t_rhs)
|
||||
{
|
||||
return oper(Operators::assign_difference, t_lhs.bv, t_rhs.bv);
|
||||
}
|
||||
|
||||
static const Boxed_Number quotient(const Boxed_Number &t_lhs, const Boxed_Number &t_rhs)
|
||||
{
|
||||
return oper(Operators::quotient, t_lhs.bv, t_rhs.bv);
|
||||
}
|
||||
|
||||
static const Boxed_Number shift_left(const Boxed_Number &t_lhs, const Boxed_Number &t_rhs)
|
||||
{
|
||||
return oper(Operators::shift_left, t_lhs.bv, t_rhs.bv);
|
||||
}
|
||||
|
||||
static const Boxed_Number product(const Boxed_Number &t_lhs, const Boxed_Number &t_rhs)
|
||||
{
|
||||
return oper(Operators::product, t_lhs.bv, t_rhs.bv);
|
||||
}
|
||||
|
||||
static const Boxed_Number remainder(const Boxed_Number &t_lhs, const Boxed_Number &t_rhs)
|
||||
{
|
||||
return oper(Operators::remainder, t_lhs.bv, t_rhs.bv);
|
||||
}
|
||||
|
||||
static const Boxed_Number shift_right(const Boxed_Number &t_lhs, const Boxed_Number &t_rhs)
|
||||
{
|
||||
return oper(Operators::shift_right, t_lhs.bv, t_rhs.bv);
|
||||
}
|
||||
|
||||
|
||||
|
||||
static Boxed_Value do_oper(Operators::Opers t_oper, const Boxed_Value &t_lhs, const Boxed_Value &t_rhs)
|
||||
{
|
||||
return oper(t_oper, t_lhs, t_rhs);
|
||||
}
|
||||
|
||||
static Boxed_Value do_oper(Operators::Opers t_oper, const Boxed_Value &t_lhs)
|
||||
{
|
||||
return oper(t_oper, t_lhs, const_var(0));
|
||||
}
|
||||
|
||||
|
||||
|
||||
Boxed_Value bv;
|
||||
};
|
||||
|
||||
namespace detail
|
||||
{
|
||||
/**
|
||||
* Cast_Helper for converting from Boxed_Value to Boxed_Number
|
||||
*/
|
||||
template<>
|
||||
struct Cast_Helper<Boxed_Number>
|
||||
{
|
||||
typedef Boxed_Number Result_Type;
|
||||
|
||||
static Result_Type cast(const Boxed_Value &ob)
|
||||
{
|
||||
return Boxed_Number(ob);
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Cast_Helper for converting from Boxed_Value to Boxed_Number
|
||||
*/
|
||||
template<>
|
||||
struct Cast_Helper<const Boxed_Number &> : Cast_Helper<Boxed_Number>
|
||||
{
|
||||
};
|
||||
|
||||
/**
|
||||
* Cast_Helper for converting from Boxed_Value to Boxed_Number
|
||||
*/
|
||||
template<>
|
||||
struct Cast_Helper<const Boxed_Number> : Cast_Helper<Boxed_Number>
|
||||
{
|
||||
};
|
||||
}
|
||||
|
||||
#ifdef BOOST_MSVC
|
||||
#pragma warning(pop)
|
||||
#endif
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
#endif
|
||||
|
@@ -1,32 +1,24 @@
|
||||
// This file is distributed under the BSD License.
|
||||
// See "license.txt" for details.
|
||||
// Copyright 2009-2010, Jonathan Turner (jturner@minnow-lang.org)
|
||||
// and Jason Turner (lefticus@gmail.com)
|
||||
// Copyright 2009-2012, Jonathan Turner (jonathan@emptycrate.com)
|
||||
// and Jason Turner (jason@emptycrate.com)
|
||||
// http://www.chaiscript.com
|
||||
|
||||
#ifndef __boxed_value_hpp__
|
||||
#define __boxed_value_hpp__
|
||||
#ifndef CHAISCRIPT_BOXED_VALUE_HPP_
|
||||
#define CHAISCRIPT_BOXED_VALUE_HPP_
|
||||
|
||||
#include "type_info.hpp"
|
||||
|
||||
#include "../chaiscript_threading.hpp"
|
||||
|
||||
#include <map>
|
||||
#include <boost/shared_ptr.hpp>
|
||||
#include <boost/any.hpp>
|
||||
#include <boost/function.hpp>
|
||||
#include <boost/ref.hpp>
|
||||
#include <boost/bind.hpp>
|
||||
#include <boost/cstdint.hpp>
|
||||
#include <boost/type_traits/add_const.hpp>
|
||||
#include <boost/integer_traits.hpp>
|
||||
#include "any.hpp"
|
||||
|
||||
namespace chaiscript
|
||||
{
|
||||
/**
|
||||
* Boxed_Value is the main tool of the dispatchkit. It allows
|
||||
* for boxed / untyped containment of any C++ object. It uses
|
||||
* boost::any internally but also provides user access the underlying
|
||||
* stored type information
|
||||
*/
|
||||
|
||||
/// \brief A wrapper for holding any valid C++ type. All types in ChaiScript are Boxed_Value objects
|
||||
/// \sa chaiscript::boxed_cast
|
||||
class Boxed_Value
|
||||
{
|
||||
public:
|
||||
@@ -43,27 +35,12 @@ namespace chaiscript
|
||||
*/
|
||||
struct Data
|
||||
{
|
||||
template<typename T>
|
||||
static bool unique(boost::any *a)
|
||||
{
|
||||
boost::shared_ptr<T> *ptr = boost::any_cast<boost::shared_ptr<T> >(a);
|
||||
return ptr->unique();
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
static bool is_null(boost::any *a)
|
||||
{
|
||||
boost::shared_ptr<T> *ptr = boost::any_cast<boost::shared_ptr<T> >(a);
|
||||
return ptr->get() == 0;
|
||||
}
|
||||
|
||||
Data(const Type_Info &ti,
|
||||
const boost::any &to,
|
||||
const chaiscript::detail::Any &to,
|
||||
bool tr,
|
||||
const boost::function<bool (boost::any*)> &t_unique = boost::function<bool (boost::any*)>(),
|
||||
const boost::function<bool (boost::any*)> &t_is_null = boost::function<bool (boost::any*)>())
|
||||
: m_type_info(ti), m_obj(to),
|
||||
m_is_ref(tr), m_unique(t_unique), m_is_null(t_is_null)
|
||||
const void *t_void_ptr)
|
||||
: m_type_info(ti), m_obj(to), m_data_ptr(ti.is_const()?0:const_cast<void *>(t_void_ptr)), m_const_data_ptr(t_void_ptr),
|
||||
m_is_ref(tr)
|
||||
{
|
||||
}
|
||||
|
||||
@@ -72,166 +49,91 @@ namespace chaiscript
|
||||
m_type_info = rhs.m_type_info;
|
||||
m_obj = rhs.m_obj;
|
||||
m_is_ref = rhs.m_is_ref;
|
||||
m_unique = rhs.m_unique;
|
||||
m_is_null = rhs.m_is_null;
|
||||
m_data_ptr = rhs.m_data_ptr;
|
||||
m_const_data_ptr = rhs.m_const_data_ptr;
|
||||
|
||||
return *this;
|
||||
}
|
||||
|
||||
Type_Info m_type_info;
|
||||
boost::any m_obj;
|
||||
bool m_is_ref;
|
||||
boost::function<bool (boost::any*)> m_unique;
|
||||
boost::function<bool (boost::any*)> m_is_null;
|
||||
};
|
||||
|
||||
/**
|
||||
* Cache of all created objects in the dispatch kit. Used to return the
|
||||
* same shared_ptr if the same object is created more than once.
|
||||
* Also used for acquiring a shared_ptr of a reference object, if the
|
||||
* value of the shared_ptr is known
|
||||
*/
|
||||
struct Object_Cache
|
||||
{
|
||||
Object_Cache()
|
||||
: m_cullcount(0)
|
||||
~Data()
|
||||
{
|
||||
}
|
||||
|
||||
boost::shared_ptr<Data> get(Boxed_Value::Void_Type)
|
||||
Type_Info m_type_info;
|
||||
chaiscript::detail::Any m_obj;
|
||||
void *m_data_ptr;
|
||||
const void *m_const_data_ptr;
|
||||
bool m_is_ref;
|
||||
};
|
||||
|
||||
struct Object_Data
|
||||
{
|
||||
return boost::shared_ptr<Data> (new Data(
|
||||
static std::shared_ptr<Data> get(Boxed_Value::Void_Type)
|
||||
{
|
||||
return std::make_shared<Data>(
|
||||
detail::Get_Type_Info<void>::get(),
|
||||
boost::any(),
|
||||
false)
|
||||
);
|
||||
chaiscript::detail::Any(),
|
||||
false,
|
||||
nullptr)
|
||||
;
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
boost::shared_ptr<Data> get(const boost::shared_ptr<T> *obj)
|
||||
static std::shared_ptr<Data> get(const std::shared_ptr<T> *obj)
|
||||
{
|
||||
return get(*obj);
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
boost::shared_ptr<Data> get(const boost::shared_ptr<T> &obj)
|
||||
static std::shared_ptr<Data> get(const std::shared_ptr<T> &obj)
|
||||
{
|
||||
bool b_const = boost::is_const<T>::value;
|
||||
|
||||
boost::shared_ptr<Data> data(new Data(
|
||||
return std::make_shared<Data>(
|
||||
detail::Get_Type_Info<T>::get(),
|
||||
boost::any(obj),
|
||||
chaiscript::detail::Any(obj),
|
||||
false,
|
||||
&Data::unique<T>,
|
||||
&Data::is_null<T>)
|
||||
obj.get()
|
||||
);
|
||||
|
||||
std::map<std::pair<const void *, bool>, Data>::iterator itr
|
||||
= m_ptrs.find(std::make_pair(obj.get(), b_const));
|
||||
|
||||
if (itr != m_ptrs.end())
|
||||
{
|
||||
(*data) = (itr->second);
|
||||
} else {
|
||||
m_ptrs.insert(std::make_pair(std::make_pair(obj.get(), b_const), *data));
|
||||
}
|
||||
|
||||
return data;
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
boost::shared_ptr<Data> get(T *t)
|
||||
static std::shared_ptr<Data> get(T *t)
|
||||
{
|
||||
return get(boost::ref(*t));
|
||||
return get(std::ref(*t));
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
boost::shared_ptr<Data> get(boost::reference_wrapper<T> obj)
|
||||
static std::shared_ptr<Data> get(std::reference_wrapper<T> obj)
|
||||
{
|
||||
bool b_const = boost::is_const<T>::value;
|
||||
|
||||
boost::shared_ptr<Data> data(new Data(
|
||||
return std::make_shared<Data>(
|
||||
detail::Get_Type_Info<T>::get(),
|
||||
boost::any(obj),
|
||||
true)
|
||||
chaiscript::detail::Any(obj),
|
||||
true,
|
||||
&obj.get()
|
||||
);
|
||||
|
||||
std::map<std::pair<const void *, bool>, Data >::iterator itr
|
||||
= m_ptrs.find(std::make_pair(obj.get_pointer(), b_const) );
|
||||
|
||||
// If the ptr is found in the cache and it is the correct type,
|
||||
// return it. It may be the incorrect type when two variables share the
|
||||
// same memory location. Example:
|
||||
// struct test { int x; };
|
||||
// test t;
|
||||
// Both t and t.x share the same memory location, but do not represent
|
||||
// objects of the same type.
|
||||
if (itr != m_ptrs.end()
|
||||
&& itr->second.m_type_info.bare_equal(data->m_type_info))
|
||||
{
|
||||
(*data) = (itr->second);
|
||||
}
|
||||
|
||||
return data;
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
boost::shared_ptr<Data> get(const T& t)
|
||||
static std::shared_ptr<Data> get(const T& t)
|
||||
{
|
||||
boost::shared_ptr<Data> data(new Data(
|
||||
auto p = std::make_shared<T>(t);
|
||||
return std::make_shared<Data>(
|
||||
detail::Get_Type_Info<T>::get(),
|
||||
boost::any(boost::shared_ptr<T>(new T(t))),
|
||||
chaiscript::detail::Any(p),
|
||||
false,
|
||||
&Data::unique<T>,
|
||||
&Data::is_null<T>)
|
||||
p.get()
|
||||
);
|
||||
|
||||
boost::shared_ptr<T> *ptr = boost::any_cast<boost::shared_ptr<T> >(&data->m_obj);
|
||||
|
||||
m_ptrs.insert(std::make_pair(std::make_pair(ptr->get(), false), *data));
|
||||
return data;
|
||||
}
|
||||
|
||||
boost::shared_ptr<Data> get()
|
||||
static std::shared_ptr<Data> get()
|
||||
{
|
||||
return boost::shared_ptr<Data> (new Data(
|
||||
return std::make_shared<Data>(
|
||||
Type_Info(),
|
||||
boost::any(),
|
||||
false)
|
||||
chaiscript::detail::Any(),
|
||||
false,
|
||||
nullptr
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Drop objects from the cache where there is only one (ie, our)
|
||||
* reference to it, so it may be destructed
|
||||
*/
|
||||
void cull(bool force = false)
|
||||
{
|
||||
|
||||
++m_cullcount;
|
||||
if (force || m_cullcount % 20 != 0)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
std::map<std::pair<const void *, bool>, Data>::iterator itr = m_ptrs.begin();
|
||||
|
||||
while (itr != m_ptrs.end())
|
||||
{
|
||||
if (itr->second.m_unique(&itr->second.m_obj))
|
||||
{
|
||||
std::map<std::pair<const void *, bool>, Data >::iterator todel = itr;
|
||||
++itr;
|
||||
m_ptrs.erase(todel);
|
||||
} else {
|
||||
++itr;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
std::map<std::pair<const void *, bool>, Data> m_ptrs;
|
||||
int m_cullcount;
|
||||
};
|
||||
|
||||
public:
|
||||
@@ -240,9 +142,8 @@ namespace chaiscript
|
||||
*/
|
||||
template<typename T>
|
||||
explicit Boxed_Value(T t)
|
||||
: m_data(get_object_cache().get(t))
|
||||
: m_data(Object_Data::get(t))
|
||||
{
|
||||
get_object_cache().cull();
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -257,7 +158,7 @@ namespace chaiscript
|
||||
* Unknown-type constructor
|
||||
*/
|
||||
Boxed_Value()
|
||||
: m_data(get_object_cache().get())
|
||||
: m_data(Object_Data::get())
|
||||
{
|
||||
}
|
||||
|
||||
@@ -270,20 +171,6 @@ namespace chaiscript
|
||||
std::swap(m_data, rhs.m_data);
|
||||
}
|
||||
|
||||
/**
|
||||
* Return a reference to the static global Object_Cache
|
||||
*/
|
||||
static Object_Cache &get_object_cache()
|
||||
{
|
||||
static chaiscript::threading::Thread_Storage<Object_Cache> oc;
|
||||
return *oc;
|
||||
}
|
||||
|
||||
static void clear_cache()
|
||||
{
|
||||
get_object_cache().m_ptrs.clear();
|
||||
}
|
||||
|
||||
/**
|
||||
* copy the values stored in rhs.m_data to m_data
|
||||
* m_data pointers are not shared in this case
|
||||
@@ -329,15 +216,10 @@ namespace chaiscript
|
||||
|
||||
bool is_null() const
|
||||
{
|
||||
if (m_data->m_is_null)
|
||||
{
|
||||
return m_data->m_is_null(&m_data->m_obj);
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
return (m_data->m_data_ptr == 0 && m_data->m_const_data_ptr == 0);
|
||||
}
|
||||
|
||||
boost::any get() const
|
||||
const chaiscript::detail::Any & get() const
|
||||
{
|
||||
return m_data->m_obj;
|
||||
}
|
||||
@@ -352,560 +234,121 @@ namespace chaiscript
|
||||
return !is_ref();
|
||||
}
|
||||
|
||||
void *get_ptr() const
|
||||
{
|
||||
return m_data->m_data_ptr;
|
||||
}
|
||||
|
||||
const void *get_const_ptr() const
|
||||
{
|
||||
return m_data->m_const_data_ptr;
|
||||
}
|
||||
|
||||
/// \returns true if the two Boxed_Values share the same internal type
|
||||
static bool type_match(Boxed_Value l, Boxed_Value r)
|
||||
{
|
||||
return l.get_type_info() == r.get_type_info();
|
||||
}
|
||||
|
||||
private:
|
||||
boost::shared_ptr<Data> m_data;
|
||||
std::shared_ptr<Data> m_data;
|
||||
};
|
||||
|
||||
|
||||
namespace detail
|
||||
{
|
||||
// Cast_Helper helper classes
|
||||
|
||||
/**
|
||||
* Generic Cast_Helper, for casting to any type
|
||||
*/
|
||||
template<typename Result>
|
||||
struct Cast_Helper
|
||||
{
|
||||
typedef typename boost::reference_wrapper<typename boost::add_const<Result>::type > Result_Type;
|
||||
|
||||
static Result_Type cast(const Boxed_Value &ob)
|
||||
{
|
||||
if (ob.is_ref())
|
||||
{
|
||||
if (!ob.get_type_info().is_const())
|
||||
{
|
||||
return boost::cref((boost::any_cast<boost::reference_wrapper<Result> >(ob.get())).get());
|
||||
} else {
|
||||
return boost::any_cast<boost::reference_wrapper<const Result> >(ob.get());
|
||||
}
|
||||
} else {
|
||||
if (!ob.get_type_info().is_const())
|
||||
{
|
||||
return boost::cref(*(boost::any_cast<boost::shared_ptr<Result> >(ob.get())));
|
||||
} else {
|
||||
return boost::cref(*(boost::any_cast<boost::shared_ptr<const Result> >(ob.get())));
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Cast_Helper for casting to a const & type
|
||||
*/
|
||||
template<typename Result>
|
||||
struct Cast_Helper<const Result &>
|
||||
{
|
||||
typedef typename boost::reference_wrapper<typename boost::add_const<Result>::type > Result_Type;
|
||||
|
||||
static Result_Type cast(const Boxed_Value &ob)
|
||||
{
|
||||
if (ob.is_ref())
|
||||
{
|
||||
if (!ob.get_type_info().is_const())
|
||||
{
|
||||
return boost::cref((boost::any_cast<boost::reference_wrapper<Result> >(ob.get())).get());
|
||||
} else {
|
||||
return boost::any_cast<boost::reference_wrapper<const Result> >(ob.get());
|
||||
}
|
||||
} else {
|
||||
if (!ob.get_type_info().is_const())
|
||||
{
|
||||
return boost::cref(*(boost::any_cast<boost::shared_ptr<Result> >(ob.get())));
|
||||
} else {
|
||||
return boost::cref(*(boost::any_cast<boost::shared_ptr<const Result> >(ob.get())));
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Cast_Helper for casting to a const * type
|
||||
*/
|
||||
template<typename Result>
|
||||
struct Cast_Helper<const Result *>
|
||||
{
|
||||
typedef const Result * Result_Type;
|
||||
|
||||
static Result_Type cast(const Boxed_Value &ob)
|
||||
{
|
||||
if (ob.is_ref())
|
||||
{
|
||||
if (!ob.get_type_info().is_const())
|
||||
{
|
||||
return (boost::any_cast<boost::reference_wrapper<Result> >(ob.get())).get_pointer();
|
||||
} else {
|
||||
return (boost::any_cast<boost::reference_wrapper<const Result> >(ob.get())).get_pointer();
|
||||
}
|
||||
} else {
|
||||
if (!ob.get_type_info().is_const())
|
||||
{
|
||||
return (boost::any_cast<boost::shared_ptr<Result> >(ob.get())).get();
|
||||
} else {
|
||||
return (boost::any_cast<boost::shared_ptr<const Result> >(ob.get())).get();
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Cast_Helper for casting to a * type
|
||||
*/
|
||||
template<typename Result>
|
||||
struct Cast_Helper<Result *>
|
||||
{
|
||||
typedef Result * Result_Type;
|
||||
|
||||
static Result_Type cast(const Boxed_Value &ob)
|
||||
{
|
||||
if (ob.is_ref())
|
||||
{
|
||||
return (boost::any_cast<boost::reference_wrapper<Result> >(ob.get())).get_pointer();
|
||||
} else {
|
||||
return (boost::any_cast<boost::shared_ptr<Result> >(ob.get())).get();
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Cast_Helper for casting to a & type
|
||||
*/
|
||||
template<typename Result>
|
||||
struct Cast_Helper<Result &>
|
||||
{
|
||||
typedef typename boost::reference_wrapper<Result> Result_Type;
|
||||
|
||||
static Result_Type cast(const Boxed_Value &ob)
|
||||
{
|
||||
if (ob.is_ref())
|
||||
{
|
||||
return boost::any_cast<boost::reference_wrapper<Result> >(ob.get());
|
||||
} else {
|
||||
return boost::ref(*(boost::any_cast<boost::shared_ptr<Result> >(ob.get())));
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Cast_Helper for casting to a boost::shared_ptr<> type
|
||||
*/
|
||||
template<typename Result>
|
||||
struct Cast_Helper<typename boost::shared_ptr<Result> >
|
||||
{
|
||||
typedef typename boost::shared_ptr<Result> Result_Type;
|
||||
|
||||
static Result_Type cast(const Boxed_Value &ob)
|
||||
{
|
||||
return boost::any_cast<boost::shared_ptr<Result> >(ob.get());
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Cast_Helper for casting to a boost::shared_ptr<const> type
|
||||
*/
|
||||
template<typename Result>
|
||||
struct Cast_Helper<typename boost::shared_ptr<const Result> >
|
||||
{
|
||||
typedef typename boost::shared_ptr<const Result> Result_Type;
|
||||
|
||||
static Result_Type cast(const Boxed_Value &ob)
|
||||
{
|
||||
if (!ob.get_type_info().is_const())
|
||||
{
|
||||
return boost::const_pointer_cast<const Result>(boost::any_cast<boost::shared_ptr<Result> >(ob.get()));
|
||||
} else {
|
||||
return boost::any_cast<boost::shared_ptr<const Result> >(ob.get());
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Cast_Helper for casting to a const boost::shared_ptr<> & type
|
||||
*/
|
||||
template<typename Result>
|
||||
struct Cast_Helper<const boost::shared_ptr<Result> &>
|
||||
{
|
||||
typedef typename boost::shared_ptr<Result> Result_Type;
|
||||
|
||||
static Result_Type cast(const Boxed_Value &ob)
|
||||
{
|
||||
return boost::any_cast<boost::shared_ptr<Result> >(ob.get());
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Cast_Helper for casting to a const boost::shared_ptr<const> & type
|
||||
*/
|
||||
template<typename Result>
|
||||
struct Cast_Helper<const boost::shared_ptr<const Result> &>
|
||||
{
|
||||
typedef typename boost::shared_ptr<const Result> Result_Type;
|
||||
|
||||
static Result_Type cast(const Boxed_Value &ob)
|
||||
{
|
||||
if (!ob.get_type_info().is_const())
|
||||
{
|
||||
return boost::const_pointer_cast<const Result>(boost::any_cast<boost::shared_ptr<Result> >(ob.get()));
|
||||
} else {
|
||||
return boost::any_cast<boost::shared_ptr<const Result> >(ob.get());
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Cast_Helper for casting to a Boxed_Value type
|
||||
*/
|
||||
template<>
|
||||
struct Cast_Helper<Boxed_Value>
|
||||
{
|
||||
typedef const Boxed_Value & Result_Type;
|
||||
|
||||
static Result_Type cast(const Boxed_Value &ob)
|
||||
{
|
||||
return ob;
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Cast_Helper for casting to a const Boxed_Value & type
|
||||
*/
|
||||
template<>
|
||||
struct Cast_Helper<const Boxed_Value &>
|
||||
{
|
||||
typedef const Boxed_Value & Result_Type;
|
||||
|
||||
static Result_Type cast(const Boxed_Value &ob)
|
||||
{
|
||||
return ob;
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* class that is thrown in the event of a bad_boxed_cast. That is,
|
||||
* in the case that a Boxed_Value cannot be cast to the desired type
|
||||
*/
|
||||
class bad_boxed_cast : public std::bad_cast
|
||||
{
|
||||
public:
|
||||
bad_boxed_cast(const Type_Info &t_from, const std::type_info &t_to) throw()
|
||||
: from(t_from), to(&t_to), m_what("Cannot perform boxed_cast")
|
||||
{
|
||||
}
|
||||
|
||||
bad_boxed_cast(const std::string &w) throw()
|
||||
: m_what(w)
|
||||
{
|
||||
}
|
||||
|
||||
virtual ~bad_boxed_cast() throw() {}
|
||||
|
||||
virtual const char * what () throw()
|
||||
{
|
||||
return m_what.c_str();
|
||||
}
|
||||
|
||||
Type_Info from;
|
||||
const std::type_info *to;
|
||||
|
||||
private:
|
||||
std::string m_what;
|
||||
};
|
||||
|
||||
/**
|
||||
* boxed_cast function for casting a Boxed_Value into a given type
|
||||
* example:
|
||||
* int &i = boxed_cast<int &>(boxedvalue);
|
||||
*/
|
||||
template<typename Type>
|
||||
typename detail::Cast_Helper<Type>::Result_Type boxed_cast(const Boxed_Value &bv)
|
||||
{
|
||||
try {
|
||||
return detail::Cast_Helper<Type>::cast(bv);
|
||||
} catch (const boost::bad_any_cast &) {
|
||||
throw bad_boxed_cast(bv.get_type_info(), typeid(Type));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Object which attempts to convert a Boxed_Value into a generic
|
||||
* POD type and provide generic POD type operations
|
||||
*/
|
||||
struct Boxed_POD_Value
|
||||
{
|
||||
Boxed_POD_Value(const Boxed_Value &v)
|
||||
: d(0), i(0), m_isfloat(false)
|
||||
{
|
||||
if (v.get_type_info().is_undef())
|
||||
{
|
||||
throw boost::bad_any_cast();
|
||||
}
|
||||
|
||||
const Type_Info &inp_ = v.get_type_info();
|
||||
|
||||
if (inp_ == typeid(double))
|
||||
{
|
||||
d = boxed_cast<double>(v);
|
||||
m_isfloat = true;
|
||||
} else if (inp_ == typeid(float)) {
|
||||
d = boxed_cast<float>(v);
|
||||
m_isfloat = true;
|
||||
} else if (inp_ == typeid(bool)) {
|
||||
i = boxed_cast<bool>(v);
|
||||
} else if (inp_ == typeid(char)) {
|
||||
i = boxed_cast<char>(v);
|
||||
} else if (inp_ == typeid(int)) {
|
||||
i = boxed_cast<int>(v);
|
||||
} else if (inp_ == typeid(unsigned int)) {
|
||||
i = boxed_cast<unsigned int>(v);
|
||||
} else if (inp_ == typeid(long)) {
|
||||
i = boxed_cast<long>(v);
|
||||
} else if (inp_ == typeid(unsigned long)) {
|
||||
i = boxed_cast<unsigned long>(v);
|
||||
} else if (inp_ == typeid(boost::int8_t)) {
|
||||
i = boxed_cast<boost::int8_t>(v);
|
||||
} else if (inp_ == typeid(boost::int16_t)) {
|
||||
i = boxed_cast<boost::int16_t>(v);
|
||||
} else if (inp_ == typeid(boost::int32_t)) {
|
||||
i = boxed_cast<boost::int32_t>(v);
|
||||
} else if (inp_ == typeid(boost::int64_t)) {
|
||||
i = boxed_cast<boost::int64_t>(v);
|
||||
} else if (inp_ == typeid(boost::uint8_t)) {
|
||||
i = boxed_cast<boost::uint8_t>(v);
|
||||
} else if (inp_ == typeid(boost::uint16_t)) {
|
||||
i = boxed_cast<boost::uint16_t>(v);
|
||||
} else if (inp_ == typeid(boost::uint32_t)) {
|
||||
i = boxed_cast<boost::uint32_t>(v);
|
||||
} else {
|
||||
throw boost::bad_any_cast();
|
||||
}
|
||||
}
|
||||
|
||||
bool operator==(const Boxed_POD_Value &r) const
|
||||
{
|
||||
return ((m_isfloat)?d:i) == ((r.m_isfloat)?r.d:r.i);
|
||||
}
|
||||
|
||||
bool operator<(const Boxed_POD_Value &r) const
|
||||
{
|
||||
return ((m_isfloat)?d:i) < ((r.m_isfloat)?r.d:r.i);
|
||||
}
|
||||
|
||||
bool operator>(const Boxed_POD_Value &r) const
|
||||
{
|
||||
return ((m_isfloat)?d:i) > ((r.m_isfloat)?r.d:r.i);
|
||||
}
|
||||
|
||||
bool operator>=(const Boxed_POD_Value &r) const
|
||||
{
|
||||
return ((m_isfloat)?d:i) >= ((r.m_isfloat)?r.d:r.i);
|
||||
}
|
||||
|
||||
bool operator<=(const Boxed_POD_Value &r) const
|
||||
{
|
||||
return ((m_isfloat)?d:i) <= ((r.m_isfloat)?r.d:r.i);
|
||||
}
|
||||
|
||||
bool operator!=(const Boxed_POD_Value &r) const
|
||||
{
|
||||
return ((m_isfloat)?d:i) != ((r.m_isfloat)?r.d:r.i);
|
||||
}
|
||||
|
||||
Boxed_Value operator+(const Boxed_POD_Value &r) const
|
||||
{
|
||||
if (!m_isfloat && !r.m_isfloat)
|
||||
{
|
||||
return smart_size(i + r.i);
|
||||
}
|
||||
|
||||
return Boxed_Value(((m_isfloat)?d:i) + ((r.m_isfloat)?r.d:r.i));
|
||||
}
|
||||
|
||||
Boxed_Value operator-(const Boxed_POD_Value &r) const
|
||||
{
|
||||
if (!m_isfloat && !r.m_isfloat)
|
||||
{
|
||||
return smart_size(i - r.i);
|
||||
}
|
||||
|
||||
return Boxed_Value(((m_isfloat)?d:i) - ((r.m_isfloat)?r.d:r.i));
|
||||
}
|
||||
|
||||
Boxed_Value operator&(const Boxed_POD_Value &r) const
|
||||
{
|
||||
if (!m_isfloat && !r.m_isfloat)
|
||||
{
|
||||
return Boxed_Value(i & r.i);
|
||||
}
|
||||
|
||||
throw bad_boxed_cast("& only valid for integer types");
|
||||
}
|
||||
|
||||
Boxed_Value operator^(const Boxed_POD_Value &r) const
|
||||
{
|
||||
if (!m_isfloat && !r.m_isfloat)
|
||||
{
|
||||
return Boxed_Value(i ^ r.i);
|
||||
}
|
||||
|
||||
throw bad_boxed_cast("^ only valid for integer types");
|
||||
}
|
||||
|
||||
Boxed_Value operator|(const Boxed_POD_Value &r) const
|
||||
{
|
||||
if (!m_isfloat && !r.m_isfloat)
|
||||
{
|
||||
return Boxed_Value(i | r.i);
|
||||
}
|
||||
|
||||
throw bad_boxed_cast("| only valid for integer types");
|
||||
}
|
||||
|
||||
Boxed_Value operator/(const Boxed_POD_Value &r) const
|
||||
{
|
||||
if (!m_isfloat && !r.m_isfloat)
|
||||
{
|
||||
return smart_size(i / r.i);
|
||||
}
|
||||
|
||||
return Boxed_Value(((m_isfloat)?d:i) / ((r.m_isfloat)?r.d:r.i));
|
||||
}
|
||||
|
||||
Boxed_Value operator<<(const Boxed_POD_Value &r) const
|
||||
{
|
||||
if (!m_isfloat && !r.m_isfloat)
|
||||
{
|
||||
return smart_size(i << r.i);
|
||||
}
|
||||
|
||||
throw bad_boxed_cast("<< only valid for integer types");
|
||||
}
|
||||
|
||||
|
||||
Boxed_Value operator*(const Boxed_POD_Value &r) const
|
||||
{
|
||||
if (!m_isfloat && !r.m_isfloat)
|
||||
{
|
||||
return smart_size(i * r.i);
|
||||
}
|
||||
|
||||
return Boxed_Value(((m_isfloat)?d:i) * ((r.m_isfloat)?r.d:r.i));
|
||||
}
|
||||
|
||||
|
||||
Boxed_Value operator%(const Boxed_POD_Value &r) const
|
||||
{
|
||||
if (!m_isfloat && !r.m_isfloat)
|
||||
{
|
||||
return smart_size(i % r.i);
|
||||
}
|
||||
|
||||
throw bad_boxed_cast("% only valid for integer types");
|
||||
}
|
||||
|
||||
Boxed_Value operator>>(const Boxed_POD_Value &r) const
|
||||
{
|
||||
if (!m_isfloat && !r.m_isfloat)
|
||||
{
|
||||
return smart_size(i >> r.i);
|
||||
}
|
||||
|
||||
throw bad_boxed_cast(">> only valid for integer types");
|
||||
}
|
||||
|
||||
Boxed_Value smart_size(boost::int64_t i) const
|
||||
{
|
||||
if (i < boost::integer_traits<int>::const_min
|
||||
|| i > boost::integer_traits<int>::const_max)
|
||||
{
|
||||
return Boxed_Value(i);
|
||||
} else {
|
||||
return Boxed_Value(static_cast<int>(i));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
double d;
|
||||
boost::int64_t i;
|
||||
|
||||
bool m_isfloat;
|
||||
};
|
||||
|
||||
namespace detail
|
||||
{
|
||||
/**
|
||||
* Cast_Helper for converting from Boxed_Value to Boxed_POD_Value
|
||||
*/
|
||||
template<>
|
||||
struct Cast_Helper<Boxed_POD_Value>
|
||||
{
|
||||
typedef Boxed_POD_Value Result_Type;
|
||||
|
||||
static Result_Type cast(const Boxed_Value &ob)
|
||||
{
|
||||
return Boxed_POD_Value(ob);
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Cast_Helper for converting from Boxed_Value to Boxed_POD_Value
|
||||
*/
|
||||
template<>
|
||||
struct Cast_Helper<const Boxed_POD_Value &>
|
||||
{
|
||||
typedef Boxed_POD_Value Result_Type;
|
||||
|
||||
static Result_Type cast(const Boxed_Value &ob)
|
||||
{
|
||||
return Boxed_POD_Value(ob);
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
/// \brief Creates a Boxed_Value. If the object passed in is a value type, it is copied. If it is a pointer, std::shared_ptr, or std::reference_type
|
||||
/// a copy is not made.
|
||||
/// \param t The value to box
|
||||
///
|
||||
/// Example:
|
||||
/// \code
|
||||
/// int i;
|
||||
/// chaiscript::ChaiScript chai;
|
||||
/// chai.add(chaiscript::var(i), "i");
|
||||
/// chai.add(chaiscript::var(&i), "ip");
|
||||
/// \endcode
|
||||
///
|
||||
/// \sa \ref addingobjects
|
||||
template<typename T>
|
||||
Boxed_Value var(T t)
|
||||
{
|
||||
return Boxed_Value(t);
|
||||
}
|
||||
|
||||
namespace detail {
|
||||
/// \brief Takes a value, copies it and returns a Boxed_Value object that is immutable
|
||||
/// \param[in] t Value to copy and make const
|
||||
/// \returns Immutable Boxed_Value
|
||||
/// \sa Boxed_Value::is_const
|
||||
template<typename T>
|
||||
Boxed_Value const_var(T *t)
|
||||
Boxed_Value const_var_impl(const T &t)
|
||||
{
|
||||
return Boxed_Value( const_cast<typename boost::add_const<T>::type>(t) );
|
||||
return Boxed_Value(std::shared_ptr<typename std::add_const<T>::type >(new T(t)));
|
||||
}
|
||||
|
||||
/// \brief Takes a pointer to a value, adds const to the pointed to type and returns an immutable Boxed_Value.
|
||||
/// Does not copy the pointed to value.
|
||||
/// \param[in] t Pointer to make immutable
|
||||
/// \returns Immutable Boxed_Value
|
||||
/// \sa Boxed_Value::is_const
|
||||
template<typename T>
|
||||
Boxed_Value const_var(const boost::shared_ptr<T> &t)
|
||||
Boxed_Value const_var_impl(T *t)
|
||||
{
|
||||
return Boxed_Value( boost::const_pointer_cast<typename boost::add_const<T>::type>(t) );
|
||||
return Boxed_Value( const_cast<typename std::add_const<T>::type *>(t) );
|
||||
}
|
||||
|
||||
/// \brief Takes a std::shared_ptr to a value, adds const to the pointed to type and returns an immutable Boxed_Value.
|
||||
/// Does not copy the pointed to value.
|
||||
/// \param[in] t Pointer to make immutable
|
||||
/// \returns Immutable Boxed_Value
|
||||
/// \sa Boxed_Value::is_const
|
||||
template<typename T>
|
||||
Boxed_Value const_var(const boost::reference_wrapper<T> &t)
|
||||
Boxed_Value const_var_impl(const std::shared_ptr<T> &t)
|
||||
{
|
||||
return Boxed_Value( boost::cref(t.get()) );
|
||||
return Boxed_Value( std::const_pointer_cast<typename std::add_const<T>::type>(t) );
|
||||
}
|
||||
|
||||
/// \brief Takes a std::reference_wrapper value, adds const to the referenced type and returns an immutable Boxed_Value.
|
||||
/// Does not copy the referenced value.
|
||||
/// \param[in] t Reference object to make immutable
|
||||
/// \returns Immutable Boxed_Value
|
||||
/// \sa Boxed_Value::is_const
|
||||
template<typename T>
|
||||
Boxed_Value const_var_impl(const std::reference_wrapper<T> &t)
|
||||
{
|
||||
return Boxed_Value( std::cref(t.get()) );
|
||||
}
|
||||
}
|
||||
|
||||
/// \brief Takes an object and returns an immutable Boxed_Value. If the object is a std::reference or pointer type
|
||||
/// the value is not copied. If it is an object type, it is copied.
|
||||
/// \param[in] t Object to make immutable
|
||||
/// \returns Immutable Boxed_Value
|
||||
/// \sa chaiscript::Boxed_Value::is_const
|
||||
/// \sa chaiscript::var
|
||||
///
|
||||
/// Example:
|
||||
/// \code
|
||||
/// enum Colors
|
||||
/// {
|
||||
/// Blue,
|
||||
/// Green,
|
||||
/// Red
|
||||
/// };
|
||||
/// chaiscript::ChaiScript chai
|
||||
/// chai.add(chaiscript::const_var(Blue), "Blue"); // add immutable constant
|
||||
/// chai.add(chaiscript::const_var(Red), "Red");
|
||||
/// chai.add(chaiscript::const_var(Green), "Green");
|
||||
/// \endcode
|
||||
///
|
||||
/// \sa \ref addingobjects
|
||||
template<typename T>
|
||||
Boxed_Value const_var(const T &t)
|
||||
{
|
||||
return Boxed_Value(boost::shared_ptr<typename boost::add_const<T>::type >(new T(t)));
|
||||
}
|
||||
|
||||
/**
|
||||
* Return true if the two Boxed_Values share the same internal type
|
||||
*/
|
||||
static bool type_match(Boxed_Value l, Boxed_Value r)
|
||||
{
|
||||
return l.get_type_info() == r.get_type_info();
|
||||
}
|
||||
return detail::const_var_impl(t);
|
||||
}
|
||||
|
||||
|
||||
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
|
File diff suppressed because it is too large
Load Diff
287
include/chaiscript/dispatchkit/dynamic_cast_conversion.hpp
Normal file
287
include/chaiscript/dispatchkit/dynamic_cast_conversion.hpp
Normal file
@@ -0,0 +1,287 @@
|
||||
// This file is distributed under the BSD License.
|
||||
// See "license.txt" for details.
|
||||
// Copyright 2009-2012, Jonathan Turner (jonathan@emptycrate.com)
|
||||
// and Jason Turner (jason@emptycrate.com)
|
||||
// http://www.chaiscript.com
|
||||
|
||||
#ifndef CHAISCRIPT_DYNAMIC_CAST_CONVERSION_HPP_
|
||||
#define CHAISCRIPT_DYNAMIC_CAST_CONVERSION_HPP_
|
||||
|
||||
#include "type_info.hpp"
|
||||
#include "boxed_value.hpp"
|
||||
#include "boxed_cast_helper.hpp"
|
||||
#include "bad_boxed_cast.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) 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) noexcept
|
||||
: bad_boxed_cast(t_from, t_to)
|
||||
{
|
||||
}
|
||||
|
||||
bad_boxed_dynamic_cast(const std::string &w) noexcept
|
||||
: bad_boxed_cast(w)
|
||||
{
|
||||
}
|
||||
|
||||
virtual ~bad_boxed_dynamic_cast() noexcept {}
|
||||
};
|
||||
}
|
||||
|
||||
namespace detail
|
||||
{
|
||||
class Dynamic_Conversion
|
||||
{
|
||||
public:
|
||||
virtual Boxed_Value convert(const Boxed_Value &derived) = 0;
|
||||
|
||||
const Type_Info &base()
|
||||
{
|
||||
return m_base;
|
||||
}
|
||||
const Type_Info &derived()
|
||||
{
|
||||
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 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(const Boxed_Value &t_derived)
|
||||
{
|
||||
if (t_derived.get_type_info().bare_equal(user_type<Derived>()))
|
||||
{
|
||||
if (t_derived.is_pointer())
|
||||
{
|
||||
// Dynamic cast out the contained boxed value, which we know is the type we want
|
||||
if (t_derived.is_const())
|
||||
{
|
||||
std::shared_ptr<const Base> data
|
||||
= std::dynamic_pointer_cast<const Base>(detail::Cast_Helper<std::shared_ptr<const Derived> >::cast(t_derived));
|
||||
if (!data)
|
||||
{
|
||||
throw std::bad_cast();
|
||||
}
|
||||
|
||||
return Boxed_Value(data);
|
||||
} else {
|
||||
std::shared_ptr<Base> data
|
||||
= std::dynamic_pointer_cast<Base>(detail::Cast_Helper<std::shared_ptr<Derived> >::cast(t_derived));
|
||||
|
||||
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_derived.is_const())
|
||||
{
|
||||
const Derived &d = detail::Cast_Helper<const Derived &>::cast(t_derived);
|
||||
const Base &data = dynamic_cast<const Base &>(d);
|
||||
return Boxed_Value(std::cref(data));
|
||||
} else {
|
||||
Derived &d = detail::Cast_Helper<Derived &>::cast(t_derived);
|
||||
Base &data = dynamic_cast<Base &>(d);
|
||||
return Boxed_Value(std::ref(data));
|
||||
}
|
||||
}
|
||||
} else {
|
||||
throw chaiscript::exception::bad_boxed_dynamic_cast(t_derived.get_type_info(), typeid(Base), "Unknown dynamic_cast_conversion");
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
class Dynamic_Conversions
|
||||
{
|
||||
public:
|
||||
static inline Dynamic_Conversions &get()
|
||||
{
|
||||
static Dynamic_Conversions obj;
|
||||
return obj;
|
||||
}
|
||||
|
||||
template<typename Base, typename Derived>
|
||||
static std::shared_ptr<Dynamic_Conversion> create()
|
||||
{
|
||||
std::shared_ptr<Dynamic_Conversion> conversion(new Dynamic_Conversion_Impl<Base, Derived>());
|
||||
|
||||
/// \todo this is a hack and a kludge. The idea is to make sure that
|
||||
/// the conversion is registered both in the module's notion of the static conversion object
|
||||
/// and in the global notion of the static conversion object
|
||||
/// someday this will almost certainly have to change. Maybe it is time for ChaiScript
|
||||
/// to become a library?
|
||||
Dynamic_Conversions::get().add_conversion(conversion);
|
||||
return conversion;
|
||||
}
|
||||
|
||||
template<typename InItr>
|
||||
void cleanup(InItr begin, const InItr &end)
|
||||
{
|
||||
chaiscript::detail::threading::unique_lock<chaiscript::detail::threading::shared_mutex> l(m_mutex);
|
||||
|
||||
while (begin != end)
|
||||
{
|
||||
if (begin->unique())
|
||||
{
|
||||
m_conversions.erase(begin->get());
|
||||
}
|
||||
|
||||
++begin;
|
||||
}
|
||||
}
|
||||
|
||||
void add_conversion(const std::shared_ptr<Dynamic_Conversion> &conversion)
|
||||
{
|
||||
chaiscript::detail::threading::unique_lock<chaiscript::detail::threading::shared_mutex> l(m_mutex);
|
||||
|
||||
m_conversions.insert(conversion.get());
|
||||
}
|
||||
|
||||
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();
|
||||
}
|
||||
|
||||
|
||||
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);
|
||||
|
||||
std::set<Dynamic_Conversion *>::const_iterator 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:
|
||||
Dynamic_Conversions() {}
|
||||
|
||||
std::set<Dynamic_Conversion *>::const_iterator find(
|
||||
const Type_Info &base, const Type_Info &derived) const
|
||||
{
|
||||
for (std::set<Dynamic_Conversion *>::const_iterator 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();
|
||||
}
|
||||
|
||||
mutable chaiscript::detail::threading::shared_mutex m_mutex;
|
||||
std::set<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
|
||||
///
|
||||
/// \todo Move share static type registration code into a mechanism that allows it to be properly
|
||||
/// shared by all modules
|
||||
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 detail::Dynamic_Conversions::create<Base, Derived>();
|
||||
}
|
||||
|
||||
namespace detail
|
||||
{
|
||||
template<typename Base, typename Derived>
|
||||
bool dynamic_cast_converts()
|
||||
{
|
||||
return dynamic_cast_converts(user_type<Base>(), user_type<Derived>());
|
||||
}
|
||||
|
||||
static bool dynamic_cast_converts(const Type_Info &base, const Type_Info &derived)
|
||||
{
|
||||
return detail::Dynamic_Conversions::get().has_conversion(base, derived);
|
||||
}
|
||||
|
||||
template<typename Base>
|
||||
Boxed_Value boxed_dynamic_cast(const Boxed_Value &derived)
|
||||
{
|
||||
try {
|
||||
return detail::Dynamic_Conversions::get().get_conversion(user_type<Base>(), derived.get_type_info())->convert(derived);
|
||||
} catch (const std::out_of_range &) {
|
||||
throw chaiscript::exception::bad_boxed_dynamic_cast(derived.get_type_info(), typeid(Base), "No known conversion");
|
||||
} catch (const std::bad_cast &) {
|
||||
throw chaiscript::exception::bad_boxed_dynamic_cast(derived.get_type_info(), typeid(Base), "Unable to perform dynamic_cast operation");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
#endif
|
@@ -1,9 +1,16 @@
|
||||
#ifndef __DYNAMIC_OBJECT_HPP__
|
||||
#define __DYNAMIC_OBJECT_HPP__
|
||||
// This file is distributed under the BSD License.
|
||||
// See "license.txt" for details.
|
||||
// Copyright 2009-2012, Jonathan Turner (jonathan@emptycrate.com)
|
||||
// and Jason Turner (jason@emptycrate.com)
|
||||
// http://www.chaiscript.com
|
||||
|
||||
#ifndef CHAISCRIPT_DYNAMIC_OBJECT_HPP_
|
||||
#define CHAISCRIPT_DYNAMIC_OBJECT_HPP_
|
||||
|
||||
#include <boost/optional.hpp>
|
||||
|
||||
namespace chaiscript
|
||||
{
|
||||
namespace dispatch
|
||||
{
|
||||
class Dynamic_Object
|
||||
{
|
||||
@@ -34,20 +41,8 @@ namespace chaiscript
|
||||
std::map<std::string, Boxed_Value> m_attrs;
|
||||
};
|
||||
|
||||
struct Dynamic_Object_Attribute
|
||||
namespace detail
|
||||
{
|
||||
static Boxed_Value func(const std::string &t_type_name, const std::string &t_attr_name,
|
||||
Dynamic_Object &t_do)
|
||||
{
|
||||
if (t_do.get_type_name() != t_type_name)
|
||||
{
|
||||
throw bad_boxed_cast("Dynamic object type mismatch");
|
||||
}
|
||||
|
||||
return t_do.get_attr(t_attr_name);
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* A Proxy_Function implementation designed for calling a function
|
||||
* that is automatically guarded based on the first param based on the
|
||||
@@ -58,10 +53,20 @@ namespace chaiscript
|
||||
public:
|
||||
Dynamic_Object_Function(
|
||||
const std::string &t_type_name,
|
||||
const Proxy_Function &t_func,
|
||||
const boost::optional<Type_Info> &t_ti = boost::optional<Type_Info>())
|
||||
const Proxy_Function &t_func)
|
||||
: Proxy_Function_Base(t_func->get_param_types()),
|
||||
m_type_name(t_type_name), m_func(t_func), m_ti(t_ti)
|
||||
m_type_name(t_type_name), m_func(t_func)
|
||||
{
|
||||
assert( (t_func->get_arity() > 0 || t_func->get_arity() < 0)
|
||||
&& "Programming error, Dynamic_Object_Function must have at least one parameter (this)");
|
||||
}
|
||||
|
||||
Dynamic_Object_Function(
|
||||
const std::string &t_type_name,
|
||||
const Proxy_Function &t_func,
|
||||
const Type_Info &t_ti)
|
||||
: Proxy_Function_Base(build_param_types(t_func->get_param_types(), t_ti)),
|
||||
m_type_name(t_type_name), m_func(t_func), m_ti(new Type_Info(t_ti))
|
||||
{
|
||||
assert( (t_func->get_arity() > 0 || t_func->get_arity() < 0)
|
||||
&& "Programming error, Dynamic_Object_Function must have at least one parameter (this)");
|
||||
@@ -71,11 +76,11 @@ namespace chaiscript
|
||||
|
||||
virtual bool operator==(const Proxy_Function_Base &f) const
|
||||
{
|
||||
try
|
||||
const Dynamic_Object_Function *df = dynamic_cast<const Dynamic_Object_Function *>(&f);
|
||||
if (df)
|
||||
{
|
||||
const Dynamic_Object_Function &df = dynamic_cast<const Dynamic_Object_Function &>(f);
|
||||
return df.m_type_name == m_type_name && (*df.m_func) == (*m_func);
|
||||
} catch (const std::bad_cast &) {
|
||||
return df->m_type_name == m_type_name && (*df->m_func) == (*m_func);
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
@@ -90,16 +95,12 @@ namespace chaiscript
|
||||
}
|
||||
}
|
||||
|
||||
virtual Boxed_Value operator()(const std::vector<Boxed_Value> ¶ms) const
|
||||
virtual std::vector<Const_Proxy_Function> get_contained_functions() const
|
||||
{
|
||||
if (dynamic_object_typename_match(params, m_type_name, m_ti))
|
||||
{
|
||||
return (*m_func)(params);
|
||||
} else {
|
||||
throw guard_error();
|
||||
}
|
||||
return {m_func};
|
||||
}
|
||||
|
||||
|
||||
virtual int get_arity() const
|
||||
{
|
||||
return m_func->get_arity();
|
||||
@@ -110,23 +111,64 @@ namespace chaiscript
|
||||
return m_func->annotation();
|
||||
}
|
||||
|
||||
private:
|
||||
static bool dynamic_object_typename_match(const std::vector<Boxed_Value> &bvs, const std::string &name,
|
||||
const boost::optional<Type_Info> &ti)
|
||||
|
||||
protected:
|
||||
virtual Boxed_Value do_call(const std::vector<Boxed_Value> ¶ms) const
|
||||
{
|
||||
if (bvs.size() > 0)
|
||||
if (dynamic_object_typename_match(params, m_type_name, m_ti))
|
||||
{
|
||||
return (*m_func)(params);
|
||||
} else {
|
||||
throw exception::guard_error();
|
||||
}
|
||||
}
|
||||
|
||||
virtual bool compare_first_type(const Boxed_Value &bv) const
|
||||
{
|
||||
return dynamic_object_typename_match(bv, m_type_name, m_ti);
|
||||
}
|
||||
|
||||
private:
|
||||
static std::vector<Type_Info> build_param_types(
|
||||
const std::vector<Type_Info> &t_inner_types, const Type_Info& t_objectti)
|
||||
{
|
||||
std::vector<Type_Info> types(t_inner_types);
|
||||
|
||||
assert(types.size() > 1);
|
||||
assert(types[1].bare_equal(user_type<Boxed_Value>()));
|
||||
types[1] = t_objectti;
|
||||
return types;
|
||||
}
|
||||
|
||||
static bool dynamic_object_typename_match(const Boxed_Value &bv, const std::string &name,
|
||||
const std::shared_ptr<Type_Info> &ti)
|
||||
{
|
||||
static Type_Info doti = user_type<Dynamic_Object>();
|
||||
if (bv.get_type_info().bare_equal(doti))
|
||||
{
|
||||
try {
|
||||
const Dynamic_Object &d = boxed_cast<const Dynamic_Object &>(bvs[0]);
|
||||
const Dynamic_Object &d = boxed_cast<const Dynamic_Object &>(bv);
|
||||
return name == "Dynamic_Object" || d.get_type_name() == name;
|
||||
} catch (const std::bad_cast &) {
|
||||
return false;
|
||||
}
|
||||
} else {
|
||||
if (ti)
|
||||
{
|
||||
return bvs[0].get_type_info().bare_equal(*ti);
|
||||
return bv.get_type_info().bare_equal(*ti);
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
static bool dynamic_object_typename_match(const std::vector<Boxed_Value> &bvs, const std::string &name,
|
||||
const std::shared_ptr<Type_Info> &ti)
|
||||
{
|
||||
if (bvs.size() > 0)
|
||||
{
|
||||
return dynamic_object_typename_match(bvs[0], name, ti);
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
@@ -134,7 +176,7 @@ namespace chaiscript
|
||||
|
||||
std::string m_type_name;
|
||||
Proxy_Function m_func;
|
||||
boost::optional<Type_Info> m_ti;
|
||||
std::shared_ptr<Type_Info> m_ti;
|
||||
|
||||
};
|
||||
|
||||
@@ -175,11 +217,11 @@ namespace chaiscript
|
||||
|
||||
virtual bool operator==(const Proxy_Function_Base &f) const
|
||||
{
|
||||
try
|
||||
const Dynamic_Object_Constructor *dc = dynamic_cast<const Dynamic_Object_Constructor*>(&f);
|
||||
if (dc)
|
||||
{
|
||||
const Dynamic_Object_Constructor &dc = dynamic_cast<const Dynamic_Object_Constructor&>(f);
|
||||
return dc.m_type_name == m_type_name && (*dc.m_func) == (*m_func);
|
||||
} catch (const std::bad_cast &) {
|
||||
return dc->m_type_name == m_type_name && (*dc->m_func) == (*m_func);
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
@@ -193,17 +235,6 @@ namespace chaiscript
|
||||
return m_func->call_match(new_vals);
|
||||
}
|
||||
|
||||
virtual Boxed_Value operator()(const std::vector<Boxed_Value> ¶ms) const
|
||||
{
|
||||
std::vector<Boxed_Value> new_params;
|
||||
chaiscript::Boxed_Value bv = var(Dynamic_Object(m_type_name));
|
||||
new_params.push_back(bv);
|
||||
new_params.insert(new_params.end(), params.begin(), params.end());
|
||||
|
||||
(*m_func)(new_params);
|
||||
|
||||
return bv;
|
||||
}
|
||||
|
||||
virtual int get_arity() const
|
||||
{
|
||||
@@ -216,11 +247,26 @@ namespace chaiscript
|
||||
return m_func->annotation();
|
||||
}
|
||||
|
||||
protected:
|
||||
virtual Boxed_Value do_call(const std::vector<Boxed_Value> ¶ms) const
|
||||
{
|
||||
std::vector<Boxed_Value> new_params;
|
||||
chaiscript::Boxed_Value bv = var(Dynamic_Object(m_type_name));
|
||||
new_params.push_back(bv);
|
||||
new_params.insert(new_params.end(), params.begin(), params.end());
|
||||
|
||||
(*m_func)(new_params);
|
||||
|
||||
return bv;
|
||||
}
|
||||
|
||||
private:
|
||||
std::string m_type_name;
|
||||
Proxy_Function m_func;
|
||||
|
||||
};
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
|
176
include/chaiscript/dispatchkit/exception_specification.hpp
Normal file
176
include/chaiscript/dispatchkit/exception_specification.hpp
Normal file
@@ -0,0 +1,176 @@
|
||||
// This file is distributed under the BSD License.
|
||||
// See "license.txt" for details.
|
||||
// Copyright 2009-2012, Jonathan Turner (jonathan@emptycrate.com)
|
||||
// and Jason Turner (jason@emptycrate.com)
|
||||
// http://www.chaiscript.com
|
||||
|
||||
#ifndef CHAISCRIPT_EXCEPTION_SPECIFICATION_HPP_
|
||||
#define CHAISCRIPT_EXCEPTION_SPECIFICATION_HPP_
|
||||
|
||||
#include "boxed_cast.hpp"
|
||||
|
||||
namespace chaiscript
|
||||
{
|
||||
namespace detail
|
||||
{
|
||||
struct Exception_Handler_Base
|
||||
{
|
||||
virtual void handle(const Boxed_Value &bv) = 0;
|
||||
|
||||
protected:
|
||||
template<typename T>
|
||||
void throw_type(const Boxed_Value &bv)
|
||||
{
|
||||
try { T t = boxed_cast<T>(bv); throw t; } catch (const chaiscript::exception::bad_boxed_cast &) {}
|
||||
}
|
||||
};
|
||||
|
||||
template<typename T1>
|
||||
struct Exception_Handler_Impl1 : Exception_Handler_Base
|
||||
{
|
||||
virtual void handle(const Boxed_Value &bv)
|
||||
{
|
||||
throw_type<T1>(bv);
|
||||
}
|
||||
};
|
||||
template<typename T1, typename T2>
|
||||
struct Exception_Handler_Impl2 : Exception_Handler_Base
|
||||
{
|
||||
virtual void handle(const Boxed_Value &bv)
|
||||
{
|
||||
throw_type<T1>(bv);
|
||||
throw_type<T2>(bv);
|
||||
}
|
||||
};
|
||||
|
||||
template<typename T1, typename T2, typename T3>
|
||||
struct Exception_Handler_Impl3 : Exception_Handler_Base
|
||||
{
|
||||
virtual void handle(const Boxed_Value &bv)
|
||||
{
|
||||
throw_type<T1>(bv);
|
||||
throw_type<T2>(bv);
|
||||
throw_type<T3>(bv);
|
||||
}
|
||||
};
|
||||
template<typename T1, typename T2, typename T3, typename T4>
|
||||
struct Exception_Handler_Impl4 : Exception_Handler_Base
|
||||
{
|
||||
virtual void handle(const Boxed_Value &bv)
|
||||
{
|
||||
throw_type<T1>(bv);
|
||||
throw_type<T2>(bv);
|
||||
throw_type<T3>(bv);
|
||||
throw_type<T4>(bv);
|
||||
}
|
||||
};
|
||||
template<typename T1, typename T2, typename T3, typename T4, typename T5>
|
||||
struct Exception_Handler_Impl5 : Exception_Handler_Base
|
||||
{
|
||||
virtual void handle(const Boxed_Value &bv)
|
||||
{
|
||||
throw_type<T1>(bv);
|
||||
throw_type<T2>(bv);
|
||||
throw_type<T3>(bv);
|
||||
throw_type<T4>(bv);
|
||||
throw_type<T5>(bv);
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
/// \brief Used in the automatic unboxing of exceptions thrown during script evaluation
|
||||
///
|
||||
/// Exception specifications allow the user to tell ChaiScript what possible exceptions are expected from the script
|
||||
/// being executed. Exception_Handler objects are created with the chaiscript::exception_specification() function.
|
||||
///
|
||||
/// Example:
|
||||
/// \code
|
||||
/// chaiscript::ChaiScript chai;
|
||||
///
|
||||
/// try {
|
||||
/// chai.eval("throw(runtime_error(\"error\"))", chaiscript::exception_specification<int, double, float, const std::string &, const std::exception &>());
|
||||
/// } catch (const double e) {
|
||||
/// } catch (int) {
|
||||
/// } catch (float) {
|
||||
/// } catch (const std::string &) {
|
||||
/// } catch (const std::exception &e) {
|
||||
/// // This is the one what will be called in the specific throw() above
|
||||
/// }
|
||||
/// \endcode
|
||||
///
|
||||
/// It is recommended that if catching the generic \c std::exception& type that you specifically catch
|
||||
/// the chaiscript::exception::eval_error type, so that there is no confusion.
|
||||
///
|
||||
/// \code
|
||||
/// try {
|
||||
/// chai.eval("throw(runtime_error(\"error\"))", chaiscript::exception_specification<const std::exception &>());
|
||||
/// } catch (const chaiscript::exception::eval_error &) {
|
||||
/// // Error in script parsing / execution
|
||||
/// } catch (const std::exception &e) {
|
||||
/// // Error explicitly thrown from script
|
||||
/// }
|
||||
/// \endcode
|
||||
///
|
||||
/// Similarly, if you are using the ChaiScript::eval form that unboxes the return value, then chaiscript::exception::bad_boxed_cast
|
||||
/// should be handled as well.
|
||||
///
|
||||
/// \code
|
||||
/// try {
|
||||
/// chai.eval<int>("1.0", chaiscript::exception_specification<const std::exception &>());
|
||||
/// } catch (const chaiscript::exception::eval_error &) {
|
||||
/// // Error in script parsing / execution
|
||||
/// } catch (const chaiscript::exception::bad_boxed_cast &) {
|
||||
/// // Error unboxing return value
|
||||
/// } catch (const std::exception &e) {
|
||||
/// // Error explicitly thrown from script
|
||||
/// }
|
||||
/// \endcode
|
||||
///
|
||||
/// \sa chaiscript::exception_specification for creation of chaiscript::Exception_Handler objects
|
||||
/// \sa \ref exceptions
|
||||
typedef std::shared_ptr<detail::Exception_Handler_Base> Exception_Handler;
|
||||
|
||||
/// \brief creates a chaiscript::Exception_Handler which handles one type of exception unboxing
|
||||
/// \sa \ref exceptions
|
||||
template<typename T1>
|
||||
Exception_Handler exception_specification()
|
||||
{
|
||||
return Exception_Handler(new detail::Exception_Handler_Impl1<T1>());
|
||||
}
|
||||
|
||||
/// \brief creates a chaiscript::Exception_Handler which handles two types of exception unboxing
|
||||
/// \sa \ref exceptions
|
||||
template<typename T1, typename T2>
|
||||
Exception_Handler exception_specification()
|
||||
{
|
||||
return Exception_Handler(new detail::Exception_Handler_Impl2<T1, T2>());
|
||||
}
|
||||
|
||||
/// \brief creates a chaiscript::Exception_Handler which handles three types of exception unboxing
|
||||
/// \sa \ref exceptions
|
||||
template<typename T1, typename T2, typename T3>
|
||||
Exception_Handler exception_specification()
|
||||
{
|
||||
return Exception_Handler(new detail::Exception_Handler_Impl3<T1, T2, T3>());
|
||||
}
|
||||
|
||||
/// \brief creates a chaiscript::Exception_Handler which handles four types of exception unboxing
|
||||
/// \sa \ref exceptions
|
||||
template<typename T1, typename T2, typename T3, typename T4>
|
||||
Exception_Handler exception_specification()
|
||||
{
|
||||
return Exception_Handler(new detail::Exception_Handler_Impl4<T1, T2, T3, T4>());
|
||||
}
|
||||
|
||||
/// \brief creates a chaiscript::Exception_Handler which handles five types of exception unboxing
|
||||
/// \sa \ref exceptions
|
||||
template<typename T1, typename T2, typename T3, typename T4, typename T5>
|
||||
Exception_Handler exception_specification()
|
||||
{
|
||||
return Exception_Handler(new detail::Exception_Handler_Impl5<T1, T2, T3, T4, T5>());
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
#endif
|
||||
|
@@ -1,33 +1,35 @@
|
||||
// This file is distributed under the BSD License.
|
||||
// See "license.txt" for details.
|
||||
// Copyright 2009-2010, Jonathan Turner (jturner@minnow-lang.org)
|
||||
// and Jason Turner (lefticus@gmail.com)
|
||||
// Copyright 2009-2010, Jonathan Turner (jonathan@emptycrate.com)
|
||||
// and Jason Turner (jason@emptycrate.com)
|
||||
// http://www.chaiscript.com
|
||||
|
||||
#ifndef __function_call_hpp__
|
||||
#define __function_call_hpp__
|
||||
#ifndef CHAISCRIPT_FUNCTION_CALL_HPP_
|
||||
#define CHAISCRIPT_FUNCTION_CALL_HPP_
|
||||
|
||||
#include <boost/shared_ptr.hpp>
|
||||
#include <boost/bind.hpp>
|
||||
#include <boost/function.hpp>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
#include "proxy_functions.hpp"
|
||||
#include "function_call_detail.hpp"
|
||||
|
||||
|
||||
#include <iostream>
|
||||
|
||||
namespace chaiscript
|
||||
{
|
||||
namespace dispatch
|
||||
{
|
||||
/**
|
||||
* Build a function caller that knows how to dispatch on a set of functions
|
||||
* example:
|
||||
* boost::function<void (int)> f =
|
||||
* std::function<void (int)> f =
|
||||
* build_function_caller(dispatchkit.get_function("print"));
|
||||
* \returns A boost::function object for dispatching
|
||||
* \returns A std::function object for dispatching
|
||||
* \param[in] funcs the set of functions to dispatch on.
|
||||
*/
|
||||
template<typename FunctionType>
|
||||
boost::function<FunctionType>
|
||||
functor(const std::vector<std::pair<std::string, Proxy_Function > > &funcs)
|
||||
std::function<FunctionType>
|
||||
functor(const std::vector<Const_Proxy_Function> &funcs)
|
||||
{
|
||||
FunctionType *p=0;
|
||||
return detail::build_function_caller_helper(p, funcs);
|
||||
@@ -40,18 +42,18 @@ namespace chaiscript
|
||||
* example:
|
||||
* void my_function(Proxy_Function f)
|
||||
* {
|
||||
* boost::function<void (int)> local_f =
|
||||
* std::function<void (int)> local_f =
|
||||
* build_function_caller(f);
|
||||
* }
|
||||
* \returns A boost::function object for dispatching
|
||||
* \returns A std::function object for dispatching
|
||||
* \param[in] func A function to execute.
|
||||
*/
|
||||
template<typename FunctionType>
|
||||
boost::function<FunctionType>
|
||||
functor(Proxy_Function func)
|
||||
std::function<FunctionType>
|
||||
functor(Const_Proxy_Function func)
|
||||
{
|
||||
std::vector<std::pair<std::string, Proxy_Function > > funcs;
|
||||
funcs.push_back(std::make_pair(std::string(), func));
|
||||
std::vector<Const_Proxy_Function> funcs;
|
||||
funcs.push_back(func);
|
||||
return functor<FunctionType>(funcs);
|
||||
}
|
||||
|
||||
@@ -60,12 +62,71 @@ namespace chaiscript
|
||||
* and creating a typesafe C++ function caller from it.
|
||||
*/
|
||||
template<typename FunctionType>
|
||||
boost::function<FunctionType>
|
||||
std::function<FunctionType>
|
||||
functor(const Boxed_Value &bv)
|
||||
{
|
||||
return functor<FunctionType>(boxed_cast<Proxy_Function >(bv));
|
||||
return functor<FunctionType>(boxed_cast<Const_Proxy_Function >(bv));
|
||||
}
|
||||
}
|
||||
|
||||
namespace detail{
|
||||
/**
|
||||
* Cast helper to handle automatic casting to const std::function &
|
||||
*/
|
||||
template<typename Signature>
|
||||
struct Cast_Helper<const std::function<Signature> &>
|
||||
{
|
||||
typedef std::function<Signature> Result_Type;
|
||||
|
||||
static Result_Type cast(const Boxed_Value &ob)
|
||||
{
|
||||
if (ob.get_type_info().bare_equal(user_type<Const_Proxy_Function>()))
|
||||
{
|
||||
return dispatch::functor<Signature>(ob);
|
||||
} else {
|
||||
return Cast_Helper_Inner<const std::function<Signature> &>::cast(ob);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Cast helper to handle automatic casting to std::function
|
||||
*/
|
||||
template<typename Signature>
|
||||
struct Cast_Helper<std::function<Signature> >
|
||||
{
|
||||
typedef std::function<Signature> Result_Type;
|
||||
|
||||
static Result_Type cast(const Boxed_Value &ob)
|
||||
{
|
||||
if (ob.get_type_info().bare_equal(user_type<Const_Proxy_Function>()))
|
||||
{
|
||||
return dispatch::functor<Signature>(ob);
|
||||
} else {
|
||||
return Cast_Helper_Inner<std::function<Signature> >::cast(ob);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Cast helper to handle automatic casting to const std::function
|
||||
*/
|
||||
template<typename Signature>
|
||||
struct Cast_Helper<const std::function<Signature> >
|
||||
{
|
||||
typedef std::function<Signature> Result_Type;
|
||||
|
||||
static Result_Type cast(const Boxed_Value &ob)
|
||||
{
|
||||
if (ob.get_type_info().bare_equal(user_type<Const_Proxy_Function>()))
|
||||
{
|
||||
return dispatch::functor<Signature>(ob);
|
||||
} else {
|
||||
return Cast_Helper_Inner<const std::function<Signature> >::cast(ob);
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
||||
|
@@ -1,30 +1,23 @@
|
||||
// This file is distributed under the BSD License.
|
||||
// See "license.txt" for details.
|
||||
// Copyright 2009-2010, Jonathan Turner (jturner@minnow-lang.org)
|
||||
// and Jason Turner (lefticus@gmail.com)
|
||||
// Copyright 2009-2012, Jonathan Turner (jonathan@emptycrate.com)
|
||||
// and Jason Turner (jason@emptycrate.com)
|
||||
// http://www.chaiscript.com
|
||||
|
||||
#include <boost/preprocessor.hpp>
|
||||
#ifndef CHAISCRIPT_FUNCTION_CALL_DETAIL_HPP_
|
||||
#define CHAISCRIPT_FUNCTION_CALL_DETAIL_HPP_
|
||||
|
||||
#define addparam(z,n,text) params.push_back(boost::is_reference<Param ## n>::value?Boxed_Value(boost::ref(BOOST_PP_CAT(p, n))):Boxed_Value(BOOST_PP_CAT(p, n) ));
|
||||
#define curry(z,n,text) BOOST_PP_CAT(_, BOOST_PP_INC(n))
|
||||
|
||||
|
||||
#ifndef BOOST_PP_IS_ITERATING
|
||||
#ifndef __function_call_detail_hpp__
|
||||
#define __function_call_detail_hpp__
|
||||
|
||||
#include <boost/shared_ptr.hpp>
|
||||
#include <boost/bind.hpp>
|
||||
#include <boost/function.hpp>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
#include "proxy_functions.hpp"
|
||||
|
||||
namespace chaiscript
|
||||
{
|
||||
namespace dispatch
|
||||
{
|
||||
namespace detail
|
||||
{
|
||||
|
||||
/**
|
||||
* Internal helper class for handling the return
|
||||
* value of a build_function_caller
|
||||
@@ -32,10 +25,10 @@ namespace chaiscript
|
||||
template<typename Ret>
|
||||
struct Function_Caller_Ret
|
||||
{
|
||||
static Ret call(const std::vector<std::pair<std::string, Proxy_Function > > &t_funcs,
|
||||
static Ret call(const std::vector<Const_Proxy_Function> &t_funcs,
|
||||
const std::vector<Boxed_Value> ¶ms)
|
||||
{
|
||||
return boxed_cast<Ret>(dispatch(t_funcs, params));
|
||||
return boxed_cast<Ret>(dispatch::dispatch(t_funcs, params));
|
||||
}
|
||||
};
|
||||
|
||||
@@ -45,55 +38,61 @@ namespace chaiscript
|
||||
template<>
|
||||
struct Function_Caller_Ret<void>
|
||||
{
|
||||
static void call(const std::vector<std::pair<std::string, Proxy_Function > > &t_funcs,
|
||||
static void call(const std::vector<Const_Proxy_Function> &t_funcs,
|
||||
const std::vector<Boxed_Value> ¶ms)
|
||||
{
|
||||
dispatch(t_funcs, params);
|
||||
dispatch::dispatch(t_funcs, params);
|
||||
}
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
#define BOOST_PP_ITERATION_LIMITS ( 0, 9 )
|
||||
#define BOOST_PP_FILENAME_1 <chaiscript/dispatchkit/function_call_detail.hpp>
|
||||
#include BOOST_PP_ITERATE()
|
||||
|
||||
# endif
|
||||
#else
|
||||
# define n BOOST_PP_ITERATION()
|
||||
|
||||
namespace chaiscript
|
||||
{
|
||||
namespace detail
|
||||
{
|
||||
/**
|
||||
* used internally for unwrapping a function call's types
|
||||
*/
|
||||
template<typename Ret BOOST_PP_COMMA_IF(n) BOOST_PP_ENUM_PARAMS(n, typename Param) >
|
||||
Ret function_caller(const std::vector<std::pair<std::string, Proxy_Function > > &funcs
|
||||
BOOST_PP_COMMA_IF(n) BOOST_PP_ENUM_BINARY_PARAMS(n, Param, p) )
|
||||
{
|
||||
std::vector<Boxed_Value> params;
|
||||
|
||||
BOOST_PP_REPEAT(n, addparam, ~)
|
||||
|
||||
return Function_Caller_Ret<Ret>::call(funcs, params);
|
||||
}
|
||||
|
||||
/**
|
||||
* used internally for unwrapping a function call's types
|
||||
*/
|
||||
template<typename Ret BOOST_PP_COMMA_IF(n) BOOST_PP_ENUM_PARAMS(n, typename Param) >
|
||||
boost::function<Ret (BOOST_PP_ENUM_PARAMS(n, Param)) >
|
||||
build_function_caller_helper(Ret (BOOST_PP_ENUM_PARAMS(n, Param)), const std::vector<std::pair<std::string, Proxy_Function> > &funcs)
|
||||
template<typename Ret, typename ... Param>
|
||||
struct Build_Function_Caller_Helper
|
||||
{
|
||||
Build_Function_Caller_Helper(const std::vector<Const_Proxy_Function> &t_funcs)
|
||||
: m_funcs(t_funcs)
|
||||
{
|
||||
return boost::bind(&function_caller<Ret BOOST_PP_COMMA_IF(n) BOOST_PP_ENUM_PARAMS(n, Param)>, funcs
|
||||
BOOST_PP_ENUM_TRAILING(n, curry, ~));
|
||||
}
|
||||
|
||||
Ret operator()(Param...param)
|
||||
{
|
||||
return Function_Caller_Ret<Ret>::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::vector<Const_Proxy_Function> m_funcs;
|
||||
};
|
||||
|
||||
|
||||
|
||||
template<typename Ret, typename ... Params>
|
||||
std::function<Ret (Params...)> build_function_caller_helper(Ret (Params...), const std::vector<Const_Proxy_Function> &funcs)
|
||||
{
|
||||
if (funcs.size() == 1)
|
||||
{
|
||||
std::shared_ptr<const Proxy_Function_Impl<Ret (Params...)>> pfi =
|
||||
std::dynamic_pointer_cast<const Proxy_Function_Impl<Ret (Params...)> >
|
||||
(funcs[0]);
|
||||
|
||||
if (pfi)
|
||||
{
|
||||
return pfi->internal_function();
|
||||
}
|
||||
// looks like this either wasn't a Proxy_Function_Impl or the types didn't match
|
||||
// we cannot make any other guesses or assumptions really, so continuing
|
||||
}
|
||||
|
||||
return std::function<Ret (Params...)>(Build_Function_Caller_Helper<Ret, Params...>(funcs));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
#undef n
|
||||
|
||||
#endif
|
||||
|
||||
|
@@ -1,21 +1,25 @@
|
||||
// This file is distributed under the BSD License.
|
||||
// See "license.txt" for details.
|
||||
// Copyright 2009-2010, Jonathan Turner (jturner@minnow-lang.org)
|
||||
// and Jason Turner (lefticus@gmail.com)
|
||||
// Copyright 2009-2012, Jonathan Turner (jonathan@emptycrate.com)
|
||||
// and Jason Turner (jason@emptycrate.com)
|
||||
// http://www.chaiscript.com
|
||||
|
||||
#ifndef __handle_return_hpp__
|
||||
#define __handle_return_hpp__
|
||||
#ifndef CHAISCRIPT_HANDLE_RETURN_HPP_
|
||||
#define CHAISCRIPT_HANDLE_RETURN_HPP_
|
||||
|
||||
#include "boxed_value.hpp"
|
||||
#include "boxed_number.hpp"
|
||||
#include "type_info.hpp"
|
||||
#include <string>
|
||||
#include <boost/function.hpp>
|
||||
|
||||
#include <stdexcept>
|
||||
#include <vector>
|
||||
|
||||
namespace chaiscript
|
||||
{
|
||||
namespace dispatch
|
||||
{
|
||||
namespace detail
|
||||
{
|
||||
/**
|
||||
* Used internally for handling a return value from a Proxy_Function call
|
||||
@@ -25,23 +29,41 @@ namespace chaiscript
|
||||
{
|
||||
static Boxed_Value handle(const Ret &r)
|
||||
{
|
||||
return Boxed_Value(r);
|
||||
return const_var(r);
|
||||
}
|
||||
};
|
||||
|
||||
template<typename Ret>
|
||||
struct Handle_Return<boost::shared_ptr<Ret> &>
|
||||
struct Handle_Return<Ret *>
|
||||
{
|
||||
static Boxed_Value handle(const boost::shared_ptr<Ret> &r)
|
||||
static Boxed_Value handle(Ret *p)
|
||||
{
|
||||
return Boxed_Value(p);
|
||||
}
|
||||
};
|
||||
|
||||
template<typename Ret>
|
||||
struct Handle_Return<std::shared_ptr<Ret> &>
|
||||
{
|
||||
static Boxed_Value handle(const std::shared_ptr<Ret> &r)
|
||||
{
|
||||
return Boxed_Value(r);
|
||||
}
|
||||
};
|
||||
|
||||
template<typename Ret>
|
||||
struct Handle_Return<const boost::shared_ptr<Ret> &>
|
||||
struct Handle_Return<std::shared_ptr<Ret> >
|
||||
{
|
||||
static Boxed_Value handle(const boost::shared_ptr<Ret> &r)
|
||||
static Boxed_Value handle(const std::shared_ptr<Ret> &r)
|
||||
{
|
||||
return Boxed_Value(r);
|
||||
}
|
||||
};
|
||||
|
||||
template<typename Ret>
|
||||
struct Handle_Return<const std::shared_ptr<Ret> &>
|
||||
{
|
||||
static Boxed_Value handle(const std::shared_ptr<Ret> &r)
|
||||
{
|
||||
return Boxed_Value(r);
|
||||
}
|
||||
@@ -52,7 +74,7 @@ namespace chaiscript
|
||||
{
|
||||
static Boxed_Value handle(const Ret &r)
|
||||
{
|
||||
return Boxed_Value(boost::cref(r));
|
||||
return Boxed_Value(std::cref(r));
|
||||
}
|
||||
};
|
||||
|
||||
@@ -65,12 +87,12 @@ namespace chaiscript
|
||||
{
|
||||
static Boxed_Value handle(Ret &r)
|
||||
{
|
||||
return Boxed_Value(boost::ref(r));
|
||||
return Boxed_Value(std::ref(r));
|
||||
}
|
||||
|
||||
static Boxed_Value handle(const Ret &r)
|
||||
{
|
||||
return Boxed_Value(boost::cref(r));
|
||||
return Boxed_Value(std::cref(r));
|
||||
}
|
||||
};
|
||||
|
||||
@@ -86,6 +108,18 @@ namespace chaiscript
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Used internally for handling a return value from a Proxy_Function call
|
||||
*/
|
||||
template<>
|
||||
struct Handle_Return<const Boxed_Value>
|
||||
{
|
||||
static Boxed_Value handle(const Boxed_Value &r)
|
||||
{
|
||||
return r;
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Used internally for handling a return value from a Proxy_Function call
|
||||
*/
|
||||
@@ -110,6 +144,30 @@ namespace chaiscript
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Used internally for handling a return value from a Proxy_Function call
|
||||
*/
|
||||
template<>
|
||||
struct Handle_Return<Boxed_Number>
|
||||
{
|
||||
static Boxed_Value handle(const Boxed_Number &r)
|
||||
{
|
||||
return r.bv;
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Used internally for handling a return value from a Proxy_Function call
|
||||
*/
|
||||
template<>
|
||||
struct Handle_Return<const Boxed_Number>
|
||||
{
|
||||
static Boxed_Value handle(const Boxed_Number &r)
|
||||
{
|
||||
return r.bv;
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Used internally for handling a return value from a Proxy_Function call
|
||||
@@ -123,5 +181,7 @@ namespace chaiscript
|
||||
}
|
||||
};
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
||||
|
@@ -1,7 +1,17 @@
|
||||
#ifndef __CHAISCRIPT_OPERATORS_HPP__
|
||||
#define __CHAISCRIPT_OPERATORS_HPP__
|
||||
// This file is distributed under the BSD License.
|
||||
// See "license.txt" for details.
|
||||
// Copyright 2009-2012, Jonathan Turner (jonathan@emptycrate.com)
|
||||
// and Jason Turner (jason@emptycrate.com)
|
||||
// http://www.chaiscript.com
|
||||
|
||||
#ifndef CHAISCRIPT_OPERATORS_HPP_
|
||||
#define CHAISCRIPT_OPERATORS_HPP_
|
||||
|
||||
#include "../chaiscript_defines.hpp"
|
||||
|
||||
namespace chaiscript
|
||||
{
|
||||
namespace bootstrap
|
||||
{
|
||||
namespace operators
|
||||
{
|
||||
@@ -146,7 +156,14 @@ namespace chaiscript
|
||||
template<typename Ret, typename L>
|
||||
Ret unary_minus(L l)
|
||||
{
|
||||
#ifdef CHAISCRIPT_MSVC
|
||||
#pragma warning(push)
|
||||
#pragma warning(disable : 4146)
|
||||
return (-l);
|
||||
#pragma warning(pop)
|
||||
#else
|
||||
return (-l);
|
||||
#endif
|
||||
}
|
||||
|
||||
template<typename Ret, typename L, typename R>
|
||||
@@ -438,5 +455,6 @@ namespace chaiscript
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
||||
|
@@ -1,39 +1,16 @@
|
||||
// This file is distributed under the BSD License.
|
||||
// See "license.txt" for details.
|
||||
// Copyright 2009-2010, Jonathan Turner (jturner@minnow-lang.org)
|
||||
// and Jason Turner (lefticus@gmail.com)
|
||||
// Copyright 2009-2012, Jonathan Turner (jonathan@emptycrate.com)
|
||||
// and Jason Turner (jason@emptycrate.com)
|
||||
// http://www.chaiscript.com
|
||||
|
||||
#include <boost/preprocessor.hpp>
|
||||
|
||||
#ifndef BOOST_PP_IS_ITERATING
|
||||
#ifndef __proxy_constructors_hpp__
|
||||
#define __proxy_constructors_hpp__
|
||||
|
||||
#include <boost/shared_ptr.hpp>
|
||||
#include <boost/bind.hpp>
|
||||
#include <boost/function.hpp>
|
||||
|
||||
|
||||
#define BOOST_PP_ITERATION_LIMITS ( 0, 10 )
|
||||
#define BOOST_PP_FILENAME_1 <chaiscript/dispatchkit/proxy_constructors.hpp>
|
||||
#include BOOST_PP_ITERATE()
|
||||
# endif
|
||||
#ifndef CHAISCRIPT_PROXY_CONSTRUCTORS_HPP_
|
||||
#define CHAISCRIPT_PROXY_CONSTRUCTORS_HPP_
|
||||
|
||||
namespace chaiscript
|
||||
{
|
||||
template<typename T>
|
||||
Proxy_Function constructor()
|
||||
{
|
||||
T *f = 0;
|
||||
return (detail::build_constructor_(f));
|
||||
}
|
||||
}
|
||||
|
||||
#else
|
||||
# define n BOOST_PP_ITERATION()
|
||||
|
||||
namespace chaiscript
|
||||
namespace dispatch
|
||||
{
|
||||
namespace detail
|
||||
{
|
||||
@@ -41,27 +18,41 @@ namespace chaiscript
|
||||
* A constructor function, used for creating a new object
|
||||
* of a given type with a given set of params
|
||||
*/
|
||||
template<typename Class BOOST_PP_COMMA_IF(n) BOOST_PP_ENUM_PARAMS(n, typename Param) >
|
||||
boost::shared_ptr<Class> constructor_( BOOST_PP_ENUM_BINARY_PARAMS(n, Param, p) )
|
||||
template<typename Class, typename ... Params>
|
||||
std::shared_ptr<Class> constructor_(Params ... params)
|
||||
{
|
||||
return boost::shared_ptr<Class>(new Class( BOOST_PP_ENUM_PARAMS(n, p) ));
|
||||
return std::shared_ptr<Class>(new Class(params...));
|
||||
}
|
||||
|
||||
/**
|
||||
* Helper function for build a constructor function
|
||||
* example:
|
||||
* dispatchengine.register_function(build_constructor<MyClass, int, const std::string&>, "MyClass");
|
||||
* \todo See if it is possible to make this not be a variadic function
|
||||
*/
|
||||
template<typename Class BOOST_PP_COMMA_IF(n) BOOST_PP_ENUM_PARAMS(n, typename Param) >
|
||||
Proxy_Function build_constructor_(Class (*)(BOOST_PP_ENUM_PARAMS(n, Param)))
|
||||
template<typename Class, typename ... Params >
|
||||
Proxy_Function build_constructor_(Class (*)(Params...))
|
||||
{
|
||||
typedef boost::shared_ptr<Class> (sig)(BOOST_PP_ENUM_PARAMS(n, Param));
|
||||
return Proxy_Function(new Proxy_Function_Impl<sig>(boost::function<sig>(&(constructor_<Class BOOST_PP_COMMA_IF(n) BOOST_PP_ENUM_PARAMS(n, Param)>))));
|
||||
typedef std::shared_ptr<Class> (sig)(Params...);
|
||||
return Proxy_Function(new Proxy_Function_Impl<sig>(std::function<sig>(&(constructor_<Class, Params...>))));
|
||||
}
|
||||
}
|
||||
}
|
||||
#undef n
|
||||
|
||||
|
||||
/// \brief Generates a constructor function for use with ChaiScript
|
||||
///
|
||||
/// \tparam T The signature of the constructor to generate. In the form of: ClassType (ParamType1, ParamType2, ...)
|
||||
///
|
||||
/// Example:
|
||||
/// \code
|
||||
/// chaiscript::ChaiScript chai;
|
||||
/// // Create a new function that creates a MyClass object using the (int, float) constructor
|
||||
/// // and call that function "MyClass" so that it appears as a normal constructor to the user.
|
||||
/// chai.add(constructor<MyClass (int, float)>(), "MyClass");
|
||||
/// \endcode
|
||||
template<typename T>
|
||||
Proxy_Function constructor()
|
||||
{
|
||||
T *f = 0;
|
||||
return (dispatch::detail::build_constructor_(f));
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
|
@@ -1,56 +1,33 @@
|
||||
// This file is distributed under the BSD License.
|
||||
// See "license.txt" for details.
|
||||
// Copyright 2009-2010, Jonathan Turner (jturner@minnow-lang.org)
|
||||
// and Jason Turner (lefticus@gmail.com)
|
||||
// Copyright 2009-2012, Jonathan Turner (jonathan@emptycrate.com)
|
||||
// and Jason Turner (jason@emptycrate.com)
|
||||
// http://www.chaiscript.com
|
||||
|
||||
|
||||
#ifndef __proxy_functions_hpp__
|
||||
#define __proxy_functions_hpp__
|
||||
#ifndef CHAISCRIPT_PROXY_FUNCTIONS_HPP_
|
||||
#define CHAISCRIPT_PROXY_FUNCTIONS_HPP_
|
||||
|
||||
|
||||
#include "boxed_value.hpp"
|
||||
#include "type_info.hpp"
|
||||
#include <string>
|
||||
#include <boost/function.hpp>
|
||||
#include <boost/type_traits/add_reference.hpp>
|
||||
#include <type_traits>
|
||||
#include <stdexcept>
|
||||
#include <vector>
|
||||
#include <cassert>
|
||||
#include "proxy_functions_detail.hpp"
|
||||
|
||||
namespace chaiscript
|
||||
{
|
||||
/**
|
||||
* Helper for building a list of parameters for calling a Proxy_Function
|
||||
* it does automatic conversion to Boxed_Value types via operator<<
|
||||
*
|
||||
* example usage:
|
||||
* Boxed_Value retval = dispatch(dispatchengine.get_function("+"),
|
||||
* chaiscript::Param_List_Builder() << 5 << 6);
|
||||
*/
|
||||
struct Param_List_Builder
|
||||
{
|
||||
Param_List_Builder &operator<<(const Boxed_Value &so)
|
||||
{
|
||||
objects.push_back(so);
|
||||
return *this;
|
||||
}
|
||||
class Boxed_Number;
|
||||
struct AST_Node;
|
||||
|
||||
template<typename T>
|
||||
Param_List_Builder &operator<<(T t)
|
||||
typedef std::shared_ptr<struct AST_Node> AST_NodePtr;
|
||||
|
||||
|
||||
namespace dispatch
|
||||
{
|
||||
objects.push_back(Boxed_Value(t));
|
||||
return *this;
|
||||
}
|
||||
|
||||
operator const std::vector<Boxed_Value> &() const
|
||||
{
|
||||
return objects;
|
||||
}
|
||||
|
||||
std::vector<Boxed_Value> objects;
|
||||
};
|
||||
|
||||
/**
|
||||
* Pure virtual base class for all Proxy_Function implementations
|
||||
* Proxy_Functions are a type erasure of type safe C++
|
||||
@@ -63,13 +40,27 @@ namespace chaiscript
|
||||
{
|
||||
public:
|
||||
virtual ~Proxy_Function_Base() {}
|
||||
virtual Boxed_Value operator()(const std::vector<Boxed_Value> ¶ms) const = 0;
|
||||
Boxed_Value operator()(const std::vector<Boxed_Value> ¶ms) const
|
||||
{
|
||||
Boxed_Value bv = do_call(params);
|
||||
return bv;
|
||||
}
|
||||
|
||||
std::vector<Type_Info> get_param_types() const { return m_types; }
|
||||
/// 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
|
||||
/// value containes exactly 1 Type_Info object: the return type
|
||||
/// \returns the types of all parameters.
|
||||
const std::vector<Type_Info> &get_param_types() const { return m_types; }
|
||||
|
||||
virtual bool operator==(const Proxy_Function_Base &) const = 0;
|
||||
virtual bool call_match(const std::vector<Boxed_Value> &vals) const = 0;
|
||||
|
||||
virtual std::vector<std::shared_ptr<const Proxy_Function_Base> > get_contained_functions() const
|
||||
{
|
||||
return std::vector<std::shared_ptr<const Proxy_Function_Base> >();
|
||||
}
|
||||
|
||||
|
||||
//! Return true if the function is a possible match
|
||||
//! to the passed in values
|
||||
bool filter(const std::vector<Boxed_Value> &vals) const
|
||||
@@ -84,40 +75,51 @@ namespace chaiscript
|
||||
{
|
||||
return true;
|
||||
} else {
|
||||
return compare_first_type(vals[0]);
|
||||
}
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/// \returns the number of arguments the function takes or -1 if it is variadic
|
||||
virtual int get_arity() const = 0;
|
||||
|
||||
virtual std::string annotation() const = 0;
|
||||
|
||||
protected:
|
||||
virtual Boxed_Value do_call(const std::vector<Boxed_Value> ¶ms) const = 0;
|
||||
|
||||
Proxy_Function_Base(const std::vector<Type_Info> &t_types)
|
||||
: m_types(t_types)
|
||||
{
|
||||
}
|
||||
|
||||
virtual bool compare_first_type(const Boxed_Value &bv) const
|
||||
{
|
||||
const std::vector<Type_Info> &types = get_param_types();
|
||||
|
||||
if (types.size() < 2)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
const Type_Info &ti = types[1];
|
||||
|
||||
|
||||
if (ti.is_undef() || vals[0].get_type_info().is_undef()
|
||||
if (ti.is_undef()
|
||||
|| ti.bare_equal(user_type<Boxed_Value>())
|
||||
|| ti.bare_equal(user_type<Boxed_POD_Value>())
|
||||
|| ti.bare_equal(vals[0].get_type_info()))
|
||||
|| (!bv.get_type_info().is_undef()
|
||||
&& (ti.bare_equal(user_type<Boxed_Number>())
|
||||
|| ti.bare_equal(bv.get_type_info())
|
||||
|| chaiscript::detail::dynamic_cast_converts(ti, bv.get_type_info())
|
||||
|| bv.get_type_info().bare_equal(user_type<std::shared_ptr<const Proxy_Function_Base> >())
|
||||
)
|
||||
)
|
||||
)
|
||||
{
|
||||
return true;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
virtual int get_arity() const = 0;
|
||||
|
||||
virtual std::string annotation() const = 0;
|
||||
|
||||
protected:
|
||||
Proxy_Function_Base(const std::vector<Type_Info> &t_types)
|
||||
: m_types(t_types)
|
||||
{
|
||||
}
|
||||
|
||||
bool compare_types(const std::vector<Type_Info> &tis, const std::vector<Boxed_Value> &bvs) const
|
||||
{
|
||||
@@ -125,8 +127,8 @@ namespace chaiscript
|
||||
{
|
||||
return false;
|
||||
} else {
|
||||
const int size = bvs.size();
|
||||
for (int i = 0; i < size; ++i)
|
||||
size_t size = bvs.size();
|
||||
for (size_t i = 0; i < size; ++i)
|
||||
{
|
||||
if (!(tis[i+1].bare_equal(bvs[i].get_type_info()) && tis[i+1].is_const() >= bvs[i].get_type_info().is_const() ))
|
||||
{
|
||||
@@ -139,24 +141,32 @@ namespace chaiscript
|
||||
|
||||
std::vector<Type_Info> m_types;
|
||||
};
|
||||
}
|
||||
|
||||
typedef boost::shared_ptr<Proxy_Function_Base> Proxy_Function;
|
||||
typedef boost::shared_ptr<const Proxy_Function_Base> Const_Proxy_Function;
|
||||
/// \brief Common typedef used for passing of any registered function in ChaiScript
|
||||
typedef std::shared_ptr<dispatch::Proxy_Function_Base> Proxy_Function;
|
||||
|
||||
/**
|
||||
* Exception thrown if a function's guard fails to execute
|
||||
*/
|
||||
/// \brief Const version of Proxy_Function chaiscript. Points to a const Proxy_Function. This is how most registered functions
|
||||
/// are handled internally.
|
||||
typedef std::shared_ptr<const dispatch::Proxy_Function_Base> Const_Proxy_Function;
|
||||
|
||||
namespace exception
|
||||
{
|
||||
/// \brief Exception thrown if a function's guard fails
|
||||
class guard_error : public std::runtime_error
|
||||
{
|
||||
public:
|
||||
guard_error() throw()
|
||||
guard_error() noexcept
|
||||
: std::runtime_error("Guard evaluation failed")
|
||||
{ }
|
||||
|
||||
virtual ~guard_error() throw()
|
||||
virtual ~guard_error() noexcept
|
||||
{ }
|
||||
};
|
||||
}
|
||||
|
||||
namespace dispatch
|
||||
{
|
||||
/**
|
||||
* A Proxy_Function implementation that is not type safe, the called function
|
||||
* is expecting a vector<Boxed_Value> that it works with how it chooses.
|
||||
@@ -165,18 +175,24 @@ namespace chaiscript
|
||||
{
|
||||
public:
|
||||
Dynamic_Proxy_Function(
|
||||
const boost::function<Boxed_Value (const std::vector<Boxed_Value> &)> &t_f,
|
||||
const std::function<Boxed_Value (const std::vector<Boxed_Value> &)> &t_f,
|
||||
int t_arity=-1,
|
||||
const AST_NodePtr &t_parsenode = AST_NodePtr(),
|
||||
const std::string &t_description = "",
|
||||
const Proxy_Function &t_guard = Proxy_Function())
|
||||
: Proxy_Function_Base(build_param_type_list(t_arity)),
|
||||
m_f(t_f), m_arity(t_arity), m_description(t_description), m_guard(t_guard)
|
||||
m_f(t_f), m_arity(t_arity), m_description(t_description), m_guard(t_guard), m_parsenode(t_parsenode)
|
||||
{
|
||||
}
|
||||
|
||||
virtual bool operator==(const Proxy_Function_Base &) const
|
||||
virtual bool operator==(const Proxy_Function_Base &rhs) const
|
||||
{
|
||||
return false;
|
||||
const Dynamic_Proxy_Function *prhs = dynamic_cast<const Dynamic_Proxy_Function *>(&rhs);
|
||||
|
||||
return this == &rhs
|
||||
|| (prhs
|
||||
&& this->m_arity == prhs->m_arity
|
||||
&& !this->m_guard && !prhs->m_guard);
|
||||
}
|
||||
|
||||
virtual bool call_match(const std::vector<Boxed_Value> &vals) const
|
||||
@@ -187,7 +203,29 @@ namespace chaiscript
|
||||
|
||||
virtual ~Dynamic_Proxy_Function() {}
|
||||
|
||||
virtual Boxed_Value operator()(const std::vector<Boxed_Value> ¶ms) const
|
||||
|
||||
virtual int get_arity() const
|
||||
{
|
||||
return m_arity;
|
||||
}
|
||||
|
||||
Proxy_Function get_guard() const
|
||||
{
|
||||
return m_guard;
|
||||
}
|
||||
|
||||
AST_NodePtr get_parse_tree() const
|
||||
{
|
||||
return m_parsenode;
|
||||
}
|
||||
|
||||
virtual std::string annotation() const
|
||||
{
|
||||
return m_description;
|
||||
}
|
||||
|
||||
protected:
|
||||
virtual Boxed_Value do_call(const std::vector<Boxed_Value> ¶ms) const
|
||||
{
|
||||
if (m_arity < 0 || params.size() == size_t(m_arity))
|
||||
{
|
||||
@@ -196,24 +234,14 @@ namespace chaiscript
|
||||
{
|
||||
return m_f(params);
|
||||
} else {
|
||||
throw guard_error();
|
||||
throw exception::guard_error();
|
||||
}
|
||||
|
||||
} else {
|
||||
throw arity_error(params.size(), m_arity);
|
||||
throw exception::arity_error(static_cast<int>(params.size()), m_arity);
|
||||
}
|
||||
}
|
||||
|
||||
virtual int get_arity() const
|
||||
{
|
||||
return m_arity;
|
||||
}
|
||||
|
||||
virtual std::string annotation() const
|
||||
{
|
||||
return m_description;
|
||||
}
|
||||
|
||||
private:
|
||||
bool test_guard(const std::vector<Boxed_Value> ¶ms) const
|
||||
{
|
||||
@@ -221,9 +249,9 @@ namespace chaiscript
|
||||
{
|
||||
try {
|
||||
return boxed_cast<bool>((*m_guard)(params));
|
||||
} catch (const arity_error &) {
|
||||
} catch (const exception::arity_error &) {
|
||||
return false;
|
||||
} catch (const bad_boxed_cast &) {
|
||||
} catch (const exception::bad_boxed_cast &) {
|
||||
return false;
|
||||
}
|
||||
} else {
|
||||
@@ -235,25 +263,25 @@ namespace chaiscript
|
||||
{
|
||||
std::vector<Type_Info> types;
|
||||
|
||||
types.push_back(detail::Get_Type_Info<Boxed_Value>::get());
|
||||
// For the return type
|
||||
types.push_back(chaiscript::detail::Get_Type_Info<Boxed_Value>::get());
|
||||
|
||||
if (arity >= 0)
|
||||
if (arity > 0)
|
||||
{
|
||||
for (int i = 0; i < arity; ++i)
|
||||
{
|
||||
types.push_back(detail::Get_Type_Info<Boxed_Value>::get());
|
||||
types.push_back(chaiscript::detail::Get_Type_Info<Boxed_Value>::get());
|
||||
}
|
||||
} else {
|
||||
types.push_back(detail::Get_Type_Info<std::vector<Boxed_Value> >::get());
|
||||
}
|
||||
|
||||
return types;
|
||||
}
|
||||
|
||||
boost::function<Boxed_Value (const std::vector<Boxed_Value> &)> m_f;
|
||||
std::function<Boxed_Value (const std::vector<Boxed_Value> &)> m_f;
|
||||
int m_arity;
|
||||
std::string m_description;
|
||||
Proxy_Function m_guard;
|
||||
AST_NodePtr m_parsenode;
|
||||
};
|
||||
|
||||
/**
|
||||
@@ -275,14 +303,15 @@ namespace chaiscript
|
||||
public:
|
||||
Bound_Function(const Const_Proxy_Function &t_f,
|
||||
const std::vector<Boxed_Value> &t_args)
|
||||
: Proxy_Function_Base(std::vector<Type_Info>()),
|
||||
m_f(t_f), m_args(t_args), m_arity(m_f->get_arity()<0?-1:(m_f->get_arity() - m_args.size()))
|
||||
: Proxy_Function_Base(build_param_type_info(t_f, t_args)),
|
||||
m_f(t_f), m_args(t_args), m_arity(t_f->get_arity()<0?-1:static_cast<int>(get_param_types().size())-1)
|
||||
{
|
||||
assert(m_f->get_arity() < 0 || m_f->get_arity() == static_cast<int>(m_args.size()));
|
||||
}
|
||||
|
||||
virtual bool operator==(const Proxy_Function_Base &) const
|
||||
virtual bool operator==(const Proxy_Function_Base &t_f) const
|
||||
{
|
||||
return false;
|
||||
return &t_f == this;
|
||||
}
|
||||
|
||||
virtual ~Bound_Function() {}
|
||||
@@ -297,6 +326,14 @@ namespace chaiscript
|
||||
return (*m_f)(build_param_list(params));
|
||||
}
|
||||
|
||||
virtual std::vector<Const_Proxy_Function> get_contained_functions() const
|
||||
{
|
||||
std::vector<Const_Proxy_Function> fs;
|
||||
fs.push_back(m_f);
|
||||
return fs;
|
||||
}
|
||||
|
||||
|
||||
std::vector<Boxed_Value> build_param_list(const std::vector<Boxed_Value> ¶ms) const
|
||||
{
|
||||
typedef std::vector<Boxed_Value>::const_iterator pitr;
|
||||
@@ -306,10 +343,10 @@ namespace chaiscript
|
||||
|
||||
std::vector<Boxed_Value> args;
|
||||
|
||||
while (true)
|
||||
while (!(parg == params.end() && barg == m_args.end()))
|
||||
{
|
||||
while (barg != m_args.end()
|
||||
&& !(barg->get_type_info() == detail::Get_Type_Info<Placeholder_Object>::get()))
|
||||
&& !(barg->get_type_info() == chaiscript::detail::Get_Type_Info<Placeholder_Object>::get()))
|
||||
{
|
||||
args.push_back(*barg);
|
||||
++barg;
|
||||
@@ -322,15 +359,10 @@ namespace chaiscript
|
||||
}
|
||||
|
||||
if (barg != m_args.end()
|
||||
&& barg->get_type_info() == detail::Get_Type_Info<Placeholder_Object>::get())
|
||||
&& barg->get_type_info() == chaiscript::detail::Get_Type_Info<Placeholder_Object>::get())
|
||||
{
|
||||
++barg;
|
||||
}
|
||||
|
||||
if (parg == params.end() && barg == m_args.end())
|
||||
{
|
||||
break;
|
||||
}
|
||||
}
|
||||
return args;
|
||||
}
|
||||
@@ -342,7 +374,36 @@ namespace chaiscript
|
||||
|
||||
virtual std::string annotation() const
|
||||
{
|
||||
return "";
|
||||
return "Bound: " + m_f->annotation();
|
||||
}
|
||||
|
||||
protected:
|
||||
static std::vector<Type_Info> build_param_type_info(const Const_Proxy_Function &t_f,
|
||||
const std::vector<Boxed_Value> &t_args)
|
||||
{
|
||||
assert(t_f->get_arity() < 0 || t_f->get_arity() == static_cast<int>(t_args.size()));
|
||||
|
||||
if (t_f->get_arity() < 0) { return std::vector<Type_Info>(); }
|
||||
|
||||
std::vector<Type_Info> types = t_f->get_param_types();
|
||||
assert(types.size() == t_args.size() + 1);
|
||||
|
||||
std::vector<Type_Info> retval;
|
||||
retval.push_back(types[0]);
|
||||
for (size_t i = 0; i < types.size()-1; ++i)
|
||||
{
|
||||
if (t_args[i].get_type_info() == chaiscript::detail::Get_Type_Info<Placeholder_Object>::get())
|
||||
{
|
||||
retval.push_back(types[i+1]);
|
||||
}
|
||||
}
|
||||
|
||||
return retval;
|
||||
}
|
||||
|
||||
virtual Boxed_Value do_call(const std::vector<Boxed_Value> ¶ms) const
|
||||
{
|
||||
return (*m_f)(build_param_list(params));
|
||||
}
|
||||
|
||||
private:
|
||||
@@ -353,15 +414,15 @@ namespace chaiscript
|
||||
|
||||
/**
|
||||
* The standard typesafe function call implementation of Proxy_Function
|
||||
* It takes a boost::function<> object and performs runtime
|
||||
* It takes a std::function<> object and performs runtime
|
||||
* type checking of Boxed_Value parameters, in a type safe manner
|
||||
*/
|
||||
template<typename Func>
|
||||
class Proxy_Function_Impl : public Proxy_Function_Base
|
||||
{
|
||||
public:
|
||||
Proxy_Function_Impl(const boost::function<Func> &f)
|
||||
: Proxy_Function_Base(build_param_type_list(static_cast<Func *>(0))),
|
||||
Proxy_Function_Impl(const std::function<Func> &f)
|
||||
: Proxy_Function_Base(detail::build_param_type_list(static_cast<Func *>(0))),
|
||||
m_f(f), m_dummy_func(0)
|
||||
{
|
||||
}
|
||||
@@ -370,25 +431,15 @@ namespace chaiscript
|
||||
|
||||
virtual bool operator==(const Proxy_Function_Base &t_func) const
|
||||
{
|
||||
try {
|
||||
dynamic_cast<const Proxy_Function_Impl<Func> &>(t_func);
|
||||
return true;
|
||||
} catch (const std::bad_cast &) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
virtual Boxed_Value operator()(const std::vector<Boxed_Value> ¶ms) const
|
||||
{
|
||||
return Do_Call<typename boost::function<Func>::result_type>::go(m_f, params);
|
||||
const Proxy_Function_Impl *pimpl = dynamic_cast<const Proxy_Function_Impl<Func> *>(&t_func);
|
||||
return pimpl != 0;
|
||||
}
|
||||
|
||||
virtual int get_arity() const
|
||||
{
|
||||
return m_types.size() - 1;
|
||||
return static_cast<int>(m_types.size()) - 1;
|
||||
}
|
||||
|
||||
|
||||
virtual bool call_match(const std::vector<Boxed_Value> &vals) const
|
||||
{
|
||||
if (int(vals.size()) != get_arity())
|
||||
@@ -396,7 +447,7 @@ namespace chaiscript
|
||||
return false;
|
||||
}
|
||||
|
||||
return compare_types(m_types, vals) || compare_types_cast(m_dummy_func, vals);
|
||||
return compare_types(m_types, vals) || detail::compare_types_cast(m_dummy_func, vals);
|
||||
}
|
||||
|
||||
virtual std::string annotation() const
|
||||
@@ -404,8 +455,19 @@ namespace chaiscript
|
||||
return "";
|
||||
}
|
||||
|
||||
std::function<Func> internal_function() const
|
||||
{
|
||||
return m_f;
|
||||
}
|
||||
|
||||
protected:
|
||||
virtual Boxed_Value do_call(const std::vector<Boxed_Value> ¶ms) const
|
||||
{
|
||||
return detail::Do_Call<typename std::function<Func>::result_type>::go(m_f, params);
|
||||
}
|
||||
|
||||
private:
|
||||
boost::function<Func> m_f;
|
||||
std::function<Func> m_f;
|
||||
Func *m_dummy_func;
|
||||
};
|
||||
|
||||
@@ -426,32 +488,16 @@ namespace chaiscript
|
||||
|
||||
virtual bool operator==(const Proxy_Function_Base &t_func) const
|
||||
{
|
||||
try {
|
||||
const Attribute_Access<T, Class> &aa
|
||||
= dynamic_cast<const Attribute_Access<T, Class> &>(t_func);
|
||||
return m_attr == aa.m_attr;
|
||||
} catch (const std::bad_cast &) {
|
||||
const Attribute_Access<T, Class> * aa
|
||||
= dynamic_cast<const Attribute_Access<T, Class> *>(&t_func);
|
||||
|
||||
if (aa) {
|
||||
return m_attr == aa->m_attr;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
virtual Boxed_Value operator()(const std::vector<Boxed_Value> ¶ms) const
|
||||
{
|
||||
if (params.size() == 1)
|
||||
{
|
||||
const Boxed_Value &bv = params[0];
|
||||
if (bv.is_const())
|
||||
{
|
||||
const Class *o = boxed_cast<const Class *>(bv);
|
||||
return Handle_Return<typename boost::add_reference<T>::type>::handle(o->*m_attr);
|
||||
} else {
|
||||
Class *o = boxed_cast<Class *>(bv);
|
||||
return Handle_Return<typename boost::add_reference<T>::type>::handle(o->*m_attr);
|
||||
}
|
||||
} else {
|
||||
throw arity_error(params.size(), 1);
|
||||
}
|
||||
}
|
||||
|
||||
virtual int get_arity() const
|
||||
{
|
||||
@@ -473,37 +519,58 @@ namespace chaiscript
|
||||
return "";
|
||||
}
|
||||
|
||||
protected:
|
||||
virtual Boxed_Value do_call(const std::vector<Boxed_Value> ¶ms) const
|
||||
{
|
||||
if (params.size() == 1)
|
||||
{
|
||||
const Boxed_Value &bv = params[0];
|
||||
if (bv.is_const())
|
||||
{
|
||||
const Class *o = boxed_cast<const Class *>(bv);
|
||||
return detail::Handle_Return<typename std::add_lvalue_reference<T>::type>::handle(o->*m_attr);
|
||||
} else {
|
||||
Class *o = boxed_cast<Class *>(bv);
|
||||
return detail::Handle_Return<typename std::add_lvalue_reference<T>::type>::handle(o->*m_attr);
|
||||
}
|
||||
} else {
|
||||
throw exception::arity_error(static_cast<int>(params.size()), 1);
|
||||
}
|
||||
}
|
||||
|
||||
private:
|
||||
static std::vector<Type_Info> param_types()
|
||||
{
|
||||
std::vector<Type_Info> v;
|
||||
v.push_back(user_type<T>());
|
||||
v.push_back(user_type<Class>());
|
||||
return v;
|
||||
return {user_type<T>(), user_type<Class>()};
|
||||
}
|
||||
|
||||
T Class::* m_attr;
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Exception thrown in the case that a multi method dispatch fails
|
||||
* because no matching function was found
|
||||
* at runtime due to either an arity_error, a guard_error or a bad_boxed_cast
|
||||
* exception
|
||||
*/
|
||||
struct dispatch_error : std::runtime_error
|
||||
namespace exception
|
||||
{
|
||||
dispatch_error() throw()
|
||||
: std::runtime_error("No matching function to dispatch to")
|
||||
/// \brief Exception thrown in the case that a method dispatch fails
|
||||
/// because no matching function was found
|
||||
///
|
||||
/// May be thrown due to an arity_error, a guard_error or a bad_boxed_cast
|
||||
/// exception
|
||||
class dispatch_error : public std::runtime_error
|
||||
{
|
||||
public:
|
||||
dispatch_error(const std::vector<Boxed_Value> &t_bvs)
|
||||
: std::runtime_error("Error with function dispatch"), parameters(t_bvs)
|
||||
{
|
||||
}
|
||||
|
||||
dispatch_error(bool is_const) throw()
|
||||
: std::runtime_error(std::string("No matching function to dispatch to") + (is_const?", parameter is const":""))
|
||||
{
|
||||
}
|
||||
virtual ~dispatch_error() noexcept {}
|
||||
|
||||
virtual ~dispatch_error() throw() {}
|
||||
std::vector<Boxed_Value> parameters;
|
||||
};
|
||||
}
|
||||
|
||||
namespace dispatch
|
||||
{
|
||||
|
||||
/**
|
||||
* Take a vector of functions and a vector of parameters. Attempt to execute
|
||||
@@ -511,28 +578,28 @@ namespace chaiscript
|
||||
* function is found or throw dispatch_error if no matching function is found
|
||||
*/
|
||||
template<typename InItr>
|
||||
Boxed_Value dispatch(InItr begin, InItr end,
|
||||
Boxed_Value dispatch(InItr begin, const InItr &end,
|
||||
const std::vector<Boxed_Value> &plist)
|
||||
{
|
||||
while (begin != end)
|
||||
{
|
||||
try {
|
||||
if (begin->second->filter(plist))
|
||||
if ((*begin)->filter(plist))
|
||||
{
|
||||
return (*begin->second)(plist);
|
||||
return (*(*begin))(plist);
|
||||
}
|
||||
} catch (const bad_boxed_cast &) {
|
||||
} catch (const exception::bad_boxed_cast &) {
|
||||
//parameter failed to cast, try again
|
||||
} catch (const arity_error &) {
|
||||
} catch (const exception::arity_error &) {
|
||||
//invalid num params, try again
|
||||
} catch (const guard_error &) {
|
||||
} catch (const exception::guard_error &) {
|
||||
//guard failed to allow the function to execute,
|
||||
//try again
|
||||
}
|
||||
++begin;
|
||||
}
|
||||
|
||||
throw dispatch_error(plist.empty()?false:plist[0].is_const());
|
||||
throw exception::dispatch_error(plist);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -544,7 +611,8 @@ namespace chaiscript
|
||||
Boxed_Value dispatch(const Funcs &funcs,
|
||||
const std::vector<Boxed_Value> &plist)
|
||||
{
|
||||
return dispatch(funcs.begin(), funcs.end(), plist);
|
||||
return dispatch::dispatch(funcs.begin(), funcs.end(), plist);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@@ -1,31 +1,24 @@
|
||||
// This file is distributed under the BSD License.
|
||||
// See "license.txt" for details.
|
||||
// Copyright 2009-2010, Jonathan Turner (jturner@minnow-lang.org)
|
||||
// and Jason Turner (lefticus@gmail.com)
|
||||
// Copyright 2009-2012, Jonathan Turner (jonathan@emptycrate.com)
|
||||
// and Jason Turner (jason@emptycrate.com)
|
||||
// http://www.chaiscript.com
|
||||
|
||||
#include <boost/preprocessor.hpp>
|
||||
|
||||
#define gettypeinfo(z,n,text) ti.push_back(detail::Get_Type_Info<Param ## n>::get());
|
||||
#define casthelper(z,n,text) BOOST_PP_COMMA_IF(n) chaiscript::boxed_cast< Param ## n >(params[n])
|
||||
#define trycast(z,n,text) chaiscript::boxed_cast<Param ## n>(params[n]);
|
||||
|
||||
#ifndef BOOST_PP_IS_ITERATING
|
||||
#ifndef __proxy_functions_detail_hpp__
|
||||
#define __proxy_functions_detail_hpp__
|
||||
#ifndef CHAISCRIPT_PROXY_FUNCTIONS_DETAIL_HPP_
|
||||
#define CHAISCRIPT_PROXY_FUNCTIONS_DETAIL_HPP_
|
||||
|
||||
#include "boxed_value.hpp"
|
||||
#include "boxed_cast.hpp"
|
||||
#include "type_info.hpp"
|
||||
#include "handle_return.hpp"
|
||||
#include <string>
|
||||
#include <boost/function.hpp>
|
||||
#include <boost/bind.hpp>
|
||||
#include <boost/lexical_cast.hpp>
|
||||
|
||||
#include <stdexcept>
|
||||
#include <vector>
|
||||
|
||||
namespace chaiscript
|
||||
{
|
||||
namespace exception
|
||||
{
|
||||
/**
|
||||
* Exception thrown when there is a mismatch in number of
|
||||
@@ -39,16 +32,132 @@ namespace chaiscript
|
||||
{
|
||||
}
|
||||
|
||||
virtual ~arity_error() throw() {}
|
||||
virtual ~arity_error() noexcept {}
|
||||
|
||||
int got;
|
||||
int expected;
|
||||
};
|
||||
}
|
||||
|
||||
namespace dispatch
|
||||
{
|
||||
namespace detail
|
||||
{
|
||||
/**
|
||||
* Used by Proxy_Function_Impl to return a list of all param types
|
||||
* it contains.
|
||||
*/
|
||||
template<typename Ret, typename ... Params>
|
||||
std::vector<Type_Info> build_param_type_list(Ret (*)(Params...))
|
||||
{
|
||||
return std::vector<Type_Info> { chaiscript::detail::Get_Type_Info<Ret>::get(),
|
||||
chaiscript::detail::Get_Type_Info<Params>::get()... };
|
||||
}
|
||||
|
||||
|
||||
// Forward declaration
|
||||
template<typename ... Rest>
|
||||
struct Try_Cast;
|
||||
|
||||
// implementation
|
||||
template<typename Param, typename ... Rest>
|
||||
struct Try_Cast<Param, Rest...>
|
||||
{
|
||||
static void do_try(const std::vector<Boxed_Value> ¶ms, int generation)
|
||||
{
|
||||
boxed_cast<Param>(params[generation]);
|
||||
Try_Cast<Rest...>::do_try(params, generation+1);
|
||||
}
|
||||
};
|
||||
|
||||
// 0th case
|
||||
template<>
|
||||
struct Try_Cast<>
|
||||
{
|
||||
static void do_try(const std::vector<Boxed_Value> &, int)
|
||||
{
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Used by Proxy_Function_Impl to determine if it is equivalent to another
|
||||
* Proxy_Function_Impl object. This function is primarly used to prevent
|
||||
* registration of two functions with the exact same signatures
|
||||
*/
|
||||
template<typename Ret, typename ... Params>
|
||||
bool compare_types_cast(Ret (*)(Params...),
|
||||
const std::vector<Boxed_Value> ¶ms)
|
||||
{
|
||||
try {
|
||||
Try_Cast<Params...>::do_try(params, 0);
|
||||
} catch (const exception::bad_boxed_cast &) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
template<typename Ret, int count, typename ... Params>
|
||||
struct Call_Func
|
||||
{
|
||||
|
||||
template<typename ... InnerParams>
|
||||
static Ret do_call(const std::function<Ret (Params...)> &f,
|
||||
const std::vector<Boxed_Value> ¶ms, InnerParams &&... innerparams)
|
||||
{
|
||||
return Call_Func<Ret, count - 1, Params...>::do_call(f, params, std::forward<InnerParams>(innerparams)..., params[sizeof...(Params) - count]);
|
||||
}
|
||||
};
|
||||
|
||||
template<typename Ret, typename ... Params>
|
||||
struct Call_Func<Ret, 0, Params...>
|
||||
{
|
||||
template<typename ... InnerParams>
|
||||
static Ret do_call(const std::function<Ret (Params...)> &f,
|
||||
const std::vector<Boxed_Value> &, InnerParams &&... innerparams)
|
||||
{
|
||||
return f(boxed_cast<Params>(std::forward<InnerParams>(innerparams))...);
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Used by Proxy_Function_Impl to perform typesafe execution of a function.
|
||||
* The function attempts to unbox each paramter to the expected type.
|
||||
* if any unboxing fails the execution of the function fails and
|
||||
* the bad_boxed_cast is passed up to the caller.
|
||||
*/
|
||||
template<typename Ret, typename ... Params>
|
||||
Ret call_func(const std::function<Ret (Params...)> &f,
|
||||
const std::vector<Boxed_Value> ¶ms)
|
||||
{
|
||||
if (params.size() == sizeof...(Params))
|
||||
{
|
||||
return Call_Func<Ret, sizeof...(Params), Params...>::do_call(f, params);
|
||||
}
|
||||
|
||||
throw exception::arity_error(static_cast<int>(params.size()), sizeof...(Params));
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
|
||||
namespace chaiscript
|
||||
{
|
||||
namespace dispatch
|
||||
{
|
||||
namespace detail
|
||||
{
|
||||
template<typename Ret>
|
||||
struct Do_Call
|
||||
{
|
||||
template<typename Fun>
|
||||
static Boxed_Value go(const boost::function<Fun> &fun, const std::vector<Boxed_Value> ¶ms)
|
||||
static Boxed_Value go(const std::function<Fun> &fun, const std::vector<Boxed_Value> ¶ms)
|
||||
{
|
||||
return Handle_Return<Ret>::handle(call_func(fun, params));
|
||||
}
|
||||
@@ -58,78 +167,14 @@ namespace chaiscript
|
||||
struct Do_Call<void>
|
||||
{
|
||||
template<typename Fun>
|
||||
static Boxed_Value go(const boost::function<Fun> &fun, const std::vector<Boxed_Value> ¶ms)
|
||||
static Boxed_Value go(const std::function<Fun> &fun, const std::vector<Boxed_Value> ¶ms)
|
||||
{
|
||||
call_func(fun, params);
|
||||
return Handle_Return<void>::handle();
|
||||
};
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
#define BOOST_PP_ITERATION_LIMITS ( 0, 10 )
|
||||
#define BOOST_PP_FILENAME_1 <chaiscript/dispatchkit/proxy_functions_detail.hpp>
|
||||
#include BOOST_PP_ITERATE()
|
||||
|
||||
|
||||
# endif
|
||||
#else
|
||||
# define n BOOST_PP_ITERATION()
|
||||
|
||||
namespace chaiscript
|
||||
{
|
||||
/**
|
||||
* Used by Proxy_Function_Impl to return a list of all param types
|
||||
* it contains.
|
||||
*/
|
||||
template<typename Ret BOOST_PP_COMMA_IF(n) BOOST_PP_ENUM_PARAMS(n, typename Param) >
|
||||
std::vector<Type_Info> build_param_type_list(Ret (*)(BOOST_PP_ENUM_PARAMS(n, Param)))
|
||||
{
|
||||
std::vector<Type_Info> ti;
|
||||
ti.push_back(detail::Get_Type_Info<Ret>::get());
|
||||
|
||||
BOOST_PP_REPEAT(n, gettypeinfo, ~)
|
||||
|
||||
return ti;
|
||||
}
|
||||
|
||||
/**
|
||||
* Used by Proxy_Function_Impl to perform typesafe execution of a function.
|
||||
* The function attempts to unbox each paramter to the expected type.
|
||||
* if any unboxing fails the execution of the function fails and
|
||||
* the bad_boxed_cast is passed up to the caller.
|
||||
*/
|
||||
template<typename Ret BOOST_PP_COMMA_IF(n) BOOST_PP_ENUM_PARAMS(n, typename Param)>
|
||||
Ret call_func(const boost::function<Ret (BOOST_PP_ENUM_PARAMS(n, Param))> &f,
|
||||
const std::vector<Boxed_Value> ¶ms)
|
||||
{
|
||||
if (params.size() != n)
|
||||
{
|
||||
throw arity_error(params.size(), n);
|
||||
} else {
|
||||
return f(BOOST_PP_REPEAT(n, casthelper, ~));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Used by Proxy_Function_Impl to determine if it is equivalent to another
|
||||
* Proxy_Function_Impl object. This function is primarly used to prevent
|
||||
* registration of two functions with the exact same signatures
|
||||
*/
|
||||
template<typename Ret BOOST_PP_COMMA_IF(n) BOOST_PP_ENUM_PARAMS(n, typename Param)>
|
||||
bool compare_types_cast(Ret (*)(BOOST_PP_ENUM_PARAMS(n, Param)),
|
||||
const std::vector<Boxed_Value> & BOOST_PP_IF(n, params, ))
|
||||
{
|
||||
try {
|
||||
BOOST_PP_REPEAT(n, trycast, ~);
|
||||
} catch (const bad_boxed_cast &) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
#undef n
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
||||
|
@@ -1,58 +1,63 @@
|
||||
// This file is distributed under the BSD License.
|
||||
// See "license.txt" for details.
|
||||
// Copyright 2009-2010, Jonathan Turner (jturner@minnow-lang.org)
|
||||
// and Jason Turner (lefticus@gmail.com)
|
||||
// Copyright 2009-2012, Jonathan Turner (jonathan@emptycrate.com)
|
||||
// and Jason Turner (jason@emptycrate.com)
|
||||
// http://www.chaiscript.com
|
||||
|
||||
#ifndef __register_function_hpp__
|
||||
#define __register_function_hpp__
|
||||
#ifndef CHAISCRIPT_REGISTER_FUNCTION_HPP_
|
||||
#define CHAISCRIPT_REGISTER_FUNCTION_HPP_
|
||||
|
||||
#include "dispatchkit.hpp"
|
||||
#include "bind_first.hpp"
|
||||
#include <boost/function.hpp>
|
||||
#include <boost/bind.hpp>
|
||||
#include <boost/function_types/components.hpp>
|
||||
#include <boost/function_types/function_type.hpp>
|
||||
#include <boost/function_types/is_member_object_pointer.hpp>
|
||||
#include <boost/function_types/is_member_function_pointer.hpp>
|
||||
|
||||
namespace chaiscript
|
||||
{
|
||||
namespace dispatch
|
||||
{
|
||||
namespace detail
|
||||
{
|
||||
template<bool Object, bool MemFn>
|
||||
template<typename T>
|
||||
struct FunctionSignature
|
||||
{
|
||||
};
|
||||
|
||||
template<typename Sig>
|
||||
struct FunctionSignature<std::function<Sig> >
|
||||
{
|
||||
typedef Sig Signature;
|
||||
};
|
||||
|
||||
template<typename Ret, typename ... Args>
|
||||
std::function<Ret (Args...) > to_function(Ret (*func)(Args...))
|
||||
{
|
||||
return std::function<Ret (Args...)>(func);
|
||||
}
|
||||
|
||||
template<typename Ret, typename Class, typename ... Args>
|
||||
std::function<Ret (Class &, Args...) > to_function(Ret (Class::*func)(Args...))
|
||||
{
|
||||
return std::function<Ret (Class &, Args...)>(func);
|
||||
}
|
||||
|
||||
template<typename Ret, typename Class, typename ... Args>
|
||||
std::function<Ret (const Class &, Args...) > to_function(Ret (Class::*func)(Args...) const)
|
||||
{
|
||||
return std::function<Ret (const Class &, Args...)>(func);
|
||||
}
|
||||
|
||||
template<bool Object>
|
||||
struct Fun_Helper
|
||||
{
|
||||
template<typename T>
|
||||
static Proxy_Function go(T t)
|
||||
{
|
||||
return Proxy_Function(
|
||||
new Proxy_Function_Impl<
|
||||
typename boost::function_types::function_type<boost::function_types::components<T> >::type> (
|
||||
boost::function<
|
||||
typename boost::function_types::function_type<boost::function_types::components<T> >::type
|
||||
>(t)));
|
||||
new Proxy_Function_Impl<typename FunctionSignature<decltype(to_function(t)) >::Signature>(to_function(t)));
|
||||
}
|
||||
};
|
||||
|
||||
template<>
|
||||
struct Fun_Helper<false, true>
|
||||
{
|
||||
template<typename T>
|
||||
static Proxy_Function go(T t)
|
||||
{
|
||||
return Proxy_Function(
|
||||
new Proxy_Function_Impl<
|
||||
typename boost::function_types::function_type<boost::function_types::components<T> >::type> (
|
||||
boost::function<
|
||||
typename boost::function_types::function_type<boost::function_types::components<T> >::type
|
||||
>(boost::mem_fn(t))));
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
template<>
|
||||
struct Fun_Helper<true, false>
|
||||
struct Fun_Helper<true>
|
||||
{
|
||||
template<typename T, typename Class>
|
||||
static Proxy_Function go(T Class::* m)
|
||||
@@ -60,31 +65,100 @@ namespace chaiscript
|
||||
return Proxy_Function(new Attribute_Access<T, Class>(m));
|
||||
}
|
||||
};
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
/// \brief Creates a new Proxy_Function object from a std::function object
|
||||
/// \param[in] f std::function to expose to ChaiScript
|
||||
///
|
||||
/// \b Example:
|
||||
/// \code
|
||||
/// std::function<int (char, float, std::string)> f = get_some_function();
|
||||
/// chaiscript::ChaiScript chai;
|
||||
/// chai.add(fun(f), "some_function");
|
||||
/// \endcode
|
||||
///
|
||||
/// \sa \ref addingfunctions
|
||||
template<typename T>
|
||||
Proxy_Function fun(const boost::function<T> &f)
|
||||
Proxy_Function fun(const std::function<T> &f)
|
||||
{
|
||||
return Proxy_Function(new Proxy_Function_Impl<T>(f));
|
||||
return Proxy_Function(new dispatch::Proxy_Function_Impl<T>(f));
|
||||
}
|
||||
|
||||
/// \brief Creates a new Proxy_Function object from a free function, member function or data member
|
||||
/// \param[in] t Function / member to expose
|
||||
///
|
||||
/// \b Example:
|
||||
/// \code
|
||||
/// int myfunction(const std::string &);
|
||||
/// class MyClass
|
||||
/// {
|
||||
/// public:
|
||||
/// void memberfunction();
|
||||
/// int memberdata;
|
||||
/// };
|
||||
///
|
||||
/// chaiscript::ChaiScript chai;
|
||||
/// chai.add(fun(&myfunction), "myfunction");
|
||||
/// chai.add(fun(&MyClass::memberfunction), "memberfunction");
|
||||
/// chai.add(fun(&MyClass::memberdata), "memberdata");
|
||||
/// \endcode
|
||||
///
|
||||
/// \sa \ref addingfunctions
|
||||
template<typename T>
|
||||
Proxy_Function fun(T t)
|
||||
{
|
||||
return detail::Fun_Helper<boost::function_types::is_member_object_pointer<T>::value, boost::function_types::is_member_function_pointer<T>::value>::go(t);
|
||||
return dispatch::detail::Fun_Helper<std::is_member_object_pointer<T>::value>::go(t);
|
||||
}
|
||||
|
||||
/// \brief Creates a new Proxy_Function object from a free function, member function or data member and binds the first parameter of it
|
||||
/// \param[in] t Function / member to expose
|
||||
/// \param[in] q Value to bind to first parameter
|
||||
///
|
||||
/// \b Example:
|
||||
/// \code
|
||||
/// struct MyClass
|
||||
/// {
|
||||
/// void memberfunction(int);
|
||||
/// };
|
||||
///
|
||||
/// MyClass obj;
|
||||
/// chaiscript::ChaiScript chai;
|
||||
/// // Add function taking only one argument, an int, and permanently bound to "obj"
|
||||
/// chai.add(fun(&MyClass::memberfunction, std::ref(obj)), "memberfunction");
|
||||
/// \endcode
|
||||
///
|
||||
/// \sa \ref addingfunctions
|
||||
template<typename T, typename Q>
|
||||
Proxy_Function fun(T t, const Q &q)
|
||||
{
|
||||
return fun(bind_first(t, q));
|
||||
return fun(detail::bind_first(t, q));
|
||||
}
|
||||
|
||||
/// \brief Creates a new Proxy_Function object from a free function or member function and binds the first and second parameters of it
|
||||
/// \param[in] t Function / member to expose
|
||||
/// \param[in] q Value to bind to first parameter
|
||||
/// \param[in] r Value to bind to second parameter
|
||||
///
|
||||
/// \b Example:
|
||||
/// \code
|
||||
/// struct MyClass
|
||||
/// {
|
||||
/// void memberfunction(int);
|
||||
/// };
|
||||
///
|
||||
/// MyClass obj;
|
||||
/// chaiscript::ChaiScript chai;
|
||||
/// // Add function taking only no arguments, and permanently bound to "obj" and "1"
|
||||
/// // memberfunction() will be equivalent to obj.memberfunction(1)
|
||||
/// chai.add(fun(&MyClass::memberfunction, std::ref(obj), 1), "memberfunction");
|
||||
/// \endcode
|
||||
///
|
||||
/// \sa \ref addingfunctions
|
||||
template<typename T, typename Q, typename R>
|
||||
Proxy_Function fun(T t, const Q &q, const R &r)
|
||||
{
|
||||
return fun(bind_first(bind_first(t, q), r));
|
||||
return fun(detail::bind_first(detail::bind_first(t, q), r));
|
||||
}
|
||||
|
||||
}
|
||||
|
@@ -1,62 +1,69 @@
|
||||
// This file is distributed under the BSD License.
|
||||
// See "license.txt" for details.
|
||||
// Copyright 2009-2010, Jonathan Turner (jturner@minnow-lang.org)
|
||||
// and Jason Turner (lefticus@gmail.com)
|
||||
// Copyright 2009-2012, Jonathan Turner (jonathan@emptycrate.com)
|
||||
// and Jason Turner (jason@emptycrate.com)
|
||||
// http://www.chaiscript.com
|
||||
|
||||
#ifndef __type_info_hpp__
|
||||
#define __type_info_hpp__
|
||||
#ifndef CHAISCRIPT_TYPE_INFO_HPP_
|
||||
#define CHAISCRIPT_TYPE_INFO_HPP_
|
||||
|
||||
#include <boost/type_traits/is_const.hpp>
|
||||
#include <boost/type_traits/is_void.hpp>
|
||||
#include <boost/type_traits/is_reference.hpp>
|
||||
#include <boost/type_traits/is_pointer.hpp>
|
||||
#include <boost/type_traits/remove_const.hpp>
|
||||
#include <boost/type_traits/remove_reference.hpp>
|
||||
#include <boost/type_traits/remove_pointer.hpp>
|
||||
#include <boost/ref.hpp>
|
||||
#include <string>
|
||||
#include <typeinfo>
|
||||
#include <memory>
|
||||
#include <type_traits>
|
||||
|
||||
namespace chaiscript
|
||||
{
|
||||
/**
|
||||
* compile time deduced information about a type
|
||||
*/
|
||||
|
||||
namespace detail
|
||||
{
|
||||
template<typename T>
|
||||
struct Bare_Type
|
||||
{
|
||||
typedef typename std::remove_cv<typename std::remove_pointer<typename std::remove_reference<T>::type>::type>::type type;
|
||||
};
|
||||
}
|
||||
|
||||
/// \brief Compile time deduced information about a type
|
||||
class Type_Info
|
||||
{
|
||||
public:
|
||||
Type_Info(bool t_is_const, bool t_is_reference, bool t_is_pointer, bool t_is_void,
|
||||
const std::type_info *t_ti, const std::type_info *t_bareti)
|
||||
: m_is_const(t_is_const), m_is_reference(t_is_reference), m_is_pointer(t_is_pointer),
|
||||
m_is_void(t_is_void),
|
||||
m_type_info(t_ti), m_bare_type_info(t_bareti),
|
||||
bool t_is_arithmetic, const std::type_info *t_ti, const std::type_info *t_bareti)
|
||||
: m_type_info(t_ti), m_bare_type_info(t_bareti),
|
||||
m_is_const(t_is_const), m_is_reference(t_is_reference), m_is_pointer(t_is_pointer),
|
||||
m_is_void(t_is_void), m_is_arithmetic(t_is_arithmetic),
|
||||
m_is_undef(false)
|
||||
{
|
||||
}
|
||||
|
||||
Type_Info()
|
||||
: m_is_const(false), m_is_reference(false), m_is_pointer(false),
|
||||
m_is_void(false), m_type_info(0), m_bare_type_info(0),
|
||||
: m_type_info(0), m_bare_type_info(0),
|
||||
m_is_const(false), m_is_reference(false), m_is_pointer(false),
|
||||
m_is_void(false), m_is_arithmetic(false),
|
||||
m_is_undef(true)
|
||||
{
|
||||
}
|
||||
|
||||
Type_Info(const Type_Info &ti)
|
||||
: 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_type_info(ti.m_type_info),
|
||||
: 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)
|
||||
{
|
||||
}
|
||||
|
||||
Type_Info &operator=(const Type_Info &ti)
|
||||
{
|
||||
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_type_info = ti.m_type_info;
|
||||
m_bare_type_info = ti.m_bare_type_info;
|
||||
m_is_arithmetic = ti.m_is_arithmetic;
|
||||
m_is_undef = ti.m_is_undef;
|
||||
return *this;
|
||||
}
|
||||
@@ -86,6 +93,7 @@ namespace chaiscript
|
||||
bool is_const() const { return m_is_const; }
|
||||
bool is_reference() const { return m_is_reference; }
|
||||
bool is_void() const { return m_is_void; }
|
||||
bool is_arithmetic() const { return m_is_arithmetic; }
|
||||
bool is_undef() const { return m_is_undef || m_bare_type_info == 0; }
|
||||
bool is_pointer() const { return m_is_pointer; }
|
||||
|
||||
@@ -110,12 +118,13 @@ namespace chaiscript
|
||||
}
|
||||
|
||||
private:
|
||||
const std::type_info *m_type_info;
|
||||
const std::type_info *m_bare_type_info;
|
||||
bool m_is_const;
|
||||
bool m_is_reference;
|
||||
bool m_is_pointer;
|
||||
bool m_is_void;
|
||||
const std::type_info *m_type_info;
|
||||
const std::type_info *m_bare_type_info;
|
||||
bool m_is_arithmetic;
|
||||
bool m_is_undef;
|
||||
};
|
||||
|
||||
@@ -127,59 +136,109 @@ namespace chaiscript
|
||||
template<typename T>
|
||||
struct Get_Type_Info
|
||||
{
|
||||
typedef T type;
|
||||
|
||||
static Type_Info get()
|
||||
{
|
||||
return Type_Info(boost::is_const<T>::value, boost::is_reference<T>::value, boost::is_pointer<T>::value,
|
||||
boost::is_void<T>::value,
|
||||
return Type_Info(std::is_const<typename std::remove_pointer<typename std::remove_reference<T>::type>::type>::value, std::is_reference<T>::value, std::is_pointer<T>::value,
|
||||
std::is_void<T>::value,
|
||||
std::is_arithmetic<T>::value && !std::is_same<typename std::remove_const<T>::type, bool>::value,
|
||||
&typeid(T),
|
||||
&typeid(typename boost::remove_const<typename boost::remove_pointer<typename boost::remove_reference<T>::type>::type>::type));
|
||||
&typeid(typename Bare_Type<T>::type));
|
||||
}
|
||||
};
|
||||
|
||||
template<typename T>
|
||||
struct Get_Type_Info<boost::shared_ptr<T> >
|
||||
struct Get_Type_Info<std::shared_ptr<T> >
|
||||
{
|
||||
typedef T type;
|
||||
|
||||
static Type_Info get()
|
||||
{
|
||||
return Type_Info(boost::is_const<T>::value, boost::is_reference<T>::value, boost::is_pointer<T>::value,
|
||||
boost::is_void<T>::value,
|
||||
&typeid(boost::shared_ptr<T> ),
|
||||
&typeid(typename boost::remove_const<typename boost::remove_pointer<typename boost::remove_reference<T>::type>::type>::type));
|
||||
return Type_Info(std::is_const<T>::value, std::is_reference<T>::value, std::is_pointer<T>::value,
|
||||
std::is_void<T>::value,
|
||||
std::is_arithmetic<T>::value && !std::is_same<typename std::remove_const<T>::type, bool>::value,
|
||||
&typeid(std::shared_ptr<T> ),
|
||||
&typeid(typename Bare_Type<T>::type));
|
||||
}
|
||||
};
|
||||
|
||||
template<typename T>
|
||||
struct Get_Type_Info<const boost::shared_ptr<T> &>
|
||||
struct Get_Type_Info<const std::shared_ptr<T> &>
|
||||
{
|
||||
typedef T type;
|
||||
|
||||
static Type_Info get()
|
||||
{
|
||||
return Type_Info(boost::is_const<T>::value, boost::is_reference<T>::value, boost::is_pointer<T>::value,
|
||||
boost::is_void<T>::value,
|
||||
&typeid(const boost::shared_ptr<T> &),
|
||||
&typeid(typename boost::remove_const<typename boost::remove_pointer<typename boost::remove_reference<T>::type>::type>::type));
|
||||
return Type_Info(std::is_const<T>::value, std::is_reference<T>::value, std::is_pointer<T>::value,
|
||||
std::is_void<T>::value,
|
||||
std::is_arithmetic<T>::value && !std::is_same<typename std::remove_const<T>::type, bool>::value,
|
||||
&typeid(const std::shared_ptr<T> &),
|
||||
&typeid(typename Bare_Type<T>::type));
|
||||
}
|
||||
};
|
||||
|
||||
template<typename T>
|
||||
struct Get_Type_Info<boost::reference_wrapper<T> >
|
||||
struct Get_Type_Info<std::reference_wrapper<T> >
|
||||
{
|
||||
typedef T type;
|
||||
|
||||
static Type_Info get()
|
||||
{
|
||||
return Type_Info(boost::is_const<T>::value, boost::is_reference<T>::value, boost::is_pointer<T>::value,
|
||||
boost::is_void<T>::value,
|
||||
&typeid(boost::reference_wrapper<T> ),
|
||||
&typeid(typename boost::remove_const<typename boost::remove_pointer<typename boost::remove_reference<T>::type>::type>::type));
|
||||
return Type_Info(std::is_const<T>::value, std::is_reference<T>::value, std::is_pointer<T>::value,
|
||||
std::is_void<T>::value,
|
||||
std::is_arithmetic<T>::value && !std::is_same<typename std::remove_const<T>::type, bool>::value,
|
||||
&typeid(std::reference_wrapper<T> ),
|
||||
&typeid(typename Bare_Type<T>::type));
|
||||
}
|
||||
};
|
||||
|
||||
template<typename T>
|
||||
struct Get_Type_Info<const std::reference_wrapper<T> &>
|
||||
{
|
||||
typedef T type;
|
||||
|
||||
static Type_Info get()
|
||||
{
|
||||
return Type_Info(std::is_const<T>::value, std::is_reference<T>::value, std::is_pointer<T>::value,
|
||||
std::is_void<T>::value,
|
||||
std::is_arithmetic<T>::value && !std::is_same<typename std::remove_const<T>::type, bool>::value,
|
||||
&typeid(const std::reference_wrapper<T> &),
|
||||
&typeid(typename Bare_Type<T>::type));
|
||||
}
|
||||
};
|
||||
|
||||
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
|
||||
/// \tparam T Type of object to get a Type_Info for, derived from the passed in parameter
|
||||
/// \return Type_Info for T
|
||||
///
|
||||
/// \b Example:
|
||||
/// \code
|
||||
/// int i;
|
||||
/// chaiscript::Type_Info ti = chaiscript::user_type(i);
|
||||
/// \endcode
|
||||
template<typename T>
|
||||
Type_Info user_type(T)
|
||||
Type_Info user_type(const T &/*t*/)
|
||||
{
|
||||
return detail::Get_Type_Info<T>::get();
|
||||
}
|
||||
|
||||
|
||||
/// \brief Creates a Type_Info object representing the templated type
|
||||
/// \tparam T Type of object to get a Type_Info for
|
||||
/// \return Type_Info for T
|
||||
///
|
||||
/// \b Example:
|
||||
/// \code
|
||||
/// chaiscript::Type_Info ti = chaiscript::user_type<int>();
|
||||
/// \endcode
|
||||
template<typename T>
|
||||
Type_Info user_type()
|
||||
{
|
||||
|
130
include/chaiscript/language/chaiscript_algebraic.hpp
Normal file
130
include/chaiscript/language/chaiscript_algebraic.hpp
Normal file
@@ -0,0 +1,130 @@
|
||||
// This file is distributed under the BSD License.
|
||||
// See "license.txt" for details.
|
||||
// Copyright 2009-2012, Jonathan Turner (jonathan@emptycrate.com)
|
||||
// and Jason Turner (jason@emptycrate.com)
|
||||
// http://www.chaiscript.com
|
||||
|
||||
#ifndef CHAISCRIPT_ALGEBRAIC_HPP_
|
||||
#define CHAISCRIPT_ALGEBRAIC_HPP_
|
||||
|
||||
#include "../dispatchkit/dispatchkit.hpp"
|
||||
|
||||
namespace chaiscript
|
||||
{
|
||||
|
||||
struct Operators {
|
||||
enum Opers
|
||||
{
|
||||
boolean_flag,
|
||||
equals, less_than, greater_than, less_than_equal, greater_than_equal, not_equal,
|
||||
non_const_flag,
|
||||
assign, pre_increment, pre_decrement, assign_product, assign_sum,
|
||||
assign_quotient, assign_difference,
|
||||
non_const_int_flag,
|
||||
assign_bitwise_and, assign_bitwise_or, assign_shift_left, assign_shift_right,
|
||||
assign_remainder, assign_bitwise_xor,
|
||||
const_int_flag,
|
||||
shift_left, shift_right, remainder, bitwise_and, bitwise_or, bitwise_xor, bitwise_complement,
|
||||
const_flag,
|
||||
sum, quotient, product, difference, unary_plus, unary_minus,
|
||||
invalid
|
||||
};
|
||||
|
||||
static const char *to_string(Opers t_oper) {
|
||||
const char *opers[] = {
|
||||
"",
|
||||
"==", "<", ">", "<=", ">=", "!=",
|
||||
"",
|
||||
"=", "++", "--", "*=", "+=",
|
||||
"/=", "-=",
|
||||
"",
|
||||
"&=", "|=", "<<=", ">>=",
|
||||
"%=", "^=",
|
||||
"",
|
||||
"<<", ">>", "%", "&", "|", "^", "~",
|
||||
"",
|
||||
"+", "/", "*", "-", "+", "-",
|
||||
""
|
||||
};
|
||||
return opers[t_oper];
|
||||
}
|
||||
|
||||
static Opers to_operator(const std::string &t_str, bool t_is_unary = false)
|
||||
{
|
||||
if (t_str == "==")
|
||||
{
|
||||
return equals;
|
||||
} else if (t_str == "<") {
|
||||
return less_than;
|
||||
} else if (t_str == ">") {
|
||||
return greater_than;
|
||||
} else if (t_str == "<=") {
|
||||
return less_than_equal;
|
||||
} else if (t_str == ">=") {
|
||||
return greater_than_equal;
|
||||
} else if (t_str == "!=") {
|
||||
return not_equal;
|
||||
} else if (t_str == "=") {
|
||||
return assign;
|
||||
} else if (t_str == "++") {
|
||||
return pre_increment;
|
||||
} else if (t_str == "--") {
|
||||
return pre_decrement;
|
||||
} else if (t_str == "*=") {
|
||||
return assign_product;
|
||||
} else if (t_str == "+=") {
|
||||
return assign_sum;
|
||||
} else if (t_str == "-=") {
|
||||
return assign_difference;
|
||||
} else if (t_str == "&=") {
|
||||
return assign_bitwise_and;
|
||||
} else if (t_str == "|=") {
|
||||
return assign_bitwise_or;
|
||||
} else if (t_str == "<<=") {
|
||||
return assign_shift_left;
|
||||
} else if (t_str == ">>=") {
|
||||
return assign_shift_right;
|
||||
} else if (t_str == "%=") {
|
||||
return assign_remainder;
|
||||
} else if (t_str == "^=") {
|
||||
return assign_bitwise_xor;
|
||||
} else if (t_str == "<<") {
|
||||
return shift_left;
|
||||
} else if (t_str == ">>") {
|
||||
return shift_right;
|
||||
} else if (t_str == "%") {
|
||||
return remainder;
|
||||
} else if (t_str == "&") {
|
||||
return bitwise_and;
|
||||
} else if (t_str == "|") {
|
||||
return bitwise_or;
|
||||
} else if (t_str == "^") {
|
||||
return bitwise_xor;
|
||||
} else if (t_str == "~") {
|
||||
return bitwise_complement;
|
||||
} else if (t_str == "+") {
|
||||
if (t_is_unary) {
|
||||
return unary_plus;
|
||||
} else {
|
||||
return sum;
|
||||
}
|
||||
} else if (t_str == "-") {
|
||||
if (t_is_unary) {
|
||||
return unary_minus;
|
||||
} else {
|
||||
return difference;
|
||||
}
|
||||
} else if (t_str == "/") {
|
||||
return quotient;
|
||||
} else if (t_str == "*") {
|
||||
return product;
|
||||
} else {
|
||||
return invalid;
|
||||
}
|
||||
}
|
||||
|
||||
};
|
||||
}
|
||||
|
||||
#endif /* _CHAISCRIPT_ALGEBRAIC_HPP */
|
||||
|
@@ -1,148 +1,380 @@
|
||||
// This file is distributed under the BSD License.
|
||||
// See "license.txt" for details.
|
||||
// Copyright 2009-2010, Jonathan Turner (jturner@minnow-lang.org)
|
||||
// and Jason Turner (lefticus@gmail.com)
|
||||
// Copyright 2009-2012, Jonathan Turner (jonathan@emptycrate.com)
|
||||
// and Jason Turner (jason@emptycrate.com)
|
||||
// http://www.chaiscript.com
|
||||
|
||||
#ifndef _CHAISCRIPT_COMMON_HPP
|
||||
#define _CHAISCRIPT_COMMON_HPP
|
||||
#ifndef CHAISCRIPT_COMMON_HPP_
|
||||
#define CHAISCRIPT_COMMON_HPP_
|
||||
|
||||
|
||||
#ifdef BOOST_HAS_DECLSPEC
|
||||
#define CHAISCRIPT_MODULE_EXPORT extern "C" __declspec(dllexport)
|
||||
#else
|
||||
#define CHAISCRIPT_MODULE_EXPORT extern "C"
|
||||
#endif
|
||||
#include <sstream>
|
||||
#include "../dispatchkit/dispatchkit.hpp"
|
||||
|
||||
namespace chaiscript
|
||||
{
|
||||
/// Signature of module entry point that all binary loadable modules must implement.
|
||||
typedef ModulePtr (*Create_Module_Func)();
|
||||
|
||||
/**
|
||||
* Types of AST nodes available to the parser and eval
|
||||
*/
|
||||
class Token_Type { public: enum Type { Error, Int, Float, Id, Char, Str, Eol, Fun_Call, Inplace_Fun_Call, Arg_List, Variable, Equation, Var_Decl,
|
||||
Comparison, Additive, Multiplicative, Array_Call, Dot_Access, Quoted_String, Single_Quoted_String,
|
||||
|
||||
/// Types of AST nodes available to the parser and eval
|
||||
class AST_Node_Type {
|
||||
public:
|
||||
enum Type { Error, Int, Float, Id, Char, Str, Eol, Fun_Call, Inplace_Fun_Call, Arg_List, Variable, Equation, Var_Decl,
|
||||
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, Map_Pair, Value_Range,
|
||||
Inline_Range, Annotation, Try, Catch, Finally, Method, Attr_Decl, Shift, Equality, Bitwise_And, Bitwise_Xor, Bitwise_Or,
|
||||
Logical_And, Logical_Or}; };
|
||||
Logical_And, Logical_Or, Reference, Switch, Case, Default, Ternary_Cond
|
||||
};
|
||||
};
|
||||
|
||||
namespace
|
||||
{
|
||||
/**
|
||||
* Helper lookup to get the name of each node type
|
||||
*/
|
||||
const char *token_type_to_string(int tokentype) {
|
||||
const char *token_types[] = { "Internal Parser Error", "Int", "Float", "Id", "Char", "Str", "Eol", "Fun_Call", "Inplace_Fun_Call", "Arg_List", "Variable", "Equation", "Var_Decl",
|
||||
"Comparison", "Additive", "Multiplicative", "Array_Call", "Dot_Access", "Quoted_String", "Single_Quoted_String",
|
||||
const char *ast_node_type_to_string(int ast_node_type) {
|
||||
const char *ast_node_types[] = { "Internal Parser Error", "Int", "Float", "Id", "Char", "Str", "Eol", "Fun_Call", "Inplace_Fun_Call", "Arg_List", "Variable", "Equation", "Var_Decl",
|
||||
"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", "Map_Pair", "Value_Range",
|
||||
"Inline_Range", "Annotation", "Try", "Catch", "Finally", "Method", "Attr_Decl", "Shift", "Equality", "Bitwise_And", "Bitwise_Xor", "Bitwise_Or",
|
||||
"Logical_And", "Logical_Or"};
|
||||
"Logical_And", "Logical_Or", "Reference", "Switch", "Case", "Default", "Ternary Condition"};
|
||||
|
||||
return token_types[tokentype];
|
||||
return ast_node_types[ast_node_type];
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Convenience type for file positions
|
||||
*/
|
||||
/// \brief Convenience type for file positions
|
||||
struct File_Position {
|
||||
int line;
|
||||
int column;
|
||||
|
||||
File_Position(int file_line, int file_column)
|
||||
: line(file_line), column(file_column) { }
|
||||
File_Position(int t_file_line, int t_file_column)
|
||||
: line(t_file_line), column(t_file_column) { }
|
||||
|
||||
File_Position() : line(0), column(0) { }
|
||||
};
|
||||
|
||||
typedef boost::shared_ptr<struct Token> TokenPtr;
|
||||
/// \brief Typedef for pointers to AST_Node objects. Used in building of the AST_Node tree
|
||||
typedef std::shared_ptr<struct AST_Node> AST_NodePtr;
|
||||
|
||||
/**
|
||||
* The struct that doubles as both a parser token and an AST node
|
||||
*/
|
||||
struct Token {
|
||||
std::string text;
|
||||
int identifier;
|
||||
const char *filename;
|
||||
File_Position start, end;
|
||||
bool is_cached;
|
||||
Boxed_Value cached_value;
|
||||
|
||||
std::vector<TokenPtr> children;
|
||||
TokenPtr annotation;
|
||||
|
||||
Token(const std::string &token_text, int id, const char *fname) :
|
||||
text(token_text), identifier(id), filename(fname), is_cached(false) { }
|
||||
|
||||
Token(const std::string &token_text, int id, const char *fname, int start_line, int start_col, int end_line, int end_col) :
|
||||
text(token_text), identifier(id), filename(fname), is_cached(false) {
|
||||
|
||||
start.line = start_line;
|
||||
start.column = start_col;
|
||||
end.line = end_line;
|
||||
end.column = end_col;
|
||||
}
|
||||
};
|
||||
|
||||
/// \brief Classes which may be thrown during error cases when ChaiScript is executing.
|
||||
namespace exception
|
||||
{
|
||||
/**
|
||||
* Errors generated during parsing or evaluation
|
||||
*/
|
||||
struct Eval_Error : public std::runtime_error {
|
||||
struct eval_error : public std::runtime_error {
|
||||
std::string reason;
|
||||
File_Position start_position;
|
||||
File_Position end_position;
|
||||
const char *filename;
|
||||
std::string filename;
|
||||
std::vector<AST_NodePtr> call_stack;
|
||||
|
||||
Eval_Error(const std::string &why, const File_Position &where, const char *fname) :
|
||||
std::runtime_error("Error: \"" + why + "\" " +
|
||||
(std::string(fname) != "__EVAL__" ? ("in '" + std::string(fname) + "' ") : "during evaluation ") +
|
||||
+ "at (" + boost::lexical_cast<std::string>(where.line) + ", " +
|
||||
boost::lexical_cast<std::string>(where.column) + ")"),
|
||||
reason(why), start_position(where), end_position(where), filename(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 chaiscript::detail::Dispatch_Engine &t_ss) noexcept :
|
||||
std::runtime_error(format(t_why, t_where, t_fname, t_parameters, t_ss)),
|
||||
reason(t_why), start_position(t_where), end_position(t_where), filename(t_fname)
|
||||
{}
|
||||
|
||||
Eval_Error(const std::string &why, const TokenPtr &where)
|
||||
: std::runtime_error("Error: \"" + why + "\" " +
|
||||
(std::string(where->filename) != "__EVAL__" ? ("in '" + std::string(where->filename) + "' ") : "during evaluation ") +
|
||||
"at (" + boost::lexical_cast<std::string>(where->start.line) + ", " +
|
||||
boost::lexical_cast<std::string>(where->start.column) + ")"),
|
||||
reason(why), start_position(where->start), end_position(where->end), filename(where->filename) {
|
||||
eval_error(const std::string &t_why,
|
||||
const std::vector<Boxed_Value> &t_parameters, const chaiscript::detail::Dispatch_Engine &t_ss) noexcept :
|
||||
std::runtime_error(format(t_why, t_parameters, t_ss)),
|
||||
reason(t_why)
|
||||
{}
|
||||
|
||||
|
||||
eval_error(const std::string &t_why, const File_Position &t_where, const std::string &t_fname) noexcept :
|
||||
std::runtime_error(format(t_why, t_where, t_fname)),
|
||||
reason(t_why), start_position(t_where), end_position(t_where), filename(t_fname)
|
||||
{}
|
||||
|
||||
eval_error(const std::string &t_why) noexcept
|
||||
: std::runtime_error("Error: \"" + t_why + "\" "),
|
||||
reason(t_why)
|
||||
{}
|
||||
|
||||
virtual ~eval_error() noexcept {}
|
||||
|
||||
private:
|
||||
static std::string format_why(const std::string &t_why)
|
||||
{
|
||||
return "Error: \"" + t_why + "\"";
|
||||
}
|
||||
|
||||
virtual ~Eval_Error() throw() {}
|
||||
static std::string format_parameters(const std::vector<Boxed_Value> &t_parameters,
|
||||
const chaiscript::detail::Dispatch_Engine &t_ss)
|
||||
{
|
||||
std::stringstream ss;
|
||||
ss << "With parameters: (";
|
||||
|
||||
if (!t_parameters.empty())
|
||||
{
|
||||
std::string paramstr;
|
||||
|
||||
for (const Boxed_Value &bv: t_parameters)
|
||||
{
|
||||
paramstr += (bv.is_const()?"const ":"");
|
||||
paramstr += t_ss.type_name(bv);
|
||||
paramstr += ", ";
|
||||
}
|
||||
|
||||
ss << paramstr.substr(0, paramstr.size() - 2);
|
||||
}
|
||||
ss << ")";
|
||||
|
||||
return ss.str();
|
||||
}
|
||||
|
||||
static std::string format_filename(const std::string &t_fname)
|
||||
{
|
||||
std::stringstream ss;
|
||||
|
||||
if (t_fname != "__EVAL__")
|
||||
{
|
||||
ss << "in '" << t_fname << "' ";
|
||||
} else {
|
||||
ss << "during evaluation ";
|
||||
}
|
||||
|
||||
return ss.str();
|
||||
}
|
||||
|
||||
static std::string format_location(const File_Position &t_where)
|
||||
{
|
||||
std::stringstream ss;
|
||||
ss << "at (" << t_where.line << ", " << t_where.column << ")";
|
||||
return ss.str();
|
||||
}
|
||||
|
||||
static std::string format(const std::string &t_why, const File_Position &t_where, const std::string &t_fname,
|
||||
const std::vector<Boxed_Value> &t_parameters, const chaiscript::detail::Dispatch_Engine &t_ss)
|
||||
{
|
||||
std::stringstream ss;
|
||||
|
||||
ss << format_why(t_why);
|
||||
ss << " ";
|
||||
|
||||
ss << format_parameters(t_parameters, t_ss);
|
||||
ss << " ";
|
||||
|
||||
ss << format_filename(t_fname);
|
||||
ss << " ";
|
||||
|
||||
ss << format_location(t_where);
|
||||
|
||||
return ss.str();
|
||||
}
|
||||
|
||||
static std::string format(const std::string &t_why,
|
||||
const std::vector<Boxed_Value> &t_parameters, const chaiscript::detail::Dispatch_Engine &t_ss)
|
||||
{
|
||||
std::stringstream ss;
|
||||
|
||||
ss << format_why(t_why);
|
||||
ss << " ";
|
||||
|
||||
ss << format_parameters(t_parameters, t_ss);
|
||||
ss << " ";
|
||||
|
||||
return ss.str();
|
||||
}
|
||||
|
||||
static std::string format(const std::string &t_why, const File_Position &t_where, const std::string &t_fname)
|
||||
{
|
||||
std::stringstream ss;
|
||||
|
||||
ss << format_why(t_why);
|
||||
ss << " ";
|
||||
|
||||
ss << format_filename(t_fname);
|
||||
ss << " ";
|
||||
|
||||
ss << format_location(t_where);
|
||||
|
||||
return ss.str();
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Errors generated when loading a file
|
||||
*/
|
||||
struct File_Not_Found_Error : public std::runtime_error {
|
||||
File_Not_Found_Error(const std::string &filename)
|
||||
: std::runtime_error("File Not Found: " + filename)
|
||||
struct file_not_found_error : public std::runtime_error {
|
||||
file_not_found_error(const std::string &t_filename) noexcept
|
||||
: std::runtime_error("File Not Found: " + t_filename)
|
||||
{ }
|
||||
|
||||
virtual ~File_Not_Found_Error() throw() {}
|
||||
virtual ~file_not_found_error() noexcept {}
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
|
||||
/// \brief Struct that doubles as both a parser ast_node and an AST node.
|
||||
struct AST_Node : std::enable_shared_from_this<AST_Node> {
|
||||
public:
|
||||
const std::string text;
|
||||
const int identifier; //< \todo shouldn't this be a strongly typed enum value?
|
||||
std::shared_ptr<const std::string> filename;
|
||||
File_Position start, end;
|
||||
std::vector<AST_NodePtr> children;
|
||||
AST_NodePtr annotation;
|
||||
|
||||
/**
|
||||
* Prints the contents of an AST node, including its children, recursively
|
||||
*/
|
||||
std::string to_string(std::string t_prepend = "") {
|
||||
std::ostringstream oss;
|
||||
|
||||
oss << t_prepend << "(" << ast_node_type_to_string(this->identifier) << ") "
|
||||
<< this->text << " : " << this->start.line << ", " << this->start.column << std::endl;
|
||||
|
||||
for (unsigned int j = 0; j < this->children.size(); ++j) {
|
||||
oss << this->children[j]->to_string(t_prepend + " ");
|
||||
}
|
||||
return oss.str();
|
||||
}
|
||||
|
||||
std::string internal_to_string() {
|
||||
return to_string();
|
||||
}
|
||||
|
||||
Boxed_Value eval(chaiscript::detail::Dispatch_Engine &t_e)
|
||||
{
|
||||
try {
|
||||
return eval_internal(t_e);
|
||||
} catch (exception::eval_error &ee) {
|
||||
ee.call_stack.push_back(shared_from_this());
|
||||
throw ee;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void replace_child(const AST_NodePtr &t_child, const AST_NodePtr &t_new_child)
|
||||
{
|
||||
std::replace(children.begin(), children.end(), t_child, t_new_child);
|
||||
}
|
||||
|
||||
protected:
|
||||
AST_Node(const std::string &t_ast_node_text, int t_id, const std::shared_ptr<std::string> &t_fname,
|
||||
int t_start_line, int t_start_col, int t_end_line, int t_end_col) :
|
||||
text(t_ast_node_text), identifier(t_id), filename(t_fname),
|
||||
start(t_start_line, t_start_col), end(t_end_line, t_end_col)
|
||||
{
|
||||
}
|
||||
|
||||
AST_Node(const std::string &t_ast_node_text, int t_id, const std::shared_ptr<std::string> &t_fname) :
|
||||
text(t_ast_node_text), identifier(t_id), filename(t_fname) {}
|
||||
|
||||
virtual ~AST_Node() {}
|
||||
|
||||
virtual Boxed_Value eval_internal(chaiscript::detail::Dispatch_Engine &)
|
||||
{
|
||||
throw std::runtime_error("Undispatched ast_node (internal error)");
|
||||
}
|
||||
|
||||
private:
|
||||
// Copy and assignment explicitly unimplemented
|
||||
AST_Node(const AST_Node &);
|
||||
AST_Node& operator=(const AST_Node &);
|
||||
};
|
||||
|
||||
|
||||
namespace eval
|
||||
{
|
||||
namespace detail
|
||||
{
|
||||
/**
|
||||
* Special type for returned values
|
||||
*/
|
||||
struct Return_Value {
|
||||
Boxed_Value retval;
|
||||
TokenPtr location;
|
||||
|
||||
Return_Value(const Boxed_Value &return_value, const TokenPtr where) : retval(return_value), location(where) { }
|
||||
Return_Value(const Boxed_Value &t_return_value) : retval(t_return_value) { }
|
||||
};
|
||||
|
||||
/**
|
||||
* Special type indicating a call to 'break'
|
||||
*/
|
||||
struct Break_Loop {
|
||||
TokenPtr location;
|
||||
|
||||
Break_Loop(const TokenPtr where) : location(where) { }
|
||||
Break_Loop() { }
|
||||
};
|
||||
|
||||
/// Creates a new scope then pops it on destruction
|
||||
struct Scope_Push_Pop
|
||||
{
|
||||
Scope_Push_Pop(chaiscript::detail::Dispatch_Engine &t_de)
|
||||
: m_de(t_de)
|
||||
{
|
||||
m_de.new_scope();
|
||||
}
|
||||
|
||||
~Scope_Push_Pop()
|
||||
{
|
||||
m_de.pop_scope();
|
||||
}
|
||||
|
||||
|
||||
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;
|
||||
};
|
||||
|
||||
/// Creates a new functon call and pops it on destruction
|
||||
struct Function_Push_Pop
|
||||
{
|
||||
Function_Push_Pop(chaiscript::detail::Dispatch_Engine &t_de)
|
||||
: m_de(t_de)
|
||||
{
|
||||
m_de.new_function_call();
|
||||
}
|
||||
|
||||
~Function_Push_Pop()
|
||||
{
|
||||
m_de.pop_function_call();
|
||||
}
|
||||
|
||||
void save_params(const std::vector<Boxed_Value> &t_params)
|
||||
{
|
||||
m_de.save_function_params(t_params);
|
||||
}
|
||||
|
||||
|
||||
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;
|
||||
};
|
||||
|
||||
/// Creates a new scope then pops it on destruction
|
||||
struct Stack_Push_Pop
|
||||
{
|
||||
Stack_Push_Pop(chaiscript::detail::Dispatch_Engine &t_de)
|
||||
: m_de(t_de)
|
||||
{
|
||||
m_de.new_stack();
|
||||
}
|
||||
|
||||
~Stack_Push_Pop()
|
||||
{
|
||||
m_de.pop_stack();
|
||||
}
|
||||
|
||||
|
||||
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;
|
||||
};
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#endif /* _CHAISCRIPT_COMMON_HPP */
|
||||
|
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@@ -1,7 +1,7 @@
|
||||
// This file is distributed under the BSD License.
|
||||
// See "license.txt" for details.
|
||||
// Copyright 2009-2010, Jonathan Turner (jturner@minnow-lang.org)
|
||||
// and Jason Turner (lefticus@gmail.com)
|
||||
// Copyright 2009-2012, Jonathan Turner (jonathan@emptycrate.com)
|
||||
// and Jason Turner (jason@emptycrate.com)
|
||||
// http://www.chaiscript.com
|
||||
|
||||
#ifndef CHAISCRIPT_PRELUDE_HPP_
|
||||
@@ -54,8 +54,8 @@ def push_front(container, x) : call_exists(push_front_ref, container, x) { conta
|
||||
def insert_at(container, pos, x) { container.insert_ref_at(pos, clone(x)); } \n\
|
||||
# Returns the reverse of the given container\n\
|
||||
def reverse(container) {\n\
|
||||
var retval = new(container); \n\
|
||||
var r = range(container); \n\
|
||||
auto retval = new(container); \n\
|
||||
auto r = range(container); \n\
|
||||
while (!r.empty()) { \n\
|
||||
retval.push_back(r.back()); \n\
|
||||
r.pop_back(); \n\
|
||||
@@ -82,7 +82,7 @@ def retro::pop_front() { pop_back(this.m_range) } \n\
|
||||
def retro::empty() { empty(this.m_range); } \n\
|
||||
# Performs the second value function over the container first value\n\
|
||||
def for_each(container, func) : call_exists(range, container) { \n\
|
||||
var t_range = range(container); \n\
|
||||
auto t_range = range(container); \n\
|
||||
while (!t_range.empty()) { \n\
|
||||
func(t_range.front()); \n\
|
||||
t_range.pop_front(); \n\
|
||||
@@ -93,7 +93,7 @@ def back_inserter(container) { \n\
|
||||
}\n\
|
||||
\n\
|
||||
def contains(container, item, compare_func) : call_exists(range, container) { \n\
|
||||
var t_range = range(container); \n\
|
||||
auto t_range = range(container); \n\
|
||||
while (!t_range.empty()) { \n\
|
||||
if ( compare_func(t_range.front(), item) ) { return true; } \n\
|
||||
t_range.pop_front(); \n\
|
||||
@@ -102,7 +102,7 @@ def contains(container, item, compare_func) : call_exists(range, container) { \n
|
||||
} \n\
|
||||
def contains(container, item) { return contains(container, item, eq) } \n\
|
||||
def map(container, func, inserter) : call_exists(range, container) { \n\
|
||||
var range = range(container); \n\
|
||||
auto range = range(container); \n\
|
||||
while (!range.empty()) { \n\
|
||||
inserter(func(range.front())); \n\
|
||||
range.pop_front(); \n\
|
||||
@@ -110,14 +110,14 @@ def map(container, func, inserter) : call_exists(range, container) { \n\
|
||||
} \n\
|
||||
# Performs the second value function over the container first value. Creates a new container with the results\n\
|
||||
def map(container, func) { \n\
|
||||
var retval = new(container); \n\
|
||||
auto retval = new(container); \n\
|
||||
map(container, func, back_inserter(retval));\n\
|
||||
retval;\n\
|
||||
}\n\
|
||||
# Performs the second value function over the container first value. Starts with initial and continues with each element.\n\
|
||||
def foldl(container, func, initial) : call_exists(range, container){ \n\
|
||||
var retval = initial; \n\
|
||||
var range = range(container); \n\
|
||||
auto retval = initial; \n\
|
||||
auto range = range(container); \n\
|
||||
while (!range.empty()) { \n\
|
||||
retval = (func(range.front(), retval)); \n\
|
||||
range.pop_front(); \n\
|
||||
@@ -130,18 +130,18 @@ def sum(container) { foldl(container, `+`, 0.0) } \n\
|
||||
def product(container) { foldl(container, `*`, 1.0) } \n\
|
||||
# Returns a new container with the elements of the first value concatenated with the elements of the second value\n\
|
||||
def concat(x, y) : call_exists(clone, x) { \n\
|
||||
var retval = x; \n\
|
||||
var len = y.size(); \n\
|
||||
var i = 0; \n\
|
||||
while (i < len) { \n\
|
||||
retval.push_back(y[i]); \n\
|
||||
++i; \n\
|
||||
auto retval = x; \n\
|
||||
auto inserter = back_inserter(retval); \n\
|
||||
auto range = range(y); \n\
|
||||
while (!range.empty()) { \n\
|
||||
inserter(range.front()); \n\
|
||||
range.pop_front(); \n\
|
||||
} \n\
|
||||
retval; \n\
|
||||
} \n\
|
||||
def take(container, num, inserter) : call_exists(range, container) { \n\
|
||||
var r = range(container); \n\
|
||||
var i = num; \n\
|
||||
auto r = range(container); \n\
|
||||
auto i = num; \n\
|
||||
while ((i > 0) && (!r.empty())) { \n\
|
||||
inserter(r.front()); \n\
|
||||
r.pop_front(); \n\
|
||||
@@ -150,12 +150,12 @@ def take(container, num, inserter) : call_exists(range, container) { \n\
|
||||
} \n\
|
||||
# Returns a new container with the given number of elements taken from the container\n\
|
||||
def take(container, num) {\n\
|
||||
var retval = new(container); \n\
|
||||
auto retval = new(container); \n\
|
||||
take(container, num, back_inserter(retval)); \n\
|
||||
retval; \n\
|
||||
}\n\
|
||||
def take_while(container, f, inserter) : call_exists(range, container) { \n\
|
||||
var r = range(container); \n\
|
||||
auto r = range(container); \n\
|
||||
while ((!r.empty()) && f(r.front())) { \n\
|
||||
inserter(r.front()); \n\
|
||||
r.pop_front(); \n\
|
||||
@@ -163,13 +163,13 @@ def take_while(container, f, inserter) : call_exists(range, container) { \n\
|
||||
} \n\
|
||||
# Returns a new container with the given elements match the second value function\n\
|
||||
def take_while(container, f) {\n\
|
||||
var retval = new(container); \n\
|
||||
auto retval = new(container); \n\
|
||||
take_while(container, f, back_inserter(retval)); \n\
|
||||
retval;\n\
|
||||
}\n\
|
||||
def drop(container, num, inserter) : call_exists(range, container) { \n\
|
||||
var r = range(container); \n\
|
||||
var i = num; \n\
|
||||
auto r = range(container); \n\
|
||||
auto i = num; \n\
|
||||
while ((i > 0) && (!r.empty())) { \n\
|
||||
r.pop_front(); \n\
|
||||
--i; \n\
|
||||
@@ -181,12 +181,12 @@ def drop(container, num, inserter) : call_exists(range, container) { \n\
|
||||
} \n\
|
||||
# Returns a new container with the given number of elements dropped from the given container \n\
|
||||
def drop(container, num) {\n\
|
||||
var retval = new(container); \n\
|
||||
auto retval = new(container); \n\
|
||||
drop(container, num, back_inserter(retval)); \n\
|
||||
retval; \n\
|
||||
}\n\
|
||||
def drop_while(container, f, inserter) : call_exists(range, container) { \n\
|
||||
var r = range(container); \n\
|
||||
auto r = range(container); \n\
|
||||
while ((!r.empty())&& f(r.front())) { \n\
|
||||
r.pop_front(); \n\
|
||||
} \n\
|
||||
@@ -197,14 +197,14 @@ def drop_while(container, f, inserter) : call_exists(range, container) { \n\
|
||||
} \n\
|
||||
# Returns a new container with the given elements dropped that match the second value function\n\
|
||||
def drop_while(container, f) {\n\
|
||||
var retval = new(container); \n\
|
||||
auto retval = new(container); \n\
|
||||
drop_while(container, f, back_inserter(retval)); \n\
|
||||
retval; \n\
|
||||
}\n\
|
||||
# Applies the second value function to the container. Starts with the first two elements. Expects at least 2 elements.\n\
|
||||
def reduce(container, func) : container.size() >= 2 && call_exists(range, container) { \n\
|
||||
var r = range(container); \n\
|
||||
var retval = r.front(); \n\
|
||||
auto r = range(container); \n\
|
||||
auto retval = r.front(); \n\
|
||||
r.pop_front(); \n\
|
||||
retval = func(retval, r.front()); \n\
|
||||
r.pop_front(); \n\
|
||||
@@ -216,8 +216,8 @@ def reduce(container, func) : container.size() >= 2 && call_exists(range, contai
|
||||
} \n\
|
||||
# Returns a string of the elements in container delimited by the second value string\n\
|
||||
def join(container, delim) { \n\
|
||||
var retval = ""; \n\
|
||||
var range = range(container); \n\
|
||||
auto retval = ""; \n\
|
||||
auto range = range(container); \n\
|
||||
if (!range.empty()) { \n\
|
||||
retval += to_string(range.front()); \n\
|
||||
range.pop_front(); \n\
|
||||
@@ -230,7 +230,7 @@ def join(container, delim) { \n\
|
||||
retval; \n\
|
||||
} \n\
|
||||
def filter(container, f, inserter) : call_exists(range, container) { \n\
|
||||
var r = range(container); \n\
|
||||
auto r = range(container); \n\
|
||||
while (!r.empty()) { \n\
|
||||
if (f(r.front())) { \n\
|
||||
inserter(r.front()); \n\
|
||||
@@ -240,12 +240,12 @@ def filter(container, f, inserter) : call_exists(range, container) { \n\
|
||||
} \n\
|
||||
# Returns a new Vector which match the second value function\n\
|
||||
def filter(container, f) { \n\
|
||||
var retval = new(container); \n\
|
||||
auto retval = new(container); \n\
|
||||
filter(container, f, back_inserter(retval));\n\
|
||||
retval;\n\
|
||||
}\n\
|
||||
def generate_range(x, y, inserter) { \n\
|
||||
var i = x; \n\
|
||||
auto i = x; \n\
|
||||
while (i <= y) { \n\
|
||||
inserter(i); \n\
|
||||
++i; \n\
|
||||
@@ -253,17 +253,17 @@ def generate_range(x, y, inserter) { \n\
|
||||
} \n\
|
||||
# Returns a new Vector which represents the range from the first value to the second value\n\
|
||||
def generate_range(x, y) { \n\
|
||||
var retval = Vector(); \n\
|
||||
auto retval = Vector(); \n\
|
||||
generate_range(x,y,back_inserter(retval)); \n\
|
||||
retval; \n\
|
||||
}\n\
|
||||
# Returns a new Vector with the first value to the second value as its elements\n\
|
||||
def collate(x, y) { \n\
|
||||
[x, y]; \n\
|
||||
return [x, y]; \n\
|
||||
} \n\
|
||||
def zip_with(f, x, y, inserter) : call_exists(range, x) && call_exists(range, y) { \n\
|
||||
var r_x = range(x); \n\
|
||||
var r_y = range(y); \n\
|
||||
auto r_x = range(x); \n\
|
||||
auto r_y = range(y); \n\
|
||||
while (!r_x.empty() && !r_y.empty()) { \n\
|
||||
inserter(f(r_x.front(), r_y.front())); \n\
|
||||
r_x.pop_front(); \n\
|
||||
@@ -272,7 +272,7 @@ def zip_with(f, x, y, inserter) : call_exists(range, x) && call_exists(range, y)
|
||||
} \n\
|
||||
# Returns a new Vector which joins matching elements of the second and third value with the first value function\n\
|
||||
def zip_with(f, x, y) { \n\
|
||||
var retval = Vector(); \n\
|
||||
auto retval = Vector(); \n\
|
||||
zip_with(f,x,y,back_inserter(retval)); \n\
|
||||
retval;\n\
|
||||
}\n\
|
||||
@@ -305,16 +305,16 @@ def string::find_last_not_of(list) : is_type(list, "string") { \n\
|
||||
int(find_last_not_of(this, list, -1)); \n\
|
||||
} \n\
|
||||
def string::ltrim() { \n\
|
||||
drop_while(this, fun(x) { x == ' ' || x == '\t' }); \n\
|
||||
drop_while(this, fun(x) { x == ' ' || x == '\t' || x == '\r' || x == '\n'}); \n\
|
||||
} \n\
|
||||
def string::rtrim() { \n\
|
||||
reverse(drop_while(reverse(this), fun(x) { x == ' ' || x == '\t' })); \n\
|
||||
reverse(drop_while(reverse(this), fun(x) { x == ' ' || x == '\t' || x == '\r' || x == '\n'})); \n\
|
||||
} \n\
|
||||
def string::trim() { \n\
|
||||
ltrim(rtrim(this)); \n\
|
||||
} \n\
|
||||
def find(container, value, compare_func) : call_exists(range, container) && is_type(compare_func, "function") { \n\
|
||||
var range = range(container); \n\
|
||||
def find(container, value, compare_func) : call_exists(range, container) && is_type(compare_func, "Function") { \n\
|
||||
auto range = range(container); \n\
|
||||
while (!range.empty()) { \n\
|
||||
if (compare_func(range.front(), value)) { \n\
|
||||
return range; \n\
|
||||
|
830
include/chaiscript/language/chaiscript_prelude_docs.hpp
Normal file
830
include/chaiscript/language/chaiscript_prelude_docs.hpp
Normal file
@@ -0,0 +1,830 @@
|
||||
/// This file is not technically part of the ChaiScript API. It is used solely for generating Doxygen docs
|
||||
/// regarding the ChaiScript standard runtime library.
|
||||
|
||||
/// \brief Items in this namespace exist in the ChaiScript language runtime. They are not part of the C++ API
|
||||
namespace ChaiScript_Language
|
||||
{
|
||||
|
||||
/// \page LangStandardLibraryRef ChaiScript Language Standard Libary Reference
|
||||
///
|
||||
/// ChaiScript, at its core, has some very functional programming-inspired habits. Few places show this off as clearly
|
||||
/// as the prelude, itself a name taken as a nod to the popular functional language Haskell. This prelude is available
|
||||
/// to all standard ChaiScript applications, and provides a simple foundation for using numbers, strings, and ranges
|
||||
/// (the general category of Range cs and their iteration).
|
||||
///
|
||||
|
||||
|
||||
/// \brief Generic concept of a value in ChaiScript.
|
||||
///
|
||||
/// The Object type exists merely as a concept. All objects in ChaiScript support this concept
|
||||
/// and have the following methods available to them. All objects are stored internally as chaiscript::Boxed_Value types.
|
||||
///
|
||||
/// \sa chaiscript::Boxed_Value
|
||||
class Object
|
||||
{
|
||||
public:
|
||||
/// \brief Returns the Type_Info value for this Object
|
||||
Type_Info get_type_info() const;
|
||||
|
||||
/// \brief Returns true if the Object is of the named type
|
||||
bool is_type(string) const;
|
||||
|
||||
/// \brief Returns true if the Object is of the Type_Info passed in
|
||||
bool is_type(Type_Info) const;
|
||||
|
||||
/// \brief Returns true if the Object is immutable
|
||||
bool is_var_const() const;
|
||||
|
||||
/// \brief Returns true if the Object is a pointer and the pointer is null
|
||||
bool is_var_null() const;
|
||||
|
||||
/// \brief Returns true if the Object is stored as a pointer
|
||||
bool is_var_pointer() const;
|
||||
|
||||
/// \brief Returns true if the Object is stored as a reference
|
||||
bool is_var_reference() const;
|
||||
|
||||
/// \brief Returns true if the Object does not contain a value is is undefined.
|
||||
bool is_var_undef() const;
|
||||
|
||||
/// \brief Returns the registered name of the type of the object.
|
||||
///
|
||||
/// \sa Type_Info::name();
|
||||
string type_name() const;
|
||||
};
|
||||
|
||||
/// \brief Item returned from a Range object from a Map
|
||||
class Map_Pair
|
||||
{
|
||||
public:
|
||||
/// \brief Returns the key of the Map entry
|
||||
const string first();
|
||||
|
||||
/// \brief Returns the value Object of the Map entry
|
||||
Object second();
|
||||
};
|
||||
|
||||
|
||||
/// \brief Maps strings to Objects
|
||||
///
|
||||
/// ChaiScript has a built in shortcut for generating Map objects:
|
||||
///
|
||||
/// Example:
|
||||
/// \code
|
||||
/// eval> var m = ["a":1, "b":2];
|
||||
/// [<a,1>, <b,2>]
|
||||
/// eval> m.count("a");
|
||||
/// 1
|
||||
/// eval> m.count("c");
|
||||
/// 0
|
||||
/// eval> m.size();
|
||||
/// 2
|
||||
/// \endcode
|
||||
///
|
||||
/// Implemented as std::map<Boxed_Value>
|
||||
///
|
||||
/// \sa Map_Pair
|
||||
/// \sa chaiscript::bootstrap::standard_library::map_type
|
||||
class Map
|
||||
{
|
||||
public:
|
||||
/// \brief Returns an object that implements the Range concept for the Map_Pair's in this Map
|
||||
Range range();
|
||||
|
||||
/// \brief Returns an object that implements the Const_Range concept for the Map_Pair's in this Map
|
||||
Const_Range range() const;
|
||||
|
||||
/// \brief Returns the number of elements in the Map
|
||||
int size() const;
|
||||
|
||||
/// \brief Returns the item at the given key, creating an undefined Object if the key does not yet exist in the map
|
||||
Object operator[](string);
|
||||
|
||||
/// \brief Clears the map of all items
|
||||
void clear();
|
||||
|
||||
/// \brief Returns the number of items in the Map with the given key. Returns 0 or 1 since this is not an std::multimap.
|
||||
int count(string) const;
|
||||
|
||||
/// \brief Returns true if the map contains no items
|
||||
bool empty() const;
|
||||
|
||||
};
|
||||
|
||||
|
||||
/// \brief A concept implemented by string, Vector and Map. It is convertable to Range, default constructable and back_insertable
|
||||
class Container
|
||||
{
|
||||
public:
|
||||
void push_back(Object);
|
||||
Range range();
|
||||
Const_Range range() const;
|
||||
};
|
||||
|
||||
|
||||
/// \brief Converts o into a string.
|
||||
///
|
||||
/// \code
|
||||
/// eval> to_string(3).is_type("string") <br>
|
||||
/// true<br>
|
||||
/// \endcode
|
||||
string to_string(Object o);
|
||||
|
||||
|
||||
/// \brief Prints o to the terminal, without a trailing carriage return. Applies conversions to string automatically.
|
||||
/// \code
|
||||
/// eval> puts("hi, "); puts("there")
|
||||
/// hi, thereeval>
|
||||
/// \endcode
|
||||
/// \sa to_string
|
||||
/// \sa print
|
||||
void puts(Object o);
|
||||
|
||||
|
||||
/// \brief Prints o to the terminal, with a trailing carriage return. Applies conversions to string automatically
|
||||
/// \code
|
||||
/// eval> print("hello")
|
||||
/// hello
|
||||
/// eval>
|
||||
/// \endcode
|
||||
/// \sa to_string
|
||||
/// \sa puts
|
||||
void print(Object o);
|
||||
|
||||
/// \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
|
||||
/// 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
|
||||
/// std::string of the same name.
|
||||
///
|
||||
/// \note Object and function notations are equivalent in ChaiScript. This means that
|
||||
/// \c "bob".find("b") and \c find("bob", "b") are exactly the same. Most examples below follow the
|
||||
/// second formation of the function calls.
|
||||
/// \sa \ref keyworddef for extending existing C++ classes in ChaiScript
|
||||
/// \sa chaiscript::bootstrap::standard_library::string_type
|
||||
class string
|
||||
{
|
||||
public:
|
||||
/// \brief Finds the first instance of substr.
|
||||
/// \code
|
||||
/// eval> find("abab", "ab")
|
||||
/// 0
|
||||
/// \endcode
|
||||
int find(string s) const;
|
||||
|
||||
|
||||
/// \brief Finds the last instance of substr.
|
||||
/// \code
|
||||
/// eval> rfind("abab", "ab")
|
||||
/// 2
|
||||
/// \endcode
|
||||
int rfind(string s) const;
|
||||
|
||||
/// \brief Finds the first of characters in list in the string.
|
||||
///
|
||||
/// \code
|
||||
/// eval> find_first_of("abab", "bec")
|
||||
/// 1
|
||||
/// \endcode
|
||||
int find_first_of(string list) const;
|
||||
|
||||
/// \brief Finds the last of characters in list in the string.
|
||||
///
|
||||
/// \code
|
||||
/// eval> find_last_of("abab", "bec")
|
||||
/// 3
|
||||
/// \endcode
|
||||
int find_last_of(string list) const;
|
||||
|
||||
/// \brief Finds the first non-matching character to list in the str string.
|
||||
///
|
||||
/// \code
|
||||
/// eval> find_first_not_of("abcd", "fec")
|
||||
/// 0
|
||||
/// \endcode
|
||||
int find_first_not_of(string list) const;
|
||||
|
||||
/// \brief Finds the last non-matching character to list in the list string.
|
||||
///
|
||||
/// \code
|
||||
/// eval> find_last_not_of("abcd", "fec")
|
||||
/// 3
|
||||
/// \endcode
|
||||
int find_last_not_of(string list) const;
|
||||
|
||||
/// \brief Removes whitespace from the front of the string, returning a new string
|
||||
///
|
||||
/// \note This function is implemented as a ChaiScript function using the def member function notation.
|
||||
///
|
||||
/// \code
|
||||
/// eval> ltrim(" bob")
|
||||
/// bob
|
||||
/// \endcode
|
||||
///
|
||||
/// \sa \ref keyworddef
|
||||
string lstrim() const;
|
||||
|
||||
/// \brief Removes whitespace from the back of the string, returning a new string
|
||||
///
|
||||
/// \note This function is implemented as a ChaiScript function using the def member function notation.
|
||||
///
|
||||
/// \code
|
||||
/// eval> rtrim("bob ") + "|"
|
||||
/// bob|
|
||||
/// \endcode
|
||||
///
|
||||
/// \sa \ref keyworddef
|
||||
string rtrim() const;
|
||||
|
||||
/// \brief Removes whitespace from the front and back of the string, returning a new string
|
||||
///
|
||||
/// \note This function is implemented as a ChaiScript function using the def member function notation.
|
||||
///
|
||||
/// \code
|
||||
/// eval> trim(" bob ") + "|"
|
||||
/// bob|
|
||||
/// \endcode
|
||||
///
|
||||
/// Equivalent to rtrim(ltrim(" bob "));
|
||||
///
|
||||
/// \sa \ref keyworddef
|
||||
string trim() const;
|
||||
|
||||
/// \brief Returns the character at the given index in the string, const version
|
||||
const char &operator[](int t_index) const;
|
||||
|
||||
/// \brief Returns the character at the given index in the string
|
||||
char &operator[](int t_index);
|
||||
|
||||
/// \brief Returns underlying const char * for C api compatibility
|
||||
const char *c_str() const;
|
||||
|
||||
/// \brief Returns a pointer to the raw data in the string
|
||||
const char *data() const;
|
||||
|
||||
/// \brief Resets the string to empty
|
||||
void clear();
|
||||
|
||||
/// \brief Returns true if the string is empty
|
||||
bool empty() const;
|
||||
|
||||
/// \brief Returns the size of the string in bytes.
|
||||
///
|
||||
/// This function normally returns size_t in C++. In ChaiScript the return value is cast to int
|
||||
/// for ease of use.
|
||||
int size() const;
|
||||
|
||||
/// \brief Returns an object that implements the Range concept for the characters of this string
|
||||
Range range();
|
||||
|
||||
/// \brief Returns an object that implements the Const_Range concept for the characters of this string
|
||||
Const_Range range() const;
|
||||
};
|
||||
|
||||
/// \brief A concept in ChaiScript that is implemented by \ref string, Vector and Map. It provides
|
||||
/// easy iteration over the elements in a container.
|
||||
///
|
||||
/// Implemented by the template chaiscript::bootstrap::standard_library::Bidir_Range
|
||||
///
|
||||
/// \sa Const_Range
|
||||
class Range
|
||||
{
|
||||
public:
|
||||
/// \brief Returns the last item of the range
|
||||
Object back();
|
||||
|
||||
/// \brief Returns true if the front and back pointers have passed each other, if no items
|
||||
/// are left in the Range
|
||||
bool empty() const;
|
||||
|
||||
/// \brief Returns the first item of the range
|
||||
Object front();
|
||||
|
||||
/// \brief Moves the back pointer back one.
|
||||
///
|
||||
/// \post back() returns the element at back() - 1;
|
||||
void pop_back();
|
||||
|
||||
/// \brief Moves the front pointer forward one
|
||||
///
|
||||
/// \post front() returne the element at front() + 1;
|
||||
void pop_front();
|
||||
|
||||
};
|
||||
|
||||
/// \brief A concept in ChaiScript that is implemented by \ref string, Vector and Map. It provides
|
||||
/// easy iteration over the elements in a container. Contained values are const.
|
||||
///
|
||||
/// Implemented by the template chaiscript::bootstrap::standard_library::Const_Bidir_Range
|
||||
///
|
||||
/// \sa Range
|
||||
class Const_Range
|
||||
{
|
||||
public:
|
||||
/// \brief Returns the last item of the range
|
||||
const Object back();
|
||||
|
||||
/// \brief Returns true if the front and back pointers have passed each other, if no items
|
||||
/// are left in the Range
|
||||
bool empty() const;
|
||||
|
||||
/// \brief Returns the first item of the range
|
||||
const Object front();
|
||||
|
||||
/// \brief Moves the back pointer back one.
|
||||
///
|
||||
/// \post back() returns the element at back() - 1;
|
||||
void pop_back();
|
||||
|
||||
/// \brief Moves the front pointer forward one
|
||||
///
|
||||
/// \post front() returne the element at front() + 1;
|
||||
void pop_front();
|
||||
|
||||
};
|
||||
|
||||
/// \brief A vector of Objects
|
||||
///
|
||||
/// ChaiScript includes a shortcut for creating a Vector of Objects
|
||||
///
|
||||
/// Example:
|
||||
/// \code
|
||||
/// eval> var v = [1,2,3,4]
|
||||
/// [1, 2, 3, 4]
|
||||
/// eval> v[0];
|
||||
/// 1
|
||||
/// eval> v.size();
|
||||
/// 4
|
||||
/// \endcode
|
||||
///
|
||||
/// Implemented with std::vector<chaiscript::Boxed_Value>
|
||||
///
|
||||
/// \sa chaiscript::bootstrap::standard_library::vector_type
|
||||
class Vector
|
||||
{
|
||||
public:
|
||||
/// \brief returns the Object at the given index. Throws an exception if the index does not exist
|
||||
Object operator[](int t_index);
|
||||
|
||||
/// \brief returns a const Object at the given index. Throws an exception if the index does not exist.
|
||||
const Object operator[](int t_index) const;
|
||||
|
||||
/// \brief returns the last item in the Vector
|
||||
Object back();
|
||||
|
||||
/// \brief Clears the Vector of all items
|
||||
void clear();
|
||||
|
||||
/// \brief Returns true if the Vector is contains 0 items
|
||||
bool empty();
|
||||
|
||||
/// \brief Erases the element at the given index
|
||||
void erase_at(int t_index);
|
||||
|
||||
/// \brief Returns the first item in the Vector
|
||||
Object front();
|
||||
|
||||
/// \brief Inserts a new item in the Vector at the given index. The item is not cloned on insert
|
||||
///
|
||||
/// \sa insert_ref
|
||||
void insert_ref_at(int, Object);
|
||||
|
||||
/// \brief Inserts a new item in the Vector at the given index. The item is cloned on insert
|
||||
///
|
||||
/// \sa insert_ref
|
||||
void insert_at(int, Object);
|
||||
|
||||
/// \brief Removes the last item from the Vector
|
||||
void pop_back();
|
||||
|
||||
/// \brief Adds an item to the end of the Vector. The item is not cloned.
|
||||
///
|
||||
/// \sa push_back
|
||||
void push_back_ref(Object);
|
||||
|
||||
/// \brief Adds an item to the end of the Vector. The item is cloned.
|
||||
///
|
||||
/// \sa push_back_ref
|
||||
void push_back(Object);
|
||||
|
||||
/// \brief Returns a Range object for the entire vector
|
||||
Range range();
|
||||
|
||||
/// \brief Returns a Const_Range object for the entire vector
|
||||
Const_Range range() const;
|
||||
|
||||
/// \brief Returns the number of elements in the Vector
|
||||
int size() const;
|
||||
|
||||
};
|
||||
|
||||
class Type_Info
|
||||
{
|
||||
public:
|
||||
/// \brief Compares this Type_Info object with another one and returns true if the two types are the same
|
||||
/// after const, pointer, reference are removed.
|
||||
bool bare_equal(Type_Info t_ti) const;
|
||||
|
||||
/// \brief Returns the mangled C++ name for the type given by the compiler after const, pointer, reference is removed.
|
||||
string cpp_bare_name() const;
|
||||
|
||||
/// \brief Returns the mangled C++ name for the type given by the compiler.
|
||||
string cpp_name() const;
|
||||
|
||||
/// \brief Returns true if the type is const
|
||||
bool is_type_const() const;
|
||||
|
||||
/// \brief Returns true if the type is a pointer
|
||||
bool is_type_pointer() const;
|
||||
|
||||
/// \brief Returns true if the type is a reference
|
||||
bool is_type_reference() const;
|
||||
|
||||
/// \brief Returns true if the type is undefined
|
||||
bool is_type_undef() const;
|
||||
|
||||
/// \brief Returns true if the type is "void"
|
||||
bool is_type_void() const;
|
||||
|
||||
/// \brief Returns the ChaiScript registered name for the type if one exists.
|
||||
string name() const;
|
||||
|
||||
};
|
||||
|
||||
|
||||
/// \brief Represents a function object in ChaiScript
|
||||
///
|
||||
/// A function object may be one function, such as:
|
||||
/// \code
|
||||
/// var f = fun(x) { return x; }
|
||||
/// \endcode
|
||||
///
|
||||
/// Or it may represent multiple functions
|
||||
/// \code
|
||||
/// var f2 = `-`; // represents the unary - as well as the set of binary - operators
|
||||
/// \endcode
|
||||
///
|
||||
/// Guarded function example
|
||||
/// \code
|
||||
/// def f3(x) : x > 2 {
|
||||
/// return x;
|
||||
/// }
|
||||
/// \endcode
|
||||
///
|
||||
/// Examples in the function definitions below will reference these examples
|
||||
class Function
|
||||
{
|
||||
public:
|
||||
/// \brief Returns the annotation description of the function
|
||||
string get_annotation() const;
|
||||
|
||||
/// \brief Returns the arity of the function, -1 if the function takes a variable number of parameters
|
||||
///
|
||||
/// Example:
|
||||
/// \code
|
||||
/// eval> f.get_arity()
|
||||
/// 1
|
||||
/// eval> f2.get_arity()
|
||||
/// -1
|
||||
/// \endcode
|
||||
int get_arity() const;
|
||||
|
||||
/// \brief Returns a vector of the contained functions
|
||||
///
|
||||
/// Example:
|
||||
/// \code
|
||||
/// eval> f.get_contained_functions().size()
|
||||
/// 0
|
||||
/// eval> f2.get_contained_functions().size()
|
||||
/// 11
|
||||
/// eval> var v = f2.get_contained_functions();
|
||||
/// v[0].get_arity()
|
||||
/// 2
|
||||
/// \endcode
|
||||
Vector get_contained_functions() const;
|
||||
|
||||
/// \brief Returns a vector of the contained functions
|
||||
///
|
||||
/// Example:
|
||||
/// \code
|
||||
/// eval> f.get_guard() // Throws exception
|
||||
/// Function does not have a guard
|
||||
/// eval> f3.get_guard().get_arity()
|
||||
/// 1
|
||||
/// \endcode
|
||||
Function get_guard() const;
|
||||
|
||||
/// \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.
|
||||
///
|
||||
/// If this function is a conglomeration 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
|
||||
/// the same arity, then it represents the arity. If they have different arities, it returns only
|
||||
/// one value - the return type.
|
||||
///
|
||||
/// For each parameter that is the same type, the type is returned. If the types are different
|
||||
/// then a Type_Info for Object is returned.
|
||||
///
|
||||
/// Example:
|
||||
/// \code
|
||||
/// eval> f2.get_param_types().size(); // Returns a Type_Info for Object for the return type
|
||||
/// 1
|
||||
/// \endcode
|
||||
Vector get_param_types() const;
|
||||
|
||||
/// \brief Returns true if the function has a guard to it. Always returns falls for a conglomerate function
|
||||
bool has_guard() const;
|
||||
|
||||
/// \brief Calls the function with the given set of parameters and returns the value;
|
||||
///
|
||||
/// Example:
|
||||
/// \code
|
||||
/// eval> `-`.call([2,1]);
|
||||
/// 1
|
||||
/// \endcode
|
||||
Object call(Vector t_params) const;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/// \brief Returns the max of a or b. Requires that operator>(a, b) exists
|
||||
/// Equivalent to
|
||||
/// \code
|
||||
/// return a>b?a:b;
|
||||
/// \endcode
|
||||
///
|
||||
/// Example:
|
||||
/// \code
|
||||
/// eval> max(4, 10)
|
||||
/// 10
|
||||
/// \endcode
|
||||
Object max(Object a, Object b);
|
||||
|
||||
/// \brief Returns the min of a or b. Requires that operator<(a, b) exists
|
||||
///
|
||||
/// Equivalent to
|
||||
/// \code
|
||||
/// return a<b?a:b;
|
||||
/// \endcode
|
||||
///
|
||||
/// Example:
|
||||
/// \code
|
||||
/// eval> min(4, 10)
|
||||
/// 4
|
||||
/// \endcode
|
||||
Object min(Object a, Object b);
|
||||
|
||||
/// \brief Returns true if x is an even integer.
|
||||
///
|
||||
/// Will also work on any non-integer type for which an operator%(x, int) exists
|
||||
///
|
||||
/// Example:
|
||||
/// \code
|
||||
/// eval> even(4)
|
||||
/// true
|
||||
/// \endcode
|
||||
bool even(Object x);
|
||||
|
||||
/// \brief Returns true if x is an odd integer.
|
||||
///
|
||||
/// Will also work on any non-integer type for which an operator%(x, int) exists
|
||||
///
|
||||
/// Example:
|
||||
/// \code
|
||||
/// eval> odd(4)
|
||||
/// false
|
||||
/// \endcode
|
||||
bool even(Object x);
|
||||
|
||||
|
||||
/// \brief Applies the function f over each element in the Range c.
|
||||
///
|
||||
/// Example:
|
||||
/// \code
|
||||
/// eval> for_each([1, 2, 3], print)
|
||||
/// 1
|
||||
/// 2
|
||||
/// 3
|
||||
/// \endcode
|
||||
void for_each(Range c, Function f);
|
||||
|
||||
|
||||
/// \brief Applies f over each element in the Range c, joining all the results.
|
||||
///
|
||||
/// Example:
|
||||
/// \code
|
||||
/// eval> map([1, 2, 3], odd)
|
||||
/// [true, false, true]
|
||||
/// \endcode
|
||||
Object map(Range c, Function f);
|
||||
|
||||
|
||||
/// \brief Starts with the initial value and applies the function f to it and the first element of the Range c.
|
||||
/// The result is then applied to the second element, and so on until the elements are exhausted.
|
||||
///
|
||||
/// Example:
|
||||
/// \code
|
||||
/// eval> foldl([1, 2, 3, 4], `+`, 0)
|
||||
/// 10
|
||||
/// \endcode
|
||||
Object foldl(Range c, Function f, Object initial);
|
||||
|
||||
|
||||
/// \brief Returns the sum total of the values in the Range c.
|
||||
///
|
||||
/// Example:
|
||||
/// \code
|
||||
/// eval> sum([1, 2, 3, 4])
|
||||
/// 10
|
||||
/// \endcode
|
||||
///
|
||||
/// Equivalent to:
|
||||
/// \code
|
||||
/// foldl(c, `+`, 0.0);
|
||||
/// \endcode
|
||||
Numeric sum(Range c);
|
||||
|
||||
|
||||
/// \brief Returns the product of the value in the Range c.
|
||||
///
|
||||
/// Example:
|
||||
/// \code
|
||||
/// eval> product([1, 2, 3, 4])
|
||||
/// 24
|
||||
/// \endcode
|
||||
///
|
||||
/// Equivalent to:
|
||||
/// \code
|
||||
/// foldl(c, `*`, 1.0);
|
||||
/// \endcode
|
||||
Numeric product(Range c);
|
||||
|
||||
|
||||
/// \brief Takes num elements from the Range c, returning them.
|
||||
///
|
||||
/// Example:
|
||||
/// \code
|
||||
/// eval> take([1, 2, 3, 4], 2)
|
||||
/// [1, 2]
|
||||
/// \endcode
|
||||
///
|
||||
/// \returns A container of the same type that was passed in
|
||||
Object take(Range c, int num);
|
||||
|
||||
|
||||
/// \brief Takes elements from the Range c that match function f, stopping at the first non-match, returning them as a new Vector.
|
||||
///
|
||||
/// Example:
|
||||
/// \code
|
||||
/// eval> take_while([1, 2, 3], odd)
|
||||
/// [1]
|
||||
/// \endcode
|
||||
///
|
||||
/// \returns A container of the same type that was passed in
|
||||
Object take_while(Range c, Function f);
|
||||
|
||||
|
||||
/// \brief Drops num elements from the Range c, returning the remainder.
|
||||
///
|
||||
/// Example:
|
||||
/// \code
|
||||
/// eval> drop([1, 2, 3, 4], 2)
|
||||
/// [3, 4]
|
||||
/// \endcode
|
||||
///
|
||||
/// \returns A container of the same type that was passed in
|
||||
Object drop(Range c, int num);
|
||||
|
||||
|
||||
/// \brief Drops elements from the Range c that match f, stopping at the first non-match, returning the remainder.
|
||||
///
|
||||
/// Example:
|
||||
/// \code
|
||||
/// eval> drop_while([1, 2, 3], odd)
|
||||
/// [2, 3]
|
||||
/// \endcode
|
||||
Object drop_while(Range c, Function f);
|
||||
|
||||
|
||||
/// \brief Similar to foldl, this takes the first two elements as its starting values for f. This assumes Range c has at least 2 elements.
|
||||
///
|
||||
/// Example:
|
||||
/// \code
|
||||
/// eval> reduce([1, 2, 3, 4], `+`)
|
||||
/// 10
|
||||
/// \endcode
|
||||
Object reduce(Range c, Function f);
|
||||
|
||||
|
||||
/// \brief Takes elements from Range c that match function f, return them.
|
||||
///
|
||||
/// Example:
|
||||
/// \code
|
||||
/// eval> filter([1, 2, 3, 4], odd)
|
||||
/// [1, 3]
|
||||
/// \endcode
|
||||
Object filter(Range c, Function f);
|
||||
|
||||
|
||||
/// \brief Joins the elements of the Range c into a string, delimiting each with the delim string.
|
||||
///
|
||||
/// Example:
|
||||
/// \code
|
||||
/// eval> join([1, 2, 3], "*")
|
||||
/// 1*2*3
|
||||
/// \endcode
|
||||
string join(Range c, string delim);
|
||||
|
||||
|
||||
/// \brief Returns the contents of the Container c in reversed order.
|
||||
///
|
||||
/// Example:
|
||||
/// \code
|
||||
/// eval> reverse([1, 2, 3, 4, 5, 6, 7])
|
||||
/// [7, 6, 5, 4, 3, 2, 1]
|
||||
/// \endcode
|
||||
Container reverse(Container c);
|
||||
|
||||
|
||||
/// \brief Generates a new Vector filled with values starting at x and ending with y.
|
||||
///
|
||||
/// Works on types supporting operator<=(x, y) and operator++(x)
|
||||
///
|
||||
/// Example:
|
||||
/// \code
|
||||
/// eval> generate_range(1, 10)
|
||||
/// [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
|
||||
/// \endcode
|
||||
Vector generate_range(Object x, Object y);
|
||||
|
||||
|
||||
/// \brief Returns a new Range with x and y concatenated.
|
||||
///
|
||||
/// Example:
|
||||
/// \code
|
||||
/// eval> concat([1, 2, 3], [4, 5, 6])
|
||||
/// [1, 2, 3, 4, 5, 6]
|
||||
/// \endcode
|
||||
Object concat(Range x, Range y);
|
||||
|
||||
|
||||
/// \brief Returns a new Vector with x and y as its values.
|
||||
///
|
||||
/// Example:
|
||||
/// \code
|
||||
/// eval> collate(1, 2)
|
||||
/// [1, 2]
|
||||
/// \endcode
|
||||
Vector collate(Object x, Object y);
|
||||
|
||||
|
||||
/// \brief Applies f to elements of x and y, returning a new Vector with the result of each application.
|
||||
///
|
||||
/// Example:
|
||||
/// \code
|
||||
/// eval> zip_with(`+`, [1, 2, 3], [4, 5, 6])
|
||||
/// [5, 7, 9]
|
||||
/// \endcode
|
||||
Vector zip_with(Function f, Range x, Range y);
|
||||
|
||||
|
||||
/// \brief Collates elements of x and y, returning a new Vector with the result.
|
||||
///
|
||||
/// Example:
|
||||
/// \code
|
||||
/// eval> zip([1, 2, 3], [4, 5, 6])
|
||||
/// [[1, 4], [2, 5], [3, 6]]
|
||||
/// \endcode
|
||||
Vector zip(Range x, Range y);
|
||||
|
||||
|
||||
/// \brief returns true if there exists a call to the Function f that takes the given parameters
|
||||
///
|
||||
/// Example:
|
||||
/// \code
|
||||
/// eval> call_exists(`+`, 1, 2)
|
||||
/// true
|
||||
/// \endcode
|
||||
bool call_exists(Function f, ...);
|
||||
|
||||
/// \brief Reverses a Range object so that the elements are accessed in reverse
|
||||
Range retro(Range);
|
||||
|
||||
/// \brief Reverses a Const_Range object so that the elements are accessed in reverse
|
||||
Const_Range retro(Const_Range);
|
||||
|
||||
|
||||
/// \brief Raises the given object as an exception. Any type of object can be thrown.
|
||||
///
|
||||
/// Example:
|
||||
/// \code
|
||||
/// eval> try { throw(1); } catch (e) { print("Exception caught: " + to_string(e)); }
|
||||
/// Exception caught: 1
|
||||
/// \endcode
|
||||
///
|
||||
/// \sa \ref keywordtry
|
||||
void throw(Object);
|
||||
}
|
||||
|
42
include/chaiscript/utility/utility.hpp
Normal file
42
include/chaiscript/utility/utility.hpp
Normal file
@@ -0,0 +1,42 @@
|
||||
// This file is distributed under the BSD License.
|
||||
// See "license.txt" for details.
|
||||
// Copyright 2009-2012, Jonathan Turner (jonathan@emptycrate.com)
|
||||
// and Jason Turner (jason@emptycrate.com)
|
||||
// http://www.chaiscript.com
|
||||
|
||||
#ifndef CHAISCRIPT_UTILITY_UTILITY_HPP_
|
||||
#define CHAISCRIPT_UTILITY_UTILITY_HPP_
|
||||
|
||||
#include "../chaiscript.hpp"
|
||||
#include <string>
|
||||
|
||||
|
||||
namespace chaiscript
|
||||
{
|
||||
namespace utility
|
||||
{
|
||||
|
||||
template<typename Class, typename ModuleType>
|
||||
void add_class(ModuleType &t_module,
|
||||
const std::string &t_classname,
|
||||
const std::vector<chaiscript::Proxy_Function> &t_constructors,
|
||||
const std::vector<std::pair<chaiscript::Proxy_Function, std::string>> &t_funcs)
|
||||
{
|
||||
t_module.add(chaiscript::user_type<Class>(), t_classname);
|
||||
|
||||
for(const chaiscript::Proxy_Function &ctor: t_constructors)
|
||||
{
|
||||
t_module.add(ctor, t_classname);
|
||||
}
|
||||
|
||||
for(auto fun: t_funcs)
|
||||
{
|
||||
t_module.add(fun.first, fun.second);
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
||||
|
@@ -1,4 +1,4 @@
|
||||
Copyright 2009-2010 Jason Turner and Jonathan Turner. All Rights Reserved.
|
||||
Copyright 2009-2012 Jason Turner and Jonathan Turner. All Rights Reserved.
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions are
|
||||
met:
|
||||
|
35
readme.txt
35
readme.txt
@@ -1,11 +1,11 @@
|
||||
ChaiScript v2.3.3
|
||||
ChaiScript
|
||||
http://www.chaiscript.com
|
||||
(c) 2009-2010 Jason Turner and Jonathan Turner
|
||||
(c) 2009-2012 Jason Turner and Jonathan Turner
|
||||
Release under the BSD license, see "license.txt" for details.
|
||||
|
||||
[Introduction]
|
||||
|
||||
ChaiScript is one of the first (and perhaps only) embedded scripting language designed from the ground up to directly target C++. Being a native C++ application, it has some advantages over existing embedded scripting languages:
|
||||
ChaiScript is one of the only embedded scripting language designed from the ground up to directly target C++ and take advantage of modern C++ development techniques, working with the developer like he expects it to work. Being a native C++ application, it has some advantages over existing embedded scripting languages:
|
||||
|
||||
1) It uses a header-only approach, which makes it easy to integrate with existing projects.
|
||||
2) It maintains type safety between your C++ application and the user scripts.
|
||||
@@ -13,19 +13,19 @@ ChaiScript is one of the first (and perhaps only) embedded scripting language de
|
||||
|
||||
[Requirements]
|
||||
|
||||
ChaiScript requires a recent version of Boost (http://www.boost.org) to build.
|
||||
ChaiScript requires a C++11 compiler to build with support for variadic templates. It has been tested with gcc 4.7 and clang 3.1 (with libcxx).
|
||||
|
||||
[Usage]
|
||||
|
||||
* Add the ChaiScript include directory to your project's header search path
|
||||
* Add "#include <chaiscript/chaiscript.hpp> to your source file
|
||||
* Instantiate the ChaiScript engine in your application. For example, create a new engine with the name 'chai' like so: "chaiscript::ChaiScript_Engine chai"
|
||||
* Instantiate the ChaiScript engine in your application. For example, create a new engine with the name 'chai' like so: "chaiscript::ChaiScript chai"
|
||||
|
||||
Once instantiated, the engine is ready to start running ChaiScript source. You have two main options for processing ChaiScript source: a line at a time using "chai.evaluate_string(string)" and a file at a time using "chai.evaluate_file(fname)"
|
||||
|
||||
To make functions in your C++ code visible to scripts, they must be registered with the scripting engine. To do so, call register_function:
|
||||
To make functions in your C++ code visible to scripts, they must be registered with the scripting engine. To do so, call add:
|
||||
|
||||
dispatchkit::register_function(chai.get_eval_engine(), &my_function, "my_function_name");
|
||||
chai.add(chaiscript::fun(&my_function), "my_function_name");
|
||||
|
||||
Once registered the function will be visible to scripts as "my_function_name"
|
||||
|
||||
@@ -33,4 +33,23 @@ Once registered the function will be visible to scripts as "my_function_name"
|
||||
|
||||
ChaiScript is similar to ECMAScript (aka JavaScript(tm)), but with some modifications to make it easier to use. For usage examples see the "samples" directory, and for more in-depth look at the language, the unit tests in the "unittests" directory cover the most ground.
|
||||
|
||||
For example of how to register parts of your C++ application, see "example.cpp" in the "src" directory.
|
||||
For examples of how to register parts of your C++ application, see "example.cpp" in the "src" directory. Example.cpp is verbose and shows every possible way of working with the library. For further documentation generate the doxygen documentation in the build folder or see the website http://www.chaiscript.com.
|
||||
|
||||
The shortest complete example possible follows:
|
||||
|
||||
/// main.cpp
|
||||
|
||||
#include <chaiscript/chaiscript.hpp>
|
||||
|
||||
double function(int i, double j)
|
||||
{
|
||||
return i * j;
|
||||
}
|
||||
|
||||
int main()
|
||||
{
|
||||
chaiscript::ChaiScript chai;
|
||||
chai.add(chaiscript::fun(&function), "function");
|
||||
|
||||
double d = chai.eval<double>("function(3, 4.75);");
|
||||
}
|
||||
|
58
releasenotes.txt
Normal file
58
releasenotes.txt
Normal file
@@ -0,0 +1,58 @@
|
||||
Changes since 4.0.0
|
||||
* Dropped boost in favor of C++11
|
||||
* Separated out stdlib to make more options for compile time improvements
|
||||
|
||||
Changes since 3.1.0
|
||||
* svenstaro: Unused variables and CMake consistency fixes
|
||||
* Added support for returning pointers from functions (#13)
|
||||
* Compile with -pedantic (#9)
|
||||
* Fix issues with multiple ChaiScript object types having the same attribute name (#15)
|
||||
* Prevent variable redeclaration in same scope (#22)
|
||||
* mgee: Boxed_Number improvements (#27)
|
||||
* Support switch statements (#34)
|
||||
* Fix uint16 comparions (#26)
|
||||
* Add ability to add const_var globals in Module objects (#14)
|
||||
* Add support for ternary operators ?:
|
||||
* Add headers to CMakeLists so they show up in IDEs
|
||||
* Add ability to get vector of defined objects and vector of defined functions
|
||||
* Fix memory leak in cyclical references
|
||||
* Clean up static analysis issues discovered
|
||||
* Fix vector construction to be consistent with map construction
|
||||
* Increased unit tests to 161
|
||||
* Performance enhancements
|
||||
|
||||
Changes since 3.0.0
|
||||
* Numeric operations performance increased approximately 10x
|
||||
* Looping operations performance increased up to 2x
|
||||
* Engine start up time decreased
|
||||
* Several parsing bugs related to index operators fixed
|
||||
* Added full support for all C algebraic types: double, long double, float, int, long, char,
|
||||
uint8_t, uint16_t, uint32_t, uint64_t, int8_t, int16_t, int32_t, int64_t
|
||||
* Enhanced support for capturing of exceptions thrown from ChaiScript in C++
|
||||
|
||||
Changes since 2.3.3
|
||||
|
||||
* Code simplifications
|
||||
* Fully integrate documentation with source code in doxygen style comments
|
||||
* Unit tests increased from 114 to 137
|
||||
* Automatic conversion between boost::function objects and ChaiScript functions
|
||||
* Many bug fixes
|
||||
* Minor performance improvements
|
||||
* Namespace reorganization to make end user code more accessible
|
||||
* clang support
|
||||
* VisualStudio 2010 Support
|
||||
* Support for C++ base classes and automatic upcasting
|
||||
* Remove __ reserved identifiers
|
||||
* Better code organization to reduce #ifdefs
|
||||
* clanmills: command line options for chai eval
|
||||
* clanmills: parser cleanups and code reduction
|
||||
* Function introspection and reflection
|
||||
* Correct function dispatch order to account for base classes and provide a defined order of dispatch
|
||||
* Predictable object lifetime that emulates C++ stack lifetime
|
||||
* emarcotte: pkgconfig support
|
||||
* standardize on method/member naming and indentation
|
||||
* 64bit Visual Studio support
|
||||
* Better support for const objects
|
||||
* Drastic reduction of runtime exceptions - making debug builds orders of magnitude faster
|
||||
* Support for platforms with no loadable module support
|
||||
* Add helper macro for registering class
|
@@ -1,22 +0,0 @@
|
||||
|
||||
def add(x, y)
|
||||
{
|
||||
return x + y;
|
||||
}
|
||||
|
||||
var b = bind(add, 2, _);
|
||||
var c = bind(b, 3);
|
||||
|
||||
print(b(4));
|
||||
print(c());
|
||||
|
||||
|
||||
def concat(a,b,c,d)
|
||||
{
|
||||
return to_string(a) + to_string(b) + to_string(c) + to_string(d);
|
||||
}
|
||||
|
||||
var d = bind(concat, _, " Hello ", _, " World ");
|
||||
print(d(1, 3));
|
||||
//This checks to make sure arity is handled correctly:
|
||||
//print(d(1, 3, 4));
|
@@ -1,25 +1,23 @@
|
||||
// This file is distributed under the BSD License.
|
||||
// See "license.txt" for details.
|
||||
// Copyright 2009-2010, Jonathan Turner (jturner@minnow-lang.org)
|
||||
// and Jason Turner (lefticus@gmail.com)
|
||||
// Copyright 2009-2010, Jonathan Turner (jonathan@emptycrate.com)
|
||||
// and Jason Turner (jason@emptycrate.com)
|
||||
// http://www.chaiscript.com
|
||||
|
||||
#include <iostream>
|
||||
|
||||
#include <chaiscript/chaiscript.hpp>
|
||||
#include <chaiscript/dispatchkit/bootstrap_stl.hpp>
|
||||
#include <chaiscript/dispatchkit/function_call.hpp>
|
||||
#include <boost/function.hpp>
|
||||
#include <boost/date_time/posix_time/posix_time.hpp>
|
||||
#include <boost/regex.hpp>
|
||||
|
||||
void log(const std::string &msg)
|
||||
{
|
||||
std::cout << "[" << boost::posix_time::microsec_clock::local_time() << "] " << msg << std::endl;
|
||||
std::cout << "[" << time(nullptr) << "] " << msg << std::endl;
|
||||
}
|
||||
|
||||
void log(const std::string &module, const std::string &msg)
|
||||
{
|
||||
std::cout << "[" << boost::posix_time::microsec_clock::local_time() << "] <" << module << "> " << msg << std::endl;
|
||||
std::cout << "[" << time(nullptr) << "] <" << module << "> " << msg << std::endl;
|
||||
}
|
||||
|
||||
void bound_log(const std::string &msg)
|
||||
@@ -27,12 +25,12 @@ void bound_log(const std::string &msg)
|
||||
log(msg);
|
||||
}
|
||||
|
||||
void hello_world(const chaiscript::Boxed_Value &o)
|
||||
void hello_world(const chaiscript::Boxed_Value & /*o*/)
|
||||
{
|
||||
std::cout << "Hello World" << std::endl;
|
||||
}
|
||||
|
||||
void hello_constructor(const chaiscript::Boxed_Value &o)
|
||||
void hello_constructor(const chaiscript::Boxed_Value & /*o*/)
|
||||
{
|
||||
std::cout << "Hello Constructor" << std::endl;
|
||||
}
|
||||
@@ -40,19 +38,19 @@ void hello_constructor(const chaiscript::Boxed_Value &o)
|
||||
|
||||
struct System
|
||||
{
|
||||
std::map<std::string, boost::function<std::string (const std::string &) > > m_callbacks;
|
||||
std::map<std::string, std::function<std::string (const std::string &) > > m_callbacks;
|
||||
|
||||
void add_callback(const std::string &t_name,
|
||||
const chaiscript::Proxy_Function &t_func)
|
||||
{
|
||||
m_callbacks[t_name] = chaiscript::functor<std::string (const std::string &)>(t_func);
|
||||
m_callbacks[t_name] = chaiscript::dispatch::functor<std::string (const std::string &)>(t_func);
|
||||
}
|
||||
|
||||
|
||||
void do_callbacks(const std::string &inp)
|
||||
{
|
||||
log("Running Callbacks: " + inp);
|
||||
for (std::map<std::string, boost::function<std::string (const std::string &)> >::iterator itr = m_callbacks.begin();
|
||||
for (std::map<std::string, std::function<std::string (const std::string &)> >::iterator itr = m_callbacks.begin();
|
||||
itr != m_callbacks.end();
|
||||
++itr)
|
||||
{
|
||||
@@ -61,12 +59,12 @@ struct System
|
||||
}
|
||||
};
|
||||
|
||||
void take_shared_ptr(const boost::shared_ptr<const std::string> &p)
|
||||
void take_shared_ptr(const std::shared_ptr<const std::string> &p)
|
||||
{
|
||||
std::cout << *p << std::endl;
|
||||
}
|
||||
|
||||
int main(int argc, char *argv[]) {
|
||||
int main(int /*argc*/, char * /*argv*/[]) {
|
||||
using namespace chaiscript;
|
||||
|
||||
ChaiScript chai;
|
||||
@@ -87,7 +85,7 @@ int main(int argc, char *argv[]) {
|
||||
// Let's use chaiscript to add a new lambda callback to our system.
|
||||
// The function "{ 'Callback1' + x }" is created in chaiscript and passed into our C++ application
|
||||
// in the "add_callback" function of struct System the chaiscript function is converted into a
|
||||
// boost::function, so it can be handled and called easily and type-safely
|
||||
// std::function, so it can be handled and called easily and type-safely
|
||||
chai.eval("system.add_callback(\"#1\", fun(x) { \"Callback1 \" + x });");
|
||||
|
||||
// Because we are sharing the "system" object with the chaiscript engine we have equal
|
||||
@@ -108,14 +106,14 @@ int main(int argc, char *argv[]) {
|
||||
// A shortcut to using eval is just to use the chai operator()
|
||||
chai("log(\"Test Module\", \"Test Message\");");
|
||||
|
||||
//Finally, it is possible to register any boost::function as a system function, in this
|
||||
//Finally, it is possible to register any std::function as a system function, in this
|
||||
//way, we can, for instance add a bound member function to the system
|
||||
chai.add(fun(&System::do_callbacks, boost::ref(system), std::string("Bound Test")), "do_callbacks");
|
||||
chai.add(fun(&System::do_callbacks, std::ref(system), std::string("Bound Test")), "do_callbacks");
|
||||
|
||||
//Call bound version of do_callbacks
|
||||
chai("do_callbacks()");
|
||||
|
||||
boost::function<void ()> caller = chai.functor<void ()>("fun() { system.do_callbacks(\"From Functor\"); }");
|
||||
std::function<void ()> caller = chai.eval<std::function<void ()> >("fun() { system.do_callbacks(\"From Functor\"); }");
|
||||
caller();
|
||||
|
||||
|
||||
@@ -139,11 +137,13 @@ int main(int argc, char *argv[]) {
|
||||
//To do: Add examples of handling Boxed_Values directly when needed
|
||||
|
||||
//Creating a functor on the stack and using it immediatly
|
||||
int x = chai.functor<int (int, int)>("fun (x, y) { return x + y; }")(5, 6);
|
||||
int x = chai.eval<std::function<int (int, int)> >("fun (x, y) { return x + y; }")(5, 6);
|
||||
|
||||
log("Functor test output", boost::lexical_cast<std::string>(x));
|
||||
std::stringstream ss;
|
||||
ss << x;
|
||||
log("Functor test output", ss.str());
|
||||
|
||||
chai.add(var(boost::shared_ptr<int>()), "nullvar");
|
||||
chai.add(var(std::shared_ptr<int>()), "nullvar");
|
||||
chai("print(\"This should be true.\"); print(nullvar.is_var_null())");
|
||||
|
||||
// test the global const action
|
||||
@@ -154,7 +154,7 @@ int main(int argc, char *argv[]) {
|
||||
|
||||
//Ability to create our own container types when needed. std::vector and std::map are
|
||||
//mostly supported currently
|
||||
chai.add(bootstrap::vector_type<std::vector<int> >("IntVector"));
|
||||
chai.add(bootstrap::standard_library::vector_type<std::vector<int> >("IntVector"));
|
||||
|
||||
|
||||
// Test ability to register a function that excepts a shared_ptr version of a type
|
||||
@@ -163,9 +163,9 @@ int main(int argc, char *argv[]) {
|
||||
chai.add(fun(&bound_log, std::string("Msg")), "BoundFun");
|
||||
|
||||
//Dynamic objects test
|
||||
chai.add(chaiscript::Proxy_Function(new Dynamic_Object_Function("TestType", fun(&hello_world))), "hello_world");
|
||||
chai.add(chaiscript::Proxy_Function(new Dynamic_Object_Constructor("TestType", fun(&hello_constructor))), "TestType");
|
||||
chai.add(fun(boost::function<Boxed_Value (Dynamic_Object &)>(boost::bind(&Dynamic_Object_Attribute::func, "TestType", "attr", _1))), "attr");
|
||||
chai.add(chaiscript::Proxy_Function(new dispatch::detail::Dynamic_Object_Function("TestType", fun(&hello_world))), "hello_world");
|
||||
chai.add(chaiscript::Proxy_Function(new dispatch::detail::Dynamic_Object_Constructor("TestType", fun(&hello_constructor))), "TestType");
|
||||
// chai.add(fun(std::function<Boxed_Value (dispatch::Dynamic_Object &)>(std::bind(&dispatch::detail::Dynamic_Object_Attribute::func, "TestType", "attr", std::placeholders::_1))), "attr");
|
||||
|
||||
chai.eval("var x = TestType()");
|
||||
// chai.eval("x.attr = \"hi\"");
|
91
samples/memory_leak_test.cpp
Normal file
91
samples/memory_leak_test.cpp
Normal file
@@ -0,0 +1,91 @@
|
||||
#include <iostream>
|
||||
|
||||
#include <chaiscript/chaiscript.hpp>
|
||||
#include <chaiscript/chaiscript_stdlib.hpp>
|
||||
|
||||
#ifdef READLINE_AVAILABLE
|
||||
#include <readline/readline.h>
|
||||
#include <readline/history.h>
|
||||
#endif
|
||||
|
||||
|
||||
|
||||
std::string get_next_command() {
|
||||
#ifdef READLINE_AVAILABLE
|
||||
char *input_raw;
|
||||
input_raw = readline("eval> ");
|
||||
add_history(input_raw);
|
||||
return std::string(input_raw);
|
||||
#else
|
||||
std::string retval;
|
||||
std::cout << "eval> ";
|
||||
std::getline(std::cin, retval);
|
||||
return retval;
|
||||
#endif
|
||||
}
|
||||
|
||||
void fuction(void)
|
||||
{
|
||||
// do nothing
|
||||
}
|
||||
|
||||
class test
|
||||
{
|
||||
chaiscript::ChaiScript chai;
|
||||
chaiscript::ChaiScript::State backupState;
|
||||
|
||||
public:
|
||||
test()
|
||||
: chai(chaiscript::Std_Lib::library())
|
||||
{
|
||||
backupState = chai.get_state();
|
||||
}
|
||||
~test(){}
|
||||
|
||||
void ResetState()
|
||||
{
|
||||
chai.set_state(backupState);
|
||||
chai.add(chaiscript::fun(&fuction),"Whatever()");
|
||||
}
|
||||
|
||||
void RunFile(std::string sFile)
|
||||
{
|
||||
try {
|
||||
chaiscript::Boxed_Value val = chai.eval_file(sFile);
|
||||
}
|
||||
catch (std::exception &e) {
|
||||
std::cout << e.what() << std::endl;
|
||||
}
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
|
||||
|
||||
int main(int /*argc*/, char * /*argv*/[]) {
|
||||
|
||||
test myChai;
|
||||
|
||||
|
||||
std::string command = "";
|
||||
|
||||
//
|
||||
// this loop increases memoryusage, if RunFile is not called (just hittin enter)
|
||||
// as soon RunFile gets called, memory will be freed.
|
||||
//
|
||||
// scenario1 - RunFile gets called every Loop: memoryusage does not change
|
||||
// scenario2 - RunFile gets never called (just hitting enter): memoryusage increases every loop
|
||||
// scenario3 - RunFile gets in changing intervals: memoryusage goes up and down, but never as
|
||||
// low as in case 1 scenario3 :
|
||||
|
||||
while(command != "quit")
|
||||
{
|
||||
for(int i = 1; i < 200; i++)
|
||||
myChai.ResetState();
|
||||
|
||||
if(command == "runfile")
|
||||
myChai.RunFile("Test.chai");
|
||||
|
||||
command = get_next_command();
|
||||
}
|
||||
}
|
@@ -1,70 +0,0 @@
|
||||
|
||||
|
||||
def initialize_cpu_sensor(state, cpuname, sensor_manager)
|
||||
{
|
||||
state[cpuname] = 0.0;
|
||||
state[cpuname + ".user"] = 0.0;
|
||||
state[cpuname + ".nice"] = 0.0;
|
||||
state[cpuname + ".system"] = 0.0;
|
||||
state[cpuname + ".idle"] = 0.0;
|
||||
state[cpuname + ".iowait"] = 0.0;
|
||||
state[cpuname + ".irq"] = 0.0;
|
||||
state[cpuname + ".softirq"] = 0.0;
|
||||
}
|
||||
|
||||
def update_cpu_state(state, statfile, cpuname)
|
||||
{
|
||||
var regex = cpuname + "\\s+([0-9]+)\\s+([0-9]+)\\s+([0-9]+)\\s+([0-9]+)\\s+([0-9]+)\\s+([0-9]+)\\s+([0-9]+)";
|
||||
var strs = regex_search(statfile, regex);
|
||||
|
||||
var user = to_double(strs[1]);
|
||||
var nice = to_double(strs[2]);
|
||||
var system = to_double(strs[3]);
|
||||
var idle = to_double(strs[4]);
|
||||
var iowait = to_double(strs[5]);
|
||||
var irq = to_double(strs[6]);
|
||||
var softirq = to_double(strs[7]);
|
||||
|
||||
var userd = user - state[cpuname + ".user"];
|
||||
var niced = nice - state[cpuname + ".nice"];
|
||||
var systemd = system - state[cpuname + ".system"];
|
||||
var idled = idle - state[cpuname + ".idle"];
|
||||
var iowaitd = iowait - state[cpuname + ".iowait"];
|
||||
var irqd = irq - state[cpuname + ".irq"];
|
||||
var softirqd = softirq - state[cpuname + ".softirq"];
|
||||
|
||||
var totalticks = userd + niced + systemd + idled + iowaitd + irqd + softirqd;
|
||||
|
||||
state[cpuname] = (totalticks - idled) / totalticks
|
||||
|
||||
state[cpuname + ".user"] = user;
|
||||
state[cpuname + ".nice"] = nice;
|
||||
state[cpuname + ".system"] = system;
|
||||
state[cpuname + ".idle"] = idle;
|
||||
state[cpuname + ".iowait"] = iowait;
|
||||
state[cpuname + ".irq"] = irq;
|
||||
state[cpuname + ".softirq"] = softirq;
|
||||
}
|
||||
|
||||
# annotation
|
||||
def update_state(state)
|
||||
{
|
||||
var file = load_text_file("/proc/stat");
|
||||
|
||||
update_cpu_state(state, file, "cpu");
|
||||
update_cpu_state(state, file, "cpu0");
|
||||
update_cpu_state(state, file, "cpu1");
|
||||
}
|
||||
|
||||
//dump_system()
|
||||
|
||||
var global_state = Map()
|
||||
|
||||
initialize_cpu_sensor(global_state, "cpu", sensor_manager);
|
||||
initialize_cpu_sensor(global_state, "cpu0", sensor_manager);
|
||||
initialize_cpu_sensor(global_state, "cpu1", sensor_manager);
|
||||
|
||||
sensor_manager.add_sensor("cpu", 500, global_state, fun(state) { update_state(state); state["cpu"]; } )
|
||||
sensor_manager.add_sensor("cpu0", 500, global_state, fun(state) { state["cpu0"]; } )
|
||||
sensor_manager.add_sensor("cpu1", 500, global_state, fun(state) { state["cpu1"]; } )
|
||||
|
21
src/chaiscript_stdlib.cpp
Normal file
21
src/chaiscript_stdlib.cpp
Normal file
@@ -0,0 +1,21 @@
|
||||
|
||||
#include <chaiscript/chaiscript_stdlib.hpp>
|
||||
|
||||
|
||||
// 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
|
||||
|
||||
|
||||
CHAISCRIPT_MODULE_EXPORT chaiscript::ModulePtr create_chaiscript_module_chaiscript_stdlib()
|
||||
{
|
||||
return chaiscript::Std_Lib::library();
|
||||
}
|
||||
|
||||
|
||||
#ifdef CHAISCRIPT_MSVC
|
||||
#pragma warning(pop)
|
||||
#endif
|
249
src/main.cpp
249
src/main.cpp
@@ -1,35 +1,61 @@
|
||||
// This file is distributed under the BSD License.
|
||||
// See "license.txt" for details.
|
||||
// Copyright 2009-2010, Jonathan Turner (jturner@minnow-lang.org)
|
||||
// and Jason Turner (lefticus@gmail.com)
|
||||
// Copyright 2009-2010, Jonathan Turner (jonathan@emptycrate.com)
|
||||
// and Jason Turner (jason@emptycrate.com)
|
||||
// http://www.chaiscript.com
|
||||
|
||||
#include <iostream>
|
||||
|
||||
#include <list>
|
||||
#include <regex>
|
||||
|
||||
#define _CRT_SECURE_NO_WARNINGS
|
||||
#include <chaiscript/chaiscript.hpp>
|
||||
|
||||
#ifdef READLINE_AVAILABLE
|
||||
#include <readline/readline.h>
|
||||
#include <readline/history.h>
|
||||
#else
|
||||
char* readline(const char* p)
|
||||
{
|
||||
std::string retval;
|
||||
std::cout << p ;
|
||||
std::getline(std::cin, retval);
|
||||
#ifdef CHAISCRIPT_MSVC
|
||||
return std::cin.eof() ? NULL : _strdup(retval.c_str());
|
||||
#else
|
||||
return std::cin.eof() ? NULL : strdup(retval.c_str());
|
||||
#endif
|
||||
}
|
||||
void add_history(const char*){}
|
||||
void using_history(){}
|
||||
#endif
|
||||
|
||||
#include <chaiscript/chaiscript.hpp>
|
||||
|
||||
|
||||
void print_help() {
|
||||
void help(int n) {
|
||||
if ( n >= 0 ) {
|
||||
std::cout << "ChaiScript evaluator. To evaluate an expression, type it and press <enter>." << std::endl;
|
||||
std::cout << "Additionally, you can inspect the runtime system using:" << std::endl;
|
||||
std::cout << " dump_system() - outputs all functions registered to the system" << std::endl;
|
||||
std::cout << " dump_object(x) - dumps information about the given symbol" << std::endl;
|
||||
} else {
|
||||
std::cout << "usage : chai [option]+" << std::endl;
|
||||
std::cout << "option:" << std::endl;
|
||||
std::cout << " -h | --help" << std::endl;
|
||||
std::cout << " -i | --interactive" << std::endl;
|
||||
std::cout << " -c | --command cmd" << std::endl;
|
||||
std::cout << " -v | --version" << std::endl;
|
||||
std::cout << " - --stdin" << std::endl;
|
||||
std::cout << " filepath" << std::endl;
|
||||
}
|
||||
}
|
||||
|
||||
void version(int){
|
||||
std::cout << "chai: compiled " << __TIME__ << " " << __DATE__ << std::endl;
|
||||
}
|
||||
|
||||
bool throws_exception(const chaiscript::Proxy_Function &f)
|
||||
bool throws_exception(const std::function<void ()> &f)
|
||||
{
|
||||
try {
|
||||
chaiscript::functor<void ()>(f)();
|
||||
f();
|
||||
} catch (...) {
|
||||
return true;
|
||||
}
|
||||
@@ -37,97 +63,196 @@ bool throws_exception(const chaiscript::Proxy_Function &f)
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
std::string get_next_command() {
|
||||
#ifdef READLINE_AVAILABLE
|
||||
char *input_raw;
|
||||
input_raw = readline("eval> ");
|
||||
add_history(input_raw);
|
||||
return std::string(input_raw);
|
||||
#else
|
||||
std::string retval;
|
||||
std::cout << "eval> ";
|
||||
std::getline(std::cin, retval);
|
||||
return retval;
|
||||
#endif
|
||||
chaiscript::exception::eval_error get_eval_error(const std::function<void ()> &f)
|
||||
{
|
||||
try {
|
||||
f();
|
||||
} catch (const chaiscript::exception::eval_error &e) {
|
||||
return e;
|
||||
}
|
||||
|
||||
int main(int argc, char *argv[]) {
|
||||
std::string input;
|
||||
throw std::runtime_error("no exception throw");
|
||||
}
|
||||
|
||||
std::string get_next_command() {
|
||||
std::string retval("quit");
|
||||
if ( ! std::cin.eof() ) {
|
||||
char *input_raw = readline("eval> ");
|
||||
if ( input_raw ) {
|
||||
add_history(input_raw);
|
||||
|
||||
std::string val(input_raw);
|
||||
size_t pos = val.find_first_not_of("\t \n");
|
||||
if (pos != std::string::npos)
|
||||
{
|
||||
val.erase(0, pos);
|
||||
}
|
||||
pos = val.find_last_not_of("\t \n");
|
||||
if (pos != std::string::npos)
|
||||
{
|
||||
val.erase(pos+1, std::string::npos);
|
||||
}
|
||||
|
||||
retval = val;
|
||||
|
||||
::free(input_raw);
|
||||
}
|
||||
}
|
||||
if( retval == "quit"
|
||||
|| retval == "exit"
|
||||
|| retval == "help"
|
||||
|| retval == "version")
|
||||
{
|
||||
retval += "(0)";
|
||||
}
|
||||
return retval;
|
||||
}
|
||||
|
||||
// We have to wrap exit with our own because Clang has a hard time with
|
||||
// function pointers to functions with special attributes (system exit being marked NORETURN)
|
||||
void myexit(int return_val) {
|
||||
exit(return_val);
|
||||
}
|
||||
|
||||
void interactive(chaiscript::ChaiScript& chai)
|
||||
{
|
||||
using_history();
|
||||
|
||||
for (;;) {
|
||||
std::string input = get_next_command();
|
||||
try {
|
||||
// evaluate input
|
||||
chaiscript::Boxed_Value val = chai.eval(input);
|
||||
|
||||
//Then, we try to print the result of the evaluation to the user
|
||||
if (!val.get_type_info().bare_equal(chaiscript::user_type<void>())) {
|
||||
try {
|
||||
std::cout << chai.eval<std::function<std::string (const chaiscript::Boxed_Value &bv)> >("to_string")(val) << std::endl;
|
||||
}
|
||||
catch (...) {} //If we can't, do nothing
|
||||
}
|
||||
}
|
||||
catch (const chaiscript::exception::eval_error &ee) {
|
||||
std::cout << ee.what();
|
||||
if (ee.call_stack.size() > 0) {
|
||||
std::cout << "during evaluation at (" << ee.call_stack[0]->start.line << ", " << ee.call_stack[0]->start.column << ")";
|
||||
}
|
||||
std::cout << std::endl;
|
||||
}
|
||||
catch (const std::exception &e) {
|
||||
std::cout << e.what();
|
||||
std::cout << std::endl;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
int main(int argc, char *argv[])
|
||||
{
|
||||
std::vector<std::string> usepaths;
|
||||
std::vector<std::string> modulepaths;
|
||||
|
||||
// Disable deprecation warning for getenv call.
|
||||
#ifdef CHAISCRIPT_MSVC
|
||||
#pragma warning(push)
|
||||
#pragma warning(disable : 4996)
|
||||
#endif
|
||||
|
||||
const char *usepath = getenv("CHAI_USE_PATH");
|
||||
const char *modulepath = getenv("CHAI_MODULE_PATH");
|
||||
|
||||
usepaths.push_back("");
|
||||
#ifdef CHAISCRIPT_MSVC
|
||||
#pragma warning(pop)
|
||||
#endif
|
||||
|
||||
usepaths.push_back("");
|
||||
if (usepath)
|
||||
{
|
||||
usepaths.push_back(usepath);
|
||||
}
|
||||
|
||||
modulepaths.push_back("");
|
||||
|
||||
if (modulepath)
|
||||
{
|
||||
modulepaths.push_back(modulepath);
|
||||
}
|
||||
|
||||
|
||||
chaiscript::ChaiScript chai(modulepaths,usepaths);
|
||||
|
||||
chai.add(chaiscript::fun(&exit), "exit");
|
||||
chai.add(chaiscript::fun(&myexit), "exit");
|
||||
chai.add(chaiscript::fun(&myexit), "quit");
|
||||
chai.add(chaiscript::fun(&help), "help");
|
||||
chai.add(chaiscript::fun(&version), "version");
|
||||
chai.add(chaiscript::fun(&throws_exception), "throws_exception");
|
||||
chai.add(chaiscript::fun(&get_eval_error), "get_eval_error");
|
||||
|
||||
if (argc < 2) {
|
||||
#ifdef READLINE_AVAILABLE
|
||||
using_history();
|
||||
#endif
|
||||
input = get_next_command();
|
||||
while (input != "quit") {
|
||||
for (int i = 0; i < argc; ++i) {
|
||||
if ( i == 0 && argc > 1 ) {
|
||||
++i;
|
||||
}
|
||||
|
||||
std::string arg( i ? argv[i] : "--interactive" );
|
||||
|
||||
enum { eInteractive
|
||||
, eCommand
|
||||
, eFile
|
||||
} mode = eCommand ;
|
||||
|
||||
if ( arg == "-c" || arg == "--command" ) {
|
||||
if ( (i+1) >= argc ) {
|
||||
std::cout << "insufficient input following " << arg << std::endl;
|
||||
return EXIT_FAILURE;
|
||||
} else {
|
||||
arg = argv[++i];
|
||||
}
|
||||
} else if ( arg == "-" || arg == "--stdin" ) {
|
||||
arg = "" ;
|
||||
std::string line;
|
||||
while ( std::getline(std::cin, line) ) {
|
||||
arg += line + '\n' ;
|
||||
}
|
||||
} else if ( arg == "-v" || arg == "--version" ) {
|
||||
arg = "version(0)" ;
|
||||
} else if ( arg == "-h" || arg == "--help" ) {
|
||||
arg = "help(-1)";
|
||||
} else if ( arg == "-i" || arg == "--interactive" ) {
|
||||
mode = eInteractive ;
|
||||
} else if ( arg.find('-') == 0 ) {
|
||||
std::cout << "unrecognised argument " << arg << std::endl;
|
||||
return EXIT_FAILURE;
|
||||
} else {
|
||||
mode = eFile;
|
||||
}
|
||||
|
||||
chaiscript::Boxed_Value val ;
|
||||
|
||||
if (input == "help") {
|
||||
print_help();
|
||||
}
|
||||
else {
|
||||
try {
|
||||
//First, we evaluate it
|
||||
val = chai.eval(input);
|
||||
|
||||
//Then, we try to print the result of the evaluation to the user
|
||||
if (!val.get_type_info().bare_equal(chaiscript::user_type<void>())) {
|
||||
try {
|
||||
chaiscript::dispatch(chai.get_eval_engine().get_function("print"), chaiscript::Param_List_Builder() << val);
|
||||
switch ( mode ) {
|
||||
case eInteractive : interactive(chai); break;
|
||||
case eCommand : val = chai.eval(arg); break;
|
||||
case eFile : val = chai.eval_file(arg); break;
|
||||
default : std::cout << "Unrecognized execution mode" << std::endl; return EXIT_FAILURE;
|
||||
}
|
||||
catch (...) {
|
||||
//If we can't, do nothing
|
||||
}
|
||||
catch (const chaiscript::exception::eval_error &ee) {
|
||||
std::cout << ee.what();
|
||||
if (ee.call_stack.size() > 0) {
|
||||
std::cout << "during evaluation at (" << *(ee.call_stack[0]->filename) << " " << ee.call_stack[0]->start.line << ", " << ee.call_stack[0]->start.column << ")";
|
||||
for (size_t j = 1; j < ee.call_stack.size(); ++j) {
|
||||
if (ee.call_stack[j]->identifier != chaiscript::AST_Node_Type::Block
|
||||
&& ee.call_stack[j]->identifier != chaiscript::AST_Node_Type::File)
|
||||
{
|
||||
std::cout << std::endl;
|
||||
std::cout << " from " << *(ee.call_stack[j]->filename) << " (" << ee.call_stack[j]->start.line << ", " << ee.call_stack[j]->start.column << ")";
|
||||
}
|
||||
}
|
||||
}
|
||||
catch (std::exception &e) {
|
||||
std::cout << e.what() << std::endl;
|
||||
}
|
||||
}
|
||||
|
||||
input = get_next_command();
|
||||
}
|
||||
}
|
||||
else {
|
||||
for (int i = 1; i < argc; ++i) {
|
||||
try {
|
||||
chaiscript::Boxed_Value val = chai.eval_file(argv[i]);
|
||||
std::cout << std::endl;
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
catch (std::exception &e) {
|
||||
std::cout << e.what() << std::endl;
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return EXIT_SUCCESS;
|
||||
}
|
||||
|
||||
|
@@ -1,83 +0,0 @@
|
||||
#include <iostream>
|
||||
|
||||
#include "chaiscript/chaiscript.hpp"
|
||||
|
||||
using namespace chaiscript;
|
||||
|
||||
std::string get_next_command() {
|
||||
#ifdef READLINE_AVAILABLE
|
||||
char *input_raw;
|
||||
input_raw = readline("eval> ");
|
||||
add_history(input_raw);
|
||||
return std::string(input_raw);
|
||||
#else
|
||||
std::string retval;
|
||||
std::cout << "eval> ";
|
||||
std::getline(std::cin, retval);
|
||||
return retval;
|
||||
#endif
|
||||
}
|
||||
|
||||
void fuction(void)
|
||||
{
|
||||
// do nothing
|
||||
}
|
||||
|
||||
class test
|
||||
{
|
||||
ChaiScript chai;
|
||||
ChaiScript::State backupState;
|
||||
public:
|
||||
test()
|
||||
{
|
||||
backupState = chai.get_state();
|
||||
}
|
||||
~test(){}
|
||||
|
||||
void ResetState()
|
||||
{
|
||||
chai.set_state(backupState);
|
||||
chai.add(fun(&fuction),"Whatever()");
|
||||
}
|
||||
void RunFile(std::string sFile)
|
||||
{
|
||||
chaiscript::Boxed_Value val;
|
||||
try {
|
||||
chaiscript::Boxed_Value val = chai.eval_file(sFile);
|
||||
}
|
||||
catch (std::exception &e) {
|
||||
std::cout << e.what() << std::endl;
|
||||
}
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
|
||||
|
||||
int main(int argc, char *argv[]) {
|
||||
|
||||
test myChai;
|
||||
|
||||
|
||||
std::string command = "";
|
||||
|
||||
//
|
||||
// this loop increases memoryusage, if RunFile is not called (just hittin enter)
|
||||
// as soon RunFile gets called, memory will be freed.
|
||||
//
|
||||
// scenario1 - RunFile gets called every Loop: memoryusage does not change
|
||||
// scenario2 - RunFile gets never called (just hitting enter): memoryusage increases every loop
|
||||
// scenario3 - RunFile gets in changing intervals: memoryusage goes up and down, but never as
|
||||
// low as in case 1 scenario3 :
|
||||
|
||||
while(command != "quit")
|
||||
{
|
||||
for(int i = 1; i < 200; i++)
|
||||
myChai.ResetState();
|
||||
|
||||
if(command == "runfile")
|
||||
myChai.RunFile("Test.chai");
|
||||
|
||||
command = get_next_command();
|
||||
}
|
||||
}
|
@@ -1,7 +1,7 @@
|
||||
// This file is distributed under the BSD License.
|
||||
// See "license.txt" for details.
|
||||
// Copyright 2009-2010, Jonathan Turner (jturner@minnow-lang.org)
|
||||
// and Jason Turner (lefticus@gmail.com)
|
||||
// Copyright 2009-2010, Jonathan Turner (jonathan@emptycrate.com)
|
||||
// and Jason Turner (jason@emptycrate.com)
|
||||
// http://www.chaiscript.com
|
||||
|
||||
#include <iostream>
|
||||
@@ -9,11 +9,14 @@
|
||||
#include <list>
|
||||
|
||||
#include <chaiscript/chaiscript.hpp>
|
||||
#include <boost/thread.hpp>
|
||||
#include <thread>
|
||||
|
||||
void do_work(chaiscript::ChaiScript &c)
|
||||
{
|
||||
// c("use(\"work.chai\"); do_chai_work(num_iterations);");
|
||||
std::stringstream ss;
|
||||
ss << "MyVar" << rand();
|
||||
c.add(chaiscript::var(5), ss.str());
|
||||
c("use(\"work.chai\"); do_chai_work(10000);");
|
||||
}
|
||||
|
||||
@@ -23,11 +26,11 @@ int main(int argc, char *argv[]) {
|
||||
|
||||
//chai.add_shared_object(chaiscript::Boxed_Value(10000), "num_iterations");
|
||||
|
||||
std::vector<boost::shared_ptr<boost::thread> > threads;
|
||||
std::vector<std::shared_ptr<std::thread> > threads;
|
||||
|
||||
for (int i = 0; i < argc - 1; ++i)
|
||||
{
|
||||
threads.push_back(boost::shared_ptr<boost::thread>(new boost::thread(boost::bind(do_work, boost::ref(chai)))));
|
||||
threads.push_back(std::shared_ptr<std::thread>(new std::thread(std::bind(do_work, std::ref(chai)))));
|
||||
}
|
||||
|
||||
for (int i = 0; i < argc - 1; ++i)
|
||||
|
104
src/reflection.cpp
Normal file
104
src/reflection.cpp
Normal file
@@ -0,0 +1,104 @@
|
||||
|
||||
#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)
|
||||
{
|
||||
return bool(pf->get_parse_tree());
|
||||
} 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");
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
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 CHAISCRIPT_MSVC
|
||||
#pragma warning(pop)
|
||||
#endif
|
@@ -1,9 +1,22 @@
|
||||
|
||||
#include <chaiscript/chaiscript.hpp>
|
||||
#include <chaiscript/dispatchkit/bootstrap_stl.hpp>
|
||||
#include <list>
|
||||
#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
|
||||
|
||||
CHAISCRIPT_MODULE_EXPORT chaiscript::ModulePtr create_chaiscript_module_stl_extra()
|
||||
{
|
||||
return chaiscript::bootstrap::list_type<std::list<chaiscript::Boxed_Value> >("List");
|
||||
return chaiscript::bootstrap::standard_library::list_type<std::list<chaiscript::Boxed_Value> >("List");
|
||||
}
|
||||
|
||||
|
||||
#ifdef CHAISCRIPT_MSVC
|
||||
#pragma warning(pop)
|
||||
#endif
|
||||
|
@@ -2,15 +2,86 @@
|
||||
#include <chaiscript/chaiscript.hpp>
|
||||
#include <string>
|
||||
|
||||
class TestBaseType
|
||||
{
|
||||
public:
|
||||
TestBaseType() {}
|
||||
TestBaseType(int) {}
|
||||
TestBaseType(int *) {}
|
||||
virtual ~TestBaseType() {}
|
||||
virtual int func() { return 0; }
|
||||
|
||||
};
|
||||
|
||||
enum TestEnum
|
||||
{
|
||||
TestValue1 = 1
|
||||
};
|
||||
|
||||
int to_int(TestEnum t)
|
||||
{
|
||||
return t;
|
||||
}
|
||||
|
||||
class TestDerivedType : public TestBaseType
|
||||
{
|
||||
public:
|
||||
virtual ~TestDerivedType() {}
|
||||
virtual int func() { return 1; }
|
||||
};
|
||||
|
||||
std::string hello_world()
|
||||
{
|
||||
return "Hello World";
|
||||
}
|
||||
|
||||
int *get_new_int()
|
||||
{
|
||||
return new int(1);
|
||||
}
|
||||
|
||||
// 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
|
||||
|
||||
|
||||
CHAISCRIPT_MODULE_EXPORT chaiscript::ModulePtr create_chaiscript_module_test_module()
|
||||
{
|
||||
chaiscript::ModulePtr m(new chaiscript::Module());
|
||||
|
||||
m->add(chaiscript::fun(hello_world), "hello_world");
|
||||
|
||||
m->add(chaiscript::user_type<TestBaseType>(), "TestBaseType");
|
||||
m->add(chaiscript::user_type<TestDerivedType>(), "TestDerivedType");
|
||||
|
||||
m->add(chaiscript::constructor<TestBaseType ()>(), "TestBaseType");
|
||||
// m->add(chaiscript::constructor<TestBaseType (int)>(), "TestBaseType");
|
||||
m->add(chaiscript::constructor<TestBaseType (const TestBaseType &)>(), "TestBaseType");
|
||||
m->add(chaiscript::constructor<TestBaseType (int *)>(), "TestBaseType");
|
||||
|
||||
m->add(chaiscript::constructor<TestDerivedType ()>(), "TestDerivedType");
|
||||
m->add(chaiscript::constructor<TestDerivedType (const TestDerivedType &)>(), "TestDerivedType");
|
||||
|
||||
m->add(chaiscript::base_class<TestBaseType, TestDerivedType>());
|
||||
|
||||
m->add(chaiscript::fun(&TestBaseType::func), "func");
|
||||
|
||||
m->add(chaiscript::fun(&get_new_int), "get_new_int");
|
||||
|
||||
m->add_global_const(chaiscript::const_var(TestValue1), "TestValue1");
|
||||
|
||||
m->add(chaiscript::user_type<TestEnum>(), "TestEnum");
|
||||
|
||||
m->add(chaiscript::fun(&to_int), "to_int");
|
||||
|
||||
|
||||
return m;
|
||||
}
|
||||
|
||||
|
||||
#ifdef CHAISCRIPT_MSVC
|
||||
#pragma warning(pop)
|
||||
#endif
|
||||
|
2
unittests/3.x/assign_const.chai
Normal file
2
unittests/3.x/assign_const.chai
Normal file
@@ -0,0 +1,2 @@
|
||||
assert_throws("Mismatched types in equation, lhs is const.", fun() { 1 = 2 } );
|
||||
assert_throws("Mismatched types in equation, lhs is const.", fun() { 1 + 2 = 2 } );
|
2
unittests/3.x/bind.chai
Normal file
2
unittests/3.x/bind.chai
Normal file
@@ -0,0 +1,2 @@
|
||||
var prod = bind(foldl, _, `*`, 1.0)
|
||||
assert_equal(60, prod([3, 4, 5]))
|
34
unittests/3.x/bind2.chai
Normal file
34
unittests/3.x/bind2.chai
Normal file
@@ -0,0 +1,34 @@
|
||||
|
||||
def add(x, y)
|
||||
{
|
||||
return x + y;
|
||||
}
|
||||
|
||||
assert_equal(2, add.get_arity());
|
||||
|
||||
var b = bind(add, 2, _);
|
||||
|
||||
assert_equal(1, b.get_arity());
|
||||
|
||||
var c = bind(b, 3);
|
||||
|
||||
assert_equal(0, c.get_arity());
|
||||
|
||||
assert_equal(6, b(4));
|
||||
assert_equal(5, c());
|
||||
|
||||
def concat2(a,b,c,d)
|
||||
{
|
||||
return to_string(a) + to_string(b) + to_string(c) + to_string(d);
|
||||
}
|
||||
|
||||
var d = bind(concat2, _, " Hello ", _, " World");
|
||||
assert_equal(2, d.get_arity());
|
||||
|
||||
assert_equal("1 Hello 3 World", d(1,3));
|
||||
|
||||
var e = bind(`<`, _, 5);
|
||||
var types = e.get_param_types();
|
||||
assert_equal(2, types.size());
|
||||
assert_equal(true, types[0].bare_equal(bool_type));
|
||||
|
1
unittests/3.x/block_start.chai
Normal file
1
unittests/3.x/block_start.chai
Normal file
@@ -0,0 +1 @@
|
||||
{print("hello")}
|
1
unittests/3.x/bool_not.chai
Normal file
1
unittests/3.x/bool_not.chai
Normal file
@@ -0,0 +1 @@
|
||||
assert_equal(false, !true)
|
7
unittests/3.x/break_while.chai
Normal file
7
unittests/3.x/break_while.chai
Normal file
@@ -0,0 +1,7 @@
|
||||
var i = 0
|
||||
while (i < 10) {
|
||||
if (++i == 5) {
|
||||
break
|
||||
}
|
||||
}
|
||||
assert_equal(5, i);
|
1
unittests/3.x/char_init.chai
Normal file
1
unittests/3.x/char_init.chai
Normal file
@@ -0,0 +1 @@
|
||||
assert_equal("b", to_string('b'))
|
7
unittests/3.x/classification.chai
Normal file
7
unittests/3.x/classification.chai
Normal file
@@ -0,0 +1,7 @@
|
||||
assert_equal(true, 1.is_var_const());
|
||||
assert_equal(false, 1.is_var_reference());
|
||||
assert_equal(true, 1.is_var_pointer());
|
||||
assert_equal(false, 1.is_var_null());
|
||||
assert_equal(false, 1.is_var_undef());
|
||||
var i;
|
||||
assert_equal(true, i.is_var_undef());
|
3
unittests/3.x/collate.chai
Normal file
3
unittests/3.x/collate.chai
Normal file
@@ -0,0 +1,3 @@
|
||||
var v = collate(1, 2)
|
||||
assert_equal(1, v[0])
|
||||
assert_equal(2, v[1])
|
1
unittests/3.x/compare_gt.chai
Normal file
1
unittests/3.x/compare_gt.chai
Normal file
@@ -0,0 +1 @@
|
||||
assert_equal(false, 1 > 2);
|
1
unittests/3.x/compare_lt.chai
Normal file
1
unittests/3.x/compare_lt.chai
Normal file
@@ -0,0 +1 @@
|
||||
assert_equal(true, 1 < 2)
|
5
unittests/3.x/concat.chai
Normal file
5
unittests/3.x/concat.chai
Normal file
@@ -0,0 +1,5 @@
|
||||
var v = concat([1, 2], [3, 4]);
|
||||
|
||||
assert_equal(4, v.size());
|
||||
assert_equal(1, v[0]);
|
||||
assert_equal(4, v[3]);
|
4
unittests/3.x/const_range_test.chai
Normal file
4
unittests/3.x/const_range_test.chai
Normal file
@@ -0,0 +1,4 @@
|
||||
//If the following succeeds, the test passes
|
||||
|
||||
|
||||
"Hello World".for_each(fun(x) { print(x) } )
|
1
unittests/3.x/convert_double_string.chai
Normal file
1
unittests/3.x/convert_double_string.chai
Normal file
@@ -0,0 +1 @@
|
||||
assert_equal("3.5bob", 3.5.to_string() + "bob");
|
1
unittests/3.x/convert_int_string.chai
Normal file
1
unittests/3.x/convert_int_string.chai
Normal file
@@ -0,0 +1 @@
|
||||
assert_equal("3bob", 3.to_string + "bob")
|
1
unittests/3.x/convert_string_double.chai
Normal file
1
unittests/3.x/convert_string_double.chai
Normal file
@@ -0,0 +1 @@
|
||||
assert_equal(6.8, "3.5".to_double() + 3.3)
|
1
unittests/3.x/convert_string_int.chai
Normal file
1
unittests/3.x/convert_string_int.chai
Normal file
@@ -0,0 +1 @@
|
||||
assert_equal(8, "4".to_int() + 4)
|
11
unittests/3.x/deep_array_lookup.chai
Normal file
11
unittests/3.x/deep_array_lookup.chai
Normal file
@@ -0,0 +1,11 @@
|
||||
var a = [1,2,3, [4,5,6] ]
|
||||
|
||||
assert_equal(a[3][0], 4)
|
||||
|
||||
|
||||
def Test::Test() { this.a = [1,2,3]; }
|
||||
attr Test::a;
|
||||
|
||||
var t = Test();
|
||||
|
||||
assert_equal(t.a[0], 1)
|
11
unittests/3.x/dispatch_functions.chai
Normal file
11
unittests/3.x/dispatch_functions.chai
Normal file
@@ -0,0 +1,11 @@
|
||||
assert_equal(`==`, `==`);
|
||||
assert_not_equal(`==`, `<`);
|
||||
assert_equal(`<`.get_arity(), 2);
|
||||
assert_equal(`+`.get_annotation(), "Multiple method dispatch function wrapper.");
|
||||
assert_equal(get_arity.get_contained_functions().size(), 0);
|
||||
assert_equal(get_arity.get_arity(), 1);
|
||||
assert_equal(get_arity.get_param_types().size(), 2);
|
||||
|
||||
var paramtypes = get_arity.get_param_types();
|
||||
|
||||
assert_equal(true, paramtypes[1].bare_equal(Function_type));
|
1
unittests/3.x/drop.chai
Normal file
1
unittests/3.x/drop.chai
Normal file
@@ -0,0 +1 @@
|
||||
assert_equal([3,4], drop([1, 2, 3, 4], 2))
|
1
unittests/3.x/drop_while.chai
Normal file
1
unittests/3.x/drop_while.chai
Normal file
@@ -0,0 +1 @@
|
||||
assert_equal([2, 3], drop_while([1, 2, 3], odd))
|
0
unittests/3.x/empty.chai
Normal file
0
unittests/3.x/empty.chai
Normal file
4
unittests/3.x/equ_shortform.chai
Normal file
4
unittests/3.x/equ_shortform.chai
Normal file
@@ -0,0 +1,4 @@
|
||||
var x=.5
|
||||
assert_equal(.5, x)
|
||||
var y=-.5
|
||||
assert_equal(-.5, y)
|
1
unittests/3.x/eval.chai
Normal file
1
unittests/3.x/eval.chai
Normal file
@@ -0,0 +1 @@
|
||||
assert_equal(7, eval("3 + 4"))
|
39
unittests/3.x/eval_error.chai
Normal file
39
unittests/3.x/eval_error.chai
Normal file
@@ -0,0 +1,39 @@
|
||||
load_module("reflection")
|
||||
|
||||
def deep()
|
||||
{
|
||||
try {
|
||||
} catch {
|
||||
|
||||
} finally {
|
||||
if (2)
|
||||
{
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
def func()
|
||||
{
|
||||
deep();
|
||||
}
|
||||
|
||||
def doing()
|
||||
{
|
||||
for (var i = 0; i < 10; ++i)
|
||||
{
|
||||
func();
|
||||
}
|
||||
}
|
||||
|
||||
def while_doing()
|
||||
{
|
||||
while (true)
|
||||
{
|
||||
doing();
|
||||
}
|
||||
}
|
||||
|
||||
var f = fun() { while_doing(); }
|
||||
|
||||
assert_equal(get_eval_error(f).call_stack.size(), 16)
|
1
unittests/3.x/even.chai
Normal file
1
unittests/3.x/even.chai
Normal file
@@ -0,0 +1 @@
|
||||
assert_equal(true, even(4))
|
9
unittests/3.x/exception.chai
Normal file
9
unittests/3.x/exception.chai
Normal file
@@ -0,0 +1,9 @@
|
||||
var x = 1
|
||||
try {
|
||||
throw(x)
|
||||
x = 2
|
||||
}
|
||||
catch(e) {
|
||||
x = e + 3
|
||||
}
|
||||
assert_equal(4, x);
|
32
unittests/3.x/exception_finally.chai
Normal file
32
unittests/3.x/exception_finally.chai
Normal file
@@ -0,0 +1,32 @@
|
||||
var finallyone = false;
|
||||
|
||||
try {
|
||||
throw(3)
|
||||
}
|
||||
catch(x) {
|
||||
assert_equal(3, x)
|
||||
}
|
||||
finally {
|
||||
finallyone = true;
|
||||
}
|
||||
|
||||
assert_equal(true, finallyone);
|
||||
|
||||
var try2 = false;
|
||||
var catch2 = false;
|
||||
var finally2 = false;
|
||||
|
||||
|
||||
try {
|
||||
try2 = true;
|
||||
}
|
||||
catch {
|
||||
catch2 = true;
|
||||
}
|
||||
finally {
|
||||
finally2 = true;
|
||||
}
|
||||
|
||||
assert_equal(true, try2);
|
||||
assert_equal(false, catch2);
|
||||
assert_equal(true, finally2);
|
34
unittests/3.x/exception_guards.chai
Normal file
34
unittests/3.x/exception_guards.chai
Normal file
@@ -0,0 +1,34 @@
|
||||
var results = [];
|
||||
|
||||
for (var i = 2; i < 6; ++i) {
|
||||
try {
|
||||
throw(i)
|
||||
}
|
||||
catch(e) : e < 2 {
|
||||
results.push_back("c1: " + e.to_string());
|
||||
}
|
||||
catch(e) : e < 4 {
|
||||
results.push_back("c2: " + e.to_string());
|
||||
}
|
||||
catch(e) {
|
||||
results.push_back("c3: " + e.to_string());
|
||||
}
|
||||
catch {
|
||||
// Should never get called
|
||||
assert_equal(false, true)
|
||||
}
|
||||
}
|
||||
|
||||
try {
|
||||
throw(3)
|
||||
}
|
||||
catch(e) : e < 3
|
||||
{
|
||||
// Should never get called
|
||||
assert_equal(false, true);
|
||||
}
|
||||
catch {
|
||||
results.push_back("defaultcatch");
|
||||
}
|
||||
|
||||
assert_equal(["c2: 2", "c2: 3", "c3: 4", "c3: 5", "defaultcatch"], results);
|
1
unittests/3.x/filter.chai
Normal file
1
unittests/3.x/filter.chai
Normal file
@@ -0,0 +1 @@
|
||||
assert_equal([1,3], filter([1, 2, 3, 4], odd))
|
7
unittests/3.x/float.chai
Normal file
7
unittests/3.x/float.chai
Normal file
@@ -0,0 +1,7 @@
|
||||
assert_equal(true, 1.2 < 2)
|
||||
assert_equal(true, 1.2 > 1)
|
||||
assert_equal(1.2, 1.2)
|
||||
|
||||
assert_equal(true, .5 > 0)
|
||||
assert_equal(true, .5 < 1)
|
||||
assert_equal(0.5, .5)
|
1
unittests/3.x/foldl.chai
Normal file
1
unittests/3.x/foldl.chai
Normal file
@@ -0,0 +1 @@
|
||||
assert_equal(10, foldl([1, 2, 3, 4], `+`, 0))
|
7
unittests/3.x/for.chai
Normal file
7
unittests/3.x/for.chai
Normal file
@@ -0,0 +1,7 @@
|
||||
var ret = []
|
||||
|
||||
for (var i = 0; i < 5; ++i) {
|
||||
ret.push_back(i);
|
||||
}
|
||||
|
||||
assert_equal([0,1,2,3,4], ret);
|
1
unittests/3.x/for_each.chai
Normal file
1
unittests/3.x/for_each.chai
Normal file
@@ -0,0 +1 @@
|
||||
for_each([1, 2, 3], print)
|
3
unittests/3.x/for_each_range.chai
Normal file
3
unittests/3.x/for_each_range.chai
Normal file
@@ -0,0 +1,3 @@
|
||||
var v = [1,2,3];
|
||||
var r = range(v);
|
||||
for_each(r, fun(x) { assert_equal(true, x>0); } )
|
4
unittests/3.x/for_each_retro.chai
Normal file
4
unittests/3.x/for_each_retro.chai
Normal file
@@ -0,0 +1,4 @@
|
||||
// Don't bother checking the output from this one, just makes sure it executes
|
||||
var v = [1,2,3];
|
||||
var r = retro(range(v));
|
||||
for_each(r, print)
|
1
unittests/3.x/function_array_adjacent.chai
Normal file
1
unittests/3.x/function_array_adjacent.chai
Normal file
@@ -0,0 +1 @@
|
||||
assert_equal(2, `+`.get_contained_functions()[0].get_arity())
|
76
unittests/3.x/function_introspection.chai
Normal file
76
unittests/3.x/function_introspection.chai
Normal file
@@ -0,0 +1,76 @@
|
||||
|
||||
#Test Function Description
|
||||
def test_function(a)
|
||||
{
|
||||
return a;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
// test_function tests
|
||||
assert_equal(test_function.get_arity(), 1);
|
||||
assert_equal(trim(test_function.get_annotation()), "#Test Function Description");
|
||||
assert_equal(test_function.get_contained_functions().size(), 0);
|
||||
assert_equal(test_function.get_param_types().size(), 2);
|
||||
|
||||
assert_equal(test_function, test_function);
|
||||
|
||||
assert_not_equal(test_function, `+`);
|
||||
|
||||
assert_equal(test_function.call([1]), 1);
|
||||
|
||||
// dynamic object function tests
|
||||
|
||||
def int::test_fun()
|
||||
{
|
||||
return this;
|
||||
}
|
||||
|
||||
assert_equal(test_fun.get_arity(), 1);
|
||||
assert_equal(test_fun.get_contained_functions.size(), 1);
|
||||
assert_equal(test_fun.get_param_types().size(), 2);
|
||||
assert_equal(test_fun, test_fun);
|
||||
var test_fun_types = test_fun.get_param_types();
|
||||
assert_equal(true, test_fun_types[0].bare_equal(Object_type));
|
||||
assert_equal(true, test_fun_types[1].bare_equal(int_type));
|
||||
|
||||
|
||||
// built-ins tests
|
||||
|
||||
assert_equal(2, `==`.get_arity());
|
||||
|
||||
// < should be the merging of two functions bool <(PODObject, PODObject) and bool <(string, string)
|
||||
// we want to peel it apart and make sure that's true
|
||||
var types = `<`.get_param_types();
|
||||
assert_equal(3, types.size());
|
||||
assert_equal(true, types[0].bare_equal(bool_type));
|
||||
assert_equal(true, types[1].bare_equal(Object_type));
|
||||
assert_equal(true, types[2].bare_equal(Object_type));
|
||||
assert_equal(2, `<`.get_contained_functions().size());
|
||||
|
||||
|
||||
// guard existence tests
|
||||
|
||||
def with_guard(x) : x > 3 {}
|
||||
def without_guard(x) {}
|
||||
|
||||
def group_guard(x) {}
|
||||
def group_guard(x) : x > 3 {}
|
||||
|
||||
assert_equal(true, with_guard.has_guard());
|
||||
assert_equal(false, without_guard.has_guard());
|
||||
|
||||
assert_equal(2, group_guard.get_contained_functions().size());
|
||||
var group = group_guard.get_contained_functions();
|
||||
|
||||
assert_equal(true, group[0].has_guard())
|
||||
assert_equal(false, group[1].has_guard())
|
||||
|
||||
assert_throws("Function does not have a guard", fun() { group[0].get_guard(); } );
|
||||
assert_throws("Function does not have a guard", fun() { without_guard.get_guard(); } );
|
||||
|
||||
var guard = with_guard.get_guard();
|
||||
|
||||
assert_equal(false, guard.has_guard());
|
||||
assert_throws("Function does not have a guard", fun() { guard.get_guard(); } );
|
3
unittests/3.x/function_reassignment.chai
Normal file
3
unittests/3.x/function_reassignment.chai
Normal file
@@ -0,0 +1,3 @@
|
||||
var x = `+`
|
||||
x = `-`
|
||||
assert_equal(1, x(5,4))
|
1
unittests/3.x/generate_range.chai
Normal file
1
unittests/3.x/generate_range.chai
Normal file
@@ -0,0 +1 @@
|
||||
assert_equal([1,2,3,4,5,6,7,8,9,10], generate_range(1, 10))
|
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user