Compare commits
169 Commits
Release-2.
...
Release-3.
Author | SHA1 | Date | |
---|---|---|---|
![]() |
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 | ||
![]() |
799b3ef388 | ||
![]() |
fe6694297f | ||
![]() |
e77ec4b16a | ||
![]() |
f070575205 | ||
![]() |
43d0d6199a | ||
![]() |
65c5178549 | ||
![]() |
c928e2992b | ||
![]() |
7fef086cab | ||
![]() |
791fd242e7 | ||
![]() |
e81b71ccc7 | ||
![]() |
ef7a785214 | ||
![]() |
f431d479fc | ||
![]() |
e11eca406d | ||
![]() |
7efb65a5c2 | ||
![]() |
39339d769a | ||
![]() |
7ac9ea7249 | ||
![]() |
7080f5d681 | ||
![]() |
22d994009e | ||
![]() |
567f911093 | ||
![]() |
5c98a5d6e7 | ||
![]() |
856b682e72 | ||
![]() |
faaa964565 | ||
![]() |
d8213a4206 | ||
![]() |
3a4421a57c | ||
![]() |
31fec2202c | ||
![]() |
13178e55e1 | ||
![]() |
968da650b2 | ||
![]() |
fb5ba0be26 | ||
![]() |
39a2c39d90 | ||
![]() |
70047424f9 | ||
![]() |
2805af1ed2 | ||
![]() |
e5a29ede5f | ||
![]() |
0c0df2c982 |
209
CMakeLists.txt
209
CMakeLists.txt
@@ -1,45 +1,212 @@
|
||||
cmake_minimum_required(VERSION 2.6)
|
||||
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 ".*~")
|
||||
|
||||
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 3)
|
||||
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)
|
||||
|
||||
enable_testing()
|
||||
|
||||
|
||||
MESSAGE(STATUS "Detecting readline support")
|
||||
if (READLINE_LIBRARY)
|
||||
MESSAGE(STATUS "Found: ${READLINE_LIBRARY}")
|
||||
SET (READLINE_LIB readline)
|
||||
SET (READLINE_FLAG " -DREADLINE_AVAILABLE")
|
||||
ADD_DEFINITIONS(/DREADLINE_AVAILABLE)
|
||||
else(READLINE_LIBRARY)
|
||||
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}")
|
||||
|
||||
SET (CMAKE_C_FLAGS " -Wall -ggdb ${READLINE_FLAG}")
|
||||
SET (CMAKE_CXX_FLAGS " -Wall -ggdb ${READLINE_FLAG}")
|
||||
IF(MSVC)
|
||||
ADD_DEFINITIONS(/W4)
|
||||
IF(CMAKE_CL_64)
|
||||
ADD_DEFINITIONS(/bigobj)
|
||||
ENDIF()
|
||||
ELSE()
|
||||
# -Wno-missing-field-initializers is for boost on macos
|
||||
ADD_DEFINITIONS(-Wall -Wextra -Wno-missing-field-initializers -Wshadow)
|
||||
ENDIF()
|
||||
|
||||
include_directories(include)
|
||||
|
||||
SET(Boost_ADDITIONAL_VERSIONS "1.44" "1.44.0" "1.43" "1.43.0" "1.42" "1.42.0" "1.41")
|
||||
SET(Boost_USE_MULTITHREADED ON)
|
||||
|
||||
if (MULTITHREAD_SUPPORT_ENABLED)
|
||||
find_package(Boost 1.36.0 COMPONENTS thread)
|
||||
|
||||
if (Boost_FOUND)
|
||||
include_directories(${Boost_INCLUDE_DIRS})
|
||||
add_executable(chaiscript_eval src/main.cpp)
|
||||
#add_executable(dispatchkit_test contrib/test/dispatchkit_test.cpp)
|
||||
target_link_libraries(chaiscript_eval dl ${Boost_LIBRARIES} ${READLINE_LIB})
|
||||
|
||||
add_library(test MODULE src/test_module.cpp)
|
||||
target_link_libraries(test ${Boost_LIBRARIES})
|
||||
|
||||
add_library(stl_extra MODULE src/stl_extra.cpp)
|
||||
target_link_libraries(stl_extra ${Boost_LIBRARIES})
|
||||
|
||||
install(TARGETS chaiscript_eval DESTINATION ${CMAKE_CURRENT_SOURCE_DIR}/bin)
|
||||
|
||||
else(Boost_FOUND)
|
||||
link_directories( ${Boost_LIBRARY_DIRS} )
|
||||
else()
|
||||
message(FATAL_ERROR "Can not find Boost")
|
||||
endif(Boost_FOUND)
|
||||
else()
|
||||
ADD_DEFINITIONS(-DCHAISCRIPT_NO_THREADS)
|
||||
endif()
|
||||
|
||||
if (CMAKE_HOST_UNIX)
|
||||
SET(DYNAMIC_LOADER "dl")
|
||||
endif(CMAKE_HOST_UNIX)
|
||||
|
||||
if (MSVC)
|
||||
# Boost on MSVC does automatic linking
|
||||
SET(LIBS ${DYNAMIC_LOADER} ${READLINE_LIB})
|
||||
else()
|
||||
SET(LIBS ${DYNAMIC_LOADER} ${Boost_LIBRARIES} ${READLINE_LIB})
|
||||
endif()
|
||||
|
||||
if (CMAKE_COMPILER_2005)
|
||||
# vs2005 is a bit too loud about possible loss of data warnings
|
||||
# ADD_DEFINITIONS(/wd4244)
|
||||
endif()
|
||||
|
||||
include_directories(${Boost_INCLUDE_DIRS})
|
||||
include_directories(${Boost_INCLUDE_DIR})
|
||||
add_executable(chai src/main.cpp)
|
||||
target_link_libraries(chai ${LIBS})
|
||||
|
||||
if (BUILD_SAMPLES)
|
||||
add_executable(example samples/example.cpp)
|
||||
target_link_libraries(example ${LIBS})
|
||||
add_executable(memory_leak_test samples/memory_leak_test.cpp)
|
||||
target_link_libraries(memory_leak_test ${LIBS})
|
||||
endif()
|
||||
|
||||
|
||||
if (BUILD_MODULES)
|
||||
add_library(stl_extra MODULE src/stl_extra.cpp)
|
||||
target_link_libraries(stl_extra ${LIBS})
|
||||
|
||||
add_library(reflection MODULE src/reflection.cpp)
|
||||
target_link_libraries(reflection ${LIBS})
|
||||
set(MODULES stl_extra reflection)
|
||||
endif()
|
||||
|
||||
file(GLOB UNIT_TESTS RELATIVE ${CMAKE_CURRENT_SOURCE_DIR}/unittests/ ${CMAKE_CURRENT_SOURCE_DIR}/unittests/*.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}
|
||||
PROPERTY ENVIRONMENT
|
||||
"CHAI_USE_PATH=${CMAKE_CURRENT_SOURCE_DIR}/unittests/"
|
||||
"CHAI_MODULE_PATH=${CMAKE_CURRENT_BINARY_DIR}/"
|
||||
)
|
||||
|
||||
IF (NOT UNIT_TEST_LIGHT)
|
||||
add_executable(utility_test unittests/utility_test.cpp)
|
||||
target_link_libraries(utility_test ${LIBS})
|
||||
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})
|
||||
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})
|
||||
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})
|
||||
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})
|
||||
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})
|
||||
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})
|
||||
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})
|
||||
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})
|
||||
add_test(NAME Eval_Catch_Exception_Test COMMAND eval_catch_exception_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})
|
||||
add_test(NAME MultiFile_Test COMMAND multifile_test)
|
||||
|
||||
add_library(test_module MODULE src/test_module.cpp)
|
||||
target_link_libraries(test_module ${LIBS})
|
||||
|
||||
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 "*/.git*" EXCLUDE
|
||||
PATTERN "*~" EXCLUDE)
|
||||
install(DIRECTORY unittests DESTINATION share/chaiscript
|
||||
PATTERN "*.chai"
|
||||
PATTERN "*.inc"
|
||||
PATTERN "*/.svn*" EXCLUDE
|
||||
PATTERN "*/.git*" EXCLUDE
|
||||
PATTERN "*~" EXCLUDE)
|
||||
install(DIRECTORY samples DESTINATION share/chaiscript
|
||||
PATTERN "*.chai"
|
||||
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
@@ -1 +0,0 @@
|
||||
This is a placeholder
|
@@ -1,8 +0,0 @@
|
||||
#!/bin/bash
|
||||
|
||||
cmake -DCMAKE_BUILD_TYPE=RelWithDebInfo .
|
||||
make install
|
||||
|
||||
INCLUDED_FILES="include/chaiscript/*.hpp include/chaiscript/dispatchkit/*.hpp include/chaiscript/language/*.hpp bin/chaiscript_eval"
|
||||
|
||||
zip -r chaiscript-1.0.zip $INCLUDED_FILES
|
136
contrib/geshi/chaiscript.php
Normal file
136
contrib/geshi/chaiscript.php
Normal file
@@ -0,0 +1,136 @@
|
||||
<?php
|
||||
/*************************************************************************************
|
||||
* chaiscript.php
|
||||
* --------------
|
||||
* Author: Jason Turner & Jonathan Turner (based on JavaScript by Ben Keen (ben.keen@gmail.com))
|
||||
* 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
|
||||
*
|
||||
* ChaiScript language file for GeSHi.
|
||||
*
|
||||
* CHANGES
|
||||
* -------
|
||||
* 2009/07/03 (1.0.0)
|
||||
* - First Release
|
||||
* 2010/03/30 (1.1.0)
|
||||
* - Updated to include more language features and remove left over pieces from JavaScript
|
||||
*
|
||||
*************************************************************************************
|
||||
*
|
||||
* This file is part of GeSHi.
|
||||
*
|
||||
* GeSHi is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* GeSHi is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with GeSHi; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*
|
||||
************************************************************************************/
|
||||
|
||||
$language_data = array (
|
||||
'LANG_NAME' => 'Chaiscript',
|
||||
'COMMENT_SINGLE' => array(1 => '//'),
|
||||
'COMMENT_MULTI' => array('/*' => '*/'),
|
||||
//Regular Expressions
|
||||
'COMMENT_REGEXP' => array(2 => "/(?<=[\\s^])s\\/(?:\\\\.|(?!\n)[^\\/\\\\])+\\/(?:\\\\.|(?!\n)[^\\/\\\\])+\\/[gimsu]*(?=[\\s$\\.\\;])|(?<=[\\s^(=])m?\\/(?:\\\\.|(?!\n)[^\\/\\\\])+\\/[gimsu]*(?=[\\s$\\.\\,\\;\\)])/iU"),
|
||||
'CASE_KEYWORDS' => GESHI_CAPS_NO_CHANGE,
|
||||
'QUOTEMARKS' => array("'", '"'),
|
||||
'ESCAPE_CHAR' => '\\',
|
||||
'KEYWORDS' => array(
|
||||
1 => array(
|
||||
'break', 'else', 'else if', 'eval', 'for', 'if', 'return', 'while', 'try', 'catch', 'finally',
|
||||
),
|
||||
2 => array(
|
||||
'def', 'false', 'fun', 'true', 'var', 'attr',
|
||||
),
|
||||
3 => array(
|
||||
// built in functions
|
||||
'throw',
|
||||
)
|
||||
),
|
||||
'SYMBOLS' => array(
|
||||
'(', ')', '[', ']', '{', '}',
|
||||
'+', '-', '*', '/', '%',
|
||||
'!', '@', '&', '|', '^',
|
||||
'<', '>', '=',
|
||||
',', ';', '?', ':'
|
||||
),
|
||||
'CASE_SENSITIVE' => array(
|
||||
GESHI_COMMENTS => false,
|
||||
1 => false,
|
||||
2 => false,
|
||||
3 => false
|
||||
),
|
||||
'STYLES' => array(
|
||||
'KEYWORDS' => array(
|
||||
1 => 'color: #000066; font-weight: bold;',
|
||||
2 => 'color: #003366; font-weight: bold;',
|
||||
3 => 'color: #000066;'
|
||||
),
|
||||
'COMMENTS' => array(
|
||||
1 => 'color: #006600; font-style: italic;',
|
||||
2 => 'color: #009966; font-style: italic;',
|
||||
'MULTI' => 'color: #006600; font-style: italic;'
|
||||
),
|
||||
'ESCAPE_CHAR' => array(
|
||||
0 => 'color: #000099; font-weight: bold;'
|
||||
),
|
||||
'BRACKETS' => array(
|
||||
0 => 'color: #009900;'
|
||||
),
|
||||
'STRINGS' => array(
|
||||
0 => 'color: #3366CC;'
|
||||
),
|
||||
'NUMBERS' => array(
|
||||
0 => 'color: #CC0000;'
|
||||
),
|
||||
'METHODS' => array(
|
||||
1 => 'color: #660066;'
|
||||
),
|
||||
'SYMBOLS' => array(
|
||||
0 => 'color: #339933;'
|
||||
),
|
||||
'REGEXPS' => array(
|
||||
),
|
||||
'SCRIPT' => array(
|
||||
0 => '',
|
||||
1 => '',
|
||||
2 => '',
|
||||
3 => ''
|
||||
)
|
||||
),
|
||||
'URLS' => array(
|
||||
1 => '',
|
||||
2 => '',
|
||||
3 => ''
|
||||
),
|
||||
'OOLANG' => true,
|
||||
'OBJECT_SPLITTERS' => array(
|
||||
1 => '.'
|
||||
),
|
||||
'REGEXPS' => array(
|
||||
),
|
||||
'STRICT_MODE_APPLIES' => GESHI_MAYBE,
|
||||
'SCRIPT_DELIMITERS' => array(
|
||||
0 => array(
|
||||
),
|
||||
1 => array(
|
||||
)
|
||||
),
|
||||
'HIGHLIGHT_STRICT_BLOCK' => array(
|
||||
0 => true,
|
||||
1 => true
|
||||
)
|
||||
);
|
||||
|
||||
?>
|
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
contrib/vim/README.txt
Normal file
7
contrib/vim/README.txt
Normal file
@@ -0,0 +1,7 @@
|
||||
Install ftdetect, indent and syntax subdirectories to:
|
||||
|
||||
~/.vim/
|
||||
|
||||
See the vim documentation on this:
|
||||
|
||||
http://vimdoc.sourceforge.net/htmldoc/syntax.html#mysyntaxfile
|
2
contrib/vim/ftdetect/chaiscript.vim
Normal file
2
contrib/vim/ftdetect/chaiscript.vim
Normal file
@@ -0,0 +1,2 @@
|
||||
au BufRead,BufNewFile *.chai set filetype=chaiscript
|
||||
|
50
contrib/vim/indent/chaiscript.vim
Normal file
50
contrib/vim/indent/chaiscript.vim
Normal file
@@ -0,0 +1,50 @@
|
||||
" Vim indent file
|
||||
" Language: ChaiScript
|
||||
" Maintainer: Jason Turner <lefticus 'at' gmail com>
|
||||
|
||||
" Only load this indent file when no other was loaded.
|
||||
if exists("b:did_indent")
|
||||
finish
|
||||
endif
|
||||
let b:did_indent = 1
|
||||
|
||||
setlocal indentexpr=GetChaiScriptIndent()
|
||||
setlocal autoindent
|
||||
|
||||
" Only define the function once.
|
||||
if exists("*GetChaiScriptIndent")
|
||||
finish
|
||||
endif
|
||||
|
||||
function! GetChaiScriptIndent()
|
||||
" Find a non-blank line above the current line.
|
||||
let lnum = prevnonblank(v:lnum - 1)
|
||||
|
||||
" Hit the start of the file, use zero indent.
|
||||
if lnum == 0
|
||||
return 0
|
||||
endif
|
||||
|
||||
" Add a 'shiftwidth' after lines that start a block:
|
||||
" lines containing a {
|
||||
let ind = indent(lnum)
|
||||
let flag = 0
|
||||
let prevline = getline(lnum)
|
||||
if prevline =~ '^.*{.*'
|
||||
let ind = ind + &shiftwidth
|
||||
let flag = 1
|
||||
endif
|
||||
|
||||
" Subtract a 'shiftwidth' after lines containing a { followed by a }
|
||||
" to keep it balanced
|
||||
if flag == 1 && prevline =~ '.*{.*}.*'
|
||||
let ind = ind - &shiftwidth
|
||||
endif
|
||||
|
||||
" Subtract a 'shiftwidth' on lines ending with }
|
||||
if getline(v:lnum) =~ '^\s*\%(}\)'
|
||||
let ind = ind - &shiftwidth
|
||||
endif
|
||||
|
||||
return ind
|
||||
endfunction
|
94
contrib/vim/syntax/chaiscript.vim
Normal file
94
contrib/vim/syntax/chaiscript.vim
Normal file
@@ -0,0 +1,94 @@
|
||||
" Vim syntax file
|
||||
" Language: ChaiScript
|
||||
" Maintainer: Jason Turner <lefticus 'at' gmail com>
|
||||
|
||||
" Quit when a (custom) syntax file was already loaded
|
||||
if exists("b:current_syntax")
|
||||
finish
|
||||
end
|
||||
|
||||
syn case match
|
||||
|
||||
" syncing method
|
||||
syn sync fromstart
|
||||
|
||||
" Strings
|
||||
syn region chaiscriptString start=+"+ end=+"+ skip=+\\\\\|\\"+ contains=chaiscriptSpecial,chaiscriptEval,@Spell
|
||||
|
||||
" Escape characters
|
||||
syn match chaiscriptSpecial contained "\\[\\abfnrtv\'\"]\|\\\d\{,3}"
|
||||
|
||||
" String evals
|
||||
syn region chaiscriptEval contained start="${" end="}"
|
||||
|
||||
" integer number
|
||||
syn match chaiscriptNumber "\<\d\+\>"
|
||||
|
||||
" floating point number, with dot, optional exponent
|
||||
syn match chaiscriptFloat "\<\d\+\.\d*\%(e[-+]\=\d\+\)\=\>"
|
||||
|
||||
" floating point number, starting with a dot, optional exponent
|
||||
syn match chaiscriptFloat "\.\d\+\%(e[-+]\=\d\+\)\=\>"
|
||||
|
||||
" floating point number, without dot, with exponent
|
||||
syn match chaiscriptFloat "\<\d\+e[-+]\=\d\+\>"
|
||||
|
||||
" Hex strings
|
||||
syn match chaiscriptNumber "\<0x\x\+\>"
|
||||
|
||||
" Binary strings
|
||||
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 chaiscriptExceptions try catch throw
|
||||
|
||||
"Keyword
|
||||
syn keyword chaiscriptKeyword def true false attr
|
||||
|
||||
"Built in types
|
||||
syn keyword chaiscriptType fun var
|
||||
|
||||
"Built in funcs, keep it simple
|
||||
syn keyword chaiscriptFunc eval throw
|
||||
|
||||
"Let's treat all backtick operator function lookups as built in too
|
||||
syn region chaiscriptFunc matchgroup=chaiscriptFunc start="`" end="`"
|
||||
|
||||
" Account for the "[1..10]" syntax, treating it as an operator
|
||||
" Intentionally leaving out all of the normal, well known operators
|
||||
syn match chaiscriptOperator "\.\."
|
||||
|
||||
" Guard seperator as an operator
|
||||
syn match chaiscriptOperator ":"
|
||||
|
||||
" Comments
|
||||
syn match chaiscriptComment "//.*$" contains=@Spell
|
||||
syn region chaiscriptComment matchgroup=chaiscriptComment start="/\*" end="\*/" contains=@Spell
|
||||
|
||||
|
||||
|
||||
hi def link chaiscriptExceptions Exception
|
||||
hi def link chaiscriptKeyword Keyword
|
||||
hi def link chaiscriptStatement Statement
|
||||
hi def link chaiscriptRepeat Repeat
|
||||
hi def link chaiscriptString String
|
||||
hi def link chaiscriptNumber Number
|
||||
hi def link chaiscriptFloat Float
|
||||
hi def link chaiscriptOperator Operator
|
||||
hi def link chaiscriptConstant Constant
|
||||
hi def link chaiscriptCond Conditional
|
||||
hi def link chaiscriptFunction Function
|
||||
hi def link chaiscriptComment Comment
|
||||
hi def link chaiscriptTodo Todo
|
||||
hi def link chaiscriptError Error
|
||||
hi def link chaiscriptSpecial SpecialChar
|
||||
hi def link chaiscriptFunc Identifier
|
||||
hi def link chaiscriptType Type
|
||||
hi def link chaiscriptEval Special
|
||||
|
||||
let b:current_syntax = "chaiscript"
|
||||
|
||||
" vim: nowrap sw=2 sts=2 ts=8 noet
|
1
description.txt
Normal file
1
description.txt
Normal file
@@ -0,0 +1 @@
|
||||
ChaiScript is a header-only C++ embedded scripting language loosely based on ECMA script. It is designed for ease of use and tight integration with C++. See http://www.chaiscript.com for more details.
|
@@ -1,27 +1,569 @@
|
||||
// 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)
|
||||
// Copyright 2009-2011, 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 \ref LangKeywordRef
|
||||
/// \sa \ref LangInPlaceRef
|
||||
/// \sa \ref LangObjectSystemRef
|
||||
/// \sa http://www.chaiscript.com
|
||||
/// \sa http://www.github.com/ChaiScript/ChaiScript
|
||||
///
|
||||
/// <hr>
|
||||
///
|
||||
/// \section gettingstarted Getting Started
|
||||
///
|
||||
/// \li \ref basics
|
||||
/// \li \ref eval
|
||||
/// \li \ref addingitems
|
||||
/// \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
|
||||
/// #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 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 #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 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 *, boost::shared_ptr<T>,
|
||||
/// boost::shared_ptr<const T>, boost::reference_wrapper<T>, boost::reference_wrapper<const T> and value types automatically.
|
||||
///
|
||||
/// If a 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(boost::shared_ptr<int>);
|
||||
/// void fun6(boost::shared_ptr<const int>);
|
||||
/// void fun7(const boost::shared_ptr<int> &);
|
||||
/// void fun8(const boost::shared_ptr<const int> &);
|
||||
/// void fun9(boost::reference_wrapper<int>);
|
||||
/// void fun10(boost::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 boost::function objects.
|
||||
///
|
||||
/// \code
|
||||
/// void callafunc(const boost::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 boost::function
|
||||
///
|
||||
/// boost::function<void ()> f = chai.eval<boost::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 and removes the requirement for boost_threads.
|
||||
///
|
||||
/// <hr>
|
||||
///
|
||||
/// \subsection exceptions Exception Handling
|
||||
///
|
||||
/// 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()
|
||||
/// {
|
||||
/// chaiscript::ChaiScript chai;
|
||||
/// chai.add(chaiscript::fun(&throwexception), "throwexception");
|
||||
/// chai("try { throwexception(); } catch (e) { print(e.what()); }"); // prints "err"
|
||||
///
|
||||
/// try {
|
||||
/// chai("throw(1)");
|
||||
/// } catch (chaiscript::Boxed_Value bv) {
|
||||
/// int i = chaiscript::boxed_cast<int>(bv);
|
||||
/// // i == 1
|
||||
/// }
|
||||
/// }
|
||||
/// \endcode
|
||||
|
||||
/// \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 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 "dispatchkit/dispatchkit.hpp"
|
||||
#include "dispatchkit/bootstrap.hpp"
|
||||
#include "dispatchkit/bootstrap_stl.hpp"
|
||||
#include "dispatchkit/function_call.hpp"
|
||||
#include "dispatchkit/dynamic_object.hpp"
|
||||
#include "dispatchkit/boxed_pod_value.hpp"
|
||||
|
||||
#ifdef BOOST_HAS_DECLSPEC
|
||||
#define CHAISCRIPT_MODULE_EXPORT extern "C" __declspec(dllexport)
|
||||
|
@@ -1,19 +1,46 @@
|
||||
#ifndef __chaiscript_threading_hpp__
|
||||
#define __chaiscript_threading_hpp__
|
||||
// This file is distributed under the BSD License.
|
||||
// See "license.txt" for details.
|
||||
// Copyright 2009-2011, 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>
|
||||
#else
|
||||
#warning "ChaiScript is compiling without thread safety."
|
||||
#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 boost::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
|
||||
using boost::unique_lock;
|
||||
using boost::shared_lock;
|
||||
using boost::lock_guard;
|
||||
using boost::shared_mutex;
|
||||
using boost::recursive_mutex;
|
||||
|
||||
|
||||
/// Typesafe thread specific storage. If threading is enabled, this class uses boost::thread_specific_ptr<T>. If
|
||||
/// threading is not enabled, the class always returns the same data, regardless of which thread it is called from.
|
||||
template<typename T>
|
||||
class Thread_Storage
|
||||
{
|
||||
@@ -43,6 +70,32 @@ namespace chaiscript
|
||||
};
|
||||
|
||||
#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 +116,7 @@ namespace chaiscript
|
||||
};
|
||||
|
||||
#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-2011, 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) throw()
|
||||
: from(t_from), to(&t_to), m_what(t_what)
|
||||
{
|
||||
}
|
||||
|
||||
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 &t_what) throw()
|
||||
: m_what(t_what)
|
||||
{
|
||||
}
|
||||
|
||||
virtual ~bad_boxed_cast() throw() {}
|
||||
|
||||
/// \brief Description of what error occured
|
||||
virtual const char * what() const throw()
|
||||
{
|
||||
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,7 +1,7 @@
|
||||
// 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)
|
||||
// Copyright 2009-2011, Jonathan Turner (jonathan@emptycrate.com)
|
||||
// and Jason Turner (jason@emptycrate.com)
|
||||
// http://www.chaiscript.com
|
||||
|
||||
#include <boost/preprocessor.hpp>
|
||||
@@ -10,8 +10,8 @@
|
||||
#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__
|
||||
#ifndef CHAISCRIPT_BIND_FIRST_HPP_
|
||||
#define CHAISCRIPT_BIND_FIRST_HPP_
|
||||
|
||||
#include <boost/function.hpp>
|
||||
#include <boost/bind.hpp>
|
||||
@@ -30,21 +30,40 @@
|
||||
|
||||
namespace chaiscript
|
||||
{
|
||||
|
||||
namespace detail
|
||||
{
|
||||
/// \brief Helper function for binding the first parameter of a class method pointer. Used in chaiscript::fun overloads
|
||||
/// that take 1 or 2 parameters to pre-bind to the function.
|
||||
///
|
||||
/// \param[in] f method pointer to bind
|
||||
/// \param[in] o object to bind as first parameter
|
||||
/// \returns a new boost::function object with one fewer parameters than the function passed in.
|
||||
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)
|
||||
{
|
||||
return boost::bind(f, o BOOST_PP_COMMA_IF(n) BOOST_PP_ENUM(n, param, _));
|
||||
return boost::bind(boost::mem_fn(f), o BOOST_PP_COMMA_IF(n) BOOST_PP_ENUM(n, param, _));
|
||||
}
|
||||
|
||||
/// \brief Helper function for binding the first parameter of a const class method pointer. Used in chaiscript::fun overloads
|
||||
/// that take 1 or 2 parameters to pre-bind to the function.
|
||||
///
|
||||
/// \param[in] f method pointer to bind
|
||||
/// \param[in] o object to bind as first parameter
|
||||
/// \returns a new boost::function object with one fewer parameters than the function passed in.
|
||||
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)
|
||||
{
|
||||
return boost::bind(f, o BOOST_PP_COMMA_IF(n) BOOST_PP_ENUM(n, param, _));
|
||||
return boost::bind(boost::mem_fn(f), o BOOST_PP_COMMA_IF(n) BOOST_PP_ENUM(n, param, _));
|
||||
}
|
||||
|
||||
/// \brief Helper function for binding the first parameter of a function pointer. Used in chaiscript::fun overloads
|
||||
/// that take 1 or 2 parameters to pre-bind to the function.
|
||||
///
|
||||
/// \param[in] f method pointer to bind
|
||||
/// \param[in] o object to bind as first parameter
|
||||
/// \returns a new boost::function object with one fewer parameters than the function passed in.
|
||||
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)
|
||||
@@ -52,6 +71,12 @@ namespace chaiscript
|
||||
return boost::bind(f, o BOOST_PP_COMMA_IF(n) BOOST_PP_ENUM(n, param, _));
|
||||
}
|
||||
|
||||
/// \brief Helper function for binding the first parameter of a boost::function object. Used in chaiscript::fun overloads
|
||||
/// that take 1 or 2 parameters to pre-bind to the function.
|
||||
///
|
||||
/// \param[in] f method pointer to bind
|
||||
/// \param[in] o object to bind as first parameter
|
||||
/// \returns a new boost::function object with one fewer parameters than the function passed in.
|
||||
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)
|
||||
@@ -59,7 +84,10 @@ namespace chaiscript
|
||||
return boost::bind(f, o BOOST_PP_COMMA_IF(n) BOOST_PP_ENUM(n, param, _));
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
#undef n
|
||||
#undef m
|
||||
|
||||
#endif
|
||||
|
@@ -1,35 +1,36 @@
|
||||
// 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)
|
||||
// Copyright 2009-2011, 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_pod_value.hpp"
|
||||
#include <boost/function_types/result_type.hpp>
|
||||
|
||||
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 Assigns a POD value from a Boxed_POD_Value. Helps support operators between
|
||||
/// disparate POD types.
|
||||
/// \param[in,out] p1 object to assign to
|
||||
/// \param[in] v Boxed_POD_Value to assign from
|
||||
/// \returns Reference to p1, to support normal C assignment semantics
|
||||
template<typename P1>
|
||||
P1 &assign_pod(P1 &p1, Boxed_POD_Value v)
|
||||
P1 &assign_pod(P1 &p1, const Boxed_POD_Value &v)
|
||||
{
|
||||
|
||||
if (v.m_isfloat)
|
||||
if (v.isfloat)
|
||||
{
|
||||
return (p1 = P1(v.d));
|
||||
} else {
|
||||
@@ -37,10 +38,13 @@ namespace chaiscript
|
||||
}
|
||||
}
|
||||
|
||||
/// \brief Constructs a new POD value object from a Boxed_POD_Value
|
||||
/// \param[in] v Boxed_POD_Value to copy into the new object
|
||||
/// \returns The newly created object.
|
||||
template<typename P1>
|
||||
P1 construct_pod(Boxed_POD_Value v)
|
||||
{
|
||||
if (v.m_isfloat)
|
||||
if (v.isfloat)
|
||||
{
|
||||
return P1(v.d);
|
||||
} else {
|
||||
@@ -48,43 +52,59 @@ namespace chaiscript
|
||||
}
|
||||
}
|
||||
|
||||
/// \brief Performs a bitwise and assignment (&=) on the given object with the given Boxed_POD_Value
|
||||
/// \param[in,out] p1 object to bitwise and assign to
|
||||
/// \param[in] r Boxed_POD_Value to assign from
|
||||
/// \returns Reference to p1, to support normal C assignment semantics
|
||||
template<typename P1>
|
||||
P1 &assign_bitwise_and_pod(P1 &p1, Boxed_POD_Value r)
|
||||
{
|
||||
if (!r.m_isfloat)
|
||||
if (!r.isfloat)
|
||||
{
|
||||
return p1 &= P1(r.i);
|
||||
}
|
||||
|
||||
throw bad_boxed_cast("&= only valid for integer types");
|
||||
throw exception::bad_boxed_cast("&= only valid for integer types");
|
||||
}
|
||||
|
||||
/// \brief Performs a xor assignment (^=) on the given object with the given Boxed_POD_Value
|
||||
/// \param[in,out] p1 object to xor assign to
|
||||
/// \param[in] r Boxed_POD_Value to assign from
|
||||
/// \returns Reference to p1, to support normal C assignment semantics
|
||||
template<typename P1>
|
||||
P1 &assign_xor_pod(P1 &p1, Boxed_POD_Value r)
|
||||
{
|
||||
if (!r.m_isfloat)
|
||||
if (!r.isfloat)
|
||||
{
|
||||
return p1 ^= P1(r.i);
|
||||
}
|
||||
|
||||
throw bad_boxed_cast("^= only valid for integer types");
|
||||
throw exception::bad_boxed_cast("^= only valid for integer types");
|
||||
}
|
||||
|
||||
/// \brief Performs a bitwise or assignment (|=) on the given object with the given Boxed_POD_Value
|
||||
/// \param[in,out] p1 object to bitwise or assign to
|
||||
/// \param[in] r Boxed_POD_Value to assign from
|
||||
/// \returns Reference to p1, to support normal C assignment semantics
|
||||
template<typename P1>
|
||||
P1 &assign_bitwise_or_pod(P1 &p1, Boxed_POD_Value r)
|
||||
{
|
||||
if (!r.m_isfloat)
|
||||
if (!r.isfloat)
|
||||
{
|
||||
return p1 |= P1(r.i);
|
||||
}
|
||||
|
||||
throw bad_boxed_cast("&= only valid for integer types");
|
||||
throw exception::bad_boxed_cast("&= only valid for integer types");
|
||||
}
|
||||
|
||||
/// \brief Performs an assign difference (-=) on the given object with the given Boxed_POD_Value
|
||||
/// \param[in,out] p1 object to difference assign to
|
||||
/// \param[in] r Boxed_POD_Value to assign from
|
||||
/// \returns Reference to p1, to support normal C assignment semantics
|
||||
template<typename P1>
|
||||
P1 &assign_difference_pod(P1 &p1, Boxed_POD_Value r)
|
||||
{
|
||||
if (r.m_isfloat)
|
||||
if (r.isfloat)
|
||||
{
|
||||
return p1 -= P1(r.d);
|
||||
} else {
|
||||
@@ -92,22 +112,30 @@ namespace chaiscript
|
||||
}
|
||||
}
|
||||
|
||||
/// \brief Performs an assign shift left (<<=) on the given object with the given Boxed_POD_Value
|
||||
/// \param[in,out] p1 object to assign shift left to
|
||||
/// \param[in] r Boxed_POD_Value to assign from
|
||||
/// \returns Reference to p1, to support normal C assignment semantics
|
||||
template<typename P1>
|
||||
P1 &assign_left_shift_pod(P1 &p1, Boxed_POD_Value r)
|
||||
{
|
||||
if (!r.m_isfloat)
|
||||
if (!r.isfloat)
|
||||
{
|
||||
return p1 <<= P1(r.i);
|
||||
}
|
||||
|
||||
throw bad_boxed_cast("<<= only valid for integer types");
|
||||
throw exception::bad_boxed_cast("<<= only valid for integer types");
|
||||
}
|
||||
|
||||
|
||||
/// \brief Performs an assign product (*=) on the given object with the given Boxed_POD_Value
|
||||
/// \param[in,out] p1 object to assign product to
|
||||
/// \param[in] r Boxed_POD_Value to assign from
|
||||
/// \returns Reference to p1, to support normal C assignment semantics
|
||||
template<typename P1>
|
||||
P1 &assign_product_pod(P1 &p1, Boxed_POD_Value r)
|
||||
{
|
||||
if (r.m_isfloat)
|
||||
if (r.isfloat)
|
||||
{
|
||||
return p1 *= P1(r.d);
|
||||
} else {
|
||||
@@ -115,10 +143,14 @@ namespace chaiscript
|
||||
}
|
||||
}
|
||||
|
||||
/// \brief Performs an assign quotient (/=) on the given object with the given Boxed_POD_Value
|
||||
/// \param[in,out] p1 object to assign quotient to
|
||||
/// \param[in] r Boxed_POD_Value to assign from
|
||||
/// \returns Reference to p1, to support normal C assignment semantics
|
||||
template<typename P1>
|
||||
P1 &assign_quotient_pod(P1 &p1, Boxed_POD_Value r)
|
||||
{
|
||||
if (r.m_isfloat)
|
||||
if (r.isfloat)
|
||||
{
|
||||
return p1 /= P1(r.d);
|
||||
} else {
|
||||
@@ -126,34 +158,45 @@ namespace chaiscript
|
||||
}
|
||||
}
|
||||
|
||||
/// \brief Performs an assign remainder (%=) on the given object with the given Boxed_POD_Value
|
||||
/// \param[in,out] p1 object to assign remainder to
|
||||
/// \param[in] r Boxed_POD_Value to assign from
|
||||
/// \returns Reference to p1, to support normal C assignment semantics
|
||||
template<typename P1>
|
||||
P1 &assign_remainder_pod(P1 &p1, Boxed_POD_Value r)
|
||||
{
|
||||
if (!r.m_isfloat)
|
||||
if (!r.isfloat)
|
||||
{
|
||||
return p1 %= P1(r.i);
|
||||
}
|
||||
|
||||
throw bad_boxed_cast("%= only valid for integer types");
|
||||
throw exception::bad_boxed_cast("%= only valid for integer types");
|
||||
}
|
||||
|
||||
|
||||
/// \brief Performs an assign shift right (>>=) on the given object with the given Boxed_POD_Value
|
||||
/// \param[in,out] p1 object to assign shift right to
|
||||
/// \param[in] r Boxed_POD_Value to assign from
|
||||
/// \returns Reference to p1, to support normal C assignment semantics
|
||||
template<typename P1>
|
||||
P1 &assign_right_shift_pod(P1 &p1, Boxed_POD_Value r)
|
||||
{
|
||||
if (!r.m_isfloat)
|
||||
if (!r.isfloat)
|
||||
{
|
||||
return p1 >>= P1(r.i);
|
||||
}
|
||||
|
||||
throw bad_boxed_cast(">>= only valid for integer types");
|
||||
throw exception::bad_boxed_cast(">>= only valid for integer types");
|
||||
}
|
||||
|
||||
|
||||
/// \brief Performs an assign sum (+=) on the given object with the given Boxed_POD_Value
|
||||
/// \param[in,out] p1 object to sum assign to
|
||||
/// \param[in] r Boxed_POD_Value to assign from
|
||||
/// \returns Reference to p1, to support normal C assignment semantics
|
||||
template<typename P1>
|
||||
P1 &assign_sum_pod(P1 &p1, Boxed_POD_Value r)
|
||||
{
|
||||
if (r.m_isfloat)
|
||||
if (r.isfloat)
|
||||
{
|
||||
return p1 += P1(r.d);
|
||||
} else {
|
||||
@@ -163,6 +206,10 @@ namespace chaiscript
|
||||
|
||||
}
|
||||
|
||||
/// \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,6 +222,12 @@ namespace chaiscript
|
||||
return m;
|
||||
}
|
||||
|
||||
|
||||
/// \brief Add all arithmetic operators appropriate for integers for the templated type.
|
||||
/// Used during bootstrap, also available to users.
|
||||
/// \tparam T Type to create arithmetic operators for
|
||||
/// \param[in,out] m module to add arithmetic operators to
|
||||
/// \returns the passed in ModulePtr or the newly constructed one if the default params are used.
|
||||
template<typename T>
|
||||
ModulePtr opers_integer_arithmetic(ModulePtr m = ModulePtr(new Module()))
|
||||
{
|
||||
@@ -207,6 +260,11 @@ namespace chaiscript
|
||||
return m;
|
||||
}
|
||||
|
||||
/// \brief Add all arithmetic operators appropriate for floating point numbers for the templated type.
|
||||
/// Used during bootstrap, also available to users.
|
||||
/// \tparam T Type to create arithmetic operators for
|
||||
/// \param[in,out] m module to add arithmetic operators to
|
||||
/// \returns the passed in ModulePtr or the newly constructed one if the default params are used.
|
||||
template<typename T>
|
||||
ModulePtr opers_float_arithmetic(ModulePtr m = ModulePtr(new Module()))
|
||||
{
|
||||
@@ -224,9 +282,11 @@ namespace chaiscript
|
||||
return m;
|
||||
}
|
||||
|
||||
/**
|
||||
* Add a copy constructor for type T
|
||||
*/
|
||||
/// \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()))
|
||||
{
|
||||
@@ -234,9 +294,13 @@ namespace chaiscript
|
||||
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 +309,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 +320,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<<
|
||||
@@ -383,7 +438,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 boost::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 +446,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 +466,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");
|
||||
}
|
||||
}
|
||||
|
||||
@@ -451,12 +506,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 +523,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 +531,38 @@ 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)
|
||||
{
|
||||
boost::shared_ptr<const dispatch::Dynamic_Proxy_Function> pf = boost::dynamic_pointer_cast<const dispatch::Dynamic_Proxy_Function>(t_pf);
|
||||
if (pf)
|
||||
{
|
||||
return pf->get_guard();
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
static Const_Proxy_Function get_guard(const Const_Proxy_Function &t_pf)
|
||||
{
|
||||
boost::shared_ptr<const dispatch::Dynamic_Proxy_Function> pf = boost::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 boost::shared_ptr<chaiscript::detail::Dispatch_Engine> bootstrap2(boost::shared_ptr<chaiscript::detail::Dispatch_Engine> e = boost::shared_ptr<chaiscript::detail::Dispatch_Engine> (new chaiscript::detail::Dispatch_Engine()))
|
||||
{
|
||||
e->add(user_type<void>(), "void");
|
||||
return e;
|
||||
@@ -504,30 +586,71 @@ namespace chaiscript
|
||||
}
|
||||
}
|
||||
|
||||
template<typename FunctionType>
|
||||
static std::vector<Boxed_Value> do_return_boxed_value_vector(FunctionType f,
|
||||
const dispatch::Proxy_Function_Base *b)
|
||||
{
|
||||
typedef typename boost::function_types::result_type<FunctionType>::type Vector;
|
||||
Vector v = (b->*f)();
|
||||
|
||||
std::vector<Boxed_Value> vbv;
|
||||
for (typename Vector::const_iterator itr = v.begin();
|
||||
itr != v.end();
|
||||
++itr)
|
||||
{
|
||||
vbv.push_back(const_var(*itr));
|
||||
}
|
||||
|
||||
return vbv;
|
||||
}
|
||||
|
||||
template<typename Function>
|
||||
static boost::function<std::vector<Boxed_Value> (const dispatch::Proxy_Function_Base*)> return_boxed_value_vector(const Function &f)
|
||||
{
|
||||
return boost::bind(&do_return_boxed_value_vector<Function>, f, _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<Proxy_Function>(), "Function");
|
||||
m->add(user_type<std::exception>(), "exception");
|
||||
|
||||
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(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(boost::function<std::string (const std::runtime_error &)>(&what)), "what");
|
||||
|
||||
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->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() { 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(&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");
|
||||
m->add(fun(&Boxed_Value::is_const), "is_var_const");
|
||||
@@ -549,6 +672,9 @@ namespace chaiscript
|
||||
m->add(fun(&Type_Info::name), "cpp_name");
|
||||
m->add(fun(&Type_Info::bare_name), "cpp_bare_name");
|
||||
m->add(fun(&Type_Info::bare_equal), "bare_equal");
|
||||
typedef bool (Type_Info::*typeinfocompare)(const Type_Info &) const;
|
||||
m->add(fun(typeinfocompare(&Type_Info::operator==)), "==");
|
||||
m->add(fun(&Type_Info::bare_equal), "bare_equal");
|
||||
|
||||
|
||||
basic_constructors<bool>("bool", m);
|
||||
@@ -575,13 +701,14 @@ namespace chaiscript
|
||||
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(boost::bind(&bind_function, _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<boost::remove_const<dispatch::Proxy_Function_Base>::type>), "=");
|
||||
m->add(fun(&ptr_assign<boost::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(boost::bind(&call_exists, _1))),
|
||||
"call_exists");
|
||||
|
||||
m->add(fun(&type_match), "type_match");
|
||||
|
@@ -1,25 +1,29 @@
|
||||
// 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)
|
||||
// Copyright 2009-2011, 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 "register_function.hpp"
|
||||
|
||||
|
||||
namespace chaiscript
|
||||
{
|
||||
namespace bootstrap
|
||||
{
|
||||
namespace standard_library
|
||||
{
|
||||
/**
|
||||
* Bidir_Range, based on the D concept of ranges.
|
||||
@@ -29,6 +33,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 +88,86 @@ 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)>(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 *)>(&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 +204,77 @@ 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(boost::function<typename ContainerType::reference (ContainerType *, int)>
|
||||
(boost::mem_fn(static_cast<indexoper>(&ContainerType::at)))), "[]");
|
||||
m->add(
|
||||
fun(boost::function<typename ContainerType::const_reference (const ContainerType *, int)>
|
||||
(boost::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(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;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Add sequence concept to the given ContainerType
|
||||
* http://www.sgi.com/tech/stl/Sequence.html
|
||||
@@ -227,8 +290,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;
|
||||
}
|
||||
@@ -252,7 +315,8 @@ namespace chaiscript
|
||||
push_back_name = "push_back";
|
||||
}
|
||||
|
||||
m->add(fun(&ContainerType::push_back), push_back_name);
|
||||
typedef void (ContainerType::*pushback)(const typename ContainerType::value_type &);
|
||||
m->add(fun(static_cast<pushback>(&ContainerType::push_back)), push_back_name);
|
||||
m->add(fun(&ContainerType::pop_back), "pop_back");
|
||||
return m;
|
||||
}
|
||||
@@ -263,9 +327,11 @@ 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");
|
||||
|
||||
@@ -276,8 +342,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 +357,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,8 +390,7 @@ namespace chaiscript
|
||||
template<typename ContainerType>
|
||||
ModulePtr unique_associative_container_type(const std::string &/*type*/, ModulePtr m = ModulePtr(new Module()))
|
||||
{
|
||||
// m->add(fun<size_t (ContainerType::*)(const typename ContainerType::key_type &) const>(&ContainerType::count), "count");
|
||||
m->add(fun(boost::function<int (const ContainerType *, const typename ContainerType::key_type &)>(&ContainerType::count)), "count");
|
||||
m->add(fun(boost::function<int (const ContainerType *, const typename ContainerType::key_type &)>(boost::mem_fn(&ContainerType::count))), "count");
|
||||
|
||||
return m;
|
||||
}
|
||||
@@ -333,7 +403,10 @@ namespace chaiscript
|
||||
ModulePtr map_type(const std::string &type, ModulePtr m = ModulePtr(new Module()))
|
||||
{
|
||||
m->add(user_type<MapType>(), type);
|
||||
m->add(fun(&MapType::operator[]), "[]");
|
||||
|
||||
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);
|
||||
assignable_type<MapType>(type, m);
|
||||
@@ -373,6 +446,10 @@ namespace chaiscript
|
||||
{
|
||||
m->add(user_type<VectorType>(), type);
|
||||
|
||||
typedef typename VectorType::reference (VectorType::*frontptr)();
|
||||
m->add(fun(static_cast<frontptr>(&VectorType::front)), "front");
|
||||
|
||||
|
||||
back_insertion_sequence_type<VectorType>(type, m);
|
||||
sequence_type<VectorType>(type, m);
|
||||
random_access_container_type<VectorType>(type, m);
|
||||
@@ -381,9 +458,30 @@ namespace chaiscript
|
||||
assignable_type<VectorType>(type, m);
|
||||
input_range_type<VectorType>(type, m);
|
||||
|
||||
return 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); \
|
||||
while (!r1.empty()) \
|
||||
{ \
|
||||
if (!eq(r1.front(), r2.front())) \
|
||||
{ \
|
||||
return false; \
|
||||
} \
|
||||
r1.pop_front(); \
|
||||
r2.pop_front(); \
|
||||
} \
|
||||
return true; \
|
||||
} \
|
||||
}");
|
||||
}
|
||||
|
||||
return m;
|
||||
}
|
||||
|
||||
/**
|
||||
* Add a String container
|
||||
@@ -417,16 +515,22 @@ namespace chaiscript
|
||||
|
||||
typedef boost::function<int (const String *, const String &, int)> find_func;
|
||||
|
||||
m->add(fun(find_func(static_cast<find_func_ptr>(&String::find))), "find");
|
||||
m->add(fun(find_func(static_cast<find_func_ptr>(&String::rfind))), "rfind");
|
||||
m->add(fun(find_func(static_cast<find_func_ptr>(&String::find_first_of))), "find_first_of");
|
||||
m->add(fun(find_func(static_cast<find_func_ptr>(&String::find_last_of))), "find_last_of");
|
||||
m->add(fun(find_func(static_cast<find_func_ptr>(&String::find_first_not_of))), "find_first_not_of");
|
||||
m->add(fun(find_func(static_cast<find_func_ptr>(&String::find_last_not_of))), "find_last_not_of");
|
||||
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");
|
||||
|
||||
m->add(fun(&String::c_str), "c_str");
|
||||
m->add(fun(&String::data), "data");
|
||||
|
||||
|
||||
return m;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
#endif
|
||||
|
112
include/chaiscript/dispatchkit/boxed_cast.hpp
Normal file
112
include/chaiscript/dispatchkit/boxed_cast.hpp
Normal file
@@ -0,0 +1,112 @@
|
||||
// This file is distributed under the BSD License.
|
||||
// See "license.txt" for details.
|
||||
// Copyright 2009-2011, Jonathan Turner (jonathan@emptycrate.com)
|
||||
// and Jason Turner (jason@emptycrate.com)
|
||||
// http://www.chaiscript.com
|
||||
|
||||
#ifndef __boxed_cast_hpp__
|
||||
#define __boxed_cast_hpp__
|
||||
|
||||
#include "type_info.hpp"
|
||||
#include "boxed_value.hpp"
|
||||
#include "boxed_cast_helper.hpp"
|
||||
#include "dynamic_cast_conversion.hpp"
|
||||
|
||||
#include "../chaiscript_threading.hpp"
|
||||
#include <boost/shared_ptr.hpp>
|
||||
#include <boost/any.hpp>
|
||||
#include <boost/function.hpp>
|
||||
#include <boost/ref.hpp>
|
||||
#include <boost/cstdint.hpp>
|
||||
#include <boost/type_traits/add_const.hpp>
|
||||
#include <boost/type_traits/is_polymorphic.hpp>
|
||||
#include <boost/integer_traits.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, &, *, boost::shared_ptr, boost::reference_wrapper,
|
||||
/// and boost::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 boost::reference_wrapper can be extracted as reference,
|
||||
/// pointer or value types
|
||||
/// \li Boxed_Value constructed from boost::shared_ptr or value types can be extracted as reference,
|
||||
/// pointer, value, or boost::shared_ptr types
|
||||
///
|
||||
/// Conversions to boost::function objects are attempted as well
|
||||
///
|
||||
/// Example:
|
||||
/// \code
|
||||
/// // All of the following should succeed
|
||||
/// chaiscript::Boxed_Value bv(1);
|
||||
/// boost::shared_ptr<int> spi = chaiscript::boxed_cast<boost::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);
|
||||
/// boost::shared_ptr<const int> cspi = chaiscript::boxed_cast<boost::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
|
||||
///
|
||||
/// boost::function conversion example
|
||||
/// \code
|
||||
/// chaiscript::ChaiScript chai;
|
||||
/// Boxed_Value bv = chai.eval("`+`"); // Get the functor for the + operator which is built in
|
||||
/// boost::function<int (int, int)> f = chaiscript::boxed_cast<boost::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 boost::bad_any_cast &) {
|
||||
|
||||
#ifdef BOOST_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 (boost::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 boost::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 BOOST_MSVC
|
||||
#pragma warning(pop)
|
||||
#endif
|
||||
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
#endif
|
||||
|
273
include/chaiscript/dispatchkit/boxed_cast_helper.hpp
Normal file
273
include/chaiscript/dispatchkit/boxed_cast_helper.hpp
Normal file
@@ -0,0 +1,273 @@
|
||||
// This file is distributed under the BSD License.
|
||||
// See "license.txt" for details.
|
||||
// Copyright 2009-2011, 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"
|
||||
|
||||
#include <boost/shared_ptr.hpp>
|
||||
#include <boost/any.hpp>
|
||||
#include <boost/ref.hpp>
|
||||
#include <boost/type_traits/add_const.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 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())));
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
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 (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_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 (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_Inner for casting to a & type
|
||||
*/
|
||||
template<typename Result>
|
||||
struct Cast_Helper_Inner<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_Inner for casting to a boost::shared_ptr<> type
|
||||
*/
|
||||
template<typename Result>
|
||||
struct Cast_Helper_Inner<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_Inner for casting to a boost::shared_ptr<const> type
|
||||
*/
|
||||
template<typename Result>
|
||||
struct Cast_Helper_Inner<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_Inner for casting to a const boost::shared_ptr<> & type
|
||||
*/
|
||||
template<typename Result>
|
||||
struct Cast_Helper_Inner<const boost::shared_ptr<Result> > : Cast_Helper_Inner<boost::shared_ptr<Result> >
|
||||
{
|
||||
};
|
||||
|
||||
template<typename Result>
|
||||
struct Cast_Helper_Inner<const boost::shared_ptr<Result> &> : Cast_Helper_Inner<boost::shared_ptr<Result> >
|
||||
{
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Cast_Helper_Inner for casting to a const boost::shared_ptr<const> & type
|
||||
*/
|
||||
template<typename Result>
|
||||
struct Cast_Helper_Inner<const boost::shared_ptr<const Result> > : Cast_Helper_Inner<boost::shared_ptr<const Result> >
|
||||
{
|
||||
};
|
||||
|
||||
template<typename Result>
|
||||
struct Cast_Helper_Inner<const boost::shared_ptr<const Result> &> : Cast_Helper_Inner<boost::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 boost::reference_wrapper type
|
||||
*/
|
||||
template<typename Result>
|
||||
struct Cast_Helper_Inner<boost::reference_wrapper<Result> > : Cast_Helper_Inner<Result &>
|
||||
{
|
||||
};
|
||||
|
||||
template<typename Result>
|
||||
struct Cast_Helper_Inner<const boost::reference_wrapper<Result> > : Cast_Helper_Inner<Result &>
|
||||
{
|
||||
};
|
||||
|
||||
template<typename Result>
|
||||
struct Cast_Helper_Inner<const boost::reference_wrapper<Result> &> : Cast_Helper_Inner<Result &>
|
||||
{
|
||||
};
|
||||
|
||||
template<typename Result>
|
||||
struct Cast_Helper_Inner<boost::reference_wrapper<const Result> > : Cast_Helper_Inner<const Result &>
|
||||
{
|
||||
};
|
||||
|
||||
template<typename Result>
|
||||
struct Cast_Helper_Inner<const boost::reference_wrapper<const Result> > : Cast_Helper_Inner<const Result &>
|
||||
{
|
||||
};
|
||||
|
||||
template<typename Result>
|
||||
struct Cast_Helper_Inner<const boost::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
|
260
include/chaiscript/dispatchkit/boxed_pod_value.hpp
Normal file
260
include/chaiscript/dispatchkit/boxed_pod_value.hpp
Normal file
@@ -0,0 +1,260 @@
|
||||
// This file is distributed under the BSD License.
|
||||
// See "license.txt" for details.
|
||||
// Copyright 2009-2011, Jonathan Turner (jonathan@emptycrate.com)
|
||||
// and Jason Turner (jason@emptycrate.com)
|
||||
// http://www.chaiscript.com
|
||||
|
||||
#ifndef CHAISCRIPT_BOXED_POD_VALUE_HPP_
|
||||
#define CHAISCRIPT_BOXED_POD_VALUE_HPP_
|
||||
|
||||
#include "type_info.hpp"
|
||||
#include "boxed_value.hpp"
|
||||
#include "boxed_cast_helper.hpp"
|
||||
#include <boost/any.hpp>
|
||||
#include <boost/cstdint.hpp>
|
||||
#include <boost/integer_traits.hpp>
|
||||
|
||||
namespace chaiscript
|
||||
{
|
||||
|
||||
/// \brief Represents any numeric type, generically. Used internally for generic operations between POD values
|
||||
class Boxed_POD_Value
|
||||
{
|
||||
public:
|
||||
Boxed_POD_Value(const Boxed_Value &v)
|
||||
: d(0), i(0), 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);
|
||||
isfloat = true;
|
||||
} else if (inp_ == typeid(float)) {
|
||||
d = boxed_cast<float>(v);
|
||||
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 ((isfloat)?d:i) == ((r.isfloat)?r.d:r.i);
|
||||
}
|
||||
|
||||
bool operator<(const Boxed_POD_Value &r) const
|
||||
{
|
||||
return ((isfloat)?d:i) < ((r.isfloat)?r.d:r.i);
|
||||
}
|
||||
|
||||
bool operator>(const Boxed_POD_Value &r) const
|
||||
{
|
||||
return ((isfloat)?d:i) > ((r.isfloat)?r.d:r.i);
|
||||
}
|
||||
|
||||
bool operator>=(const Boxed_POD_Value &r) const
|
||||
{
|
||||
return ((isfloat)?d:i) >= ((r.isfloat)?r.d:r.i);
|
||||
}
|
||||
|
||||
bool operator<=(const Boxed_POD_Value &r) const
|
||||
{
|
||||
return ((isfloat)?d:i) <= ((r.isfloat)?r.d:r.i);
|
||||
}
|
||||
|
||||
bool operator!=(const Boxed_POD_Value &r) const
|
||||
{
|
||||
return ((isfloat)?d:i) != ((r.isfloat)?r.d:r.i);
|
||||
}
|
||||
|
||||
Boxed_Value operator+(const Boxed_POD_Value &r) const
|
||||
{
|
||||
if (!isfloat && !r.isfloat)
|
||||
{
|
||||
return smart_size(i + r.i);
|
||||
}
|
||||
|
||||
return Boxed_Value(((isfloat)?d:i) + ((r.isfloat)?r.d:r.i));
|
||||
}
|
||||
|
||||
Boxed_Value operator-(const Boxed_POD_Value &r) const
|
||||
{
|
||||
if (!isfloat && !r.isfloat)
|
||||
{
|
||||
return smart_size(i - r.i);
|
||||
}
|
||||
|
||||
return Boxed_Value(((isfloat)?d:i) - ((r.isfloat)?r.d:r.i));
|
||||
}
|
||||
|
||||
Boxed_Value operator&(const Boxed_POD_Value &r) const
|
||||
{
|
||||
if (!isfloat && !r.isfloat)
|
||||
{
|
||||
return Boxed_Value(i & r.i);
|
||||
}
|
||||
|
||||
throw exception::bad_boxed_cast("& only valid for integer types");
|
||||
}
|
||||
|
||||
Boxed_Value operator^(const Boxed_POD_Value &r) const
|
||||
{
|
||||
if (!isfloat && !r.isfloat)
|
||||
{
|
||||
return Boxed_Value(i ^ r.i);
|
||||
}
|
||||
|
||||
throw exception::bad_boxed_cast("^ only valid for integer types");
|
||||
}
|
||||
|
||||
Boxed_Value operator|(const Boxed_POD_Value &r) const
|
||||
{
|
||||
if (!isfloat && !r.isfloat)
|
||||
{
|
||||
return Boxed_Value(i | r.i);
|
||||
}
|
||||
|
||||
throw exception::bad_boxed_cast("| only valid for integer types");
|
||||
}
|
||||
|
||||
Boxed_Value operator/(const Boxed_POD_Value &r) const
|
||||
{
|
||||
if (!isfloat && !r.isfloat)
|
||||
{
|
||||
return smart_size(i / r.i);
|
||||
}
|
||||
|
||||
return Boxed_Value(((isfloat)?d:i) / ((r.isfloat)?r.d:r.i));
|
||||
}
|
||||
|
||||
Boxed_Value operator<<(const Boxed_POD_Value &r) const
|
||||
{
|
||||
if (!isfloat && !r.isfloat)
|
||||
{
|
||||
return smart_size(i << r.i);
|
||||
}
|
||||
|
||||
throw exception::bad_boxed_cast("<< only valid for integer types");
|
||||
}
|
||||
|
||||
|
||||
Boxed_Value operator*(const Boxed_POD_Value &r) const
|
||||
{
|
||||
if (!isfloat && !r.isfloat)
|
||||
{
|
||||
return smart_size(i * r.i);
|
||||
}
|
||||
|
||||
return Boxed_Value(((isfloat)?d:i) * ((r.isfloat)?r.d:r.i));
|
||||
}
|
||||
|
||||
|
||||
Boxed_Value operator%(const Boxed_POD_Value &r) const
|
||||
{
|
||||
if (!isfloat && !r.isfloat)
|
||||
{
|
||||
return smart_size(i % r.i);
|
||||
}
|
||||
|
||||
throw exception::bad_boxed_cast("% only valid for integer types");
|
||||
}
|
||||
|
||||
Boxed_Value operator>>(const Boxed_POD_Value &r) const
|
||||
{
|
||||
if (!isfloat && !r.isfloat)
|
||||
{
|
||||
return smart_size(i >> r.i);
|
||||
}
|
||||
|
||||
throw exception::bad_boxed_cast(">> only valid for integer types");
|
||||
}
|
||||
|
||||
Boxed_Value smart_size(boost::int64_t t_i) const
|
||||
{
|
||||
if (t_i < boost::integer_traits<int>::const_min
|
||||
|| t_i > boost::integer_traits<int>::const_max)
|
||||
{
|
||||
return Boxed_Value(t_i);
|
||||
} else {
|
||||
return Boxed_Value(static_cast<int>(t_i));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
double d;
|
||||
boost::int64_t i;
|
||||
|
||||
bool 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 &> : Cast_Helper<Boxed_POD_Value>
|
||||
{
|
||||
};
|
||||
|
||||
/**
|
||||
* Cast_Helper for converting from Boxed_Value to Boxed_POD_Value
|
||||
*/
|
||||
template<>
|
||||
struct Cast_Helper<const Boxed_POD_Value> : Cast_Helper<Boxed_POD_Value>
|
||||
{
|
||||
};
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
#endif
|
||||
|
@@ -1,14 +1,16 @@
|
||||
// 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)
|
||||
// Copyright 2009-2011, 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>
|
||||
@@ -17,15 +19,12 @@
|
||||
#include <boost/bind.hpp>
|
||||
#include <boost/cstdint.hpp>
|
||||
#include <boost/type_traits/add_const.hpp>
|
||||
#include <boost/integer_traits.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:
|
||||
@@ -42,13 +41,6 @@ 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)
|
||||
{
|
||||
@@ -59,10 +51,9 @@ namespace chaiscript
|
||||
Data(const Type_Info &ti,
|
||||
const boost::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)
|
||||
m_is_ref(tr), m_is_null(t_is_null)
|
||||
{
|
||||
}
|
||||
|
||||
@@ -71,33 +62,25 @@ 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;
|
||||
|
||||
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;
|
||||
boost::any m_obj;
|
||||
bool m_is_ref;
|
||||
boost::function<bool (boost::any*)> m_is_null;
|
||||
std::vector<boost::shared_ptr<Data> > m_dependencies;
|
||||
};
|
||||
|
||||
struct Object_Data
|
||||
{
|
||||
static boost::shared_ptr<Data> get(Boxed_Value::Void_Type)
|
||||
{
|
||||
return boost::shared_ptr<Data> (new Data(
|
||||
detail::Get_Type_Info<void>::get(),
|
||||
@@ -107,91 +90,50 @@ namespace chaiscript
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
boost::shared_ptr<Data> get(const boost::shared_ptr<T> *obj)
|
||||
static boost::shared_ptr<Data> get(const boost::shared_ptr<T> *obj)
|
||||
{
|
||||
return get(*obj);
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
boost::shared_ptr<Data> get(const boost::shared_ptr<T> &obj)
|
||||
static boost::shared_ptr<Data> get(const boost::shared_ptr<T> &obj)
|
||||
{
|
||||
bool b_const = boost::is_const<T>::value;
|
||||
|
||||
boost::shared_ptr<Data> data(new Data(
|
||||
return boost::shared_ptr<Data>(new Data(
|
||||
detail::Get_Type_Info<T>::get(),
|
||||
boost::any(obj),
|
||||
false,
|
||||
&Data::unique<T>,
|
||||
&Data::is_null<T>)
|
||||
boost::function<bool (boost::any *)>(&Data::is_null<T>))
|
||||
);
|
||||
|
||||
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 boost::shared_ptr<Data> get(T *t)
|
||||
{
|
||||
return get(boost::ref(*t));
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
boost::shared_ptr<Data> get(boost::reference_wrapper<T> obj)
|
||||
static boost::shared_ptr<Data> get(boost::reference_wrapper<T> obj)
|
||||
{
|
||||
bool b_const = boost::is_const<T>::value;
|
||||
|
||||
boost::shared_ptr<Data> data(new Data(
|
||||
return boost::shared_ptr<Data>(new Data(
|
||||
detail::Get_Type_Info<T>::get(),
|
||||
boost::any(obj),
|
||||
true)
|
||||
);
|
||||
|
||||
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 boost::shared_ptr<Data> get(const T& t)
|
||||
{
|
||||
boost::shared_ptr<Data> data(new Data(
|
||||
return boost::shared_ptr<Data>(new Data(
|
||||
detail::Get_Type_Info<T>::get(),
|
||||
boost::any(boost::shared_ptr<T>(new T(t))),
|
||||
false,
|
||||
&Data::unique<T>,
|
||||
&Data::is_null<T>)
|
||||
boost::function<bool (boost::any *)>(&Data::is_null<T>))
|
||||
);
|
||||
|
||||
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 boost::shared_ptr<Data> get()
|
||||
{
|
||||
return boost::shared_ptr<Data> (new Data(
|
||||
Type_Info(),
|
||||
@@ -200,37 +142,6 @@ namespace chaiscript
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* 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:
|
||||
@@ -239,9 +150,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();
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -256,7 +166,7 @@ namespace chaiscript
|
||||
* Unknown-type constructor
|
||||
*/
|
||||
Boxed_Value()
|
||||
: m_data(get_object_cache().get())
|
||||
: m_data(Object_Data::get())
|
||||
{
|
||||
}
|
||||
|
||||
@@ -269,20 +179,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
|
||||
@@ -336,7 +232,7 @@ namespace chaiscript
|
||||
}
|
||||
}
|
||||
|
||||
boost::any get() const
|
||||
const boost::any & get() const
|
||||
{
|
||||
return m_data->m_obj;
|
||||
}
|
||||
@@ -351,566 +247,129 @@ namespace chaiscript
|
||||
return !is_ref();
|
||||
}
|
||||
|
||||
void clear_dependencies()
|
||||
{
|
||||
m_data->m_dependencies.clear();
|
||||
}
|
||||
|
||||
template<typename InItr>
|
||||
void add_dependencies(InItr begin, const InItr &end)
|
||||
{
|
||||
while (begin != end)
|
||||
{
|
||||
if (begin->m_data != m_data)
|
||||
{
|
||||
m_data->m_dependencies.push_back(begin->m_data);
|
||||
}
|
||||
++begin;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
private:
|
||||
boost::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 < std::numeric_limits<int>::min()
|
||||
|| i > std::numeric_limits<int>::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, boost::shared_ptr, or boost::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)
|
||||
{
|
||||
return Boxed_Value( const_cast<typename boost::add_const<T>::type>(t) );
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
Boxed_Value const_var(const boost::shared_ptr<T> &t)
|
||||
{
|
||||
return Boxed_Value( boost::const_pointer_cast<typename boost::add_const<T>::type>(t) );
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
Boxed_Value const_var(const boost::reference_wrapper<T> &t)
|
||||
{
|
||||
return Boxed_Value( boost::cref(t.get()) );
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
Boxed_Value const_var(const T &t)
|
||||
Boxed_Value const_var_impl(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
|
||||
*/
|
||||
/// \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_impl(T *t)
|
||||
{
|
||||
return Boxed_Value( const_cast<typename boost::add_const<T>::type *>(t) );
|
||||
}
|
||||
|
||||
/// \brief Takes a boost::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_impl(const boost::shared_ptr<T> &t)
|
||||
{
|
||||
return Boxed_Value( boost::const_pointer_cast<typename boost::add_const<T>::type>(t) );
|
||||
}
|
||||
|
||||
/// \brief Takes a boost::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 boost::reference_wrapper<T> &t)
|
||||
{
|
||||
return Boxed_Value( boost::cref(t.get()) );
|
||||
}
|
||||
}
|
||||
|
||||
/// \brief Takes an object and returns an immutable Boxed_Value. If the object is a boost::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 detail::const_var_impl(t);
|
||||
}
|
||||
|
||||
|
||||
|
||||
/// \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();
|
||||
}
|
||||
}
|
||||
|
||||
namespace std
|
||||
{
|
||||
template<> void swap(chaiscript::Boxed_Value &lhs, chaiscript::Boxed_Value &rhs)
|
||||
{
|
||||
lhs.swap(rhs);
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
|
@@ -1,11 +1,11 @@
|
||||
// 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)
|
||||
// Copyright 2009-2011, Jonathan Turner (jonathan@emptycrate.com)
|
||||
// and Jason Turner (jason@emptycrate.com)
|
||||
// http://www.chaiscript.com
|
||||
|
||||
#ifndef __dispatchkit_hpp__
|
||||
#define __dispatchkit_hpp__
|
||||
#ifndef CHAISCRIPT_DISPATCHKIT_HPP_
|
||||
#define CHAISCRIPT_DISPATCHKIT_HPP_
|
||||
|
||||
#include <typeinfo>
|
||||
#include <string>
|
||||
@@ -26,8 +26,14 @@
|
||||
#include "dynamic_object.hpp"
|
||||
#include "../chaiscript_threading.hpp"
|
||||
|
||||
|
||||
/// \namespace chaiscript::dispatch
|
||||
/// \brief Classes and functions specific to the runtime dispatch side of ChaiScript. Some items may be of use to the end user.
|
||||
|
||||
namespace chaiscript
|
||||
{
|
||||
/// \brief Holds a collection of ChaiScript settings which can be applied to the ChaiScript runtime.
|
||||
/// Used to implement loadable module support.
|
||||
class Module
|
||||
{
|
||||
public:
|
||||
@@ -37,6 +43,12 @@ namespace chaiscript
|
||||
return *this;
|
||||
}
|
||||
|
||||
Module &add(const Dynamic_Cast_Conversion &d)
|
||||
{
|
||||
m_conversions.push_back(d);
|
||||
return *this;
|
||||
}
|
||||
|
||||
Module &add(const Proxy_Function &f, const std::string &name)
|
||||
{
|
||||
m_funcs.push_back(std::make_pair(f, name));
|
||||
@@ -63,12 +75,14 @@ namespace chaiscript
|
||||
apply(m_typeinfos.begin(), m_typeinfos.end(), t_engine);
|
||||
apply(m_funcs.begin(), m_funcs.end(), t_engine);
|
||||
apply_eval(m_evals.begin(), m_evals.end(), t_eval);
|
||||
apply_single(m_conversions.begin(), m_conversions.end(), t_engine);
|
||||
}
|
||||
|
||||
private:
|
||||
std::vector<std::pair<Type_Info, std::string> > m_typeinfos;
|
||||
std::vector<std::pair<Proxy_Function, std::string> > m_funcs;
|
||||
std::vector<std::string> m_evals;
|
||||
std::vector<Dynamic_Cast_Conversion> m_conversions;
|
||||
|
||||
template<typename T, typename InItr>
|
||||
void apply(InItr begin, InItr end, T &t) const
|
||||
@@ -80,6 +94,16 @@ namespace chaiscript
|
||||
}
|
||||
}
|
||||
|
||||
template<typename T, typename InItr>
|
||||
void apply_single(InItr begin, InItr end, T &t) const
|
||||
{
|
||||
while (begin != end)
|
||||
{
|
||||
t.add(*begin);
|
||||
++begin;
|
||||
}
|
||||
}
|
||||
|
||||
template<typename T, typename InItr>
|
||||
void apply_eval(InItr begin, InItr end, T &t) const
|
||||
{
|
||||
@@ -89,53 +113,85 @@ namespace chaiscript
|
||||
++begin;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
};
|
||||
|
||||
/// Convenience typedef for Module objects to be added to the ChaiScript runtime
|
||||
typedef boost::shared_ptr<Module> ModulePtr;
|
||||
|
||||
namespace detail
|
||||
{
|
||||
/**
|
||||
* A Proxy_Function implementation that is able to take
|
||||
* a vector of Proxy_Functions and perform a dispatch on them. It is
|
||||
* used specifically in the case of dealing with Function object variables
|
||||
*/
|
||||
class Dispatch_Function : public Proxy_Function_Base
|
||||
class Dispatch_Function : public dispatch::Proxy_Function_Base
|
||||
{
|
||||
public:
|
||||
Dispatch_Function(const std::vector<std::pair<std::string, Proxy_Function > > &t_funcs)
|
||||
: Proxy_Function_Base(std::vector<Type_Info>()),
|
||||
Dispatch_Function(const std::vector<Proxy_Function> &t_funcs)
|
||||
: Proxy_Function_Base(build_type_infos(t_funcs)),
|
||||
m_funcs(t_funcs)
|
||||
{
|
||||
}
|
||||
|
||||
virtual bool operator==(const Proxy_Function_Base &) const
|
||||
virtual bool operator==(const dispatch::Proxy_Function_Base &rhs) const
|
||||
{
|
||||
try {
|
||||
const Dispatch_Function &dispatchfun = dynamic_cast<const Dispatch_Function &>(rhs);
|
||||
return m_funcs == dispatchfun.m_funcs;
|
||||
} catch (const std::bad_cast &) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
virtual ~Dispatch_Function() {}
|
||||
|
||||
virtual Boxed_Value operator()(const std::vector<Boxed_Value> ¶ms) const
|
||||
virtual std::vector<Const_Proxy_Function> get_contained_functions() const
|
||||
{
|
||||
return dispatch(m_funcs.begin(), m_funcs.end(), params);
|
||||
return std::vector<Const_Proxy_Function>(m_funcs.begin(), m_funcs.end());
|
||||
}
|
||||
|
||||
|
||||
virtual int get_arity() const
|
||||
{
|
||||
typedef std::vector<Proxy_Function> function_vec;
|
||||
|
||||
function_vec::const_iterator begin = m_funcs.begin();
|
||||
const function_vec::const_iterator end = m_funcs.end();
|
||||
|
||||
if (begin != end)
|
||||
{
|
||||
int arity = (*begin)->get_arity();
|
||||
|
||||
++begin;
|
||||
|
||||
while (begin != end)
|
||||
{
|
||||
if (arity != (*begin)->get_arity())
|
||||
{
|
||||
// The arities in the list do not match, so it's unspecified
|
||||
return -1;
|
||||
}
|
||||
|
||||
++begin;
|
||||
}
|
||||
|
||||
return arity;
|
||||
}
|
||||
|
||||
return -1; // unknown arity
|
||||
}
|
||||
|
||||
virtual bool call_match(const std::vector<Boxed_Value> &vals) const
|
||||
{
|
||||
typedef std::vector<std::pair<std::string, Proxy_Function > > function_vec;
|
||||
typedef std::vector<Proxy_Function> function_vec;
|
||||
|
||||
function_vec::const_iterator begin = m_funcs.begin();
|
||||
function_vec::const_iterator end = m_funcs.end();
|
||||
|
||||
while (begin != end)
|
||||
{
|
||||
if (begin->second->call_match(vals))
|
||||
if ((*begin)->call_match(vals))
|
||||
{
|
||||
return true;
|
||||
} else {
|
||||
@@ -148,35 +204,102 @@ namespace chaiscript
|
||||
|
||||
virtual std::string annotation() const
|
||||
{
|
||||
return "";
|
||||
return "Multiple method dispatch function wrapper.";
|
||||
}
|
||||
|
||||
protected:
|
||||
virtual Boxed_Value do_call(const std::vector<Boxed_Value> ¶ms) const
|
||||
{
|
||||
return dispatch::dispatch(m_funcs.begin(), m_funcs.end(), params);
|
||||
}
|
||||
|
||||
private:
|
||||
std::vector<std::pair<std::string, Proxy_Function > > m_funcs;
|
||||
std::vector<Proxy_Function> m_funcs;
|
||||
|
||||
static std::vector<Type_Info> build_type_infos(const std::vector<Proxy_Function> &t_funcs)
|
||||
{
|
||||
typedef std::vector<Proxy_Function> function_vec;
|
||||
|
||||
function_vec::const_iterator begin = t_funcs.begin();
|
||||
const function_vec::const_iterator end = t_funcs.end();
|
||||
|
||||
if (begin != end)
|
||||
{
|
||||
std::vector<Type_Info> type_infos = (*begin)->get_param_types();
|
||||
|
||||
++begin;
|
||||
|
||||
bool sizemismatch = false;
|
||||
|
||||
while (begin != end)
|
||||
{
|
||||
std::vector<Type_Info> param_types = (*begin)->get_param_types();
|
||||
|
||||
if (param_types.size() != type_infos.size())
|
||||
{
|
||||
sizemismatch = true;
|
||||
}
|
||||
|
||||
for (size_t i = 0; i < type_infos.size() && i < param_types.size(); ++i)
|
||||
{
|
||||
if (!(type_infos[i] == param_types[i]))
|
||||
{
|
||||
type_infos[i] = detail::Get_Type_Info<Boxed_Value>::get();
|
||||
}
|
||||
}
|
||||
|
||||
++begin;
|
||||
}
|
||||
|
||||
assert(type_infos.size() > 0 && " type_info vector size is < 0, this is only possible if something else is broken");
|
||||
|
||||
if (sizemismatch)
|
||||
{
|
||||
type_infos.resize(1);
|
||||
}
|
||||
|
||||
return type_infos;
|
||||
}
|
||||
|
||||
return std::vector<Type_Info>();
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
namespace exception
|
||||
{
|
||||
/**
|
||||
* 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 reserved_word_error : std::runtime_error
|
||||
class reserved_word_error : public std::runtime_error
|
||||
{
|
||||
reserved_word_error(const std::string &word) throw()
|
||||
: std::runtime_error("Reserved word not allowed in object name: " + word)
|
||||
public:
|
||||
reserved_word_error(const std::string &t_word) throw()
|
||||
: std::runtime_error("Reserved word not allowed in object name: " + t_word), m_word(t_word)
|
||||
{
|
||||
}
|
||||
|
||||
virtual ~reserved_word_error() throw() {}
|
||||
|
||||
std::string word() const
|
||||
{
|
||||
return m_word;
|
||||
}
|
||||
|
||||
private:
|
||||
std::string m_word;
|
||||
|
||||
};
|
||||
|
||||
/**
|
||||
* Exception thrown in the case that a non-const object was added as a shared object
|
||||
*/
|
||||
struct global_non_const : std::runtime_error
|
||||
class global_non_const : public std::runtime_error
|
||||
{
|
||||
public:
|
||||
global_non_const() throw()
|
||||
: std::runtime_error("a global object must be const")
|
||||
{
|
||||
@@ -184,8 +307,10 @@ namespace chaiscript
|
||||
|
||||
virtual ~global_non_const() throw() {}
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
namespace detail
|
||||
{
|
||||
/**
|
||||
* Main class for the dispatchkit. Handles management
|
||||
* of the object stack, functions and registered types.
|
||||
@@ -195,27 +320,34 @@ namespace chaiscript
|
||||
public:
|
||||
typedef std::map<std::string, chaiscript::Type_Info> Type_Name_Map;
|
||||
typedef std::map<std::string, Boxed_Value> Scope;
|
||||
typedef boost::tuples::tuple<std::map<std::string, Boxed_Value>, std::deque<Scope>, bool> StackData;
|
||||
typedef std::deque<Scope> StackData;
|
||||
typedef boost::shared_ptr<StackData> Stack;
|
||||
|
||||
struct State
|
||||
{
|
||||
std::multimap<std::string, Proxy_Function> m_functions;
|
||||
std::map<std::string, std::vector<Proxy_Function> > m_functions;
|
||||
std::map<std::string, Boxed_Value> m_global_objects;
|
||||
Type_Name_Map m_types;
|
||||
std::set<std::string> m_reserved_words;
|
||||
};
|
||||
|
||||
Dispatch_Engine()
|
||||
: m_place_holder(boost::shared_ptr<Placeholder_Object>(new Placeholder_Object()))
|
||||
: m_place_holder(boost::shared_ptr<dispatch::Placeholder_Object>(new dispatch::Placeholder_Object()))
|
||||
{
|
||||
StackData &stack = get_stack_data();
|
||||
stack.get<1>().push_back(Scope());
|
||||
}
|
||||
|
||||
~Dispatch_Engine()
|
||||
{
|
||||
Boxed_Value::clear_cache();
|
||||
detail::Dynamic_Conversions::get().cleanup(m_conversions.begin(), m_conversions.end());
|
||||
}
|
||||
|
||||
/**
|
||||
* Add a new conversion for upcasting to a base class
|
||||
*/
|
||||
void add(const Dynamic_Cast_Conversion &d)
|
||||
{
|
||||
m_conversions.push_back(d);
|
||||
return detail::Dynamic_Conversions::get().add_conversion(d);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -224,9 +356,6 @@ namespace chaiscript
|
||||
bool add(const Proxy_Function &f, const std::string &name)
|
||||
{
|
||||
validate_object_name(name);
|
||||
|
||||
StackData &stack = get_stack_data();
|
||||
stack.get<0>().erase(name);
|
||||
return add_function(f, name);
|
||||
}
|
||||
|
||||
@@ -239,13 +368,12 @@ namespace chaiscript
|
||||
validate_object_name(name);
|
||||
StackData &stack = get_stack_data();
|
||||
|
||||
for (int i = stack.get<1>().size()-1; i >= 0; --i)
|
||||
for (int i = static_cast<int>(stack.size())-1; i >= 0; --i)
|
||||
{
|
||||
std::map<std::string, Boxed_Value>::const_iterator itr = (stack.get<1>())[i].find(name);
|
||||
if (itr != (stack.get<1>())[i].end())
|
||||
std::map<std::string, Boxed_Value>::const_iterator itr = stack[i].find(name);
|
||||
if (itr != stack[i].end())
|
||||
{
|
||||
stack.get<0>().erase(name);
|
||||
(stack.get<1>())[i][name] = obj;
|
||||
stack[i][name] = obj;
|
||||
return;
|
||||
}
|
||||
}
|
||||
@@ -260,8 +388,7 @@ namespace chaiscript
|
||||
{
|
||||
StackData &stack = get_stack_data();
|
||||
validate_object_name(name);
|
||||
stack.get<0>().erase(name);
|
||||
stack.get<1>().back()[name] = obj;
|
||||
stack.back()[name] = obj;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -269,18 +396,13 @@ namespace chaiscript
|
||||
*/
|
||||
void add_global_const(const Boxed_Value &obj, const std::string &name)
|
||||
{
|
||||
StackData &stack = get_stack_data();
|
||||
validate_object_name(name);
|
||||
if (!obj.is_const())
|
||||
{
|
||||
throw global_non_const();
|
||||
throw exception::global_non_const();
|
||||
}
|
||||
|
||||
stack.get<0>().erase(name);
|
||||
|
||||
#ifndef CHAISCRIPT_NO_THREADS
|
||||
boost::unique_lock<boost::shared_mutex> l(m_global_object_mutex);
|
||||
#endif
|
||||
chaiscript::detail::threading::unique_lock<chaiscript::detail::threading::shared_mutex> l(m_global_object_mutex);
|
||||
|
||||
m_state.m_global_objects[name] = obj;
|
||||
}
|
||||
@@ -291,7 +413,7 @@ namespace chaiscript
|
||||
void new_scope()
|
||||
{
|
||||
StackData &stack = get_stack_data();
|
||||
stack.get<1>().push_back(Scope());
|
||||
stack.push_back(Scope());
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -300,16 +422,9 @@ namespace chaiscript
|
||||
void pop_scope()
|
||||
{
|
||||
StackData &stack = get_stack_data();
|
||||
if (stack.get<1>().size() > 1)
|
||||
if (stack.size() > 1)
|
||||
{
|
||||
Scope &scope(stack.get<1>().back());
|
||||
for (Scope::const_iterator itr = scope.begin();
|
||||
itr != scope.end();
|
||||
++itr)
|
||||
{
|
||||
stack.get<0>().erase(itr->first);
|
||||
}
|
||||
stack.get<1>().pop_back();
|
||||
stack.pop_back();
|
||||
} else {
|
||||
throw std::range_error("Unable to pop global stack");
|
||||
}
|
||||
@@ -330,8 +445,7 @@ namespace chaiscript
|
||||
Stack new_stack() const
|
||||
{
|
||||
Stack s(new Stack::element_type());
|
||||
s->get<1>().push_back(Scope());
|
||||
s->get<2>() = false;
|
||||
s->push_back(Scope());
|
||||
return s;
|
||||
}
|
||||
|
||||
@@ -340,17 +454,6 @@ namespace chaiscript
|
||||
return m_stack_holder->stack;
|
||||
}
|
||||
|
||||
void sync_cache()
|
||||
{
|
||||
m_stack_holder->stack->get<0>().clear();
|
||||
|
||||
#ifndef CHAISCRIPT_NO_THREADS
|
||||
boost::shared_lock<boost::shared_mutex> l(m_mutex);
|
||||
#endif
|
||||
|
||||
get_function_cache() = m_state.m_functions;
|
||||
}
|
||||
|
||||
/**
|
||||
* Searches the current stack for an object of the given name
|
||||
* includes a special overload for the _ place holder object to
|
||||
@@ -365,50 +468,43 @@ namespace chaiscript
|
||||
}
|
||||
|
||||
StackData &stack = get_stack_data();
|
||||
std::map<std::string, Boxed_Value> &cache = stack.get<0>();
|
||||
|
||||
// Is it in the cache?
|
||||
std::map<std::string, Boxed_Value>::const_iterator itr = cache.find(name);
|
||||
if (itr != cache.end())
|
||||
{
|
||||
return itr->second;
|
||||
}
|
||||
|
||||
// Is it in the stack?
|
||||
for (int i = stack.get<1>().size()-1; i >= 0; --i)
|
||||
for (int i = static_cast<int>(stack.size())-1; i >= 0; --i)
|
||||
{
|
||||
std::map<std::string, Boxed_Value>::const_iterator stackitr = (stack.get<1>())[i].find(name);
|
||||
if (stackitr != (stack.get<1>())[i].end())
|
||||
std::map<std::string, Boxed_Value>::const_iterator stackitr = stack[i].find(name);
|
||||
if (stackitr != stack[i].end())
|
||||
{
|
||||
cache[name] = stackitr->second;
|
||||
return stackitr->second;
|
||||
}
|
||||
}
|
||||
|
||||
// Is the value we are looking for a global?
|
||||
{
|
||||
#ifndef CHAISCRIPT_NO_THREADS
|
||||
boost::shared_lock<boost::shared_mutex> l(m_global_object_mutex);
|
||||
#endif
|
||||
chaiscript::detail::threading::shared_lock<chaiscript::detail::threading::shared_mutex> l(m_global_object_mutex);
|
||||
|
||||
itr = m_state.m_global_objects.find(name);
|
||||
std::map<std::string, Boxed_Value>::const_iterator itr = m_state.m_global_objects.find(name);
|
||||
if (itr != m_state.m_global_objects.end())
|
||||
{
|
||||
cache[name] = itr->second;
|
||||
return itr->second;
|
||||
}
|
||||
}
|
||||
|
||||
// If all that failed, then check to see if it's a function
|
||||
std::vector<std::pair<std::string, std::multimap<std::string, Proxy_Function >::mapped_type> > funcs = get_function(name);
|
||||
std::vector<Proxy_Function> funcs = get_function(name);
|
||||
|
||||
if (funcs.empty())
|
||||
{
|
||||
throw std::range_error("Object not known: " + name);
|
||||
} else {
|
||||
Boxed_Value f(Const_Proxy_Function(new Dispatch_Function(funcs)));
|
||||
cache[name] = f;
|
||||
return f;
|
||||
if (funcs.size() == 1)
|
||||
{
|
||||
// Return the first item if there is only one,
|
||||
// no reason to take the cast of the extra level of dispatch
|
||||
return const_var(*funcs.begin());
|
||||
} else {
|
||||
return Boxed_Value(Const_Proxy_Function(new Dispatch_Function(funcs)));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -419,9 +515,7 @@ namespace chaiscript
|
||||
{
|
||||
add_global_const(const_var(ti), name + "_type");
|
||||
|
||||
#ifndef CHAISCRIPT_NO_THREADS
|
||||
boost::unique_lock<boost::shared_mutex> l(m_mutex);
|
||||
#endif
|
||||
chaiscript::detail::threading::unique_lock<chaiscript::detail::threading::shared_mutex> l(m_mutex);
|
||||
|
||||
m_state.m_types.insert(std::make_pair(name, ti));
|
||||
}
|
||||
@@ -431,9 +525,7 @@ namespace chaiscript
|
||||
*/
|
||||
Type_Info get_type(const std::string &name) const
|
||||
{
|
||||
#ifndef CHAISCRIPT_NO_THREADS
|
||||
boost::shared_lock<boost::shared_mutex> l(m_mutex);
|
||||
#endif
|
||||
chaiscript::detail::threading::shared_lock<chaiscript::detail::threading::shared_mutex> l(m_mutex);
|
||||
|
||||
Type_Name_Map::const_iterator itr = m_state.m_types.find(name);
|
||||
|
||||
@@ -452,9 +544,7 @@ namespace chaiscript
|
||||
*/
|
||||
std::string get_type_name(const Type_Info &ti) const
|
||||
{
|
||||
#ifndef CHAISCRIPT_NO_THREADS
|
||||
boost::shared_lock<boost::shared_mutex> l(m_mutex);
|
||||
#endif
|
||||
chaiscript::detail::threading::shared_lock<chaiscript::detail::threading::shared_mutex> l(m_mutex);
|
||||
|
||||
for (Type_Name_Map::const_iterator itr = m_state.m_types.begin();
|
||||
itr != m_state.m_types.end();
|
||||
@@ -474,9 +564,7 @@ namespace chaiscript
|
||||
*/
|
||||
std::vector<std::pair<std::string, Type_Info> > get_types() const
|
||||
{
|
||||
#ifndef CHAISCRIPT_NO_THREADS
|
||||
boost::shared_lock<boost::shared_mutex> l(m_mutex);
|
||||
#endif
|
||||
chaiscript::detail::threading::shared_lock<chaiscript::detail::threading::shared_mutex> l(m_mutex);
|
||||
|
||||
return std::vector<std::pair<std::string, Type_Info> >(m_state.m_types.begin(), m_state.m_types.end());
|
||||
}
|
||||
@@ -484,13 +572,23 @@ namespace chaiscript
|
||||
/**
|
||||
* Return a function by name
|
||||
*/
|
||||
std::vector<std::pair<std::string, std::multimap<std::string, Proxy_Function >::mapped_type> >
|
||||
std::vector< Proxy_Function >
|
||||
get_function(const std::string &t_name) const
|
||||
{
|
||||
std::pair<std::multimap<std::string, Proxy_Function >::const_iterator, std::multimap<std::string, Proxy_Function >::const_iterator> range
|
||||
= get_function_cache().equal_range(t_name);
|
||||
chaiscript::detail::threading::shared_lock<chaiscript::detail::threading::shared_mutex> l(m_mutex);
|
||||
|
||||
const std::map<std::string, std::vector<Proxy_Function> > &funs = get_functions_int();
|
||||
|
||||
std::map<std::string, std::vector<Proxy_Function> >::const_iterator itr
|
||||
= funs.find(t_name);
|
||||
|
||||
if (itr != funs.end())
|
||||
{
|
||||
return itr->second;
|
||||
} else {
|
||||
return std::vector<Proxy_Function>();
|
||||
}
|
||||
|
||||
return std::vector<std::pair<std::string, std::multimap<std::string, Proxy_Function >::mapped_type> >(range.first, range.second);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -498,7 +596,9 @@ namespace chaiscript
|
||||
*/
|
||||
bool function_exists(const std::string &name) const
|
||||
{
|
||||
std::multimap<std::string, Proxy_Function> &functions = get_function_cache();
|
||||
chaiscript::detail::threading::shared_lock<chaiscript::detail::threading::shared_mutex> l(m_mutex);
|
||||
|
||||
const std::map<std::string, std::vector<Proxy_Function> > &functions = get_functions_int();
|
||||
return functions.find(name) != functions.end();
|
||||
}
|
||||
|
||||
@@ -507,26 +607,39 @@ namespace chaiscript
|
||||
*/
|
||||
std::vector<std::pair<std::string, Proxy_Function > > get_functions() const
|
||||
{
|
||||
std::multimap<std::string, Proxy_Function> &functions = get_function_cache();
|
||||
return std::vector<std::pair<std::string, Proxy_Function > >(functions.begin(), functions.end());
|
||||
chaiscript::detail::threading::shared_lock<chaiscript::detail::threading::shared_mutex> l(m_mutex);
|
||||
|
||||
std::vector<std::pair<std::string, Proxy_Function> > rets;
|
||||
|
||||
const std::map<std::string, std::vector<Proxy_Function> > &functions = get_functions_int();
|
||||
|
||||
for (std::map<std::string, std::vector<Proxy_Function> >::const_iterator itr = functions.begin();
|
||||
itr != functions.end();
|
||||
++itr)
|
||||
{
|
||||
for (std::vector<Proxy_Function>::const_iterator itr2 = itr->second.begin();
|
||||
itr2 != itr->second.end();
|
||||
++itr2)
|
||||
{
|
||||
rets.push_back(std::make_pair(itr->first, *itr2));
|
||||
}
|
||||
}
|
||||
|
||||
return rets;
|
||||
}
|
||||
|
||||
void add_reserved_word(const std::string &name)
|
||||
{
|
||||
#ifndef CHAISCRIPT_NO_THREADS
|
||||
boost::unique_lock<boost::shared_mutex> l(m_mutex);
|
||||
#endif
|
||||
chaiscript::detail::threading::unique_lock<chaiscript::detail::threading::shared_mutex> l(m_mutex);
|
||||
|
||||
m_state.m_reserved_words.insert(name);
|
||||
}
|
||||
|
||||
Boxed_Value call_function(const std::string &t_name, const std::vector<Boxed_Value> ¶ms) const
|
||||
{
|
||||
std::multimap<std::string, Proxy_Function> &functions = get_function_cache();
|
||||
std::pair<std::multimap<std::string, Proxy_Function >::const_iterator, std::multimap<std::string, Proxy_Function >::const_iterator> range
|
||||
= functions.equal_range(t_name);
|
||||
std::vector<Proxy_Function> functions = get_function(t_name);
|
||||
|
||||
return dispatch(range.first, range.second, params);
|
||||
return dispatch::dispatch(functions.begin(), functions.end(), params);
|
||||
}
|
||||
|
||||
Boxed_Value call_function(const std::string &t_name) const
|
||||
@@ -628,7 +741,7 @@ namespace chaiscript
|
||||
/**
|
||||
* return true if the Boxed_Value matches the registered type by name
|
||||
*/
|
||||
bool is_type(Boxed_Value r, const std::string &user_typename) const
|
||||
bool is_type(const Boxed_Value &r, const std::string &user_typename) const
|
||||
{
|
||||
try {
|
||||
if (get_type(user_typename).bare_equal(r.get_type_info()))
|
||||
@@ -639,7 +752,7 @@ namespace chaiscript
|
||||
}
|
||||
|
||||
try {
|
||||
const Dynamic_Object &d = boxed_cast<const Dynamic_Object &>(r);
|
||||
const dispatch::Dynamic_Object &d = boxed_cast<const dispatch::Dynamic_Object &>(r);
|
||||
return d.get_type_name() == user_typename;
|
||||
} catch (const std::bad_cast &) {
|
||||
}
|
||||
@@ -654,20 +767,16 @@ namespace chaiscript
|
||||
|
||||
State get_state()
|
||||
{
|
||||
#ifndef CHAISCRIPT_NO_THREADS
|
||||
boost::unique_lock<boost::shared_mutex> l(m_mutex);
|
||||
boost::unique_lock<boost::shared_mutex> l2(m_global_object_mutex);
|
||||
#endif
|
||||
chaiscript::detail::threading::shared_lock<chaiscript::detail::threading::shared_mutex> l(m_mutex);
|
||||
chaiscript::detail::threading::shared_lock<chaiscript::detail::threading::shared_mutex> l2(m_global_object_mutex);
|
||||
|
||||
return m_state;
|
||||
}
|
||||
|
||||
void set_state(const State &t_state)
|
||||
{
|
||||
#ifndef CHAISCRIPT_NO_THREADS
|
||||
boost::unique_lock<boost::shared_mutex> l(m_mutex);
|
||||
boost::unique_lock<boost::shared_mutex> l2(m_global_object_mutex);
|
||||
#endif
|
||||
chaiscript::detail::threading::unique_lock<chaiscript::detail::threading::shared_mutex> l(m_mutex);
|
||||
chaiscript::detail::threading::unique_lock<chaiscript::detail::threading::shared_mutex> l2(m_global_object_mutex);
|
||||
|
||||
m_state = t_state;
|
||||
}
|
||||
@@ -683,9 +792,108 @@ namespace chaiscript
|
||||
return *(m_stack_holder->stack);
|
||||
}
|
||||
|
||||
std::multimap<std::string, Proxy_Function> &get_function_cache() const
|
||||
const std::map<std::string, std::vector<Proxy_Function> > &get_functions_int() const
|
||||
{
|
||||
return m_stack_holder->function_cache;
|
||||
return m_state.m_functions;
|
||||
}
|
||||
|
||||
std::map<std::string, std::vector<Proxy_Function> > &get_functions_int()
|
||||
{
|
||||
return m_state.m_functions;
|
||||
}
|
||||
|
||||
static bool function_less_than(const Proxy_Function &lhs, const Proxy_Function &rhs)
|
||||
{
|
||||
const std::vector<Type_Info> lhsparamtypes = lhs->get_param_types();
|
||||
const std::vector<Type_Info> rhsparamtypes = rhs->get_param_types();
|
||||
|
||||
const size_t lhssize = lhsparamtypes.size();
|
||||
const size_t rhssize = rhsparamtypes.size();
|
||||
|
||||
const Type_Info boxed_type = user_type<Boxed_Value>();
|
||||
const Type_Info boxed_pod_type = user_type<Boxed_POD_Value>();
|
||||
|
||||
boost::shared_ptr<const dispatch::Dynamic_Proxy_Function> dynamic_lhs(boost::dynamic_pointer_cast<const dispatch::Dynamic_Proxy_Function>(lhs));
|
||||
boost::shared_ptr<const dispatch::Dynamic_Proxy_Function> dynamic_rhs(boost::dynamic_pointer_cast<const dispatch::Dynamic_Proxy_Function>(rhs));
|
||||
|
||||
if (dynamic_lhs && dynamic_rhs)
|
||||
{
|
||||
if (dynamic_lhs->get_guard())
|
||||
{
|
||||
if (dynamic_rhs->get_guard())
|
||||
{
|
||||
return false;
|
||||
} else {
|
||||
return true;
|
||||
}
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
if (dynamic_lhs && !dynamic_rhs)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!dynamic_lhs && dynamic_rhs)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
|
||||
for (size_t i = 1; i < lhssize && i < rhssize; ++i)
|
||||
{
|
||||
const Type_Info lt = lhsparamtypes[i];
|
||||
const Type_Info rt = rhsparamtypes[i];
|
||||
|
||||
if (lt.bare_equal(rt) && lt.is_const() == rt.is_const())
|
||||
{
|
||||
continue; // The first two types are essentially the same, next iteration
|
||||
}
|
||||
|
||||
// const is after non-const for the same type
|
||||
if (lt.bare_equal(rt) && lt.is_const() && !rt.is_const())
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
if (lt.bare_equal(rt) && !lt.is_const())
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
// boxed_values are sorted last
|
||||
if (lt.bare_equal(boxed_type))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
if (rt.bare_equal(boxed_type))
|
||||
{
|
||||
if (lt.bare_equal(boxed_pod_type))
|
||||
{
|
||||
return true;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
if (lt.bare_equal(boxed_pod_type))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
if (rt.bare_equal(boxed_pod_type))
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
// otherwise, we want to sort by typeid
|
||||
return lt < rt;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
@@ -694,13 +902,11 @@ namespace chaiscript
|
||||
*/
|
||||
void validate_object_name(const std::string &name) const
|
||||
{
|
||||
#ifndef CHAISCRIPT_NO_THREADS
|
||||
boost::shared_lock<boost::shared_mutex> l(m_mutex);
|
||||
#endif
|
||||
chaiscript::detail::threading::shared_lock<chaiscript::detail::threading::shared_mutex> l(m_mutex);
|
||||
|
||||
if (m_state.m_reserved_words.find(name) != m_state.m_reserved_words.end())
|
||||
{
|
||||
throw reserved_word_error(name);
|
||||
throw exception::reserved_word_error(name);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -709,56 +915,62 @@ namespace chaiscript
|
||||
* true if the function was added, false if a function with the
|
||||
* same signature and name already exists.
|
||||
*/
|
||||
bool add_function(const Proxy_Function &f, const std::string &t_name)
|
||||
bool add_function(const Proxy_Function &t_f, const std::string &t_name)
|
||||
{
|
||||
#ifndef CHAISCRIPT_NO_THREADS
|
||||
boost::unique_lock<boost::shared_mutex> l(m_mutex);
|
||||
#endif
|
||||
chaiscript::detail::threading::unique_lock<chaiscript::detail::threading::shared_mutex> l(m_mutex);
|
||||
|
||||
std::pair<std::multimap<std::string, Proxy_Function >::const_iterator, std::multimap<std::string, Proxy_Function >::const_iterator> range
|
||||
= m_state.m_functions.equal_range(t_name);
|
||||
std::map<std::string, std::vector<Proxy_Function> > &funcs = get_functions_int();
|
||||
|
||||
while (range.first != range.second)
|
||||
std::map<std::string, std::vector<Proxy_Function> >::iterator itr
|
||||
= funcs.find(t_name);
|
||||
|
||||
if (itr != funcs.end())
|
||||
{
|
||||
if ((*f) == *(range.first->second))
|
||||
std::vector<Proxy_Function> &vec = itr->second;
|
||||
for (std::vector<Proxy_Function>::const_iterator itr2 = vec.begin();
|
||||
itr2 != vec.end();
|
||||
++itr2)
|
||||
{
|
||||
if ((*t_f) == *(*itr2))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
++range.first;
|
||||
}
|
||||
|
||||
m_state.m_functions.insert(std::make_pair(t_name, f));
|
||||
get_function_cache().insert(std::make_pair(t_name, f));
|
||||
vec.push_back(t_f);
|
||||
std::stable_sort(vec.begin(), vec.end(), &function_less_than);
|
||||
} else {
|
||||
std::vector<Proxy_Function> vec;
|
||||
vec.push_back(t_f);
|
||||
funcs.insert(std::make_pair(t_name, vec));
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
#ifndef CHAISCRIPT_NO_THREADS
|
||||
mutable boost::shared_mutex m_mutex;
|
||||
mutable boost::shared_mutex m_global_object_mutex;
|
||||
#endif
|
||||
mutable chaiscript::detail::threading::shared_mutex m_mutex;
|
||||
mutable chaiscript::detail::threading::shared_mutex m_global_object_mutex;
|
||||
|
||||
struct Stack_Holder
|
||||
{
|
||||
Stack_Holder()
|
||||
: stack(new StackData())
|
||||
{
|
||||
stack->get<2>() = true;
|
||||
stack->push_back(Scope());
|
||||
}
|
||||
|
||||
Stack stack;
|
||||
|
||||
std::multimap<std::string, Proxy_Function> function_cache;
|
||||
};
|
||||
|
||||
chaiscript::threading::Thread_Storage<Stack_Holder> m_stack_holder;
|
||||
std::vector<Dynamic_Cast_Conversion> m_conversions;
|
||||
chaiscript::detail::threading::Thread_Storage<Stack_Holder> m_stack_holder;
|
||||
|
||||
|
||||
State m_state;
|
||||
|
||||
Boxed_Value m_place_holder;
|
||||
};
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
||||
|
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-2011, 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"
|
||||
#include <boost/static_assert.hpp>
|
||||
#include <boost/type_traits/is_polymorphic.hpp>
|
||||
#include <boost/type_traits/is_base_of.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) throw()
|
||||
: bad_boxed_cast(t_from, t_to, t_what)
|
||||
{
|
||||
}
|
||||
|
||||
bad_boxed_dynamic_cast(const Type_Info &t_from, const std::type_info &t_to) throw()
|
||||
: bad_boxed_cast(t_from, t_to)
|
||||
{
|
||||
}
|
||||
|
||||
bad_boxed_dynamic_cast(const std::string &w) throw()
|
||||
: bad_boxed_cast(w)
|
||||
{
|
||||
}
|
||||
|
||||
virtual ~bad_boxed_dynamic_cast() throw() {}
|
||||
};
|
||||
}
|
||||
|
||||
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)
|
||||
{
|
||||
}
|
||||
|
||||
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())
|
||||
{
|
||||
boost::shared_ptr<const Base> data
|
||||
= boost::dynamic_pointer_cast<const Base>(detail::Cast_Helper<boost::shared_ptr<const Derived> >::cast(t_derived));
|
||||
if (!data)
|
||||
{
|
||||
throw std::bad_cast();
|
||||
}
|
||||
|
||||
return Boxed_Value(data);
|
||||
} else {
|
||||
boost::shared_ptr<Base> data
|
||||
= boost::dynamic_pointer_cast<Base>(detail::Cast_Helper<boost::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(boost::cref(data));
|
||||
} else {
|
||||
Derived &d = detail::Cast_Helper<Derived &>::cast(t_derived);
|
||||
Base &data = dynamic_cast<Base &>(d);
|
||||
return Boxed_Value(boost::ref(data));
|
||||
}
|
||||
}
|
||||
} else {
|
||||
throw 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 boost::shared_ptr<Dynamic_Conversion> create()
|
||||
{
|
||||
boost::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 boost::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 boost::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
|
||||
BOOST_STATIC_ASSERT((boost::is_base_of<Base,Derived>::value));
|
||||
BOOST_STATIC_ASSERT(boost::is_polymorphic<Base>::value);
|
||||
BOOST_STATIC_ASSERT(boost::is_polymorphic<Derived>::value);
|
||||
|
||||
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 exception::bad_boxed_dynamic_cast(derived.get_type_info(), typeid(Base), "No known conversion");
|
||||
} catch (const std::bad_cast &) {
|
||||
throw exception::bad_boxed_dynamic_cast(derived.get_type_info(), typeid(Base), "Unable to perform dynamic_cast operation");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
#endif
|
@@ -1,9 +1,17 @@
|
||||
#ifndef __DYNAMIC_OBJECT_HPP__
|
||||
#define __DYNAMIC_OBJECT_HPP__
|
||||
// This file is distributed under the BSD License.
|
||||
// See "license.txt" for details.
|
||||
// Copyright 2009-2011, 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,6 +42,8 @@ namespace chaiscript
|
||||
std::map<std::string, Boxed_Value> m_attrs;
|
||||
};
|
||||
|
||||
namespace detail
|
||||
{
|
||||
struct Dynamic_Object_Attribute
|
||||
{
|
||||
static Boxed_Value func(const std::string &t_type_name, const std::string &t_attr_name,
|
||||
@@ -41,7 +51,7 @@ namespace chaiscript
|
||||
{
|
||||
if (t_do.get_type_name() != t_type_name)
|
||||
{
|
||||
throw bad_boxed_cast("Dynamic object type mismatch");
|
||||
throw exception::bad_boxed_cast("Dynamic object type mismatch");
|
||||
}
|
||||
|
||||
return t_do.get_attr(t_attr_name);
|
||||
@@ -60,7 +70,7 @@ namespace chaiscript
|
||||
const std::string &t_type_name,
|
||||
const Proxy_Function &t_func,
|
||||
const boost::optional<Type_Info> &t_ti = boost::optional<Type_Info>())
|
||||
: Proxy_Function_Base(t_func->get_param_types()),
|
||||
: 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(t_ti)
|
||||
{
|
||||
assert( (t_func->get_arity() > 0 || t_func->get_arity() < 0)
|
||||
@@ -71,11 +81,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 +100,14 @@ 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();
|
||||
}
|
||||
std::vector<Const_Proxy_Function> fs;
|
||||
fs.push_back(m_func);
|
||||
return fs;
|
||||
}
|
||||
|
||||
|
||||
virtual int get_arity() const
|
||||
{
|
||||
return m_func->get_arity();
|
||||
@@ -110,23 +118,69 @@ namespace chaiscript
|
||||
return m_func->annotation();
|
||||
}
|
||||
|
||||
|
||||
protected:
|
||||
virtual Boxed_Value do_call(const std::vector<Boxed_Value> ¶ms) const
|
||||
{
|
||||
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, boost::optional<Type_Info> t_objectti)
|
||||
{
|
||||
if (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;
|
||||
} else {
|
||||
return t_inner_types;
|
||||
}
|
||||
}
|
||||
|
||||
static bool dynamic_object_typename_match(const Boxed_Value &bv, const std::string &name,
|
||||
const boost::optional<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 &>(bv);
|
||||
return name == "Dynamic_Object" || d.get_type_name() == name;
|
||||
} catch (const std::bad_cast &) {
|
||||
return false;
|
||||
}
|
||||
} else {
|
||||
if (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 boost::optional<Type_Info> &ti)
|
||||
{
|
||||
if (bvs.size() > 0)
|
||||
{
|
||||
try {
|
||||
const Dynamic_Object &d = boxed_cast<const Dynamic_Object &>(bvs[0]);
|
||||
return name == "Dynamic_Object" || d.get_type_name() == name;
|
||||
} catch (const std::bad_cast &) {
|
||||
if (ti)
|
||||
{
|
||||
return bvs[0].get_type_info().bare_equal(*ti);
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return dynamic_object_typename_match(bvs[0], name, ti);
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
@@ -175,11 +229,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 +247,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 +259,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
|
||||
|
||||
|
@@ -1,11 +1,11 @@
|
||||
// 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)
|
||||
// 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>
|
||||
@@ -15,7 +15,12 @@
|
||||
#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
|
||||
@@ -27,7 +32,7 @@ namespace chaiscript
|
||||
*/
|
||||
template<typename FunctionType>
|
||||
boost::function<FunctionType>
|
||||
functor(const std::vector<std::pair<std::string, Proxy_Function > > &funcs)
|
||||
functor(const std::vector<Const_Proxy_Function> &funcs)
|
||||
{
|
||||
FunctionType *p=0;
|
||||
return detail::build_function_caller_helper(p, funcs);
|
||||
@@ -48,10 +53,10 @@ namespace chaiscript
|
||||
*/
|
||||
template<typename FunctionType>
|
||||
boost::function<FunctionType>
|
||||
functor(Proxy_Function func)
|
||||
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);
|
||||
}
|
||||
|
||||
@@ -63,9 +68,68 @@ namespace chaiscript
|
||||
boost::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 boost::function &
|
||||
*/
|
||||
template<typename Signature>
|
||||
struct Cast_Helper<const boost::function<Signature> &>
|
||||
{
|
||||
typedef boost::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 boost::function<Signature> &>::cast(ob);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Cast helper to handle automatic casting to boost::function
|
||||
*/
|
||||
template<typename Signature>
|
||||
struct Cast_Helper<boost::function<Signature> >
|
||||
{
|
||||
typedef boost::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<boost::function<Signature> >::cast(ob);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Cast helper to handle automatic casting to const boost::function
|
||||
*/
|
||||
template<typename Signature>
|
||||
struct Cast_Helper<const boost::function<Signature> >
|
||||
{
|
||||
typedef boost::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 boost::function<Signature> >::cast(ob);
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
||||
|
@@ -1,18 +1,18 @@
|
||||
// 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)
|
||||
// Copyright 2009-2011, Jonathan Turner (jonathan@emptycrate.com)
|
||||
// and Jason Turner (jason@emptycrate.com)
|
||||
// http://www.chaiscript.com
|
||||
|
||||
#include <boost/preprocessor.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 addparam(z,n,text) params.push_back((boost::is_reference<Param ## n>::value&&!(boost::is_same<chaiscript::Boxed_Value, typename boost::remove_const<typename boost::remove_reference<Param ## n>::type>::type>::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__
|
||||
#ifndef CHAISCRIPT_FUNCTION_CALL_DETAIL_HPP_
|
||||
#define CHAISCRIPT_FUNCTION_CALL_DETAIL_HPP_
|
||||
|
||||
#include <boost/shared_ptr.hpp>
|
||||
#include <boost/bind.hpp>
|
||||
@@ -22,9 +22,12 @@
|
||||
#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 +35,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,14 +48,15 @@ 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>
|
||||
@@ -63,6 +67,8 @@ namespace chaiscript
|
||||
# define n BOOST_PP_ITERATION()
|
||||
|
||||
namespace chaiscript
|
||||
{
|
||||
namespace dispatch
|
||||
{
|
||||
namespace detail
|
||||
{
|
||||
@@ -70,7 +76,7 @@ namespace chaiscript
|
||||
* 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
|
||||
Ret function_caller(const std::vector<Const_Proxy_Function> &funcs
|
||||
BOOST_PP_COMMA_IF(n) BOOST_PP_ENUM_BINARY_PARAMS(n, Param, p) )
|
||||
{
|
||||
std::vector<Boxed_Value> params;
|
||||
@@ -85,14 +91,29 @@ namespace chaiscript
|
||||
*/
|
||||
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)
|
||||
build_function_caller_helper(Ret (BOOST_PP_ENUM_PARAMS(n, Param)), const std::vector<Const_Proxy_Function> &funcs)
|
||||
{
|
||||
if (funcs.size() == 1)
|
||||
{
|
||||
boost::shared_ptr<const Proxy_Function_Impl<Ret (BOOST_PP_ENUM_PARAMS(n, Param))> > pfi =
|
||||
boost::dynamic_pointer_cast<const Proxy_Function_Impl<Ret (BOOST_PP_ENUM_PARAMS(n, Param))> >
|
||||
(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 boost::bind(&function_caller<Ret BOOST_PP_COMMA_IF(n) BOOST_PP_ENUM_PARAMS(n, Param)>, funcs
|
||||
BOOST_PP_ENUM_TRAILING(n, curry, ~));
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
#undef n
|
||||
|
||||
#endif
|
||||
|
||||
|
@@ -1,11 +1,11 @@
|
||||
// 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)
|
||||
// Copyright 2009-2011, 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 "type_info.hpp"
|
||||
@@ -16,6 +16,10 @@
|
||||
#include <vector>
|
||||
|
||||
namespace chaiscript
|
||||
{
|
||||
namespace dispatch
|
||||
{
|
||||
namespace detail
|
||||
{
|
||||
/**
|
||||
* Used internally for handling a return value from a Proxy_Function call
|
||||
@@ -25,7 +29,7 @@ namespace chaiscript
|
||||
{
|
||||
static Boxed_Value handle(const Ret &r)
|
||||
{
|
||||
return Boxed_Value(r);
|
||||
return const_var(r);
|
||||
}
|
||||
};
|
||||
|
||||
@@ -38,6 +42,15 @@ namespace chaiscript
|
||||
}
|
||||
};
|
||||
|
||||
template<typename Ret>
|
||||
struct Handle_Return<boost::shared_ptr<Ret> >
|
||||
{
|
||||
static Boxed_Value handle(const boost::shared_ptr<Ret> &r)
|
||||
{
|
||||
return Boxed_Value(r);
|
||||
}
|
||||
};
|
||||
|
||||
template<typename Ret>
|
||||
struct Handle_Return<const boost::shared_ptr<Ret> &>
|
||||
{
|
||||
@@ -86,6 +99,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
|
||||
*/
|
||||
@@ -123,5 +148,7 @@ namespace chaiscript
|
||||
}
|
||||
};
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
||||
|
@@ -1,7 +1,15 @@
|
||||
#ifndef __CHAISCRIPT_OPERATORS_HPP__
|
||||
#define __CHAISCRIPT_OPERATORS_HPP__
|
||||
// This file is distributed under the BSD License.
|
||||
// See "license.txt" for details.
|
||||
// Copyright 2009-2011, Jonathan Turner (jonathan@emptycrate.com)
|
||||
// and Jason Turner (jason@emptycrate.com)
|
||||
// http://www.chaiscript.com
|
||||
|
||||
#ifndef CHAISCRIPT_OPERATORS_HPP_
|
||||
#define CHAISCRIPT_OPERATORS_HPP_
|
||||
|
||||
namespace chaiscript
|
||||
{
|
||||
namespace bootstrap
|
||||
{
|
||||
namespace operators
|
||||
{
|
||||
@@ -146,7 +154,14 @@ namespace chaiscript
|
||||
template<typename Ret, typename L>
|
||||
Ret unary_minus(L l)
|
||||
{
|
||||
#ifdef BOOST_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 +453,6 @@ namespace chaiscript
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
||||
|
@@ -1,14 +1,14 @@
|
||||
// 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)
|
||||
// Copyright 2009-2011, 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__
|
||||
#ifndef CHAISCRIPT_PROXY_CONSTRUCTORS_HPP_
|
||||
#define CHAISCRIPT_PROXY_CONSTRUCTORS_HPP_
|
||||
|
||||
#include <boost/shared_ptr.hpp>
|
||||
#include <boost/bind.hpp>
|
||||
@@ -22,11 +22,22 @@
|
||||
|
||||
namespace chaiscript
|
||||
{
|
||||
/// \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 (detail::build_constructor_(f));
|
||||
return (dispatch::detail::build_constructor_(f));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -34,6 +45,8 @@ namespace chaiscript
|
||||
# define n BOOST_PP_ITERATION()
|
||||
|
||||
namespace chaiscript
|
||||
{
|
||||
namespace dispatch
|
||||
{
|
||||
namespace detail
|
||||
{
|
||||
@@ -61,6 +74,8 @@ namespace chaiscript
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
#undef n
|
||||
|
||||
#endif
|
||||
|
||||
|
@@ -1,12 +1,12 @@
|
||||
// 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)
|
||||
// Copyright 2009-2011, 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"
|
||||
@@ -19,6 +19,14 @@
|
||||
#include "proxy_functions_detail.hpp"
|
||||
|
||||
namespace chaiscript
|
||||
{
|
||||
class Boxed_POD_Value;
|
||||
struct AST_Node;
|
||||
|
||||
typedef boost::shared_ptr<struct AST_Node> AST_NodePtr;
|
||||
|
||||
|
||||
namespace dispatch
|
||||
{
|
||||
/**
|
||||
* Helper for building a list of parameters for calling a Proxy_Function
|
||||
@@ -63,13 +71,28 @@ 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);
|
||||
bv.add_dependencies(params.begin(), params.end());
|
||||
return bv;
|
||||
}
|
||||
|
||||
/// 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.
|
||||
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<boost::shared_ptr<const Proxy_Function_Base> > get_contained_functions() const
|
||||
{
|
||||
return std::vector<boost::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 +107,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_POD_Value>())
|
||||
|| 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<boost::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 +159,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,13 +173,18 @@ 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 boost::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 boost::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:
|
||||
@@ -156,7 +195,10 @@ namespace chaiscript
|
||||
virtual ~guard_error() throw()
|
||||
{ }
|
||||
};
|
||||
}
|
||||
|
||||
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.
|
||||
@@ -167,16 +209,17 @@ namespace chaiscript
|
||||
Dynamic_Proxy_Function(
|
||||
const boost::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;
|
||||
return this == &rhs;
|
||||
}
|
||||
|
||||
virtual bool call_match(const std::vector<Boxed_Value> &vals) const
|
||||
@@ -187,7 +230,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 +261,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 +276,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,16 +290,15 @@ 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)
|
||||
{
|
||||
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;
|
||||
@@ -254,6 +308,7 @@ namespace chaiscript
|
||||
int m_arity;
|
||||
std::string m_description;
|
||||
Proxy_Function m_guard;
|
||||
AST_NodePtr m_parsenode;
|
||||
};
|
||||
|
||||
/**
|
||||
@@ -275,14 +330,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 +353,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 +370,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 +386,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 +401,35 @@ 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:
|
||||
@@ -361,7 +448,7 @@ namespace chaiscript
|
||||
{
|
||||
public:
|
||||
Proxy_Function_Impl(const boost::function<Func> &f)
|
||||
: Proxy_Function_Base(build_param_type_list(static_cast<Func *>(0))),
|
||||
: Proxy_Function_Base(detail::build_param_type_list(static_cast<Func *>(0))),
|
||||
m_f(f), m_dummy_func(0)
|
||||
{
|
||||
}
|
||||
@@ -370,22 +457,14 @@ 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;
|
||||
}
|
||||
const Proxy_Function_Impl *pimpl = dynamic_cast<const Proxy_Function_Impl<Func> *>(&t_func);
|
||||
return pimpl != 0;
|
||||
}
|
||||
|
||||
virtual Boxed_Value operator()(const std::vector<Boxed_Value> ¶ms) const
|
||||
{
|
||||
return Do_Call<typename boost::function<Func>::result_type>::go(m_f, params);
|
||||
}
|
||||
|
||||
virtual int get_arity() const
|
||||
{
|
||||
return m_types.size() - 1;
|
||||
return static_cast<int>(m_types.size()) - 1;
|
||||
}
|
||||
|
||||
|
||||
@@ -396,7 +475,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,6 +483,17 @@ namespace chaiscript
|
||||
return "";
|
||||
}
|
||||
|
||||
boost::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 boost::function<Func>::result_type>::go(m_f, params);
|
||||
}
|
||||
|
||||
private:
|
||||
boost::function<Func> m_f;
|
||||
Func *m_dummy_func;
|
||||
@@ -426,32 +516,15 @@ 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<const 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,6 +546,25 @@ 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 boost::add_reference<T>::type>::handle(o->*m_attr);
|
||||
} else {
|
||||
Class *o = boxed_cast<Class *>(bv);
|
||||
return detail::Handle_Return<typename boost::add_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()
|
||||
{
|
||||
@@ -483,15 +575,18 @@ namespace chaiscript
|
||||
}
|
||||
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
|
||||
{
|
||||
/// \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() throw()
|
||||
: std::runtime_error("No matching function to dispatch to")
|
||||
{
|
||||
@@ -504,6 +599,10 @@ namespace chaiscript
|
||||
|
||||
virtual ~dispatch_error() throw() {}
|
||||
};
|
||||
}
|
||||
|
||||
namespace dispatch
|
||||
{
|
||||
|
||||
/**
|
||||
* Take a vector of functions and a vector of parameters. Attempt to execute
|
||||
@@ -517,22 +616,22 @@ namespace chaiscript
|
||||
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.empty()?false:plist[0].is_const());
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -544,7 +643,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,20 +1,21 @@
|
||||
// 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)
|
||||
// Copyright 2009-2011, 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 gettypeinfo(z,n,text) ti.push_back(chaiscript::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>
|
||||
@@ -26,6 +27,8 @@
|
||||
#include <vector>
|
||||
|
||||
namespace chaiscript
|
||||
{
|
||||
namespace exception
|
||||
{
|
||||
/**
|
||||
* Exception thrown when there is a mismatch in number of
|
||||
@@ -40,30 +43,12 @@ namespace chaiscript
|
||||
}
|
||||
|
||||
virtual ~arity_error() throw() {}
|
||||
|
||||
int got;
|
||||
int expected;
|
||||
};
|
||||
|
||||
template<typename Ret>
|
||||
struct Do_Call
|
||||
{
|
||||
template<typename Fun>
|
||||
static Boxed_Value go(const boost::function<Fun> &fun, const std::vector<Boxed_Value> ¶ms)
|
||||
{
|
||||
return Handle_Return<Ret>::handle(call_func(fun, params));
|
||||
}
|
||||
};
|
||||
|
||||
template<>
|
||||
struct Do_Call<void>
|
||||
{
|
||||
template<typename Fun>
|
||||
static Boxed_Value go(const boost::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 )
|
||||
@@ -76,6 +61,10 @@ namespace chaiscript
|
||||
# define n BOOST_PP_ITERATION()
|
||||
|
||||
namespace chaiscript
|
||||
{
|
||||
namespace dispatch
|
||||
{
|
||||
namespace detail
|
||||
{
|
||||
/**
|
||||
* Used by Proxy_Function_Impl to return a list of all param types
|
||||
@@ -85,7 +74,7 @@ namespace chaiscript
|
||||
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());
|
||||
ti.push_back(chaiscript::detail::Get_Type_Info<Ret>::get());
|
||||
|
||||
BOOST_PP_REPEAT(n, gettypeinfo, ~)
|
||||
|
||||
@@ -104,7 +93,7 @@ namespace chaiscript
|
||||
{
|
||||
if (params.size() != n)
|
||||
{
|
||||
throw arity_error(params.size(), n);
|
||||
throw exception::arity_error(static_cast<int>(params.size()), n);
|
||||
} else {
|
||||
return f(BOOST_PP_REPEAT(n, casthelper, ~));
|
||||
}
|
||||
@@ -121,13 +110,51 @@ namespace chaiscript
|
||||
{
|
||||
try {
|
||||
BOOST_PP_REPEAT(n, trycast, ~);
|
||||
} catch (const bad_boxed_cast &) {
|
||||
} catch (const exception::bad_boxed_cast &) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#undef n
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
#ifndef BOOST_PP_IS_ITERATING
|
||||
|
||||
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)
|
||||
{
|
||||
return Handle_Return<Ret>::handle(call_func(fun, params));
|
||||
}
|
||||
};
|
||||
|
||||
template<>
|
||||
struct Do_Call<void>
|
||||
{
|
||||
template<typename Fun>
|
||||
static Boxed_Value go(const boost::function<Fun> &fun, const std::vector<Boxed_Value> ¶ms)
|
||||
{
|
||||
call_func(fun, params);
|
||||
return Handle_Return<void>::handle();
|
||||
}
|
||||
};
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
||||
|
@@ -1,11 +1,11 @@
|
||||
// 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)
|
||||
// Copyright 2009-2011, 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"
|
||||
@@ -14,12 +14,15 @@
|
||||
#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>
|
||||
template<bool Object, bool MemFn>
|
||||
struct Fun_Helper
|
||||
{
|
||||
template<typename T>
|
||||
@@ -35,7 +38,23 @@ namespace chaiscript
|
||||
};
|
||||
|
||||
template<>
|
||||
struct Fun_Helper<true>
|
||||
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>
|
||||
{
|
||||
template<typename T, typename Class>
|
||||
static Proxy_Function go(T Class::* m)
|
||||
@@ -43,31 +62,100 @@ namespace chaiscript
|
||||
return Proxy_Function(new Attribute_Access<T, Class>(m));
|
||||
}
|
||||
};
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
/// \brief Creates a new Proxy_Function object from a boost::function object
|
||||
/// \param[in] f boost::function to expose to ChaiScript
|
||||
///
|
||||
/// \b Example:
|
||||
/// \code
|
||||
/// boost::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)
|
||||
{
|
||||
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>::go(t);
|
||||
return dispatch::detail::Fun_Helper<boost::function_types::is_member_object_pointer<T>::value, boost::function_types::is_member_function_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, boost::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, boost::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,12 +1,15 @@
|
||||
// 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)
|
||||
// Copyright 2009-2011, 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 <string>
|
||||
#include <typeinfo>
|
||||
#include <boost/shared_ptr.hpp>
|
||||
#include <boost/type_traits/is_const.hpp>
|
||||
#include <boost/type_traits/is_void.hpp>
|
||||
#include <boost/type_traits/is_reference.hpp>
|
||||
@@ -18,9 +21,17 @@
|
||||
|
||||
namespace chaiscript
|
||||
{
|
||||
/**
|
||||
* compile time deduced information about a type
|
||||
*/
|
||||
|
||||
namespace detail
|
||||
{
|
||||
template<typename T>
|
||||
struct Bare_Type
|
||||
{
|
||||
typedef typename boost::remove_const<typename boost::remove_pointer<typename boost::remove_reference<T>::type>::type>::type type;
|
||||
};
|
||||
}
|
||||
|
||||
/// \brief Compile time deduced information about a type
|
||||
class Type_Info
|
||||
{
|
||||
public:
|
||||
@@ -127,59 +138,104 @@ 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,
|
||||
return Type_Info(boost::is_const<typename boost::remove_pointer<typename boost::remove_reference<T>::type>::type>::value, boost::is_reference<T>::value, boost::is_pointer<T>::value,
|
||||
boost::is_void<T>::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> >
|
||||
{
|
||||
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));
|
||||
&typeid(typename Bare_Type<T>::type));
|
||||
}
|
||||
};
|
||||
|
||||
template<typename T>
|
||||
struct Get_Type_Info<const boost::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));
|
||||
&typeid(typename Bare_Type<T>::type));
|
||||
}
|
||||
};
|
||||
|
||||
template<typename T>
|
||||
struct Get_Type_Info<boost::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));
|
||||
&typeid(typename Bare_Type<T>::type));
|
||||
}
|
||||
};
|
||||
|
||||
template<typename T>
|
||||
struct Get_Type_Info<const boost::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(const boost::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()
|
||||
{
|
||||
|
@@ -1,136 +1,219 @@
|
||||
// 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)
|
||||
// Copyright 2009-2011, 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 <chaiscript/dispatchkit/dispatchkit.hpp>
|
||||
#include <boost/enable_shared_from_this.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,
|
||||
/// 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, Additive, Multiplicative, 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
|
||||
};
|
||||
};
|
||||
|
||||
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",
|
||||
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", "Additive", "Multiplicative", "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"};
|
||||
|
||||
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 boost::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) throw() :
|
||||
std::runtime_error("Error: \"" + t_why + "\" " +
|
||||
(t_fname != "__EVAL__" ? ("in '" + t_fname + "' ") : "during evaluation ") +
|
||||
+ "at (" + boost::lexical_cast<std::string>(t_where.line) + ", " +
|
||||
boost::lexical_cast<std::string>(t_where.column) + ")"),
|
||||
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) throw()
|
||||
: std::runtime_error("Error: \"" + t_why + "\" "),
|
||||
reason(t_why)
|
||||
{}
|
||||
|
||||
virtual ~Eval_Error() throw() {}
|
||||
virtual ~eval_error() throw() {}
|
||||
};
|
||||
|
||||
/**
|
||||
* Errors generated when loading a file
|
||||
*/
|
||||
struct file_not_found_error : public std::runtime_error {
|
||||
file_not_found_error(const std::string &t_filename) throw()
|
||||
: std::runtime_error("File Not Found: " + t_filename)
|
||||
{ }
|
||||
|
||||
virtual ~file_not_found_error() throw() {}
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
|
||||
/// \brief Struct that doubles as both a parser ast_node and an AST node.
|
||||
struct AST_Node : boost::enable_shared_from_this<AST_Node> {
|
||||
public:
|
||||
const std::string text;
|
||||
const int identifier;
|
||||
boost::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 boost::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 boost::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;
|
||||
};
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#endif /* _CHAISCRIPT_COMMON_HPP */
|
||||
|
@@ -1,7 +1,7 @@
|
||||
// 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)
|
||||
// Copyright 2009-2011, Jonathan Turner (jonathan@emptycrate.com)
|
||||
// and Jason Turner (jason@emptycrate.com)
|
||||
// http://www.chaiscript.com
|
||||
|
||||
#ifndef CHAISCRIPT_ENGINE_HPP_
|
||||
@@ -15,20 +15,26 @@
|
||||
#ifdef _POSIX_VERSION
|
||||
#include <dlfcn.h>
|
||||
#else
|
||||
#ifdef WIN32
|
||||
#ifdef BOOST_WINDOWS
|
||||
#define VC_EXTRA_LEAN
|
||||
#define WIN32_LEAN_AND_MEAN
|
||||
#include <Windows.h>
|
||||
#endif
|
||||
#endif
|
||||
|
||||
|
||||
#include <chaiscript/language/chaiscript_prelude.hpp>
|
||||
#include <chaiscript/language/chaiscript_parser.hpp>
|
||||
|
||||
namespace chaiscript
|
||||
{
|
||||
namespace exception
|
||||
{
|
||||
/// \brief Thrown if an error occurs while attempting to load a binary module
|
||||
struct load_module_error : std::runtime_error
|
||||
{
|
||||
load_module_error(const std::string &reason) throw()
|
||||
: std::runtime_error(reason)
|
||||
load_module_error(const std::string &t_reason) throw()
|
||||
: std::runtime_error(t_reason)
|
||||
{
|
||||
}
|
||||
|
||||
@@ -36,7 +42,10 @@ namespace chaiscript
|
||||
{
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
namespace detail
|
||||
{
|
||||
#ifdef _POSIX_VERSION
|
||||
struct Loadable_Module
|
||||
{
|
||||
@@ -47,7 +56,7 @@ namespace chaiscript
|
||||
{
|
||||
if (!m_data)
|
||||
{
|
||||
throw load_module_error(dlerror());
|
||||
throw exception::load_module_error(dlerror());
|
||||
}
|
||||
}
|
||||
|
||||
@@ -70,7 +79,7 @@ namespace chaiscript
|
||||
{
|
||||
if (!m_symbol)
|
||||
{
|
||||
throw load_module_error(dlerror());
|
||||
throw exception::load_module_error(dlerror());
|
||||
}
|
||||
}
|
||||
|
||||
@@ -95,32 +104,32 @@ namespace chaiscript
|
||||
struct Loadable_Module
|
||||
{
|
||||
template<typename T>
|
||||
static std::wstring towstring(const T &str)
|
||||
static std::wstring towstring(const T &t_str)
|
||||
{
|
||||
return std::wstring(str.begin(), str.end());
|
||||
return std::wstring(t_str.begin(), t_str.end());
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
static std::string tostring(const T &str)
|
||||
static std::string tostring(const T &t_str)
|
||||
{
|
||||
return std::string(str.begin(), str.end());
|
||||
return std::string(t_str.begin(), t_str.end());
|
||||
}
|
||||
|
||||
#ifdef _UNICODE
|
||||
template<typename T>
|
||||
static std::wstring toproperstring(const T &str)
|
||||
static std::wstring toproperstring(const T &t_str)
|
||||
{
|
||||
return towstring(str);
|
||||
return towstring(t_str);
|
||||
}
|
||||
#else
|
||||
template<typename T>
|
||||
static std::string toproperstring(const T &str)
|
||||
static std::string toproperstring(const T &t_str)
|
||||
{
|
||||
return tostring(str);
|
||||
return tostring(t_str);
|
||||
}
|
||||
#endif
|
||||
|
||||
static std::string GetErrorMessage(DWORD err)
|
||||
static std::string GetErrorMessage(DWORD t_err)
|
||||
{
|
||||
#ifdef _UNICODE
|
||||
typedef LPWSTR StringType;
|
||||
@@ -136,7 +145,7 @@ namespace chaiscript
|
||||
FORMAT_MESSAGE_FROM_SYSTEM |
|
||||
FORMAT_MESSAGE_IGNORE_INSERTS,
|
||||
NULL,
|
||||
err,
|
||||
t_err,
|
||||
MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
|
||||
(StringType)&lpMsgBuf,
|
||||
0, NULL );
|
||||
@@ -157,7 +166,7 @@ namespace chaiscript
|
||||
{
|
||||
if (!m_data)
|
||||
{
|
||||
throw load_module_error(GetErrorMessage(GetLastError()));
|
||||
throw exception::load_module_error(GetErrorMessage(GetLastError()));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -177,7 +186,7 @@ namespace chaiscript
|
||||
{
|
||||
if (!m_symbol)
|
||||
{
|
||||
throw load_module_error(GetErrorMessage(GetLastError()));
|
||||
throw exception::load_module_error(GetErrorMessage(GetLastError()));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -186,7 +195,7 @@ namespace chaiscript
|
||||
|
||||
Loadable_Module(const std::string &t_module_name, const std::string &t_filename)
|
||||
: m_dlmodule(t_filename), m_func(m_dlmodule, "create_chaiscript_module_" + t_module_name),
|
||||
m_moduleptr(m_func.m_symbol());
|
||||
m_moduleptr(m_func.m_symbol())
|
||||
{
|
||||
}
|
||||
|
||||
@@ -200,205 +209,324 @@ namespace chaiscript
|
||||
{
|
||||
Loadable_Module(const std::string &, const std::string &)
|
||||
{
|
||||
throw load_module_error("Loadable module support not available for your platform");
|
||||
throw exception::load_module_error("Loadable module support not available for your platform");
|
||||
}
|
||||
|
||||
ModulePtr get()
|
||||
{
|
||||
throw load_module_error("Loadable module support not available for your platform");
|
||||
}
|
||||
ModulePtr m_moduleptr;
|
||||
};
|
||||
#endif
|
||||
#endif
|
||||
|
||||
typedef boost::shared_ptr<Loadable_Module> Loadable_Module_Ptr;
|
||||
}
|
||||
|
||||
|
||||
template <typename Eval_Engine>
|
||||
class ChaiScript_System {
|
||||
#ifndef CHAISCRIPT_NO_THREADS
|
||||
mutable boost::shared_mutex mutex;
|
||||
mutable boost::recursive_mutex use_mutex;
|
||||
#endif
|
||||
/// \brief The main object that the ChaiScript user will use.
|
||||
class ChaiScript {
|
||||
|
||||
std::set<std::string> loaded_files;
|
||||
std::map<std::string, Loadable_Module_Ptr> loaded_modules;
|
||||
std::set<std::string> active_loaded_modules;
|
||||
mutable chaiscript::detail::threading::shared_mutex m_mutex;
|
||||
mutable chaiscript::detail::threading::recursive_mutex m_use_mutex;
|
||||
|
||||
Eval_Engine engine;
|
||||
std::set<std::string> m_used_files;
|
||||
std::map<std::string, detail::Loadable_Module_Ptr> m_loaded_modules;
|
||||
std::set<std::string> m_active_loaded_modules;
|
||||
|
||||
std::vector<std::string> m_modulepaths;
|
||||
std::vector<std::string> m_usepaths;
|
||||
|
||||
chaiscript::detail::Dispatch_Engine m_engine;
|
||||
|
||||
|
||||
/**
|
||||
* Evaluates the given string in by parsing it and running the results through the evaluator
|
||||
*/
|
||||
Boxed_Value do_eval(const std::string &input, const std::string &filename = "__EVAL__", bool internal = false) {
|
||||
ChaiScript_Parser parser;
|
||||
|
||||
if (!internal)
|
||||
Boxed_Value do_eval(const std::string &t_input, const std::string &t_filename = "__EVAL__", bool /* t_internal*/ = false)
|
||||
{
|
||||
engine.sync_cache();
|
||||
}
|
||||
|
||||
//debug_print(tokens);
|
||||
Boxed_Value value;
|
||||
|
||||
// Keep a cache of all loaded filenames and use the char * from this cache to pass
|
||||
// to the parser. This is so that the parser does not have the overhead of passing
|
||||
// around and copying strings
|
||||
//
|
||||
if (filename != "__EVAL__")
|
||||
{
|
||||
#ifndef CHAISCRIPT_NO_THREADS
|
||||
boost::unique_lock<boost::shared_mutex> l(mutex);
|
||||
#endif
|
||||
loaded_files.insert(filename);
|
||||
try {
|
||||
if (parser.parse(input, loaded_files.find(filename)->c_str())) {
|
||||
#ifndef CHAISCRIPT_NO_THREADS
|
||||
l.unlock();
|
||||
#endif
|
||||
parser::ChaiScript_Parser parser;
|
||||
if (parser.parse(t_input, t_filename)) {
|
||||
//parser.show_match_stack();
|
||||
value = eval_token<Eval_Engine>(engine, parser.ast());
|
||||
}
|
||||
}
|
||||
catch (const Return_Value &rv) {
|
||||
value = rv.retval;
|
||||
}
|
||||
return parser.ast()->eval(m_engine);
|
||||
} else {
|
||||
try {
|
||||
#ifndef CHAISCRIPT_NO_THREADS
|
||||
boost::shared_lock<boost::shared_mutex> l(mutex);
|
||||
#endif
|
||||
const char *fname = loaded_files.find("__EVAL__")->c_str();
|
||||
#ifndef CHAISCRIPT_NO_THREADS
|
||||
l.unlock();
|
||||
#endif
|
||||
|
||||
if (parser.parse(input, fname)) {
|
||||
//parser.show_match_stack();
|
||||
value = eval_token<Eval_Engine>(engine, parser.ast());
|
||||
return Boxed_Value();
|
||||
}
|
||||
}
|
||||
catch (const Return_Value &rv) {
|
||||
value = rv.retval;
|
||||
catch (const chaiscript::eval::detail::Return_Value &rv) {
|
||||
return rv.retval;
|
||||
}
|
||||
}
|
||||
|
||||
if (!internal)
|
||||
|
||||
|
||||
const Boxed_Value internal_eval_ast(const AST_NodePtr &t_ast)
|
||||
{
|
||||
engine.sync_cache();
|
||||
return t_ast->eval(m_engine);
|
||||
}
|
||||
|
||||
return value;
|
||||
|
||||
/**
|
||||
* Evaluates the given string, used during eval() inside of a script
|
||||
*/
|
||||
const Boxed_Value internal_eval(const std::string &t_e) {
|
||||
return do_eval(t_e, "__EVAL__", true);
|
||||
}
|
||||
|
||||
void use(const std::string &t_filename)
|
||||
{
|
||||
for (size_t i = 0; i < m_usepaths.size(); ++i)
|
||||
{
|
||||
|
||||
try {
|
||||
const std::string appendedpath = m_usepaths[i] + t_filename;
|
||||
|
||||
chaiscript::detail::threading::lock_guard<chaiscript::detail::threading::recursive_mutex> l(m_use_mutex);
|
||||
chaiscript::detail::threading::shared_lock<chaiscript::detail::threading::shared_mutex> l2(m_mutex);
|
||||
|
||||
if (m_used_files.count(appendedpath) == 0)
|
||||
{
|
||||
m_used_files.insert(appendedpath);
|
||||
l2.unlock();
|
||||
eval_file(appendedpath);
|
||||
}
|
||||
} catch (const exception::file_not_found_error &) {
|
||||
if (i == m_usepaths.size() - 1)
|
||||
{
|
||||
throw exception::file_not_found_error(t_filename);
|
||||
}
|
||||
|
||||
// failed to load, try the next path
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Evaluates the given boxed string, used during eval() inside of a script
|
||||
* Returns the current evaluation m_engine
|
||||
*/
|
||||
const Boxed_Value internal_eval(const std::string &e) {
|
||||
return do_eval(e, "__EVAL__", true);
|
||||
chaiscript::detail::Dispatch_Engine &get_eval_engine() {
|
||||
return m_engine;
|
||||
}
|
||||
|
||||
void use(const std::string &filename)
|
||||
{
|
||||
#ifndef CHAISCRIPT_NO_THREADS
|
||||
boost::lock_guard<boost::recursive_mutex> l(use_mutex);
|
||||
boost::shared_lock<boost::shared_mutex> l2(mutex);
|
||||
#endif
|
||||
/**
|
||||
* Builds all the requirements for ChaiScript, including its evaluator and a run of its prelude.
|
||||
*/
|
||||
void build_eval_system() {
|
||||
using namespace bootstrap;
|
||||
m_engine.add_reserved_word("def");
|
||||
m_engine.add_reserved_word("fun");
|
||||
m_engine.add_reserved_word("while");
|
||||
m_engine.add_reserved_word("for");
|
||||
m_engine.add_reserved_word("if");
|
||||
m_engine.add_reserved_word("else");
|
||||
m_engine.add_reserved_word("&&");
|
||||
m_engine.add_reserved_word("||");
|
||||
m_engine.add_reserved_word(",");
|
||||
m_engine.add_reserved_word(":=");
|
||||
m_engine.add_reserved_word("var");
|
||||
m_engine.add_reserved_word("return");
|
||||
m_engine.add_reserved_word("break");
|
||||
m_engine.add_reserved_word("true");
|
||||
m_engine.add_reserved_word("false");
|
||||
m_engine.add_reserved_word("_");
|
||||
|
||||
if (loaded_files.count(filename) == 0)
|
||||
add(Bootstrap::bootstrap());
|
||||
|
||||
m_engine.add(fun(&chaiscript::detail::Dispatch_Engine::dump_system, boost::ref(m_engine)), "dump_system");
|
||||
m_engine.add(fun(&chaiscript::detail::Dispatch_Engine::dump_object, boost::ref(m_engine)), "dump_object");
|
||||
m_engine.add(fun(&chaiscript::detail::Dispatch_Engine::is_type, boost::ref(m_engine)), "is_type");
|
||||
m_engine.add(fun(&chaiscript::detail::Dispatch_Engine::type_name, boost::ref(m_engine)), "type_name");
|
||||
m_engine.add(fun(&chaiscript::detail::Dispatch_Engine::function_exists, boost::ref(m_engine)), "function_exists");
|
||||
|
||||
m_engine.add(fun(&chaiscript::detail::Dispatch_Engine::get_type_name, boost::ref(m_engine)), "name");
|
||||
|
||||
|
||||
typedef void (ChaiScript::*load_mod_1)(const std::string&);
|
||||
typedef void (ChaiScript::*load_mod_2)(const std::string&, const std::string&);
|
||||
|
||||
m_engine.add(fun(static_cast<load_mod_1>(&ChaiScript::load_module), this), "load_module");
|
||||
m_engine.add(fun(static_cast<load_mod_2>(&ChaiScript::load_module), this), "load_module");
|
||||
|
||||
add(standard_library::vector_type<std::vector<Boxed_Value> >("Vector"));
|
||||
add(standard_library::string_type<std::string>("string"));
|
||||
add(standard_library::map_type<std::map<std::string, Boxed_Value> >("Map"));
|
||||
add(standard_library::pair_type<std::pair<Boxed_Value, Boxed_Value > >("Pair"));
|
||||
|
||||
m_engine.add(fun(&ChaiScript::use, this), "use");
|
||||
m_engine.add(fun(&ChaiScript::internal_eval, this), "eval");
|
||||
m_engine.add(fun(&ChaiScript::internal_eval_ast, this), "eval");
|
||||
|
||||
do_eval(chaiscript_prelude, "standard prelude");
|
||||
}
|
||||
|
||||
/**
|
||||
* Helper function for loading a file
|
||||
*/
|
||||
std::string load_file(const std::string &t_filename) {
|
||||
std::ifstream infile(t_filename.c_str(), std::ios::in | std::ios::ate | std::ios::binary );
|
||||
|
||||
if (!infile.is_open()) {
|
||||
throw exception::file_not_found_error(t_filename);
|
||||
}
|
||||
|
||||
std::streampos size = infile.tellg();
|
||||
infile.seekg(0, std::ios::beg);
|
||||
|
||||
assert(size >= 0);
|
||||
|
||||
if (size == std::streampos(0))
|
||||
{
|
||||
#ifndef CHAISCRIPT_NO_THREADS
|
||||
l2.unlock();
|
||||
#endif
|
||||
eval_file(filename);
|
||||
return std::string();
|
||||
} else {
|
||||
engine.sync_cache();
|
||||
std::vector<char> v(static_cast<unsigned int>(size));
|
||||
infile.read(&v[0], size);
|
||||
return std::string(v.begin(), v.end());
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
public:
|
||||
ChaiScript_System() {
|
||||
loaded_files.insert("__EVAL__"); // Make sure the default name is already registered
|
||||
/// \brief Constructor for ChaiScript
|
||||
/// \param[in] t_modulepaths Vector of paths to search when attempting to load a binary module
|
||||
/// \param[in] t_usepaths Vector of paths to search when attempting to "use" an included ChaiScript file
|
||||
ChaiScript(const std::vector<std::string> &t_modulepaths = std::vector<std::string>(),
|
||||
const std::vector<std::string> &t_usepaths = std::vector<std::string>())
|
||||
: m_modulepaths(t_modulepaths), m_usepaths(t_usepaths)
|
||||
{
|
||||
if (m_modulepaths.empty())
|
||||
{
|
||||
m_modulepaths.push_back("");
|
||||
}
|
||||
|
||||
if (m_usepaths.empty())
|
||||
{
|
||||
m_usepaths.push_back("");
|
||||
}
|
||||
|
||||
build_eval_system();
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds a shared object, that can be used by all threads, to the system
|
||||
*/
|
||||
ChaiScript_System &add_global_const(const Boxed_Value &bv, const std::string &name)
|
||||
/// \brief Adds a constant object that is available in all contexts and to all threads
|
||||
/// \param[in] t_bv Boxed_Value to add as a global
|
||||
/// \param[in] t_name Name of the value to add
|
||||
/// \throw exception::global_non_const If t_bv is not a constant object
|
||||
/// \sa Boxed_Value::is_const
|
||||
ChaiScript &add_global_const(const Boxed_Value &t_bv, const std::string &t_name)
|
||||
{
|
||||
engine.add_global_const(bv, name);
|
||||
m_engine.add_global_const(t_bv, t_name);
|
||||
return *this;
|
||||
}
|
||||
|
||||
/// \brief Represents the current state of the ChaiScript system. State and be saved and restored
|
||||
/// \sa ChaiScript::get_state
|
||||
/// \sa ChaiScript::set_state
|
||||
struct State
|
||||
{
|
||||
std::set<std::string> loaded_files;
|
||||
typename Eval_Engine::State engine_state;
|
||||
std::set<std::string> used_files;
|
||||
chaiscript::detail::Dispatch_Engine::State engine_state;
|
||||
std::set<std::string> active_loaded_modules;
|
||||
};
|
||||
|
||||
/**
|
||||
* Returns a state object that represents the current
|
||||
* set of loaded files, the set of global variables and
|
||||
* the set of initialized functions
|
||||
*/
|
||||
/// \brief Returns a state object that represents the current state of the system
|
||||
/// \return Current state of the system
|
||||
///
|
||||
/// \b Example:
|
||||
///
|
||||
/// \code
|
||||
/// chaiscript::ChaiScript chai;
|
||||
/// chaiscript::ChaiScript::State s = chai.get_state(); // represents bootstrapped initial state
|
||||
/// \endcode
|
||||
State get_state()
|
||||
{
|
||||
#ifndef CHAISCRIPT_NO_THREADS
|
||||
boost::lock_guard<boost::recursive_mutex> l(use_mutex);
|
||||
boost::shared_lock<boost::shared_mutex> l2(mutex);
|
||||
#endif
|
||||
chaiscript::detail::threading::lock_guard<chaiscript::detail::threading::recursive_mutex> l(m_use_mutex);
|
||||
chaiscript::detail::threading::shared_lock<chaiscript::detail::threading::shared_mutex> l2(m_mutex);
|
||||
|
||||
State s;
|
||||
s.loaded_files = loaded_files;
|
||||
s.engine_state = engine.get_state();
|
||||
s.active_loaded_modules = active_loaded_modules;
|
||||
s.used_files = m_used_files;
|
||||
s.engine_state = m_engine.get_state();
|
||||
s.active_loaded_modules = m_active_loaded_modules;
|
||||
return s;
|
||||
}
|
||||
|
||||
/**
|
||||
* Restores the state from a saved State object.
|
||||
*/
|
||||
/// \brief Sets the state of the system
|
||||
/// \param[in] t_state New state to set
|
||||
///
|
||||
/// \b Example:
|
||||
/// \code
|
||||
/// chaiscript::ChaiScript chai;
|
||||
/// chaiscript::ChaiScript::State s = chai.get_state(); // get initial state
|
||||
/// chai.add(chaiscript::fun(&somefunction), "somefunction");
|
||||
/// chai.set_state(s); // restore initial state, which does not have the recently added "somefunction"
|
||||
/// \endcode
|
||||
void set_state(const State &t_state)
|
||||
{
|
||||
#ifndef CHAISCRIPT_NO_THREADS
|
||||
boost::lock_guard<boost::recursive_mutex> l(use_mutex);
|
||||
boost::shared_lock<boost::shared_mutex> l2(mutex);
|
||||
#endif
|
||||
chaiscript::detail::threading::lock_guard<chaiscript::detail::threading::recursive_mutex> l(m_use_mutex);
|
||||
chaiscript::detail::threading::shared_lock<chaiscript::detail::threading::shared_mutex> l2(m_mutex);
|
||||
|
||||
loaded_files = t_state.loaded_files;
|
||||
active_loaded_modules = t_state.active_loaded_modules;
|
||||
engine.set_state(t_state.engine_state);
|
||||
m_used_files = t_state.used_files;
|
||||
m_active_loaded_modules = t_state.active_loaded_modules;
|
||||
m_engine.set_state(t_state.engine_state);
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds an object to the system: type, function, object
|
||||
*/
|
||||
/// \brief Adds a type, function or object to ChaiScript
|
||||
/// \param[in] t_t Item to add
|
||||
/// \param[in] t_name Name of item to add
|
||||
/// \returns Reference to current ChaiScript object
|
||||
///
|
||||
/// \b Examples:
|
||||
/// \code
|
||||
/// chaiscript::ChaiScript chai;
|
||||
/// chai.add(chaiscript::user_type<MyClass>(), "MyClass"); // Add explicit type info (not strictly necessary)
|
||||
/// chai.add(chaiscript::fun(&MyClass::function), "function"); // Add a class method
|
||||
/// MyClass obj;
|
||||
/// chai.add(chaiscript::var(&obj), "obj"); // Add a pointer to a locally defined object
|
||||
/// \endcode
|
||||
///
|
||||
/// \sa \ref addingitems
|
||||
template<typename T>
|
||||
ChaiScript_System &add(const T &t, const std::string &name)
|
||||
ChaiScript &add(const T &t_t, const std::string &t_name)
|
||||
{
|
||||
engine.add(t, name);
|
||||
m_engine.add(t_t, t_name);
|
||||
return *this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds a module object to the system
|
||||
*/
|
||||
ChaiScript_System &add(const ModulePtr &p)
|
||||
/// \brief Add a new conversion for upcasting to a base class
|
||||
/// \sa chaiscript::base_class
|
||||
/// \param[in] d Base class / parent class
|
||||
///
|
||||
/// \b Example:
|
||||
/// \code
|
||||
/// chaiscript::ChaiScript chai;
|
||||
/// chai.add(chaiscript::base_class<std::runtime_error, chaiscript::dispatch_error>());
|
||||
/// \endcode
|
||||
ChaiScript &add(const Dynamic_Cast_Conversion &d)
|
||||
{
|
||||
p->apply(*this, this->get_eval_engine());
|
||||
m_engine.add(d);
|
||||
return *this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Load a dynamic library containing a chaiscript module
|
||||
*/
|
||||
/// \brief Adds all elements of a module to ChaiScript runtime
|
||||
/// \param[in] t_p The module to add.
|
||||
/// \sa chaiscript::Module
|
||||
ChaiScript &add(const ModulePtr &t_p)
|
||||
{
|
||||
t_p->apply(*this, this->get_eval_engine());
|
||||
return *this;
|
||||
}
|
||||
|
||||
/// \brief Load a binary module from a dynamic library. Works on platforms that support
|
||||
/// dynamic libraries.
|
||||
/// \param[in] t_module_name Name of the module to load
|
||||
///
|
||||
/// The module is searched for in the registered module path folders (chaiscript::ChaiScript::ChaiScript)
|
||||
/// and with standard prefixes and postfixes: ("lib"|"")\<t_module_name\>(".dll"|".so"|"").
|
||||
///
|
||||
/// Once the file is located, the system looks for the symbol "create_chaiscript_module_\<t_module_name\>".
|
||||
/// If no file can be found matching the search criteria and containing the appropriate entry point
|
||||
/// (the symbol mentioned above), an exception is thrown.
|
||||
///
|
||||
/// \throw exception::load_module_error In the event that no matching module can be found.
|
||||
void load_module(const std::string &t_module_name)
|
||||
{
|
||||
std::vector<exception::load_module_error> errors;
|
||||
|
||||
std::vector<std::string> prefixes;
|
||||
prefixes.push_back("lib");
|
||||
prefixes.push_back("");
|
||||
@@ -408,187 +536,126 @@ namespace chaiscript
|
||||
postfixes.push_back(".so");
|
||||
postfixes.push_back("");
|
||||
|
||||
for (size_t i = 0; i < prefixes.size(); ++i)
|
||||
for (size_t i = 0; i < m_modulepaths.size(); ++i)
|
||||
{
|
||||
for (size_t j = 0; j < postfixes.size(); ++j)
|
||||
for (size_t j = 0; j < prefixes.size(); ++j)
|
||||
{
|
||||
for (size_t k = 0; k < postfixes.size(); ++k)
|
||||
{
|
||||
try {
|
||||
std::string name = prefixes[i] + t_module_name + postfixes[j];
|
||||
std::string name = m_modulepaths[i] + prefixes[j] + t_module_name + postfixes[k];
|
||||
load_module(t_module_name, name);
|
||||
return;
|
||||
} catch (const load_module_error &) {
|
||||
} catch (const exception::load_module_error &e) {
|
||||
errors.push_back(e);
|
||||
// Try next set
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
throw load_module_error("Unable to find module: " + t_module_name);
|
||||
}
|
||||
|
||||
/**
|
||||
* Load a dynamic library and provide the file name to load it from
|
||||
*/
|
||||
std::string errstring;
|
||||
|
||||
for (std::vector<exception::load_module_error>::const_iterator itr = errors.begin();
|
||||
itr != errors.end();
|
||||
++itr)
|
||||
{
|
||||
if (!errstring.empty())
|
||||
{
|
||||
errstring += "; ";
|
||||
}
|
||||
|
||||
errstring += itr->what();
|
||||
}
|
||||
|
||||
throw exception::load_module_error("Unable to find module: " + t_module_name + " Errors: " + errstring);
|
||||
}
|
||||
|
||||
/// \brief Load a binary module from a dynamic library. Works on platforms that support
|
||||
/// dynamic libraries.
|
||||
///
|
||||
/// \param[in] t_module_name Module name to load
|
||||
/// \param[in] t_filename Ignore normal filename search process and use specific filename
|
||||
///
|
||||
/// \sa ChaiScript::load_module(const std::string &t_module_name)
|
||||
void load_module(const std::string &t_module_name, const std::string &t_filename)
|
||||
{
|
||||
#ifndef CHAISCRIPT_NO_THREADS
|
||||
boost::lock_guard<boost::recursive_mutex> l(use_mutex);
|
||||
#endif
|
||||
chaiscript::detail::threading::lock_guard<chaiscript::detail::threading::recursive_mutex> l(m_use_mutex);
|
||||
|
||||
if (loaded_modules.count(t_module_name) == 0)
|
||||
if (m_loaded_modules.count(t_module_name) == 0)
|
||||
{
|
||||
Loadable_Module_Ptr lm(new Loadable_Module(t_module_name, t_filename));
|
||||
loaded_modules[t_module_name] = lm;
|
||||
active_loaded_modules.insert(t_module_name);
|
||||
detail::Loadable_Module_Ptr lm(new detail::Loadable_Module(t_module_name, t_filename));
|
||||
m_loaded_modules[t_module_name] = lm;
|
||||
m_active_loaded_modules.insert(t_module_name);
|
||||
add(lm->m_moduleptr);
|
||||
} else if (active_loaded_modules.count(t_module_name) == 0) {
|
||||
active_loaded_modules.insert(t_module_name);
|
||||
add(loaded_modules[t_module_name]->m_moduleptr);
|
||||
} else {
|
||||
engine.sync_cache();
|
||||
} else if (m_active_loaded_modules.count(t_module_name) == 0) {
|
||||
m_active_loaded_modules.insert(t_module_name);
|
||||
add(m_loaded_modules[t_module_name]->m_moduleptr);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Helper for calling script code as if it were native C++ code
|
||||
* example:
|
||||
* boost::function<int (int, int)> f = build_functor(chai, "func(x, y){x+y}");
|
||||
* \return a boost::function representing the passed in script
|
||||
* \param[in] script Script code to build a function from
|
||||
*/
|
||||
template<typename FunctionType>
|
||||
boost::function<FunctionType> functor(const std::string &script)
|
||||
/// \brief Evaluates a string. Equivalent to ChaiScript::eval.
|
||||
///
|
||||
/// \param[in] t_script Script to execute
|
||||
///
|
||||
/// \return result of the script execution
|
||||
///
|
||||
/// \throw exception::eval_error In the case that evaluation fails.
|
||||
Boxed_Value operator()(const std::string &t_script)
|
||||
{
|
||||
return chaiscript::functor<FunctionType>(eval(script));
|
||||
}
|
||||
|
||||
/**
|
||||
* Evaluate a string via eval method
|
||||
*/
|
||||
Boxed_Value operator()(const std::string &script)
|
||||
{
|
||||
return do_eval(script);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Returns the current evaluation engine
|
||||
*/
|
||||
Eval_Engine &get_eval_engine() {
|
||||
return engine;
|
||||
}
|
||||
|
||||
/**
|
||||
* Prints the contents of an AST node, including its children, recursively
|
||||
*/
|
||||
void debug_print(TokenPtr t, std::string prepend = "") {
|
||||
std::cout << prepend << "(" << token_type_to_string(t->identifier) << ") " << t->text << " : " << t->start.line << ", " << t->start.column << std::endl;
|
||||
for (unsigned int j = 0; j < t->children.size(); ++j) {
|
||||
debug_print(t->children[j], prepend + " ");
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Helper function for loading a file
|
||||
*/
|
||||
std::string load_file(const std::string &filename) {
|
||||
std::ifstream infile (filename.c_str(), std::ios::in | std::ios::ate);
|
||||
|
||||
if (!infile.is_open()) {
|
||||
throw std::runtime_error("Can not open: " + filename);
|
||||
}
|
||||
|
||||
std::streampos size = infile.tellg();
|
||||
infile.seekg(0, std::ios::beg);
|
||||
|
||||
std::vector<char> v(size);
|
||||
infile.read(&v[0], size);
|
||||
|
||||
std::string ret_val (v.empty() ? std::string() : std::string (v.begin(), v.end()).c_str());
|
||||
|
||||
return ret_val;
|
||||
}
|
||||
|
||||
/**
|
||||
* Builds all the requirements for ChaiScript, including its evaluator and a run of its prelude.
|
||||
*/
|
||||
void build_eval_system() {
|
||||
using namespace bootstrap;
|
||||
engine.add_reserved_word("def");
|
||||
engine.add_reserved_word("fun");
|
||||
engine.add_reserved_word("while");
|
||||
engine.add_reserved_word("for");
|
||||
engine.add_reserved_word("if");
|
||||
engine.add_reserved_word("else");
|
||||
engine.add_reserved_word("&&");
|
||||
engine.add_reserved_word("||");
|
||||
engine.add_reserved_word(",");
|
||||
engine.add_reserved_word(":=");
|
||||
engine.add_reserved_word("var");
|
||||
engine.add_reserved_word("return");
|
||||
engine.add_reserved_word("break");
|
||||
engine.add_reserved_word("true");
|
||||
engine.add_reserved_word("false");
|
||||
engine.add_reserved_word("_");
|
||||
|
||||
add(Bootstrap::bootstrap());
|
||||
|
||||
engine.add(fun(&Eval_Engine::dump_system, boost::ref(engine)), "dump_system");
|
||||
engine.add(fun(&Eval_Engine::dump_object, boost::ref(engine)), "dump_object");
|
||||
engine.add(fun(&Eval_Engine::is_type, boost::ref(engine)), "is_type");
|
||||
engine.add(fun(&Eval_Engine::type_name, boost::ref(engine)), "type_name");
|
||||
engine.add(fun(&Eval_Engine::function_exists, boost::ref(engine)), "function_exists");
|
||||
|
||||
engine.add(fun(&Eval_Engine::get_type_name, boost::ref(engine)), "name");
|
||||
|
||||
|
||||
typedef void (ChaiScript_System<Eval_Engine>::*load_mod_1)(const std::string&);
|
||||
typedef void (ChaiScript_System<Eval_Engine>::*load_mod_2)(const std::string&, const std::string&);
|
||||
|
||||
engine.add(fun(static_cast<load_mod_1>(&ChaiScript_System<Eval_Engine>::load_module), this), "load_module");
|
||||
engine.add(fun(static_cast<load_mod_2>(&ChaiScript_System<Eval_Engine>::load_module), this), "load_module");
|
||||
|
||||
|
||||
add(vector_type<std::vector<Boxed_Value> >("Vector"));
|
||||
add(string_type<std::string>("string"));
|
||||
add(map_type<std::map<std::string, Boxed_Value> >("Map"));
|
||||
add(pair_type<std::pair<Boxed_Value, Boxed_Value > >("Pair"));
|
||||
|
||||
engine.add(fun(&ChaiScript_System<Eval_Engine>::use, this), "use");
|
||||
engine.add(fun(&ChaiScript_System<Eval_Engine>::internal_eval, this), "eval");
|
||||
|
||||
|
||||
do_eval(chaiscript_prelude, "standard prelude");
|
||||
return do_eval(t_script);
|
||||
}
|
||||
|
||||
/// \brief Evaluates a string and returns a typesafe result.
|
||||
///
|
||||
/// \tparam T Type to extract from the result value of the script execution
|
||||
/// \param[in] t_input Script to execute
|
||||
///
|
||||
/// \return result of the script execution
|
||||
///
|
||||
/// \throw exception::eval_error In the case that evaluation fails.
|
||||
/// \throw exception::bad_boxed_cast In the case that evaluation succeeds but the result value cannot be converted
|
||||
/// to the requested type.
|
||||
template<typename T>
|
||||
T eval(const std::string &input)
|
||||
T eval(const std::string &t_input)
|
||||
{
|
||||
return boxed_cast<T>(do_eval(input));
|
||||
return boxed_cast<T>(do_eval(t_input));
|
||||
}
|
||||
|
||||
Boxed_Value eval(const std::string &input)
|
||||
/// \brief Evaluates a string.
|
||||
///
|
||||
/// \param[in] t_input Script to execute
|
||||
///
|
||||
/// \return result of the script execution
|
||||
///
|
||||
/// \throw exception::eval_error In the case that evaluation fails.
|
||||
Boxed_Value eval(const std::string &t_input)
|
||||
{
|
||||
return do_eval(input);
|
||||
return do_eval(t_input);
|
||||
}
|
||||
|
||||
/**
|
||||
* Loads the file specified by filename, evaluates it, and returns the result
|
||||
*/
|
||||
Boxed_Value eval_file(const std::string &filename) {
|
||||
return do_eval(load_file(filename), filename);
|
||||
/// \brief Loads the file specified by filename, evaluates it, and returns the result.
|
||||
/// \param[in] t_filename File to load and parse.
|
||||
/// \return result of the script execution
|
||||
/// \throw exception::eval_error In the case that evaluation fails.
|
||||
Boxed_Value eval_file(const std::string &t_filename) {
|
||||
return do_eval(load_file(t_filename), t_filename);
|
||||
}
|
||||
|
||||
/**
|
||||
* Loads the file specified by filename, evaluates it, and returns the as the specified type
|
||||
*/
|
||||
/// \brief Loads the file specified by filename, evaluates it, and returns the typesafe result.
|
||||
/// \tparam T Type to extract from the result value of the script execution
|
||||
/// \param[in] t_filename File to load and parse.
|
||||
/// \return result of the script execution
|
||||
/// \throw exception::eval_error In the case that evaluation fails.
|
||||
/// \throw exception::bad_boxed_cast In the case that evaluation succeeds but the result value cannot be converted
|
||||
/// to the requested type.
|
||||
template<typename T>
|
||||
T eval_file(const std::string &filename) {
|
||||
return boxed_cast<T>(do_eval(load_file(filename), filename));
|
||||
T eval_file(const std::string &t_filename) {
|
||||
return boxed_cast<T>(do_eval(load_file(t_filename), t_filename));
|
||||
}
|
||||
};
|
||||
|
||||
typedef ChaiScript_System<Dispatch_Engine> ChaiScript;
|
||||
}
|
||||
#endif /* CHAISCRIPT_ENGINE_HPP_ */
|
||||
|
||||
|
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, Jonathan Turner (jturner@minnow-lang.org)
|
||||
// and Jason Turner (lefticus@gmail.com)
|
||||
// Copyright 2009-2011, Jonathan Turner (jonathan@emptycrate.com)
|
||||
// and Jason Turner (jason@emptycrate.com)
|
||||
// http://www.chaiscript.com
|
||||
|
||||
#ifndef CHAISCRIPT_PRELUDE_HPP_
|
||||
@@ -131,11 +131,11 @@ 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\
|
||||
var inserter = back_inserter(retval); \n\
|
||||
var range = range(y); \n\
|
||||
while (!range.empty()) { \n\
|
||||
inserter(range.front()); \n\
|
||||
range.pop_front(); \n\
|
||||
} \n\
|
||||
retval; \n\
|
||||
} \n\
|
||||
@@ -305,15 +305,15 @@ 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\
|
||||
def find(container, value, compare_func) : call_exists(range, container) && is_type(compare_func, "Function") { \n\
|
||||
var range = range(container); \n\
|
||||
while (!range.empty()) { \n\
|
||||
if (compare_func(range.front(), value)) { \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);
|
||||
}
|
||||
|
89
include/chaiscript/utility/utility.hpp
Normal file
89
include/chaiscript/utility/utility.hpp
Normal file
@@ -0,0 +1,89 @@
|
||||
// This file is distributed under the BSD License.
|
||||
// See "license.txt" for details.
|
||||
// Copyright 2009-2011, 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 <boost/preprocessor.hpp>
|
||||
#include <string>
|
||||
|
||||
#define CHAISCRIPT_MODULE(_info) BOOST_PP_SEQ_ELEM(0, _info)
|
||||
|
||||
#define CHAISCRIPT_CLASS_ELEM(_info) BOOST_PP_SEQ_ELEM(1, _info)
|
||||
|
||||
#define CHAISCRIPT_METHOD(_info, _method) & CHAISCRIPT_CLASS_ELEM(_info) :: BOOST_PP_SEQ_ELEM(0, _method)
|
||||
|
||||
#define CHAISCRIPT_METHOD_NAME(_info, _method) \
|
||||
BOOST_PP_SEQ_ELEM(3, _info) (BOOST_PP_STRINGIZE(BOOST_PP_SEQ_ELEM(0, _method ) ) )
|
||||
|
||||
#define CHAISCRIPT_CLASS_NAME(_info) \
|
||||
BOOST_PP_SEQ_ELEM(2, _info) (BOOST_PP_STRINGIZE(CHAISCRIPT_CLASS_ELEM(_info) ) )
|
||||
|
||||
#define CHAISCRIPT_METHOD_SIGNATURE_PART(_r, _info, _i, _method_part) \
|
||||
BOOST_PP_EXPR_IF(BOOST_PP_EQUAL(_i, 1), < _method_part > )
|
||||
|
||||
#define CHAISCRIPT_METHOD_SIGNATURE(_info, _method) \
|
||||
BOOST_PP_SEQ_FOR_EACH_I(CHAISCRIPT_METHOD_SIGNATURE_PART, _info, _method)
|
||||
|
||||
#define CHAISCRIPT_CLASS_CONSTRUCTOR(_r, _info, _constructor) \
|
||||
CHAISCRIPT_MODULE(_info) ->add BOOST_PP_LPAREN() chaiscript::constructor<_constructor>() BOOST_PP_COMMA() CHAISCRIPT_CLASS_NAME(_info) BOOST_PP_RPAREN() ;
|
||||
|
||||
#define CHAISCRIPT_CLASS_METHOD(_r, _info, _method) \
|
||||
CHAISCRIPT_MODULE(_info) ->add BOOST_PP_LPAREN() chaiscript::fun CHAISCRIPT_METHOD_SIGNATURE(_info, _method) \
|
||||
BOOST_PP_LPAREN() CHAISCRIPT_METHOD(_info, _method) BOOST_PP_RPAREN() BOOST_PP_COMMA() CHAISCRIPT_METHOD_NAME(_info, _method)BOOST_PP_RPAREN() ;
|
||||
|
||||
#define CHAISCRIPT_CLASS_CONSTRUCTORS(_info, _constructors) \
|
||||
BOOST_PP_SEQ_FOR_EACH(CHAISCRIPT_CLASS_CONSTRUCTOR, _info, _constructors)
|
||||
|
||||
#define CHAISCRIPT_CLASS_METHODS(_info, _methods) \
|
||||
BOOST_PP_SEQ_FOR_EACH(CHAISCRIPT_CLASS_METHOD, _info, _methods)
|
||||
|
||||
#define CHAISCRIPT_CLASS_EX(_module, _class_name, _class_name_translator, _method_name_translator, _constructors, _methods) \
|
||||
{ \
|
||||
_module->add(chaiscript::user_type<_class_name>(), _class_name_translator (BOOST_PP_STRINGIZE(_class_name))); \
|
||||
CHAISCRIPT_CLASS_CONSTRUCTORS((_module)(_class_name)(_class_name_translator), _constructors) \
|
||||
CHAISCRIPT_CLASS_METHODS((_module)(_class_name)(_class_name_translator)(_method_name_translator), _methods) \
|
||||
}
|
||||
|
||||
#define CHAISCRIPT_CLASS(_module, _class_name, _constructors, _methods) \
|
||||
CHAISCRIPT_CLASS_EX(_module, _class_name, chaiscript::utility::class_name_translator, \
|
||||
chaiscript::utility::method_name_translator, _constructors, _methods)
|
||||
|
||||
namespace chaiscript
|
||||
{
|
||||
/// \brief Classes and functions which provide general utility to the end user.
|
||||
namespace utility
|
||||
{
|
||||
inline std::string class_name_translator(const std::string &t_name)
|
||||
{
|
||||
size_t colon = t_name.rfind("::");
|
||||
if (colon != std::string::npos)
|
||||
{
|
||||
return t_name.substr(colon+2, std::string::npos);
|
||||
} else {
|
||||
return t_name;
|
||||
}
|
||||
}
|
||||
|
||||
inline std::string method_name_translator(const std::string &t_name)
|
||||
{
|
||||
size_t namestart = t_name.rfind("operator");
|
||||
namestart = (namestart == std::string::npos)?0:namestart+strlen("operator");
|
||||
|
||||
if (namestart == 0)
|
||||
{
|
||||
namestart = t_name.rfind("::");
|
||||
namestart = (namestart == std::string::npos)?0:namestart+strlen("::");
|
||||
}
|
||||
|
||||
return t_name.substr(namestart, std::string::npos);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
||||
|
@@ -1,4 +1,4 @@
|
||||
Copyright 2009 Jason and Jonathan Turner. All Rights Reserved.
|
||||
Copyright 2009-2010 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:
|
||||
|
@@ -1,197 +0,0 @@
|
||||
<?xml version="1.0" encoding="Windows-1252"?>
|
||||
<VisualStudioProject
|
||||
ProjectType="Visual C++"
|
||||
Version="9.00"
|
||||
Name="chai-example"
|
||||
ProjectGUID="{CE422E94-B360-4588-8C65-6A9BE80798F9}"
|
||||
RootNamespace="chaiexample"
|
||||
Keyword="Win32Proj"
|
||||
TargetFrameworkVersion="196613"
|
||||
>
|
||||
<Platforms>
|
||||
<Platform
|
||||
Name="Win32"
|
||||
/>
|
||||
</Platforms>
|
||||
<ToolFiles>
|
||||
</ToolFiles>
|
||||
<Configurations>
|
||||
<Configuration
|
||||
Name="Debug|Win32"
|
||||
OutputDirectory="$(SolutionDir)$(ConfigurationName)"
|
||||
IntermediateDirectory="$(ConfigurationName)"
|
||||
ConfigurationType="1"
|
||||
InheritedPropertySheets="..\chaiscript\Boost.vsprops"
|
||||
CharacterSet="0"
|
||||
>
|
||||
<Tool
|
||||
Name="VCPreBuildEventTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCCustomBuildTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCXMLDataGeneratorTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCWebServiceProxyGeneratorTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCMIDLTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCCLCompilerTool"
|
||||
Optimization="0"
|
||||
AdditionalIncludeDirectories=""$(ProjectDir)\..\..\include""
|
||||
PreprocessorDefinitions="WIN32;_DEBUG;_CONSOLE"
|
||||
MinimalRebuild="true"
|
||||
BasicRuntimeChecks="3"
|
||||
RuntimeLibrary="3"
|
||||
UsePrecompiledHeader="0"
|
||||
WarningLevel="3"
|
||||
DebugInformationFormat="4"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCManagedResourceCompilerTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCResourceCompilerTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCPreLinkEventTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCLinkerTool"
|
||||
LinkIncremental="2"
|
||||
GenerateDebugInformation="true"
|
||||
SubSystem="1"
|
||||
TargetMachine="1"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCALinkTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCManifestTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCXDCMakeTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCBscMakeTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCFxCopTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCAppVerifierTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCPostBuildEventTool"
|
||||
/>
|
||||
</Configuration>
|
||||
<Configuration
|
||||
Name="Release|Win32"
|
||||
OutputDirectory="$(SolutionDir)$(ConfigurationName)"
|
||||
IntermediateDirectory="$(ConfigurationName)"
|
||||
ConfigurationType="1"
|
||||
InheritedPropertySheets="..\chaiscript\Boost.vsprops"
|
||||
CharacterSet="0"
|
||||
WholeProgramOptimization="1"
|
||||
>
|
||||
<Tool
|
||||
Name="VCPreBuildEventTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCCustomBuildTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCXMLDataGeneratorTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCWebServiceProxyGeneratorTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCMIDLTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCCLCompilerTool"
|
||||
Optimization="2"
|
||||
EnableIntrinsicFunctions="true"
|
||||
AdditionalIncludeDirectories=""$(ProjectDir)\..\..\include""
|
||||
PreprocessorDefinitions="WIN32;NDEBUG;_CONSOLE"
|
||||
RuntimeLibrary="2"
|
||||
EnableFunctionLevelLinking="true"
|
||||
UsePrecompiledHeader="0"
|
||||
WarningLevel="3"
|
||||
DebugInformationFormat="3"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCManagedResourceCompilerTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCResourceCompilerTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCPreLinkEventTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCLinkerTool"
|
||||
LinkIncremental="1"
|
||||
GenerateDebugInformation="true"
|
||||
SubSystem="1"
|
||||
OptimizeReferences="2"
|
||||
EnableCOMDATFolding="2"
|
||||
TargetMachine="1"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCALinkTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCManifestTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCXDCMakeTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCBscMakeTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCFxCopTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCAppVerifierTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCPostBuildEventTool"
|
||||
/>
|
||||
</Configuration>
|
||||
</Configurations>
|
||||
<References>
|
||||
</References>
|
||||
<Files>
|
||||
<Filter
|
||||
Name="Source Files"
|
||||
Filter="cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx"
|
||||
UniqueIdentifier="{4FC737F1-C7A5-4376-A066-2A32D752A2FF}"
|
||||
>
|
||||
<File
|
||||
RelativePath="..\..\src\example.cpp"
|
||||
>
|
||||
</File>
|
||||
</Filter>
|
||||
<Filter
|
||||
Name="Header Files"
|
||||
Filter="h;hpp;hxx;hm;inl;inc;xsd"
|
||||
UniqueIdentifier="{93995380-89BD-4b04-88EB-625FBE52EBFB}"
|
||||
>
|
||||
</Filter>
|
||||
<Filter
|
||||
Name="Resource Files"
|
||||
Filter="rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav"
|
||||
UniqueIdentifier="{67DA6AB6-F800-4c08-8B7A-83BB121AAD01}"
|
||||
>
|
||||
</Filter>
|
||||
</Files>
|
||||
<Globals>
|
||||
</Globals>
|
||||
</VisualStudioProject>
|
@@ -1,19 +0,0 @@
|
||||
<?xml version="1.0" encoding="Windows-1252"?>
|
||||
<VisualStudioPropertySheet
|
||||
ProjectType="Visual C++"
|
||||
Version="8.00"
|
||||
Name="Boost"
|
||||
>
|
||||
<Tool
|
||||
Name="VCCLCompilerTool"
|
||||
AdditionalIncludeDirectories=""C:\boost\include\boost-1_38""
|
||||
/>
|
||||
<Tool
|
||||
Name="VCLibrarianTool"
|
||||
AdditionalLibraryDirectories="C:\Programming\Boost\lib"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCLinkerTool"
|
||||
AdditionalLibraryDirectories="C:\Boost\lib;C:\Programming\Boost\lib"
|
||||
/>
|
||||
</VisualStudioPropertySheet>
|
@@ -1,32 +0,0 @@
|
||||
|
||||
Microsoft Visual Studio Solution File, Format Version 10.00
|
||||
# Visual C++ Express 2008
|
||||
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "chaiscript", "chaiscript.vcproj", "{46FD9DC7-2DA9-4C17-ADE4-E3A18C46E87B}"
|
||||
EndProject
|
||||
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "chai-example", "..\chai-example\chai-example.vcproj", "{CE422E94-B360-4588-8C65-6A9BE80798F9}"
|
||||
EndProject
|
||||
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "test_module", "..\test_module\test_module.vcproj", "{775EDCC2-102F-4E75-A860-9AF398D04145}"
|
||||
EndProject
|
||||
Global
|
||||
GlobalSection(SolutionConfigurationPlatforms) = preSolution
|
||||
Debug|Win32 = Debug|Win32
|
||||
Release|Win32 = Release|Win32
|
||||
EndGlobalSection
|
||||
GlobalSection(ProjectConfigurationPlatforms) = postSolution
|
||||
{46FD9DC7-2DA9-4C17-ADE4-E3A18C46E87B}.Debug|Win32.ActiveCfg = Debug|Win32
|
||||
{46FD9DC7-2DA9-4C17-ADE4-E3A18C46E87B}.Debug|Win32.Build.0 = Debug|Win32
|
||||
{46FD9DC7-2DA9-4C17-ADE4-E3A18C46E87B}.Release|Win32.ActiveCfg = Release|Win32
|
||||
{46FD9DC7-2DA9-4C17-ADE4-E3A18C46E87B}.Release|Win32.Build.0 = Release|Win32
|
||||
{CE422E94-B360-4588-8C65-6A9BE80798F9}.Debug|Win32.ActiveCfg = Debug|Win32
|
||||
{CE422E94-B360-4588-8C65-6A9BE80798F9}.Debug|Win32.Build.0 = Debug|Win32
|
||||
{CE422E94-B360-4588-8C65-6A9BE80798F9}.Release|Win32.ActiveCfg = Release|Win32
|
||||
{CE422E94-B360-4588-8C65-6A9BE80798F9}.Release|Win32.Build.0 = Release|Win32
|
||||
{775EDCC2-102F-4E75-A860-9AF398D04145}.Debug|Win32.ActiveCfg = Debug|Win32
|
||||
{775EDCC2-102F-4E75-A860-9AF398D04145}.Debug|Win32.Build.0 = Debug|Win32
|
||||
{775EDCC2-102F-4E75-A860-9AF398D04145}.Release|Win32.ActiveCfg = Release|Win32
|
||||
{775EDCC2-102F-4E75-A860-9AF398D04145}.Release|Win32.Build.0 = Release|Win32
|
||||
EndGlobalSection
|
||||
GlobalSection(SolutionProperties) = preSolution
|
||||
HideSolutionNode = FALSE
|
||||
EndGlobalSection
|
||||
EndGlobal
|
@@ -1,286 +0,0 @@
|
||||
<?xml version="1.0" encoding="Windows-1252"?>
|
||||
<VisualStudioProject
|
||||
ProjectType="Visual C++"
|
||||
Version="9.00"
|
||||
Name="chaiscript"
|
||||
ProjectGUID="{46FD9DC7-2DA9-4C17-ADE4-E3A18C46E87B}"
|
||||
RootNamespace="chaiscript"
|
||||
Keyword="Win32Proj"
|
||||
TargetFrameworkVersion="196613"
|
||||
>
|
||||
<Platforms>
|
||||
<Platform
|
||||
Name="Win32"
|
||||
/>
|
||||
</Platforms>
|
||||
<ToolFiles>
|
||||
</ToolFiles>
|
||||
<Configurations>
|
||||
<Configuration
|
||||
Name="Debug|Win32"
|
||||
OutputDirectory="$(SolutionDir)$(ConfigurationName)"
|
||||
IntermediateDirectory="$(ConfigurationName)"
|
||||
ConfigurationType="1"
|
||||
InheritedPropertySheets=".\Boost.vsprops"
|
||||
UseOfMFC="2"
|
||||
CharacterSet="1"
|
||||
>
|
||||
<Tool
|
||||
Name="VCPreBuildEventTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCCustomBuildTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCXMLDataGeneratorTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCWebServiceProxyGeneratorTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCMIDLTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCCLCompilerTool"
|
||||
UseUnicodeResponseFiles="false"
|
||||
Optimization="0"
|
||||
AdditionalIncludeDirectories=""$(ProjectDir)\..\..\include""
|
||||
PreprocessorDefinitions="WIN32;_DEBUG;_CONSOLE"
|
||||
MinimalRebuild="true"
|
||||
BasicRuntimeChecks="3"
|
||||
RuntimeLibrary="3"
|
||||
DisableLanguageExtensions="false"
|
||||
TreatWChar_tAsBuiltInType="false"
|
||||
UsePrecompiledHeader="0"
|
||||
WarningLevel="4"
|
||||
DebugInformationFormat="4"
|
||||
CompileAs="2"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCManagedResourceCompilerTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCResourceCompilerTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCPreLinkEventTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCLinkerTool"
|
||||
LinkIncremental="2"
|
||||
GenerateDebugInformation="true"
|
||||
SubSystem="1"
|
||||
TargetMachine="1"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCALinkTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCManifestTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCXDCMakeTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCBscMakeTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCFxCopTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCAppVerifierTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCPostBuildEventTool"
|
||||
/>
|
||||
</Configuration>
|
||||
<Configuration
|
||||
Name="Release|Win32"
|
||||
OutputDirectory="$(SolutionDir)$(ConfigurationName)"
|
||||
IntermediateDirectory="$(ConfigurationName)"
|
||||
ConfigurationType="1"
|
||||
InheritedPropertySheets=".\Boost.vsprops"
|
||||
CharacterSet="1"
|
||||
WholeProgramOptimization="1"
|
||||
>
|
||||
<Tool
|
||||
Name="VCPreBuildEventTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCCustomBuildTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCXMLDataGeneratorTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCWebServiceProxyGeneratorTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCMIDLTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCCLCompilerTool"
|
||||
Optimization="3"
|
||||
EnableIntrinsicFunctions="true"
|
||||
AdditionalIncludeDirectories=""$(ProjectDir)\..\..\include""
|
||||
PreprocessorDefinitions="WIN32;NDEBUG;_CONSOLE"
|
||||
RuntimeLibrary="2"
|
||||
EnableFunctionLevelLinking="true"
|
||||
UsePrecompiledHeader="0"
|
||||
WarningLevel="4"
|
||||
DebugInformationFormat="3"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCManagedResourceCompilerTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCResourceCompilerTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCPreLinkEventTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCLinkerTool"
|
||||
LinkIncremental="1"
|
||||
GenerateDebugInformation="true"
|
||||
SubSystem="1"
|
||||
OptimizeReferences="2"
|
||||
EnableCOMDATFolding="2"
|
||||
TargetMachine="1"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCALinkTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCManifestTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCXDCMakeTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCBscMakeTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCFxCopTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCAppVerifierTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCPostBuildEventTool"
|
||||
/>
|
||||
</Configuration>
|
||||
</Configurations>
|
||||
<References>
|
||||
</References>
|
||||
<Files>
|
||||
<Filter
|
||||
Name="Source Files"
|
||||
Filter="cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx"
|
||||
UniqueIdentifier="{4FC737F1-C7A5-4376-A066-2A32D752A2FF}"
|
||||
>
|
||||
<File
|
||||
RelativePath="..\..\src\main.cpp"
|
||||
>
|
||||
</File>
|
||||
</Filter>
|
||||
<Filter
|
||||
Name="Header Files"
|
||||
Filter="h;hpp;hxx;hm;inl;inc;xsd"
|
||||
UniqueIdentifier="{93995380-89BD-4b04-88EB-625FBE52EBFB}"
|
||||
>
|
||||
<File
|
||||
RelativePath="..\..\include\chaiscript\dispatchkit\bind_first.hpp"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\..\include\chaiscript\dispatchkit\bootstrap.hpp"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\..\include\chaiscript\dispatchkit\bootstrap_stl.hpp"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\..\include\chaiscript\dispatchkit\boxed_value.hpp"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\..\include\chaiscript\chaiscript.hpp"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\..\include\chaiscript\language\chaiscript_engine.hpp"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\..\include\chaiscript\language\chaiscript_eval.hpp"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\..\include\chaiscript\language\chaiscript_parser.hpp"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\..\include\chaiscript\language\chaiscript_prelude.hpp"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\..\include\chaiscript\chaiscript_threading.hpp"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\..\include\chaiscript\dispatchkit\dispatchkit.hpp"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\..\include\chaiscript\dispatchkit\dynamic_object.hpp"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\..\include\chaiscript\dispatchkit\function_call.hpp"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\..\include\chaiscript\dispatchkit\function_call_detail.hpp"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\..\include\chaiscript\dispatchkit\handle_return.hpp"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\..\include\chaiscript\dispatchkit\operators.hpp"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\..\include\chaiscript\dispatchkit\proxy_constructors.hpp"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\..\include\chaiscript\dispatchkit\proxy_functions.hpp"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\..\include\chaiscript\dispatchkit\proxy_functions_detail.hpp"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\..\include\chaiscript\dispatchkit\register_function.hpp"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\..\include\chaiscript\dispatchkit\type_info.hpp"
|
||||
>
|
||||
</File>
|
||||
</Filter>
|
||||
<Filter
|
||||
Name="Resource Files"
|
||||
Filter="rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav"
|
||||
UniqueIdentifier="{67DA6AB6-F800-4c08-8B7A-83BB121AAD01}"
|
||||
>
|
||||
</Filter>
|
||||
</Files>
|
||||
<Globals>
|
||||
</Globals>
|
||||
</VisualStudioProject>
|
@@ -1,198 +0,0 @@
|
||||
<?xml version="1.0" encoding="Windows-1252"?>
|
||||
<VisualStudioProject
|
||||
ProjectType="Visual C++"
|
||||
Version="9.00"
|
||||
Name="test_module"
|
||||
ProjectGUID="{775EDCC2-102F-4E75-A860-9AF398D04145}"
|
||||
RootNamespace="test_module"
|
||||
Keyword="Win32Proj"
|
||||
TargetFrameworkVersion="196613"
|
||||
>
|
||||
<Platforms>
|
||||
<Platform
|
||||
Name="Win32"
|
||||
/>
|
||||
</Platforms>
|
||||
<ToolFiles>
|
||||
</ToolFiles>
|
||||
<Configurations>
|
||||
<Configuration
|
||||
Name="Debug|Win32"
|
||||
OutputDirectory="$(SolutionDir)$(ConfigurationName)"
|
||||
IntermediateDirectory="$(ConfigurationName)"
|
||||
ConfigurationType="2"
|
||||
InheritedPropertySheets="..\chaiscript\Boost.vsprops"
|
||||
UseOfMFC="0"
|
||||
CharacterSet="0"
|
||||
>
|
||||
<Tool
|
||||
Name="VCPreBuildEventTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCCustomBuildTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCXMLDataGeneratorTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCWebServiceProxyGeneratorTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCMIDLTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCCLCompilerTool"
|
||||
Optimization="0"
|
||||
AdditionalIncludeDirectories=""$(ProjectDir)\..\..\include""
|
||||
PreprocessorDefinitions="WIN32;_DEBUG;_WINDOWS;_USRDLL;TEST_MODULE_EXPORTS"
|
||||
MinimalRebuild="true"
|
||||
BasicRuntimeChecks="3"
|
||||
RuntimeLibrary="3"
|
||||
UsePrecompiledHeader="0"
|
||||
WarningLevel="3"
|
||||
DebugInformationFormat="4"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCManagedResourceCompilerTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCResourceCompilerTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCPreLinkEventTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCLinkerTool"
|
||||
LinkIncremental="2"
|
||||
GenerateDebugInformation="true"
|
||||
SubSystem="2"
|
||||
TargetMachine="1"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCALinkTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCManifestTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCXDCMakeTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCBscMakeTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCFxCopTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCAppVerifierTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCPostBuildEventTool"
|
||||
/>
|
||||
</Configuration>
|
||||
<Configuration
|
||||
Name="Release|Win32"
|
||||
OutputDirectory="$(SolutionDir)$(ConfigurationName)"
|
||||
IntermediateDirectory="$(ConfigurationName)"
|
||||
ConfigurationType="2"
|
||||
InheritedPropertySheets="..\chaiscript\Boost.vsprops"
|
||||
CharacterSet="1"
|
||||
WholeProgramOptimization="1"
|
||||
>
|
||||
<Tool
|
||||
Name="VCPreBuildEventTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCCustomBuildTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCXMLDataGeneratorTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCWebServiceProxyGeneratorTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCMIDLTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCCLCompilerTool"
|
||||
Optimization="2"
|
||||
EnableIntrinsicFunctions="true"
|
||||
AdditionalIncludeDirectories=""$(ProjectDir)\..\..\include""
|
||||
PreprocessorDefinitions="WIN32;NDEBUG;_WINDOWS;_USRDLL;TEST_MODULE_EXPORTS"
|
||||
RuntimeLibrary="2"
|
||||
EnableFunctionLevelLinking="true"
|
||||
UsePrecompiledHeader="0"
|
||||
WarningLevel="3"
|
||||
DebugInformationFormat="3"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCManagedResourceCompilerTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCResourceCompilerTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCPreLinkEventTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCLinkerTool"
|
||||
LinkIncremental="1"
|
||||
GenerateDebugInformation="true"
|
||||
SubSystem="2"
|
||||
OptimizeReferences="2"
|
||||
EnableCOMDATFolding="2"
|
||||
TargetMachine="1"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCALinkTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCManifestTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCXDCMakeTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCBscMakeTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCFxCopTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCAppVerifierTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCPostBuildEventTool"
|
||||
/>
|
||||
</Configuration>
|
||||
</Configurations>
|
||||
<References>
|
||||
</References>
|
||||
<Files>
|
||||
<Filter
|
||||
Name="Source Files"
|
||||
Filter="cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx"
|
||||
UniqueIdentifier="{4FC737F1-C7A5-4376-A066-2A32D752A2FF}"
|
||||
>
|
||||
<File
|
||||
RelativePath="..\..\src\test_module.cpp"
|
||||
>
|
||||
</File>
|
||||
</Filter>
|
||||
<Filter
|
||||
Name="Header Files"
|
||||
Filter="h;hpp;hxx;hm;inl;inc;xsd"
|
||||
UniqueIdentifier="{93995380-89BD-4b04-88EB-625FBE52EBFB}"
|
||||
>
|
||||
</Filter>
|
||||
<Filter
|
||||
Name="Resource Files"
|
||||
Filter="rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav"
|
||||
UniqueIdentifier="{67DA6AB6-F800-4c08-8B7A-83BB121AAD01}"
|
||||
>
|
||||
</Filter>
|
||||
</Files>
|
||||
<Globals>
|
||||
</Globals>
|
||||
</VisualStudioProject>
|
33
readme.txt
33
readme.txt
@@ -1,11 +1,11 @@
|
||||
ChaiScript v1.0
|
||||
ChaiScript v2.3.3
|
||||
http://www.chaiscript.com
|
||||
(c) 2009 Jason Turner and Jonathan Turner
|
||||
(c) 2009-2010 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 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.
|
||||
@@ -19,13 +19,13 @@ ChaiScript requires a recent version of Boost (http://www.boost.org) to build.
|
||||
|
||||
* 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(&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(&function, "function");
|
||||
|
||||
double d = chai.eval<double>("function(3, 4.75);");
|
||||
}
|
||||
|
26
releasenotes.txt
Normal file
26
releasenotes.txt
Normal file
@@ -0,0 +1,26 @@
|
||||
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,26 +0,0 @@
|
||||
#!/bin/bash
|
||||
|
||||
|
||||
successes=0
|
||||
failures=0
|
||||
|
||||
echo -n "Running unit tests"
|
||||
for file in unittests/*.chai
|
||||
do
|
||||
tstname=${file%.*}
|
||||
tst="$tstname.txt"
|
||||
LD_LIBRARY_PATH=. ./chaiscript_eval $file > /tmp/tstout.txt
|
||||
diff $tst /tmp/tstout.txt
|
||||
if [ "$?" -eq "0" ]
|
||||
then
|
||||
echo -n "."
|
||||
successes=$((successes+1))
|
||||
else
|
||||
echo "[from failed test $file]"
|
||||
failures=$((failures+1))
|
||||
fi
|
||||
done
|
||||
echo ""
|
||||
|
||||
total=$((successes+failures))
|
||||
echo "$successes out of $total succeeded"
|
@@ -1,27 +0,0 @@
|
||||
#!/bin/bash
|
||||
|
||||
successes=0
|
||||
failures=0
|
||||
|
||||
echo -n "Running unit tests"
|
||||
for file in unittests/*.chai
|
||||
do
|
||||
tstname=${file%.*}
|
||||
tst="$tstname.txt"
|
||||
./chaiscript_eval $file > /tmp/tstout.txt
|
||||
cat $tst > /tmp/tstmaster.txt
|
||||
awk 'sub("$", "\r")' $tst > /tmp/tstmaster.txt
|
||||
diff /tmp/tstmaster.txt /tmp/tstout.txt
|
||||
if [ "$?" -eq "0" ]
|
||||
then
|
||||
echo -n "."
|
||||
successes=$((successes+1))
|
||||
else
|
||||
echo "[from failed test $file]"
|
||||
failures=$((failures+1))
|
||||
fi
|
||||
done
|
||||
echo ""
|
||||
|
||||
total=$((successes+failures))
|
||||
echo "$successes out of $total succeeded"
|
@@ -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,7 +1,7 @@
|
||||
// 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)
|
||||
// Copyright 2009-2010, Jonathan Turner (jonathan@emptycrate.com)
|
||||
// and Jason Turner (jason@emptycrate.com)
|
||||
// http://www.chaiscript.com
|
||||
|
||||
#include <iostream>
|
||||
@@ -27,12 +27,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;
|
||||
}
|
||||
@@ -45,7 +45,7 @@ struct System
|
||||
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);
|
||||
}
|
||||
|
||||
|
||||
@@ -66,7 +66,7 @@ void take_shared_ptr(const boost::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;
|
||||
@@ -115,7 +115,7 @@ int main(int argc, char *argv[]) {
|
||||
//Call bound version of do_callbacks
|
||||
chai("do_callbacks()");
|
||||
|
||||
boost::function<void ()> caller = chai.functor<void ()>("fun() { system.do_callbacks(\"From Functor\"); }");
|
||||
boost::function<void ()> caller = chai.eval<boost::function<void ()> >("fun() { system.do_callbacks(\"From Functor\"); }");
|
||||
caller();
|
||||
|
||||
|
||||
@@ -139,12 +139,12 @@ 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<boost::function<int (int, int)> >("fun (x, y) { return x + y; }")(5, 6);
|
||||
|
||||
log("Functor test output", boost::lexical_cast<std::string>(x));
|
||||
|
||||
chai.add(var(boost::shared_ptr<int>()), "nullvar");
|
||||
chai("print(\"This should be true.\"); print(nullvar.is_null())");
|
||||
chai("print(\"This should be true.\"); print(nullvar.is_var_null())");
|
||||
|
||||
// test the global const action
|
||||
chai.add_global_const(const_var(1), "constvar");
|
||||
@@ -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,13 +163,13 @@ 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(boost::function<Boxed_Value (dispatch::Dynamic_Object &)>(boost::bind(&dispatch::detail::Dynamic_Object_Attribute::func, "TestType", "attr", _1))), "attr");
|
||||
|
||||
chai.eval("var x = TestType()");
|
||||
chai.eval("x.attr = \"hi\"");
|
||||
chai.eval("print(x.attr)");
|
||||
// chai.eval("x.attr = \"hi\"");
|
||||
// chai.eval("print(x.attr)");
|
||||
chai.eval("x.hello_world()");
|
||||
}
|
||||
|
88
samples/memory_leak_test.cpp
Normal file
88
samples/memory_leak_test.cpp
Normal file
@@ -0,0 +1,88 @@
|
||||
#include <iostream>
|
||||
|
||||
#include "chaiscript/chaiscript.hpp"
|
||||
#ifdef READLINE_AVAILABLE
|
||||
#include <readline/readline.h>
|
||||
#include <readline/history.h>
|
||||
#endif
|
||||
|
||||
|
||||
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)
|
||||
{
|
||||
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"]; } )
|
||||
|
242
src/main.cpp
242
src/main.cpp
@@ -1,93 +1,243 @@
|
||||
// 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)
|
||||
// Copyright 2009-2010, Jonathan Turner (jonathan@emptycrate.com)
|
||||
// and Jason Turner (jason@emptycrate.com)
|
||||
// http://www.chaiscript.com
|
||||
|
||||
#include <iostream>
|
||||
|
||||
#include <list>
|
||||
#include <boost/algorithm/string/trim.hpp>
|
||||
|
||||
#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 BOOST_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 boost::function<void ()> &f)
|
||||
{
|
||||
try {
|
||||
f();
|
||||
} catch (...) {
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
chaiscript::exception::eval_error get_eval_error(const boost::function<void ()> &f)
|
||||
{
|
||||
try {
|
||||
f();
|
||||
} catch (const chaiscript::exception::eval_error &e) {
|
||||
return e;
|
||||
}
|
||||
|
||||
throw std::runtime_error("no exception throw");
|
||||
}
|
||||
|
||||
std::string get_next_command() {
|
||||
#ifdef READLINE_AVAILABLE
|
||||
char *input_raw;
|
||||
input_raw = readline("eval> ");
|
||||
std::string retval("quit");
|
||||
if ( ! std::cin.eof() ) {
|
||||
char *input_raw = readline("eval> ");
|
||||
if ( input_raw ) {
|
||||
add_history(input_raw);
|
||||
return std::string(input_raw);
|
||||
#else
|
||||
std::string retval;
|
||||
std::cout << "eval> ";
|
||||
std::getline(std::cin, retval);
|
||||
retval = boost::trim_copy_if(std::string(input_raw),boost::is_any_of(" \t"));
|
||||
::free(input_raw);
|
||||
}
|
||||
}
|
||||
if( retval == "quit"
|
||||
|| retval == "exit"
|
||||
|| retval == "help"
|
||||
|| retval == "version")
|
||||
{
|
||||
retval += "(0)";
|
||||
}
|
||||
return retval;
|
||||
#endif
|
||||
}
|
||||
|
||||
int main(int argc, char *argv[]) {
|
||||
std::string input;
|
||||
chaiscript::ChaiScript chai;
|
||||
// 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);
|
||||
}
|
||||
|
||||
|
||||
if (argc < 2) {
|
||||
//std::cout << "eval> ";
|
||||
//std::getline(std::cin, input);
|
||||
#ifdef READLINE_AVAILABLE
|
||||
void interactive(chaiscript::ChaiScript& chai)
|
||||
{
|
||||
using_history();
|
||||
#endif
|
||||
input = get_next_command();
|
||||
while (input != "quit") {
|
||||
|
||||
chaiscript::Boxed_Value val;
|
||||
|
||||
if (input == "help") {
|
||||
print_help();
|
||||
}
|
||||
else {
|
||||
for (;;) {
|
||||
std::string input = get_next_command();
|
||||
try {
|
||||
//First, we evaluate it
|
||||
val = chai.eval(input);
|
||||
// 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 {
|
||||
chaiscript::dispatch(chai.get_eval_engine().get_function("print"), chaiscript::Param_List_Builder() << val);
|
||||
std::cout << chai.eval<boost::function<std::string (const chaiscript::Boxed_Value &bv)> >("to_string")(val) << std::endl;
|
||||
}
|
||||
catch (...) {
|
||||
//If we can't, do nothing
|
||||
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;
|
||||
}
|
||||
catch (std::exception &e) {
|
||||
std::cout << e.what() << std::endl;
|
||||
}
|
||||
}
|
||||
|
||||
input = get_next_command();
|
||||
int main(int argc, char *argv[])
|
||||
{
|
||||
std::vector<std::string> usepaths;
|
||||
std::vector<std::string> modulepaths;
|
||||
|
||||
// Disable deprecation warning for getenv call.
|
||||
#ifdef BOOST_MSVC
|
||||
#pragma warning(push)
|
||||
#pragma warning(disable : 4996)
|
||||
#endif
|
||||
|
||||
const char *usepath = getenv("CHAI_USE_PATH");
|
||||
const char *modulepath = getenv("CHAI_MODULE_PATH");
|
||||
|
||||
#ifdef BOOST_MSVC
|
||||
#pragma warning(pop)
|
||||
#endif
|
||||
|
||||
usepaths.push_back("");
|
||||
if (usepath)
|
||||
{
|
||||
usepaths.push_back(usepath);
|
||||
}
|
||||
|
||||
modulepaths.push_back("");
|
||||
if (modulepath)
|
||||
{
|
||||
modulepaths.push_back(modulepath);
|
||||
}
|
||||
else {
|
||||
for (int i = 1; i < argc; ++i) {
|
||||
std::string filename(argv[i]);
|
||||
|
||||
chaiscript::ChaiScript chai(modulepaths,usepaths);
|
||||
|
||||
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");
|
||||
|
||||
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 ;
|
||||
try {
|
||||
chaiscript::Boxed_Value val = chai.eval_file(argv[i]);
|
||||
switch ( mode ) {
|
||||
case eInteractive : interactive(chai); break;
|
||||
case eCommand : val = chai.eval(arg); break;
|
||||
case eFile : val = chai.eval_file(arg); break;
|
||||
}
|
||||
}
|
||||
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 << ")";
|
||||
}
|
||||
}
|
||||
}
|
||||
std::cout << std::endl;
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
catch (std::exception &e) {
|
||||
std::cout << e.what() << std::endl;
|
||||
}
|
||||
}
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
}
|
||||
|
||||
return EXIT_SUCCESS;
|
||||
}
|
||||
|
@@ -1,7 +1,7 @@
|
||||
// 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)
|
||||
// Copyright 2009-2010, Jonathan Turner (jonathan@emptycrate.com)
|
||||
// and Jason Turner (jason@emptycrate.com)
|
||||
// http://www.chaiscript.com
|
||||
|
||||
#include <iostream>
|
||||
@@ -14,6 +14,8 @@
|
||||
void do_work(chaiscript::ChaiScript &c)
|
||||
{
|
||||
// c("use(\"work.chai\"); do_chai_work(num_iterations);");
|
||||
std::string name = "MyVar" + boost::lexical_cast<std::string>(rand());
|
||||
c.add(chaiscript::var(5), name);
|
||||
c("use(\"work.chai\"); do_chai_work(10000);");
|
||||
}
|
||||
|
||||
|
97
src/reflection.cpp
Normal file
97
src/reflection.cpp
Normal file
@@ -0,0 +1,97 @@
|
||||
|
||||
#include <chaiscript/chaiscript.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 BOOST_MSVC
|
||||
#pragma warning(push)
|
||||
#pragma warning(disable : 4190)
|
||||
#endif
|
||||
|
||||
|
||||
bool has_parse_tree(const chaiscript::Const_Proxy_Function &t_pf)
|
||||
{
|
||||
boost::shared_ptr<const chaiscript::dispatch::Dynamic_Proxy_Function> pf
|
||||
= boost::dynamic_pointer_cast<const chaiscript::dispatch::Dynamic_Proxy_Function>(t_pf);
|
||||
if (pf)
|
||||
{
|
||||
return pf->get_parse_tree();
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
chaiscript::AST_NodePtr get_parse_tree(const chaiscript::Const_Proxy_Function &t_pf)
|
||||
{
|
||||
boost::shared_ptr<const chaiscript::dispatch::Dynamic_Proxy_Function> pf
|
||||
= boost::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");
|
||||
|
||||
|
||||
chaiscript::bootstrap::standard_library::vector_type<std::vector<boost::shared_ptr<chaiscript::AST_Node> > >("AST_NodeVector", m);
|
||||
|
||||
CHAISCRIPT_CLASS( m,
|
||||
chaiscript::exception::eval_error,
|
||||
,
|
||||
((reason))
|
||||
((call_stack))
|
||||
);
|
||||
|
||||
CHAISCRIPT_CLASS( m,
|
||||
chaiscript::File_Position,
|
||||
(chaiscript::File_Position())
|
||||
(chaiscript::File_Position(int,int)),
|
||||
((line))
|
||||
((column))
|
||||
);
|
||||
|
||||
CHAISCRIPT_CLASS( m,
|
||||
chaiscript::AST_Node,
|
||||
,
|
||||
((text))
|
||||
((identifier))
|
||||
((filename))
|
||||
((start))
|
||||
((end))
|
||||
((internal_to_string))
|
||||
((children))
|
||||
((replace_child))
|
||||
);
|
||||
|
||||
CHAISCRIPT_CLASS( m,
|
||||
chaiscript::parser::ChaiScript_Parser,
|
||||
(chaiscript::parser::ChaiScript_Parser ()),
|
||||
((parse))
|
||||
((ast))
|
||||
);
|
||||
|
||||
|
||||
return m;
|
||||
}
|
||||
|
||||
|
||||
#ifdef BOOST_MSVC
|
||||
#pragma warning(pop)
|
||||
#endif
|
@@ -1,9 +1,21 @@
|
||||
|
||||
#include <chaiscript/chaiscript.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 BOOST_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 BOOST_MSVC
|
||||
#pragma warning(pop)
|
||||
#endif
|
||||
|
@@ -2,15 +2,60 @@
|
||||
#include <chaiscript/chaiscript.hpp>
|
||||
#include <string>
|
||||
|
||||
class TestBaseType
|
||||
{
|
||||
public:
|
||||
TestBaseType() {}
|
||||
TestBaseType(int) {}
|
||||
virtual ~TestBaseType() {}
|
||||
virtual int func() { return 0; }
|
||||
|
||||
};
|
||||
|
||||
class TestDerivedType : public TestBaseType
|
||||
{
|
||||
public:
|
||||
virtual ~TestDerivedType() {}
|
||||
virtual int func() { return 1; }
|
||||
};
|
||||
|
||||
std::string hello_world()
|
||||
{
|
||||
return "Hello World";
|
||||
}
|
||||
|
||||
CHAISCRIPT_MODULE_EXPORT chaiscript::ModulePtr create_chaiscript_module_test()
|
||||
// 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 BOOST_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<TestDerivedType ()>(), "TestDerivedType");
|
||||
m->add(chaiscript::constructor<TestDerivedType (const TestDerivedType &)>(), "TestDerivedType");
|
||||
|
||||
m->add(chaiscript::base_class<TestBaseType, TestDerivedType>());
|
||||
|
||||
m->add(chaiscript::fun(&TestBaseType::func), "func");
|
||||
|
||||
return m;
|
||||
}
|
||||
|
||||
|
||||
#ifdef BOOST_MSVC
|
||||
#pragma warning(pop)
|
||||
#endif
|
||||
|
2
unittests/assign_const.chai
Normal file
2
unittests/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 } );
|
@@ -1,2 +1,2 @@
|
||||
var prod = bind(foldl, _, `*`, 1.0)
|
||||
print(prod([3, 4, 5]))
|
||||
assert_equal(60, prod([3, 4, 5]))
|
||||
|
@@ -1 +0,0 @@
|
||||
60
|
34
unittests/bind2.chai
Normal file
34
unittests/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 +0,0 @@
|
||||
hello
|
@@ -1 +1 @@
|
||||
print(!true)
|
||||
assert_equal(false, !true)
|
||||
|
@@ -1 +0,0 @@
|
||||
false
|
317
unittests/boxed_cast_test.cpp
Normal file
317
unittests/boxed_cast_test.cpp
Normal file
@@ -0,0 +1,317 @@
|
||||
#include <chaiscript/utility/utility.hpp>
|
||||
|
||||
|
||||
using namespace chaiscript;
|
||||
|
||||
|
||||
template<typename T>
|
||||
void use(T){}
|
||||
|
||||
template<typename To>
|
||||
bool run_test_type_conversion(const Boxed_Value &bv, bool expectedpass)
|
||||
{
|
||||
try {
|
||||
To ret = chaiscript::boxed_cast<To>(bv);
|
||||
use(ret);
|
||||
} catch (const chaiscript::exception::bad_boxed_cast &/*e*/) {
|
||||
if (expectedpass) {
|
||||
// std::cerr << "Failure in run_test_type_conversion: " << e.what() << std::endl;
|
||||
return false;
|
||||
} else {
|
||||
return true;
|
||||
}
|
||||
} catch (const std::exception &e) {
|
||||
std::cerr << "Unexpected standard exception when attempting cast_conversion: " << e.what() << std::endl;
|
||||
return false;
|
||||
} catch (...) {
|
||||
std::cerr << "Unexpected unknown exception when attempting cast_conversion." << std::endl;
|
||||
return false;
|
||||
}
|
||||
|
||||
if (expectedpass)
|
||||
{
|
||||
return true;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
template<typename To>
|
||||
bool test_type_conversion(const Boxed_Value &bv, bool expectedpass)
|
||||
{
|
||||
bool ret = run_test_type_conversion<To>(bv, expectedpass);
|
||||
|
||||
if (!ret)
|
||||
{
|
||||
std::cerr << "Error with type conversion test. From: "
|
||||
<< (bv.is_const()?(std::string("const ")):(std::string())) << bv.get_type_info().name()
|
||||
<< " To: "
|
||||
<< (boost::is_const<To>::value?(std::string("const ")):(std::string())) << typeid(To).name()
|
||||
<< " test was expected to " << ((expectedpass)?(std::string("succeed")):(std::string("fail"))) << " but did not" << std::endl;
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
template<typename Type>
|
||||
bool do_test(const Boxed_Value &bv, bool T, bool ConstT, bool TRef, bool ConstTRef, bool TPtr, bool ConstTPtr, bool TPtrConst,
|
||||
bool ConstTPtrConst, bool SharedPtrT, bool SharedConstPtrT,
|
||||
bool ConstSharedPtrT, bool ConstSharedConstPtrT, bool ConstSharedPtrTRef, bool ConstSharedPtrTConstRef,
|
||||
bool BoostRef, bool BoostConstRef, bool ConstBoostRef, bool ConstBoostConstRef,
|
||||
bool ConstBoostRefRef, bool ConstBoostConstRefRef, bool PODValue,
|
||||
bool ConstPODValue, bool ConstPODValueRef, bool TPtrConstRef, bool ConstTPtrConstRef)
|
||||
{
|
||||
bool passed = true;
|
||||
passed &= test_type_conversion<Type>(bv, T);
|
||||
passed &= test_type_conversion<const Type>(bv, ConstT);
|
||||
passed &= test_type_conversion<Type &>(bv, TRef);
|
||||
passed &= test_type_conversion<const Type &>(bv, ConstTRef);
|
||||
passed &= test_type_conversion<Type *>(bv, TPtr);
|
||||
passed &= test_type_conversion<const Type *>(bv, ConstTPtr);
|
||||
passed &= test_type_conversion<Type * const>(bv, TPtrConst);
|
||||
passed &= test_type_conversion<const Type * const>(bv, ConstTPtrConst);
|
||||
passed &= test_type_conversion<boost::shared_ptr<Type> >(bv, SharedPtrT);
|
||||
passed &= test_type_conversion<boost::shared_ptr<const Type> >(bv, SharedConstPtrT);
|
||||
passed &= test_type_conversion<boost::shared_ptr<Type> &>(bv, false);
|
||||
passed &= test_type_conversion<boost::shared_ptr<const Type> &>(bv, false);
|
||||
passed &= test_type_conversion<const boost::shared_ptr<Type> >(bv, ConstSharedPtrT);
|
||||
passed &= test_type_conversion<const boost::shared_ptr<const Type> >(bv, ConstSharedConstPtrT);
|
||||
passed &= test_type_conversion<const boost::shared_ptr<Type> &>(bv, ConstSharedPtrTRef);
|
||||
passed &= test_type_conversion<const boost::shared_ptr<const Type> &>(bv, ConstSharedPtrTConstRef);
|
||||
passed &= test_type_conversion<boost::reference_wrapper<Type> >(bv, BoostRef);
|
||||
passed &= test_type_conversion<boost::reference_wrapper<const Type> >(bv, BoostConstRef);
|
||||
passed &= test_type_conversion<boost::reference_wrapper<Type> &>(bv, false);
|
||||
passed &= test_type_conversion<boost::reference_wrapper<const Type> &>(bv, false);
|
||||
passed &= test_type_conversion<const boost::reference_wrapper<Type> >(bv, ConstBoostRef);
|
||||
passed &= test_type_conversion<const boost::reference_wrapper<const Type> >(bv, ConstBoostConstRef);
|
||||
passed &= test_type_conversion<const boost::reference_wrapper<Type> &>(bv, ConstBoostRefRef);
|
||||
passed &= test_type_conversion<const boost::reference_wrapper<const Type> &>(bv, ConstBoostConstRefRef);
|
||||
passed &= test_type_conversion<Boxed_POD_Value>(bv, PODValue);
|
||||
passed &= test_type_conversion<const Boxed_POD_Value>(bv, ConstPODValue);
|
||||
passed &= test_type_conversion<Boxed_POD_Value &>(bv, false);
|
||||
passed &= test_type_conversion<const Boxed_POD_Value &>(bv, ConstPODValueRef);
|
||||
passed &= test_type_conversion<Boxed_POD_Value *>(bv, false);
|
||||
passed &= test_type_conversion<const Boxed_POD_Value *>(bv, false);
|
||||
passed &= test_type_conversion<Boxed_POD_Value * const>(bv, false);
|
||||
passed &= test_type_conversion<const Boxed_POD_Value *const>(bv, false);
|
||||
passed &= test_type_conversion<Type *&>(bv, false);
|
||||
passed &= test_type_conversion<const Type *&>(bv, false);
|
||||
passed &= test_type_conversion<Type * const&>(bv, TPtrConstRef);
|
||||
passed &= test_type_conversion<const Type * const&>(bv, ConstTPtrConstRef);
|
||||
passed &= test_type_conversion<Boxed_Value>(bv, true);
|
||||
passed &= test_type_conversion<const Boxed_Value>(bv, true);
|
||||
passed &= test_type_conversion<const Boxed_Value &>(bv, true);
|
||||
|
||||
return passed;
|
||||
}
|
||||
|
||||
/** Tests intended for built int types **/
|
||||
template<typename T>
|
||||
bool built_in_type_test(const T &initial, bool ispod)
|
||||
{
|
||||
bool passed = true;
|
||||
|
||||
/** value tests **/
|
||||
T i = T(initial);
|
||||
passed &= do_test<T>(var(i), true, true, true, true, true,
|
||||
true, true, true, true, true,
|
||||
true, true, true, true, true,
|
||||
true, true, true, true, true,
|
||||
ispod && true, ispod && true, ispod && true, true, true);
|
||||
|
||||
passed &= do_test<T>(const_var(i), true, true, false, true, false,
|
||||
true, false, true, false, true,
|
||||
false, true, false, true, false,
|
||||
true, false, true, false, true,
|
||||
ispod && true, ispod && true, ispod && true, false, true);
|
||||
|
||||
passed &= do_test<T>(var(&i), true, true, true, true, true,
|
||||
true, true, true, false, false,
|
||||
false, false, false, false, true,
|
||||
true, true, true, true, true,
|
||||
ispod && true, ispod && true, ispod && true, true, true);
|
||||
|
||||
passed &= do_test<T>(const_var(&i), true, true, false, true, false,
|
||||
true, false, true, false, false,
|
||||
false, false, false, false, false,
|
||||
true, false, true, false, true,
|
||||
ispod && true, ispod && true, ispod && true, ispod && false, true);
|
||||
|
||||
passed &= do_test<T>(var(boost::ref(i)), true, true, true, true, true,
|
||||
true, true, true, false, false,
|
||||
false, false, false, false, true,
|
||||
true, true, true, true, true,
|
||||
ispod && true, ispod && true, ispod && true, true, true);
|
||||
|
||||
passed &= do_test<T>(var(boost::cref(i)), true, true, false, true, false,
|
||||
true, false, true, false, false,
|
||||
false, false, false, false, false,
|
||||
true, false, true, false, true,
|
||||
ispod && true, ispod && true, ispod && true, false, true);
|
||||
|
||||
/** Const Reference Variable tests */
|
||||
|
||||
// This reference will be copied on input, which is expected
|
||||
const T &ir = i;
|
||||
|
||||
passed &= do_test<T>(var(i), true, true, true, true, true,
|
||||
true, true, true, true, true,
|
||||
true, true, true, true, true,
|
||||
true, true, true, true, true,
|
||||
ispod && true, ispod && true, ispod && true, true, true);
|
||||
|
||||
// But a pointer or reference to it should be necessarily const
|
||||
passed &= do_test<T>(var(&ir), true, true, false, true, false,
|
||||
true, false, true, false, false,
|
||||
false, false, false, false, false,
|
||||
true, false, true, false, true,
|
||||
ispod && true, ispod && true, ispod && true, false, true);
|
||||
|
||||
passed &= do_test<T>(var(boost::ref(ir)), true, true, false, true, false,
|
||||
true, false, true, false, false,
|
||||
false, false, false, false, false,
|
||||
true, false, true, false, true,
|
||||
ispod && true, ispod && true, ispod && true, false, true);
|
||||
|
||||
// Make sure const of const works too
|
||||
passed &= do_test<T>(const_var(&ir), true, true, false, true, false,
|
||||
true, false, true, false, false,
|
||||
false, false, false, false, false,
|
||||
true, false, true, false, true,
|
||||
ispod && true, ispod && true, ispod && true, false, true);
|
||||
|
||||
passed &= do_test<T>(const_var(boost::ref(ir)), true, true, false, true, false,
|
||||
true, false, true, false, false,
|
||||
false, false, false, false, false,
|
||||
true, false, true, false, true,
|
||||
ispod && true, ispod && true, ispod && true, false, true);
|
||||
|
||||
/** Const Reference Variable tests */
|
||||
|
||||
// This will always be seen as a const
|
||||
const T*cip = &i;
|
||||
passed &= do_test<T>(var(cip), true, true, false, true, false,
|
||||
true, false, true, false, false,
|
||||
false, false, false, false, false,
|
||||
true, false, true, false, true,
|
||||
ispod && true, ispod && true, ispod && true, false, true);
|
||||
|
||||
// make sure const of const works
|
||||
passed &= do_test<T>(const_var(cip), true, true, false, true, false,
|
||||
true, false, true, false, false,
|
||||
false, false, false, false, false,
|
||||
true, false, true, false, true,
|
||||
ispod && true, ispod && true, ispod && true, false, true);
|
||||
|
||||
/** shared_ptr tests **/
|
||||
|
||||
boost::shared_ptr<T> ip(new T(initial));
|
||||
|
||||
passed &= do_test<T>(var(ip), true, true, true, true, true,
|
||||
true, true, true, true, true,
|
||||
true, true, true, true, true,
|
||||
true, true, true, true, true,
|
||||
ispod && true, ispod && true, ispod && true, true, true);
|
||||
|
||||
passed &= do_test<T>(const_var(ip), true, true, false, true, false,
|
||||
true, false, true, false, true,
|
||||
false, true, false, true, false,
|
||||
true, false, true, false, true,
|
||||
ispod && true, ispod && true, ispod && true, false, true);
|
||||
|
||||
/** const shared_ptr tests **/
|
||||
boost::shared_ptr<const T> ipc(new T(initial));
|
||||
|
||||
passed &= do_test<T>(var(ipc), true, true, false, true, false,
|
||||
true, false, true, false, true,
|
||||
false, true, false, true, false,
|
||||
true, false, true, false, true,
|
||||
ispod && true, ispod && true, ispod && true, false, true);
|
||||
|
||||
// const of this should be the same, making sure it compiles
|
||||
passed &= do_test<T>(const_var(ipc), true, true, false, true, false,
|
||||
true, false, true, false, true,
|
||||
false, true, false, true, false,
|
||||
true, false, true, false, true,
|
||||
ispod && true, ispod && true, ispod && true, false, true);
|
||||
|
||||
|
||||
/** Double ptr tests **/
|
||||
|
||||
/*
|
||||
T **doublep;
|
||||
|
||||
passed &= do_test<T*>(var(doublep), true, true, false, true, false,
|
||||
true, false, true, false, true,
|
||||
false, true, false, true, false,
|
||||
true, false, true, false, true,
|
||||
ispod && true, ispod && true, ispod && true, false, true);
|
||||
*/
|
||||
|
||||
return passed;
|
||||
}
|
||||
|
||||
|
||||
template<typename T>
|
||||
bool pointer_test(const T& default_value, const T& new_value)
|
||||
{
|
||||
T *p = new T(default_value);
|
||||
|
||||
// we store a pointer to a pointer, so we can get a pointer to a pointer
|
||||
try {
|
||||
T **result = boxed_cast<T **>(var(&p));
|
||||
*(*result) = new_value;
|
||||
|
||||
|
||||
if (p != (*result) ) {
|
||||
std::cerr << "Pointer passed in different than one returned" << std::endl;
|
||||
return false;
|
||||
}
|
||||
|
||||
if (*p != *(*result) ) {
|
||||
std::cerr << "Somehow dereferenced pointer values are not the same?" << std::endl;
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
} catch (const exception::bad_boxed_cast &) {
|
||||
std::cerr << "Bad boxed cast performing ** to ** test" << std::endl;
|
||||
return false;
|
||||
} catch (...) {
|
||||
std::cerr << "Unknown exception performing ** to ** test" << std::endl;
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
|
||||
int main()
|
||||
{
|
||||
bool passed = true;
|
||||
|
||||
/*
|
||||
bool T, bool ConstT, bool TRef, bool ConstTRef, bool TPtr,
|
||||
bool ConstTPtr, bool TPtrConst, bool ConstTPtrConst, bool SharedPtrT, bool SharedConstPtrT,
|
||||
bool ConstSharedPtrT, bool ConstSharedConstPtrT, bool ConstSharedPtrTRef, bool ConstSharedPtrTConstRef, bool BoostRef,
|
||||
bool BoostConstRef, bool ConstBoostRef, bool ConstBoostConstRef, bool ConstBoostRefRef, bool ConstBoostConstRefRef,
|
||||
bool PODValue, bool ConstPODValue, bool ConstPODValueRef
|
||||
*/
|
||||
|
||||
passed &= built_in_type_test<int>(5, true);
|
||||
passed &= built_in_type_test<double>(1.1, true);
|
||||
passed &= built_in_type_test<char>('a', true);
|
||||
passed &= built_in_type_test<bool>(false, true);
|
||||
passed &= built_in_type_test<std::string>("Hello World", false);
|
||||
|
||||
// storing a pointer
|
||||
passed &= pointer_test<int>(1, 0);
|
||||
|
||||
if (passed)
|
||||
{
|
||||
return EXIT_SUCCESS;
|
||||
} else {
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
|
||||
}
|
@@ -4,4 +4,4 @@ while (i < 10) {
|
||||
break
|
||||
}
|
||||
}
|
||||
print(i)
|
||||
assert_equal(5, i);
|
||||
|
@@ -1 +0,0 @@
|
||||
5
|
@@ -1 +1 @@
|
||||
print('b')
|
||||
assert_equal("b", to_string('b'))
|
||||
|
@@ -1 +0,0 @@
|
||||
b
|
@@ -1,7 +1,7 @@
|
||||
print(1.is_var_const());
|
||||
print(1.is_var_reference());
|
||||
print(1.is_var_pointer());
|
||||
print(1.is_var_null());
|
||||
print(1.is_var_undef());
|
||||
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;
|
||||
print(i.is_var_undef());
|
||||
assert_equal(true, i.is_var_undef());
|
||||
|
@@ -1,6 +0,0 @@
|
||||
true
|
||||
false
|
||||
true
|
||||
false
|
||||
false
|
||||
true
|
@@ -1 +1,3 @@
|
||||
print(collate(1, 2))
|
||||
var v = collate(1, 2)
|
||||
assert_equal(1, v[0])
|
||||
assert_equal(2, v[1])
|
||||
|
@@ -1 +0,0 @@
|
||||
[1, 2]
|
@@ -1 +1 @@
|
||||
print(1 > 2)
|
||||
assert_equal(false, 1 > 2);
|
||||
|
@@ -1 +0,0 @@
|
||||
false
|
@@ -1 +1 @@
|
||||
print(1 < 2)
|
||||
assert_equal(true, 1 < 2)
|
||||
|
@@ -1 +0,0 @@
|
||||
true
|
@@ -1 +1,5 @@
|
||||
print(concat([1, 2], [3, 4]))
|
||||
var v = concat([1, 2], [3, 4]);
|
||||
|
||||
assert_equal(4, v.size());
|
||||
assert_equal(1, v[0]);
|
||||
assert_equal(4, v[3]);
|
||||
|
@@ -1 +0,0 @@
|
||||
[1, 2, 3, 4]
|
4
unittests/const_range_test.chai
Normal file
4
unittests/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 +1 @@
|
||||
print(3.5.to_string() + "bob")
|
||||
assert_equal("3.5bob", 3.5.to_string() + "bob");
|
||||
|
@@ -1 +0,0 @@
|
||||
3.5bob
|
@@ -1 +1 @@
|
||||
print(3.to_string + "bob")
|
||||
assert_equal("3bob", 3.to_string + "bob")
|
||||
|
@@ -1 +0,0 @@
|
||||
3bob
|
@@ -1 +1 @@
|
||||
print("3.5".to_double() + 3.3)
|
||||
assert_equal(6.8, "3.5".to_double() + 3.3)
|
||||
|
@@ -1 +0,0 @@
|
||||
6.7999999999999998
|
@@ -1 +1 @@
|
||||
print("4".to_int() + 4)
|
||||
assert_equal(8, "4".to_int() + 4)
|
||||
|
@@ -1 +0,0 @@
|
||||
8
|
11
unittests/deep_array_lookup.chai
Normal file
11
unittests/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/dispatch_functions.chai
Normal file
11
unittests/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 +1 @@
|
||||
print(drop([1, 2, 3, 4], 2))
|
||||
assert_equal([3,4], drop([1, 2, 3, 4], 2))
|
||||
|
@@ -1 +0,0 @@
|
||||
[3, 4]
|
@@ -1 +1 @@
|
||||
print(drop_while([1, 2, 3], odd))
|
||||
assert_equal([2, 3], drop_while([1, 2, 3], odd))
|
||||
|
@@ -1 +0,0 @@
|
||||
[2, 3]
|
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user