Compare commits

..

91 Commits

Author SHA1 Message Date
Jason Turner
41bf96c42e Update release notes for release 4.3.1 2014-05-03 17:44:54 -06:00
Jason Turner
c9a244019e Enhance the inheritance unit tests #117 2014-04-13 08:05:46 -06:00
Jason Turner
caf4495cff Add unit tests for inheritance with multiple layers 2014-03-29 06:16:21 -06:00
Jason Turner
6b0e0dc7ae Removed erroneously kept debug output 2014-03-28 07:04:51 -06:00
Jason Turner
65b0846e41 Address some of the issues found by cppcheck 2014-03-26 16:59:41 -06:00
Jason Turner
296769ee24 Version number bump, cppcheck fix 2014-03-26 15:20:06 -06:00
Jason Turner
d9bdad714f Fix syntax problem with .travis.yml 2014-03-26 14:45:01 -06:00
Jason Turner
12de955a47 Post cppcheck results to pull request 2014-03-26 13:56:02 -06:00
Jason Turner
a652a7e564 Only post comment if this is a pull request 2014-03-26 13:37:51 -06:00
Jason Turner
611692646f Add travis support for testing with cppcheck 2014-03-26 13:32:25 -06:00
Jason Turner
96acf5e833 Update travis in 4.x branch for coveralls support 2014-03-26 11:37:37 -06:00
Jason Turner
656b438002 First cast up chain, if that fails, cast down 2014-03-26 10:52:56 -06:00
Jason Turner
56b036052f Add test for automatic casting down in inheritance 2014-03-26 09:14:06 -06:00
Jason Turner
7fade8e841 Allow for automatic conversion of arithmetic types
for returns from chaiscript function wrappers
2014-03-26 08:11:37 -06:00
Jason Turner
db8be03cee Add tests for returning of arithmetic types with conversions 2014-03-26 07:26:23 -06:00
Jason Turner
27307b17d1 Update readme.md 2014-03-10 15:04:47 -06:00
Jason Turner
0162757158 Add missing boost dependency for travis 2014-03-10 14:48:59 -06:00
Jason Turner
d22fb19e0e Add travis-ci support for master branch 2014-03-10 14:31:02 -06:00
Jason Turner
8c70fff02b Update version to 4.3.0 2014-02-23 07:10:03 -07:00
Jason Turner
af44da916a Fix warnings and errors on VisualStudio 2013
Interestingly, VS2013 with Boost 1.55 exhibited the issues complained
about in issue #92, so I was able to provide an appropriate fix. It would
appear to be bugs in both compilers, which seems very odd.
2014-02-22 16:09:34 -07:00
Jason Turner
04131d208b Fix type on range.chai 2014-02-22 14:44:07 -07:00
Jason Turner
9c35ede59a Merge branch 'master' of https://github.com/ChaiScript/ChaiScript 2014-02-18 13:02:28 -07:00
Jason Turner
71348b7967 Update copyrights to 2014 and some comment formatting 2014-02-17 16:24:29 -07:00
Jason Turner
eb1a1c0275 Port windows unicode fix from @da2ce7 to 4.x branch 2014-01-23 12:28:33 -07:00
Jason Turner
8724e0cb80 Fix build error on 4.x branch if readline is found 2014-01-23 12:17:06 -07:00
Jason Turner
b872a50acc Add module search path relative to current exe #94 2014-01-05 14:59:31 -07:00
Jason Turner
36466a4ac5 Add unit tests for string size() fixes #93 #95 2014-01-05 12:22:44 -07:00
Jason Turner
bf83969723 Add unit test for calling 'count' on const map object. #90 2013-11-27 09:28:23 -07:00
Jason Turner
41f6ca18ea Prevent the user from naming an object with "::" #91 2013-11-27 08:53:34 -07:00
Jason Turner
a26d628e5c Cleanup (indentation, comments) for non-const global support
@Zoomulator - I pulled in your non-const global commits.
2013-11-27 08:19:26 -07:00
Jason Turner
d5fef3121a Merge remote-tracking branch 'zoomulator/master'
Adding zoomulator's patches for allowing of non-const globals if the user
wants to.
2013-11-27 08:06:39 -07:00
Jason Turner
16f09794cf Fixes #88: Linking error on MacOS Mavericks
The c++ library implementation on MacOS is broken, it does not allow you to
correctly use points to members of std::string. We work around this by not
directly using member pointers and instead wrapping the method calls
with our own functions.
2013-11-27 08:00:23 -07:00
Jason Turner
d44de49fb1 Add explicit tests for accessing data members of const objects 2013-09-27 20:19:16 -06:00
Jason Turner
101225aa68 - Fix legit threading issue which shows itself on clang / macos mostly
- Fix all warnings that I can / ignore those caused by boost
2013-05-26 22:47:23 -06:00
Jason Turner
feb344e744 Fix various warnings found by MSVC 2013-04-25 15:39:03 -06:00
Jason Turner
12d842ca5a Fix some additional warnings on MacOS 2013-04-25 12:21:41 -06:00
Jason Turner
e68599920a Move to pointers for Dynamic_Cast_Conversions to avoid problems with using the class before it's defined 2013-04-25 09:15:09 -06:00
Jason Turner
1e1385bc52 Do not link dl if on FreeBSD 2013-03-28 21:59:36 -06:00
Jason Turner
ae1221d46d Merge branch 'master' of https://github.com/ChaiScript/ChaiScript 2013-03-28 21:18:44 -06:00
Jason Turner
4fc51dfe05 Merge pull request #82 from mgee/master
Fix pretty_print for inline arrays.
2013-03-28 19:25:50 -07:00
Markus Groß
241ca75204 Correct pretty_print for inline arrays. 2013-02-28 17:39:30 +01:00
Jason Turner
2afc09dad4 Eradicate global base_class registrations to prevent problems with threading and general memory management issues with knowing how and when to clean them up. 2013-02-25 11:00:14 -07:00
Jason Turner
1858885010 Add example of wrapping data members of a class #79 2013-02-24 15:11:06 -07:00
Jason Turner
d068ce472c Clean up constuctors for AST_Node types 2013-02-24 13:55:20 -07:00
Jason Turner
380b94a8d2 Clean up implementation of for and while loops to make them easier to read and reduce code copying 2013-02-24 09:01:26 -07:00
Jason Turner
fd72b2951a Correct broken unit test for vector of suffixed numbers 2013-02-23 21:27:01 -07:00
Jason Turner
48f538438d Get all for loop related unit tests passing and expand the types of expressions
that can exist in a for loop
2013-02-23 21:14:37 -07:00
Jason Turner
c9995480e6 Add 'continue' command for loops. Also enhance for() unit tests which are now breaking and need to be fixed 2013-02-23 14:49:20 -07:00
Jason Turner
e298333ac6 Add unit test of suffixed number inside of vector initialization 2013-02-23 08:53:25 -07:00
Jason Turner
d225e09d5d Add profile for calling functions on members of a heterogeneous array 2013-02-23 08:49:31 -07:00
Jason Turner
59df213e66 Update version to 4.2.0 2012-11-30 20:38:17 -07:00
Jason Turner
0ea8931b21 Add ability to call functions requiring arithmetic value conversions
- Conversions are only attempted on a dispatch
 - Conversions are only attempted after a normal dispatch has failed
 - Conversions are only attempted if exactly one function matches
   the signature of the parameters passed in - excluding the mismatched
   arithmetic parameters
 - This feature should not be relied on in performance critical code
   overhead is added for each function call that requires a conversion
   to execute, see the tests performed above.
2012-11-27 21:21:37 -07:00
Jason Turner
f24d376fa5 Update for release 4.1.1 2012-11-17 20:48:25 -07:00
Jason Turner
7917ea02dc Fix linux build error discovered with 4.0.0 release 2012-11-17 20:30:53 -07:00
Jason Turner
deef33640c Update releasenotes and version numbers for 4.1.0 release 2012-11-17 18:31:48 -07:00
Jason Turner
58f3256389 Fix function pointer issue for substr on VS 2010 32bit 2012-11-16 13:58:03 -07:00
Jason Turner
f1a4c4c427 Fix compiler warning found on VS 2008 64bit 2012-11-16 12:57:15 -07:00
Jason Turner
afd27a4b01 Fix errors and warnings found on VisualStudio 2005 2012-11-16 12:27:41 -07:00
Jason Turner
4c65e45598 Correct signing and sizing of integer literals #77 2012-11-10 16:31:05 -07:00
Jason Turner
923369a4f4 Add support for string::substr #75
Also add forgotten missing test for number suffixes
2012-11-07 15:48:25 -07:00
Jason Turner
964342bff3 Prevent leaking macros #76 2012-11-07 14:13:08 -07:00
Jason Turner
623c64299a Add ability to specify number prefixes for floating point and integers. 2012-11-07 12:05:34 -07:00
Kim Simmons
abcc6c9e3e Chai::add_global was added
Just a modification of the add_global_const. I don't see the point in
limiting the user to binding only constants to the global scope if the user
wishes to have a thread safe mutable object as a global. This was my case
anyway.
2012-11-06 17:20:56 +01:00
Jason Turner
9832d1ce39 Add insert and insert_ref methods to "map" types 2012-09-26 12:38:32 -06:00
Jason Turner
ed7bdfb172 Add "erase" function to associative sets (maps) 2012-09-26 11:31:19 -06:00
Jason Turner
204ab53afc Update readme.txt to readme.md for better formatting. 2012-08-14 12:00:44 -06:00
Jason Turner
8f7226051e Add boost::system to linkage to support boost 1.50. Should not cause any issue for older users of boost 2012-08-14 08:59:48 -06:00
Jason Turner
46d1c50923 Merge pull request #66 from mgee/master
Make Boxed_Number utility functions const
2012-07-18 06:29:22 -07:00
Markus Groß
9e3c2960aa Make some Boxed_Number functions const. 2012-07-17 18:26:58 +02:00
Jason Turner
9fd4a1b9f5 Merge pull request #53 from mgee/master
More Boxed_Number enhancements
2012-07-16 21:18:18 -07:00
Jason Turner
441cdf0935 Add test showing c linkage working fine [#16] 2012-07-16 22:10:40 -06:00
Jason Turner
f0016d978a Add test to make sure simultaneous ChaiScript instantiations work 2012-07-16 21:51:06 -06:00
Jason Turner
1155720b14 Add the ability to save and restore the state of local variables #25 2012-07-16 21:27:42 -06:00
Jason Turner
f5b7be3743 Correct building on threadless 2012-07-13 13:14:48 -06:00
Jason Turner
d8f881239f Merge branch 'master' of https://github.com/ChaiScript/ChaiScript 2012-07-13 12:36:37 -06:00
Jason Turner
0a436398dd Use make_shared #64 2012-07-13 12:25:50 -06:00
Jason Turner
9f309fcbe9 Add tests for multithreaded features #55 2012-07-10 15:10:09 -06:00
Jason Turner
4e33e969dc Minor header file include cleanup 2012-07-10 13:27:47 -06:00
Markus Groß
08d9d9e28e Adapt toString to proper naming scheme. 2012-07-03 18:42:27 +02:00
Markus Groß
935276fccd Adapt getAs function to proper naming scheme. 2012-07-03 18:42:04 +02:00
Markus Groß
f8feaf6ea8 Add toString function to Boxed_Number.
For uint8_t, int8_t and char the value is first
converted to an appropriate int type.
This way the value is converted to a number
rather than a character.
2012-06-29 16:48:53 +02:00
Markus Groß
dfcc415c31 Add getAs<T> function to Boxed_Number to enable casting to a target type. 2012-06-29 08:00:00 +02:00
Markus Groß
927235d871 Add templated constructor to Boxed_Number to allow creating from primitive number types. 2012-06-29 07:42:16 +02:00
Jason Turner
bf4f90a4ff Fix build error for building without threads 2012-06-25 16:44:22 -06:00
Jason Turner
45f07f9924 Update method error output to show the expression it is trying to execute. 2012-06-25 16:26:36 -06:00
Jason Turner
39d817469c Optionally allow the user to specify the file name to report to end users when calling "eval" 2012-06-25 08:05:58 -06:00
Jason Turner
7a25625fdd Fix failing error reporting for solitary (non-dispatched) guarded function 2012-06-25 07:53:15 -06:00
Jason Turner
5e6a51ba63 Add failing unit test for remaining error condition to check for. 2012-06-25 07:44:14 -06:00
Jason Turner
a8ea5f151d Extreme error reporting capabilities update and bug fixes 2012-06-25 06:31:34 -06:00
Jason Turner
5a76d98692 Enhance and correct error messages
Backported from C++11 branch.

Conflicts:

	include/chaiscript/dispatchkit/proxy_functions.hpp
	include/chaiscript/language/chaiscript_common.hpp
	include/chaiscript/language/chaiscript_eval.hpp
	include/chaiscript/language/chaiscript_parser.hpp
2012-06-22 18:00:10 -06:00
Jason Turner
3bccf4d977 Explicitly link to pthreads, seems some systems need this #47 2012-06-09 18:02:35 -04:00
302 changed files with 4382 additions and 3523 deletions

25
.travis.yml Normal file
View File

@@ -0,0 +1,25 @@
language: cpp
compiler:
- gcc
before_install:
- sudo apt-get install libboost-dev libboost-all-dev
- sudo pip install cpp-coveralls
script:
- cmake -D ENABLE_COVERAGE:BOOL=TRUE -D CMAKE_BUILD_TYPE:STRING=Debug .
- make -j2
- make test
- mkdir gcov
- find CMakeFiles/ -name "*.gc*" -exec mv {} gcov/ \;
- gcov -d -o gcov gcov/*.gcda
- coveralls -n -E ".*\.cpp"
after_script:
- contrib/codeanalysis/runcppcheck.sh
notifications:
email:
recipients:
- jason@emptycrate.com
on_success: always
on_failure: always
env:
global:
secure: LCUAKUCRtFp2ak81nVLR+jx0C9+Drwx1OR4VzuvH+HNGWFdUZmAIV3R84euDqFC5cUhYYipaeMbiSOJUHE4MNlL58eQZryED6KSL7k7SgxOLpFSspMvuMjIYZLlBWpBneCR/EMDilu+zXEnASfVUMPuLmtY1GAyfSoZboqFProc=

View File

@@ -6,6 +6,18 @@ option(MULTITHREAD_SUPPORT_ENABLED "Multithreaded Support Enabled" TRUE)
option(BUILD_MODULES "Build Extra Modules (stl, reflection)" TRUE)
option(BUILD_SAMPLES "Build Samples Folder" FALSE)
set(EXTRA_LINKER_FLAGS "")
if (CMAKE_COMPILER_IS_GNUCC)
option(ENABLE_COVERAGE "Enable Coverage Reporting in GCC" FALSE)
if (ENABLE_COVERAGE)
add_definitions(--coverage -O0)
SET(EXTRA_LINKER_FLAGS ${EXTRA_LINKER_FLAGS} "--coverage")
endif()
endif()
list(APPEND CPACK_SOURCE_IGNORE_FILES "${CMAKE_CURRENT_BINARY_DIR}")
list(APPEND CPACK_SOURCE_IGNORE_FILES "\\\\.svn")
list(APPEND CPACK_SOURCE_IGNORE_FILES "\\\\.git")
@@ -13,22 +25,24 @@ 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_RESOURCE_FILE_README "${CMAKE_CURRENT_SOURCE_DIR}/readme.md")
set(CPACK_PACKAGE_DESCRIPTION_FILE "${CMAKE_CURRENT_SOURCE_DIR}/description.txt")
set(CPACK_PACKAGE_VERSION_MAJOR 5)
set(CPACK_PACKAGE_VERSION_MINOR 0)
set(CPACK_PACKAGE_VERSION_PATCH 0)
set(CPACK_PACKAGE_VERSION_MAJOR 4)
set(CPACK_PACKAGE_VERSION_MINOR 3)
set(CPACK_PACKAGE_VERSION_PATCH 1)
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})
@@ -59,56 +73,60 @@ if(MSVC)
add_definitions(/bigobj)
endif()
else()
add_definitions(-Wall -Wextra -Wshadow -pedantic -std=c++0x)
add_definitions(-Wall -Wextra -Wshadow -pedantic)
if (APPLE)
add_definitions(-Wno-sign-compare)
# -Wno-missing-field-initializers is for boost on macos
add_definitions(-Wno-missing-field-initializers -Wno-sign-compare)
endif()
endif()
if (CMAKE_CXX_COMPILER MATCHES ".*clang")
option(USE_LIBCXX "Use clang's libcxx" TRUE)
if (USE_LIBCXX)
add_definitions(-stdlib=libc++)
set (EXTRA_LINKER_FLAGS -std=c++0x -stdlib=libc++)
else ()
set (EXTRA_LINKER_FLAGS -std=c++0x )
endif()
else()
set (EXTRA_LINKER_FLAGS )
endif()
include_directories(include)
set(Boost_ADDITIONAL_VERSIONS "1.44" "1.44.0" "1.43" "1.43.0" "1.42" "1.42.0" "1.41")
set(Boost_USE_MULTITHREADED ON)
set (Chai_INCLUDES include/chaiscript/chaiscript.hpp include/chaiscript/chaiscript_threading.hpp include/chaiscript/dispatchkit/bad_boxed_cast.hpp include/chaiscript/dispatchkit/bind_first.hpp include/chaiscript/dispatchkit/bootstrap.hpp include/chaiscript/dispatchkit/bootstrap_stl.hpp include/chaiscript/dispatchkit/boxed_cast.hpp include/chaiscript/dispatchkit/boxed_cast_helper.hpp include/chaiscript/dispatchkit/boxed_number.hpp include/chaiscript/dispatchkit/boxed_value.hpp include/chaiscript/dispatchkit/dispatchkit.hpp include/chaiscript/dispatchkit/dynamic_cast_conversion.hpp include/chaiscript/dispatchkit/dynamic_object.hpp include/chaiscript/dispatchkit/exception_specification.hpp include/chaiscript/dispatchkit/function_call.hpp include/chaiscript/dispatchkit/function_call_detail.hpp include/chaiscript/dispatchkit/handle_return.hpp include/chaiscript/dispatchkit/operators.hpp include/chaiscript/dispatchkit/proxy_constructors.hpp include/chaiscript/dispatchkit/proxy_functions.hpp include/chaiscript/dispatchkit/proxy_functions_detail.hpp include/chaiscript/dispatchkit/register_function.hpp include/chaiscript/dispatchkit/type_info.hpp include/chaiscript/language/chaiscript_algebraic.hpp include/chaiscript/language/chaiscript_common.hpp include/chaiscript/language/chaiscript_engine.hpp include/chaiscript/language/chaiscript_eval.hpp include/chaiscript/language/chaiscript_parser.hpp include/chaiscript/language/chaiscript_prelude.hpp include/chaiscript/language/chaiscript_prelude_docs.hpp include/chaiscript/utility/utility.hpp)
set_source_files_properties(${Chai_INCLUDES} PROPERTIES HEADER_FILE_ONLY TRUE)
if (MULTITHREAD_SUPPORT_ENABLED)
find_package(Boost 1.36.0 COMPONENTS thread system)
if (Boost_FOUND)
link_directories( ${Boost_LIBRARY_DIRS} )
else()
message(FATAL_ERROR "Can not find Boost")
endif(Boost_FOUND)
if (CMAKE_HOST_UNIX)
add_definitions(-pthread)
list(APPEND LIBS "pthread")
endif()
else()
add_definitions(-DCHAISCRIPT_NO_THREADS)
endif()
if (CMAKE_HOST_UNIX)
set(DYNAMIC_LOADER "dl")
endif(CMAKE_HOST_UNIX)
if (CMAKE_HOST_UNIX AND NOT ${CMAKE_SYSTEM_NAME} MATCHES "FreeBSD")
list(APPEND LIBS "dl")
endif()
set(LIBS ${DYNAMIC_LOADER} ${READLINE_LIB})
list(APPEND LIBS ${READLINE_LIB})
if (NOT MSVC)
# Boost on MSVC does automatic linking
list(APPEND LIBS ${Boost_LIBRARIES})
endif()
if (CMAKE_COMPILER_2005)
# vs2005 is a bit too loud about possible loss of data warnings
# ADD_DEFINITIONS(/wd4244)
endif()
add_library(chaiscript_stdlib MODULE src/chaiscript_stdlib.cpp)
target_link_libraries(chaiscript_stdlib ${LIBS} ${EXTRA_LINKER_FLAGS})
include_directories(${Boost_INCLUDE_DIRS})
include_directories(${Boost_INCLUDE_DIR})
add_executable(chai src/main.cpp ${Chai_INCLUDES})
target_link_libraries(chai ${LIBS} ${EXTRA_LINKER_FLAGS})
add_dependencies(chai chaiscript_stdlib)
if (BUILD_SAMPLES)
add_executable(example samples/example.cpp)
@@ -127,7 +145,7 @@ if (BUILD_MODULES)
set(MODULES stl_extra reflection)
endif()
file(GLOB UNIT_TESTS RELATIVE ${CMAKE_CURRENT_SOURCE_DIR}/unittests/ ${CMAKE_CURRENT_SOURCE_DIR}/unittests/*.chai ${CMAKE_CURRENT_SOURCE_DIR}/unittests/3.x/*.chai)
file(GLOB UNIT_TESTS RELATIVE ${CMAKE_CURRENT_SOURCE_DIR}/unittests/ ${CMAKE_CURRENT_SOURCE_DIR}/unittests/*.chai)
list(SORT UNIT_TESTS)
@@ -186,9 +204,41 @@ if(BUILD_TESTING)
target_link_libraries(short_comparison_test ${LIBS} ${EXTRA_LINKER_FLAGS})
add_test(NAME Short_Comparison_Test COMMAND short_comparison_test)
add_executable(cpp_lambda_test unittests/cpp_lambda_test.cpp)
target_link_libraries(cpp_lambda_test ${LIBS} ${EXTRA_LINKER_FLAGS})
add_test(NAME cpp_lambda_test COMMAND cpp_lambda_test)
add_executable(expected_eval_errors_test unittests/expected_eval_errors_test.cpp)
target_link_libraries(expected_eval_errors_test ${LIBS} ${EXTRA_LINKER_FLAGS})
add_test(NAME Expected_Eval_Errors_Test COMMAND expected_eval_errors_test)
add_executable(set_state_test unittests/set_state_test.cpp)
target_link_libraries(set_state_test ${LIBS} ${EXTRA_LINKER_FLAGS})
add_test(NAME Set_State_Test COMMAND set_state_test)
add_executable(simultaneous_chaiscript_test unittests/simultaneous_chaiscript_test.cpp)
target_link_libraries(simultaneous_chaiscript_test ${LIBS} ${EXTRA_LINKER_FLAGS})
add_test(NAME Simultaneous_Chaiscript_Test COMMAND simultaneous_chaiscript_test)
add_executable(c_linkage_test unittests/c_linkage_test.cpp)
target_link_libraries(c_linkage_test ${LIBS} ${EXTRA_LINKER_FLAGS})
add_test(NAME C_Linkage_Test COMMAND c_linkage_test)
add_executable(integer_literal_test unittests/integer_literal_test.cpp)
target_link_libraries(integer_literal_test ${LIBS} ${EXTRA_LINKER_FLAGS})
add_test(NAME Integer_Literal_Test COMMAND integer_literal_test)
add_executable(arithmetic_conversions_test unittests/arithmetic_conversions_test.cpp)
target_link_libraries(arithmetic_conversions_test ${LIBS} ${EXTRA_LINKER_FLAGS})
add_test(NAME Arithmetic_Conversions_Test COMMAND arithmetic_conversions_test)
if (MULTITHREAD_SUPPORT_ENABLED)
add_executable(multithreaded_test unittests/multithreaded_test.cpp)
target_link_libraries(multithreaded_test ${LIBS} ${EXTRA_LINKER_FLAGS})
add_test(NAME Multithreaded_Test COMMAND multithreaded_test)
set_property(TEST Multithreaded_Test
PROPERTY ENVIRONMENT
"CHAI_USE_PATH=${CMAKE_CURRENT_SOURCE_DIR}/unittests/"
"CHAI_MODULE_PATH=${CMAKE_CURRENT_BINARY_DIR}/"
)
endif()
add_executable(multifile_test unittests/multifile_test_main.cpp unittests/multifile_test_chai.cpp
@@ -204,6 +254,7 @@ if(BUILD_TESTING)
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

View File

@@ -50,7 +50,7 @@ function run_test
# Run multithreaded tests
echo "****Building multithreaded test"
pushd src
g++ multithreaded.cpp -ldl -omultithreaded -I../include -O3
g++ multithreaded.cpp -lboost_thread-mt -ldl -omultithreaded -I../include -O3
echo "****Testing 1 thread runtime"
/usr/bin/time -p ./multithreaded 1 2> ../../r$1-1threadruntime.out
echo "****Testing 2 thread runtime"

View File

@@ -0,0 +1,10 @@
var my_array=["1", 4, 6.6l, 10ul, "1000", 100, 10.9f ];
for (var j = 0; j < 10000; ++j)
{
for (var i = 0; i < 6; ++i)
{
to_string(my_array[i]);
}
}

View File

@@ -1,6 +1,6 @@
def isprime(n)
{
for (auto i = 2; i < n; ++i)
for (var i = 2; i < n; ++i)
{
if (n % i == 0) {return false}
}
@@ -11,8 +11,8 @@ def isprime(n)
def primes(n)
{
auto count = 0
for (auto i = 2; i <= n; ++i)
var count = 0
for (var i = 2; i <= n; ++i)
{
if (isprime(i)) {++count}
}
@@ -21,6 +21,5 @@ def primes(n)
}
auto N = 5000
var N = 5000
print("primes: " + primes(N).to_string())

View File

@@ -0,0 +1,16 @@
#!/bin/bash
pushd ..
wget http://sourceforge.net/projects/cppcheck/files/cppcheck/1.64/cppcheck-1.64.tar.bz2
tar -xvf cppcheck-1.64.tar.bz2
cd cppcheck-1.64
make -j2
popd
../cppcheck-1.64/cppcheck --enable=all --inconclusive -I include --inline-suppr --std=c++11 --platform=unix64 src/main.cpp src/chai*.cpp --template ' - __{severity}__: [{file}:{line}](../blob/TRAVIS_COMMIT/{file}#L{line}) {message} ({id})' 2>output
sed -i "s/TRAVIS_COMMIT/${TRAVIS_COMMIT}/g" output
echo -n '{ "body": " ' > output.json
echo -n `awk '{printf "%s\\\\n", $0;}' output` >> output.json
echo -n '"}' >> output.json
if [ "${TRAVIS_PULL_REQUEST}" = "false" ]; then curl -H "Authorization: token ${TOKEN}" --request POST --data @output.json https://api.github.com/repos/ChaiScript/ChaiScript/commits/${TRAVIS_COMMIT}/comments; else curl -H "Authorization: token ${TOKEN}" --request POST --data @output.json https://api.github.com/repos/ChaiScript/ChaiScript/issues/${TRAVIS_PULL_REQUEST}/comments; fi

View File

@@ -51,7 +51,7 @@ $language_data = array (
'break', 'else', 'else if', 'eval', 'for', 'if', 'return', 'while', 'try', 'catch', 'finally', 'case', 'switch', 'default',
),
2 => array(
'def', 'false', 'fun', 'true', 'var', 'auto', 'attr',
'def', 'false', 'fun', 'true', 'var', 'attr',
),
3 => array(
// built in functions

View File

@@ -52,7 +52,7 @@ syn keyword chaiscriptExceptions try catch throw
syn keyword chaiscriptKeyword def true false attr
"Built in types
syn keyword chaiscriptType fun var auto
syn keyword chaiscriptType fun var
"Built in funcs, keep it simple
syn keyword chaiscriptFunc eval throw

View File

@@ -1,7 +1,7 @@
// This file is distributed under the BSD License.
// See "license.txt" for details.
// Copyright 2009-2012, Jonathan Turner (jonathan@emptycrate.com)
// and Jason Turner (jason@emptycrate.com)
// Copyright 2009-2014, Jason Turner (jason@emptycrate.com)
// http://www.chaiscript.com
#ifndef CHAISCRIPT_HPP_
@@ -74,16 +74,16 @@
/// <hr>
/// \subsection compiling Compiling ChaiScript Applications
///
/// ChaiScript is a header only library with only one dependecy: The
/// ChaiScript is a header only library with only two dependecies. boost::threads (optional) and the
/// operating system provided dynamic library loader, which has to be specified on some platforms.
///
/// \subsubsection compilinggcc Compiling with GCC
///
/// To compile the above application on a Unix like operating system (MacOS, Linux) with GCC you need to link
/// the dynamic loader. For example:
/// both boost::threads and the dynamic loader. For example:
///
/// \code
/// gcc main.cpp -I/path/to/chaiscript/headers -ldl
/// gcc main.cpp -I/path/to/chaiscript/headers -ldl -lboost_threads
/// \endcode
///
/// Alternatively, you may compile without threading support.
@@ -140,7 +140,10 @@
///
/// \subsubsection addingobjects Adding Objects
///
/// Named objects can be created with the chaiscript::var function.
/// Named objects can be created with the chaiscript::var function. Note: adding a object
/// adds it to the current thread scope, not to a global scope. If you have multiple
/// threads that need to access the same variables you will need to add them
/// separately for each thread, from the thread itself.
///
/// \code
/// using namespace chaiscript;
@@ -245,9 +248,7 @@
///
/// std::string append_string_int(const std::string &t_lhs, int t_rhs)
/// {
/// std::stringstream ss;
/// ss << t_lhs << t_rhs;
/// return ss.str();
/// return t_lhs + boost::lexical_cast<std::string>(t_rhs);
/// }
///
/// chai.add(fun(append_string_int), "+");
@@ -299,8 +300,8 @@
/// <hr>
/// \subsection pointerconversions Pointer / Object Conversions
///
/// As much as possible, ChaiScript attempts to convert between &, *, const &, const *, std::shared_ptr<T>,
/// std::shared_ptr<const T>, std::reference_wrapper<T>, std::reference_wrapper<const T> and value types automatically.
/// 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 chaiscript::var object was created in C++ from a pointer, it cannot be convered to a shared_ptr (this would add invalid reference counting).
/// Const may be added, but never removed.
@@ -313,12 +314,12 @@
/// void fun3(int);
/// void fun4(int &);
/// void fun5(const int &);
/// void fun5(std::shared_ptr<int>);
/// void fun6(std::shared_ptr<const int>);
/// void fun7(const std::shared_ptr<int> &);
/// void fun8(const std::shared_ptr<const int> &);
/// void fun9(std::reference_wrapper<int>);
/// void fun10(std::reference_wrapper<const int>);
/// 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()
/// {
@@ -379,10 +380,10 @@
/// \subsection functionobjects Function Objects
///
/// Functions are first class objects in Chaiscript and ChaiScript supports automatic conversion
/// between ChaiScript functions and std::function objects.
/// between ChaiScript functions and boost::function objects.
///
/// \code
/// void callafunc(const std::function<void (const std::string &)> &t_func)
/// void callafunc(const boost::function<void (const std::string &)> &t_func)
/// {
/// t_func("bob");
/// }
@@ -392,9 +393,9 @@
/// chaiscript::ChaiScript chai;
/// chai.add(chaiscript::fun(&callafunc), "callafunc");
/// chai("callafunc(fun(x) { print(x); })"); // pass a lambda function to the registered function
/// // which expects a typed std::function
/// // which expects a typed boost::function
///
/// std::function<void ()> f = chai.eval<std::function<void ()> >("dump_system");
/// boost::function<void ()> f = chai.eval<boost::function<void ()> >("dump_system");
/// f(); // call the ChaiScript function dump_system, from C++
/// }
/// \endcode
@@ -409,7 +410,7 @@
///
/// Thread safety can be disabled by defining CHAISCRIPT_NO_THREADS when using the library.
///
/// Disabling thread safety increases performance in many cases.
/// Disabling thread safety increases performance and removes the requirement for boost_threads.
///
/// <hr>
///
@@ -745,16 +746,20 @@
/// \namespace chaiscript::detail
/// \brief Classes and functions reserved for internal use. Items in this namespace are not supported.
#include "chaiscript_defines.hpp"
#include "dispatchkit/dispatchkit.hpp"
#include "dispatchkit/bootstrap.hpp"
#include "dispatchkit/bootstrap_stl.hpp"
#include "dispatchkit/function_call.hpp"
#include "dispatchkit/dynamic_object.hpp"
#include "dispatchkit/boxed_number.hpp"
#ifdef BOOST_HAS_DECLSPEC
#define CHAISCRIPT_MODULE_EXPORT extern "C" __declspec(dllexport)
#else
#define CHAISCRIPT_MODULE_EXPORT extern "C"
#endif
#include "language/chaiscript_eval.hpp"
#include "language/chaiscript_engine.hpp"
#endif /* CHAISCRIPT_HPP_ */

View File

@@ -1,28 +0,0 @@
// This file is distributed under the BSD License.
// See "license.txt" for details.
// Copyright 2009-2012, Jonathan Turner (jonathan@emptycrate.com)
// and Jason Turner (jason@emptycrate.com)
// http://www.chaiscript.com
#ifndef CHAISCRIPT_DEFINES_HPP_
#define CHAISCRIPT_DEFINES_HPP_
#ifdef _MSC_VER
#define CHAISCRIPT_MSVC _MSC_VER
#define CHAISCRIPT_HAS_DECLSPEc
#endif
#ifdef _WIN32
#define CHAISCRIPT_WINDOWS
#endif
#ifdef CHAISCRIPT_HAS_DECLSPEC
#define CHAISCRIPT_MODULE_EXPORT extern "C" __declspec(dllexport)
#else
#define CHAISCRIPT_MODULE_EXPORT extern "C"
#endif
#endif

View File

@@ -1,44 +0,0 @@
// This file is distributed under the BSD License.
// See "license.txt" for details.
// Copyright 2009-2012, Jonathan Turner (jonathan@emptycrate.com)
// and Jason Turner (jason@emptycrate.com)
// http://www.chaiscript.com
#ifndef CHAISCRIPT_STDLIB_HPP_
#define CHAISCRIPT_STDLIB_HPP_
#include "chaiscript_defines.hpp"
#include "dispatchkit/bootstrap.hpp"
#include "dispatchkit/bootstrap_stl.hpp"
/// \file
///
/// This file generates the standard library that normal ChaiScript usage requires.
namespace chaiscript
{
class Std_Lib
{
public:
static ModulePtr library()
{
using namespace bootstrap;
ModulePtr lib = Bootstrap::bootstrap();
lib->add(standard_library::vector_type<std::vector<Boxed_Value> >("Vector"));
lib->add(standard_library::string_type<std::string>("string"));
lib->add(standard_library::map_type<std::map<std::string, Boxed_Value> >("Map"));
lib->add(standard_library::pair_type<std::pair<Boxed_Value, Boxed_Value > >("Pair"));
return lib;
}
};
}
#endif

View File

@@ -1,15 +1,23 @@
// This file is distributed under the BSD License.
// See "license.txt" for details.
// Copyright 2009-2012, Jonathan Turner (jonathan@emptycrate.com)
// and Jason Turner (jason@emptycrate.com)
// Copyright 2009-2014, Jason Turner (jason@emptycrate.com)
// http://www.chaiscript.com
#ifndef CHAISCRIPT_THREADING_HPP_
#define CHAISCRIPT_THREADING_HPP_
#ifndef CHAISCRIPT_NO_THREADS
#include <thread>
#include <mutex>
#ifdef __llvm__
#pragma clang diagnostic push
#pragma clang diagnostic ignored "-Wc++11-long-long"
#pragma clang diagnostic ignored "-Wshadow"
#endif
#include <boost/thread.hpp>
#ifdef __llvm__
#pragma clang diagnostic pop
#endif
#else
#pragma message ("ChaiScript is compiling without thread safety.")
#endif
@@ -26,81 +34,48 @@ namespace chaiscript
{
namespace detail
{
/// If threading is enabled, then this namespace contains std thread classes.
/// 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
template<typename T>
class unique_lock : public std::unique_lock<T>
{
public:
unique_lock(T &t) : std::unique_lock<T>(t) {}
};
template<typename T>
class shared_lock : public std::unique_lock<T>
{
public:
shared_lock(T &t) : std::unique_lock<T>(t) {}
void unlock() {}
};
template<typename T>
class lock_guard : public std::lock_guard<T>
{
public:
lock_guard(T &t) : std::lock_guard<T>(t) {}
};
class shared_mutex : public std::mutex { };
using std::mutex;
using std::recursive_mutex;
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 a mutex protected map. If
/// 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.
///
/// \todo move to thread_local when it exists
template<typename T>
class Thread_Storage
{
public:
~Thread_Storage()
{
m_thread_storage.reset();
}
inline T *operator->() const
{
return get_tls().get();
if (!m_thread_storage.get())
{
m_thread_storage.reset(new T());
}
return m_thread_storage.get();
}
inline T &operator*() const
{
return *get_tls();
return *(this->operator->());
}
private:
std::shared_ptr<T> get_tls() const
{
unique_lock<mutex> lock(m_mutex);
auto itr = m_instances.find(std::this_thread::get_id());
if (itr != m_instances.end()) { return itr->second; }
std::shared_ptr<T> new_instance(new T());
m_instances.insert(std::make_pair(std::this_thread::get_id(), new_instance));
return new_instance;
}
mutable mutex m_mutex;
mutable std::map<std::thread::id, std::shared_ptr<T> > m_instances;
mutable boost::thread_specific_ptr<T> m_thread_storage;
};
#else
@@ -109,6 +84,8 @@ namespace chaiscript
{
public:
unique_lock(T &) {}
void lock() {}
void unlock() {}
};
template<typename T>
@@ -116,6 +93,7 @@ namespace chaiscript
{
public:
shared_lock(T &) {}
void lock() {}
void unlock() {}
};

View File

@@ -1,162 +0,0 @@
// This file is distributed under the BSD License.
// See "license.txt" for details.
// Copyright 2009-2012, Jonathan Turner (jonathan@emptycrate.com)
// and Jason Turner (jason@emptycrate.com)
// http://www.chaiscript.com
#ifndef CHAISCRIPT_ANY_HPP_
#define CHAISCRIPT_ANY_HPP_
namespace chaiscript {
namespace detail {
namespace exception
{
/// \brief Thrown in the event that an Any cannot be cast to the desired type
///
/// It is used internally during function dispatch.
///
/// \sa chaiscript::detail::Any
class bad_any_cast : public std::bad_cast
{
public:
bad_any_cast() noexcept
: m_what("bad any cast")
{
}
virtual ~bad_any_cast() noexcept {}
/// \brief Description of what error occured
virtual const char * what() const noexcept
{
return m_what.c_str();
}
private:
std::string m_what;
};
}
class Any {
private:
struct Data
{
virtual void *data() = 0;
virtual const std::type_info &type() const = 0;
virtual std::shared_ptr<Data> clone() const = 0;
};
template<typename T>
struct Data_Impl : Data
{
Data_Impl(const T &t_type)
: m_type(typeid(T)),
m_data(t_type)
{
}
virtual void *data()
{
return &m_data;
}
const std::type_info &type() const
{
return m_type;
}
std::shared_ptr<Data> clone() const
{
return std::shared_ptr<Data>(new Data_Impl<T>(m_data));
}
const std::type_info &m_type;
T m_data;
};
std::shared_ptr<Data> m_data;
public:
// construct/copy/destruct
Any() = default;
Any(const Any &t_any)
{
if (!t_any.empty())
{
m_data = t_any.m_data->clone();
} else {
m_data.reset();
}
}
template<typename ValueType>
Any(const ValueType &t_value)
{
m_data = std::shared_ptr<Data>(new Data_Impl<ValueType>(t_value));
}
Any & operator=(const Any &t_any)
{
Any copy(t_any);
swap(copy);
return *this;
}
template<typename ValueType>
Any & operator=(const ValueType &t_value)
{
m_data = std::shared_ptr<Data>(new Data_Impl<ValueType>(t_value));
return *this;
}
template<typename ToType>
ToType &cast() const
{
if (m_data && typeid(ToType) == m_data->type())
{
return *static_cast<ToType *>(m_data->data());
} else {
throw chaiscript::detail::exception::bad_any_cast();
}
}
~Any()
{
}
// modifiers
Any & swap(Any &t_other)
{
std::shared_ptr<Data> data = t_other.m_data;
t_other.m_data = m_data;
m_data = data;
return *this;
}
// queries
bool empty() const
{
return !bool(m_data);
}
const std::type_info & type() const
{
if (m_data)
{
return m_data->type();
} else {
return typeid(void);
}
}
};
}
}
#endif

View File

@@ -1,7 +1,7 @@
// This file is distributed under the BSD License.
// See "license.txt" for details.
// Copyright 2009-2012, Jonathan Turner (jonathan@emptycrate.com)
// and Jason Turner (jason@emptycrate.com)
// Copyright 2009-2014, Jason Turner (jason@emptycrate.com)
// http://www.chaiscript.com
#ifndef CHAISCRIPT_BAD_BOXED_CAST_HPP_
@@ -22,25 +22,25 @@ namespace chaiscript
{
public:
bad_boxed_cast(const Type_Info &t_from, const std::type_info &t_to,
const std::string &t_what) noexcept
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) noexcept
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) noexcept
bad_boxed_cast(const std::string &t_what) throw()
: to(0), m_what(t_what)
{
}
virtual ~bad_boxed_cast() noexcept {}
virtual ~bad_boxed_cast() throw() {}
/// \brief Description of what error occured
virtual const char * what() const noexcept
virtual const char * what() const throw()
{
return m_what.c_str();
}

View File

@@ -1,133 +1,94 @@
// This file is distributed under the BSD License.
// See "license.txt" for details.
// Copyright 2009-2012, Jonathan Turner (jonathan@emptycrate.com)
// and Jason Turner (jason@emptycrate.com)
// Copyright 2009-2014, Jason Turner (jason@emptycrate.com)
// http://www.chaiscript.com
#include <boost/preprocessor.hpp>
#include <boost/preprocessor/arithmetic/inc.hpp>
#define param(z,n,text) BOOST_PP_CAT(text, BOOST_PP_INC(n))
#ifndef BOOST_PP_IS_ITERATING
#ifndef CHAISCRIPT_BIND_FIRST_HPP_
#define CHAISCRIPT_BIND_FIRST_HPP_
#include <functional>
#include <boost/function.hpp>
#include <boost/bind.hpp>
#include <boost/ref.hpp>
#define BOOST_PP_ITERATION_LIMITS ( 0, 8 )
#define BOOST_PP_FILENAME_1 <chaiscript/dispatchkit/bind_first.hpp>
#include BOOST_PP_ITERATE()
# endif
#else
# define n BOOST_PP_ITERATION()
# define m BOOST_PP_INC(n)
namespace chaiscript
{
namespace detail
{
template<int>
struct Placeholder
/// \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)
{
};
template<>
struct Placeholder<1>
{
static decltype(std::placeholders::_1) value() { return std::placeholders::_1; }
};
template<>
struct Placeholder<2>
{
static decltype(std::placeholders::_2) value() { return std::placeholders::_2; }
};
template<>
struct Placeholder<3>
{
static decltype(std::placeholders::_3) value() { return std::placeholders::_3; }
};
template<>
struct Placeholder<4>
{
static decltype(std::placeholders::_4) value() { return std::placeholders::_4; }
};
template<>
struct Placeholder<5>
{
static decltype(std::placeholders::_5) value() { return std::placeholders::_5; }
};
template<>
struct Placeholder<6>
{
static decltype(std::placeholders::_6) value() { return std::placeholders::_6; }
};
template<>
struct Placeholder<7>
{
static decltype(std::placeholders::_7) value() { return std::placeholders::_7; }
};
template<>
struct Placeholder<8>
{
static decltype(std::placeholders::_8) value() { return std::placeholders::_8; }
};
template<>
struct Placeholder<9>
{
static decltype(std::placeholders::_9) value() { return std::placeholders::_9; }
};
template<>
struct Placeholder<10>
{
static decltype(std::placeholders::_10) value() { return std::placeholders::_10; }
};
template<int count, int maxcount, typename Sig>
struct Bind_First
{
template<typename F, typename ... InnerParams>
static std::function<Sig> bind(F f, InnerParams ... innerparams)
{
return Bind_First<count - 1, maxcount, Sig>::bind(f, innerparams..., Placeholder<maxcount - count + 1>::value());
}
};
template<int maxcount, typename Sig>
struct Bind_First<0, maxcount, Sig>
{
template<typename F, typename ... InnerParams>
static std::function<Sig> bind(F f, InnerParams ... innerparams)
{
return std::bind(f, innerparams...);
}
};
template<typename O, typename Ret, typename P1, typename ... Param>
std::function<Ret (Param...)> bind_first(Ret (*f)(P1, Param...), O o)
{
return Bind_First<sizeof...(Param), sizeof...(Param), Ret (Param...)>::bind(f, o);
return boost::bind(boost::mem_fn(f), o BOOST_PP_COMMA_IF(n) BOOST_PP_ENUM(n, param, _));
}
template<typename O, typename Ret, typename Class, typename ... Param>
std::function<Ret (Param...)> bind_first(Ret (Class::*f)(Param...), O o)
/// \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 Bind_First<sizeof...(Param), sizeof...(Param), Ret (Param...)>::bind(f, o);
return boost::bind(boost::mem_fn(f), o BOOST_PP_COMMA_IF(n) BOOST_PP_ENUM(n, param, _));
}
template<typename O, typename Ret, typename Class, typename ... Param>
std::function<Ret (Param...)> bind_first(Ret (Class::*f)(Param...) const, O o)
/// \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)
{
return Bind_First<sizeof...(Param), sizeof...(Param), Ret (Param...)>::bind(f, o);
return boost::bind(f, o BOOST_PP_COMMA_IF(n) BOOST_PP_ENUM(n, param, _));
}
template<typename O, typename Ret, typename P1, typename ... Param>
std::function<Ret (Param...)> bind_first(const std::function<Ret (P1, Param...)> &f, O o)
/// \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)
{
return Bind_First<sizeof...(Param), sizeof...(Param), Ret (Param...)>::bind(f, o);
return boost::bind(f, o BOOST_PP_COMMA_IF(n) BOOST_PP_ENUM(n, param, _));
}
}
}
#undef n
#undef m
#undef param
#endif

View File

@@ -1,7 +1,7 @@
// This file is distributed under the BSD License.
// See "license.txt" for details.
// Copyright 2009-2012, Jonathan Turner (jonathan@emptycrate.com)
// and Jason Turner (jason@emptycrate.com)
// Copyright 2009-2014, Jason Turner (jason@emptycrate.com)
// http://www.chaiscript.com
#ifndef CHAISCRIPT_BOOTSTRAP_HPP_
@@ -12,8 +12,8 @@
#include "register_function.hpp"
#include "operators.hpp"
#include "boxed_number.hpp"
#include <boost/function_types/result_type.hpp>
#include <sstream>
#include <type_traits>
namespace chaiscript
{
@@ -26,9 +26,9 @@ namespace chaiscript
/// \param[in] v Boxed_Number to copy into the new object
/// \returns The newly created object.
template<typename P1>
std::shared_ptr<P1> construct_pod(Boxed_Number v)
boost::shared_ptr<P1> construct_pod(Boxed_Number v)
{
std::shared_ptr<P1> p(new P1());
boost::shared_ptr<P1> p(new P1());
Boxed_Value bv(p);
Boxed_Number nb(bv);
nb = v;
@@ -118,6 +118,10 @@ namespace chaiscript
}
/**
* Add all common functions for a POD type. All operators, and
* common conversions
@@ -143,7 +147,7 @@ namespace chaiscript
* function variables.
*/
template<typename Type>
std::shared_ptr<Type> shared_ptr_clone(const std::shared_ptr<Type> &p)
boost::shared_ptr<Type> shared_ptr_clone(const boost::shared_ptr<Type> &p)
{
return p;
}
@@ -152,10 +156,10 @@ namespace chaiscript
* Specific version of shared_ptr_clone just for Proxy_Functions
*/
template<typename Type>
std::shared_ptr<typename std::remove_const<Type>::type>
shared_ptr_unconst_clone(const std::shared_ptr<typename std::add_const<Type>::type> &p)
boost::shared_ptr<typename boost::remove_const<Type>::type>
shared_ptr_unconst_clone(const boost::shared_ptr<typename boost::add_const<Type>::type> &p)
{
return std::const_pointer_cast<typename std::remove_const<Type>::type>(p);
return boost::const_pointer_cast<typename boost::remove_const<Type>::type>(p);
}
@@ -166,7 +170,7 @@ namespace chaiscript
* Similar to shared_ptr_clone. Used for Proxy_Function.
*/
template<typename Type>
Boxed_Value ptr_assign(Boxed_Value lhs, const std::shared_ptr<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())))
@@ -269,28 +273,17 @@ namespace chaiscript
std::vector<Boxed_Value>(params.begin() + 1, params.end()))));
}
/**
* Returns true if a call can be made that consists of the first parameter
* (the function) with the remaining parameters as its arguments.
*/
static Boxed_Value call_exists(const std::vector<Boxed_Value> &params)
{
if (params.size() < 1)
{
throw exception::arity_error(static_cast<int>(params.size()), 1);
}
Const_Proxy_Function f = boxed_cast<Const_Proxy_Function>(params[0]);
return Boxed_Value(f->call_match(std::vector<Boxed_Value>(params.begin() + 1, params.end())));
}
static bool has_guard(const Const_Proxy_Function &t_pf)
{
auto pf = std::dynamic_pointer_cast<const dispatch::Dynamic_Proxy_Function>(t_pf);
boost::shared_ptr<const dispatch::Dynamic_Proxy_Function> pf = boost::dynamic_pointer_cast<const dispatch::Dynamic_Proxy_Function>(t_pf);
if (pf)
{
return bool(pf->get_guard());
if (pf->get_guard()) {
return true;
} else {
return false;
}
} else {
return false;
}
@@ -298,7 +291,7 @@ namespace chaiscript
static Const_Proxy_Function get_guard(const Const_Proxy_Function &t_pf)
{
auto pf = std::dynamic_pointer_cast<const dispatch::Dynamic_Proxy_Function>(t_pf);
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())
@@ -316,14 +309,6 @@ namespace chaiscript
throw bv;
}
static std::shared_ptr<chaiscript::detail::Dispatch_Engine> bootstrap2(
std::shared_ptr<chaiscript::detail::Dispatch_Engine> e
= std::shared_ptr<chaiscript::detail::Dispatch_Engine> (new chaiscript::detail::Dispatch_Engine()))
{
e->add(user_type<void>(), "void");
return e;
}
static std::string what(const std::exception &e)
{
return e.what();
@@ -346,22 +331,24 @@ namespace chaiscript
static std::vector<Boxed_Value> do_return_boxed_value_vector(FunctionType f,
const dispatch::Proxy_Function_Base *b)
{
auto v = (b->*f)();
typedef typename boost::function_types::result_type<FunctionType>::type Vector;
Vector v = (b->*f)();
std::vector<Boxed_Value> vbv;
for (const auto &o: v)
for (typename Vector::const_iterator itr = v.begin();
itr != v.end();
++itr)
{
vbv.push_back(const_var(o));
vbv.push_back(const_var(*itr));
}
return vbv;
}
template<typename Function>
static std::function<std::vector<Boxed_Value> (const dispatch::Proxy_Function_Base*)> return_boxed_value_vector(const Function &f)
static boost::function<std::vector<Boxed_Value> (const dispatch::Proxy_Function_Base*)> return_boxed_value_vector(const Function &f)
{
return std::bind(&do_return_boxed_value_vector<Function>, f, std::placeholders::_1);
return boost::bind(&do_return_boxed_value_vector<Function>, f, _1);
}
public:
@@ -379,7 +366,6 @@ namespace chaiscript
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==), "==");
@@ -392,7 +378,7 @@ namespace chaiscript
m->add(constructor<std::runtime_error (const std::string &)>(), "runtime_error");
m->add(fun(std::function<std::string (const std::runtime_error &)>(&what)), "what");
m->add(fun(boost::function<std::string (const std::runtime_error &)>(&what)), "what");
m->add(user_type<dispatch::Dynamic_Object>(), "Dynamic_Object");
m->add(constructor<dispatch::Dynamic_Object (const std::string &)>(), "Dynamic_Object");
@@ -400,7 +386,7 @@ namespace chaiscript
m->add(fun(&dispatch::Dynamic_Object::get_attrs), "get_attrs");
m->add(fun(&dispatch::Dynamic_Object::get_attr), "get_attr");
m->eval("def Dynamic_Object::clone() { auto &new_o = Dynamic_Object(this.get_type_name()); for_each(this.get_attrs(), bind(fun(new_o, x) { new_o.get_attr(x.first) = x.second; }, new_o, _) ); return new_o; }");
m->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");
@@ -423,6 +409,7 @@ namespace chaiscript
m->add(fun(&Type_Info::is_void), "is_type_void");
m->add(fun(&Type_Info::is_undef), "is_type_undef");
m->add(fun(&Type_Info::is_pointer), "is_type_pointer");
m->add(fun(&Type_Info::is_arithmetic), "is_type_arithmetic");
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");
@@ -442,18 +429,19 @@ namespace chaiscript
bootstrap_pod_type<long double>("long_double", m);
bootstrap_pod_type<float>("float", m);
bootstrap_pod_type<int>("int", m);
bootstrap_pod_type<long>("long", m);
bootstrap_pod_type<unsigned int>("unsigned_int", m);
bootstrap_pod_type<unsigned long>("unsigned_long", m);
bootstrap_pod_type<size_t>("size_t", m);
bootstrap_pod_type<char>("char", m);
bootstrap_pod_type<std::int8_t>("int8_t", m);
bootstrap_pod_type<std::int16_t>("int16_t", m);
bootstrap_pod_type<std::int32_t>("int32_t", m);
bootstrap_pod_type<std::int64_t>("int64_t", m);
bootstrap_pod_type<std::uint8_t>("uint8_t", m);
bootstrap_pod_type<std::uint16_t>("uint16_t", m);
bootstrap_pod_type<std::uint32_t>("uint32_t", m);
bootstrap_pod_type<std::uint64_t>("uint64_t", m);
bootstrap_pod_type<boost::int8_t>("int8_t", m);
bootstrap_pod_type<boost::int16_t>("int16_t", m);
bootstrap_pod_type<boost::int32_t>("int32_t", m);
bootstrap_pod_type<boost::int64_t>("int64_t", m);
bootstrap_pod_type<boost::uint8_t>("uint8_t", m);
bootstrap_pod_type<boost::uint16_t>("uint16_t", m);
bootstrap_pod_type<boost::uint32_t>("uint32_t", m);
bootstrap_pod_type<boost::uint64_t>("uint64_t", m);
operators::logical_compliment<bool>(m);
@@ -463,17 +451,14 @@ namespace chaiscript
m->add(fun(&print), "print_string");
m->add(fun(&println), "println_string");
m->add(Proxy_Function(new dispatch::Dynamic_Proxy_Function(std::bind(&bind_function, std::placeholders::_1))),
m->add(Proxy_Function(new dispatch::Dynamic_Proxy_Function(boost::bind(&bind_function, _1))),
"bind");
m->add(fun(&shared_ptr_unconst_clone<dispatch::Proxy_Function_Base>), "clone");
m->add(fun(&ptr_assign<std::remove_const<dispatch::Proxy_Function_Base>::type>), "=");
m->add(fun(&ptr_assign<std::add_const<dispatch::Proxy_Function_Base>::type>), "=");
m->add(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 dispatch::Dynamic_Proxy_Function(std::bind(&call_exists, std::placeholders::_1))),
"call_exists");
m->add(fun(&Boxed_Value::type_match), "type_match");
m->add(fun(&type_match), "type_match");
return m;
}

View File

@@ -1,23 +1,19 @@
// This file is distributed under the BSD License.
// See "license.txt" for details.
// Copyright 2009-2012, Jonathan Turner (jonathan@emptycrate.com)
// and Jason Turner (jason@emptycrate.com)
// Copyright 2009-2014, 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
*/
/// \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 CHAISCRIPT_BOOTSTRAP_STL_HPP_
#define CHAISCRIPT_BOOTSTRAP_STL_HPP_
#include "dispatchkit.hpp"
#include "bootstrap.hpp"
#include "register_function.hpp"
namespace chaiscript
@@ -26,11 +22,10 @@ namespace chaiscript
{
namespace standard_library
{
/**
* Bidir_Range, based on the D concept of ranges.
* \todo Update the Range code to base its capabilities on
* the user_typetraits of the iterator passed in
*/
/// Bidir_Range, based on the D concept of ranges.
/// \todo Update the Range code to base its capabilities on
/// the user_typetraits of the iterator passed in
template<typename Container>
struct Bidir_Range
{
@@ -148,10 +143,106 @@ namespace chaiscript
};
namespace detail {
template<typename T>
int return_int_impl(const boost::function<typename T::size_type (const T *)> &t_func, const T *t_obj)
{
#ifdef BOOST_MSVC
#pragma warning(push)
#pragma warning(disable : 4267)
#endif
return t_func(t_obj);
#ifdef BOOST_MSVC
#pragma warning(pop)
#endif
}
/**
* Add Bidir_Range support for the given ContainerType
*/
template<typename T>
boost::function<int (const T *)> return_int(size_t (T::*t_func)() const)
{
return boost::bind(&return_int_impl<T>, boost::function<size_t (const T *)>(boost::mem_fn(t_func)), _1);
}
template<typename T, typename P1>
int return_int_impl(const boost::function<typename T::size_type (const T *, P1)> &t_func, const T *t_obj, P1 p1)
{
#ifdef BOOST_MSVC
#pragma warning(push)
#pragma warning(disable : 4267)
#endif
return t_func(t_obj, p1);
#ifdef BOOST_MSVC
#pragma warning(pop)
#endif
}
template<typename T, typename P1>
int return_int_impl_non_const(const boost::function<typename T::size_type (T *, P1)> &t_func, T *t_obj, P1 p1)
{
#ifdef BOOST_MSVC
#pragma warning(push)
#pragma warning(disable : 4267)
#endif
return t_func(t_obj, p1);
#ifdef BOOST_MSVC
#pragma warning(pop)
#endif
}
template<typename T, typename P1>
boost::function<int (const T *, P1)> return_int(size_t (T::*t_func)(P1) const)
{
return boost::bind(&return_int_impl<T, P1>, boost::function<size_t (const T *, P1)>(boost::mem_fn(t_func)), _1, _2);
}
template<typename T, typename P1>
boost::function<int (T *, P1)> return_int(size_t (T::*t_func)(P1) )
{
return boost::bind(&return_int_impl_non_const<T, P1>, boost::function<size_t (T*, P1)>(boost::mem_fn(t_func)), _1, _2);
}
template<typename T, typename P1, typename P2>
int return_int_impl(const boost::function<typename T::size_type (const T *, P1, P2)> &t_func, const T *t_obj, P1 p1, P2 p2)
{
#ifdef BOOST_MSVC
#pragma warning(push)
#pragma warning(disable : 4267)
#endif
return t_func(t_obj, p1, p2);
#ifdef BOOST_MSVC
#pragma warning(pop)
#endif
}
template<typename StringType, StringType (StringType::*Func)(typename StringType::size_type, typename StringType::size_type) const >
StringType substr_helper(const StringType &str, int begin, int end)
{
return (str.*Func)(begin, end);
}
template<typename T, typename P1, typename P2>
boost::function<int (const T *, P1, P2)> return_int(size_t (T::*t_func)(P1, P2) const)
{
return boost::bind(&return_int_impl<T, P1, P2>, boost::function<size_t (const T *, P1, P2)>(boost::mem_fn(t_func)), _1, _2, _3);
}
template<typename T>
void insert(T &t_target, const T &t_other)
{
t_target.insert(t_other.begin(), t_other.end());
}
template<typename T>
void insert_ref(T &t_target, const typename T::value_type &t_val)
{
t_target.insert(t_val);
}
/// Add Bidir_Range support for the given ContainerType
template<typename Bidir_Type>
ModulePtr input_range_type_impl(const std::string &type, ModulePtr m = ModulePtr(new Module()))
{
@@ -170,9 +261,8 @@ namespace chaiscript
return m;
}
/**
* Algorithm for inserting at a specific position into a container
*/
/// Algorithm for inserting at a specific position into a container
template<typename Type>
void insert_at(Type &container, int pos, const typename Type::value_type &v)
{
@@ -188,9 +278,8 @@ namespace chaiscript
container.insert(itr, v);
}
/**
* Algorithm for erasing a specific position from a container
*/
/// Algorithm for erasing a specific position from a container
template<typename Type>
void erase_at(Type &container, int pos)
{
@@ -216,10 +305,9 @@ namespace chaiscript
return m;
}
/**
* Add random_access_container concept to the given ContainerType
* http://www.sgi.com/tech/stl/RandomAccessContainer.html
*/
/// 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()))
{
@@ -229,19 +317,18 @@ namespace chaiscript
//In the interest of runtime safety for the m, we prefer the at() method for [] access,
//to throw an exception in an out of bounds condition.
m->add(
fun(std::function<typename ContainerType::reference (ContainerType *, int)>
(std::mem_fn(static_cast<indexoper>(&ContainerType::at)))), "[]");
fun(boost::function<typename ContainerType::reference (ContainerType *, int)>
(boost::mem_fn(static_cast<indexoper>(&ContainerType::at)))), "[]");
m->add(
fun(std::function<typename ContainerType::const_reference (const ContainerType *, int)>
(std::mem_fn(static_cast<constindexoper>(&ContainerType::at)))), "[]");
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
*/
/// 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()))
{
@@ -250,23 +337,22 @@ namespace chaiscript
return m;
}
/**
* Add container concept to the given ContainerType
* http://www.sgi.com/tech/stl/Container.html
*/
/// Add container concept to the given ContainerType
/// http://www.sgi.com/tech/stl/Container.html
template<typename ContainerType>
ModulePtr container_type(const std::string &/*type*/, ModulePtr m = ModulePtr(new Module()))
{
m->add(fun( std::function<int (const ContainerType *)>( [](const ContainerType *a) { return a->size(); } ) ), "size");
m->add(fun( std::function<bool (const ContainerType *)>( [](const ContainerType *a) { return a->empty(); } ) ), "empty");
m->add(fun( std::function<void (ContainerType *)>( [](ContainerType *a) { a->clear(); } ) ), "clear");
boost::function<int (const ContainerType *)> f = detail::return_int(&ContainerType::size);
m->add(fun(f), "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
*/
/// 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()))
{
@@ -276,10 +362,9 @@ namespace chaiscript
/**
* Add sequence concept to the given ContainerType
* http://www.sgi.com/tech/stl/Sequence.html
*/
/// Add sequence concept to the given ContainerType
/// http://www.sgi.com/tech/stl/Sequence.html
template<typename ContainerType>
ModulePtr sequence_type(const std::string &/*type*/, ModulePtr m = ModulePtr(new Module()))
{
@@ -297,10 +382,9 @@ namespace chaiscript
return m;
}
/**
* Add back insertion sequence concept to the given ContainerType
* http://www.sgi.com/tech/stl/BackInsertionSequence.html
*/
/// Add back insertion sequence concept to the given ContainerType
/// http://www.sgi.com/tech/stl/BackInsertionSequence.html
template<typename ContainerType>
ModulePtr back_insertion_sequence_type(const std::string &/*type*/, ModulePtr m = ModulePtr(new Module()))
{
@@ -323,10 +407,9 @@ namespace chaiscript
}
/**
*Front insertion sequence
*http://www.sgi.com/tech/stl/FrontInsertionSequence.html
*/
/// Front insertion sequence
/// http://www.sgi.com/tech/stl/FrontInsertionSequence.html
template<typename ContainerType>
ModulePtr front_insertion_sequence_type(const std::string &, ModulePtr m = ModulePtr(new Module()))
{
@@ -349,10 +432,9 @@ namespace chaiscript
return m;
}
/**
* bootstrap a given PairType
* http://www.sgi.com/tech/stl/pair.html
*/
/// bootstrap a given PairType
/// http://www.sgi.com/tech/stl/pair.html
template<typename PairType>
ModulePtr pair_type(const std::string &type, ModulePtr m = ModulePtr(new Module()))
{
@@ -372,10 +454,10 @@ namespace chaiscript
}
/**
* Add pair associative container concept to the given ContainerType
* http://www.sgi.com/tech/stl/PairAssociativeContainer.html
*/
/// Add pair associative container concept to the given ContainerType
/// http://www.sgi.com/tech/stl/PairAssociativeContainer.html
template<typename ContainerType>
ModulePtr pair_associative_container_type(const std::string &type, ModulePtr m = ModulePtr(new Module()))
{
@@ -384,22 +466,37 @@ namespace chaiscript
return m;
}
/**
* Add unique associative container concept to the given ContainerType
* http://www.sgi.com/tech/stl/UniqueAssociativeContainer.html
*/
/// Add unique associative container concept to the given ContainerType
/// http://www.sgi.com/tech/stl/UniqueAssociativeContainer.html
template<typename ContainerType>
ModulePtr unique_associative_container_type(const std::string &/*type*/, ModulePtr m = ModulePtr(new Module()))
{
m->add(fun<int (const ContainerType *, const typename ContainerType::key_type &)>(&ContainerType::count), "count");
m->add(fun(boost::function<int (const ContainerType *, const typename ContainerType::key_type &)>(detail::return_int(&ContainerType::count))), "count");
typedef size_t (ContainerType::*erase)(const typename ContainerType::key_type &);
erase eraseptr(&ContainerType::erase);
m->add(fun(boost::function<int (ContainerType *, const typename ContainerType::key_type &)>(detail::return_int(eraseptr))), "erase");
m->add(fun(&detail::insert<ContainerType>), "insert");
std::string insert_name;
if (typeid(typename ContainerType::mapped_type) == typeid(Boxed_Value))
{
insert_name = "insert_ref";
} else {
insert_name = "insert";
}
m->add(fun(&detail::insert_ref<ContainerType>), insert_name);
return m;
}
/**
* Add a MapType container
* http://www.sgi.com/tech/stl/Map.html
*/
/// Add a MapType container
/// http://www.sgi.com/tech/stl/Map.html
template<typename MapType>
ModulePtr map_type(const std::string &type, ModulePtr m = ModulePtr(new Module()))
{
@@ -418,10 +515,9 @@ namespace chaiscript
return m;
}
/**
* hopefully working List type
* http://www.sgi.com/tech/stl/List.html
*/
/// hopefully working List type
/// http://www.sgi.com/tech/stl/List.html
template<typename ListType>
ModulePtr list_type(const std::string &type, ModulePtr m = ModulePtr(new Module()))
{
@@ -438,10 +534,9 @@ namespace chaiscript
return m;
}
/**
* Create a vector type with associated concepts
* http://www.sgi.com/tech/stl/Vector.html
*/
/// Create a vector type with associated concepts
/// http://www.sgi.com/tech/stl/Vector.html
template<typename VectorType>
ModulePtr vector_type(const std::string &type, ModulePtr m = ModulePtr(new Module()))
{
@@ -465,8 +560,8 @@ namespace chaiscript
if ( rhs.size() != this.size() ) { \
return false; \
} else { \
auto r1 = range(this); \
auto r2 = range(rhs); \
var r1 = range(this); \
var r2 = range(rhs); \
while (!r1.empty()) \
{ \
if (!eq(r1.front(), r2.front())) \
@@ -484,10 +579,34 @@ namespace chaiscript
return m;
}
/**
* Add a String container
* http://www.sgi.com/tech/stl/basic_string.html
*/
namespace detail {
template<typename String>
struct apple_string_workarounds
{
/// The latest version of MacOS has a broken std::string implementation which will not allow
/// us to take pointers to the members. Code compiles, but does not link
/// \todo re-evaluate at some point
static size_t find(const String *s, const String &w, int pos) { return s->find(w, pos); }
static size_t rfind(const String *s, const String &w, size_t pos) { return s->rfind(w, pos); }
static size_t find_first_of(const String *s, const String &w, size_t pos) { return s->find_first_of(w, pos); }
static size_t find_last_of(const String *s, const String &w, size_t pos) { return s->find_last_of(w, pos); }
static size_t find_first_not_of(const String *s, const String &w, size_t pos) { return s->find_first_not_of(w, pos); }
static size_t find_last_not_of(const String *s, const String &w, size_t pos) { return s->find_last_not_of(w, pos); }
static void clear(String *s) { s->clear(); }
static bool empty(const String *s) { return s->empty(); }
static size_t size(const String *s) { return s->size(); }
static std::string substr(const String *s, size_t pos, size_t len) { return s->substr(pos,len); }
static const char *c_str(const String *s) { return s->c_str(); }
static const char *data(const String *s) { return s->data(); }
};
}
/// Add a String container
/// http://www.sgi.com/tech/stl/basic_string.html
template<typename String>
ModulePtr string_type(const std::string &type, ModulePtr m = ModulePtr(new Module()))
{
@@ -498,7 +617,7 @@ namespace chaiscript
random_access_container_type<String>(type, m);
sequence_type<String>(type, m);
default_constructible_type<String>(type, m);
container_type<String>(type, m);
// container_type<String>(type, m);
assignable_type<String>(type, m);
input_range_type<String>(type, m);
@@ -512,17 +631,19 @@ namespace chaiscript
}
m->add(fun(&String::push_back), push_back_name);
typedef std::function<int (const String *, const String &, int)> find_func;
m->add(fun(find_func( [](const String *s, const String &f, int pos) { return s->find(f, pos); } )), "find");
m->add(fun(find_func( [](const String *s, const String &f, int pos) { return s->rfind(f, pos); } ) ), "rfind");
m->add(fun(find_func( [](const String *s, const String &f, int pos) { return s->find_first_of(f, pos); } ) ), "find_first_of");
m->add(fun(find_func( [](const String *s, const String &f, int pos) { return s->find_last_of(f, pos); } ) ), "find_last_of");
m->add(fun(find_func( [](const String *s, const String &f, int pos) { return s->find_last_not_of(f, pos); } ) ), "find_last_not_of");
m->add(fun(find_func( [](const String *s, const String &f, int pos) { return s->find_first_not_of(f, pos); } ) ), "find_first_not_of");
m->add(fun( std::function<const char *(const String *)>( [](const String *s) { return s->c_str(); } ) ), "c_str");
m->add(fun( std::function<const char *(const String *)>( [](const String *s) { return s->data(); } ) ), "data");
m->add(fun(&detail::apple_string_workarounds<String>::find), "find");
m->add(fun(&detail::apple_string_workarounds<String>::rfind), "rfind");
m->add(fun(&detail::apple_string_workarounds<String>::find_first_of), "find_first_of");
m->add(fun(&detail::apple_string_workarounds<String>::find_last_of), "find_last_of");
m->add(fun(&detail::apple_string_workarounds<String>::find_first_not_of), "find_first_not_of");
m->add(fun(&detail::apple_string_workarounds<String>::find_last_not_of), "find_last_not_of");
m->add(fun(&detail::apple_string_workarounds<String>::clear), "clear");
m->add(fun(&detail::apple_string_workarounds<String>::size), "size");
m->add(fun(&detail::apple_string_workarounds<String>::empty), "empty");
m->add(fun(&detail::apple_string_workarounds<String>::substr), "substr");
m->add(fun(&detail::apple_string_workarounds<String>::c_str), "c_str");
m->add(fun(&detail::apple_string_workarounds<String>::data), "data");
return m;

View File

@@ -1,20 +1,26 @@
// This file is distributed under the BSD License.
// See "license.txt" for details.
// Copyright 2009-2012, Jonathan Turner (jonathan@emptycrate.com)
// and Jason Turner (jason@emptycrate.com)
// Copyright 2009-2014, Jason Turner (jason@emptycrate.com)
// http://www.chaiscript.com
#ifndef CHAISCRIPT_BOXED_CAST_HPP_
#define CHAISCRIPT_BOXED_CAST_HPP_
#include "../chaiscript_defines.hpp"
#include "type_info.hpp"
#include "boxed_value.hpp"
#include "boxed_cast_helper.hpp"
#include "dynamic_cast_conversion.hpp"
#include "../chaiscript_threading.hpp"
#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
{
@@ -25,73 +31,79 @@ namespace chaiscript
/// \returns Type equivalent to the requested type
/// \throws exception::bad_boxed_cast If the requested conversion is not possible
///
/// boxed_cast will attempt to make conversions between value, &, *, std::shared_ptr, std::reference_wrapper,
/// and std::function (const and non-const) where possible. boxed_cast is used internally during function
/// 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 std::reference_wrapper can be extracted as reference,
/// \li Boxed_Value constructed from pointer or boost::reference_wrapper can be extracted as reference,
/// pointer or value types
/// \li Boxed_Value constructed from std::shared_ptr or value types can be extracted as reference,
/// pointer, value, or std::shared_ptr types
/// \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 std::function objects are attempted as well
/// Conversions to boost::function objects are attempted as well
///
/// Example:
/// \code
/// // All of the following should succeed
/// chaiscript::Boxed_Value bv(1);
/// std::shared_ptr<int> spi = chaiscript::boxed_cast<std::shared_ptr<int> >(bv);
/// 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);
/// std::shared_ptr<const int> cspi = chaiscript::boxed_cast<std::shared_ptr<const 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
///
/// std::function conversion example
/// boost::function conversion example
/// \code
/// chaiscript::ChaiScript chai;
/// Boxed_Value bv = chai.eval("`+`"); // Get the functor for the + operator which is built in
/// std::function<int (int, int)> f = chaiscript::boxed_cast<std::function<int (int, int)> >(bv);
/// 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)
typename detail::Cast_Helper<Type>::Result_Type boxed_cast(const Boxed_Value &bv, const Dynamic_Cast_Conversions *t_conversions = 0)
{
try {
return detail::Cast_Helper<Type>::cast(bv);
} catch (const chaiscript::detail::exception::bad_any_cast &) {
return detail::Cast_Helper<Type>::cast(bv, t_conversions);
} catch (const boost::bad_any_cast &) {
#ifdef CHAISCRIPT_MSVC
#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 (std::is_polymorphic<typename detail::Stripped_Type<Type>::type>::value)
if (boost::is_polymorphic<typename detail::Stripped_Type<Type>::type>::value && t_conversions)
{
try {
// std::cout << "trying an up conversion " << typeid(Type).name() << std::endl;
// We will not catch any bad_boxed_dynamic_cast that is thrown, let the user get it
// either way, we are not responsible if it doesn't work
return detail::Cast_Helper<Type>::cast(detail::boxed_dynamic_cast<Type>(bv));
} catch (const chaiscript::detail::exception::bad_any_cast &) {
return detail::Cast_Helper<Type>::cast(t_conversions->boxed_dynamic_cast<Type>(bv), t_conversions);
} catch (...) {
try {
// std::cout << "trying a down conversion " << typeid(Type).name() << std::endl;
// try going the other way - down the inheritance graph
return detail::Cast_Helper<Type>::cast(t_conversions->boxed_dynamic_down_cast<Type>(bv), t_conversions);
} 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 CHAISCRIPT_MSVC
#ifdef BOOST_MSVC
#pragma warning(pop)
#endif

View File

@@ -1,7 +1,7 @@
// This file is distributed under the BSD License.
// See "license.txt" for details.
// Copyright 2009-2012, Jonathan Turner (jonathan@emptycrate.com)
// and Jason Turner (jason@emptycrate.com)
// Copyright 2009-2014, Jason Turner (jason@emptycrate.com)
// http://www.chaiscript.com
#ifndef CHAISCRIPT_BOXED_CAST_HELPER_HPP_
@@ -10,9 +10,15 @@
#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
{
class Dynamic_Cast_Conversions;
namespace detail
{
// Cast_Helper_Inner helper classes
@@ -23,24 +29,24 @@ namespace chaiscript
template<typename Result>
struct Cast_Helper_Inner
{
typedef typename std::reference_wrapper<typename std::add_const<Result>::type > Result_Type;
typedef typename boost::reference_wrapper<typename boost::add_const<Result>::type > Result_Type;
static Result_Type cast(const Boxed_Value &ob)
static Result_Type cast(const Boxed_Value &ob, const Dynamic_Cast_Conversions *)
{
if (ob.is_ref())
{
if (!ob.get_type_info().is_const())
{
return std::cref((ob.get().cast<std::reference_wrapper<Result> >()).get());
return boost::cref((boost::any_cast<boost::reference_wrapper<Result> >(ob.get())).get());
} else {
return ob.get().cast<std::reference_wrapper<const Result> >();
return boost::any_cast<boost::reference_wrapper<const Result> >(ob.get());
}
} else {
if (!ob.get_type_info().is_const())
{
return std::cref(*(ob.get().cast<std::shared_ptr<Result> >()));
return boost::cref(*(boost::any_cast<boost::shared_ptr<Result> >(ob.get())));
} else {
return std::cref(*(ob.get().cast<std::shared_ptr<const Result> >()));
return boost::cref(*(boost::any_cast<boost::shared_ptr<const Result> >(ob.get())));
}
}
}
@@ -67,22 +73,22 @@ namespace chaiscript
{
typedef const Result * Result_Type;
static Result_Type cast(const Boxed_Value &ob)
static Result_Type cast(const Boxed_Value &ob, const Dynamic_Cast_Conversions *)
{
if (ob.is_ref())
{
if (!ob.get_type_info().is_const())
{
return &(ob.get().cast<std::reference_wrapper<Result> >()).get();
return (boost::any_cast<boost::reference_wrapper<Result> >(ob.get())).get_pointer();
} else {
return &(ob.get().cast<std::reference_wrapper<const Result> >()).get();
return (boost::any_cast<boost::reference_wrapper<const Result> >(ob.get())).get_pointer();
}
} else {
if (!ob.get_type_info().is_const())
{
return (ob.get().cast<std::shared_ptr<Result> >()).get();
return (boost::any_cast<boost::shared_ptr<Result> >(ob.get())).get();
} else {
return (ob.get().cast<std::shared_ptr<const Result> >()).get();
return (boost::any_cast<boost::shared_ptr<const Result> >(ob.get())).get();
}
}
}
@@ -96,13 +102,13 @@ namespace chaiscript
{
typedef Result * Result_Type;
static Result_Type cast(const Boxed_Value &ob)
static Result_Type cast(const Boxed_Value &ob, const Dynamic_Cast_Conversions *)
{
if (ob.is_ref())
{
return &(ob.get().cast<std::reference_wrapper<Result> >()).get();
return (boost::any_cast<boost::reference_wrapper<Result> >(ob.get())).get_pointer();
} else {
return (ob.get().cast<std::shared_ptr<Result> >()).get();
return (boost::any_cast<boost::shared_ptr<Result> >(ob.get())).get();
}
}
};
@@ -113,77 +119,76 @@ namespace chaiscript
template<typename Result>
struct Cast_Helper_Inner<Result &>
{
typedef Result& Result_Type;
typedef typename boost::reference_wrapper<Result> Result_Type;
static Result &cast(const Boxed_Value &ob)
static Result_Type cast(const Boxed_Value &ob, const Dynamic_Cast_Conversions *)
{
if (ob.is_ref())
{
return ob.get().cast<std::reference_wrapper<Result> >();
return boost::any_cast<boost::reference_wrapper<Result> >(ob.get());
} else {
Result &r = *(ob.get().cast<std::shared_ptr<Result> >());
return r;
return boost::ref(*(boost::any_cast<boost::shared_ptr<Result> >(ob.get())));
}
}
};
/**
* Cast_Helper_Inner for casting to a std::shared_ptr<> type
* Cast_Helper_Inner for casting to a boost::shared_ptr<> type
*/
template<typename Result>
struct Cast_Helper_Inner<typename std::shared_ptr<Result> >
struct Cast_Helper_Inner<typename boost::shared_ptr<Result> >
{
typedef typename std::shared_ptr<Result> Result_Type;
typedef typename boost::shared_ptr<Result> Result_Type;
static Result_Type cast(const Boxed_Value &ob)
static Result_Type cast(const Boxed_Value &ob, const Dynamic_Cast_Conversions *)
{
return ob.get().cast<std::shared_ptr<Result> >();
return boost::any_cast<boost::shared_ptr<Result> >(ob.get());
}
};
/**
* Cast_Helper_Inner for casting to a std::shared_ptr<const> type
* Cast_Helper_Inner for casting to a boost::shared_ptr<const> type
*/
template<typename Result>
struct Cast_Helper_Inner<typename std::shared_ptr<const Result> >
struct Cast_Helper_Inner<typename boost::shared_ptr<const Result> >
{
typedef typename std::shared_ptr<const Result> Result_Type;
typedef typename boost::shared_ptr<const Result> Result_Type;
static Result_Type cast(const Boxed_Value &ob)
static Result_Type cast(const Boxed_Value &ob, const Dynamic_Cast_Conversions *)
{
if (!ob.get_type_info().is_const())
{
return std::const_pointer_cast<const Result>(ob.get().cast<std::shared_ptr<Result> >());
return boost::const_pointer_cast<const Result>(boost::any_cast<boost::shared_ptr<Result> >(ob.get()));
} else {
return ob.get().cast<std::shared_ptr<const Result> >();
return boost::any_cast<boost::shared_ptr<const Result> >(ob.get());
}
}
};
/**
* Cast_Helper_Inner for casting to a const std::shared_ptr<> & type
* Cast_Helper_Inner for casting to a const boost::shared_ptr<> & type
*/
template<typename Result>
struct Cast_Helper_Inner<const std::shared_ptr<Result> > : Cast_Helper_Inner<std::shared_ptr<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 std::shared_ptr<Result> &> : Cast_Helper_Inner<std::shared_ptr<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 std::shared_ptr<const> & type
* Cast_Helper_Inner for casting to a const boost::shared_ptr<const> & type
*/
template<typename Result>
struct Cast_Helper_Inner<const std::shared_ptr<const Result> > : Cast_Helper_Inner<std::shared_ptr<const Result> >
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 std::shared_ptr<const Result> &> : Cast_Helper_Inner<std::shared_ptr<const Result> >
struct Cast_Helper_Inner<const boost::shared_ptr<const Result> &> : Cast_Helper_Inner<boost::shared_ptr<const Result> >
{
};
@@ -197,7 +202,7 @@ namespace chaiscript
{
typedef const Boxed_Value & Result_Type;
static Result_Type cast(const Boxed_Value &ob)
static Result_Type cast(const Boxed_Value &ob, const Dynamic_Cast_Conversions *)
{
return ob;
}
@@ -218,35 +223,35 @@ namespace chaiscript
/**
* Cast_Helper_Inner for casting to a std::reference_wrapper type
* Cast_Helper_Inner for casting to a boost::reference_wrapper type
*/
template<typename Result>
struct Cast_Helper_Inner<std::reference_wrapper<Result> > : Cast_Helper_Inner<Result &>
struct Cast_Helper_Inner<boost::reference_wrapper<Result> > : Cast_Helper_Inner<Result &>
{
};
template<typename Result>
struct Cast_Helper_Inner<const std::reference_wrapper<Result> > : Cast_Helper_Inner<Result &>
struct Cast_Helper_Inner<const boost::reference_wrapper<Result> > : Cast_Helper_Inner<Result &>
{
};
template<typename Result>
struct Cast_Helper_Inner<const std::reference_wrapper<Result> &> : Cast_Helper_Inner<Result &>
struct Cast_Helper_Inner<const boost::reference_wrapper<Result> &> : Cast_Helper_Inner<Result &>
{
};
template<typename Result>
struct Cast_Helper_Inner<std::reference_wrapper<const Result> > : Cast_Helper_Inner<const Result &>
struct Cast_Helper_Inner<boost::reference_wrapper<const Result> > : Cast_Helper_Inner<const Result &>
{
};
template<typename Result>
struct Cast_Helper_Inner<const std::reference_wrapper<const Result> > : Cast_Helper_Inner<const Result &>
struct Cast_Helper_Inner<const boost::reference_wrapper<const Result> > : Cast_Helper_Inner<const Result &>
{
};
template<typename Result>
struct Cast_Helper_Inner<const std::reference_wrapper<const Result> & > : Cast_Helper_Inner<const Result &>
struct Cast_Helper_Inner<const boost::reference_wrapper<const Result> & > : Cast_Helper_Inner<const Result &>
{
};
@@ -258,9 +263,9 @@ namespace chaiscript
{
typedef typename Cast_Helper_Inner<T>::Result_Type Result_Type;
static Result_Type cast(const Boxed_Value &ob)
static Result_Type cast(const Boxed_Value &ob, const Dynamic_Cast_Conversions *t_conversions)
{
return Cast_Helper_Inner<T>::cast(ob);
return Cast_Helper_Inner<T>::cast(ob, t_conversions);
}
};
}

View File

@@ -1,7 +1,7 @@
// This file is distributed under the BSD License.
// See "license.txt" for details.
// Copyright 2009-2012, Jonathan Turner (jonathan@emptycrate.com)
// and Jason Turner (jason@emptycrate.com)
// Copyright 2009-2014, Jason Turner (jason@emptycrate.com)
// http://www.chaiscript.com
#ifndef CHAISCRIPT_BOXED_NUMERIC_HPP_
@@ -9,6 +9,8 @@
#include "boxed_value.hpp"
#include "../language/chaiscript_algebraic.hpp"
#include <boost/cstdint.hpp>
#include <sstream>
namespace chaiscript
{
@@ -46,9 +48,8 @@ namespace chaiscript
case Operators::not_equal:
return const_var(t != u);
default:
throw chaiscript::detail::exception::bad_any_cast();
throw boost::bad_any_cast();
}
throw chaiscript::detail::exception::bad_any_cast();
}
};
@@ -81,7 +82,7 @@ namespace chaiscript
t -= u;
break;
default:
throw chaiscript::detail::exception::bad_any_cast();
throw boost::bad_any_cast();
}
return t_lhs;
@@ -114,7 +115,7 @@ namespace chaiscript
t ^= u;
break;
default:
throw chaiscript::detail::exception::bad_any_cast();
throw boost::bad_any_cast();
}
return t_lhs;
}
@@ -142,9 +143,8 @@ namespace chaiscript
case Operators::bitwise_complement:
return const_var(~t);
default:
throw chaiscript::detail::exception::bad_any_cast();
throw boost::bad_any_cast();
}
throw chaiscript::detail::exception::bad_any_cast();
}
};
@@ -168,9 +168,8 @@ namespace chaiscript
case Operators::unary_plus:
return const_var(+t);
default:
throw chaiscript::detail::exception::bad_any_cast();
throw boost::bad_any_cast();
}
throw chaiscript::detail::exception::bad_any_cast();
}
};
@@ -191,7 +190,7 @@ namespace chaiscript
} else if (t_oper > Operators::const_flag) {
return const_binary::go<LHS, RHS>(t_oper, *static_cast<const LHS *>(t_lhs.get_const_ptr()), *static_cast<const RHS *>(t_rhs.get_const_ptr()), t_lhs);
} else {
throw chaiscript::detail::exception::bad_any_cast();
throw boost::bad_any_cast();
}
}
};
@@ -207,13 +206,13 @@ namespace chaiscript
} else if (t_oper > Operators::non_const_flag && t_oper < Operators::non_const_int_flag && !t_lhs.is_const()) {
return binary::go<LHS, RHS>(t_oper, *static_cast<LHS *>(t_lhs.get_ptr()), *static_cast<const RHS *>(t_rhs.get_const_ptr()), t_lhs);
} else if (t_oper > Operators::non_const_int_flag && t_oper < Operators::const_int_flag) {
throw chaiscript::detail::exception::bad_any_cast();
throw boost::bad_any_cast();
} else if (t_oper > Operators::const_int_flag && t_oper < Operators::const_flag) {
throw chaiscript::detail::exception::bad_any_cast();
throw boost::bad_any_cast();
} else if (t_oper > Operators::const_flag) {
return const_binary::go<LHS, RHS>(t_oper, *static_cast<const LHS *>(t_lhs.get_const_ptr()), *static_cast<const RHS *>(t_rhs.get_const_ptr()), t_lhs);
} else {
throw chaiscript::detail::exception::bad_any_cast();
throw boost::bad_any_cast();
}
}
};
@@ -239,24 +238,24 @@ namespace chaiscript
return Go<LHS, long, Float>::go(t_oper, t_lhs, t_rhs);
} else if (inp_ == typeid(unsigned long)) {
return Go<LHS, unsigned long, Float>::go(t_oper, t_lhs, t_rhs);
} else if (inp_ == typeid(std::int8_t)) {
return Go<LHS, std::int8_t, Float>::go(t_oper, t_lhs, t_rhs);
} else if (inp_ == typeid(std::int16_t)) {
return Go<LHS, std::int16_t, Float>::go(t_oper, t_lhs, t_rhs);
} else if (inp_ == typeid(std::int32_t)) {
return Go<LHS, std::int32_t, Float>::go(t_oper, t_lhs, t_rhs);
} else if (inp_ == typeid(std::int64_t)) {
return Go<LHS, std::int64_t, Float>::go(t_oper, t_lhs, t_rhs);
} else if (inp_ == typeid(std::uint8_t)) {
return Go<LHS, std::uint8_t, Float>::go(t_oper, t_lhs, t_rhs);
} else if (inp_ == typeid(std::uint16_t)) {
return Go<LHS, std::uint16_t, Float>::go(t_oper, t_lhs, t_rhs);
} else if (inp_ == typeid(std::uint32_t)) {
return Go<LHS, std::uint32_t, Float>::go(t_oper, t_lhs, t_rhs);
} else if (inp_ == typeid(std::uint64_t)) {
return Go<LHS, std::uint64_t, Float>::go(t_oper, t_lhs, t_rhs);
} else if (inp_ == typeid(boost::int8_t)) {
return Go<LHS, boost::int8_t, Float>::go(t_oper, t_lhs, t_rhs);
} else if (inp_ == typeid(boost::int16_t)) {
return Go<LHS, boost::int16_t, Float>::go(t_oper, t_lhs, t_rhs);
} else if (inp_ == typeid(boost::int32_t)) {
return Go<LHS, boost::int32_t, Float>::go(t_oper, t_lhs, t_rhs);
} else if (inp_ == typeid(boost::int64_t)) {
return Go<LHS, boost::int64_t, Float>::go(t_oper, t_lhs, t_rhs);
} else if (inp_ == typeid(boost::uint8_t)) {
return Go<LHS, boost::uint8_t, Float>::go(t_oper, t_lhs, t_rhs);
} else if (inp_ == typeid(boost::uint16_t)) {
return Go<LHS, boost::uint16_t, Float>::go(t_oper, t_lhs, t_rhs);
} else if (inp_ == typeid(boost::uint32_t)) {
return Go<LHS, boost::uint32_t, Float>::go(t_oper, t_lhs, t_rhs);
} else if (inp_ == typeid(boost::uint64_t)) {
return Go<LHS, boost::uint64_t, Float>::go(t_oper, t_lhs, t_rhs);
} else {
throw chaiscript::detail::exception::bad_any_cast();
throw boost::bad_any_cast();
}
}
@@ -280,27 +279,40 @@ namespace chaiscript
return oper_rhs<long, false>(t_oper, t_lhs, t_rhs);
} else if (inp_ == typeid(unsigned long)) {
return oper_rhs<unsigned long, false>(t_oper, t_lhs, t_rhs);
} else if (inp_ == typeid(std::int8_t)) {
return oper_rhs<std::int8_t, false>(t_oper, t_lhs, t_rhs);
} else if (inp_ == typeid(std::int16_t)) {
return oper_rhs<std::int16_t, false>(t_oper, t_lhs, t_rhs);
} else if (inp_ == typeid(std::int32_t)) {
return oper_rhs<std::int32_t, false>(t_oper, t_lhs, t_rhs);
} else if (inp_ == typeid(std::int64_t)) {
return oper_rhs<std::int64_t, false>(t_oper, t_lhs, t_rhs);
} else if (inp_ == typeid(std::uint8_t)) {
return oper_rhs<std::uint8_t, false>(t_oper, t_lhs, t_rhs);
} else if (inp_ == typeid(std::uint16_t)) {
return oper_rhs<std::uint16_t, false>(t_oper, t_lhs, t_rhs);
} else if (inp_ == typeid(std::uint32_t)) {
return oper_rhs<std::uint32_t, false>(t_oper, t_lhs, t_rhs);
} else if (inp_ == typeid(std::uint64_t)) {
return oper_rhs<std::uint64_t, false>(t_oper, t_lhs, t_rhs);
} else if (inp_ == typeid(boost::int8_t)) {
return oper_rhs<boost::int8_t, false>(t_oper, t_lhs, t_rhs);
} else if (inp_ == typeid(boost::int16_t)) {
return oper_rhs<boost::int16_t, false>(t_oper, t_lhs, t_rhs);
} else if (inp_ == typeid(boost::int32_t)) {
return oper_rhs<boost::int32_t, false>(t_oper, t_lhs, t_rhs);
} else if (inp_ == typeid(boost::int64_t)) {
return oper_rhs<boost::int64_t, false>(t_oper, t_lhs, t_rhs);
} else if (inp_ == typeid(boost::uint8_t)) {
return oper_rhs<boost::uint8_t, false>(t_oper, t_lhs, t_rhs);
} else if (inp_ == typeid(boost::uint16_t)) {
return oper_rhs<boost::uint16_t, false>(t_oper, t_lhs, t_rhs);
} else if (inp_ == typeid(boost::uint32_t)) {
return oper_rhs<boost::uint32_t, false>(t_oper, t_lhs, t_rhs);
} else if (inp_ == typeid(boost::uint64_t)) {
return oper_rhs<boost::uint64_t, false>(t_oper, t_lhs, t_rhs);
} else {
throw chaiscript::detail::exception::bad_any_cast();
throw boost::bad_any_cast();
}
}
template<typename Target, typename Source>
Target get_as_aux() const
{
return static_cast<Target>(*static_cast<const Source *>(bv.get_const_ptr()));
}
template<typename Source>
static std::string to_string_aux(const Boxed_Value &v)
{
std::ostringstream oss;
oss << *static_cast<const Source *>(v.get_const_ptr());
return oss.str();
}
public:
@@ -315,6 +327,133 @@ namespace chaiscript
validate_boxed_number(v);
}
template<typename T> explicit Boxed_Number(T t)
: bv(Boxed_Value(t))
{
validate_boxed_number(bv);
}
Boxed_Number get_as(const Type_Info &inp_) const
{
if (inp_.bare_equal_type_info(typeid(int))) {
return Boxed_Number(get_as<int>());
} else if (inp_.bare_equal_type_info(typeid(double))) {
return Boxed_Number(get_as<double>());
} else if (inp_.bare_equal_type_info(typeid(float))) {
return Boxed_Number(get_as<float>());
} else if (inp_.bare_equal_type_info(typeid(long double))) {
return Boxed_Number(get_as<long double>());
} else if (inp_.bare_equal_type_info(typeid(char))) {
return Boxed_Number(get_as<char>());
} else if (inp_.bare_equal_type_info(typeid(unsigned int))) {
return Boxed_Number(get_as<unsigned int>());
} else if (inp_.bare_equal_type_info(typeid(long))) {
return Boxed_Number(get_as<long>());
} else if (inp_.bare_equal_type_info(typeid(unsigned long))) {
return Boxed_Number(get_as<unsigned long>());
} else if (inp_.bare_equal_type_info(typeid(boost::int8_t))) {
return Boxed_Number(get_as<boost::int8_t>());
} else if (inp_.bare_equal_type_info(typeid(boost::int16_t))) {
return Boxed_Number(get_as<boost::int16_t>());
} else if (inp_.bare_equal_type_info(typeid(boost::int32_t))) {
return Boxed_Number(get_as<boost::int32_t>());
} else if (inp_.bare_equal_type_info(typeid(boost::int64_t))) {
return Boxed_Number(get_as<boost::int64_t>());
} else if (inp_.bare_equal_type_info(typeid(boost::uint8_t))) {
return Boxed_Number(get_as<boost::uint8_t>());
} else if (inp_.bare_equal_type_info(typeid(boost::uint16_t))) {
return Boxed_Number(get_as<boost::uint16_t>());
} else if (inp_.bare_equal_type_info(typeid(boost::uint32_t))) {
return Boxed_Number(get_as<boost::uint32_t>());
} else if (inp_.bare_equal_type_info(typeid(boost::uint64_t))) {
return Boxed_Number(get_as<boost::uint64_t>());
} else {
throw boost::bad_any_cast();
}
}
template<typename Target> Target get_as() const
{
const Type_Info &inp_ = bv.get_type_info();
if (inp_ == typeid(int)) {
return get_as_aux<Target, int>();
} else if (inp_ == typeid(double)) {
return get_as_aux<Target, double>();
} else if (inp_ == typeid(float)) {
return get_as_aux<Target, float>();
} else if (inp_ == typeid(long double)) {
return get_as_aux<Target, long double>();
} else if (inp_ == typeid(char)) {
return get_as_aux<Target, char>();
} else if (inp_ == typeid(unsigned int)) {
return get_as_aux<Target, unsigned int>();
} else if (inp_ == typeid(long)) {
return get_as_aux<Target, long>();
} else if (inp_ == typeid(unsigned long)) {
return get_as_aux<Target, unsigned long>();
} else if (inp_ == typeid(boost::int8_t)) {
return get_as_aux<Target, boost::int8_t>();
} else if (inp_ == typeid(boost::int16_t)) {
return get_as_aux<Target, boost::int16_t>();
} else if (inp_ == typeid(boost::int32_t)) {
return get_as_aux<Target, boost::int32_t>();
} else if (inp_ == typeid(boost::int64_t)) {
return get_as_aux<Target, boost::int64_t>();
} else if (inp_ == typeid(boost::uint8_t)) {
return get_as_aux<Target, boost::uint8_t>();
} else if (inp_ == typeid(boost::uint16_t)) {
return get_as_aux<Target, boost::uint16_t>();
} else if (inp_ == typeid(boost::uint32_t)) {
return get_as_aux<Target, boost::uint32_t>();
} else if (inp_ == typeid(boost::uint64_t)) {
return get_as_aux<Target, boost::uint64_t>();
} else {
throw boost::bad_any_cast();
}
}
std::string to_string() const
{
const Type_Info &inp_ = bv.get_type_info();
if (inp_ == typeid(int)) {
return to_string_aux<int>(bv);
} else if (inp_ == typeid(double)) {
return to_string_aux<double>(bv);
} else if (inp_ == typeid(float)) {
return to_string_aux<float>(bv);
} else if (inp_ == typeid(long double)) {
return to_string_aux<long double>(bv);
} else if (inp_ == typeid(char)) {
return to_string_aux<int>(Boxed_Value(get_as_aux<int, char>()));
} else if (inp_ == typeid(unsigned int)) {
return to_string_aux<unsigned int>(bv);
} else if (inp_ == typeid(long)) {
return to_string_aux<long>(bv);
} else if (inp_ == typeid(unsigned long)) {
return to_string_aux<unsigned long>(bv);
} else if (inp_ == typeid(boost::int8_t)) {
return to_string_aux<int>(Boxed_Value(get_as_aux<int, boost::int8_t>()));
} else if (inp_ == typeid(boost::int16_t)) {
return to_string_aux<boost::int16_t>(bv);
} else if (inp_ == typeid(boost::int32_t)) {
return to_string_aux<boost::int32_t>(bv);
} else if (inp_ == typeid(boost::int64_t)) {
return to_string_aux<boost::int64_t>(bv);
} else if (inp_ == typeid(boost::uint8_t)) {
return to_string_aux<unsigned int>(Boxed_Value(get_as_aux<unsigned int, boost::uint8_t>()));
} else if (inp_ == typeid(boost::uint16_t)) {
return to_string_aux<boost::uint16_t>(bv);
} else if (inp_ == typeid(boost::uint32_t)) {
return to_string_aux<boost::uint32_t>(bv);
} else if (inp_ == typeid(boost::uint64_t)) {
return to_string_aux<boost::uint64_t>(bv);
} else {
throw boost::bad_any_cast();
}
}
bool operator==(const Boxed_Number &t_rhs) const
{
@@ -381,17 +520,17 @@ namespace chaiscript
return oper(Operators::assign_bitwise_and, this->bv, t_rhs.bv);
}
void validate_boxed_number(const Boxed_Value &v)
static void validate_boxed_number(const Boxed_Value &v)
{
const Type_Info &inp_ = v.get_type_info();
if (inp_ == typeid(bool))
{
throw chaiscript::detail::exception::bad_any_cast();
throw boost::bad_any_cast();
}
if (!inp_.is_arithmetic())
{
throw chaiscript::detail::exception::bad_any_cast();
throw boost::bad_any_cast();
}
}
@@ -682,7 +821,7 @@ namespace chaiscript
{
typedef Boxed_Number Result_Type;
static Result_Type cast(const Boxed_Value &ob)
static Result_Type cast(const Boxed_Value &ob, const Dynamic_Cast_Conversions *)
{
return Boxed_Number(ob);
}

View File

@@ -1,7 +1,7 @@
// This file is distributed under the BSD License.
// See "license.txt" for details.
// Copyright 2009-2012, Jonathan Turner (jonathan@emptycrate.com)
// and Jason Turner (jason@emptycrate.com)
// Copyright 2009-2014, Jason Turner (jason@emptycrate.com)
// http://www.chaiscript.com
#ifndef CHAISCRIPT_BOXED_VALUE_HPP_
@@ -12,7 +12,27 @@
#include "../chaiscript_threading.hpp"
#include <map>
#include "any.hpp"
#include <boost/shared_ptr.hpp>
#ifdef __llvm__
#pragma clang diagnostic push
#pragma clang diagnostic ignored "-Wshadow"
#pragma clang diagnostic ignored "-Wunused-parameter"
#endif
#include <boost/make_shared.hpp>
#ifdef __llvm__
#pragma clang diagnostic pop
#endif
#include <boost/any.hpp>
#include <boost/function.hpp>
#include <boost/ref.hpp>
#include <boost/bind.hpp>
#include <boost/cstdint.hpp>
#include <boost/type_traits/add_const.hpp>
#include <boost/integer_traits.hpp>
namespace chaiscript
{
@@ -36,7 +56,7 @@ namespace chaiscript
struct Data
{
Data(const Type_Info &ti,
const chaiscript::detail::Any &to,
const boost::any &to,
bool tr,
const void *t_void_ptr)
: m_type_info(ti), m_obj(to), m_data_ptr(ti.is_const()?0:const_cast<void *>(t_void_ptr)), m_const_data_ptr(t_void_ptr),
@@ -60,7 +80,7 @@ namespace chaiscript
}
Type_Info m_type_info;
chaiscript::detail::Any m_obj;
boost::any m_obj;
void *m_data_ptr;
const void *m_const_data_ptr;
bool m_is_ref;
@@ -68,70 +88,65 @@ namespace chaiscript
struct Object_Data
{
static std::shared_ptr<Data> get(Boxed_Value::Void_Type)
static boost::shared_ptr<Data> get(Boxed_Value::Void_Type)
{
return std::make_shared<Data>(
return boost::make_shared<Data>(
detail::Get_Type_Info<void>::get(),
chaiscript::detail::Any(),
boost::any(),
false,
nullptr)
;
static_cast<void *>(0));
}
template<typename T>
static std::shared_ptr<Data> get(const std::shared_ptr<T> *obj)
static boost::shared_ptr<Data> get(const boost::shared_ptr<T> *obj)
{
return get(*obj);
}
template<typename T>
static std::shared_ptr<Data> get(const std::shared_ptr<T> &obj)
static boost::shared_ptr<Data> get(const boost::shared_ptr<T> &obj)
{
return std::make_shared<Data>(
return boost::make_shared<Data>(
detail::Get_Type_Info<T>::get(),
chaiscript::detail::Any(obj),
boost::any(obj),
false,
obj.get()
);
obj.get());
}
template<typename T>
static std::shared_ptr<Data> get(T *t)
static boost::shared_ptr<Data> get(T *t)
{
return get(std::ref(*t));
return get(boost::ref(*t));
}
template<typename T>
static std::shared_ptr<Data> get(std::reference_wrapper<T> obj)
static boost::shared_ptr<Data> get(boost::reference_wrapper<T> obj)
{
return std::make_shared<Data>(
return boost::make_shared<Data>(
detail::Get_Type_Info<T>::get(),
chaiscript::detail::Any(obj),
boost::any(obj),
true,
&obj.get()
);
obj.get_pointer());
}
template<typename T>
static std::shared_ptr<Data> get(const T& t)
static boost::shared_ptr<Data> get(const T& t)
{
auto p = std::make_shared<T>(t);
return std::make_shared<Data>(
boost::shared_ptr<T> p(new T(t));
return boost::make_shared<Data>(
detail::Get_Type_Info<T>::get(),
chaiscript::detail::Any(p),
boost::any(p),
false,
p.get()
);
p.get());
}
static std::shared_ptr<Data> get()
static boost::shared_ptr<Data> get()
{
return std::make_shared<Data>(
return boost::make_shared<Data>(
Type_Info(),
chaiscript::detail::Any(),
boost::any(),
false,
nullptr
);
static_cast<void *>(0));
}
};
@@ -219,7 +234,7 @@ namespace chaiscript
return (m_data->m_data_ptr == 0 && m_data->m_const_data_ptr == 0);
}
const chaiscript::detail::Any & get() const
const boost::any & get() const
{
return m_data->m_obj;
}
@@ -244,17 +259,11 @@ namespace chaiscript
return m_data->m_const_data_ptr;
}
/// \returns true if the two Boxed_Values share the same internal type
static bool type_match(Boxed_Value l, Boxed_Value r)
{
return l.get_type_info() == r.get_type_info();
}
private:
std::shared_ptr<Data> m_data;
boost::shared_ptr<Data> m_data;
};
/// \brief Creates a Boxed_Value. If the object passed in is a value type, it is copied. If it is a pointer, std::shared_ptr, or std::reference_type
/// \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
///
@@ -281,7 +290,7 @@ namespace chaiscript
template<typename T>
Boxed_Value const_var_impl(const T &t)
{
return Boxed_Value(std::shared_ptr<typename std::add_const<T>::type >(new T(t)));
return Boxed_Value(boost::shared_ptr<typename boost::add_const<T>::type >(new T(t)));
}
/// \brief Takes a pointer to a value, adds const to the pointed to type and returns an immutable Boxed_Value.
@@ -292,33 +301,33 @@ namespace chaiscript
template<typename T>
Boxed_Value const_var_impl(T *t)
{
return Boxed_Value( const_cast<typename std::add_const<T>::type *>(t) );
return Boxed_Value( const_cast<typename boost::add_const<T>::type *>(t) );
}
/// \brief Takes a std::shared_ptr to a value, adds const to the pointed to type and returns an immutable Boxed_Value.
/// \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 std::shared_ptr<T> &t)
Boxed_Value const_var_impl(const boost::shared_ptr<T> &t)
{
return Boxed_Value( std::const_pointer_cast<typename std::add_const<T>::type>(t) );
return Boxed_Value( boost::const_pointer_cast<typename boost::add_const<T>::type>(t) );
}
/// \brief Takes a std::reference_wrapper value, adds const to the referenced type and returns an immutable Boxed_Value.
/// \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 std::reference_wrapper<T> &t)
Boxed_Value const_var_impl(const boost::reference_wrapper<T> &t)
{
return Boxed_Value( std::cref(t.get()) );
return Boxed_Value( boost::cref(t.get()) );
}
}
/// \brief Takes an object and returns an immutable Boxed_Value. If the object is a std::reference or pointer type
/// \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
@@ -348,6 +357,11 @@ namespace chaiscript
/// \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();
}
}
#endif

View File

@@ -1,7 +1,7 @@
// This file is distributed under the BSD License.
// See "license.txt" for details.
// Copyright 2009-2012, Jonathan Turner (jonathan@emptycrate.com)
// and Jason Turner (jason@emptycrate.com)
// Copyright 2009-2014, Jason Turner (jason@emptycrate.com)
// http://www.chaiscript.com
#ifndef CHAISCRIPT_DISPATCHKIT_HPP_
@@ -11,12 +11,12 @@
#include <string>
#include <map>
#include <set>
#include <boost/shared_ptr.hpp>
#include <stdexcept>
#include <vector>
#include <iostream>
#include <deque>
#include <list>
#include <algorithm>
#include "boxed_value.hpp"
#include "type_info.hpp"
@@ -39,12 +39,12 @@ namespace chaiscript
class reserved_word_error : public std::runtime_error
{
public:
reserved_word_error(const std::string &t_word) noexcept
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() noexcept {}
virtual ~reserved_word_error() throw() {}
std::string word() const
{
@@ -53,9 +53,31 @@ namespace chaiscript
private:
std::string m_word;
};
/**
* Exception thrown in the case that an object name is invalid because it contains illegal characters
*/
class illegal_name_error : public std::runtime_error
{
public:
illegal_name_error(const std::string &t_name) throw()
: std::runtime_error("Reserved name not allowed in object name: " + t_name), m_name(t_name)
{
}
virtual ~illegal_name_error() throw() {}
std::string name() const
{
return m_name;
}
private:
std::string m_name;
};
/**
* Exception thrown in the case that an object name is invalid because it already exists in current context
*/
@@ -86,12 +108,12 @@ namespace chaiscript
class global_non_const : public std::runtime_error
{
public:
global_non_const() noexcept
global_non_const() throw()
: std::runtime_error("a global object must be const")
{
}
virtual ~global_non_const() noexcept {}
virtual ~global_non_const() throw() {}
};
}
@@ -123,7 +145,7 @@ namespace chaiscript
{
if (!t_bv.is_const())
{
throw chaiscript::exception::global_non_const();
throw exception::global_non_const();
}
m_globals.push_back(std::make_pair(t_bv, t_name));
@@ -138,7 +160,7 @@ namespace chaiscript
return *this;
}
Module &add(const std::shared_ptr<Module> &m)
Module &add(const boost::shared_ptr<Module> &m)
{
m->apply(*this, *this);
return *m;
@@ -154,11 +176,6 @@ namespace chaiscript
apply_globals(m_globals.begin(), m_globals.end(), t_engine);
}
~Module()
{
detail::Dynamic_Conversions::get().cleanup(m_conversions.begin(), m_conversions.end());
}
private:
std::vector<std::pair<Type_Info, std::string> > m_typeinfos;
std::vector<std::pair<Proxy_Function, std::string> > m_funcs;
@@ -173,7 +190,7 @@ namespace chaiscript
{
try {
t.add(begin->first, begin->second);
} catch (const chaiscript::exception::name_conflict_error &) {
} catch (const exception::name_conflict_error &) {
/// \todo Should we throw an error if there's a name conflict
/// while applying a module?
}
@@ -213,7 +230,7 @@ namespace chaiscript
};
/// Convenience typedef for Module objects to be added to the ChaiScript runtime
typedef std::shared_ptr<Module> ModulePtr;
typedef boost::shared_ptr<Module> ModulePtr;
namespace detail
{
@@ -279,7 +296,7 @@ namespace chaiscript
return -1; // unknown arity
}
virtual bool call_match(const std::vector<Boxed_Value> &vals) const
virtual bool call_match(const std::vector<Boxed_Value> &vals, const Dynamic_Cast_Conversions &t_conversions) const
{
typedef std::vector<Proxy_Function> function_vec;
@@ -288,7 +305,7 @@ namespace chaiscript
while (begin != end)
{
if ((*begin)->call_match(vals))
if ((*begin)->call_match(vals, t_conversions))
{
return true;
} else {
@@ -305,9 +322,9 @@ namespace chaiscript
}
protected:
virtual Boxed_Value do_call(const std::vector<Boxed_Value> &params) const
virtual Boxed_Value do_call(const std::vector<Boxed_Value> &params, const Dynamic_Cast_Conversions &t_conversions) const
{
return dispatch::dispatch(m_funcs.begin(), m_funcs.end(), params);
return dispatch::dispatch(m_funcs.begin(), m_funcs.end(), params, t_conversions);
}
private:
@@ -376,7 +393,7 @@ namespace chaiscript
typedef std::map<std::string, chaiscript::Type_Info> Type_Name_Map;
typedef std::map<std::string, Boxed_Value> Scope;
typedef std::deque<Scope> StackData;
typedef std::shared_ptr<StackData> Stack;
typedef boost::shared_ptr<StackData> Stack;
struct State
{
@@ -385,18 +402,22 @@ namespace chaiscript
std::map<std::string, Boxed_Value> m_global_objects;
Type_Name_Map m_types;
std::set<std::string> m_reserved_words;
State &operator=(const State &) = default;
};
Dispatch_Engine()
: m_place_holder(std::shared_ptr<dispatch::Placeholder_Object>(new dispatch::Placeholder_Object()))
: m_place_holder(boost::shared_ptr<dispatch::Placeholder_Object>(new dispatch::Placeholder_Object()))
{
}
~Dispatch_Engine()
{
detail::Dynamic_Conversions::get().cleanup(m_conversions.begin(), m_conversions.end());
}
/// \brief casts an object while applying any Dynamic_Conversion available
template<typename Type>
typename detail::Cast_Helper<Type>::Result_Type boxed_cast(const Boxed_Value &bv) const
{
return chaiscript::boxed_cast<Type>(bv, &m_conversions);
}
/**
@@ -404,8 +425,7 @@ namespace chaiscript
*/
void add(const Dynamic_Cast_Conversion &d)
{
m_conversions.push_back(d);
return detail::Dynamic_Conversions::get().add_conversion(d);
m_conversions.add_conversion(d);
}
/**
@@ -452,7 +472,7 @@ namespace chaiscript
Scope::iterator itr = scope.find(name);
if (itr != stack.back().end())
{
throw chaiscript::exception::name_conflict_error(name);
throw exception::name_conflict_error(name);
} else {
stack.back().insert(std::make_pair(name, obj));
}
@@ -466,19 +486,38 @@ namespace chaiscript
validate_object_name(name);
if (!obj.is_const())
{
throw chaiscript::exception::global_non_const();
throw exception::global_non_const();
}
chaiscript::detail::threading::unique_lock<chaiscript::detail::threading::shared_mutex> l(m_global_object_mutex);
if (m_state.m_global_objects.find(name) != m_state.m_global_objects.end())
{
throw chaiscript::exception::name_conflict_error(name);
throw exception::name_conflict_error(name);
} else {
m_state.m_global_objects.insert(std::make_pair(name, obj));
}
}
/**
* Adds a new global (non-const) shared object, between all the threads
*/
void add_global(const Boxed_Value &obj, const std::string &name)
{
validate_object_name(name);
chaiscript::detail::threading::unique_lock<chaiscript::detail::threading::shared_mutex> l(m_global_object_mutex);
if (m_state.m_global_objects.find(name) != m_state.m_global_objects.end())
{
throw exception::name_conflict_error(name);
} else {
m_state.m_global_objects.insert(std::make_pair(name, obj));
}
}
/**
* Adds a new scope to the stack
*/
@@ -673,6 +712,27 @@ namespace chaiscript
return functions.find(name) != functions.end();
}
/// \returns All values in the local thread state, added through the add() function
std::map<std::string, Boxed_Value> get_locals() const
{
StackData &stack = get_stack_data();
Scope &scope = stack.front();
return scope;
}
/// \brief Sets all of the locals for the current thread state.
///
/// \param[in] t_locals The map<name, value> set of variables to replace the current state with
///
/// Any existing locals are removed and the given set of variables is added
void set_locals(const std::map<std::string, Boxed_Value> &t_locals)
{
StackData &stack = get_stack_data();
Scope &scope = stack.front();
scope = t_locals;
}
///
/// Get a map of all objects that can be seen from the current scope in a scripting context
@@ -757,11 +817,16 @@ namespace chaiscript
m_state.m_reserved_words.insert(name);
}
const Dynamic_Cast_Conversions &conversions() const
{
return m_conversions;
}
Boxed_Value call_function(const std::string &t_name, const std::vector<Boxed_Value> &params) const
{
std::vector<Proxy_Function> functions = get_function(t_name);
return dispatch::dispatch(functions.begin(), functions.end(), params);
return dispatch::dispatch(functions.begin(), functions.end(), params, m_conversions);
}
Boxed_Value call_function(const std::string &t_name) const
@@ -830,6 +895,22 @@ namespace chaiscript
std::cout << ") " << std::endl;
}
/**
* Returns true if a call can be made that consists of the first parameter
* (the function) with the remaining parameters as its arguments.
*/
Boxed_Value call_exists(const std::vector<Boxed_Value> &params)
{
if (params.size() < 1)
{
throw exception::arity_error(static_cast<int>(params.size()), 1);
}
Const_Proxy_Function f = this->boxed_cast<Const_Proxy_Function>(params[0]);
return Boxed_Value(f->call_match(std::vector<Boxed_Value>(params.begin() + 1, params.end()), m_conversions));
}
/**
* Dump all system info to stdout
*/
@@ -967,8 +1048,8 @@ namespace chaiscript
const Type_Info boxed_type = user_type<Boxed_Value>();
const Type_Info boxed_pod_type = user_type<Boxed_Number>();
std::shared_ptr<const dispatch::Dynamic_Proxy_Function> dynamic_lhs(std::dynamic_pointer_cast<const dispatch::Dynamic_Proxy_Function>(lhs));
std::shared_ptr<const dispatch::Dynamic_Proxy_Function> dynamic_rhs(std::dynamic_pointer_cast<const dispatch::Dynamic_Proxy_Function>(rhs));
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)
{
@@ -1056,11 +1137,15 @@ namespace chaiscript
*/
void validate_object_name(const std::string &name) const
{
if (name.find("::") != std::string::npos) {
throw exception::illegal_name_error(name);
}
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 chaiscript::exception::reserved_word_error(name);
throw exception::reserved_word_error(name);
}
}
@@ -1088,13 +1173,21 @@ namespace chaiscript
{
if ((*t_f) == *(*itr2))
{
throw chaiscript::exception::name_conflict_error(t_name);
throw exception::name_conflict_error(t_name);
}
}
vec.push_back(t_f);
std::stable_sort(vec.begin(), vec.end(), &function_less_than);
func_objs[t_name] = Proxy_Function(new Dispatch_Function(vec));
} else if (t_f->has_arithmetic_param()) {
// if the function is the only function but it also contains
// arithmetic operators, we must wrap it in a dispatch function
// to allow for automatic arithmetic type conversions
std::vector<Proxy_Function> vec;
vec.push_back(t_f);
funcs.insert(std::make_pair(t_name, vec));
func_objs[t_name] = Proxy_Function(new Dispatch_Function(vec));
} else {
std::vector<Proxy_Function> vec;
vec.push_back(t_f);
@@ -1124,7 +1217,7 @@ namespace chaiscript
int call_depth;
};
std::vector<Dynamic_Cast_Conversion> m_conversions;
Dynamic_Cast_Conversions m_conversions;
chaiscript::detail::threading::Thread_Storage<Stack_Holder> m_stack_holder;

View File

@@ -1,7 +1,7 @@
// This file is distributed under the BSD License.
// See "license.txt" for details.
// Copyright 2009-2012, Jonathan Turner (jonathan@emptycrate.com)
// and Jason Turner (jason@emptycrate.com)
// Copyright 2009-2014, Jason Turner (jason@emptycrate.com)
// http://www.chaiscript.com
#ifndef CHAISCRIPT_DYNAMIC_CAST_CONVERSION_HPP_
@@ -11,6 +11,9 @@
#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
{
@@ -20,22 +23,22 @@ namespace chaiscript
{
public:
bad_boxed_dynamic_cast(const Type_Info &t_from, const std::type_info &t_to,
const std::string &t_what) noexcept
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) noexcept
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) noexcept
bad_boxed_dynamic_cast(const std::string &w) throw()
: bad_boxed_cast(w)
{
}
virtual ~bad_boxed_dynamic_cast() noexcept {}
virtual ~bad_boxed_dynamic_cast() throw() {}
};
}
@@ -44,13 +47,14 @@ namespace chaiscript
class Dynamic_Conversion
{
public:
virtual Boxed_Value convert(const Boxed_Value &derived) = 0;
virtual Boxed_Value convert(const Boxed_Value &derived) const = 0;
virtual Boxed_Value convert_down(const Boxed_Value &base) const = 0;
const Type_Info &base()
const Type_Info &base() const
{
return m_base;
}
const Type_Info &derived()
const Type_Info &derived() const
{
return m_derived;
}
@@ -69,26 +73,21 @@ namespace chaiscript
};
template<typename Base, typename Derived>
class Dynamic_Conversion_Impl : public Dynamic_Conversion
template<typename From, typename To>
class Dynamic_Caster
{
public:
Dynamic_Conversion_Impl()
: Dynamic_Conversion(user_type<Base>(), user_type<Derived>())
static Boxed_Value cast(const Boxed_Value &t_from)
{
}
virtual Boxed_Value convert(const Boxed_Value &t_derived)
if (t_from.get_type_info().bare_equal(user_type<From>()))
{
if (t_derived.get_type_info().bare_equal(user_type<Derived>()))
{
if (t_derived.is_pointer())
if (t_from.is_pointer())
{
// Dynamic cast out the contained boxed value, which we know is the type we want
if (t_derived.is_const())
if (t_from.is_const())
{
std::shared_ptr<const Base> data
= std::dynamic_pointer_cast<const Base>(detail::Cast_Helper<std::shared_ptr<const Derived> >::cast(t_derived));
boost::shared_ptr<const To> data
= boost::dynamic_pointer_cast<const To>(detail::Cast_Helper<boost::shared_ptr<const From> >::cast(t_from, 0));
if (!data)
{
throw std::bad_cast();
@@ -96,8 +95,8 @@ namespace chaiscript
return Boxed_Value(data);
} else {
std::shared_ptr<Base> data
= std::dynamic_pointer_cast<Base>(detail::Cast_Helper<std::shared_ptr<Derived> >::cast(t_derived));
boost::shared_ptr<To> data
= boost::dynamic_pointer_cast<To>(detail::Cast_Helper<boost::shared_ptr<From> >::cast(t_from, 0));
if (!data)
{
@@ -108,83 +107,109 @@ namespace chaiscript
}
} else {
// Pull the reference out of the contained boxed value, which we know is the type we want
if (t_derived.is_const())
if (t_from.is_const())
{
const Derived &d = detail::Cast_Helper<const Derived &>::cast(t_derived);
const Base &data = dynamic_cast<const Base &>(d);
return Boxed_Value(std::cref(data));
const From &d = detail::Cast_Helper<const From &>::cast(t_from, 0);
const To &data = dynamic_cast<const To &>(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(std::ref(data));
From &d = detail::Cast_Helper<From &>::cast(t_from, 0);
To &data = dynamic_cast<To &>(d);
return Boxed_Value(boost::ref(data));
}
}
} else {
throw chaiscript::exception::bad_boxed_dynamic_cast(t_derived.get_type_info(), typeid(Base), "Unknown dynamic_cast_conversion");
throw exception::bad_boxed_dynamic_cast(t_from.get_type_info(), typeid(To), "Unknown dynamic_cast_conversion");
}
}
};
class Dynamic_Conversions
template<typename Base, typename Derived>
class Dynamic_Conversion_Impl : public Dynamic_Conversion
{
public:
static inline Dynamic_Conversions &get()
Dynamic_Conversion_Impl()
: Dynamic_Conversion(user_type<Base>(), user_type<Derived>())
{
static Dynamic_Conversions obj;
return obj;
}
virtual Boxed_Value convert_down(const Boxed_Value &t_base) const
{
return Dynamic_Caster<Base, Derived>::cast(t_base);
}
virtual Boxed_Value convert(const Boxed_Value &t_derived) const
{
return Dynamic_Caster<Derived, Base>::cast(t_derived);
}
};
}
class Dynamic_Cast_Conversions
{
public:
Dynamic_Cast_Conversions()
{
}
Dynamic_Cast_Conversions(const Dynamic_Cast_Conversions &t_other)
: m_conversions(t_other.get_conversions())
{
}
void add_conversion(const boost::shared_ptr<detail::Dynamic_Conversion> &conversion)
{
chaiscript::detail::threading::unique_lock<chaiscript::detail::threading::shared_mutex> l(m_mutex);
m_conversions.insert(conversion);
}
template<typename Base, typename Derived>
static std::shared_ptr<Dynamic_Conversion> create()
bool dynamic_cast_converts() const
{
std::shared_ptr<Dynamic_Conversion> conversion(new Dynamic_Conversion_Impl<Base, Derived>());
/// \todo this is a hack and a kludge. The idea is to make sure that
/// the conversion is registered both in the module's notion of the static conversion object
/// and in the global notion of the static conversion object
/// someday this will almost certainly have to change. Maybe it is time for ChaiScript
/// to become a library?
Dynamic_Conversions::get().add_conversion(conversion);
return conversion;
return dynamic_cast_converts(user_type<Base>(), user_type<Derived>());
}
template<typename InItr>
void cleanup(InItr begin, const InItr &end)
bool dynamic_cast_converts(const Type_Info &base, const Type_Info &derived) const
{
chaiscript::detail::threading::unique_lock<chaiscript::detail::threading::shared_mutex> l(m_mutex);
while (begin != end)
{
if (begin->unique())
{
m_conversions.erase(begin->get());
return has_conversion(base, derived) || has_conversion(derived, base);
}
++begin;
template<typename Base>
Boxed_Value boxed_dynamic_cast(const Boxed_Value &derived) const
{
try {
return get_conversion(user_type<Base>(), derived.get_type_info())->convert(derived);
} catch (const std::out_of_range &) {
throw exception::bad_boxed_dynamic_cast(derived.get_type_info(), typeid(Base), "No known conversion");
} catch (const std::bad_cast &) {
throw exception::bad_boxed_dynamic_cast(derived.get_type_info(), typeid(Base), "Unable to perform dynamic_cast operation");
}
}
void add_conversion(const std::shared_ptr<Dynamic_Conversion> &conversion)
template<typename Derived>
Boxed_Value boxed_dynamic_down_cast(const Boxed_Value &base) const
{
chaiscript::detail::threading::unique_lock<chaiscript::detail::threading::shared_mutex> l(m_mutex);
m_conversions.insert(conversion.get());
try {
return get_conversion(base.get_type_info(), user_type<Derived>())->convert_down(base);
} catch (const std::out_of_range &) {
throw exception::bad_boxed_dynamic_cast(base.get_type_info(), typeid(Derived), "No known conversion");
} catch (const std::bad_cast &) {
throw exception::bad_boxed_dynamic_cast(base.get_type_info(), typeid(Derived), "Unable to perform dynamic_cast operation");
}
}
bool has_conversion(const Type_Info &base, const Type_Info &derived) const
{
chaiscript::detail::threading::shared_lock<chaiscript::detail::threading::shared_mutex> l(m_mutex);
return find(base, derived) != m_conversions.end();
}
Dynamic_Conversion *get_conversion(const Type_Info &base, const Type_Info &derived) const
boost::shared_ptr<detail::Dynamic_Conversion> get_conversion(const Type_Info &base, const Type_Info &derived) const
{
chaiscript::detail::threading::shared_lock<chaiscript::detail::threading::shared_mutex> l(m_mutex);
std::set<Dynamic_Conversion *>::const_iterator itr =
std::set<boost::shared_ptr<detail::Dynamic_Conversion> >::const_iterator itr =
find(base, derived);
if (itr != m_conversions.end())
@@ -196,12 +221,10 @@ namespace chaiscript
}
private:
Dynamic_Conversions() {}
std::set<Dynamic_Conversion *>::const_iterator find(
std::set<boost::shared_ptr<detail::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();
for (std::set<boost::shared_ptr<detail::Dynamic_Conversion> >::const_iterator itr = m_conversions.begin();
itr != m_conversions.end();
++itr)
{
@@ -214,12 +237,18 @@ namespace chaiscript
return m_conversions.end();
}
mutable chaiscript::detail::threading::shared_mutex m_mutex;
std::set<Dynamic_Conversion *> m_conversions;
};
std::set<boost::shared_ptr<detail::Dynamic_Conversion> > get_conversions() const
{
chaiscript::detail::threading::shared_lock<chaiscript::detail::threading::shared_mutex> l(m_mutex);
return m_conversions;
}
typedef std::shared_ptr<chaiscript::detail::Dynamic_Conversion> Dynamic_Cast_Conversion;
mutable chaiscript::detail::threading::shared_mutex m_mutex;
std::set<boost::shared_ptr<detail::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.
@@ -242,45 +271,18 @@ namespace chaiscript
/// chai.add(chaiscript::base_class<Base, Derived>());
/// \endcode
///
/// \todo Move share static type registration code into a mechanism that allows it to be properly
/// shared by all modules
template<typename Base, typename Derived>
Dynamic_Cast_Conversion base_class()
{
//Can only be used with related polymorphic types
//may be expanded some day to support conversions other than child -> parent
static_assert(std::is_base_of<Base,Derived>::value, "Classes are not related by inheritance");
static_assert(std::is_polymorphic<Base>::value, "Base class must be polymorphic");
static_assert(std::is_polymorphic<Derived>::value, "Derived class must be polymorphic");
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>();
return boost::shared_ptr<detail::Dynamic_Conversion>(new detail::Dynamic_Conversion_Impl<Base, Derived>());
}
namespace detail
{
template<typename Base, typename Derived>
bool dynamic_cast_converts()
{
return dynamic_cast_converts(user_type<Base>(), user_type<Derived>());
}
static bool dynamic_cast_converts(const Type_Info &base, const Type_Info &derived)
{
return detail::Dynamic_Conversions::get().has_conversion(base, derived);
}
template<typename Base>
Boxed_Value boxed_dynamic_cast(const Boxed_Value &derived)
{
try {
return detail::Dynamic_Conversions::get().get_conversion(user_type<Base>(), derived.get_type_info())->convert(derived);
} catch (const std::out_of_range &) {
throw chaiscript::exception::bad_boxed_dynamic_cast(derived.get_type_info(), typeid(Base), "No known conversion");
} catch (const std::bad_cast &) {
throw chaiscript::exception::bad_boxed_dynamic_cast(derived.get_type_info(), typeid(Base), "Unable to perform dynamic_cast operation");
}
}
}
}

View File

@@ -1,12 +1,13 @@
// This file is distributed under the BSD License.
// See "license.txt" for details.
// Copyright 2009-2012, Jonathan Turner (jonathan@emptycrate.com)
// and Jason Turner (jason@emptycrate.com)
// Copyright 2009-2014, 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
{
@@ -30,7 +31,7 @@ namespace chaiscript
return m_attrs[t_attr_name];
}
std::map<std::string, Boxed_Value> get_attrs()
std::map<std::string, Boxed_Value> get_attrs() const
{
return m_attrs;
}
@@ -51,22 +52,12 @@ namespace chaiscript
class Dynamic_Object_Function : public Proxy_Function_Base
{
public:
Dynamic_Object_Function(
const std::string &t_type_name,
const Proxy_Function &t_func)
: Proxy_Function_Base(t_func->get_param_types()),
m_type_name(t_type_name), m_func(t_func)
{
assert( (t_func->get_arity() > 0 || t_func->get_arity() < 0)
&& "Programming error, Dynamic_Object_Function must have at least one parameter (this)");
}
Dynamic_Object_Function(
const std::string &t_type_name,
const Proxy_Function &t_func,
const Type_Info &t_ti)
const boost::optional<Type_Info> &t_ti = boost::optional<Type_Info>())
: Proxy_Function_Base(build_param_types(t_func->get_param_types(), t_ti)),
m_type_name(t_type_name), m_func(t_func), m_ti(new Type_Info(t_ti))
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)
&& "Programming error, Dynamic_Object_Function must have at least one parameter (this)");
@@ -85,11 +76,11 @@ namespace chaiscript
}
}
virtual bool call_match(const std::vector<Boxed_Value> &vals) const
virtual bool call_match(const std::vector<Boxed_Value> &vals, const Dynamic_Cast_Conversions &t_conversions) const
{
if (dynamic_object_typename_match(vals, m_type_name, m_ti))
if (dynamic_object_typename_match(vals, m_type_name, m_ti, t_conversions))
{
return m_func->call_match(vals);
return m_func->call_match(vals, t_conversions);
} else {
return false;
}
@@ -97,7 +88,9 @@ namespace chaiscript
virtual std::vector<Const_Proxy_Function> get_contained_functions() const
{
return {m_func};
std::vector<Const_Proxy_Function> fs;
fs.push_back(m_func);
return fs;
}
@@ -113,41 +106,46 @@ namespace chaiscript
protected:
virtual Boxed_Value do_call(const std::vector<Boxed_Value> &params) const
virtual Boxed_Value do_call(const std::vector<Boxed_Value> &params, const Dynamic_Cast_Conversions &t_conversions) const
{
if (dynamic_object_typename_match(params, m_type_name, m_ti))
if (dynamic_object_typename_match(params, m_type_name, m_ti, t_conversions))
{
return (*m_func)(params);
return (*m_func)(params, t_conversions);
} else {
throw exception::guard_error();
}
}
virtual bool compare_first_type(const Boxed_Value &bv) const
virtual bool compare_first_type(const Boxed_Value &bv, const Dynamic_Cast_Conversions &t_conversions) const
{
return dynamic_object_typename_match(bv, m_type_name, m_ti);
return dynamic_object_typename_match(bv, m_type_name, m_ti, t_conversions);
}
private:
static std::vector<Type_Info> build_param_types(
const std::vector<Type_Info> &t_inner_types, const Type_Info& t_objectti)
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;
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 std::shared_ptr<Type_Info> &ti)
const boost::optional<Type_Info> &ti, const Dynamic_Cast_Conversions &t_conversions)
{
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);
const Dynamic_Object &d = boxed_cast<const Dynamic_Object &>(bv, &t_conversions);
return name == "Dynamic_Object" || d.get_type_name() == name;
} catch (const std::bad_cast &) {
return false;
@@ -164,11 +162,11 @@ namespace chaiscript
}
static bool dynamic_object_typename_match(const std::vector<Boxed_Value> &bvs, const std::string &name,
const std::shared_ptr<Type_Info> &ti)
const boost::optional<Type_Info> &ti, const Dynamic_Cast_Conversions &t_conversions)
{
if (bvs.size() > 0)
{
return dynamic_object_typename_match(bvs[0], name, ti);
return dynamic_object_typename_match(bvs[0], name, ti, t_conversions);
} else {
return false;
}
@@ -176,7 +174,7 @@ namespace chaiscript
std::string m_type_name;
Proxy_Function m_func;
std::shared_ptr<Type_Info> m_ti;
boost::optional<Type_Info> m_ti;
};
@@ -226,13 +224,13 @@ namespace chaiscript
}
}
virtual bool call_match(const std::vector<Boxed_Value> &vals) const
virtual bool call_match(const std::vector<Boxed_Value> &vals, const Dynamic_Cast_Conversions &t_conversions) const
{
std::vector<Boxed_Value> new_vals;
new_vals.push_back(Boxed_Value(Dynamic_Object(m_type_name)));
new_vals.insert(new_vals.end(), vals.begin(), vals.end());
return m_func->call_match(new_vals);
return m_func->call_match(new_vals, t_conversions);
}
@@ -248,14 +246,14 @@ namespace chaiscript
}
protected:
virtual Boxed_Value do_call(const std::vector<Boxed_Value> &params) const
virtual Boxed_Value do_call(const std::vector<Boxed_Value> &params, const Dynamic_Cast_Conversions &t_conversions) 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);
(*m_func)(new_params, t_conversions);
return bv;
}

View File

@@ -1,7 +1,7 @@
// This file is distributed under the BSD License.
// See "license.txt" for details.
// Copyright 2009-2012, Jonathan Turner (jonathan@emptycrate.com)
// and Jason Turner (jason@emptycrate.com)
// Copyright 2009-2014, Jason Turner (jason@emptycrate.com)
// http://www.chaiscript.com
#ifndef CHAISCRIPT_EXCEPTION_SPECIFICATION_HPP_
@@ -15,65 +15,77 @@ namespace chaiscript
{
struct Exception_Handler_Base
{
virtual void handle(const Boxed_Value &bv) = 0;
virtual void handle(const Boxed_Value &bv, const Dispatch_Engine &t_engine) = 0;
virtual ~Exception_Handler_Base() {}
protected:
template<typename T>
void throw_type(const Boxed_Value &bv)
void throw_type(const Boxed_Value &bv, const Dispatch_Engine &t_engine)
{
try { T t = boxed_cast<T>(bv); throw t; } catch (const chaiscript::exception::bad_boxed_cast &) {}
try { T t = t_engine.boxed_cast<T>(bv); throw t; } catch (const exception::bad_boxed_cast &) {}
}
};
template<typename T1>
struct Exception_Handler_Impl1 : Exception_Handler_Base
{
virtual void handle(const Boxed_Value &bv)
virtual ~Exception_Handler_Impl1() {}
virtual void handle(const Boxed_Value &bv, const Dispatch_Engine &t_engine)
{
throw_type<T1>(bv);
throw_type<T1>(bv, t_engine);
}
};
template<typename T1, typename T2>
struct Exception_Handler_Impl2 : Exception_Handler_Base
{
virtual void handle(const Boxed_Value &bv)
virtual ~Exception_Handler_Impl2() {}
virtual void handle(const Boxed_Value &bv, const Dispatch_Engine &t_engine)
{
throw_type<T1>(bv);
throw_type<T2>(bv);
throw_type<T1>(bv, t_engine);
throw_type<T2>(bv, t_engine);
}
};
template<typename T1, typename T2, typename T3>
struct Exception_Handler_Impl3 : Exception_Handler_Base
{
virtual void handle(const Boxed_Value &bv)
virtual ~Exception_Handler_Impl3() {}
virtual void handle(const Boxed_Value &bv, const Dispatch_Engine &t_engine)
{
throw_type<T1>(bv);
throw_type<T2>(bv);
throw_type<T3>(bv);
throw_type<T1>(bv, t_engine);
throw_type<T2>(bv, t_engine);
throw_type<T3>(bv, t_engine);
}
};
template<typename T1, typename T2, typename T3, typename T4>
struct Exception_Handler_Impl4 : Exception_Handler_Base
{
virtual void handle(const Boxed_Value &bv)
virtual ~Exception_Handler_Impl4() {}
virtual void handle(const Boxed_Value &bv, const Dispatch_Engine &t_engine)
{
throw_type<T1>(bv);
throw_type<T2>(bv);
throw_type<T3>(bv);
throw_type<T4>(bv);
throw_type<T1>(bv, t_engine);
throw_type<T2>(bv, t_engine);
throw_type<T3>(bv, t_engine);
throw_type<T4>(bv, t_engine);
}
};
template<typename T1, typename T2, typename T3, typename T4, typename T5>
struct Exception_Handler_Impl5 : Exception_Handler_Base
{
virtual void handle(const Boxed_Value &bv)
virtual ~Exception_Handler_Impl5() {}
virtual void handle(const Boxed_Value &bv, const Dispatch_Engine &t_engine)
{
throw_type<T1>(bv);
throw_type<T2>(bv);
throw_type<T3>(bv);
throw_type<T4>(bv);
throw_type<T5>(bv);
throw_type<T1>(bv, t_engine);
throw_type<T2>(bv, t_engine);
throw_type<T3>(bv, t_engine);
throw_type<T4>(bv, t_engine);
throw_type<T5>(bv, t_engine);
}
};
}
@@ -128,7 +140,7 @@ namespace chaiscript
///
/// \sa chaiscript::exception_specification for creation of chaiscript::Exception_Handler objects
/// \sa \ref exceptions
typedef std::shared_ptr<detail::Exception_Handler_Base> Exception_Handler;
typedef boost::shared_ptr<detail::Exception_Handler_Base> Exception_Handler;
/// \brief creates a chaiscript::Exception_Handler which handles one type of exception unboxing
/// \sa \ref exceptions

View File

@@ -1,12 +1,15 @@
// This file is distributed under the BSD License.
// See "license.txt" for details.
// Copyright 2009-2010, Jonathan Turner (jonathan@emptycrate.com)
// and Jason Turner (jason@emptycrate.com)
// Copyright 2009-2012, Jonathan Turner (jonathan@emptycrate.com)
// Copyright 2009-2014, Jason Turner (jason@emptycrate.com)
// http://www.chaiscript.com
#ifndef CHAISCRIPT_FUNCTION_CALL_HPP_
#define CHAISCRIPT_FUNCTION_CALL_HPP_
#include <boost/shared_ptr.hpp>
#include <boost/bind.hpp>
#include <boost/function.hpp>
#include <string>
#include <vector>
#include "proxy_functions.hpp"
@@ -22,17 +25,17 @@ namespace chaiscript
/**
* Build a function caller that knows how to dispatch on a set of functions
* example:
* std::function<void (int)> f =
* boost::function<void (int)> f =
* build_function_caller(dispatchkit.get_function("print"));
* \returns A std::function object for dispatching
* \returns A boost::function object for dispatching
* \param[in] funcs the set of functions to dispatch on.
*/
template<typename FunctionType>
std::function<FunctionType>
functor(const std::vector<Const_Proxy_Function> &funcs)
boost::function<FunctionType>
functor(const std::vector<Const_Proxy_Function> &funcs, const Dynamic_Cast_Conversions *t_conversions)
{
FunctionType *p=0;
return detail::build_function_caller_helper(p, funcs);
return detail::build_function_caller_helper(p, funcs, t_conversions);
}
/**
@@ -42,19 +45,19 @@ namespace chaiscript
* example:
* void my_function(Proxy_Function f)
* {
* std::function<void (int)> local_f =
* boost::function<void (int)> local_f =
* build_function_caller(f);
* }
* \returns A std::function object for dispatching
* \returns A boost::function object for dispatching
* \param[in] func A function to execute.
*/
template<typename FunctionType>
std::function<FunctionType>
functor(Const_Proxy_Function func)
boost::function<FunctionType>
functor(Const_Proxy_Function func, const Dynamic_Cast_Conversions *t_conversions)
{
std::vector<Const_Proxy_Function> funcs;
funcs.push_back(func);
return functor<FunctionType>(funcs);
return functor<FunctionType>(funcs, t_conversions);
}
/**
@@ -62,67 +65,67 @@ namespace chaiscript
* and creating a typesafe C++ function caller from it.
*/
template<typename FunctionType>
std::function<FunctionType>
functor(const Boxed_Value &bv)
boost::function<FunctionType>
functor(const Boxed_Value &bv, const Dynamic_Cast_Conversions *t_conversions)
{
return functor<FunctionType>(boxed_cast<Const_Proxy_Function >(bv));
return functor<FunctionType>(boxed_cast<Const_Proxy_Function >(bv, t_conversions), t_conversions);
}
}
namespace detail{
/**
* Cast helper to handle automatic casting to const std::function &
* Cast helper to handle automatic casting to const boost::function &
*/
template<typename Signature>
struct Cast_Helper<const std::function<Signature> &>
struct Cast_Helper<const boost::function<Signature> &>
{
typedef std::function<Signature> Result_Type;
typedef boost::function<Signature> Result_Type;
static Result_Type cast(const Boxed_Value &ob)
static Result_Type cast(const Boxed_Value &ob, const Dynamic_Cast_Conversions *t_conversions)
{
if (ob.get_type_info().bare_equal(user_type<Const_Proxy_Function>()))
{
return dispatch::functor<Signature>(ob);
return dispatch::functor<Signature>(ob, t_conversions);
} else {
return Cast_Helper_Inner<const std::function<Signature> &>::cast(ob);
return Cast_Helper_Inner<const boost::function<Signature> &>::cast(ob, t_conversions);
}
}
};
/**
* Cast helper to handle automatic casting to std::function
* Cast helper to handle automatic casting to boost::function
*/
template<typename Signature>
struct Cast_Helper<std::function<Signature> >
struct Cast_Helper<boost::function<Signature> >
{
typedef std::function<Signature> Result_Type;
typedef boost::function<Signature> Result_Type;
static Result_Type cast(const Boxed_Value &ob)
static Result_Type cast(const Boxed_Value &ob, const Dynamic_Cast_Conversions *t_conversions)
{
if (ob.get_type_info().bare_equal(user_type<Const_Proxy_Function>()))
{
return dispatch::functor<Signature>(ob);
return dispatch::functor<Signature>(ob, t_conversions);
} else {
return Cast_Helper_Inner<std::function<Signature> >::cast(ob);
return Cast_Helper_Inner<boost::function<Signature> >::cast(ob, t_conversions);
}
}
};
/**
* Cast helper to handle automatic casting to const std::function
* Cast helper to handle automatic casting to const boost::function
*/
template<typename Signature>
struct Cast_Helper<const std::function<Signature> >
struct Cast_Helper<const boost::function<Signature> >
{
typedef std::function<Signature> Result_Type;
typedef boost::function<Signature> Result_Type;
static Result_Type cast(const Boxed_Value &ob)
static Result_Type cast(const Boxed_Value &ob, const Dynamic_Cast_Conversions *t_conversions)
{
if (ob.get_type_info().bare_equal(user_type<Const_Proxy_Function>()))
{
return dispatch::functor<Signature>(ob);
return dispatch::functor<Signature>(ob, t_conversions);
} else {
return Cast_Helper_Inner<const std::function<Signature> >::cast(ob);
return Cast_Helper_Inner<const boost::function<Signature> >::cast(ob, t_conversions);
}
}
};

View File

@@ -1,12 +1,22 @@
// This file is distributed under the BSD License.
// See "license.txt" for details.
// Copyright 2009-2012, Jonathan Turner (jonathan@emptycrate.com)
// and Jason Turner (jason@emptycrate.com)
// Copyright 2009-2014, 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&&!(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 CHAISCRIPT_FUNCTION_CALL_DETAIL_HPP_
#define CHAISCRIPT_FUNCTION_CALL_DETAIL_HPP_
#include <boost/shared_ptr.hpp>
#include <boost/bind.hpp>
#include <boost/function.hpp>
#include <string>
#include <vector>
#include "proxy_functions.hpp"
@@ -17,67 +27,90 @@ namespace chaiscript
{
namespace detail
{
/**
* Internal helper class for handling the return
* value of a build_function_caller
*/
template<typename Ret>
template<typename Ret, bool is_arithmetic>
struct Function_Caller_Ret
{
static Ret call(const std::vector<Const_Proxy_Function> &t_funcs,
const std::vector<Boxed_Value> &params)
const std::vector<Boxed_Value> &params, const Dynamic_Cast_Conversions &t_conversions)
{
return boxed_cast<Ret>(dispatch::dispatch(t_funcs, params));
return boxed_cast<Ret>(dispatch::dispatch(t_funcs, params, t_conversions));
}
};
/**
* Specialization for arithmetic return types
*/
template<typename Ret>
struct Function_Caller_Ret<Ret, true>
{
static Ret call(const std::vector<Const_Proxy_Function> &t_funcs,
const std::vector<Boxed_Value> &params, const Dynamic_Cast_Conversions &t_conversions)
{
return Boxed_Number(dispatch::dispatch(t_funcs, params, t_conversions)).get_as<Ret>();
}
};
/**
* Specialization for void return types
*/
template<>
struct Function_Caller_Ret<void>
struct Function_Caller_Ret<void, false>
{
static void call(const std::vector<Const_Proxy_Function> &t_funcs,
const std::vector<Boxed_Value> &params)
const std::vector<Boxed_Value> &params, const Dynamic_Cast_Conversions &t_conversions)
{
dispatch::dispatch(t_funcs, params);
dispatch::dispatch(t_funcs, params, t_conversions);
}
};
}
}
}
#define BOOST_PP_ITERATION_LIMITS ( 0, 9 )
#define BOOST_PP_FILENAME_1 <chaiscript/dispatchkit/function_call_detail.hpp>
#include BOOST_PP_ITERATE()
# endif
#else
# define n BOOST_PP_ITERATION()
namespace chaiscript
{
namespace dispatch
{
namespace detail
{
/**
* used internally for unwrapping a function call's types
*/
template<typename Ret BOOST_PP_COMMA_IF(n) BOOST_PP_ENUM_PARAMS(n, typename Param) >
Ret function_caller(const std::vector<Const_Proxy_Function> &funcs, const Dynamic_Cast_Conversions &t_conversions
BOOST_PP_COMMA_IF(n) BOOST_PP_ENUM_BINARY_PARAMS(n, Param, p) )
{
std::vector<Boxed_Value> params;
BOOST_PP_REPEAT(n, addparam, ~);
return Function_Caller_Ret<Ret, boost::is_arithmetic<Ret>::value>::call(funcs, params, t_conversions);
}
/**
* used internally for unwrapping a function call's types
*/
template<typename Ret, typename ... Param>
struct Build_Function_Caller_Helper
{
Build_Function_Caller_Helper(const std::vector<Const_Proxy_Function> &t_funcs)
: m_funcs(t_funcs)
{
}
Ret operator()(Param...param)
{
return Function_Caller_Ret<Ret>::call(m_funcs, {
(std::is_reference<Param>::value&&!(std::is_same<chaiscript::Boxed_Value, typename std::remove_const<typename std::remove_reference<Param>::type>::type>::value))?Boxed_Value(std::ref(param)):Boxed_Value(param)...
}
);
}
std::vector<Const_Proxy_Function> m_funcs;
};
template<typename Ret, typename ... Params>
std::function<Ret (Params...)> build_function_caller_helper(Ret (Params...), const std::vector<Const_Proxy_Function> &funcs)
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<Const_Proxy_Function> &funcs,
const Dynamic_Cast_Conversions *t_conversions)
{
if (funcs.size() == 1)
{
std::shared_ptr<const Proxy_Function_Impl<Ret (Params...)>> pfi =
std::dynamic_pointer_cast<const Proxy_Function_Impl<Ret (Params...)> >
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)
@@ -88,11 +121,15 @@ namespace chaiscript
// we cannot make any other guesses or assumptions really, so continuing
}
return std::function<Ret (Params...)>(Build_Function_Caller_Helper<Ret, Params...>(funcs));
return boost::bind(&function_caller<Ret BOOST_PP_COMMA_IF(n) BOOST_PP_ENUM_PARAMS(n, Param)>, funcs, (t_conversions?*t_conversions:Dynamic_Cast_Conversions())
BOOST_PP_ENUM_TRAILING(n, curry, ~));
}
}
}
}
#undef n
#undef addparam
#undef curry
#endif

View File

@@ -1,7 +1,7 @@
// This file is distributed under the BSD License.
// See "license.txt" for details.
// Copyright 2009-2012, Jonathan Turner (jonathan@emptycrate.com)
// and Jason Turner (jason@emptycrate.com)
// Copyright 2009-2014, Jason Turner (jason@emptycrate.com)
// http://www.chaiscript.com
#ifndef CHAISCRIPT_HANDLE_RETURN_HPP_
@@ -11,6 +11,7 @@
#include "boxed_number.hpp"
#include "type_info.hpp"
#include <string>
#include <boost/function.hpp>
#include <stdexcept>
#include <vector>
@@ -43,27 +44,27 @@ namespace chaiscript
};
template<typename Ret>
struct Handle_Return<std::shared_ptr<Ret> &>
struct Handle_Return<boost::shared_ptr<Ret> &>
{
static Boxed_Value handle(const std::shared_ptr<Ret> &r)
static Boxed_Value handle(const boost::shared_ptr<Ret> &r)
{
return Boxed_Value(r);
}
};
template<typename Ret>
struct Handle_Return<std::shared_ptr<Ret> >
struct Handle_Return<boost::shared_ptr<Ret> >
{
static Boxed_Value handle(const std::shared_ptr<Ret> &r)
static Boxed_Value handle(const boost::shared_ptr<Ret> &r)
{
return Boxed_Value(r);
}
};
template<typename Ret>
struct Handle_Return<const std::shared_ptr<Ret> &>
struct Handle_Return<const boost::shared_ptr<Ret> &>
{
static Boxed_Value handle(const std::shared_ptr<Ret> &r)
static Boxed_Value handle(const boost::shared_ptr<Ret> &r)
{
return Boxed_Value(r);
}
@@ -74,7 +75,7 @@ namespace chaiscript
{
static Boxed_Value handle(const Ret &r)
{
return Boxed_Value(std::cref(r));
return Boxed_Value(boost::cref(r));
}
};
@@ -87,12 +88,12 @@ namespace chaiscript
{
static Boxed_Value handle(Ret &r)
{
return Boxed_Value(std::ref(r));
return Boxed_Value(boost::ref(r));
}
static Boxed_Value handle(const Ret &r)
{
return Boxed_Value(std::cref(r));
return Boxed_Value(boost::cref(r));
}
};

View File

@@ -1,14 +1,12 @@
// This file is distributed under the BSD License.
// See "license.txt" for details.
// Copyright 2009-2012, Jonathan Turner (jonathan@emptycrate.com)
// and Jason Turner (jason@emptycrate.com)
// Copyright 2009-2014, Jason Turner (jason@emptycrate.com)
// http://www.chaiscript.com
#ifndef CHAISCRIPT_OPERATORS_HPP_
#define CHAISCRIPT_OPERATORS_HPP_
#include "../chaiscript_defines.hpp"
namespace chaiscript
{
namespace bootstrap
@@ -156,7 +154,7 @@ namespace chaiscript
template<typename Ret, typename L>
Ret unary_minus(L l)
{
#ifdef CHAISCRIPT_MSVC
#ifdef BOOST_MSVC
#pragma warning(push)
#pragma warning(disable : 4146)
return (-l);

View File

@@ -1,39 +1,27 @@
// This file is distributed under the BSD License.
// See "license.txt" for details.
// Copyright 2009-2012, Jonathan Turner (jonathan@emptycrate.com)
// and Jason Turner (jason@emptycrate.com)
// Copyright 2009-2014, Jason Turner (jason@emptycrate.com)
// http://www.chaiscript.com
#include <boost/preprocessor.hpp>
#ifndef BOOST_PP_IS_ITERATING
#ifndef CHAISCRIPT_PROXY_CONSTRUCTORS_HPP_
#define CHAISCRIPT_PROXY_CONSTRUCTORS_HPP_
#include <boost/shared_ptr.hpp>
#include <boost/bind.hpp>
#include <boost/function.hpp>
#define BOOST_PP_ITERATION_LIMITS ( 0, 10 )
#define BOOST_PP_FILENAME_1 <chaiscript/dispatchkit/proxy_constructors.hpp>
#include BOOST_PP_ITERATE()
# endif
namespace chaiscript
{
namespace dispatch
{
namespace detail
{
/**
* A constructor function, used for creating a new object
* of a given type with a given set of params
*/
template<typename Class, typename ... Params>
std::shared_ptr<Class> constructor_(Params ... params)
{
return std::shared_ptr<Class>(new Class(params...));
}
template<typename Class, typename ... Params >
Proxy_Function build_constructor_(Class (*)(Params...))
{
typedef std::shared_ptr<Class> (sig)(Params...);
return Proxy_Function(new Proxy_Function_Impl<sig>(std::function<sig>(&(constructor_<Class, Params...>))));
}
}
}
/// \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, ...)
@@ -51,8 +39,43 @@ namespace chaiscript
T *f = 0;
return (dispatch::detail::build_constructor_(f));
}
}
#else
# define n BOOST_PP_ITERATION()
namespace chaiscript
{
namespace dispatch
{
namespace detail
{
/**
* A constructor function, used for creating a new object
* of a given type with a given set of params
*/
template<typename Class BOOST_PP_COMMA_IF(n) BOOST_PP_ENUM_PARAMS(n, typename Param) >
boost::shared_ptr<Class> constructor_( BOOST_PP_ENUM_BINARY_PARAMS(n, Param, p) )
{
return boost::shared_ptr<Class>(new Class( BOOST_PP_ENUM_PARAMS(n, p) ));
}
/**
* Helper function for build a constructor function
* example:
* dispatchengine.register_function(build_constructor<MyClass, int, const std::string&>, "MyClass");
* \todo See if it is possible to make this not be a variadic function
*/
template<typename Class BOOST_PP_COMMA_IF(n) BOOST_PP_ENUM_PARAMS(n, typename Param) >
Proxy_Function build_constructor_(Class (*)(BOOST_PP_ENUM_PARAMS(n, Param)))
{
typedef boost::shared_ptr<Class> (sig)(BOOST_PP_ENUM_PARAMS(n, Param));
return Proxy_Function(new Proxy_Function_Impl<sig>(boost::function<sig>(&(constructor_<Class BOOST_PP_COMMA_IF(n) BOOST_PP_ENUM_PARAMS(n, Param)>))));
}
}
}
}
#undef n
#endif

View File

@@ -1,7 +1,7 @@
// This file is distributed under the BSD License.
// See "license.txt" for details.
// Copyright 2009-2012, Jonathan Turner (jonathan@emptycrate.com)
// and Jason Turner (jason@emptycrate.com)
// Copyright 2009-2014, Jason Turner (jason@emptycrate.com)
// http://www.chaiscript.com
@@ -12,10 +12,10 @@
#include "boxed_value.hpp"
#include "type_info.hpp"
#include <string>
#include <type_traits>
#include <boost/function.hpp>
#include <boost/type_traits/add_reference.hpp>
#include <stdexcept>
#include <vector>
#include <cassert>
#include "proxy_functions_detail.hpp"
namespace chaiscript
@@ -23,11 +23,41 @@ namespace chaiscript
class Boxed_Number;
struct AST_Node;
typedef std::shared_ptr<struct AST_Node> AST_NodePtr;
typedef boost::shared_ptr<AST_Node> AST_NodePtr;
namespace dispatch
{
/**
* Helper for building a list of parameters for calling a Proxy_Function
* it does automatic conversion to Boxed_Value types via operator<<
*
* example usage:
* Boxed_Value retval = dispatch(dispatchengine.get_function("+"),
* chaiscript::Param_List_Builder() << 5 << 6);
*/
struct Param_List_Builder
{
Param_List_Builder &operator<<(const Boxed_Value &so)
{
objects.push_back(so);
return *this;
}
template<typename T>
Param_List_Builder &operator<<(T t)
{
objects.push_back(Boxed_Value(t));
return *this;
}
operator const std::vector<Boxed_Value> &() const
{
return objects;
}
std::vector<Boxed_Value> objects;
};
/**
* Pure virtual base class for all Proxy_Function implementations
* Proxy_Functions are a type erasure of type safe C++
@@ -40,9 +70,9 @@ namespace chaiscript
{
public:
virtual ~Proxy_Function_Base() {}
Boxed_Value operator()(const std::vector<Boxed_Value> &params) const
Boxed_Value operator()(const std::vector<Boxed_Value> &params, const chaiscript::Dynamic_Cast_Conversions &t_conversions) const
{
Boxed_Value bv = do_call(params);
Boxed_Value bv = do_call(params, t_conversions);
return bv;
}
@@ -50,20 +80,25 @@ namespace chaiscript
/// if the function is variadic or takes no arguments (arity of 0 or -1), the returned
/// value containes exactly 1 Type_Info object: the return type
/// \returns the types of all parameters.
const std::vector<Type_Info> &get_param_types() const { return m_types; }
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 bool call_match(const std::vector<Boxed_Value> &vals, const Dynamic_Cast_Conversions &t_conversions) const = 0;
virtual std::vector<std::shared_ptr<const Proxy_Function_Base> > get_contained_functions() const
bool has_arithmetic_param() const
{
return std::vector<std::shared_ptr<const Proxy_Function_Base> >();
return m_has_arithmetic_param;
}
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
bool filter(const std::vector<Boxed_Value> &vals, const Dynamic_Cast_Conversions &t_conversions) const
{
int arity = get_arity();
@@ -75,7 +110,7 @@ namespace chaiscript
{
return true;
} else {
return compare_first_type(vals[0]);
return compare_first_type(vals[0], t_conversions);
}
} else {
return false;
@@ -87,30 +122,15 @@ namespace chaiscript
virtual std::string annotation() const = 0;
protected:
virtual Boxed_Value do_call(const std::vector<Boxed_Value> &params) const = 0;
Proxy_Function_Base(const std::vector<Type_Info> &t_types)
: m_types(t_types)
static bool compare_type_to_param(const Type_Info &ti, const Boxed_Value &bv, const Dynamic_Cast_Conversions &t_conversions)
{
}
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()
|| ti.bare_equal(user_type<Boxed_Value>())
|| (!bv.get_type_info().is_undef()
&& (ti.bare_equal(user_type<Boxed_Number>())
|| ti.bare_equal(bv.get_type_info())
|| chaiscript::detail::dynamic_cast_converts(ti, bv.get_type_info())
|| bv.get_type_info().bare_equal(user_type<std::shared_ptr<const Proxy_Function_Base> >())
|| bv.get_type_info().bare_equal(user_type<boost::shared_ptr<const Proxy_Function_Base> >())
|| t_conversions.dynamic_cast_converts(ti, bv.get_type_info())
)
)
)
@@ -120,8 +140,38 @@ namespace chaiscript
return false;
}
}
protected:
virtual Boxed_Value do_call(const std::vector<Boxed_Value> &params, const Dynamic_Cast_Conversions &t_conversions) const = 0;
bool compare_types(const std::vector<Type_Info> &tis, const std::vector<Boxed_Value> &bvs) const
Proxy_Function_Base(const std::vector<Type_Info> &t_types)
: m_types(t_types), m_has_arithmetic_param(false)
{
for (size_t i = 1; i < m_types.size(); ++i)
{
if (m_types[i].is_arithmetic())
{
m_has_arithmetic_param = true;
return;
}
}
}
virtual bool compare_first_type(const Boxed_Value &bv, const Dynamic_Cast_Conversions &t_conversions) const
{
const std::vector<Type_Info> &types = get_param_types();
if (types.size() < 2)
{
return true;
}
const Type_Info &ti = types[1];
return compare_type_to_param(ti, bv, t_conversions);
}
static bool compare_types(const std::vector<Type_Info> &tis, const std::vector<Boxed_Value> &bvs)
{
if (tis.size() - 1 != bvs.size())
{
@@ -140,15 +190,17 @@ namespace chaiscript
}
std::vector<Type_Info> m_types;
bool m_has_arithmetic_param;
};
}
/// \brief Common typedef used for passing of any registered function in ChaiScript
typedef std::shared_ptr<dispatch::Proxy_Function_Base> Proxy_Function;
typedef boost::shared_ptr<dispatch::Proxy_Function_Base> Proxy_Function;
/// \brief Const version of Proxy_Function chaiscript. Points to a const Proxy_Function. This is how most registered functions
/// are handled internally.
typedef std::shared_ptr<const dispatch::Proxy_Function_Base> Const_Proxy_Function;
typedef boost::shared_ptr<const dispatch::Proxy_Function_Base> Const_Proxy_Function;
namespace exception
{
@@ -156,11 +208,11 @@ namespace chaiscript
class guard_error : public std::runtime_error
{
public:
guard_error() noexcept
guard_error() throw()
: std::runtime_error("Guard evaluation failed")
{ }
virtual ~guard_error() noexcept
virtual ~guard_error() throw()
{ }
};
}
@@ -175,7 +227,7 @@ namespace chaiscript
{
public:
Dynamic_Proxy_Function(
const std::function<Boxed_Value (const std::vector<Boxed_Value> &)> &t_f,
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 = "",
@@ -195,10 +247,10 @@ namespace chaiscript
&& !this->m_guard && !prhs->m_guard);
}
virtual bool call_match(const std::vector<Boxed_Value> &vals) const
virtual bool call_match(const std::vector<Boxed_Value> &vals, const Dynamic_Cast_Conversions &t_conversions) const
{
return (m_arity < 0 || vals.size() == size_t(m_arity))
&& test_guard(vals);
&& test_guard(vals, t_conversions);
}
virtual ~Dynamic_Proxy_Function() {}
@@ -225,12 +277,12 @@ namespace chaiscript
}
protected:
virtual Boxed_Value do_call(const std::vector<Boxed_Value> &params) const
virtual Boxed_Value do_call(const std::vector<Boxed_Value> &params, const Dynamic_Cast_Conversions &t_conversions) const
{
if (m_arity < 0 || params.size() == size_t(m_arity))
{
if (test_guard(params))
if (test_guard(params, t_conversions))
{
return m_f(params);
} else {
@@ -243,12 +295,12 @@ namespace chaiscript
}
private:
bool test_guard(const std::vector<Boxed_Value> &params) const
bool test_guard(const std::vector<Boxed_Value> &params, const Dynamic_Cast_Conversions &t_conversions) const
{
if (m_guard)
{
try {
return boxed_cast<bool>((*m_guard)(params));
return boxed_cast<bool>((*m_guard)(params, t_conversions));
} catch (const exception::arity_error &) {
return false;
} catch (const exception::bad_boxed_cast &) {
@@ -266,7 +318,7 @@ namespace chaiscript
// For the return type
types.push_back(chaiscript::detail::Get_Type_Info<Boxed_Value>::get());
if (arity > 0)
if (arity >= 0)
{
for (int i = 0; i < arity; ++i)
{
@@ -277,7 +329,7 @@ namespace chaiscript
return types;
}
std::function<Boxed_Value (const std::vector<Boxed_Value> &)> m_f;
boost::function<Boxed_Value (const std::vector<Boxed_Value> &)> m_f;
int m_arity;
std::string m_description;
Proxy_Function m_guard;
@@ -316,14 +368,9 @@ namespace chaiscript
virtual ~Bound_Function() {}
virtual bool call_match(const std::vector<Boxed_Value> &vals) const
virtual bool call_match(const std::vector<Boxed_Value> &vals, const Dynamic_Cast_Conversions &t_conversions) const
{
return m_f->call_match(build_param_list(vals));
}
virtual Boxed_Value operator()(const std::vector<Boxed_Value> &params) const
{
return (*m_f)(build_param_list(params));
return m_f->call_match(build_param_list(vals), t_conversions);
}
virtual std::vector<Const_Proxy_Function> get_contained_functions() const
@@ -382,7 +429,6 @@ namespace chaiscript
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();
@@ -401,9 +447,9 @@ namespace chaiscript
return retval;
}
virtual Boxed_Value do_call(const std::vector<Boxed_Value> &params) const
virtual Boxed_Value do_call(const std::vector<Boxed_Value> &params, const Dynamic_Cast_Conversions &t_conversions) const
{
return (*m_f)(build_param_list(params));
return (*m_f)(build_param_list(params), t_conversions);
}
private:
@@ -414,14 +460,14 @@ namespace chaiscript
/**
* The standard typesafe function call implementation of Proxy_Function
* It takes a std::function<> object and performs runtime
* It takes a boost::function<> object and performs runtime
* type checking of Boxed_Value parameters, in a type safe manner
*/
template<typename Func>
class Proxy_Function_Impl : public Proxy_Function_Base
{
public:
Proxy_Function_Impl(const std::function<Func> &f)
Proxy_Function_Impl(const boost::function<Func> &f)
: Proxy_Function_Base(detail::build_param_type_list(static_cast<Func *>(0))),
m_f(f), m_dummy_func(0)
{
@@ -435,19 +481,21 @@ namespace chaiscript
return pimpl != 0;
}
virtual int get_arity() const
{
return static_cast<int>(m_types.size()) - 1;
}
virtual bool call_match(const std::vector<Boxed_Value> &vals) const
virtual bool call_match(const std::vector<Boxed_Value> &vals, const Dynamic_Cast_Conversions &t_conversions) const
{
if (int(vals.size()) != get_arity())
{
return false;
}
return compare_types(m_types, vals) || detail::compare_types_cast(m_dummy_func, vals);
return compare_types(m_types, vals) || detail::compare_types_cast(m_dummy_func, vals, t_conversions);
}
virtual std::string annotation() const
@@ -455,19 +503,19 @@ namespace chaiscript
return "";
}
std::function<Func> internal_function() const
boost::function<Func> internal_function() const
{
return m_f;
}
protected:
virtual Boxed_Value do_call(const std::vector<Boxed_Value> &params) const
virtual Boxed_Value do_call(const std::vector<Boxed_Value> &params, const Dynamic_Cast_Conversions &t_conversions) const
{
return detail::Do_Call<typename std::function<Func>::result_type>::go(m_f, params);
return detail::Do_Call<typename boost::function<Func>::result_type>::go(m_f, params, t_conversions);
}
private:
std::function<Func> m_f;
boost::function<Func> m_f;
Func *m_dummy_func;
};
@@ -490,7 +538,6 @@ namespace chaiscript
{
const Attribute_Access<T, Class> * aa
= dynamic_cast<const Attribute_Access<T, Class> *>(&t_func);
if (aa) {
return m_attr == aa->m_attr;
} else {
@@ -504,7 +551,7 @@ namespace chaiscript
return 1;
}
virtual bool call_match(const std::vector<Boxed_Value> &vals) const
virtual bool call_match(const std::vector<Boxed_Value> &vals, const Dynamic_Cast_Conversions &) const
{
if (vals.size() != 1)
{
@@ -520,18 +567,18 @@ namespace chaiscript
}
protected:
virtual Boxed_Value do_call(const std::vector<Boxed_Value> &params) const
virtual Boxed_Value do_call(const std::vector<Boxed_Value> &params, const Dynamic_Cast_Conversions &t_conversions) const
{
if (params.size() == 1)
{
const Boxed_Value &bv = params[0];
if (bv.is_const())
{
const Class *o = boxed_cast<const Class *>(bv);
return detail::Handle_Return<typename std::add_lvalue_reference<T>::type>::handle(o->*m_attr);
const Class *o = boxed_cast<const Class *>(bv, &t_conversions);
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 std::add_lvalue_reference<T>::type>::handle(o->*m_attr);
Class *o = boxed_cast<Class *>(bv, &t_conversions);
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);
@@ -541,9 +588,11 @@ namespace chaiscript
private:
static std::vector<Type_Info> param_types()
{
return {user_type<T>(), user_type<Class>()};
std::vector<Type_Info> v;
v.push_back(user_type<T>());
v.push_back(user_type<Class>());
return v;
}
T Class::* m_attr;
};
}
@@ -558,19 +607,109 @@ namespace chaiscript
class dispatch_error : public std::runtime_error
{
public:
dispatch_error(const std::vector<Boxed_Value> &t_bvs)
: std::runtime_error("Error with function dispatch"), parameters(t_bvs)
dispatch_error(const std::vector<Boxed_Value> &t_parameters,
const std::vector<Const_Proxy_Function> &t_functions)
: std::runtime_error("Error with function dispatch"), parameters(t_parameters), functions(t_functions)
{
}
virtual ~dispatch_error() noexcept {}
virtual ~dispatch_error() throw() {}
std::vector<Boxed_Value> parameters;
std::vector<Const_Proxy_Function> functions;
};
}
namespace dispatch
{
namespace detail
{
template<typename FuncType>
bool types_match_except_for_arithmetic(const FuncType &t_func, const std::vector<Boxed_Value> &plist,
const Dynamic_Cast_Conversions &t_conversions)
{
if (t_func->get_arity() != static_cast<int>(plist.size()))
{
return false;
}
const std::vector<Type_Info> &types = t_func->get_param_types();
assert(plist.size() == types.size() - 1);
for (size_t i = 0; i < plist.size(); ++i)
{
if (Proxy_Function_Base::compare_type_to_param(types[i+1], plist[i], t_conversions)
|| (types[i+1].is_arithmetic() && plist[i].get_type_info().is_arithmetic()))
{
// types continue to match
} else {
return false;
}
}
// all types match
return true;
}
template<typename InItr>
Boxed_Value dispatch_with_conversions(InItr begin, const InItr &end, const std::vector<Boxed_Value> &plist,
const Dynamic_Cast_Conversions &t_conversions)
{
InItr orig(begin);
InItr matching_func(end);
while (begin != end)
{
if (types_match_except_for_arithmetic(*begin, plist, t_conversions))
{
if (matching_func == end)
{
matching_func = begin;
} else {
// More than one function matches, not attempting
throw exception::dispatch_error(plist, std::vector<Const_Proxy_Function>(orig, end));
}
}
++begin;
}
if (matching_func == end)
{
// no appropriate function to attempt arithmetic type conversion on
throw exception::dispatch_error(plist, std::vector<Const_Proxy_Function>(orig, end));
}
std::vector<Boxed_Value> newplist;
const std::vector<Type_Info> &tis = (*matching_func)->get_param_types();
for (size_t i = 0; i < plist.size(); ++i)
{
if (tis[i+1].is_arithmetic()
&& plist[i].get_type_info().is_arithmetic()) {
newplist.push_back(Boxed_Number(plist[i]).get_as(tis[i+1]).bv);
} else {
newplist.push_back(plist[i]);
}
}
try {
return (*(*matching_func))(newplist, t_conversions);
} catch (const exception::bad_boxed_cast &) {
//parameter failed to cast
} catch (const exception::arity_error &) {
//invalid num params
} catch (const exception::guard_error &) {
//guard failed to allow the function to execute
}
throw exception::dispatch_error(plist, std::vector<Const_Proxy_Function>(orig, end));
}
}
/**
* Take a vector of functions and a vector of parameters. Attempt to execute
@@ -579,14 +718,15 @@ namespace chaiscript
*/
template<typename InItr>
Boxed_Value dispatch(InItr begin, const InItr &end,
const std::vector<Boxed_Value> &plist)
const std::vector<Boxed_Value> &plist, const Dynamic_Cast_Conversions &t_conversions)
{
InItr orig(begin);
while (begin != end)
{
try {
if ((*begin)->filter(plist))
if ((*begin)->filter(plist, t_conversions))
{
return (*(*begin))(plist);
return (*(*begin))(plist, t_conversions);
}
} catch (const exception::bad_boxed_cast &) {
//parameter failed to cast, try again
@@ -599,7 +739,7 @@ namespace chaiscript
++begin;
}
throw exception::dispatch_error(plist);
return detail::dispatch_with_conversions(orig, end, plist, t_conversions);
}
/**
@@ -609,9 +749,9 @@ namespace chaiscript
*/
template<typename Funcs>
Boxed_Value dispatch(const Funcs &funcs,
const std::vector<Boxed_Value> &plist)
const std::vector<Boxed_Value> &plist, const Dynamic_Cast_Conversions &t_conversions)
{
return dispatch::dispatch(funcs.begin(), funcs.end(), plist);
return dispatch::dispatch(funcs.begin(), funcs.end(), plist, t_conversions);
}
}
}

View File

@@ -1,9 +1,16 @@
// This file is distributed under the BSD License.
// See "license.txt" for details.
// Copyright 2009-2012, Jonathan Turner (jonathan@emptycrate.com)
// and Jason Turner (jason@emptycrate.com)
// Copyright 2009-2014, Jason Turner (jason@emptycrate.com)
// http://www.chaiscript.com
#include <boost/preprocessor.hpp>
#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], &t_conversions)
#define trycast(z,n,text) chaiscript::boxed_cast<Param ## n>(params[n], &t_conversions);
#ifndef BOOST_PP_IS_ITERATING
#ifndef CHAISCRIPT_PROXY_FUNCTIONS_DETAIL_HPP_
#define CHAISCRIPT_PROXY_FUNCTIONS_DETAIL_HPP_
@@ -12,6 +19,8 @@
#include "type_info.hpp"
#include "handle_return.hpp"
#include <string>
#include <boost/function.hpp>
#include <boost/bind.hpp>
#include <stdexcept>
#include <vector>
@@ -32,13 +41,26 @@ namespace chaiscript
{
}
virtual ~arity_error() noexcept {}
virtual ~arity_error() throw() {}
int got;
int expected;
};
}
}
#define BOOST_PP_ITERATION_LIMITS ( 0, 10 )
#define BOOST_PP_FILENAME_1 <chaiscript/dispatchkit/proxy_functions_detail.hpp>
#include BOOST_PP_ITERATE()
# endif
#else
# define n BOOST_PP_ITERATION()
namespace chaiscript
{
namespace dispatch
{
namespace detail
@@ -47,105 +69,106 @@ namespace chaiscript
* Used by Proxy_Function_Impl to return a list of all param types
* it contains.
*/
template<typename Ret, typename ... Params>
std::vector<Type_Info> build_param_type_list(Ret (*)(Params...))
template<typename Ret BOOST_PP_COMMA_IF(n) BOOST_PP_ENUM_PARAMS(n, typename Param) >
std::vector<Type_Info> build_param_type_list(Ret (*)(BOOST_PP_ENUM_PARAMS(n, Param)))
{
return std::vector<Type_Info> { chaiscript::detail::Get_Type_Info<Ret>::get(),
chaiscript::detail::Get_Type_Info<Params>::get()... };
std::vector<Type_Info> ti;
ti.push_back(chaiscript::detail::Get_Type_Info<Ret>::get());
BOOST_PP_REPEAT(n, gettypeinfo, ~)
return ti;
}
// Forward declaration
template<typename ... Rest>
struct Try_Cast;
// implementation
template<typename Param, typename ... Rest>
struct Try_Cast<Param, Rest...>
{
static void do_try(const std::vector<Boxed_Value> &params, int generation)
{
boxed_cast<Param>(params[generation]);
Try_Cast<Rest...>::do_try(params, generation+1);
}
};
// 0th case
template<>
struct Try_Cast<>
{
static void do_try(const std::vector<Boxed_Value> &, int)
{
}
};
/**
* Used by Proxy_Function_Impl to determine if it is equivalent to another
* Proxy_Function_Impl object. This function is primarly used to prevent
* registration of two functions with the exact same signatures
*/
template<typename Ret, typename ... Params>
bool compare_types_cast(Ret (*)(Params...),
const std::vector<Boxed_Value> &params)
{
try {
Try_Cast<Params...>::do_try(params, 0);
} catch (const exception::bad_boxed_cast &) {
return false;
}
return true;
}
template<typename Ret, int count, typename ... Params>
struct Call_Func
{
template<typename ... InnerParams>
static Ret do_call(const std::function<Ret (Params...)> &f,
const std::vector<Boxed_Value> &params, InnerParams &&... innerparams)
{
return Call_Func<Ret, count - 1, Params...>::do_call(f, params, std::forward<InnerParams>(innerparams)..., params[sizeof...(Params) - count]);
}
};
template<typename Ret, typename ... Params>
struct Call_Func<Ret, 0, Params...>
{
template<typename ... InnerParams>
static Ret do_call(const std::function<Ret (Params...)> &f,
const std::vector<Boxed_Value> &, InnerParams &&... innerparams)
{
return f(boxed_cast<Params>(std::forward<InnerParams>(innerparams))...);
}
};
/**
* Used by Proxy_Function_Impl to perform typesafe execution of a function.
* The function attempts to unbox each paramter to the expected type.
* if any unboxing fails the execution of the function fails and
* the bad_boxed_cast is passed up to the caller.
*/
template<typename Ret, typename ... Params>
Ret call_func(const std::function<Ret (Params...)> &f,
const std::vector<Boxed_Value> &params)
#ifdef BOOST_MSVC
#pragma warning(push)
#pragma warning(disable : 4100)
#endif
#ifdef __llvm__
#pragma clang diagnostic push
#pragma clang diagnostic ignored "-Wunused-parameter"
#endif
template<typename Ret BOOST_PP_COMMA_IF(n) BOOST_PP_ENUM_PARAMS(n, typename Param)>
Ret call_func(const boost::function<Ret (BOOST_PP_ENUM_PARAMS(n, Param))> &f,
const std::vector<Boxed_Value> &params, const Dynamic_Cast_Conversions & BOOST_PP_IF(n, t_conversions, BOOST_PP_EMPTY))
#ifdef __llvm__
#pragma clang diagnostic pop
#endif
{
if (params.size() == sizeof...(Params))
if (params.size() != n)
{
return Call_Func<Ret, sizeof...(Params), Params...>::do_call(f, params);
}
throw exception::arity_error(static_cast<int>(params.size()), sizeof...(Params));
}
throw exception::arity_error(static_cast<int>(params.size()), n);
} else {
return f(BOOST_PP_REPEAT(n, casthelper, ~));
}
}
#ifdef BOOST_MSVC
#pragma warning(pop)
#endif
/**
* Used by Proxy_Function_Impl to determine if it is equivalent to another
* Proxy_Function_Impl object. This function is primarly used to prevent
* registration of two functions with the exact same signatures
*/
#ifdef BOOST_MSVC
#pragma warning(push)
#pragma warning(disable : 4100)
#endif
#ifdef __llvm__
#pragma clang diagnostic push
#pragma clang diagnostic ignored "-Wunused-parameter"
#endif
template<typename Ret BOOST_PP_COMMA_IF(n) BOOST_PP_ENUM_PARAMS(n, typename Param)>
bool compare_types_cast(Ret (*)(BOOST_PP_ENUM_PARAMS(n, Param)),
const std::vector<Boxed_Value> & BOOST_PP_IF(n, params, BOOST_PP_EMPTY), const Dynamic_Cast_Conversions &t_conversions)
#ifdef __llvm__
#pragma clang diagnostic pop
#endif
{
try {
(void)t_conversions;
BOOST_PP_REPEAT(n, trycast, ~);
} catch (const exception::bad_boxed_cast &) {
return false;
}
return true;
}
#ifdef BOOST_MSVC
#pragma warning(pop)
#endif
}
}
}
#undef n
#undef gettypeinfo
#undef casthelper
#undef trycast
#endif
#ifndef BOOST_PP_IS_ITERATING
namespace chaiscript
{
@@ -157,9 +180,9 @@ namespace chaiscript
struct Do_Call
{
template<typename Fun>
static Boxed_Value go(const std::function<Fun> &fun, const std::vector<Boxed_Value> &params)
static Boxed_Value go(const boost::function<Fun> &fun, const std::vector<Boxed_Value> &params, const Dynamic_Cast_Conversions &t_conversions)
{
return Handle_Return<Ret>::handle(call_func(fun, params));
return Handle_Return<Ret>::handle(call_func(fun, params, t_conversions));
}
};
@@ -167,9 +190,9 @@ namespace chaiscript
struct Do_Call<void>
{
template<typename Fun>
static Boxed_Value go(const std::function<Fun> &fun, const std::vector<Boxed_Value> &params)
static Boxed_Value go(const boost::function<Fun> &fun, const std::vector<Boxed_Value> &params, const Dynamic_Cast_Conversions &t_conversions)
{
call_func(fun, params);
call_func(fun, params, t_conversions);
return Handle_Return<void>::handle();
}
};

View File

@@ -1,7 +1,7 @@
// This file is distributed under the BSD License.
// See "license.txt" for details.
// Copyright 2009-2012, Jonathan Turner (jonathan@emptycrate.com)
// and Jason Turner (jason@emptycrate.com)
// Copyright 2009-2014, Jason Turner (jason@emptycrate.com)
// http://www.chaiscript.com
#ifndef CHAISCRIPT_REGISTER_FUNCTION_HPP_
@@ -9,6 +9,12 @@
#include "dispatchkit.hpp"
#include "bind_first.hpp"
#include <boost/function.hpp>
#include <boost/bind.hpp>
#include <boost/function_types/components.hpp>
#include <boost/function_types/function_type.hpp>
#include <boost/function_types/is_member_object_pointer.hpp>
#include <boost/function_types/is_member_function_pointer.hpp>
namespace chaiscript
{
@@ -16,48 +22,39 @@ namespace chaiscript
{
namespace detail
{
template<typename T>
struct FunctionSignature
{
};
template<typename Sig>
struct FunctionSignature<std::function<Sig> >
{
typedef Sig Signature;
};
template<typename Ret, typename ... Args>
std::function<Ret (Args...) > to_function(Ret (*func)(Args...))
{
return std::function<Ret (Args...)>(func);
}
template<typename Ret, typename Class, typename ... Args>
std::function<Ret (Class &, Args...) > to_function(Ret (Class::*func)(Args...))
{
return std::function<Ret (Class &, Args...)>(func);
}
template<typename Ret, typename Class, typename ... Args>
std::function<Ret (const Class &, Args...) > to_function(Ret (Class::*func)(Args...) const)
{
return std::function<Ret (const Class &, Args...)>(func);
}
template<bool Object>
template<bool Object, bool MemFn>
struct Fun_Helper
{
template<typename T>
static Proxy_Function go(T t)
{
return Proxy_Function(
new Proxy_Function_Impl<typename FunctionSignature<decltype(to_function(t)) >::Signature>(to_function(t)));
new Proxy_Function_Impl<
typename boost::function_types::function_type<boost::function_types::components<T> >::type> (
boost::function<
typename boost::function_types::function_type<boost::function_types::components<T> >::type
>(t)));
}
};
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)
@@ -68,19 +65,19 @@ namespace chaiscript
}
}
/// \brief Creates a new Proxy_Function object from a std::function object
/// \param[in] f std::function to expose to ChaiScript
/// \brief Creates a new Proxy_Function object from a boost::function object
/// \param[in] f boost::function to expose to ChaiScript
///
/// \b Example:
/// \code
/// std::function<int (char, float, std::string)> f = get_some_function();
/// 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 std::function<T> &f)
Proxy_Function fun(const boost::function<T> &f)
{
return Proxy_Function(new dispatch::Proxy_Function_Impl<T>(f));
}
@@ -108,7 +105,7 @@ namespace chaiscript
template<typename T>
Proxy_Function fun(T t)
{
return dispatch::detail::Fun_Helper<std::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
@@ -125,7 +122,7 @@ namespace chaiscript
/// MyClass obj;
/// chaiscript::ChaiScript chai;
/// // Add function taking only one argument, an int, and permanently bound to "obj"
/// chai.add(fun(&MyClass::memberfunction, std::ref(obj)), "memberfunction");
/// chai.add(fun(&MyClass::memberfunction, boost::ref(obj)), "memberfunction");
/// \endcode
///
/// \sa \ref addingfunctions
@@ -151,7 +148,7 @@ namespace chaiscript
/// chaiscript::ChaiScript chai;
/// // Add function taking only no arguments, and permanently bound to "obj" and "1"
/// // memberfunction() will be equivalent to obj.memberfunction(1)
/// chai.add(fun(&MyClass::memberfunction, std::ref(obj), 1), "memberfunction");
/// chai.add(fun(&MyClass::memberfunction, boost::ref(obj), 1), "memberfunction");
/// \endcode
///
/// \sa \ref addingfunctions

View File

@@ -1,7 +1,7 @@
// This file is distributed under the BSD License.
// See "license.txt" for details.
// Copyright 2009-2012, Jonathan Turner (jonathan@emptycrate.com)
// and Jason Turner (jason@emptycrate.com)
// Copyright 2009-2014, Jason Turner (jason@emptycrate.com)
// http://www.chaiscript.com
#ifndef CHAISCRIPT_TYPE_INFO_HPP_
@@ -9,8 +9,17 @@
#include <string>
#include <typeinfo>
#include <memory>
#include <type_traits>
#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>
#include <boost/type_traits/is_pointer.hpp>
#include <boost/type_traits/is_same.hpp>
#include <boost/type_traits/is_arithmetic.hpp>
#include <boost/type_traits/remove_const.hpp>
#include <boost/type_traits/remove_reference.hpp>
#include <boost/type_traits/remove_pointer.hpp>
#include <boost/ref.hpp>
namespace chaiscript
{
@@ -20,7 +29,7 @@ namespace chaiscript
template<typename T>
struct Bare_Type
{
typedef typename std::remove_cv<typename std::remove_pointer<typename std::remove_reference<T>::type>::type>::type type;
typedef typename boost::remove_const<typename boost::remove_pointer<typename boost::remove_reference<T>::type>::type>::type type;
};
}
@@ -90,6 +99,12 @@ namespace chaiscript
|| (ti.m_bare_type_info && m_bare_type_info && *ti.m_bare_type_info == *m_bare_type_info);
}
bool bare_equal_type_info(const std::type_info &ti) const
{
return m_bare_type_info != 0
&& (*m_bare_type_info) == ti;
}
bool is_const() const { return m_is_const; }
bool is_reference() const { return m_is_reference; }
bool is_void() const { return m_is_void; }
@@ -140,70 +155,70 @@ namespace chaiscript
static Type_Info get()
{
return Type_Info(std::is_const<typename std::remove_pointer<typename std::remove_reference<T>::type>::type>::value, std::is_reference<T>::value, std::is_pointer<T>::value,
std::is_void<T>::value,
std::is_arithmetic<T>::value && !std::is_same<typename std::remove_const<T>::type, bool>::value,
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,
boost::is_arithmetic<T>::value && !boost::is_same<typename boost::remove_const<T>::type, bool>::value,
&typeid(T),
&typeid(typename Bare_Type<T>::type));
}
};
template<typename T>
struct Get_Type_Info<std::shared_ptr<T> >
struct Get_Type_Info<boost::shared_ptr<T> >
{
typedef T type;
static Type_Info get()
{
return Type_Info(std::is_const<T>::value, std::is_reference<T>::value, std::is_pointer<T>::value,
std::is_void<T>::value,
std::is_arithmetic<T>::value && !std::is_same<typename std::remove_const<T>::type, bool>::value,
&typeid(std::shared_ptr<T> ),
return Type_Info(boost::is_const<T>::value, boost::is_reference<T>::value, boost::is_pointer<T>::value,
boost::is_void<T>::value,
boost::is_arithmetic<T>::value && !boost::is_same<typename boost::remove_const<T>::type, bool>::value,
&typeid(boost::shared_ptr<T> ),
&typeid(typename Bare_Type<T>::type));
}
};
template<typename T>
struct Get_Type_Info<const std::shared_ptr<T> &>
struct Get_Type_Info<const boost::shared_ptr<T> &>
{
typedef T type;
static Type_Info get()
{
return Type_Info(std::is_const<T>::value, std::is_reference<T>::value, std::is_pointer<T>::value,
std::is_void<T>::value,
std::is_arithmetic<T>::value && !std::is_same<typename std::remove_const<T>::type, bool>::value,
&typeid(const std::shared_ptr<T> &),
return Type_Info(boost::is_const<T>::value, boost::is_reference<T>::value, boost::is_pointer<T>::value,
boost::is_void<T>::value,
boost::is_arithmetic<T>::value && !boost::is_same<typename boost::remove_const<T>::type, bool>::value,
&typeid(const boost::shared_ptr<T> &),
&typeid(typename Bare_Type<T>::type));
}
};
template<typename T>
struct Get_Type_Info<std::reference_wrapper<T> >
struct Get_Type_Info<boost::reference_wrapper<T> >
{
typedef T type;
static Type_Info get()
{
return Type_Info(std::is_const<T>::value, std::is_reference<T>::value, std::is_pointer<T>::value,
std::is_void<T>::value,
std::is_arithmetic<T>::value && !std::is_same<typename std::remove_const<T>::type, bool>::value,
&typeid(std::reference_wrapper<T> ),
return Type_Info(boost::is_const<T>::value, boost::is_reference<T>::value, boost::is_pointer<T>::value,
boost::is_void<T>::value,
boost::is_arithmetic<T>::value && !boost::is_same<typename boost::remove_const<T>::type, bool>::value,
&typeid(boost::reference_wrapper<T> ),
&typeid(typename Bare_Type<T>::type));
}
};
template<typename T>
struct Get_Type_Info<const std::reference_wrapper<T> &>
struct Get_Type_Info<const boost::reference_wrapper<T> &>
{
typedef T type;
static Type_Info get()
{
return Type_Info(std::is_const<T>::value, std::is_reference<T>::value, std::is_pointer<T>::value,
std::is_void<T>::value,
std::is_arithmetic<T>::value && !std::is_same<typename std::remove_const<T>::type, bool>::value,
&typeid(const std::reference_wrapper<T> &),
return Type_Info(boost::is_const<T>::value, boost::is_reference<T>::value, boost::is_pointer<T>::value,
boost::is_void<T>::value,
boost::is_arithmetic<T>::value && !boost::is_same<typename boost::remove_const<T>::type, bool>::value,
&typeid(const boost::reference_wrapper<T> &),
&typeid(typename Bare_Type<T>::type));
}
};

View File

@@ -1,13 +1,14 @@
// This file is distributed under the BSD License.
// See "license.txt" for details.
// Copyright 2009-2012, Jonathan Turner (jonathan@emptycrate.com)
// and Jason Turner (jason@emptycrate.com)
// Copyright 2009-2014, Jason Turner (jason@emptycrate.com)
// http://www.chaiscript.com
#ifndef CHAISCRIPT_ALGEBRAIC_HPP_
#define CHAISCRIPT_ALGEBRAIC_HPP_
#include "../dispatchkit/dispatchkit.hpp"
#include <chaiscript/dispatchkit/dispatchkit.hpp>
#include <boost/enable_shared_from_this.hpp>
namespace chaiscript
{

View File

@@ -1,14 +1,14 @@
// This file is distributed under the BSD License.
// See "license.txt" for details.
// Copyright 2009-2012, Jonathan Turner (jonathan@emptycrate.com)
// and Jason Turner (jason@emptycrate.com)
// Copyright 2009-2014, Jason Turner (jason@emptycrate.com)
// http://www.chaiscript.com
#ifndef CHAISCRIPT_COMMON_HPP_
#define CHAISCRIPT_COMMON_HPP_
#include <sstream>
#include "../dispatchkit/dispatchkit.hpp"
#include <chaiscript/dispatchkit/dispatchkit.hpp>
#include <boost/enable_shared_from_this.hpp>
namespace chaiscript
{
@@ -21,23 +21,22 @@ namespace chaiscript
public:
enum Type { Error, Int, Float, Id, Char, Str, Eol, Fun_Call, Inplace_Fun_Call, Arg_List, Variable, Equation, Var_Decl,
Comparison, Addition, Subtraction, Multiplication, Division, Modulus, Array_Call, Dot_Access, Quoted_String, Single_Quoted_String,
Lambda, Block, Def, While, If, For, Inline_Array, Inline_Map, Return, File, Prefix, Break, Map_Pair, Value_Range,
Lambda, Block, Def, While, If, For, Inline_Array, Inline_Map, Return, File, Prefix, Break, Continue, Map_Pair, Value_Range,
Inline_Range, Annotation, Try, Catch, Finally, Method, Attr_Decl, Shift, Equality, Bitwise_And, Bitwise_Xor, Bitwise_Or,
Logical_And, Logical_Or, Reference, Switch, Case, Default, Ternary_Cond
Logical_And, Logical_Or, Switch, Case, Default, Ternary_Cond, Noop
};
};
namespace
{
/**
* Helper lookup to get the name of each node type
*/
/// Helper lookup to get the name of each node type
const char *ast_node_type_to_string(int ast_node_type) {
const char *ast_node_types[] = { "Internal Parser Error", "Int", "Float", "Id", "Char", "Str", "Eol", "Fun_Call", "Inplace_Fun_Call", "Arg_List", "Variable", "Equation", "Var_Decl",
"Comparison", "Addition", "Subtraction", "Multiplication", "Division", "Modulus", "Array_Call", "Dot_Access", "Quoted_String", "Single_Quoted_String",
"Lambda", "Block", "Def", "While", "If", "For", "Inline_Array", "Inline_Map", "Return", "File", "Prefix", "Break", "Map_Pair", "Value_Range",
"Lambda", "Block", "Def", "While", "If", "For", "Inline_Array", "Inline_Map", "Return", "File", "Prefix", "Break", "Continue", "Map_Pair", "Value_Range",
"Inline_Range", "Annotation", "Try", "Catch", "Finally", "Method", "Attr_Decl", "Shift", "Equality", "Bitwise_And", "Bitwise_Xor", "Bitwise_Or",
"Logical_And", "Logical_Or", "Reference", "Switch", "Case", "Default", "Ternary Condition"};
"Logical_And", "Logical_Or", "Switch", "Case", "Default", "Ternary Condition", "Noop"};
return ast_node_types[ast_node_type];
}
@@ -55,69 +54,247 @@ namespace chaiscript
};
/// \brief Typedef for pointers to AST_Node objects. Used in building of the AST_Node tree
typedef std::shared_ptr<struct AST_Node> AST_NodePtr;
typedef boost::shared_ptr<AST_Node> AST_NodePtr;
/// \brief Classes which may be thrown during error cases when ChaiScript is executing.
namespace exception
{
/**
* Errors generated during parsing or evaluation
*/
/// Errors generated during parsing or evaluation
struct eval_error : public std::runtime_error {
std::string reason;
File_Position start_position;
File_Position end_position;
std::string filename;
std::string detail;
std::vector<AST_NodePtr> call_stack;
eval_error(const std::string &t_why, const File_Position &t_where, const std::string &t_fname,
const std::vector<Boxed_Value> &t_parameters, const chaiscript::detail::Dispatch_Engine &t_ss) noexcept :
std::runtime_error(format(t_why, t_where, t_fname, t_parameters, t_ss)),
reason(t_why), start_position(t_where), end_position(t_where), filename(t_fname)
const std::vector<Boxed_Value> &t_parameters, const std::vector<chaiscript::Const_Proxy_Function> &t_functions,
bool t_dot_notation,
const chaiscript::detail::Dispatch_Engine &t_ss) :
std::runtime_error(format(t_why, t_where, t_fname, t_parameters, t_dot_notation, t_ss)),
reason(t_why), start_position(t_where), end_position(t_where), filename(t_fname), detail(format_detail(t_functions, t_dot_notation, t_ss))
{}
eval_error(const std::string &t_why,
const std::vector<Boxed_Value> &t_parameters, const chaiscript::detail::Dispatch_Engine &t_ss) noexcept :
std::runtime_error(format(t_why, t_parameters, t_ss)),
reason(t_why)
const std::vector<Boxed_Value> &t_parameters, const std::vector<chaiscript::Const_Proxy_Function> &t_functions,
bool t_dot_notation,
const chaiscript::detail::Dispatch_Engine &t_ss) :
std::runtime_error(format(t_why, t_parameters, t_dot_notation, t_ss)),
reason(t_why), detail(format_detail(t_functions, t_dot_notation, t_ss))
{}
eval_error(const std::string &t_why, const File_Position &t_where, const std::string &t_fname) noexcept :
eval_error(const std::string &t_why, const File_Position &t_where, const std::string &t_fname) :
std::runtime_error(format(t_why, t_where, t_fname)),
reason(t_why), start_position(t_where), end_position(t_where), filename(t_fname)
{}
eval_error(const std::string &t_why) noexcept
eval_error(const std::string &t_why) throw()
: std::runtime_error("Error: \"" + t_why + "\" "),
reason(t_why)
{}
virtual ~eval_error() noexcept {}
std::string pretty_print() const
{
std::ostringstream ss;
ss << what();
if (call_stack.size() > 0) {
ss << "during evaluation at (" << fname(call_stack[0]) << " " << startpos(call_stack[0]) << ")" << std::endl;
ss << std::endl << detail << std::endl;
ss << " " << fname(call_stack[0]) << " (" << startpos(call_stack[0]) << ") '" << pretty(call_stack[0]) << "'";
for (size_t j = 1; j < call_stack.size(); ++j) {
if (id(call_stack[j]) != chaiscript::AST_Node_Type::Block
&& id(call_stack[j]) != chaiscript::AST_Node_Type::File)
{
ss << std::endl;
ss << " from " << fname(call_stack[j]) << " (" << startpos(call_stack[j]) << ") '" << pretty(call_stack[j]) << "'";
}
}
}
ss << std::endl;
return ss.str();
}
virtual ~eval_error() throw() {}
private:
template<typename T>
static int id(const T& t)
{
return t->identifier;
}
template<typename T>
static std::string pretty(const T& t)
{
return t->pretty_print();
}
template<typename T>
static std::string fname(const T& t)
{
return *t->filename;
}
template<typename T>
static std::string startpos(const T& t)
{
std::ostringstream oss;
oss << t->start.line << ", " << t->start.column;
return oss.str();
}
static std::string format_why(const std::string &t_why)
{
return "Error: \"" + t_why + "\"";
}
static std::string format_parameters(const std::vector<Boxed_Value> &t_parameters,
static std::string format_types(const Const_Proxy_Function &t_func,
bool t_dot_notation,
const chaiscript::detail::Dispatch_Engine &t_ss)
{
int arity = t_func->get_arity();
std::vector<Type_Info> types = t_func->get_param_types();
std::string retval;
if (arity == -1)
{
retval = "(...)";
if (t_dot_notation)
{
retval = "(Object)." + retval;
}
} else if (types.size() <= 1) {
retval = "()";
} else {
std::stringstream ss;
ss << "(";
std::string paramstr;
for (size_t index = 1;
index != types.size();
++index)
{
paramstr += (types[index].is_const()?"const ":"");
paramstr += t_ss.get_type_name(types[index]);
if (index == 1 && t_dot_notation)
{
paramstr += ").(";
if (types.size() == 2)
{
paramstr += ", ";
}
} else {
paramstr += ", ";
}
}
ss << paramstr.substr(0, paramstr.size() - 2);
ss << ")";
retval = ss.str();
}
boost::shared_ptr<const dispatch::Dynamic_Proxy_Function> dynfun
= boost::dynamic_pointer_cast<const dispatch::Dynamic_Proxy_Function>(t_func);
if (dynfun)
{
Proxy_Function f = dynfun->get_guard();
if (f)
{
boost::shared_ptr<const dispatch::Dynamic_Proxy_Function> dynfunguard
= boost::dynamic_pointer_cast<const dispatch::Dynamic_Proxy_Function>(f);
if (dynfunguard)
{
retval += " : " + format_guard(dynfunguard->get_parse_tree());
}
}
retval += "\n Defined at " + format_location(dynfun->get_parse_tree());
}
return retval;
}
template<typename T>
static std::string format_guard(const T &t)
{
return t->pretty_print();
}
template<typename T>
static std::string format_location(const T &t)
{
std::ostringstream oss;
oss << "(" << *t->filename << " " << t->start.line << ", " << t->start.column << ")";
return oss.str();
}
static std::string format_detail(const std::vector<chaiscript::Const_Proxy_Function> &t_functions,
bool t_dot_notation,
const chaiscript::detail::Dispatch_Engine &t_ss)
{
std::stringstream ss;
ss << "With parameters: (";
if (t_functions.size() == 1)
{
ss << " Expected: " << format_types(t_functions[0], t_dot_notation, t_ss) << std::endl;
} else {
ss << " " << t_functions.size() << " overloads available:" << std::endl;
for (std::vector<chaiscript::Const_Proxy_Function>::const_iterator itr = t_functions.begin();
itr != t_functions.end();
++itr)
{
ss << " " << format_types((*itr), t_dot_notation, t_ss) << std::endl;
}
}
return ss.str();
}
static std::string format_parameters(const std::vector<Boxed_Value> &t_parameters,
bool t_dot_notation,
const chaiscript::detail::Dispatch_Engine &t_ss)
{
std::stringstream ss;
ss << "(";
if (!t_parameters.empty())
{
std::string paramstr;
for (const Boxed_Value &bv: t_parameters)
for (std::vector<Boxed_Value>::const_iterator itr = t_parameters.begin();
itr != t_parameters.end();
++itr)
{
paramstr += (itr->is_const()?"const ":"");
paramstr += t_ss.type_name(*itr);
if (itr == t_parameters.begin() && t_dot_notation)
{
paramstr += ").(";
if (t_parameters.size() == 1)
{
paramstr += (bv.is_const()?"const ":"");
paramstr += t_ss.type_name(bv);
paramstr += ", ";
}
} else {
paramstr += ", ";
}
}
ss << paramstr.substr(0, paramstr.size() - 2);
}
@@ -148,14 +325,14 @@ namespace chaiscript
}
static std::string format(const std::string &t_why, const File_Position &t_where, const std::string &t_fname,
const std::vector<Boxed_Value> &t_parameters, const chaiscript::detail::Dispatch_Engine &t_ss)
const std::vector<Boxed_Value> &t_parameters, bool t_dot_notation, const chaiscript::detail::Dispatch_Engine &t_ss)
{
std::stringstream ss;
ss << format_why(t_why);
ss << " ";
ss << format_parameters(t_parameters, t_ss);
ss << "With parameters: " << format_parameters(t_parameters, t_dot_notation, t_ss);
ss << " ";
ss << format_filename(t_fname);
@@ -167,14 +344,16 @@ namespace chaiscript
}
static std::string format(const std::string &t_why,
const std::vector<Boxed_Value> &t_parameters, const chaiscript::detail::Dispatch_Engine &t_ss)
const std::vector<Boxed_Value> &t_parameters,
bool t_dot_notation,
const chaiscript::detail::Dispatch_Engine &t_ss)
{
std::stringstream ss;
ss << format_why(t_why);
ss << " ";
ss << format_parameters(t_parameters, t_ss);
ss << "With parameters: " << format_parameters(t_parameters, t_dot_notation, t_ss);
ss << " ";
return ss.str();
@@ -196,33 +375,44 @@ namespace chaiscript
}
};
/**
* Errors generated when loading a file
*/
/// Errors generated when loading a file
struct file_not_found_error : public std::runtime_error {
file_not_found_error(const std::string &t_filename) noexcept
file_not_found_error(const std::string &t_filename) throw()
: std::runtime_error("File Not Found: " + t_filename)
{ }
virtual ~file_not_found_error() noexcept {}
virtual ~file_not_found_error() throw() {}
};
}
/// \brief Struct that doubles as both a parser ast_node and an AST node.
struct AST_Node : std::enable_shared_from_this<AST_Node> {
struct AST_Node : boost::enable_shared_from_this<AST_Node> {
public:
const std::string text;
const int identifier; //< \todo shouldn't this be a strongly typed enum value?
std::shared_ptr<const std::string> filename;
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
*/
virtual std::string pretty_print() const
{
std::ostringstream oss;
oss << text;
for (unsigned int j = 0; j < this->children.size(); ++j) {
oss << this->children[j]->pretty_print();
}
return oss.str();
}
/// Prints the contents of an AST node, including its children, recursively
std::string to_string(std::string t_prepend = "") {
std::ostringstream oss;
@@ -245,7 +435,7 @@ namespace chaiscript
return eval_internal(t_e);
} catch (exception::eval_error &ee) {
ee.call_stack.push_back(shared_from_this());
throw ee;
throw;
}
}
@@ -256,14 +446,14 @@ namespace chaiscript
}
protected:
AST_Node(const std::string &t_ast_node_text, int t_id, const std::shared_ptr<std::string> &t_fname,
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 std::shared_ptr<std::string> &t_fname) :
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() {}
@@ -284,22 +474,27 @@ namespace chaiscript
{
namespace detail
{
/**
* Special type for returned values
*/
/// Special type for returned values
struct Return_Value {
Boxed_Value retval;
Return_Value(const Boxed_Value &t_return_value) : retval(t_return_value) { }
};
/**
* Special type indicating a call to 'break'
*/
/// Special type indicating a call to 'break'
struct Break_Loop {
Break_Loop() { }
};
/// Special type indicating a call to 'continue'
struct Continue_Loop {
Continue_Loop() { }
};
/// Creates a new scope then pops it on destruction
struct Scope_Push_Pop
{

View File

@@ -1,7 +1,7 @@
// This file is distributed under the BSD License.
// See "license.txt" for details.
// Copyright 2009-2012, Jonathan Turner (jonathan@emptycrate.com)
// and Jason Turner (jason@emptycrate.com)
// Copyright 2009-2014, Jason Turner (jason@emptycrate.com)
// http://www.chaiscript.com
#ifndef CHAISCRIPT_ENGINE_HPP_
@@ -10,17 +10,12 @@
#include <exception>
#include <fstream>
#include "../chaiscript_defines.hpp"
#include "chaiscript_common.hpp"
#if defined(__linux__) || defined(__unix__) || defined(__APPLE__)
#include <unistd.h>
#endif
#ifdef _POSIX_VERSION
#include <dlfcn.h>
#else
#ifdef CHAISCRIPT_WINDOWS
#ifdef BOOST_WINDOWS
#define VC_EXTRA_LEAN
#define WIN32_LEAN_AND_MEAN
#include <Windows.h>
@@ -39,12 +34,12 @@ namespace chaiscript
/// \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 &t_reason) noexcept
load_module_error(const std::string &t_reason) throw()
: std::runtime_error(t_reason)
{
}
virtual ~load_module_error() noexcept
virtual ~load_module_error() throw()
{
}
};
@@ -62,7 +57,7 @@ namespace chaiscript
{
if (!m_data)
{
throw chaiscript::exception::load_module_error(dlerror());
throw exception::load_module_error(dlerror());
}
}
@@ -85,7 +80,7 @@ namespace chaiscript
{
if (!m_symbol)
{
throw chaiscript::exception::load_module_error(dlerror());
throw exception::load_module_error(dlerror());
}
}
@@ -185,7 +180,7 @@ namespace chaiscript
{
if (!m_data)
{
throw chaiscript::exception::load_module_error(GetErrorMessage(GetLastError()));
throw exception::load_module_error(GetErrorMessage(GetLastError()));
}
}
@@ -205,7 +200,7 @@ namespace chaiscript
{
if (!m_symbol)
{
throw chaiscript::exception::load_module_error(GetErrorMessage(GetLastError()));
throw exception::load_module_error(GetErrorMessage(GetLastError()));
}
}
@@ -228,7 +223,7 @@ namespace chaiscript
{
Loadable_Module(const std::string &, const std::string &)
{
throw chaiscript::exception::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 m_moduleptr;
@@ -236,7 +231,7 @@ namespace chaiscript
#endif
#endif
typedef std::shared_ptr<Loadable_Module> Loadable_Module_Ptr;
typedef boost::shared_ptr<Loadable_Module> Loadable_Module_Ptr;
}
@@ -256,9 +251,8 @@ namespace chaiscript
chaiscript::detail::Dispatch_Engine m_engine;
/**
* Evaluates the given string in by parsing it and running the results through the evaluator
*/
/// Evaluates the given string in by parsing it and running the results through the evaluator
Boxed_Value do_eval(const std::string &t_input, const std::string &t_filename = "__EVAL__", bool /* t_internal*/ = false)
{
try {
@@ -287,9 +281,8 @@ namespace chaiscript
}
/**
* Evaluates the given string, used during eval() inside of a script
*/
/// Evaluates the given string, used during eval() inside of a script
const Boxed_Value internal_eval(const std::string &t_e) {
try {
return do_eval(t_e, "__EVAL__", true);
@@ -298,17 +291,18 @@ namespace chaiscript
}
}
/**
* Returns the current evaluation m_engine
*/
/// Returns the current evaluation m_engine
chaiscript::detail::Dispatch_Engine &get_eval_engine() {
return m_engine;
}
/**
* Builds all the requirements for ChaiScript, including its evaluator and a run of its prelude.
*/
void build_eval_system(const ModulePtr &t_lib) {
/// 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("auto");
m_engine.add_reserved_word("def");
m_engine.add_reserved_word("fun");
m_engine.add_reserved_word("while");
@@ -318,27 +312,32 @@ namespace chaiscript
m_engine.add_reserved_word("&&");
m_engine.add_reserved_word("||");
m_engine.add_reserved_word(",");
m_engine.add_reserved_word("auto");
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 (t_lib)
{
add(t_lib);
}
add(Bootstrap::bootstrap());
m_engine.add(fun(&chaiscript::detail::Dispatch_Engine::dump_system, std::ref(m_engine)), "dump_system");
m_engine.add(fun(&chaiscript::detail::Dispatch_Engine::dump_object, std::ref(m_engine)), "dump_object");
m_engine.add(fun(&chaiscript::detail::Dispatch_Engine::is_type, std::ref(m_engine)), "is_type");
m_engine.add(fun(&chaiscript::detail::Dispatch_Engine::type_name, std::ref(m_engine)), "type_name");
m_engine.add(fun(&chaiscript::detail::Dispatch_Engine::function_exists, std::ref(m_engine)), "function_exists");
m_engine.add(fun(&chaiscript::detail::Dispatch_Engine::get_function_objects, std::ref(m_engine)), "get_functions");
m_engine.add(fun(&chaiscript::detail::Dispatch_Engine::get_scripting_objects, std::ref(m_engine)), "get_objects");
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_function_objects, boost::ref(m_engine)), "get_functions");
m_engine.add(fun(&chaiscript::detail::Dispatch_Engine::get_scripting_objects, boost::ref(m_engine)), "get_objects");
m_engine.add(fun(&chaiscript::detail::Dispatch_Engine::get_type_name, std::ref(m_engine)), "name");
m_engine.add(Proxy_Function(new dispatch::Dynamic_Proxy_Function(boost::bind(&chaiscript::detail::Dispatch_Engine::call_exists, boost::ref(m_engine), _1))),
"call_exists");
m_engine.add(fun<Boxed_Value (const dispatch::Proxy_Function_Base *, const std::vector<Boxed_Value> &)>(boost::bind(&chaiscript::dispatch::Proxy_Function_Base::operator(), _1, _2, boost::ref(m_engine.conversions()))), "call");
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&);
@@ -347,6 +346,11 @@ namespace chaiscript
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");
@@ -354,14 +358,13 @@ namespace chaiscript
do_eval(chaiscript_prelude, "standard prelude");
}
/**
* Helper function for loading a file
*/
/// 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 chaiscript::exception::file_not_found_error(t_filename);
throw exception::file_not_found_error(t_filename);
}
std::streampos size = infile.tellg();
@@ -381,11 +384,9 @@ namespace chaiscript
public:
/// \brief Constructor for ChaiScript
/// \param[in] t_lib Standard library to apply to this ChaiScript instance
/// \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 ModulePtr &t_lib,
const std::vector<std::string> &t_modulepaths = std::vector<std::string>(),
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)
{
@@ -399,74 +400,9 @@ namespace chaiscript
m_usepaths.push_back("");
}
build_eval_system(t_lib);
build_eval_system();
}
/// \brief Constructor for ChaiScript.
///
/// This version of the ChaiScript constructor attempts to find the stdlib module to load
/// at runtime generates an error if it cannot be found.
///
/// \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("");
}
#ifdef _POSIX_VERSION
// If on Unix, add the path of the current executable to the module search path
// as windows would do
union cast_union
{
void (ChaiScript::*in_ptr)(const std::string&);
void *out_ptr;
};
Dl_info rInfo;
memset( &rInfo, 0, sizeof(rInfo) );
cast_union u;
u.in_ptr = &ChaiScript::use;
if ( dladdr((void*)(u.out_ptr), &rInfo) && rInfo.dli_fname ) {
std::string dllpath(rInfo.dli_fname);
size_t lastslash = dllpath.rfind('/');
if (lastslash != std::string::npos)
{
dllpath.erase(lastslash);
}
// Let's see if this is a link that we should expand
std::vector<char> buf(2048);
size_t pathlen = readlink(dllpath.c_str(), &buf.front(), buf.size());
if (pathlen > 0 && pathlen < buf.size())
{
dllpath = std::string(&buf.front(), pathlen);
}
m_modulepaths.push_back(dllpath+"/");
}
#endif
// attempt to load the stdlib
load_module("chaiscript_stdlib");
build_eval_system(ModulePtr());
}
/// \brief Loads and parses a file. If the file is already, it is not reloaded
/// The use paths specified at ChaiScript construction time are searched for the
/// requested file.
@@ -479,14 +415,15 @@ namespace chaiscript
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);
chaiscript::detail::threading::unique_lock<chaiscript::detail::threading::recursive_mutex> l(m_use_mutex);
chaiscript::detail::threading::unique_lock<chaiscript::detail::threading::shared_mutex> l2(m_mutex);
if (m_used_files.count(appendedpath) == 0)
{
m_used_files.insert(appendedpath);
l2.unlock();
eval_file(appendedpath);
l2.lock();
m_used_files.insert(appendedpath);
}
return; // return, we loaded it, or it was already loaded
@@ -504,7 +441,7 @@ namespace chaiscript
/// \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 chaiscript::exception::global_non_const If t_bv is not a constant object
/// \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)
{
@@ -512,6 +449,17 @@ namespace chaiscript
return *this;
}
/// \brief Adds a mutable 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
/// \warning The user is responsible for making sure the object is thread-safe if necessary
/// ChaiScript is thread-safe but provides no threading locking mechanism to the script
ChaiScript &add_global(const Boxed_Value &t_bv, const std::string &t_name)
{
m_engine.add_global(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
@@ -522,8 +470,12 @@ namespace chaiscript
std::set<std::string> active_loaded_modules;
};
/// \brief Returns a state object that represents the current state of the system
/// \return Current state of the system
/// \brief Returns a state object that represents the current state of the global system
///
/// The global system includes the reserved words, global const objects, functions and types.
/// local variables are thread specific and not included.
///
/// \return Current state of the global system
///
/// \b Example:
///
@@ -544,6 +496,10 @@ namespace chaiscript
}
/// \brief Sets the state of the system
///
/// The global system includes the reserved words, global objects, functions and types.
/// local variables are thread specific and not included.
///
/// \param[in] t_state New state to set
///
/// \b Example:
@@ -563,7 +519,23 @@ namespace chaiscript
m_engine.set_state(t_state.engine_state);
}
/// \brief Adds a type, function or object to ChaiScript
/// \returns All values in the local thread state, added through the add() function
std::map<std::string, Boxed_Value> get_locals() const
{
return m_engine.get_locals();
}
/// \brief Sets all of the locals for the current thread state.
///
/// \param[in] t_locals The map<name, value> set of variables to replace the current state with
///
/// Any existing locals are removed and the given set of variables is added
void set_locals(const std::map<std::string, Boxed_Value> &t_locals)
{
m_engine.set_locals(t_locals);
}
/// \brief Adds a type, function or object to ChaiScript. Objects are added to the local thread state.
/// \param[in] t_t Item to add
/// \param[in] t_name Name of item to add
/// \returns Reference to current ChaiScript object
@@ -620,7 +592,7 @@ namespace chaiscript
/// 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 chaiscript::exception::load_module_error In the event that no matching module can be found.
/// \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;
@@ -644,7 +616,7 @@ namespace chaiscript
std::string name = m_modulepaths[i] + prefixes[j] + t_module_name + postfixes[k];
load_module(t_module_name, name);
return;
} catch (const chaiscript::exception::load_module_error &e) {
} catch (const exception::load_module_error &e) {
errors.push_back(e);
// Try next set
}
@@ -666,7 +638,7 @@ namespace chaiscript
errstring += itr->what();
}
throw chaiscript::exception::load_module_error("Unable to find module: " + t_module_name + " Errors: " + errstring);
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
@@ -700,16 +672,16 @@ namespace chaiscript
///
/// \return result of the script execution
///
/// \throw chaiscript::exception::eval_error In the case that evaluation fails.
/// \throw exception::eval_error In the case that evaluation fails.
Boxed_Value operator()(const std::string &t_script, const Exception_Handler &t_handler = Exception_Handler())
{
try {
return do_eval(t_script);
} catch (Boxed_Value &bv) {
if (t_handler) {
t_handler->handle(bv);
t_handler->handle(bv, m_engine);
}
throw bv;
throw;
}
}
@@ -718,42 +690,54 @@ namespace chaiscript
/// \tparam T Type to extract from the result value of the script execution
/// \param[in] t_input Script to execute
/// \param[in] t_handler Optional Exception_Handler used for automatic unboxing of script thrown exceptions
/// \param[in] t_filename Optional filename to report to the user for where the error occured. Useful
/// in special cases where you are loading a file internally instead of using eval_file
///
/// \return result of the script execution
///
/// \throw chaiscript::exception::eval_error In the case that evaluation fails.
/// \throw chaiscript::exception::bad_boxed_cast In the case that evaluation succeeds but the result value cannot be converted
/// \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 &t_input, const Exception_Handler &t_handler = Exception_Handler())
T eval(const std::string &t_input, const Exception_Handler &t_handler = Exception_Handler(), const std::string &t_filename="__EVAL__")
{
try {
return boxed_cast<T>(do_eval(t_input));
return m_engine.boxed_cast<T>(do_eval(t_input, t_filename));
} catch (Boxed_Value &bv) {
if (t_handler) {
t_handler->handle(bv);
t_handler->handle(bv, m_engine);
}
throw bv;
throw;
}
}
/// \brief casts an object while applying any Dynamic_Conversion available
template<typename Type>
typename detail::Cast_Helper<Type>::Result_Type boxed_cast(const Boxed_Value &bv) const
{
return m_engine.boxed_cast<Type>(bv);
}
/// \brief Evaluates a string.
///
/// \param[in] t_input Script to execute
/// \param[in] t_handler Optional Exception_Handler used for automatic unboxing of script thrown exceptions
/// \param[in] t_filename Optional filename to report to the user for where the error occured. Useful
/// in special cases where you are loading a file internally instead of using eval_file
///
/// \return result of the script execution
///
/// \throw chaiscript::exception::eval_error In the case that evaluation fails.
Boxed_Value eval(const std::string &t_input, const Exception_Handler &t_handler = Exception_Handler())
/// \throw exception::eval_error In the case that evaluation fails.
Boxed_Value eval(const std::string &t_input, const Exception_Handler &t_handler = Exception_Handler(), const std::string &t_filename="__EVAL__")
{
try {
return do_eval(t_input);
return do_eval(t_input, t_filename);
} catch (Boxed_Value &bv) {
if (t_handler) {
t_handler->handle(bv);
t_handler->handle(bv, m_engine);
}
throw bv;
throw;
}
}
@@ -761,15 +745,15 @@ namespace chaiscript
/// \param[in] t_filename File to load and parse.
/// \param[in] t_handler Optional Exception_Handler used for automatic unboxing of script thrown exceptions
/// \return result of the script execution
/// \throw chaiscript::exception::eval_error In the case that evaluation fails.
/// \throw exception::eval_error In the case that evaluation fails.
Boxed_Value eval_file(const std::string &t_filename, const Exception_Handler &t_handler = Exception_Handler()) {
try {
return do_eval(load_file(t_filename), t_filename);
} catch (Boxed_Value &bv) {
if (t_handler) {
t_handler->handle(bv);
t_handler->handle(bv, m_engine);
}
throw bv;
throw;
}
}
@@ -778,18 +762,18 @@ namespace chaiscript
/// \param[in] t_filename File to load and parse.
/// \param[in] t_handler Optional Exception_Handler used for automatic unboxing of script thrown exceptions
/// \return result of the script execution
/// \throw chaiscript::exception::eval_error In the case that evaluation fails.
/// \throw chaiscript::exception::bad_boxed_cast In the case that evaluation succeeds but the result value cannot be converted
/// \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 &t_filename, const Exception_Handler &t_handler = Exception_Handler()) {
try {
return boxed_cast<T>(do_eval(load_file(t_filename), t_filename));
return m_engine.boxed_cast<T>(do_eval(load_file(t_filename), t_filename));
} catch (Boxed_Value &bv) {
if (t_handler) {
t_handler->handle(bv);
t_handler->handle(bv, m_engine);
}
throw bv;
throw;
}
}
};

File diff suppressed because it is too large Load Diff

View File

@@ -1,7 +1,7 @@
// This file is distributed under the BSD License.
// See "license.txt" for details.
// Copyright 2009-2012, Jonathan Turner (jonathan@emptycrate.com)
// and Jason Turner (jason@emptycrate.com)
// Copyright 2009-2014, Jason Turner (jason@emptycrate.com)
// http://www.chaiscript.com
#ifndef CHAISCRIPT_PARSER_HPP_
@@ -10,7 +10,6 @@
#include <exception>
#include <fstream>
#include <sstream>
#include <cstring>
#include "chaiscript_prelude.hpp"
#include "chaiscript_common.hpp"
@@ -34,6 +33,8 @@ namespace chaiscript
, bin_alphabet
, id_alphabet
, white_alphabet
, int_suffix_alphabet
, float_suffix_alphabet
, max_alphabet
, lengthof_alphabet = 256
};
@@ -46,7 +47,7 @@ namespace chaiscript
std::string m_multiline_comment_begin;
std::string m_multiline_comment_end;
std::string m_singleline_comment;
std::shared_ptr<std::string> m_filename;
boost::shared_ptr<std::string> m_filename;
std::vector<AST_NodePtr> m_match_stack;
bool m_alphabet[detail::max_alphabet][detail::lengthof_alphabet];
@@ -55,7 +56,8 @@ namespace chaiscript
public:
ChaiScript_Parser()
: m_multiline_comment_begin("/*"),
: m_line(-1), m_col(-1),
m_multiline_comment_begin("/*"),
m_multiline_comment_end("*/"),
m_singleline_comment("//")
{
@@ -176,6 +178,17 @@ namespace chaiscript
m_alphabet[detail::white_alphabet][static_cast<int>(' ')]=true;
m_alphabet[detail::white_alphabet][static_cast<int>('\t')]=true;
m_alphabet[detail::int_suffix_alphabet][static_cast<int>('l')] = true;
m_alphabet[detail::int_suffix_alphabet][static_cast<int>('L')] = true;
m_alphabet[detail::int_suffix_alphabet][static_cast<int>('u')] = true;
m_alphabet[detail::int_suffix_alphabet][static_cast<int>('U')] = true;
m_alphabet[detail::float_suffix_alphabet][static_cast<int>('l')] = true;
m_alphabet[detail::float_suffix_alphabet][static_cast<int>('L')] = true;
m_alphabet[detail::float_suffix_alphabet][static_cast<int>('f')] = true;
m_alphabet[detail::float_suffix_alphabet][static_cast<int>('F')] = true;
}
/**
@@ -344,6 +357,12 @@ namespace chaiscript
++m_input_pos;
++m_col;
}
while (has_more_input() && char_in_alphabet(*m_input_pos, detail::float_suffix_alphabet))
{
++m_input_pos;
++m_col;
}
}
else {
--m_input_pos;
@@ -372,6 +391,11 @@ namespace chaiscript
++m_input_pos;
++m_col;
}
while (has_more_input() && char_in_alphabet(*m_input_pos, detail::int_suffix_alphabet))
{
++m_input_pos;
++m_col;
}
}
else {
--m_input_pos;
@@ -387,6 +411,14 @@ namespace chaiscript
return retval;
}
void IntSuffix_() {
while (has_more_input() && char_in_alphabet(*m_input_pos, detail::int_suffix_alphabet))
{
++m_input_pos;
++m_col;
}
}
/**
* Reads a binary value from input, without skipping initial whitespace
*/
@@ -420,6 +452,173 @@ namespace chaiscript
return retval;
}
Boxed_Value buildFloat(const std::string &t_val)
{
bool float_ = false;
bool long_ = false;
size_t i = t_val.size();
for (; i > 0; --i)
{
char val = t_val[i-1];
if (val == 'f' || val == 'F')
{
float_ = true;
} else if (val == 'l' || val == 'L') {
long_ = true;
} else {
break;
}
}
std::stringstream ss(t_val.substr(0, i));
if (float_)
{
float f;
ss >> f;
return Boxed_Value(const_var(f));
} else if (long_) {
long double f;
ss >> f;
return Boxed_Value(const_var(f));
} else {
double f;
ss >> f;
return Boxed_Value(const_var(f));
}
}
template<typename IntType>
Boxed_Value buildInt(const IntType &t_type, const std::string &t_val)
{
bool unsigned_ = false;
bool long_ = false;
bool longlong_ = false;
size_t i = t_val.size();
for (; i > 0; --i)
{
char val = t_val[i-1];
if (val == 'u' || val == 'U')
{
unsigned_ = true;
} else if (val == 'l' || val == 'L') {
if (long_)
{
longlong_ = true;
}
long_ = true;
} else {
break;
}
}
std::stringstream ss(t_val.substr(0, i));
ss >> t_type;
std::stringstream testu(t_val.substr(0, i));
boost::uint64_t u;
testu >> t_type >> u;
bool unsignedrequired = false;
size_t size = sizeof(int) * 8;
if ((u >> (sizeof(int) * 8)) > 0)
{
//requires something bigger than int
long_ = true;
}
BOOST_ASSERT(sizeof(long) == sizeof(boost::uint64_t) || sizeof(long) * 2 == sizeof(boost::uint64_t));
#ifdef BOOST_MSVC
//Thank you MSVC, yes we know that a constant value is being used in the if
// statment in this compiler / architecture
#pragma warning(push)
#pragma warning(disable : 4127)
#endif
if ( sizeof(long) < sizeof(boost::uint64_t) && (u >> ((sizeof(boost::uint64_t) - sizeof(long)) * 8)) > 0)
{
//requires something bigger than long
longlong_ = true;
}
#ifdef BOOST_MSVC
#pragma warning(pop)
#endif
if (longlong_)
{
size = sizeof(boost::int64_t) * 8;
} else if (long_) {
size = sizeof(long) * 8;
}
if ( (u >> (size - 1)) > 0)
{
unsignedrequired = true;
}
if (unsignedrequired && !unsigned_)
{
if (t_type == &std::hex || t_type == &std::oct)
{
// with hex and octal we are happy to just make it unsigned
unsigned_ = true;
} else {
// with decimal we must bump it up to the next size
if (long_)
{
longlong_ = true;
} else if (!long_ && !longlong_) {
long_ = true;
}
}
}
if (unsigned_)
{
if (longlong_)
{
boost::uint64_t val;
ss >> val;
return Boxed_Value(const_var(val));
} else if (long_) {
unsigned long val;
ss >> val;
return Boxed_Value(const_var(val));
} else {
unsigned int val;
ss >> val;
return Boxed_Value(const_var(val));
}
} else {
if (longlong_)
{
boost::int64_t val;
ss >> val;
return Boxed_Value(const_var(val));
} else if (long_) {
long val;
ss >> val;
return Boxed_Value(const_var(val));
} else {
int val;
ss >> val;
return Boxed_Value(const_var(val));
}
}
}
/**
* Reads a number from the input, detecting if it's an integer or floating point
*/
@@ -436,19 +635,14 @@ namespace chaiscript
if (has_more_input() && char_in_alphabet(*m_input_pos, detail::float_alphabet) ) {
if (Hex_()) {
std::string match(start, m_input_pos);
std::stringstream ss(match);
unsigned int temp_int;
ss >> std::hex >> temp_int;
std::ostringstream out_int;
out_int << static_cast<int>(temp_int);
AST_NodePtr t(new eval::Int_AST_Node(out_int.str(), AST_Node_Type::Int, m_filename, prev_line, prev_col, m_line, m_col));
Boxed_Value i = buildInt(std::hex, match);
AST_NodePtr t(new eval::Int_AST_Node(match, i, m_filename, prev_line, prev_col, m_line, m_col));
m_match_stack.push_back(t);
return true;
}
if (Binary_()) {
std::string match(start, m_input_pos);
int temp_int = 0;
boost::int64_t temp_int = 0;
size_t pos = 0, end = match.length();
while ((pos < end) && (pos < (2 + sizeof(int) * 8))) {
@@ -459,32 +653,36 @@ namespace chaiscript
++pos;
}
std::ostringstream out_int;
out_int << temp_int;
AST_NodePtr t(new eval::Int_AST_Node(out_int.str(), AST_Node_Type::Int, m_filename, prev_line, prev_col, m_line, m_col));
Boxed_Value i;
if (match.length() <= sizeof(int) * 8)
{
i = Boxed_Value(const_var(int(temp_int)));
} else {
i = Boxed_Value(const_var(temp_int));
}
AST_NodePtr t(new eval::Int_AST_Node(match, i, m_filename, prev_line, prev_col, m_line, m_col));
m_match_stack.push_back(t);
return true;
}
if (Float_()) {
std::string match(start, m_input_pos);
AST_NodePtr t(new eval::Float_AST_Node(match, AST_Node_Type::Float, m_filename, prev_line, prev_col, m_line, m_col));
Boxed_Value f = buildFloat(match);
AST_NodePtr t(new eval::Float_AST_Node(match, f, m_filename, prev_line, prev_col, m_line, m_col));
m_match_stack.push_back(t);
return true;
}
else {
IntSuffix_();
std::string match(start, m_input_pos);
if ((match.size() > 0) && (match[0] == '0')) {
std::stringstream ss(match);
unsigned int temp_int;
ss >> std::oct >> temp_int;
std::ostringstream out_int;
out_int << int(temp_int);
AST_NodePtr t(new eval::Int_AST_Node(out_int.str(), AST_Node_Type::Int, m_filename, prev_line, prev_col, m_line, m_col));
Boxed_Value i = buildInt(std::oct, match);
AST_NodePtr t(new eval::Int_AST_Node(match, i, m_filename, prev_line, prev_col, m_line, m_col));
m_match_stack.push_back(t);
}
else {
AST_NodePtr t(new eval::Int_AST_Node(match, AST_Node_Type::Int, m_filename, prev_line, prev_col, m_line, m_col));
Boxed_Value i = buildInt(std::dec, match);
AST_NodePtr t(new eval::Int_AST_Node(match, i, m_filename, prev_line, prev_col, m_line, m_col));
m_match_stack.push_back(t);
}
return true;
@@ -554,13 +752,13 @@ namespace chaiscript
if (*start == '`') {
//Id Literal
std::string match(start+1, m_input_pos-1);
AST_NodePtr t(new eval::Id_AST_Node(match, AST_Node_Type::Id, m_filename, prev_line, prev_col, m_line, m_col));
AST_NodePtr t(new eval::Id_AST_Node(match, m_filename, prev_line, prev_col, m_line, m_col));
m_match_stack.push_back(t);
return true;
}
else {
std::string match(start, m_input_pos);
AST_NodePtr t(new eval::Id_AST_Node(match, AST_Node_Type::Id, m_filename, prev_line, prev_col, m_line, m_col));
AST_NodePtr t(new eval::Id_AST_Node(match, m_filename, prev_line, prev_col, m_line, m_col));
m_match_stack.push_back(t);
return true;
}
@@ -593,7 +791,7 @@ namespace chaiscript
} while (Symbol("#"));
std::string match(start, m_input_pos);
AST_NodePtr t(new eval::Annotation_AST_Node(match, AST_Node_Type::Annotation, m_filename, prev_line, prev_col, m_line, m_col));
AST_NodePtr t(new eval::Annotation_AST_Node(match, m_filename, prev_line, prev_col, m_line, m_col));
m_match_stack.push_back(t);
return true;
}
@@ -607,10 +805,9 @@ namespace chaiscript
*/
bool Quoted_String_() {
bool retval = false;
char prev_char = 0;
if (has_more_input() && (*m_input_pos == '\"')) {
retval = true;
prev_char = *m_input_pos;
char prev_char = *m_input_pos;
++m_input_pos;
++m_col;
@@ -668,13 +865,13 @@ namespace chaiscript
if (is_interpolated) {
//If we've seen previous interpolation, add on instead of making a new one
AST_NodePtr t(new eval::Quoted_String_AST_Node(match, AST_Node_Type::Quoted_String, m_filename, prev_line, prev_col, m_line, m_col));
AST_NodePtr t(new eval::Quoted_String_AST_Node(match, m_filename, prev_line, prev_col, m_line, m_col));
m_match_stack.push_back(t);
build_match(AST_NodePtr(new eval::Addition_AST_Node()), prev_stack_top);
}
else {
AST_NodePtr t(new eval::Quoted_String_AST_Node(match, AST_Node_Type::Quoted_String, m_filename, prev_line, prev_col, m_line, m_col));
AST_NodePtr t(new eval::Quoted_String_AST_Node(match, m_filename, prev_line, prev_col, m_line, m_col));
m_match_stack.push_back(t);
}
@@ -694,17 +891,17 @@ namespace chaiscript
size_t tostr_stack_top = m_match_stack.size();
AST_NodePtr tostr(new eval::Id_AST_Node("to_string", AST_Node_Type::Id, m_filename, prev_line, prev_col, m_line, m_col));
AST_NodePtr tostr(new eval::Id_AST_Node("to_string", m_filename, prev_line, prev_col, m_line, m_col));
m_match_stack.push_back(tostr);
size_t ev_stack_top = m_match_stack.size();
AST_NodePtr ev(new eval::Id_AST_Node("eval", AST_Node_Type::Id, m_filename, prev_line, prev_col, m_line, m_col));
AST_NodePtr ev(new eval::Id_AST_Node("eval", m_filename, prev_line, prev_col, m_line, m_col));
m_match_stack.push_back(ev);
size_t arg_stack_top = m_match_stack.size();
AST_NodePtr t(new eval::Quoted_String_AST_Node(eval_match, AST_Node_Type::Quoted_String, m_filename, prev_line, prev_col, m_line, m_col));
AST_NodePtr t(new eval::Quoted_String_AST_Node(eval_match, m_filename, prev_line, prev_col, m_line, m_col));
m_match_stack.push_back(t);
build_match(AST_NodePtr(new eval::Arg_List_AST_Node()), arg_stack_top);
@@ -762,13 +959,13 @@ namespace chaiscript
}
}
if (is_interpolated) {
AST_NodePtr t(new eval::Quoted_String_AST_Node(match, AST_Node_Type::Quoted_String, m_filename, prev_line, prev_col, m_line, m_col));
AST_NodePtr t(new eval::Quoted_String_AST_Node(match, m_filename, prev_line, prev_col, m_line, m_col));
m_match_stack.push_back(t);
build_match(AST_NodePtr(new eval::Addition_AST_Node()), prev_stack_top);
}
else {
AST_NodePtr t(new eval::Quoted_String_AST_Node(match, AST_Node_Type::Quoted_String, m_filename, prev_line, prev_col, m_line, m_col));
AST_NodePtr t(new eval::Quoted_String_AST_Node(match, m_filename, prev_line, prev_col, m_line, m_col));
m_match_stack.push_back(t);
}
return true;
@@ -784,10 +981,9 @@ namespace chaiscript
*/
bool Single_Quoted_String_() {
bool retval = false;
char prev_char = 0;
if (has_more_input() && (*m_input_pos == '\'')) {
retval = true;
prev_char = *m_input_pos;
char prev_char = *m_input_pos;
++m_input_pos;
++m_col;
@@ -860,7 +1056,7 @@ namespace chaiscript
is_escaped = false;
}
}
AST_NodePtr t(new eval::Single_Quoted_String_AST_Node(match, AST_Node_Type::Single_Quoted_String, m_filename, prev_line, prev_col, m_line, m_col));
AST_NodePtr t(new eval::Single_Quoted_String_AST_Node(match, m_filename, prev_line, prev_col, m_line, m_col));
m_match_stack.push_back(t);
return true;
}
@@ -899,7 +1095,7 @@ namespace chaiscript
int prev_line = m_line;
if (Char_(t_c)) {
std::string match(start, m_input_pos);
AST_NodePtr t(new eval::Char_AST_Node(match, AST_Node_Type::Char, m_filename, prev_line, prev_col, m_line, m_col));
AST_NodePtr t(new eval::Char_AST_Node(match, m_filename, prev_line, prev_col, m_line, m_col));
m_match_stack.push_back(t);
return true;
}
@@ -951,7 +1147,7 @@ namespace chaiscript
if ( t_capture && retval ) {
std::string match(start, m_input_pos);
AST_NodePtr t(new eval::Str_AST_Node(match, AST_Node_Type::Str, m_filename, prev_line, prev_col, m_line, m_col));
AST_NodePtr t(new eval::Str_AST_Node(match, m_filename, prev_line, prev_col, m_line, m_col));
m_match_stack.push_back(t);
}
return retval;
@@ -999,7 +1195,7 @@ namespace chaiscript
if ( t_capture && retval ) {
std::string match(start, m_input_pos);
AST_NodePtr t(new eval::Str_AST_Node(match, AST_Node_Type::Str, m_filename, prev_line, prev_col, m_line, m_col));
AST_NodePtr t(new eval::Str_AST_Node(match, m_filename, prev_line, prev_col, m_line, m_col));
m_match_stack.push_back(t);
}
@@ -1039,7 +1235,7 @@ namespace chaiscript
int prev_line = m_line;
if (Eol_()) {
std::string match(start, m_input_pos);
AST_NodePtr t(new eval::Eol_AST_Node(match, AST_Node_Type::Eol, m_filename, prev_line, prev_col, m_line, m_col));
AST_NodePtr t(new eval::Eol_AST_Node(match, m_filename, prev_line, prev_col, m_line, m_col));
m_match_stack.push_back(t);
return true;
}
@@ -1153,7 +1349,6 @@ namespace chaiscript
bool Def() {
bool retval = false;
bool is_annotated = false;
bool is_method = false;
AST_NodePtr annotation;
if (Annotation()) {
@@ -1172,6 +1367,8 @@ namespace chaiscript
throw exception::eval_error("Missing function name in definition", File_Position(m_line, m_col), *m_filename);
}
bool is_method = false;
if (Symbol("::", false)) {
//We're now a method
is_method = true;
@@ -1309,7 +1506,7 @@ namespace chaiscript
if (Keyword("else", true)) {
if (Keyword("if")) {
AST_NodePtr back(m_match_stack.back());
m_match_stack.back() = AST_NodePtr(new eval::If_AST_Node("else if", back->identifier));
m_match_stack.back() = AST_NodePtr(new eval::If_AST_Node("else if"));
m_match_stack.back()->start = back->start;
m_match_stack.back()->end = back->end;
m_match_stack.back()->children = back->children;
@@ -1377,19 +1574,41 @@ namespace chaiscript
return retval;
}
/**
* Reads the C-style for conditions from input
*/
bool For_Guards() {
Equation();
if (!(Equation() && Eol()))
{
if (!Eol())
{
throw exception::eval_error("'for' loop initial statment missing", File_Position(m_line, m_col), *m_filename);
} else {
AST_NodePtr t(new eval::Noop_AST_Node());
m_match_stack.push_back(t);
}
}
if (!(Equation() && Eol()))
{
if (!Eol())
{
throw exception::eval_error("'for' loop condition missing", File_Position(m_line, m_col), *m_filename);
} else {
AST_NodePtr t(new eval::Noop_AST_Node());
m_match_stack.push_back(t);
}
}
if (!Equation())
{
AST_NodePtr t(new eval::Noop_AST_Node());
m_match_stack.push_back(t);
}
if (Char(';') && Operator() && Char(';') && Equation()) {
return true;
}
else {
throw exception::eval_error("Incomplete conditions in 'for' loop", File_Position(m_line, m_col), *m_filename);
}
}
/**
* Reads a for block from input
@@ -1563,6 +1782,23 @@ namespace chaiscript
return retval;
}
/**
* Reads a continue statement from input
*/
bool Continue() {
bool retval = false;
size_t prev_stack_top = m_match_stack.size();
if (Keyword("continue")) {
retval = true;
build_match(AST_NodePtr(new eval::Continue_AST_Node()), prev_stack_top);
}
return retval;
}
/**
* Reads a dot expression(member access), then proceeds to check if it's a function or array call
*/
@@ -1632,10 +1868,10 @@ namespace chaiscript
size_t prev_stack_top = m_match_stack.size();
if (Keyword("auto") || Keyword("var")) {
if (Keyword("var")) {
retval = true;
if (!(Reference() || Id(true))) {
if (!Id(true)) {
throw exception::eval_error("Incomplete variable declaration", File_Position(m_line, m_col), *m_filename);
}
@@ -1691,7 +1927,7 @@ namespace chaiscript
retval = true;
Container_Arg_List();
if (!Char(']')) {
throw exception::eval_error("Missing closing brace '}' in container initializer", File_Position(m_line, m_col), *m_filename);
throw exception::eval_error("Missing closing square bracket ']' in container initializer", File_Position(m_line, m_col), *m_filename);
}
if ((prev_stack_top != m_match_stack.size()) && (m_match_stack.back()->children.size() > 0)) {
if (m_match_stack.back()->children[0]->identifier == AST_Node_Type::Value_Range) {
@@ -1712,25 +1948,6 @@ namespace chaiscript
return retval;
}
bool Reference() {
bool retval = false;
size_t prev_stack_top = m_match_stack.size();
if (Symbol("&", false)) {
retval = true;
if (!Id(true)) {
throw exception::eval_error("Incomplete '&' expression", File_Position(m_line, m_col), *m_filename);
}
build_match(AST_NodePtr(
new eval::Reference_AST_Node()), prev_stack_top);
}
return retval;
}
/**
* Reads a unary prefixed expression from input
*/
@@ -1793,15 +2010,6 @@ namespace chaiscript
build_match(AST_NodePtr(new eval::Prefix_AST_Node()), prev_stack_top);
}
else if (Char('&', true)) {
retval = true;
if (!Operator(m_operators.size()-1)) {
throw exception::eval_error("Incomplete '~' expression", File_Position(m_line, m_col), *m_filename);
}
build_match(AST_NodePtr(new eval::Prefix_AST_Node()), prev_stack_top);
}
return retval;
}
@@ -2088,10 +2296,13 @@ namespace chaiscript
retval = true;
saw_eol = false;
}
else if (Block()) {
else if (Continue()) {
if (!saw_eol) {
throw exception::eval_error("Two expressions missing line separator", File_Position(prev_line, prev_col), *m_filename);
}
has_more = true;
retval = true;
saw_eol = true;
saw_eol = false;
}
else if (Equation()) {
if (!saw_eol) {
@@ -2106,6 +2317,11 @@ namespace chaiscript
retval = true;
saw_eol = true;
}
else if (Block()) {
has_more = true;
retval = true;
saw_eol = true;
}
else {
has_more = false;
}
@@ -2122,7 +2338,7 @@ namespace chaiscript
m_input_end = t_input.end();
m_line = 1;
m_col = 1;
m_filename = std::shared_ptr<std::string>(new std::string(t_fname));
m_filename = boost::shared_ptr<std::string>(new std::string(t_fname));
if ((t_input.size() > 1) && (t_input[0] == '#') && (t_input[1] == '!')) {
while ((m_input_pos != m_input_end) && (!Eol())) {

View File

@@ -1,7 +1,7 @@
// This file is distributed under the BSD License.
// See "license.txt" for details.
// Copyright 2009-2012, Jonathan Turner (jonathan@emptycrate.com)
// and Jason Turner (jason@emptycrate.com)
// Copyright 2009-2014, Jason Turner (jason@emptycrate.com)
// http://www.chaiscript.com
#ifndef CHAISCRIPT_PRELUDE_HPP_
@@ -54,8 +54,8 @@ def push_front(container, x) : call_exists(push_front_ref, container, x) { conta
def insert_at(container, pos, x) { container.insert_ref_at(pos, clone(x)); } \n\
# Returns the reverse of the given container\n\
def reverse(container) {\n\
auto retval = new(container); \n\
auto r = range(container); \n\
var retval = new(container); \n\
var r = range(container); \n\
while (!r.empty()) { \n\
retval.push_back(r.back()); \n\
r.pop_back(); \n\
@@ -82,7 +82,7 @@ def retro::pop_front() { pop_back(this.m_range) } \n\
def retro::empty() { empty(this.m_range); } \n\
# Performs the second value function over the container first value\n\
def for_each(container, func) : call_exists(range, container) { \n\
auto t_range = range(container); \n\
var t_range = range(container); \n\
while (!t_range.empty()) { \n\
func(t_range.front()); \n\
t_range.pop_front(); \n\
@@ -93,7 +93,7 @@ def back_inserter(container) { \n\
}\n\
\n\
def contains(container, item, compare_func) : call_exists(range, container) { \n\
auto t_range = range(container); \n\
var t_range = range(container); \n\
while (!t_range.empty()) { \n\
if ( compare_func(t_range.front(), item) ) { return true; } \n\
t_range.pop_front(); \n\
@@ -102,7 +102,7 @@ def contains(container, item, compare_func) : call_exists(range, container) { \n
} \n\
def contains(container, item) { return contains(container, item, eq) } \n\
def map(container, func, inserter) : call_exists(range, container) { \n\
auto range = range(container); \n\
var range = range(container); \n\
while (!range.empty()) { \n\
inserter(func(range.front())); \n\
range.pop_front(); \n\
@@ -110,14 +110,14 @@ def map(container, func, inserter) : call_exists(range, container) { \n\
} \n\
# Performs the second value function over the container first value. Creates a new container with the results\n\
def map(container, func) { \n\
auto retval = new(container); \n\
var retval = new(container); \n\
map(container, func, back_inserter(retval));\n\
retval;\n\
}\n\
# Performs the second value function over the container first value. Starts with initial and continues with each element.\n\
def foldl(container, func, initial) : call_exists(range, container){ \n\
auto retval = initial; \n\
auto range = range(container); \n\
var retval = initial; \n\
var range = range(container); \n\
while (!range.empty()) { \n\
retval = (func(range.front(), retval)); \n\
range.pop_front(); \n\
@@ -130,9 +130,9 @@ def sum(container) { foldl(container, `+`, 0.0) } \n\
def product(container) { foldl(container, `*`, 1.0) } \n\
# Returns a new container with the elements of the first value concatenated with the elements of the second value\n\
def concat(x, y) : call_exists(clone, x) { \n\
auto retval = x; \n\
auto inserter = back_inserter(retval); \n\
auto range = range(y); \n\
var retval = x; \n\
var inserter = back_inserter(retval); \n\
var range = range(y); \n\
while (!range.empty()) { \n\
inserter(range.front()); \n\
range.pop_front(); \n\
@@ -140,8 +140,8 @@ def concat(x, y) : call_exists(clone, x) { \n\
retval; \n\
} \n\
def take(container, num, inserter) : call_exists(range, container) { \n\
auto r = range(container); \n\
auto i = num; \n\
var r = range(container); \n\
var i = num; \n\
while ((i > 0) && (!r.empty())) { \n\
inserter(r.front()); \n\
r.pop_front(); \n\
@@ -150,12 +150,12 @@ def take(container, num, inserter) : call_exists(range, container) { \n\
} \n\
# Returns a new container with the given number of elements taken from the container\n\
def take(container, num) {\n\
auto retval = new(container); \n\
var retval = new(container); \n\
take(container, num, back_inserter(retval)); \n\
retval; \n\
}\n\
def take_while(container, f, inserter) : call_exists(range, container) { \n\
auto r = range(container); \n\
var r = range(container); \n\
while ((!r.empty()) && f(r.front())) { \n\
inserter(r.front()); \n\
r.pop_front(); \n\
@@ -163,13 +163,13 @@ def take_while(container, f, inserter) : call_exists(range, container) { \n\
} \n\
# Returns a new container with the given elements match the second value function\n\
def take_while(container, f) {\n\
auto retval = new(container); \n\
var retval = new(container); \n\
take_while(container, f, back_inserter(retval)); \n\
retval;\n\
}\n\
def drop(container, num, inserter) : call_exists(range, container) { \n\
auto r = range(container); \n\
auto i = num; \n\
var r = range(container); \n\
var i = num; \n\
while ((i > 0) && (!r.empty())) { \n\
r.pop_front(); \n\
--i; \n\
@@ -181,12 +181,12 @@ def drop(container, num, inserter) : call_exists(range, container) { \n\
} \n\
# Returns a new container with the given number of elements dropped from the given container \n\
def drop(container, num) {\n\
auto retval = new(container); \n\
var retval = new(container); \n\
drop(container, num, back_inserter(retval)); \n\
retval; \n\
}\n\
def drop_while(container, f, inserter) : call_exists(range, container) { \n\
auto r = range(container); \n\
var r = range(container); \n\
while ((!r.empty())&& f(r.front())) { \n\
r.pop_front(); \n\
} \n\
@@ -197,14 +197,14 @@ def drop_while(container, f, inserter) : call_exists(range, container) { \n\
} \n\
# Returns a new container with the given elements dropped that match the second value function\n\
def drop_while(container, f) {\n\
auto retval = new(container); \n\
var retval = new(container); \n\
drop_while(container, f, back_inserter(retval)); \n\
retval; \n\
}\n\
# Applies the second value function to the container. Starts with the first two elements. Expects at least 2 elements.\n\
def reduce(container, func) : container.size() >= 2 && call_exists(range, container) { \n\
auto r = range(container); \n\
auto retval = r.front(); \n\
var r = range(container); \n\
var retval = r.front(); \n\
r.pop_front(); \n\
retval = func(retval, r.front()); \n\
r.pop_front(); \n\
@@ -216,8 +216,8 @@ def reduce(container, func) : container.size() >= 2 && call_exists(range, contai
} \n\
# Returns a string of the elements in container delimited by the second value string\n\
def join(container, delim) { \n\
auto retval = ""; \n\
auto range = range(container); \n\
var retval = ""; \n\
var range = range(container); \n\
if (!range.empty()) { \n\
retval += to_string(range.front()); \n\
range.pop_front(); \n\
@@ -230,7 +230,7 @@ def join(container, delim) { \n\
retval; \n\
} \n\
def filter(container, f, inserter) : call_exists(range, container) { \n\
auto r = range(container); \n\
var r = range(container); \n\
while (!r.empty()) { \n\
if (f(r.front())) { \n\
inserter(r.front()); \n\
@@ -240,12 +240,12 @@ def filter(container, f, inserter) : call_exists(range, container) { \n\
} \n\
# Returns a new Vector which match the second value function\n\
def filter(container, f) { \n\
auto retval = new(container); \n\
var retval = new(container); \n\
filter(container, f, back_inserter(retval));\n\
retval;\n\
}\n\
def generate_range(x, y, inserter) { \n\
auto i = x; \n\
var i = x; \n\
while (i <= y) { \n\
inserter(i); \n\
++i; \n\
@@ -253,17 +253,17 @@ def generate_range(x, y, inserter) { \n\
} \n\
# Returns a new Vector which represents the range from the first value to the second value\n\
def generate_range(x, y) { \n\
auto retval = Vector(); \n\
var retval = Vector(); \n\
generate_range(x,y,back_inserter(retval)); \n\
retval; \n\
}\n\
# Returns a new Vector with the first value to the second value as its elements\n\
def collate(x, y) { \n\
return [x, y]; \n\
[x, y]; \n\
} \n\
def zip_with(f, x, y, inserter) : call_exists(range, x) && call_exists(range, y) { \n\
auto r_x = range(x); \n\
auto r_y = range(y); \n\
var r_x = range(x); \n\
var r_y = range(y); \n\
while (!r_x.empty() && !r_y.empty()) { \n\
inserter(f(r_x.front(), r_y.front())); \n\
r_x.pop_front(); \n\
@@ -272,7 +272,7 @@ def zip_with(f, x, y, inserter) : call_exists(range, x) && call_exists(range, y)
} \n\
# Returns a new Vector which joins matching elements of the second and third value with the first value function\n\
def zip_with(f, x, y) { \n\
auto retval = Vector(); \n\
var retval = Vector(); \n\
zip_with(f,x,y,back_inserter(retval)); \n\
retval;\n\
}\n\
@@ -314,7 +314,7 @@ 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\
auto range = range(container); \n\
var range = range(container); \n\
while (!range.empty()) { \n\
if (compare_func(range.front(), value)) { \n\
return range; \n\

View File

@@ -1,39 +1,96 @@
// This file is distributed under the BSD License.
// See "license.txt" for details.
// Copyright 2009-2012, Jonathan Turner (jonathan@emptycrate.com)
// and Jason Turner (jason@emptycrate.com)
// Copyright 2009-2014, 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_NO_CONSTRUCTOR_EX(_module, _class_name, _class_name_translator, _method_name_translator, _methods) \
{ \
_module->add(chaiscript::user_type<_class_name>(), _class_name_translator (BOOST_PP_STRINGIZE(_class_name))); \
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)
#define CHAISCRIPT_CLASS_NO_CONSTRUCTOR(_module, _class_name, _methods) \
CHAISCRIPT_CLASS_NO_CONSTRUCTOR_EX(_module, _class_name, chaiscript::utility::class_name_translator, \
chaiscript::utility::method_name_translator, _methods)
namespace chaiscript
{
/// \brief Classes and functions which provide general utility to the end user.
namespace utility
{
template<typename Class, typename ModuleType>
void add_class(ModuleType &t_module,
const std::string &t_classname,
const std::vector<chaiscript::Proxy_Function> &t_constructors,
const std::vector<std::pair<chaiscript::Proxy_Function, std::string>> &t_funcs)
inline std::string class_name_translator(const std::string &t_name)
{
t_module.add(chaiscript::user_type<Class>(), t_classname);
for(const chaiscript::Proxy_Function &ctor: t_constructors)
size_t colon = t_name.rfind("::");
if (colon != std::string::npos)
{
t_module.add(ctor, t_classname);
return t_name.substr(colon+2, std::string::npos);
} else {
return t_name;
}
}
for(auto fun: t_funcs)
inline std::string method_name_translator(const std::string &t_name)
{
t_module.add(fun.first, fun.second);
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);
}
}
}

View File

@@ -1,4 +1,7 @@
Copyright 2009-2012 Jason Turner and Jonathan Turner. All Rights Reserved.
Copyright 2009-2014 Jason Turner
Copyright 2009-2012 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:

85
readme.md Normal file
View File

@@ -0,0 +1,85 @@
[![Build Status](https://travis-ci.org/ChaiScript/ChaiScript.png?branch=master)](https://travis-ci.org/ChaiScript/ChaiScript)
ChaiScript
http://www.chaiscript.com
(c) 2009-2012 Jonathan Turner
(c) 2009-2014 Jason Turner
Release under the BSD license, see "license.txt" for details.
Introduction
============
ChaiScript is one of the only embedded scripting language designed from the
ground up to directly target C++ and take advantage of modern C++ development
techniques, working with the developer like he expects it to work. Being a
native C++ application, it has some advantages over existing embedded scripting
languages:
1) It uses a header-only approach, which makes it easy to integrate with
existing projects.
2) It maintains type safety between your C++ application and the user scripts.
3) It supports a variety of C++ techniques including callbacks, overloaded
functions, class methods, and stl containers.
Requirements
============
ChaiScript requires a recent version of Boost (http://www.boost.org) to build.
Usage
=====
* Add the ChaiScript include directory to your project's header search path
* Add `#include <chaiscript/chaiscript.hpp>` to your source file
* Instantiate the ChaiScript engine in your application. For example, create
a new engine with the name `chai` like so: `chaiscript::ChaiScript 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.eval(string)` and a file at a time using `chai.eval_file(fname)`
To make functions in your C++ code visible to scripts, they must be registered
with the scripting engine. To do so, call add:
chai.add(chaiscript::fun(&my_function), "my_function_name");
Once registered the function will be visible to scripts as "my_function_name"
Examples
========
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 examples of how to register parts of your C++ application, see
"example.cpp" in the "src" directory. Example.cpp is verbose and shows every
possible way of working with the library. For further documentation generate
the doxygen documentation in the build folder or see the website
http://www.chaiscript.com.
The shortest complete example possible follows:
/// main.cpp
#include <chaiscript/chaiscript.hpp>
double function(int i, double j)
{
return i * j;
}
int main()
{
chaiscript::ChaiScript chai;
chai.add(chaiscript::fun(&function), "function");
double d = chai.eval<double>("function(3, 4.75);");
}

View File

@@ -1,55 +0,0 @@
ChaiScript
http://www.chaiscript.com
(c) 2009-2012 Jason Turner and Jonathan Turner
Release under the BSD license, see "license.txt" for details.
[Introduction]
ChaiScript is one of the only embedded scripting language designed from the ground up to directly target C++ and take advantage of modern C++ development techniques, working with the developer like he expects it to work. Being a native C++ application, it has some advantages over existing embedded scripting languages:
1) It uses a header-only approach, which makes it easy to integrate with existing projects.
2) It maintains type safety between your C++ application and the user scripts.
3) It supports a variety of C++ techniques including callbacks, overloaded functions, class methods, and stl containers.
[Requirements]
ChaiScript requires a C++11 compiler to build with support for variadic templates. It has been tested with gcc 4.7 and clang 3.1 (with libcxx).
[Usage]
* Add the ChaiScript include directory to your project's header search path
* Add "#include <chaiscript/chaiscript.hpp> to your source file
* Instantiate the ChaiScript engine in your application. For example, create a new engine with the name 'chai' like so: "chaiscript::ChaiScript 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 add:
chai.add(chaiscript::fun(&my_function), "my_function_name");
Once registered the function will be visible to scripts as "my_function_name"
[Examples]
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 examples of how to register parts of your C++ application, see "example.cpp" in the "src" directory. Example.cpp is verbose and shows every possible way of working with the library. For further documentation generate the doxygen documentation in the build folder or see the website http://www.chaiscript.com.
The shortest complete example possible follows:
/// main.cpp
#include <chaiscript/chaiscript.hpp>
double function(int i, double j)
{
return i * j;
}
int main()
{
chaiscript::ChaiScript chai;
chai.add(chaiscript::fun(&function), "function");
double d = chai.eval<double>("function(3, 4.75);");
}

View File

@@ -1,6 +1,41 @@
Current Version: 4.3.1
Note: this is scheduled to be the last release that requires boost, new releases after this will require a C++11 compiler.
### Changes since 4.3.0
* Add automatic conversion of arithmetic return types, following the same
rules as conversion of arithmetic types when passing parameters
* Add automatic casting up the inheritence hierarchy when possible.
* Enable travis.ci testing
### Changes since 4.2.0
* Enhanced unit tests
* Add `continue` statement, fix various use cases for `for` loops
* Fix use of suffixed numbers in vector initialization
* Code cleanups
* Eliminate global data, which makes code more portable and thread safe
* Fix issue #79
* Merge pretty_print fixes from @mgee #82
* Compiler warning fixes for latest compiler releases
* Fix threading problems
* Fix linking error on MacOS Mavericks #88
* Allow non-const globals
* Make sure user cannot name a variable with `::` in it #91
* Fix various string / map / vector `size` and `count` calls for compilers which have weird overloads for them. #90 #93 #95
* Make module search path relative to the currently running executable
* Build and work with wstring windows builds
### Changes since 4.1.1
* Add support for automatic conversion of arithmetic types when possible
and when no ambiguous method dispatch exists.
### Changes since 4.1.0
* Fix missed gcc build error in 4.1.0
Changes since 4.0.0
* Dropped boost in favor of C++11
* Separated out stdlib to make more options for compile time improvements
* Fix sizing of numeric constants to match that of the C++ standard
* Add support for u,ll,l,f suffixes for numeric constants
* Siginificant improvement in error reporting
Changes since 3.1.0
* svenstaro: Unused variables and CMake consistency fixes
@@ -21,7 +56,7 @@ Changes since 3.1.0
* Increased unit tests to 161
* Performance enhancements
Changes since 3.0.0
### Changes since 3.0.0
* Numeric operations performance increased approximately 10x
* Looping operations performance increased up to 2x
* Engine start up time decreased
@@ -30,8 +65,7 @@ Changes since 3.0.0
uint8_t, uint16_t, uint32_t, uint64_t, int8_t, int16_t, int32_t, int64_t
* Enhanced support for capturing of exceptions thrown from ChaiScript in C++
Changes since 2.3.3
### Changes since 2.3.3
* Code simplifications
* Fully integrate documentation with source code in doxygen style comments
* Unit tests increased from 114 to 137

View File

@@ -7,17 +7,30 @@
#include <iostream>
#include <chaiscript/chaiscript.hpp>
#include <chaiscript/dispatchkit/bootstrap_stl.hpp>
#include <chaiscript/dispatchkit/function_call.hpp>
#include <boost/function.hpp>
#ifdef __llvm__
#pragma clang diagnostic push
#pragma clang diagnostic ignored "-Wunused-parameter"
#endif
#include <boost/date_time/posix_time/posix_time.hpp>
#ifdef __llvm__
#pragma clang diagnostic pop
#endif
#include <boost/regex.hpp>
void log(const std::string &msg)
{
std::cout << "[" << time(nullptr) << "] " << msg << std::endl;
std::cout << "[" << boost::posix_time::microsec_clock::local_time() << "] " << msg << std::endl;
}
void log(const std::string &module, const std::string &msg)
{
std::cout << "[" << time(nullptr) << "] <" << module << "> " << msg << std::endl;
std::cout << "[" << boost::posix_time::microsec_clock::local_time() << "] <" << module << "> " << msg << std::endl;
}
void bound_log(const std::string &msg)
@@ -38,19 +51,19 @@ void hello_constructor(const chaiscript::Boxed_Value & /*o*/)
struct System
{
std::map<std::string, std::function<std::string (const std::string &) > > m_callbacks;
std::map<std::string, boost::function<std::string (const std::string &) > > m_callbacks;
void add_callback(const std::string &t_name,
const chaiscript::Proxy_Function &t_func)
const boost::function<std::string (const std::string &)> &t_func)
{
m_callbacks[t_name] = chaiscript::dispatch::functor<std::string (const std::string &)>(t_func);
m_callbacks[t_name] = t_func;
}
void do_callbacks(const std::string &inp)
{
log("Running Callbacks: " + inp);
for (std::map<std::string, std::function<std::string (const std::string &)> >::iterator itr = m_callbacks.begin();
for (std::map<std::string, boost::function<std::string (const std::string &)> >::iterator itr = m_callbacks.begin();
itr != m_callbacks.end();
++itr)
{
@@ -59,7 +72,7 @@ struct System
}
};
void take_shared_ptr(const std::shared_ptr<const std::string> &p)
void take_shared_ptr(const boost::shared_ptr<const std::string> &p)
{
std::cout << *p << std::endl;
}
@@ -85,7 +98,7 @@ int main(int /*argc*/, char * /*argv*/[]) {
// Let's use chaiscript to add a new lambda callback to our system.
// The function "{ 'Callback1' + x }" is created in chaiscript and passed into our C++ application
// in the "add_callback" function of struct System the chaiscript function is converted into a
// std::function, so it can be handled and called easily and type-safely
// boost::function, so it can be handled and called easily and type-safely
chai.eval("system.add_callback(\"#1\", fun(x) { \"Callback1 \" + x });");
// Because we are sharing the "system" object with the chaiscript engine we have equal
@@ -106,14 +119,14 @@ int main(int /*argc*/, char * /*argv*/[]) {
// A shortcut to using eval is just to use the chai operator()
chai("log(\"Test Module\", \"Test Message\");");
//Finally, it is possible to register any std::function as a system function, in this
//Finally, it is possible to register any boost::function as a system function, in this
//way, we can, for instance add a bound member function to the system
chai.add(fun(&System::do_callbacks, std::ref(system), std::string("Bound Test")), "do_callbacks");
chai.add(fun(&System::do_callbacks, boost::ref(system), std::string("Bound Test")), "do_callbacks");
//Call bound version of do_callbacks
chai("do_callbacks()");
std::function<void ()> caller = chai.eval<std::function<void ()> >("fun() { system.do_callbacks(\"From Functor\"); }");
boost::function<void ()> caller = chai.eval<boost::function<void ()> >("fun() { system.do_callbacks(\"From Functor\"); }");
caller();
@@ -137,13 +150,13 @@ int main(int /*argc*/, char * /*argv*/[]) {
//To do: Add examples of handling Boxed_Values directly when needed
//Creating a functor on the stack and using it immediatly
int x = chai.eval<std::function<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);
std::stringstream ss;
ss << x;
log("Functor test output", ss.str());
chai.add(var(std::shared_ptr<int>()), "nullvar");
chai.add(var(boost::shared_ptr<int>()), "nullvar");
chai("print(\"This should be true.\"); print(nullvar.is_var_null())");
// test the global const action
@@ -165,7 +178,7 @@ int main(int /*argc*/, char * /*argv*/[]) {
//Dynamic objects test
chai.add(chaiscript::Proxy_Function(new dispatch::detail::Dynamic_Object_Function("TestType", fun(&hello_world))), "hello_world");
chai.add(chaiscript::Proxy_Function(new dispatch::detail::Dynamic_Object_Constructor("TestType", fun(&hello_constructor))), "TestType");
// chai.add(fun(std::function<Boxed_Value (dispatch::Dynamic_Object &)>(std::bind(&dispatch::detail::Dynamic_Object_Attribute::func, "TestType", "attr", std::placeholders::_1))), "attr");
// chai.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\"");

View File

@@ -1,14 +1,13 @@
#include <iostream>
#include <chaiscript/chaiscript.hpp>
#include <chaiscript/chaiscript_stdlib.hpp>
#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
@@ -31,12 +30,10 @@ void fuction(void)
class test
{
chaiscript::ChaiScript chai;
chaiscript::ChaiScript::State backupState;
ChaiScript chai;
ChaiScript::State backupState;
public:
test()
: chai(chaiscript::Std_Lib::library())
{
backupState = chai.get_state();
}
@@ -45,7 +42,7 @@ class test
void ResetState()
{
chai.set_state(backupState);
chai.add(chaiscript::fun(&fuction),"Whatever()");
chai.add(fun(&fuction),"Whatever()");
}
void RunFile(std::string sFile)

View File

@@ -5,7 +5,7 @@ def for_each(container, function)
while (!range.empty())
{
function(range.front());
range.popFront();
range.pop_front();
}
}

View File

@@ -1,21 +0,0 @@
#include <chaiscript/chaiscript_stdlib.hpp>
// MSVC doesn't like that we are using C++ return types from our C declared module
// but this is the best way to do it for cross platform compatibility
#ifdef CHAISCRIPT_MSVC
#pragma warning(push)
#pragma warning(disable : 4190)
#endif
CHAISCRIPT_MODULE_EXPORT chaiscript::ModulePtr create_chaiscript_module_chaiscript_stdlib()
{
return chaiscript::Std_Lib::library();
}
#ifdef CHAISCRIPT_MSVC
#pragma warning(pop)
#endif

View File

@@ -1,12 +1,12 @@
// This file is distributed under the BSD License.
// See "license.txt" for details.
// Copyright 2009-2010, Jonathan Turner (jonathan@emptycrate.com)
// and Jason Turner (jason@emptycrate.com)
// Copyright 2009-2012, Jonathan Turner (jonathan@emptycrate.com)
// Copyright 2009-2014, Jason Turner (jason@emptycrate.com)
// http://www.chaiscript.com
#include <iostream>
#include <list>
#include <regex>
#include <boost/algorithm/string/trim.hpp>
#define _CRT_SECURE_NO_WARNINGS
#include <chaiscript/chaiscript.hpp>
@@ -20,7 +20,7 @@ char* readline(const char* p)
std::string retval;
std::cout << p ;
std::getline(std::cin, retval);
#ifdef CHAISCRIPT_MSVC
#ifdef BOOST_MSVC
return std::cin.eof() ? NULL : _strdup(retval.c_str());
#else
return std::cin.eof() ? NULL : strdup(retval.c_str());
@@ -30,6 +30,86 @@ void add_history(const char*){}
void using_history(){}
#endif
void *cast_module_symbol(std::string (*t_path)())
{
union cast_union
{
std::string (*in_ptr)();
void *out_ptr;
};
cast_union c;
c.in_ptr = t_path;
return c.out_ptr;
}
std::string default_search_path()
{
#ifdef BOOST_WINDOWS // force no unicode
CHAR path[4096];
int size = GetModuleFileNameA(0, path, sizeof(path)-1);
std::string exepath(path, size);
size_t secondtolastslash = exepath.rfind('\\', exepath.rfind('\\') - 1);
if (secondtolastslash != std::string::npos)
{
return exepath.substr(0, secondtolastslash) + "\\lib\\chaiscript\\";
} else {
return "";
}
#else
std::string exepath;
std::vector<char> buf(2048);
ssize_t size = -1;
if ((size = readlink("/proc/self/exe", &buf.front(), buf.size())) != -1)
{
exepath = std::string(&buf.front(), size);
}
if (exepath.empty())
{
if ((size = readlink("/proc/curproc/file", &buf.front(), buf.size())) != -1)
{
exepath = std::string(&buf.front(), size);
}
}
if (exepath.empty())
{
if ((size = readlink("/proc/self/path/a.out", &buf.front(), buf.size())) != -1)
{
exepath = std::string(&buf.front(), size);
}
}
if (exepath.empty())
{
Dl_info rInfo;
memset( &rInfo, 0, sizeof(rInfo) );
if ( !dladdr(cast_module_symbol(&default_search_path), &rInfo) || !rInfo.dli_fname ) {
return "";
}
exepath = std::string(rInfo.dli_fname);
}
size_t secondtolastslash = exepath.rfind('/', exepath.rfind('/') - 1);
if (secondtolastslash != std::string::npos)
{
return exepath.substr(0, secondtolastslash) + "/lib/chaiscript/";
} else {
return "";
}
#endif
}
void help(int n) {
if ( n >= 0 ) {
std::cout << "ChaiScript evaluator. To evaluate an expression, type it and press <enter>." << std::endl;
@@ -52,7 +132,7 @@ void version(int){
std::cout << "chai: compiled " << __TIME__ << " " << __DATE__ << std::endl;
}
bool throws_exception(const std::function<void ()> &f)
bool throws_exception(const boost::function<void ()> &f)
{
try {
f();
@@ -63,7 +143,7 @@ bool throws_exception(const std::function<void ()> &f)
return false;
}
chaiscript::exception::eval_error get_eval_error(const std::function<void ()> &f)
chaiscript::exception::eval_error get_eval_error(const boost::function<void ()> &f)
{
try {
f();
@@ -80,7 +160,6 @@ std::string get_next_command() {
char *input_raw = readline("eval> ");
if ( input_raw ) {
add_history(input_raw);
std::string val(input_raw);
size_t pos = val.find_first_not_of("\t \n");
if (pos != std::string::npos)
@@ -92,9 +171,7 @@ std::string get_next_command() {
{
val.erase(pos+1, std::string::npos);
}
retval = val;
::free(input_raw);
}
}
@@ -127,7 +204,7 @@ void interactive(chaiscript::ChaiScript& chai)
//Then, we try to print the result of the evaluation to the user
if (!val.get_type_info().bare_equal(chaiscript::user_type<void>())) {
try {
std::cout << chai.eval<std::function<std::string (const chaiscript::Boxed_Value &bv)> >("to_string")(val) << std::endl;
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
}
@@ -152,7 +229,7 @@ int main(int argc, char *argv[])
std::vector<std::string> modulepaths;
// Disable deprecation warning for getenv call.
#ifdef CHAISCRIPT_MSVC
#ifdef BOOST_MSVC
#pragma warning(push)
#pragma warning(disable : 4996)
#endif
@@ -160,7 +237,7 @@ int main(int argc, char *argv[])
const char *usepath = getenv("CHAI_USE_PATH");
const char *modulepath = getenv("CHAI_MODULE_PATH");
#ifdef CHAISCRIPT_MSVC
#ifdef BOOST_MSVC
#pragma warning(pop)
#endif
@@ -170,6 +247,8 @@ int main(int argc, char *argv[])
usepaths.push_back(usepath);
}
std::string searchpath = default_search_path();
modulepaths.push_back(searchpath);
modulepaths.push_back("");
if (modulepath)
{
@@ -233,18 +312,7 @@ int main(int argc, char *argv[])
}
}
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 << ee.pretty_print();
std::cout << std::endl;
return EXIT_FAILURE;
}

View File

@@ -1,41 +0,0 @@
// This file is distributed under the BSD License.
// See "license.txt" for details.
// Copyright 2009-2010, Jonathan Turner (jonathan@emptycrate.com)
// and Jason Turner (jason@emptycrate.com)
// http://www.chaiscript.com
#include <iostream>
#include <list>
#include <chaiscript/chaiscript.hpp>
#include <thread>
void do_work(chaiscript::ChaiScript &c)
{
// c("use(\"work.chai\"); do_chai_work(num_iterations);");
std::stringstream ss;
ss << "MyVar" << rand();
c.add(chaiscript::var(5), ss.str());
c("use(\"work.chai\"); do_chai_work(10000);");
}
int main(int argc, char *argv[]) {
std::string input;
chaiscript::ChaiScript chai;
//chai.add_shared_object(chaiscript::Boxed_Value(10000), "num_iterations");
std::vector<std::shared_ptr<std::thread> > threads;
for (int i = 0; i < argc - 1; ++i)
{
threads.push_back(std::shared_ptr<std::thread>(new std::thread(std::bind(do_work, std::ref(chai)))));
}
for (int i = 0; i < argc - 1; ++i)
{
threads[i]->join();
}
}

View File

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

View File

@@ -1,22 +1,34 @@
// This file is distributed under the BSD License.
// See "license.txt" for details.
// Copyright 2009-2012, Jonathan Turner (jonathan@emptycrate.com)
// Copyright 2009-2014, Jason Turner (jason@emptycrate.com)
// http://www.chaiscript.com
#include <chaiscript/chaiscript.hpp>
#include <chaiscript/dispatchkit/bootstrap_stl.hpp>
#include <list>
#include <string>
// MSVC doesn't like that we are using C++ return types from our C declared module
// but this is the best way to do it for cross platform compatibility
#ifdef CHAISCRIPT_MSVC
#ifdef BOOST_MSVC
#pragma warning(push)
#pragma warning(disable : 4190)
#endif
#ifdef __llvm__
#pragma clang diagnostic push
#pragma clang diagnostic ignored "-Wreturn-type-c-linkage"
#endif
CHAISCRIPT_MODULE_EXPORT chaiscript::ModulePtr create_chaiscript_module_stl_extra()
{
return chaiscript::bootstrap::standard_library::list_type<std::list<chaiscript::Boxed_Value> >("List");
}
#ifdef __llvm__
#pragma clang diagnostic pop
#endif
#ifdef CHAISCRIPT_MSVC
#ifdef BOOST_MSVC
#pragma warning(pop)
#endif

View File

@@ -5,12 +5,21 @@
class TestBaseType
{
public:
TestBaseType() {}
TestBaseType(int) {}
TestBaseType(int *) {}
TestBaseType() : val(10), const_val(15) { }
TestBaseType(int) : val(10), const_val(15) {}
TestBaseType(int *) : val(10), const_val(15) {}
virtual ~TestBaseType() {}
virtual int func() { return 0; }
int base_only_func() { return -9; }
const TestBaseType &constMe() const { return *this; }
int val;
const int const_val;
private:
TestBaseType &operator=(const TestBaseType &);
};
enum TestEnum
@@ -28,8 +37,28 @@ class TestDerivedType : public TestBaseType
public:
virtual ~TestDerivedType() {}
virtual int func() { return 1; }
int derived_only_func() { return 19; }
private:
TestDerivedType &operator=(const TestDerivedType &);
};
class TestMoreDerivedType : public TestDerivedType
{
public:
virtual ~TestMoreDerivedType() {}
};
boost::shared_ptr<TestBaseType> derived_type_factory()
{
return boost::shared_ptr<TestBaseType>(new TestDerivedType());
}
boost::shared_ptr<TestBaseType> more_derived_type_factory()
{
return boost::shared_ptr<TestBaseType>(new TestMoreDerivedType());
}
std::string hello_world()
{
return "Hello World";
@@ -42,11 +71,15 @@ int *get_new_int()
// MSVC doesn't like that we are using C++ return types from our C declared module
// but this is the best way to do it for cross platform compatibility
#ifdef CHAISCRIPT_MSVC
#ifdef BOOST_MSVC
#pragma warning(push)
#pragma warning(disable : 4190)
#endif
#ifdef __llvm__
#pragma clang diagnostic push
#pragma clang diagnostic ignored "-Wreturn-type-c-linkage"
#endif
CHAISCRIPT_MODULE_EXPORT chaiscript::ModulePtr create_chaiscript_module_test_module()
{
@@ -56,6 +89,7 @@ CHAISCRIPT_MODULE_EXPORT chaiscript::ModulePtr create_chaiscript_module_test_mo
m->add(chaiscript::user_type<TestBaseType>(), "TestBaseType");
m->add(chaiscript::user_type<TestDerivedType>(), "TestDerivedType");
m->add(chaiscript::user_type<TestMoreDerivedType>(), "TestMoreDerivedType");
m->add(chaiscript::constructor<TestBaseType ()>(), "TestBaseType");
// m->add(chaiscript::constructor<TestBaseType (int)>(), "TestBaseType");
@@ -65,23 +99,45 @@ CHAISCRIPT_MODULE_EXPORT chaiscript::ModulePtr create_chaiscript_module_test_mo
m->add(chaiscript::constructor<TestDerivedType ()>(), "TestDerivedType");
m->add(chaiscript::constructor<TestDerivedType (const TestDerivedType &)>(), "TestDerivedType");
m->add(chaiscript::constructor<TestMoreDerivedType ()>(), "TestMoreDerivedType");
m->add(chaiscript::constructor<TestMoreDerivedType (const TestMoreDerivedType &)>(), "TestMoreDerivedType");
/// \todo automatic chaining of base classes?
m->add(chaiscript::base_class<TestBaseType, TestDerivedType>());
m->add(chaiscript::base_class<TestBaseType, TestMoreDerivedType>());
m->add(chaiscript::base_class<TestDerivedType, TestMoreDerivedType>());
m->add(chaiscript::fun(&TestDerivedType::derived_only_func), "derived_only_func");
m->add(chaiscript::fun(&derived_type_factory), "derived_type_factory");
m->add(chaiscript::fun(&more_derived_type_factory), "more_derived_type_factory");
m->add(chaiscript::fun(&TestDerivedType::func), "func");
m->add(chaiscript::fun(&TestBaseType::func), "func");
m->add(chaiscript::fun(&TestBaseType::val), "val");
m->add(chaiscript::fun(&TestBaseType::const_val), "const_val");
m->add(chaiscript::fun(&TestBaseType::base_only_func), "base_only_func");
m->add(chaiscript::fun(&get_new_int), "get_new_int");
m->add_global_const(chaiscript::const_var(TestValue1), "TestValue1");
m->add(chaiscript::user_type<TestEnum>(), "TestEnum");
m->add(chaiscript::fun(&to_int), "to_int");
m->add(chaiscript::fun(&TestBaseType::constMe), "constMe");
return m;
}
#ifdef CHAISCRIPT_MSVC
#ifdef __llvm__
#pragma clang diagnostic pop
#endif
#ifdef BOOST_MSVC
#pragma warning(pop)
#endif

View File

@@ -1,10 +0,0 @@
def do_chai_work(num_iters)
{
var i = 0;
for (var k = 0; k<num_iters * 10; ++k)
{
i += k;
}
print(i);
}

View File

@@ -1,2 +0,0 @@
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 } );

View File

@@ -1,2 +0,0 @@
var prod = bind(foldl, _, `*`, 1.0)
assert_equal(60, prod([3, 4, 5]))

View File

@@ -1,34 +0,0 @@
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));

View File

@@ -1 +0,0 @@
{print("hello")}

View File

@@ -1 +0,0 @@
assert_equal(false, !true)

View File

@@ -1,7 +0,0 @@
var i = 0
while (i < 10) {
if (++i == 5) {
break
}
}
assert_equal(5, i);

View File

@@ -1 +0,0 @@
assert_equal("b", to_string('b'))

View File

@@ -1,7 +0,0 @@
assert_equal(true, 1.is_var_const());
assert_equal(false, 1.is_var_reference());
assert_equal(true, 1.is_var_pointer());
assert_equal(false, 1.is_var_null());
assert_equal(false, 1.is_var_undef());
var i;
assert_equal(true, i.is_var_undef());

View File

@@ -1,3 +0,0 @@
var v = collate(1, 2)
assert_equal(1, v[0])
assert_equal(2, v[1])

View File

@@ -1 +0,0 @@
assert_equal(false, 1 > 2);

View File

@@ -1 +0,0 @@
assert_equal(true, 1 < 2)

View File

@@ -1,5 +0,0 @@
var v = concat([1, 2], [3, 4]);
assert_equal(4, v.size());
assert_equal(1, v[0]);
assert_equal(4, v[3]);

View File

@@ -1,4 +0,0 @@
//If the following succeeds, the test passes
"Hello World".for_each(fun(x) { print(x) } )

View File

@@ -1 +0,0 @@
assert_equal("3.5bob", 3.5.to_string() + "bob");

View File

@@ -1 +0,0 @@
assert_equal("3bob", 3.to_string + "bob")

View File

@@ -1 +0,0 @@
assert_equal(6.8, "3.5".to_double() + 3.3)

View File

@@ -1 +0,0 @@
assert_equal(8, "4".to_int() + 4)

View File

@@ -1,11 +0,0 @@
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)

View File

@@ -1,11 +0,0 @@
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));

View File

@@ -1 +0,0 @@
assert_equal([3,4], drop([1, 2, 3, 4], 2))

View File

@@ -1 +0,0 @@
assert_equal([2, 3], drop_while([1, 2, 3], odd))

View File

@@ -1,4 +0,0 @@
var x=.5
assert_equal(.5, x)
var y=-.5
assert_equal(-.5, y)

View File

@@ -1 +0,0 @@
assert_equal(7, eval("3 + 4"))

View File

@@ -1,39 +0,0 @@
load_module("reflection")
def deep()
{
try {
} catch {
} finally {
if (2)
{
}
}
}
def func()
{
deep();
}
def doing()
{
for (var i = 0; i < 10; ++i)
{
func();
}
}
def while_doing()
{
while (true)
{
doing();
}
}
var f = fun() { while_doing(); }
assert_equal(get_eval_error(f).call_stack.size(), 16)

View File

@@ -1 +0,0 @@
assert_equal(true, even(4))

View File

@@ -1,9 +0,0 @@
var x = 1
try {
throw(x)
x = 2
}
catch(e) {
x = e + 3
}
assert_equal(4, x);

View File

@@ -1,32 +0,0 @@
var finallyone = false;
try {
throw(3)
}
catch(x) {
assert_equal(3, x)
}
finally {
finallyone = true;
}
assert_equal(true, finallyone);
var try2 = false;
var catch2 = false;
var finally2 = false;
try {
try2 = true;
}
catch {
catch2 = true;
}
finally {
finally2 = true;
}
assert_equal(true, try2);
assert_equal(false, catch2);
assert_equal(true, finally2);

View File

@@ -1,34 +0,0 @@
var results = [];
for (var i = 2; i < 6; ++i) {
try {
throw(i)
}
catch(e) : e < 2 {
results.push_back("c1: " + e.to_string());
}
catch(e) : e < 4 {
results.push_back("c2: " + e.to_string());
}
catch(e) {
results.push_back("c3: " + e.to_string());
}
catch {
// Should never get called
assert_equal(false, true)
}
}
try {
throw(3)
}
catch(e) : e < 3
{
// Should never get called
assert_equal(false, true);
}
catch {
results.push_back("defaultcatch");
}
assert_equal(["c2: 2", "c2: 3", "c3: 4", "c3: 5", "defaultcatch"], results);

View File

@@ -1 +0,0 @@
assert_equal([1,3], filter([1, 2, 3, 4], odd))

View File

@@ -1,7 +0,0 @@
assert_equal(true, 1.2 < 2)
assert_equal(true, 1.2 > 1)
assert_equal(1.2, 1.2)
assert_equal(true, .5 > 0)
assert_equal(true, .5 < 1)
assert_equal(0.5, .5)

View File

@@ -1 +0,0 @@
assert_equal(10, foldl([1, 2, 3, 4], `+`, 0))

View File

@@ -1,7 +0,0 @@
var ret = []
for (var i = 0; i < 5; ++i) {
ret.push_back(i);
}
assert_equal([0,1,2,3,4], ret);

View File

@@ -1 +0,0 @@
for_each([1, 2, 3], print)

View File

@@ -1,3 +0,0 @@
var v = [1,2,3];
var r = range(v);
for_each(r, fun(x) { assert_equal(true, x>0); } )

View File

@@ -1,4 +0,0 @@
// Don't bother checking the output from this one, just makes sure it executes
var v = [1,2,3];
var r = retro(range(v));
for_each(r, print)

View File

@@ -1 +0,0 @@
assert_equal(2, `+`.get_contained_functions()[0].get_arity())

View File

@@ -1,76 +0,0 @@
#Test Function Description
def test_function(a)
{
return a;
}
// test_function tests
assert_equal(test_function.get_arity(), 1);
assert_equal(trim(test_function.get_annotation()), "#Test Function Description");
assert_equal(test_function.get_contained_functions().size(), 0);
assert_equal(test_function.get_param_types().size(), 2);
assert_equal(test_function, test_function);
assert_not_equal(test_function, `+`);
assert_equal(test_function.call([1]), 1);
// dynamic object function tests
def int::test_fun()
{
return this;
}
assert_equal(test_fun.get_arity(), 1);
assert_equal(test_fun.get_contained_functions.size(), 1);
assert_equal(test_fun.get_param_types().size(), 2);
assert_equal(test_fun, test_fun);
var test_fun_types = test_fun.get_param_types();
assert_equal(true, test_fun_types[0].bare_equal(Object_type));
assert_equal(true, test_fun_types[1].bare_equal(int_type));
// built-ins tests
assert_equal(2, `==`.get_arity());
// < should be the merging of two functions bool <(PODObject, PODObject) and bool <(string, string)
// we want to peel it apart and make sure that's true
var types = `<`.get_param_types();
assert_equal(3, types.size());
assert_equal(true, types[0].bare_equal(bool_type));
assert_equal(true, types[1].bare_equal(Object_type));
assert_equal(true, types[2].bare_equal(Object_type));
assert_equal(2, `<`.get_contained_functions().size());
// guard existence tests
def with_guard(x) : x > 3 {}
def without_guard(x) {}
def group_guard(x) {}
def group_guard(x) : x > 3 {}
assert_equal(true, with_guard.has_guard());
assert_equal(false, without_guard.has_guard());
assert_equal(2, group_guard.get_contained_functions().size());
var group = group_guard.get_contained_functions();
assert_equal(true, group[0].has_guard())
assert_equal(false, group[1].has_guard())
assert_throws("Function does not have a guard", fun() { group[0].get_guard(); } );
assert_throws("Function does not have a guard", fun() { without_guard.get_guard(); } );
var guard = with_guard.get_guard();
assert_equal(false, guard.has_guard());
assert_throws("Function does not have a guard", fun() { guard.get_guard(); } );

View File

@@ -1,3 +0,0 @@
var x = `+`
x = `-`
assert_equal(1, x(5,4))

View File

@@ -1 +0,0 @@
assert_equal([1,2,3,4,5,6,7,8,9,10], generate_range(1, 10))

View File

@@ -1,7 +0,0 @@
load_module("test_module")
assert_equal(to_int(TestValue1), 1)
assert_equal(TestValue1.type_name(), "TestEnum")

View File

@@ -1,7 +0,0 @@
var t = false;
if (true) {
t = true;
}
assert_equal(true, t);

View File

@@ -1,13 +0,0 @@
var i = 3
var b1 = false;
var b2 = false;
if (i == 2) {
b1 = true;
}
else {
b2 = true;
}
assert_equal(false, b1);
assert_equal(true, b2);

View File

@@ -1,18 +0,0 @@
var b1 = false;
var b2 = false;
var b3 = false;
var i = 3
if (i == 2) {
b1 = true;
}
else if (i == 4) {
b2 = true;
}
else if (i == 3) {
b3 = true;
}
assert_equal(false, b1);
assert_equal(false, b2);
assert_equal(true, b3);

View File

@@ -1,14 +0,0 @@
var i = 3
var b = false
if (i == 2) {
assert_equal(false, true)
}
else if (i == 4) {
assert_equal(false, true)
}
else {
assert_equal(true, true)
b = true
}
assert_equal(true, b)

Some files were not shown because too many files have changed in this diff Show More